blob: aaf7f935bfd37e16c44e6ff70e84b38bde1c71c4 [file] [log] [blame]
Jan Glauber779e6e12008-07-17 17:16:48 +02001/*
2 * drivers/s390/cio/qdio_debug.c
3 *
Jan Glauber3f09bb82009-09-11 10:28:22 +02004 * Copyright IBM Corp. 2008,2009
Jan Glauber779e6e12008-07-17 17:16:48 +02005 *
6 * Author: Jan Glauber (jang@linux.vnet.ibm.com)
7 */
Jan Glauber779e6e12008-07-17 17:16:48 +02008#include <linux/seq_file.h>
9#include <linux/debugfs.h>
Jan Glauber779e6e12008-07-17 17:16:48 +020010#include <asm/debug.h>
11#include "qdio_debug.h"
12#include "qdio.h"
13
14debug_info_t *qdio_dbf_setup;
Jan Glauber22f99342008-12-25 13:38:46 +010015debug_info_t *qdio_dbf_error;
Jan Glauber779e6e12008-07-17 17:16:48 +020016
17static struct dentry *debugfs_root;
Jan Glauber3f09bb82009-09-11 10:28:22 +020018#define QDIO_DEBUGFS_NAME_LEN 10
Jan Glauber779e6e12008-07-17 17:16:48 +020019
Jan Glauber22f99342008-12-25 13:38:46 +010020void qdio_allocate_dbf(struct qdio_initialize *init_data,
21 struct qdio_irq *irq_ptr)
Jan Glauber779e6e12008-07-17 17:16:48 +020022{
Jan Glauber22f99342008-12-25 13:38:46 +010023 char text[20];
Jan Glauber779e6e12008-07-17 17:16:48 +020024
Jan Glauber22f99342008-12-25 13:38:46 +010025 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));
Jan Glauber22f99342008-12-25 13:38:46 +010036 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);
Jan Glauber779e6e12008-07-17 17:16:48 +020039
Jan Glauber22f99342008-12-25 13:38:46 +010040 /* 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");
Jan Glauber779e6e12008-07-17 17:16:48 +020046}
47
48static 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
Jan Glauber6486cda2010-01-04 09:05:42 +010057 seq_printf(m, "DSCI: %d nr_used: %d\n",
58 *(u32 *)q->irq_ptr->dsci, atomic_read(&q->nr_buf_used));
Jan Glauberd36deae2010-09-07 21:14:39 +000059 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 }
Jan Glauberd3072972010-02-26 22:37:36 +010069 seq_printf(m, "SBAL states:\n");
Jan Glauber50f769d2008-12-25 13:38:47 +010070 seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n");
Jan Glauber779e6e12008-07-17 17:16:48 +020071
Jan Glauber779e6e12008-07-17 17:16:48 +020072 for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
Jan Glauber60b5df22009-06-22 12:08:10 +020073 debug_get_buf_state(q, i, &state);
Jan Glauber779e6e12008-07-17 17:16:48 +020074 switch (state) {
75 case SLSB_P_INPUT_NOT_INIT:
76 case SLSB_P_OUTPUT_NOT_INIT:
77 seq_printf(m, "N");
78 break;
frank.blaschka@de.ibm.com104ea552011-08-08 01:33:55 +000079 case SLSB_P_OUTPUT_PENDING:
80 seq_printf(m, "P");
81 break;
Jan Glauber779e6e12008-07-17 17:16:48 +020082 case SLSB_P_INPUT_PRIMED:
83 case SLSB_CU_OUTPUT_PRIMED:
84 seq_printf(m, "+");
85 break;
86 case SLSB_P_INPUT_ACK:
87 seq_printf(m, "A");
88 break;
89 case SLSB_P_INPUT_ERROR:
90 case SLSB_P_OUTPUT_ERROR:
91 seq_printf(m, "x");
92 break;
93 case SLSB_CU_INPUT_EMPTY:
94 case SLSB_P_OUTPUT_EMPTY:
95 seq_printf(m, "-");
96 break;
97 case SLSB_P_INPUT_HALTED:
98 case SLSB_P_OUTPUT_HALTED:
99 seq_printf(m, ".");
100 break;
101 default:
102 seq_printf(m, "?");
103 }
104 if (i == 63)
105 seq_printf(m, "\n");
106 }
107 seq_printf(m, "\n");
Jan Glauber50f769d2008-12-25 13:38:47 +0100108 seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n");
Jan Glauberd3072972010-02-26 22:37:36 +0100109
110 seq_printf(m, "\nSBAL statistics:");
111 if (!q->irq_ptr->perf_stat_enabled) {
112 seq_printf(m, " disabled\n");
113 return 0;
114 }
115
116 seq_printf(m, "\n1 2.. 4.. 8.. "
117 "16.. 32.. 64.. 127\n");
118 for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
119 seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
120 seq_printf(m, "\nError NOP Total\n%-10u %-10u %-10u\n\n",
121 q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
122 q->q_stats.nr_sbal_total);
Jan Glauber779e6e12008-07-17 17:16:48 +0200123 return 0;
124}
125
Jan Glauber779e6e12008-07-17 17:16:48 +0200126static int qstat_seq_open(struct inode *inode, struct file *filp)
127{
128 return single_open(filp, qstat_show,
129 filp->f_path.dentry->d_inode->i_private);
130}
131
Alexey Dobriyan828c0952009-10-01 15:43:56 -0700132static const struct file_operations debugfs_fops = {
Jan Glauber779e6e12008-07-17 17:16:48 +0200133 .owner = THIS_MODULE,
134 .open = qstat_seq_open,
135 .read = seq_read,
Jan Glauber779e6e12008-07-17 17:16:48 +0200136 .llseek = seq_lseek,
137 .release = single_release,
138};
139
Jan Glauber6486cda2010-01-04 09:05:42 +0100140static char *qperf_names[] = {
141 "Assumed adapter interrupts",
142 "QDIO interrupts",
143 "Requested PCIs",
144 "Inbound tasklet runs",
145 "Inbound tasklet resched",
146 "Inbound tasklet resched2",
147 "Outbound tasklet runs",
148 "SIGA read",
149 "SIGA write",
150 "SIGA sync",
151 "Inbound calls",
152 "Inbound handler",
153 "Inbound stop_polling",
154 "Inbound queue full",
155 "Outbound calls",
156 "Outbound handler",
Jan Glauber01958432011-01-05 12:47:51 +0100157 "Outbound queue full",
Jan Glauber6486cda2010-01-04 09:05:42 +0100158 "Outbound fast_requeue",
159 "Outbound target_full",
160 "QEBSM eqbs",
161 "QEBSM eqbs partial",
162 "QEBSM sqbs",
Jan Glauberd36deae2010-09-07 21:14:39 +0000163 "QEBSM sqbs partial",
164 "Discarded interrupts"
Jan Glauber6486cda2010-01-04 09:05:42 +0100165};
166
167static int qperf_show(struct seq_file *m, void *v)
168{
169 struct qdio_irq *irq_ptr = m->private;
170 unsigned int *stat;
171 int i;
172
173 if (!irq_ptr)
174 return 0;
175 if (!irq_ptr->perf_stat_enabled) {
176 seq_printf(m, "disabled\n");
177 return 0;
178 }
179 stat = (unsigned int *)&irq_ptr->perf_stat;
180
181 for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
182 seq_printf(m, "%26s:\t%u\n",
183 qperf_names[i], *(stat + i));
184 return 0;
185}
186
187static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
188 size_t count, loff_t *off)
189{
190 struct seq_file *seq = file->private_data;
191 struct qdio_irq *irq_ptr = seq->private;
Jan Glauberd3072972010-02-26 22:37:36 +0100192 struct qdio_q *q;
Jan Glauber6486cda2010-01-04 09:05:42 +0100193 unsigned long val;
Jan Glauberd3072972010-02-26 22:37:36 +0100194 int ret, i;
Jan Glauber6486cda2010-01-04 09:05:42 +0100195
196 if (!irq_ptr)
197 return 0;
Jan Glauber6486cda2010-01-04 09:05:42 +0100198
Peter Hueweaf6df872011-08-03 16:44:30 +0200199 ret = kstrtoul_from_user(ubuf, count, 10, &val);
200 if (ret)
Jan Glauber6486cda2010-01-04 09:05:42 +0100201 return ret;
202
203 switch (val) {
204 case 0:
205 irq_ptr->perf_stat_enabled = 0;
206 memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
Jan Glauberd3072972010-02-26 22:37:36 +0100207 for_each_input_queue(irq_ptr, q, i)
208 memset(&q->q_stats, 0, sizeof(q->q_stats));
209 for_each_output_queue(irq_ptr, q, i)
210 memset(&q->q_stats, 0, sizeof(q->q_stats));
Jan Glauber6486cda2010-01-04 09:05:42 +0100211 break;
212 case 1:
213 irq_ptr->perf_stat_enabled = 1;
214 break;
215 }
216 return count;
217}
218
219static int qperf_seq_open(struct inode *inode, struct file *filp)
220{
221 return single_open(filp, qperf_show,
222 filp->f_path.dentry->d_inode->i_private);
223}
224
225static struct file_operations debugfs_perf_fops = {
226 .owner = THIS_MODULE,
227 .open = qperf_seq_open,
228 .read = seq_read,
229 .write = qperf_seq_write,
230 .llseek = seq_lseek,
231 .release = single_release,
232};
Jan Glauber779e6e12008-07-17 17:16:48 +0200233static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
234{
Jan Glauber2c780912008-10-28 11:10:14 +0100235 char name[QDIO_DEBUGFS_NAME_LEN];
Jan Glauber779e6e12008-07-17 17:16:48 +0200236
Jan Glauber3f09bb82009-09-11 10:28:22 +0200237 snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
Jan Glauber2c780912008-10-28 11:10:14 +0100238 q->is_input_q ? "input" : "output",
239 q->nr);
Jan Glauber3f09bb82009-09-11 10:28:22 +0200240 q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
241 q->irq_ptr->debugfs_dev, q, &debugfs_fops);
242 if (IS_ERR(q->debugfs_q))
243 q->debugfs_q = NULL;
Jan Glauber779e6e12008-07-17 17:16:48 +0200244}
245
246void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
247{
248 struct qdio_q *q;
249 int i;
250
Jan Glauber3f09bb82009-09-11 10:28:22 +0200251 irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
252 debugfs_root);
253 if (IS_ERR(irq_ptr->debugfs_dev))
254 irq_ptr->debugfs_dev = NULL;
Jan Glauber6486cda2010-01-04 09:05:42 +0100255
256 irq_ptr->debugfs_perf = debugfs_create_file("statistics",
257 S_IFREG | S_IRUGO | S_IWUSR,
258 irq_ptr->debugfs_dev, irq_ptr,
259 &debugfs_perf_fops);
260 if (IS_ERR(irq_ptr->debugfs_perf))
261 irq_ptr->debugfs_perf = NULL;
262
Jan Glauber779e6e12008-07-17 17:16:48 +0200263 for_each_input_queue(irq_ptr, q, i)
264 setup_debugfs_entry(q, cdev);
265 for_each_output_queue(irq_ptr, q, i)
266 setup_debugfs_entry(q, cdev);
Jan Glauber779e6e12008-07-17 17:16:48 +0200267}
268
269void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
270{
271 struct qdio_q *q;
272 int i;
273
Jan Glauber779e6e12008-07-17 17:16:48 +0200274 for_each_input_queue(irq_ptr, q, i)
Jan Glauber3f09bb82009-09-11 10:28:22 +0200275 debugfs_remove(q->debugfs_q);
Jan Glauber779e6e12008-07-17 17:16:48 +0200276 for_each_output_queue(irq_ptr, q, i)
Jan Glauber3f09bb82009-09-11 10:28:22 +0200277 debugfs_remove(q->debugfs_q);
Jan Glauber6486cda2010-01-04 09:05:42 +0100278 debugfs_remove(irq_ptr->debugfs_perf);
Jan Glauber3f09bb82009-09-11 10:28:22 +0200279 debugfs_remove(irq_ptr->debugfs_dev);
Jan Glauber779e6e12008-07-17 17:16:48 +0200280}
281
282int __init qdio_debug_init(void)
283{
Jan Glauber3f09bb82009-09-11 10:28:22 +0200284 debugfs_root = debugfs_create_dir("qdio", NULL);
Jan Glauber22f99342008-12-25 13:38:46 +0100285
286 qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
287 debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
288 debug_set_level(qdio_dbf_setup, DBF_INFO);
289 DBF_EVENT("dbf created\n");
290
291 qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
292 debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
293 debug_set_level(qdio_dbf_error, DBF_INFO);
294 DBF_ERROR("dbf created\n");
295 return 0;
Jan Glauber779e6e12008-07-17 17:16:48 +0200296}
297
298void qdio_debug_exit(void)
299{
300 debugfs_remove(debugfs_root);
Jan Glauber22f99342008-12-25 13:38:46 +0100301 if (qdio_dbf_setup)
302 debug_unregister(qdio_dbf_setup);
303 if (qdio_dbf_error)
304 debug_unregister(qdio_dbf_error);
Jan Glauber779e6e12008-07-17 17:16:48 +0200305}