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: Thu, 08 Jun 2006 01:09:01 +0900 (JST)
Cc: linux-mips@linux-mips.org
In-reply-to: <20051118.122242.07017522.nemoto@toshiba-tops.co.jp>
Original-recipient: rfc822;linux-mips@linux-mips.org
References: <20051117.011906.25910026.anemo@mba.ocn.ne.jp> <20051116184201.GJ3229@linux-mips.org> <20051118.122242.07017522.nemoto@toshiba-tops.co.jp>
Sender: linux-mips-bounce@linux-mips.org
On Fri, 18 Nov 2005 12:22:42 +0900 (JST), Atsushi Nemoto <anemo@mba.ocn.ne.jp> 
wrote:
> By datasheets, MIPS4K?, MIPS5Kc, TX49 (and TX39 using HALT bit instead
> of WAIT insn) allow us entering WAIT with interrupt disabled.

Updated against current git tree.


[MIPS] reduce race between cpu_wait() and need_resched() checking

If a thread became runnable between need_resched() and the WAIT
instruction, switching to the thread will delay until a next interrupt.
Some CPUs can execute the WAIT instruction with interrupt disabled, so
we can get rid of this race on them (at least UP case).

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 66e47e7..bc79c5b 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. */
@@ -111,11 +128,6 @@ static inline void check_wait(void)
        case CPU_R5000:
        case CPU_NEVADA:
        case CPU_RM7000:
-       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>
  • Re: cpu_idle and cpu_wait, Atsushi Nemoto <=