mmiotrace: print header using the read hook.
[safe/jmp/linux-2.6] / kernel / trace / trace_mmiotrace.c
1 /*
2  * Memory mapped I/O tracing
3  *
4  * Copyright (C) 2008 Pekka Paalanen <pq@iki.fi>
5  */
6
7 #define DEBUG 1
8
9 #include <linux/kernel.h>
10 #include <linux/mmiotrace.h>
11 #include <linux/pci.h>
12
13 #include "trace.h"
14
15 struct header_iter {
16         struct pci_dev *dev;
17 };
18
19 static struct trace_array *mmio_trace_array;
20
21 static void mmio_reset_data(struct trace_array *tr)
22 {
23         int cpu;
24
25         tr->time_start = ftrace_now(tr->cpu);
26
27         for_each_online_cpu(cpu)
28                 tracing_reset(tr->data[cpu]);
29 }
30
31 static void mmio_trace_init(struct trace_array *tr)
32 {
33         pr_debug("in %s\n", __func__);
34         mmio_trace_array = tr;
35         if (tr->ctrl) {
36                 mmio_reset_data(tr);
37                 enable_mmiotrace();
38         }
39 }
40
41 static void mmio_trace_reset(struct trace_array *tr)
42 {
43         pr_debug("in %s\n", __func__);
44         if (tr->ctrl)
45                 disable_mmiotrace();
46         mmio_reset_data(tr);
47         mmio_trace_array = NULL;
48 }
49
50 static void mmio_trace_ctrl_update(struct trace_array *tr)
51 {
52         pr_debug("in %s\n", __func__);
53         if (tr->ctrl) {
54                 mmio_reset_data(tr);
55                 enable_mmiotrace();
56         } else {
57                 disable_mmiotrace();
58         }
59 }
60
61 static int mmio_print_pcidev(struct trace_seq *s, const struct pci_dev *dev)
62 {
63         int ret = 0;
64         int i;
65         resource_size_t start, end;
66         const struct pci_driver *drv = pci_dev_driver(dev);
67
68         /* XXX: incomplete checks for trace_seq_printf() return value */
69         ret += trace_seq_printf(s, "PCIDEV %02x%02x %04x%04x %x",
70                                 dev->bus->number, dev->devfn,
71                                 dev->vendor, dev->device, dev->irq);
72         /*
73          * XXX: is pci_resource_to_user() appropriate, since we are
74          * supposed to interpret the __ioremap() phys_addr argument based on
75          * these printed values?
76          */
77         for (i = 0; i < 7; i++) {
78                 pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
79                 ret += trace_seq_printf(s, " %llx",
80                         (unsigned long long)(start |
81                         (dev->resource[i].flags & PCI_REGION_FLAG_MASK)));
82         }
83         for (i = 0; i < 7; i++) {
84                 pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
85                 ret += trace_seq_printf(s, " %llx",
86                         dev->resource[i].start < dev->resource[i].end ?
87                         (unsigned long long)(end - start) + 1 : 0);
88         }
89         if (drv)
90                 ret += trace_seq_printf(s, " %s\n", drv->name);
91         else
92                 ret += trace_seq_printf(s, " \n");
93         return ret;
94 }
95
96 static void destroy_header_iter(struct header_iter *hiter)
97 {
98         if (!hiter)
99                 return;
100         pci_dev_put(hiter->dev);
101         kfree(hiter);
102 }
103
104 static void mmio_pipe_open(struct trace_iterator *iter)
105 {
106         struct header_iter *hiter;
107         struct trace_seq *s = &iter->seq;
108
109         trace_seq_printf(s, "VERSION 20070824\n");
110
111         hiter = kzalloc(sizeof(*hiter), GFP_KERNEL);
112         if (!hiter)
113                 return;
114
115         hiter->dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
116         iter->private = hiter;
117 }
118
119 /* XXX: This is not called when the pipe is closed! */
120 static void mmio_close(struct trace_iterator *iter)
121 {
122         struct header_iter *hiter = iter->private;
123         destroy_header_iter(hiter);
124         iter->private = NULL;
125 }
126
127 static ssize_t mmio_read(struct trace_iterator *iter, struct file *filp,
128                                 char __user *ubuf, size_t cnt, loff_t *ppos)
129 {
130         ssize_t ret;
131         struct header_iter *hiter = iter->private;
132         struct trace_seq *s = &iter->seq;
133
134         if (!hiter)
135                 return 0;
136
137         mmio_print_pcidev(s, hiter->dev);
138         hiter->dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, hiter->dev);
139
140         if (!hiter->dev) {
141                 destroy_header_iter(hiter);
142                 iter->private = NULL;
143         }
144
145         ret = trace_seq_to_user(s, ubuf, cnt);
146         return (ret == -EBUSY) ? 0 : ret;
147 }
148
149 static int mmio_print_rw(struct trace_iterator *iter)
150 {
151         struct trace_entry *entry = iter->ent;
152         struct mmiotrace_rw *rw = &entry->mmiorw;
153         struct trace_seq *s     = &iter->seq;
154         unsigned long long t    = ns2usecs(entry->t);
155         unsigned long usec_rem  = do_div(t, 1000000ULL);
156         unsigned secs           = (unsigned long)t;
157         int ret = 1;
158
159         switch (entry->mmiorw.opcode) {
160         case MMIO_READ:
161                 ret = trace_seq_printf(s,
162                         "R %d %lu.%06lu %d 0x%lx 0x%lx 0x%lx %d\n",
163                         rw->width, secs, usec_rem, rw->map_id, rw->phys,
164                         rw->value, rw->pc, 0);
165                 break;
166         case MMIO_WRITE:
167                 ret = trace_seq_printf(s,
168                         "W %d %lu.%06lu %d 0x%lx 0x%lx 0x%lx %d\n",
169                         rw->width, secs, usec_rem, rw->map_id, rw->phys,
170                         rw->value, rw->pc, 0);
171                 break;
172         case MMIO_UNKNOWN_OP:
173                 ret = trace_seq_printf(s,
174                         "UNKNOWN %lu.%06lu %d 0x%lx %02x,%02x,%02x 0x%lx %d\n",
175                         secs, usec_rem, rw->map_id, rw->phys,
176                         (rw->value >> 16) & 0xff, (rw->value >> 8) & 0xff,
177                         (rw->value >> 0) & 0xff, rw->pc, 0);
178                 break;
179         default:
180                 ret = trace_seq_printf(s, "rw what?\n");
181                 break;
182         }
183         if (ret)
184                 return 1;
185         return 0;
186 }
187
188 static int mmio_print_map(struct trace_iterator *iter)
189 {
190         struct trace_entry *entry = iter->ent;
191         struct mmiotrace_map *m = &entry->mmiomap;
192         struct trace_seq *s     = &iter->seq;
193         unsigned long long t    = ns2usecs(entry->t);
194         unsigned long usec_rem  = do_div(t, 1000000ULL);
195         unsigned secs           = (unsigned long)t;
196         int ret = 1;
197
198         switch (entry->mmiorw.opcode) {
199         case MMIO_PROBE:
200                 ret = trace_seq_printf(s,
201                         "MAP %lu.%06lu %d 0x%lx 0x%lx 0x%lx 0x%lx %d\n",
202                         secs, usec_rem, m->map_id, m->phys, m->virt, m->len,
203                         0UL, entry->pid);
204                 break;
205         case MMIO_UNPROBE:
206                 ret = trace_seq_printf(s,
207                         "UNMAP %lu.%06lu %d 0x%lx %d\n",
208                         secs, usec_rem, m->map_id, 0UL, entry->pid);
209                 break;
210         default:
211                 ret = trace_seq_printf(s, "map what?\n");
212                 break;
213         }
214         if (ret)
215                 return 1;
216         return 0;
217 }
218
219 /* return 0 to abort printing without consuming current entry in pipe mode */
220 static int mmio_print_line(struct trace_iterator *iter)
221 {
222         switch (iter->ent->type) {
223         case TRACE_MMIO_RW:
224                 return mmio_print_rw(iter);
225         case TRACE_MMIO_MAP:
226                 return mmio_print_map(iter);
227         default:
228                 return 1; /* ignore unknown entries */
229         }
230 }
231
232 static struct tracer mmio_tracer __read_mostly =
233 {
234         .name           = "mmiotrace",
235         .init           = mmio_trace_init,
236         .reset          = mmio_trace_reset,
237         .pipe_open      = mmio_pipe_open,
238         .close          = mmio_close,
239         .read           = mmio_read,
240         .ctrl_update    = mmio_trace_ctrl_update,
241         .print_line     = mmio_print_line,
242 };
243
244 __init static int init_mmio_trace(void)
245 {
246         return register_tracer(&mmio_tracer);
247 }
248 device_initcall(init_mmio_trace);
249
250 void mmio_trace_rw(struct mmiotrace_rw *rw)
251 {
252         struct trace_array *tr = mmio_trace_array;
253         struct trace_array_cpu *data = tr->data[smp_processor_id()];
254         __trace_mmiotrace_rw(tr, data, rw);
255 }
256
257 void mmio_trace_mapping(struct mmiotrace_map *map)
258 {
259         struct trace_array *tr = mmio_trace_array;
260         struct trace_array_cpu *data;
261
262         preempt_disable();
263         data = tr->data[smp_processor_id()];
264         __trace_mmiotrace_map(tr, data, map);
265         preempt_enable();
266 }