Commit ace2dc7d authored by Paul Mundt's avatar Paul Mundt
Browse files

sh: wire up perf alignment and emulation faults.



This plugs in the alignment and emulation fault reporting for perf sw
events.

Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent 5a30d7bf
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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)
{
+1 −1
Original line number Diff line number Diff line
@@ -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;
}
+19 −7
Original line number Diff line number Diff line
@@ -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 @@ fixup:

		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 @@ uspace_segv:

		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);
	}
}
+9 −0
Original line number Diff line number Diff line
@@ -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;
+3 −0
Original line number Diff line number Diff line
@@ -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);