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 strscpy(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: %llx\n", q->timestamp);
109 seq_printf(m, "Last Data IRQ: %llx Last AI: %llx\n",
110 q->irq_ptr->last_data_irq_time, last_ai_time);
111 seq_printf(m, "nr_used: %d ftc: %d\n",
112 atomic_read(&q->nr_buf_used), q->first_to_check);
113 if (q->is_input_q) {
114 seq_printf(m, "batch start: %u batch count: %u\n",
115 q->u.in.batch_start, q->u.in.batch_count);
116 seq_printf(m, "DSCI: %x IRQs disabled: %u\n",
117 *(u8 *)q->irq_ptr->dsci,
118 test_bit(QDIO_IRQ_DISABLED,
119 &q->irq_ptr->poll_state));
120 }
121 seq_printf(m, "SBAL states:\n");
122 seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n");
123
124 for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
125 debug_get_buf_state(q, i, &state);
126 switch (state) {
127 case SLSB_P_INPUT_NOT_INIT:
128 case SLSB_P_OUTPUT_NOT_INIT:
129 seq_printf(m, "N");
130 break;
131 case SLSB_P_OUTPUT_PENDING:
132 seq_printf(m, "P");
133 break;
134 case SLSB_P_INPUT_PRIMED:
135 case SLSB_CU_OUTPUT_PRIMED:
136 seq_printf(m, "+");
137 break;
138 case SLSB_P_INPUT_ACK:
139 seq_printf(m, "A");
140 break;
141 case SLSB_P_INPUT_ERROR:
142 case SLSB_P_OUTPUT_ERROR:
143 seq_printf(m, "x");
144 break;
145 case SLSB_CU_INPUT_EMPTY:
146 case SLSB_P_OUTPUT_EMPTY:
147 seq_printf(m, "-");
148 break;
149 case SLSB_P_INPUT_HALTED:
150 case SLSB_P_OUTPUT_HALTED:
151 seq_printf(m, ".");
152 break;
153 default:
154 seq_printf(m, "?");
155 }
156 if (i == 63)
157 seq_printf(m, "\n");
158 }
159 seq_printf(m, "\n");
160 seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n");
161
162 seq_printf(m, "\nSBAL statistics:");
163 if (!q->irq_ptr->perf_stat_enabled) {
164 seq_printf(m, " disabled\n");
165 return 0;
166 }
167
168 seq_printf(m, "\n1 2.. 4.. 8.. "
169 "16.. 32.. 64.. 128\n");
170 for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
171 seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
172 seq_printf(m, "\nError NOP Total\n%-10u %-10u %-10u\n\n",
173 q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
174 q->q_stats.nr_sbal_total);
175 return 0;
176}
177
178DEFINE_SHOW_ATTRIBUTE(qstat);
179
180static int ssqd_show(struct seq_file *m, void *v)
181{
182 struct ccw_device *cdev = m->private;
183 struct qdio_ssqd_desc ssqd;
184 int rc;
185
186 rc = qdio_get_ssqd_desc(cdev, &ssqd);
187 if (rc)
188 return rc;
189
190 seq_hex_dump(m, "", DUMP_PREFIX_NONE, 16, 4, &ssqd, sizeof(ssqd),
191 false);
192 return 0;
193}
194
195DEFINE_SHOW_ATTRIBUTE(ssqd);
196
197static char *qperf_names[] = {
198 "Assumed adapter interrupts",
199 "QDIO interrupts",
200 "SIGA read",
201 "SIGA write",
202 "SIGA sync",
203 "Inbound calls",
204 "Inbound stop_polling",
205 "Inbound queue full",
206 "Outbound calls",
207 "Outbound queue full",
208 "Outbound fast_requeue",
209 "Outbound target_full",
210 "QEBSM eqbs",
211 "QEBSM eqbs partial",
212 "QEBSM sqbs",
213 "QEBSM sqbs partial",
214 "Discarded interrupts"
215};
216
217static int qperf_show(struct seq_file *m, void *v)
218{
219 struct qdio_irq *irq_ptr = m->private;
220 unsigned int *stat;
221 int i;
222
223 if (!irq_ptr)
224 return 0;
225 if (!irq_ptr->perf_stat_enabled) {
226 seq_printf(m, "disabled\n");
227 return 0;
228 }
229 stat = (unsigned int *)&irq_ptr->perf_stat;
230
231 for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
232 seq_printf(m, "%26s:\t%u\n",
233 qperf_names[i], *(stat + i));
234 return 0;
235}
236
237static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
238 size_t count, loff_t *off)
239{
240 struct seq_file *seq = file->private_data;
241 struct qdio_irq *irq_ptr = seq->private;
242 struct qdio_q *q;
243 unsigned long val;
244 int ret, i;
245
246 if (!irq_ptr)
247 return 0;
248
249 ret = kstrtoul_from_user(ubuf, count, 10, &val);
250 if (ret)
251 return ret;
252
253 switch (val) {
254 case 0:
255 irq_ptr->perf_stat_enabled = 0;
256 memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
257 for_each_input_queue(irq_ptr, q, i)
258 memset(&q->q_stats, 0, sizeof(q->q_stats));
259 for_each_output_queue(irq_ptr, q, i)
260 memset(&q->q_stats, 0, sizeof(q->q_stats));
261 break;
262 case 1:
263 irq_ptr->perf_stat_enabled = 1;
264 break;
265 }
266 return count;
267}
268
269static int qperf_seq_open(struct inode *inode, struct file *filp)
270{
271 return single_open(filp, qperf_show,
272 file_inode(filp)->i_private);
273}
274
275static const struct file_operations debugfs_perf_fops = {
276 .owner = THIS_MODULE,
277 .open = qperf_seq_open,
278 .read = seq_read,
279 .write = qperf_seq_write,
280 .llseek = seq_lseek,
281 .release = single_release,
282};
283
284static void setup_debugfs_entry(struct dentry *parent, struct qdio_q *q)
285{
286 char name[QDIO_DEBUGFS_NAME_LEN];
287
288 snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
289 q->is_input_q ? "input" : "output",
290 q->nr);
291 debugfs_create_file(name, 0444, parent, q, &qstat_fops);
292}
293
294void qdio_setup_debug_entries(struct qdio_irq *irq_ptr)
295{
296 struct qdio_q *q;
297 int i;
298
299 irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&irq_ptr->cdev->dev),
300 debugfs_root);
301 debugfs_create_file("statistics", S_IFREG | S_IRUGO | S_IWUSR,
302 irq_ptr->debugfs_dev, irq_ptr, &debugfs_perf_fops);
303 debugfs_create_file("ssqd", 0444, irq_ptr->debugfs_dev, irq_ptr->cdev,
304 &ssqd_fops);
305
306 for_each_input_queue(irq_ptr, q, i)
307 setup_debugfs_entry(irq_ptr->debugfs_dev, q);
308 for_each_output_queue(irq_ptr, q, i)
309 setup_debugfs_entry(irq_ptr->debugfs_dev, q);
310}
311
312void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr)
313{
314 debugfs_remove_recursive(irq_ptr->debugfs_dev);
315}
316
317int __init qdio_debug_init(void)
318{
319 debugfs_root = debugfs_create_dir("qdio", NULL);
320
321 qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
322 debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
323 debug_set_level(qdio_dbf_setup, DBF_INFO);
324 DBF_EVENT("dbf created\n");
325
326 qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
327 debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
328 debug_set_level(qdio_dbf_error, DBF_INFO);
329 DBF_ERROR("dbf created\n");
330 return 0;
331}
332
333void qdio_debug_exit(void)
334{
335 qdio_clear_dbf_list();
336 debugfs_remove_recursive(debugfs_root);
337 debug_unregister(qdio_dbf_setup);
338 debug_unregister(qdio_dbf_error);
339}