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