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