diff options
author | Jiang Liu <jiang.liu@hauwei.com> | 2012-06-22 02:55:14 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2012-06-22 17:16:38 -0400 |
commit | 95c5e92f4f691bbaba40bbf3decfc8e13b6ea897 (patch) | |
tree | 0f7e180f2e7b743cb2260e5cf6f88b351cf760e0 /arch/x86/pci | |
parent | 9cf0105da5a315677d8f91043fb87fdade0d8b39 (diff) |
x86/PCI: prepare pci_mmcfg_check_reserved() to be called at runtime
Prepare function pci_mmcfg_check_reserved() to be called at runtime
for PCI host bridge hot-plugging
Reviewed-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Jiang Liu <liuj97@gmail.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'arch/x86/pci')
-rw-r--r-- | arch/x86/pci/mmconfig-shared.c | 104 |
1 files changed, 68 insertions, 36 deletions
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c index 0ac97d54bcac..15a7abf5139c 100644 --- a/arch/x86/pci/mmconfig-shared.c +++ b/arch/x86/pci/mmconfig-shared.c | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | /* Indicate if the mmcfg resources have been placed into the resource table. */ | 28 | /* Indicate if the mmcfg resources have been placed into the resource table. */ |
29 | static int __initdata pci_mmcfg_resources_inserted; | 29 | static int __initdata pci_mmcfg_resources_inserted; |
30 | static bool pci_mmcfg_running_state; | ||
30 | static DEFINE_MUTEX(pci_mmcfg_lock); | 31 | static DEFINE_MUTEX(pci_mmcfg_lock); |
31 | 32 | ||
32 | LIST_HEAD(pci_mmcfg_list); | 33 | LIST_HEAD(pci_mmcfg_list); |
@@ -375,14 +376,15 @@ static void __init pci_mmcfg_insert_resources(void) | |||
375 | struct pci_mmcfg_region *cfg; | 376 | struct pci_mmcfg_region *cfg; |
376 | 377 | ||
377 | list_for_each_entry(cfg, &pci_mmcfg_list, list) | 378 | list_for_each_entry(cfg, &pci_mmcfg_list, list) |
378 | insert_resource(&iomem_resource, &cfg->res); | 379 | if (!cfg->res.parent) |
380 | insert_resource(&iomem_resource, &cfg->res); | ||
379 | 381 | ||
380 | /* Mark that the resources have been inserted. */ | 382 | /* Mark that the resources have been inserted. */ |
381 | pci_mmcfg_resources_inserted = 1; | 383 | pci_mmcfg_resources_inserted = 1; |
382 | } | 384 | } |
383 | 385 | ||
384 | static acpi_status __init check_mcfg_resource(struct acpi_resource *res, | 386 | static acpi_status __devinit check_mcfg_resource(struct acpi_resource *res, |
385 | void *data) | 387 | void *data) |
386 | { | 388 | { |
387 | struct resource *mcfg_res = data; | 389 | struct resource *mcfg_res = data; |
388 | struct acpi_resource_address64 address; | 390 | struct acpi_resource_address64 address; |
@@ -418,8 +420,8 @@ static acpi_status __init check_mcfg_resource(struct acpi_resource *res, | |||
418 | return AE_OK; | 420 | return AE_OK; |
419 | } | 421 | } |
420 | 422 | ||
421 | static acpi_status __init find_mboard_resource(acpi_handle handle, u32 lvl, | 423 | static acpi_status __devinit find_mboard_resource(acpi_handle handle, u32 lvl, |
422 | void *context, void **rv) | 424 | void *context, void **rv) |
423 | { | 425 | { |
424 | struct resource *mcfg_res = context; | 426 | struct resource *mcfg_res = context; |
425 | 427 | ||
@@ -432,7 +434,7 @@ static acpi_status __init find_mboard_resource(acpi_handle handle, u32 lvl, | |||
432 | return AE_OK; | 434 | return AE_OK; |
433 | } | 435 | } |
434 | 436 | ||
435 | static int __init is_acpi_reserved(u64 start, u64 end, unsigned not_used) | 437 | static int __devinit is_acpi_reserved(u64 start, u64 end, unsigned not_used) |
436 | { | 438 | { |
437 | struct resource mcfg_res; | 439 | struct resource mcfg_res; |
438 | 440 | ||
@@ -451,13 +453,15 @@ static int __init is_acpi_reserved(u64 start, u64 end, unsigned not_used) | |||
451 | 453 | ||
452 | typedef int (*check_reserved_t)(u64 start, u64 end, unsigned type); | 454 | typedef int (*check_reserved_t)(u64 start, u64 end, unsigned type); |
453 | 455 | ||
454 | static int __init is_mmconf_reserved(check_reserved_t is_reserved, | 456 | static int __ref is_mmconf_reserved(check_reserved_t is_reserved, |
455 | struct pci_mmcfg_region *cfg, int with_e820) | 457 | struct pci_mmcfg_region *cfg, |
458 | struct device *dev, int with_e820) | ||
456 | { | 459 | { |
457 | u64 addr = cfg->res.start; | 460 | u64 addr = cfg->res.start; |
458 | u64 size = resource_size(&cfg->res); | 461 | u64 size = resource_size(&cfg->res); |
459 | u64 old_size = size; | 462 | u64 old_size = size; |
460 | int valid = 0, num_buses; | 463 | int num_buses; |
464 | char *method = with_e820 ? "E820" : "ACPI motherboard resources"; | ||
461 | 465 | ||
462 | while (!is_reserved(addr, addr + size, E820_RESERVED)) { | 466 | while (!is_reserved(addr, addr + size, E820_RESERVED)) { |
463 | size >>= 1; | 467 | size >>= 1; |
@@ -465,49 +469,75 @@ static int __init is_mmconf_reserved(check_reserved_t is_reserved, | |||
465 | break; | 469 | break; |
466 | } | 470 | } |
467 | 471 | ||
468 | if (size >= (16UL<<20) || size == old_size) { | 472 | if (size < (16UL<<20) && size != old_size) |
469 | printk(KERN_INFO PREFIX "MMCONFIG at %pR reserved in %s\n", | 473 | return 0; |
470 | &cfg->res, | 474 | |
471 | with_e820 ? "E820" : "ACPI motherboard resources"); | 475 | if (dev) |
472 | valid = 1; | 476 | dev_info(dev, "MMCONFIG at %pR reserved in %s\n", |
473 | 477 | &cfg->res, method); | |
474 | if (old_size != size) { | 478 | else |
475 | /* update end_bus */ | 479 | printk(KERN_INFO PREFIX |
476 | cfg->end_bus = cfg->start_bus + ((size>>20) - 1); | 480 | "MMCONFIG at %pR reserved in %s\n", |
477 | num_buses = cfg->end_bus - cfg->start_bus + 1; | 481 | &cfg->res, method); |
478 | cfg->res.end = cfg->res.start + | 482 | |
479 | PCI_MMCFG_BUS_OFFSET(num_buses) - 1; | 483 | if (old_size != size) { |
480 | snprintf(cfg->name, PCI_MMCFG_RESOURCE_NAME_LEN, | 484 | /* update end_bus */ |
481 | "PCI MMCONFIG %04x [bus %02x-%02x]", | 485 | cfg->end_bus = cfg->start_bus + ((size>>20) - 1); |
482 | cfg->segment, cfg->start_bus, cfg->end_bus); | 486 | num_buses = cfg->end_bus - cfg->start_bus + 1; |
487 | cfg->res.end = cfg->res.start + | ||
488 | PCI_MMCFG_BUS_OFFSET(num_buses) - 1; | ||
489 | snprintf(cfg->name, PCI_MMCFG_RESOURCE_NAME_LEN, | ||
490 | "PCI MMCONFIG %04x [bus %02x-%02x]", | ||
491 | cfg->segment, cfg->start_bus, cfg->end_bus); | ||
492 | |||
493 | if (dev) | ||
494 | dev_info(dev, | ||
495 | "MMCONFIG " | ||
496 | "at %pR (base %#lx) (size reduced!)\n", | ||
497 | &cfg->res, (unsigned long) cfg->address); | ||
498 | else | ||
483 | printk(KERN_INFO PREFIX | 499 | printk(KERN_INFO PREFIX |
484 | "MMCONFIG for %04x [bus%02x-%02x] " | 500 | "MMCONFIG for %04x [bus%02x-%02x] " |
485 | "at %pR (base %#lx) (size reduced!)\n", | 501 | "at %pR (base %#lx) (size reduced!)\n", |
486 | cfg->segment, cfg->start_bus, cfg->end_bus, | 502 | cfg->segment, cfg->start_bus, cfg->end_bus, |
487 | &cfg->res, (unsigned long) cfg->address); | 503 | &cfg->res, (unsigned long) cfg->address); |
488 | } | ||
489 | } | 504 | } |
490 | 505 | ||
491 | return valid; | 506 | return 1; |
492 | } | 507 | } |
493 | 508 | ||
494 | static int __devinit pci_mmcfg_check_reserved(struct pci_mmcfg_region *cfg, | 509 | static int __ref pci_mmcfg_check_reserved(struct device *dev, |
495 | int early) | 510 | struct pci_mmcfg_region *cfg, int early) |
496 | { | 511 | { |
497 | if (!early && !acpi_disabled) { | 512 | if (!early && !acpi_disabled) { |
498 | if (is_mmconf_reserved(is_acpi_reserved, cfg, 0)) | 513 | if (is_mmconf_reserved(is_acpi_reserved, cfg, dev, 0)) |
499 | return 1; | 514 | return 1; |
515 | |||
516 | if (dev) | ||
517 | dev_info(dev, FW_INFO | ||
518 | "MMCONFIG at %pR not reserved in " | ||
519 | "ACPI motherboard resources\n", | ||
520 | &cfg->res); | ||
500 | else | 521 | else |
501 | printk(KERN_ERR FW_BUG PREFIX | 522 | printk(KERN_INFO FW_INFO PREFIX |
502 | "MMCONFIG at %pR not reserved in " | 523 | "MMCONFIG at %pR not reserved in " |
503 | "ACPI motherboard resources\n", | 524 | "ACPI motherboard resources\n", |
504 | &cfg->res); | 525 | &cfg->res); |
505 | } | 526 | } |
506 | 527 | ||
528 | /* | ||
529 | * e820_all_mapped() is marked as __init. | ||
530 | * All entries from ACPI MCFG table have been checked at boot time. | ||
531 | * For MCFG information constructed from hotpluggable host bridge's | ||
532 | * _CBA method, just assume it's reserved. | ||
533 | */ | ||
534 | if (pci_mmcfg_running_state) | ||
535 | return 1; | ||
536 | |||
507 | /* Don't try to do this check unless configuration | 537 | /* Don't try to do this check unless configuration |
508 | type 1 is available. how about type 2 ?*/ | 538 | type 1 is available. how about type 2 ?*/ |
509 | if (raw_pci_ops) | 539 | if (raw_pci_ops) |
510 | return is_mmconf_reserved(e820_all_mapped, cfg, 1); | 540 | return is_mmconf_reserved(e820_all_mapped, cfg, dev, 1); |
511 | 541 | ||
512 | return 0; | 542 | return 0; |
513 | } | 543 | } |
@@ -517,7 +547,7 @@ static void __init pci_mmcfg_reject_broken(int early) | |||
517 | struct pci_mmcfg_region *cfg; | 547 | struct pci_mmcfg_region *cfg; |
518 | 548 | ||
519 | list_for_each_entry(cfg, &pci_mmcfg_list, list) { | 549 | list_for_each_entry(cfg, &pci_mmcfg_list, list) { |
520 | if (pci_mmcfg_check_reserved(cfg, early) == 0) { | 550 | if (pci_mmcfg_check_reserved(NULL, cfg, early) == 0) { |
521 | printk(KERN_INFO PREFIX "not using MMCONFIG\n"); | 551 | printk(KERN_INFO PREFIX "not using MMCONFIG\n"); |
522 | free_all_mmcfg(); | 552 | free_all_mmcfg(); |
523 | return; | 553 | return; |
@@ -656,6 +686,8 @@ void __init pci_mmcfg_late_init(void) | |||
656 | 686 | ||
657 | static int __init pci_mmcfg_late_insert_resources(void) | 687 | static int __init pci_mmcfg_late_insert_resources(void) |
658 | { | 688 | { |
689 | pci_mmcfg_running_state = true; | ||
690 | |||
659 | /* | 691 | /* |
660 | * If resources are already inserted or we are not using MMCONFIG, | 692 | * If resources are already inserted or we are not using MMCONFIG, |
661 | * don't insert the resources. | 693 | * don't insert the resources. |