diff options
Diffstat (limited to 'arch/x86/pci/acpi.c')
-rw-r--r-- | arch/x86/pci/acpi.c | 170 |
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 | ||
9 | struct pci_root_info { | 10 | struct 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 | ||
19 | static bool pci_use_crs = true; | ||
20 | |||
21 | static int __init set_use_crs(const struct dmi_system_id *id) | ||
22 | { | ||
23 | pci_use_crs = true; | ||
24 | return 0; | ||
25 | } | ||
26 | |||
27 | static 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 | |||
40 | void __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 | |||
17 | static acpi_status | 64 | static acpi_status |
18 | resource_to_addr(struct acpi_resource *resource, | 65 | resource_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 | ||
47 | static int | ||
48 | bus_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 | |||
61 | static acpi_status | 124 | static acpi_status |
62 | setup_resource(struct acpi_resource *acpi_res, void *data) | 125 | setup_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 | /* |