Commit 1a699476 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

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: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 5e6f236c
...@@ -340,62 +340,77 @@ static void acpi_bus_osc_support(void) ...@@ -340,62 +340,77 @@ static void acpi_bus_osc_support(void)
*/ */
static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
{ {
struct acpi_device *device; struct acpi_device *adev;
struct acpi_driver *driver; struct acpi_driver *driver;
acpi_status status;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n", u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
type, handle));
switch (type) { switch (type) {
case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_BUS_CHECK:
/* TBD */ acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
break; break;
case ACPI_NOTIFY_DEVICE_CHECK: case ACPI_NOTIFY_DEVICE_CHECK:
/* TBD */ acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
break; break;
case ACPI_NOTIFY_DEVICE_WAKE: case ACPI_NOTIFY_DEVICE_WAKE:
/* TBD */ acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_WAKE event\n");
break; break;
case ACPI_NOTIFY_EJECT_REQUEST: case ACPI_NOTIFY_EJECT_REQUEST:
/* TBD */ acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
break; break;
case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: case ACPI_NOTIFY_DEVICE_CHECK_LIGHT:
acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK_LIGHT event\n");
/* TBD: Exactly what does 'light' mean? */ /* TBD: Exactly what does 'light' mean? */
break; break;
case ACPI_NOTIFY_FREQUENCY_MISMATCH: case ACPI_NOTIFY_FREQUENCY_MISMATCH:
/* TBD */ acpi_handle_err(handle, "Device cannot be configured due "
"to a frequency mismatch\n");
break; break;
case ACPI_NOTIFY_BUS_MODE_MISMATCH: case ACPI_NOTIFY_BUS_MODE_MISMATCH:
/* TBD */ acpi_handle_err(handle, "Device cannot be configured due "
"to a bus mode mismatch\n");
break; break;
case ACPI_NOTIFY_POWER_FAULT: case ACPI_NOTIFY_POWER_FAULT:
/* TBD */ acpi_handle_err(handle, "Device has suffered a power fault\n");
break; break;
default: default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO, acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
"Received unknown/unsupported notification [%08x]\n", ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY;
type)); goto err;
break;
} }
device = acpi_bus_get_acpi_device(handle); adev = acpi_bus_get_acpi_device(handle);
if (device) { if (!adev)
driver = device->driver; goto err;
if (driver && driver->ops.notify &&
(driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
driver->ops.notify(device, type);
acpi_bus_put_acpi_device(device); 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;
err:
acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
} }
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
......
...@@ -73,6 +73,7 @@ static inline void acpi_lpss_init(void) {} ...@@ -73,6 +73,7 @@ static inline void acpi_lpss_init(void) {}
#endif #endif
bool acpi_queue_hotplug_work(struct work_struct *work); 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); bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent);
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
......
...@@ -470,7 +470,7 @@ static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type) ...@@ -470,7 +470,7 @@ static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type)
return -EINVAL; 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; u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
struct acpi_device *adev = data; struct acpi_device *adev = data;
...@@ -520,75 +520,6 @@ static void acpi_device_hotplug(void *data, u32 src) ...@@ -520,75 +520,6 @@ static void acpi_device_hotplug(void *data, u32 src)
unlock_device_hotplug(); 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, static ssize_t real_power_state_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
...@@ -2037,12 +1968,10 @@ static void acpi_scan_init_hotplug(struct acpi_device *adev) ...@@ -2037,12 +1968,10 @@ static void acpi_scan_init_hotplug(struct acpi_device *adev)
struct acpi_scan_handler *handler; struct acpi_scan_handler *handler;
handler = acpi_scan_match_handler(hwid->id, NULL); handler = acpi_scan_match_handler(hwid->id, NULL);
if (!handler) if (handler) {
continue; adev->flags.hotplug_notify = true;
break;
acpi_install_hotplug_notify_handler(adev->handle); }
adev->flags.hotplug_notify = true;
break;
} }
} }
......
...@@ -167,7 +167,6 @@ struct acpiphp_attention_info ...@@ -167,7 +167,6 @@ struct acpiphp_attention_info
#define FUNC_HAS_STA (0x00000001) #define FUNC_HAS_STA (0x00000001)
#define FUNC_HAS_EJ0 (0x00000002) #define FUNC_HAS_EJ0 (0x00000002)
#define FUNC_HAS_DCK (0x00000004)
/* function prototypes */ /* function prototypes */
......
...@@ -297,7 +297,6 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, ...@@ -297,7 +297,6 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
newfunc = &context->func; newfunc = &context->func;
newfunc->function = function; newfunc->function = function;
newfunc->parent = bridge; newfunc->parent = bridge;
acpi_unlock_hp_context();
if (acpi_has_method(handle, "_EJ0")) if (acpi_has_method(handle, "_EJ0"))
newfunc->flags = FUNC_HAS_EJ0; newfunc->flags = FUNC_HAS_EJ0;
...@@ -305,8 +304,14 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, ...@@ -305,8 +304,14 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
if (acpi_has_method(handle, "_STA")) if (acpi_has_method(handle, "_STA"))
newfunc->flags |= FUNC_HAS_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")) 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 */ /* search for objects that share the same slot */
list_for_each_entry(slot, &bridge->slots, node) list_for_each_entry(slot, &bridge->slots, node)
...@@ -374,10 +379,6 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, ...@@ -374,10 +379,6 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
pr_debug("failed to register dock device\n"); 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; return AE_OK;
} }
...@@ -411,13 +412,14 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) ...@@ -411,13 +412,14 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
list_for_each_entry(slot, &bridge->slots, node) { list_for_each_entry(slot, &bridge->slots, node) {
list_for_each_entry(func, &slot->funcs, sibling) { 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)) if (is_dock_device(adev->handle))
unregister_hotplug_dock_device(handle); unregister_hotplug_dock_device(adev->handle);
if (!(func->flags & FUNC_HAS_DCK)) acpi_lock_hp_context();
acpi_remove_hotplug_notify_handler(handle); adev->hp->event = NULL;
acpi_unlock_hp_context();
} }
slot->flags |= SLOT_IS_GOING_AWAY; slot->flags |= SLOT_IS_GOING_AWAY;
if (slot->slot) if (slot->slot)
......
...@@ -446,8 +446,6 @@ static inline bool acpi_device_enumerated(struct acpi_device *adev) ...@@ -446,8 +446,6 @@ static inline bool acpi_device_enumerated(struct acpi_device *adev)
typedef void (*acpi_hp_callback)(void *data, u32 src); typedef void (*acpi_hp_callback)(void *data, u32 src);
acpi_status acpi_hotplug_execute(acpi_hp_callback func, 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 * module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment