static void handle_hotplug_event(acpi_handle handle, u32 type, void *data);
static void acpiphp_sanitize_bus(struct pci_bus *bus);
static void acpiphp_set_hpp_values(struct pci_bus *bus);
-static void hotplug_event_func(acpi_handle handle, u32 type, void *context);
+static void hotplug_event(acpi_handle handle, u32 type, void *data);
static void free_bridge(struct kref *kref);
/* callback routine to check for the existence of a pci dock device */
*/
static void post_dock_fixups(acpi_handle not_used, u32 event, void *data)
{
- struct acpiphp_func *func = data;
- struct pci_bus *bus = func->slot->bridge->pci_bus;
+ struct acpiphp_context *context = data;
+ struct pci_bus *bus = context->func->slot->bridge->pci_bus;
u32 buses;
if (!bus->self)
static const struct acpi_dock_ops acpiphp_dock_ops = {
.fixup = post_dock_fixups,
- .handler = hotplug_event_func,
+ .handler = hotplug_event,
};
/* Check whether the PCI device is managed by native PCIe hotplug driver */
static void acpiphp_dock_init(void *data)
{
- struct acpiphp_func *func = data;
+ struct acpiphp_context *context = data;
- get_bridge(func->slot->bridge);
+ get_bridge(context->func->slot->bridge);
}
static void acpiphp_dock_release(void *data)
{
- struct acpiphp_func *func = data;
+ struct acpiphp_context *context = data;
- put_bridge(func->slot->bridge);
+ put_bridge(context->func->slot->bridge);
}
/* callback routine to register each ACPI PCI slot object */
*/
newfunc->flags &= ~FUNC_HAS_EJ0;
if (register_hotplug_dock_device(handle,
- &acpiphp_dock_ops, newfunc,
+ &acpiphp_dock_ops, context,
acpiphp_dock_init, acpiphp_dock_release))
dbg("failed to register dock device\n");
}
ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
}
-static void _handle_hotplug_event_bridge(struct work_struct *work)
+static void hotplug_event(acpi_handle handle, u32 type, void *data)
{
- struct acpiphp_context *context;
+ struct acpiphp_context *context = data;
struct acpiphp_bridge *bridge;
+ struct acpiphp_func *func;
char objname[64];
struct acpi_buffer buffer = { .length = sizeof(objname),
.pointer = objname };
- struct acpi_hp_work *hp_work;
- acpi_handle handle;
- u32 type;
- hp_work = container_of(work, struct acpi_hp_work, work);
- handle = hp_work->handle;
- type = hp_work->type;
- context = hp_work->context;
+ mutex_lock(&acpiphp_context_lock);
bridge = context->bridge;
+ if (bridge)
+ get_bridge(bridge);
- acpi_scan_lock_acquire();
+ /*
+ * If context->func is not NULL, we are holding a reference to its
+ * parent bridge, so it won't go away until we drop that reference.
+ */
+ func = context->func;
+ mutex_unlock(&acpiphp_context_lock);
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
/* bus re-enumerate */
dbg("%s: Bus check notify on %s\n", __func__, objname);
dbg("%s: re-enumerating slots under %s\n", __func__, objname);
- acpiphp_check_bridge(bridge);
- acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
- ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
+ 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);
+ }
break;
case ACPI_NOTIFY_DEVICE_CHECK:
/* device check */
dbg("%s: Device check notify on %s\n", __func__, objname);
- acpiphp_check_bridge(bridge);
+ if (bridge)
+ acpiphp_check_bridge(bridge);
+ else
+ acpiphp_check_bridge(func->slot->bridge);
+
break;
case ACPI_NOTIFY_DEVICE_WAKE:
case ACPI_NOTIFY_EJECT_REQUEST:
/* request device eject */
dbg("%s: Device eject notify on %s\n", __func__, objname);
- if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
- struct acpiphp_slot *slot;
- slot = bridge->func->slot;
- if (!acpiphp_disable_slot(slot))
- acpiphp_eject_slot(slot);
- }
+ if (!func)
+ break;
+
+ 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:
break;
default:
- warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
+ warn("notify_handler: unknown event type 0x%x for %s\n", type,
+ objname);
break;
}
- acpi_scan_lock_release();
- kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
- put_bridge(bridge);
-}
-
-static void hotplug_event_func(acpi_handle handle, u32 type, void *context)
-{
- struct acpiphp_func *func = context;
- char objname[64];
- struct acpi_buffer buffer = { .length = sizeof(objname),
- .pointer = objname };
-
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-
- switch (type) {
- case ACPI_NOTIFY_BUS_CHECK:
- /* bus re-enumerate */
- dbg("%s: Bus check notify on %s\n", __func__, objname);
- acpiphp_enable_slot(func->slot);
- break;
-
- case ACPI_NOTIFY_DEVICE_CHECK:
- /* device check : re-enumerate from parent bus */
- dbg("%s: Device check notify on %s\n", __func__, objname);
- acpiphp_check_bridge(func->slot->bridge);
- 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;
-
- default:
- warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
- break;
- }
+ if (bridge)
+ put_bridge(bridge);
}
-static void _handle_hotplug_event_func(struct work_struct *work)
+static void hotplug_event_work(struct work_struct *work)
{
struct acpiphp_context *context;
struct acpi_hp_work *hp_work;
context = hp_work->context;
acpi_scan_lock_acquire();
- hotplug_event_func(hp_work->handle, hp_work->type, context->func);
+ hotplug_event(hp_work->handle, hp_work->type, context);
acpi_scan_lock_release();
- kfree(hp_work); /* allocated in handle_hotplug_event_func */
- put_bridge(context->func->slot->bridge);
+ kfree(hp_work); /* allocated in handle_hotplug_event() */
+
+ mutex_lock(&acpiphp_context_lock);
+ if (context->func)
+ put_bridge(context->func->slot->bridge);
+ else
+ acpiphp_put_context(context);
+
+ mutex_unlock(&acpiphp_context_lock);
}
/**
static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
{
struct acpiphp_context *context;
- void (*work_func)(struct work_struct *work) = NULL;
mutex_lock(&acpiphp_context_lock);
context = acpiphp_get_context(handle);
if (context) {
- if (context->bridge) {
- get_bridge(context->bridge);
- work_func = _handle_hotplug_event_bridge;
- } else if (context->func) {
+ if (context->func) {
get_bridge(context->func->slot->bridge);
- work_func = _handle_hotplug_event_func;
+ acpiphp_put_context(context);
+ } else if (!context->bridge) {
+ acpiphp_put_context(context);
+ context = NULL;
}
- acpiphp_put_context(context);
}
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.
* For now just re-add this work to the kacpi_hotplug_wq so we
* don't deadlock on hotplug actions.
*/
- if (work_func)
- alloc_acpi_hp_work(handle, type, context, work_func);
+ if (context)
+ alloc_acpi_hp_work(handle, type, context, hotplug_event_work);
}
/*