blob: 0e615cb912d0eb0a90a2d510b5814d3586b06297 [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;
79 case SLSB_P_INPUT_PRIMED:
80 case SLSB_CU_OUTPUT_PRIMED:
81 seq_printf(m, "+");
82 break;
83 case SLSB_P_INPUT_ACK:
84 seq_printf(m, "A");
85 break;
86 case SLSB_P_INPUT_ERROR:
87 case SLSB_P_OUTPUT_ERROR:
88 seq_printf(m, "x");
89 break;
90 case SLSB_CU_INPUT_EMPTY:
91 case SLSB_P_OUTPUT_EMPTY:
92 seq_printf(m, "-");
93 break;
94 case SLSB_P_INPUT_HALTED:
95 case SLSB_P_OUTPUT_HALTED:
96 seq_printf(m, ".");
97 break;
98 default:
99 seq_printf(m, "?");
100 }
101 if (i == 63)
102 seq_printf(m, "\n");
103 }
104 seq_printf(m, "\n");
Jan Glauber50f769d2008-12-25 13:38:47 +0100105 seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n");
Jan Glauberd3072972010-02-26 22:37:36 +0100106
107 seq_printf(m, "\nSBAL statistics:");
108 if (!q->irq_ptr->perf_stat_enabled) {
109 seq_printf(m, " disabled\n");
110 return 0;
111 }
112
113 seq_printf(m, "\n1 2.. 4.. 8.. "
114 "16.. 32.. 64.. 127\n");
115 for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
116 seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
117 seq_printf(m, "\nError NOP Total\n%-10u %-10u %-10u\n\n",
118 q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
119 q->q_stats.nr_sbal_total);
Jan Glauber779e6e12008-07-17 17:16:48 +0200120 return 0;
121}
122
Jan Glauber779e6e12008-07-17 17:16:48 +0200123static int qstat_seq_open(struct inode *inode, struct file *filp)
124{
125 return single_open(filp, qstat_show,
126 filp->f_path.dentry->d_inode->i_private);
127}
128
Alexey Dobriyan828c0952009-10-01 15:43:56 -0700129static const struct file_operations debugfs_fops = {
Jan Glauber779e6e12008-07-17 17:16:48 +0200130 .owner = THIS_MODULE,
131 .open = qstat_seq_open,
132 .read = seq_read,
Jan Glauber779e6e12008-07-17 17:16:48 +0200133 .llseek = seq_lseek,
134 .release = single_release,
135};
136
Jan Glauber6486cda2010-01-04 09:05:42 +0100137static char *qperf_names[] = {
138 "Assumed adapter interrupts",
139 "QDIO interrupts",
140 "Requested PCIs",
141 "Inbound tasklet runs",
142 "Inbound tasklet resched",
143 "Inbound tasklet resched2",
144 "Outbound tasklet runs",
145 "SIGA read",
146 "SIGA write",
147 "SIGA sync",
148 "Inbound calls",
149 "Inbound handler",
150 "Inbound stop_polling",
151 "Inbound queue full",
152 "Outbound calls",
153 "Outbound handler",
Jan Glauber01958432011-01-05 12:47:51 +0100154 "Outbound queue full",
Jan Glauber6486cda2010-01-04 09:05:42 +0100155 "Outbound fast_requeue",
156 "Outbound target_full",
157 "QEBSM eqbs",
158 "QEBSM eqbs partial",
159 "QEBSM sqbs",
Jan Glauberd36deae2010-09-07 21:14:39 +0000160 "QEBSM sqbs partial",
161 "Discarded interrupts"
Jan Glauber6486cda2010-01-04 09:05:42 +0100162};
163
164static int qperf_show(struct seq_file *m, void *v)
165{
166 struct qdio_irq *irq_ptr = m->private;
167 unsigned int *stat;
168 int i;
169
170 if (!irq_ptr)
171 return 0;
172 if (!irq_ptr->perf_stat_enabled) {
173 seq_printf(m, "disabled\n");
174 return 0;
175 }
176 stat = (unsigned int *)&irq_ptr->perf_stat;
177
178 for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
179 seq_printf(m, "%26s:\t%u\n",
180 qperf_names[i], *(stat + i));
181 return 0;
182}
183
184static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
185 size_t count, loff_t *off)
186{
187 struct seq_file *seq = file->private_data;
188 struct qdio_irq *irq_ptr = seq->private;
Jan Glauberd3072972010-02-26 22:37:36 +0100189 struct qdio_q *q;
Jan Glauber6486cda2010-01-04 09:05:42 +0100190 unsigned long val;
Jan Glauberd3072972010-02-26 22:37:36 +0100191 int ret, i;
Jan Glauber6486cda2010-01-04 09:05:42 +0100192
193 if (!irq_ptr)
194 return 0;
Jan Glauber6486cda2010-01-04 09:05:42 +0100195
Peter Hueweaf6df872011-08-03 16:44:30 +0200196 ret = kstrtoul_from_user(ubuf, count, 10, &val);
197 if (ret)
Jan Glauber6486cda2010-01-04 09:05:42 +0100198 return ret;
199
200 switch (val) {
201 case 0:
202 irq_ptr->perf_stat_enabled = 0;
203 memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
Jan Glauberd3072972010-02-26 22:37:36 +0100204 for_each_input_queue(irq_ptr, q, i)
205 memset(&q->q_stats, 0, sizeof(q->q_stats));
206 for_each_output_queue(irq_ptr, q, i)
207 memset(&q->q_stats, 0, sizeof(q->q_stats));
Jan Glauber6486cda2010-01-04 09:05:42 +0100208 break;
209 case 1:
210 irq_ptr->perf_stat_enabled = 1;
211 break;
212 }
213 return count;
214}
215
216static int qperf_seq_open(struct inode *inode, struct file *filp)
217{
218 return single_open(filp, qperf_show,
219 filp->f_path.dentry->d_inode->i_private);
220}
221
222static struct file_operations debugfs_perf_fops = {
223 .owner = THIS_MODULE,
224 .open = qperf_seq_open,
225 .read = seq_read,
226 .write = qperf_seq_write,
227 .llseek = seq_lseek,
228 .release = single_release,
229};
Jan Glauber779e6e12008-07-17 17:16:48 +0200230static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
231{
Jan Glauber2c780912008-10-28 11:10:14 +0100232 char name[QDIO_DEBUGFS_NAME_LEN];
Jan Glauber779e6e12008-07-17 17:16:48 +0200233
Jan Glauber3f09bb82009-09-11 10:28:22 +0200234 snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
Jan Glauber2c780912008-10-28 11:10:14 +0100235 q->is_input_q ? "input" : "output",
236 q->nr);
Jan Glauber3f09bb82009-09-11 10:28:22 +0200237 q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
238 q->irq_ptr->debugfs_dev, q, &debugfs_fops);
239 if (IS_ERR(q->debugfs_q))
240 q->debugfs_q = NULL;
Jan Glauber779e6e12008-07-17 17:16:48 +0200241}
242
243void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
244{
245 struct qdio_q *q;
246 int i;
247
Jan Glauber3f09bb82009-09-11 10:28:22 +0200248 irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
249 debugfs_root);
250 if (IS_ERR(irq_ptr->debugfs_dev))
251 irq_ptr->debugfs_dev = NULL;
Jan Glauber6486cda2010-01-04 09:05:42 +0100252
253 irq_ptr->debugfs_perf = debugfs_create_file("statistics",
254 S_IFREG | S_IRUGO | S_IWUSR,
255 irq_ptr->debugfs_dev, irq_ptr,
256 &debugfs_perf_fops);
257 if (IS_ERR(irq_ptr->debugfs_perf))
258 irq_ptr->debugfs_perf = NULL;
259
Jan Glauber779e6e12008-07-17 17:16:48 +0200260 for_each_input_queue(irq_ptr, q, i)
261 setup_debugfs_entry(q, cdev);
262 for_each_output_queue(irq_ptr, q, i)
263 setup_debugfs_entry(q, cdev);
Jan Glauber779e6e12008-07-17 17:16:48 +0200264}
265
266void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
267{
268 struct qdio_q *q;
269 int i;
270
Jan Glauber779e6e12008-07-17 17:16:48 +0200271 for_each_input_queue(irq_ptr, q, i)
Jan Glauber3f09bb82009-09-11 10:28:22 +0200272 debugfs_remove(q->debugfs_q);
Jan Glauber779e6e12008-07-17 17:16:48 +0200273 for_each_output_queue(irq_ptr, q, i)
Jan Glauber3f09bb82009-09-11 10:28:22 +0200274 debugfs_remove(q->debugfs_q);
Jan Glauber6486cda2010-01-04 09:05:42 +0100275 debugfs_remove(irq_ptr->debugfs_perf);
Jan Glauber3f09bb82009-09-11 10:28:22 +0200276 debugfs_remove(irq_ptr->debugfs_dev);
Jan Glauber779e6e12008-07-17 17:16:48 +0200277}
278
279int __init qdio_debug_init(void)
280{
Jan Glauber3f09bb82009-09-11 10:28:22 +0200281 debugfs_root = debugfs_create_dir("qdio", NULL);
Jan Glauber22f99342008-12-25 13:38:46 +0100282
283 qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
284 debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
285 debug_set_level(qdio_dbf_setup, DBF_INFO);
286 DBF_EVENT("dbf created\n");
287
288 qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
289 debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
290 debug_set_level(qdio_dbf_error, DBF_INFO);
291 DBF_ERROR("dbf created\n");
292 return 0;
Jan Glauber779e6e12008-07-17 17:16:48 +0200293}
294
295void qdio_debug_exit(void)
296{
297 debugfs_remove(debugfs_root);
Jan Glauber22f99342008-12-25 13:38:46 +0100298 if (qdio_dbf_setup)
299 debug_unregister(qdio_dbf_setup);
300 if (qdio_dbf_error)
301 debug_unregister(qdio_dbf_error);
Jan Glauber779e6e12008-07-17 17:16:48 +0200302}