diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-06-22 06:55:50 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-06-23 11:59:38 -0400 |
commit | 1b19ca9f0bdab7d5035821e1ec8f39df9a6e3ee0 (patch) | |
tree | 3c2d550bba679b7c88c01c066cac696f2d19ffbb /init | |
parent | 33b1e6939f5c37ab8e64280fd3d54046607b5c80 (diff) |
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 'init')
-rw-r--r-- | init/calibrate.c | 14 |
1 files changed, 8 insertions, 6 deletions
diff --git a/init/calibrate.c b/init/calibrate.c index 2568d22a304e..aae2f40fea4c 100644 --- a/init/calibrate.c +++ b/init/calibrate.c | |||
@@ -245,30 +245,32 @@ recalibrate: | |||
245 | 245 | ||
246 | void __cpuinit calibrate_delay(void) | 246 | void __cpuinit calibrate_delay(void) |
247 | { | 247 | { |
248 | unsigned long lpj; | ||
248 | static bool printed; | 249 | static bool printed; |
249 | 250 | ||
250 | if (preset_lpj) { | 251 | if (preset_lpj) { |
251 | loops_per_jiffy = preset_lpj; | 252 | lpj = preset_lpj; |
252 | if (!printed) | 253 | if (!printed) |
253 | pr_info("Calibrating delay loop (skipped) " | 254 | pr_info("Calibrating delay loop (skipped) " |
254 | "preset value.. "); | 255 | "preset value.. "); |
255 | } else if ((!printed) && lpj_fine) { | 256 | } else if ((!printed) && lpj_fine) { |
256 | loops_per_jiffy = lpj_fine; | 257 | lpj = lpj_fine; |
257 | pr_info("Calibrating delay loop (skipped), " | 258 | pr_info("Calibrating delay loop (skipped), " |
258 | "value calculated using timer frequency.. "); | 259 | "value calculated using timer frequency.. "); |
259 | } else if ((loops_per_jiffy = calibrate_delay_direct()) != 0) { | 260 | } else if ((lpj = calibrate_delay_direct()) != 0) { |
260 | if (!printed) | 261 | if (!printed) |
261 | pr_info("Calibrating delay using timer " | 262 | pr_info("Calibrating delay using timer " |
262 | "specific routine.. "); | 263 | "specific routine.. "); |
263 | } else { | 264 | } else { |
264 | if (!printed) | 265 | if (!printed) |
265 | pr_info("Calibrating delay loop... "); | 266 | pr_info("Calibrating delay loop... "); |
266 | loops_per_jiffy = calibrate_delay_converge(); | 267 | lpj = calibrate_delay_converge(); |
267 | } | 268 | } |
268 | if (!printed) | 269 | if (!printed) |
269 | pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n", | 270 | pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n", |
270 | loops_per_jiffy/(500000/HZ), | 271 | lpj/(500000/HZ), |
271 | (loops_per_jiffy/(5000/HZ)) % 100, loops_per_jiffy); | 272 | (lpj/(5000/HZ)) % 100, lpj); |
272 | 273 | ||
274 | loops_per_jiffy = lpj; | ||
273 | printed = true; | 275 | printed = true; |
274 | } | 276 | } |