Skip to content

Commit

Permalink
ACPICA: Add support for multiple notify handlers
Browse files Browse the repository at this point in the history
This change adds support to allow multiple notify handlers on
Device, ThermalZone, and Processor objects. Also re-worked
and restructured the entire notify support code for handler
installation, handler removal, notify event queuing, and notify
dispatch to handler.

Extends and updates original commit 3f0be67("ACPI / ACPICA: Multiple
system notify handlers per device") by Rafael Wysocki.

Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
  • Loading branch information
Bob Moore authored and Len Brown committed Jun 1, 2012
1 parent 5134abf commit 86ed4bc
Show file tree
Hide file tree
Showing 9 changed files with 266 additions and 441 deletions.
3 changes: 1 addition & 2 deletions drivers/acpi/acpica/acglobal.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,7 @@ ACPI_EXTERN acpi_cache_t *acpi_gbl_operand_cache;

/* Global handlers */

ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_device_notify;
ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_system_notify;
ACPI_EXTERN struct acpi_global_notify_handler acpi_gbl_global_notify[2];
ACPI_EXTERN acpi_exception_handler acpi_gbl_exception_handler;
ACPI_EXTERN acpi_init_handler acpi_gbl_init_handler;
ACPI_EXTERN acpi_tbl_handler acpi_gbl_table_handler;
Expand Down
13 changes: 11 additions & 2 deletions drivers/acpi/acpica/aclocal.h
Original file line number Diff line number Diff line change
Expand Up @@ -600,13 +600,22 @@ acpi_status(*acpi_parse_downwards) (struct acpi_walk_state * walk_state,

typedef acpi_status(*acpi_parse_upwards) (struct acpi_walk_state * walk_state);

/* Global handlers for AML Notifies */

struct acpi_global_notify_handler {
acpi_notify_handler handler;
void *context;
};

/*
* Notify info - used to pass info to the deferred notify
* handler/dispatcher.
*/
struct acpi_notify_info {
ACPI_STATE_COMMON struct acpi_namespace_node *node;
union acpi_operand_object *handler_obj;
ACPI_STATE_COMMON u8 handler_list_id;
struct acpi_namespace_node *node;
union acpi_operand_object *handler_list_head;
struct acpi_global_notify_handler *global;
};

/* Generic state is union of structs above */
Expand Down
9 changes: 4 additions & 5 deletions drivers/acpi/acpica/acobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,7 @@ struct acpi_object_method {
* Common fields for objects that support ASL notifications
*/
#define ACPI_COMMON_NOTIFY_INFO \
union acpi_operand_object *system_notify; /* Handler for system notifies */\
union acpi_operand_object *device_notify; /* Handler for driver notifies */\
union acpi_operand_object *notify_list[2]; /* Handlers for system/device notifies */\
union acpi_operand_object *handler; /* Handler for Address space */

struct acpi_object_notify_common { /* COMMON NOTIFY for POWER, PROCESSOR, DEVICE, and THERMAL */
Expand Down Expand Up @@ -296,10 +295,10 @@ struct acpi_object_buffer_field {

struct acpi_object_notify_handler {
ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *node; /* Parent device */
u32 handler_type;
acpi_notify_handler handler;
u32 handler_type; /* Type: Device/System/Both */
acpi_notify_handler handler; /* Handler address */
void *context;
struct acpi_object_notify_handler *next;
union acpi_operand_object *next[2]; /* Device and System handler lists */
};

struct acpi_object_addr_handler {
Expand Down
185 changes: 67 additions & 118 deletions drivers/acpi/acpica/evmisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,102 +101,77 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
u32 notify_value)
{
union acpi_operand_object *obj_desc;
union acpi_operand_object *handler_obj = NULL;
union acpi_generic_state *notify_info;
union acpi_operand_object *handler_list_head = NULL;
union acpi_generic_state *info;
u8 handler_list_id = 0;
acpi_status status = AE_OK;

ACPI_FUNCTION_NAME(ev_queue_notify_request);

/*
* For value 0x03 (Ejection Request), may need to run a device method.
* For value 0x02 (Device Wake), if _PRW exists, may need to run
* the _PS0 method.
* For value 0x80 (Status Change) on the power button or sleep button,
* initiate soft-off or sleep operation.
*
* For all cases, simply dispatch the notify to the handler.
*/
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n",
acpi_ut_get_node_name(node),
acpi_ut_get_type_name(node->type), notify_value,
acpi_ut_get_notify_name(notify_value), node));
/* Are Notifies allowed on this object? */

/* Get the notify object attached to the NS Node */

obj_desc = acpi_ns_get_attached_object(node);
if (obj_desc) {

/* We have the notify object, Get the correct handler */

switch (node->type) {
if (!acpi_ev_is_notify_object(node)) {
return (AE_TYPE);
}

/* Notify is allowed only on these types */
/* Get the correct notify list type (System or Device) */

case ACPI_TYPE_DEVICE:
case ACPI_TYPE_THERMAL:
case ACPI_TYPE_PROCESSOR:
if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
handler_list_id = ACPI_SYSTEM_HANDLER_LIST;
} else {
handler_list_id = ACPI_DEVICE_HANDLER_LIST;
}

if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
handler_obj =
obj_desc->common_notify.system_notify;
} else {
handler_obj =
obj_desc->common_notify.device_notify;
}
break;
/* Get the notify object attached to the namespace Node */

default:
obj_desc = acpi_ns_get_attached_object(node);
if (obj_desc) {

/* All other types are not supported */
/* We have an attached object, Get the correct handler list */

return (AE_TYPE);
}
handler_list_head =
obj_desc->common_notify.notify_list[handler_list_id];
}

/*
* If there is a handler to run, schedule the dispatcher.
* Check for:
* 1) Global system notify handler
* 2) Global device notify handler
* 3) Per-device notify handler
* If there is no notify handler (Global or Local)
* for this object, just ignore the notify
*/
if ((acpi_gbl_system_notify.handler &&
(notify_value <= ACPI_MAX_SYS_NOTIFY)) ||
(acpi_gbl_device_notify.handler &&
(notify_value > ACPI_MAX_SYS_NOTIFY)) || handler_obj) {
notify_info = acpi_ut_create_generic_state();
if (!notify_info) {
return (AE_NO_MEMORY);
}
if (!acpi_gbl_global_notify[handler_list_id].handler
&& !handler_list_head) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"No notify handler for Notify, ignoring (%4.4s, %X) node %p\n",
acpi_ut_get_node_name(node), notify_value,
node));

if (!handler_obj) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Executing system notify handler for Notify (%4.4s, %X) "
"node %p\n",
acpi_ut_get_node_name(node),
notify_value, node));
}
return (AE_OK);
}

