]>
Commit | Line | Data |
---|---|---|
dfa4698c AK |
1 | /* Various workarounds for chipset bugs. |
2 | This code runs very early and can't use the regular PCI subsystem | |
3 | The entries are keyed to PCI bridges which usually identify chipsets | |
4 | uniquely. | |
5 | This is only for whole classes of chipsets with specific problems which | |
6 | need early invasive action (e.g. before the timers are initialized). | |
7 | Most PCI device specific workarounds can be done later and should be | |
8 | in standard PCI quirks | |
9 | Mainboard specific bugs should be handled by DMI entries. | |
10 | CPU specific bugs in setup.c */ | |
11 | ||
12 | #include <linux/pci.h> | |
13 | #include <linux/acpi.h> | |
14 | #include <linux/pci_ids.h> | |
15 | #include <asm/pci-direct.h> | |
dfa4698c | 16 | #include <asm/dma.h> |
54ef3400 AK |
17 | #include <asm/io_apic.h> |
18 | #include <asm/apic.h> | |
19 | ||
20 | #ifdef CONFIG_IOMMU | |
395624fc | 21 | #include <asm/gart.h> |
54ef3400 | 22 | #endif |
dfa4698c | 23 | |
43999d9e | 24 | static void __init via_bugs(void) |
dfa4698c AK |
25 | { |
26 | #ifdef CONFIG_IOMMU | |
27 | if ((end_pfn > MAX_DMA32_PFN || force_iommu) && | |
28 | !iommu_aperture_allowed) { | |
29 | printk(KERN_INFO | |
54ef3400 AK |
30 | "Looks like a VIA chipset. Disabling IOMMU." |
31 | " Override with iommu=allowed\n"); | |
dfa4698c AK |
32 | iommu_aperture_disabled = 1; |
33 | } | |
34 | #endif | |
35 | } | |
36 | ||
37 | #ifdef CONFIG_ACPI | |
03d0d20e | 38 | #ifdef CONFIG_X86_IO_APIC |
dfa4698c | 39 | |
15a58ed1 | 40 | static int __init nvidia_hpet_check(struct acpi_table_header *header) |
dfa4698c | 41 | { |
dfa4698c AK |
42 | return 0; |
43 | } | |
03d0d20e JG |
44 | #endif /* CONFIG_X86_IO_APIC */ |
45 | #endif /* CONFIG_ACPI */ | |
dfa4698c | 46 | |
43999d9e | 47 | static void __init nvidia_bugs(void) |
dfa4698c AK |
48 | { |
49 | #ifdef CONFIG_ACPI | |
54ef3400 | 50 | #ifdef CONFIG_X86_IO_APIC |
dfa4698c AK |
51 | /* |
52 | * All timer overrides on Nvidia are | |
53 | * wrong unless HPET is enabled. | |
fa18f477 AK |
54 | * Unfortunately that's not true on many Asus boards. |
55 | * We don't know yet how to detect this automatically, but | |
56 | * at least allow a command line override. | |
dfa4698c | 57 | */ |
fa18f477 AK |
58 | if (acpi_use_timer_override) |
59 | return; | |
60 | ||
fe699336 | 61 | if (acpi_table_parse(ACPI_SIG_HPET, nvidia_hpet_check)) { |
dfa4698c AK |
62 | acpi_skip_timer_override = 1; |
63 | printk(KERN_INFO "Nvidia board " | |
64 | "detected. Ignoring ACPI " | |
65 | "timer override.\n"); | |
fa18f477 AK |
66 | printk(KERN_INFO "If you got timer trouble " |
67 | "try acpi_use_timer_override\n"); | |
dfa4698c | 68 | } |
54ef3400 | 69 | #endif |
dfa4698c AK |
70 | #endif |
71 | /* RED-PEN skip them on mptables too? */ | |
72 | ||
73 | } | |
74 | ||
43999d9e | 75 | static void __init ati_bugs(void) |
dfa4698c | 76 | { |
54ef3400 | 77 | #ifdef CONFIG_X86_IO_APIC |
fea5f1e1 LT |
78 | if (timer_over_8254 == 1) { |
79 | timer_over_8254 = 0; | |
80 | printk(KERN_INFO | |
54ef3400 | 81 | "ATI board detected. Disabling timer routing over 8254.\n"); |
fea5f1e1 | 82 | } |
54ef3400 | 83 | #endif |
dfa4698c AK |
84 | } |
85 | ||
86 | struct chipset { | |
87 | u16 vendor; | |
88 | void (*f)(void); | |
89 | }; | |
90 | ||
c993c735 | 91 | static struct chipset early_qrk[] __initdata = { |
dfa4698c AK |
92 | { PCI_VENDOR_ID_NVIDIA, nvidia_bugs }, |
93 | { PCI_VENDOR_ID_VIA, via_bugs }, | |
94 | { PCI_VENDOR_ID_ATI, ati_bugs }, | |
95 | {} | |
96 | }; | |
97 | ||
98 | void __init early_quirks(void) | |
99 | { | |
100 | int num, slot, func; | |
0637a70a AK |
101 | |
102 | if (!early_pci_allowed()) | |
103 | return; | |
104 | ||
dfa4698c AK |
105 | /* Poor man's PCI discovery */ |
106 | for (num = 0; num < 32; num++) { | |
107 | for (slot = 0; slot < 32; slot++) { | |
108 | for (func = 0; func < 8; func++) { | |
109 | u32 class; | |
110 | u32 vendor; | |
111 | u8 type; | |
112 | int i; | |
113 | class = read_pci_config(num,slot,func, | |
114 | PCI_CLASS_REVISION); | |
115 | if (class == 0xffffffff) | |
116 | break; | |
117 | ||
54ef3400 | 118 | if ((class >> 16) != PCI_CLASS_BRIDGE_PCI) |
dfa4698c AK |
119 | continue; |
120 | ||
121 | vendor = read_pci_config(num, slot, func, | |
122 | PCI_VENDOR_ID); | |
123 | vendor &= 0xffff; | |
124 | ||
125 | for (i = 0; early_qrk[i].f; i++) | |
126 | if (early_qrk[i].vendor == vendor) { | |
127 | early_qrk[i].f(); | |
128 | return; | |
129 | } | |
130 | ||
131 | type = read_pci_config_byte(num, slot, func, | |
132 | PCI_HEADER_TYPE); | |
133 | if (!(type & 0x80)) | |
134 | break; | |
135 | } | |
136 | } | |
137 | } | |
138 | } |