aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndi Kleen <ak@suse.de>2006-02-25 22:18:52 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-02-26 12:53:31 -0500
commitab9b32ee626e9b6df4ce2560a70ae15e62423cf4 (patch)
tree4bae7b0a38b9e69d33dc7b80ad434274019d9e38
parente8b917775b572bc27de105f1317c2de4335db5b3 (diff)
[PATCH] x86_64: Better ATI timer fix
The previous experiment for using apicmaintimer on ATI systems didn't work out very well. In particular laptops with C2/C3 support often don't let it tick during idle, which makes it useless. There were also some other bugs that made the apicmaintimer often not used at all. I tried some other experiments - running timer over RTC and some other things but they didn't really work well neither. I rechecked the specs now and it turns out this simple change is actually enough to avoid the double ticks on the ATI systems. We just turn off IRQ 0 in the 8254 and only route it directly using the IO-APIC. I tested it on a few ATI systems and it worked there. In fact it worked on all chipsets (NVidia, Intel, AMD, ATI) I tried it on. According to the ACPI spec routing should always work through the IO-APIC so I think it's the correct thing to do anyways (and most of the old gunk in check_timer should be thrown away for x86-64). But for 2.6.16 it's best to do a fairly minimal change: - Use the known to be working everywhere-but-ATI IRQ0 both over 8254 and IO-APIC setup everywhere - Except on ATI disable IRQ0 in the 8254 - Remove the code to select apicmaintimer on ATI chipsets - Add some boot options to allow to override this (just paranoia) In 2.6.17 I hope to switch the default over to this for everybody. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--Documentation/x86_64/boot-options.txt4
-rw-r--r--arch/x86_64/kernel/io_apic.c46
2 files changed, 33 insertions, 17 deletions
diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt
index 153740f460a6..1921353259ae 100644
--- a/Documentation/x86_64/boot-options.txt
+++ b/Documentation/x86_64/boot-options.txt
@@ -52,6 +52,10 @@ APICs
52 apicmaintimer. Useful when your PIT timer is totally 52 apicmaintimer. Useful when your PIT timer is totally
53 broken. 53 broken.
54 54
55 disable_8254_timer / enable_8254_timer
56 Enable interrupt 0 timer routing over the 8254 in addition to over
57 the IO-APIC. The kernel tries to set a sensible default.
58
55Early Console 59Early Console
56 60
57 syntax: earlyprintk=vga 61 syntax: earlyprintk=vga
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index ffab8a756664..ffed464e6b12 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -50,6 +50,8 @@ static int no_timer_check;
50 50
51int disable_timer_pin_1 __initdata; 51int disable_timer_pin_1 __initdata;
52 52
53int timer_over_8254 __initdata = 1;
54
53/* Where if anywhere is the i8259 connect in external int mode */ 55/* Where if anywhere is the i8259 connect in external int mode */
54static struct { int pin, apic; } ioapic_i8259 = { -1, -1 }; 56static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
55 57
@@ -251,6 +253,20 @@ static int __init enable_ioapic_setup(char *str)
251__setup("noapic", disable_ioapic_setup); 253__setup("noapic", disable_ioapic_setup);
252__setup("apic", enable_ioapic_setup); 254__setup("apic", enable_ioapic_setup);
253 255
256static int __init setup_disable_8254_timer(char *s)
257{
258 timer_over_8254 = -1;
259 return 1;
260}
261static int __init setup_enable_8254_timer(char *s)
262{
263 timer_over_8254 = 2;
264 return 1;
265}
266
267__setup("disable_8254_timer", setup_disable_8254_timer);
268__setup("enable_8254_timer", setup_enable_8254_timer);
269
254#include <asm/pci-direct.h> 270#include <asm/pci-direct.h>
255#include <linux/pci_ids.h> 271#include <linux/pci_ids.h>
256#include <linux/pci.h> 272#include <linux/pci.h>
@@ -309,27 +325,20 @@ void __init check_ioapic(void)
309#endif 325#endif
310 /* RED-PEN skip them on mptables too? */ 326 /* RED-PEN skip them on mptables too? */
311 return; 327 return;
328
329 /* This should be actually default, but
330 for 2.6.16 let's do it for ATI only where
331 it's really needed. */
312 case PCI_VENDOR_ID_ATI: 332 case PCI_VENDOR_ID_ATI:
313 if (apic_runs_main_timer != 0) 333 if (timer_over_8254 == 1) {
314 break; 334 timer_over_8254 = 0;
315#ifdef CONFIG_ACPI
316 /* Don't do this for laptops right
317 right now because their timer
318 doesn't necessarily tick in C2/3 */
319 if (acpi_fadt.revision >= 3 &&
320 (acpi_fadt.plvl2_lat + acpi_fadt.plvl3_lat) < 1100) {
321 printk(KERN_INFO
322"ATI board detected, but seems to be a laptop. Timer might be shakey, sorry\n");
323 break;
324 }
325#endif
326 printk(KERN_INFO 335 printk(KERN_INFO
327 "ATI board detected. Using APIC/PM timer.\n"); 336 "ATI board detected. Disabling timer routing over 8254.\n");
328 apic_runs_main_timer = 1; 337 }
329 nohpet = 1;
330 return; 338 return;
331 } 339 }
332 340
341
333 /* No multi-function device? */ 342 /* No multi-function device? */
334 type = read_pci_config_byte(num,slot,func, 343 type = read_pci_config_byte(num,slot,func,
335 PCI_HEADER_TYPE); 344 PCI_HEADER_TYPE);
@@ -1773,6 +1782,8 @@ static inline void unlock_ExtINT_logic(void)
1773 * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ 1782 * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ
1774 * is so screwy. Thanks to Brian Perkins for testing/hacking this beast 1783 * is so screwy. Thanks to Brian Perkins for testing/hacking this beast
1775 * fanatically on his truly buggy board. 1784 * fanatically on his truly buggy board.
1785 *
1786 * FIXME: really need to revamp this for modern platforms only.
1776 */ 1787 */
1777static inline void check_timer(void) 1788static inline void check_timer(void)
1778{ 1789{
@@ -1795,7 +1806,8 @@ static inline void check_timer(void)
1795 */ 1806 */
1796 apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT); 1807 apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
1797 init_8259A(1); 1808 init_8259A(1);
1798 enable_8259A_irq(0); 1809 if (timer_over_8254 > 0)
1810 enable_8259A_irq(0);
1799 1811
1800 pin1 = find_isa_irq_pin(0, mp_INT); 1812 pin1 = find_isa_irq_pin(0, mp_INT);
1801 apic1 = find_isa_irq_apic(0, mp_INT); 1813 apic1 = find_isa_irq_apic(0, mp_INT);