]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/pci/hotplug/acpiphp_glue.c
Merge branch 'acpi-processor'
[karo-tx-linux.git] / drivers / pci / hotplug / acpiphp_glue.c
index bbbf8f4e84827032d28e140613081e036abe5aa3..8054ddcdaed0a195f02e83d19513c61b8b284368 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
 #include <linux/pci-acpi.h>
+#include <linux/pm_runtime.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/acpi.h>
@@ -165,7 +166,7 @@ static void free_bridge(struct kref *kref)
        /* Root bridges will not have hotplug context. */
        if (context) {
                /* Release the reference taken by acpiphp_enumerate_slots(). */
-               put_bridge(context->func.slot->bridge);
+               put_bridge(context->func.parent);
                context->bridge = NULL;
                acpiphp_put_context(context);
        }
@@ -187,7 +188,7 @@ static void free_bridge(struct kref *kref)
 static void post_dock_fixups(acpi_handle not_used, u32 event, void *data)
 {
        struct acpiphp_context *context = data;
-       struct pci_bus *bus = context->func.slot->bridge->pci_bus;
+       struct pci_bus *bus = context->func.slot->bus;
        u32 buses;
 
        if (!bus->self)
@@ -248,14 +249,14 @@ static void acpiphp_dock_init(void *data)
 {
        struct acpiphp_context *context = data;
 
-       get_bridge(context->func.slot->bridge);
+       get_bridge(context->func.parent);
 }
 
 static void acpiphp_dock_release(void *data)
 {
        struct acpiphp_context *context = data;
 
-       put_bridge(context->func.slot->bridge);
+       put_bridge(context->func.parent);
 }
 
 /* callback routine to register each ACPI PCI slot object */
@@ -294,6 +295,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
        }
        newfunc = &context->func;
        newfunc->function = function;
+       newfunc->parent = bridge;
        mutex_unlock(&acpiphp_context_lock);
 
        if (acpi_has_method(handle, "_EJ0"))
@@ -302,12 +304,6 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
        if (acpi_has_method(handle, "_STA"))
                newfunc->flags |= FUNC_HAS_STA;
 
-       if (acpi_has_method(handle, "_PS0"))
-               newfunc->flags |= FUNC_HAS_PS0;
-
-       if (acpi_has_method(handle, "_PS3"))
-               newfunc->flags |= FUNC_HAS_PS3;
-
        if (acpi_has_method(handle, "_DCK"))
                newfunc->flags |= FUNC_HAS_DCK;
 
@@ -322,14 +318,12 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
                goto err;
        }
 
-       slot->bridge = bridge;
+       slot->bus = bridge->pci_bus;
        slot->device = device;
        INIT_LIST_HEAD(&slot->funcs);
        mutex_init(&slot->crit_sect);
 
-       mutex_lock(&bridge_mutex);
        list_add_tail(&slot->node, &bridge->slots);
