Commit f72dccac authored by Yinghai Lu's avatar Yinghai Lu Committed by Ingo Molnar
Browse files

x86: check_timer cleanup



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: default avatarYinghai Lu <yinghai@kernel.org>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent abcaa2b8
Loading
Loading
Loading
Loading
+22 −8
Original line number Diff line number Diff line
@@ -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
	{
		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);
		}
		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");