[PATCH] x86-64: i386/x86-64: Fix time going twice as fast problem on ATI Xpress chipsets
authorChuck Ebbert <76306.1226@compuserve.com>
Mon, 12 Sep 2005 16:49:25 +0000 (18:49 +0200)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 12 Sep 2005 17:50:58 +0000 (10:50 -0700)
Original patch from Bertro Simul

This is probably still not quite correct, but seems to be
the best solution so far.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Documentation/kernel-parameters.txt
arch/i386/kernel/acpi/earlyquirk.c
arch/i386/kernel/io_apic.c
arch/i386/kernel/setup.c
arch/x86_64/kernel/io_apic.c
arch/x86_64/kernel/setup.c
include/asm-i386/apic.h
include/asm-x86_64/apic.h

index db2603ceabba6f6743438a4e74d458865ba504bb..7086f0a90d14a47d6ba3295e624a7bda414062a9 100644 (file)
@@ -164,6 +164,15 @@ running once the system is up.
                        over-ride platform specific driver.
                        See also Documentation/acpi-hotkey.txt.
 
+       enable_timer_pin_1 [i386,x86-64]
+                       Enable PIN 1 of APIC timer
+                       Can be useful to work around chipset bugs (in particular on some ATI chipsets)
+                       The kernel tries to set a reasonable default.
+
+       disable_timer_pin_1 [i386,x86-64]
+                       Disable PIN 1 of APIC timer
+                       Can be useful to work around chipset bugs.
+
        ad1816=         [HW,OSS]
                        Format: <io>,<irq>,<dma>,<dma2>
                        See also Documentation/sound/oss/AD1816.
index f1b9d2a46dab860c0cbf100e1bf6b9b0b220c024..087ecc67e9b358e265e79ee450995e1ed73b6c46 100644 (file)
@@ -15,6 +15,13 @@ static int __init check_bridge(int vendor, int device)
        if (vendor == PCI_VENDOR_ID_NVIDIA) {
                acpi_skip_timer_override = 1;
        }
+       /*
+        * ATI IXP chipsets get double timer interrupts.
+        * For now just do this for all ATI chipsets.
+        * FIXME: this needs to be checked for the non ACPI case too.
+        */
+       if (vendor == PCI_VENDOR_ID_ATI)
+               disable_timer_pin_1 = 1;
        return 0;
 }
 
index 35d3ce26a544aed8d45b3428444d0211c3593e3c..378313b0cce9ac9ba8de933303e5e432959cfa05 100644 (file)
@@ -60,6 +60,8 @@ int sis_apic_bug = -1;
  */
 int nr_ioapic_registers[MAX_IO_APICS];
 
+int disable_timer_pin_1 __initdata;
+
 /*
  * Rough estimation of how many shared IRQs there are, can
  * be changed anytime.
@@ -2211,6 +2213,8 @@ static inline void check_timer(void)
                                setup_nmi();
                                enable_8259A_irq(0);
                        }
+                       if (disable_timer_pin_1 > 0)
+                               clear_IO_APIC_pin(0, pin1);
                        return;
                }
                clear_IO_APIC_pin(0, pin1);
index f3d808451d253ecc08ae6ab30b68eba39f351e69..dc39ca6a7eca82f546c649cb6b2e1b3c6a20b4a2 100644 (file)
@@ -851,6 +851,11 @@ static void __init parse_cmdline_early (char ** cmdline_p)
 #endif
 
 #ifdef CONFIG_X86_LOCAL_APIC
+               if (!memcmp(from, "disable_timer_pin_1", 19))
+                       disable_timer_pin_1 = 1;
+               if (!memcmp(from, "enable_timer_pin_1", 18))
+                       disable_timer_pin_1 = -1;
+
                /* disable IO-APIC */
                else if (!memcmp(from, "noapic", 6))
                        disable_ioapic_setup();
index 961b519bda5673b42dfac2483a5ad900cb2f041e..522944a000ad9c8755ad529ba0c74bff3353c897 100644 (file)
@@ -44,6 +44,8 @@ int sis_apic_bug; /* not actually supported, dummy for compile */
 
 static int no_timer_check;
 
+int disable_timer_pin_1 __initdata;
+
 static DEFINE_SPINLOCK(ioapic_lock);
 
 /*
@@ -297,6 +299,15 @@ void __init check_ioapic(void)
 #endif
                                        /* RED-PEN skip them on mptables too? */
                                        return;
+                               case PCI_VENDOR_ID_ATI:
+                                       /* All timer interrupts on atiixp
+                                          are doubled. Disable one. */
+                                       if (disable_timer_pin_1 == 0) {
+                                               disable_timer_pin_1 = 1;
+                                               printk(KERN_INFO
+               "ATI board detected. Disabling timer pin 1.\n");
+                                       }
+                                       return;
                                } 
 
                                /* No multi-function device? */
@@ -1658,6 +1669,8 @@ static inline void check_timer(void)
                                setup_nmi();
                                enable_8259A_irq(0);
                        }
+                       if (disable_timer_pin_1 > 0)
+                               clear_IO_APIC_pin(0, pin1);
                        return;
                }
                clear_IO_APIC_pin(0, pin1);
index 869770da2933194d7fe5a3e2b4bc6084f2bff397..351d8d64c2fbf45cff433c18fe38cba1156f2b7f 100644 (file)
@@ -336,6 +336,11 @@ static __init void parse_cmdline_early (char ** cmdline_p)
 #endif
 #endif
 
+               if (!memcmp(from, "disable_timer_pin_1", 19))
+                       disable_timer_pin_1 = 1;
+               if (!memcmp(from, "enable_timer_pin_1", 18))
+                       disable_timer_pin_1 = -1;
+
                if (!memcmp(from, "nolapic", 7) ||
                    !memcmp(from, "disableapic", 11))
                        disable_apic = 1;
index 6a1b1882285c004a1c5f80b109c046fe483c8bee..8c454aa58ac6b157441ad2a77f9211e4a30f882e 100644 (file)
@@ -130,6 +130,8 @@ extern unsigned int nmi_watchdog;
 #define NMI_LOCAL_APIC 2
 #define NMI_INVALID    3
 
+extern int disable_timer_pin_1;
+
 #else /* !CONFIG_X86_LOCAL_APIC */
 static inline void lapic_shutdown(void) { }
 
index 1559d78894acc5b3519e8c25f37edbac14542ef7..6c5d5ca8383a2abf4e2bd437bdb4ea865a6ec1e5 100644 (file)
@@ -109,6 +109,8 @@ extern unsigned int nmi_watchdog;
 #define NMI_LOCAL_APIC 2
 #define NMI_INVALID    3
 
+extern int disable_timer_pin_1;
+
 #endif /* CONFIG_X86_LOCAL_APIC */
 
 extern unsigned boot_cpu_id;