diff options
Diffstat (limited to 'kernel/trace/trace_mmiotrace.c')
-rw-r--r-- | kernel/trace/trace_mmiotrace.c | 153 |
1 files changed, 112 insertions, 41 deletions
diff --git a/kernel/trace/trace_mmiotrace.c b/kernel/trace/trace_mmiotrace.c index b13dc19dcbb4..fffcb069f1dc 100644 --- a/kernel/trace/trace_mmiotrace.c +++ b/kernel/trace/trace_mmiotrace.c | |||
@@ -18,46 +18,39 @@ struct header_iter { | |||
18 | 18 | ||
19 | static struct trace_array *mmio_trace_array; | 19 | static struct trace_array *mmio_trace_array; |
20 | static bool overrun_detected; | 20 | static bool overrun_detected; |
21 | static unsigned long prev_overruns; | ||
21 | 22 | ||
22 | static void mmio_reset_data(struct trace_array *tr) | 23 | static void mmio_reset_data(struct trace_array *tr) |
23 | { | 24 | { |
24 | int cpu; | ||
25 | |||
26 | overrun_detected = false; | 25 | overrun_detected = false; |
27 | tr->time_start = ftrace_now(tr->cpu); | 26 | prev_overruns = 0; |
28 | 27 | ||
29 | for_each_online_cpu(cpu) | 28 | tracing_reset_online_cpus(tr); |
30 | tracing_reset(tr->data[cpu]); | ||
31 | } | 29 | } |
32 | 30 | ||
33 | static void mmio_trace_init(struct trace_array *tr) | 31 | static int mmio_trace_init(struct trace_array *tr) |
34 | { | 32 | { |
35 | pr_debug("in %s\n", __func__); | 33 | pr_debug("in %s\n", __func__); |
36 | mmio_trace_array = tr; | 34 | mmio_trace_array = tr; |
37 | if (tr->ctrl) { | 35 | |
38 | mmio_reset_data(tr); | 36 | mmio_reset_data(tr); |
39 | enable_mmiotrace(); | 37 | enable_mmiotrace(); |
40 | } | 38 | return 0; |
41 | } | 39 | } |
42 | 40 | ||
43 | static void mmio_trace_reset(struct trace_array *tr) | 41 | static void mmio_trace_reset(struct trace_array *tr) |
44 | { | 42 | { |
45 | pr_debug("in %s\n", __func__); | 43 | pr_debug("in %s\n", __func__); |
46 | if (tr->ctrl) | 44 | |
47 | disable_mmiotrace(); | 45 | disable_mmiotrace(); |
48 | mmio_reset_data(tr); | 46 | mmio_reset_data(tr); |
49 | mmio_trace_array = NULL; | 47 | mmio_trace_array = NULL; |
50 | } | 48 | } |
51 | 49 | ||
52 | static void mmio_trace_ctrl_update(struct trace_array *tr) | 50 | static void mmio_trace_start(struct trace_array *tr) |
53 | { | 51 | { |
54 | pr_debug("in %s\n", __func__); | 52 | pr_debug("in %s\n", __func__); |
55 | if (tr->ctrl) { | 53 | mmio_reset_data(tr); |
56 | mmio_reset_data(tr); | ||
57 | enable_mmiotrace(); | ||
58 | } else { | ||
59 | disable_mmiotrace(); | ||
60 | } | ||
61 | } | 54 | } |
62 | 55 | ||
63 | static int mmio_print_pcidev(struct trace_seq *s, const struct pci_dev *dev) | 56 | static int mmio_print_pcidev(struct trace_seq *s, const struct pci_dev *dev) |
@@ -128,12 +121,12 @@ static void mmio_close(struct trace_iterator *iter) | |||
128 | 121 | ||
129 | static unsigned long count_overruns(struct trace_iterator *iter) | 122 | static unsigned long count_overruns(struct trace_iterator *iter) |
130 | { | 123 | { |
131 | int cpu; | ||
132 | unsigned long cnt = 0; | 124 | unsigned long cnt = 0; |
133 | for_each_online_cpu(cpu) { | 125 | unsigned long over = ring_buffer_overruns(iter->tr->buffer); |
134 | cnt += iter->overrun[cpu]; | 126 | |
135 | iter->overrun[cpu] = 0; | 127 | if (over > prev_overruns) |
136 | } | 128 | cnt = over - prev_overruns; |
129 | prev_overruns = over; | ||
137 | return cnt; | 130 | return cnt; |
138 | } | 131 | } |
139 | 132 | ||
@@ -171,17 +164,21 @@ print_out: | |||
171 | return (ret == -EBUSY) ? 0 : ret; | 164 | return (ret == -EBUSY) ? 0 : ret; |
172 | } | 165 | } |
173 | 166 | ||
174 | static int mmio_print_rw(struct trace_iterator *iter) | 167 | static enum print_line_t mmio_print_rw(struct trace_iterator *iter) |
175 | { | 168 | { |
176 | struct trace_entry *entry = iter->ent; | 169 | struct trace_entry *entry = iter->ent; |
177 | struct mmiotrace_rw *rw = &entry->mmiorw; | 170 | struct trace_mmiotrace_rw *field; |
171 | struct mmiotrace_rw *rw; | ||
178 | struct trace_seq *s = &iter->seq; | 172 | struct trace_seq *s = &iter->seq; |
179 | unsigned long long t = ns2usecs(entry->t); | 173 | unsigned long long t = ns2usecs(iter->ts); |
180 | unsigned long usec_rem = do_div(t, 1000000ULL); | 174 | unsigned long usec_rem = do_div(t, 1000000ULL); |
181 | unsigned secs = (unsigned long)t; | 175 | unsigned secs = (unsigned long)t; |
182 | int ret = 1; | 176 | int ret = 1; |
183 | 177 | ||
184 | switch (entry->mmiorw.opcode) { | 178 | trace_assign_type(field, entry); |
179 | rw = &field->rw; | ||
180 | |||
181 | switch (rw->opcode) { | ||
185 | case MMIO_READ: | 182 | case MMIO_READ: |
186 | ret = trace_seq_printf(s, | 183 | ret = trace_seq_printf(s, |
187 | "R %d %lu.%06lu %d 0x%llx 0x%lx 0x%lx %d\n", | 184 | "R %d %lu.%06lu %d 0x%llx 0x%lx 0x%lx %d\n", |
@@ -209,21 +206,25 @@ static int mmio_print_rw(struct trace_iterator *iter) | |||
209 | break; | 206 | break; |
210 | } | 207 | } |
211 | if (ret) | 208 | if (ret) |
212 | return 1; | 209 | return TRACE_TYPE_HANDLED; |
213 | return 0; | 210 | return TRACE_TYPE_PARTIAL_LINE; |
214 | } | 211 | } |
215 | 212 | ||
216 | static int mmio_print_map(struct trace_iterator *iter) | 213 | static enum print_line_t mmio_print_map(struct trace_iterator *iter) |
217 | { | 214 | { |
218 | struct trace_entry *entry = iter->ent; | 215 | struct trace_entry *entry = iter->ent; |
219 | struct mmiotrace_map *m = &entry->mmiomap; | 216 | struct trace_mmiotrace_map *field; |
217 | struct mmiotrace_map *m; | ||
220 | struct trace_seq *s = &iter->seq; | 218 | struct trace_seq *s = &iter->seq; |
221 | unsigned long long t = ns2usecs(entry->t); | 219 | unsigned long long t = ns2usecs(iter->ts); |
222 | unsigned long usec_rem = do_div(t, 1000000ULL); | 220 | unsigned long usec_rem = do_div(t, 1000000ULL); |
223 | unsigned secs = (unsigned long)t; | 221 | unsigned secs = (unsigned long)t; |
224 | int ret = 1; | 222 | int ret; |
225 | 223 | ||
226 | switch (entry->mmiorw.opcode) { | 224 | trace_assign_type(field, entry); |
225 | m = &field->map; | ||
226 | |||
227 | switch (m->opcode) { | ||
227 | case MMIO_PROBE: | 228 | case MMIO_PROBE: |
228 | ret = trace_seq_printf(s, | 229 | ret = trace_seq_printf(s, |
229 | "MAP %lu.%06lu %d 0x%llx 0x%lx 0x%lx 0x%lx %d\n", | 230 | "MAP %lu.%06lu %d 0x%llx 0x%lx 0x%lx 0x%lx %d\n", |
@@ -241,20 +242,43 @@ static int mmio_print_map(struct trace_iterator *iter) | |||
241 | break; | 242 | break; |
242 | } | 243 | } |
243 | if (ret) | 244 | if (ret) |
244 | return 1; | 245 | return TRACE_TYPE_HANDLED; |
245 | return 0; | 246 | return TRACE_TYPE_PARTIAL_LINE; |
247 | } | ||
248 | |||
249 | static enum print_line_t mmio_print_mark(struct trace_iterator *iter) | ||
250 | { | ||
251 | struct trace_entry *entry = iter->ent; | ||
252 | struct print_entry *print = (struct print_entry *)entry; | ||
253 | const char *msg = print->buf; | ||
254 | struct trace_seq *s = &iter->seq; | ||
255 | unsigned long long t = ns2usecs(iter->ts); | ||
256 | unsigned long usec_rem = do_div(t, 1000000ULL); | ||
257 | unsigned secs = (unsigned long)t; | ||
258 | int ret; | ||
259 | |||
260 | /* The trailing newline must be in the message. */ | ||
261 | ret = trace_seq_printf(s, "MARK %lu.%06lu %s", secs, usec_rem, msg); | ||
262 | if (!ret) | ||
263 | return TRACE_TYPE_PARTIAL_LINE; | ||
264 | |||
265 | if (entry->flags & TRACE_FLAG_CONT) | ||
266 | trace_seq_print_cont(s, iter); | ||
267 | |||
268 | return TRACE_TYPE_HANDLED; | ||
246 | } | 269 | } |
247 | 270 | ||
248 | /* return 0 to abort printing without consuming current entry in pipe mode */ | 271 | static enum print_line_t mmio_print_line(struct trace_iterator *iter) |
249 | static int mmio_print_line(struct trace_iterator *iter) | ||
250 | { | 272 | { |
251 | switch (iter->ent->type) { | 273 | switch (iter->ent->type) { |
252 | case TRACE_MMIO_RW: | 274 | case TRACE_MMIO_RW: |
253 | return mmio_print_rw(iter); | 275 | return mmio_print_rw(iter); |
254 | case TRACE_MMIO_MAP: | 276 | case TRACE_MMIO_MAP: |
255 | return mmio_print_map(iter); | 277 | return mmio_print_map(iter); |
278 | case TRACE_PRINT: | ||
279 | return mmio_print_mark(iter); | ||
256 | default: | 280 | default: |
257 | return 1; /* ignore unknown entries */ | 281 | return TRACE_TYPE_HANDLED; /* ignore unknown entries */ |
258 | } | 282 | } |
259 | } | 283 | } |
260 | 284 | ||
@@ -263,10 +287,10 @@ static struct tracer mmio_tracer __read_mostly = | |||
263 | .name = "mmiotrace", | 287 | .name = "mmiotrace", |
264 | .init = mmio_trace_init, | 288 | .init = mmio_trace_init, |
265 | .reset = mmio_trace_reset, | 289 | .reset = mmio_trace_reset, |
290 | .start = mmio_trace_start, | ||
266 | .pipe_open = mmio_pipe_open, | 291 | .pipe_open = mmio_pipe_open, |
267 | .close = mmio_close, | 292 | .close = mmio_close, |
268 | .read = mmio_read, | 293 | .read = mmio_read, |
269 | .ctrl_update = mmio_trace_ctrl_update, | ||
270 | .print_line = mmio_print_line, | 294 | .print_line = mmio_print_line, |
271 | }; | 295 | }; |
272 | 296 | ||
@@ -276,6 +300,27 @@ __init static int init_mmio_trace(void) | |||
276 | } | 300 | } |
277 | device_initcall(init_mmio_trace); | 301 | device_initcall(init_mmio_trace); |
278 | 302 | ||
303 | static void __trace_mmiotrace_rw(struct trace_array *tr, | ||
304 | struct trace_array_cpu *data, | ||
305 | struct mmiotrace_rw *rw) | ||
306 | { | ||
307 | struct ring_buffer_event *event; | ||
308 | struct trace_mmiotrace_rw *entry; | ||
309 | unsigned long irq_flags; | ||
310 | |||
311 | event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry), | ||
312 | &irq_flags); | ||
313 | if (!event) | ||
314 | return; | ||
315 | entry = ring_buffer_event_data(event); | ||
316 | tracing_generic_entry_update(&entry->ent, 0, preempt_count()); | ||
317 | entry->ent.type = TRACE_MMIO_RW; | ||
318 | entry->rw = *rw; | ||
319 | ring_buffer_unlock_commit(tr->buffer, event, irq_flags); | ||
320 | |||
321 | trace_wake_up(); | ||
322 | } | ||
323 | |||
279 | void mmio_trace_rw(struct mmiotrace_rw *rw) | 324 | void mmio_trace_rw(struct mmiotrace_rw *rw) |
280 | { | 325 | { |
281 | struct trace_array *tr = mmio_trace_array; | 326 | struct trace_array *tr = mmio_trace_array; |
@@ -283,6 +328,27 @@ void mmio_trace_rw(struct mmiotrace_rw *rw) | |||
283 | __trace_mmiotrace_rw(tr, data, rw); | 328 | __trace_mmiotrace_rw(tr, data, rw); |
284 | } | 329 | } |
285 | 330 | ||
331 | static void __trace_mmiotrace_map(struct trace_array *tr, | ||
332 | struct trace_array_cpu *data, | ||
333 | struct mmiotrace_map *map) | ||
334 | { | ||
335 | struct ring_buffer_event *event; | ||
336 | struct trace_mmiotrace_map *entry; | ||
337 | unsigned long irq_flags; | ||
338 | |||
339 | event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry), | ||
340 | &irq_flags); | ||
341 | if (!event) | ||
342 | return; | ||
343 | entry = ring_buffer_event_data(event); | ||
344 | tracing_generic_entry_update(&entry->ent, 0, preempt_count()); | ||
345 | entry->ent.type = TRACE_MMIO_MAP; | ||
346 | entry->map = *map; | ||
347 | ring_buffer_unlock_commit(tr->buffer, event, irq_flags); | ||
348 | |||
349 | trace_wake_up(); | ||
350 | } | ||
351 | |||
286 | void mmio_trace_mapping(struct mmiotrace_map *map) | 352 | void mmio_trace_mapping(struct mmiotrace_map *map) |
287 | { | 353 | { |
288 | struct trace_array *tr = mmio_trace_array; | 354 | struct trace_array *tr = mmio_trace_array; |
@@ -293,3 +359,8 @@ void mmio_trace_mapping(struct mmiotrace_map *map) | |||
293 | __trace_mmiotrace_map(tr, data, map); | 359 | __trace_mmiotrace_map(tr, data, map); |
294 | preempt_enable(); | 360 | preempt_enable(); |
295 | } | 361 | } |
362 | |||
363 | int mmio_trace_printk(const char *fmt, va_list args) | ||
364 | { | ||
365 | return trace_vprintk(0, -1, fmt, args); | ||
366 | } | ||