]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86/kernel/io_apic_64.c
x86: I/O APIC: timer through 8259A second-chance
[linux-2.6-omap-h63xx.git] / arch / x86 / kernel / io_apic_64.c
index ae0ac990574fa4ea2cd3f01418413a9d00abbade..9a54b779abd47faa4e460bb14b064745f3c579f2 100644 (file)
@@ -1638,6 +1638,7 @@ static inline void __init check_timer(void)
        struct irq_cfg *cfg = irq_cfg + 0;
        int apic1, pin1, apic2, pin2;
        unsigned long flags;
+       int no_pin1 = 0;
 
        local_irq_save(flags);
 
@@ -1662,10 +1663,30 @@ static inline void __init check_timer(void)
        apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n",
                cfg->vector, apic1, pin1, apic2, pin2);
 
+       /*
+        * Some BIOS writers are clueless and report the ExtINTA
+        * I/O APIC input from the cascaded 8259A as the timer
+        * interrupt input.  So just in case, if only one pin
+        * was found above, try it both directly and through the
+        * 8259A.
+        */
+       if (pin1 == -1) {
+               pin1 = pin2;
+               apic1 = apic2;
+               no_pin1 = 1;
+       } else if (pin2 == -1) {
+               pin2 = pin1;
+               apic2 = apic1;
+       }
+
        if (pin1 != -1) {
                /*
                 * Ok, does IRQ0 through the IOAPIC work?
                 */
+               if (no_pin1) {
+                       add_pin_to_irq(0, apic1, pin1);
+                       setup_timer_IRQ0_pin(apic1, pin1, vector);
+               }
                unmask_IO_APIC_irq(0);
                if (!no_timer_check && timer_irq_works()) {
                        nmi_watchdog_default();
@@ -1678,18 +1699,19 @@ static inline void __init check_timer(void)
                        goto out;
                }
                clear_IO_APIC_pin(apic1, pin1);
-               apic_printk(APIC_QUIET,KERN_ERR "..MP-BIOS bug: 8254 timer not "
-                               "connected to IO-APIC\n");
-       }
+               if (!no_pin1)
+                       apic_printk(APIC_QUIET,KERN_ERR "..MP-BIOS bug: "
+                                   "8254 timer not connected to IO-APIC\n");
 
-       apic_printk(APIC_VERBOSE,KERN_INFO "...trying to set up timer (IRQ0) "
-                               "through the 8259A ... ");
-       if (pin2 != -1) {
+               apic_printk(APIC_VERBOSE,KERN_INFO
+                       "...trying to set up timer (IRQ0) "
+                       "through the 8259A ... ");
                apic_printk(APIC_VERBOSE,"\n..... (found apic %d pin %d) ...",
                        apic2, pin2);
                /*
                 * legacy devices should be connected to IO APIC #0
                 */
+               /* replace_pin_at_irq(0, apic1, pin1, apic2, pin2); */
                setup_timer_IRQ0_pin(apic2, pin2, cfg->vector);
                unmask_IO_APIC_irq(0);
                enable_8259A_irq(0);
@@ -1709,8 +1731,8 @@ static inline void __init check_timer(void)
                 */
                disable_8259A_irq(0);
                clear_IO_APIC_pin(apic2, pin2);
+               apic_printk(APIC_VERBOSE," failed.\n");
        }
-       apic_printk(APIC_VERBOSE," failed.\n");
 
        if (nmi_watchdog == NMI_IO_APIC) {
                printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n");