Loading...
1/*
2 * drivers/s390/cio/qdio_debug.c
3 *
4 * Copyright IBM Corp. 2008,2009
5 *
6 * Author: Jan Glauber (jang@linux.vnet.ibm.com)
7 */
8#include <linux/seq_file.h>
9#include <linux/debugfs.h>
10#include <asm/debug.h>
11#include "qdio_debug.h"
12#include "qdio.h"
13
14debug_info_t *qdio_dbf_setup;
15debug_info_t *qdio_dbf_error;
16
17static struct dentry *debugfs_root;
18#define QDIO_DEBUGFS_NAME_LEN 10
19
20void qdio_allocate_dbf(struct qdio_initialize *init_data,
21 struct qdio_irq *irq_ptr)
22{
23 char text[20];
24
25 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->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);
39
40 /* 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");
46}
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
57 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",
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 }
69 seq_printf(m, "SBAL states:\n");
70 seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n");
71
72 for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
73 debug_get_buf_state(q, i, &state);
74 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");
105 seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n");
106
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);
120 return 0;
121}
122
123static 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
129static const struct file_operations debugfs_fops = {
130 .owner = THIS_MODULE,
131 .open = qstat_seq_open,
132 .read = seq_read,
133 .llseek = seq_lseek,
134 .release = single_release,
135};
136
137static 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",
154 "Outbound queue full",
155 "Outbound fast_requeue",
156 "Outbound target_full",
157 "QEBSM eqbs",
158 "QEBSM eqbs partial",
159 "QEBSM sqbs",
160 "QEBSM sqbs partial",
161 "Discarded interrupts"
162};
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;
189 struct qdio_q *q;
190 unsigned long val;
191 int ret, i;
192
193 if (!irq_ptr)
194 return 0;
195
196 ret = kstrtoul_from_user(ubuf, count, 10, &val);
197 if (ret)
198 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));
204 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));
208 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};
230static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
231{
232 char name[QDIO_DEBUGFS_NAME_LEN];
233
234 snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
235 q->is_input_q ? "input" : "output",
236 q->nr);
237 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;
241}
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
248 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;
252
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
260 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);
264}
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
271 for_each_input_queue(irq_ptr, q, i)
272 debugfs_remove(q->debugfs_q);
273 for_each_output_queue(irq_ptr, q, i)
274 debugfs_remove(q->debugfs_q);
275 debugfs_remove(irq_ptr->debugfs_perf);
276 debugfs_remove(irq_ptr->debugfs_dev);
277}
278
279int __init qdio_debug_init(void)
280{
281 debugfs_root = debugfs_create_dir("qdio", NULL);
282
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;
293}
294
295void qdio_debug_exit(void)
296{
297 debugfs_remove(debugfs_root);
298 if (qdio_dbf_setup)
299 debug_unregister(qdio_dbf_setup);
300 if (qdio_dbf_error)
301 debug_unregister(qdio_dbf_error);
302}
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright IBM Corp. 2008, 2009
4 *
5 * Author: Jan Glauber (jang@linux.vnet.ibm.com)
6 */
7#include <linux/seq_file.h>
8#include <linux/debugfs.h>
9#include <linux/uaccess.h>
10#include <linux/export.h>
11#include <linux/slab.h>
12#include <asm/debug.h>
13#include "qdio_debug.h"
14#include "qdio.h"
15
16debug_info_t *qdio_dbf_setup;
17debug_info_t *qdio_dbf_error;
18
19static struct dentry *debugfs_root;
20#define QDIO_DEBUGFS_NAME_LEN 10
21#define QDIO_DBF_NAME_LEN 20
22
23struct qdio_dbf_entry {
24 char dbf_name[QDIO_DBF_NAME_LEN];
25 debug_info_t *dbf_info;
26 struct list_head dbf_list;
27};
28
29static LIST_HEAD(qdio_dbf_list);
30static DEFINE_MUTEX(qdio_dbf_list_mutex);
31
32static debug_info_t *qdio_get_dbf_entry(char *name)
33{
34 struct qdio_dbf_entry *entry;
35 debug_info_t *rc = NULL;
36
37 mutex_lock(&qdio_dbf_list_mutex);
38 list_for_each_entry(entry, &qdio_dbf_list, dbf_list) {
39 if (strcmp(entry->dbf_name, name) == 0) {
40 rc = entry->dbf_info;
41 break;
42 }
43 }
44 mutex_unlock(&qdio_dbf_list_mutex);
45 return rc;
46}
47
48static void qdio_clear_dbf_list(void)
49{
50 struct qdio_dbf_entry *entry, *tmp;
51
52 mutex_lock(&qdio_dbf_list_mutex);
53 list_for_each_entry_safe(entry, tmp, &qdio_dbf_list, dbf_list) {
54 list_del(&entry->dbf_list);
55 debug_unregister(entry->dbf_info);
56 kfree(entry);
57 }
58 mutex_unlock(&qdio_dbf_list_mutex);
59}
60
61int qdio_allocate_dbf(struct qdio_irq *irq_ptr)
62{
63 char text[QDIO_DBF_NAME_LEN];
64 struct qdio_dbf_entry *new_entry;
65
66 DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr);
67
68 /* allocate trace view for the interface */
69 snprintf(text, QDIO_DBF_NAME_LEN, "qdio_%s",
70 dev_name(&irq_ptr->cdev->dev));
71 irq_ptr->debug_area = qdio_get_dbf_entry(text);
72 if (irq_ptr->debug_area)
73 DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf reused");
74 else {
75 irq_ptr->debug_area = debug_register(text, 2, 1, 16);
76 if (!irq_ptr->debug_area)
77 return -ENOMEM;
78 if (debug_register_view(irq_ptr->debug_area,
79 &debug_hex_ascii_view)) {
80 debug_unregister(irq_ptr->debug_area);
81 return -ENOMEM;
82 }
83 debug_set_level(irq_ptr->debug_area, DBF_WARN);
84 DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created");
85 new_entry = kzalloc(sizeof(struct qdio_dbf_entry), GFP_KERNEL);
86 if (!new_entry) {
87 debug_unregister(irq_ptr->debug_area);
88 return -ENOMEM;
89 }
90 strlcpy(new_entry->dbf_name, text, QDIO_DBF_NAME_LEN);
91 new_entry->dbf_info = irq_ptr->debug_area;
92 mutex_lock(&qdio_dbf_list_mutex);
93 list_add(&new_entry->dbf_list, &qdio_dbf_list);
94 mutex_unlock(&qdio_dbf_list_mutex);
95 }
96 return 0;
97}
98
99static int qstat_show(struct seq_file *m, void *v)
100{
101 unsigned char state;
102 struct qdio_q *q = m->private;
103 int i;
104
105 if (!q)
106 return 0;
107
108 seq_printf(m, "Timestamp: %Lx Last AI: %Lx\n",
109 q->timestamp, last_ai_time);
110 seq_printf(m, "nr_used: %d ftc: %d\n",
111 atomic_read(&q->nr_buf_used), q->first_to_check);
112 if (q->is_input_q) {
113 seq_printf(m, "batch start: %u batch count: %u\n",
114 q->u.in.batch_start, q->u.in.batch_count);
115 seq_printf(m, "DSCI: %x IRQs disabled: %u\n",
116 *(u8 *)q->irq_ptr->dsci,
117 test_bit(QDIO_IRQ_DISABLED,
118 &q->irq_ptr->poll_state));
119 }
120 seq_printf(m, "SBAL states:\n");
121 seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n");
122
123 for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
124 debug_get_buf_state(q, i, &state);
125 switch (state) {
126 case SLSB_P_INPUT_NOT_INIT:
127 case SLSB_P_OUTPUT_NOT_INIT:
128 seq_printf(m, "N");
129 break;
130 case SLSB_P_OUTPUT_PENDING:
131 seq_printf(m, "P");
132 break;
133 case SLSB_P_INPUT_PRIMED:
134 case SLSB_CU_OUTPUT_PRIMED:
135 seq_printf(m, "+");
136 break;
137 case SLSB_P_INPUT_ACK:
138 seq_printf(m, "A");
139 break;
140 case SLSB_P_INPUT_ERROR:
141 case SLSB_P_OUTPUT_ERROR:
142 seq_printf(m, "x");
143 break;
144 case SLSB_CU_INPUT_EMPTY:
145 case SLSB_P_OUTPUT_EMPTY:
146 seq_printf(m, "-");
147 break;
148 case SLSB_P_INPUT_HALTED:
149 case SLSB_P_OUTPUT_HALTED:
150 seq_printf(m, ".");
151 break;
152 default:
153 seq_printf(m, "?");
154 }
155 if (i == 63)
156 seq_printf(m, "\n");
157 }
158 seq_printf(m, "\n");
159 seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n");
160
161 seq_printf(m, "\nSBAL statistics:");
162 if (!q->irq_ptr->perf_stat_enabled) {
163 seq_printf(m, " disabled\n");
164 return 0;
165 }
166
167 seq_printf(m, "\n1 2.. 4.. 8.. "
168 "16.. 32.. 64.. 128\n");
169 for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
170 seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
171 seq_printf(m, "\nError NOP Total\n%-10u %-10u %-10u\n\n",
172 q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
173 q->q_stats.nr_sbal_total);
174 return 0;
175}
176
177DEFINE_SHOW_ATTRIBUTE(qstat);
178
179static int ssqd_show(struct seq_file *m, void *v)
180{
181 struct ccw_device *cdev = m->private;
182 struct qdio_ssqd_desc ssqd;
183 int rc;
184
185 rc = qdio_get_ssqd_desc(cdev, &ssqd);
186 if (rc)
187 return rc;
188
189 seq_hex_dump(m, "", DUMP_PREFIX_NONE, 16, 4, &ssqd, sizeof(ssqd),
190 false);
191 return 0;
192}
193
194DEFINE_SHOW_ATTRIBUTE(ssqd);
195
196static char *qperf_names[] = {
197 "Assumed adapter interrupts",
198 "QDIO interrupts",
199 "Requested PCIs",
200 "Inbound tasklet runs",
201 "Inbound tasklet resched",
202 "Inbound tasklet resched2",
203 "Outbound tasklet runs",
204 "SIGA read",
205 "SIGA write",
206 "SIGA sync",
207 "Inbound calls",
208 "Inbound handler",
209 "Inbound stop_polling",
210 "Inbound queue full",
211 "Outbound calls",
212 "Outbound handler",
213 "Outbound queue full",
214 "Outbound fast_requeue",
215 "Outbound target_full",
216 "QEBSM eqbs",
217 "QEBSM eqbs partial",
218 "QEBSM sqbs",
219 "QEBSM sqbs partial",
220 "Discarded interrupts"
221};
222
223static int qperf_show(struct seq_file *m, void *v)
224{
225 struct qdio_irq *irq_ptr = m->private;
226 unsigned int *stat;
227 int i;
228
229 if (!irq_ptr)
230 return 0;
231 if (!irq_ptr->perf_stat_enabled) {
232 seq_printf(m, "disabled\n");
233 return 0;
234 }
235 stat = (unsigned int *)&irq_ptr->perf_stat;
236
237 for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
238 seq_printf(m, "%26s:\t%u\n",
239 qperf_names[i], *(stat + i));
240 return 0;
241}
242
243static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
244 size_t count, loff_t *off)
245{
246 struct seq_file *seq = file->private_data;
247 struct qdio_irq *irq_ptr = seq->private;
248 struct qdio_q *q;
249 unsigned long val;
250 int ret, i;
251
252 if (!irq_ptr)
253 return 0;
254
255 ret = kstrtoul_from_user(ubuf, count, 10, &val);
256 if (ret)
257 return ret;
258
259 switch (val) {
260 case 0:
261 irq_ptr->perf_stat_enabled = 0;
262 memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
263 for_each_input_queue(irq_ptr, q, i)
264 memset(&q->q_stats, 0, sizeof(q->q_stats));
265 for_each_output_queue(irq_ptr, q, i)
266 memset(&q->q_stats, 0, sizeof(q->q_stats));
267 break;
268 case 1:
269 irq_ptr->perf_stat_enabled = 1;
270 break;
271 }
272 return count;
273}
274
275static int qperf_seq_open(struct inode *inode, struct file *filp)
276{
277 return single_open(filp, qperf_show,
278 file_inode(filp)->i_private);
279}
280
281static const struct file_operations debugfs_perf_fops = {
282 .owner = THIS_MODULE,
283 .open = qperf_seq_open,
284 .read = seq_read,
285 .write = qperf_seq_write,
286 .llseek = seq_lseek,
287 .release = single_release,
288};
289
290static void setup_debugfs_entry(struct dentry *parent, struct qdio_q *q)
291{
292 char name[QDIO_DEBUGFS_NAME_LEN];
293
294 snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
295 q->is_input_q ? "input" : "output",
296 q->nr);
297 debugfs_create_file(name, 0444, parent, q, &qstat_fops);
298}
299
300void qdio_setup_debug_entries(struct qdio_irq *irq_ptr)
301{
302 struct qdio_q *q;
303 int i;
304
305 irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&irq_ptr->cdev->dev),
306 debugfs_root);
307 debugfs_create_file("statistics", S_IFREG | S_IRUGO | S_IWUSR,
308 irq_ptr->debugfs_dev, irq_ptr, &debugfs_perf_fops);
309 debugfs_create_file("ssqd", 0444, irq_ptr->debugfs_dev, irq_ptr->cdev,
310 &ssqd_fops);
311
312 for_each_input_queue(irq_ptr, q, i)
313 setup_debugfs_entry(irq_ptr->debugfs_dev, q);
314 for_each_output_queue(irq_ptr, q, i)
315 setup_debugfs_entry(irq_ptr->debugfs_dev, q);
316}
317
318void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr)
319{
320 debugfs_remove_recursive(irq_ptr->debugfs_dev);
321}
322
323int __init qdio_debug_init(void)
324{
325 debugfs_root = debugfs_create_dir("qdio", NULL);
326
327 qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
328 debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
329 debug_set_level(qdio_dbf_setup, DBF_INFO);
330 DBF_EVENT("dbf created\n");
331
332 qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
333 debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
334 debug_set_level(qdio_dbf_error, DBF_INFO);
335 DBF_ERROR("dbf created\n");
336 return 0;
337}
338
339void qdio_debug_exit(void)
340{
341 qdio_clear_dbf_list();
342 debugfs_remove_recursive(debugfs_root);
343 debug_unregister(qdio_dbf_setup);
344 debug_unregister(qdio_dbf_error);
345}