blob: c94eb2a0fa2ed2fb3c02f807b1dabc762a9d680f [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));
36 DBF_HEX(&init_data->flags, sizeof(long));
37 DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *));
38 DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *));
39 DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr);
Jan Glauber779e6e12008-07-17 17:16:48 +020040
Jan Glauber22f99342008-12-25 13:38:46 +010041 /* allocate trace view for the interface */
42 snprintf(text, 20, "qdio_%s", dev_name(&init_data->cdev->dev));
43 irq_ptr->debug_area = debug_register(text, 2, 1, 16);
44 debug_register_view(irq_ptr->debug_area, &debug_hex_ascii_view);
45 debug_set_level(irq_ptr->debug_area, DBF_WARN);
46 DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created");
Jan Glauber779e6e12008-07-17 17:16:48 +020047}
48
49static int qstat_show(struct seq_file *m, void *v)
50{
51 unsigned char state;
52 struct qdio_q *q = m->private;
53 int i;
54
55 if (!q)
56 return 0;
57
Jan Glauber6486cda2010-01-04 09:05:42 +010058 seq_printf(m, "DSCI: %d nr_used: %d\n",
59 *(u32 *)q->irq_ptr->dsci, atomic_read(&q->nr_buf_used));
60 seq_printf(m, "ftc: %d last_move: %d\n", q->first_to_check, q->last_move);
61 seq_printf(m, "polling: %d ack start: %d ack count: %d\n",
62 q->u.in.polling, q->u.in.ack_start, q->u.in.ack_count);
Jan Glauberd3072972010-02-26 22:37:36 +010063 seq_printf(m, "SBAL states:\n");
Jan Glauber50f769d2008-12-25 13:38:47 +010064 seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n");
Jan Glauber779e6e12008-07-17 17:16:48 +020065
Jan Glauber779e6e12008-07-17 17:16:48 +020066 for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
Jan Glauber60b5df22009-06-22 12:08:10 +020067 debug_get_buf_state(q, i, &state);
Jan Glauber779e6e12008-07-17 17:16:48 +020068 switch (state) {
69 case SLSB_P_INPUT_NOT_INIT:
70 case SLSB_P_OUTPUT_NOT_INIT:
71 seq_printf(m, "N");
72 break;
73 case SLSB_P_INPUT_PRIMED:
74 case SLSB_CU_OUTPUT_PRIMED:
75 seq_printf(m, "+");
76 break;
77 case SLSB_P_INPUT_ACK:
78 seq_printf(m, "A");
79 break;
80 case SLSB_P_INPUT_ERROR:
81 case SLSB_P_OUTPUT_ERROR:
82 seq_printf(m, "x");
83 break;
84 case SLSB_CU_INPUT_EMPTY:
85 case SLSB_P_OUTPUT_EMPTY:
86 seq_printf(m, "-");
87 break;
88 case SLSB_P_INPUT_HALTED:
89 case SLSB_P_OUTPUT_HALTED:
90 seq_printf(m, ".");
91 break;
92 default:
93 seq_printf(m, "?");
94 }
95 if (i == 63)
96 seq_printf(m, "\n");
97 }
98 seq_printf(m, "\n");
Jan Glauber50f769d2008-12-25 13:38:47 +010099 seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n");
Jan Glauberd3072972010-02-26 22:37:36 +0100100
101 seq_printf(m, "\nSBAL statistics:");
102 if (!q->irq_ptr->perf_stat_enabled) {
103 seq_printf(m, " disabled\n");
104 return 0;
105 }
106
107 seq_printf(m, "\n1 2.. 4.. 8.. "
108 "16.. 32.. 64.. 127\n");
109 for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
110 seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
111 seq_printf(m, "\nError NOP Total\n%-10u %-10u %-10u\n\n",
112 q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
113 q->q_stats.nr_sbal_total);
Jan Glauber779e6e12008-07-17 17:16:48 +0200114 return 0;
115}
116
117static ssize_t qstat_seq_write(struct file *file, const char __user *buf,
118 size_t count, loff_t *off)
119{
120 struct seq_file *seq = file->private_data;
121 struct qdio_q *q = seq->private;
122
123 if (!q)
124 return 0;
Jan Glauber779e6e12008-07-17 17:16:48 +0200125 if (q->is_input_q)
126 xchg(q->irq_ptr->dsci, 1);
127 local_bh_disable();
128 tasklet_schedule(&q->tasklet);
129 local_bh_enable();
130 return count;
131}
132
133static int qstat_seq_open(struct inode *inode, struct file *filp)
134{
135 return single_open(filp, qstat_show,
136 filp->f_path.dentry->d_inode->i_private);
137}
138
Alexey Dobriyan828c0952009-10-01 15:43:56 -0700139static const struct file_operations debugfs_fops = {
Jan Glauber779e6e12008-07-17 17:16:48 +0200140 .owner = THIS_MODULE,
141 .open = qstat_seq_open,
142 .read = seq_read,
143 .write = qstat_seq_write,
144 .llseek = seq_lseek,
145 .release = single_release,
146};
147
Jan Glauber6486cda2010-01-04 09:05:42 +0100148static char *qperf_names[] = {
149 "Assumed adapter interrupts",
150 "QDIO interrupts",
151 "Requested PCIs",
152 "Inbound tasklet runs",
153 "Inbound tasklet resched",
154 "Inbound tasklet resched2",
155 "Outbound tasklet runs",
156 "SIGA read",
157 "SIGA write",
158 "SIGA sync",
159 "Inbound calls",
160 "Inbound handler",
161 "Inbound stop_polling",
162 "Inbound queue full",
163 "Outbound calls",
164 "Outbound handler",
165 "Outbound fast_requeue",
166 "Outbound target_full",
167 "QEBSM eqbs",
168 "QEBSM eqbs partial",
169 "QEBSM sqbs",
170 "QEBSM sqbs partial"
171};
172
173static int qperf_show(struct seq_file *m, void *v)
174{
175 struct qdio_irq *irq_ptr = m->private;
176 unsigned int *stat;
177 int i;
178
179 if (!irq_ptr)
180 return 0;
181 if (!irq_ptr->perf_stat_enabled) {
182 seq_printf(m, "disabled\n");
183 return 0;
184 }
185 stat = (unsigned int *)&irq_ptr->perf_stat;
186
187 for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
188 seq_printf(m, "%26s:\t%u\n",
189 qperf_names[i], *(stat + i));
190 return 0;
191}
192
193static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
194 size_t count, loff_t *off)
195{
196 struct seq_file *seq = file->private_data;
197 struct qdio_irq *irq_ptr = seq->private;
Jan Glauberd3072972010-02-26 22:37:36 +0100198 struct qdio_q *q;
Jan Glauber6486cda2010-01-04 09:05:42 +0100199 unsigned long val;
200 char buf[8];
Jan Glauberd3072972010-02-26 22:37:36 +0100201 int ret, i;
Jan Glauber6486cda2010-01-04 09:05:42 +0100202
203 if (!irq_ptr)
204 return 0;
205 if (count >= sizeof(buf))
206 return -EINVAL;
207 if (copy_from_user(&buf, ubuf, count))
208 return -EFAULT;
209 buf[count] = 0;
210
211 ret = strict_strtoul(buf, 10, &val);
212 if (ret < 0)
213 return ret;
214
215 switch (val) {
216 case 0:
217 irq_ptr->perf_stat_enabled = 0;
218 memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
Jan Glauberd3072972010-02-26 22:37:36 +0100219 for_each_input_queue(irq_ptr, q, i)
220 memset(&q->q_stats, 0, sizeof(q->q_stats));
221 for_each_output_queue(irq_ptr, q, i)
222 memset(&q->q_stats, 0, sizeof(q->q_stats));
Jan Glauber6486cda2010-01-04 09:05:42 +0100223 break;
224 case 1:
225 irq_ptr->perf_stat_enabled = 1;
226 break;
227 }
228 return count;
229}
230
231static int qperf_seq_open(struct inode *inode, struct file *filp)
232{
233 return single_open(filp, qperf_show,
234 filp->f_path.dentry->d_inode->i_private);
235}
236
237static struct file_operations debugfs_perf_fops = {
238 .owner = THIS_MODULE,
239 .open = qperf_seq_open,
240 .read = seq_read,
241 .write = qperf_seq_write,
242 .llseek = seq_lseek,
243 .release = single_release,
244};
Jan Glauber779e6e12008-07-17 17:16:48 +0200245static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
246{
Jan Glauber2c780912008-10-28 11:10:14 +0100247 char name[QDIO_DEBUGFS_NAME_LEN];
Jan Glauber779e6e12008-07-17 17:16:48 +0200248
Jan Glauber3f09bb82009-09-11 10:28:22 +0200249 snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
Jan Glauber2c780912008-10-28 11:10:14 +0100250 q->is_input_q ? "input" : "output",
251 q->nr);
Jan Glauber3f09bb82009-09-11 10:28:22 +0200252 q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
253 q->irq_ptr->debugfs_dev, q, &debugfs_fops);
254 if (IS_ERR(q->debugfs_q))
255 q->debugfs_q = NULL;
Jan Glauber779e6e12008-07-17 17:16:48 +0200256}
257
258void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
259{
260 struct qdio_q *q;
261 int i;
262
Jan Glauber3f09bb82009-09-11 10:28:22 +0200263 irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
264 debugfs_root);
265 if (IS_ERR(irq_ptr->debugfs_dev))
266 irq_ptr->debugfs_dev = NULL;
Jan Glauber6486cda2010-01-04 09:05:42 +0100267
268 irq_ptr->debugfs_perf = debugfs_create_file("statistics",
269 S_IFREG | S_IRUGO | S_IWUSR,
270 irq_ptr->debugfs_dev, irq_ptr,
271 &debugfs_perf_fops);
272 if (IS_ERR(irq_ptr->debugfs_perf))
273 irq_ptr->debugfs_perf = NULL;
274
Jan Glauber779e6e12008-07-17 17:16:48 +0200275 for_each_input_queue(irq_ptr, q, i)
276 setup_debugfs_entry(q, cdev);
277 for_each_output_queue(irq_ptr, q, i)
278 setup_debugfs_entry(q, cdev);
Jan Glauber779e6e12008-07-17 17:16:48 +0200279}
280
281void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
282{
283 struct qdio_q *q;
284 int i;
285
Jan Glauber779e6e12008-07-17 17:16:48 +0200286 for_each_input_queue(irq_ptr, q, i)
Jan Glauber3f09bb82009-09-11 10:28:22 +0200287 debugfs_remove(q->debugfs_q);
Jan Glauber779e6e12008-07-17 17:16:48 +0200288 for_each_output_queue(irq_ptr, q, i)
Jan Glauber3f09bb82009-09-11 10:28:22 +0200289 debugfs_remove(q->debugfs_q);
Jan Glauber6486cda2010-01-04 09:05:42 +0100290 debugfs_remove(irq_ptr->debugfs_perf);
Jan Glauber3f09bb82009-09-11 10:28:22 +0200291 debugfs_remove(irq_ptr->debugfs_dev);
Jan Glauber779e6e12008-07-17 17:16:48 +0200292}
293
294int __init qdio_debug_init(void)
295{
Jan Glauber3f09bb82009-09-11 10:28:22 +0200296 debugfs_root = debugfs_create_dir("qdio", NULL);
Jan Glauber22f99342008-12-25 13:38:46 +0100297
298 qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
299 debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
300 debug_set_level(qdio_dbf_setup, DBF_INFO);
301 DBF_EVENT("dbf created\n");
302
303 qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
304 debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
305 debug_set_level(qdio_dbf_error, DBF_INFO);
306 DBF_ERROR("dbf created\n");
307 return 0;
Jan Glauber779e6e12008-07-17 17:16:48 +0200308}
309
310void qdio_debug_exit(void)
311{
312 debugfs_remove(debugfs_root);
Jan Glauber22f99342008-12-25 13:38:46 +0100313 if (qdio_dbf_setup)
314 debug_unregister(qdio_dbf_setup);
315 if (qdio_dbf_error)
316 debug_unregister(qdio_dbf_error);
Jan Glauber779e6e12008-07-17 17:16:48 +0200317}