-       mutex_unlock(&bridge_mutex);
 
        /* Register slots for ejectable funtions only. */
        if (acpi_pci_check_ejectable(pbus, handle)  || is_dock_device(handle)) {
@@ -346,6 +340,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
 
                retval = acpiphp_register_hotplug_slot(slot, sun);
                if (retval) {
+                       slot->slot = NULL;
                        bridge->nr_slots--;
                        if (retval == -EBUSY)
                                warn("Slot %llu already registered by another "
@@ -359,13 +354,11 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
 
  slot_found:
        newfunc->slot = slot;
-       mutex_lock(&bridge_mutex);
        list_add_tail(&newfunc->sibling, &slot->funcs);
-       mutex_unlock(&bridge_mutex);
 
        if (pci_bus_read_dev_vendor_id(pbus, PCI_DEVFN(device, function),
                                       &val, 60*1000))
-               slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
+               slot->flags |= SLOT_ENABLED;
 
        if (is_dock_device(handle)) {
                /* we don't want to call this device's _EJ0
@@ -437,7 +430,8 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
                                        err("failed to remove notify handler\n");
                        }
                }
-               acpiphp_unregister_hotplug_slot(slot);
+               if (slot->slot)
+                       acpiphp_unregister_hotplug_slot(slot);
        }
 
        mutex_lock(&bridge_mutex);
@@ -445,73 +439,6 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
        mutex_unlock(&bridge_mutex);
 }
 
-static int power_on_slot(struct acpiphp_slot *slot)
-{
-       acpi_status status;
-       struct acpiphp_func *func;
-       int retval = 0;
-
-       /* if already enabled, just skip */
-       if (slot->flags & SLOT_POWEREDON)
-               goto err_exit;
-
-       list_for_each_entry(func, &slot->funcs, sibling) {
-               if (func->flags & FUNC_HAS_PS0) {
-                       dbg("%s: executing _PS0\n", __func__);
-                       status = acpi_evaluate_object(func_to_handle(func),
-                                                     "_PS0", NULL, NULL);
-                       if (ACPI_FAILURE(status)) {
-                               warn("%s: _PS0 failed\n", __func__);
-                               retval = -1;
-                               goto err_exit;
-                       } else
-                               break;
-               }
-       }
-
-       /* TBD: evaluate _STA to check if the slot is enabled */
-
-       slot->flags |= SLOT_POWEREDON;
-
- err_exit:
-       return retval;
-}
-
-
-static int power_off_slot(struct acpiphp_slot *slot)
-{
-       acpi_status status;
-       struct acpiphp_func *func;
-
-       int retval = 0;
-
-       /* if already disabled, just skip */
-       if ((slot->flags & SLOT_POWEREDON) == 0)
-               goto err_exit;
-
-       list_for_each_entry(func, &slot->funcs, sibling) {
-               if (func->flags & FUNC_HAS_PS3) {
-                       status = acpi_evaluate_object(func_to_handle(func),
-                                                     "_PS3", NULL, NULL);
-                       if (ACPI_FAILURE(status)) {
-                               warn("%s: _PS3 failed\n", __func__);
-                               retval = -1;
-                               goto err_exit;
-                       } else
-                               break;
-               }
-       }
-
-       /* TBD: evaluate _STA to check if the slot is disabled */
-
-       slot->flags &= (~SLOT_POWEREDON);
-
- err_exit:
-       return retval;
-}
-
-
-
 /**
  * acpiphp_max_busnr - return the highest reserved bus number under the given bus.
  * @bus: bus to start search with
@@ -539,53 +466,32 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
        return max;
 }
 
-
 /**
- * acpiphp_bus_add - add a new bus to acpi subsystem
- * @func: acpiphp_func of the bridge
+ * acpiphp_bus_trim - Trim device objects in an ACPI namespace subtree.
+ * @handle: ACPI device object handle to start from.
  */
-static int acpiphp_bus_add(struct acpiphp_func *func)
+static void acpiphp_bus_trim(acpi_handle handle)
 {
-       acpi_handle handle = func_to_handle(func);
-       struct acpi_device *device;
-       int ret_val;
-
-       if (!acpi_bus_get_device(handle, &device)) {
-               dbg("bus exists... trim\n");
-               /* this shouldn't be in here, so remove
-                * the bus then re-add it...
-                */
-               acpi_bus_trim(device);
-       }
-
-       ret_val = acpi_bus_scan(handle);
-       if (!ret_val)
-               ret_val = acpi_bus_get_device(handle, &device);
+       struct acpi_device *adev = NULL;
 
-       if (ret_val)
-               dbg("error adding bus, %x\n", -ret_val);
-
-       return ret_val;
+       acpi_bus_get_device(handle, &adev);
+       if (adev)
+               acpi_bus_trim(adev);
 }
 
-
 /**
- * acpiphp_bus_trim - trim a bus from acpi subsystem
- * @handle: handle to acpi namespace
+ * acpiphp_bus_add - Scan ACPI namespace subtree.
+ * @handle: ACPI object handle to start the scan from.
  */
-static int acpiphp_bus_trim(acpi_handle handle)
+static void acpiphp_bus_add(acpi_handle handle)
 {
-       struct acpi_device *device;
-       int retval;
+       struct acpi_device *adev = NULL;
 
-       retval = acpi_bus_get_device(handle, &device);
-       if (retval) {
-               dbg("acpi_device not found\n");
-               return retval;
-       }
-
-       acpi_bus_trim(device);
-       return 0;
+       acpiphp_bus_trim(handle);
+       acpi_bus_scan(handle);
+       acpi_bus_get_device(handle, &adev);
+       if (adev)
+               acpi_device_set_power(adev, ACPI_STATE_D0);
 }
 
 static void acpiphp_set_acpi_region(struct acpiphp_slot *slot)
@@ -611,16 +517,10 @@ static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev)
 {
        struct acpiphp_func *func;
 
-       if (!dev->subordinate)
-               return;
-
        /* quirk, or pcie could set it already */
        if (dev->is_hotplug_bridge)
                return;
 
-       if (PCI_SLOT(dev->devfn) != slot->device)
-               return;
-
        list_for_each_entry(func, &slot->funcs, sibling) {
                if (PCI_FUNC(dev->devfn) == func->function) {
                        dev->is_hotplug_bridge = 1;
@@ -630,38 +530,31 @@ static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev)
 }
 
 /**
- * enable_device - enable, configure a slot
+ * enable_slot - enable, configure a slot
  * @slot: slot to be enabled
  *
  * This function should be called per *physical slot*,
  * not per each slot object in ACPI namespace.
  */
-static int __ref enable_device(struct acpiphp_slot *slot)
+static void __ref enable_slot(struct acpiphp_slot *slot)
 {
        struct pci_dev *dev;
-       struct pci_bus *bus = slot->bridge->pci_bus;
+       struct pci_bus *bus = slot->bus;
        struct acpiphp_func *func;
-       int num, max, pass;
+       int max, pass;
        LIST_HEAD(add_list);
 
-       if (slot->flags & SLOT_ENABLED)
-               goto err_exit;
-
        list_for_each_entry(func, &slot->funcs, sibling)
-               acpiphp_bus_add(func);
+               acpiphp_bus_add(func_to_handle(func));
 
-       num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
-       if (num == 0) {
-               /* Maybe only part of funcs are added. */
-               dbg("No new device found\n");
-               goto err_exit;
-       }
+       pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
 
        max = acpiphp_max_busnr(bus);
        for (pass = 0; pass < 2; pass++) {
                list_for_each_entry(dev, &bus->devices, bus_list) {
                        if (PCI_SLOT(dev->devfn) != slot->device)
                                continue;
+
                        if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
                            dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
                                max = pci_scan_bridge(bus, dev, max, pass);
@@ -700,16 +593,12 @@ static int __ref enable_device(struct acpiphp_slot *slot)
                        continue;
                }
        }
-
-
- err_exit:
-       return 0;
 }
 
 /* return first device in slot, acquiring a reference on it */
 static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot)
 {
-       struct pci_bus *bus = slot->bridge->pci_bus;
+       struct pci_bus *bus = slot->bus;
        struct pci_dev *dev;
        struct pci_dev *ret = NULL;
 
@@ -725,16 +614,16 @@ static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot)
 }
 
 /**
- * disable_device - disable a slot
+ * disable_slot - disable a slot
  * @slot: ACPI PHP slot
  */
-static int disable_device(struct acpiphp_slot *slot)
+static void disable_slot(struct acpiphp_slot *slot)
 {
        struct acpiphp_func *func;
        struct pci_dev *pdev;
 
        /*
-        * enable_device() enumerates all functions in this device via
+        * enable_slot() enumerates all functions in this device via
         * pci_scan_slot(), whether they have associated ACPI hotplug
         * methods (_EJ0, etc.) or not.  Therefore, we remove all functions
         * here.
@@ -748,8 +637,6 @@ static int disable_device(struct acpiphp_slot *slot)
                acpiphp_bus_trim(func_to_handle(func));
 
        slot->flags &= (~SLOT_ENABLED);
-
-       return 0;
 }
 
 
@@ -781,7 +668,7 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot)
                } else {
                        u32 dvid;
 
-                       pci_bus_read_config_dword(slot->bridge->pci_bus,
+                       pci_bus_read_config_dword(slot->bus,
                                                  PCI_DEVFN(slot->device,
                                                            func->function),
                                                  PCI_VENDOR_ID, &dvid);
@@ -796,24 +683,42 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot)
 }
 
 /**
- * acpiphp_eject_slot - physically eject the slot
- * @slot: ACPI PHP slot
+ * trim_stale_devices - remove PCI devices that are not responding.
+ * @dev: PCI device to start walking the hierarchy from.
  */
-int acpiphp_eject_slot(struct acpiphp_slot *slot)
+static void trim_stale_devices(struct pci_dev *dev)
 {
-       struct acpiphp_func *func;
+       acpi_handle handle = ACPI_HANDLE(&dev->dev);
+       struct pci_bus *bus = dev->subordinate;
+       bool alive = false;
 
-       list_for_each_entry(func, &slot->funcs, sibling) {
-               /* We don't want to call _EJ0 on non-existing functions. */
-               if (!(func->flags & FUNC_HAS_EJ0))
-                       continue;
+       if (handle) {
+               acpi_status status;
+               unsigned long long sta;
 
-               if (ACPI_FAILURE(acpi_evaluate_ej0(func_to_handle(func))))
-                       return -1;
-               else
-                       break;
+               status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+               alive = ACPI_SUCCESS(status) && sta == ACPI_STA_ALL;
+       }
+       if (!alive) {
+               u32 v;
+
+               /* Check if the device responds. */
+               alive = pci_bus_read_dev_vendor_id(dev->bus, dev->devfn, &v, 0);
+       }
+       if (!alive) {
+               pci_stop_and_remove_bus_device(dev);
+               if (handle)
+                       acpiphp_bus_trim(handle);
+       } else if (bus) {
+               struct pci_dev *child, *tmp;
+
+               /* The device is a bridge. so check the bus below it. */
+               pm_runtime_get_sync(&dev->dev);
+               list_for_each_entry_safe(child, tmp, &bus->devices, bus_list)
+                       trim_stale_devices(child);
+
+               pm_runtime_put(&dev->dev);
        }
-       return 0;
 }
 
 /**
@@ -823,43 +728,30 @@ int acpiphp_eject_slot(struct acpiphp_slot *slot)
  * Iterate over all slots under this bridge and make sure that if a
  * card is present they are enabled, and if not they are disabled.
  */
-static int acpiphp_check_bridge(struct acpiphp_bridge *bridge)
+static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
 {
        struct acpiphp_slot *slot;
-       int retval = 0;
-       int enabled, disabled;
-
-       enabled = disabled = 0;
 
        list_for_each_entry(slot, &bridge->slots, node) {
-               unsigned int status = get_slot_status(slot);
-               if (slot->flags & SLOT_ENABLED) {
-                       if (status == ACPI_STA_ALL)
-                               continue;
-                       retval = acpiphp_disable_slot(slot);
-                       if (retval) {
-                               err("Error occurred in disabling\n");
-                               goto err_exit;
-                       } else {
-                               acpiphp_eject_slot(slot);
-                       }
-                       disabled++;
+               struct pci_bus *bus = slot->bus;
+               struct pci_dev *dev, *tmp;
+
+               mutex_lock(&slot->crit_sect);
+               /* wake up all functions */
+               if (get_slot_status(slot) == ACPI_STA_ALL) {
+                       /* remove stale devices if any */
+                       list_for_each_entry_safe(dev, tmp, &bus->devices,
+                                                bus_list)
+                               if (PCI_SLOT(dev->devfn) == slot->device)
+                                       trim_stale_devices(dev);
+
+                       /* configure all functions */
+                       enable_slot(slot);
                } else {
-                       if (status != ACPI_STA_ALL)
-                               continue;
-                       retval = acpiphp_enable_slot(slot);
-                       if (retval) {
-                               err("Error occurred in enabling\n");
-                               goto err_exit;
-                       }
-                       enabled++;
+                       disable_slot(slot);
                }
+               mutex_unlock(&slot->crit_sect);
        }
-
-       dbg("%s: %d enabled, %d disabled\n", __func__, enabled, disabled);
-
- err_exit:
-       return retval;
 }
 
 static void acpiphp_set_hpp_values(struct pci_bus *bus)
@@ -898,25 +790,6 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus)
  * ACPI event handlers
  */
 
-static acpi_status
-check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-       struct acpiphp_bridge *bridge;
-       char objname[64];
-       struct acpi_buffer buffer = { .length = sizeof(objname),
-                                     .pointer = objname };
-
-       bridge = acpiphp_handle_to_bridge(handle);
-       if (bridge) {
-               acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-               dbg("%s: re-enumerating slots under %s\n",
-                       __func__, objname);
-               acpiphp_check_bridge(bridge);
-               put_bridge(bridge);
-       }
-       return AE_OK ;
-}
-
 void acpiphp_check_host_bridge(acpi_handle handle)
 {
        struct acpiphp_bridge *bridge;
@@ -926,9 +799,6 @@ void acpiphp_check_host_bridge(acpi_handle handle)
                acpiphp_check_bridge(bridge);
                put_bridge(bridge);
        }
-
-       acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
-               ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
 }
 
 static void hotplug_event(acpi_handle handle, u32 type, void *data)
@@ -956,11 +826,12 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data)
                dbg("%s: re-enumerating slots under %s\n", __func__, objname);
                if (bridge) {
                        acpiphp_check_bridge(bridge);
-                       acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
-                                           ACPI_UINT32_MAX, check_sub_bridges,
-                                           NULL, NULL, NULL);
                } else {
-                       acpiphp_enable_slot(func->slot);
+                       struct acpiphp_slot *slot = func->slot;
+
+                       mutex_lock(&slot->crit_sect);
+                       enable_slot(slot);
+                       mutex_unlock(&slot->crit_sect);
                }
                break;
 
