xref: /openbmc/linux/drivers/s390/cio/qdio_debug.c (revision 2359ccdd)
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  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 
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 
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 
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 
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 
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 
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 
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 
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 
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