aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel
diff options
context:
space:
mode:
authorAtsushi Nemoto <anemo@mba.ocn.ne.jp>2006-06-07 12:09:01 -0400
committerRalf Baechle <ralf@linux-mips.org>2006-09-27 08:37:40 -0400
commit60a6c3777ec607c5b19df9eac35088db4e142a6b (patch)
tree8f4a680f4667ac4698dfd80bd4ccd79a34f10b19 /arch/mips/kernel
parent7fdeb048141b363a23b8cf6f6a226d74aca4d724 (diff)
[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). Original Patch by Atsushi with fixing up for MIPS Technology's cores by Ralf based on feedback from the RTL designers. Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/cpu-probe.c62
1 files changed, 45 insertions, 17 deletions
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index aa2caa67299a..9fbf8430c849 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -38,15 +38,40 @@ static void r3081_wait(void)
38 38
39static void r39xx_wait(void) 39static void r39xx_wait(void)
40{ 40{
41 unsigned long cfg = read_c0_conf(); 41 local_irq_disable();
42 write_c0_conf(cfg | TX39_CONF_HALT); 42 if (!need_resched())
43 write_c0_conf(read_c0_conf() | TX39_CONF_HALT);
44 local_irq_enable();
43} 45}
44 46
47/*
48 * There is a race when WAIT instruction executed with interrupt
49 * enabled.
50 * But it is implementation-dependent wheter the pipelie restarts when
51 * a non-enabled interrupt is requested.
52 */
45static void r4k_wait(void) 53static void r4k_wait(void)
46{ 54{
47 __asm__(".set\tmips3\n\t" 55 __asm__(" .set mips3 \n"
48 "wait\n\t" 56 " wait \n"
49 ".set\tmips0"); 57 " .set mips0 \n");
58}
59
60/*
61 * This variant is preferable as it allows testing need_resched and going to
62 * sleep depending on the outcome atomically. Unfortunately the "It is
63 * implementation-dependent whether the pipeline restarts when a non-enabled
64 * interrupt is requested" restriction in the MIPS32/MIPS64 architecture makes
65 * using this version a gamble.
66 */
67static void r4k_wait_irqoff(void)
68{
69 local_irq_disable();
70 if (!need_resched())
71 __asm__(" .set mips3 \n"
72 " wait \n"
73 " .set mips0 \n");
74 local_irq_enable();
50} 75}
51 76
52/* The Au1xxx wait is available only if using 32khz counter or 77/* The Au1xxx wait is available only if using 32khz counter or
@@ -56,17 +81,17 @@ int allow_au1k_wait;
56static void au1k_wait(void) 81static void au1k_wait(void)
57{ 82{
58 /* using the wait instruction makes CP0 counter unusable */ 83 /* using the wait instruction makes CP0 counter unusable */
59 __asm__(".set mips3\n\t" 84 __asm__(" .set mips3 \n"
60 "cache 0x14, 0(%0)\n\t" 85 " cache 0x14, 0(%0) \n"
61 "cache 0x14, 32(%0)\n\t" 86 " cache 0x14, 32(%0) \n"
62 "sync\n\t" 87 " sync \n"
63 "nop\n\t" 88 " nop \n"
64 "wait\n\t" 89 " wait \n"
65 "nop\n\t" 90 " nop \n"
66 "nop\n\t" 91 " nop \n"
67 "nop\n\t" 92 " nop \n"
68 "nop\n\t" 93 " nop \n"
69 ".set mips0\n\t" 94 " .set mips0 \n"
70 : : "r" (au1k_wait)); 95 : : "r" (au1k_wait));
71} 96}
72 97
@@ -111,7 +136,6 @@ static inline void check_wait(void)
111 case CPU_NEVADA: 136 case CPU_NEVADA:
112 case CPU_RM7000: 137 case CPU_RM7000:
113 case CPU_RM9000: 138 case CPU_RM9000:
114 case CPU_TX49XX:
115 case CPU_4KC: 139 case CPU_4KC:
116 case CPU_4KEC: 140 case CPU_4KEC:
117 case CPU_4KSC: 141 case CPU_4KSC:
@@ -125,6 +149,10 @@ static inline void check_wait(void)
125 cpu_wait = r4k_wait; 149 cpu_wait = r4k_wait;
126 printk(" available.\n"); 150 printk(" available.\n");
127 break; 151 break;
152 case CPU_TX49XX:
153 cpu_wait = r4k_wait_irqoff;
154 printk(" available.\n");
155 break;
128 case CPU_AU1000: 156 case CPU_AU1000:
129 case CPU_AU1100: 157 case CPU_AU1100:
130 case CPU_AU1500: 158 case CPU_AU1500: