diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index e17ef54f0efc..c62ab8d240aa 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c @@ -501,5 +501,74 @@ int acpi_root_bridge(acpi_handle handle) } EXPORT_SYMBOL_GPL(acpi_root_bridge); + +static int is_ejectable(acpi_handle handle) +{ + acpi_status status; + acpi_handle tmp; + unsigned long long removable; + status = acpi_get_handle(handle, "_ADR", &tmp); + if (ACPI_FAILURE(status)) + return 0; + status = acpi_get_handle(handle, "_EJ0", &tmp); + if (ACPI_SUCCESS(status)) + return 1; + status = acpi_evaluate_integer(handle, "_RMV", NULL, &removable); + if (ACPI_SUCCESS(status) && removable) + return 1; + return 0; +} + +/** + * acpi_pcihp_check_ejectable - check if handle is ejectable ACPI PCI slot + * @pbus: the PCI bus of the PCI slot corresponding to 'handle' + * @handle: ACPI handle to check + * + * Return 1 if handle is ejectable PCI slot, 0 otherwise. + */ +int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle) +{ + acpi_handle bridge_handle, parent_handle; + + if (!(bridge_handle = acpi_pci_get_bridge_handle(pbus))) + return 0; + if ((ACPI_FAILURE(acpi_get_parent(handle, &parent_handle)))) + return 0; + if (bridge_handle != parent_handle) + return 0; + return is_ejectable(handle); +} +EXPORT_SYMBOL_GPL(acpi_pci_check_ejectable); + +static acpi_status +check_hotplug(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + int *found = (int *)context; + if (is_ejectable(handle)) { + *found = 1; + return AE_CTRL_TERMINATE; + } + return AE_OK; +} + +/** + * acpi_pci_detect_ejectable - check if the PCI bus has ejectable slots + * @pbus - PCI bus to scan + * + * Returns 1 if the PCI bus has ACPI based ejectable slots, 0 otherwise. + */ +int acpi_pci_detect_ejectable(struct pci_bus *pbus) +{ + acpi_handle handle; + int found = 0; + + if (!(handle = acpi_pci_get_bridge_handle(pbus))) + return 0; + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, + check_hotplug, (void *)&found, NULL); + return found; +} +EXPORT_SYMBOL_GPL(acpi_pci_detect_ejectable); + module_param(debug_acpi, bool, 0644); MODULE_PARM_DESC(debug_acpi, "Debugging mode for ACPI enabled or not"); diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 7a5760426897..f09b1010d477 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include "../pci.h" @@ -62,68 +63,6 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus); static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus); static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context); - -/* - * initialization & terminatation routines - */ - -/** - * is_ejectable - determine if a slot is ejectable - * @handle: handle to acpi namespace - * - * Ejectable slot should satisfy at least these conditions: - * - * 1. has _ADR method - * 2. has _EJ0 method or _RMV method - * - * optionally - * - * 1. has _STA method - * 2. has _PS0 method - * 3. has _PS3 method - * 4. .. - */ -static int is_ejectable(acpi_handle handle) -{ - acpi_status status; - acpi_handle tmp; - unsigned long long removable; - - status = acpi_get_handle(handle, "_ADR", &tmp); - if (ACPI_FAILURE(status)) - return 0; - - status = acpi_get_handle(handle, "_EJ0", &tmp); - if (ACPI_SUCCESS(status)) - return 1; - - status = acpi_get_handle(handle, "_RMV", &tmp); - if (ACPI_SUCCESS(status)) { - status = acpi_evaluate_integer(handle, "_RMV", NULL, - &removable); - if (ACPI_SUCCESS(status) && removable) - return 1; - } - - return 0; -} - - -/* callback routine to check for the existence of ejectable slots */ -static acpi_status -is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - int *count = (int *)context; - - if (is_ejectable(handle)) { - (*count)++; - /* only one ejectable slot is enough */ - return AE_CTRL_TERMINATE; - } else { - return AE_OK; - } -} - /* callback routine to check for the existence of a pci dock device */ static acpi_status is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) @@ -138,9 +77,6 @@ is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) } } - - - /* * the _DCK method can do funny things... and sometimes not * hah-hah funny. @@ -191,8 +127,9 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) acpi_status status = AE_OK; unsigned long long adr, sun; int device, function, retval; + struct pci_bus *pbus = bridge->pci_bus; - if (!is_ejectable(handle) && !is_dock_device(handle)) + if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle)) return AE_OK; acpi_evaluate_integer(handle, "_ADR", NULL, &adr); @@ -258,8 +195,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) bridge->nr_slots++; dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", - slot->sun, pci_domain_nr(bridge->pci_bus), - bridge->pci_bus->number, slot->device); + slot->sun, pci_domain_nr(pbus), pbus->number, device); retval = acpiphp_register_hotplug_slot(slot); if (retval) { if (retval == -EBUSY) @@ -276,8 +212,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) list_add_tail(&newfunc->sibling, &slot->funcs); /* associate corresponding pci_dev */ - newfunc->pci_dev = pci_get_slot(bridge->pci_bus, - PCI_DEVFN(device, function)); + newfunc->pci_dev = pci_get_slot(pbus, PCI_DEVFN(device, function)); if (newfunc->pci_dev) { slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); } @@ -326,27 +261,15 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) /* see if it's worth looking at this bridge */ -static int detect_ejectable_slots(acpi_handle *bridge_handle) +static int detect_ejectable_slots(struct pci_bus *pbus) { - acpi_status status; - int count; - - count = 0; - - /* only check slots defined directly below bridge object */ - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1, - is_ejectable_slot, (void *)&count, NULL); - - /* - * we also need to add this bridge if there is a dock bridge or - * other pci device on a dock station (removable) - */ - if (!count) - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, - (u32)1, is_pci_dock_device, (void *)&count, - NULL); - - return count; + int found = acpi_pci_detect_ejectable(pbus); + if (!found) { + acpi_handle bridge_handle = acpi_pci_get_bridge_handle(pbus); + acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1, + is_pci_dock_device, (void *)&found, NULL); + } + return found; } @@ -556,7 +479,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) goto out; /* check if this bridge has ejectable slots */ - if ((detect_ejectable_slots(handle) > 0)) { + if ((detect_ejectable_slots(dev->subordinate) > 0)) { dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); add_p2p_bridge(handle, dev); } @@ -617,7 +540,7 @@ static int add_bridge(acpi_handle handle) } /* check if this bridge has ejectable slots */ - if (detect_ejectable_slots(handle) > 0) { + if (detect_ejectable_slots(pci_bus) > 0) { dbg("found PCI host-bus bridge with hot-pluggable slots\n"); add_host_bridge(handle, pci_bus); } diff --git a/drivers/pci/hotplug/pciehp_acpi.c b/drivers/pci/hotplug/pciehp_acpi.c index 88a5c57f2e5b..438d795f9fe3 100644 --- a/drivers/pci/hotplug/pciehp_acpi.c +++ b/drivers/pci/hotplug/pciehp_acpi.c @@ -24,6 +24,8 @@ */ #include +#include +#include #include "pciehp.h" #define PCIEHP_DETECT_PCIE (0) @@ -41,59 +43,11 @@ MODULE_PARM_DESC(pciehp_detect_mode, " auto(default) - Auto select mode. Use acpi option if duplicate\n" " slot ids are found. Otherwise, use pcie option\n"); -static int is_ejectable(acpi_handle handle) -{ - acpi_status status; - acpi_handle tmp; - unsigned long long removable; - status = acpi_get_handle(handle, "_ADR", &tmp); - if (ACPI_FAILURE(status)) - return 0; - status = acpi_get_handle(handle, "_EJ0", &tmp); - if (ACPI_SUCCESS(status)) - return 1; - status = acpi_evaluate_integer(handle, "_RMV", NULL, &removable); - if (ACPI_SUCCESS(status) && removable) - return 1; - return 0; -} - -static acpi_status -check_hotplug(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - int *found = (int *)context; - if (is_ejectable(handle)) { - *found = 1; - return AE_CTRL_TERMINATE; - } - return AE_OK; -} - -static int pciehp_detect_acpi_slot(struct pci_bus *pbus) -{ - acpi_handle handle; - struct pci_dev *pdev = pbus->self; - int found = 0; - - if (!pdev){ - int seg = pci_domain_nr(pbus), busnr = pbus->number; - handle = acpi_get_pci_rootbridge_handle(seg, busnr); - } else - handle = DEVICE_ACPI_HANDLE(&(pdev->dev)); - - if (!handle) - return 0; - - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, - check_hotplug, (void *)&found, NULL); - return found; -} - int pciehp_acpi_slot_detection_check(struct pci_dev *dev) { if (slot_detection_mode != PCIEHP_DETECT_ACPI) return 0; - if (pciehp_detect_acpi_slot(dev->subordinate)) + if (acpi_pci_detect_ejectable(dev->subordinate)) return 0; return -ENODEV; } @@ -135,6 +89,7 @@ static int __init dummy_probe(struct pcie_device *dev, u32 slot_cap; struct slot *slot, *tmp; struct pci_dev *pdev = dev->port; + struct pci_bus *pbus = pdev->subordinate; if (!(slot = kzalloc(sizeof(*slot), GFP_KERNEL))) return -ENOMEM; /* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */ @@ -149,7 +104,7 @@ static int __init dummy_probe(struct pcie_device *dev, dup_slot_id++; } list_add_tail(&slot->slot_list, &dummy_slots); - if (!acpi_slot_detected && pciehp_detect_acpi_slot(pdev->subordinate)) + if (!acpi_slot_detected && acpi_pci_detect_ejectable(pbus)) acpi_slot_detected = 1; return -ENODEV; /* dummy driver always returns error */ } diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h index 871e096e0fbc..042c166f65d5 100644 --- a/include/linux/pci-acpi.h +++ b/include/linux/pci-acpi.h @@ -60,6 +60,15 @@ static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev) return acpi_get_pci_rootbridge_handle(pci_domain_nr(pdev->bus), pdev->bus->number); } + +static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus) +{ + int seg = pci_domain_nr(pbus), busnr = pbus->number; + struct pci_dev *bridge = pbus->self; + if (bridge) + return DEVICE_ACPI_HANDLE(&(bridge->dev)); + return acpi_get_pci_rootbridge_handle(seg, busnr); +} #else #if !defined(AE_ERROR) typedef u32 acpi_status; diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index a00bd1a0f156..f7cc204fab07 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h @@ -228,6 +228,8 @@ extern acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus, struct hotplug_params *hpp); int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags); int acpi_root_bridge(acpi_handle handle); +int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle); +int acpi_pci_detect_ejectable(struct pci_bus *pbus); #endif #endif