summaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel
diff options
context:
space:
mode:
authorAndi Kleen <ak@suse.de>2006-03-08 17:57:25 -0800
committerLinus Torvalds <torvalds@g5.osdl.org>2006-03-08 18:10:31 -0800
commitf9262c12c0084ddba445a9a42e98994018e51400 (patch)
treeb54948e654e68c1e5263d955c76bf3a41dfa14da /arch/i386/kernel
parent979ce809bab37cf438f0db22bfa732d01a84a8c2 (diff)
[PATCH] i386: port ATI timer fix from x86_64 to i386 II
ATI chipsets tend to generate double timer interrupts for the local APIC timer when both the 8254 and the IO-APIC timer pins are enabled. This is because they route it to both and the result is anded together and the CPU ends up processing it twice. This patch changes check_timer to disable the 8254 routing for interrupt 0. I think it would be safe on all chipsets actually (i tested it on a couple and it worked everywhere) and Windows seems to do it in a similar way, but to be conservative this patch only enables this mode on ATI (and adds options to enable/disable too) Ported over from a similar x86-64 change. I reused the ACPI earlyquirk infrastructure for the ATI bridge check, but tweaked it a bit to work even without ACPI. Inspired by a patch from Chuck Ebbert, but redone. Cc: Chuck Ebbert <76306.1226@compuserve.com> Cc: "Brown, Len" <len.brown@intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/i386/kernel')
-rw-r--r--arch/i386/kernel/Makefile2
-rw-r--r--arch/i386/kernel/acpi/Makefile2
-rw-r--r--arch/i386/kernel/acpi/boot.c3
-rw-r--r--arch/i386/kernel/acpi/earlyquirk.c8
-rw-r--r--arch/i386/kernel/io_apic.c19
-rw-r--r--arch/i386/kernel/setup.c4
6 files changed, 32 insertions, 6 deletions
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index 53bb9a79e27..65656c033d7 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -11,7 +11,7 @@ obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \
obj-y += cpu/
obj-y += timers/
-obj-$(CONFIG_ACPI) += acpi/
+obj-y += acpi/
obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o
obj-$(CONFIG_MCA) += mca.o
obj-$(CONFIG_X86_MSR) += msr.o
diff --git a/arch/i386/kernel/acpi/Makefile b/arch/i386/kernel/acpi/Makefile
index d51c7313cae..7e9ac99354f 100644
--- a/arch/i386/kernel/acpi/Makefile
+++ b/arch/i386/kernel/acpi/Makefile
@@ -1,4 +1,4 @@
-obj-y := boot.o
+obj-$(CONFIG_ACPI) += boot.o
obj-$(CONFIG_X86_IO_APIC) += earlyquirk.o
obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o
diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
index 79577f0ace9..f1a21945963 100644
--- a/arch/i386/kernel/acpi/boot.c
+++ b/arch/i386/kernel/acpi/boot.c
@@ -1111,9 +1111,6 @@ int __init acpi_boot_table_init(void)
disable_acpi();
return error;
}
-#ifdef __i386__
- check_acpi_pci();
-#endif
acpi_table_parse(ACPI_BOOT, acpi_parse_sbf);
diff --git a/arch/i386/kernel/acpi/earlyquirk.c b/arch/i386/kernel/acpi/earlyquirk.c
index f1b9d2a46da..2e3b643a4dc 100644
--- a/arch/i386/kernel/acpi/earlyquirk.c
+++ b/arch/i386/kernel/acpi/earlyquirk.c
@@ -7,14 +7,22 @@
#include <linux/pci.h>
#include <asm/pci-direct.h>
#include <asm/acpi.h>
+#include <asm/apic.h>
static int __init check_bridge(int vendor, int device)
{
+#ifdef CONFIG_ACPI
/* According to Nvidia all timer overrides are bogus. Just ignore
them all. */
if (vendor == PCI_VENDOR_ID_NVIDIA) {
acpi_skip_timer_override = 1;
}
+#endif
+ if (vendor == PCI_VENDOR_ID_ATI && timer_over_8254 == 1) {
+ timer_over_8254 = 0;
+ printk(KERN_INFO "ATI board detected. Disabling timer routing "
+ "over 8254.\n");
+ }
return 0;
}
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index 235822b3f41..39d9a5fa907 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -51,6 +51,8 @@ static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
static DEFINE_SPINLOCK(ioapic_lock);
+int timer_over_8254 __initdata = 1;
+
/*
* Is the SiS APIC rmw bug present ?
* -1 = don't know, 0 = no, 1 = yes
@@ -2267,7 +2269,8 @@ static inline void check_timer(void)
apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
init_8259A(1);
timer_ack = 1;
- enable_8259A_irq(0);
+ 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);
@@ -2392,6 +2395,20 @@ void __init setup_IO_APIC(void)
print_IO_APIC();
}
+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);
+
/*
* Called after all the initialization is done. If we didnt find any
* APIC bugs then we can allow the modify fast path
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index 51e513b4f72..ab62a9f4701 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -1599,6 +1599,10 @@ void __init setup_arch(char **cmdline_p)
if (efi_enabled)
efi_map_memmap();
+#ifdef CONFIG_X86_IO_APIC
+ check_acpi_pci(); /* Checks more than just ACPI actually */
+#endif
+
#ifdef CONFIG_ACPI
/*
* Parse the ACPI tables for possible boot-time SMP configuration.