ia64/xen-unstable

changeset 18915:c15244125a69

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>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Dec 11 11:40:10 2008 +0000 (2008-12-11)
parents f4c1a347311b
children 2941b1a97c60
files xen/arch/x86/io_apic.c
line diff
     1.1 --- a/xen/arch/x86/io_apic.c	Thu Dec 11 11:36:00 2008 +0000
     1.2 +++ b/xen/arch/x86/io_apic.c	Thu Dec 11 11:40:10 2008 +0000
     1.3 @@ -1257,14 +1257,16 @@ static void __init setup_ioapic_ids_from
     1.4  static int __init timer_irq_works(void)
     1.5  {
     1.6      extern unsigned long pit0_ticks;
     1.7 -    unsigned long t1;
     1.8 +    unsigned long t1, flags;
     1.9  
    1.10      t1 = pit0_ticks;
    1.11      mb();
    1.12  
    1.13 +    local_save_flags(flags);
    1.14      local_irq_enable();
    1.15      /* Let ten ticks pass... */
    1.16      mdelay((10 * 1000) / HZ);
    1.17 +    local_irq_restore(flags);
    1.18  
    1.19      /*
    1.20       * Expect a few ticks at least, to be sure some possible
    1.21 @@ -1707,6 +1709,9 @@ static inline void check_timer(void)
    1.22  {
    1.23      int apic1, pin1, apic2, pin2;
    1.24      int vector;
    1.25 +    unsigned long flags;
    1.26 +
    1.27 +    local_irq_save(flags);
    1.28  
    1.29      /*
    1.30       * get/set the timer IRQ vector:
    1.31 @@ -1748,6 +1753,7 @@ static inline void check_timer(void)
    1.32           */
    1.33          unmask_IO_APIC_irq(0);
    1.34          if (timer_irq_works()) {
    1.35 +            local_irq_restore(flags);
    1.36              if (disable_timer_pin_1 > 0)
    1.37                  clear_IO_APIC_pin(apic1, pin1);
    1.38              return;
    1.39 @@ -1765,6 +1771,7 @@ static inline void check_timer(void)
    1.40           */
    1.41          setup_ExtINT_IRQ0_pin(apic2, pin2, vector);
    1.42          if (timer_irq_works()) {
    1.43 +            local_irq_restore(flags);
    1.44              printk("works.\n");
    1.45              if (pin1 != -1)
    1.46                  replace_pin_at_irq(0, apic1, pin1, apic2, pin2);
    1.47 @@ -1792,6 +1799,7 @@ static inline void check_timer(void)
    1.48      enable_8259A_irq(0);
    1.49  
    1.50      if (timer_irq_works()) {
    1.51 +        local_irq_restore(flags);
    1.52          printk(" works.\n");
    1.53          return;
    1.54      }
    1.55 @@ -1807,6 +1815,8 @@ static inline void check_timer(void)
    1.56  
    1.57      unlock_ExtINT_logic();
    1.58  
    1.59 +    local_irq_restore(flags);
    1.60 +
    1.61      if (timer_irq_works()) {
    1.62          printk(" works.\n");
    1.63          return;