qdio_debug.c revision 496ad9aa8ef448058e36ca7a787c61f2e63f0f54
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};
235static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
236{
237	char name[QDIO_DEBUGFS_NAME_LEN];
238
239	snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
240		 q->is_input_q ? "input" : "output",
241		 q->nr);
242	q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
243				q->irq_ptr->debugfs_dev, q, &debugfs_fops);
244	if (IS_ERR(q->debugfs_q))
245		q->debugfs_q = NULL;
246}
247
248void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
249{
250	struct qdio_q *q;
251	int i;
252
253	irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
254						  debugfs_root);
255	if (IS_ERR(irq_ptr->debugfs_dev))
256		irq_ptr->debugfs_dev = NULL;
257
258	irq_ptr->debugfs_perf = debugfs_create_file("statistics",
259				S_IFREG | S_IRUGO | S_IWUSR,
260				irq_ptr->debugfs_dev, irq_ptr,
261				&debugfs_perf_fops);
262	if (IS_ERR(irq_ptr->debugfs_perf))
263		irq_ptr->debugfs_perf = NULL;
264
265	for_each_input_queue(irq_ptr, q, i)
266		setup_debugfs_entry(q, cdev);
267	for_each_output_queue(irq_ptr, q, i)
268		setup_debugfs_entry(q, cdev);
269}
270
271void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
272{
273	struct qdio_q *q;
274	int i;
275
276	for_each_input_queue(irq_ptr, q, i)
277		debugfs_remove(q->debugfs_q);
278	for_each_output_queue(irq_ptr, q, i)
279		debugfs_remove(q->debugfs_q);
280	debugfs_remove(irq_ptr->debugfs_perf);
281	debugfs_remove(irq_ptr->debugfs_dev);
282}
283
284int __init qdio_debug_init(void)
285{
286	debugfs_root = debugfs_create_dir("qdio", NULL);
287
288	qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
289	debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
290	debug_set_level(qdio_dbf_setup, DBF_INFO);
291	DBF_EVENT("dbf created\n");
292
293	qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
294	debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
295	debug_set_level(qdio_dbf_error, DBF_INFO);
296	DBF_ERROR("dbf created\n");
297	return 0;
298}
299
300void qdio_debug_exit(void)
301{
302	debugfs_remove(debugfs_root);
303	if (qdio_dbf_setup)
304		debug_unregister(qdio_dbf_setup);
305	if (qdio_dbf_error)
306		debug_unregister(qdio_dbf_error);
307}
308