MIPS: Alchemy: fix wait function
authorManuel Lauss <manuel.lauss@gmail.com>
Sat, 8 Jun 2013 19:15:41 +0000 (19:15 +0000)
committerRalf Baechle <ralf@linux-mips.org>
Mon, 10 Jun 2013 15:59:46 +0000 (17:59 +0200)
Only an interrupt can wake the core from 'wait', enable interrupts
locally before executing 'wait'.

[ralf@linux-mips.org: This leave the race between an interrupt that's
setting TIF_NEED_RESCHEd and entering the WAIT status. but at least it's
going to bring Alchemy back from the dead, so I'm going to apply this
patch.]

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
Cc: Linux-MIPS <linux-mips@linux-mips.org>
Cc: Maciej W. Rozycki <macro@linux-mips.org>
Patchwork: https://patchwork.linux-mips.org/patch/5408/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/kernel/idle.c

index 3b09b88..0c655de 100644 (file)
@@ -93,26 +93,27 @@ static void rm7k_wait_irqoff(void)
 }
 
 /*
- * The Au1xxx wait is available only if using 32khz counter or
- * external timer source, but specifically not CP0 Counter.
- * alchemy/common/time.c may override cpu_wait!
+ * Au1 'wait' is only useful when the 32kHz counter is used as timer,
+ * since coreclock (and the cp0 counter) stops upon executing it. Only an
+ * interrupt can wake it, so they must be enabled before entering idle modes.
  */
 static void au1k_wait(void)
 {
+       unsigned long c0status = read_c0_status() | 1;  /* irqs on */
+
        __asm__(
        "       .set    mips3                   \n"
        "       cache   0x14, 0(%0)             \n"
        "       cache   0x14, 32(%0)            \n"
        "       sync                            \n"
-       "       nop                             \n"
+       "       mtc0    %1, $12                 \n" /* wr c0status */
        "       wait                            \n"
        "       nop                             \n"
        "       nop                             \n"
        "       nop                             \n"
        "       nop                             \n"
        "       .set    mips0                   \n"
-       : : "r" (au1k_wait));
-       local_irq_enable();
+       : : "r" (au1k_wait), "r" (c0status));
 }
 
 static int __initdata nowait;