]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/s390/cio/qdio_debug.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
[karo-tx-linux.git] / drivers / s390 / cio / qdio_debug.c
1 /*
2  *  Copyright IBM Corp. 2008, 2009
3  *
4  *  Author: Jan Glauber (jang@linux.vnet.ibm.com)
5  */
6 #include <linux/seq_file.h>
7 #include <linux/debugfs.h>
8 #include <linux/uaccess.h>
9 #include <linux/export.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, "Timestamp: %Lx  Last AI: %Lx\n",
58                    q->timestamp, last_ai_time);
59         seq_printf(m, "nr_used: %d  ftc: %d  last_move: %d\n",
60                    atomic_read(&q->nr_buf_used),
61                    q->first_to_check, q->last_move);
62         if (q->is_input_q) {
63                 seq_printf(m, "polling: %d  ack start: %d  ack count: %d\n",
64                            q->u.in.polling, q->u.in.ack_start,
65                            q->u.in.ack_count);
66                 seq_printf(m, "DSCI: %d   IRQs disabled: %u\n",
67                            *(u32 *)q->irq_ptr->dsci,
68                            test_bit(QDIO_QUEUE_IRQS_DISABLED,
69                            &q->u.in.queue_irq_state));
70         }
71         seq_printf(m, "SBAL states:\n");
72         seq_printf(m, "|0      |8      |16     |24     |32     |40     |48     |56  63|\n");
73
74         for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
75                 debug_get_buf_state(q, i, &state);
76                 switch (state) {
77                 case SLSB_P_INPUT_NOT_INIT:
78                 case SLSB_P_OUTPUT_NOT_INIT:
79                         seq_printf(m, "N");
80                         break;
81                 case SLSB_P_OUTPUT_PENDING:
82                         seq_printf(m, "P");
83                         break;
84                 case SLSB_P_INPUT_PRIMED:
85                 case SLSB_CU_OUTPUT_PRIMED:
86                         seq_printf(m, "+");
87                         break;
88                 case SLSB_P_INPUT_ACK:
89                         seq_printf(m, "A");
90                         break;
91                 case SLSB_P_INPUT_ERROR:
92                 case SLSB_P_OUTPUT_ERROR:
93                         seq_printf(m, "x");
94                         break;
95                 case SLSB_CU_INPUT_EMPTY:
96                 case SLSB_P_OUTPUT_EMPTY:
97                         seq_printf(m, "-");
98                         break;
99                 case SLSB_P_INPUT_HALTED:
100                 case SLSB_P_OUTPUT_HALTED:
101                         seq_printf(m, ".");
102                         break;
103                 default:
104                         seq_printf(m, "?");
105                 }
106                 if (i == 63)
107                         seq_printf(m, "\n");
108         }
109         seq_printf(m, "\n");
110         seq_printf(m, "|64     |72     |80     |88     |96     |104    |112    |   127|\n");
111
112         seq_printf(m, "\nSBAL statistics:");
113         if (!q->irq_ptr->perf_stat_enabled) {
114                 seq_printf(m, " disabled\n");
115                 return 0;
116         }
117
118         seq_printf(m, "\n1          2..        4..        8..        "
119                    "16..       32..       64..       127\n");
120         for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
121                 seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
122         seq_printf(m, "\nError      NOP        Total\n%-10u %-10u %-10u\n\n",
123                    q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
124                    q->q_stats.nr_sbal_total);
125         return 0;
126 }
127
128 static int qstat_seq_open(struct inode *inode, struct file *filp)
129 {
130         return single_open(filp, qstat_show,
131                            file_inode(filp)->i_private);
132 }
133
134 static const struct file_operations debugfs_fops = {
135         .owner   = THIS_MODULE,
136         .open    = qstat_seq_open,
137         .read    = seq_read,
138         .llseek  = seq_lseek,
139         .release = single_release,
140 };
141
142 static char *qperf_names[] = {
143         "Assumed adapter interrupts",
144         "QDIO interrupts",
145         "Requested PCIs",
146         "Inbound tasklet runs",
147         "Inbound tasklet resched",
148         "Inbound tasklet resched2",
149         "Outbound tasklet runs",
150         "SIGA read",
151         "SIGA write",
152         "SIGA sync",
153         "Inbound calls",
154         "Inbound handler",
155         "Inbound stop_polling",
156         "Inbound queue full",
157         "Outbound calls",
158         "Outbound handler",
159         "Outbound queue full",
160         "Outbound fast_requeue",
161         "Outbound target_full",
162         "QEBSM eqbs",
163         "QEBSM eqbs partial",
164         "QEBSM sqbs",
165         "QEBSM sqbs partial",
166         "Discarded interrupts"
167 };
168
169 static int qperf_show(struct seq_file *m, void *v)
170 {
171         struct qdio_irq *irq_ptr = m->private;
172         unsigned int *stat;
173         int i;
174
175         if (!irq_ptr)
176                 return 0;
177         if (!irq_ptr->perf_stat_enabled) {
178                 seq_printf(m, "disabled\n");
179                 return 0;
180         }
181         stat = (unsigned int *)&irq_ptr->perf_stat;
182
183         for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
184                 seq_printf(m, "%26s:\t%u\n",
185                            qperf_names[i], *(stat + i));
186         return 0;
187 }
188
189 static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
190                                size_t count, loff_t *off)
191 {
192         struct seq_file *seq = file->private_data;
193         struct qdio_irq *irq_ptr = seq->private;
194         struct qdio_q *q;
195         unsigned long val;
196         int ret, i;
197
198         if (!irq_ptr)
199                 return 0;
200
201         ret = kstrtoul_from_user(ubuf, count, 10, &val);
202         if (ret)
203                 return ret;
204
205         switch (val) {
206         case 0:
207                 irq_ptr->perf_stat_enabled = 0;
208                 memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
209                 for_each_input_queue(irq_ptr, q, i)
210                         memset(&q->q_stats, 0, sizeof(q->q_stats));
211                 for_each_output_queue(irq_ptr, q, i)
212                         memset(&q->q_stats, 0, sizeof(q->q_stats));
213                 break;
214         case 1:
215                 irq_ptr->perf_stat_enabled = 1;
216                 break;
217         }
218         return count;
219 }
220
221 static int qperf_seq_open(struct inode *inode, struct file *filp)
222 {
223         return single_open(filp, qperf_show,
224                            file_inode(filp)->i_private);
225 }
226
227 static struct file_operations debugfs_perf_fops = {
228         .owner   = THIS_MODULE,
229         .open    = qperf_seq_open,
230         .read    = seq_read,
231         .write   = qperf_seq_write,
232         .llseek  = seq_lseek,
233         .release = single_release,
234 };
235
236 static void setup_debugfs_entry(struct qdio_q *q)
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);
268         for_each_output_queue(irq_ptr, q, i)
269                 setup_debugfs_entry(q);
270 }
271
272 void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr)
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 }