xref: /openbmc/linux/drivers/s390/cio/qdio_debug.c (revision a8fe58ce)
1 /*
2  *  Copyright IBM Corp. 2008, 2009
3  *
4  *  Author: Jan Glauber (jang@linux.vnet.ibm.com)
5  */
6 #include <linux/seq_file.h>
7 #include <linux/debugfs.h>
8 #include <linux/uaccess.h>
9 #include <linux/export.h>
10 #include <linux/slab.h>
11 #include <asm/debug.h>
12 #include "qdio_debug.h"
13 #include "qdio.h"
14 
15 debug_info_t *qdio_dbf_setup;
16 debug_info_t *qdio_dbf_error;
17 
18 static struct dentry *debugfs_root;
19 #define QDIO_DEBUGFS_NAME_LEN	10
20 #define QDIO_DBF_NAME_LEN	20
21 
22 struct qdio_dbf_entry {
23 	char dbf_name[QDIO_DBF_NAME_LEN];
24 	debug_info_t *dbf_info;
25 	struct list_head dbf_list;
26 };
27 
28 static LIST_HEAD(qdio_dbf_list);
29 static DEFINE_MUTEX(qdio_dbf_list_mutex);
30 
31 static debug_info_t *qdio_get_dbf_entry(char *name)
32 {
33 	struct qdio_dbf_entry *entry;
34 	debug_info_t *rc = NULL;
35 
36 	mutex_lock(&qdio_dbf_list_mutex);
37 	list_for_each_entry(entry, &qdio_dbf_list, dbf_list) {
38 		if (strcmp(entry->dbf_name, name) == 0) {
39 			rc = entry->dbf_info;
40 			break;
41 		}
42 	}
43 	mutex_unlock(&qdio_dbf_list_mutex);
44 	return rc;
45 }
46 
47 static void qdio_clear_dbf_list(void)
48 {
49 	struct qdio_dbf_entry *entry, *tmp;
50 
51 	mutex_lock(&qdio_dbf_list_mutex);
52 	list_for_each_entry_safe(entry, tmp, &qdio_dbf_list, dbf_list) {
53 		list_del(&entry->dbf_list);
54 		debug_unregister(entry->dbf_info);
55 		kfree(entry);
56 	}
57 	mutex_unlock(&qdio_dbf_list_mutex);
58 }
59 
60 int qdio_allocate_dbf(struct qdio_initialize *init_data,
61 		       struct qdio_irq *irq_ptr)
62 {
63 	char text[QDIO_DBF_NAME_LEN];
64 	struct qdio_dbf_entry *new_entry;
65 
66 	DBF_EVENT("qfmt:%1d", init_data->q_format);
67 	DBF_HEX(init_data->adapter_name, 8);
68 	DBF_EVENT("qpff%4x", init_data->qib_param_field_format);
69 	DBF_HEX(&init_data->qib_param_field, sizeof(void *));
70 	DBF_HEX(&init_data->input_slib_elements, sizeof(void *));
71 	DBF_HEX(&init_data->output_slib_elements, sizeof(void *));
72 	DBF_EVENT("niq:%1d noq:%1d", init_data->no_input_qs,
73 		  init_data->no_output_qs);
74 	DBF_HEX(&init_data->input_handler, sizeof(void *));
75 	DBF_HEX(&init_data->output_handler, sizeof(void *));
76 	DBF_HEX(&init_data->int_parm, sizeof(long));
77 	DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *));
78 	DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *));
79 	DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr);
80 
81 	/* allocate trace view for the interface */
82 	snprintf(text, QDIO_DBF_NAME_LEN, "qdio_%s",
83 					dev_name(&init_data->cdev->dev));
84 	irq_ptr->debug_area = qdio_get_dbf_entry(text);
85 	if (irq_ptr->debug_area)
86 		DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf reused");
87 	else {
88 		irq_ptr->debug_area = debug_register(text, 2, 1, 16);
89 		if (!irq_ptr->debug_area)
90 			return -ENOMEM;
91 		if (debug_register_view(irq_ptr->debug_area,
92 						&debug_hex_ascii_view)) {
93 			debug_unregister(irq_ptr->debug_area);
94 			return -ENOMEM;
95 		}
96 		debug_set_level(irq_ptr->debug_area, DBF_WARN);
97 		DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created");
98 		new_entry = kzalloc(sizeof(struct qdio_dbf_entry), GFP_KERNEL);
99 		if (!new_entry) {
100 			debug_unregister(irq_ptr->debug_area);
101 			return -ENOMEM;
102 		}
103 		strlcpy(new_entry->dbf_name, text, QDIO_DBF_NAME_LEN);
104 		new_entry->dbf_info = irq_ptr->debug_area;
105 		mutex_lock(&qdio_dbf_list_mutex);
106 		list_add(&new_entry->dbf_list, &qdio_dbf_list);
107 		mutex_unlock(&qdio_dbf_list_mutex);
108 	}
109 	return 0;
110 }
111 
112 static int qstat_show(struct seq_file *m, void *v)
113 {
114 	unsigned char state;
115 	struct qdio_q *q = m->private;
116 	int i;
117 
118 	if (!q)
119 		return 0;
120 
121 	seq_printf(m, "Timestamp: %Lx  Last AI: %Lx\n",
122 		   q->timestamp, last_ai_time);
123 	seq_printf(m, "nr_used: %d  ftc: %d  last_move: %d\n",
124 		   atomic_read(&q->nr_buf_used),
125 		   q->first_to_check, q->last_move);
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: %d   IRQs disabled: %u\n",
131 			   *(u32 *)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 static int qstat_seq_open(struct inode *inode, struct file *filp)
193 {
194 	return single_open(filp, qstat_show,
195 			   file_inode(filp)->i_private);
196 }
197 
198 static const struct file_operations debugfs_fops = {
199 	.owner	 = THIS_MODULE,
200 	.open	 = qstat_seq_open,
201 	.read	 = seq_read,
202 	.llseek  = seq_lseek,
203 	.release = single_release,
204 };
205 
206 static char *qperf_names[] = {
207 	"Assumed adapter interrupts",
208 	"QDIO interrupts",
209 	"Requested PCIs",
210 	"Inbound tasklet runs",
211 	"Inbound tasklet resched",
212 	"Inbound tasklet resched2",
213 	"Outbound tasklet runs",
214 	"SIGA read",
215 	"SIGA write",
216 	"SIGA sync",
217 	"Inbound calls",
218 	"Inbound handler",
219 	"Inbound stop_polling",
220 	"Inbound queue full",
221 	"Outbound calls",
222 	"Outbound handler",
223 	"Outbound queue full",
224 	"Outbound fast_requeue",
225 	"Outbound target_full",
226 	"QEBSM eqbs",
227 	"QEBSM eqbs partial",
228 	"QEBSM sqbs",
229 	"QEBSM sqbs partial",
230 	"Discarded interrupts"
231 };
232 
233 static int qperf_show(struct seq_file *m, void *v)
234 {
235 	struct qdio_irq *irq_ptr = m->private;
236 	unsigned int *stat;
237 	int i;
238 
239 	if (!irq_ptr)
240 		return 0;
241 	if (!irq_ptr->perf_stat_enabled) {
242 		seq_printf(m, "disabled\n");
243 		return 0;
244 	}
245 	stat = (unsigned int *)&irq_ptr->perf_stat;
246 
247 	for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
248 		seq_printf(m, "%26s:\t%u\n",
249 			   qperf_names[i], *(stat + i));
250 	return 0;
251 }
252 
253 static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
254 			       size_t count, loff_t *off)
255 {
256 	struct seq_file *seq = file->private_data;
257 	struct qdio_irq *irq_ptr = seq->private;
258 	struct qdio_q *q;
259 	unsigned long val;
260 	int ret, i;
261 
262 	if (!irq_ptr)
263 		return 0;
264 
265 	ret = kstrtoul_from_user(ubuf, count, 10, &val);
266 	if (ret)
267 		return ret;
268 
269 	switch (val) {
270 	case 0:
271 		irq_ptr->perf_stat_enabled = 0;
272 		memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
273 		for_each_input_queue(irq_ptr, q, i)
274 			memset(&q->q_stats, 0, sizeof(q->q_stats));
275 		for_each_output_queue(irq_ptr, q, i)
276 			memset(&q->q_stats, 0, sizeof(q->q_stats));
277 		break;
278 	case 1:
279 		irq_ptr->perf_stat_enabled = 1;
280 		break;
281 	}
282 	return count;
283 }
284 
285 static int qperf_seq_open(struct inode *inode, struct file *filp)
286 {
287 	return single_open(filp, qperf_show,
288 			   file_inode(filp)->i_private);
289 }
290 
291 static const struct file_operations debugfs_perf_fops = {
292 	.owner	 = THIS_MODULE,
293 	.open	 = qperf_seq_open,
294 	.read	 = seq_read,
295 	.write	 = qperf_seq_write,
296 	.llseek  = seq_lseek,
297 	.release = single_release,
298 };
299 
300 static void setup_debugfs_entry(struct qdio_q *q)
301 {
302 	char name[QDIO_DEBUGFS_NAME_LEN];
303 
304 	snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
305 		 q->is_input_q ? "input" : "output",
306 		 q->nr);
307 	q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
308 				q->irq_ptr->debugfs_dev, q, &debugfs_fops);
309 	if (IS_ERR(q->debugfs_q))
310 		q->debugfs_q = NULL;
311 }
312 
313 void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
314 {
315 	struct qdio_q *q;
316 	int i;
317 
318 	irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
319 						  debugfs_root);
320 	if (IS_ERR(irq_ptr->debugfs_dev))
321 		irq_ptr->debugfs_dev = NULL;
322 
323 	irq_ptr->debugfs_perf = debugfs_create_file("statistics",
324 				S_IFREG | S_IRUGO | S_IWUSR,
325 				irq_ptr->debugfs_dev, irq_ptr,
326 				&debugfs_perf_fops);
327 	if (IS_ERR(irq_ptr->debugfs_perf))
328 		irq_ptr->debugfs_perf = NULL;
329 
330 	for_each_input_queue(irq_ptr, q, i)
331 		setup_debugfs_entry(q);
332 	for_each_output_queue(irq_ptr, q, i)
333 		setup_debugfs_entry(q);
334 }
335 
336 void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr)
337 {
338 	struct qdio_q *q;
339 	int i;
340 
341 	for_each_input_queue(irq_ptr, q, i)
342 		debugfs_remove(q->debugfs_q);
343 	for_each_output_queue(irq_ptr, q, i)
344 		debugfs_remove(q->debugfs_q);
345 	debugfs_remove(irq_ptr->debugfs_perf);
346 	debugfs_remove(irq_ptr->debugfs_dev);
347 }
348 
349 int __init qdio_debug_init(void)
350 {
351 	debugfs_root = debugfs_create_dir("qdio", NULL);
352 
353 	qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
354 	debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
355 	debug_set_level(qdio_dbf_setup, DBF_INFO);
356 	DBF_EVENT("dbf created\n");
357 
358 	qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
359 	debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
360 	debug_set_level(qdio_dbf_error, DBF_INFO);
361 	DBF_ERROR("dbf created\n");
362 	return 0;
363 }
364 
365 void qdio_debug_exit(void)
366 {
367 	qdio_clear_dbf_list();
368 	debugfs_remove(debugfs_root);
369 	debug_unregister(qdio_dbf_setup);
370 	debug_unregister(qdio_dbf_error);
371 }
372