mirror of https://gitee.com/openkylin/linux.git
Revert "[PATCH] x86-64: Try multiple timer variants in check_timer"
This reverts commit b026872601
, 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>
This commit is contained in:
parent
bf81b46482
commit
fea5f1e196
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
/* Then try pure 8259A routing on the 8259 as reported by BIOS*/
|
||||
enable_8259A_irq(0);
|
||||
if (pin2 != -1) {
|
||||
setup_ExtINT_IRQ0_pin(apic2, pin2, vector);
|
||||
if (try_apic_pin(apic2,pin2,"8259A broadcast ExtINT from BIOS"))
|
||||
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");
|
||||
}
|
||||
|
||||
/* Tried all possibilities to go through the IO-APIC. Now come the
|
||||
really cheesy fallbacks. */
|
||||
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 (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);
|
||||
}
|
||||
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");
|
||||
|
|
Loading…
Reference in New Issue