[MIPS] Workaround for RM7000 WAIT instruction aka erratum 38
authorRalf Baechle <ralf@linux-mips.org>
Tue, 17 Jul 2007 17:49:48 +0000 (18:49 +0100)
committerRalf Baechle <ralf@linux-mips.org>
Fri, 20 Jul 2007 17:57:39 +0000 (18:57 +0100)
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/kernel/cpu-probe.c

index c6b8b074a81aa65fad1fa9d0ce3aede09bff8ef5..06448a9656dce69f5920de6b21cdca5e05c98498 100644 (file)
@@ -75,6 +75,27 @@ static void r4k_wait_irqoff(void)
        local_irq_enable();
 }
 
+/*
+ * The RM7000 variant has to handle erratum 38.  The workaround is to not
+ * have any pending stores when the WAIT instruction is executed.
+ */
+static void rm7k_wait_irqoff(void)
+{
+       local_irq_disable();
+       if (!need_resched())
+               __asm__(
+               "       .set    push                                    \n"
+               "       .set    mips3                                   \n"
+               "       .set    noat                                    \n"
+               "       mfc0    $1, $12                                 \n"
+               "       sync                                            \n"
+               "       mtc0    $1, $12         # stalls until W stage  \n"
+               "       wait                                            \n"
+               "       mtc0    $1, $12         # stalls until W stage  \n"
+               "       .set    pop                                     \n");
+       local_irq_enable();
+}
+
 /* The Au1xxx wait is available only if using 32khz counter or
  * external timer source, but specifically not CP0 Counter. */
 int allow_au1k_wait;
@@ -132,7 +153,6 @@ static inline void check_wait(void)
        case CPU_R4700:
        case CPU_R5000:
        case CPU_NEVADA:
-       case CPU_RM7000:
        case CPU_4KC:
        case CPU_4KEC:
        case CPU_4KSC:
@@ -142,6 +162,10 @@ static inline void check_wait(void)
                cpu_wait = r4k_wait;
                break;
 
+       case CPU_RM7000:
+               cpu_wait = rm7k_wait_irqoff;
+               break;
+
        case CPU_24K:
        case CPU_34K:
                cpu_wait = r4k_wait;