ftrace: mmiotrace, updates
[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
12 #include "trace.h"
13
14 static struct trace_array *mmio_trace_array;
15
16 static void mmio_reset_data(struct trace_array *tr)
17 {
18         int cpu;
19
20         tr->time_start = ftrace_now(tr->cpu);
21
22         for_each_online_cpu(cpu)
23                 tracing_reset(tr->data[cpu]);
24 }
25
26 static void mmio_trace_init(struct trace_array *tr)
27 {
28         pr_debug("in %s\n", __func__);
29         mmio_trace_array = tr;
30         if (tr->ctrl) {
31                 mmio_reset_data(tr);
32                 enable_mmiotrace();
33         }
34 }
35
36 static void mmio_trace_reset(struct trace_array *tr)
37 {
38         pr_debug("in %s\n", __func__);
39         if (tr->ctrl)
40                 disable_mmiotrace();
41         mmio_reset_data(tr);
42         mmio_trace_array = NULL;
43 }
44
45 static void mmio_trace_ctrl_update(struct trace_array *tr)
46 {
47         pr_debug("in %s\n", __func__);
48         if (tr->ctrl) {
49                 mmio_reset_data(tr);
50                 enable_mmiotrace();
51         } else {
52                 disable_mmiotrace();
53         }
54 }
55
56 /* XXX: This is not called for trace_pipe file! */
57 void mmio_print_header(struct trace_iterator *iter)
58 {
59         struct trace_seq *s = &iter->seq;
60         trace_seq_printf(s, "VERSION broken 20070824\n");
61         /* TODO: print /proc/bus/pci/devices contents as PCIDEV lines */
62 }
63
64 static int mmio_print_rw(struct trace_iterator *iter)
65 {
66         struct trace_entry *entry = iter->ent;
67         struct mmiotrace_rw *rw = &entry->mmiorw;
68         struct trace_seq *s     = &iter->seq;
69         unsigned long long t    = ns2usecs(entry->t);
70         unsigned long usec_rem  = do_div(t, 1000000ULL);
71         unsigned secs           = (unsigned long)t;
72         int ret = 1;
73
74         switch (entry->mmiorw.opcode) {
75         case MMIO_READ:
76                 ret = trace_seq_printf(s,
77                         "R %d %lu.%06lu %d 0x%lx 0x%lx 0x%lx %d\n",
78                         rw->width, secs, usec_rem, rw->map_id, rw->phys,
79                         rw->value, rw->pc, entry->pid);
80                 break;
81         case MMIO_WRITE:
82                 ret = trace_seq_printf(s,
83                         "W %d %lu.%06lu %d 0x%lx 0x%lx 0x%lx %d\n",
84                         rw->width, secs, usec_rem, rw->map_id, rw->phys,
85                         rw->value, rw->pc, entry->pid);
86                 break;
87         case MMIO_UNKNOWN_OP:
88                 ret = trace_seq_printf(s,
89                         "UNKNOWN %lu.%06lu %d 0x%lx %02x,%02x,%02x 0x%lx %d\n",
90                         secs, usec_rem, rw->map_id, rw->phys,
91                         (rw->value >> 16) & 0xff, (rw->value >> 8) & 0xff,
92                         (rw->value >> 0) & 0xff, rw->pc, entry->pid);
93                 break;
94         default:
95                 ret = trace_seq_printf(s, "rw what?\n");
96                 break;
97         }
98         if (ret)
99                 return 1;
100         return 0;
101 }
102
103 static int mmio_print_map(struct trace_iterator *iter)
104 {
105         struct trace_entry *entry = iter->ent;
106         struct mmiotrace_map *m = &entry->mmiomap;
107         struct trace_seq *s     = &iter->seq;
108         unsigned long long t    = ns2usecs(entry->t);
109         unsigned long usec_rem  = do_div(t, 1000000ULL);
110         unsigned secs           = (unsigned long)t;
111         int ret = 1;
112
113         switch (entry->mmiorw.opcode) {
114         case MMIO_PROBE:
115                 ret = trace_seq_printf(s,
116                         "MAP %lu.%06lu %d 0x%lx 0x%lx 0x%lx 0x%lx %d\n",
117                         secs, usec_rem, m->map_id, m->phys, m->virt, m->len,
118                         0UL, entry->pid);
119                 break;
120         case MMIO_UNPROBE:
121                 ret = trace_seq_printf(s,
122                         "UNMAP %lu.%06lu %d 0x%lx %d\n",
123                         secs, usec_rem, m->map_id, 0UL, entry->pid);
124                 break;
125         default:
126                 ret = trace_seq_printf(s, "map what?\n");
127                 break;
128         }
129         if (ret)
130                 return 1;
131         return 0;
132 }
133
134 /* return 0 to abort printing without consuming current entry in pipe mode */
135 static int mmio_print_line(struct trace_iterator *iter)
136 {
137         switch (iter->ent->type) {
138         case TRACE_MMIO_RW:
139                 return mmio_print_rw(iter);
140         case TRACE_MMIO_MAP:
141                 return mmio_print_map(iter);
142         default:
143                 return 1; /* ignore unknown entries */
144         }
145 }
146
147 static struct tracer mmio_tracer __read_mostly =
148 {
149         .name           = "mmiotrace",
150         .init           = mmio_trace_init,
151         .reset          = mmio_trace_reset,
152         .open           = mmio_print_header,
153         .ctrl_update    = mmio_trace_ctrl_update,
154         .print_line     = mmio_print_line,
155 };
156
157 __init static int init_mmio_trace(void)
158 {
159         return register_tracer(&mmio_tracer);
160 }
161 device_initcall(init_mmio_trace);
162
163 void mmio_trace_rw(struct mmiotrace_rw *rw)
164 {
165         struct trace_array *tr = mmio_trace_array;
166         struct trace_array_cpu *data = tr->data[smp_processor_id()];
167         __trace_mmiotrace_rw(tr, data, rw);
168 }
169
170 void mmio_trace_mapping(struct mmiotrace_map *map)
171 {
172         struct trace_array *tr = mmio_trace_array;
173         struct trace_array_cpu *data;
174
175         preempt_disable();
176         data = tr->data[smp_processor_id()];
177         __trace_mmiotrace_map(tr, data, map);
178         preempt_enable();
179 }