e70ea8c09d
By default route the 8254 over the 8259 and only disable it on ATI boards where this causes double timer interrupts. This should unbreak some Nvidia boards where the timer doesn't seem to tick of it isn't enabled in the 8259. At least one VIA board also seemed to have a little trouble with the disabled 8259. For 2.6.20 we'll try both dynamically without black listing, but I think for .19 this is the safer approach because it has been already well tested in earlier kernels. This also makes the x86-64 behaviour the same as i386. Command line options can change all this of course. Signed-off-by: Andi Kleen <ak@suse.de>
123 lines
2.7 KiB
C
123 lines
2.7 KiB
C
/* Various workarounds for chipset bugs.
|
|
This code runs very early and can't use the regular PCI subsystem
|
|
The entries are keyed to PCI bridges which usually identify chipsets
|
|
uniquely.
|
|
This is only for whole classes of chipsets with specific problems which
|
|
need early invasive action (e.g. before the timers are initialized).
|
|
Most PCI device specific workarounds can be done later and should be
|
|
in standard PCI quirks
|
|
Mainboard specific bugs should be handled by DMI entries.
|
|
CPU specific bugs in setup.c */
|
|
|
|
#include <linux/pci.h>
|
|
#include <linux/acpi.h>
|
|
#include <linux/pci_ids.h>
|
|
#include <asm/pci-direct.h>
|
|
#include <asm/proto.h>
|
|
#include <asm/dma.h>
|
|
|
|
static void via_bugs(void)
|
|
{
|
|
#ifdef CONFIG_IOMMU
|
|
if ((end_pfn > MAX_DMA32_PFN || force_iommu) &&
|
|
!iommu_aperture_allowed) {
|
|
printk(KERN_INFO
|
|
"Looks like a VIA chipset. Disabling IOMMU. Override with iommu=allowed\n");
|
|
iommu_aperture_disabled = 1;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef CONFIG_ACPI
|
|
|
|
static int nvidia_hpet_detected __initdata;
|
|
|
|
static int __init nvidia_hpet_check(unsigned long phys, unsigned long size)
|
|
{
|
|
nvidia_hpet_detected = 1;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static void nvidia_bugs(void)
|
|
{
|
|
#ifdef CONFIG_ACPI
|
|
/*
|
|
* All timer overrides on Nvidia are
|
|
* wrong unless HPET is enabled.
|
|
*/
|
|
nvidia_hpet_detected = 0;
|
|
acpi_table_parse(ACPI_HPET, nvidia_hpet_check);
|
|
if (nvidia_hpet_detected == 0) {
|
|
acpi_skip_timer_override = 1;
|
|
printk(KERN_INFO "Nvidia board "
|
|
"detected. Ignoring ACPI "
|
|
"timer override.\n");
|
|
}
|
|
#endif
|
|
/* RED-PEN skip them on mptables too? */
|
|
|
|
}
|
|
|
|
static void ati_bugs(void)
|
|
{
|
|
if (timer_over_8254 == 1) {
|
|
timer_over_8254 = 0;
|
|
printk(KERN_INFO
|
|
"ATI board detected. Disabling timer routing over 8254.\n");
|
|
}
|
|
}
|
|
|
|
struct chipset {
|
|
u16 vendor;
|
|
void (*f)(void);
|
|
};
|
|
|
|
static struct chipset early_qrk[] = {
|
|
{ PCI_VENDOR_ID_NVIDIA, nvidia_bugs },
|
|
{ PCI_VENDOR_ID_VIA, via_bugs },
|
|
{ PCI_VENDOR_ID_ATI, ati_bugs },
|
|
{}
|
|
};
|
|
|
|
void __init early_quirks(void)
|
|
{
|
|
int num, slot, func;
|
|
|
|
if (!early_pci_allowed())
|
|
return;
|
|
|
|
/* 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;
|
|
u8 type;
|
|
int i;
|
|
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);
|
|
vendor &= 0xffff;
|
|
|
|
for (i = 0; early_qrk[i].f; i++)
|
|
if (early_qrk[i].vendor == vendor) {
|
|
early_qrk[i].f();
|
|
return;
|
|
}
|
|
|
|
type = read_pci_config_byte(num, slot, func,
|
|
PCI_HEADER_TYPE);
|
|
if (!(type & 0x80))
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|