]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/s390/cio/qdio_debug.c
Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jlbec...
[karo-tx-linux.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->flags, sizeof(long));
37         DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *));
38         DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *));
39         DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr);
40
41         /* allocate trace view for the interface */
42         snprintf(text, 20, "qdio_%s", dev_name(&init_data->cdev->dev));
43         irq_ptr->debug_area = debug_register(text, 2, 1, 16);
44         debug_register_view(irq_ptr->debug_area, &debug_hex_ascii_view);
45         debug_set_level(irq_ptr->debug_area, DBF_WARN);
46         DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created");
47 }
48
49 static int qstat_show(struct seq_file *m, void *v)
50 {
51         unsigned char state;
52         struct qdio_q *q = m->private;
53         int i;
54
55         if (!q)
56                 return 0;
57
58         seq_printf(m, "DSCI: %d   nr_used: %d\n",
59                    *(u32 *)q->irq_ptr->dsci, atomic_read(&q->nr_buf_used));
60         seq_printf(m, "ftc: %d  last_move: %d\n", q->first_to_check, q->last_move);
61         seq_printf(m, "polling: %d  ack start: %d  ack count: %d\n",
62                    q->u.in.polling, q->u.in.ack_start, q->u.in.ack_count);
63         seq_printf(m, "SBAL states:\n");
64         seq_printf(m, "|0      |8      |16     |24     |32     |40     |48     |56  63|\n");
65
66         for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
67                 debug_get_buf_state(q, i, &state);
68                 switch (state) {
69                 case SLSB_P_INPUT_NOT_INIT:
70                 case SLSB_P_OUTPUT_NOT_INIT:
71                         seq_printf(m, "N");
72                         break;
73                 case SLSB_P_INPUT_PRIMED:
74                 case SLSB_CU_OUTPUT_PRIMED:
75                         seq_printf(m, "+");
76                         break;
77                 case SLSB_P_INPUT_ACK:
78                         seq_printf(m, "A");
79                         break;
80                 case SLSB_P_INPUT_ERROR:
81                 case SLSB_P_OUTPUT_ERROR:
82                         seq_printf(m, "x");
83                         break;
84                 case SLSB_CU_INPUT_EMPTY:
85                 case SLSB_P_OUTPUT_EMPTY:
86                         seq_printf(m, "-");
87                         break;
88                 case SLSB_P_INPUT_HALTED:
89                 case SLSB_P_OUTPUT_HALTED:
90                         seq_printf(m, ".");
91                         break;
92                 default:
93                         seq_printf(m, "?");
94                 }
95                 if (i == 63)
96                         seq_printf(m, "\n");
97         }
98         seq_printf(m, "\n");
99         seq_printf(m, "|64     |72     |80     |88     |96     |104    |112    |   127|\n");
100
101         seq_printf(m, "\nSBAL statistics:");
102         if (!q->irq_ptr->perf_stat_enabled) {
103                 seq_printf(m, " disabled\n");
104                 return 0;
105         }
106
107         seq_printf(m, "\n1          2..        4..        8..        "
108                    "16..       32..       64..       127\n");
109         for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
110                 seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
111         seq_printf(m, "\nError      NOP        Total\n%-10u %-10u %-10u\n\n",
112                    q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
113                    q->q_stats.nr_sbal_total);
114         return 0;
115 }
116
117 static ssize_t qstat_seq_write(struct file *file, const char __user *buf,
118                                size_t count, loff_t *off)
119 {
120         struct seq_file *seq = file->private_data;
121         struct qdio_q *q = seq->private;
122
123         if (!q)
124                 return 0;
125         if (q->is_input_q)
126                 xchg(q->irq_ptr->dsci, 1);
127         local_bh_disable();
128         tasklet_schedule(&q->tasklet);
129         local_bh_enable();
130         return count;
131 }
132
133 static int qstat_seq_open(struct inode *inode, struct file *filp)
134 {
135         return single_open(filp, qstat_show,
136                            filp->f_path.dentry->d_inode->i_private);
137 }
138
139 static const struct file_operations debugfs_fops = {
140         .owner   = THIS_MODULE,
141         .open    = qstat_seq_open,
142         .read    = seq_read,
143         .write   = qstat_seq_write,
144         .llseek  = seq_lseek,
145         .release = single_release,
146 };
147
148 static char *qperf_names[] = {
149         "Assumed adapter interrupts",
150         "QDIO interrupts",
151         "Requested PCIs",
152         "Inbound tasklet runs",
153         "Inbound tasklet resched",
154         "Inbound tasklet resched2",
155         "Outbound tasklet runs",
156         "SIGA read",
157         "SIGA write",
158         "SIGA sync",
159         "Inbound calls",
160         "Inbound handler",
161         "Inbound stop_polling",
162         "Inbound queue full",
163         "Outbound calls",
164         "Outbound handler",
165         "Outbound fast_requeue",
166         "Outbound target_full",
167         "QEBSM eqbs",
168         "QEBSM eqbs partial",
169         "QEBSM sqbs",
170         "QEBSM sqbs partial"
171 };
172
173 static int qperf_show(struct seq_file *m, void *v)
174 {
175         struct qdio_irq *irq_ptr = m->private;
176         unsigned int *stat;
177         int i;
178
179         if (!irq_ptr)
180                 return 0;
181         if (!irq_ptr->perf_stat_enabled) {
182                 seq_printf(m, "disabled\n");
183                 return 0;
184         }
185         stat = (unsigned int *)&irq_ptr->perf_stat;
186
187         for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
188                 seq_printf(m, "%26s:\t%u\n",
189                            qperf_names[i], *(stat + i));
190         return 0;
191 }
192
193 static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
194                                size_t count, loff_t *off)
195 {
196         struct seq_file *seq = file->private_data;
197         struct qdio_irq *irq_ptr = seq->private;
198         struct qdio_q *q;
199         unsigned long val;
200         char buf[8];
201         int ret, i;
202
203         if (!irq_ptr)
204                 return 0;
205         if (count >= sizeof(buf))
206                 return -EINVAL;
207         if (copy_from_user(&buf, ubuf, count))
208                 return -EFAULT;
209         buf[count] = 0;
210
211         ret = strict_strtoul(buf, 10, &val);
212         if (ret < 0)
213                 return ret;
214
215         switch (val) {
216         case 0:
217                 irq_ptr->perf_stat_enabled = 0;
218                 memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
219                 for_each_input_queue(irq_ptr, q, i)
220                         memset(&q->q_stats, 0, sizeof(q->q_stats));
221                 for_each_output_queue(irq_ptr, q, i)
222                         memset(&q->q_stats, 0, sizeof(q->q_stats));
223                 break;
224         case 1:
225                 irq_ptr->perf_stat_enabled = 1;
226                 break;
227         }
228         return count;
229 }
230
231 static int qperf_seq_open(struct inode *inode, struct file *filp)
232 {
233         return single_open(filp, qperf_show,
234                            filp->f_path.dentry->d_inode->i_private);
235 }
236
237 static struct file_operations debugfs_perf_fops = {
238         .owner   = THIS_MODULE,
239         .open    = qperf_seq_open,
240         .read    = seq_read,
241         .write   = qperf_seq_write,
242         .llseek  = seq_lseek,
243         .release = single_release,
244 };
245 static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
246 {
247         char name[QDIO_DEBUGFS_NAME_LEN];
248
249         snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
250                  q->is_input_q ? "input" : "output",
251                  q->nr);
252         q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
253                                 q->irq_ptr->debugfs_dev, q, &debugfs_fops);
254         if (IS_ERR(q->debugfs_q))
255                 q->debugfs_q = NULL;
256 }
257
258 void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
259 {
260         struct qdio_q *q;
261         int i;
262
263         irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
264                                                   debugfs_root);
265         if (IS_ERR(irq_ptr->debugfs_dev))
266                 irq_ptr->debugfs_dev = NULL;
267
268         irq_ptr->debugfs_perf = debugfs_create_file("statistics",
269                                 S_IFREG | S_IRUGO | S_IWUSR,
270                                 irq_ptr->debugfs_dev, irq_ptr,
271                                 &debugfs_perf_fops);
272         if (IS_ERR(irq_ptr->debugfs_perf))
273                 irq_ptr->debugfs_perf = NULL;
274
275         for_each_input_queue(irq_ptr, q, i)
276                 setup_debugfs_entry(q, cdev);
277         for_each_output_queue(irq_ptr, q, i)
278                 setup_debugfs_entry(q, cdev);
279 }
280
281 void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
282 {
283         struct qdio_q *q;
284         int i;
285
286         for_each_input_queue(irq_ptr, q, i)
287                 debugfs_remove(q->debugfs_q);
288         for_each_output_queue(irq_ptr, q, i)
289                 debugfs_remove(q->debugfs_q);
290         debugfs_remove(irq_ptr->debugfs_perf);
291         debugfs_remove(irq_ptr->debugfs_dev);
292 }
293
294 int __init qdio_debug_init(void)
295 {
296         debugfs_root = debugfs_create_dir("qdio", NULL);
297
298         qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
299         debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
300         debug_set_level(qdio_dbf_setup, DBF_INFO);
301         DBF_EVENT("dbf created\n");
302
303         qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
304         debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
305         debug_set_level(qdio_dbf_error, DBF_INFO);
306         DBF_ERROR("dbf created\n");
307         return 0;
308 }
309
310 void qdio_debug_exit(void)
311 {
312         debugfs_remove(debugfs_root);
313         if (qdio_dbf_setup)
314                 debug_unregister(qdio_dbf_setup);
315         if (qdio_dbf_error)
316                 debug_unregister(qdio_dbf_error);
317 }