xref: /openbmc/linux/drivers/s390/cio/qdio_debug.c (revision 165f2d28)
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_irq *irq_ptr)
62 {
63 	char text[QDIO_DBF_NAME_LEN];
64 	struct qdio_dbf_entry *new_entry;
65 
66 	DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr);
67 
68 	/* allocate trace view for the interface */
69 	snprintf(text, QDIO_DBF_NAME_LEN, "qdio_%s",
70 		 dev_name(&irq_ptr->cdev->dev));
71 	irq_ptr->debug_area = qdio_get_dbf_entry(text);
72 	if (irq_ptr->debug_area)
73 		DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf reused");
74 	else {
75 		irq_ptr->debug_area = debug_register(text, 2, 1, 16);
76 		if (!irq_ptr->debug_area)
77 			return -ENOMEM;
78 		if (debug_register_view(irq_ptr->debug_area,
79 						&debug_hex_ascii_view)) {
80 			debug_unregister(irq_ptr->debug_area);
81 			return -ENOMEM;
82 		}
83 		debug_set_level(irq_ptr->debug_area, DBF_WARN);
84 		DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created");
85 		new_entry = kzalloc(sizeof(struct qdio_dbf_entry), GFP_KERNEL);
86 		if (!new_entry) {
87 			debug_unregister(irq_ptr->debug_area);
88 			return -ENOMEM;
89 		}
90 		strlcpy(new_entry->dbf_name, text, QDIO_DBF_NAME_LEN);
91 		new_entry->dbf_info = irq_ptr->debug_area;
92 		mutex_lock(&qdio_dbf_list_mutex);
93 		list_add(&new_entry->dbf_list, &qdio_dbf_list);
94 		mutex_unlock(&qdio_dbf_list_mutex);
95 	}
96 	return 0;
97 }
98 
99 static int qstat_show(struct seq_file *m, void *v)
100 {
101 	unsigned char state;
102 	struct qdio_q *q = m->private;
103 	int i;
104 
105 	if (!q)
106 		return 0;
107 
108 	seq_printf(m, "Timestamp: %Lx  Last AI: %Lx\n",
109 		   q->timestamp, last_ai_time);
110 	seq_printf(m, "nr_used: %d  ftc: %d\n",
111 		   atomic_read(&q->nr_buf_used), q->first_to_check);
112 	if (q->is_input_q) {
113 		seq_printf(m, "ack start: %d  ack count: %d\n",
114 			   q->u.in.ack_start, q->u.in.ack_count);
115 		seq_printf(m, "DSCI: %x   IRQs disabled: %u\n",
116 			   *(u8 *)q->irq_ptr->dsci,
117 			   test_bit(QDIO_IRQ_DISABLED,
118 				    &q->irq_ptr->poll_state));
119 	}
120 	seq_printf(m, "SBAL states:\n");
121 	seq_printf(m, "|0      |8      |16     |24     |32     |40     |48     |56  63|\n");
122 
123 	for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
124 		debug_get_buf_state(q, i, &state);
125 		switch (state) {
126 		case SLSB_P_INPUT_NOT_INIT:
127 		case SLSB_P_OUTPUT_NOT_INIT:
128 			seq_printf(m, "N");
129 			break;
130 		case SLSB_P_OUTPUT_PENDING:
131 			seq_printf(m, "P");
132 			break;
133 		case SLSB_P_INPUT_PRIMED:
134 		case SLSB_CU_OUTPUT_PRIMED:
135 			seq_printf(m, "+");
136 			break;
137 		case SLSB_P_INPUT_ACK:
138 			seq_printf(m, "A");
139 			break;
140 		case SLSB_P_INPUT_ERROR:
141 		case SLSB_P_OUTPUT_ERROR:
142 			seq_printf(m, "x");
143 			break;
144 		case SLSB_CU_INPUT_EMPTY:
145 		case SLSB_P_OUTPUT_EMPTY:
146 			seq_printf(m, "-");
147 			break;
148 		case SLSB_P_INPUT_HALTED:
149 		case SLSB_P_OUTPUT_HALTED:
150 			seq_printf(m, ".");
151 			break;
152 		default:
153 			seq_printf(m, "?");
154 		}
155 		if (i == 63)
156 			seq_printf(m, "\n");
157 	}
158 	seq_printf(m, "\n");
159 	seq_printf(m, "|64     |72     |80     |88     |96     |104    |112    |   127|\n");
160 
161 	seq_printf(m, "\nSBAL statistics:");
162 	if (!q->irq_ptr->perf_stat_enabled) {
163 		seq_printf(m, " disabled\n");
164 		return 0;
165 	}
166 
167 	seq_printf(m, "\n1          2..        4..        8..        "
168 		   "16..       32..       64..       127\n");
169 	for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
170 		seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
171 	seq_printf(m, "\nError      NOP        Total\n%-10u %-10u %-10u\n\n",
172 		   q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
173 		   q->q_stats.nr_sbal_total);
174 	return 0;
175 }
176 
177 DEFINE_SHOW_ATTRIBUTE(qstat);
178 
179 static int ssqd_show(struct seq_file *m, void *v)
180 {
181 	struct ccw_device *cdev = m->private;
182 	struct qdio_ssqd_desc ssqd;
183 	int rc;
184 
185 	rc = qdio_get_ssqd_desc(cdev, &ssqd);
186 	if (rc)
187 		return rc;
188 
189 	seq_hex_dump(m, "", DUMP_PREFIX_NONE, 16, 4, &ssqd, sizeof(ssqd),
190 		     false);
191 	return 0;
192 }
193 
194 DEFINE_SHOW_ATTRIBUTE(ssqd);
195 
196 static char *qperf_names[] = {
197 	"Assumed adapter interrupts",
198 	"QDIO interrupts",
199 	"Requested PCIs",
200 	"Inbound tasklet runs",
201 	"Inbound tasklet resched",
202 	"Inbound tasklet resched2",
203 	"Outbound tasklet runs",
204 	"SIGA read",
205 	"SIGA write",
206 	"SIGA sync",
207 	"Inbound calls",
208 	"Inbound handler",
209 	"Inbound stop_polling",
210 	"Inbound queue full",
211 	"Outbound calls",
212 	"Outbound handler",
213 	"Outbound queue full",
214 	"Outbound fast_requeue",
215 	"Outbound target_full",
216 	"QEBSM eqbs",
217 	"QEBSM eqbs partial",
218 	"QEBSM sqbs",
219 	"QEBSM sqbs partial",
220 	"Discarded interrupts"
221 };
222 
223 static int qperf_show(struct seq_file *m, void *v)
224 {
225 	struct qdio_irq *irq_ptr = m->private;
226 	unsigned int *stat;
227 	int i;
228 
229 	if (!irq_ptr)
230 		return 0;
231 	if (!irq_ptr->perf_stat_enabled) {
232 		seq_printf(m, "disabled\n");
233 		return 0;
234 	}
235 	stat = (unsigned int *)&irq_ptr->perf_stat;
236 
237 	for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
238 		seq_printf(m, "%26s:\t%u\n",
239 			   qperf_names[i], *(stat + i));
240 	return 0;
241 }
242 
243 static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
244 			       size_t count, loff_t *off)
245 {
246 	struct seq_file *seq = file->private_data;
247 	struct qdio_irq *irq_ptr = seq->private;
248 	struct qdio_q *q;
249 	unsigned long val;
250 	int ret, i;
251 
252 	if (!irq_ptr)
253 		return 0;
254 
255 	ret = kstrtoul_from_user(ubuf, count, 10, &val);
256 	if (ret)
257 		return ret;
258 
259 	switch (val) {
260 	case 0:
261 		irq_ptr->perf_stat_enabled = 0;
262 		memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
263 		for_each_input_queue(irq_ptr, q, i)
264 			memset(&q->q_stats, 0, sizeof(q->q_stats));
265 		for_each_output_queue(irq_ptr, q, i)
266 			memset(&q->q_stats, 0, sizeof(q->q_stats));
267 		break;
268 	case 1:
269 		irq_ptr->perf_stat_enabled = 1;
270 		break;
271 	}
272 	return count;
273 }
274 
275 static int qperf_seq_open(struct inode *inode, struct file *filp)
276 {
277 	return single_open(filp, qperf_show,
278 			   file_inode(filp)->i_private);
279 }
280 
281 static const struct file_operations debugfs_perf_fops = {
282 	.owner	 = THIS_MODULE,
283 	.open	 = qperf_seq_open,
284 	.read	 = seq_read,
285 	.write	 = qperf_seq_write,
286 	.llseek  = seq_lseek,
287 	.release = single_release,
288 };
289 
290 static void setup_debugfs_entry(struct dentry *parent, struct qdio_q *q)
291 {
292 	char name[QDIO_DEBUGFS_NAME_LEN];
293 
294 	snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
295 		 q->is_input_q ? "input" : "output",
296 		 q->nr);
297 	debugfs_create_file(name, 0444, parent, q, &qstat_fops);
298 }
299 
300 void qdio_setup_debug_entries(struct qdio_irq *irq_ptr)
301 {
302 	struct qdio_q *q;
303 	int i;
304 
305 	irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&irq_ptr->cdev->dev),
306 						  debugfs_root);
307 	debugfs_create_file("statistics", S_IFREG | S_IRUGO | S_IWUSR,
308 			    irq_ptr->debugfs_dev, irq_ptr, &debugfs_perf_fops);
309 	debugfs_create_file("ssqd", 0444, irq_ptr->debugfs_dev, irq_ptr->cdev,
310 			    &ssqd_fops);
311 
312 	for_each_input_queue(irq_ptr, q, i)
313 		setup_debugfs_entry(irq_ptr->debugfs_dev, q);
314 	for_each_output_queue(irq_ptr, q, i)
315 		setup_debugfs_entry(irq_ptr->debugfs_dev, q);
316 }
317 
318 void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr)
319 {
320 	debugfs_remove_recursive(irq_ptr->debugfs_dev);
321 }
322 
323 int __init qdio_debug_init(void)
324 {
325 	debugfs_root = debugfs_create_dir("qdio", NULL);
326 
327 	qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
328 	debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
329 	debug_set_level(qdio_dbf_setup, DBF_INFO);
330 	DBF_EVENT("dbf created\n");
331 
332 	qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
333 	debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
334 	debug_set_level(qdio_dbf_error, DBF_INFO);
335 	DBF_ERROR("dbf created\n");
336 	return 0;
337 }
338 
339 void qdio_debug_exit(void)
340 {
341 	qdio_clear_dbf_list();
342 	debugfs_remove_recursive(debugfs_root);
343 	debug_unregister(qdio_dbf_setup);
344 	debug_unregister(qdio_dbf_error);
345 }
346