]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/s390/cio/qdio_debug.c
Merge remote-tracking branches 'spi/topic/adi-v3', 'spi/topic/atmel', 'spi/topic...
[mirror_ubuntu-artful-kernel.git] / drivers / s390 / cio / qdio_debug.c
CommitLineData
779e6e1c 1/*
a53c8fab 2 * Copyright IBM Corp. 2008, 2009
779e6e1c
JG
3 *
4 * Author: Jan Glauber (jang@linux.vnet.ibm.com)
5 */
779e6e1c
JG
6#include <linux/seq_file.h>
7#include <linux/debugfs.h>
3a4c5d59
HC
8#include <linux/uaccess.h>
9#include <linux/export.h>
613c4e04 10#include <linux/slab.h>
779e6e1c
JG
11#include <asm/debug.h>
12#include "qdio_debug.h"
13#include "qdio.h"
14
15debug_info_t *qdio_dbf_setup;
22f99347 16debug_info_t *qdio_dbf_error;
779e6e1c
JG
17
18static struct dentry *debugfs_root;
3f09bb89 19#define QDIO_DEBUGFS_NAME_LEN 10
613c4e04 20#define QDIO_DBF_NAME_LEN 20
779e6e1c 21
613c4e04
SR
22struct 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
28static LIST_HEAD(qdio_dbf_list);
29static DEFINE_MUTEX(qdio_dbf_list_mutex);
30
31static 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
47static 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
60int qdio_allocate_dbf(struct qdio_initialize *init_data,
22f99347 61 struct qdio_irq *irq_ptr)
779e6e1c 62{
613c4e04
SR
63 char text[QDIO_DBF_NAME_LEN];
64 struct qdio_dbf_entry *new_entry;
22f99347
JG
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));
22f99347
JG
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 */
613c4e04
SR
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;
779e6e1c
JG
110}
111
112static 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
a2b86019
JG
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),
d36deae7
JG
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);
a2b86019
JG
130 seq_printf(m, "DSCI: %d IRQs disabled: %u\n",
131 *(u32 *)q->irq_ptr->dsci,
d36deae7
JG
132 test_bit(QDIO_QUEUE_IRQS_DISABLED,
133 &q->u.in.queue_irq_state));
134 }
d307297f 135 seq_printf(m, "SBAL states:\n");
50f769df 136 seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n");
779e6e1c 137
779e6e1c 138 for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
60b5df2f 139 debug_get_buf_state(q, i, &state);
779e6e1c
JG
140 switch (state) {
141 case SLSB_P_INPUT_NOT_INIT:
142 case SLSB_P_OUTPUT_NOT_INIT:
143 seq_printf(m, "N");
144 break;
104ea556 145 case SLSB_P_OUTPUT_PENDING:
146 seq_printf(m, "P");
147 break;
779e6e1c
JG
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");
50f769df 174 seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n");
d307297f
JG
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);
779e6e1c
JG
189 return 0;
190}
191
779e6e1c
JG
192static int qstat_seq_open(struct inode *inode, struct file *filp)
193{
194 return single_open(filp, qstat_show,
496ad9aa 195 file_inode(filp)->i_private);
779e6e1c
JG
196}
197
828c0950 198static const struct file_operations debugfs_fops = {
779e6e1c
JG
199 .owner = THIS_MODULE,
200 .open = qstat_seq_open,
201 .read = seq_read,
779e6e1c
JG
202 .llseek = seq_lseek,
203 .release = single_release,
204};
205
6486cda6
JG
206static 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",
0195843b 223 "Outbound queue full",
6486cda6
JG
224 "Outbound fast_requeue",
225 "Outbound target_full",
226 "QEBSM eqbs",
227 "QEBSM eqbs partial",
228 "QEBSM sqbs",
d36deae7
JG
229 "QEBSM sqbs partial",
230 "Discarded interrupts"
6486cda6
JG
231};
232
233static 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
253static 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;
d307297f 258 struct qdio_q *q;
6486cda6 259 unsigned long val;
d307297f 260 int ret, i;
6486cda6
JG
261
262 if (!irq_ptr)
263 return 0;
af6df871
PH
264
265 ret = kstrtoul_from_user(ubuf, count, 10, &val);
266 if (ret)
6486cda6
JG
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));
d307297f
JG
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));
6486cda6
JG
277 break;
278 case 1:
279 irq_ptr->perf_stat_enabled = 1;
280 break;
281 }
282 return count;
283}
284
285static int qperf_seq_open(struct inode *inode, struct file *filp)
286{
287 return single_open(filp, qperf_show,
496ad9aa 288 file_inode(filp)->i_private);
6486cda6
JG
289}
290
75ef9de1 291static const struct file_operations debugfs_perf_fops = {
6486cda6
JG
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};
aa2383f8
SR
299
300static void setup_debugfs_entry(struct qdio_q *q)
779e6e1c 301{
2c780914 302 char name[QDIO_DEBUGFS_NAME_LEN];
779e6e1c 303
3f09bb89 304 snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
2c780914
JG
305 q->is_input_q ? "input" : "output",
306 q->nr);
3f09bb89
JG
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;
779e6e1c
JG
311}
312
313void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
314{
315 struct qdio_q *q;
316 int i;
317
3f09bb89
JG
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;
6486cda6
JG
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
779e6e1c 330 for_each_input_queue(irq_ptr, q, i)
aa2383f8 331 setup_debugfs_entry(q);
779e6e1c 332 for_each_output_queue(irq_ptr, q, i)
aa2383f8 333 setup_debugfs_entry(q);
779e6e1c
JG
334}
335
aa2383f8 336void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr)
779e6e1c
JG
337{
338 struct qdio_q *q;
339 int i;
340
779e6e1c 341 for_each_input_queue(irq_ptr, q, i)
3f09bb89 342 debugfs_remove(q->debugfs_q);
779e6e1c 343 for_each_output_queue(irq_ptr, q, i)
3f09bb89 344 debugfs_remove(q->debugfs_q);
6486cda6 345 debugfs_remove(irq_ptr->debugfs_perf);
3f09bb89 346 debugfs_remove(irq_ptr->debugfs_dev);
779e6e1c
JG
347}
348
349int __init qdio_debug_init(void)
350{
3f09bb89 351 debugfs_root = debugfs_create_dir("qdio", NULL);
22f99347
JG
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;
779e6e1c
JG
363}
364
365void qdio_debug_exit(void)
366{
613c4e04 367 qdio_clear_dbf_list();
779e6e1c 368 debugfs_remove(debugfs_root);
22f99347
JG
369 if (qdio_dbf_setup)
370 debug_unregister(qdio_dbf_setup);
371 if (qdio_dbf_error)
372 debug_unregister(qdio_dbf_error);
779e6e1c 373}