aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug/acpiphp_glue.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/hotplug/acpiphp_glue.c')
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c99
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 */
119static 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, &reg32))
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 */
119static acpi_status 148static acpi_status
120register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) 149register_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 */
385static void add_host_bridge(acpi_handle *handle) 406static 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 */
471static int add_bridge(acpi_handle handle) 492static 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
591static void remove_bridge(acpi_handle handle) 613static 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
872static 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 */
884static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot) 896static 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 */
1486static 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