Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6a800f36 authored by Liu Yu's avatar Liu Yu Committed by Kumar Gala
Browse files

powerpc: Add SPE/EFP math emulation for E500v1/v2 processors.



This patch add the handlers of SPE/EFP exceptions.
The code is used to emulate float point arithmetic,
when MSR(SPE) is enabled and receive EFP data interrupt or EFP round interrupt.

This patch has no conflict with or dependence on FP math-emu.

The code has been tested by TestFloat.

Now the code doesn't support SPE/EFP instructions emulation
(it won't be called when receive program interrupt),
but it could be easily added.

Signed-off-by: default avatarLiu Yu <yu.liu@freescale.com>
Signed-off-by: default avatarKumar Gala <galak@kernel.crashing.org>
parent 033b8a33
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -207,6 +207,11 @@ struct thread_struct {
#define INIT_SP_LIMIT \
	(_ALIGN_UP(sizeof(init_thread_info), 16) + (unsigned long) &init_stack)

#ifdef CONFIG_SPE
#define SPEFSCR_INIT .spefscr = SPEFSCR_FINVE | SPEFSCR_FDBZE | SPEFSCR_FUNFE | SPEFSCR_FOVFE,
#else
#define SPEFSCR_INIT
#endif

#ifdef CONFIG_PPC32
#define INIT_THREAD { \
@@ -215,6 +220,7 @@ struct thread_struct {
	.fs = KERNEL_DS, \
	.pgdir = swapper_pg_dir, \
	.fpexc_mode = MSR_FE0 | MSR_FE1, \
	SPEFSCR_INIT \
}
#else
#define INIT_THREAD  { \
+26 −10
Original line number Diff line number Diff line
@@ -97,6 +97,20 @@

#define _FP_KEEPNANFRACP 1

#ifdef FP_EX_BOOKE_E500_SPE
#define FP_EX_INEXACT		(1 << 21)
#define FP_EX_INVALID		(1 << 20)
#define FP_EX_DIVZERO		(1 << 19)
#define FP_EX_UNDERFLOW		(1 << 18)
#define FP_EX_OVERFLOW		(1 << 17)
#define FP_INHIBIT_RESULTS	0

#define __FPU_FPSCR	(current->thread.spefscr)
#define __FPU_ENABLED_EXC		\
({					\
	(__FPU_FPSCR >> 2) & 0x1f;	\
})
#else
/* Exception flags.  We use the bit positions of the appropriate bits
   in the FPSCR, which also correspond to the FE_* bits.  This makes
   everything easier ;-).  */
@@ -111,6 +125,18 @@
#define FP_EX_DIVZERO         (1 << (31 - 5))
#define FP_EX_INEXACT         (1 << (31 - 6))

#define __FPU_FPSCR	(current->thread.fpscr.val)

/* We only actually write to the destination register
 * if exceptions signalled (if any) will not trap.
 */
#define __FPU_ENABLED_EXC \
({						\
	(__FPU_FPSCR >> 3) & 0x1f;	\
})

#endif

/*
 * If one NaN is signaling and the other is not,
 * we choose that one, otherwise we choose X.
@@ -135,16 +161,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>

#define __FPU_FPSCR	(current->thread.fpscr.val)

/* We only actually write to the destination register
 * if exceptions signalled (if any) will not trap.
 */
#define __FPU_ENABLED_EXC \
({						\
	(__FPU_FPSCR >> 3) & 0x1f;	\
})

#define __FPU_TRAP_P(bits) \
	((__FPU_ENABLED_EXC & (bits)) != 0)

+4 −3
Original line number Diff line number Diff line
@@ -685,12 +685,13 @@ interrupt_base:
	/* SPE Floating Point Data */
#ifdef CONFIG_SPE
	EXCEPTION(0x2030, SPEFloatingPointData, SPEFloatingPointException, EXC_XFER_EE);
#else
	EXCEPTION(0x2040, SPEFloatingPointData, unknown_exception, EXC_XFER_EE)
#endif /* CONFIG_SPE */

	/* SPE Floating Point Round */
	EXCEPTION(0x2050, SPEFloatingPointRound, SPEFloatingPointRoundException, EXC_XFER_EE)
#else
	EXCEPTION(0x2040, SPEFloatingPointData, unknown_exception, EXC_XFER_EE)
	EXCEPTION(0x2050, SPEFloatingPointRound, unknown_exception, EXC_XFER_EE)
#endif /* CONFIG_SPE */

	/* Performance Monitor */
	EXCEPTION(0x2060, PerformanceMonitor, performance_monitor_exception, EXC_XFER_STD)
+55 −7
Original line number Diff line number Diff line
@@ -1160,37 +1160,85 @@ void CacheLockingException(struct pt_regs *regs, unsigned long address,
#ifdef CONFIG_SPE
void SPEFloatingPointException(struct pt_regs *regs)
{
	extern int do_spe_mathemu(struct pt_regs *regs);
	unsigned long spefscr;
	int fpexc_mode;
	int code = 0;
	int err;

	preempt_disable();
	if (regs->msr & MSR_SPE)
		giveup_spe(current);
	preempt_enable();

	spefscr = current->thread.spefscr;
	fpexc_mode = current->thread.fpexc_mode;

	/* Hardware does not neccessarily set sticky
	 * underflow/overflow/invalid flags */
	if ((spefscr & SPEFSCR_FOVF) && (fpexc_mode & PR_FP_EXC_OVF)) {
		code = FPE_FLTOVF;
		spefscr |= SPEFSCR_FOVFS;
	}
	else if ((spefscr & SPEFSCR_FUNF) && (fpexc_mode & PR_FP_EXC_UND)) {
		code = FPE_FLTUND;
		spefscr |= SPEFSCR_FUNFS;
	}
	else if ((spefscr & SPEFSCR_FDBZ) && (fpexc_mode & PR_FP_EXC_DIV))
		code = FPE_FLTDIV;
	else if ((spefscr & SPEFSCR_FINV) && (fpexc_mode & PR_FP_EXC_INV)) {
		code = FPE_FLTINV;
		spefscr |= SPEFSCR_FINVS;
	}
	else if ((spefscr & (SPEFSCR_FG | SPEFSCR_FX)) && (fpexc_mode & PR_FP_EXC_RES))
		code = FPE_FLTRES;

	current->thread.spefscr = spefscr;
	err = do_spe_mathemu(regs);
	if (err == 0) {
		regs->nip += 4;		/* skip emulated instruction */
		emulate_single_step(regs);
		return;
	}

	if (err == -EFAULT) {
		/* got an error reading the instruction */
		_exception(SIGSEGV, regs, SEGV_ACCERR, regs->nip);
	} else if (err == -EINVAL) {
		/* didn't recognize the instruction */
		printk(KERN_ERR "unrecognized spe instruction "
		       "in %s at %lx\n", current->comm, regs->nip);
	} else {
		_exception(SIGFPE, regs, code, regs->nip);
	}

	return;
}

void SPEFloatingPointRoundException(struct pt_regs *regs)
{
	extern int speround_handler(struct pt_regs *regs);
	int err;

	preempt_disable();
	if (regs->msr & MSR_SPE)
		giveup_spe(current);
	preempt_enable();

	regs->nip -= 4;
	err = speround_handler(regs);
	if (err == 0) {
		regs->nip += 4;		/* skip emulated instruction */
		emulate_single_step(regs);
		return;
	}

	if (err == -EFAULT) {
		/* got an error reading the instruction */
		_exception(SIGSEGV, regs, SEGV_ACCERR, regs->nip);
	} else if (err == -EINVAL) {
		/* didn't recognize the instruction */
		printk(KERN_ERR "unrecognized spe instruction "
		       "in %s at %lx\n", current->comm, regs->nip);
	} else {
		_exception(SIGFPE, regs, 0, regs->nip);
		return;
	}
}
#endif

/*
+2 −0
Original line number Diff line number Diff line
@@ -11,6 +11,8 @@ obj-$(CONFIG_MATH_EMULATION) += fabs.o fadd.o fadds.o fcmpo.o fcmpu.o \
					mcrfs.o mffs.o mtfsb0.o mtfsb1.o \
					mtfsf.o mtfsfi.o stfiwx.o stfs.o

obj-$(CONFIG_SPE)		+= math_efp.o

CFLAGS_fabs.o = -fno-builtin-fabs
CFLAGS_math.o = -fno-builtin-fabs

Loading