Blame view

arch/x86/kernel/early-quirks.c 7.23 KB
dfa4698c5   Andi Kleen   [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   Andi Kleen   [PATCH] Move earl...
16
  #include <asm/dma.h>
54ef34009   Andi Kleen   x86: Unify i386 a...
17
18
  #include <asm/io_apic.h>
  #include <asm/apic.h>
46a7fa270   FUJITA Tomonori   x86: make only GA...
19
  #include <asm/iommu.h>
1d9b16d16   Joerg Roedel   x86: move GART sp...
20
  #include <asm/gart.h>
dfa4698c5   Andi Kleen   [PATCH] Move earl...
21

c6b483243   Neil Horman   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   Neil Horman   x86: clean up arc...
33
34
35
  		printk(KERN_INFO "Detected use of extended apic ids "
  				 "on hypertransport bus
  ");
c6b483243   Neil Horman   x86, kexec: force...
36
  		if ((htcfg & (1 << 17)) == 0) {
7bcbc78de   Neil Horman   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   Neil Horman   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   Andi Kleen   [PATCH] Move earl...
52
  {
966396d3a   Joerg Roedel   x86 gart: rename ...
53
  #ifdef CONFIG_GART_IOMMU
c987d12f8   Yinghai Lu   x86: remove end_p...
54
  	if ((max_pfn > MAX_DMA32_PFN ||  force_iommu) &&
0440d4c00   Joerg Roedel   x86 gart: rename ...
55
  	    !gart_iommu_aperture_allowed) {
dfa4698c5   Andi Kleen   [PATCH] Move earl...
56
  		printk(KERN_INFO
54ef34009   Andi Kleen   x86: Unify i386 a...
57
58
59
  		       "Looks like a VIA chipset. Disabling IOMMU."
  		       " Override with iommu=allowed
  ");
0440d4c00   Joerg Roedel   x86 gart: rename ...
60
  		gart_iommu_aperture_disabled = 1;
dfa4698c5   Andi Kleen   [PATCH] Move earl...
61
62
63
64
65
  	}
  #endif
  }
  
  #ifdef CONFIG_ACPI
03d0d20e6   Jeff Garzik   x86: fix compiler...
66
  #ifdef CONFIG_X86_IO_APIC
dfa4698c5   Andi Kleen   [PATCH] Move earl...
67

15a58ed12   Alexey Starikovskiy   ACPICA: Remove du...
68
  static int __init nvidia_hpet_check(struct acpi_table_header *header)
dfa4698c5   Andi Kleen   [PATCH] Move earl...
69
  {
dfa4698c5   Andi Kleen   [PATCH] Move earl...
70
71
  	return 0;
  }
03d0d20e6   Jeff Garzik   x86: fix compiler...
72
73
  #endif /* CONFIG_X86_IO_APIC */
  #endif /* CONFIG_ACPI */
dfa4698c5   Andi Kleen   [PATCH] Move earl...
74

c6b483243   Neil Horman   x86, kexec: force...
75
  static void __init nvidia_bugs(int num, int slot, int func)
dfa4698c5   Andi Kleen   [PATCH] Move earl...
76
77
  {
  #ifdef CONFIG_ACPI
54ef34009   Andi Kleen   x86: Unify i386 a...
78
  #ifdef CONFIG_X86_IO_APIC
dfa4698c5   Andi Kleen   [PATCH] Move earl...
79
80
81
  	/*
  	 * All timer overrides on Nvidia are
  	 * wrong unless HPET is enabled.
fa18f477d   Andi Kleen   [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   Andi Kleen   [PATCH] Move earl...
85
  	 */
fa18f477d   Andi Kleen   [PATCH] x86: Add ...
86
87
  	if (acpi_use_timer_override)
  		return;
fe6993365   Len Brown   [PATCH] ACPI: rep...
88
  	if (acpi_table_parse(ACPI_SIG_HPET, nvidia_hpet_check)) {
dfa4698c5   Andi Kleen   [PATCH] Move earl...
89
90
91
92
93
  		acpi_skip_timer_override = 1;
  		printk(KERN_INFO "Nvidia board "
  		       "detected. Ignoring ACPI "
  		       "timer override.
  ");
fa18f477d   Andi Kleen   [PATCH] x86: Add ...
94
95
96
  		printk(KERN_INFO "If you got timer trouble "
  			"try acpi_use_timer_override
  ");
dfa4698c5   Andi Kleen   [PATCH] Move earl...
97
98
  	}
  #endif
54ef34009   Andi Kleen   x86: Unify i386 a...
99
  #endif
dfa4698c5   Andi Kleen   [PATCH] Move earl...
100
101
102
  	/* RED-PEN skip them on mptables too? */
  
  }
26adcfbf0   Andreas Herrmann   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   Andreas Herrmann   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   Andreas Herrmann   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   Andreas Herrmann   x86: SB450: skip ...
149
  }
26adcfbf0   Andreas Herrmann   x86: SB600: skip ...
150
151
  static u32 __init ati_sbx00_rev(int num, int slot, int func)
  {
7f74f8f28   Andreas Herrmann   x86 quirk: Fix po...
152
  	u32 d;
26adcfbf0   Andreas Herrmann   x86: SB600: skip ...
153

26adcfbf0   Andreas Herrmann   x86: SB600: skip ...
154
155
  	d = read_pci_config(num, slot, func, 0x8);
  	d &= 0xff;
26adcfbf0   Andreas Herrmann   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   Andreas Herrmann   x86: SB600: skip ...
163
  	rev = ati_sbx00_rev(num, slot, func);
7f74f8f28   Andreas Herrmann   x86 quirk: Fix po...
164
165
  	if (rev >= 0x40)
  		acpi_fix_pin2_polarity = 1;
1d3e09a30   Andreas Herrmann   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   Andreas Herrmann   x86: SB600: skip ...
172
  		return;
7f74f8f28   Andreas Herrmann   x86 quirk: Fix po...
173
174
  	if (acpi_use_timer_override)
  		return;
26adcfbf0   Andreas Herrmann   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   Neil Horman   x86, kexec: force...
199
200
201
  #define QFLAG_APPLY_ONCE 	0x1
  #define QFLAG_APPLIED		0x2
  #define QFLAG_DONE		(QFLAG_APPLY_ONCE|QFLAG_APPLIED)
dfa4698c5   Andi Kleen   [PATCH] Move earl...
202
  struct chipset {
c6b483243   Neil Horman   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   Andi Kleen   [PATCH] Move earl...
209
  };
8659c406a   Andi Kleen   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   Andrew Morton   [PATCH] x86_64 ea...
216
  static struct chipset early_qrk[] __initdata = {
c6b483243   Neil Horman   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   Neil Horman   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   Andreas Herrmann   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   Andreas Herrmann   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   Andi Kleen   [PATCH] Move earl...
227
228
  	{}
  };
15650a2f6   Jesse Barnes   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   Neil Horman   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   Jesse Barnes   x86/PCI: fixup ea...
251
  		return -1; /* no class, treat as single function */
7bcbc78de   Neil Horman   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   Jesse Barnes   x86/PCI: fixup ea...
274
275
276
  		return -1;
  
  	return 0;
7bcbc78de   Neil Horman   x86: clean up arc...
277
  }
dfa4698c5   Andi Kleen   [PATCH] Move earl...
278
279
  void __init early_quirks(void)
  {
8659c406a   Andi Kleen   x86: only scan th...
280
  	int slot, func;
0637a70a5   Andi Kleen   [PATCH] x86: Allo...
281
282
283
  
  	if (!early_pci_allowed())
  		return;
dfa4698c5   Andi Kleen   [PATCH] Move earl...
284
  	/* Poor man's PCI discovery */
8659c406a   Andi Kleen   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   Andi Kleen   [PATCH] Move earl...
292
  }