@@ -970,41 +841,14 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data)
                if (bridge)
                        acpiphp_check_bridge(bridge);
                else
-                       acpiphp_check_bridge(func->slot->bridge);
+                       acpiphp_check_bridge(func->parent);
 
                break;
 
-       case ACPI_NOTIFY_DEVICE_WAKE:
-               /* wake event */
-               dbg("%s: Device wake notify on %s\n", __func__, objname);
-               break;
-
        case ACPI_NOTIFY_EJECT_REQUEST:
                /* request device eject */
                dbg("%s: Device eject notify on %s\n", __func__, objname);
-               if (!(acpiphp_disable_slot(func->slot)))
-                       acpiphp_eject_slot(func->slot);
-
-               break;
-
-       case ACPI_NOTIFY_FREQUENCY_MISMATCH:
-               printk(KERN_ERR "Device %s cannot be configured due"
-                               " to a frequency mismatch\n", objname);
-               break;
-
-       case ACPI_NOTIFY_BUS_MODE_MISMATCH:
-               printk(KERN_ERR "Device %s cannot be configured due"
-                               " to a bus mode mismatch\n", objname);
-               break;
-
-       case ACPI_NOTIFY_POWER_FAULT:
-               printk(KERN_ERR "Device %s has suffered a power fault\n",
-                               objname);
-               break;
-
-       default:
-               warn("notify_handler: unknown event type 0x%x for %s\n", type,
-                    objname);
+               acpiphp_disable_and_eject_slot(func->slot);
                break;
        }
 
