Blame view
arch/x86/kernel/early-quirks.c
7.23 KB
dfa4698c5 [PATCH] Move earl... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* 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> |
dfa4698c5 [PATCH] Move earl... |
16 |
#include <asm/dma.h> |
54ef34009 x86: Unify i386 a... |
17 18 |
#include <asm/io_apic.h> #include <asm/apic.h> |
46a7fa270 x86: make only GA... |
19 |
#include <asm/iommu.h> |
1d9b16d16 x86: move GART sp... |
20 |
#include <asm/gart.h> |
dfa4698c5 [PATCH] Move earl... |
21 |
|
c6b483243 x86, kexec: force... |
22 23 24 25 26 27 28 29 30 31 32 |
static void __init fix_hypertransport_config(int num, int slot, int func) { u32 htcfg; /* * we found a hypertransport bus * make sure that we are broadcasting * interrupts to all cpus on the ht bus * if we're using extended apic ids */ htcfg = read_pci_config(num, slot, func, 0x68); if (htcfg & (1 << 18)) { |
7bcbc78de x86: clean up arc... |
33 34 35 |
printk(KERN_INFO "Detected use of extended apic ids " "on hypertransport bus "); |
c6b483243 x86, kexec: force... |
36 |
if ((htcfg & (1 << 17)) == 0) { |
7bcbc78de x86: clean up arc... |
37 38 39 40 41 42 |
printk(KERN_INFO "Enabling hypertransport extended " "apic interrupt broadcast "); printk(KERN_INFO "Note this is a bios bug, " "please contact your hw vendor "); |
c6b483243 x86, kexec: force... |
43 44 45 46 47 48 49 50 51 |
htcfg |= (1 << 17); write_pci_config(num, slot, func, 0x68, htcfg); } } } static void __init via_bugs(int num, int slot, int func) |
dfa4698c5 [PATCH] Move earl... |
52 |
{ |
966396d3a x86 gart: rename ... |
53 |
#ifdef CONFIG_GART_IOMMU |
c987d12f8 x86: remove end_p... |
54 |
if ((max_pfn > MAX_DMA32_PFN || force_iommu) && |
0440d4c00 x86 gart: rename ... |
55 |
!gart_iommu_aperture_allowed) { |
dfa4698c5 [PATCH] Move earl... |
56 |
printk(KERN_INFO |
54ef34009 x86: Unify i386 a... |
57 58 59 |
"Looks like a VIA chipset. Disabling IOMMU." " Override with iommu=allowed "); |
0440d4c00 x86 gart: rename ... |
60 |
gart_iommu_aperture_disabled = 1; |
dfa4698c5 [PATCH] Move earl... |
61 62 63 64 65 |
} #endif } #ifdef CONFIG_ACPI |
03d0d20e6 x86: fix compiler... |
66 |
#ifdef CONFIG_X86_IO_APIC |
dfa4698c5 [PATCH] Move earl... |
67 |
|
15a58ed12 ACPICA: Remove du... |
68 |
static int __init nvidia_hpet_check(struct acpi_table_header *header) |
dfa4698c5 [PATCH] Move earl... |
69 |
{ |
dfa4698c5 [PATCH] Move earl... |
70 71 |
return 0; } |
03d0d20e6 x86: fix compiler... |
72 73 |
#endif /* CONFIG_X86_IO_APIC */ #endif /* CONFIG_ACPI */ |
dfa4698c5 [PATCH] Move earl... |
74 |
|
c6b483243 x86, kexec: force... |
75 |
static void __init nvidia_bugs(int num, int slot, int func) |
dfa4698c5 [PATCH] Move earl... |
76 77 |
{ #ifdef CONFIG_ACPI |
54ef34009 x86: Unify i386 a... |
78 |
#ifdef CONFIG_X86_IO_APIC |
dfa4698c5 [PATCH] Move earl... |
79 80 81 |
/* * All timer overrides on Nvidia are * wrong unless HPET is enabled. |
fa18f477d [PATCH] x86: Add ... |
82 83 84 |
* 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. |
dfa4698c5 [PATCH] Move earl... |
85 |
*/ |
fa18f477d [PATCH] x86: Add ... |
86 87 |
if (acpi_use_timer_override) return; |
fe6993365 [PATCH] ACPI: rep... |
88 |
if (acpi_table_parse(ACPI_SIG_HPET, nvidia_hpet_check)) { |
dfa4698c5 [PATCH] Move earl... |
89 90 91 92 93 |
acpi_skip_timer_override = 1; printk(KERN_INFO "Nvidia board " "detected. Ignoring ACPI " "timer override. "); |
fa18f477d [PATCH] x86: Add ... |
94 95 96 |
printk(KERN_INFO "If you got timer trouble " "try acpi_use_timer_override "); |
dfa4698c5 [PATCH] Move earl... |
97 98 |
} #endif |
54ef34009 x86: Unify i386 a... |
99 |
#endif |
dfa4698c5 [PATCH] Move earl... |
100 101 102 |
/* RED-PEN skip them on mptables too? */ } |
26adcfbf0 x86: SB600: skip ... |
103 104 |
#if defined(CONFIG_ACPI) && defined(CONFIG_X86_IO_APIC) static u32 __init ati_ixp4x0_rev(int num, int slot, int func) |
33fb0e4eb x86: SB450: skip ... |
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
{ u32 d; u8 b; b = read_pci_config_byte(num, slot, func, 0xac); b &= ~(1<<5); write_pci_config_byte(num, slot, func, 0xac, b); d = read_pci_config(num, slot, func, 0x70); d |= 1<<8; write_pci_config(num, slot, func, 0x70, d); d = read_pci_config(num, slot, func, 0x8); d &= 0xff; return d; } static void __init ati_bugs(int num, int slot, int func) { |
33fb0e4eb x86: SB450: skip ... |
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
u32 d; u8 b; if (acpi_use_timer_override) return; d = ati_ixp4x0_rev(num, slot, func); if (d < 0x82) acpi_skip_timer_override = 1; else { /* check for IRQ0 interrupt swap */ outb(0x72, 0xcd6); b = inb(0xcd7); if (!(b & 0x2)) acpi_skip_timer_override = 1; } if (acpi_skip_timer_override) { printk(KERN_INFO "SB4X0 revision 0x%x ", d); printk(KERN_INFO "Ignoring ACPI timer override. "); printk(KERN_INFO "If you got timer trouble " "try acpi_use_timer_override "); } |
33fb0e4eb x86: SB450: skip ... |
149 |
} |
26adcfbf0 x86: SB600: skip ... |
150 151 |
static u32 __init ati_sbx00_rev(int num, int slot, int func) { |
7f74f8f28 x86 quirk: Fix po... |
152 |
u32 d; |
26adcfbf0 x86: SB600: skip ... |
153 |
|
26adcfbf0 x86: SB600: skip ... |
154 155 |
d = read_pci_config(num, slot, func, 0x8); d &= 0xff; |
26adcfbf0 x86: SB600: skip ... |
156 157 158 159 160 161 162 |
return d; } static void __init ati_bugs_contd(int num, int slot, int func) { u32 d, rev; |
26adcfbf0 x86: SB600: skip ... |
163 |
rev = ati_sbx00_rev(num, slot, func); |
7f74f8f28 x86 quirk: Fix po... |
164 165 |
if (rev >= 0x40) acpi_fix_pin2_polarity = 1; |
1d3e09a30 x86, quirk: Fix S... |
166 167 168 169 170 171 |
/* * SB600: revisions 0x11, 0x12, 0x13, 0x14, ... * SB700: revisions 0x39, 0x3a, ... * SB800: revisions 0x40, 0x41, ... */ if (rev >= 0x39) |
26adcfbf0 x86: SB600: skip ... |
172 |
return; |
7f74f8f28 x86 quirk: Fix po... |
173 174 |
if (acpi_use_timer_override) return; |
26adcfbf0 x86: SB600: skip ... |
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
/* check for IRQ0 interrupt swap */ d = read_pci_config(num, slot, func, 0x64); if (!(d & (1<<14))) acpi_skip_timer_override = 1; if (acpi_skip_timer_override) { printk(KERN_INFO "SB600 revision 0x%x ", rev); printk(KERN_INFO "Ignoring ACPI timer override. "); printk(KERN_INFO "If you got timer trouble " "try acpi_use_timer_override "); } } #else static void __init ati_bugs(int num, int slot, int func) { } static void __init ati_bugs_contd(int num, int slot, int func) { } #endif |
c6b483243 x86, kexec: force... |
199 200 201 |
#define QFLAG_APPLY_ONCE 0x1 #define QFLAG_APPLIED 0x2 #define QFLAG_DONE (QFLAG_APPLY_ONCE|QFLAG_APPLIED) |
dfa4698c5 [PATCH] Move earl... |
202 |
struct chipset { |
c6b483243 x86, kexec: force... |
203 204 205 206 207 208 |
u32 vendor; u32 device; u32 class; u32 class_mask; u32 flags; void (*f)(int num, int slot, int func); |
dfa4698c5 [PATCH] Move earl... |
209 |
}; |
8659c406a x86: only scan th... |
210 211 212 213 214 215 |
/* * Only works for devices on the root bus. If you add any devices * not on bus 0 readd another loop level in early_quirks(). But * be careful because at least the Nvidia quirk here relies on * only matching on bus 0. */ |
c993c7355 [PATCH] x86_64 ea... |
216 |
static struct chipset early_qrk[] __initdata = { |
c6b483243 x86, kexec: force... |
217 218 219 220 |
{ PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, nvidia_bugs }, { PCI_VENDOR_ID_VIA, PCI_ANY_ID, PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, via_bugs }, |
c6b483243 x86, kexec: force... |
221 222 |
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB, PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, fix_hypertransport_config }, |
33fb0e4eb x86: SB450: skip ... |
223 224 |
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS, PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs }, |
26adcfbf0 x86: SB600: skip ... |
225 226 |
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs_contd }, |
dfa4698c5 [PATCH] Move earl... |
227 228 |
{} }; |
15650a2f6 x86/PCI: fixup ea... |
229 230 231 232 233 234 235 236 237 238 239 240 |
/** * check_dev_quirk - apply early quirks to a given PCI device * @num: bus number * @slot: slot number * @func: PCI function * * Check the vendor & device ID against the early quirks table. * * If the device is single function, let early_quirks() know so we don't * poke at this device again. */ static int __init check_dev_quirk(int num, int slot, int func) |
7bcbc78de x86: clean up arc... |
241 242 243 244 245 246 247 248 249 250 |
{ u16 class; u16 vendor; u16 device; u8 type; int i; class = read_pci_config_16(num, slot, func, PCI_CLASS_DEVICE); if (class == 0xffff) |
15650a2f6 x86/PCI: fixup ea... |
251 |
return -1; /* no class, treat as single function */ |
7bcbc78de x86: clean up arc... |
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
vendor = read_pci_config_16(num, slot, func, PCI_VENDOR_ID); device = read_pci_config_16(num, slot, func, PCI_DEVICE_ID); for (i = 0; early_qrk[i].f != NULL; i++) { if (((early_qrk[i].vendor == PCI_ANY_ID) || (early_qrk[i].vendor == vendor)) && ((early_qrk[i].device == PCI_ANY_ID) || (early_qrk[i].device == device)) && (!((early_qrk[i].class ^ class) & early_qrk[i].class_mask))) { if ((early_qrk[i].flags & QFLAG_DONE) != QFLAG_DONE) early_qrk[i].f(num, slot, func); early_qrk[i].flags |= QFLAG_APPLIED; } } type = read_pci_config_byte(num, slot, func, PCI_HEADER_TYPE); if (!(type & 0x80)) |
15650a2f6 x86/PCI: fixup ea... |
274 275 276 |
return -1; return 0; |
7bcbc78de x86: clean up arc... |
277 |
} |
dfa4698c5 [PATCH] Move earl... |
278 279 |
void __init early_quirks(void) { |
8659c406a x86: only scan th... |
280 |
int slot, func; |
0637a70a5 [PATCH] x86: Allo... |
281 282 283 |
if (!early_pci_allowed()) return; |
dfa4698c5 [PATCH] Move earl... |
284 |
/* Poor man's PCI discovery */ |
8659c406a x86: only scan th... |
285 286 287 288 289 290 291 |
/* Only scan the root bus */ for (slot = 0; slot < 32; slot++) for (func = 0; func < 8; func++) { /* Only probe function 0 on single fn devices */ if (check_dev_quirk(0, slot, func)) break; } |
dfa4698c5 [PATCH] Move earl... |
292 |
} |