[S390] qdio: convert global statistics to per-device stats
[linux-2.6.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, "slsb buffer 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         return 0;
101 }
102
103 static ssize_t qstat_seq_write(struct file *file, const char __user *buf,
104                                size_t count, loff_t *off)
105 {
106         struct seq_file *seq = file->private_data;
107         struct qdio_q *q = seq->private;
108
109         if (!q)
110                 return 0;
111         if (q->is_input_q)
112                 xchg(q->irq_ptr->dsci, 1);
113         local_bh_disable();
114         tasklet_schedule(&q->tasklet);
115         local_bh_enable();
116         return count;
117 }
118
119 static int qstat_seq_open(struct inode *inode, struct file *filp)
120 {
121         return single_open(filp, qstat_show,
122                            filp->f_path.dentry->d_inode->i_private);
123 }
124
125 static const struct file_operations debugfs_fops = {
126         .owner   = THIS_MODULE,
127         .open    = qstat_seq_open,
128         .read    = seq_read,
129         .write   = qstat_seq_write,
130         .llseek  = seq_lseek,
131         .release = single_release,
132 };
133
134 static char *qperf_names[] = {
135         "Assumed adapter interrupts",
136         "QDIO interrupts",
137         "Requested PCIs",
138         "Inbound tasklet runs",
139         "Inbound tasklet resched",
140         "Inbound tasklet resched2",
141         "Outbound tasklet runs",
142         "SIGA read",
143         "SIGA write",
144         "SIGA sync",
145         "Inbound calls",
146         "Inbound handler",
147         "Inbound stop_polling",
148         "Inbound queue full",
149         "Outbound calls",
150         "Outbound handler",
151         "Outbound fast_requeue",
152         "Outbound target_full",
153         "QEBSM eqbs",
154         "QEBSM eqbs partial",
155         "QEBSM sqbs",
156         "QEBSM sqbs partial"
157 };
158
159 static int qperf_show(struct seq_file *m, void *v)
160 {
161         struct qdio_irq *irq_ptr = m->private;
162         unsigned int *stat;
163         int i;
164
165         if (!irq_ptr)
166                 return 0;
167         if (!irq_ptr->perf_stat_enabled) {
168                 seq_printf(m, "disabled\n");
169                 return 0;
170         }
171         stat = (unsigned int *)&irq_ptr->perf_stat;
172
173         for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
174                 seq_printf(m, "%26s:\t%u\n",
175                            qperf_names[i], *(stat + i));
176         return 0;
177 }
178
179 static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
180                                size_t count, loff_t *off)
181 {
182         struct seq_file *seq = file->private_data;
183         struct qdio_irq *irq_ptr = seq->private;
184         unsigned long val;
185         char buf[8];
186         int ret;
187
188         if (!irq_ptr)
189                 return 0;
190         if (count >= sizeof(buf))
191                 return -EINVAL;
192         if (copy_from_user(&buf, ubuf, count))
193                 return -EFAULT;
194         buf[count] = 0;
195
196         ret = strict_strtoul(buf, 10, &val);
197         if (ret < 0)
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                 break;
205         case 1:
206                 irq_ptr->perf_stat_enabled = 1;
207                 break;
208         }
209         return count;
210 }
211
212 static int qperf_seq_open(struct inode *inode, struct file *filp)
213 {
214         return single_open(filp, qperf_show,
215                            filp->f_path.dentry->d_inode->i_private);
216 }
217
218 static struct file_operations debugfs_perf_fops = {
219         .owner   = THIS_MODULE,
220         .open    = qperf_seq_open,
221         .read    = seq_read,
222         .write   = qperf_seq_write,
223         .llseek  = seq_lseek,
224         .release = single_release,
225 };
226 static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
227 {
228         char name[QDIO_DEBUGFS_NAME_LEN];
229
230         snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
231                  q->is_input_q ? "input" : "output",
232                  q->nr);
233         q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
234                                 q->irq_ptr->debugfs_dev, q, &debugfs_fops);
235         if (IS_ERR(q->debugfs_q))
236                 q->debugfs_q = NULL;
237 }
238
239 void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
240 {
241         struct qdio_q *q;
242         int i;
243
244         irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
245                                                   debugfs_root);
246         if (IS_ERR(irq_ptr->debugfs_dev))
247                 irq_ptr->debugfs_dev = NULL;
248
249         irq_ptr->debugfs_perf = debugfs_create_file("statistics",
250                                 S_IFREG | S_IRUGO | S_IWUSR,
251                                 irq_ptr->debugfs_dev, irq_ptr,
252                                 &debugfs_perf_fops);
253         if (IS_ERR(irq_ptr->debugfs_perf))
254                 irq_ptr->debugfs_perf = NULL;
255
256         for_each_input_queue(irq_ptr, q, i)
257                 setup_debugfs_entry(q, cdev);
258         for_each_output_queue(irq_ptr, q, i)
259                 setup_debugfs_entry(q, cdev);
260 }
261
262 void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
263 {
264         struct qdio_q *q;
265         int i;
266
267         for_each_input_queue(irq_ptr, q, i)
268                 debugfs_remove(q->debugfs_q);
269         for_each_output_queue(irq_ptr, q, i)
270                 debugfs_remove(q->debugfs_q);
271         debugfs_remove(irq_ptr->debugfs_perf);
272         debugfs_remove(irq_ptr->debugfs_dev);
273 }
274
275 int __init qdio_debug_init(void)
276 {
277         debugfs_root = debugfs_create_dir("qdio", NULL);
278
279         qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
280         debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
281         debug_set_level(qdio_dbf_setup, DBF_INFO);
282         DBF_EVENT("dbf created\n");
283
284         qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
285         debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
286         debug_set_level(qdio_dbf_error, DBF_INFO);
287         DBF_ERROR("dbf created\n");
288         return 0;
289 }
290
291 void qdio_debug_exit(void)
292 {
293         debugfs_remove(debugfs_root);
294         if (qdio_dbf_setup)
295                 debug_unregister(qdio_dbf_setup);
296         if (qdio_dbf_error)
297                 debug_unregister(qdio_dbf_error);
298 }