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