~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/kernel/early-quirks.c

Version: ~ [ linux-5.1-rc1 ] ~ [ linux-5.0.2 ] ~ [ linux-4.20.16 ] ~ [ linux-4.19.29 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.106 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.163 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.176 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.136 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.63 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp