diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2007-10-11 05:16:36 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2007-10-11 05:16:36 -0400 |
commit | fb9aa6f1d4a1e11e66a680460b2c2b2b10b62f79 (patch) | |
tree | e0ad51f39b48a342244cef62099bd1a8a93927db /arch/x86/pci/common.c | |
parent | 4b60eb8380a0b588a03b6052d7ac93e1964c75b8 (diff) |
i386: move pci
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/pci/common.c')
-rw-r--r-- | arch/x86/pci/common.c | 480 |
1 files changed, 480 insertions, 0 deletions
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c new file mode 100644 index 000000000000..ebc6f3c66340 --- /dev/null +++ b/arch/x86/pci/common.c | |||
@@ -0,0 +1,480 @@ | |||
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> | ||
11 | #include <linux/dmi.h> | ||
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 | |||
20 | unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | | ||
21 | PCI_PROBE_MMCONF; | ||
22 | |||
23 | static int pci_bf_sort; | ||
24 | int pci_routeirq; | ||
25 | int pcibios_last_bus = -1; | ||
26 | unsigned long pirq_table_addr; | ||
27 | struct pci_bus *pci_root_bus; | ||
28 | struct pci_raw_ops *raw_pci_ops; | ||
29 | |||
30 | static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) | ||
31 | { | ||
32 | return raw_pci_ops->read(0, bus->number, devfn, where, size, value); | ||
33 | } | ||
34 | |||
35 | static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) | ||
36 | { | ||
37 | return raw_pci_ops->write(0, bus->number, devfn, where, size, value); | ||
38 | } | ||
39 | |||
40 | struct pci_ops pci_root_ops = { | ||
41 | .read = pci_read, | ||
42 | .write = pci_write, | ||
43 | }; | ||
44 | |||
45 | /* | ||
46 | * legacy, numa, and acpi all want to call pcibios_scan_root | ||
47 | * from their initcalls. This flag prevents that. | ||
48 | */ | ||
49 | int pcibios_scanned; | ||
50 | |||
51 | /* | ||
52 | * This interrupt-safe spinlock protects all accesses to PCI | ||
53 | * configuration space. | ||
54 | */ | ||
55 | DEFINE_SPINLOCK(pci_config_lock); | ||
56 | |||
57 | /* | ||
58 | * Several buggy motherboards address only 16 devices and mirror | ||
59 | * them to next 16 IDs. We try to detect this `feature' on all | ||
60 | * primary buses (those containing host bridges as they are | ||
61 | * expected to be unique) and remove the ghost devices. | ||
62 | */ | ||
63 | |||
64 | static void __devinit pcibios_fixup_ghosts(struct pci_bus *b) | ||
65 | { | ||
66 | struct list_head *ln, *mn; | ||
67 | struct pci_dev *d, *e; | ||
68 | int mirror = PCI_DEVFN(16,0); | ||
69 | int seen_host_bridge = 0; | ||
70 | int i; | ||
71 | |||
72 | DBG("PCI: Scanning for ghost devices on bus %d\n", b->number); | ||
73 | list_for_each(ln, &b->devices) { | ||
74 | d = pci_dev_b(ln); | ||
75 | if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST) | ||
76 | seen_host_bridge++; | ||
77 | for (mn=ln->next; mn != &b->devices; mn=mn->next) { | ||
78 | e = pci_dev_b(mn); | ||
79 | if (e->devfn != d->devfn + mirror || | ||
80 | e->vendor != d->vendor || | ||
81 | e->device != d->device || | ||
82 | e->class != d->class) | ||
83 | continue; | ||
84 | for(i=0; i<PCI_NUM_RESOURCES; i++) | ||
85 | if (e->resource[i].start != d->resource[i].start || | ||
86 | e->resource[i].end != d->resource[i].end || | ||
87 | e->resource[i].flags != d->resource[i].flags) | ||
88 | continue; | ||
89 | break; | ||
90 | } | ||
91 | if (mn == &b->devices) | ||
92 | return; | ||
93 | } | ||
94 | if (!seen_host_bridge) | ||
95 | return; | ||
96 | printk(KERN_WARNING "PCI: Ignoring ghost devices on bus %02x\n", b->number); | ||
97 | |||
98 | ln = &b->devices; | ||
99 | while (ln->next != &b->devices) { | ||
100 | d = pci_dev_b(ln->next); | ||
101 | if (d->devfn >= mirror) { | ||
102 | list_del(&d->global_list); | ||
103 | list_del(&d->bus_list); | ||
104 | kfree(d); | ||
105 | } else | ||
106 | ln = ln->next; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | * Called after each bus is probed, but before its children | ||
112 | * are examined. | ||
113 | */ | ||
114 | |||
115 | void __devinit pcibios_fixup_bus(struct pci_bus *b) | ||
116 | { | ||
117 | pcibios_fixup_ghosts(b); | ||
118 | pci_read_bridge_bases(b); | ||
119 | } | ||
120 | |||
121 | /* | ||
122 | * Only use DMI information to set this if nothing was passed | ||
123 | * on the kernel command line (which was parsed earlier). | ||
124 | */ | ||
125 | |||
126 | static int __devinit set_bf_sort(struct dmi_system_id *d) | ||
127 | { | ||
128 | if (pci_bf_sort == pci_bf_sort_default) { | ||
129 | pci_bf_sort = pci_dmi_bf; | ||
130 | printk(KERN_INFO "PCI: %s detected, enabling pci=bfsort.\n", d->ident); | ||
131 | } | ||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | * Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus) | ||
137 | */ | ||
138 | #ifdef __i386__ | ||
139 | static int __devinit assign_all_busses(struct dmi_system_id *d) | ||
140 | { | ||
141 | pci_probe |= PCI_ASSIGN_ALL_BUSSES; | ||
142 | printk(KERN_INFO "%s detected: enabling PCI bus# renumbering" | ||
143 | " (pci=assign-busses)\n", d->ident); | ||
144 | return 0; | ||
145 | } | ||
146 | #endif | ||
147 | |||
148 | static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = { | ||
149 | #ifdef __i386__ | ||
150 | /* | ||
151 | * Laptops which need pci=assign-busses to see Cardbus cards | ||
152 | */ | ||
153 | { | ||
154 | .callback = assign_all_busses, | ||
155 | .ident = "Samsung X20 Laptop", | ||
156 | .matches = { | ||
157 | DMI_MATCH(DMI_SYS_VENDOR, "Samsung Electronics"), | ||
158 | DMI_MATCH(DMI_PRODUCT_NAME, "SX20S"), | ||
159 | }, | ||
160 | }, | ||
161 | #endif /* __i386__ */ | ||
162 | { | ||
163 | .callback = set_bf_sort, | ||
164 | .ident = "Dell PowerEdge 1950", | ||
165 | .matches = { | ||
166 | DMI_MATCH(DMI_SYS_VENDOR, "Dell"), | ||
167 | DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1950"), | ||
168 | }, | ||
169 | }, | ||
170 | { | ||
171 | .callback = set_bf_sort, | ||
172 | .ident = "Dell PowerEdge 1955", | ||
173 | .matches = { | ||
174 | DMI_MATCH(DMI_SYS_VENDOR, "Dell"), | ||
175 | DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1955"), | ||
176 | }, | ||
177 | }, | ||
178 | { | ||
179 | .callback = set_bf_sort, | ||
180 | .ident = "Dell PowerEdge 2900", | ||
181 | .matches = { | ||
182 | DMI_MATCH(DMI_SYS_VENDOR, "Dell"), | ||
183 | DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2900"), | ||
184 | }, | ||
185 | }, | ||
186 | { | ||
187 | .callback = set_bf_sort, | ||
188 | .ident = "Dell PowerEdge 2950", | ||
189 | .matches = { | ||
190 | DMI_MATCH(DMI_SYS_VENDOR, "Dell"), | ||
191 | DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2950"), | ||
192 | }, | ||
193 | }, | ||
194 | { | ||
195 | .callback = set_bf_sort, | ||
196 | .ident = "Dell PowerEdge R900", | ||
197 | .matches = { | ||
198 | DMI_MATCH(DMI_SYS_VENDOR, "Dell"), | ||
199 | DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R900"), | ||
200 | }, | ||
201 | }, | ||
202 | { | ||
203 | .callback = set_bf_sort, | ||
204 | .ident = "HP ProLiant BL20p G3", | ||
205 | .matches = { | ||
206 | DMI_MATCH(DMI_SYS_VENDOR, "HP"), | ||
207 | DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL20p G3"), | ||
208 | }, | ||
209 | }, | ||
210 | { | ||
211 | .callback = set_bf_sort, | ||
212 | .ident = "HP ProLiant BL20p G4", | ||
213 | .matches = { | ||
214 | DMI_MATCH(DMI_SYS_VENDOR, "HP"), | ||
215 | DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL20p G4"), | ||
216 | }, | ||
217 | }, | ||
218 | { | ||
219 | .callback = set_bf_sort, | ||
220 | .ident = "HP ProLiant BL30p G1", | ||
221 | .matches = { | ||
222 | DMI_MATCH(DMI_SYS_VENDOR, "HP"), | ||
223 | DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL30p G1"), | ||
224 | }, | ||
225 | }, | ||
226 | { | ||
227 | .callback = set_bf_sort, | ||
228 | .ident = "HP ProLiant BL25p G1", | ||
229 | .matches = { | ||
230 | DMI_MATCH(DMI_SYS_VENDOR, "HP"), | ||
231 | DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL25p G1"), | ||
232 | }, | ||
233 | }, | ||
234 | { | ||
235 | .callback = set_bf_sort, | ||
236 | .ident = "HP ProLiant BL35p G1", | ||
237 | .matches = { | ||
238 | DMI_MATCH(DMI_SYS_VENDOR, "HP"), | ||
239 | DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL35p G1"), | ||
240 | }, | ||
241 | }, | ||
242 | { | ||
243 | .callback = set_bf_sort, | ||
244 | .ident = "HP ProLiant BL45p G1", | ||
245 | .matches = { | ||
246 | DMI_MATCH(DMI_SYS_VENDOR, "HP"), | ||
247 | DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL45p G1"), | ||
248 | }, | ||
249 | }, | ||
250 | { | ||
251 | .callback = set_bf_sort, | ||
252 | .ident = "HP ProLiant BL45p G2", | ||
253 | .matches = { | ||
254 | DMI_MATCH(DMI_SYS_VENDOR, "HP"), | ||
255 | DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL45p G2"), | ||
256 | }, | ||
257 | }, | ||
258 | { | ||
259 | .callback = set_bf_sort, | ||
260 | .ident = "HP ProLiant BL460c G1", | ||
261 | .matches = { | ||
262 | DMI_MATCH(DMI_SYS_VENDOR, "HP"), | ||
263 | DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL460c G1"), | ||
264 | }, | ||
265 | }, | ||
266 | { | ||
267 | .callback = set_bf_sort, | ||
268 | .ident = "HP ProLiant BL465c G1", | ||
269 | .matches = { | ||
270 | DMI_MATCH(DMI_SYS_VENDOR, "HP"), | ||
271 | DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL465c G1"), | ||
272 | }, | ||
273 | }, | ||
274 | { | ||
275 | .callback = set_bf_sort, | ||
276 | .ident = "HP ProLiant BL480c G1", | ||
277 | .matches = { | ||
278 | DMI_MATCH(DMI_SYS_VENDOR, "HP"), | ||
279 | DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL480c G1"), | ||
280 | }, | ||
281 | }, | ||
282 | { | ||
283 | .callback = set_bf_sort, | ||
284 | .ident = "HP ProLiant BL685c G1", | ||
285 | .matches = { | ||
286 | DMI_MATCH(DMI_SYS_VENDOR, "HP"), | ||
287 | DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL685c G1"), | ||
288 | }, | ||
289 | }, | ||
290 | {} | ||
291 | }; | ||
292 | |||
293 | struct pci_bus * __devinit pcibios_scan_root(int busnum) | ||
294 | { | ||
295 | struct pci_bus *bus = NULL; | ||
296 | struct pci_sysdata *sd; | ||
297 | |||
298 | dmi_check_system(pciprobe_dmi_table); | ||
299 | |||
300 | while ((bus = pci_find_next_bus(bus)) != NULL) { | ||
301 | if (bus->number == busnum) { | ||
302 | /* Already scanned */ | ||
303 | return bus; | ||
304 | } | ||
305 | } | ||
306 | |||
307 | /* Allocate per-root-bus (not per bus) arch-specific data. | ||
308 | * TODO: leak; this memory is never freed. | ||
309 | * It's arguable whether it's worth the trouble to care. | ||
310 | */ | ||
311 | sd = kzalloc(sizeof(*sd), GFP_KERNEL); | ||
312 | if (!sd) { | ||
313 | printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum); | ||
314 | return NULL; | ||
315 | } | ||
316 | |||
317 | printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum); | ||
318 | |||
319 | return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd); | ||
320 | } | ||
321 | |||
322 | extern u8 pci_cache_line_size; | ||
323 | |||
324 | static int __init pcibios_init(void) | ||
325 | { | ||
326 | struct cpuinfo_x86 *c = &boot_cpu_data; | ||
327 | |||
328 | if (!raw_pci_ops) { | ||
329 | printk(KERN_WARNING "PCI: System does not support PCI\n"); | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | /* | ||
334 | * Assume PCI cacheline size of 32 bytes for all x86s except K7/K8 | ||
335 | * and P4. It's also good for 386/486s (which actually have 16) | ||
336 | * as quite a few PCI devices do not support smaller values. | ||
337 | */ | ||
338 | pci_cache_line_size = 32 >> 2; | ||
339 | if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD) | ||
340 | pci_cache_line_size = 64 >> 2; /* K7 & K8 */ | ||
341 | else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL) | ||
342 | pci_cache_line_size = 128 >> 2; /* P4 */ | ||
343 | |||
344 | pcibios_resource_survey(); | ||
345 | |||
346 | if (pci_bf_sort >= pci_force_bf) | ||
347 | pci_sort_breadthfirst(); | ||
348 | #ifdef CONFIG_PCI_BIOS | ||
349 | if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT)) | ||
350 | pcibios_sort(); | ||
351 | #endif | ||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | subsys_initcall(pcibios_init); | ||
356 | |||
357 | char * __devinit pcibios_setup(char *str) | ||
358 | { | ||
359 | if (!strcmp(str, "off")) { | ||
360 | pci_probe = 0; | ||
361 | return NULL; | ||
362 | } else if (!strcmp(str, "bfsort")) { | ||
363 | pci_bf_sort = pci_force_bf; | ||
364 | return NULL; | ||
365 | } else if (!strcmp(str, "nobfsort")) { | ||
366 | pci_bf_sort = pci_force_nobf; | ||
367 | return NULL; | ||
368 | } | ||
369 | #ifdef CONFIG_PCI_BIOS | ||
370 | else if (!strcmp(str, "bios")) { | ||
371 | pci_probe = PCI_PROBE_BIOS; | ||
372 | return NULL; | ||
373 | } else if (!strcmp(str, "nobios")) { | ||
374 | pci_probe &= ~PCI_PROBE_BIOS; | ||
375 | return NULL; | ||
376 | } else if (!strcmp(str, "nosort")) { | ||
377 | pci_probe |= PCI_NO_SORT; | ||
378 | return NULL; | ||
379 | } else if (!strcmp(str, "biosirq")) { | ||
380 | pci_probe |= PCI_BIOS_IRQ_SCAN; | ||
381 | return NULL; | ||
382 | } else if (!strncmp(str, "pirqaddr=", 9)) { | ||
383 | pirq_table_addr = simple_strtoul(str+9, NULL, 0); | ||
384 | return NULL; | ||
385 | } | ||
386 | #endif | ||
387 | #ifdef CONFIG_PCI_DIRECT | ||
388 | else if (!strcmp(str, "conf1")) { | ||
389 | pci_probe = PCI_PROBE_CONF1 | PCI_NO_CHECKS; | ||
390 | return NULL; | ||
391 | } | ||
392 | else if (!strcmp(str, "conf2")) { | ||
393 | pci_probe = PCI_PROBE_CONF2 | PCI_NO_CHECKS; | ||
394 | return NULL; | ||
395 | } | ||
396 | #endif | ||
397 | #ifdef CONFIG_PCI_MMCONFIG | ||
398 | else if (!strcmp(str, "nommconf")) { | ||
399 | pci_probe &= ~PCI_PROBE_MMCONF; | ||
400 | return NULL; | ||
401 | } | ||
402 | #endif | ||
403 | else if (!strcmp(str, "noacpi")) { | ||
404 | acpi_noirq_set(); | ||
405 | return NULL; | ||
406 | } | ||
407 | else if (!strcmp(str, "noearly")) { | ||
408 | pci_probe |= PCI_PROBE_NOEARLY; | ||
409 | return NULL; | ||
410 | } | ||
411 | #ifndef CONFIG_X86_VISWS | ||
412 | else if (!strcmp(str, "usepirqmask")) { | ||
413 | pci_probe |= PCI_USE_PIRQ_MASK; | ||
414 | return NULL; | ||
415 | } else if (!strncmp(str, "irqmask=", 8)) { | ||
416 | pcibios_irq_mask = simple_strtol(str+8, NULL, 0); | ||
417 | return NULL; | ||
418 | } else if (!strncmp(str, "lastbus=", 8)) { | ||
419 | pcibios_last_bus = simple_strtol(str+8, NULL, 0); | ||
420 | return NULL; | ||
421 | } | ||
422 | #endif | ||
423 | else if (!strcmp(str, "rom")) { | ||
424 | pci_probe |= PCI_ASSIGN_ROMS; | ||
425 | return NULL; | ||
426 | } else if (!strcmp(str, "assign-busses")) { | ||
427 | pci_probe |= PCI_ASSIGN_ALL_BUSSES; | ||
428 | return NULL; | ||
429 | } else if (!strcmp(str, "routeirq")) { | ||
430 | pci_routeirq = 1; | ||
431 | return NULL; | ||
432 | } | ||
433 | return str; | ||
434 | } | ||
435 | |||
436 | unsigned int pcibios_assign_all_busses(void) | ||
437 | { | ||
438 | return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0; | ||
439 | } | ||
440 | |||
441 | int pcibios_enable_device(struct pci_dev *dev, int mask) | ||
442 | { | ||
443 | int err; | ||
444 | |||
445 | if ((err = pcibios_enable_resources(dev, mask)) < 0) | ||
446 | return err; | ||
447 | |||
448 | if (!dev->msi_enabled) | ||
449 | return pcibios_enable_irq(dev); | ||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | void pcibios_disable_device (struct pci_dev *dev) | ||
454 | { | ||
455 | if (!dev->msi_enabled && pcibios_disable_irq) | ||
456 | pcibios_disable_irq(dev); | ||
457 | } | ||
458 | |||
459 | struct pci_bus *pci_scan_bus_with_sysdata(int busno) | ||
460 | { | ||
461 | struct pci_bus *bus = NULL; | ||
462 | struct pci_sysdata *sd; | ||
463 | |||
464 | /* | ||
465 | * Allocate per-root-bus (not per bus) arch-specific data. | ||
466 | * TODO: leak; this memory is never freed. | ||
467 | * It's arguable whether it's worth the trouble to care. | ||
468 | */ | ||
469 | sd = kzalloc(sizeof(*sd), GFP_KERNEL); | ||
470 | if (!sd) { | ||
471 | printk(KERN_ERR "PCI: OOM, skipping PCI bus %02x\n", busno); | ||
472 | return NULL; | ||
473 | } | ||
474 | sd->node = -1; | ||
475 | bus = pci_scan_bus(busno, &pci_root_ops, sd); | ||
476 | if (!bus) | ||
477 | kfree(sd); | ||
478 | |||
479 | return bus; | ||
480 | } | ||