Merge branch 'i2c/for-current-fixed' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.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 static int qstat_seq_open(struct inode *inode, struct file *filp)
194 {
195         return single_open(filp, qstat_show,
196                            file_inode(filp)->i_private);
197 }
198
199 static const struct file_operations debugfs_fops = {
200         .owner   = THIS_MODULE,
201         .open    = qstat_seq_open,
202         .read    = seq_read,
203         .llseek  = seq_lseek,
204         .release = single_release,
205 };
206
207 static char *qperf_names[] = {
208         "Assumed adapter interrupts",
209         "QDIO interrupts",
210         "Requested PCIs",
211         "Inbound tasklet runs",
212         "Inbound tasklet resched",
213         "Inbound tasklet resched2",
214         "Outbound tasklet runs",
215         "SIGA read",
216         "SIGA write",
217         "SIGA sync",
218         "Inbound calls",
219         "Inbound handler",
220         "Inbound stop_polling",
221         "Inbound queue full",
222         "Outbound calls",
223         "Outbound handler",
224         "Outbound queue full",
225         "Outbound fast_requeue",
226         "Outbound target_full",
227         "QEBSM eqbs",
228         "QEBSM eqbs partial",
229         "QEBSM sqbs",
230         "QEBSM sqbs partial",
231         "Discarded interrupts"
232 };
233
234 static int qperf_show(struct seq_file *m, void *v)
235 {
236         struct qdio_irq *irq_ptr = m->private;
237         unsigned int *stat;
238         int i;
239
240         if (!irq_ptr)
241                 return 0;
242         if (!irq_ptr->perf_stat_enabled) {
243                 seq_printf(m, "disabled\n");
244                 return 0;
245         }
246         stat = (unsigned int *)&irq_ptr->perf_stat;
247
248         for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
249                 seq_printf(m, "%26s:\t%u\n",
250                            qperf_names[i], *(stat + i));
251         return 0;
252 }
253
254 static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
255                                size_t count, loff_t *off)
256 {
257         struct seq_file *seq = file->private_data;
258         struct qdio_irq *irq_ptr = seq->private;
259         struct qdio_q *q;
260         unsigned long val;
261         int ret, i;
262
263         if (!irq_ptr)
264                 return 0;
265
266         ret = kstrtoul_from_user(ubuf, count, 10, &val);
267         if (ret)
268                 return ret;
269
270         switch (val) {
271         case 0:
272                 irq_ptr->perf_stat_enabled = 0;
273                 memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
274                 for_each_input_queue(irq_ptr, q, i)
275                         memset(&q->q_stats, 0, sizeof(q->q_stats));
276                 for_each_output_queue(irq_ptr, q, i)
277                         memset(&q->q_stats, 0, sizeof(q->q_stats));
278                 break;
279         case 1:
280                 irq_ptr->perf_stat_enabled = 1;
281                 break;
282         }
283         return count;
284 }
285
286 static int qperf_seq_open(struct inode *inode, struct file *filp)
287 {
288         return single_open(filp, qperf_show,
289                            file_inode(filp)->i_private);
290 }
291
292 static const struct file_operations debugfs_perf_fops = {
293         .owner   = THIS_MODULE,
294         .open    = qperf_seq_open,
295         .read    = seq_read,
296         .write   = qperf_seq_write,
297         .llseek  = seq_lseek,
298         .release = single_release,
299 };
300
301 static void setup_debugfs_entry(struct qdio_q *q)
302 {
303         char name[QDIO_DEBUGFS_NAME_LEN];
304
305         snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
306                  q->is_input_q ? "input" : "output",
307                  q->nr);
308         q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
309                                 q->irq_ptr->debugfs_dev, q, &debugfs_fops);
310         if (IS_ERR(q->debugfs_q))
311                 q->debugfs_q = NULL;
312 }
313
314 void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
315 {
316         struct qdio_q *q;
317         int i;
318
319         irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
320                                                   debugfs_root);
321         if (IS_ERR(irq_ptr->debugfs_dev))
322                 irq_ptr->debugfs_dev = NULL;
323
324         irq_ptr->debugfs_perf = debugfs_create_file("statistics",
325                                 S_IFREG | S_IRUGO | S_IWUSR,
326                                 irq_ptr->debugfs_dev, irq_ptr,
327                                 &debugfs_perf_fops);
328         if (IS_ERR(irq_ptr->debugfs_perf))
329                 irq_ptr->debugfs_perf = NULL;
330
331         for_each_input_queue(irq_ptr, q, i)
332                 setup_debugfs_entry(q);
333         for_each_output_queue(irq_ptr, q, i)
334                 setup_debugfs_entry(q);
335 }
336
337 void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr)
338 {
339         struct qdio_q *q;
340         int i;
341
342         for_each_input_queue(irq_ptr, q, i)
343                 debugfs_remove(q->debugfs_q);
344         for_each_output_queue(irq_ptr, q, i)
345                 debugfs_remove(q->debugfs_q);
346         debugfs_remove(irq_ptr->debugfs_perf);
347         debugfs_remove(irq_ptr->debugfs_dev);
348 }
349
350 int __init qdio_debug_init(void)
351 {
352         debugfs_root = debugfs_create_dir("qdio", NULL);
353
354         qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
355         debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
356         debug_set_level(qdio_dbf_setup, DBF_INFO);
357         DBF_EVENT("dbf created\n");
358
359         qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
360         debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
361         debug_set_level(qdio_dbf_error, DBF_INFO);
362         DBF_ERROR("dbf created\n");
363         return 0;
364 }
365
366 void qdio_debug_exit(void)
367 {
368         qdio_clear_dbf_list();
369         debugfs_remove(debugfs_root);
370         debug_unregister(qdio_dbf_setup);
371         debug_unregister(qdio_dbf_error);
372 }