powerpc/fsl-booke: Work around erratum A-006958
authorScott Wood <scottwood@freescale.com>
Wed, 24 Jul 2013 01:21:11 +0000 (20:21 -0500)
committerScott Wood <scottwood@freescale.com>
Tue, 20 Aug 2013 20:45:49 +0000 (15:45 -0500)
Erratum A-006598 says that 64-bit mftb is not atomic -- it's subject
to a similar race condition as doing mftbu/mftbl on 32-bit.  The lower
half of timebase is updated before the upper half; thus, we can share
the workaround for a similar bug on Cell.  This workaround involves
looping if the lower half of timebase is zero, thus avoiding the need
for a scratch register (other than CR0).  This workaround must be
avoided when the timebase is frozen, such as during the timebase sync
code.

This deals with kernel and vdso accesses, but other userspace accesses
will of course need to be fixed elsewhere.

Signed-off-by: Scott Wood <scottwood@freescale.com>
arch/powerpc/include/asm/cputable.h
arch/powerpc/include/asm/ppc_asm.h
arch/powerpc/include/asm/reg.h
arch/powerpc/platforms/85xx/smp.c

index 6f3887d884d2a56b538e398a9216da62ef86370b..0d4939ba48e72167a9a496f4f10a805d0badd3eb 100644 (file)
@@ -371,14 +371,19 @@ extern const char *powerpc_base_platform;
 #define CPU_FTRS_E500MC        (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | \
            CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \
            CPU_FTR_DBELL | CPU_FTR_DEBUG_LVL_EXC | CPU_FTR_EMB_HV)
+/*
+ * e5500/e6500 erratum A-006958 is a timebase bug that can use the
+ * same workaround as CPU_FTR_CELL_TB_BUG.
+ */
 #define CPU_FTRS_E5500 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | \
            CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \
            CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
-           CPU_FTR_DEBUG_LVL_EXC | CPU_FTR_EMB_HV)
+           CPU_FTR_DEBUG_LVL_EXC | CPU_FTR_EMB_HV | CPU_FTR_CELL_TB_BUG)
 #define CPU_FTRS_E6500 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | \
            CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \
            CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
-           CPU_FTR_DEBUG_LVL_EXC | CPU_FTR_EMB_HV | CPU_FTR_ALTIVEC_COMP)
+           CPU_FTR_DEBUG_LVL_EXC | CPU_FTR_EMB_HV | CPU_FTR_ALTIVEC_COMP | \
+           CPU_FTR_CELL_TB_BUG)
 #define CPU_FTRS_GENERIC_32    (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN)
 
 /* 64-bit CPUs */
index 4ebb4f8f41887d686c336e1e8b0ce02d6709f41d..8fdd3da134e0d8f1d3ff2ee438a8008c327f702e 100644 (file)
@@ -431,7 +431,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_601)
 #define ISYNC_601
 #endif
 
-#ifdef CONFIG_PPC_CELL
+#if defined(CONFIG_PPC_CELL) || defined(CONFIG_PPC_FSL_BOOK3E)
 #define MFTB(dest)                     \
 90:    mftb  dest;                     \
 BEGIN_FTR_SECTION_NESTED(96);          \
index a312e0c8cef4d1ccbd795fa2e83579dea2120fd3..55b03079d197590504b491a94ab2376e20a2ec52 100644 (file)
                                     : "memory")
 
 #ifdef __powerpc64__
-#ifdef CONFIG_PPC_CELL
+#if defined(CONFIG_PPC_CELL) || defined(CONFIG_PPC_FSL_BOOK3E)
 #define mftb()         ({unsigned long rval;                           \
                        asm volatile(                                   \
                                "90:    mftb %0;\n"                     \
index ea9c6269ead06e6d8e7fcfecaf2c82be34adbf31..ea7e62910891518d163b8544df33ebf2e006a807 100644 (file)
@@ -69,7 +69,30 @@ static void mpc85xx_give_timebase(void)
        tb_req = 0;
 
        mpc85xx_timebase_freeze(1);
+#ifdef CONFIG_PPC64
+       /*
+        * e5500/e6500 have a workaround for erratum A-006958 in place
+        * that will reread the timebase until TBL is non-zero.
+        * That would be a bad thing when the timebase is frozen.
+        *
+        * Thus, we read it manually, and instead of checking that
+        * TBL is non-zero, we ensure that TB does not change.  We don't
+        * do that for the main mftb implementation, because it requires
+        * a scratch register
+        */
+       {
+               u64 prev;
+
+               asm volatile("mftb %0" : "=r" (timebase));
+
+               do {
+                       prev = timebase;
+                       asm volatile("mftb %0" : "=r" (timebase));
+               } while (prev != timebase);
+       }
+#else
        timebase = get_tb();
+#endif
        mb();
        tb_valid = 1;