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 = { .handler = handle_hotplug_event_func, }; +/* Check whether the PCI device is managed by native PCIe hotplug driver */ +static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev) +{ + u32 reg32; + acpi_handle tmp; + struct acpi_pci_root *root; + + /* Check whether the PCIe port supports native PCIe hotplug */ + if (pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, ®32)) + return false; + if (!(reg32 & PCI_EXP_SLTCAP_HPC)) + return false; + + /* + * Check whether native PCIe hotplug has been enabled for + * this PCIe hierarchy. + */ + tmp = acpi_find_root_bridge_handle(pdev); + if (!tmp) + return false; + root = acpi_pci_find_root(tmp); + if (!root) + return false; + if (!(root->osc_control_set & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL)) + return false; + + return true; +} + /* callback routine to register each ACPI PCI slot object */ static acpi_status 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) function = adr & 0xffff; pdev = pbus->self; - if (pdev && pci_is_pcie(pdev)) { - tmp = acpi_find_root_bridge_handle(pdev); - if (tmp) { - struct acpi_pci_root *root = acpi_pci_find_root(tmp); - - if (root && (root->osc_control_set & - OSC_PCI_EXPRESS_NATIVE_HP_CONTROL)) - return AE_OK; - } - } + if (pdev && device_is_managed_by_native_pciehp(pdev)) + return AE_OK; newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL); if (!newfunc) @@ -382,10 +403,10 @@ static inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge) /* allocate and initialize host bridge data structure */ -static void add_host_bridge(acpi_handle *handle) +static void add_host_bridge(struct acpi_pci_root *root) { struct acpiphp_bridge *bridge; - struct acpi_pci_root *root = acpi_pci_find_root(handle); + acpi_handle handle = root->device->handle; bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); if (bridge == NULL) @@ -468,11 +489,12 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) /* find hot-pluggable slots, and then find P2P bridge */ -static int add_bridge(acpi_handle handle) +static int add_bridge(struct acpi_pci_root *root) { acpi_status status; unsigned long long tmp; acpi_handle dummy_handle; + acpi_handle handle = root->device->handle; /* if the bridge doesn't have _STA, we assume it is always there */ status = acpi_get_handle(handle, "_STA", &dummy_handle); @@ -490,7 +512,7 @@ static int add_bridge(acpi_handle handle) /* check if this bridge has ejectable slots */ if (detect_ejectable_slots(handle) > 0) { dbg("found PCI host-bus bridge with hot-pluggable slots\n"); - add_host_bridge(handle); + add_host_bridge(root); } /* search P2P bridges under this host bridge */ @@ -588,9 +610,10 @@ cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) return AE_OK; } -static void remove_bridge(acpi_handle handle) +static void remove_bridge(struct acpi_pci_root *root) { struct acpiphp_bridge *bridge; + acpi_handle handle = root->device->handle; /* cleanup p2p bridges under this host bridge in a depth-first manner */ @@ -869,17 +892,6 @@ static int __ref enable_device(struct acpiphp_slot *slot) return retval; } -static void disable_bridges(struct pci_bus *bus) -{ - struct pci_dev *dev; - list_for_each_entry(dev, &bus->devices, bus_list) { - if (dev->subordinate) { - disable_bridges(dev->subordinate); - pci_disable_device(dev); - } - } -} - /* return first device in slot, acquiring a reference on it */ static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot) { @@ -931,12 +943,7 @@ static int disable_device(struct acpiphp_slot *slot) * here. */ while ((pdev = dev_in_slot(slot))) { - pci_stop_bus_device(pdev); - if (pdev->subordinate) { - disable_bridges(pdev->subordinate); - pci_disable_device(pdev); - } - __pci_remove_bus_device(pdev); + pci_stop_and_remove_bus_device(pdev); pci_dev_put(pdev); } @@ -1477,34 +1484,6 @@ int __init acpiphp_get_num_slots(void) } -#if 0 -/** - * acpiphp_for_each_slot - call function for each slot - * @fn: callback function - * @data: context to be passed to callback function - */ -static int acpiphp_for_each_slot(acpiphp_callback fn, void *data) -{ - struct list_head *node; - struct acpiphp_bridge *bridge; - struct acpiphp_slot *slot; - int retval = 0; - - list_for_each (node, &bridge_list) { - bridge = (struct acpiphp_bridge *)node; - for (slot = bridge->slots; slot; slot = slot->next) { - retval = fn(slot, data); - if (!retval) - goto err_exit; - } - } - - err_exit: - return retval; -} -#endif - - /** * acpiphp_enable_slot - power on slot * @slot: ACPI PHP slot |