Blame view
kernel/trace/trace_mmiotrace.c
8.98 KB
f984b51e0 ftrace: add mmiot... |
1 2 3 4 5 6 7 8 9 10 |
/* * Memory mapped I/O tracing * * Copyright (C) 2008 Pekka Paalanen <pq@iki.fi> */ #define DEBUG 1 #include <linux/kernel.h> #include <linux/mmiotrace.h> |
138295373 ftrace: mmiotrace... |
11 |
#include <linux/pci.h> |
5a0e3ad6a include cleanup: ... |
12 |
#include <linux/slab.h> |
a5dec5573 tracing: use macr... |
13 |
#include <linux/time.h> |
60063497a atomic: use <linu... |
14 |
#include <linux/atomic.h> |
f984b51e0 ftrace: add mmiot... |
15 16 |
#include "trace.h" |
f0868d1e2 ftrace: set up tr... |
17 |
#include "trace_output.h" |
f984b51e0 ftrace: add mmiot... |
18 |
|
d0a7e8ca5 mmiotrace: print ... |
19 20 21 |
struct header_iter { struct pci_dev *dev; }; |
f984b51e0 ftrace: add mmiot... |
22 |
static struct trace_array *mmio_trace_array; |
2039238b7 mmiotrace: print ... |
23 |
static bool overrun_detected; |
7ee1768dd x86, mmiotrace: f... |
24 |
static unsigned long prev_overruns; |
173ed24ee mmiotrace: count ... |
25 |
static atomic_t dropped_count; |
f984b51e0 ftrace: add mmiot... |
26 |
|
bd8ac686c ftrace: mmiotrace... |
27 28 |
static void mmio_reset_data(struct trace_array *tr) { |
2039238b7 mmiotrace: print ... |
29 |
overrun_detected = false; |
7ee1768dd x86, mmiotrace: f... |
30 |
prev_overruns = 0; |
bd8ac686c ftrace: mmiotrace... |
31 |
|
213cc0607 ftrace: introduce... |
32 |
tracing_reset_online_cpus(tr); |
bd8ac686c ftrace: mmiotrace... |
33 |
} |
f984b51e0 ftrace: add mmiot... |
34 |
|
1c80025a4 tracing/ftrace: c... |
35 |
static int mmio_trace_init(struct trace_array *tr) |
f984b51e0 ftrace: add mmiot... |
36 37 38 39 |
{ pr_debug("in %s ", __func__); mmio_trace_array = tr; |
c76f06945 ftrace: remove tr... |
40 41 42 |
mmio_reset_data(tr); enable_mmiotrace(); |
1c80025a4 tracing/ftrace: c... |
43 |
return 0; |
f984b51e0 ftrace: add mmiot... |
44 45 46 47 48 49 |
} static void mmio_trace_reset(struct trace_array *tr) { pr_debug("in %s ", __func__); |
c76f06945 ftrace: remove tr... |
50 51 |
disable_mmiotrace(); |
bd8ac686c ftrace: mmiotrace... |
52 53 |
mmio_reset_data(tr); mmio_trace_array = NULL; |
f984b51e0 ftrace: add mmiot... |
54 |
} |
bbf5b1a0c ftrace: remove ct... |
55 |
static void mmio_trace_start(struct trace_array *tr) |
f984b51e0 ftrace: add mmiot... |
56 57 58 |
{ pr_debug("in %s ", __func__); |
bbf5b1a0c ftrace: remove ct... |
59 |
mmio_reset_data(tr); |
bd8ac686c ftrace: mmiotrace... |
60 |
} |
138295373 ftrace: mmiotrace... |
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
static int mmio_print_pcidev(struct trace_seq *s, const struct pci_dev *dev) { int ret = 0; int i; resource_size_t start, end; const struct pci_driver *drv = pci_dev_driver(dev); /* XXX: incomplete checks for trace_seq_printf() return value */ ret += trace_seq_printf(s, "PCIDEV %02x%02x %04x%04x %x", dev->bus->number, dev->devfn, dev->vendor, dev->device, dev->irq); /* * XXX: is pci_resource_to_user() appropriate, since we are * supposed to interpret the __ioremap() phys_addr argument based on * these printed values? */ for (i = 0; i < 7; i++) { pci_resource_to_user(dev, i, &dev->resource[i], &start, &end); ret += trace_seq_printf(s, " %llx", (unsigned long long)(start | (dev->resource[i].flags & PCI_REGION_FLAG_MASK))); } for (i = 0; i < 7; i++) { pci_resource_to_user(dev, i, &dev->resource[i], &start, &end); ret += trace_seq_printf(s, " %llx", dev->resource[i].start < dev->resource[i].end ? (unsigned long long)(end - start) + 1 : 0); } if (drv) ret += trace_seq_printf(s, " %s ", drv->name); else ret += trace_seq_printf(s, " "); return ret; } |
d0a7e8ca5 mmiotrace: print ... |
97 98 99 100 101 102 103 104 105 |
static void destroy_header_iter(struct header_iter *hiter) { if (!hiter) return; pci_dev_put(hiter->dev); kfree(hiter); } static void mmio_pipe_open(struct trace_iterator *iter) |
bd8ac686c ftrace: mmiotrace... |
106 |
{ |
d0a7e8ca5 mmiotrace: print ... |
107 |
struct header_iter *hiter; |
bd8ac686c ftrace: mmiotrace... |
108 |
struct trace_seq *s = &iter->seq; |
138295373 ftrace: mmiotrace... |
109 110 111 |
trace_seq_printf(s, "VERSION 20070824 "); |
d0a7e8ca5 mmiotrace: print ... |
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
hiter = kzalloc(sizeof(*hiter), GFP_KERNEL); if (!hiter) return; hiter->dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); iter->private = hiter; } /* XXX: This is not called when the pipe is closed! */ static void mmio_close(struct trace_iterator *iter) { struct header_iter *hiter = iter->private; destroy_header_iter(hiter); iter->private = NULL; } |
2039238b7 mmiotrace: print ... |
127 128 |
static unsigned long count_overruns(struct trace_iterator *iter) { |
173ed24ee mmiotrace: count ... |
129 |
unsigned long cnt = atomic_xchg(&dropped_count, 0); |
7ee1768dd x86, mmiotrace: f... |
130 131 132 |
unsigned long over = ring_buffer_overruns(iter->tr->buffer); if (over > prev_overruns) |
173ed24ee mmiotrace: count ... |
133 |
cnt += over - prev_overruns; |
7ee1768dd x86, mmiotrace: f... |
134 |
prev_overruns = over; |
2039238b7 mmiotrace: print ... |
135 136 |
return cnt; } |
d0a7e8ca5 mmiotrace: print ... |
137 138 139 140 141 142 |
static ssize_t mmio_read(struct trace_iterator *iter, struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) { ssize_t ret; struct header_iter *hiter = iter->private; struct trace_seq *s = &iter->seq; |
2039238b7 mmiotrace: print ... |
143 144 145 146 147 148 149 150 151 152 153 154 155 |
unsigned long n; n = count_overruns(iter); if (n) { /* XXX: This is later than where events were lost. */ trace_seq_printf(s, "MARK 0.000000 Lost %lu events. ", n); if (!overrun_detected) pr_warning("mmiotrace has lost events. "); overrun_detected = true; goto print_out; } |
d0a7e8ca5 mmiotrace: print ... |
156 157 158 159 160 161 162 163 164 165 166 |
if (!hiter) return 0; mmio_print_pcidev(s, hiter->dev); hiter->dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, hiter->dev); if (!hiter->dev) { destroy_header_iter(hiter); iter->private = NULL; } |
2039238b7 mmiotrace: print ... |
167 |
print_out: |
d0a7e8ca5 mmiotrace: print ... |
168 169 |
ret = trace_seq_to_user(s, ubuf, cnt); return (ret == -EBUSY) ? 0 : ret; |
bd8ac686c ftrace: mmiotrace... |
170 |
} |
07f4e4f79 tracing/ftrace: a... |
171 |
static enum print_line_t mmio_print_rw(struct trace_iterator *iter) |
bd8ac686c ftrace: mmiotrace... |
172 173 |
{ struct trace_entry *entry = iter->ent; |
7104f300c ftrace: type cast... |
174 175 |
struct trace_mmiotrace_rw *field; struct mmiotrace_rw *rw; |
bd8ac686c ftrace: mmiotrace... |
176 |
struct trace_seq *s = &iter->seq; |
3928a8a2d ftrace: make work... |
177 |
unsigned long long t = ns2usecs(iter->ts); |
a5dec5573 tracing: use macr... |
178 |
unsigned long usec_rem = do_div(t, USEC_PER_SEC); |
bd8ac686c ftrace: mmiotrace... |
179 180 |
unsigned secs = (unsigned long)t; int ret = 1; |
7104f300c ftrace: type cast... |
181 182 |
trace_assign_type(field, entry); rw = &field->rw; |
777e208d4 ftrace: take adva... |
183 |
switch (rw->opcode) { |
bd8ac686c ftrace: mmiotrace... |
184 185 |
case MMIO_READ: ret = trace_seq_printf(s, |
5e4abc983 trace: clean up f... |
186 187 |
"R %d %u.%06lu %d 0x%llx 0x%lx 0x%lx %d ", |
dee310d0a x86 mmiotrace: us... |
188 189 |
rw->width, secs, usec_rem, rw->map_id, (unsigned long long)rw->phys, |
736ca61fa x86 mmiotrace: Do... |
190 |
rw->value, rw->pc, 0); |
bd8ac686c ftrace: mmiotrace... |
191 192 193 |
break; case MMIO_WRITE: ret = trace_seq_printf(s, |
5e4abc983 trace: clean up f... |
194 195 |
"W %d %u.%06lu %d 0x%llx 0x%lx 0x%lx %d ", |
dee310d0a x86 mmiotrace: us... |
196 197 |
rw->width, secs, usec_rem, rw->map_id, (unsigned long long)rw->phys, |
736ca61fa x86 mmiotrace: Do... |
198 |
rw->value, rw->pc, 0); |
bd8ac686c ftrace: mmiotrace... |
199 200 201 |
break; case MMIO_UNKNOWN_OP: ret = trace_seq_printf(s, |
5e4abc983 trace: clean up f... |
202 203 204 |
"UNKNOWN %u.%06lu %d 0x%llx %02lx,%02lx," "%02lx 0x%lx %d ", |
dee310d0a x86 mmiotrace: us... |
205 206 |
secs, usec_rem, rw->map_id, (unsigned long long)rw->phys, |
bd8ac686c ftrace: mmiotrace... |
207 |
(rw->value >> 16) & 0xff, (rw->value >> 8) & 0xff, |
736ca61fa x86 mmiotrace: Do... |
208 |
(rw->value >> 0) & 0xff, rw->pc, 0); |
bd8ac686c ftrace: mmiotrace... |
209 210 211 212 213 214 215 |
break; default: ret = trace_seq_printf(s, "rw what? "); break; } if (ret) |
07f4e4f79 tracing/ftrace: a... |
216 217 |
return TRACE_TYPE_HANDLED; return TRACE_TYPE_PARTIAL_LINE; |
bd8ac686c ftrace: mmiotrace... |
218 |
} |
07f4e4f79 tracing/ftrace: a... |
219 |
static enum print_line_t mmio_print_map(struct trace_iterator *iter) |
bd8ac686c ftrace: mmiotrace... |
220 221 |
{ struct trace_entry *entry = iter->ent; |
7104f300c ftrace: type cast... |
222 223 |
struct trace_mmiotrace_map *field; struct mmiotrace_map *m; |
bd8ac686c ftrace: mmiotrace... |
224 |
struct trace_seq *s = &iter->seq; |
3928a8a2d ftrace: make work... |
225 |
unsigned long long t = ns2usecs(iter->ts); |
a5dec5573 tracing: use macr... |
226 |
unsigned long usec_rem = do_div(t, USEC_PER_SEC); |
bd8ac686c ftrace: mmiotrace... |
227 |
unsigned secs = (unsigned long)t; |
07f4e4f79 tracing/ftrace: a... |
228 |
int ret; |
bd8ac686c ftrace: mmiotrace... |
229 |
|
7104f300c ftrace: type cast... |
230 231 |
trace_assign_type(field, entry); m = &field->map; |
777e208d4 ftrace: take adva... |
232 |
switch (m->opcode) { |
bd8ac686c ftrace: mmiotrace... |
233 234 |
case MMIO_PROBE: ret = trace_seq_printf(s, |
5e4abc983 trace: clean up f... |
235 236 |
"MAP %u.%06lu %d 0x%llx 0x%lx 0x%lx 0x%lx %d ", |
dee310d0a x86 mmiotrace: us... |
237 238 |
secs, usec_rem, m->map_id, (unsigned long long)m->phys, m->virt, m->len, |
e0fd5c2fa mmiotrace: do not... |
239 |
0UL, 0); |
bd8ac686c ftrace: mmiotrace... |
240 241 242 |
break; case MMIO_UNPROBE: ret = trace_seq_printf(s, |
5e4abc983 trace: clean up f... |
243 244 |
"UNMAP %u.%06lu %d 0x%lx %d ", |
e0fd5c2fa mmiotrace: do not... |
245 |
secs, usec_rem, m->map_id, 0UL, 0); |
bd8ac686c ftrace: mmiotrace... |
246 247 248 249 250 251 252 |
break; default: ret = trace_seq_printf(s, "map what? "); break; } if (ret) |
07f4e4f79 tracing/ftrace: a... |
253 254 |
return TRACE_TYPE_HANDLED; return TRACE_TYPE_PARTIAL_LINE; |
bd8ac686c ftrace: mmiotrace... |
255 |
} |
07f4e4f79 tracing/ftrace: a... |
256 |
static enum print_line_t mmio_print_mark(struct trace_iterator *iter) |
fc5e27ae4 mmiotrace: handle... |
257 258 |
{ struct trace_entry *entry = iter->ent; |
777e208d4 ftrace: take adva... |
259 |
struct print_entry *print = (struct print_entry *)entry; |
48ead0203 tracing/core: bri... |
260 |
const char *msg = print->buf; |
fc5e27ae4 mmiotrace: handle... |
261 |
struct trace_seq *s = &iter->seq; |
3928a8a2d ftrace: make work... |
262 |
unsigned long long t = ns2usecs(iter->ts); |
769b0441f tracing/core: dro... |
263 |
unsigned long usec_rem = do_div(t, USEC_PER_SEC); |
fc5e27ae4 mmiotrace: handle... |
264 265 266 267 |
unsigned secs = (unsigned long)t; int ret; /* The trailing newline must be in the message. */ |
48ead0203 tracing/core: bri... |
268 |
ret = trace_seq_printf(s, "MARK %u.%06lu %s", secs, usec_rem, msg); |
fc5e27ae4 mmiotrace: handle... |
269 |
if (!ret) |
07f4e4f79 tracing/ftrace: a... |
270 |
return TRACE_TYPE_PARTIAL_LINE; |
fc5e27ae4 mmiotrace: handle... |
271 |
|
07f4e4f79 tracing/ftrace: a... |
272 |
return TRACE_TYPE_HANDLED; |
fc5e27ae4 mmiotrace: handle... |
273 |
} |
07f4e4f79 tracing/ftrace: a... |
274 |
static enum print_line_t mmio_print_line(struct trace_iterator *iter) |
bd8ac686c ftrace: mmiotrace... |
275 276 277 278 279 280 |
{ switch (iter->ent->type) { case TRACE_MMIO_RW: return mmio_print_rw(iter); case TRACE_MMIO_MAP: return mmio_print_map(iter); |
fc5e27ae4 mmiotrace: handle... |
281 282 |
case TRACE_PRINT: return mmio_print_mark(iter); |
bd8ac686c ftrace: mmiotrace... |
283 |
default: |
07f4e4f79 tracing/ftrace: a... |
284 |
return TRACE_TYPE_HANDLED; /* ignore unknown entries */ |
bd8ac686c ftrace: mmiotrace... |
285 |
} |
f984b51e0 ftrace: add mmiot... |
286 287 288 289 290 291 292 |
} static struct tracer mmio_tracer __read_mostly = { .name = "mmiotrace", .init = mmio_trace_init, .reset = mmio_trace_reset, |
bbf5b1a0c ftrace: remove ct... |
293 |
.start = mmio_trace_start, |
d0a7e8ca5 mmiotrace: print ... |
294 295 296 |
.pipe_open = mmio_pipe_open, .close = mmio_close, .read = mmio_read, |
bd8ac686c ftrace: mmiotrace... |
297 |
.print_line = mmio_print_line, |
f984b51e0 ftrace: add mmiot... |
298 299 300 301 |
}; __init static int init_mmio_trace(void) { |
f984b51e0 ftrace: add mmiot... |
302 303 304 |
return register_tracer(&mmio_tracer); } device_initcall(init_mmio_trace); |
45dcd8b8a ftrace: move mmio... |
305 306 307 308 |
static void __trace_mmiotrace_rw(struct trace_array *tr, struct trace_array_cpu *data, struct mmiotrace_rw *rw) { |
60ba77022 tracing: add filt... |
309 |
struct ftrace_event_call *call = &event_mmiotrace_rw; |
e77405ad8 tracing: pass aro... |
310 |
struct ring_buffer *buffer = tr->buffer; |
3928a8a2d ftrace: make work... |
311 |
struct ring_buffer_event *event; |
777e208d4 ftrace: take adva... |
312 |
struct trace_mmiotrace_rw *entry; |
51a763dd8 tracing: Introduc... |
313 |
int pc = preempt_count(); |
45dcd8b8a ftrace: move mmio... |
314 |
|
e77405ad8 tracing: pass aro... |
315 |
event = trace_buffer_lock_reserve(buffer, TRACE_MMIO_RW, |
51a763dd8 tracing: Introduc... |
316 |
sizeof(*entry), 0, pc); |
173ed24ee mmiotrace: count ... |
317 318 |
if (!event) { atomic_inc(&dropped_count); |
3928a8a2d ftrace: make work... |
319 |
return; |
173ed24ee mmiotrace: count ... |
320 |
} |
3928a8a2d ftrace: make work... |
321 |
entry = ring_buffer_event_data(event); |
777e208d4 ftrace: take adva... |
322 |
entry->rw = *rw; |
60ba77022 tracing: add filt... |
323 324 325 |
if (!filter_check_discard(call, entry, buffer, event)) trace_buffer_unlock_commit(buffer, event, 0, pc); |
45dcd8b8a ftrace: move mmio... |
326 |
} |
bd8ac686c ftrace: mmiotrace... |
327 |
void mmio_trace_rw(struct mmiotrace_rw *rw) |
f984b51e0 ftrace: add mmiot... |
328 329 330 |
{ struct trace_array *tr = mmio_trace_array; struct trace_array_cpu *data = tr->data[smp_processor_id()]; |
bd8ac686c ftrace: mmiotrace... |
331 332 |
__trace_mmiotrace_rw(tr, data, rw); } |
f984b51e0 ftrace: add mmiot... |
333 |
|
45dcd8b8a ftrace: move mmio... |
334 335 336 337 |
static void __trace_mmiotrace_map(struct trace_array *tr, struct trace_array_cpu *data, struct mmiotrace_map *map) { |
60ba77022 tracing: add filt... |
338 |
struct ftrace_event_call *call = &event_mmiotrace_map; |
e77405ad8 tracing: pass aro... |
339 |
struct ring_buffer *buffer = tr->buffer; |
3928a8a2d ftrace: make work... |
340 |
struct ring_buffer_event *event; |
777e208d4 ftrace: take adva... |
341 |
struct trace_mmiotrace_map *entry; |
51a763dd8 tracing: Introduc... |
342 |
int pc = preempt_count(); |
45dcd8b8a ftrace: move mmio... |
343 |
|
e77405ad8 tracing: pass aro... |
344 |
event = trace_buffer_lock_reserve(buffer, TRACE_MMIO_MAP, |
51a763dd8 tracing: Introduc... |
345 |
sizeof(*entry), 0, pc); |
173ed24ee mmiotrace: count ... |
346 347 |
if (!event) { atomic_inc(&dropped_count); |
3928a8a2d ftrace: make work... |
348 |
return; |
173ed24ee mmiotrace: count ... |
349 |
} |
3928a8a2d ftrace: make work... |
350 |
entry = ring_buffer_event_data(event); |
777e208d4 ftrace: take adva... |
351 |
entry->map = *map; |
60ba77022 tracing: add filt... |
352 353 354 |
if (!filter_check_discard(call, entry, buffer, event)) trace_buffer_unlock_commit(buffer, event, 0, pc); |
45dcd8b8a ftrace: move mmio... |
355 |
} |
bd8ac686c ftrace: mmiotrace... |
356 357 358 359 360 361 362 363 364 |
void mmio_trace_mapping(struct mmiotrace_map *map) { struct trace_array *tr = mmio_trace_array; struct trace_array_cpu *data; preempt_disable(); data = tr->data[smp_processor_id()]; __trace_mmiotrace_map(tr, data, map); preempt_enable(); |
f984b51e0 ftrace: add mmiot... |
365 |
} |
9e57fb35d x86 mmiotrace: im... |
366 367 368 |
int mmio_trace_printk(const char *fmt, va_list args) { |
40ce74f19 tracing: remove r... |
369 |
return trace_vprintk(0, fmt, args); |
9e57fb35d x86 mmiotrace: im... |
370 |
} |