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