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