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
qdio_get_dbf_entry(char * name)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
qdio_clear_dbf_list(void)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
qdio_allocate_dbf(struct qdio_initialize * init_data,struct qdio_irq * irq_ptr)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
qstat_show(struct seq_file * m,void * v)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
qstat_seq_open(struct inode * inode,struct file * filp)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
qperf_show(struct seq_file * m,void * v)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
qperf_seq_write(struct file * file,const char __user * ubuf,size_t count,loff_t * off)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
qperf_seq_open(struct inode * inode,struct file * filp)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
setup_debugfs_entry(struct qdio_q * q)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
qdio_setup_debug_entries(struct qdio_irq * irq_ptr,struct ccw_device * cdev)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
qdio_shutdown_debug_entries(struct qdio_irq * irq_ptr)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
qdio_debug_init(void)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
qdio_debug_exit(void)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 }
373