Skip to content

Commit

Permalink
[PATCH] x86_64: Better ATI timer fix
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Andi Kleen authored and Linus Torvalds committed Feb 26, 2006
1 parent e8b9177 commit ab9b32e
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 17 deletions.
4 changes: 4 additions & 0 deletions Documentation/x86_64/boot-options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
46 changes: 29 additions & 17 deletions arch/x86_64/kernel/io_apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ static int no_timer_check;

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 };

Expand Down Expand Up @@ -251,6 +253,20 @@ static int __init enable_ioapic_setup(char *str)
__setup("noapic", disable_ioapic_setup);
__setup("apic", enable_ioapic_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);

#include <asm/pci-direct.h>
#include <linux/pci_ids.h>
#include <linux/pci.h>
Expand Down Expand Up @@ -309,27 +325,20 @@ void __init check_ioapic(void)
#endif
/* RED-PEN skip them on mptables too? */
return;

/* This should be actually default, but
for 2.6.16 let's do it for ATI only where
it's really needed. */
case PCI_VENDOR_ID_ATI:
if (apic_runs_main_timer != 0)
break;
#ifdef CONFIG_ACPI
/* Don't do this for laptops right
right now because their timer
doesn't necessarily tick in C2/3 */
if (acpi_fadt.revision >= 3 &&
(acpi_fadt.plvl2_lat + acpi_fadt.plvl3_lat) < 1100) {
printk(KERN_INFO
"ATI board detected, but seems to be a laptop. Timer might be shakey, sorry\n");
break;
}
#endif
if (timer_over_8254 == 1) {
timer_over_8254 = 0;
printk(KERN_INFO
"ATI board detected. Using APIC/PM timer.\n");
apic_runs_main_timer = 1;
nohpet = 1;
"ATI board detected. Disabling timer routing over 8254.\n");
}
return;
}


/* No multi-function device? */
type = read_pci_config_byte(num,slot,func,
PCI_HEADER_TYPE);
Expand Down Expand Up @@ -1773,6 +1782,8 @@ 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 inline void check_timer(void)
{
Expand All @@ -1795,7 +1806,8 @@ static inline void check_timer(void)
*/
apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
init_8259A(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);
Expand Down

0 comments on commit ab9b32e

Please sign in to comment.