GNU Linux-libre 5.10.217-gnu1
[releases.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_irq *irq_ptr)
62 {
63         char text[QDIO_DBF_NAME_LEN];
64         struct qdio_dbf_entry *new_entry;
65
66         DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr);
67
68         /* allocate trace view for the interface */
69         snprintf(text, QDIO_DBF_NAME_LEN, "qdio_%s",
70                  dev_name(&irq_ptr->cdev->dev));
71         irq_ptr->debug_area = qdio_get_dbf_entry(text);
72         if (irq_ptr->debug_area)
73                 DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf reused");
74         else {
75                 irq_ptr->debug_area = debug_register(text, 2, 1, 16);
76                 if (!irq_ptr->debug_area)
77                         return -ENOMEM;
78                 if (debug_register_view(irq_ptr->debug_area,
79                                                 &debug_hex_ascii_view)) {
80                         debug_unregister(irq_ptr->debug_area);
81                         return -ENOMEM;
82                 }
83                 debug_set_level(irq_ptr->debug_area, DBF_WARN);
84                 DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created");
85                 new_entry = kzalloc(sizeof(struct qdio_dbf_entry), GFP_KERNEL);
86                 if (!new_entry) {
87                         debug_unregister(irq_ptr->debug_area);
88                         return -ENOMEM;
89                 }
90                 strlcpy(new_entry->dbf_name, text, QDIO_DBF_NAME_LEN);
91                 new_entry->dbf_info = irq_ptr->debug_area;
92                 mutex_lock(&qdio_dbf_list_mutex);
93                 list_add(&new_entry->dbf_list, &qdio_dbf_list);
94                 mutex_unlock(&qdio_dbf_list_mutex);
95         }
96         return 0;
97 }
98
99 static int qstat_show(struct seq_file *m, void *v)
100 {
101         unsigned char state;
102         struct qdio_q *q = m->private;
103         int i;
104
105         if (!q)
106                 return 0;
107
108         seq_printf(m, "Timestamp: %Lx  Last AI: %Lx\n",
109                    q->timestamp, last_ai_time);
110         seq_printf(m, "nr_used: %d  ftc: %d\n",
111                    atomic_read(&q->nr_buf_used), q->first_to_check);
112         if (q->is_input_q) {
113                 seq_printf(m, "batch start: %u  batch count: %u\n",
114                            q->u.in.batch_start, q->u.in.batch_count);
115                 seq_printf(m, "DSCI: %x   IRQs disabled: %u\n",
116                            *(u8 *)q->irq_ptr->dsci,
117                            test_bit(QDIO_IRQ_DISABLED,
118                                     &q->irq_ptr->poll_state));
119         }
120         seq_printf(m, "SBAL states:\n");
121         seq_printf(m, "|0      |8      |16     |24     |32     |40     |48     |56  63|\n");
122
123         for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
124                 debug_get_buf_state(q, i, &state);
125                 switch (state) {
126                 case SLSB_P_INPUT_NOT_INIT:
127                 case SLSB_P_OUTPUT_NOT_INIT:
128                         seq_printf(m, "N");
129                         break;
130                 case SLSB_P_OUTPUT_PENDING:
131                         seq_printf(m, "P");
132                         break;
133                 case SLSB_P_INPUT_PRIMED:
134                 case SLSB_CU_OUTPUT_PRIMED:
135                         seq_printf(m, "+");
136                         break;
137                 case SLSB_P_INPUT_ACK:
138                         seq_printf(m, "A");
139                         break;
140                 case SLSB_P_INPUT_ERROR:
141                 case SLSB_P_OUTPUT_ERROR:
142                         seq_printf(m, "x");
143                         break;
144                 case SLSB_CU_INPUT_EMPTY:
145                 case SLSB_P_OUTPUT_EMPTY:
146                         seq_printf(m, "-");
147                         break;
148                 case SLSB_P_INPUT_HALTED:
149                 case SLSB_P_OUTPUT_HALTED:
150                         seq_printf(m, ".");
151                         break;
152                 default:
153                         seq_printf(m, "?");
154                 }
155                 if (i == 63)
156                         seq_printf(m, "\n");
157         }
158         seq_printf(m, "\n");
159         seq_printf(m, "|64     |72     |80     |88     |96     |104    |112    |   127|\n");
160
161         seq_printf(m, "\nSBAL statistics:");
162         if (!q->irq_ptr->perf_stat_enabled) {
163                 seq_printf(m, " disabled\n");
164                 return 0;
165         }
166
167         seq_printf(m, "\n1          2..        4..        8..        "
168                    "16..       32..       64..       128\n");
169         for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
170                 seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
171         seq_printf(m, "\nError      NOP        Total\n%-10u %-10u %-10u\n\n",
172                    q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
173                    q->q_stats.nr_sbal_total);
174         return 0;
175 }
176
177 DEFINE_SHOW_ATTRIBUTE(qstat);
178
179 static int ssqd_show(struct seq_file *m, void *v)
180 {
181         struct ccw_device *cdev = m->private;
182         struct qdio_ssqd_desc ssqd;
183         int rc;
184
185         rc = qdio_get_ssqd_desc(cdev, &ssqd);
186         if (rc)
187                 return rc;
188
189         seq_hex_dump(m, "", DUMP_PREFIX_NONE, 16, 4, &ssqd, sizeof(ssqd),
190                      false);
191         return 0;
192 }
193
194 DEFINE_SHOW_ATTRIBUTE(ssqd);
195
196 static char *qperf_names[] = {
197         "Assumed adapter interrupts",
198         "QDIO interrupts",
199         "Requested PCIs",
200         "Inbound tasklet runs",
201         "Inbound tasklet resched",
202         "Inbound tasklet resched2",
203         "Outbound tasklet runs",
204         "SIGA read",
205         "SIGA write",
206         "SIGA sync",
207         "Inbound calls",
208         "Inbound handler",
209         "Inbound stop_polling",
210         "Inbound queue full",
211         "Outbound calls",
212         "Outbound handler",
213         "Outbound queue full",
214         "Outbound fast_requeue",
215         "Outbound target_full",
216         "QEBSM eqbs",
217         "QEBSM eqbs partial",
218         "QEBSM sqbs",
219         "QEBSM sqbs partial",
220         "Discarded interrupts"
221 };
222
223 static int qperf_show(struct seq_file *m, void *v)
224 {
225         struct qdio_irq *irq_ptr = m->private;
226         unsigned int *stat;
227         int i;
228
229         if (!irq_ptr)
230                 return 0;
231         if (!irq_ptr->perf_stat_enabled) {
232                 seq_printf(m, "disabled\n");
233                 return 0;
234         }
235         stat = (unsigned int *)&irq_ptr->perf_stat;
236
237         for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
238                 seq_printf(m, "%26s:\t%u\n",
239                            qperf_names[i], *(stat + i));
240         return 0;
241 }
242
243 static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
244                                size_t count, loff_t *off)
245 {
246         struct seq_file *seq = file->private_data;
247         struct qdio_irq *irq_ptr = seq->private;
248         struct qdio_q *q;
249         unsigned long val;
250         int ret, i;
251
252         if (!irq_ptr)
253                 return 0;
254
255         ret = kstrtoul_from_user(ubuf, count, 10, &val);
256         if (ret)
257                 return ret;
258
259         switch (val) {
260         case 0:
261                 irq_ptr->perf_stat_enabled = 0;
262                 memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
263                 for_each_input_queue(irq_ptr, q, i)
264                         memset(&q->q_stats, 0, sizeof(q->q_stats));
265                 for_each_output_queue(irq_ptr, q, i)
266                         memset(&q->q_stats, 0, sizeof(q->q_stats));
267                 break;
268         case 1:
269                 irq_ptr->perf_stat_enabled = 1;
270                 break;
271         }
272         return count;
273 }
274
275 static int qperf_seq_open(struct inode *inode, struct file *filp)
276 {
277         return single_open(filp, qperf_show,
278                            file_inode(filp)->i_private);
279 }
280
281 static const struct file_operations debugfs_perf_fops = {
282         .owner   = THIS_MODULE,
283         .open    = qperf_seq_open,
284         .read    = seq_read,
285         .write   = qperf_seq_write,
286         .llseek  = seq_lseek,
287         .release = single_release,
288 };
289
290 static void setup_debugfs_entry(struct dentry *parent, struct qdio_q *q)
291 {
292         char name[QDIO_DEBUGFS_NAME_LEN];
293
294         snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
295                  q->is_input_q ? "input" : "output",
296                  q->nr);
297         debugfs_create_file(name, 0444, parent, q, &qstat_fops);
298 }
299
300 void qdio_setup_debug_entries(struct qdio_irq *irq_ptr)
301 {
302         struct qdio_q *q;
303         int i;
304
305         irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&irq_ptr->cdev->dev),
306                                                   debugfs_root);
307         debugfs_create_file("statistics", S_IFREG | S_IRUGO | S_IWUSR,
308                             irq_ptr->debugfs_dev, irq_ptr, &debugfs_perf_fops);
309         debugfs_create_file("ssqd", 0444, irq_ptr->debugfs_dev, irq_ptr->cdev,
310                             &ssqd_fops);
311
312         for_each_input_queue(irq_ptr, q, i)
313                 setup_debugfs_entry(irq_ptr->debugfs_dev, q);
314         for_each_output_queue(irq_ptr, q, i)
315                 setup_debugfs_entry(irq_ptr->debugfs_dev, q);
316 }
317
318 void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr)
319 {
320         debugfs_remove_recursive(irq_ptr->debugfs_dev);
321 }
322
323 int __init qdio_debug_init(void)
324 {
325         debugfs_root = debugfs_create_dir("qdio", NULL);
326
327         qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
328         debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
329         debug_set_level(qdio_dbf_setup, DBF_INFO);
330         DBF_EVENT("dbf created\n");
331
332         qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
333         debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
334         debug_set_level(qdio_dbf_error, DBF_INFO);
335         DBF_ERROR("dbf created\n");
336         return 0;
337 }
338
339 void qdio_debug_exit(void)
340 {
341         qdio_clear_dbf_list();
342         debugfs_remove_recursive(debugfs_root);
343         debug_unregister(qdio_dbf_setup);
344         debug_unregister(qdio_dbf_error);
345 }