diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-06-22 11:55:50 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-06-23 08:59:38 -0700 |
commit | 1b19ca9f0bdab7d5035821e1ec8f39df9a6e3ee0 (patch) | |
tree | 3c2d550bba679b7c88c01c066cac696f2d19ffbb /usr | |
parent | 33b1e6939f5c37ab8e64280fd3d54046607b5c80 (diff) | |
download | op-kernel-dev-1b19ca9f0bdab7d5035821e1ec8f39df9a6e3ee0.zip op-kernel-dev-1b19ca9f0bdab7d5035821e1ec8f39df9a6e3ee0.tar.gz |
Fix CPU spinlock lockups on secondary CPU bringup
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>
Cc: <stable@kernel.org> (2.6.39-stable)
--
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.
init/calibrate.c | 14 ++++++++------
1 files changed, 8 insertions(+), 6 deletions(-)
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'usr')
0 files changed, 0 insertions, 0 deletions