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