]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/s390/cio/qdio_debug.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[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\n",
125                    atomic_read(&q->nr_buf_used), q->first_to_check);
126         if (q->is_input_q) {
127                 seq_printf(m, "ack start: %d  ack count: %d\n",
128                            q->u.in.ack_start, q->u.in.ack_count);
129                 seq_printf(m, "DSCI: %x   IRQs disabled: %u\n",
130                            *(u8 *)q->irq_ptr->dsci,
131                            test_bit(QDIO_QUEUE_IRQS_DISABLED,
132                            &q->u.in.queue_irq_state));
133         }
134         seq_printf(m, "SBAL states:\n");
135         seq_printf(m, "|0      |8      |16     |24     |32     |40     |48     |56  63|\n");
136
137         for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
138                 debug_get_buf_state(q, i, &state);
139                 switch (state) {
140                 case SLSB_P_INPUT_NOT_INIT:
141                 case SLSB_P_OUTPUT_NOT_INIT:
142                         seq_printf(m, "N");
143                         break;
144                 case SLSB_P_OUTPUT_PENDING:
145                         seq_printf(m, "P");
146                         break;
147                 case SLSB_P_INPUT_PRIMED:
148                 case SLSB_CU_OUTPUT_PRIMED:
149                         seq_printf(m, "+");
150                         break;
151                 case SLSB_P_INPUT_ACK:
152                         seq_printf(m, "A");
153                         break;
154                 case SLSB_P_INPUT_ERROR:
155                 case SLSB_P_OUTPUT_ERROR:
156                         seq_printf(m, "x");
157                         break;
158                 case SLSB_CU_INPUT_EMPTY:
159                 case SLSB_P_OUTPUT_EMPTY:
160                         seq_printf(m, "-");
161                         break;
162                 case SLSB_P_INPUT_HALTED:
163                 case SLSB_P_OUTPUT_HALTED:
164                         seq_printf(m, ".");
165                         break;
166                 default:
167                         seq_printf(m, "?");
168                 }
169                 if (i == 63)
170                         seq_printf(m, "\n");
171         }
172         seq_printf(m, "\n");
173         seq_printf(m, "|64     |72     |80     |88     |96     |104    |112    |   127|\n");
174
175         seq_printf(m, "\nSBAL statistics:");
176         if (!q->irq_ptr->perf_stat_enabled) {
177                 seq_printf(m, " disabled\n");
178                 return 0;
179         }
180
181         seq_printf(m, "\n1          2..        4..        8..        "
182                    "16..       32..       64..       127\n");
183         for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
184                 seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
185         seq_printf(m, "\nError      NOP        Total\n%-10u %-10u %-10u\n\n",
186                    q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
187                    q->q_stats.nr_sbal_total);
188         return 0;
189 }
190
191 DEFINE_SHOW_ATTRIBUTE(qstat);
192
193 static char *qperf_names[] = {
194         "Assumed adapter interrupts",
195         "QDIO interrupts",
196         "Requested PCIs",
197         "Inbound tasklet runs",
198         "Inbound tasklet resched",
199         "Inbound tasklet resched2",
200         "Outbound tasklet runs",
201         "SIGA read",
202         "SIGA write",
203         "SIGA sync",
204         "Inbound calls",
205         "Inbound handler",
206         "Inbound stop_polling",
207         "Inbound queue full",
208         "Outbound calls",
209         "Outbound handler",
210         "Outbound queue full",
211         "Outbound fast_requeue",
212         "Outbound target_full",
213         "QEBSM eqbs",
214         "QEBSM eqbs partial",
215         "QEBSM sqbs",
216         "QEBSM sqbs partial",
217         "Discarded interrupts"
218 };
219
220 static int qperf_show(struct seq_file *m, void *v)
221 {
222         struct qdio_irq *irq_ptr = m->private;
223         unsigned int *stat;
224         int i;
225
226         if (!irq_ptr)
227                 return 0;
228         if (!irq_ptr->perf_stat_enabled) {
229                 seq_printf(m, "disabled\n");
230                 return 0;
231         }
232         stat = (unsigned int *)&irq_ptr->perf_stat;
233
234         for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
235                 seq_printf(m, "%26s:\t%u\n",
236                            qperf_names[i], *(stat + i));
237         return 0;
238 }
239
240 static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
241                                size_t count, loff_t *off)
242 {
243         struct seq_file *seq = file->private_data;
244         struct qdio_irq *irq_ptr = seq->private;
245         struct qdio_q *q;
246         unsigned long val;
247         int ret, i;
248
249         if (!irq_ptr)
250                 return 0;
251
252         ret = kstrtoul_from_user(ubuf, count, 10, &val);
253         if (ret)
254                 return ret;
255
256         switch (val) {
257         case 0:
258                 irq_ptr->perf_stat_enabled = 0;
259                 memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
260                 for_each_input_queue(irq_ptr, q, i)
261                         memset(&q->q_stats, 0, sizeof(q->q_stats));
262                 for_each_output_queue(irq_ptr, q, i)
263                         memset(&q->q_stats, 0, sizeof(q->q_stats));
264                 break;
265         case 1:
266                 irq_ptr->perf_stat_enabled = 1;
267                 break;
268         }
269         return count;
270 }
271
272 static int qperf_seq_open(struct inode *inode, struct file *filp)
273 {
274         return single_open(filp, qperf_show,
275                            file_inode(filp)->i_private);
276 }
277
278 static const struct file_operations debugfs_perf_fops = {
279         .owner   = THIS_MODULE,
280         .open    = qperf_seq_open,
281         .read    = seq_read,
282         .write   = qperf_seq_write,
283         .llseek  = seq_lseek,
284         .release = single_release,
285 };
286
287 static void setup_debugfs_entry(struct qdio_q *q)
288 {
289         char name[QDIO_DEBUGFS_NAME_LEN];
290
291         snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
292                  q->is_input_q ? "input" : "output",
293                  q->nr);
294         q->debugfs_q = debugfs_create_file(name, 0444,
295                                 q->irq_ptr->debugfs_dev, q, &qstat_fops);
296         if (IS_ERR(q->debugfs_q))
297                 q->debugfs_q = NULL;
298 }
299
300 void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
301 {
302         struct qdio_q *q;
303         int i;
304
305         irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
306                                                   debugfs_root);
307         if (IS_ERR(irq_ptr->debugfs_dev))
308                 irq_ptr->debugfs_dev = NULL;
309
310         irq_ptr->debugfs_perf = debugfs_create_file("statistics",
311                                 S_IFREG | S_IRUGO | S_IWUSR,
312                                 irq_ptr->debugfs_dev, irq_ptr,
313                                 &debugfs_perf_fops);
314         if (IS_ERR(irq_ptr->debugfs_perf))
315                 irq_ptr->debugfs_perf = NULL;
316
317         for_each_input_queue(irq_ptr, q, i)
318                 setup_debugfs_entry(q);
319         for_each_output_queue(irq_ptr, q, i)
320                 setup_debugfs_entry(q);
321 }
322
323 void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr)
324 {
325         struct qdio_q *q;
326         int i;
327
328         for_each_input_queue(irq_ptr, q, i)
329                 debugfs_remove(q->debugfs_q);
330         for_each_output_queue(irq_ptr, q, i)
331                 debugfs_remove(q->debugfs_q);
332         debugfs_remove(irq_ptr->debugfs_perf);
333         debugfs_remove(irq_ptr->debugfs_dev);
334 }
335
336 int __init qdio_debug_init(void)
337 {
338         debugfs_root = debugfs_create_dir("qdio", NULL);
339
340         qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
341         debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
342         debug_set_level(qdio_dbf_setup, DBF_INFO);
343         DBF_EVENT("dbf created\n");
344
345         qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
346         debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
347         debug_set_level(qdio_dbf_error, DBF_INFO);
348         DBF_ERROR("dbf created\n");
349         return 0;
350 }
351
352 void qdio_debug_exit(void)
353 {
354         qdio_clear_dbf_list();
355         debugfs_remove(debugfs_root);
356         debug_unregister(qdio_dbf_setup);
357         debug_unregister(qdio_dbf_error);
358 }