x86, pci: introduce pci=noioapicquirk kernel cmdline option
[deliverable/linux.git] / arch / x86 / pci / common.c
CommitLineData
1da177e4
LT
1/*
2 * Low-Level PCI Support for PC
3 *
4 * (c) 1999--2000 Martin Mares <mj@ucw.cz>
5 */
6
7#include <linux/sched.h>
8#include <linux/pci.h>
9#include <linux/ioport.h>
10#include <linux/init.h>
8c4b2cf9 11#include <linux/dmi.h>
1da177e4
LT
12
13#include <asm/acpi.h>
14#include <asm/segment.h>
15#include <asm/io.h>
16#include <asm/smp.h>
17
18#include "pci.h"
19
1da177e4
LT
20unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
21 PCI_PROBE_MMCONF;
22
2b290da0 23static int pci_bf_sort;
1da177e4 24int pci_routeirq;
a9322f64 25int noioapicquirk;
1da177e4 26int pcibios_last_bus = -1;
120bb424 27unsigned long pirq_table_addr;
28struct pci_bus *pci_root_bus;
1da177e4 29struct pci_raw_ops *raw_pci_ops;
b6ce068a
MW
30struct pci_raw_ops *raw_pci_ext_ops;
31
32int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn,
33 int reg, int len, u32 *val)
34{
35 if (reg < 256 && raw_pci_ops)
36 return raw_pci_ops->read(domain, bus, devfn, reg, len, val);
37 if (raw_pci_ext_ops)
38 return raw_pci_ext_ops->read(domain, bus, devfn, reg, len, val);
39 return -EINVAL;
40}
41
42int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn,
43 int reg, int len, u32 val)
44{
45 if (reg < 256 && raw_pci_ops)
46 return raw_pci_ops->write(domain, bus, devfn, reg, len, val);
47 if (raw_pci_ext_ops)
48 return raw_pci_ext_ops->write(domain, bus, devfn, reg, len, val);
49 return -EINVAL;
50}
1da177e4
LT
51
52static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
53{
b6ce068a 54 return raw_pci_read(pci_domain_nr(bus), bus->number,
a79e4198 55 devfn, where, size, value);
1da177e4
LT
56}
57
58static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
59{
b6ce068a 60 return raw_pci_write(pci_domain_nr(bus), bus->number,
a79e4198 61 devfn, where, size, value);
1da177e4
LT
62}
63
64struct pci_ops pci_root_ops = {
65 .read = pci_read,
66 .write = pci_write,
67};
68
69/*
70 * legacy, numa, and acpi all want to call pcibios_scan_root
71 * from their initcalls. This flag prevents that.
72 */
73int pcibios_scanned;
74
75/*
76 * This interrupt-safe spinlock protects all accesses to PCI
77 * configuration space.
78 */
79DEFINE_SPINLOCK(pci_config_lock);
80
13a6ddb0
YL
81static int __devinit can_skip_ioresource_align(const struct dmi_system_id *d)
82{
83 pci_probe |= PCI_CAN_SKIP_ISA_ALIGN;
84 printk(KERN_INFO "PCI: %s detected, can skip ISA alignment\n", d->ident);
85 return 0;
86}
87
88static struct dmi_system_id can_skip_pciprobe_dmi_table[] __devinitdata = {
89/*
90 * Systems where PCI IO resource ISA alignment can be skipped
91 * when the ISA enable bit in the bridge control is not set
92 */
93 {
94 .callback = can_skip_ioresource_align,
95 .ident = "IBM System x3800",
96 .matches = {
97 DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
98 DMI_MATCH(DMI_PRODUCT_NAME, "x3800"),
99 },
100 },
101 {
102 .callback = can_skip_ioresource_align,
103 .ident = "IBM System x3850",
104 .matches = {
105 DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
106 DMI_MATCH(DMI_PRODUCT_NAME, "x3850"),
107 },
108 },
109 {
110 .callback = can_skip_ioresource_align,
111 .ident = "IBM System x3950",
112 .matches = {
113 DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
114 DMI_MATCH(DMI_PRODUCT_NAME, "x3950"),
115 },
116 },
117 {}
118};
119
120void __init dmi_check_skip_isa_align(void)
121{
122 dmi_check_system(can_skip_pciprobe_dmi_table);
123}
124
1da177e4
LT
125/*
126 * Called after each bus is probed, but before its children
127 * are examined.
128 */
129
130void __devinit pcibios_fixup_bus(struct pci_bus *b)
131{
1da177e4
LT
132 pci_read_bridge_bases(b);
133}
134
6b4b78fe
MD
135/*
136 * Only use DMI information to set this if nothing was passed
137 * on the kernel command line (which was parsed earlier).
138 */
139
1855256c 140static int __devinit set_bf_sort(const struct dmi_system_id *d)
6b4b78fe
MD
141{
142 if (pci_bf_sort == pci_bf_sort_default) {
143 pci_bf_sort = pci_dmi_bf;
144 printk(KERN_INFO "PCI: %s detected, enabling pci=bfsort.\n", d->ident);
145 }
146 return 0;
147}
148
8c4b2cf9
BK
149/*
150 * Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus)
151 */
152#ifdef __i386__
1855256c 153static int __devinit assign_all_busses(const struct dmi_system_id *d)
8c4b2cf9
BK
154{
155 pci_probe |= PCI_ASSIGN_ALL_BUSSES;
156 printk(KERN_INFO "%s detected: enabling PCI bus# renumbering"
157 " (pci=assign-busses)\n", d->ident);
158 return 0;
159}
160#endif
161
6b4b78fe
MD
162static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = {
163#ifdef __i386__
8c4b2cf9
BK
164/*
165 * Laptops which need pci=assign-busses to see Cardbus cards
166 */
8c4b2cf9
BK
167 {
168 .callback = assign_all_busses,
169 .ident = "Samsung X20 Laptop",
170 .matches = {
171 DMI_MATCH(DMI_SYS_VENDOR, "Samsung Electronics"),
172 DMI_MATCH(DMI_PRODUCT_NAME, "SX20S"),
173 },
174 },
175#endif /* __i386__ */
6b4b78fe
MD
176 {
177 .callback = set_bf_sort,
178 .ident = "Dell PowerEdge 1950",
179 .matches = {
180 DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
181 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1950"),
182 },
183 },
184 {
185 .callback = set_bf_sort,
186 .ident = "Dell PowerEdge 1955",
187 .matches = {
188 DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
189 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1955"),
190 },
191 },
192 {
193 .callback = set_bf_sort,
194 .ident = "Dell PowerEdge 2900",
195 .matches = {
196 DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
197 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2900"),
198 },
199 },
200 {
201 .callback = set_bf_sort,
202 .ident = "Dell PowerEdge 2950",
203 .matches = {
204 DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
205 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2950"),
206 },
207 },
f7a9dae7
MD
208 {
209 .callback = set_bf_sort,
210 .ident = "Dell PowerEdge R900",
211 .matches = {
212 DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
213 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R900"),
214 },
215 },
f52383d3
AG
216 {
217 .callback = set_bf_sort,
218 .ident = "HP ProLiant BL20p G3",
219 .matches = {
220 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
221 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL20p G3"),
222 },
223 },
224 {
225 .callback = set_bf_sort,
226 .ident = "HP ProLiant BL20p G4",
227 .matches = {
228 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
229 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL20p G4"),
230 },
231 },
232 {
233 .callback = set_bf_sort,
234 .ident = "HP ProLiant BL30p G1",
235 .matches = {
236 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
237 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL30p G1"),
238 },
239 },
240 {
241 .callback = set_bf_sort,
242 .ident = "HP ProLiant BL25p G1",
243 .matches = {
244 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
245 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL25p G1"),
246 },
247 },
248 {
249 .callback = set_bf_sort,
250 .ident = "HP ProLiant BL35p G1",
251 .matches = {
252 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
253 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL35p G1"),
254 },
255 },
256 {
257 .callback = set_bf_sort,
258 .ident = "HP ProLiant BL45p G1",
259 .matches = {
260 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
261 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL45p G1"),
262 },
263 },
264 {
265 .callback = set_bf_sort,
266 .ident = "HP ProLiant BL45p G2",
267 .matches = {
268 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
269 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL45p G2"),
270 },
271 },
272 {
273 .callback = set_bf_sort,
274 .ident = "HP ProLiant BL460c G1",
275 .matches = {
276 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
277 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL460c G1"),
278 },
279 },
280 {
281 .callback = set_bf_sort,
282 .ident = "HP ProLiant BL465c G1",
283 .matches = {
284 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
285 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL465c G1"),
286 },
287 },
288 {
289 .callback = set_bf_sort,
290 .ident = "HP ProLiant BL480c G1",
291 .matches = {
292 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
293 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL480c G1"),
294 },
295 },
296 {
297 .callback = set_bf_sort,
298 .ident = "HP ProLiant BL685c G1",
299 .matches = {
300 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
301 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL685c G1"),
302 },
303 },
8f8ae1a7
MS
304 {
305 .callback = set_bf_sort,
8d64c781 306 .ident = "HP ProLiant DL360",
8f8ae1a7
MS
307 .matches = {
308 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
8d64c781 309 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL360"),
8f8ae1a7
MS
310 },
311 },
312 {
313 .callback = set_bf_sort,
8d64c781 314 .ident = "HP ProLiant DL380",
8f8ae1a7
MS
315 .matches = {
316 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
8d64c781 317 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL380"),
8f8ae1a7
MS
318 },
319 },
5b1ea82f
JL
320#ifdef __i386__
321 {
322 .callback = assign_all_busses,
323 .ident = "Compaq EVO N800c",
324 .matches = {
325 DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
326 DMI_MATCH(DMI_PRODUCT_NAME, "EVO N800c"),
327 },
328 },
329#endif
c82bc5ad
MS
330 {
331 .callback = set_bf_sort,
a1676072 332 .ident = "HP ProLiant DL360",
c82bc5ad
MS
333 .matches = {
334 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
a1676072 335 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL360"),
c82bc5ad
MS
336 },
337 },
338 {
339 .callback = set_bf_sort,
a1676072 340 .ident = "HP ProLiant DL380",
c82bc5ad
MS
341 .matches = {
342 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
a1676072 343 DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL380"),
c82bc5ad
MS
344 },
345 },
8c4b2cf9
BK
346 {}
347};
1da177e4 348
0df18ff3
YL
349void __init dmi_check_pciprobe(void)
350{
351 dmi_check_system(pciprobe_dmi_table);
352}
353
1da177e4
LT
354struct pci_bus * __devinit pcibios_scan_root(int busnum)
355{
356 struct pci_bus *bus = NULL;
08f1c192 357 struct pci_sysdata *sd;
1da177e4
LT
358
359 while ((bus = pci_find_next_bus(bus)) != NULL) {
360 if (bus->number == busnum) {
361 /* Already scanned */
362 return bus;
363 }
364 }
365
08f1c192
MBY
366 /* Allocate per-root-bus (not per bus) arch-specific data.
367 * TODO: leak; this memory is never freed.
368 * It's arguable whether it's worth the trouble to care.
369 */
370 sd = kzalloc(sizeof(*sd), GFP_KERNEL);
371 if (!sd) {
372 printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum);
373 return NULL;
374 }
375
871d5f8d
YL
376 sd->node = get_mp_bus_to_node(busnum);
377