Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

[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>

authored by

Andi Kleen and committed by
Linus Torvalds
ab9b32ee e8b91777

+33 -17
+4
Documentation/x86_64/boot-options.txt
··· 52 52 apicmaintimer. Useful when your PIT timer is totally 53 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 + 55 59 Early Console 56 60 57 61 syntax: earlyprintk=vga
+29 -17
arch/x86_64/kernel/io_apic.c
··· 50 50 51 51 int disable_timer_pin_1 __initdata; 52 52 53 + int timer_over_8254 __initdata = 1; 54 + 53 55 /* Where if anywhere is the i8259 connect in external int mode */ 54 56 static struct { int pin, apic; } ioapic_i8259 = { -1, -1 }; 55 57 ··· 253 251 __setup("noapic", disable_ioapic_setup); 254 252 __setup("apic", enable_ioapic_setup); 255 253 254 + static int __init setup_disable_8254_timer(char *s) 255 + { 256 + timer_over_8254 = -1; 257 + return 1; 258 + } 259 + static int __init setup_enable_8254_timer(char *s) 260 + { 261 + timer_over_8254 = 2; 262 + return 1; 263 + } 264 + 265 + __setup("disable_8254_timer", setup_disable_8254_timer); 266 + __setup("enable_8254_timer", setup_enable_8254_timer); 267 + 256 268 #include <asm/pci-direct.h> 257 269 #include <linux/pci_ids.h> 258 270 #include <linux/pci.h> ··· 325 309 #endif 326 310 /* RED-PEN skip them on mptables too? */ 327 311 return; 312 + 313 + /* This should be actually default, but 314 + for 2.6.16 let's do it for ATI only where 315 + it's really needed. */ 328 316 case PCI_VENDOR_ID_ATI: 329 - if (apic_runs_main_timer != 0) 330 - break; 331 - #ifdef CONFIG_ACPI 332 - /* Don't do this for laptops right 333 - right now because their timer 334 - doesn't necessarily tick in C2/3 */ 335 - if (acpi_fadt.revision >= 3 && 336 - (acpi_fadt.plvl2_lat + acpi_fadt.plvl3_lat) < 1100) { 337 - printk(KERN_INFO 338 - "ATI board detected, but seems to be a laptop. Timer might be shakey, sorry\n"); 339 - break; 340 - } 341 - #endif 317 + if (timer_over_8254 == 1) { 318 + timer_over_8254 = 0; 342 319 printk(KERN_INFO 343 - "ATI board detected. Using APIC/PM timer.\n"); 344 - apic_runs_main_timer = 1; 345 - nohpet = 1; 320 + "ATI board detected. Disabling timer routing over 8254.\n"); 321 + } 346 322 return; 347 323 } 324 + 348 325 349 326 /* No multi-function device? */ 350 327 type = read_pci_config_byte(num,slot,func, ··· 1782 1773 * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ 1783 1774 * is so screwy. Thanks to Brian Perkins for testing/hacking this beast 1784 1775 * fanatically on his truly buggy board. 1776 + * 1777 + * FIXME: really need to revamp this for modern platforms only. 1785 1778 */ 1786 1779 static inline void check_timer(void) 1787 1780 { ··· 1806 1795 */ 1807 1796 apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT); 1808 1797 init_8259A(1); 1809 - enable_8259A_irq(0); 1798 + if (timer_over_8254 > 0) 1799 + enable_8259A_irq(0); 1810 1800 1811 1801 pin1 = find_isa_irq_pin(0, mp_INT); 1812 1802 apic1 = find_isa_irq_apic(0, mp_INT);