xref: /openbmc/linux/drivers/s390/cio/qdio_debug.c (revision 0d456bad)
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 			   filp->f_path.dentry->d_inode->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 			   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