@@ -1025,7 +869,7 @@ static void hotplug_event_work(struct work_struct *work)
 
        acpi_scan_lock_release();
        kfree(hp_work); /* allocated in handle_hotplug_event() */
-       put_bridge(context->func.slot->bridge);
+       put_bridge(context->func.parent);
 }
 
 /**
@@ -1040,23 +884,42 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
 {
        struct acpiphp_context *context;
 
+       switch (type) {
+       case ACPI_NOTIFY_BUS_CHECK:
+       case ACPI_NOTIFY_DEVICE_CHECK:
+       case ACPI_NOTIFY_EJECT_REQUEST:
+               break;
+
+       case ACPI_NOTIFY_DEVICE_WAKE:
+               return;
+
+       case ACPI_NOTIFY_FREQUENCY_MISMATCH:
+               acpi_handle_err(handle, "Device cannot be configured due "
+                               "to a frequency mismatch\n");
+               return;
+
+       case ACPI_NOTIFY_BUS_MODE_MISMATCH:
+               acpi_handle_err(handle, "Device cannot be configured due "
+                               "to a bus mode mismatch\n");
+               return;
+
+       case ACPI_NOTIFY_POWER_FAULT:
+               acpi_handle_err(handle, "Device has suffered a power fault\n");
+               return;
+
+       default:
+               acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
+               return;
+       }
+
        mutex_lock(&acpiphp_context_lock);
        context = acpiphp_get_context(handle);
        if (context) {
-               get_bridge(context->func.slot->bridge);
+               get_bridge(context->func.parent);
                acpiphp_put_context(context);
+               alloc_acpi_hp_work(handle, type, context, hotplug_event_work);
        }
        mutex_unlock(&acpiphp_context_lock);
-       /*
-        * Currently the code adds all hotplug events to the kacpid_wq
-        * queue when it should add hotplug events to the kacpi_hotplug_wq.
-        * The proper way to fix this is to reorganize the code so that
-        * drivers (dock, etc.) do not call acpi_os_execute(), etc.
-        * For now just re-add this work to the kacpi_hotplug_wq so we
-        * don't deadlock on hotplug actions.
-        */
-       if (context)
-               alloc_acpi_hp_work(handle, type, context, hotplug_event_work);
 }
 
 /*
@@ -1113,7 +976,7 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
                bridge->context = context;
                context->bridge = bridge;
                /* Get a reference to the parent bridge. */
