Merge branch 'master' of git://1984.lsi.us.es/net-next-2.6
[pandora-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_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
123 static 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
129 static 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
137 static 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
164 static 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
184 static 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         char buf[8];
192         int ret, i;
193
194         if (!irq_ptr)
195                 return 0;
196         if (count >= sizeof(buf))
197                 return -EINVAL;
198         if (copy_from_user(&buf, ubuf, count))
199                 return -EFAULT;
200         buf[count] = 0;
201
202         ret = strict_strtoul(buf, 10, &val);
203         if (ret < 0)
204                 return ret;
205
206         switch (val) {
207         case 0:
208                 irq_ptr->perf_stat_enabled = 0;
209                 memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
210                 for_each_input_queue(irq_ptr, q, i)
211                         memset(&q->q_stats, 0, sizeof(q->q_stats));
212                 for_each_output_queue(irq_ptr, q, i)
213                         memset(&q->q_stats, 0, sizeof(q->q_stats));
214                 break;
215         case 1:
216                 irq_ptr->perf_stat_enabled = 1;
217                 break;
218         }
219         return count;
220 }
221
222 static int qperf_seq_open(struct inode *inode, struct file *filp)
223 {
224         return single_open(filp, qperf_show,
225                            filp->f_path.dentry->d_inode->i_private);
226 }
227
228 static struct file_operations debugfs_perf_fops = {
229         .owner   = THIS_MODULE,
230         .open    = qperf_seq_open,
231         .read    = seq_read,
232         .write   = qperf_seq_write,
233         .llseek  = seq_lseek,
234         .release = single_release,
235 };
236 static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
237 {
238         char name[QDIO_DEBUGFS_NAME_LEN];
239
240         snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
241                  q->is_input_q ? "input" : "output",
242                  q->nr);
243         q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
244                                 q->irq_ptr->debugfs_dev, q, &debugfs_fops);
245         if (IS_ERR(q->debugfs_q))
246                 q->debugfs_q = NULL;
247 }
248
249 void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
250 {
251         struct qdio_q *q;
252         int i;
253
254         irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
255                                                   debugfs_root);
256         if (IS_ERR(irq_ptr->debugfs_dev))
257                 irq_ptr->debugfs_dev = NULL;
258
259         irq_ptr->debugfs_perf = debugfs_create_file("statistics",
260                                 S_IFREG | S_IRUGO | S_IWUSR,
261                                 irq_ptr->debugfs_dev, irq_ptr,
262                                 &debugfs_perf_fops);
263         if (IS_ERR(irq_ptr->debugfs_perf))
264                 irq_ptr->debugfs_perf = NULL;
265
266         for_each_input_queue(irq_ptr, q, i)
267                 setup_debugfs_entry(q, cdev);
268         for_each_output_queue(irq_ptr, q, i)
269                 setup_debugfs_entry(q, cdev);
270 }
271
272 void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
273 {
274         struct qdio_q *q;
275         int i;
276
277         for_each_input_queue(irq_ptr, q, i)
278                 debugfs_remove(q->debugfs_q);
279         for_each_output_queue(irq_ptr, q, i)
280                 debugfs_remove(q->debugfs_q);
281         debugfs_remove(irq_ptr->debugfs_perf);
282         debugfs_remove(irq_ptr->debugfs_dev);
283 }
284
285 int __init qdio_debug_init(void)
286 {
287         debugfs_root = debugfs_create_dir("qdio", NULL);
288
289         qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
290         debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
291         debug_set_level(qdio_dbf_setup, DBF_INFO);
292         DBF_EVENT("dbf created\n");
293
294         qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
295         debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
296         debug_set_level(qdio_dbf_error, DBF_INFO);
297         DBF_ERROR("dbf created\n");
298         return 0;
299 }
300
301 void qdio_debug_exit(void)
302 {
303         debugfs_remove(debugfs_root);
304         if (qdio_dbf_setup)
305                 debug_unregister(qdio_dbf_setup);
306         if (qdio_dbf_error)
307                 debug_unregister(qdio_dbf_error);
308 }