mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-23 09:56:00 +00:00
f9262c12c0
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>
60 lines
1.3 KiB
C
60 lines
1.3 KiB
C
/*
|
|
* Do early PCI probing for bug detection when the main PCI subsystem is
|
|
* not up yet.
|
|
*/
|
|
#include <linux/init.h>
|
|
#include <linux/kernel.h>
|
|
#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;
|
|
}
|
|
|
|
void __init check_acpi_pci(void)
|
|
{
|
|
int num, slot, func;
|
|
|
|
/* Assume the machine supports type 1. If not it will
|
|
always read ffffffff and should not have any side effect. */
|
|
|
|
/* Poor man's PCI discovery */
|
|
for (num = 0; num < 32; num++) {
|
|
for (slot = 0; slot < 32; slot++) {
|
|
for (func = 0; func < 8; func++) {
|
|
u32 class;
|
|
u32 vendor;
|
|
class = read_pci_config(num, slot, func,
|
|
PCI_CLASS_REVISION);
|
|
if (class == 0xffffffff)
|
|
break;
|
|
|
|
if ((class >> 16) != PCI_CLASS_BRIDGE_PCI)
|
|
continue;
|
|
|
|
vendor = read_pci_config(num, slot, func,
|
|
PCI_VENDOR_ID);
|
|
|
|
if (check_bridge(vendor & 0xffff, vendor >> 16))
|
|
return;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|