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