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