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