#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>
if (--context->refcount)
return;
- WARN_ON(context->func || context->bridge);
+ WARN_ON(context->bridge);
acpi_detach_data(context->handle, acpiphp_context_handler);
kfree(context);
}
bridge = container_of(kref, struct acpiphp_bridge, ref);
list_for_each_entry_safe(slot, next, &bridge->slots, node) {
- list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) {
- context = func->context;
- context->func = NULL;
- acpiphp_put_context(context);
- kfree(func);
- }
+ list_for_each_entry_safe(func, tmp, &slot->funcs, sibling)
+ acpiphp_put_context(func_to_context(func));
+
kfree(slot);
}
/* 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);
}
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)
{
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 */
device = (adr >> 16) & 0xffff;
function = adr & 0xffff;
- newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL);
- if (!newfunc)
- return AE_NO_MEMORY;
-
- newfunc->handle = handle;
- newfunc->function = function;
-
mutex_lock(&acpiphp_context_lock);
context = acpiphp_init_context(handle);
if (!context) {
mutex_unlock(&acpiphp_context_lock);
acpi_handle_err(handle, "No hotplug context\n");
- kfree(newfunc);
return AE_NOT_EXIST;
}
- newfunc->context = context;
- context->func = newfunc;
+ newfunc = &context->func;
+ newfunc->function = function;
+ newfunc->parent = bridge;
mutex_unlock(&acpiphp_context_lock);
if (acpi_has_method(handle, "_EJ0"))
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;
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)) {
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 "
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
err:
mutex_lock(&acpiphp_context_lock);
- context->func = NULL;
acpiphp_put_context(context);
mutex_unlock(&acpiphp_context_lock);
- kfree(newfunc);
return status;
}
list_for_each_entry(slot, &bridge->slots, node) {
list_for_each_entry(func, &slot->funcs, sibling) {
- if (is_dock_device(func->handle)) {
- unregister_hotplug_dock_device(func->handle);
- }
+ acpi_handle handle = func_to_handle(func);
+
+ if (is_dock_device(handle))
+ unregister_hotplug_dock_device(handle);
+
if (!(func->flags & FUNC_HAS_DCK)) {
- status = acpi_remove_notify_handler(func->handle,
+ status = acpi_remove_notify_handler(handle,
ACPI_SYSTEM_NOTIFY,
handle_hotplug_event);
if (ACPI_FAILURE(status))
err("failed to remove notify handler\n");
}
}
- acpiphp_unregister_hotplug_slot(slot);
+ if (slot->slot)
+ acpiphp_unregister_hotplug_slot(slot);
}
mutex_lock(&bridge_mutex);
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->handle, "_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->handle, "_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
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)
{
- struct acpi_device *device;
- int ret_val;
+ struct acpi_device *adev = NULL;
- if (!acpi_bus_get_device(func->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(func->handle);
- if (!ret_val)
- ret_val = acpi_bus_get_device(func->handle, &device);
-
- 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)
params[1].type = ACPI_TYPE_INTEGER;
params[1].integer.value = 1;
/* _REG is optional, we don't care about if there is failure */
- acpi_evaluate_object(func->handle, "_REG", &arg_list, NULL);
+ acpi_evaluate_object(func_to_handle(func), "_REG", &arg_list,
+ NULL);
}
}
{
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;
}
/**
- * 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);
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;
}
/**
- * 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.
pci_dev_put(pdev);
}
- list_for_each_entry(func, &slot->funcs, sibling) {
- acpiphp_bus_trim(func->handle);
- }
+ list_for_each_entry(func, &slot->funcs, sibling)
+ acpiphp_bus_trim(func_to_handle(func));
slot->flags &= (~SLOT_ENABLED);
-
- return 0;
}
*/
static unsigned int get_slot_status(struct acpiphp_slot *slot)
{
- acpi_status status;
unsigned long long sta = 0;
- u32 dvid;
struct acpiphp_func *func;
list_for_each_entry(func, &slot->funcs, sibling) {
if (func->flags & FUNC_HAS_STA) {
- status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta);
+ acpi_status status;
+
+ status = acpi_evaluate_integer(func_to_handle(func),
+ "_STA", NULL, &sta);
if (ACPI_SUCCESS(status) && sta)
break;
} else {
- pci_bus_read_config_dword(slot->bridge->pci_bus,
+ u32 dvid;
+
+ pci_bus_read_config_dword(slot->bus,
PCI_DEVFN(slot->device,
func->function),
PCI_VENDOR_ID, &dvid);
}
/**
- * 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)) {
- if (ACPI_FAILURE(acpi_evaluate_ej0(func->handle)))
- return -1;
- else
- break;
- }
+ if (handle) {
+ acpi_status status;
+ unsigned long long sta;
+
+ 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;
}
/**
* 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)
* 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;
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)
{
struct acpiphp_context *context = data;
- struct acpiphp_func *func = context->func;
+ struct acpiphp_func *func = &context->func;
struct acpiphp_bridge *bridge;
char objname[64];
struct acpi_buffer buffer = { .length = sizeof(objname),
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;
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 (bridge && !(bridge->flags & BRIDGE_HAS_EJ0))
- break;
-
- 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;
}
acpi_scan_lock_release();
kfree(hp_work); /* allocated in handle_hotplug_event() */
- put_bridge(context->func->slot->bridge);
+ put_bridge(context->func.parent);
}
/**
{
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);
}
/*
INIT_LIST_HEAD(&bridge->slots);
kref_init(&bridge->ref);
- bridge->handle = handle;
bridge->pci_dev = pci_dev_get(bus->self);
bridge->pci_bus = bus;
*/
mutex_lock(&acpiphp_context_lock);
context = acpiphp_get_context(handle);
- if (WARN_ON(!context || !context->func)) {
+ if (WARN_ON(!context)) {
mutex_unlock(&acpiphp_context_lock);
put_device(&bus->dev);
kfree(bridge);
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);
}
- status = acpi_get_handle(bridge->handle, "_EJ0", &handle);
- if (ACPI_SUCCESS(status)) {
- dbg("found ejectable p2p bridge\n");
- bridge->flags |= BRIDGE_HAS_EJ0;
- }
-
/* must be added to the list prior to calling register_slot */
mutex_lock(&bridge_mutex);
list_add(&bridge->list, &bridge_list);
mutex_unlock(&bridge_mutex);
/* register all slot objects under this bridge */
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, 1,
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
register_slot, NULL, bridge, NULL);
if (ACPI_FAILURE(status)) {
- acpi_handle_err(bridge->handle, "failed to register slots\n");
+ acpi_handle_err(handle, "failed to register slots\n");
cleanup_bridge(bridge);
put_bridge(bridge);
}
/* 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);
}
/**
*/
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);
+
+ list_for_each_entry(func, &slot->funcs, sibling)
+ if (func->flags & FUNC_HAS_EJ0) {
+ acpi_handle handle = func_to_handle(func);
- /* power off all functions */
- retval = power_off_slot(slot);
- if (retval)
- goto err_exit;
+ if (ACPI_FAILURE(acpi_evaluate_ej0(handle)))
+ acpi_handle_err(handle, "_EJ0 failed\n");
+
+ break;
+ }
- err_exit:
mutex_unlock(&slot->crit_sect);
return retval;
}
*/
u8 acpiphp_get_power_status(struct acpiphp_slot *slot)
{
- return (slot->flags & SLOT_POWEREDON);
+ return (slot->flags & SLOT_ENABLED);
}
*/
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);
}
*/
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);
}