]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/s390/cio/qdio_debug.c
aaf7f935bfd37e16c44e6ff70e84b38bde1c71c4
[mirror_ubuntu-artful-kernel.git] / drivers / s390 / cio / qdio_debug.c
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
14 debug_info_t *qdio_dbf_setup;
15 debug_info_t *qdio_dbf_error;
16
17 static struct dentry *debugfs_root;
18 #define QDIO_DEBUGFS_NAME_LEN 10
19
20 void 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
48 static 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_OUTPUT_PENDING:
80 seq_printf(m, "P");
81 break;
82 case SLSB_P_INPUT_PRIMED:
83 case SLSB_CU_OUTPUT_PRIMED:
84 seq_printf(m, "+");
85 break;
86 case SLSB_P_INPUT_ACK:
87 seq_printf(m, "A");
88 break;
89 case SLSB_P_INPUT_ERROR:
90 case SLSB_P_OUTPUT_ERROR:
91 seq_printf(m, "x");
92 break;
93 case SLSB_CU_INPUT_EMPTY:
94 case SLSB_P_OUTPUT_EMPTY:
95 seq_printf(m, "-");
96 break;
97 case SLSB_P_INPUT_HALTED:
98 case SLSB_P_OUTPUT_HALTED:
99 seq_printf(m, ".");
100 break;
101 default:
102 seq_printf(m, "?");
103 }
104 if (i == 63)
105 seq_printf(m, "\n");
106 }
107 seq_printf(m, "\n");
108 seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n");
109
110 seq_printf(m, "\nSBAL statistics:");
111 if (!q->irq_ptr->perf_stat_enabled) {
112 seq_printf(m, " disabled\n");
113 return 0;
114 }
115
116 seq_printf(m, "\n1 2.. 4.. 8.. "
117 "16.. 32.. 64.. 127\n");
118 for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
119 seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
120 seq_printf(m, "\nError NOP Total\n%-10u %-10u %-10u\n\n",
121 q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
122 q->q_stats.nr_sbal_total);
123 return 0;
124 }
125
126 static int qstat_seq_open(struct inode *inode, struct file *filp)
127 {
128 return single_open(filp, qstat_show,
129 filp->f_path.dentry->d_inode->i_private);
130 }
131
132 static const struct file_operations debugfs_fops = {
133 .owner = THIS_MODULE,
134 .open = qstat_seq_open,
135 .read = seq_read,
136 .llseek = seq_lseek,
137 .release = single_release,
138 };
139
140 static char *qperf_names[] = {
141 "Assumed adapter interrupts",
142 "QDIO interrupts",
143 "Requested PCIs",
144 "Inbound tasklet runs",
145 "Inbound tasklet resched",
146 "Inbound tasklet resched2",
147 "Outbound tasklet runs",
148 "SIGA read",
149 "SIGA write",
150 "SIGA sync",
151 "Inbound calls",
152 "Inbound handler",
153 "Inbound stop_polling",
154 "Inbound queue full",
155 "Outbound calls",
156 "Outbound handler",
157 "Outbound queue full",
158 "Outbound fast_requeue",
159 "Outbound target_full",
160 "QEBSM eqbs",
161 "QEBSM eqbs partial",
162 "QEBSM sqbs",
163 "QEBSM sqbs partial",
164 "Discarded interrupts"
165 };
166
167 static int qperf_show(struct seq_file *m, void *v)
168 {
169 struct qdio_irq *irq_ptr = m->private;
170 unsigned int *stat;
171 int i;
172
173 if (!irq_ptr)
174 return 0;
175 if (!irq_ptr->perf_stat_enabled) {
176 seq_printf(m, "disabled\n");
177 return 0;
178 }
179 stat = (unsigned int *)&irq_ptr->perf_stat;
180
181 for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
182 seq_printf(m, "%26s:\t%u\n",
183 qperf_names[i], *(stat + i));
184 return 0;
185 }
186
187 static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
188 size_t count, loff_t *off)
189 {
190 struct seq_file *seq = file->private_data;
191 struct qdio_irq *irq_ptr = seq->private;
192 struct qdio_q *q;
193 unsigned long val;
194 int ret, i;
195
196 if (!irq_ptr)
197 return 0;
198
199 ret = kstrtoul_from_user(ubuf, count, 10, &val);
200 if (ret)
201 return ret;
202
203 switch (val) {
204 case 0:
205 irq_ptr->perf_stat_enabled = 0;
206 memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
207 for_each_input_queue(irq_ptr, q, i)
208 memset(&q->q_stats, 0, sizeof(q->q_stats));
209 for_each_output_queue(irq_ptr, q, i)
210 memset(&q->q_stats, 0, sizeof(q->q_stats));
211 break;
212 case 1:
213 irq_ptr->perf_stat_enabled = 1;
214 break;
215 }
216 return count;
217 }
218
219 static int qperf_seq_open(struct inode *inode, struct file *filp)
220 {
221 return single_open(filp, qperf_show,
222 filp->f_path.dentry->d_inode->i_private);
223 }
224
225 static struct file_operations debugfs_perf_fops = {
226 .owner = THIS_MODULE,
227 .open = qperf_seq_open,
228 .read = seq_read,
229 .write = qperf_seq_write,
230 .llseek = seq_lseek,
231 .release = single_release,
232 };
233 static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
234 {
235 char name[QDIO_DEBUGFS_NAME_LEN];
236
237 snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
238 q->is_input_q ? "input" : "output",
239 q->nr);
240 q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
241 q->irq_ptr->debugfs_dev, q, &debugfs_fops);
242 if (IS_ERR(q->debugfs_q))
243 q->debugfs_q = NULL;
244 }
245
246 void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
247 {
248 struct qdio_q *q;
249 int i;
250
251 irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
252 debugfs_root);
253 if (IS_ERR(irq_ptr->debugfs_dev))
254 irq_ptr->debugfs_dev = NULL;
255
256 irq_ptr->debugfs_perf = debugfs_create_file("statistics",
257 S_IFREG | S_IRUGO | S_IWUSR,
258 irq_ptr->debugfs_dev, irq_ptr,
259 &debugfs_perf_fops);
260 if (IS_ERR(irq_ptr->debugfs_perf))
261 irq_ptr->debugfs_perf = NULL;
262
263 for_each_input_queue(irq_ptr, q, i)
264 setup_debugfs_entry(q, cdev);
265 for_each_output_queue(irq_ptr, q, i)
266 setup_debugfs_entry(q, cdev);
267 }
268
269 void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
270 {
271 struct qdio_q *q;
272 int i;
273
274 for_each_input_queue(irq_ptr, q, i)
275 debugfs_remove(q->debugfs_q);
276 for_each_output_queue(irq_ptr, q, i)
277 debugfs_remove(q->debugfs_q);
278 debugfs_remove(irq_ptr->debugfs_perf);
279 debugfs_remove(irq_ptr->debugfs_dev);
280 }
281
282 int __init qdio_debug_init(void)
283 {
284 debugfs_root = debugfs_create_dir("qdio", NULL);
285
286 qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
287 debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
288 debug_set_level(qdio_dbf_setup, DBF_INFO);
289 DBF_EVENT("dbf created\n");
290
291 qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
292 debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
293 debug_set_level(qdio_dbf_error, DBF_INFO);
294 DBF_ERROR("dbf created\n");
295 return 0;
296 }
297
298 void qdio_debug_exit(void)
299 {
300 debugfs_remove(debugfs_root);
301 if (qdio_dbf_setup)
302 debug_unregister(qdio_dbf_setup);
303 if (qdio_dbf_error)
304 debug_unregister(qdio_dbf_error);
305 }