diff options
-rw-r--r-- | arch/x86/pci/acpi.c | 294 |
1 files changed, 87 insertions, 207 deletions
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 5bc018559cc4..3cd69832d7f4 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c | |||
@@ -4,16 +4,15 @@ | |||
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 <linux/slab.h> |
7 | #include <linux/pci-acpi.h> | ||
7 | #include <asm/numa.h> | 8 | #include <asm/numa.h> |
8 | #include <asm/pci_x86.h> | 9 | #include <asm/pci_x86.h> |
9 | 10 | ||
10 | struct pci_root_info { | 11 | struct pci_root_info { |
11 | struct acpi_device *bridge; | 12 | struct acpi_pci_root_info common; |
12 | char name[16]; | ||
13 | struct pci_sysdata sd; | 13 | struct pci_sysdata sd; |
14 | #ifdef CONFIG_PCI_MMCONFIG | 14 | #ifdef CONFIG_PCI_MMCONFIG |
15 | bool mcfg_added; | 15 | bool mcfg_added; |
16 | u16 segment; | ||
17 | u8 start_bus; | 16 | u8 start_bus; |
18 | u8 end_bus; | 17 | u8 end_bus; |
19 | #endif | 18 | #endif |
@@ -178,15 +177,18 @@ static int check_segment(u16 seg, struct device *dev, char *estr) | |||
178 | return 0; | 177 | return 0; |
179 | } | 178 | } |
180 | 179 | ||
181 | static int setup_mcfg_map(struct pci_root_info *info, u16 seg, u8 start, | 180 | static int setup_mcfg_map(struct acpi_pci_root_info *ci) |
182 | u8 end, phys_addr_t addr) | ||
183 | { | 181 | { |
184 | int result; | 182 | int result, seg; |
185 | struct device *dev = &info->bridge->dev; | 183 | struct pci_root_info *info; |
184 | struct acpi_pci_root *root = ci->root; | ||
185 | struct device *dev = &ci->bridge->dev; | ||
186 | 186 | ||
187 | info->start_bus = start; | 187 | info = container_of(ci, struct pci_root_info, common); |
188 | info->end_bus = end; | 188 | info->start_bus = (u8)root->secondary.start; |
189 | info->end_bus = (u8)root->secondary.end; | ||
189 | info->mcfg_added = false; | 190 | info->mcfg_added = false; |
191 | seg = info->sd.domain; | ||
190 | 192 | ||
191 | /* return success if MMCFG is not in use */ | 193 | /* return success if MMCFG is not in use */ |
192 | if (raw_pci_ext_ops && raw_pci_ext_ops != &pci_mmcfg) | 194 | if (raw_pci_ext_ops && raw_pci_ext_ops != &pci_mmcfg) |
@@ -195,7 +197,8 @@ static int setup_mcfg_map(struct pci_root_info *info, u16 seg, u8 start, | |||
195 | if (!(pci_probe & PCI_PROBE_MMCONF)) | 197 | if (!(pci_probe & PCI_PROBE_MMCONF)) |
196 | return check_segment(seg, dev, "MMCONFIG is disabled,"); | 198 | return check_segment(seg, dev, "MMCONFIG is disabled,"); |
197 | 199 | ||
198 | result = pci_mmconfig_insert(dev, seg, start, end, addr); | 200 | result = pci_mmconfig_insert(dev, seg, info->start_bus, info->end_bus, |
201 | root->mcfg_addr); | ||
199 | if (result == 0) { | 202 | if (result == 0) { |
200 | /* enable MMCFG if it hasn't been enabled yet */ | 203 | /* enable MMCFG if it hasn't been enabled yet */ |
201 | if (raw_pci_ext_ops == NULL) | 204 | if (raw_pci_ext_ops == NULL) |
@@ -208,134 +211,55 @@ static int setup_mcfg_map(struct pci_root_info *info, u16 seg, u8 start, | |||
208 | return 0; | 211 | return 0; |
209 | } | 212 | } |
210 | 213 | ||
211 | static void teardown_mcfg_map(struct pci_root_info *info) | 214 | static void teardown_mcfg_map(struct acpi_pci_root_info *ci) |
212 | { | 215 | { |
216 | struct pci_root_info *info; | ||
217 | |||
218 | info = container_of(ci, struct pci_root_info, common); | ||
213 | if (info->mcfg_added) { | 219 | if (info->mcfg_added) { |
214 | pci_mmconfig_delete(info->segment, info->start_bus, | 220 | pci_mmconfig_delete(info->sd.domain, |
215 | info->end_bus); | 221 | info->start_bus, info->end_bus); |
216 | info->mcfg_added = false; | 222 | info->mcfg_added = false; |
217 | } | 223 | } |
218 | } | 224 | } |
219 | #else | 225 | #else |
220 | static int setup_mcfg_map(struct pci_root_info *info, | 226 | static int setup_mcfg_map(struct acpi_pci_root_info *ci) |
221 | u16 seg, u8 start, u8 end, | ||
222 | phys_addr_t addr) | ||
223 | { | 227 | { |
224 | return 0; | 228 | return 0; |
225 | } | 229 | } |
226 | static void teardown_mcfg_map(struct pci_root_info *info) | 230 | |
231 | static void teardown_mcfg_map(struct acpi_pci_root_info *ci) | ||
227 | { | 232 | { |
228 | } | 233 | } |
229 | #endif | 234 | #endif |
230 | 235 | ||
231 | static void validate_resources(struct device *dev, struct list_head *crs_res, | 236 | static int pci_acpi_root_get_node(struct acpi_pci_root *root) |
232 | unsigned long type) | ||
233 | { | 237 | { |
234 | LIST_HEAD(list); | 238 | int busnum = root->secondary.start; |
235 | struct resource *res1, *res2, *root = NULL; | 239 | struct acpi_device *device = root->device; |
236 | struct resource_entry *tmp, *entry, *entry2; | 240 | int node = acpi_get_node(device->handle); |
237 | |||
238 | BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0); | ||
239 | root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource; | ||
240 | |||
241 | list_splice_init(crs_res, &list); | ||
242 | resource_list_for_each_entry_safe(entry, tmp, &list) { | ||
243 | bool free = false; | ||
244 | resource_size_t end; | ||
245 | |||
246 | res1 = entry->res; | ||
247 | if (!(res1->flags & type)) | ||
248 | goto next; | ||
249 | |||
250 | /* Exclude non-addressable range or non-addressable portion */ | ||
251 | end = min(res1->end, root->end); | ||
252 | if (end <= res1->start) { | ||
253 | dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n", | ||
254 | res1); | ||
255 | free = true; | ||
256 | goto next; | ||
257 | } else if (res1->end != end) { | ||
258 | dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n", | ||
259 | res1, (unsigned long long)end + 1, | ||
260 | (unsigned long long)res1->end); | ||
261 | res1->end = end; | ||
262 | } | ||
263 | |||
264 | resource_list_for_each_entry(entry2, crs_res) { | ||
265 | res2 = entry2->res; | ||
266 | if (!(res2->flags & type)) | ||
267 | continue; | ||
268 | |||
269 | /* | ||
270 | * I don't like throwing away windows because then | ||
271 | * our resources no longer match the ACPI _CRS, but | ||
272 | * the kernel resource tree doesn't allow overlaps. | ||
273 | */ | ||
274 | if (resource_overlaps(res1, res2)) { | ||
275 | res2->start = min(res1->start, res2->start); | ||
276 | res2->end = max(res1->end, res2->end); | ||
277 | dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n", | ||
278 | res2, res1); | ||
279 | free = true; | ||
280 | goto next; | ||
281 | } | ||
282 | } | ||
283 | 241 | ||
284 | next: | 242 | if (node == NUMA_NO_NODE) { |
285 | resource_list_del(entry); | 243 | node = x86_pci_root_bus_node(busnum); |
286 | if (free) | 244 | if (node != 0 && node != NUMA_NO_NODE) |
287 | resource_list_free_entry(entry); | 245 | dev_info(&device->dev, FW_BUG "no _PXM; falling back to node %d from hardware (may be inconsistent with ACPI node numbers)\n", |
288 | else | 246 | node); |
289 | resource_list_add_tail(entry, crs_res); | ||
290 | } | 247 | } |
248 | if (node != NUMA_NO_NODE && !node_online(node)) | ||
249 | node = NUMA_NO_NODE; | ||
250 | |||
251 | return node; | ||
291 | } | 252 | } |
292 | 253 | ||
293 | static void add_resources(struct pci_root_info *info, | 254 | static int pci_acpi_root_init_info(struct acpi_pci_root_info *ci) |
294 | struct list_head *resources, | ||
295 | struct list_head *crs_res) | ||
296 | { | 255 | { |
297 | struct resource_entry *entry, *tmp; | 256 | return setup_mcfg_map(ci); |
298 | struct resource *res, *conflict, *root = NULL; | ||
299 | |||
300 | validate_resources(&info->bridge->dev, crs_res, IORESOURCE_MEM); | ||
301 | validate_resources(&info->bridge->dev, crs_res, IORESOURCE_IO); | ||
302 | |||
303 | resource_list_for_each_entry_safe(entry, tmp, crs_res) { | ||
304 | res = entry->res; | ||
305 | if (res->flags & IORESOURCE_MEM) | ||
306 | root = &iomem_resource; | ||
307 | else if (res->flags & IORESOURCE_IO) | ||
308 | root = &ioport_resource; | ||
309 | else | ||
310 | BUG_ON(res); | ||
311 | |||
312 | conflict = insert_resource_conflict(root, res); | ||
313 | if (conflict) { | ||
314 | dev_info(&info->bridge->dev, | ||
315 | "ignoring host bridge window %pR (conflicts with %s %pR)\n", | ||
316 | res, conflict->name, conflict); | ||
317 | resource_list_destroy_entry(entry); | ||
318 | } | ||
319 | } | ||
320 | |||
321 | list_splice_tail(crs_res, resources); | ||
322 | } | 257 | } |
323 | 258 | ||
324 | static void release_pci_root_info(struct pci_host_bridge *bridge) | 259 | static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci) |
325 | { | 260 | { |
326 | struct resource *res; | 261 | teardown_mcfg_map(ci); |
327 | struct resource_entry *entry; | 262 | kfree(container_of(ci, struct pci_root_info, common)); |
328 | struct pci_root_info *info = bridge->release_data; | ||
329 | |||
330 | resource_list_for_each_entry(entry, &bridge->windows) { | ||
331 | res = entry->res; | ||
332 | if (res->parent && | ||
333 | (res->flags & (IORESOURCE_MEM | IORESOURCE_IO))) | ||
334 | release_resource(res); | ||
335 | } | ||
336 | |||
337 | teardown_mcfg_map(info); | ||
338 | kfree(info); | ||
339 | } | 263 | } |
340 | 264 | ||
341 | /* | 265 | /* |
@@ -358,47 +282,44 @@ static bool resource_is_pcicfg_ioport(struct resource *res) | |||
358 | res->start == 0xCF8 && res->end == 0xCFF; | 282 | res->start == 0xCF8 && res->end == 0xCFF; |
359 | } | 283 | } |
360 | 284 | ||
361 | static void probe_pci_root_info(struct pci_root_info *info, | 285 | static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci) |
362 | struct acpi_device *device, | ||
363 | int busnum, int domain, | ||
364 | struct list_head *list) | ||
365 | { | 286 | { |
366 | int ret; | 287 | struct acpi_device *device = ci->bridge; |
288 | int busnum = ci->root->secondary.start; | ||
367 | struct resource_entry *entry, *tmp; | 289 | struct resource_entry *entry, *tmp; |
290 | int status; | ||
368 | 291 | ||
369 | sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum); | 292 | status = acpi_pci_probe_root_resources(ci); |
370 | info->bridge = device; | 293 | if (pci_use_crs) { |
371 | ret = acpi_dev_get_resources(device, list, | 294 | resource_list_for_each_entry_safe(entry, tmp, &ci->resources) |
372 | acpi_dev_filter_resource_type_cb, | 295 | if (resource_is_pcicfg_ioport(entry->res)) |
373 | (void *)(IORESOURCE_IO | IORESOURCE_MEM)); | ||
374 | if (ret < 0) | ||
375 | dev_warn(&device->dev, | ||
376 | "failed to parse _CRS method, error code %d\n", ret); | ||
377 | else if (ret == 0) | ||
378 | dev_dbg(&device->dev, | ||
379 | "no IO and memory resources present in _CRS\n"); | ||
380 | else | ||
381 | resource_list_for_each_entry_safe(entry, tmp, list) { | ||
382 | if ((entry->res->flags & IORESOURCE_DISABLED) || | ||
383 | resource_is_pcicfg_ioport(entry->res)) | ||
384 | resource_list_destroy_entry(entry); | 296 | resource_list_destroy_entry(entry); |
385 | else | 297 | return status; |
386 | entry->res->name = info->name; | 298 | } |
387 | } | 299 | |
300 | resource_list_for_each_entry_safe(entry, tmp, &ci->resources) { | ||
301 | dev_printk(KERN_DEBUG, &device->dev, | ||
302 | "host bridge window %pR (ignored)\n", entry->res); | ||
303 | resource_list_destroy_entry(entry); | ||
304 | } | ||
305 | x86_pci_root_bus_resources(busnum, &ci->resources); | ||
306 | |||
307 | return 0; | ||
388 | } | 308 | } |
389 | 309 | ||
310 | static struct acpi_pci_root_ops acpi_pci_root_ops = { | ||
311 | .pci_ops = &pci_root_ops, | ||
312 | .init_info = pci_acpi_root_init_info, | ||
313 | .release_info = pci_acpi_root_release_info, | ||
314 | .prepare_resources = pci_acpi_root_prepare_resources, | ||
315 | }; | ||
316 | |||
390 | struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) | 317 | struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) |
391 | { | 318 | { |
392 | struct acpi_device *device = root->device; | ||
393 | struct pci_root_info *info; | ||
394 | int domain = root->segment; | 319 | int domain = root->segment; |
395 | int busnum = root->secondary.start; | 320 | int busnum = root->secondary.start; |
396 | struct resource_entry *res_entry; | 321 | int node = pci_acpi_root_get_node(root); |
397 | LIST_HEAD(crs_res); | ||
398 | LIST_HEAD(resources); | ||
399 | struct pci_bus *bus; | 322 | struct pci_bus *bus; |
400 | struct pci_sysdata *sd; | ||
401 | int node; | ||
402 | 323 | ||
403 | if (pci_ignore_seg) | 324 | if (pci_ignore_seg) |
404 | root->segment = domain = 0; | 325 | root->segment = domain = 0; |
@@ -410,71 +331,33 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) | |||
410 | return NULL; | 331 | return NULL; |
411 | } | 332 | } |
412 | 333 | ||
413 | node = acpi_get_node(device->handle); | ||
414 | if (node == NUMA_NO_NODE) { | ||
415 | node = x86_pci_root_bus_node(busnum); | ||
416 | if (node != 0 && node != NUMA_NO_NODE) | ||
417 | dev_info(&device->dev, FW_BUG "no _PXM; falling back to node %d from hardware (may be inconsistent with ACPI node numbers)\n", | ||
418 | node); | ||
419 | } | ||
420 | |||
421 | if (node != NUMA_NO_NODE && !node_online(node)) | ||
422 | node = NUMA_NO_NODE; | ||
423 | |||
424 | info = kzalloc_node(sizeof(*info), GFP_KERNEL, node); | ||
425 | if (!info) { | ||
426 | printk(KERN_WARNING "pci_bus %04x:%02x: " | ||
427 | "ignored (out of memory)\n", domain, busnum); | ||
428 | return NULL; | ||
429 | } | ||
430 | |||
431 | sd = &info->sd; | ||
432 | sd->domain = domain; | ||
433 | sd->node = node; | ||
434 | sd->companion = device; | ||
435 | |||
436 | bus = pci_find_bus(domain, busnum); | 334 | bus = pci_find_bus(domain, busnum); |
437 | if (bus) { | 335 | if (bus) { |
438 | /* | 336 | /* |
439 | * If the desired bus has been scanned already, replace | 337 | * If the desired bus has been scanned already, replace |
440 | * its bus->sysdata. | 338 | * its bus->sysdata. |
441 | */ | 339 | */ |
442 | memcpy(bus->sysdata, sd, sizeof(*sd)); | 340 | struct pci_sysdata sd = { |
443 | kfree(info); | 341 | .domain = domain, |
444 | } else { | 342 | .node = node, |
445 | /* insert busn res at first */ | 343 | .companion = root->device |
446 | pci_add_resource(&resources, &root->secondary); | 344 | }; |
447 | 345 | ||
448 | /* | 346 | memcpy(bus->sysdata, &sd, sizeof(sd)); |
449 | * _CRS with no apertures is normal, so only fall back to | 347 | } else { |
450 | * defaults or native bridge info if we're ignoring _CRS. | 348 | struct pci_root_info *info; |
451 | */ | 349 | |
452 | probe_pci_root_info(info, device, busnum, domain, &crs_res); | 350 | info = kzalloc_node(sizeof(*info), GFP_KERNEL, node); |
453 | if (pci_use_crs) { | 351 | if (!info) |
454 | add_resources(info, &resources, &crs_res); | 352 | dev_err(&root->device->dev, |
455 | } else { | 353 | "pci_bus %04x:%02x: ignored (out of memory)\n", |
456 | resource_list_for_each_entry(res_entry, &crs_res) | 354 | domain, busnum); |
457 | dev_printk(KERN_DEBUG, &device->dev, | 355 | else { |
458 | "host bridge window %pR (ignored)\n", | 356 | info->sd.domain = domain; |
459 | res_entry->res); | 357 | info->sd.node = node; |
460 | resource_list_free(&crs_res); | 358 | info->sd.companion = root->device; |
461 | x86_pci_root_bus_resources(busnum, &resources); | 359 | bus = acpi_pci_root_create(root, &acpi_pci_root_ops, |
462 | } | 360 | &info->common, &info->sd); |
463 | |||
464 | if (!setup_mcfg_map(info, domain, (u8)root->secondary.start, | ||
465 | (u8)root->secondary.end, root->mcfg_addr)) | ||
466 | bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, | ||
467 | sd, &resources); | ||
468 | |||
469 | if (bus) { | ||
470 | pci_scan_child_bus(bus); | ||
471 | pci_set_host_bridge_release( | ||
472 | to_pci_host_bridge(bus->bridge), | ||
473 | release_pci_root_info, info); | ||
474 | } else { | ||
475 | resource_list_free(&resources); | ||
476 | teardown_mcfg_map(info); | ||
477 | kfree(info); | ||
478 | } | 361 | } |
479 | } | 362 | } |
480 | 363 | ||
@@ -487,9 +370,6 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) | |||
487 | pcie_bus_configure_settings(child); | 370 | pcie_bus_configure_settings(child); |
488 | } | 371 | } |
489 | 372 | ||
490 | if (bus && node != NUMA_NO_NODE) | ||
491 | dev_printk(KERN_DEBUG, &bus->dev, "on NUMA node %d\n", node); | ||
492 | |||
493 | return bus; | 373 | return bus; |
494 | } | 374 | } |
495 | 375 | ||