xref: /openbmc/linux/drivers/s390/cio/qdio_debug.c (revision 9c1f8594)
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 queue full",
155 	"Outbound fast_requeue",
156 	"Outbound target_full",
157 	"QEBSM eqbs",
158 	"QEBSM eqbs partial",
159 	"QEBSM sqbs",
160 	"QEBSM sqbs partial",
161 	"Discarded interrupts"
162 };
163 
164 static int qperf_show(struct seq_file *m, void *v)
165 {
166 	struct qdio_irq *irq_ptr = m->private;
167 	unsigned int *stat;
168 	int i;
169 
170 	if (!irq_ptr)
171 		return 0;
172 	if (!irq_ptr->perf_stat_enabled) {
173 		seq_printf(m, "disabled\n");
174 		return 0;
175 	}
176 	stat = (unsigned int *)&irq_ptr->perf_stat;
177 
178 	for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
179 		seq_printf(m, "%26s:\t%u\n",
180 			   qperf_names[i], *(stat + i));
181 	return 0;
182 }
183 
184 static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
185 			       size_t count, loff_t *off)
186 {
187 	struct seq_file *seq = file->private_data;
188 	struct qdio_irq *irq_ptr = seq->private;
189 	struct qdio_q *q;
190 	unsigned long val;
191 	int ret, i;
192 
193 	if (!irq_ptr)
194 		return 0;
195 
196 	ret = kstrtoul_from_user(ubuf, count, 10, &val);
197 	if (ret)
198 		return ret;
199 
200 	switch (val) {
201 	case 0:
202 		irq_ptr->perf_stat_enabled = 0;
203 		memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
204 		for_each_input_queue(irq_ptr, q, i)
205 			memset(&q->q_stats, 0, sizeof(q->q_stats));
206 		for_each_output_queue(irq_ptr, q, i)
207 			memset(&q->q_stats, 0, sizeof(q->q_stats));
208 		break;
209 	case 1:
210 		irq_ptr->perf_stat_enabled = 1;
211 		break;
212 	}
213 	return count;
214 }
215 
216 static int qperf_seq_open(struct inode *inode, struct file *filp)
217 {
218 	return single_open(filp, qperf_show,
219 			   filp->f_path.dentry->d_inode->i_private);
220 }
221 
222 static struct file_operations debugfs_perf_fops = {
223 	.owner	 = THIS_MODULE,
224 	.open	 = qperf_seq_open,
225 	.read	 = seq_read,
226 	.write	 = qperf_seq_write,
227 	.llseek  = seq_lseek,
228 	.release = single_release,
229 };
230 static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
231 {
232 	char name[QDIO_DEBUGFS_NAME_LEN];
233 
234 	snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
235 		 q->is_input_q ? "input" : "output",
236 		 q->nr);
237 	q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
238 				q->irq_ptr->debugfs_dev, q, &debugfs_fops);
239 	if (IS_ERR(q->debugfs_q))
240 		q->debugfs_q = NULL;
241 }
242 
243 void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
244 {
245 	struct qdio_q *q;
246 	int i;
247 
248 	irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
249 						  debugfs_root);
250 	if (IS_ERR(irq_ptr->debugfs_dev))
251 		irq_ptr->debugfs_dev = NULL;
252 
253 	irq_ptr->debugfs_perf = debugfs_create_file("statistics",
254 				S_IFREG | S_IRUGO | S_IWUSR,
255 				irq_ptr->debugfs_dev, irq_ptr,
256 				&debugfs_perf_fops);
257 	if (IS_ERR(irq_ptr->debugfs_perf))
258 		irq_ptr->debugfs_perf = NULL;
259 
260 	for_each_input_queue(irq_ptr, q, i)
261 		setup_debugfs_entry(q, cdev);
262 	for_each_output_queue(irq_ptr, q, i)
263 		setup_debugfs_entry(q, cdev);
264 }
265 
266 void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
267 {
268 	struct qdio_q *q;
269 	int i;
270 
271 	for_each_input_queue(irq_ptr, q, i)
272 		debugfs_remove(q->debugfs_q);
273 	for_each_output_queue(irq_ptr, q, i)
274 		debugfs_remove(q->debugfs_q);
275 	debugfs_remove(irq_ptr->debugfs_perf);
276 	debugfs_remove(irq_ptr->debugfs_dev);
277 }
278 
279 int __init qdio_debug_init(void)
280 {
281 	debugfs_root = debugfs_create_dir("qdio", NULL);
282 
283 	qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
284 	debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
285 	debug_set_level(qdio_dbf_setup, DBF_INFO);
286 	DBF_EVENT("dbf created\n");
287 
288 	qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
289 	debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
290 	debug_set_level(qdio_dbf_error, DBF_INFO);
291 	DBF_ERROR("dbf created\n");
292 	return 0;
293 }
294 
295 void qdio_debug_exit(void)
296 {
297 	debugfs_remove(debugfs_root);
298 	if (qdio_dbf_setup)
299 		debug_unregister(qdio_dbf_setup);
300 	if (qdio_dbf_error)
301 		debug_unregister(qdio_dbf_error);
302 }
303