diff options
| author | TAMUKI Shoichi <tamuki@linet.gr.jp> | 2010-08-10 21:03:28 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-11 11:59:22 -0400 |
| commit | c7ff0d9c92435e836e13aaa8d0e56d4000424bcc (patch) | |
| tree | 96f56d15b5dd96c44fb183ce00152608df50dc5c | |
| parent | bebf8cfaea1df1a104b993b995bb385e998a4dc8 (diff) | |
panic: keep blinking in spite of long spin timer mode
To keep panic_timeout accuracy when running under a hypervisor, the
current implementation only spins on long time (1 second) calls to mdelay.
That brings a good effect, but the problem is the keyboard LEDs don't
blink at all on that situation.
This patch changes to call to panic_blink_enter() between every mdelay and
keeps blinking in spite of long spin timer mode.
The time to call to mdelay is now 100ms. Even this change will keep
panic_timeout accuracy enough when running under a hypervisor.
Signed-off-by: TAMUKI Shoichi <tamuki@linet.gr.jp>
Cc: Ben Dooks <ben-linux@fluff.org>
Cc: Russell King <linux@arm.linux.org.uk>
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Cc: Anton Blanchard <anton@samba.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | Documentation/kernel-parameters.txt | 3 | ||||
| -rw-r--r-- | arch/arm/mach-s3c2440/mach-gta02.c | 17 | ||||
| -rw-r--r-- | drivers/input/serio/i8042.c | 25 | ||||
| -rw-r--r-- | include/linux/kernel.h | 2 | ||||
| -rw-r--r-- | kernel/panic.c | 58 |
5 files changed, 37 insertions, 68 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index d529b1363e95..873b68090098 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
| @@ -915,9 +915,6 @@ and is between 256 and 4096 characters. It is defined in the file | |||
| 915 | controller | 915 | controller |
| 916 | i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX | 916 | i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX |
| 917 | controllers | 917 | controllers |
| 918 | i8042.panicblink= | ||
| 919 | [HW] Frequency with which keyboard LEDs should blink | ||
| 920 | when kernel panics (default is 0.5 sec) | ||
| 921 | i8042.reset [HW] Reset the controller during init and cleanup | 918 | i8042.reset [HW] Reset the controller during init and cleanup |
| 922 | i8042.unlock [HW] Unlock (ignore) the keylock | 919 | i8042.unlock [HW] Unlock (ignore) the keylock |
| 923 | 920 | ||
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c index 9e39faa283b9..deaabe86741d 100644 --- a/arch/arm/mach-s3c2440/mach-gta02.c +++ b/arch/arm/mach-s3c2440/mach-gta02.c | |||
| @@ -90,24 +90,17 @@ | |||
| 90 | static struct pcf50633 *gta02_pcf; | 90 | static struct pcf50633 *gta02_pcf; |
| 91 | 91 | ||
| 92 | /* | 92 | /* |
| 93 | * This gets called every 1ms when we paniced. | 93 | * This gets called frequently when we paniced. |
| 94 | */ | 94 | */ |
| 95 | 95 | ||
| 96 | static long gta02_panic_blink(long count) | 96 | static long gta02_panic_blink(int state) |
| 97 | { | 97 | { |
| 98 | long delay = 0; | 98 | long delay = 0; |
| 99 | static long last_blink; | 99 | char led; |
| 100 | static char led; | ||
| 101 | 100 | ||
| 102 | /* Fast blink: 200ms period. */ | 101 | led = (state) ? 1 : 0; |
| 103 | if (count - last_blink < 100) | ||
| 104 | return 0; | ||
| 105 | |||
| 106 | led ^= 1; | ||
| 107 | gpio_direction_output(GTA02_GPIO_AUX_LED, led); | 102 | gpio_direction_output(GTA02_GPIO_AUX_LED, led); |
| 108 | 103 | ||
| 109 | last_blink = count; | ||
| 110 | |||
| 111 | return delay; | 104 | return delay; |
| 112 | } | 105 | } |
| 113 | 106 | ||
| @@ -556,7 +549,7 @@ static void gta02_poweroff(void) | |||
| 556 | 549 | ||
| 557 | static void __init gta02_machine_init(void) | 550 | static void __init gta02_machine_init(void) |
| 558 | { | 551 | { |
| 559 | /* Set the panic callback to make AUX LED blink at ~5Hz. */ | 552 | /* Set the panic callback to turn AUX LED on or off. */ |
| 560 | panic_blink = gta02_panic_blink; | 553 | panic_blink = gta02_panic_blink; |
| 561 | 554 | ||
| 562 | s3c_pm_init(); | 555 | s3c_pm_init(); |
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 258b98b9d7c2..46e4ba0b9246 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c | |||
| @@ -61,10 +61,6 @@ static bool i8042_noloop; | |||
| 61 | module_param_named(noloop, i8042_noloop, bool, 0); | 61 | module_param_named(noloop, i8042_noloop, bool, 0); |
| 62 | MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port"); | 62 | MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port"); |
| 63 | 63 | ||
| 64 | static unsigned int i8042_blink_frequency = 500; | ||
| 65 | module_param_named(panicblink, i8042_blink_frequency, uint, 0600); | ||
| 66 | MODULE_PARM_DESC(panicblink, "Frequency with which keyboard LEDs should blink when kernel panics"); | ||
| 67 | |||
| 68 | #ifdef CONFIG_X86 | 64 | #ifdef CONFIG_X86 |
| 69 | static bool i8042_dritek; | 65 | static bool i8042_dritek; |
| 70 | module_param_named(dritek, i8042_dritek, bool, 0); | 66 | module_param_named(dritek, i8042_dritek, bool, 0); |
| @@ -1030,8 +1026,8 @@ static void i8042_controller_reset(void) | |||
| 1030 | 1026 | ||
| 1031 | 1027 | ||
| 1032 | /* | 1028 | /* |
| 1033 | * i8042_panic_blink() will flash the keyboard LEDs and is called when | 1029 | * i8042_panic_blink() will turn the keyboard LEDs on or off and is called |
| 1034 | * kernel panics. Flashing LEDs is useful for users running X who may | 1030 | * when kernel panics. Flashing LEDs is useful for users running X who may |
| 1035 | * not see the console and will help distingushing panics from "real" | 1031 | * not see the console and will help distingushing panics from "real" |
| 1036 | * lockups. | 1032 | * lockups. |
| 1037 | * | 1033 | * |
| @@ -1041,22 +1037,12 @@ static void i8042_controller_reset(void) | |||
| 1041 | 1037 | ||
| 1042 | #define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0) | 1038 | #define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0) |
| 1043 | 1039 | ||
| 1044 | static long i8042_panic_blink(long count) | 1040 | static long i8042_panic_blink(int state) |
| 1045 | { | 1041 | { |
| 1046 | long delay = 0; | 1042 | long delay = 0; |
| 1047 | static long last_blink; | 1043 | char led; |
| 1048 | static char led; | ||
| 1049 | |||
| 1050 | /* | ||
| 1051 | * We expect frequency to be about 1/2s. KDB uses about 1s. | ||
| 1052 | * Make sure they are different. | ||
| 1053 | */ | ||
| 1054 | if (!i8042_blink_frequency) | ||
| 1055 | return 0; | ||
| 1056 | if (count - last_blink < i8042_blink_frequency) | ||
| 1057 | return 0; | ||
| 1058 | 1044 | ||
| 1059 | led ^= 0x01 | 0x04; | 1045 | led = (state) ? 0x01 | 0x04 : 0; |
| 1060 | while (i8042_read_status() & I8042_STR_IBF) | 1046 | while (i8042_read_status() & I8042_STR_IBF) |
| 1061 | DELAY; | 1047 | DELAY; |
| 1062 | dbg("%02x -> i8042 (panic blink)", 0xed); | 1048 | dbg("%02x -> i8042 (panic blink)", 0xed); |
| @@ -1069,7 +1055,6 @@ static long i8042_panic_blink(long count) | |||
| 1069 | dbg("%02x -> i8042 (panic blink)", led); | 1055 | dbg("%02x -> i8042 (panic blink)", led); |
| 1070 | i8042_write_data(led); | 1056 | i8042_write_data(led); |
| 1071 | DELAY; | 1057 | DELAY; |
| 1072 | last_blink = count; | ||
| 1073 | return delay; | 1058 | return delay; |
| 1074 | } | 1059 | } |
| 1075 | 1060 | ||
diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 5b57236dfbd0..452833d67b21 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h | |||
| @@ -177,7 +177,7 @@ struct va_format { | |||
| 177 | }; | 177 | }; |
| 178 | 178 | ||
| 179 | extern struct atomic_notifier_head panic_notifier_list; | 179 | extern struct atomic_notifier_head panic_notifier_list; |
| 180 | extern long (*panic_blink)(long time); | 180 | extern long (*panic_blink)(int state); |
| 181 | NORET_TYPE void panic(const char * fmt, ...) | 181 | NORET_TYPE void panic(const char * fmt, ...) |
| 182 | __attribute__ ((NORET_AND format (printf, 1, 2))) __cold; | 182 | __attribute__ ((NORET_AND format (printf, 1, 2))) __cold; |
| 183 | extern void oops_enter(void); | 183 | extern void oops_enter(void); |
diff --git a/kernel/panic.c b/kernel/panic.c index 3b16cd93fa7d..3e9037ae10e1 100644 --- a/kernel/panic.c +++ b/kernel/panic.c | |||
| @@ -24,6 +24,9 @@ | |||
| 24 | #include <linux/nmi.h> | 24 | #include <linux/nmi.h> |
| 25 | #include <linux/dmi.h> | 25 | #include <linux/dmi.h> |
| 26 | 26 | ||
| 27 | #define PANIC_TIMER_STEP 100 | ||
| 28 | #define PANIC_BLINK_SPD 18 | ||
| 29 | |||
| 27 | int panic_on_oops; | 30 | int panic_on_oops; |
| 28 | static unsigned long tainted_mask; | 31 | static unsigned long tainted_mask; |
| 29 | static int pause_on_oops; | 32 | static int pause_on_oops; |
| @@ -36,36 +39,15 @@ ATOMIC_NOTIFIER_HEAD(panic_notifier_list); | |||
| 36 | 39 | ||
| 37 | EXPORT_SYMBOL(panic_notifier_list); | 40 | EXPORT_SYMBOL(panic_notifier_list); |
| 38 | 41 | ||
| 39 | /* Returns how long it waited in ms */ | 42 | static long no_blink(int state) |
| 40 | long (*panic_blink)(long time); | ||
| 41 | EXPORT_SYMBOL(panic_blink); | ||
| 42 | |||
| 43 | static void panic_blink_one_second(void) | ||
| 44 | { | 43 | { |
| 45 | static long i = 0, end; | 44 | return 0; |
| 46 | |||
| 47 | if (panic_blink) { | ||
| 48 | end = i + MSEC_PER_SEC; | ||
| 49 | |||
| 50 | while (i < end) { | ||
| 51 | i += panic_blink(i); | ||
| 52 | mdelay(1); | ||
| 53 | i++; | ||
| 54 | } | ||
| 55 | } else { | ||
| 56 | /* | ||
| 57 | * When running under a hypervisor a small mdelay may get | ||
| 58 | * rounded up to the hypervisor timeslice. For example, with | ||
| 59 | * a 1ms in 10ms hypervisor timeslice we might inflate a | ||
| 60 | * mdelay(1) loop by 10x. | ||
| 61 | * | ||
| 62 | * If we have nothing to blink, spin on 1 second calls to | ||
| 63 | * mdelay to avoid this. | ||
| 64 | */ | ||
| 65 | mdelay(MSEC_PER_SEC); | ||
| 66 | } | ||
| 67 | } | 45 | } |
| 68 | 46 | ||
| 47 | /* Returns how long it waited in ms */ | ||
| 48 | long (*panic_blink)(int state); | ||
| 49 | EXPORT_SYMBOL(panic_blink); | ||
| 50 | |||
| 69 | /** | 51 | /** |
| 70 | * panic - halt the system | 52 | * panic - halt the system |
| 71 | * @fmt: The text string to print | 53 | * @fmt: The text string to print |
| @@ -78,7 +60,8 @@ NORET_TYPE void panic(const char * fmt, ...) | |||
| 78 | { | 60 | { |
| 79 | static char buf[1024]; | 61 | static char buf[1024]; |
| 80 | va_list args; | 62 | va_list args; |
| 81 | long i; | 63 | long i, i_next = 0; |
| 64 | int state = 0; | ||
| 82 | 65 | ||
| 83 | /* | 66 | /* |
| 84 | * It's possible to come here directly from a panic-assertion and | 67 | * It's possible to come here directly from a panic-assertion and |
| @@ -117,6 +100,9 @@ NORET_TYPE void panic(const char * fmt, ...) | |||
| 117 | 100 | ||
| 118 | bust_spinlocks(0); | 101 | bust_spinlocks(0); |
| 119 | 102 | ||
| 103 | if (!panic_blink) | ||
| 104 | panic_blink = no_blink; | ||
| 105 | |||
| 120 | if (panic_timeout > 0) { | 106 | if (panic_timeout > 0) { |
| 121 | /* | 107 | /* |
| 122 | * Delay timeout seconds before rebooting the machine. | 108 | * Delay timeout seconds before rebooting the machine. |
| @@ -124,9 +110,13 @@ NORET_TYPE void panic(const char * fmt, ...) | |||
| 124 | */ | 110 | */ |
| 125 | printk(KERN_EMERG "Rebooting in %d seconds..", panic_timeout); | 111 | printk(KERN_EMERG "Rebooting in %d seconds..", panic_timeout); |
| 126 | 112 | ||
| 127 | for (i = 0; i < panic_timeout; i++) { | 113 | for (i = 0; i < panic_timeout * 1000; i += PANIC_TIMER_STEP) { |
| 128 | touch_nmi_watchdog(); | 114 | touch_nmi_watchdog(); |
| 129 | panic_blink_one_second(); | 115 | if (i >= i_next) { |
| 116 | i += panic_blink(state ^= 1); | ||
| 117 | i_next = i + 3600 / PANIC_BLINK_SPD; | ||
| 118 | } | ||
| 119 | mdelay(PANIC_TIMER_STEP); | ||
| 130 | } | 120 | } |
| 131 | /* | 121 | /* |
| 132 | * This will not be a clean reboot, with everything | 122 | * This will not be a clean reboot, with everything |
| @@ -152,9 +142,13 @@ NORET_TYPE void panic(const char * fmt, ...) | |||
| 152 | } | 142 | } |
| 153 | #endif | 143 | #endif |
| 154 | local_irq_enable(); | 144 | local_irq_enable(); |
| 155 | while (1) { | 145 | for (i = 0; ; i += PANIC_TIMER_STEP) { |
| 156 | touch_softlockup_watchdog(); | 146 | touch_softlockup_watchdog(); |
| 157 | panic_blink_one_second(); | 147 | if (i >= i_next) { |
| 148 | i += panic_blink(state ^= 1); | ||
| 149 | i_next = i + 3600 / PANIC_BLINK_SPD; | ||
| 150 | } | ||
| 151 | mdelay(PANIC_TIMER_STEP); | ||
| 158 | } | 152 | } |
| 159 | } | 153 | } |
| 160 | 154 | ||
