===================================================================
@@ -61,7 +61,7 @@ static DEFINE_MUTEX(bridge_mutex);
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 */
@@ -210,7 +210,7 @@ static int post_dock_fixups(struct notif
static const struct acpi_dock_ops acpiphp_dock_ops = {
- .handler = hotplug_event_func,
+ .handler = hotplug_event,
};
/* Check whether the PCI device is managed by native PCIe hotplug driver */
@@ -244,16 +244,24 @@ static bool device_is_managed_by_native_
static void acpiphp_dock_init(void *data)
{
- struct acpiphp_func *func = data;
+ struct acpiphp_context *context = data;
+
+ if (context->func)
+ get_bridge(context->func->slot->bridge);
- get_bridge(func->slot->bridge);
+ if (context->bridge)
+ get_bridge(context->bridge);
}
static void acpiphp_dock_release(void *data)
{
- struct acpiphp_func *func = data;
+ struct acpiphp_context *context = data;
+
+ if (context->bridge)
+ put_bridge(context->bridge);
- put_bridge(func->slot->bridge);
+ if (context->func)
+ put_bridge(context->func->slot->bridge);
}
/* callback routine to register each ACPI PCI slot object */
@@ -390,7 +398,7 @@ static acpi_status register_slot(acpi_ha
*/
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");
@@ -982,24 +990,14 @@ void acpiphp_check_host_bridge(acpi_hand
acpiphp_put_context(context);
}
-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_bridge *bridge;
+ struct acpiphp_context *context = data;
+ struct acpiphp_bridge *bridge = context->bridge;
+ struct acpiphp_func *func = context->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;
- bridge = context->bridge;
-
- acpi_scan_lock_acquire();
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
@@ -1008,15 +1006,24 @@ static void _handle_hotplug_event_bridge
/* 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:
@@ -1027,12 +1034,15 @@ static void _handle_hotplug_event_bridge
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:
@@ -1051,56 +1061,13 @@ static void _handle_hotplug_event_bridge
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;
- }
-}
-
-static void _handle_hotplug_event_func(struct work_struct *work)
+static void handle_hotplug_event_work_fn(struct work_struct *work)
{
struct acpiphp_context *context;
struct acpi_hp_work *hp_work;
@@ -1109,11 +1076,16 @@ static void _handle_hotplug_event_func(s
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() */
+ if (context->bridge)
+ put_bridge(context->bridge);
+
+ if (context->func)
+ put_bridge(context->func->slot->bridge);
+
}
/**
@@ -1127,17 +1099,16 @@ static void _handle_hotplug_event_func(s
static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
{
struct acpiphp_context *context = data;
- void (*work_func)(struct work_struct *work);
- if (context->bridge) {
- get_bridge(context->bridge);
- work_func = _handle_hotplug_event_bridge;
- } else if (context->func) {
- get_bridge(context->func->slot->bridge);
- work_func = _handle_hotplug_event_func;
- } else {
+ if (WARN_ON(!context->bridge && !context->func))
return;
- }
+
+ if (context->func)
+ get_bridge(context->func->slot->bridge);
+
+ if (context->bridge)
+ get_bridge(context->bridge);
+
/*
* Currently the code adds all hotplug events to the kacpid_wq
* queue when it should add hotplug events to the kacpi_hotplug_wq.
@@ -1146,7 +1117,7 @@ static void handle_hotplug_event(acpi_ha
* For now just re-add this work to the kacpi_hotplug_wq so we
* don't deadlock on hotplug actions.
*/
- alloc_acpi_hp_work(handle, type, context, work_func);
+ alloc_acpi_hp_work(handle, type, context, handle_hotplug_event_work_fn);
}
/*
@@ -1226,6 +1197,11 @@ void acpiphp_enumerate_slots(struct pci_
return;
}
+ /* If it has _DCK, there is a notify handler for it already. */
+ status = acpi_get_handle(bridge->handle, "_DCK", &handle);
+ if (ACPI_SUCCESS(status))
+ return;
+
/* install notify handler for P2P bridges */
status = acpi_install_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY,
handle_hotplug_event, context);