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