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