linux-mips
[Top] [All Lists]

Re: cpu_idle and cpu_wait

To: ralf@linux-mips.org
Subject: Re: cpu_idle and cpu_wait
From: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Date: Fri, 18 Nov 2005 12:22:42 +0900 (JST)
Cc: linux-mips@linux-mips.org
In-reply-to: <20051116184201.GJ3229@linux-mips.org>
Original-recipient: rfc822;linux-mips@linux-mips.org
References: <20051117.011906.25910026.anemo@mba.ocn.ne.jp> <20051116184201.GJ3229@linux-mips.org>
Sender: linux-mips-bounce@linux-mips.org
>>>>> On Wed, 16 Nov 2005 18:42:01 +0000, Ralf Baechle <ralf@linux-mips.org> 
>>>>> said:
>> The CPU can surely exit from the WAIT instruction by interrupt even
>> if interrupts disabled?

ralf> That's implementation dependent behaviour, unfortunately.

Then how about this patch?

By datasheets, MIPS4K?, MIPS5Kc, TX49 (and TX39 using HALT bit instead
of WAIT insn) allow us entering WAIT with interrupt disabled.

Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>

diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index d2ae111..4bdd8c1 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -39,16 +39,33 @@ static void r3081_wait(void)
 
 static void r39xx_wait(void)
 {
-       unsigned long cfg = read_c0_conf();
-       write_c0_conf(cfg | TX39_CONF_HALT);
+       local_irq_disable();
+       if (!need_resched())
+               write_c0_conf(read_c0_conf() | TX39_CONF_HALT);
+       local_irq_enable();
 }
 
+/*
+ * There is a race when WAIT instruction executed with interrupt
+ * enabled.
+ * But it is implementation-dependent wheter the pipelie restarts when
+ * a non-enabled interrupt is requested.
+ */
 static void r4k_wait(void)
 {
        __asm__(".set\tmips3\n\t"
                "wait\n\t"
                ".set\tmips0");
 }
+static void r4k_wait_irqoff(void)
+{
+       local_irq_disable();
+       if (!need_resched())
+               __asm__(".set\tmips3\n\t"
+                       "wait\n\t"
+                       ".set\tmips0");
+       local_irq_enable();
+}
 
 /* The Au1xxx wait is available only if using 32khz counter or
  * external timer source, but specifically not CP0 Counter. */
@@ -112,11 +129,6 @@ static inline void check_wait(void)
        case CPU_NEVADA:
        case CPU_RM7000:
        case CPU_RM9000:
-       case CPU_TX49XX:
-       case CPU_4KC:
-       case CPU_4KEC:
-       case CPU_4KSC:
-       case CPU_5KC:
 /*     case CPU_20KC:*/
        case CPU_24K:
        case CPU_25KF:
@@ -125,6 +137,14 @@ static inline void check_wait(void)
                cpu_wait = r4k_wait;
                printk(" available.\n");
                break;
+       case CPU_TX49XX:
+       case CPU_4KC:
+       case CPU_4KEC:
+       case CPU_4KSC:
+       case CPU_5KC:
+               cpu_wait = r4k_wait_irqoff;
+               printk(" available.\n");
+               break;
        case CPU_AU1000:
        case CPU_AU1100:
        case CPU_AU1500:

<Prev in Thread] Current Thread [Next in Thread>