ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify()

Since acpi_bus_notify() is executed on all notifications for all
devices anyway, make it execute acpi_device_hotplug() for all
hotplug events instead of installing notify handlers pointing to
the same function for all hotplug devices.

This change reduces both the size and complexity of ACPI-based device
hotplug code.  Moreover, since acpi_device_hotplug() only does
significant things for devices that have either an ACPI scan handler,
or a hotplug context with .eject() defined, and those devices
had notify handlers pointing to acpi_hotplug_notify_cb() installed
before anyway, this modification shouldn't change functionality.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
Rafael J. Wysocki 2014-02-06 13:58:13 +01:00
parent 5e6f236c26
commit 1a699476e2
6 changed files with 58 additions and 114 deletions

View File

@ -340,62 +340,77 @@ static void acpi_bus_osc_support(void)
*/
static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
{
struct acpi_device *device;
struct acpi_device *adev;
struct acpi_driver *driver;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n",
type, handle));
acpi_status status;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
/* TBD */
acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
break;
case ACPI_NOTIFY_DEVICE_CHECK:
/* TBD */
acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
break;
case ACPI_NOTIFY_DEVICE_WAKE:
/* TBD */
acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_WAKE event\n");
break;
case ACPI_NOTIFY_EJECT_REQUEST:
/* TBD */
acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
break;
case ACPI_NOTIFY_DEVICE_CHECK_LIGHT:
acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK_LIGHT event\n");
/* TBD: Exactly what does 'light' mean? */
break;
case ACPI_NOTIFY_FREQUENCY_MISMATCH:
/* TBD */
acpi_handle_err(handle, "Device cannot be configured due "
"to a frequency mismatch\n");
break;
case ACPI_NOTIFY_BUS_MODE_MISMATCH:
/* TBD */
acpi_handle_err(handle, "Device cannot be configured due "
"to a bus mode mismatch\n");
break;
case ACPI_NOTIFY_POWER_FAULT:
/* TBD */
acpi_handle_err(handle, "Device has suffered a power fault\n");
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Received unknown/unsupported notification [%08x]\n",
type));
acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY;
goto err;
}
adev = acpi_bus_get_acpi_device(handle);
if (!adev)
goto err;
driver = adev->driver;
if (driver && driver->ops.notify &&
(driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
driver->ops.notify(adev, type);
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK:
case ACPI_NOTIFY_EJECT_REQUEST:
status = acpi_hotplug_execute(acpi_device_hotplug, adev, type);
if (ACPI_SUCCESS(status))
return;
default:
break;
}
acpi_bus_put_acpi_device(adev);
return;
device = acpi_bus_get_acpi_device(handle);
if (device) {
driver = device->driver;
if (driver && driver->ops.notify &&
(driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
driver->ops.notify(device, type);
acpi_bus_put_acpi_device(device);
}
err:
acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
}
/* --------------------------------------------------------------------------

View File

@ -73,6 +73,7 @@ static inline void acpi_lpss_init(void) {}
#endif
bool acpi_queue_hotplug_work(struct work_struct *work);
void acpi_device_hotplug(void *data, u32 src);
bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent);
/* --------------------------------------------------------------------------

View File

@ -470,7 +470,7 @@ static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type)
return -EINVAL;
}
static void acpi_device_hotplug(void *data, u32 src)
void acpi_device_hotplug(void *data, u32 src)
{
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
struct acpi_device *adev = data;
@ -520,75 +520,6 @@ static void acpi_device_hotplug(void *data, u32 src)
unlock_device_hotplug();
}
static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data)
{
u32 ost_code = ACPI_OST_SC_SUCCESS;
struct acpi_device *adev;
acpi_status status;
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
break;
case ACPI_NOTIFY_DEVICE_CHECK:
acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
break;
case ACPI_NOTIFY_EJECT_REQUEST:
acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
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");
goto out;
case ACPI_NOTIFY_BUS_MODE_MISMATCH:
acpi_handle_err(handle, "Device cannot be configured due "
"to a bus mode mismatch\n");
goto out;
case ACPI_NOTIFY_POWER_FAULT:
acpi_handle_err(handle, "Device has suffered a power fault\n");
goto out;
default:
acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY;
goto out;
}
ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
adev = acpi_bus_get_acpi_device(handle);
if (!adev)
goto out;
status = acpi_hotplug_execute(acpi_device_hotplug, adev, type);
if (ACPI_SUCCESS(status))
return;
acpi_bus_put_acpi_device(adev);
out:
acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
}
void acpi_install_hotplug_notify_handler(acpi_handle handle)
{
acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
acpi_hotplug_notify_cb, NULL);
}
void acpi_remove_hotplug_notify_handler(acpi_handle handle)
{
acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
acpi_hotplug_notify_cb);
}
static ssize_t real_power_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@ -2037,12 +1968,10 @@ static void acpi_scan_init_hotplug(struct acpi_device *adev)
struct acpi_scan_handler *handler;
handler = acpi_scan_match_handler(hwid->id, NULL);
if (!handler)
continue;
acpi_install_hotplug_notify_handler(adev->handle);
adev->flags.hotplug_notify = true;
break;
if (handler) {
adev->flags.hotplug_notify = true;
break;
}
}
}

View File

@ -167,7 +167,6 @@ struct acpiphp_attention_info
#define FUNC_HAS_STA (0x00000001)
#define FUNC_HAS_EJ0 (0x00000002)
#define FUNC_HAS_DCK (0x00000004)
/* function prototypes */

View File

@ -297,7 +297,6 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
newfunc = &context->func;
newfunc->function = function;
newfunc->parent = bridge;
acpi_unlock_hp_context();
if (acpi_has_method(handle, "_EJ0"))
newfunc->flags = FUNC_HAS_EJ0;
@ -305,8 +304,14 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
if (acpi_has_method(handle, "_STA"))
newfunc->flags |= FUNC_HAS_STA;
/*
* Dock stations' notify handler should be used for dock devices instead
* of the common one, so clear hp.event in their contexts.
*/
if (acpi_has_method(handle, "_DCK"))
newfunc->flags |= FUNC_HAS_DCK;
context->hp.event = NULL;
acpi_unlock_hp_context();
/* search for objects that share the same slot */
list_for_each_entry(slot, &bridge->slots, node)
@ -374,10 +379,6 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
pr_debug("failed to register dock device\n");
}
/* install notify handler */
if (!(newfunc->flags & FUNC_HAS_DCK))
acpi_install_hotplug_notify_handler(handle);
return AE_OK;
}
@ -411,13 +412,14 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
list_for_each_entry(slot, &bridge->slots, node) {
list_for_each_entry(func, &slot->funcs, sibling) {
acpi_handle handle = func_to_handle(func);
struct acpi_device *adev = func_to_acpi_device(func);
if (is_dock_device(handle))
unregister_hotplug_dock_device(handle);
if (is_dock_device(adev->handle))
unregister_hotplug_dock_device(adev->handle);
if (!(func->flags & FUNC_HAS_DCK))
acpi_remove_hotplug_notify_handler(handle);
acpi_lock_hp_context();
adev->hp->event = NULL;
acpi_unlock_hp_context();
}
slot->flags |= SLOT_IS_GOING_AWAY;
if (slot->slot)

View File

@ -446,8 +446,6 @@ static inline bool acpi_device_enumerated(struct acpi_device *adev)
typedef void (*acpi_hp_callback)(void *data, u32 src);
acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src);
void acpi_install_hotplug_notify_handler(acpi_handle handle);
void acpi_remove_hotplug_notify_handler(acpi_handle handle);
/**
* module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver