Skip to content

Commit 1b19ca9

Browse files
Russell Kingtorvalds
Russell King
authored andcommitted
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 71c696b ("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 <[email protected]> Signed-off-by: Russell King <[email protected]> Cc: <[email protected]> (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 <[email protected]>
1 parent 33b1e69 commit 1b19ca9

File tree

1 file changed

+8
-6
lines changed

1 file changed

+8
-6
lines changed

init/calibrate.c

+8-6
Original file line numberDiff line numberDiff line change
@@ -245,30 +245,32 @@ static unsigned long __cpuinit calibrate_delay_converge(void)
245245

246246
void __cpuinit calibrate_delay(void)
247247
{
248+
unsigned long lpj;
248249
static bool printed;
249250

250251
if (preset_lpj) {
251-
loops_per_jiffy = preset_lpj;
252+
lpj = preset_lpj;
252253
if (!printed)
253254
pr_info("Calibrating delay loop (skipped) "
254255
"preset value.. ");
255256
} else if ((!printed) && lpj_fine) {
256-
loops_per_jiffy = lpj_fine;
257+
lpj = lpj_fine;
257258
pr_info("Calibrating delay loop (skipped), "
258259
"value calculated using timer frequency.. ");
259-
} else if ((loops_per_jiffy = calibrate_delay_direct()) != 0) {
260+
} else if ((lpj = calibrate_delay_direct()) != 0) {
260261
if (!printed)
261262
pr_info("Calibrating delay using timer "
262263
"specific routine.. ");
263264
} else {
264265
if (!printed)
265266
pr_info("Calibrating delay loop... ");
266-
loops_per_jiffy = calibrate_delay_converge();
267+
lpj = calibrate_delay_converge();
267268
}
268269
if (!printed)
269270
pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n",
270-
loops_per_jiffy/(500000/HZ),
271-
(loops_per_jiffy/(5000/HZ)) % 100, loops_per_jiffy);
271+
lpj/(500000/HZ),
272+
(lpj/(5000/HZ)) % 100, lpj);
272273

274+
loops_per_jiffy = lpj;
273275
printed = true;
274276
}

0 commit comments

Comments
 (0)