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 
qdio_allocate_dbf(struct qdio_initialize * init_data,struct qdio_irq * irq_ptr)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 
qstat_show(struct seq_file * m,void * v)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 
qstat_seq_open(struct inode * inode,struct file * filp)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 
qperf_show(struct seq_file * m,void * v)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 
qperf_seq_write(struct file * file,const char __user * ubuf,size_t count,loff_t * off)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 	char buf[8];
192 	int ret, i;
193 
194 	if (!irq_ptr)
195 		return 0;
196 	if (count >= sizeof(buf))
197 		return -EINVAL;
198 	if (copy_from_user(&buf, ubuf, count))
199 		return -EFAULT;
200 	buf[count] = 0;
201 
202 	ret = strict_strtoul(buf, 10, &val);
203 	if (ret < 0)
204 		return ret;
205 
206 	switch (val) {
207 	case 0:
208 		irq_ptr->perf_stat_enabled = 0;
209 		memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
210 		for_each_input_queue(irq_ptr, q, i)
211 			memset(&q->q_stats, 0, sizeof(q->q_stats));
212 		for_each_output_queue(irq_ptr, q, i)
213 			memset(&q->q_stats, 0, sizeof(q->q_stats));
214 		break;
215 	case 1:
216 		irq_ptr->perf_stat_enabled = 1;
217 		break;
218 	}
219 	return count;
220 }
221 
qperf_seq_open(struct inode * inode,struct file * filp)222 static int qperf_seq_open(struct inode *inode, struct file *filp)
223 {
224 	return single_open(filp, qperf_show,
225 			   filp->f_path.dentry->d_inode->i_private);
226 }
227 
228 static struct file_operations debugfs_perf_fops = {
229 	.owner	 = THIS_MODULE,
230 	.open	 = qperf_seq_open,
231 	.read	 = seq_read,
232 	.write	 = qperf_seq_write,
233 	.llseek  = seq_lseek,
234 	.release = single_release,
235 };
setup_debugfs_entry(struct qdio_q * q,struct ccw_device * cdev)236 static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
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 
qdio_setup_debug_entries(struct qdio_irq * irq_ptr,struct ccw_device * cdev)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, cdev);
268 	for_each_output_queue(irq_ptr, q, i)
269 		setup_debugfs_entry(q, cdev);
270 }
271 
qdio_shutdown_debug_entries(struct qdio_irq * irq_ptr,struct ccw_device * cdev)272 void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
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 
qdio_debug_init(void)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 
qdio_debug_exit(void)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