]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - drivers/s390/cio/qdio_debug.c
Merge tag 'asoc-v5.7' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[mirror_ubuntu-hirsute-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);
dccbbaff
JW
124 seq_printf(m, "nr_used: %d ftc: %d\n",
125 atomic_read(&q->nr_buf_used), q->first_to_check);
d36deae7 126 if (q->is_input_q) {
0b6f4990
JW
127 seq_printf(m, "ack start: %d ack count: %d\n",
128 q->u.in.ack_start, q->u.in.ack_count);
34298422
JW
129 seq_printf(m, "DSCI: %x IRQs disabled: %u\n",
130 *(u8 *)q->irq_ptr->dsci,
d36deae7
JG
131 test_bit(QDIO_QUEUE_IRQS_DISABLED,
132 &q->u.in.queue_irq_state));
133 }
d307297f 134 seq_printf(m, "SBAL states:\n");
50f769df 135 seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n");
779e6e1c 136
779e6e1c 137 for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
60b5df2f 138 debug_get_buf_state(q, i, &state);
779e6e1c
JG
139 switch (state) {
140 case SLSB_P_INPUT_NOT_INIT:
141 case SLSB_P_OUTPUT_NOT_INIT:
142 seq_printf(m, "N");
143 break;
104ea556 144 case SLSB_P_OUTPUT_PENDING:
145 seq_printf(m, "P");
146 break;
779e6e1c
JG
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");
50f769df 173 seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n");
d307297f
JG
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);
779e6e1c
JG
188 return 0;
189}
190
ca92b93d 191DEFINE_SHOW_ATTRIBUTE(qstat);
779e6e1c 192
6486cda6
JG
193static 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",
0195843b 210 "Outbound queue full",
6486cda6
JG
211 "Outbound fast_requeue",
212 "Outbound target_full",
213 "QEBSM eqbs",
214 "QEBSM eqbs partial",
215 "QEBSM sqbs",
d36deae7
JG
216 "QEBSM sqbs partial",
217 "Discarded interrupts"
6486cda6
JG
218};
219
220static 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
240static 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;
d307297f 245 struct qdio_q *q;
6486cda6 246 unsigned long val;
d307297f 247 int ret, i;
6486cda6
JG
248
249 if (!irq_ptr)
250 return 0;
af6df871
PH
251
252 ret = kstrtoul_from_user(ubuf, count, 10, &val);
253 if (ret)
6486cda6
JG
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));
d307297f
JG
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));
6486cda6
JG
264 break;
265 case 1:
266 irq_ptr->perf_stat_enabled = 1;
267 break;
268 }
269 return count;
270}
271
272static int qperf_seq_open(struct inode *inode, struct file *filp)
273{
274 return single_open(filp, qperf_show,
496ad9aa 275 file_inode(filp)->i_private);
6486cda6
JG
276}
277
75ef9de1 278static const struct file_operations debugfs_perf_fops = {
6486cda6
JG
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};
aa2383f8
SR
286
287static void setup_debugfs_entry(struct qdio_q *q)
779e6e1c 288{
2c780914 289 char name[QDIO_DEBUGFS_NAME_LEN];
779e6e1c 290
3f09bb89 291 snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
2c780914
JG
292 q->is_input_q ? "input" : "output",
293 q->nr);
87ccdcfa 294 q->debugfs_q = debugfs_create_file(name, 0444,
ca92b93d 295 q->irq_ptr->debugfs_dev, q, &qstat_fops);
3f09bb89
JG
296 if (IS_ERR(q->debugfs_q))
297 q->debugfs_q = NULL;
779e6e1c
JG
298}
299
300void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
301{
302 struct qdio_q *q;
303 int i;
304
3f09bb89
JG
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;
6486cda6
JG
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
779e6e1c 317 for_each_input_queue(irq_ptr, q, i)
aa2383f8 318 setup_debugfs_entry(q);
779e6e1c 319 for_each_output_queue(irq_ptr, q, i)
aa2383f8 320 setup_debugfs_entry(q);
779e6e1c
JG
321}
322
aa2383f8 323void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr)
779e6e1c
JG
324{
325 struct qdio_q *q;
326 int i;
327
779e6e1c 328 for_each_input_queue(irq_ptr, q, i)
3f09bb89 329 debugfs_remove(q->debugfs_q);
779e6e1c 330 for_each_output_queue(irq_ptr, q, i)
3f09bb89 331 debugfs_remove(q->debugfs_q);
6486cda6 332 debugfs_remove(irq_ptr->debugfs_perf);
3f09bb89 333 debugfs_remove(irq_ptr->debugfs_dev);
779e6e1c
JG
334}
335
336int __init qdio_debug_init(void)
337{
3f09bb89 338 debugfs_root = debugfs_create_dir("qdio", NULL);
22f99347
JG
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;
779e6e1c
JG
350}
351
352void qdio_debug_exit(void)
353{
613c4e04 354 qdio_clear_dbf_list();
779e6e1c 355 debugfs_remove(debugfs_root);
a6e975c5
ME
356 debug_unregister(qdio_dbf_setup);
357 debug_unregister(qdio_dbf_error);
779e6e1c 358}