notify_info->common.descriptor_type =
ACPI_DESC_TYPE_STATE_NOTIFY;
notify_info->notify.node = node;
notify_info->notify.value = (u16) notify_value;
notify_info->notify.handler_obj = handler_obj;
/* Setup notify info and schedule the notify dispatcher */

status =
acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch,
notify_info);
if (ACPI_FAILURE(status)) {
acpi_ut_delete_generic_state(notify_info);
}
} else {
/* There is no notify handler (per-device or system) for this device */
info = acpi_ut_create_generic_state();
if (!info) {
return (AE_NO_MEMORY);
}

ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"No notify handler for Notify (%4.4s, %X) node %p\n",
acpi_ut_get_node_name(node), notify_value,
node));
info->common.descriptor_type = ACPI_DESC_TYPE_STATE_NOTIFY;

info->notify.node = node;
info->notify.value = (u16)notify_value;
info->notify.handler_list_id = handler_list_id;
info->notify.handler_list_head = handler_list_head;
info->notify.global = &acpi_gbl_global_notify[handler_list_id];

ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n",
acpi_ut_get_node_name(node),
acpi_ut_get_type_name(node->type), notify_value,
acpi_ut_get_notify_name(notify_value), node));

status = acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch,
info);
if (ACPI_FAILURE(status)) {
acpi_ut_delete_generic_state(info);
}

return (status);
Expand All @@ -217,60 +192,34 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,

static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
{
union acpi_generic_state *notify_info =
(union acpi_generic_state *)context;
acpi_notify_handler global_handler = NULL;
void *global_context = NULL;
union acpi_generic_state *info = (union acpi_generic_state *)context;
union acpi_operand_object *handler_obj;

ACPI_FUNCTION_ENTRY();

/*
* We will invoke a global notify handler if installed. This is done
* _before_ we invoke the per-device handler attached to the device.
*/
if (notify_info->notify.value <= ACPI_MAX_SYS_NOTIFY) {

/* Global system notification handler */

if (acpi_gbl_system_notify.handler) {
global_handler = acpi_gbl_system_notify.handler;
global_context = acpi_gbl_system_notify.context;
}
} else {
/* Global driver notification handler */

if (acpi_gbl_device_notify.handler) {
global_handler = acpi_gbl_device_notify.handler;
global_context = acpi_gbl_device_notify.context;
}
}

/* Invoke the system handler first, if present */
/* Invoke a global notify handler if installed */

if (global_handler) {
global_handler(notify_info->notify.node,
notify_info->notify.value, global_context);
if (info->notify.global->handler) {
info->notify.global->handler(info->notify.node,
info->notify.value,
info->notify.global->context);
}

/* Now invoke the per-device handler, if present */
/* Now invoke the local notify handler(s) if any are installed */

handler_obj = notify_info->notify.handler_obj;
if (handler_obj) {
struct acpi_object_notify_handler *notifier;
handler_obj = info->notify.handler_list_head;
while (handler_obj) {
handler_obj->notify.handler(info->notify.node,
info->notify.value,
handler_obj->notify.context);

notifier = &handler_obj->notify;
while (notifier) {
notifier->handler(notify_info->notify.node,
notify_info->notify.value,
notifier->context);
notifier = notifier->next;
}
handler_obj =
handler_obj->notify.next[info->notify.handler_list_id];
}

/* All done with the info object */

acpi_ut_delete_generic_state(notify_info);
acpi_ut_delete_generic_state(info);
}

#if (!ACPI_REDUCED_HARDWARE)
Expand Down
Loading

0 comments on commit 86ed4bc

Please sign in to comment.