diff options
Diffstat (limited to 'drivers/pci/hotplug/acpiphp_glue.c')
| -rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 99 |
1 files changed, 39 insertions, 60 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index ad6fd6695495..3d6d4fd1e3c5 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
| @@ -115,6 +115,35 @@ static const struct acpi_dock_ops acpiphp_dock_ops = { | |||
| 115 | .handler = handle_hotplug_event_func, | 115 | .handler = handle_hotplug_event_func, |
| 116 | }; | 116 | }; |
| 117 | 117 | ||
| 118 | /* Check whether the PCI device is managed by native PCIe hotplug driver */ | ||
| 119 | static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev) | ||
| 120 | { | ||
| 121 | u32 reg32; | ||
| 122 | acpi_handle tmp; | ||
| 123 | struct acpi_pci_root *root; | ||
| 124 | |||
| 125 | /* Check whether the PCIe port supports native PCIe hotplug */ | ||
| 126 | if (pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, ®32)) | ||
| 127 | return false; | ||
| 128 | if (!(reg32 & PCI_EXP_SLTCAP_HPC)) | ||
| 129 | return false; | ||
| 130 | |||
| 131 | /* | ||
| 132 | * Check whether native PCIe hotplug has been enabled for | ||
| 133 | * this PCIe hierarchy. | ||
| 134 | */ | ||
| 135 | tmp = acpi_find_root_bridge_handle(pdev); | ||
| 136 | if (!tmp) | ||
| 137 | return false; | ||
| 138 | root = acpi_pci_find_root(tmp); | ||
| 139 | if (!root) | ||
| 140 | return false; | ||
| 141 | if (!(root->osc_control_set & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL)) | ||
| 142 | return false; | ||
| 143 | |||
| 144 | return true; | ||
| 145 | } | ||
| 146 | |||
| 118 | /* callback routine to register each ACPI PCI slot object */ | 147 | /* callback routine to register each ACPI PCI slot object */ |
| 119 | static acpi_status | 148 | static acpi_status |
| 120 | register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | 149 | register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) |
| @@ -142,16 +171,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
| 142 | function = adr & 0xffff; | 171 | function = adr & 0xffff; |
| 143 | 172 | ||
| 144 | pdev = pbus->self; | 173 | pdev = pbus->self; |
| 145 | if (pdev && pci_is_pcie(pdev)) { | 174 | if (pdev && device_is_managed_by_native_pciehp(pdev)) |
| 146 | tmp = acpi_find_root_bridge_handle(pdev); | 175 | return AE_OK; |
| 147 | if (tmp) { | ||
| 148 | struct acpi_pci_root *root = acpi_pci_find_root(tmp); | ||
| 149 | |||
| 150 | if (root && (root->osc_control_set & | ||
| 151 | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL)) | ||
| 152 | return AE_OK; | ||
| 153 | } | ||
| 154 | } | ||
| 155 | 176 | ||
| 156 | newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL); | 177 | newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL); |
| 157 | if (!newfunc) | 178 | if (!newfunc) |
| @@ -382,10 +403,10 @@ static inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge) | |||
| 382 | 403 | ||
| 383 | 404 | ||
| 384 | /* allocate and initialize host bridge data structure */ | 405 | /* allocate and initialize host bridge data structure */ |
| 385 | static void add_host_bridge(acpi_handle *handle) | 406 | static void add_host_bridge(struct acpi_pci_root *root) |
| 386 | { | 407 | { |
| 387 | struct acpiphp_bridge *bridge; | 408 | struct acpiphp_bridge *bridge; |
| 388 | struct acpi_pci_root *root = acpi_pci_find_root(handle); | 409 | acpi_handle handle = root->device->handle; |
| 389 | 410 | ||
| 390 | bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); | 411 | bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); |
| 391 | if (bridge == NULL) | 412 | if (bridge == NULL) |
| @@ -468,11 +489,12 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
| 468 | 489 | ||
| 469 | 490 | ||
| 470 | /* find hot-pluggable slots, and then find P2P bridge */ | 491 | /* find hot-pluggable slots, and then find P2P bridge */ |
| 471 | static int add_bridge(acpi_handle handle) | 492 | static int add_bridge(struct acpi_pci_root *root) |
| 472 | { | 493 | { |
| 473 | acpi_status status; | 494 | acpi_status status; |
| 474 | unsigned long long tmp; | 495 | unsigned long long tmp; |
| 475 | acpi_handle dummy_handle; | 496 | acpi_handle dummy_handle; |
| 497 | acpi_handle handle = root->device->handle; | ||
| 476 | 498 | ||
| 477 | /* if the bridge doesn't have _STA, we assume it is always there */ | 499 | /* if the bridge doesn't have _STA, we assume it is always there */ |
| 478 | status = acpi_get_handle(handle, "_STA", &dummy_handle); | 500 | status = acpi_get_handle(handle, "_STA", &dummy_handle); |
| @@ -490,7 +512,7 @@ static int add_bridge(acpi_handle handle) | |||
| 490 | /* check if this bridge has ejectable slots */ | 512 | /* check if this bridge has ejectable slots */ |
| 491 | if (detect_ejectable_slots(handle) > 0) { | 513 | if (detect_ejectable_slots(handle) > 0) { |
| 492 | dbg("found PCI host-bus bridge with hot-pluggable slots\n"); | 514 | dbg("found PCI host-bus bridge with hot-pluggable slots\n"); |
| 493 | add_host_bridge(handle); | 515 | add_host_bridge(root); |
| 494 | } | 516 | } |
| 495 | 517 | ||
| 496 | /* search P2P bridges under this host bridge */ | 518 | /* search P2P bridges under this host bridge */ |
| @@ -588,9 +610,10 @@ cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
| 588 | return AE_OK; | 610 | return AE_OK; |
| 589 | } | 611 | } |
| 590 | 612 | ||
| 591 | static void remove_bridge(acpi_handle handle) | 613 | static void remove_bridge(struct acpi_pci_root *root) |
| 592 | { | 614 | { |
| 593 | struct acpiphp_bridge *bridge; | 615 | struct acpiphp_bridge *bridge; |
| 616 | acpi_handle handle = root->device->handle; | ||
| 594 | 617 | ||
| 595 | /* cleanup p2p bridges under this host bridge | 618 | /* cleanup p2p bridges under this host bridge |
| 596 | in a depth-first manner */ | 619 | in a depth-first manner */ |
| @@ -869,17 +892,6 @@ static int __ref enable_device(struct acpiphp_slot *slot) | |||
| 869 | return retval; | 892 | return retval; |
| 870 | } | 893 | } |
| 871 | 894 | ||
| 872 | static void disable_bridges(struct pci_bus *bus) | ||
| 873 | { | ||
| 874 | struct pci_dev *dev; | ||
| 875 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
| 876 | if (dev->subordinate) { | ||
| 877 | disable_bridges(dev->subordinate); | ||
| 878 | pci_disable_device(dev); | ||
| 879 | } | ||
| 880 | } | ||
| 881 | } | ||
| 882 | |||
| 883 | /* return first device in slot, acquiring a reference on it */ | 895 | /* return first device in slot, acquiring a reference on it */ |
| 884 | static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot) | 896 | static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot) |
| 885 | { | 897 | { |
| @@ -931,12 +943,7 @@ static int disable_device(struct acpiphp_slot *slot) | |||
| 931 | * here. | 943 | * here. |
| 932 | */ | 944 | */ |
| 933 | while ((pdev = dev_in_slot(slot))) { | 945 | while ((pdev = dev_in_slot(slot))) { |
| 934 | pci_stop_bus_device(pdev); | 946 | pci_stop_and_remove_bus_device(pdev); |
| 935 | if (pdev->subordinate) { | ||
| 936 | disable_bridges(pdev->subordinate); | ||
| 937 | pci_disable_device(pdev); | ||
| 938 | } | ||
| 939 | __pci_remove_bus_device(pdev); | ||
| 940 | pci_dev_put(pdev); | 947 | pci_dev_put(pdev); |
| 941 | } | 948 | } |
| 942 | 949 | ||
| @@ -1477,34 +1484,6 @@ int __init acpiphp_get_num_slots(void) | |||
| 1477 | } | 1484 | } |
| 1478 | 1485 | ||
| 1479 | 1486 | ||
| 1480 | #if 0 | ||
| 1481 | /** | ||
| 1482 | * acpiphp_for_each_slot - call function for each slot | ||
| 1483 | * @fn: callback function | ||
| 1484 | * @data: context to be passed to callback function | ||
| 1485 | */ | ||
| 1486 | static int acpiphp_for_each_slot(acpiphp_callback fn, void *data) | ||
| 1487 | { | ||
| 1488 | struct list_head *node; | ||
| 1489 | struct acpiphp_bridge *bridge; | ||
| 1490 | struct acpiphp_slot *slot; | ||
| 1491 | int retval = 0; | ||
| 1492 | |||
| 1493 | list_for_each (node, &bridge_list) { | ||
| 1494 | bridge = (struct acpiphp_bridge *)node; | ||
| 1495 | for (slot = bridge->slots; slot; slot = slot->next) { | ||
| 1496 | retval = fn(slot, data); | ||
| 1497 | if (!retval) | ||
| 1498 | goto err_exit; | ||
| 1499 | } | ||
| 1500 | } | ||
| 1501 | |||
| 1502 | err_exit: | ||
| 1503 | return retval; | ||
| 1504 | } | ||
| 1505 | #endif | ||
| 1506 | |||
| 1507 | |||
| 1508 | /** | 1487 | /** |
| 1509 | * acpiphp_enable_slot - power on slot | 1488 | * acpiphp_enable_slot - power on slot |
| 1510 | * @slot: ACPI PHP slot | 1489 | * @slot: ACPI PHP slot |
