Skip to content
  • Russell King's avatar
    Fix CPU spinlock lockups on secondary CPU bringup · 1b19ca9f
    Russell King authored
    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: default avatarSantosh Shilimkar <santosh.shilimkar@ti.com>
    Signed-off-by: default avatarRussell 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: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    1b19ca9f