powerpc/85xx: Workaroudn e500 CPU erratum A005
authorLiu Yu <yu.liu@freescale.com>
Tue, 25 Jan 2011 06:02:13 +0000 (14:02 +0800)
committerKumar Gala <galak@kernel.crashing.org>
Tue, 15 Mar 2011 15:05:06 +0000 (10:05 -0500)
This erratum can occur if a single-precision floating-point,
double-precision floating-point or vector floating-point instruction on a
mispredicted branch path signals one of the floating-point data interrupts
which are enabled by the SPEFSCR (FINVE, FDBZE, FUNFE or FOVFE bits).  This
interrupt must be recorded in a one-cycle window when the misprediction is
resolved.  If this extremely rare event should occur, the result could be:

The SPE Data Exception from the mispredicted path may be reported
erroneously if a single-precision floating-point, double-precision
floating-point or vector floating-point instruction is the second
instruction on the correct branch path.

According to errata description, some efp instructions which are not
supposed to trigger SPE exceptions can trigger the exceptions in this case.
However, as we haven't emulated these instructions here, a signal will
send to userspace, and userspace application would exit.

This patch re-issue the efp instruction that we haven't emulated,
so that hardware can properly execute it again if this case happen.

Signed-off-by: Liu Yu <yu.liu@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
arch/powerpc/include/asm/reg.h
arch/powerpc/math-emu/math_efp.c

index bd0d36e1c9451c321b341e7461e555309e2a39b5..1bc6a12f3725a3b87ff4bc7c0771eb129382278e 100644 (file)
 #define PVR_7450       0x80000000
 #define PVR_8540       0x80200000
 #define PVR_8560       0x80200000
+#define PVR_VER_E500V1 0x8020
+#define PVR_VER_E500V2 0x8021
 /*
  * For the 8xx processors, all of them report the same PVR family for
  * the PowerPC core. The various versions of these processors must be
index 41f4ef30e480e6deb7584627d42a91f5d3f4f674..634830bdc0beda431a5a6c348ccd36f167803a02 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/powerpc/math-emu/math_efp.c
  *
- * Copyright (C) 2006-2008 Freescale Semiconductor, Inc. All rights reserved.
+ * Copyright (C) 2006-2008, 2010 Freescale Semiconductor, Inc.
  *
  * Author: Ebony Zhu,  <ebony.zhu@freescale.com>
  *         Yu Liu,     <yu.liu@freescale.com>
 #define FP_EX_MASK     (FP_EX_INEXACT | FP_EX_INVALID | FP_EX_DIVZERO | \
                        FP_EX_UNDERFLOW | FP_EX_OVERFLOW)
 
+static int have_e500_cpu_a005_erratum;
+
 union dw_union {
        u64 dp[1];
        u32 wp[2];
@@ -652,6 +654,15 @@ update_regs:
        return 0;
 
 illegal:
+       if (have_e500_cpu_a005_erratum) {
+               /* according to e500 cpu a005 erratum, reissue efp inst */
+               regs->nip -= 4;
+#ifdef DEBUG
+               printk(KERN_DEBUG "re-issue efp inst: %08lx\n", speinsn);
+#endif
+               return 0;
+       }
+
        printk(KERN_ERR "\nOoops! IEEE-754 compliance handler encountered un-supported instruction.\ninst code: %08lx\n", speinsn);
        return -ENOSYS;
 }
@@ -718,3 +729,43 @@ int speround_handler(struct pt_regs *regs)
 
        return 0;
 }
+
+int __init spe_mathemu_init(void)
+{
+       u32 pvr, maj, min;
+
+       pvr = mfspr(SPRN_PVR);
+
+       if ((PVR_VER(pvr) == PVR_VER_E500V1) ||
+           (PVR_VER(pvr) == PVR_VER_E500V2)) {
+               maj = PVR_MAJ(pvr);
+               min = PVR_MIN(pvr);
+
+               /*
+                * E500 revision below 1.1, 2.3, 3.1, 4.1, 5.1
+                * need cpu a005 errata workaround
+                */
+               switch (maj) {
+               case 1:
+                       if (min < 1)
+                               have_e500_cpu_a005_erratum = 1;
+                       break;
+               case 2:
+                       if (min < 3)
+                               have_e500_cpu_a005_erratum = 1;
+                       break;
+               case 3:
+               case 4:
+               case 5:
+                       if (min < 1)
+                               have_e500_cpu_a005_erratum = 1;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+module_init(spe_mathemu_init);