blob: 29021f4e96b6409bc5dffc12b9717871a652bb49 [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>
Heiko Carstens3a4c5d52011-07-30 09:25:15 +020010#include <linux/uaccess.h>
11#include <linux/export.h>
Jan Glauber779e6e12008-07-17 17:16:48 +020012#include <asm/debug.h>
13#include "qdio_debug.h"
14#include "qdio.h"
15
16debug_info_t *qdio_dbf_setup;
Jan Glauber22f99342008-12-25 13:38:46 +010017debug_info_t *qdio_dbf_error;
Jan Glauber779e6e12008-07-17 17:16:48 +020018
19static struct dentry *debugfs_root;
Jan Glauber3f09bb82009-09-11 10:28:22 +020020#define QDIO_DEBUGFS_NAME_LEN 10
Jan Glauber779e6e12008-07-17 17:16:48 +020021
Jan Glauber22f99342008-12-25 13:38:46 +010022void qdio_allocate_dbf(struct qdio_initialize *init_data,
23 struct qdio_irq *irq_ptr)
Jan Glauber779e6e12008-07-17 17:16:48 +020024{
Jan Glauber22f99342008-12-25 13:38:46 +010025 char text[20];
Jan Glauber779e6e12008-07-17 17:16:48 +020026
Jan Glauber22f99342008-12-25 13:38:46 +010027 DBF_EVENT("qfmt:%1d", init_data->q_format);
28 DBF_HEX(init_data->adapter_name, 8);
29 DBF_EVENT("qpff%4x", init_data->qib_param_field_format);
30 DBF_HEX(&init_data->qib_param_field, sizeof(void *));
31 DBF_HEX(&init_data->input_slib_elements, sizeof(void *));
32 DBF_HEX(&init_data->output_slib_elements, sizeof(void *));
33 DBF_EVENT("niq:%1d noq:%1d", init_data->no_input_qs,
34 init_data->no_output_qs);
35 DBF_HEX(&init_data->input_handler, sizeof(void *));
36 DBF_HEX(&init_data->output_handler, sizeof(void *));
37 DBF_HEX(&init_data->int_parm, sizeof(long));
Jan Glauber22f99342008-12-25 13:38:46 +010038 DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *));
39 DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *));
40 DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr);
Jan Glauber779e6e12008-07-17 17:16:48 +020041
Jan Glauber22f99342008-12-25 13:38:46 +010042 /* allocate trace view for the interface */
43 snprintf(text, 20, "qdio_%s", dev_name(&init_data->cdev->dev));
44 irq_ptr->debug_area = debug_register(text, 2, 1, 16);
45 debug_register_view(irq_ptr->debug_area, &debug_hex_ascii_view);
46 debug_set_level(irq_ptr->debug_area, DBF_WARN);
47 DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created");
Jan Glauber779e6e12008-07-17 17:16:48 +020048}
49
50static int qstat_show(struct seq_file *m, void *v)
51{
52 unsigned char state;
53 struct qdio_q *q = m->private;
54 int i;
55
56 if (!q)
57 return 0;
58
Jan Glaubera2b86012011-10-30 15:17:05 +010059 seq_printf(m, "Timestamp: %Lx Last AI: %Lx\n",
60 q->timestamp, last_ai_time);
61 seq_printf(m, "nr_used: %d ftc: %d last_move: %d\n",
62 atomic_read(&q->nr_buf_used),
Jan Glauberd36deae2010-09-07 21:14:39 +000063 q->first_to_check, q->last_move);
64 if (q->is_input_q) {
65 seq_printf(m, "polling: %d ack start: %d ack count: %d\n",
66 q->u.in.polling, q->u.in.ack_start,
67 q->u.in.ack_count);
Jan Glaubera2b86012011-10-30 15:17:05 +010068 seq_printf(m, "DSCI: %d IRQs disabled: %u\n",
69 *(u32 *)q->irq_ptr->dsci,
Jan Glauberd36deae2010-09-07 21:14:39 +000070 test_bit(QDIO_QUEUE_IRQS_DISABLED,
71 &q->u.in.queue_irq_state));
72 }
Jan Glauberd3072972010-02-26 22:37:36 +010073 seq_printf(m, "SBAL states:\n");
Jan Glauber50f769d2008-12-25 13:38:47 +010074 seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n");
Jan Glauber779e6e12008-07-17 17:16:48 +020075
Jan Glauber779e6e12008-07-17 17:16:48 +020076 for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
Jan Glauber60b5df22009-06-22 12:08:10 +020077 debug_get_buf_state(q, i, &state);
Jan Glauber779e6e12008-07-17 17:16:48 +020078 switch (state) {
79 case SLSB_P_INPUT_NOT_INIT:
80 case SLSB_P_OUTPUT_NOT_INIT:
81 seq_printf(m, "N");
82 break;
frank.blaschka@de.ibm.com104ea552011-08-08 01:33:55 +000083 case SLSB_P_OUTPUT_PENDING:
84 seq_printf(m, "P");
85 break;
Jan Glauber779e6e12008-07-17 17:16:48 +020086 case SLSB_P_INPUT_PRIMED:
87 case SLSB_CU_OUTPUT_PRIMED:
88 seq_printf(m, "+");
89 break;
90 case SLSB_P_INPUT_ACK:
91 seq_printf(m, "A");
92 break;
93 case SLSB_P_INPUT_ERROR:
94 case SLSB_P_OUTPUT_ERROR:
95 seq_printf(m, "x");
96 break;
97 case SLSB_CU_INPUT_EMPTY:
98 case SLSB_P_OUTPUT_EMPTY:
99 seq_printf(m, "-");
100 break;
101 case SLSB_P_INPUT_HALTED:
102 case SLSB_P_OUTPUT_HALTED:
103 seq_printf(m, ".");
104 break;
105 default:
106 seq_printf(m, "?");
107 }
108 if (i == 63)
109 seq_printf(m, "\n");
110 }
111 seq_printf(m, "\n");
Jan Glauber50f769d2008-12-25 13:38:47 +0100112 seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n");
Jan Glauberd3072972010-02-26 22:37:36 +0100113
114 seq_printf(m, "\nSBAL statistics:");
115 if (!q->irq_ptr->perf_stat_enabled) {
116 seq_printf(m, " disabled\n");
117 return 0;
118 }
119
120 seq_printf(m, "\n1 2.. 4.. 8.. "
121 "16.. 32.. 64.. 127\n");
122 for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
123 seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
124 seq_printf(m, "\nError NOP Total\n%-10u %-10u %-10u\n\n",
125 q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
126 q->q_stats.nr_sbal_total);
Jan Glauber779e6e12008-07-17 17:16:48 +0200127 return 0;
128}
129
Jan Glauber779e6e12008-07-17 17:16:48 +0200130static int qstat_seq_open(struct inode *inode, struct file *filp)
131{
132 return single_open(filp, qstat_show,
133 filp->f_path.dentry->d_inode->i_private);
134}
135
Alexey Dobriyan828c0952009-10-01 15:43:56 -0700136static const struct file_operations debugfs_fops = {
Jan Glauber779e6e12008-07-17 17:16:48 +0200137 .owner = THIS_MODULE,
138 .open = qstat_seq_open,
139 .read = seq_read,
Jan Glauber779e6e12008-07-17 17:16:48 +0200140 .llseek = seq_lseek,
141 .release = single_release,
142};
143
Jan Glauber6486cda2010-01-04 09:05:42 +0100144static char *qperf_names[] = {
145 "Assumed adapter interrupts",
146 "QDIO interrupts",
147 "Requested PCIs",
148 "Inbound tasklet runs",
149 "Inbound tasklet resched",
150 "Inbound tasklet resched2",
151 "Outbound tasklet runs",
152 "SIGA read",
153 "SIGA write",
154 "SIGA sync",
155 "Inbound calls",
156 "Inbound handler",
157 "Inbound stop_polling",
158 "Inbound queue full",
159 "Outbound calls",
160 "Outbound handler",
Jan Glauber01958432011-01-05 12:47:51 +0100161 "Outbound queue full",
Jan Glauber6486cda2010-01-04 09:05:42 +0100162 "Outbound fast_requeue",
163 "Outbound target_full",
164 "QEBSM eqbs",
165 "QEBSM eqbs partial",
166 "QEBSM sqbs",
Jan Glauberd36deae2010-09-07 21:14:39 +0000167 "QEBSM sqbs partial",
168 "Discarded interrupts"
Jan Glauber6486cda2010-01-04 09:05:42 +0100169};
170
171static int qperf_show(struct seq_file *m, void *v)
172{
173 struct qdio_irq *irq_ptr = m->private;
174 unsigned int *stat;
175 int i;
176
177 if (!irq_ptr)
178 return 0;
179 if (!irq_ptr->perf_stat_enabled) {
180 seq_printf(m, "disabled\n");
181 return 0;
182 }
183 stat = (unsigned int *)&irq_ptr->perf_stat;
184
185 for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
186 seq_printf(m, "%26s:\t%u\n",
187 qperf_names[i], *(stat + i));
188 return 0;
189}
190
191static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
192 size_t count, loff_t *off)
193{
194 struct seq_file *seq = file->private_data;
195 struct qdio_irq *irq_ptr = seq->private;
Jan Glauberd3072972010-02-26 22:37:36 +0100196 struct qdio_q *q;
Jan Glauber6486cda2010-01-04 09:05:42 +0100197 unsigned long val;
Jan Glauberd3072972010-02-26 22:37:36 +0100198 int ret, i;
Jan Glauber6486cda2010-01-04 09:05:42 +0100199
200 if (!irq_ptr)
201 return 0;
Jan Glauber6486cda2010-01-04 09:05:42 +0100202
Peter Hueweaf6df872011-08-03 16:44:30 +0200203 ret = kstrtoul_from_user(ubuf, count, 10, &val);
204 if (ret)
Jan Glauber6486cda2010-01-04 09:05:42 +0100205 return ret;
206
207 switch (val) {
208 case 0:
209 irq_ptr->perf_stat_enabled = 0;
210 memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
Jan Glauberd3072972010-02-26 22:37:36 +0100211 for_each_input_queue(irq_ptr, q, i)
212 memset(&q->q_stats, 0, sizeof(q->q_stats));
213 for_each_output_queue(irq_ptr, q, i)
214 memset(&q->q_stats, 0, sizeof(q->q_stats));
Jan Glauber6486cda2010-01-04 09:05:42 +0100215 break;
216 case 1:
217 irq_ptr->perf_stat_enabled = 1;
218 break;
219 }
220 return count;
221}
222
223static int qperf_seq_open(struct inode *inode, struct file *filp)
224{
225 return single_open(filp, qperf_show,
226 filp->f_path.dentry->d_inode->i_private);
227}
228
229static struct file_operations debugfs_perf_fops = {
230 .owner = THIS_MODULE,
231 .open = qperf_seq_open,
232 .read = seq_read,
233 .write = qperf_seq_write,
234 .llseek = seq_lseek,
235 .release = single_release,
236};
Jan Glauber779e6e12008-07-17 17:16:48 +0200237static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
238{
Jan Glauber2c780912008-10-28 11:10:14 +0100239 char name[QDIO_DEBUGFS_NAME_LEN];
Jan Glauber779e6e12008-07-17 17:16:48 +0200240
Jan Glauber3f09bb82009-09-11 10:28:22 +0200241 snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
Jan Glauber2c780912008-10-28 11:10:14 +0100242 q->is_input_q ? "input" : "output",
243 q->nr);
Jan Glauber3f09bb82009-09-11 10:28:22 +0200244 q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
245 q->irq_ptr->debugfs_dev, q, &debugfs_fops);
246 if (IS_ERR(q->debugfs_q))
247 q->debugfs_q = NULL;
Jan Glauber779e6e12008-07-17 17:16:48 +0200248}
249
250void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
251{
252 struct qdio_q *q;
253 int i;
254
Jan Glauber3f09bb82009-09-11 10:28:22 +0200255 irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
256 debugfs_root);
257 if (IS_ERR(irq_ptr->debugfs_dev))
258 irq_ptr->debugfs_dev = NULL;
Jan Glauber6486cda2010-01-04 09:05:42 +0100259
260 irq_ptr->debugfs_perf = debugfs_create_file("statistics",
261 S_IFREG | S_IRUGO | S_IWUSR,
262 irq_ptr->debugfs_dev, irq_ptr,
263 &debugfs_perf_fops);
264 if (IS_ERR(irq_ptr->debugfs_perf))
265 irq_ptr->debugfs_perf = NULL;
266
Jan Glauber779e6e12008-07-17 17:16:48 +0200267 for_each_input_queue(irq_ptr, q, i)
268 setup_debugfs_entry(q, cdev);
269 for_each_output_queue(irq_ptr, q, i)
270 setup_debugfs_entry(q, cdev);
Jan Glauber779e6e12008-07-17 17:16:48 +0200271}
272
273void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
274{
275 struct qdio_q *q;
276 int i;
277
Jan Glauber779e6e12008-07-17 17:16:48 +0200278 for_each_input_queue(irq_ptr, q, i)
Jan Glauber3f09bb82009-09-11 10:28:22 +0200279 debugfs_remove(q->debugfs_q);
Jan Glauber779e6e12008-07-17 17:16:48 +0200280 for_each_output_queue(irq_ptr, q, i)
Jan Glauber3f09bb82009-09-11 10:28:22 +0200281 debugfs_remove(q->debugfs_q);
Jan Glauber6486cda2010-01-04 09:05:42 +0100282 debugfs_remove(irq_ptr->debugfs_perf);
Jan Glauber3f09bb82009-09-11 10:28:22 +0200283 debugfs_remove(irq_ptr->debugfs_dev);
Jan Glauber779e6e12008-07-17 17:16:48 +0200284}
285
286int __init qdio_debug_init(void)
287{
Jan Glauber3f09bb82009-09-11 10:28:22 +0200288 debugfs_root = debugfs_create_dir("qdio", NULL);
Jan Glauber22f99342008-12-25 13:38:46 +0100289
290 qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
291 debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
292 debug_set_level(qdio_dbf_setup, DBF_INFO);
293 DBF_EVENT("dbf created\n");
294
295 qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
296 debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
297 debug_set_level(qdio_dbf_error, DBF_INFO);
298 DBF_ERROR("dbf created\n");
299 return 0;
Jan Glauber779e6e12008-07-17 17:16:48 +0200300}
301
302void qdio_debug_exit(void)
303{
304 debugfs_remove(debugfs_root);
Jan Glauber22f99342008-12-25 13:38:46 +0100305 if (qdio_dbf_setup)
306 debug_unregister(qdio_dbf_setup);
307 if (qdio_dbf_error)
308 debug_unregister(qdio_dbf_error);
Jan Glauber779e6e12008-07-17 17:16:48 +0200309}