xref: /linux/drivers/s390/cio/qdio_debug.c (revision 5499b45190237ca90dd2ac86395cf464fe1f4cc7)
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 
14 debug_info_t *qdio_dbf_setup;
15 debug_info_t *qdio_dbf_error;
16 
17 static struct dentry *debugfs_root;
18 #define QDIO_DEBUGFS_NAME_LEN	10
19 
20 void 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 
49 static 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, "SBAL 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 
101 	seq_printf(m, "\nSBAL statistics:");
102 	if (!q->irq_ptr->perf_stat_enabled) {
103 		seq_printf(m, " disabled\n");
104 		return 0;
105 	}
106 
107 	seq_printf(m, "\n1          2..        4..        8..        "
108 		   "16..       32..       64..       127\n");
109 	for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
110 		seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
111 	seq_printf(m, "\nError      NOP        Total\n%-10u %-10u %-10u\n\n",
112 		   q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
113 		   q->q_stats.nr_sbal_total);
114 	return 0;
115 }
116 
117 static ssize_t qstat_seq_write(struct file *file, const char __user *buf,
118 			       size_t count, loff_t *off)
119 {
120 	struct seq_file *seq = file->private_data;
121 	struct qdio_q *q = seq->private;
122 
123 	if (!q)
124 		return 0;
125 	if (q->is_input_q)
126 		xchg(q->irq_ptr->dsci, 1);
127 	local_bh_disable();
128 	tasklet_schedule(&q->tasklet);
129 	local_bh_enable();
130 	return count;
131 }
132 
133 static int qstat_seq_open(struct inode *inode, struct file *filp)
134 {
135 	return single_open(filp, qstat_show,
136 			   filp->f_path.dentry->d_inode->i_private);
137 }
138 
139 static const struct file_operations debugfs_fops = {
140 	.owner	 = THIS_MODULE,
141 	.open	 = qstat_seq_open,
142 	.read	 = seq_read,
143 	.write	 = qstat_seq_write,
144 	.llseek  = seq_lseek,
145 	.release = single_release,
146 };
147 
148 static char *qperf_names[] = {
149 	"Assumed adapter interrupts",
150 	"QDIO interrupts",
151 	"Requested PCIs",
152 	"Inbound tasklet runs",
153 	"Inbound tasklet resched",
154 	"Inbound tasklet resched2",
155 	"Outbound tasklet runs",
156 	"SIGA read",
157 	"SIGA write",
158 	"SIGA sync",
159 	"Inbound calls",
160 	"Inbound handler",
161 	"Inbound stop_polling",
162 	"Inbound queue full",
163 	"Outbound calls",
164 	"Outbound handler",
165 	"Outbound fast_requeue",
166 	"Outbound target_full",
167 	"QEBSM eqbs",
168 	"QEBSM eqbs partial",
169 	"QEBSM sqbs",
170 	"QEBSM sqbs partial"
171 };
172 
173 static int qperf_show(struct seq_file *m, void *v)
174 {
175 	struct qdio_irq *irq_ptr = m->private;
176 	unsigned int *stat;
177 	int i;
178 
179 	if (!irq_ptr)
180 		return 0;
181 	if (!irq_ptr->perf_stat_enabled) {
182 		seq_printf(m, "disabled\n");
183 		return 0;
184 	}
185 	stat = (unsigned int *)&irq_ptr->perf_stat;
186 
187 	for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
188 		seq_printf(m, "%26s:\t%u\n",
189 			   qperf_names[i], *(stat + i));
190 	return 0;
191 }
192 
193 static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
194 			       size_t count, loff_t *off)
195 {
196 	struct seq_file *seq = file->private_data;
197 	struct qdio_irq *irq_ptr = seq->private;
198 	struct qdio_q *q;
199 	unsigned long val;
200 	char buf[8];
201 	int ret, i;
202 
203 	if (!irq_ptr)
204 		return 0;
205 	if (count >= sizeof(buf))
206 		return -EINVAL;
207 	if (copy_from_user(&buf, ubuf, count))
208 		return -EFAULT;
209 	buf[count] = 0;
210 
211 	ret = strict_strtoul(buf, 10, &val);
212 	if (ret < 0)
213 		return ret;
214 
215 	switch (val) {
216 	case 0:
217 		irq_ptr->perf_stat_enabled = 0;
218 		memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
219 		for_each_input_queue(irq_ptr, q, i)
220 			memset(&q->q_stats, 0, sizeof(q->q_stats));
221 		for_each_output_queue(irq_ptr, q, i)
222 			memset(&q->q_stats, 0, sizeof(q->q_stats));
223 		break;
224 	case 1:
225 		irq_ptr->perf_stat_enabled = 1;
226 		break;
227 	}
228 	return count;
229 }
230 
231 static int qperf_seq_open(struct inode *inode, struct file *filp)
232 {
233 	return single_open(filp, qperf_show,
234 			   filp->f_path.dentry->d_inode->i_private);
235 }
236 
237 static struct file_operations debugfs_perf_fops = {
238 	.owner	 = THIS_MODULE,
239 	.open	 = qperf_seq_open,
240 	.read	 = seq_read,
241 	.write	 = qperf_seq_write,
242 	.llseek  = seq_lseek,
243 	.release = single_release,
244 };
245 static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
246 {
247 	char name[QDIO_DEBUGFS_NAME_LEN];
248 
249 	snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
250 		 q->is_input_q ? "input" : "output",
251 		 q->nr);
252 	q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
253 				q->irq_ptr->debugfs_dev, q, &debugfs_fops);
254 	if (IS_ERR(q->debugfs_q))
255 		q->debugfs_q = NULL;
256 }
257 
258 void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
259 {
260 	struct qdio_q *q;
261 	int i;
262 
263 	irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
264 						  debugfs_root);
265 	if (IS_ERR(irq_ptr->debugfs_dev))
266 		irq_ptr->debugfs_dev = NULL;
267 
268 	irq_ptr->debugfs_perf = debugfs_create_file("statistics",
269 				S_IFREG | S_IRUGO | S_IWUSR,
270 				irq_ptr->debugfs_dev, irq_ptr,
271 				&debugfs_perf_fops);
272 	if (IS_ERR(irq_ptr->debugfs_perf))
273 		irq_ptr->debugfs_perf = NULL;
274 
275 	for_each_input_queue(irq_ptr, q, i)
276 		setup_debugfs_entry(q, cdev);
277 	for_each_output_queue(irq_ptr, q, i)
278 		setup_debugfs_entry(q, cdev);
279 }
280 
281 void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
282 {
283 	struct qdio_q *q;
284 	int i;
285 
286 	for_each_input_queue(irq_ptr, q, i)
287 		debugfs_remove(q->debugfs_q);
288 	for_each_output_queue(irq_ptr, q, i)
289 		debugfs_remove(q->debugfs_q);
290 	debugfs_remove(irq_ptr->debugfs_perf);
291 	debugfs_remove(irq_ptr->debugfs_dev);
292 }
293 
294 int __init qdio_debug_init(void)
295 {
296 	debugfs_root = debugfs_create_dir("qdio", NULL);
297 
298 	qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
299 	debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
300 	debug_set_level(qdio_dbf_setup, DBF_INFO);
301 	DBF_EVENT("dbf created\n");
302 
303 	qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
304 	debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
305 	debug_set_level(qdio_dbf_error, DBF_INFO);
306 	DBF_ERROR("dbf created\n");
307 	return 0;
308 }
309 
310 void qdio_debug_exit(void)
311 {
312 	debugfs_remove(debugfs_root);
313 	if (qdio_dbf_setup)
314 		debug_unregister(qdio_dbf_setup);
315 	if (qdio_dbf_error)
316 		debug_unregister(qdio_dbf_error);
317 }
318