]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/s390/cio/qdio_debug.c
Merge branch 'next' into for-linus
[linux.git] / drivers / s390 / cio / qdio_debug.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  Copyright IBM Corp. 2008, 2009
4  *
5  *  Author: Jan Glauber (jang@linux.vnet.ibm.com)
6  */
7 #include <linux/seq_file.h>
8 #include <linux/debugfs.h>
9 #include <linux/uaccess.h>
10 #include <linux/export.h>
11 #include <linux/slab.h>
12 #include <asm/debug.h>
13 #include "qdio_debug.h"
14 #include "qdio.h"
15
16 debug_info_t *qdio_dbf_setup;
17 debug_info_t *qdio_dbf_error;
18
19 static struct dentry *debugfs_root;
20 #define QDIO_DEBUGFS_NAME_LEN   10
21 #define QDIO_DBF_NAME_LEN       20
22
23 struct qdio_dbf_entry {
24         char dbf_name[QDIO_DBF_NAME_LEN];
25         debug_info_t *dbf_info;
26         struct list_head dbf_list;
27 };
28
29 static LIST_HEAD(qdio_dbf_list);
30 static DEFINE_MUTEX(qdio_dbf_list_mutex);
31
32 static debug_info_t *qdio_get_dbf_entry(char *name)
33 {
34         struct qdio_dbf_entry *entry;
35         debug_info_t *rc = NULL;
36
37         mutex_lock(&qdio_dbf_list_mutex);
38         list_for_each_entry(entry, &qdio_dbf_list, dbf_list) {
39                 if (strcmp(entry->dbf_name, name) == 0) {
40                         rc = entry->dbf_info;
41                         break;
42                 }
43         }
44         mutex_unlock(&qdio_dbf_list_mutex);
45         return rc;
46 }
47
48 static void qdio_clear_dbf_list(void)
49 {
50         struct qdio_dbf_entry *entry, *tmp;
51
52         mutex_lock(&qdio_dbf_list_mutex);
53         list_for_each_entry_safe(entry, tmp, &qdio_dbf_list, dbf_list) {
54                 list_del(&entry->dbf_list);
55                 debug_unregister(entry->dbf_info);
56                 kfree(entry);
57         }
58         mutex_unlock(&qdio_dbf_list_mutex);
59 }
60
61 int qdio_allocate_dbf(struct qdio_initialize *init_data,
62                        struct qdio_irq *irq_ptr)
63 {
64         char text[QDIO_DBF_NAME_LEN];
65         struct qdio_dbf_entry *new_entry;
66
67         DBF_EVENT("qfmt:%1d", init_data->q_format);
68         DBF_HEX(init_data->adapter_name, 8);
69         DBF_EVENT("qpff%4x", init_data->qib_param_field_format);
70         DBF_HEX(&init_data->qib_param_field, sizeof(void *));
71         DBF_HEX(&init_data->input_slib_elements, sizeof(void *));
72         DBF_HEX(&init_data->output_slib_elements, sizeof(void *));
73         DBF_EVENT("niq:%1d noq:%1d", init_data->no_input_qs,
74                   init_data->no_output_qs);
75         DBF_HEX(&init_data->input_handler, sizeof(void *));
76         DBF_HEX(&init_data->output_handler, sizeof(void *));
77         DBF_HEX(&init_data->int_parm, sizeof(long));
78         DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *));
79         DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *));
80         DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr);
81
82         /* allocate trace view for the interface */
83         snprintf(text, QDIO_DBF_NAME_LEN, "qdio_%s",
84                                         dev_name(&init_data->cdev->dev));
85         irq_ptr->debug_area = qdio_get_dbf_entry(text);
86         if (irq_ptr->debug_area)
87                 DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf reused");
88         else {
89                 irq_ptr->debug_area = debug_register(text, 2, 1, 16);
90                 if (!irq_ptr->debug_area)
91                         return -ENOMEM;
92                 if (debug_register_view(irq_ptr->debug_area,
93                                                 &debug_hex_ascii_view)) {
94                         debug_unregister(irq_ptr->debug_area);
95                         return -ENOMEM;
96                 }
97                 debug_set_level(irq_ptr->debug_area, DBF_WARN);
98                 DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created");
99                 new_entry = kzalloc(sizeof(struct qdio_dbf_entry), GFP_KERNEL);
100                 if (!new_entry) {
101                         debug_unregister(irq_ptr->debug_area);
102                         return -ENOMEM;
103                 }
104                 strlcpy(new_entry->dbf_name, text, QDIO_DBF_NAME_LEN);
105                 new_entry->dbf_info = irq_ptr->debug_area;
106                 mutex_lock(&qdio_dbf_list_mutex);
107                 list_add(&new_entry->dbf_list, &qdio_dbf_list);
108                 mutex_unlock(&qdio_dbf_list_mutex);
109         }
110         return 0;
111 }
112
113 static int qstat_show(struct seq_file *m, void *v)
114 {
115         unsigned char state;
116         struct qdio_q *q = m->private;
117         int i;
118
119         if (!q)
120                 return 0;
121
122         seq_printf(m, "Timestamp: %Lx  Last AI: %Lx\n",
123                    q->timestamp, last_ai_time);
124         seq_printf(m, "nr_used: %d  ftc: %d  last_move: %d\n",
125                    atomic_read(&q->nr_buf_used),
126                    q->first_to_check, q->last_move);
127         if (q->is_input_q) {
128                 seq_printf(m, "polling: %d  ack start: %d  ack count: %d\n",
129                            q->u.in.polling, q->u.in.ack_start,
130                            q->u.in.ack_count);
131                 seq_printf(m, "DSCI: %d   IRQs disabled: %u\n",
132                            *(u32 *)q->irq_ptr->dsci,
133                            test_bit(QDIO_QUEUE_IRQS_DISABLED,
134                            &q->u.in.queue_irq_state));
135         }
136         seq_printf(m, "SBAL states:\n");
137         seq_printf(m, "|0      |8      |16     |24     |32     |40     |48     |56  63|\n");
138
139         for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
140                 debug_get_buf_state(q, i, &state);
141                 switch (state) {
142                 case SLSB_P_INPUT_NOT_INIT:
143                 case SLSB_P_OUTPUT_NOT_INIT:
144                         seq_printf(m, "N");
145                         break;
146                 case SLSB_P_OUTPUT_PENDING:
147                         seq_printf(m, "P");
148                         break;
149                 case SLSB_P_INPUT_PRIMED:
150                 case SLSB_CU_OUTPUT_PRIMED:
151                         seq_printf(m, "+");
152                         break;
153                 case SLSB_P_INPUT_ACK:
154                         seq_printf(m, "A");
155                         break;
156                 case SLSB_P_INPUT_ERROR:
157                 case SLSB_P_OUTPUT_ERROR:
158                         seq_printf(m, "x");
159                         break;
160                 case SLSB_CU_INPUT_EMPTY:
161                 case SLSB_P_OUTPUT_EMPTY:
162                         seq_printf(m, "-");
163                         break;
164                 case SLSB_P_INPUT_HALTED:
165                 case SLSB_P_OUTPUT_HALTED:
166                         seq_printf(m, ".");
167                         break;
168                 default:
169                         seq_printf(m, "?");
170                 }
171                 if (i == 63)
172                         seq_printf(m, "\n");
173         }
174         seq_printf(m, "\n");
175         seq_printf(m, "|64     |72     |80     |88     |96     |104    |112    |   127|\n");
176
177         seq_printf(m, "\nSBAL statistics:");
178         if (!q->irq_ptr->perf_stat_enabled) {
179                 seq_printf(m, " disabled\n");
180                 return 0;
181         }
182
183         seq_printf(m, "\n1          2..        4..        8..        "
184                    "16..       32..       64..       127\n");
185         for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
186                 seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
187         seq_printf(m, "\nError      NOP        Total\n%-10u %-10u %-10u\n\n",
188                    q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
189                    q->q_stats.nr_sbal_total);
190         return 0;
191 }
192
193 DEFINE_SHOW_ATTRIBUTE(qstat);
194
195 static char *qperf_names[] = {
196         "Assumed adapter interrupts",
197         "QDIO interrupts",
198         "Requested PCIs",
199         "Inbound tasklet runs",
200         "Inbound tasklet resched",
201         "Inbound tasklet resched2",
202         "Outbound tasklet runs",
203         "SIGA read",
204         "SIGA write",
205         "SIGA sync",
206         "Inbound calls",
207         "Inbound handler",
208         "Inbound stop_polling",
209         "Inbound queue full",
210         "Outbound calls",
211         "Outbound handler",
212         "Outbound queue full",
213         "Outbound fast_requeue",
214         "Outbound target_full",
215         "QEBSM eqbs",
216         "QEBSM eqbs partial",
217         "QEBSM sqbs",
218         "QEBSM sqbs partial",
219         "Discarded interrupts"
220 };
221
222 static int qperf_show(struct seq_file *m, void *v)
223 {
224         struct qdio_irq *irq_ptr = m->private;
225         unsigned int *stat;
226         int i;
227
228         if (!irq_ptr)
229                 return 0;
230         if (!irq_ptr->perf_stat_enabled) {
231                 seq_printf(m, "disabled\n");
232                 return 0;
233         }
234         stat = (unsigned int *)&irq_ptr->perf_stat;
235
236         for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
237                 seq_printf(m, "%26s:\t%u\n",
238                            qperf_names[i], *(stat + i));
239         return 0;
240 }
241
242 static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
243                                size_t count, loff_t *off)
244 {
245         struct seq_file *seq = file->private_data;
246         struct qdio_irq *irq_ptr = seq->private;
247         struct qdio_q *q;
248         unsigned long val;
249         int ret, i;
250
251         if (!irq_ptr)
252                 return 0;
253
254         ret = kstrtoul_from_user(ubuf, count, 10, &val);
255         if (ret)
256                 return ret;
257
258         switch (val) {
259         case 0:
260                 irq_ptr->perf_stat_enabled = 0;
261                 memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
262                 for_each_input_queue(irq_ptr, q, i)
263                         memset(&q->q_stats, 0, sizeof(q->q_stats));
264                 for_each_output_queue(irq_ptr, q, i)
265                         memset(&q->q_stats, 0, sizeof(q->q_stats));
266                 break;
267         case 1:
268                 irq_ptr->perf_stat_enabled = 1;
269                 break;
270         }
271         return count;
272 }
273
274 static int qperf_seq_open(struct inode *inode, struct file *filp)
275 {
276         return single_open(filp, qperf_show,
277                            file_inode(filp)->i_private);
278 }
279
280 static const struct file_operations debugfs_perf_fops = {
281         .owner   = THIS_MODULE,
282         .open    = qperf_seq_open,
283         .read    = seq_read,
284         .write   = qperf_seq_write,
285         .llseek  = seq_lseek,
286         .release = single_release,
287 };
288
289 static void setup_debugfs_entry(struct qdio_q *q)
290 {
291         char name[QDIO_DEBUGFS_NAME_LEN];
292
293         snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
294                  q->is_input_q ? "input" : "output",
295                  q->nr);
296         q->debugfs_q = debugfs_create_file(name, 0444,
297                                 q->irq_ptr->debugfs_dev, q, &qstat_fops);
298         if (IS_ERR(q->debugfs_q))
299                 q->debugfs_q = NULL;
300 }
301
302 void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
303 {
304         struct qdio_q *q;
305         int i;
306
307         irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
308                                                   debugfs_root);
309         if (IS_ERR(irq_ptr->debugfs_dev))
310                 irq_ptr->debugfs_dev = NULL;
311
312         irq_ptr->debugfs_perf = debugfs_create_file("statistics",
313                                 S_IFREG | S_IRUGO | S_IWUSR,
314                                 irq_ptr->debugfs_dev, irq_ptr,
315                                 &debugfs_perf_fops);
316         if (IS_ERR(irq_ptr->debugfs_perf))
317                 irq_ptr->debugfs_perf = NULL;
318
319         for_each_input_queue(irq_ptr, q, i)
320                 setup_debugfs_entry(q);
321         for_each_output_queue(irq_ptr, q, i)
322                 setup_debugfs_entry(q);
323 }
324
325 void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr)
326 {
327         struct qdio_q *q;
328         int i;
329
330         for_each_input_queue(irq_ptr, q, i)
331                 debugfs_remove(q->debugfs_q);
332         for_each_output_queue(irq_ptr, q, i)
333                 debugfs_remove(q->debugfs_q);
334         debugfs_remove(irq_ptr->debugfs_perf);
335         debugfs_remove(irq_ptr->debugfs_dev);
336 }
337
338 int __init qdio_debug_init(void)
339 {
340         debugfs_root = debugfs_create_dir("qdio", NULL);
341
342         qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
343         debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
344         debug_set_level(qdio_dbf_setup, DBF_INFO);
345         DBF_EVENT("dbf created\n");
346
347         qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
348         debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
349         debug_set_level(qdio_dbf_error, DBF_INFO);
350         DBF_ERROR("dbf created\n");
351         return 0;
352 }
353
354 void qdio_debug_exit(void)
355 {
356         qdio_clear_dbf_list();
357         debugfs_remove(debugfs_root);
358         debug_unregister(qdio_dbf_setup);
359         debug_unregister(qdio_dbf_error);
360 }