diff options
author | Linus Torvalds <torvalds@woody.osdl.org> | 2007-01-08 15:04:46 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2007-01-08 15:04:46 -0800 |
commit | fea5f1e19611d94fbf3905875a427c4cb959cd06 (patch) | |
tree | 5a4c0584eea3ba74745e836e370fa1bbd0dacb02 | |
parent | bf81b46482c0fa8ea638e409d39768ea92a6b0f0 (diff) |
Revert "[PATCH] x86-64: Try multiple timer variants in check_timer"
This reverts commit b026872601976f666bae77b609dc490d1834bf77, which has
been linked to several problem reports with IO-APIC and the timer.
Machines either don't boot because the timer doesn't happen, or we get
double timer interrupts because we end up double-routing the timer irq
through multiple interfaces.
See for example
http://lkml.org/lkml/2006/12/16/101
http://lkml.org/lkml/2007/1/3/9
http://bugzilla.kernel.org/show_bug.cgi?id=7789
about some of the discussion.
Patches to fix this cleanup exist (and have been confirmed to work fine
at least for some of the affected cases) and we'll revisit it for
2.6.21, but this late in the -rc series we're better off just reverting
the incomplete commit that caused the problems.
Suggested-by: Adrian Bunk <bunk@stusta.de>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Yinghai Lu <yinghai.lu@amd.com>
Cc: Andrew Morton <akpm@osdl.org>
Cc: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | Documentation/x86_64/boot-options.txt | 4 | ||||
-rw-r--r-- | arch/x86_64/kernel/early-quirks.c | 5 | ||||
-rw-r--r-- | arch/x86_64/kernel/io_apic.c | 124 |
3 files changed, 82 insertions, 51 deletions
diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt index dbdcaf68e3ea..5c86ed6f0448 100644 --- a/Documentation/x86_64/boot-options.txt +++ b/Documentation/x86_64/boot-options.txt @@ -52,6 +52,10 @@ APICs apicmaintimer. Useful when your PIT timer is totally broken. + disable_8254_timer / enable_8254_timer + Enable interrupt 0 timer routing over the 8254 in addition to over + the IO-APIC. The kernel tries to set a sensible default. + Early Console syntax: earlyprintk=vga diff --git a/arch/x86_64/kernel/early-quirks.c b/arch/x86_64/kernel/early-quirks.c index 829698f6d049..49802f1bee94 100644 --- a/arch/x86_64/kernel/early-quirks.c +++ b/arch/x86_64/kernel/early-quirks.c @@ -69,6 +69,11 @@ static void nvidia_bugs(void) static void ati_bugs(void) { + if (timer_over_8254 == 1) { + timer_over_8254 = 0; + printk(KERN_INFO + "ATI board detected. Disabling timer routing over 8254.\n"); + } } static void intel_bugs(void) diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 2a1dcd5f69c2..d7bad90a5ad8 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -55,6 +55,10 @@ int sis_apic_bug; /* not actually supported, dummy for compile */ static int no_timer_check; +static int disable_timer_pin_1 __initdata; + +int timer_over_8254 __initdata = 1; + /* Where if anywhere is the i8259 connect in external int mode */ static struct { int pin, apic; } ioapic_i8259 = { -1, -1 }; @@ -350,6 +354,29 @@ static int __init disable_ioapic_setup(char *str) } early_param("noapic", disable_ioapic_setup); +/* Actually the next is obsolete, but keep it for paranoid reasons -AK */ +static int __init disable_timer_pin_setup(char *arg) +{ + disable_timer_pin_1 = 1; + return 1; +} +__setup("disable_timer_pin_1", disable_timer_pin_setup); + +static int __init setup_disable_8254_timer(char *s) +{ + timer_over_8254 = -1; + return 1; +} +static int __init setup_enable_8254_timer(char *s) +{ + timer_over_8254 = 2; + return 1; +} + +__setup("disable_8254_timer", setup_disable_8254_timer); +__setup("enable_8254_timer", setup_enable_8254_timer); + + /* * Find the IRQ entry number of a certain pin. */ @@ -1568,33 +1595,10 @@ static inline void unlock_ExtINT_logic(void) * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ * is so screwy. Thanks to Brian Perkins for testing/hacking this beast * fanatically on his truly buggy board. + * + * FIXME: really need to revamp this for modern platforms only. */ - -static int try_apic_pin(int apic, int pin, char *msg) -{ - apic_printk(APIC_VERBOSE, KERN_INFO - "..TIMER: trying IO-APIC=%d PIN=%d %s", - apic, pin, msg); - - /* - * Ok, does IRQ0 through the IOAPIC work? - */ - if (!no_timer_check && timer_irq_works()) { - nmi_watchdog_default(); - if (nmi_watchdog == NMI_IO_APIC) { - disable_8259A_irq(0); - setup_nmi(); - enable_8259A_irq(0); - } - return 1; - } - clear_IO_APIC_pin(apic, pin); - apic_printk(APIC_QUIET, KERN_ERR " .. failed\n"); - return 0; -} - -/* The function from hell */ -static void check_timer(void) +static inline void check_timer(void) { int apic1, pin1, apic2, pin2; int vector; @@ -1615,43 +1619,61 @@ static void check_timer(void) */ apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT); init_8259A(1); + if (timer_over_8254 > 0) + enable_8259A_irq(0); pin1 = find_isa_irq_pin(0, mp_INT); apic1 = find_isa_irq_apic(0, mp_INT); pin2 = ioapic_i8259.pin; apic2 = ioapic_i8259.apic; - /* Do this first, otherwise we get double interrupts on ATI boards */ - if ((pin1 != -1) && try_apic_pin(apic1, pin1,"with 8259 IRQ0 disabled")) - return; + apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n", + vector, apic1, pin1, apic2, pin2); - /* Now try again with IRQ0 8259A enabled. - Assumes timer is on IO-APIC 0 ?!? */ - enable_8259A_irq(0); - unmask_IO_APIC_irq(0); - if (try_apic_pin(apic1, pin1, "with 8259 IRQ0 enabled")) - return; - disable_8259A_irq(0); - - /* Always try pin0 and pin2 on APIC 0 to handle buggy timer overrides - on Nvidia boards */ - if (!(apic1 == 0 && pin1 == 0) && - try_apic_pin(0, 0, "fallback with 8259 IRQ0 disabled")) - return; - if (!(apic1 == 0 && pin1 == 2) && - try_apic_pin(0, 2, "fallback with 8259 IRQ0 disabled")) - return; + if (pin1 != -1) { + /* + * Ok, does IRQ0 through the IOAPIC work? + */ + unmask_IO_APIC_irq(0); + if (!no_timer_check && timer_irq_works()) { + nmi_watchdog_default(); + if (nmi_watchdog == NMI_IO_APIC) { + disable_8259A_irq(0); + setup_nmi(); + enable_8259A_irq(0); + } + if (disable_timer_pin_1 > 0) + clear_IO_APIC_pin(0, pin1); + return; + } + clear_IO_APIC_pin(apic1, pin1); + apic_printk(APIC_QUIET,KERN_ERR "..MP-BIOS bug: 8254 timer not " + "connected to IO-APIC\n"); + } - /* Then try pure 8259A routing on the 8259 as reported by BIOS*/ - enable_8259A_irq(0); + apic_printk(APIC_VERBOSE,KERN_INFO "...trying to set up timer (IRQ0) " + "through the 8259A ... "); if (pin2 != -1) { + apic_printk(APIC_VERBOSE,"\n..... (found apic %d pin %d) ...", + apic2, pin2); + /* + * legacy devices should be connected to IO APIC #0 + */ setup_ExtINT_IRQ0_pin(apic2, pin2, vector); - if (try_apic_pin(apic2,pin2,"8259A broadcast ExtINT from BIOS")) + if (timer_irq_works()) { + apic_printk(APIC_VERBOSE," works.\n"); + nmi_watchdog_default(); + if (nmi_watchdog == NMI_IO_APIC) { + setup_nmi(); + } return; + } + /* + * Cleanup, just in case ... + */ + clear_IO_APIC_pin(apic2, pin2); } - - /* Tried all possibilities to go through the IO-APIC. Now come the - really cheesy fallbacks. */ + 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"); |