qdio_debug.c revision aa2383f815c3720f1f406d2f574dfb65aedce2ec
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 <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, "Timestamp: %Lx  Last AI: %Lx\n",
58		   q->timestamp, last_ai_time);
59	seq_printf(m, "nr_used: %d  ftc: %d  last_move: %d\n",
60		   atomic_read(&q->nr_buf_used),
61		   q->first_to_check, q->last_move);
62	if (q->is_input_q) {
63		seq_printf(m, "polling: %d  ack start: %d  ack count: %d\n",
64			   q->u.in.polling, q->u.in.ack_start,
65			   q->u.in.ack_count);
66		seq_printf(m, "DSCI: %d   IRQs disabled: %u\n",
67			   *(u32 *)q->irq_ptr->dsci,
68			   test_bit(QDIO_QUEUE_IRQS_DISABLED,
69			   &q->u.in.queue_irq_state));
70	}
71	seq_printf(m, "SBAL states:\n");
72	seq_printf(m, "|0      |8      |16     |24     |32     |40     |48     |56  63|\n");
73
74	for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
75		debug_get_buf_state(q, i, &state);
76		switch (state) {
77		case SLSB_P_INPUT_NOT_INIT:
78		case SLSB_P_OUTPUT_NOT_INIT:
79			seq_printf(m, "N");
80			break;
81		case SLSB_P_OUTPUT_PENDING:
82			seq_printf(m, "P");
83			break;
84		case SLSB_P_INPUT_PRIMED:
85		case SLSB_CU_OUTPUT_PRIMED:
86			seq_printf(m, "+");
87			break;
88		case SLSB_P_INPUT_ACK:
89			seq_printf(m, "A");
90			break;
91		case SLSB_P_INPUT_ERROR:
92		case SLSB_P_OUTPUT_ERROR:
93			seq_printf(m, "x");
94			break;
95		case SLSB_CU_INPUT_EMPTY:
96		case SLSB_P_OUTPUT_EMPTY:
97			seq_printf(m, "-");
98			break;
99		case SLSB_P_INPUT_HALTED:
100		case SLSB_P_OUTPUT_HALTED:
101			seq_printf(m, ".");
102			break;
103		default:
104			seq_printf(m, "?");
105		}
106		if (i == 63)
107			seq_printf(m, "\n");
108	}
109	seq_printf(m, "\n");
110	seq_printf(m, "|64     |72     |80     |88     |96     |104    |112    |   127|\n");
111
112	seq_printf(m, "\nSBAL statistics:");
113	if (!q->irq_ptr->perf_stat_enabled) {
114		seq_printf(m, " disabled\n");
115		return 0;
116	}
117
118	seq_printf(m, "\n1          2..        4..        8..        "
119		   "16..       32..       64..       127\n");
120	for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
121		seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
122	seq_printf(m, "\nError      NOP        Total\n%-10u %-10u %-10u\n\n",
123		   q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
124		   q->q_stats.nr_sbal_total);
125	return 0;
126}
127
128static int qstat_seq_open(struct inode *inode, struct file *filp)
129{
130	return single_open(filp, qstat_show,
131			   file_inode(filp)->i_private);
132}
133
134static const struct file_operations debugfs_fops = {
135	.owner	 = THIS_MODULE,
136	.open	 = qstat_seq_open,
137	.read	 = seq_read,
138	.llseek  = seq_lseek,
139	.release = single_release,
140};
141
142static char *qperf_names[] = {
143	"Assumed adapter interrupts",
144	"QDIO interrupts",
145	"Requested PCIs",
146	"Inbound tasklet runs",
147	"Inbound tasklet resched",
148	"Inbound tasklet resched2",
149	"Outbound tasklet runs",
150	"SIGA read",
151	"SIGA write",
152	"SIGA sync",
153	"Inbound calls",
154	"Inbound handler",
155	"Inbound stop_polling",
156	"Inbound queue full",
157	"Outbound calls",
158	"Outbound handler",
159	"Outbound queue full",
160	"Outbound fast_requeue",
161	"Outbound target_full",
162	"QEBSM eqbs",
163	"QEBSM eqbs partial",
164	"QEBSM sqbs",
165	"QEBSM sqbs partial",
166	"Discarded interrupts"
167};
168
169static int qperf_show(struct seq_file *m, void *v)
170{
171	struct qdio_irq *irq_ptr = m->private;
172	unsigned int *stat;
173	int i;
174
175	if (!irq_ptr)
176		return 0;
177	if (!irq_ptr->perf_stat_enabled) {
178		seq_printf(m, "disabled\n");
179		return 0;
180	}
181	stat = (unsigned int *)&irq_ptr->perf_stat;
182
183	for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
184		seq_printf(m, "%26s:\t%u\n",
185			   qperf_names[i], *(stat + i));
186	return 0;
187}
188
189static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
190			       size_t count, loff_t *off)
191{
192	struct seq_file *seq = file->private_data;
193	struct qdio_irq *irq_ptr = seq->private;
194	struct qdio_q *q;
195	unsigned long val;
196	int ret, i;
197
198	if (!irq_ptr)
199		return 0;
200
201	ret = kstrtoul_from_user(ubuf, count, 10, &val);
202	if (ret)
203		return ret;
204
205	switch (val) {
206	case 0:
207		irq_ptr->perf_stat_enabled = 0;
208		memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
209		for_each_input_queue(irq_ptr, q, i)
210			memset(&q->q_stats, 0, sizeof(q->q_stats));
211		for_each_output_queue(irq_ptr, q, i)
212			memset(&q->q_stats, 0, sizeof(q->q_stats));
213		break;
214	case 1:
215		irq_ptr->perf_stat_enabled = 1;
216		break;
217	}
218	return count;
219}
220
221static int qperf_seq_open(struct inode *inode, struct file *filp)
222{
223	return single_open(filp, qperf_show,
224			   file_inode(filp)->i_private);
225}
226
227static struct file_operations debugfs_perf_fops = {
228	.owner	 = THIS_MODULE,
229	.open	 = qperf_seq_open,
230	.read	 = seq_read,
231	.write	 = qperf_seq_write,
232	.llseek  = seq_lseek,
233	.release = single_release,
234};
235
236static void setup_debugfs_entry(struct qdio_q *q)
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);
268	for_each_output_queue(irq_ptr, q, i)
269		setup_debugfs_entry(q);
270}
271
272void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr)
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