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