Fix CPU spinlock lockups on secondary CPU bringup
commit0185a6fcc949e606b4de21afc01b2cb1bf632f73
authorRussell King <rmk+kernel@arm.linux.org.uk>
Wed, 22 Jun 2011 10:55:50 +0000 (22 11:55 +0100)
committerGreg Kroah-Hartman <gregkh@suse.de>
Sat, 9 Jul 2011 06:15:35 +0000 (8 23:15 -0700)
tree85032bc1451e70d445aa1e217abfce549c5397cd
parent196188270f0ef3f44f77457517af7c03c06faa48
Fix CPU spinlock lockups on secondary CPU bringup

commit 1b19ca9f0bdab7d5035821e1ec8f39df9a6e3ee0 upstream.

Secondary CPU bringup typically calls calibrate_delay() during its
initialization.  However, calibrate_delay() modifies a global variable
(loops_per_jiffy) used for udelay() and __delay().

A side effect of 71c696b1 ("calibrate: extract fall-back calculation
into own helper") introduced in the 2.6.39 merge window means that we
end up with a substantial period where loops_per_jiffy is zero.  This
causes the spinlock debugging code to malfunction:

u64 loops = loops_per_jiffy * HZ;
for (;;) {
for (i = 0; i < loops; i++) {
if (arch_spin_trylock(&lock->raw_lock))
return;
__delay(1);
}
...
}

by never calling arch_spin_trylock() - resulting in the CPU locking
up in an infinite loop inside __spin_lock_debug().

Work around this by only writing to loops_per_jiffy only once we have
completed all the calibration decisions.

Tested-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
--
Better solutions (such as omitting the calibration for secondary CPUs,
or arranging for calibrate_delay() to return the LPJ value and leave
it to the caller to decide where to store it) are a possibility, but
would be much more invasive into each architecture.

I think this is the best solution for -rc and stable, but it should be
revisited for the next merge window.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
init/calibrate.c