xref: /openbmc/linux/drivers/s390/cio/qdio_debug.c (revision baa7eb025ab14f3cba2e35c0a8648f9c9f01d24f)
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",
60 		   q->first_to_check, q->last_move);
61 	if (q->is_input_q) {
62 		seq_printf(m, "polling: %d  ack start: %d  ack count: %d\n",
63 			   q->u.in.polling, q->u.in.ack_start,
64 			   q->u.in.ack_count);
65 		seq_printf(m, "IRQs disabled: %u\n",
66 			   test_bit(QDIO_QUEUE_IRQS_DISABLED,
67 			   &q->u.in.queue_irq_state));
68 	}
69 	seq_printf(m, "SBAL states:\n");
70 	seq_printf(m, "|0      |8      |16     |24     |32     |40     |48     |56  63|\n");
71 
72 	for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
73 		debug_get_buf_state(q, i, &state);
74 		switch (state) {
75 		case SLSB_P_INPUT_NOT_INIT:
76 		case SLSB_P_OUTPUT_NOT_INIT:
77 			seq_printf(m, "N");
78 			break;
79 		case SLSB_P_INPUT_PRIMED:
80 		case SLSB_CU_OUTPUT_PRIMED:
81 			seq_printf(m, "+");
82 			break;
83 		case SLSB_P_INPUT_ACK:
84 			seq_printf(m, "A");
85 			break;
86 		case SLSB_P_INPUT_ERROR:
87 		case SLSB_P_OUTPUT_ERROR:
88 			seq_printf(m, "x");
89 			break;
90 		case SLSB_CU_INPUT_EMPTY:
91 		case SLSB_P_OUTPUT_EMPTY:
92 			seq_printf(m, "-");
93 			break;
94 		case SLSB_P_INPUT_HALTED:
95 		case SLSB_P_OUTPUT_HALTED:
96 			seq_printf(m, ".");
97 			break;
98 		default:
99 			seq_printf(m, "?");
100 		}
101 		if (i == 63)
102 			seq_printf(m, "\n");
103 	}
104 	seq_printf(m, "\n");
105 	seq_printf(m, "|64     |72     |80     |88     |96     |104    |112    |   127|\n");
106 
107 	seq_printf(m, "\nSBAL statistics:");
108 	if (!q->irq_ptr->perf_stat_enabled) {
109 		seq_printf(m, " disabled\n");
110 		return 0;
111 	}
112 
113 	seq_printf(m, "\n1          2..        4..        8..        "
114 		   "16..       32..       64..       127\n");
115 	for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
116 		seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
117 	seq_printf(m, "\nError      NOP        Total\n%-10u %-10u %-10u\n\n",
118 		   q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
119 		   q->q_stats.nr_sbal_total);
120 	return 0;
121 }
122 
123 static int qstat_seq_open(struct inode *inode, struct file *filp)
124 {
125 	return single_open(filp, qstat_show,
126 			   filp->f_path.dentry->d_inode->i_private);
127 }
128 
129 static const struct file_operations debugfs_fops = {
130 	.owner	 = THIS_MODULE,
131 	.open	 = qstat_seq_open,
132 	.read	 = seq_read,
133 	.llseek  = seq_lseek,
134 	.release = single_release,
135 };
136 
137 static char *qperf_names[] = {
138 	"Assumed adapter interrupts",
139 	"QDIO interrupts",
140 	"Requested PCIs",
141 	"Inbound tasklet runs",
142 	"Inbound tasklet resched",
143 	"Inbound tasklet resched2",
144 	"Outbound tasklet runs",
145 	"SIGA read",
146 	"SIGA write",
147 	"SIGA sync",
148 	"Inbound calls",
149 	"Inbound handler",
150 	"Inbound stop_polling",
151 	"Inbound queue full",
152 	"Outbound calls",
153 	"Outbound handler",
154 	"Outbound fast_requeue",
155 	"Outbound target_full",
156 	"QEBSM eqbs",
157 	"QEBSM eqbs partial",
158 	"QEBSM sqbs",
159 	"QEBSM sqbs partial",
160 	"Discarded interrupts"
161 };
162 
163 static int qperf_show(struct seq_file *m, void *v)
164 {
165 	struct qdio_irq *irq_ptr = m->private;
166 	unsigned int *stat;
167 	int i;
168 
169 	if (!irq_ptr)
170 		return 0;
171 	if (!irq_ptr->perf_stat_enabled) {
172 		seq_printf(m, "disabled\n");
173 		return 0;
174 	}
175 	stat = (unsigned int *)&irq_ptr->perf_stat;
176 
177 	for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
178 		seq_printf(m, "%26s:\t%u\n",
179 			   qperf_names[i], *(stat + i));
180 	return 0;
181 }
182 
183 static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
184 			       size_t count, loff_t *off)
185 {
186 	struct seq_file *seq = file->private_data;
187 	struct qdio_irq *irq_ptr = seq->private;
188 	struct qdio_q *q;
189 	unsigned long val;
190 	char buf[8];
191 	int ret, i;
192 
193 	if (!irq_ptr)
194 		return 0;
195 	if (count >= sizeof(buf))
196 		return -EINVAL;
197 	if (copy_from_user(&buf, ubuf, count))
198 		return -EFAULT;
199 	buf[count] = 0;
200 
201 	ret = strict_strtoul(buf, 10, &val);
202 	if (ret < 0)
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 
221 static int qperf_seq_open(struct inode *inode, struct file *filp)
222 {
223 	return single_open(filp, qperf_show,
224 			   filp->f_path.dentry->d_inode->i_private);
225 }
226 
227 static 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 };
235 static 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 
248 void 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 
271 void 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 
284 int __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 
300 void 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