]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/blame - drivers/s390/cio/qdio_debug.c
License cleanup: add SPDX GPL-2.0 license identifier to files with no license
[mirror_ubuntu-eoan-kernel.git] / drivers / s390 / cio / qdio_debug.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
779e6e1c 2/*
a53c8fab 3 * Copyright IBM Corp. 2008, 2009
779e6e1c
JG
4 *
5 * Author: Jan Glauber (jang@linux.vnet.ibm.com)
6 */
779e6e1c
JG
7#include <linux/seq_file.h>
8#include <linux/debugfs.h>
3a4c5d59
HC
9#include <linux/uaccess.h>
10#include <linux/export.h>
613c4e04 11#include <linux/slab.h>
779e6e1c
JG
12#include <asm/debug.h>
13#include "qdio_debug.h"
14#include "qdio.h"
15
16debug_info_t *qdio_dbf_setup;
22f99347 17debug_info_t *qdio_dbf_error;
779e6e1c
JG
18
19static struct dentry *debugfs_root;
3f09bb89 20#define QDIO_DEBUGFS_NAME_LEN 10
613c4e04 21#define QDIO_DBF_NAME_LEN 20
779e6e1c 22
613c4e04
SR
23struct 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
29static LIST_HEAD(qdio_dbf_list);
30static DEFINE_MUTEX(qdio_dbf_list_mutex);
31
32static 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
48static 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
61int qdio_allocate_dbf(struct qdio_initialize *init_data,
22f99347 62 struct qdio_irq *irq_ptr)
779e6e1c 63{
613c4e04
SR
64 char text[QDIO_DBF_NAME_LEN];
65 struct qdio_dbf_entry *new_entry;
22f99347
JG
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));
22f99347
JG
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 */
613c4e04
SR
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;
779e6e1c
JG
111}
112
113static 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
a2b86019
JG
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),
d36deae7
JG
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);
a2b86019
JG
131 seq_printf(m, "DSCI: %d IRQs disabled: %u\n",
132 *(u32 *)q->irq_ptr->dsci,
d36deae7
JG
133 test_bit(QDIO_QUEUE_IRQS_DISABLED,
134 &q->u.in.queue_irq_state));
135 }
d307297f 136 seq_printf(m, "SBAL states:\n");
50f769df 137 seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n");
779e6e1c 138
779e6e1c 139 for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
60b5df2f 140 debug_get_buf_state(q, i, &state);
779e6e1c
JG
141 switch (state) {
142 case SLSB_P_INPUT_NOT_INIT:
143 case SLSB_P_OUTPUT_NOT_INIT:
144 seq_printf(m, "N");
145 break;
104ea556 146 case SLSB_P_OUTPUT_PENDING:
147 seq_printf(m, "P");
148 break;
779e6e1c
JG
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");
50f769df 175 seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n");
d307297f
JG
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);
779e6e1c
JG
190 return 0;
191}
192
779e6e1c
JG
193static int qstat_seq_open(struct inode *inode, struct file *filp)
194{
195 return single_open(filp, qstat_show,
496ad9aa 196 file_inode(filp)->i_private);
779e6e1c
JG
197}
198
828c0950 199static const struct file_operations debugfs_fops = {
779e6e1c
JG
200 .owner = THIS_MODULE,
201 .open = qstat_seq_open,
202 .read = seq_read,
779e6e1c
JG
203 .llseek = seq_lseek,
204 .release = single_release,
205};
206
6486cda6
JG
207static 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",
0195843b 224 "Outbound queue full",
6486cda6
JG
225 "Outbound fast_requeue",
226 "Outbound target_full",
227 "QEBSM eqbs",
228 "QEBSM eqbs partial",
229 "QEBSM sqbs",
d36deae7
JG
230 "QEBSM sqbs partial",
231 "Discarded interrupts"
6486cda6
JG
232};
233
234static 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
254static 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;
d307297f 259 struct qdio_q *q;
6486cda6 260 unsigned long val;
d307297f 261 int ret, i;
6486cda6
JG
262
263 if (!irq_ptr)
264 return 0;
af6df871
PH
265
266 ret = kstrtoul_from_user(ubuf, count, 10, &val);
267 if (ret)
6486cda6
JG
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));
d307297f
JG
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));
6486cda6
JG
278 break;
279 case 1:
280 irq_ptr->perf_stat_enabled = 1;
281 break;
282 }
283 return count;
284}
285
286static int qperf_seq_open(struct inode *inode, struct file *filp)
287{
288 return single_open(filp, qperf_show,
496ad9aa 289 file_inode(filp)->i_private);
6486cda6
JG
290}
291
75ef9de1 292static const struct file_operations debugfs_perf_fops = {
6486cda6
JG
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};
aa2383f8
SR
300
301static void setup_debugfs_entry(struct qdio_q *q)
779e6e1c 302{
2c780914 303 char name[QDIO_DEBUGFS_NAME_LEN];
779e6e1c 304
3f09bb89 305 snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
2c780914
JG
306 q->is_input_q ? "input" : "output",
307 q->nr);
3f09bb89
JG
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;
779e6e1c
JG
312}
313
314void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
315{
316 struct qdio_q *q;
317 int i;
318
3f09bb89
JG
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;
6486cda6
JG
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
779e6e1c 331 for_each_input_queue(irq_ptr, q, i)
aa2383f8 332 setup_debugfs_entry(q);
779e6e1c 333 for_each_output_queue(irq_ptr, q, i)
aa2383f8 334 setup_debugfs_entry(q);
779e6e1c
JG
335}
336
aa2383f8 337void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr)
779e6e1c
JG
338{
339 struct qdio_q *q;
340 int i;
341
779e6e1c 342 for_each_input_queue(irq_ptr, q, i)
3f09bb89 343 debugfs_remove(q->debugfs_q);
779e6e1c 344 for_each_output_queue(irq_ptr, q, i)
3f09bb89 345 debugfs_remove(q->debugfs_q);
6486cda6 346 debugfs_remove(irq_ptr->debugfs_perf);
3f09bb89 347 debugfs_remove(irq_ptr->debugfs_dev);
779e6e1c
JG
348}
349
350int __init qdio_debug_init(void)
351{
3f09bb89 352 debugfs_root = debugfs_create_dir("qdio", NULL);
22f99347
JG
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;
779e6e1c
JG
364}
365
366void qdio_debug_exit(void)
367{
613c4e04 368 qdio_clear_dbf_list();
779e6e1c 369 debugfs_remove(debugfs_root);
a6e975c5
ME
370 debug_unregister(qdio_dbf_setup);
371 debug_unregister(qdio_dbf_error);
779e6e1c 372}