aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/pci/acpi.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/pci/acpi.c')
-rw-r--r--arch/x86/pci/acpi.c170
1 files changed, 119 insertions, 51 deletions
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 1014eb4bfc37..31930fd30ea9 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -3,10 +3,12 @@
3#include <linux/init.h> 3#include <linux/init.h>
4#include <linux/irq.h> 4#include <linux/irq.h>
5#include <linux/dmi.h> 5#include <linux/dmi.h>
6#include <linux/slab.h>
6#include <asm/numa.h> 7#include <asm/numa.h>
7#include <asm/pci_x86.h> 8#include <asm/pci_x86.h>
8 9
9struct pci_root_info { 10struct pci_root_info {
11 struct acpi_device *bridge;
10 char *name; 12 char *name;
11 unsigned int res_num; 13 unsigned int res_num;
12 struct resource *res; 14 struct resource *res;
@@ -14,19 +16,94 @@ struct pci_root_info {
14 int busnum; 16 int busnum;
15}; 17};
16 18
19static bool pci_use_crs = true;
20
21static int __init set_use_crs(const struct dmi_system_id *id)
22{
23 pci_use_crs = true;
24 return 0;
25}
26
27static const struct dmi_system_id pci_use_crs_table[] __initconst = {
28 /* http://bugzilla.kernel.org/show_bug.cgi?id=14183 */
29 {
30 .callback = set_use_crs,
31 .ident = "IBM System x3800",
32 .matches = {
33 DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
34 DMI_MATCH(DMI_PRODUCT_NAME, "x3800"),
35 },
36 },
37 {}
38};
39
40void __init pci_acpi_crs_quirks(void)
41{
42 int year;
43
44 if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && year < 2008)
45 pci_use_crs = false;
46
47 dmi_check_system(pci_use_crs_table);
48
49 /*
50 * If the user specifies "pci=use_crs" or "pci=nocrs" explicitly, that
51 * takes precedence over anything we figured out above.
52 */
53 if (pci_probe & PCI_ROOT_NO_CRS)
54 pci_use_crs = false;
55 else if (pci_probe & PCI_USE__CRS)
56 pci_use_crs = true;
57
58 printk(KERN_INFO "PCI: %s host bridge windows from ACPI; "
59 "if necessary, use \"pci=%s\" and report a bug\n",
60 pci_use_crs ? "Using" : "Ignoring",
61 pci_use_crs ? "nocrs" : "use_crs");
62}
63
17static acpi_status 64static acpi_status
18resource_to_addr(struct acpi_resource *resource, 65resource_to_addr(struct acpi_resource *resource,
19 struct acpi_resource_address64 *addr) 66 struct acpi_resource_address64 *addr)
20{ 67{
21 acpi_status status; 68 acpi_status status;
22 69 struct acpi_resource_memory24 *memory24;
23 status = acpi_resource_to_address64(resource, addr); 70 struct acpi_resource_memory32 *memory32;
24 if (ACPI_SUCCESS(status) && 71 struct acpi_resource_fixed_memory32 *fixed_memory32;
25 (addr->resource_type == ACPI_MEMORY_RANGE || 72
26 addr->resource_type == ACPI_IO_RANGE) && 73 memset(addr, 0, sizeof(*addr));
27 addr->address_length > 0 && 74 switch (resource->type) {
28 addr->producer_consumer == ACPI_PRODUCER) { 75 case ACPI_RESOURCE_TYPE_MEMORY24:
76 memory24 = &resource->data.memory24;
77 addr->resource_type = ACPI_MEMORY_RANGE;
78 addr->minimum = memory24->minimum;
79 addr->address_length = memory24->address_length;
80 addr->maximum = addr->minimum + addr->address_length - 1;
81 return AE_OK;
82 case ACPI_RESOURCE_TYPE_MEMORY32:
83 memory32 = &resource->data.memory32;
84 addr->resource_type = ACPI_MEMORY_RANGE;
85 addr->minimum = memory32->minimum;
86 addr->address_length = memory32->address_length;
87 addr->maximum = addr->minimum + addr->address_length - 1;
29 return AE_OK; 88 return AE_OK;
89 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
90 fixed_memory32 = &resource->data.fixed_memory32;
91 addr->resource_type = ACPI_MEMORY_RANGE;
92 addr->minimum = fixed_memory32->address;
93 addr->address_length = fixed_memory32->address_length;
94 addr->maximum = addr->minimum + addr->address_length - 1;
95 return AE_OK;
96 case ACPI_RESOURCE_TYPE_ADDRESS16:
97 case ACPI_RESOURCE_TYPE_ADDRESS32:
98 case ACPI_RESOURCE_TYPE_ADDRESS64:
99 status = acpi_resource_to_address64(resource, addr);
100 if (ACPI_SUCCESS(status) &&
101 (addr->resource_type == ACPI_MEMORY_RANGE ||
102 addr->resource_type == ACPI_IO_RANGE) &&
103 addr->address_length > 0) {
104 return AE_OK;
105 }
106 break;
30 } 107 }
31 return AE_ERROR; 108 return AE_ERROR;
32} 109}
@@ -44,20 +121,6 @@ count_resource(struct acpi_resource *acpi_res, void *data)
44 return AE_OK; 121 return AE_OK;
45} 122}
46 123
47static int
48bus_has_transparent_bridge(struct pci_bus *bus)
49{
50 struct pci_dev *dev;
51
52 list_for_each_entry(dev, &bus->devices, bus_list) {
53 u16 class = dev->class >> 8;
54
55 if (class == PCI_CLASS_BRIDGE_PCI && dev->transparent)
56 return true;
57 }
58 return false;
59}
60
61static acpi_status 124static acpi_status
62setup_resource(struct acpi_resource *acpi_res, void *data) 125setup_resource(struct acpi_resource *acpi_res, void *data)
63{ 126{
@@ -66,13 +129,9 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
66 struct acpi_resource_address64 addr; 129 struct acpi_resource_address64 addr;
67 acpi_status status; 130 acpi_status status;
68 unsigned long flags; 131 unsigned long flags;
69 struct resource *root; 132 struct resource *root, *conflict;
70 int max_root_bus_resources = PCI_BUS_NUM_RESOURCES;
71 u64 start, end; 133 u64 start, end;
72 134
73 if (bus_has_transparent_bridge(info->bus))
74 max_root_bus_resources -= 3;
75
76 status = resource_to_addr(acpi_res, &addr); 135 status = resource_to_addr(acpi_res, &addr);
77 if (!ACPI_SUCCESS(status)) 136 if (!ACPI_SUCCESS(status))
78 return AE_OK; 137 return AE_OK;
@@ -89,15 +148,7 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
89 return AE_OK; 148 return AE_OK;
90 149
91 start = addr.minimum + addr.translation_offset; 150 start = addr.minimum + addr.translation_offset;
92 end = start + addr.address_length - 1; 151 end = addr.maximum + addr.translation_offset;
93 if (info->res_num >= max_root_bus_resources) {
94 printk(KERN_WARNING "PCI: Failed to allocate 0x%lx-0x%lx "
95 "from %s for %s due to _CRS returning more than "
96 "%d resource descriptors\n", (unsigned long) start,
97 (unsigned long) end, root->name, info->name,
98 max_root_bus_resources);
99 return AE_OK;
100 }
101 152
102 res = &info->res[info->res_num]; 153 res = &info->res[info->res_num];
103 res->name = info->name; 154 res->name = info->name;
@@ -106,13 +157,29 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
106 res->end = end; 157 res->end = end;
107 res->child = NULL; 158 res->child = NULL;
108 159
109 if (insert_resource(root, res)) { 160 if (!pci_use_crs) {
110 printk(KERN_ERR "PCI: Failed to allocate 0x%lx-0x%lx " 161 dev_printk(KERN_DEBUG, &info->bridge->dev,
111 "from %s for %s\n", (unsigned long) res->start, 162 "host bridge window %pR (ignored)\n", res);
112 (unsigned long) res->end, root->name, info->name); 163 return AE_OK;
164 }
165
166 conflict = insert_resource_conflict(root, res);
167 if (conflict) {
168 dev_err(&info->bridge->dev,
169 "address space collision: host bridge window %pR "
170 "conflicts with %s %pR\n",
171 res, conflict->name, conflict);
113 } else { 172 } else {
114 info->bus->resource[info->res_num] = res; 173 pci_bus_add_resource(info->bus, res, 0);
115 info->res_num++; 174 info->res_num++;
175 if (addr.translation_offset)
176 dev_info(&info->bridge->dev, "host bridge window %pR "
177 "(PCI address [%#llx-%#llx])\n",
178 res, res->start - addr.translation_offset,
179 res->end - addr.translation_offset);
180 else
181 dev_info(&info->bridge->dev,
182 "host bridge window %pR\n", res);
116 } 183 }
117 return AE_OK; 184 return AE_OK;
118} 185}
@@ -124,6 +191,10 @@ get_current_resources(struct acpi_device *device, int busnum,
124 struct pci_root_info info; 191 struct pci_root_info info;
125 size_t size; 192 size_t size;
126 193
194 if (pci_use_crs)
195 pci_bus_remove_resources(bus);
196
197 info.bridge = device;
127 info.bus = bus; 198 info.bus = bus;
128 info.res_num = 0; 199 info.res_num = 0;
129 acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource, 200 acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource,
@@ -163,8 +234,9 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
163#endif 234#endif
164 235
165 if (domain && !pci_domains_supported) { 236 if (domain && !pci_domains_supported) {
166 printk(KERN_WARNING "PCI: Multiple domains not supported " 237 printk(KERN_WARNING "pci_bus %04x:%02x: "
167 "(dom %d, bus %d)\n", domain, busnum); 238 "ignored (multiple domains not supported)\n",
239 domain, busnum);
168 return NULL; 240 return NULL;
169 } 241 }
170 242
@@ -188,7 +260,8 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
188 */ 260 */
189 sd = kzalloc(sizeof(*sd), GFP_KERNEL); 261 sd = kzalloc(sizeof(*sd), GFP_KERNEL);
190 if (!sd) { 262 if (!sd) {
191 printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum); 263 printk(KERN_WARNING "pci_bus %04x:%02x: "
264 "ignored (out of memory)\n", domain, busnum);
192 return NULL; 265 return NULL;
193 } 266 }
194 267
@@ -209,9 +282,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
209 } else { 282 } else {
210 bus = pci_create_bus(NULL, busnum, &pci_root_ops, sd); 283 bus = pci_create_bus(NULL, busnum, &pci_root_ops, sd);
211 if (bus) { 284 if (bus) {
212 if (pci_probe & PCI_USE__CRS) 285 get_current_resources(device, busnum, domain, bus);
213 get_current_resources(device, busnum, domain,
214 bus);
215 bus->subordinate = pci_scan_child_bus(bus); 286 bus->subordinate = pci_scan_child_bus(bus);
216 } 287 }
217 } 288 }
@@ -236,17 +307,14 @@ int __init pci_acpi_init(void)
236{ 307{
237 struct pci_dev *dev = NULL; 308 struct pci_dev *dev = NULL;
238 309
239 if (pcibios_scanned)
240 return 0;
241
242 if (acpi_noirq) 310 if (acpi_noirq)
243 return 0; 311 return -ENODEV;
244 312
245 printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n"); 313 printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
246 acpi_irq_penalty_init(); 314 acpi_irq_penalty_init();
247 pcibios_scanned++;
248 pcibios_enable_irq = acpi_pci_irq_enable; 315 pcibios_enable_irq = acpi_pci_irq_enable;
249 pcibios_disable_irq = acpi_pci_irq_disable; 316 pcibios_disable_irq = acpi_pci_irq_disable;
317 x86_init.pci.init_irq = x86_init_noop;
250 318
251 if (pci_routeirq) { 319 if (pci_routeirq) {
252 /* 320 /*