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>
This commit is contained in:
Paul Mundt 2010-10-13 06:55:26 +09:00
parent 5a30d7bfcd
commit ace2dc7d12
5 changed files with 33 additions and 9 deletions

View file

@ -212,7 +212,7 @@ static inline reg_size_t register_align(void *val)
}
int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
struct mem_access *ma, int);
struct mem_access *ma, int, unsigned long address);
static inline void trigger_address_error(void)
{

View file

@ -291,7 +291,7 @@ int handle_trapped_io(struct pt_regs *regs, unsigned long address)
}
tmp = handle_unaligned_access(instruction, regs,
&trapped_io_access, 1);
&trapped_io_access, 1, address);
set_fs(oldfs);
return tmp == 0;
}

View file

@ -5,7 +5,7 @@
* SuperH version: Copyright (C) 1999 Niibe Yutaka
* Copyright (C) 2000 Philipp Rumpf
* Copyright (C) 2000 David Howells
* Copyright (C) 2002 - 2007 Paul Mundt
* Copyright (C) 2002 - 2010 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@ -26,6 +26,7 @@
#include <linux/limits.h>
#include <linux/sysfs.h>
#include <linux/uaccess.h>
#include <linux/perf_event.h>
#include <asm/system.h>
#include <asm/alignment.h>
#include <asm/fpu.h>
@ -369,7 +370,8 @@ static inline int handle_delayslot(struct pt_regs *regs,
#define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4)
int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
struct mem_access *ma, int expected)
struct mem_access *ma, int expected,
unsigned long address)
{
u_int rm;
int ret, index;
@ -383,9 +385,18 @@ int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
index = (instruction>>8)&15; /* 0x0F00 */
rm = regs->regs[index];
/* shout about fixups */
if (!expected)
/*
* Log the unexpected fixups, and then pass them on to perf.
*
* We intentionally don't report the expected cases to perf as
* otherwise the trapped I/O case will skew the results too much
* to be useful.
*/
if (!expected) {
unaligned_fixups_notify(current, instruction, regs);
perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0,
regs, address);
}
ret = -EFAULT;
switch (instruction&0xF000) {
@ -574,7 +585,8 @@ asmlinkage void do_address_error(struct pt_regs *regs,
set_fs(USER_DS);
tmp = handle_unaligned_access(instruction, regs,
&user_mem_access, 0);
&user_mem_access, 0,
address);
set_fs(oldfs);
if (tmp == 0)
@ -607,8 +619,8 @@ asmlinkage void do_address_error(struct pt_regs *regs,
unaligned_fixups_notify(current, instruction, regs);
handle_unaligned_access(instruction, regs,
&user_mem_access, 0);
handle_unaligned_access(instruction, regs, &user_mem_access,
0, address);
set_fs(oldfs);
}
}

View file

@ -24,6 +24,7 @@
#include <linux/interrupt.h>
#include <linux/sysctl.h>
#include <linux/module.h>
#include <linux/perf_event.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@ -433,6 +434,8 @@ static int misaligned_load(struct pt_regs *regs,
return error;
}
perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, regs, address);
destreg = (opcode >> 4) & 0x3f;
if (user_mode(regs)) {
__u64 buffer;
@ -509,6 +512,8 @@ static int misaligned_store(struct pt_regs *regs,
return error;
}
perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, regs, address);
srcreg = (opcode >> 4) & 0x3f;
if (user_mode(regs)) {
__u64 buffer;
@ -583,6 +588,8 @@ static int misaligned_fpu_load(struct pt_regs *regs,
return error;
}
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, address);
destreg = (opcode >> 4) & 0x3f;
if (user_mode(regs)) {
__u64 buffer;
@ -658,6 +665,8 @@ static int misaligned_fpu_store(struct pt_regs *regs,
return error;
}
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, address);
srcreg = (opcode >> 4) & 0x3f;
if (user_mode(regs)) {
__u64 buffer;

View file

@ -12,6 +12,7 @@
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/perf_event.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@ -619,6 +620,8 @@ int do_fpu_inst(unsigned short inst, struct pt_regs *regs)
struct task_struct *tsk = current;
struct sh_fpu_soft_struct *fpu = &(tsk->thread.xstate->softfpu);
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, 0);
if (!(task_thread_info(tsk)->status & TS_USEDFPU)) {
/* initialize once. */
fpu_init(fpu);