diff -urN a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt --- a/Documentation/kernel-parameters.txt 2010-02-25 03:52:17.000000000 +0900 +++ b/Documentation/kernel-parameters.txt 2010-04-10 12:24:29.000000000 +0900 @@ -899,9 +899,6 @@ controller i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX controllers - i8042.panicblink= - [HW] Frequency with which keyboard LEDs should blink - when kernel panics (default is 0.5 sec) i8042.reset [HW] Reset the controller during init and cleanup i8042.unlock [HW] Unlock (ignore) the keylock @@ -1824,6 +1821,9 @@ panic= [KNL] Kernel behaviour on panic Format: + panicblink= [KNL] The speed of panic blink (range is 1 to 100, the + lower the slower, the higher the faster, default is 12) + Should be 5 or less when running under a hypervisor parkbd.port= [HW] Parallel port number the keyboard adapter is connected to, default is 0. diff -urN a/arch/arm/mach-s3c2442/mach-gta02.c b/arch/arm/mach-s3c2442/mach-gta02.c --- a/arch/arm/mach-s3c2442/mach-gta02.c 2010-02-25 03:52:17.000000000 +0900 +++ b/arch/arm/mach-s3c2442/mach-gta02.c 2010-04-10 12:24:29.000000000 +0900 @@ -90,24 +90,17 @@ static struct pcf50633 *gta02_pcf; /* - * This gets called every 1ms when we paniced. + * This gets called frequently when we paniced. */ -static long gta02_panic_blink(long count) +static long gta02_panic_blink(int state) { long delay = 0; - static long last_blink; - static char led; + char led; - /* Fast blink: 200ms period. */ - if (count - last_blink < 100) - return 0; - - led ^= 1; + led = (state) ? 1 : 0; gpio_direction_output(GTA02_GPIO_AUX_LED, led); - last_blink = count; - return delay; } @@ -614,7 +607,7 @@ static void __init gta02_machine_init(void) { - /* Set the panic callback to make AUX LED blink at ~5Hz. */ + /* Set the panic callback to turn AUX LED on or off. */ panic_blink = gta02_panic_blink; s3c_pm_init(); diff -urN a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c --- a/drivers/input/serio/i8042.c 2010-02-25 03:52:17.000000000 +0900 +++ b/drivers/input/serio/i8042.c 2010-04-10 12:24:29.000000000 +0900 @@ -60,10 +60,6 @@ module_param_named(noloop, i8042_noloop, bool, 0); MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port"); -static unsigned int i8042_blink_frequency = 500; -module_param_named(panicblink, i8042_blink_frequency, uint, 0600); -MODULE_PARM_DESC(panicblink, "Frequency with which keyboard LEDs should blink when kernel panics"); - #ifdef CONFIG_X86 static bool i8042_dritek; module_param_named(dritek, i8042_dritek, bool, 0); @@ -1031,8 +1027,8 @@ /* - * i8042_panic_blink() will flash the keyboard LEDs and is called when - * kernel panics. Flashing LEDs is useful for users running X who may + * i8042_panic_blink() will turn the keyboard LEDs on or off and is called + * when kernel panics. Flashing LEDs is useful for users running X who may * not see the console and will help distingushing panics from "real" * lockups. * @@ -1042,22 +1038,12 @@ #define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0) -static long i8042_panic_blink(long count) +static long i8042_panic_blink(int state) { long delay = 0; - static long last_blink; - static char led; - - /* - * We expect frequency to be about 1/2s. KDB uses about 1s. - * Make sure they are different. - */ - if (!i8042_blink_frequency) - return 0; - if (count - last_blink < i8042_blink_frequency) - return 0; + char led; - led ^= 0x01 | 0x04; + led = (state) ? 0x01 | 0x04 : 0; while (i8042_read_status() & I8042_STR_IBF) DELAY; dbg("%02x -> i8042 (panic blink)", 0xed); @@ -1070,7 +1056,6 @@ dbg("%02x -> i8042 (panic blink)", led); i8042_write_data(led); DELAY; - last_blink = count; return delay; } diff -urN a/include/linux/kernel.h b/include/linux/kernel.h --- a/include/linux/kernel.h 2010-02-25 03:52:17.000000000 +0900 +++ b/include/linux/kernel.h 2010-04-10 12:24:29.000000000 +0900 @@ -159,7 +159,7 @@ #endif extern struct atomic_notifier_head panic_notifier_list; -extern long (*panic_blink)(long time); +extern long (*panic_blink)(int state); NORET_TYPE void panic(const char * fmt, ...) __attribute__ ((NORET_AND format (printf, 1, 2))) __cold; extern void oops_enter(void); diff -urN a/kernel/panic.c b/kernel/panic.c --- a/kernel/panic.c 2010-02-25 03:52:17.000000000 +0900 +++ b/kernel/panic.c 2010-04-10 12:24:29.000000000 +0900 @@ -31,20 +31,45 @@ static DEFINE_SPINLOCK(pause_on_oops_lock); int panic_timeout; +static int panic_blink_wpm = 12; ATOMIC_NOTIFIER_HEAD(panic_notifier_list); EXPORT_SYMBOL(panic_notifier_list); -static long no_blink(long time) +static long no_blink(int state) { return 0; } /* Returns how long it waited in ms */ -long (*panic_blink)(long time); +long (*panic_blink)(int state); EXPORT_SYMBOL(panic_blink); +static long panic_blink_enter(long count) +{ + int len; + long delay = 0; + static int state = 1; + static int first = 1; + static long next_count; + + len = 3600 / panic_blink_wpm; + if (!first && count - next_count < 0) + return 0; + if (state) { + delay += panic_blink(0); + state = 0; + if (first) + first = 0; + } else { + delay += panic_blink(1); + state = 1; + } + next_count = count + len; + return delay; +} + /** * panic - halt the system * @fmt: The text string to print @@ -58,6 +83,7 @@ static char buf[1024]; va_list args; long i; + int step; /* * It's possible to come here directly from a panic-assertion and @@ -95,9 +121,22 @@ bust_spinlocks(0); + panic_blink_wpm = clamp(panic_blink_wpm, 1, 100); + if (!panic_blink) panic_blink = no_blink; + /* + * When running under a hypervisor a small mdelay may get + * rounded up to the hypervisor timeslice. For example, with + * a 1ms in 10ms hypervisor timeslice we might inflate a + * mdelay(1) loop by 10x. + * + * If panic_blink_wpm is 5 or less, spin on 240 millisecond + * calls to mdelay to avoid this. + */ + step = (panic_blink_wpm <= 5) ? 240 : 1; + if (panic_timeout > 0) { /* * Delay timeout seconds before rebooting the machine. @@ -105,11 +144,10 @@ */ printk(KERN_EMERG "Rebooting in %d seconds..", panic_timeout); - for (i = 0; i < panic_timeout*1000; ) { + for (i = 0; i < panic_timeout * 1000; i += step) { touch_nmi_watchdog(); - i += panic_blink(i); - mdelay(1); - i++; + i += panic_blink_enter(i); + mdelay(step); } /* * This will not be a clean reboot, with everything @@ -135,11 +173,10 @@ } #endif local_irq_enable(); - for (i = 0; ; ) { + for (i = 0; ; i += step) { touch_softlockup_watchdog(); - i += panic_blink(i); - mdelay(1); - i++; + i += panic_blink_enter(i); + mdelay(step); } } @@ -404,4 +441,5 @@ #endif core_param(panic, panic_timeout, int, 0644); +core_param(panicblink, panic_blink_wpm, int, 0644); core_param(pause_on_oops, pause_on_oops, int, 0644);