diff options
-rw-r--r-- | arch/x86_64/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/x86_64/kernel/early-quirks.c | 118 | ||||
-rw-r--r-- | arch/x86_64/kernel/io_apic.c | 101 | ||||
-rw-r--r-- | arch/x86_64/kernel/setup.c | 2 | ||||
-rw-r--r-- | include/asm-x86_64/proto.h | 2 |
5 files changed, 121 insertions, 104 deletions
diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 0ef39553c0f6..000e67e8f028 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile | |||
@@ -8,7 +8,7 @@ obj-y := process.o signal.o entry.o traps.o irq.o \ | |||
8 | ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_x86_64.o \ | 8 | ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_x86_64.o \ |
9 | x8664_ksyms.o i387.o syscall.o vsyscall.o \ | 9 | x8664_ksyms.o i387.o syscall.o vsyscall.o \ |
10 | setup64.o bootflag.o e820.o reboot.o quirks.o i8237.o \ | 10 | setup64.o bootflag.o e820.o reboot.o quirks.o i8237.o \ |
11 | pci-dma.o pci-nommu.o alternative.o | 11 | pci-dma.o pci-nommu.o alternative.o early-quirks.o |
12 | 12 | ||
13 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | 13 | obj-$(CONFIG_STACKTRACE) += stacktrace.o |
14 | obj-$(CONFIG_X86_MCE) += mce.o | 14 | obj-$(CONFIG_X86_MCE) += mce.o |
diff --git a/arch/x86_64/kernel/early-quirks.c b/arch/x86_64/kernel/early-quirks.c new file mode 100644 index 000000000000..d637cff1c4b1 --- /dev/null +++ b/arch/x86_64/kernel/early-quirks.c | |||
@@ -0,0 +1,118 @@ | |||
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> | ||
16 | #include <asm/proto.h> | ||
17 | #include <asm/dma.h> | ||
18 | |||
19 | static void via_bugs(void) | ||
20 | { | ||
21 | #ifdef CONFIG_IOMMU | ||
22 | if ((end_pfn > MAX_DMA32_PFN || force_iommu) && | ||
23 | !iommu_aperture_allowed) { | ||
24 | printk(KERN_INFO | ||
25 | "Looks like a VIA chipset. Disabling IOMMU. Override with iommu=allowed\n"); | ||
26 | iommu_aperture_disabled = 1; | ||
27 | } | ||
28 | #endif | ||
29 | } | ||
30 | |||
31 | #ifdef CONFIG_ACPI | ||
32 | |||
33 | static int nvidia_hpet_detected __initdata; | ||
34 | |||
35 | static int __init nvidia_hpet_check(unsigned long phys, unsigned long size) | ||
36 | { | ||
37 | nvidia_hpet_detected = 1; | ||
38 | return 0; | ||
39 | } | ||
40 | #endif | ||
41 | |||
42 | static void nvidia_bugs(void) | ||
43 | { | ||
44 | #ifdef CONFIG_ACPI | ||
45 | /* | ||
46 | * All timer overrides on Nvidia are | ||
47 | * wrong unless HPET is enabled. | ||
48 | */ | ||
49 | nvidia_hpet_detected = 0; | ||
50 | acpi_table_parse(ACPI_HPET, nvidia_hpet_check); | ||
51 | if (nvidia_hpet_detected == 0) { | ||
52 | acpi_skip_timer_override = 1; | ||
53 | printk(KERN_INFO "Nvidia board " | ||
54 | "detected. Ignoring ACPI " | ||
55 | "timer override.\n"); | ||
56 | } | ||
57 | #endif | ||
58 | /* RED-PEN skip them on mptables too? */ | ||
59 | |||
60 | } | ||
61 | |||
62 | static void ati_bugs(void) | ||
63 | { | ||
64 | #if 1 /* for testing */ | ||
65 | printk("ATI board detected\n"); | ||
66 | #endif | ||
67 | /* No bugs right now */ | ||
68 | } | ||
69 | |||
70 | struct chipset { | ||
71 | u16 vendor; | ||
72 | void (*f)(void); | ||
73 | }; | ||
74 | |||
75 | static struct chipset early_qrk[] = { | ||
76 | { PCI_VENDOR_ID_NVIDIA, nvidia_bugs }, | ||
77 | { PCI_VENDOR_ID_VIA, via_bugs }, | ||
78 | { PCI_VENDOR_ID_ATI, ati_bugs }, | ||
79 | {} | ||
80 | }; | ||
81 | |||
82 | void __init early_quirks(void) | ||
83 | { | ||
84 | int num, slot, func; | ||
85 | /* Poor man's PCI discovery */ | ||
86 | for (num = 0; num < 32; num++) { | ||
87 | for (slot = 0; slot < 32; slot++) { | ||
88 | for (func = 0; func < 8; func++) { | ||
89 | u32 class; | ||
90 | u32 vendor; | ||
91 | u8 type; | ||
92 | int i; | ||
93 | class = read_pci_config(num,slot,func, | ||
94 | PCI_CLASS_REVISION); | ||
95 | if (class == 0xffffffff) | ||
96 | break; | ||
97 | |||
98 | if ((class >> 16) != PCI_CLASS_BRIDGE_PCI) | ||
99 | continue; | ||
100 | |||
101 | vendor = read_pci_config(num, slot, func, | ||
102 | PCI_VENDOR_ID); | ||
103 | vendor &= 0xffff; | ||
104 | |||
105 | for (i = 0; early_qrk[i].f; i++) | ||
106 | if (early_qrk[i].vendor == vendor) { | ||
107 | early_qrk[i].f(); | ||
108 | return; | ||
109 | } | ||
110 | |||
111 | type = read_pci_config_byte(num, slot, func, | ||
112 | PCI_HEADER_TYPE); | ||
113 | if (!(type & 0x80)) | ||
114 | break; | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | } | ||
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index a02ed17d05dc..8bbff64c20d7 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c | |||
@@ -280,107 +280,6 @@ static int __init setup_enable_8254_timer(char *s) | |||
280 | __setup("disable_8254_timer", setup_disable_8254_timer); | 280 | __setup("disable_8254_timer", setup_disable_8254_timer); |
281 | __setup("enable_8254_timer", setup_enable_8254_timer); | 281 | __setup("enable_8254_timer", setup_enable_8254_timer); |
282 | 282 | ||
283 | #include <asm/pci-direct.h> | ||
284 | #include <linux/pci_ids.h> | ||
285 | #include <linux/pci.h> | ||
286 | |||
287 | |||
288 | #ifdef CONFIG_ACPI | ||
289 | |||
290 | static int nvidia_hpet_detected __initdata; | ||
291 | |||
292 | static int __init nvidia_hpet_check(unsigned long phys, unsigned long size) | ||
293 | { | ||
294 | nvidia_hpet_detected = 1; | ||
295 | return 0; | ||
296 | } | ||
297 | #endif | ||
298 | |||
299 | /* Temporary Hack. Nvidia and VIA boards currently only work with IO-APIC | ||
300 | off. Check for an Nvidia or VIA PCI bridge and turn it off. | ||
301 | Use pci direct infrastructure because this runs before the PCI subsystem. | ||
302 | |||
303 | Can be overwritten with "apic" | ||
304 | |||
305 | And another hack to disable the IOMMU on VIA chipsets. | ||
306 | |||
307 | ... and others. Really should move this somewhere else. | ||
308 | |||
309 | Kludge-O-Rama. */ | ||
310 | void __init check_ioapic(void) | ||
311 | { | ||
312 | int num,slot,func; | ||
313 | /* Poor man's PCI discovery */ | ||
314 | for (num = 0; num < 32; num++) { | ||
315 | for (slot = 0; slot < 32; slot++) { | ||
316 | for (func = 0; func < 8; func++) { | ||
317 | u32 class; | ||
318 | u32 vendor; | ||
319 | u8 type; | ||
320 | class = read_pci_config(num,slot,func, | ||
321 | PCI_CLASS_REVISION); | ||
322 | if (class == 0xffffffff) | ||
323 | break; | ||
324 | |||
325 | if ((class >> 16) != PCI_CLASS_BRIDGE_PCI) | ||
326 | continue; | ||
327 | |||
328 | vendor = read_pci_config(num, slot, func, | ||
329 | PCI_VENDOR_ID); | ||
330 | vendor &= 0xffff; | ||
331 | switch (vendor) { | ||
332 | case PCI_VENDOR_ID_VIA: | ||
333 | #ifdef CONFIG_IOMMU | ||
334 | if ((end_pfn > MAX_DMA32_PFN || | ||
335 | force_iommu) && | ||
336 | !iommu_aperture_allowed) { | ||
337 | printk(KERN_INFO | ||
338 | "Looks like a VIA chipset. Disabling IOMMU. Override with \"iommu=allowed\"\n"); | ||
339 | iommu_aperture_disabled = 1; | ||
340 | } | ||
341 | #endif | ||
342 | return; | ||
343 | case PCI_VENDOR_ID_NVIDIA: | ||
344 | #ifdef CONFIG_ACPI | ||
345 | /* | ||
346 | * All timer overrides on Nvidia are | ||
347 | * wrong unless HPET is enabled. | ||
348 | */ | ||
349 | nvidia_hpet_detected = 0; | ||
350 | acpi_table_parse(ACPI_HPET, | ||
351 | nvidia_hpet_check); | ||
352 | if (nvidia_hpet_detected == 0) { | ||
353 | acpi_skip_timer_override = 1; | ||
354 | printk(KERN_INFO "Nvidia board " | ||
355 | "detected. Ignoring ACPI " | ||
356 | "timer override.\n"); | ||
357 | } | ||
358 | #endif | ||
359 | /* RED-PEN skip them on mptables too? */ | ||
360 | return; | ||
361 | |||
362 | /* This should be actually default, but | ||
363 | for 2.6.16 let's do it for ATI only where | ||
364 | it's really needed. */ | ||
365 | case PCI_VENDOR_ID_ATI: | ||
366 | if (timer_over_8254 == 1) { | ||
367 | timer_over_8254 = 0; | ||
368 | printk(KERN_INFO | ||
369 | "ATI board detected. Disabling timer routing over 8254.\n"); | ||
370 | } | ||
371 | return; | ||
372 | } | ||
373 | |||
374 | |||
375 | /* No multi-function device? */ | ||
376 | type = read_pci_config_byte(num,slot,func, | ||
377 | PCI_HEADER_TYPE); | ||
378 | if (!(type & 0x80)) | ||
379 | break; | ||
380 | } | ||
381 | } | ||
382 | } | ||
383 | } | ||
384 | 283 | ||
385 | /* | 284 | /* |
386 | * Find the IRQ entry number of a certain pin. | 285 | * Find the IRQ entry number of a certain pin. |
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index fbe9f7faa2db..aab4bd66aa0d 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c | |||
@@ -653,7 +653,7 @@ void __init setup_arch(char **cmdline_p) | |||
653 | 653 | ||
654 | paging_init(); | 654 | paging_init(); |
655 | 655 | ||
656 | check_ioapic(); | 656 | early_quirks(); |
657 | 657 | ||
658 | /* | 658 | /* |
659 | * set this early, so we dont allocate cpu0 | 659 | * set this early, so we dont allocate cpu0 |
diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h index 3b1c60247902..58fec91318e4 100644 --- a/include/asm-x86_64/proto.h +++ b/include/asm-x86_64/proto.h | |||
@@ -92,7 +92,7 @@ extern void syscall32_cpu_init(void); | |||
92 | 92 | ||
93 | extern void setup_node_bootmem(int nodeid, unsigned long start, unsigned long end); | 93 | extern void setup_node_bootmem(int nodeid, unsigned long start, unsigned long end); |
94 | 94 | ||
95 | extern void check_ioapic(void); | 95 | extern void early_quirks(void); |
96 | extern void check_efer(void); | 96 | extern void check_efer(void); |
97 | 97 | ||
98 | extern int unhandled_signal(struct task_struct *tsk, int sig); | 98 | extern int unhandled_signal(struct task_struct *tsk, int sig); |