aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86_64/kernel/Makefile2
-rw-r--r--arch/x86_64/kernel/early-quirks.c118
-rw-r--r--arch/x86_64/kernel/io_apic.c101
-rw-r--r--arch/x86_64/kernel/setup.c2
-rw-r--r--include/asm-x86_64/proto.h2
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
13obj-$(CONFIG_STACKTRACE) += stacktrace.o 13obj-$(CONFIG_STACKTRACE) += stacktrace.o
14obj-$(CONFIG_X86_MCE) += mce.o 14obj-$(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
19static 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
33static int nvidia_hpet_detected __initdata;
34
35static int __init nvidia_hpet_check(unsigned long phys, unsigned long size)
36{
37 nvidia_hpet_detected = 1;
38 return 0;
39}
40#endif
41
42static 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
62static 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
70struct chipset {
71 u16 vendor;
72 void (*f)(void);
73};
74
75static 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
82void __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
290static int nvidia_hpet_detected __initdata;
291
292static 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. */
310void __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
93extern void setup_node_bootmem(int nodeid, unsigned long start, unsigned long end); 93extern void setup_node_bootmem(int nodeid, unsigned long start, unsigned long end);
94 94
95extern void check_ioapic(void); 95extern void early_quirks(void);
96extern void check_efer(void); 96extern void check_efer(void);
97 97
98extern int unhandled_signal(struct task_struct *tsk, int sig); 98extern int unhandled_signal(struct task_struct *tsk, int sig);