95 lines
3.1 KiB
Diff
95 lines
3.1 KiB
Diff
# HG changeset patch
|
|
# User Keir Fraser <keir.fraser@citrix.com>
|
|
# Date 1228995610 0
|
|
# Node ID c15244125a693d2a1ae5e5745a649467394d8dac
|
|
# Parent f4c1a347311bbdc7dbf3b1b213719929cf03ede3
|
|
x86: fix the potential of encountering panic "IO-APIC + timer doesn't work! ..."
|
|
|
|
Signed-off-by: Jan Beulich <jbeulich@novell.com>
|
|
|
|
Linux commit:
|
|
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=4aae07025265151e3f7041dfbf0f529e122de1d8
|
|
|
|
x86: fix "Kernel panic - not syncing: IO-APIC + timer doesn't work!"
|
|
|
|
Under rare circumstances we found we could have an IRQ0 entry while we
|
|
are in the middle of setting up the local APIC, the i8259A and the
|
|
PIT. That is certainly not how it's supposed to work! check_timer()
|
|
was supposed to be called with irqs turned off - but this eroded away
|
|
sometime in the past. This code would still work most of the time
|
|
because this code runs very quickly, but just the right timing
|
|
conditions are present and IRQ0 hits in this small, ~30 usecs window,
|
|
timer irqs stop and the system does not boot up. Also, given how early
|
|
this is during bootup, the hang is very deterministic - but it would
|
|
only occur on certain machines (and certain configs).
|
|
|
|
The fix was quite simple: disable/restore interrupts properly in this
|
|
function. With that in place the test-system now boots up just fine.
|
|
|
|
Signed-off-by: Ingo Molnar <mingo@elte.hu>
|
|
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
|
|
|
|
--- a/xen/arch/x86/io_apic.c
|
|
+++ b/xen/arch/x86/io_apic.c
|
|
@@ -1259,14 +1259,16 @@ static void __init setup_ioapic_ids_from
|
|
static int __init timer_irq_works(void)
|
|
{
|
|
extern unsigned long pit0_ticks;
|
|
- unsigned long t1;
|
|
+ unsigned long t1, flags;
|
|
|
|
t1 = pit0_ticks;
|
|
mb();
|
|
|
|
+ local_save_flags(flags);
|
|
local_irq_enable();
|
|
/* Let ten ticks pass... */
|
|
mdelay((10 * 1000) / HZ);
|
|
+ local_irq_restore(flags);
|
|
|
|
/*
|
|
* Expect a few ticks at least, to be sure some possible
|
|
@@ -1720,6 +1722,9 @@ static inline void check_timer(void)
|
|
{
|
|
int apic1, pin1, apic2, pin2;
|
|
int vector;
|
|
+ unsigned long flags;
|
|
+
|
|
+ local_irq_save(flags);
|
|
|
|
/*
|
|
* get/set the timer IRQ vector:
|
|
@@ -1761,6 +1766,7 @@ static inline void check_timer(void)
|
|
*/
|
|
unmask_IO_APIC_irq(0);
|
|
if (timer_irq_works()) {
|
|
+ local_irq_restore(flags);
|
|
if (disable_timer_pin_1 > 0)
|
|
clear_IO_APIC_pin(apic1, pin1);
|
|
return;
|
|
@@ -1778,6 +1784,7 @@ static inline void check_timer(void)
|
|
*/
|
|
setup_ExtINT_IRQ0_pin(apic2, pin2, vector);
|
|
if (timer_irq_works()) {
|
|
+ local_irq_restore(flags);
|
|
printk("works.\n");
|
|
if (pin1 != -1)
|
|
replace_pin_at_irq(0, apic1, pin1, apic2, pin2);
|
|
@@ -1805,6 +1812,7 @@ static inline void check_timer(void)
|
|
enable_8259A_irq(0);
|
|
|
|
if (timer_irq_works()) {
|
|
+ local_irq_restore(flags);
|
|
printk(" works.\n");
|
|
return;
|
|
}
|
|
@@ -1820,6 +1828,8 @@ static inline void check_timer(void)
|
|
|
|
unlock_ExtINT_logic();
|
|
|
|
+ local_irq_restore(flags);
|
|
+
|
|
if (timer_irq_works()) {
|
|
printk(" works.\n");
|
|
return;
|