blob: 6ce83f56d5371c5acdd0a216b9992019188a6e69 [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));
59 seq_printf(m, "ftc: %d last_move: %d\n", q->first_to_check, q->last_move);
60 seq_printf(m, "polling: %d ack start: %d ack count: %d\n",
61 q->u.in.polling, q->u.in.ack_start, q->u.in.ack_count);
Jan Glauberd3072972010-02-26 22:37:36 +010062 seq_printf(m, "SBAL states:\n");
Jan Glauber50f769d2008-12-25 13:38:47 +010063 seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n");
Jan Glauber779e6e12008-07-17 17:16:48 +020064
Jan Glauber779e6e12008-07-17 17:16:48 +020065 for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
Jan Glauber60b5df22009-06-22 12:08:10 +020066 debug_get_buf_state(q, i, &state);
Jan Glauber779e6e12008-07-17 17:16:48 +020067 switch (state) {
68 case SLSB_P_INPUT_NOT_INIT:
69 case SLSB_P_OUTPUT_NOT_INIT:
70 seq_printf(m, "N");
71 break;
72 case SLSB_P_INPUT_PRIMED:
73 case SLSB_CU_OUTPUT_PRIMED:
74 seq_printf(m, "+");
75 break;
76 case SLSB_P_INPUT_ACK:
77 seq_printf(m, "A");
78 break;
79 case SLSB_P_INPUT_ERROR:
80 case SLSB_P_OUTPUT_ERROR:
81 seq_printf(m, "x");
82 break;
83 case SLSB_CU_INPUT_EMPTY:
84 case SLSB_P_OUTPUT_EMPTY:
85 seq_printf(m, "-");
86 break;
87 case SLSB_P_INPUT_HALTED:
88 case SLSB_P_OUTPUT_HALTED:
89 seq_printf(m, ".");
90 break;
91 default:
92 seq_printf(m, "?");
93 }
94 if (i == 63)
95 seq_printf(m, "\n");
96 }
97 seq_printf(m, "\n");
Jan Glauber50f769d2008-12-25 13:38:47 +010098 seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n");
Jan Glauberd3072972010-02-26 22:37:36 +010099
100 seq_printf(m, "\nSBAL statistics:");
101 if (!q->irq_ptr->perf_stat_enabled) {
102 seq_printf(m, " disabled\n");
103 return 0;
104 }
105
106 seq_printf(m, "\n1 2.. 4.. 8.. "
107 "16.. 32.. 64.. 127\n");
108 for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
109 seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
110 seq_printf(m, "\nError NOP Total\n%-10u %-10u %-10u\n\n",
111 q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
112 q->q_stats.nr_sbal_total);
Jan Glauber779e6e12008-07-17 17:16:48 +0200113 return 0;
114}
115
116static ssize_t qstat_seq_write(struct file *file, const char __user *buf,
117 size_t count, loff_t *off)
118{
119 struct seq_file *seq = file->private_data;
120 struct qdio_q *q = seq->private;
121
122 if (!q)
123 return 0;
Jan Glauber779e6e12008-07-17 17:16:48 +0200124 if (q->is_input_q)
125 xchg(q->irq_ptr->dsci, 1);
126 local_bh_disable();
127 tasklet_schedule(&q->tasklet);
128 local_bh_enable();
129 return count;
130}
131
132static int qstat_seq_open(struct inode *inode, struct file *filp)
133{
134 return single_open(filp, qstat_show,
135 filp->f_path.dentry->d_inode->i_private);
136}
137
Alexey Dobriyan828c0952009-10-01 15:43:56 -0700138static const struct file_operations debugfs_fops = {
Jan Glauber779e6e12008-07-17 17:16:48 +0200139 .owner = THIS_MODULE,
140 .open = qstat_seq_open,
141 .read = seq_read,
142 .write = qstat_seq_write,
143 .llseek = seq_lseek,
144 .release = single_release,
145};
146
Jan Glauber6486cda2010-01-04 09:05:42 +0100147static char *qperf_names[] = {
148 "Assumed adapter interrupts",
149 "QDIO interrupts",
150 "Requested PCIs",
151 "Inbound tasklet runs",
152 "Inbound tasklet resched",
153 "Inbound tasklet resched2",
154 "Outbound tasklet runs",
155 "SIGA read",
156 "SIGA write",
157 "SIGA sync",
158 "Inbound calls",
159 "Inbound handler",
160 "Inbound stop_polling",
161 "Inbound queue full",
162 "Outbound calls",
163 "Outbound handler",
164 "Outbound fast_requeue",
165 "Outbound target_full",
166 "QEBSM eqbs",
167 "QEBSM eqbs partial",
168 "QEBSM sqbs",
169 "QEBSM sqbs partial"
170};
171
172static int qperf_show(struct seq_file *m, void *v)
173{
174 struct qdio_irq *irq_ptr = m->private;
175 unsigned int *stat;
176 int i;
177
178 if (!irq_ptr)
179 return 0;
180 if (!irq_ptr->perf_stat_enabled) {
181 seq_printf(m, "disabled\n");
182 return 0;
183 }
184 stat = (unsigned int *)&irq_ptr->perf_stat;
185
186 for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
187 seq_printf(m, "%26s:\t%u\n",
188 qperf_names[i], *(stat + i));
189 return 0;
190}
191
192static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
193 size_t count, loff_t *off)
194{
195 struct seq_file *seq = file->private_data;
196 struct qdio_irq *irq_ptr = seq->private;
Jan Glauberd3072972010-02-26 22:37:36 +0100197 struct qdio_q *q;
Jan Glauber6486cda2010-01-04 09:05:42 +0100198 unsigned long val;
199 char buf[8];
Jan Glauberd3072972010-02-26 22:37:36 +0100200 int ret, i;
Jan Glauber6486cda2010-01-04 09:05:42 +0100201
202 if (!irq_ptr)
203 return 0;
204 if (count >= sizeof(buf))
205 return -EINVAL;
206 if (copy_from_user(&buf, ubuf, count))
207 return -EFAULT;
208 buf[count] = 0;
209
210 ret = strict_strtoul(buf, 10, &val);
211 if (ret < 0)
212 return ret;
213
214 switch (val) {
215 case 0:
216 irq_ptr->perf_stat_enabled = 0;
217 memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
Jan Glauberd3072972010-02-26 22:37:36 +0100218 for_each_input_queue(irq_ptr, q, i)
219 memset(&q->q_stats, 0, sizeof(q->q_stats));
220 for_each_output_queue(irq_ptr, q, i)
221 memset(&q->q_stats, 0, sizeof(q->q_stats));
Jan Glauber6486cda2010-01-04 09:05:42 +0100222 break;
223 case 1:
224 irq_ptr->perf_stat_enabled = 1;
225 break;
226 }
227 return count;
228}
229
230static int qperf_seq_open(struct inode *inode, struct file *filp)
231{
232 return single_open(filp, qperf_show,
233 filp->f_path.dentry->d_inode->i_private);
234}
235
236static struct file_operations debugfs_perf_fops = {
237 .owner = THIS_MODULE,
238 .open = qperf_seq_open,
239 .read = seq_read,
240 .write = qperf_seq_write,
241 .llseek = seq_lseek,
242 .release = single_release,
243};
Jan Glauber779e6e12008-07-17 17:16:48 +0200244static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
245{
Jan Glauber2c780912008-10-28 11:10:14 +0100246 char name[QDIO_DEBUGFS_NAME_LEN];
Jan Glauber779e6e12008-07-17 17:16:48 +0200247
Jan Glauber3f09bb82009-09-11 10:28:22 +0200248 snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
Jan Glauber2c780912008-10-28 11:10:14 +0100249 q->is_input_q ? "input" : "output",
250 q->nr);
Jan Glauber3f09bb82009-09-11 10:28:22 +0200251 q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
252 q->irq_ptr->debugfs_dev, q, &debugfs_fops);
253 if (IS_ERR(q->debugfs_q))
254 q->debugfs_q = NULL;
Jan Glauber779e6e12008-07-17 17:16:48 +0200255}
256
257void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
258{
259 struct qdio_q *q;
260 int i;
261
Jan Glauber3f09bb82009-09-11 10:28:22 +0200262 irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
263 debugfs_root);
264 if (IS_ERR(irq_ptr->debugfs_dev))
265 irq_ptr->debugfs_dev = NULL;
Jan Glauber6486cda2010-01-04 09:05:42 +0100266
267 irq_ptr->debugfs_perf = debugfs_create_file("statistics",
268 S_IFREG | S_IRUGO | S_IWUSR,
269 irq_ptr->debugfs_dev, irq_ptr,
270 &debugfs_perf_fops);
271 if (IS_ERR(irq_ptr->debugfs_perf))
272 irq_ptr->debugfs_perf = NULL;
273
Jan Glauber779e6e12008-07-17 17:16:48 +0200274 for_each_input_queue(irq_ptr, q, i)
275 setup_debugfs_entry(q, cdev);
276 for_each_output_queue(irq_ptr, q, i)
277 setup_debugfs_entry(q, cdev);
Jan Glauber779e6e12008-07-17 17:16:48 +0200278}
279
280void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
281{
282 struct qdio_q *q;
283 int i;
284
Jan Glauber779e6e12008-07-17 17:16:48 +0200285 for_each_input_queue(irq_ptr, q, i)
Jan Glauber3f09bb82009-09-11 10:28:22 +0200286 debugfs_remove(q->debugfs_q);
Jan Glauber779e6e12008-07-17 17:16:48 +0200287 for_each_output_queue(irq_ptr, q, i)
Jan Glauber3f09bb82009-09-11 10:28:22 +0200288 debugfs_remove(q->debugfs_q);
Jan Glauber6486cda2010-01-04 09:05:42 +0100289 debugfs_remove(irq_ptr->debugfs_perf);
Jan Glauber3f09bb82009-09-11 10:28:22 +0200290 debugfs_remove(irq_ptr->debugfs_dev);
Jan Glauber779e6e12008-07-17 17:16:48 +0200291}
292
293int __init qdio_debug_init(void)
294{
Jan Glauber3f09bb82009-09-11 10:28:22 +0200295 debugfs_root = debugfs_create_dir("qdio", NULL);
Jan Glauber22f99342008-12-25 13:38:46 +0100296
297 qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
298 debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
299 debug_set_level(qdio_dbf_setup, DBF_INFO);
300 DBF_EVENT("dbf created\n");
301
302 qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
303 debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
304 debug_set_level(qdio_dbf_error, DBF_INFO);
305 DBF_ERROR("dbf created\n");
306 return 0;
Jan Glauber779e6e12008-07-17 17:16:48 +0200307}
308
309void qdio_debug_exit(void)
310{
311 debugfs_remove(debugfs_root);
Jan Glauber22f99342008-12-25 13:38:46 +0100312 if (qdio_dbf_setup)
313 debug_unregister(qdio_dbf_setup);
314 if (qdio_dbf_error)
315 debug_unregister(qdio_dbf_error);
Jan Glauber779e6e12008-07-17 17:16:48 +0200316}