x86: check_timer cleanup
authorYinghai Lu <yinghai@kernel.org>
Mon, 9 Feb 2009 00:18:03 +0000 (16:18 -0800)
committerIngo Molnar <mingo@elte.hu>
Mon, 9 Feb 2009 08:21:29 +0000 (09:21 +0100)
Impact: make check-timer more robust potentially solve boot fragility

For edge trigger io-apic routing, we already unmasked the pin via
setup_IO_APIC_irq(), so don't unmask it again.

Also call local_irq_disable() between timer_irq_works(), because it
calls local_irq_enable() inside.

Also remove not needed apic version reading for 64-bit

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
arch/x86/kernel/io_apic.c

index e5be9f3..855209a 100644 (file)
@@ -1657,7 +1657,7 @@ static void __init setup_timer_IRQ0_pin(unsigned int apic_id, unsigned int pin,
         * to the first CPU.
         */
        entry.dest_mode = apic->irq_dest_mode;
-       entry.mask = 1;                                 /* mask IRQ now */
+       entry.mask = 0;                 /* don't mask IRQ for edge */
        entry.dest = apic->cpu_mask_to_apicid(apic->target_cpus());
        entry.delivery_mode = apic->irq_delivery_mode;
        entry.polarity = 0;
@@ -2863,14 +2863,10 @@ static inline void __init check_timer(void)
        int cpu = boot_cpu_id;
        int apic1, pin1, apic2, pin2;
        unsigned long flags;
-       unsigned int ver;
        int no_pin1 = 0;
 
        local_irq_save(flags);
 
-       ver = apic_read(APIC_LVR);
-       ver = GET_APIC_VERSION(ver);
-
        /*
         * get/set the timer IRQ vector:
         */
@@ -2889,7 +2885,13 @@ static inline void __init check_timer(void)
        apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
        init_8259A(1);
 #ifdef CONFIG_X86_32
-       timer_ack = (nmi_watchdog == NMI_IO_APIC && !APIC_INTEGRATED(ver));
+       {
+               unsigned int ver;
+
+               ver = apic_read(APIC_LVR);
+               ver = GET_APIC_VERSION(ver);
+               timer_ack = (nmi_watchdog == NMI_IO_APIC && !APIC_INTEGRATED(ver));
+       }
 #endif
 
        pin1  = find_isa_irq_pin(0, mp_INT);
@@ -2928,8 +2930,17 @@ static inline void __init check_timer(void)
                if (no_pin1) {
                        add_pin_to_irq_cpu(cfg, cpu, apic1, pin1);
                        setup_timer_IRQ0_pin(apic1, pin1, cfg->vector);
+               } else {
+                       /* for edge trigger, setup_IO_APIC_irq already
+                        * leave it unmasked.
+                        * so only need to unmask if it is level-trigger
+                        * do we really have level trigger timer?
+                        */
+                       int idx;
+                       idx = find_irq_entry(apic1, pin1, mp_INT);
+                       if (idx != -1 && irq_trigger(idx))
+                               unmask_IO_APIC_irq_desc(desc);
                }
-               unmask_IO_APIC_irq_desc(desc);
                if (timer_irq_works()) {
                        if (nmi_watchdog == NMI_IO_APIC) {
                                setup_nmi();
@@ -2943,6 +2954,7 @@ static inline void __init check_timer(void)
                if (intr_remapping_enabled)
                        panic("timer doesn't work through Interrupt-remapped IO-APIC");
 #endif
+               local_irq_disable();
                clear_IO_APIC_pin(apic1, pin1);
                if (!no_pin1)
                        apic_printk(APIC_QUIET, KERN_ERR "..MP-BIOS bug: "
@@ -2957,7 +2969,6 @@ static inline void __init check_timer(void)
                 */
                replace_pin_at_irq_cpu(cfg, cpu, apic1, pin1, apic2, pin2);
                setup_timer_IRQ0_pin(apic2, pin2, cfg->vector);
-               unmask_IO_APIC_irq_desc(desc);
                enable_8259A_irq(0);
                if (timer_irq_works()) {
                        apic_printk(APIC_QUIET, KERN_INFO "....... works.\n");
@@ -2972,6 +2983,7 @@ static inline void __init check_timer(void)
                /*
                 * Cleanup, just in case ...
                 */
+               local_irq_disable();
                disable_8259A_irq(0);
                clear_IO_APIC_pin(apic2, pin2);
                apic_printk(APIC_QUIET, KERN_INFO "....... failed.\n");
@@ -2997,6 +3009,7 @@ static inline void __init check_timer(void)
                apic_printk(APIC_QUIET, KERN_INFO "..... works.\n");
                goto out;
        }
+       local_irq_disable();
        disable_8259A_irq(0);
        apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | cfg->vector);
        apic_printk(APIC_QUIET, KERN_INFO "..... failed.\n");
@@ -3014,6 +3027,7 @@ static inline void __init check_timer(void)
                apic_printk(APIC_QUIET, KERN_INFO "..... works.\n");
                goto out;
        }
+       local_irq_disable();
        apic_printk(APIC_QUIET, KERN_INFO "..... failed :(.\n");
        panic("IO-APIC + timer doesn't work!  Boot with apic=debug and send a "
                "report.  Then try booting with the 'noapic' option.\n");