qdio_debug.c revision 50f769df1c4bea766c4eb927eae35728fb93e305
1/*
2 *  drivers/s390/cio/qdio_debug.c
3 *
4 *  Copyright IBM Corp. 2008
5 *
6 *  Author: Jan Glauber (jang@linux.vnet.ibm.com)
7 */
8#include <linux/proc_fs.h>
9#include <linux/seq_file.h>
10#include <linux/debugfs.h>
11#include <asm/qdio.h>
12#include <asm/debug.h>
13#include "qdio_debug.h"
14#include "qdio.h"
15
16debug_info_t *qdio_dbf_setup;
17debug_info_t *qdio_dbf_error;
18
19static struct dentry *debugfs_root;
20#define MAX_DEBUGFS_QUEUES	32
21static struct dentry *debugfs_queues[MAX_DEBUGFS_QUEUES] = { NULL };
22static DEFINE_MUTEX(debugfs_mutex);
23#define QDIO_DEBUGFS_NAME_LEN	40
24
25void qdio_allocate_dbf(struct qdio_initialize *init_data,
26		       struct qdio_irq *irq_ptr)
27{
28	char text[20];
29
30	DBF_EVENT("qfmt:%1d", init_data->q_format);
31	DBF_HEX(init_data->adapter_name, 8);
32	DBF_EVENT("qpff%4x", init_data->qib_param_field_format);
33	DBF_HEX(&init_data->qib_param_field, sizeof(void *));
34	DBF_HEX(&init_data->input_slib_elements, sizeof(void *));
35	DBF_HEX(&init_data->output_slib_elements, sizeof(void *));
36	DBF_EVENT("niq:%1d noq:%1d", init_data->no_input_qs,
37		  init_data->no_output_qs);
38	DBF_HEX(&init_data->input_handler, sizeof(void *));
39	DBF_HEX(&init_data->output_handler, sizeof(void *));
40	DBF_HEX(&init_data->int_parm, sizeof(long));
41	DBF_HEX(&init_data->flags, sizeof(long));
42	DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *));
43	DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *));
44	DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr);
45
46	/* allocate trace view for the interface */
47	snprintf(text, 20, "qdio_%s", dev_name(&init_data->cdev->dev));
48	irq_ptr->debug_area = debug_register(text, 2, 1, 16);
49	debug_register_view(irq_ptr->debug_area, &debug_hex_ascii_view);
50	debug_set_level(irq_ptr->debug_area, DBF_WARN);
51	DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created");
52}
53
54static int qstat_show(struct seq_file *m, void *v)
55{
56	unsigned char state;
57	struct qdio_q *q = m->private;
58	int i;
59
60	if (!q)
61		return 0;
62
63	seq_printf(m, "device state indicator: %d\n", *(u32 *)q->irq_ptr->dsci);
64	seq_printf(m, "nr_used: %d\n", atomic_read(&q->nr_buf_used));
65	seq_printf(m, "ftc: %d\n", q->first_to_check);
66	seq_printf(m, "last_move_ftc: %d\n", q->last_move_ftc);
67	seq_printf(m, "polling: %d\n", q->u.in.polling);
68	seq_printf(m, "ack count: %d\n", q->u.in.ack_count);
69	seq_printf(m, "slsb buffer states:\n");
70	seq_printf(m, "|0      |8      |16     |24     |32     |40     |48     |56  63|\n");
71
72	qdio_siga_sync_q(q);
73	for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
74		get_buf_state(q, i, &state, 0);
75		switch (state) {
76		case SLSB_P_INPUT_NOT_INIT:
77		case SLSB_P_OUTPUT_NOT_INIT:
78			seq_printf(m, "N");
79			break;
80		case SLSB_P_INPUT_PRIMED:
81		case SLSB_CU_OUTPUT_PRIMED:
82			seq_printf(m, "+");
83			break;
84		case SLSB_P_INPUT_ACK:
85			seq_printf(m, "A");
86			break;
87		case SLSB_P_INPUT_ERROR:
88		case SLSB_P_OUTPUT_ERROR:
89			seq_printf(m, "x");
90			break;
91		case SLSB_CU_INPUT_EMPTY:
92		case SLSB_P_OUTPUT_EMPTY:
93			seq_printf(m, "-");
94			break;
95		case SLSB_P_INPUT_HALTED:
96		case SLSB_P_OUTPUT_HALTED:
97			seq_printf(m, ".");
98			break;
99		default:
100			seq_printf(m, "?");
101		}
102		if (i == 63)
103			seq_printf(m, "\n");
104	}
105	seq_printf(m, "\n");
106	seq_printf(m, "|64     |72     |80     |88     |96     |104    |112    |   127|\n");
107	return 0;
108}
109
110static ssize_t qstat_seq_write(struct file *file, const char __user *buf,
111			       size_t count, loff_t *off)
112{
113	struct seq_file *seq = file->private_data;
114	struct qdio_q *q = seq->private;
115
116	if (!q)
117		return 0;
118
119	if (q->is_input_q)
120		xchg(q->irq_ptr->dsci, 1);
121	local_bh_disable();
122	tasklet_schedule(&q->tasklet);
123	local_bh_enable();
124	return count;
125}
126
127static int qstat_seq_open(struct inode *inode, struct file *filp)
128{
129	return single_open(filp, qstat_show,
130			   filp->f_path.dentry->d_inode->i_private);
131}
132
133static void remove_debugfs_entry(struct qdio_q *q)
134{
135	int i;
136
137	for (i = 0; i < MAX_DEBUGFS_QUEUES; i++) {
138		if (!debugfs_queues[i])
139			continue;
140		if (debugfs_queues[i]->d_inode->i_private == q) {
141			debugfs_remove(debugfs_queues[i]);
142			debugfs_queues[i] = NULL;
143		}
144	}
145}
146
147static struct file_operations debugfs_fops = {
148	.owner	 = THIS_MODULE,
149	.open	 = qstat_seq_open,
150	.read	 = seq_read,
151	.write	 = qstat_seq_write,
152	.llseek  = seq_lseek,
153	.release = single_release,
154};
155
156static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
157{
158	int i = 0;
159	char name[QDIO_DEBUGFS_NAME_LEN];
160
161	while (debugfs_queues[i] != NULL) {
162		i++;
163		if (i >= MAX_DEBUGFS_QUEUES)
164			return;
165	}
166	snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%s_%d",
167		 dev_name(&cdev->dev),
168		 q->is_input_q ? "input" : "output",
169		 q->nr);
170	debugfs_queues[i] = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
171						debugfs_root, q, &debugfs_fops);
172}
173
174void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
175{
176	struct qdio_q *q;
177	int i;
178
179	mutex_lock(&debugfs_mutex);
180	for_each_input_queue(irq_ptr, q, i)
181		setup_debugfs_entry(q, cdev);
182	for_each_output_queue(irq_ptr, q, i)
183		setup_debugfs_entry(q, cdev);
184	mutex_unlock(&debugfs_mutex);
185}
186
187void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
188{
189	struct qdio_q *q;
190	int i;
191
192	mutex_lock(&debugfs_mutex);
193	for_each_input_queue(irq_ptr, q, i)
194		remove_debugfs_entry(q);
195	for_each_output_queue(irq_ptr, q, i)
196		remove_debugfs_entry(q);
197	mutex_unlock(&debugfs_mutex);
198}
199
200int __init qdio_debug_init(void)
201{
202	debugfs_root = debugfs_create_dir("qdio_queues", NULL);
203
204	qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
205	debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
206	debug_set_level(qdio_dbf_setup, DBF_INFO);
207	DBF_EVENT("dbf created\n");
208
209	qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
210	debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
211	debug_set_level(qdio_dbf_error, DBF_INFO);
212	DBF_ERROR("dbf created\n");
213	return 0;
214}
215
216void qdio_debug_exit(void)
217{
218	debugfs_remove(debugfs_root);
219	if (qdio_dbf_setup)
220		debug_unregister(qdio_dbf_setup);
221	if (qdio_dbf_error)
222		debug_unregister(qdio_dbf_error);
223}
224