-               get_bridge(context->func.slot->bridge);
+               get_bridge(context->func.parent);
                mutex_unlock(&acpiphp_context_lock);
        }
 
@@ -1135,17 +998,21 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
 /* Destroy hotplug slots associated with the PCI bus */
 void acpiphp_remove_slots(struct pci_bus *bus)
 {
-       struct acpiphp_bridge *bridge, *tmp;
+       struct acpiphp_bridge *bridge;
 
        if (acpiphp_disabled)
                return;
 
-       list_for_each_entry_safe(bridge, tmp, &bridge_list, list)
+       mutex_lock(&bridge_mutex);
+       list_for_each_entry(bridge, &bridge_list, list)
                if (bridge->pci_bus == bus) {
+                       mutex_unlock(&bridge_mutex);
                        cleanup_bridge(bridge);
                        put_bridge(bridge);
-                       break;
+                       return;
                }
+
+       mutex_unlock(&bridge_mutex);
 }
 
 /**
@@ -1154,51 +1021,39 @@ void acpiphp_remove_slots(struct pci_bus *bus)
  */
 int acpiphp_enable_slot(struct acpiphp_slot *slot)
 {
-       int retval;
-
        mutex_lock(&slot->crit_sect);
+       /* configure all functions */
+       if (!(slot->flags & SLOT_ENABLED))
+               enable_slot(slot);
 
-       /* wake up all functions */
-       retval = power_on_slot(slot);
-       if (retval)
-               goto err_exit;
-
-       if (get_slot_status(slot) == ACPI_STA_ALL) {
-               /* configure all functions */
-               retval = enable_device(slot);
-               if (retval)
-                       power_off_slot(slot);
-       } else {
-               dbg("%s: Slot status is not ACPI_STA_ALL\n", __func__);
-               power_off_slot(slot);
-       }
-
- err_exit:
        mutex_unlock(&slot->crit_sect);
-       return retval;
+       return 0;
 }
 
 /**
- * acpiphp_disable_slot - power off slot
+ * acpiphp_disable_and_eject_slot - power off and eject slot
  * @slot: ACPI PHP slot
  */
