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