blob: b6fc147f83d866107e7aa0d8b2b390f04e3d58e1 [file] [log] [blame]
Jan Glauber779e6e12008-07-17 17:16:48 +02001/*
Heiko Carstensa53c8fa2012-07-20 11:15:04 +02002 * Copyright IBM Corp. 2008, 2009
Jan Glauber779e6e12008-07-17 17:16:48 +02003 *
4 * Author: Jan Glauber (jang@linux.vnet.ibm.com)
5 */
Jan Glauber779e6e12008-07-17 17:16:48 +02006#include <linux/seq_file.h>
7#include <linux/debugfs.h>
Heiko Carstens3a4c5d52011-07-30 09:25:15 +02008#include <linux/uaccess.h>
9#include <linux/export.h>
Stefan Raspl613c4e02014-06-12 14:24:45 +020010#include <linux/slab.h>
Jan Glauber779e6e12008-07-17 17:16:48 +020011#include <asm/debug.h>
12#include "qdio_debug.h"
13#include "qdio.h"
14
15debug_info_t *qdio_dbf_setup;
Jan Glauber22f99342008-12-25 13:38:46 +010016debug_info_t *qdio_dbf_error;
Jan Glauber779e6e12008-07-17 17:16:48 +020017
18static struct dentry *debugfs_root;
Jan Glauber3f09bb82009-09-11 10:28:22 +020019#define QDIO_DEBUGFS_NAME_LEN 10
Stefan Raspl613c4e02014-06-12 14:24:45 +020020#define QDIO_DBF_NAME_LEN 20
Jan Glauber779e6e12008-07-17 17:16:48 +020021
Stefan Raspl613c4e02014-06-12 14:24:45 +020022struct qdio_dbf_entry {
23 char dbf_name[QDIO_DBF_NAME_LEN];
24 debug_info_t *dbf_info;
25 struct list_head dbf_list;
26};
27
28static LIST_HEAD(qdio_dbf_list);
29static DEFINE_MUTEX(qdio_dbf_list_mutex);
30
31static debug_info_t *qdio_get_dbf_entry(char *name)
32{
33 struct qdio_dbf_entry *entry;
34 debug_info_t *rc = NULL;
35
36 mutex_lock(&qdio_dbf_list_mutex);
37 list_for_each_entry(entry, &qdio_dbf_list, dbf_list) {
38 if (strcmp(entry->dbf_name, name) == 0) {
39 rc = entry->dbf_info;
40 break;
41 }
42 }
43 mutex_unlock(&qdio_dbf_list_mutex);
44 return rc;
45}
46
47static void qdio_clear_dbf_list(void)
48{
49 struct qdio_dbf_entry *entry, *tmp;
50
51 mutex_lock(&qdio_dbf_list_mutex);
52 list_for_each_entry_safe(entry, tmp, &qdio_dbf_list, dbf_list) {
53 list_del(&entry->dbf_list);
54 debug_unregister(entry->dbf_info);
55 kfree(entry);
56 }
57 mutex_unlock(&qdio_dbf_list_mutex);
58}
59
60int qdio_allocate_dbf(struct qdio_initialize *init_data,
Jan Glauber22f99342008-12-25 13:38:46 +010061 struct qdio_irq *irq_ptr)
Jan Glauber779e6e12008-07-17 17:16:48 +020062{
Stefan Raspl613c4e02014-06-12 14:24:45 +020063 char text[QDIO_DBF_NAME_LEN];
64 struct qdio_dbf_entry *new_entry;
Jan Glauber779e6e12008-07-17 17:16:48 +020065
Jan Glauber22f99342008-12-25 13:38:46 +010066 DBF_EVENT("qfmt:%1d", init_data->q_format);
67 DBF_HEX(init_data->adapter_name, 8);
68 DBF_EVENT("qpff%4x", init_data->qib_param_field_format);
69 DBF_HEX(&init_data->qib_param_field, sizeof(void *));
70 DBF_HEX(&init_data->input_slib_elements, sizeof(void *));
71 DBF_HEX(&init_data->output_slib_elements, sizeof(void *));
72 DBF_EVENT("niq:%1d noq:%1d", init_data->no_input_qs,
73 init_data->no_output_qs);
74 DBF_HEX(&init_data->input_handler, sizeof(void *));
75 DBF_HEX(&init_data->output_handler, sizeof(void *));
76 DBF_HEX(&init_data->int_parm, sizeof(long));
Jan Glauber22f99342008-12-25 13:38:46 +010077 DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *));
78 DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *));
79 DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr);
Jan Glauber779e6e12008-07-17 17:16:48 +020080
Jan Glauber22f99342008-12-25 13:38:46 +010081 /* allocate trace view for the interface */
Stefan Raspl613c4e02014-06-12 14:24:45 +020082 snprintf(text, QDIO_DBF_NAME_LEN, "qdio_%s",
83 dev_name(&init_data->cdev->dev));
84 irq_ptr->debug_area = qdio_get_dbf_entry(text);
85 if (irq_ptr->debug_area)
86 DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf reused");
87 else {
88 irq_ptr->debug_area = debug_register(text, 2, 1, 16);
89 if (!irq_ptr->debug_area)
90 return -ENOMEM;
91 if (debug_register_view(irq_ptr->debug_area,
92 &debug_hex_ascii_view)) {
93 debug_unregister(irq_ptr->debug_area);
94 return -ENOMEM;
95 }
96 debug_set_level(irq_ptr->debug_area, DBF_WARN);
97 DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created");
98 new_entry = kzalloc(sizeof(struct qdio_dbf_entry), GFP_KERNEL);
99 if (!new_entry) {
100 debug_unregister(irq_ptr->debug_area);
101 return -ENOMEM;
102 }
103 strlcpy(new_entry->dbf_name, text, QDIO_DBF_NAME_LEN);
104 new_entry->dbf_info = irq_ptr->debug_area;
105 mutex_lock(&qdio_dbf_list_mutex);
106 list_add(&new_entry->dbf_list, &qdio_dbf_list);
107 mutex_unlock(&qdio_dbf_list_mutex);
108 }
109 return 0;
Jan Glauber779e6e12008-07-17 17:16:48 +0200110}
111
112static int qstat_show(struct seq_file *m, void *v)
113{
114 unsigned char state;
115 struct qdio_q *q = m->private;
116 int i;
117
118 if (!q)
119 return 0;
120
Jan Glaubera2b86012011-10-30 15:17:05 +0100121 seq_printf(m, "Timestamp: %Lx Last AI: %Lx\n",
122 q->timestamp, last_ai_time);
123 seq_printf(m, "nr_used: %d ftc: %d last_move: %d\n",
124 atomic_read(&q->nr_buf_used),
Jan Glauberd36deae2010-09-07 21:14:39 +0000125 q->first_to_check, q->last_move);
126 if (q->is_input_q) {
127 seq_printf(m, "polling: %d ack start: %d ack count: %d\n",
128 q->u.in.polling, q->u.in.ack_start,
129 q->u.in.ack_count);
Jan Glaubera2b86012011-10-30 15:17:05 +0100130 seq_printf(m, "DSCI: %d IRQs disabled: %u\n",
131 *(u32 *)q->irq_ptr->dsci,
Jan Glauberd36deae2010-09-07 21:14:39 +0000132 test_bit(QDIO_QUEUE_IRQS_DISABLED,
133 &q->u.in.queue_irq_state));
134 }
Jan Glauberd3072972010-02-26 22:37:36 +0100135 seq_printf(m, "SBAL states:\n");
Jan Glauber50f769d2008-12-25 13:38:47 +0100136 seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n");
Jan Glauber779e6e12008-07-17 17:16:48 +0200137
Jan Glauber779e6e12008-07-17 17:16:48 +0200138 for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
Jan Glauber60b5df22009-06-22 12:08:10 +0200139 debug_get_buf_state(q, i, &state);
Jan Glauber779e6e12008-07-17 17:16:48 +0200140 switch (state) {
141 case SLSB_P_INPUT_NOT_INIT:
142 case SLSB_P_OUTPUT_NOT_INIT:
143 seq_printf(m, "N");
144 break;
frank.blaschka@de.ibm.com104ea552011-08-08 01:33:55 +0000145 case SLSB_P_OUTPUT_PENDING:
146 seq_printf(m, "P");
147 break;
Jan Glauber779e6e12008-07-17 17:16:48 +0200148 case SLSB_P_INPUT_PRIMED:
149 case SLSB_CU_OUTPUT_PRIMED:
150 seq_printf(m, "+");
151 break;
152 case SLSB_P_INPUT_ACK:
153 seq_printf(m, "A");
154 break;
155 case SLSB_P_INPUT_ERROR:
156 case SLSB_P_OUTPUT_ERROR:
157 seq_printf(m, "x");
158 break;
159 case SLSB_CU_INPUT_EMPTY:
160 case SLSB_P_OUTPUT_EMPTY:
161 seq_printf(m, "-");
162 break;
163 case SLSB_P_INPUT_HALTED:
164 case SLSB_P_OUTPUT_HALTED:
165 seq_printf(m, ".");
166 break;
167 default:
168 seq_printf(m, "?");
169 }
170 if (i == 63)
171 seq_printf(m, "\n");
172 }
173 seq_printf(m, "\n");
Jan Glauber50f769d2008-12-25 13:38:47 +0100174 seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n");
Jan Glauberd3072972010-02-26 22:37:36 +0100175
176 seq_printf(m, "\nSBAL statistics:");
177 if (!q->irq_ptr->perf_stat_enabled) {
178 seq_printf(m, " disabled\n");
179 return 0;
180 }
181
182 seq_printf(m, "\n1 2.. 4.. 8.. "
183 "16.. 32.. 64.. 127\n");
184 for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
185 seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
186 seq_printf(m, "\nError NOP Total\n%-10u %-10u %-10u\n\n",
187 q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
188 q->q_stats.nr_sbal_total);
Jan Glauber779e6e12008-07-17 17:16:48 +0200189 return 0;
190}
191
Jan Glauber779e6e12008-07-17 17:16:48 +0200192static int qstat_seq_open(struct inode *inode, struct file *filp)
193{
194 return single_open(filp, qstat_show,
Al Viro496ad9a2013-01-23 17:07:38 -0500195 file_inode(filp)->i_private);
Jan Glauber779e6e12008-07-17 17:16:48 +0200196}
197
Alexey Dobriyan828c0952009-10-01 15:43:56 -0700198static const struct file_operations debugfs_fops = {
Jan Glauber779e6e12008-07-17 17:16:48 +0200199 .owner = THIS_MODULE,
200 .open = qstat_seq_open,
201 .read = seq_read,
Jan Glauber779e6e12008-07-17 17:16:48 +0200202 .llseek = seq_lseek,
203 .release = single_release,
204};
205
Jan Glauber6486cda2010-01-04 09:05:42 +0100206static char *qperf_names[] = {
207 "Assumed adapter interrupts",
208 "QDIO interrupts",
209 "Requested PCIs",
210 "Inbound tasklet runs",
211 "Inbound tasklet resched",
212 "Inbound tasklet resched2",
213 "Outbound tasklet runs",
214 "SIGA read",
215 "SIGA write",
216 "SIGA sync",
217 "Inbound calls",
218 "Inbound handler",
219 "Inbound stop_polling",
220 "Inbound queue full",
221 "Outbound calls",
222 "Outbound handler",
Jan Glauber01958432011-01-05 12:47:51 +0100223 "Outbound queue full",
Jan Glauber6486cda2010-01-04 09:05:42 +0100224 "Outbound fast_requeue",
225 "Outbound target_full",
226 "QEBSM eqbs",
227 "QEBSM eqbs partial",
228 "QEBSM sqbs",
Jan Glauberd36deae2010-09-07 21:14:39 +0000229 "QEBSM sqbs partial",
230 "Discarded interrupts"
Jan Glauber6486cda2010-01-04 09:05:42 +0100231};
232
233static int qperf_show(struct seq_file *m, void *v)
234{
235 struct qdio_irq *irq_ptr = m->private;
236 unsigned int *stat;
237 int i;
238
239 if (!irq_ptr)
240 return 0;
241 if (!irq_ptr->perf_stat_enabled) {
242 seq_printf(m, "disabled\n");
243 return 0;
244 }
245 stat = (unsigned int *)&irq_ptr->perf_stat;
246
247 for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
248 seq_printf(m, "%26s:\t%u\n",
249 qperf_names[i], *(stat + i));
250 return 0;
251}
252
253static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
254 size_t count, loff_t *off)
255{
256 struct seq_file *seq = file->private_data;
257 struct qdio_irq *irq_ptr = seq->private;
Jan Glauberd3072972010-02-26 22:37:36 +0100258 struct qdio_q *q;
Jan Glauber6486cda2010-01-04 09:05:42 +0100259 unsigned long val;
Jan Glauberd3072972010-02-26 22:37:36 +0100260 int ret, i;
Jan Glauber6486cda2010-01-04 09:05:42 +0100261
262 if (!irq_ptr)
263 return 0;
Jan Glauber6486cda2010-01-04 09:05:42 +0100264
Peter Hueweaf6df872011-08-03 16:44:30 +0200265 ret = kstrtoul_from_user(ubuf, count, 10, &val);
266 if (ret)
Jan Glauber6486cda2010-01-04 09:05:42 +0100267 return ret;
268
269 switch (val) {
270 case 0:
271 irq_ptr->perf_stat_enabled = 0;
272 memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
Jan Glauberd3072972010-02-26 22:37:36 +0100273 for_each_input_queue(irq_ptr, q, i)
274 memset(&q->q_stats, 0, sizeof(q->q_stats));
275 for_each_output_queue(irq_ptr, q, i)
276 memset(&q->q_stats, 0, sizeof(q->q_stats));
Jan Glauber6486cda2010-01-04 09:05:42 +0100277 break;
278 case 1:
279 irq_ptr->perf_stat_enabled = 1;
280 break;
281 }
282 return count;
283}
284
285static int qperf_seq_open(struct inode *inode, struct file *filp)
286{
287 return single_open(filp, qperf_show,
Al Viro496ad9a2013-01-23 17:07:38 -0500288 file_inode(filp)->i_private);
Jan Glauber6486cda2010-01-04 09:05:42 +0100289}
290
Al Viro75ef9de2013-04-04 19:09:41 -0400291static const struct file_operations debugfs_perf_fops = {
Jan Glauber6486cda2010-01-04 09:05:42 +0100292 .owner = THIS_MODULE,
293 .open = qperf_seq_open,
294 .read = seq_read,
295 .write = qperf_seq_write,
296 .llseek = seq_lseek,
297 .release = single_release,
298};
Stefan Rasplaa2383f2013-02-26 13:08:34 +0100299
300static void setup_debugfs_entry(struct qdio_q *q)
Jan Glauber779e6e12008-07-17 17:16:48 +0200301{
Jan Glauber2c780912008-10-28 11:10:14 +0100302 char name[QDIO_DEBUGFS_NAME_LEN];
Jan Glauber779e6e12008-07-17 17:16:48 +0200303
Jan Glauber3f09bb82009-09-11 10:28:22 +0200304 snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
Jan Glauber2c780912008-10-28 11:10:14 +0100305 q->is_input_q ? "input" : "output",
306 q->nr);
Jan Glauber3f09bb82009-09-11 10:28:22 +0200307 q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
308 q->irq_ptr->debugfs_dev, q, &debugfs_fops);
309 if (IS_ERR(q->debugfs_q))
310 q->debugfs_q = NULL;
Jan Glauber779e6e12008-07-17 17:16:48 +0200311}
312
313void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
314{
315 struct qdio_q *q;
316 int i;
317
Jan Glauber3f09bb82009-09-11 10:28:22 +0200318 irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
319 debugfs_root);
320 if (IS_ERR(irq_ptr->debugfs_dev))
321 irq_ptr->debugfs_dev = NULL;
Jan Glauber6486cda2010-01-04 09:05:42 +0100322
323 irq_ptr->debugfs_perf = debugfs_create_file("statistics",
324 S_IFREG | S_IRUGO | S_IWUSR,
325 irq_ptr->debugfs_dev, irq_ptr,
326 &debugfs_perf_fops);
327 if (IS_ERR(irq_ptr->debugfs_perf))
328 irq_ptr->debugfs_perf = NULL;
329
Jan Glauber779e6e12008-07-17 17:16:48 +0200330 for_each_input_queue(irq_ptr, q, i)
Stefan Rasplaa2383f2013-02-26 13:08:34 +0100331 setup_debugfs_entry(q);
Jan Glauber779e6e12008-07-17 17:16:48 +0200332 for_each_output_queue(irq_ptr, q, i)
Stefan Rasplaa2383f2013-02-26 13:08:34 +0100333 setup_debugfs_entry(q);
Jan Glauber779e6e12008-07-17 17:16:48 +0200334}
335
Stefan Rasplaa2383f2013-02-26 13:08:34 +0100336void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr)
Jan Glauber779e6e12008-07-17 17:16:48 +0200337{
338 struct qdio_q *q;
339 int i;
340
Jan Glauber779e6e12008-07-17 17:16:48 +0200341 for_each_input_queue(irq_ptr, q, i)
Jan Glauber3f09bb82009-09-11 10:28:22 +0200342 debugfs_remove(q->debugfs_q);
Jan Glauber779e6e12008-07-17 17:16:48 +0200343 for_each_output_queue(irq_ptr, q, i)
Jan Glauber3f09bb82009-09-11 10:28:22 +0200344 debugfs_remove(q->debugfs_q);
Jan Glauber6486cda2010-01-04 09:05:42 +0100345 debugfs_remove(irq_ptr->debugfs_perf);
Jan Glauber3f09bb82009-09-11 10:28:22 +0200346 debugfs_remove(irq_ptr->debugfs_dev);
Jan Glauber779e6e12008-07-17 17:16:48 +0200347}
348
349int __init qdio_debug_init(void)
350{
Jan Glauber3f09bb82009-09-11 10:28:22 +0200351 debugfs_root = debugfs_create_dir("qdio", NULL);
Jan Glauber22f99342008-12-25 13:38:46 +0100352
353 qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
354 debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
355 debug_set_level(qdio_dbf_setup, DBF_INFO);
356 DBF_EVENT("dbf created\n");
357
358 qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
359 debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
360 debug_set_level(qdio_dbf_error, DBF_INFO);
361 DBF_ERROR("dbf created\n");
362 return 0;
Jan Glauber779e6e12008-07-17 17:16:48 +0200363}
364
365void qdio_debug_exit(void)
366{
Stefan Raspl613c4e02014-06-12 14:24:45 +0200367 qdio_clear_dbf_list();
Jan Glauber779e6e12008-07-17 17:16:48 +0200368 debugfs_remove(debugfs_root);
Markus Elfringa6e975c2015-11-16 14:45:40 +0100369 debug_unregister(qdio_dbf_setup);
370 debug_unregister(qdio_dbf_error);
Jan Glauber779e6e12008-07-17 17:16:48 +0200371}