diff options
Diffstat (limited to 'arch/x86_64/kernel/early-quirks.c')
-rw-r--r-- | arch/x86_64/kernel/early-quirks.c | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/arch/x86_64/kernel/early-quirks.c b/arch/x86_64/kernel/early-quirks.c new file mode 100644 index 000000000000..208e38a372c1 --- /dev/null +++ b/arch/x86_64/kernel/early-quirks.c | |||
@@ -0,0 +1,122 @@ | |||
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 | |||
86 | if (!early_pci_allowed()) | ||
87 | return; | ||
88 | |||
89 | /* Poor man's PCI discovery */ | ||
90 | for (num = 0; num < 32; num++) { | ||
91 | for (slot = 0; slot < 32; slot++) { | ||
92 | for (func = 0; func < 8; func++) { | ||
93 | u32 class; | ||
94 | u32 vendor; | ||
95 | u8 type; | ||
96 | int i; | ||
97 | class = read_pci_config(num,slot,func, | ||
98 | PCI_CLASS_REVISION); | ||
99 | if (class == 0xffffffff) | ||
100 | break; | ||
101 | |||
102 | if ((class >> 16) != PCI_CLASS_BRIDGE_PCI) | ||
103 | continue; | ||
104 | |||
105 | vendor = read_pci_config(num, slot, func, | ||
106 | PCI_VENDOR_ID); | ||
107 | vendor &= 0xffff; | ||
108 | |||
109 | for (i = 0; early_qrk[i].f; i++) | ||
110 | if (early_qrk[i].vendor == vendor) { | ||
111 | early_qrk[i].f(); | ||
112 | return; | ||
113 | } | ||
114 | |||
115 | type = read_pci_config_byte(num, slot, func, | ||
116 | PCI_HEADER_TYPE); | ||
117 | if (!(type & 0x80)) | ||
118 | break; | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | } | ||