fea5f1e196
This reverts commit b026872601
, which has
been linked to several problem reports with IO-APIC and the timer.
Machines either don't boot because the timer doesn't happen, or we get
double timer interrupts because we end up double-routing the timer irq
through multiple interfaces.
See for example
http://lkml.org/lkml/2006/12/16/101
http://lkml.org/lkml/2007/1/3/9
http://bugzilla.kernel.org/show_bug.cgi?id=7789
about some of the discussion.
Patches to fix this cleanup exist (and have been confirmed to work fine
at least for some of the affected cases) and we'll revisit it for
2.6.21, but this late in the -rc series we're better off just reverting
the incomplete commit that caused the problems.
Suggested-by: Adrian Bunk <bunk@stusta.de>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Yinghai Lu <yinghai.lu@amd.com>
Cc: Andrew Morton <akpm@osdl.org>
Cc: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
145 lines
3.3 KiB
C
145 lines
3.3 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.
|
|
* Unfortunately that's not true on many Asus boards.
|
|
* We don't know yet how to detect this automatically, but
|
|
* at least allow a command line override.
|
|
*/
|
|
if (acpi_use_timer_override)
|
|
return;
|
|
|
|
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");
|
|
printk(KERN_INFO "If you got timer trouble "
|
|
"try acpi_use_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");
|
|
}
|
|
}
|
|
|
|
static void intel_bugs(void)
|
|
{
|
|
u16 device = read_pci_config_16(0, 0, 0, PCI_DEVICE_ID);
|
|
|
|
#ifdef CONFIG_SMP
|
|
if (device == PCI_DEVICE_ID_INTEL_E7320_MCH ||
|
|
device == PCI_DEVICE_ID_INTEL_E7520_MCH ||
|
|
device == PCI_DEVICE_ID_INTEL_E7525_MCH)
|
|
quirk_intel_irqbalance();
|
|
#endif
|
|
}
|
|
|
|
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 },
|
|
{ PCI_VENDOR_ID_INTEL, intel_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;
|
|
}
|
|
}
|
|
}
|
|
}
|