qdio_debug.c revision 0195843bfda90a215f3b72c9aac2fd0bc9244b67
1/*
2 *  drivers/s390/cio/qdio_debug.c
3 *
4 *  Copyright IBM Corp. 2008,2009
5 *
6 *  Author: Jan Glauber (jang@linux.vnet.ibm.com)
7 */
8#include <linux/seq_file.h>
9#include <linux/debugfs.h>
10#include <asm/debug.h>
11#include "qdio_debug.h"
12#include "qdio.h"
13
14debug_info_t *qdio_dbf_setup;
15debug_info_t *qdio_dbf_error;
16
17static struct dentry *debugfs_root;
18#define QDIO_DEBUGFS_NAME_LEN	10
19
20void qdio_allocate_dbf(struct qdio_initialize *init_data,
21		       struct qdio_irq *irq_ptr)
22{
23	char text[20];
24
25	DBF_EVENT("qfmt:%1d", init_data->q_format);
26	DBF_HEX(init_data->adapter_name, 8);
27	DBF_EVENT("qpff%4x", init_data->qib_param_field_format);
28	DBF_HEX(&init_data->qib_param_field, sizeof(void *));
29	DBF_HEX(&init_data->input_slib_elements, sizeof(void *));
30	DBF_HEX(&init_data->output_slib_elements, sizeof(void *));
31	DBF_EVENT("niq:%1d noq:%1d", init_data->no_input_qs,
32		  init_data->no_output_qs);
33	DBF_HEX(&init_data->input_handler, sizeof(void *));
34	DBF_HEX(&init_data->output_handler, sizeof(void *));
35	DBF_HEX(&init_data->int_parm, sizeof(long));
36	DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *));
37	DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *));
38	DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr);
39
40	/* allocate trace view for the interface */
41	snprintf(text, 20, "qdio_%s", dev_name(&init_data->cdev->dev));
42	irq_ptr->debug_area = debug_register(text, 2, 1, 16);
43	debug_register_view(irq_ptr->debug_area, &debug_hex_ascii_view);
44	debug_set_level(irq_ptr->debug_area, DBF_WARN);
45	DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created");
46}
47
48static int qstat_show(struct seq_file *m, void *v)
49{
50	unsigned char state;
51	struct qdio_q *q = m->private;
52	int i;
53
54	if (!q)
55		return 0;
56
57	seq_printf(m, "DSCI: %d   nr_used: %d\n",
58		   *(u32 *)q->irq_ptr->dsci, atomic_read(&q->nr_buf_used));
59	seq_printf(m, "ftc: %d  last_move: %d\n",
60		   q->first_to_check, q->last_move);
61	if (q->is_input_q) {
62		seq_printf(m, "polling: %d  ack start: %d  ack count: %d\n",
63			   q->u.in.polling, q->u.in.ack_start,
64			   q->u.in.ack_count);
65		seq_printf(m, "IRQs disabled: %u\n",
66			   test_bit(QDIO_QUEUE_IRQS_DISABLED,
67			   &q->u.in.queue_irq_state));
68	}
69	seq_printf(m, "SBAL states:\n");
70	seq_printf(m, "|0      |8      |16     |24     |32     |40     |48     |56  63|\n");
71
72	for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
73		debug_get_buf_state(q, i, &state);
74		switch (state) {
75		case SLSB_P_INPUT_NOT_INIT:
76		case SLSB_P_OUTPUT_NOT_INIT:
77			seq_printf(m, "N");
78			break;
79		case SLSB_P_INPUT_PRIMED:
80		case SLSB_CU_OUTPUT_PRIMED:
81			seq_printf(m, "+");
82			break;
83		case SLSB_P_INPUT_ACK:
84			seq_printf(m, "A");
85			break;
86		case SLSB_P_INPUT_ERROR:
87		case SLSB_P_OUTPUT_ERROR:
88			seq_printf(m, "x");
89			break;
90		case SLSB_CU_INPUT_EMPTY:
91		case SLSB_P_OUTPUT_EMPTY:
92			seq_printf(m, "-");
93			break;
94		case SLSB_P_INPUT_HALTED:
95		case SLSB_P_OUTPUT_HALTED:
96			seq_printf(m, ".");
97			break;
98		default:
99			seq_printf(m, "?");
100		}
101		if (i == 63)
102			seq_printf(m, "\n");
103	}
104	seq_printf(m, "\n");
105	seq_printf(m, "|64     |72     |80     |88     |96     |104    |112    |   127|\n");
106
107	seq_printf(m, "\nSBAL statistics:");
108	if (!q->irq_ptr->perf_stat_enabled) {
109		seq_printf(m, " disabled\n");
110		return 0;
111	}
112
113	seq_printf(m, "\n1          2..        4..        8..        "
114		   "16..       32..       64..       127\n");
115	for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
116		seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
117	seq_printf(m, "\nError      NOP        Total\n%-10u %-10u %-10u\n\n",
118		   q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
119		   q->q_stats.nr_sbal_total);
120	return 0;
121}
122
123static int qstat_seq_open(struct inode *inode, struct file *filp)
124{
125	return single_open(filp, qstat_show,
126			   filp->f_path.dentry->d_inode->i_private);
127}
128
129static const struct file_operations debugfs_fops = {
130	.owner	 = THIS_MODULE,
131	.open	 = qstat_seq_open,
132	.read	 = seq_read,
133	.llseek  = seq_lseek,
134	.release = single_release,
135};
136
137static char *qperf_names[] = {
138	"Assumed adapter interrupts",
139	"QDIO interrupts",
140	"Requested PCIs",
141	"Inbound tasklet runs",
142	"Inbound tasklet resched",
143	"Inbound tasklet resched2",
144	"Outbound tasklet runs",
145	"SIGA read",
146	"SIGA write",
147	"SIGA sync",
148	"Inbound calls",
149	"Inbound handler",
150	"Inbound stop_polling",
151	"Inbound queue full",
152	"Outbound calls",
153	"Outbound handler",
154	"Outbound queue full",
155	"Outbound fast_requeue",
156	"Outbound target_full",
157	"QEBSM eqbs",
158	"QEBSM eqbs partial",
159	"QEBSM sqbs",
160	"QEBSM sqbs partial",
161	"Discarded interrupts"
162};
163
164static int qperf_show(struct seq_file *m, void *v)
165{
166	struct qdio_irq *irq_ptr = m->private;
167	unsigned int *stat;
168	int i;
169
170	if (!irq_ptr)
171		return 0;
172	if (!irq_ptr->perf_stat_enabled) {
173		seq_printf(m, "disabled\n");
174		return 0;
175	}
176	stat = (unsigned int *)&irq_ptr->perf_stat;
177
178	for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
179		seq_printf(m, "%26s:\t%u\n",
180			   qperf_names[i], *(stat + i));
181	return 0;
182}
183
184static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
185			       size_t count, loff_t *off)
186{
187	struct seq_file *seq = file->private_data;
188	struct qdio_irq *irq_ptr = seq->private;
189	struct qdio_q *q;
190	unsigned long val;
191	char buf[8];
192	int ret, i;
193
194	if (!irq_ptr)
195		return 0;
196	if (count >= sizeof(buf))
197		return -EINVAL;
198	if (copy_from_user(&buf, ubuf, count))
199		return -EFAULT;
200	buf[count] = 0;
201
202	ret = strict_strtoul(buf, 10, &val);
203	if (ret < 0)
204		return ret;
205
206	switch (val) {
207	case 0:
208		irq_ptr->perf_stat_enabled = 0;
209		memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
210		for_each_input_queue(irq_ptr, q, i)
211			memset(&q->q_stats, 0, sizeof(q->q_stats));
212		for_each_output_queue(irq_ptr, q, i)
213			memset(&q->q_stats, 0, sizeof(q->q_stats));
214		break;
215	case 1:
216		irq_ptr->perf_stat_enabled = 1;
217		break;
218	}
219	return count;
220}
221
222static int qperf_seq_open(struct inode *inode, struct file *filp)
223{
224	return single_open(filp, qperf_show,
225			   filp->f_path.dentry->d_inode->i_private);
226}
227
228static struct file_operations debugfs_perf_fops = {
229	.owner	 = THIS_MODULE,
230	.open	 = qperf_seq_open,
231	.read	 = seq_read,
232	.write	 = qperf_seq_write,
233	.llseek  = seq_lseek,
234	.release = single_release,
235};
236static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
237{
238	char name[QDIO_DEBUGFS_NAME_LEN];
239
240	snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
241		 q->is_input_q ? "input" : "output",
242		 q->nr);
243	q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
244				q->irq_ptr->debugfs_dev, q, &debugfs_fops);
245	if (IS_ERR(q->debugfs_q))
246		q->debugfs_q = NULL;
247}
248
249void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
250{
251	struct qdio_q *q;
252	int i;
253
254	irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
255						  debugfs_root);
256	if (IS_ERR(irq_ptr->debugfs_dev))
257		irq_ptr->debugfs_dev = NULL;
258
259	irq_ptr->debugfs_perf = debugfs_create_file("statistics",
260				S_IFREG | S_IRUGO | S_IWUSR,
261				irq_ptr->debugfs_dev, irq_ptr,
262				&debugfs_perf_fops);
263	if (IS_ERR(irq_ptr->debugfs_perf))
264		irq_ptr->debugfs_perf = NULL;
265
266	for_each_input_queue(irq_ptr, q, i)
267		setup_debugfs_entry(q, cdev);
268	for_each_output_queue(irq_ptr, q, i)
269		setup_debugfs_entry(q, cdev);
270}
271
272void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
273{
274	struct qdio_q *q;
275	int i;
276
277	for_each_input_queue(irq_ptr, q, i)
278		debugfs_remove(q->debugfs_q);
279	for_each_output_queue(irq_ptr, q, i)
280		debugfs_remove(q->debugfs_q);
281	debugfs_remove(irq_ptr->debugfs_perf);
282	debugfs_remove(irq_ptr->debugfs_dev);
283}
284
285int __init qdio_debug_init(void)
286{
287	debugfs_root = debugfs_create_dir("qdio", NULL);
288
289	qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
290	debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
291	debug_set_level(qdio_dbf_setup, DBF_INFO);
292	DBF_EVENT("dbf created\n");
293
294	qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
295	debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
296	debug_set_level(qdio_dbf_error, DBF_INFO);
297	DBF_ERROR("dbf created\n");
298	return 0;
299}
300
301void qdio_debug_exit(void)
302{
303	debugfs_remove(debugfs_root);
304	if (qdio_dbf_setup)
305		debug_unregister(qdio_dbf_setup);
306	if (qdio_dbf_error)
307		debug_unregister(qdio_dbf_error);
308}
309