-int acpiphp_disable_slot(struct acpiphp_slot *slot)
+int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot)
 {
+       struct acpiphp_func *func;
        int retval = 0;
 
        mutex_lock(&slot->crit_sect);
 
        /* unconfigure all functions */
-       retval = disable_device(slot);
-       if (retval)
-               goto err_exit;
+       disable_slot(slot);
 
-       /* power off all functions */
-       retval = power_off_slot(slot);
-       if (retval)
-               goto err_exit;
+       list_for_each_entry(func, &slot->funcs, sibling)
+               if (func->flags & FUNC_HAS_EJ0) {
+                       acpi_handle handle = func_to_handle(func);
+
+                       if (ACPI_FAILURE(acpi_evaluate_ej0(handle)))
+                               acpi_handle_err(handle, "_EJ0 failed\n");
+
+                       break;
+               }
 
- err_exit:
        mutex_unlock(&slot->crit_sect);
        return retval;
 }
@@ -1210,7 +1065,7 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot)
  */
 u8 acpiphp_get_power_status(struct acpiphp_slot *slot)
 {
-       return (slot->flags & SLOT_POWEREDON);
+       return (slot->flags & SLOT_ENABLED);
 }
 
 
@@ -1220,11 +1075,7 @@ u8 acpiphp_get_power_status(struct acpiphp_slot *slot)
  */
 u8 acpiphp_get_latch_status(struct acpiphp_slot *slot)
 {
-       unsigned int sta;
-
-       sta = get_slot_status(slot);
-
-       return (sta & ACPI_STA_DEVICE_UI) ? 0 : 1;
+       return !(get_slot_status(slot) & ACPI_STA_DEVICE_UI);
 }
 
 
@@ -1234,9 +1085,5 @@ u8 acpiphp_get_latch_status(struct acpiphp_slot *slot)
  */
 u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot)
 {
-       unsigned int sta;
-
-       sta = get_slot_status(slot);
-
-       return (sta == 0) ? 0 : 1;
+       return !!get_slot_status(slot);
 }