aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2010-10-12 17:55:26 -0400
committerPaul Mundt <lethal@linux-sh.org>2010-10-12 17:55:26 -0400
commitace2dc7d12693545b67f15ab8cdb3d255c937713 (patch)
tree18fa828ebe254e0137ec96a9e1cd4e146c6a7119
parent5a30d7bfcd33c03f1f67d3e1c317eb5d6a6bc811 (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>
-rw-r--r--arch/sh/include/asm/system_32.h2
-rw-r--r--arch/sh/kernel/io_trapped.c2
-rw-r--r--arch/sh/kernel/traps_32.c26
-rw-r--r--arch/sh/kernel/traps_64.c9
-rw-r--r--arch/sh/math-emu/math.c3
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
214int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, 214int 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
217static inline void trigger_address_error(void) 217static 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
371int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, 372int 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);