aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorPekka Paalanen <pq@iki.fi>2008-05-12 15:20:57 -0400
committerThomas Gleixner <tglx@linutronix.de>2008-05-24 05:24:53 -0400
commitbd8ac686c73c7e925fcfe0b02dc4e7b947127864 (patch)
tree7a675c4919429b507bb8e7b09677d96ae30ec561 /arch/x86
parentf984b51e0779a6dd30feedc41404013ca54e5d05 (diff)
ftrace: mmiotrace, updates
here is a patch that makes mmiotrace work almost well within the tracing framework. The patch applies on top of my previous patch. I have my own output formatting in place now. Summary of changes: - fix the NULL dereference that was due to not calling tracing_reset() - add print_line() callback into struct tracer - implement print_line() for mmiotrace, producing up-to-spec text - add my output header, but that is not really called in the right place - rewrote the main structs in mmiotrace - added two new trace entry types: TRACE_MMIO_RW and TRACE_MMIO_MAP - made some functions in trace.c non-static - check current==NULL in tracing_generic_entry_update() - fix(?) comparison in trace_seq_printf() Things seem to work fine except a few issues. Markers (text lines injected into mmiotrace log) are missing, I did not feel hacking them in before we have variable length entries. My output header is printed only for 'trace' file, but not 'trace_pipe'. For some reason, despite my quick fix, iter->trace is NULL in print_trace_line() when called from 'trace_pipe' file, which means I don't get proper output formatting. I only tried by loading nouveau.ko, which just detects the card, and that is traced fine. I didn't try further. Map, two reads and unmap. Works perfectly. I am missing the information about overflows, I'd prefer to have a counter for lost events. I didn't try, but I guess currently there is no way of knowning when it overflows? So, not too far from being fully operational, it seems :-) And looking at the diffstat, there also is some 700-900 lines of user space code that just became obsolete. Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/Kconfig.debug2
-rw-r--r--arch/x86/kernel/mmiotrace/mmio-mod.c140
2 files changed, 42 insertions, 100 deletions
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 7e4b8494078e..1d6de0d67f99 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -173,7 +173,7 @@ config MMIOTRACE_HOOKS
173 173
174config MMIOTRACE 174config MMIOTRACE
175 bool "Memory mapped IO tracing" 175 bool "Memory mapped IO tracing"
176 depends on DEBUG_KERNEL && RELAY 176 depends on DEBUG_KERNEL
177 select TRACING 177 select TRACING
178 select MMIOTRACE_HOOKS 178 select MMIOTRACE_HOOKS
179 default y 179 default y
diff --git a/arch/x86/kernel/mmiotrace/mmio-mod.c b/arch/x86/kernel/mmiotrace/mmio-mod.c
index c7a67d7e482b..62abc281a512 100644
--- a/arch/x86/kernel/mmiotrace/mmio-mod.c
+++ b/arch/x86/kernel/mmiotrace/mmio-mod.c
@@ -37,11 +37,6 @@
37 37
38#define NAME "mmiotrace: " 38#define NAME "mmiotrace: "
39 39
40/* This app's relay channel files will appear in /debug/mmio-trace */
41static const char APP_DIR[] = "mmio-trace";
42/* the marker injection file in /debug/APP_DIR */
43static const char MARKER_FILE[] = "mmio-marker";
44
45struct trap_reason { 40struct trap_reason {
46 unsigned long addr; 41 unsigned long addr;
47 unsigned long ip; 42 unsigned long ip;
@@ -56,18 +51,15 @@ struct remap_trace {
56 unsigned long id; 51 unsigned long id;
57}; 52};
58 53
59static const size_t subbuf_size = 256*1024;
60
61/* Accessed per-cpu. */ 54/* Accessed per-cpu. */
62static DEFINE_PER_CPU(struct trap_reason, pf_reason); 55static DEFINE_PER_CPU(struct trap_reason, pf_reason);
63static DEFINE_PER_CPU(struct mm_io_header_rw, cpu_trace); 56static DEFINE_PER_CPU(struct mmiotrace_rw, cpu_trace);
64 57
65#if 0 /* XXX: no way gather this info anymore */ 58#if 0 /* XXX: no way gather this info anymore */
66/* Access to this is not per-cpu. */ 59/* Access to this is not per-cpu. */
67static DEFINE_PER_CPU(atomic_t, dropped); 60static DEFINE_PER_CPU(atomic_t, dropped);
68#endif 61#endif
69 62
70static struct dentry *dir;
71static struct dentry *marker_file; 63static struct dentry *marker_file;
72 64
73static DEFINE_MUTEX(mmiotrace_mutex); 65static DEFINE_MUTEX(mmiotrace_mutex);
@@ -82,24 +74,21 @@ static LIST_HEAD(trace_list); /* struct remap_trace */
82 * and trace_lock. 74 * and trace_lock.
83 * - Routines depending on is_enabled() must take trace_lock. 75 * - Routines depending on is_enabled() must take trace_lock.
84 * - trace_list users must hold trace_lock. 76 * - trace_list users must hold trace_lock.
85 * - is_enabled() guarantees that chan is valid. 77 * - is_enabled() guarantees that mmio_trace_record is allowed.
86 * - pre/post callbacks assume the effect of is_enabled() being true. 78 * - pre/post callbacks assume the effect of is_enabled() being true.
87 */ 79 */
88 80
89/* module parameters */ 81/* module parameters */
90static unsigned int n_subbufs = 32*4;
91static unsigned long filter_offset; 82static unsigned long filter_offset;
92static int nommiotrace; 83static int nommiotrace;
93static int ISA_trace; 84static int ISA_trace;
94static int trace_pc; 85static int trace_pc;
95 86
96module_param(n_subbufs, uint, 0);
97module_param(filter_offset, ulong, 0); 87module_param(filter_offset, ulong, 0);
98module_param(nommiotrace, bool, 0); 88module_param(nommiotrace, bool, 0);
99module_param(ISA_trace, bool, 0); 89module_param(ISA_trace, bool, 0);
100module_param(trace_pc, bool, 0); 90module_param(trace_pc, bool, 0);
101 91
102MODULE_PARM_DESC(n_subbufs, "Number of 256kB buffers, default 128.");
103MODULE_PARM_DESC(filter_offset, "Start address of traced mappings."); 92MODULE_PARM_DESC(filter_offset, "Start address of traced mappings.");
104MODULE_PARM_DESC(nommiotrace, "Disable actual MMIO tracing."); 93MODULE_PARM_DESC(nommiotrace, "Disable actual MMIO tracing.");
105MODULE_PARM_DESC(ISA_trace, "Do not exclude the low ISA range."); 94MODULE_PARM_DESC(ISA_trace, "Do not exclude the low ISA range.");
@@ -110,6 +99,7 @@ static bool is_enabled(void)
110 return atomic_read(&mmiotrace_enabled); 99 return atomic_read(&mmiotrace_enabled);
111} 100}
112 101
102#if 0 /* XXX: needs rewrite */
113/* 103/*
114 * Write callback for the debugfs entry: 104 * Write callback for the debugfs entry:
115 * Read a marker and write it to the mmio trace log 105 * Read a marker and write it to the mmio trace log
@@ -145,6 +135,7 @@ static ssize_t write_marker(struct file *file, const char __user *buffer,
145 kfree(event); 135 kfree(event);
146 return len; 136 return len;
147} 137}
138#endif
148 139
149static void print_pte(unsigned long address) 140static void print_pte(unsigned long address)
150{ 141{
@@ -198,9 +189,10 @@ static void pre(struct kmmio_probe *p, struct pt_regs *regs,
198 unsigned long addr) 189 unsigned long addr)
199{ 190{
200 struct trap_reason *my_reason = &get_cpu_var(pf_reason); 191 struct trap_reason *my_reason = &get_cpu_var(pf_reason);
201 struct mm_io_header_rw *my_trace = &get_cpu_var(cpu_trace); 192 struct mmiotrace_rw *my_trace = &get_cpu_var(cpu_trace);
202 const unsigned long instptr = instruction_pointer(regs); 193 const unsigned long instptr = instruction_pointer(regs);
203 const enum reason_type type = get_ins_type(instptr); 194 const enum reason_type type = get_ins_type(instptr);
195 struct remap_trace *trace = p->user_data;
204 196
205 /* it doesn't make sense to have more than one active trace per cpu */ 197 /* it doesn't make sense to have more than one active trace per cpu */
206 if (my_reason->active_traces) 198 if (my_reason->active_traces)
@@ -212,23 +204,17 @@ static void pre(struct kmmio_probe *p, struct pt_regs *regs,
212 my_reason->addr = addr; 204 my_reason->addr = addr;
213 my_reason->ip = instptr; 205 my_reason->ip = instptr;
214 206
215 my_trace->header.type = MMIO_MAGIC; 207 my_trace->phys = addr - trace->probe.addr + trace->phys;
216 my_trace->header.pid = 0; 208 my_trace->map_id = trace->id;
217 my_trace->header.data_len = sizeof(struct mm_io_rw);
218 my_trace->rw.address = addr;
219 /*
220 * struct remap_trace *trace = p->user_data;
221 * phys = addr - trace->probe.addr + trace->phys;
222 */
223 209
224 /* 210 /*
225 * Only record the program counter when requested. 211 * Only record the program counter when requested.
226 * It may taint clean-room reverse engineering. 212 * It may taint clean-room reverse engineering.
227 */ 213 */
228 if (trace_pc) 214 if (trace_pc)
229 my_trace->rw.pc = instptr; 215 my_trace->pc = instptr;
230 else 216 else
231 my_trace->rw.pc = 0; 217 my_trace->pc = 0;
232 218
233 /* 219 /*
234 * XXX: the timestamp recorded will be *after* the tracing has been 220 * XXX: the timestamp recorded will be *after* the tracing has been
@@ -238,28 +224,25 @@ static void pre(struct kmmio_probe *p, struct pt_regs *regs,
238 224
239 switch (type) { 225 switch (type) {
240 case REG_READ: 226 case REG_READ:
241 my_trace->header.type |= 227 my_trace->opcode = MMIO_READ;
242 (MMIO_READ << MMIO_OPCODE_SHIFT) | 228 my_trace->width = get_ins_mem_width(instptr);
243 (get_ins_mem_width(instptr) << MMIO_WIDTH_SHIFT);
244 break; 229 break;
245 case REG_WRITE: 230 case REG_WRITE:
246 my_trace->header.type |= 231 my_trace->opcode = MMIO_WRITE;
247 (MMIO_WRITE << MMIO_OPCODE_SHIFT) | 232 my_trace->width = get_ins_mem_width(instptr);
248 (get_ins_mem_width(instptr) << MMIO_WIDTH_SHIFT); 233 my_trace->value = get_ins_reg_val(instptr, regs);
249 my_trace->rw.value = get_ins_reg_val(instptr, regs);
250 break; 234 break;
251 case IMM_WRITE: 235 case IMM_WRITE:
252 my_trace->header.type |= 236 my_trace->opcode = MMIO_WRITE;
253 (MMIO_WRITE << MMIO_OPCODE_SHIFT) | 237 my_trace->width = get_ins_mem_width(instptr);
254 (get_ins_mem_width(instptr) << MMIO_WIDTH_SHIFT); 238 my_trace->value = get_ins_imm_val(instptr);
255 my_trace->rw.value = get_ins_imm_val(instptr);
256 break; 239 break;
257 default: 240 default:
258 { 241 {
259 unsigned char *ip = (unsigned char *)instptr; 242 unsigned char *ip = (unsigned char *)instptr;
260 my_trace->header.type |= 243 my_trace->opcode = MMIO_UNKNOWN_OP;
261 (MMIO_UNKNOWN_OP << MMIO_OPCODE_SHIFT); 244 my_trace->width = 0;
262 my_trace->rw.value = (*ip) << 16 | *(ip + 1) << 8 | 245 my_trace->value = (*ip) << 16 | *(ip + 1) << 8 |
263 *(ip + 2); 246 *(ip + 2);
264 } 247 }
265 } 248 }
@@ -271,7 +254,7 @@ static void post(struct kmmio_probe *p, unsigned long condition,
271 struct pt_regs *regs) 254 struct pt_regs *regs)
272{ 255{
273 struct trap_reason *my_reason = &get_cpu_var(pf_reason); 256 struct trap_reason *my_reason = &get_cpu_var(pf_reason);
274 struct mm_io_header_rw *my_trace = &get_cpu_var(cpu_trace); 257 struct mmiotrace_rw *my_trace = &get_cpu_var(cpu_trace);
275 258
276 /* this should always return the active_trace count to 0 */ 259 /* this should always return the active_trace count to 0 */
277 my_reason->active_traces--; 260 my_reason->active_traces--;
@@ -282,20 +265,13 @@ static void post(struct kmmio_probe *p, unsigned long condition,
282 265
283 switch (my_reason->type) { 266 switch (my_reason->type) {
284 case REG_READ: 267 case REG_READ:
285 my_trace->rw.value = get_ins_reg_val(my_reason->ip, regs); 268 my_trace->value = get_ins_reg_val(my_reason->ip, regs);
286 break; 269 break;
287 default: 270 default:
288 break; 271 break;
289 } 272 }
290 273
291 /* 274 mmio_trace_rw(my_trace);
292 * XXX: Several required values are ignored:
293 * - mapping id
294 * - program counter
295 * Also the address should be physical, not virtual.
296 */
297 mmio_trace_record(my_trace->header.type, my_trace->rw.address,
298 my_trace->rw.value);
299 put_cpu_var(cpu_trace); 275 put_cpu_var(cpu_trace);
300 put_cpu_var(pf_reason); 276 put_cpu_var(pf_reason);
301} 277}
@@ -305,21 +281,11 @@ static void ioremap_trace_core(unsigned long offset, unsigned long size,
305{ 281{
306 static atomic_t next_id; 282 static atomic_t next_id;
307 struct remap_trace *trace = kmalloc(sizeof(*trace), GFP_KERNEL); 283 struct remap_trace *trace = kmalloc(sizeof(*trace), GFP_KERNEL);
308 struct mm_io_header_map event = { 284 struct mmiotrace_map map = {
309 .header = { 285 .phys = offset,
310 .type = MMIO_MAGIC | 286 .virt = (unsigned long)addr,
311 (MMIO_PROBE << MMIO_OPCODE_SHIFT), 287 .len = size,
312 .sec = 0, 288 .opcode = MMIO_PROBE
313 .nsec = 0,
314 .pid = 0,
315 .data_len = sizeof(struct mm_io_map)
316 },
317 .map = {
318 .phys = offset,
319 .addr = (unsigned long)addr,
320 .len = size,
321 .pc = 0
322 }
323 }; 289 };
324 290
325 if (!trace) { 291 if (!trace) {
@@ -338,15 +304,13 @@ static void ioremap_trace_core(unsigned long offset, unsigned long size,
338 .phys = offset, 304 .phys = offset,
339 .id = atomic_inc_return(&next_id) 305 .id = atomic_inc_return(&next_id)
340 }; 306 };
307 map.map_id = trace->id;
341 308
342 spin_lock_irq(&trace_lock); 309 spin_lock_irq(&trace_lock);
343 if (!is_enabled()) 310 if (!is_enabled())
344 goto not_enabled; 311 goto not_enabled;
345 312
346 /* 313 mmio_trace_mapping(&map);
347 * XXX: Insufficient data recorded!
348 */
349 mmio_trace_record(event.header.type, event.map.addr, event.map.len);
350 list_add_tail(&trace->list, &trace_list); 314 list_add_tail(&trace->list, &trace_list);
351 if (!nommiotrace) 315 if (!nommiotrace)
352 register_kmmio_probe(&trace->probe); 316 register_kmmio_probe(&trace->probe);
@@ -369,21 +333,11 @@ mmiotrace_ioremap(unsigned long offset, unsigned long size, void __iomem *addr)
369 333
370static void iounmap_trace_core(volatile void __iomem *addr) 334static void iounmap_trace_core(volatile void __iomem *addr)
371{ 335{
372 struct mm_io_header_map event = { 336 struct mmiotrace_map map = {
373 .header = { 337 .phys = 0,
374 .type = MMIO_MAGIC | 338 .virt = (unsigned long)addr,
375 (MMIO_UNPROBE << MMIO_OPCODE_SHIFT), 339 .len = 0,
376 .sec = 0, 340 .opcode = MMIO_UNPROBE
377 .nsec = 0,
378 .pid = 0,
379 .data_len = sizeof(struct mm_io_map)
380 },
381 .map = {
382 .phys = 0,
383 .addr = (unsigned long)addr,
384 .len = 0,
385 .pc = 0
386 }
387 }; 341 };
388 struct remap_trace *trace; 342 struct remap_trace *trace;
389 struct remap_trace *tmp; 343 struct remap_trace *tmp;
@@ -404,8 +358,8 @@ static void iounmap_trace_core(volatile void __iomem *addr)
404 break; 358 break;
405 } 359 }
406 } 360 }
407 mmio_trace_record(event.header.type, event.map.addr, 361 map.map_id = (found_trace) ? found_trace->id : -1;
408 found_trace ? found_trace->id : -1); 362 mmio_trace_mapping(&map);
409 363
410not_enabled: 364not_enabled:
411 spin_unlock_irq(&trace_lock); 365 spin_unlock_irq(&trace_lock);
@@ -448,10 +402,12 @@ static void clear_trace_list(void)
448 } 402 }
449} 403}
450 404
405#if 0 /* XXX: out of order */
451static struct file_operations fops_marker = { 406static struct file_operations fops_marker = {
452 .owner = THIS_MODULE, 407 .owner = THIS_MODULE,
453 .write = write_marker 408 .write = write_marker
454}; 409};
410#endif
455 411
456void enable_mmiotrace(void) 412void enable_mmiotrace(void)
457{ 413{
@@ -464,9 +420,9 @@ void enable_mmiotrace(void)
464#if 0 /* XXX: tracing does not support text entries */ 420#if 0 /* XXX: tracing does not support text entries */
465 marker_file = debugfs_create_file("marker", 0660, dir, NULL, 421 marker_file = debugfs_create_file("marker", 0660, dir, NULL,
466 &fops_marker); 422 &fops_marker);
467#endif
468 if (!marker_file) 423 if (!marker_file)
469 pr_err(NAME "marker file creation failed.\n"); 424 pr_err(NAME "marker file creation failed.\n");
425#endif
470 426
471 if (nommiotrace) 427 if (nommiotrace)
472 pr_info(NAME "MMIO tracing disabled.\n"); 428 pr_info(NAME "MMIO tracing disabled.\n");
@@ -502,17 +458,3 @@ void disable_mmiotrace(void)
502out: 458out:
503 mutex_unlock(&mmiotrace_mutex); 459 mutex_unlock(&mmiotrace_mutex);
504} 460}
505
506int __init init_mmiotrace(void)
507{
508 pr_debug(NAME "load...\n");
509 if (n_subbufs < 2)
510 return -EINVAL;
511
512 dir = debugfs_create_dir(APP_DIR, NULL);
513 if (!dir) {
514 pr_err(NAME "Couldn't create relay app directory.\n");
515 return -ENOMEM;
516 }
517 return 0;
518}