diff options
Diffstat (limited to 'drivers/s390/cio/qdio_debug.c')
-rw-r--r-- | drivers/s390/cio/qdio_debug.c | 136 |
1 files changed, 126 insertions, 10 deletions
diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index 76769978285f..6ce83f56d537 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c | |||
@@ -33,7 +33,6 @@ void qdio_allocate_dbf(struct qdio_initialize *init_data, | |||
33 | DBF_HEX(&init_data->input_handler, sizeof(void *)); | 33 | DBF_HEX(&init_data->input_handler, sizeof(void *)); |
34 | DBF_HEX(&init_data->output_handler, sizeof(void *)); | 34 | DBF_HEX(&init_data->output_handler, sizeof(void *)); |
35 | DBF_HEX(&init_data->int_parm, sizeof(long)); | 35 | DBF_HEX(&init_data->int_parm, sizeof(long)); |
36 | DBF_HEX(&init_data->flags, sizeof(long)); | ||
37 | DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *)); | 36 | DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *)); |
38 | DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *)); | 37 | DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *)); |
39 | DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr); | 38 | DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr); |
@@ -55,14 +54,12 @@ static int qstat_show(struct seq_file *m, void *v) | |||
55 | if (!q) | 54 | if (!q) |
56 | return 0; | 55 | return 0; |
57 | 56 | ||
58 | seq_printf(m, "device state indicator: %d\n", *(u32 *)q->irq_ptr->dsci); | 57 | seq_printf(m, "DSCI: %d nr_used: %d\n", |
59 | seq_printf(m, "nr_used: %d\n", atomic_read(&q->nr_buf_used)); | 58 | *(u32 *)q->irq_ptr->dsci, atomic_read(&q->nr_buf_used)); |
60 | seq_printf(m, "ftc: %d\n", q->first_to_check); | 59 | seq_printf(m, "ftc: %d last_move: %d\n", q->first_to_check, q->last_move); |
61 | seq_printf(m, "last_move: %d\n", q->last_move); | 60 | seq_printf(m, "polling: %d ack start: %d ack count: %d\n", |
62 | seq_printf(m, "polling: %d\n", q->u.in.polling); | 61 | q->u.in.polling, q->u.in.ack_start, q->u.in.ack_count); |
63 | seq_printf(m, "ack start: %d\n", q->u.in.ack_start); | 62 | seq_printf(m, "SBAL states:\n"); |
64 | seq_printf(m, "ack count: %d\n", q->u.in.ack_count); | ||
65 | seq_printf(m, "slsb buffer states:\n"); | ||
66 | seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n"); | 63 | seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n"); |
67 | 64 | ||
68 | for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) { | 65 | for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) { |
@@ -99,6 +96,20 @@ static int qstat_show(struct seq_file *m, void *v) | |||
99 | } | 96 | } |
100 | seq_printf(m, "\n"); | 97 | seq_printf(m, "\n"); |
101 | seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n"); | 98 | seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n"); |
99 | |||
100 | seq_printf(m, "\nSBAL statistics:"); | ||
101 | if (!q->irq_ptr->perf_stat_enabled) { | ||
102 | seq_printf(m, " disabled\n"); | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | seq_printf(m, "\n1 2.. 4.. 8.. " | ||
107 | "16.. 32.. 64.. 127\n"); | ||
108 | for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++) | ||
109 | seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]); | ||
110 | seq_printf(m, "\nError NOP Total\n%-10u %-10u %-10u\n\n", | ||
111 | q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop, | ||
112 | q->q_stats.nr_sbal_total); | ||
102 | return 0; | 113 | return 0; |
103 | } | 114 | } |
104 | 115 | ||
@@ -110,7 +121,6 @@ static ssize_t qstat_seq_write(struct file *file, const char __user *buf, | |||
110 | 121 | ||
111 | if (!q) | 122 | if (!q) |
112 | return 0; | 123 | return 0; |
113 | |||
114 | if (q->is_input_q) | 124 | if (q->is_input_q) |
115 | xchg(q->irq_ptr->dsci, 1); | 125 | xchg(q->irq_ptr->dsci, 1); |
116 | local_bh_disable(); | 126 | local_bh_disable(); |
@@ -134,6 +144,103 @@ static const struct file_operations debugfs_fops = { | |||
134 | .release = single_release, | 144 | .release = single_release, |
135 | }; | 145 | }; |
136 | 146 | ||
147 | static char *qperf_names[] = { | ||
148 | "Assumed adapter interrupts", | ||
149 | "QDIO interrupts", | ||
150 | "Requested PCIs", | ||
151 | "Inbound tasklet runs", | ||
152 | "Inbound tasklet resched", | ||
153 | "Inbound tasklet resched2", | ||
154 | "Outbound tasklet runs", | ||
155 | "SIGA read", | ||
156 | "SIGA write", | ||
157 | "SIGA sync", | ||
158 | "Inbound calls", | ||
159 | "Inbound handler", | ||
160 | "Inbound stop_polling", | ||
161 | "Inbound queue full", | ||
162 | "Outbound calls", | ||
163 | "Outbound handler", | ||
164 | "Outbound fast_requeue", | ||
165 | "Outbound target_full", | ||
166 | "QEBSM eqbs", | ||
167 | "QEBSM eqbs partial", | ||
168 | "QEBSM sqbs", | ||
169 | "QEBSM sqbs partial" | ||
170 | }; | ||
171 | |||
172 | static int qperf_show(struct seq_file *m, void *v) | ||
173 | { | ||
174 | struct qdio_irq *irq_ptr = m->private; | ||
175 | unsigned int *stat; | ||
176 | int i; | ||
177 | |||
178 | if (!irq_ptr) | ||
179 | return 0; | ||
180 | if (!irq_ptr->perf_stat_enabled) { | ||
181 | seq_printf(m, "disabled\n"); | ||
182 | return 0; | ||
183 | } | ||
184 | stat = (unsigned int *)&irq_ptr->perf_stat; | ||
185 | |||
186 | for (i = 0; i < ARRAY_SIZE(qperf_names); i++) | ||
187 | seq_printf(m, "%26s:\t%u\n", | ||
188 | qperf_names[i], *(stat + i)); | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf, | ||
193 | size_t count, loff_t *off) | ||
194 | { | ||
195 | struct seq_file *seq = file->private_data; | ||
196 | struct qdio_irq *irq_ptr = seq->private; | ||
197 | struct qdio_q *q; | ||
198 | unsigned long val; | ||
199 | char buf[8]; | ||
200 | int ret, i; | ||
201 | |||
202 | if (!irq_ptr) | ||
203 | return 0; | ||
204 | if (count >= sizeof(buf)) | ||
205 | return -EINVAL; | ||
206 | if (copy_from_user(&buf, ubuf, count)) | ||
207 | return -EFAULT; | ||
208 | buf[count] = 0; | ||
209 | |||
210 | ret = strict_strtoul(buf, 10, &val); | ||
211 | if (ret < 0) | ||
212 | return ret; | ||
213 | |||
214 | switch (val) { | ||
215 | case 0: | ||
216 | irq_ptr->perf_stat_enabled = 0; | ||
217 | memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat)); | ||
218 | for_each_input_queue(irq_ptr, q, i) | ||
219 | memset(&q->q_stats, 0, sizeof(q->q_stats)); | ||
220 | for_each_output_queue(irq_ptr, q, i) | ||
221 | memset(&q->q_stats, 0, sizeof(q->q_stats)); | ||
222 | break; | ||
223 | case 1: | ||
224 | irq_ptr->perf_stat_enabled = 1; | ||
225 | break; | ||
226 | } | ||
227 | return count; | ||
228 | } | ||
229 | |||
230 | static int qperf_seq_open(struct inode *inode, struct file *filp) | ||
231 | { | ||
232 | return single_open(filp, qperf_show, | ||
233 | filp->f_path.dentry->d_inode->i_private); | ||
234 | } | ||
235 | |||
236 | static struct file_operations debugfs_perf_fops = { | ||
237 | .owner = THIS_MODULE, | ||
238 | .open = qperf_seq_open, | ||
239 | .read = seq_read, | ||
240 | .write = qperf_seq_write, | ||
241 | .llseek = seq_lseek, | ||
242 | .release = single_release, | ||
243 | }; | ||
137 | static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev) | 244 | static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev) |
138 | { | 245 | { |
139 | char name[QDIO_DEBUGFS_NAME_LEN]; | 246 | char name[QDIO_DEBUGFS_NAME_LEN]; |
@@ -156,6 +263,14 @@ void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev) | |||
156 | debugfs_root); | 263 | debugfs_root); |
157 | if (IS_ERR(irq_ptr->debugfs_dev)) | 264 | if (IS_ERR(irq_ptr->debugfs_dev)) |
158 | irq_ptr->debugfs_dev = NULL; | 265 | irq_ptr->debugfs_dev = NULL; |
266 | |||
267 | irq_ptr->debugfs_perf = debugfs_create_file("statistics", | ||
268 | S_IFREG | S_IRUGO | S_IWUSR, | ||
269 | irq_ptr->debugfs_dev, irq_ptr, | ||
270 | &debugfs_perf_fops); | ||
271 | if (IS_ERR(irq_ptr->debugfs_perf)) | ||
272 | irq_ptr->debugfs_perf = NULL; | ||
273 | |||
159 | for_each_input_queue(irq_ptr, q, i) | 274 | for_each_input_queue(irq_ptr, q, i) |
160 | setup_debugfs_entry(q, cdev); | 275 | setup_debugfs_entry(q, cdev); |
161 | for_each_output_queue(irq_ptr, q, i) | 276 | for_each_output_queue(irq_ptr, q, i) |
@@ -171,6 +286,7 @@ void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cd | |||
171 | debugfs_remove(q->debugfs_q); | 286 | debugfs_remove(q->debugfs_q); |
172 | for_each_output_queue(irq_ptr, q, i) | 287 | for_each_output_queue(irq_ptr, q, i) |
173 | debugfs_remove(q->debugfs_q); | 288 | debugfs_remove(q->debugfs_q); |
289 | debugfs_remove(irq_ptr->debugfs_perf); | ||
174 | debugfs_remove(irq_ptr->debugfs_dev); | 290 | debugfs_remove(irq_ptr->debugfs_dev); |
175 | } | 291 | } |
176 | 292 | ||