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