xref: /openbmc/linux/drivers/s390/cio/qdio_debug.c (revision b830f94f)
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\n",
125 		   atomic_read(&q->nr_buf_used), q->first_to_check);
126 	if (q->is_input_q) {
127 		seq_printf(m, "polling: %d  ack start: %d  ack count: %d\n",
128 			   q->u.in.polling, q->u.in.ack_start,
129 			   q->u.in.ack_count);
130 		seq_printf(m, "DSCI: %x   IRQs disabled: %u\n",
131 			   *(u8 *)q->irq_ptr->dsci,
132 			   test_bit(QDIO_QUEUE_IRQS_DISABLED,
133 			   &q->u.in.queue_irq_state));
134 	}
135 	seq_printf(m, "SBAL states:\n");
136 	seq_printf(m, "|0      |8      |16     |24     |32     |40     |48     |56  63|\n");
137 
138 	for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
139 		debug_get_buf_state(q, i, &state);
140 		switch (state) {
141 		case SLSB_P_INPUT_NOT_INIT:
142 		case SLSB_P_OUTPUT_NOT_INIT:
143 			seq_printf(m, "N");
144 			break;
145 		case SLSB_P_OUTPUT_PENDING:
146 			seq_printf(m, "P");
147 			break;
148 		case SLSB_P_INPUT_PRIMED:
149 		case SLSB_CU_OUTPUT_PRIMED:
150 			seq_printf(m, "+");
151 			break;
152 		case SLSB_P_INPUT_ACK:
153 			seq_printf(m, "A");
154 			break;
155 		case SLSB_P_INPUT_ERROR:
156 		case SLSB_P_OUTPUT_ERROR:
157 			seq_printf(m, "x");
158 			break;
159 		case SLSB_CU_INPUT_EMPTY:
160 		case SLSB_P_OUTPUT_EMPTY:
161 			seq_printf(m, "-");
162 			break;
163 		case SLSB_P_INPUT_HALTED:
164 		case SLSB_P_OUTPUT_HALTED:
165 			seq_printf(m, ".");
166 			break;
167 		default:
168 			seq_printf(m, "?");
169 		}
170 		if (i == 63)
171 			seq_printf(m, "\n");
172 	}
173 	seq_printf(m, "\n");
174 	seq_printf(m, "|64     |72     |80     |88     |96     |104    |112    |   127|\n");
175 
176 	seq_printf(m, "\nSBAL statistics:");
177 	if (!q->irq_ptr->perf_stat_enabled) {
178 		seq_printf(m, " disabled\n");
179 		return 0;
180 	}
181 
182 	seq_printf(m, "\n1          2..        4..        8..        "
183 		   "16..       32..       64..       127\n");
184 	for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
185 		seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
186 	seq_printf(m, "\nError      NOP        Total\n%-10u %-10u %-10u\n\n",
187 		   q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
188 		   q->q_stats.nr_sbal_total);
189 	return 0;
190 }
191 
192 DEFINE_SHOW_ATTRIBUTE(qstat);
193 
194 static char *qperf_names[] = {
195 	"Assumed adapter interrupts",
196 	"QDIO interrupts",
197 	"Requested PCIs",
198 	"Inbound tasklet runs",
199 	"Inbound tasklet resched",
200 	"Inbound tasklet resched2",
201 	"Outbound tasklet runs",
202 	"SIGA read",
203 	"SIGA write",
204 	"SIGA sync",
205 	"Inbound calls",
206 	"Inbound handler",
207 	"Inbound stop_polling",
208 	"Inbound queue full",
209 	"Outbound calls",
210 	"Outbound handler",
211 	"Outbound queue full",
212 	"Outbound fast_requeue",
213 	"Outbound target_full",
214 	"QEBSM eqbs",
215 	"QEBSM eqbs partial",
216 	"QEBSM sqbs",
217 	"QEBSM sqbs partial",
218 	"Discarded interrupts"
219 };
220 
221 static int qperf_show(struct seq_file *m, void *v)
222 {
223 	struct qdio_irq *irq_ptr = m->private;
224 	unsigned int *stat;
225 	int i;
226 
227 	if (!irq_ptr)
228 		return 0;
229 	if (!irq_ptr->perf_stat_enabled) {
230 		seq_printf(m, "disabled\n");
231 		return 0;
232 	}
233 	stat = (unsigned int *)&irq_ptr->perf_stat;
234 
235 	for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
236 		seq_printf(m, "%26s:\t%u\n",
237 			   qperf_names[i], *(stat + i));
238 	return 0;
239 }
240 
241 static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
242 			       size_t count, loff_t *off)
243 {
244 	struct seq_file *seq = file->private_data;
245 	struct qdio_irq *irq_ptr = seq->private;
246 	struct qdio_q *q;
247 	unsigned long val;
248 	int ret, i;
249 
250 	if (!irq_ptr)
251 		return 0;
252 
253 	ret = kstrtoul_from_user(ubuf, count, 10, &val);
254 	if (ret)
255 		return ret;
256 
257 	switch (val) {
258 	case 0:
259 		irq_ptr->perf_stat_enabled = 0;
260 		memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
261 		for_each_input_queue(irq_ptr, q, i)
262 			memset(&q->q_stats, 0, sizeof(q->q_stats));
263 		for_each_output_queue(irq_ptr, q, i)
264 			memset(&q->q_stats, 0, sizeof(q->q_stats));
265 		break;
266 	case 1:
267 		irq_ptr->perf_stat_enabled = 1;
268 		break;
269 	}
270 	return count;
271 }
272 
273 static int qperf_seq_open(struct inode *inode, struct file *filp)
274 {
275 	return single_open(filp, qperf_show,
276 			   file_inode(filp)->i_private);
277 }
278 
279 static const struct file_operations debugfs_perf_fops = {
280 	.owner	 = THIS_MODULE,
281 	.open	 = qperf_seq_open,
282 	.read	 = seq_read,
283 	.write	 = qperf_seq_write,
284 	.llseek  = seq_lseek,
285 	.release = single_release,
286 };
287 
288 static void setup_debugfs_entry(struct qdio_q *q)
289 {
290 	char name[QDIO_DEBUGFS_NAME_LEN];
291 
292 	snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
293 		 q->is_input_q ? "input" : "output",
294 		 q->nr);
295 	q->debugfs_q = debugfs_create_file(name, 0444,
296 				q->irq_ptr->debugfs_dev, q, &qstat_fops);
297 	if (IS_ERR(q->debugfs_q))
298 		q->debugfs_q = NULL;
299 }
300 
301 void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
302 {
303 	struct qdio_q *q;
304 	int i;
305 
306 	irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
307 						  debugfs_root);
308 	if (IS_ERR(irq_ptr->debugfs_dev))
309 		irq_ptr->debugfs_dev = NULL;
310 
311 	irq_ptr->debugfs_perf = debugfs_create_file("statistics",
312 				S_IFREG | S_IRUGO | S_IWUSR,
313 				irq_ptr->debugfs_dev, irq_ptr,
314 				&debugfs_perf_fops);
315 	if (IS_ERR(irq_ptr->debugfs_perf))
316 		irq_ptr->debugfs_perf = NULL;
317 
318 	for_each_input_queue(irq_ptr, q, i)
319 		setup_debugfs_entry(q);
320 	for_each_output_queue(irq_ptr, q, i)
321 		setup_debugfs_entry(q);
322 }
323 
324 void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr)
325 {
326 	struct qdio_q *q;
327 	int i;
328 
329 	for_each_input_queue(irq_ptr, q, i)
330 		debugfs_remove(q->debugfs_q);
331 	for_each_output_queue(irq_ptr, q, i)
332 		debugfs_remove(q->debugfs_q);
333 	debugfs_remove(irq_ptr->debugfs_perf);
334 	debugfs_remove(irq_ptr->debugfs_dev);
335 }
336 
337 int __init qdio_debug_init(void)
338 {
339 	debugfs_root = debugfs_create_dir("qdio", NULL);
340 
341 	qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
342 	debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
343 	debug_set_level(qdio_dbf_setup, DBF_INFO);
344 	DBF_EVENT("dbf created\n");
345 
346 	qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
347 	debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
348 	debug_set_level(qdio_dbf_error, DBF_INFO);
349 	DBF_ERROR("dbf created\n");
350 	return 0;
351 }
352 
353 void qdio_debug_exit(void)
354 {
355 	qdio_clear_dbf_list();
356 	debugfs_remove(debugfs_root);
357 	debug_unregister(qdio_dbf_setup);
358 	debug_unregister(qdio_dbf_error);
359 }
360