On Fri, 17 Aug 2007, Satyam Sharma wrote:
> On Fri, 17 Aug 2007, Andi Kleen wrote:
> [...]
>
> [PATCH] i386, x86_64: __const_udelay() should not be marked inline
Eek, this one wasn't quite right on both counts, (1) correctness of
kernel/crash.c did not depend on __const_udelay() being uninlined because
it used wmb() a few lines above the while loop which includes a memory
clobber anyway, and, (2) __udelay() and __ndelay() are two callsites of
__const_udelay() where it does get inlined (being in the same .c file).
Sorry, silly me.
But this one I've test-built and verified the resulting kernel images:
[PATCH] i386: Fix a couple busy loops in mach_wakecpu.h:wait_for_init_deassert()
Use cpu_relax() in the busy loops, as atomic_read() doesn't automatically
imply a compiler barrier for x86. x86_64 doesn't have this issue because
it open-codes the while loop in smpboot.c:smp_callin() itself, and already
uses cpu_relax().
For i386, however, smpboot.c:smp_callin() calls wait_for_init_deassert()
which is buggy for mach-default and mach-es7000 cases.
[ I test-built a kernel -- smp_callin() itself got inlined in its only
callsite, smpboot.c:start_secondary() -- and the relevant piece of
code disassembles to the following:
0xc1019704 <start_secondary+12>: mov 0xc144c4c8,%eax
0xc1019709 <start_secondary+17>: test %eax,%eax
0xc101970b <start_secondary+19>: je 0xc1019709 <start_secondary+17>
init_deasserted (at 0xc144c4c8) gets fetched into %%eax only once and
then we loop over the test of the stale value in the register only,
so these look like real bugs to me. With the fix below, this becomes:
0xc1019706 <start_secondary+14>: pause
0xc1019708 <start_secondary+16>: cmpl $0x0,0xc144c4c8
0xc101970f <start_secondary+23>: je 0xc1019706 <start_secondary+14>
which looks nice and healthy. ]
Thanks to Heiko Carstens for noticing this.
Signed-off-by: Satyam Sharma <[email protected]>
---
Previously sent: http://lkml.org/lkml/2007/8/15/407
include/asm-i386/mach-default/mach_wakecpu.h | 3 ++-
include/asm-i386/mach-es7000/mach_wakecpu.h | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/include/asm-i386/mach-default/mach_wakecpu.h b/include/asm-i386/mach-default/mach_wakecpu.h
index 673b85c..3ebb178 100644
--- a/include/asm-i386/mach-default/mach_wakecpu.h
+++ b/include/asm-i386/mach-default/mach_wakecpu.h
@@ -15,7 +15,8 @@
static inline void wait_for_init_deassert(atomic_t *deassert)
{
- while (!atomic_read(deassert));
+ while (!atomic_read(deassert))
+ cpu_relax();
return;
}
diff --git a/include/asm-i386/mach-es7000/mach_wakecpu.h b/include/asm-i386/mach-es7000/mach_wakecpu.h
index efc903b..84ff583 100644
--- a/include/asm-i386/mach-es7000/mach_wakecpu.h
+++ b/include/asm-i386/mach-es7000/mach_wakecpu.h
@@ -31,7 +31,8 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
static inline void wait_for_init_deassert(atomic_t *deassert)
{
#ifdef WAKE_SECONDARY_VIA_INIT
- while (!atomic_read(deassert));
+ while (!atomic_read(deassert))
+ cpu_relax();
#endif
return;
}