blob: 1dd6f3fc077db0724aaea14752577c6882b23bed [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#include <linux/pci.h>
2#include <linux/acpi.h>
3#include <linux/init.h>
Nick Pigginb33fa1f2005-10-01 02:34:42 +10004#include <linux/irq.h>
Gary Hade036fff42007-10-03 15:56:14 -07005#include <linux/dmi.h>
Andi Kleen69e1a332005-09-12 18:49:24 +02006#include <asm/numa.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007#include "pci.h"
8
Gary Hade036fff42007-10-03 15:56:14 -07009static int __devinit can_skip_ioresource_align(struct dmi_system_id *d)
10{
11 pci_probe |= PCI_CAN_SKIP_ISA_ALIGN;
12 printk(KERN_INFO "PCI: %s detected, can skip ISA alignment\n", d->ident);
13 return 0;
14}
15
16static struct dmi_system_id acpi_pciprobe_dmi_table[] = {
17/*
18 * Systems where PCI IO resource ISA alignment can be skipped
19 * when the ISA enable bit in the bridge control is not set
20 */
21 {
22 .callback = can_skip_ioresource_align,
23 .ident = "IBM System x3800",
24 .matches = {
25 DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
26 DMI_MATCH(DMI_PRODUCT_NAME, "x3800"),
27 },
28 },
29 {
30 .callback = can_skip_ioresource_align,
31 .ident = "IBM System x3850",
32 .matches = {
33 DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
34 DMI_MATCH(DMI_PRODUCT_NAME, "x3850"),
35 },
36 },
37 {
38 .callback = can_skip_ioresource_align,
39 .ident = "IBM System x3950",
40 .matches = {
41 DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
42 DMI_MATCH(DMI_PRODUCT_NAME, "x3950"),
43 },
44 },
45 {}
46};
47
Linus Torvalds1da177e2005-04-16 15:20:36 -070048struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum)
49{
Andi Kleen69e1a332005-09-12 18:49:24 +020050 struct pci_bus *bus;
Muli Ben-Yehuda08f1c192007-07-22 00:23:39 +030051 struct pci_sysdata *sd;
52 int pxm;
Andi Kleen69e1a332005-09-12 18:49:24 +020053
Gary Hade036fff42007-10-03 15:56:14 -070054 dmi_check_system(acpi_pciprobe_dmi_table);
55
Muli Ben-Yehuda08f1c192007-07-22 00:23:39 +030056 /* Allocate per-root-bus (not per bus) arch-specific data.
57 * TODO: leak; this memory is never freed.
58 * It's arguable whether it's worth the trouble to care.
59 */
60 sd = kzalloc(sizeof(*sd), GFP_KERNEL);
61 if (!sd) {
62 printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 return NULL;
64 }
65
Muli Ben-Yehuda08f1c192007-07-22 00:23:39 +030066 if (domain != 0) {
67 printk(KERN_WARNING "PCI: Multiple domains not supported\n");
68 kfree(sd);
69 return NULL;
70 }
71
72 sd->node = -1;
73
74 pxm = acpi_get_pxm(device->handle);
75#ifdef CONFIG_ACPI_NUMA
76 if (pxm >= 0)
77 sd->node = pxm_to_node(pxm);
78#endif
79
80 bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
81 if (!bus)
82 kfree(sd);
83
Andi Kleen69e1a332005-09-12 18:49:24 +020084#ifdef CONFIG_ACPI_NUMA
85 if (bus != NULL) {
Andi Kleen69e1a332005-09-12 18:49:24 +020086 if (pxm >= 0) {
Muli Ben-Yehuda08f1c192007-07-22 00:23:39 +030087 printk("bus %d -> pxm %d -> node %d\n",
88 busnum, pxm, sd->node);
Andi Kleen69e1a332005-09-12 18:49:24 +020089 }
90 }
91#endif
92
93 return bus;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094}
95
96extern int pci_routeirq;
97static int __init pci_acpi_init(void)
98{
99 struct pci_dev *dev = NULL;
100
101 if (pcibios_scanned)
102 return 0;
103
104 if (acpi_noirq)
105 return 0;
106
107 printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
108 acpi_irq_penalty_init();
109 pcibios_scanned++;
110 pcibios_enable_irq = acpi_pci_irq_enable;
David Shaohua Li87bec662005-07-27 23:02:00 -0400111 pcibios_disable_irq = acpi_pci_irq_disable;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112
113 if (pci_routeirq) {
114 /*
115 * PCI IRQ routing is set up by pci_enable_device(), but we
116 * also do it here in case there are still broken drivers that
117 * don't use pci_enable_device().
118 */
119 printk(KERN_INFO "PCI: Routing PCI interrupts for all devices because \"pci=routeirq\" specified\n");
Hanna Linderfb37fb92005-11-06 23:39:36 -0800120 for_each_pci_dev(dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 acpi_pci_irq_enable(dev);
122 } else
123 printk(KERN_INFO "PCI: If a device doesn't work, try \"pci=routeirq\". If it helps, post a report\n");
124
125#ifdef CONFIG_X86_IO_APIC
126 if (acpi_ioapic)
127 print_IO_APIC();
128#endif
129
130 return 0;
131}
132subsys_initcall(pci_acpi_init);