diff options
author | Paul Mundt <lethal@linux-sh.org> | 2010-10-12 17:55:26 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2010-10-12 17:55:26 -0400 |
commit | ace2dc7d12693545b67f15ab8cdb3d255c937713 (patch) | |
tree | 18fa828ebe254e0137ec96a9e1cd4e146c6a7119 /arch | |
parent | 5a30d7bfcd33c03f1f67d3e1c317eb5d6a6bc811 (diff) |
sh: wire up perf alignment and emulation faults.
This plugs in the alignment and emulation fault reporting for perf sw
events.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/sh/include/asm/system_32.h | 2 | ||||
-rw-r--r-- | arch/sh/kernel/io_trapped.c | 2 | ||||
-rw-r--r-- | arch/sh/kernel/traps_32.c | 26 | ||||
-rw-r--r-- | arch/sh/kernel/traps_64.c | 9 | ||||
-rw-r--r-- | arch/sh/math-emu/math.c | 3 |
5 files changed, 33 insertions, 9 deletions
diff --git a/arch/sh/include/asm/system_32.h b/arch/sh/include/asm/system_32.h index 9bd2684f908e..c941b2739405 100644 --- a/arch/sh/include/asm/system_32.h +++ b/arch/sh/include/asm/system_32.h | |||
@@ -212,7 +212,7 @@ static inline reg_size_t register_align(void *val) | |||
212 | } | 212 | } |
213 | 213 | ||
214 | int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, | 214 | int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, |
215 | struct mem_access *ma, int); | 215 | struct mem_access *ma, int, unsigned long address); |
216 | 216 | ||
217 | static inline void trigger_address_error(void) | 217 | static inline void trigger_address_error(void) |
218 | { | 218 | { |
diff --git a/arch/sh/kernel/io_trapped.c b/arch/sh/kernel/io_trapped.c index 2947d2bd1291..32c385ef1011 100644 --- a/arch/sh/kernel/io_trapped.c +++ b/arch/sh/kernel/io_trapped.c | |||
@@ -291,7 +291,7 @@ int handle_trapped_io(struct pt_regs *regs, unsigned long address) | |||
291 | } | 291 | } |
292 | 292 | ||
293 | tmp = handle_unaligned_access(instruction, regs, | 293 | tmp = handle_unaligned_access(instruction, regs, |
294 | &trapped_io_access, 1); | 294 | &trapped_io_access, 1, address); |
295 | set_fs(oldfs); | 295 | set_fs(oldfs); |
296 | return tmp == 0; | 296 | return tmp == 0; |
297 | } | 297 | } |
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index f5613529a6bf..3484c2f65aba 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * SuperH version: Copyright (C) 1999 Niibe Yutaka | 5 | * SuperH version: Copyright (C) 1999 Niibe Yutaka |
6 | * Copyright (C) 2000 Philipp Rumpf | 6 | * Copyright (C) 2000 Philipp Rumpf |
7 | * Copyright (C) 2000 David Howells | 7 | * Copyright (C) 2000 David Howells |
8 | * Copyright (C) 2002 - 2007 Paul Mundt | 8 | * Copyright (C) 2002 - 2010 Paul Mundt |
9 | * | 9 | * |
10 | * This file is subject to the terms and conditions of the GNU General Public | 10 | * This file is subject to the terms and conditions of the GNU General Public |
11 | * License. See the file "COPYING" in the main directory of this archive | 11 | * License. See the file "COPYING" in the main directory of this archive |
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/limits.h> | 26 | #include <linux/limits.h> |
27 | #include <linux/sysfs.h> | 27 | #include <linux/sysfs.h> |
28 | #include <linux/uaccess.h> | 28 | #include <linux/uaccess.h> |
29 | #include <linux/perf_event.h> | ||
29 | #include <asm/system.h> | 30 | #include <asm/system.h> |
30 | #include <asm/alignment.h> | 31 | #include <asm/alignment.h> |
31 | #include <asm/fpu.h> | 32 | #include <asm/fpu.h> |
@@ -369,7 +370,8 @@ static inline int handle_delayslot(struct pt_regs *regs, | |||
369 | #define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4) | 370 | #define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4) |
370 | 371 | ||
371 | int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, | 372 | int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, |
372 | struct mem_access *ma, int expected) | 373 | struct mem_access *ma, int expected, |
374 | unsigned long address) | ||
373 | { | 375 | { |
374 | u_int rm; | 376 | u_int rm; |
375 | int ret, index; | 377 | int ret, index; |
@@ -383,9 +385,18 @@ int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, | |||
383 | index = (instruction>>8)&15; /* 0x0F00 */ | 385 | index = (instruction>>8)&15; /* 0x0F00 */ |
384 | rm = regs->regs[index]; | 386 | rm = regs->regs[index]; |
385 | 387 | ||
386 | /* shout about fixups */ | 388 | /* |
387 | if (!expected) | 389 | * Log the unexpected fixups, and then pass them on to perf. |
390 | * | ||
391 | * We intentionally don't report the expected cases to perf as | ||
392 | * otherwise the trapped I/O case will skew the results too much | ||
393 | * to be useful. | ||
394 | */ | ||
395 | if (!expected) { | ||
388 | unaligned_fixups_notify(current, instruction, regs); | 396 | unaligned_fixups_notify(current, instruction, regs); |
397 | perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, | ||
398 | regs, address); | ||
399 | } | ||
389 | 400 | ||
390 | ret = -EFAULT; | 401 | ret = -EFAULT; |
391 | switch (instruction&0xF000) { | 402 | switch (instruction&0xF000) { |
@@ -574,7 +585,8 @@ fixup: | |||
574 | 585 | ||
575 | set_fs(USER_DS); | 586 | set_fs(USER_DS); |
576 | tmp = handle_unaligned_access(instruction, regs, | 587 | tmp = handle_unaligned_access(instruction, regs, |
577 | &user_mem_access, 0); | 588 | &user_mem_access, 0, |
589 | address); | ||
578 | set_fs(oldfs); | 590 | set_fs(oldfs); |
579 | 591 | ||
580 | if (tmp == 0) | 592 | if (tmp == 0) |
@@ -607,8 +619,8 @@ uspace_segv: | |||
607 | 619 | ||
608 | unaligned_fixups_notify(current, instruction, regs); | 620 | unaligned_fixups_notify(current, instruction, regs); |
609 | 621 | ||
610 | handle_unaligned_access(instruction, regs, | 622 | handle_unaligned_access(instruction, regs, &user_mem_access, |
611 | &user_mem_access, 0); | 623 | 0, address); |
612 | set_fs(oldfs); | 624 | set_fs(oldfs); |
613 | } | 625 | } |
614 | } | 626 | } |
diff --git a/arch/sh/kernel/traps_64.c b/arch/sh/kernel/traps_64.c index fda6355654b7..6713ca97e553 100644 --- a/arch/sh/kernel/traps_64.c +++ b/arch/sh/kernel/traps_64.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
25 | #include <linux/sysctl.h> | 25 | #include <linux/sysctl.h> |
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/perf_event.h> | ||
27 | #include <asm/system.h> | 28 | #include <asm/system.h> |
28 | #include <asm/uaccess.h> | 29 | #include <asm/uaccess.h> |
29 | #include <asm/io.h> | 30 | #include <asm/io.h> |
@@ -433,6 +434,8 @@ static int misaligned_load(struct pt_regs *regs, | |||
433 | return error; | 434 | return error; |
434 | } | 435 | } |
435 | 436 | ||
437 | perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, regs, address); | ||
438 | |||
436 | destreg = (opcode >> 4) & 0x3f; | 439 | destreg = (opcode >> 4) & 0x3f; |
437 | if (user_mode(regs)) { | 440 | if (user_mode(regs)) { |
438 | __u64 buffer; | 441 | __u64 buffer; |
@@ -509,6 +512,8 @@ static int misaligned_store(struct pt_regs *regs, | |||
509 | return error; | 512 | return error; |
510 | } | 513 | } |
511 | 514 | ||
515 | perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, regs, address); | ||
516 | |||
512 | srcreg = (opcode >> 4) & 0x3f; | 517 | srcreg = (opcode >> 4) & 0x3f; |
513 | if (user_mode(regs)) { | 518 | if (user_mode(regs)) { |
514 | __u64 buffer; | 519 | __u64 buffer; |
@@ -583,6 +588,8 @@ static int misaligned_fpu_load(struct pt_regs *regs, | |||
583 | return error; | 588 | return error; |
584 | } | 589 | } |
585 | 590 | ||
591 | perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, address); | ||
592 | |||
586 | destreg = (opcode >> 4) & 0x3f; | 593 | destreg = (opcode >> 4) & 0x3f; |
587 | if (user_mode(regs)) { | 594 | if (user_mode(regs)) { |
588 | __u64 buffer; | 595 | __u64 buffer; |
@@ -658,6 +665,8 @@ static int misaligned_fpu_store(struct pt_regs *regs, | |||
658 | return error; | 665 | return error; |
659 | } | 666 | } |
660 | 667 | ||
668 | perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, address); | ||
669 | |||
661 | srcreg = (opcode >> 4) & 0x3f; | 670 | srcreg = (opcode >> 4) & 0x3f; |
662 | if (user_mode(regs)) { | 671 | if (user_mode(regs)) { |
663 | __u64 buffer; | 672 | __u64 buffer; |
diff --git a/arch/sh/math-emu/math.c b/arch/sh/math-emu/math.c index 1fcdb1220975..f76a5090d5d1 100644 --- a/arch/sh/math-emu/math.c +++ b/arch/sh/math-emu/math.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/types.h> | 12 | #include <linux/types.h> |
13 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
14 | #include <linux/signal.h> | 14 | #include <linux/signal.h> |
15 | #include <linux/perf_event.h> | ||
15 | 16 | ||
16 | #include <asm/system.h> | 17 | #include <asm/system.h> |
17 | #include <asm/uaccess.h> | 18 | #include <asm/uaccess.h> |
@@ -619,6 +620,8 @@ int do_fpu_inst(unsigned short inst, struct pt_regs *regs) | |||
619 | struct task_struct *tsk = current; | 620 | struct task_struct *tsk = current; |
620 | struct sh_fpu_soft_struct *fpu = &(tsk->thread.xstate->softfpu); | 621 | struct sh_fpu_soft_struct *fpu = &(tsk->thread.xstate->softfpu); |
621 | 622 | ||
623 | perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, 0); | ||
624 | |||
622 | if (!(task_thread_info(tsk)->status & TS_USEDFPU)) { | 625 | if (!(task_thread_info(tsk)->status & TS_USEDFPU)) { |
623 | /* initialize once. */ | 626 | /* initialize once. */ |
624 | fpu_init(fpu); | 627 | fpu_init(fpu); |