x86 mmiotrace: Do not print bogus pid
[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 static struct trace_array *mmio_trace_array;
16
17 static void mmio_reset_data(struct trace_array *tr)
18 {
19         int cpu;
20
21         tr->time_start = ftrace_now(tr->cpu);
22
23         for_each_online_cpu(cpu)
24                 tracing_reset(tr->data[cpu]);
25 }
26
27 static void mmio_trace_init(struct trace_array *tr)
28 {
29         pr_debug("in %s\n", __func__);
30         mmio_trace_array = tr;
31         if (tr->ctrl) {
32                 mmio_reset_data(tr);
33                 enable_mmiotrace();
34         }
35 }
36
37 static void mmio_trace_reset(struct trace_array *tr)
38 {
39         pr_debug("in %s\n", __func__);
40         if (tr->ctrl)
41                 disable_mmiotrace();
42         mmio_reset_data(tr);
43         mmio_trace_array = NULL;
44 }
45
46 static void mmio_trace_ctrl_update(struct trace_array *tr)
47 {
48         pr_debug("in %s\n", __func__);
49         if (tr->ctrl) {
50                 mmio_reset_data(tr);
51                 enable_mmiotrace();
52         } else {
53                 disable_mmiotrace();
54         }
55 }
56
57 static int mmio_print_pcidev(struct trace_seq *s, const struct pci_dev *dev)
58 {
59         int ret = 0;
60         int i;
61         resource_size_t start, end;
62         const struct pci_driver *drv = pci_dev_driver(dev);
63
64         /* XXX: incomplete checks for trace_seq_printf() return value */
65         ret += trace_seq_printf(s, "PCIDEV %02x%02x %04x%04x %x",
66                                 dev->bus->number, dev->devfn,
67                                 dev->vendor, dev->device, dev->irq);
68         /*
69          * XXX: is pci_resource_to_user() appropriate, since we are
70          * supposed to interpret the __ioremap() phys_addr argument based on
71          * these printed values?
72          */
73         for (i = 0; i < 7; i++) {
74                 pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
75                 ret += trace_seq_printf(s, " %llx",
76                         (unsigned long long)(start |
77                         (dev->resource[i].flags & PCI_REGION_FLAG_MASK)));
78         }
79         for (i = 0; i < 7; i++) {
80                 pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
81                 ret += trace_seq_printf(s, " %llx",
82                         dev->resource[i].start < dev->resource[i].end ?
83                         (unsigned long long)(end - start) + 1 : 0);
84         }
85         if (drv)
86                 ret += trace_seq_printf(s, " %s\n", drv->name);
87         else
88                 ret += trace_seq_printf(s, " \n");
89         return ret;
90 }
91
92 /* XXX: This is not called for trace_pipe file! */
93 static void mmio_print_header(struct trace_iterator *iter)
94 {
95         struct trace_seq *s = &iter->seq;
96         struct pci_dev *dev = NULL;
97
98         trace_seq_printf(s, "VERSION 20070824\n");
99
100         for_each_pci_dev(dev)
101                 mmio_print_pcidev(s, dev);
102         /* XXX: return value? What if header is very long? */
103 }
104
105 static int mmio_print_rw(struct trace_iterator *iter)
106 {
107         struct trace_entry *entry = iter->ent;
108         struct mmiotrace_rw *rw = &entry->mmiorw;
109         struct trace_seq *s     = &iter->seq;
110         unsigned long long t    = ns2usecs(entry->t);
111         unsigned long usec_rem  = do_div(t, 1000000ULL);
112         unsigned secs           = (unsigned long)t;
113         int ret = 1;
114
115         switch (entry->mmiorw.opcode) {
116         case MMIO_READ:
117                 ret = trace_seq_printf(s,
118                         "R %d %lu.%06lu %d 0x%lx 0x%lx 0x%lx %d\n",
119                         rw->width, secs, usec_rem, rw->map_id, rw->phys,
120                         rw->value, rw->pc, 0);
121                 break;
122         case MMIO_WRITE:
123                 ret = trace_seq_printf(s,
124                         "W %d %lu.%06lu %d 0x%lx 0x%lx 0x%lx %d\n",
125                         rw->width, secs, usec_rem, rw->map_id, rw->phys,
126                         rw->value, rw->pc, 0);
127                 break;
128         case MMIO_UNKNOWN_OP:
129                 ret = trace_seq_printf(s,
130                         "UNKNOWN %lu.%06lu %d 0x%lx %02x,%02x,%02x 0x%lx %d\n",
131                         secs, usec_rem, rw->map_id, rw->phys,
132                         (rw->value >> 16) & 0xff, (rw->value >> 8) & 0xff,
133                         (rw->value >> 0) & 0xff, rw->pc, 0);
134                 break;
135         default:
136                 ret = trace_seq_printf(s, "rw what?\n");
137                 break;
138         }
139         if (ret)
140                 return 1;
141         return 0;
142 }
143
144 static int mmio_print_map(struct trace_iterator *iter)
145 {
146         struct trace_entry *entry = iter->ent;
147         struct mmiotrace_map *m = &entry->mmiomap;
148         struct trace_seq *s     = &iter->seq;
149         unsigned long long t    = ns2usecs(entry->t);
150         unsigned long usec_rem  = do_div(t, 1000000ULL);
151         unsigned secs           = (unsigned long)t;
152         int ret = 1;
153
154         switch (entry->mmiorw.opcode) {
155         case MMIO_PROBE:
156                 ret = trace_seq_printf(s,
157                         "MAP %lu.%06lu %d 0x%lx 0x%lx 0x%lx 0x%lx %d\n",
158                         secs, usec_rem, m->map_id, m->phys, m->virt, m->len,
159                         0UL, entry->pid);
160                 break;
161         case MMIO_UNPROBE:
162                 ret = trace_seq_printf(s,
163                         "UNMAP %lu.%06lu %d 0x%lx %d\n",
164                         secs, usec_rem, m->map_id, 0UL, entry->pid);
165                 break;
166         default:
167                 ret = trace_seq_printf(s, "map what?\n");
168                 break;
169         }
170         if (ret)
171                 return 1;
172         return 0;
173 }
174
175 /* return 0 to abort printing without consuming current entry in pipe mode */
176 static int mmio_print_line(struct trace_iterator *iter)
177 {
178         switch (iter->ent->type) {
179         case TRACE_MMIO_RW:
180                 return mmio_print_rw(iter);
181         case TRACE_MMIO_MAP:
182                 return mmio_print_map(iter);
183         default:
184                 return 1; /* ignore unknown entries */
185         }
186 }
187
188 static struct tracer mmio_tracer __read_mostly =
189 {
190         .name           = "mmiotrace",
191         .init           = mmio_trace_init,
192         .reset          = mmio_trace_reset,
193         .open           = mmio_print_header,
194         .ctrl_update    = mmio_trace_ctrl_update,
195         .print_line     = mmio_print_line,
196 };
197
198 __init static int init_mmio_trace(void)
199 {
200         return register_tracer(&mmio_tracer);
201 }
202 device_initcall(init_mmio_trace);
203
204 void mmio_trace_rw(struct mmiotrace_rw *rw)
205 {
206         struct trace_array *tr = mmio_trace_array;
207         struct trace_array_cpu *data = tr->data[smp_processor_id()];
208         __trace_mmiotrace_rw(tr, data, rw);
209 }
210
211 void mmio_trace_mapping(struct mmiotrace_map *map)
212 {
213         struct trace_array *tr = mmio_trace_array;
214         struct trace_array_cpu *data;
215
216         preempt_disable();
217         data = tr->data[smp_processor_id()];
218         __trace_mmiotrace_map(tr, data, map);
219         preempt_enable();
220 }