On Fri, 18 Nov 2005 12:22:42 +0900 (JST), Atsushi Nemoto <anemo@xxxxxxxxxxxxx> 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@xxxxxxxxxxxxx> 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: