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 static bool overrun_detected; 21 22 static void mmio_reset_data(struct trace_array *tr) 23 { 24 int cpu; 25 26 overrun_detected = false; 27 tr->time_start = ftrace_now(tr->cpu); 28 29 for_each_online_cpu(cpu) 30 tracing_reset(tr, cpu); 31 } 32 33 static void mmio_trace_init(struct trace_array *tr) 34 { 35 pr_debug("in %s\n", __func__); 36 mmio_trace_array = tr; 37 if (tr->ctrl) { 38 mmio_reset_data(tr); 39 enable_mmiotrace(); 40 } 41 } 42 43 static void mmio_trace_reset(struct trace_array *tr) 44 { 45 pr_debug("in %s\n", __func__); 46 if (tr->ctrl) 47 disable_mmiotrace(); 48 mmio_reset_data(tr); 49 mmio_trace_array = NULL; 50 } 51 52 static void mmio_trace_ctrl_update(struct trace_array *tr) 53 { 54 pr_debug("in %s\n", __func__); 55 if (tr->ctrl) { 56 mmio_reset_data(tr); 57 enable_mmiotrace(); 58 } else { 59 disable_mmiotrace(); 60 } 61 } 62 63 static int mmio_print_pcidev(struct trace_seq *s, const struct pci_dev *dev) 64 { 65 int ret = 0; 66 int i; 67 resource_size_t start, end; 68 const struct pci_driver *drv = pci_dev_driver(dev); 69 70 /* XXX: incomplete checks for trace_seq_printf() return value */ 71 ret += trace_seq_printf(s, "PCIDEV %02x%02x %04x%04x %x", 72 dev->bus->number, dev->devfn, 73 dev->vendor, dev->device, dev->irq); 74 /* 75 * XXX: is pci_resource_to_user() appropriate, since we are 76 * supposed to interpret the __ioremap() phys_addr argument based on 77 * these printed values? 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 (unsigned long long)(start | 83 (dev->resource[i].flags & PCI_REGION_FLAG_MASK))); 84 } 85 for (i = 0; i < 7; i++) { 86 pci_resource_to_user(dev, i, &dev->resource[i], &start, &end); 87 ret += trace_seq_printf(s, " %llx", 88 dev->resource[i].start < dev->resource[i].end ? 89 (unsigned long long)(end - start) + 1 : 0); 90 } 91 if (drv) 92 ret += trace_seq_printf(s, " %s\n", drv->name); 93 else 94 ret += trace_seq_printf(s, " \n"); 95 return ret; 96 } 97 98 static void destroy_header_iter(struct header_iter *hiter) 99 { 100 if (!hiter) 101 return; 102 pci_dev_put(hiter->dev); 103 kfree(hiter); 104 } 105 106 static void mmio_pipe_open(struct trace_iterator *iter) 107 { 108 struct header_iter *hiter; 109 struct trace_seq *s = &iter->seq; 110 111 trace_seq_printf(s, "VERSION 20070824\n"); 112 113 hiter = kzalloc(sizeof(*hiter), GFP_KERNEL); 114 if (!hiter) 115 return; 116 117 hiter->dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); 118 iter->private = hiter; 119 } 120 121 /* XXX: This is not called when the pipe is closed! */ 122 static void mmio_close(struct trace_iterator *iter) 123 { 124 struct header_iter *hiter = iter->private; 125 destroy_header_iter(hiter); 126 iter->private = NULL; 127 } 128 129 static unsigned long count_overruns(struct trace_iterator *iter) 130 { 131 int cpu; 132 unsigned long cnt = 0; 133 /* FIXME: */ 134 #if 0 135 for_each_online_cpu(cpu) { 136 cnt += iter->overrun[cpu]; 137 iter->overrun[cpu] = 0; 138 } 139 #endif 140 (void)cpu; 141 return cnt; 142 } 143 144 static ssize_t mmio_read(struct trace_iterator *iter, struct file *filp, 145 char __user *ubuf, size_t cnt, loff_t *ppos) 146 { 147 ssize_t ret; 148 struct header_iter *hiter = iter->private; 149 struct trace_seq *s = &iter->seq; 150 unsigned long n; 151 152 n = count_overruns(iter); 153 if (n) { 154 /* XXX: This is later than where events were lost. */ 155 trace_seq_printf(s, "MARK 0.000000 Lost %lu events.\n", n); 156 if (!overrun_detected) 157 pr_warning("mmiotrace has lost events.\n"); 158 overrun_detected = true; 159 goto print_out; 160 } 161 162 if (!hiter) 163 return 0; 164 165 mmio_print_pcidev(s, hiter->dev); 166 hiter->dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, hiter->dev); 167 168 if (!hiter->dev) { 169 destroy_header_iter(hiter); 170 iter->private = NULL; 171 } 172 173 print_out: 174 ret = trace_seq_to_user(s, ubuf, cnt); 175 return (ret == -EBUSY) ? 0 : ret; 176 } 177 178 static enum print_line_t mmio_print_rw(struct trace_iterator *iter) 179 { 180 struct trace_entry *entry = iter->ent; 181 struct trace_mmiotrace_rw *field; 182 struct mmiotrace_rw *rw; 183 struct trace_seq *s = &iter->seq; 184 unsigned long long t = ns2usecs(iter->ts); 185 unsigned long usec_rem = do_div(t, 1000000ULL); 186 unsigned secs = (unsigned long)t; 187 int ret = 1; 188 189 trace_assign_type(field, entry); 190 rw = &field->rw; 191 192 switch (rw->opcode) { 193 case MMIO_READ: 194 ret = trace_seq_printf(s, 195 "R %d %lu.%06lu %d 0x%llx 0x%lx 0x%lx %d\n", 196 rw->width, secs, usec_rem, rw->map_id, 197 (unsigned long long)rw->phys, 198 rw->value, rw->pc, 0); 199 break; 200 case MMIO_WRITE: 201 ret = trace_seq_printf(s, 202 "W %d %lu.%06lu %d 0x%llx 0x%lx 0x%lx %d\n", 203 rw->width, secs, usec_rem, rw->map_id, 204 (unsigned long long)rw->phys, 205 rw->value, rw->pc, 0); 206 break; 207 case MMIO_UNKNOWN_OP: 208 ret = trace_seq_printf(s, 209 "UNKNOWN %lu.%06lu %d 0x%llx %02x,%02x,%02x 0x%lx %d\n", 210 secs, usec_rem, rw->map_id, 211 (unsigned long long)rw->phys, 212 (rw->value >> 16) & 0xff, (rw->value >> 8) & 0xff, 213 (rw->value >> 0) & 0xff, rw->pc, 0); 214 break; 215 default: 216 ret = trace_seq_printf(s, "rw what?\n"); 217 break; 218 } 219 if (ret) 220 return TRACE_TYPE_HANDLED; 221 return TRACE_TYPE_PARTIAL_LINE; 222 } 223 224 static enum print_line_t mmio_print_map(struct trace_iterator *iter) 225 { 226 struct trace_entry *entry = iter->ent; 227 struct trace_mmiotrace_map *field; 228 struct mmiotrace_map *m; 229 struct trace_seq *s = &iter->seq; 230 unsigned long long t = ns2usecs(iter->ts); 231 unsigned long usec_rem = do_div(t, 1000000ULL); 232 unsigned secs = (unsigned long)t; 233 int ret; 234 235 trace_assign_type(field, entry); 236 m = &field->map; 237 238 switch (m->opcode) { 239 case MMIO_PROBE: 240 ret = trace_seq_printf(s, 241 "MAP %lu.%06lu %d 0x%llx 0x%lx 0x%lx 0x%lx %d\n", 242 secs, usec_rem, m->map_id, 243 (unsigned long long)m->phys, m->virt, m->len, 244 0UL, 0); 245 break; 246 case MMIO_UNPROBE: 247 ret = trace_seq_printf(s, 248 "UNMAP %lu.%06lu %d 0x%lx %d\n", 249 secs, usec_rem, m->map_id, 0UL, 0); 250 break; 251 default: 252 ret = trace_seq_printf(s, "map what?\n"); 253 break; 254 } 255 if (ret) 256 return TRACE_TYPE_HANDLED; 257 return TRACE_TYPE_PARTIAL_LINE; 258 } 259 260 static enum print_line_t mmio_print_mark(struct trace_iterator *iter) 261 { 262 struct trace_entry *entry = iter->ent; 263 struct print_entry *print = (struct print_entry *)entry; 264 const char *msg = print->buf; 265 struct trace_seq *s = &iter->seq; 266 unsigned long long t = ns2usecs(iter->ts); 267 unsigned long usec_rem = do_div(t, 1000000ULL); 268 unsigned secs = (unsigned long)t; 269 int ret; 270 271 /* The trailing newline must be in the message. */ 272 ret = trace_seq_printf(s, "MARK %lu.%06lu %s", secs, usec_rem, msg); 273 if (!ret) 274 return TRACE_TYPE_PARTIAL_LINE; 275 276 if (entry->flags & TRACE_FLAG_CONT) 277 trace_seq_print_cont(s, iter); 278 279 return TRACE_TYPE_HANDLED; 280 } 281 282 static enum print_line_t mmio_print_line(struct trace_iterator *iter) 283 { 284 switch (iter->ent->type) { 285 case TRACE_MMIO_RW: 286 return mmio_print_rw(iter); 287 case TRACE_MMIO_MAP: 288 return mmio_print_map(iter); 289 case TRACE_PRINT: 290 return mmio_print_mark(iter); 291 default: 292 return TRACE_TYPE_HANDLED; /* ignore unknown entries */ 293 } 294 } 295 296 static struct tracer mmio_tracer __read_mostly = 297 { 298 .name = "mmiotrace", 299 .init = mmio_trace_init, 300 .reset = mmio_trace_reset, 301 .pipe_open = mmio_pipe_open, 302 .close = mmio_close, 303 .read = mmio_read, 304 .ctrl_update = mmio_trace_ctrl_update, 305 .print_line = mmio_print_line, 306 }; 307 308 __init static int init_mmio_trace(void) 309 { 310 return register_tracer(&mmio_tracer); 311 } 312 device_initcall(init_mmio_trace); 313 314 static void __trace_mmiotrace_rw(struct trace_array *tr, 315 struct trace_array_cpu *data, 316 struct mmiotrace_rw *rw) 317 { 318 struct ring_buffer_event *event; 319 struct trace_mmiotrace_rw *entry; 320 unsigned long irq_flags; 321 322 event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry), 323 &irq_flags); 324 if (!event) 325 return; 326 entry = ring_buffer_event_data(event); 327 tracing_generic_entry_update(&entry->ent, 0, preempt_count()); 328 entry->ent.type = TRACE_MMIO_RW; 329 entry->rw = *rw; 330 ring_buffer_unlock_commit(tr->buffer, event, irq_flags); 331 332 trace_wake_up(); 333 } 334 335 void mmio_trace_rw(struct mmiotrace_rw *rw) 336 { 337 struct trace_array *tr = mmio_trace_array; 338 struct trace_array_cpu *data = tr->data[smp_processor_id()]; 339 __trace_mmiotrace_rw(tr, data, rw); 340 } 341 342 static void __trace_mmiotrace_map(struct trace_array *tr, 343 struct trace_array_cpu *data, 344 struct mmiotrace_map *map) 345 { 346 struct ring_buffer_event *event; 347 struct trace_mmiotrace_map *entry; 348 unsigned long irq_flags; 349 350 event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry), 351 &irq_flags); 352 if (!event) 353 return; 354 entry = ring_buffer_event_data(event); 355 tracing_generic_entry_update(&entry->ent, 0, preempt_count()); 356 entry->ent.type = TRACE_MMIO_MAP; 357 entry->map = *map; 358 ring_buffer_unlock_commit(tr->buffer, event, irq_flags); 359 360 trace_wake_up(); 361 } 362 363 void mmio_trace_mapping(struct mmiotrace_map *map) 364 { 365 struct trace_array *tr = mmio_trace_array; 366 struct trace_array_cpu *data; 367 368 preempt_disable(); 369 data = tr->data[smp_processor_id()]; 370 __trace_mmiotrace_map(tr, data, map); 371 preempt_enable(); 372 } 373 374 int mmio_trace_printk(const char *fmt, va_list args) 375 { 376 return trace_vprintk(0, fmt, args); 377 } 378