Skip to content

Commit

Permalink
powerpc: Add SPE/EFP math emulation for E500v1/v2 processors.
Browse files Browse the repository at this point in the history
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: Liu Yu <yu.liu@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
  • Loading branch information
Liu Yu authored and Kumar Gala committed Dec 3, 2008
1 parent 033b8a3 commit 6a800f3
Show file tree
Hide file tree
Showing 6 changed files with 813 additions and 20 deletions.
6 changes: 6 additions & 0 deletions arch/powerpc/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 { \
Expand All @@ -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 { \
Expand Down
36 changes: 26 additions & 10 deletions arch/powerpc/include/asm/sfp-machine.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 ;-). */
Expand All @@ -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.
Expand All @@ -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)

Expand Down
7 changes: 4 additions & 3 deletions arch/powerpc/kernel/head_fsl_booke.S
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
62 changes: 55 additions & 7 deletions arch/powerpc/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

_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

/*
Expand Down
2 changes: 2 additions & 0 deletions arch/powerpc/math-emu/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Loading

0 comments on commit 6a800f3

Please sign in to comment.