Commit 86ed4bc8 authored by Bob Moore's avatar Bob Moore Committed by Len Brown

ACPICA: Add support for multiple notify handlers

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 3f0be671("ACPI / ACPICA: Multiple
system notify handlers per device") by Rafael Wysocki.
Signed-off-by: default avatarBob Moore <robert.moore@intel.com>
Signed-off-by: default avatarLin Ming <ming.m.lin@intel.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 5134abfc
...@@ -278,8 +278,7 @@ ACPI_EXTERN acpi_cache_t *acpi_gbl_operand_cache; ...@@ -278,8 +278,7 @@ ACPI_EXTERN acpi_cache_t *acpi_gbl_operand_cache;
/* Global handlers */ /* Global handlers */
ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_device_notify; ACPI_EXTERN struct acpi_global_notify_handler acpi_gbl_global_notify[2];
ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_system_notify;
ACPI_EXTERN acpi_exception_handler acpi_gbl_exception_handler; ACPI_EXTERN acpi_exception_handler acpi_gbl_exception_handler;
ACPI_EXTERN acpi_init_handler acpi_gbl_init_handler; ACPI_EXTERN acpi_init_handler acpi_gbl_init_handler;
ACPI_EXTERN acpi_tbl_handler acpi_gbl_table_handler; ACPI_EXTERN acpi_tbl_handler acpi_gbl_table_handler;
......
...@@ -600,13 +600,22 @@ acpi_status(*acpi_parse_downwards) (struct acpi_walk_state * walk_state, ...@@ -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); 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 * Notify info - used to pass info to the deferred notify
* handler/dispatcher. * handler/dispatcher.
*/ */
struct acpi_notify_info { struct acpi_notify_info {
ACPI_STATE_COMMON struct acpi_namespace_node *node; ACPI_STATE_COMMON u8 handler_list_id;
union acpi_operand_object *handler_obj; 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 */ /* Generic state is union of structs above */
......
...@@ -206,8 +206,7 @@ struct acpi_object_method { ...@@ -206,8 +206,7 @@ struct acpi_object_method {
* Common fields for objects that support ASL notifications * Common fields for objects that support ASL notifications
*/ */
#define ACPI_COMMON_NOTIFY_INFO \ #define ACPI_COMMON_NOTIFY_INFO \
union acpi_operand_object *system_notify; /* Handler for system notifies */\ union acpi_operand_object *notify_list[2]; /* Handlers for system/device notifies */\
union acpi_operand_object *device_notify; /* Handler for driver notifies */\
union acpi_operand_object *handler; /* Handler for Address space */ union acpi_operand_object *handler; /* Handler for Address space */
struct acpi_object_notify_common { /* COMMON NOTIFY for POWER, PROCESSOR, DEVICE, and THERMAL */ struct acpi_object_notify_common { /* COMMON NOTIFY for POWER, PROCESSOR, DEVICE, and THERMAL */
...@@ -296,10 +295,10 @@ struct acpi_object_buffer_field { ...@@ -296,10 +295,10 @@ struct acpi_object_buffer_field {
struct acpi_object_notify_handler { struct acpi_object_notify_handler {
ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *node; /* Parent device */ ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *node; /* Parent device */
u32 handler_type; u32 handler_type; /* Type: Device/System/Both */
acpi_notify_handler handler; acpi_notify_handler handler; /* Handler address */
void *context; void *context;
struct acpi_object_notify_handler *next; union acpi_operand_object *next[2]; /* Device and System handler lists */
}; };
struct acpi_object_addr_handler { struct acpi_object_addr_handler {
......
...@@ -101,102 +101,77 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, ...@@ -101,102 +101,77 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
u32 notify_value) u32 notify_value)
{ {
union acpi_operand_object *obj_desc; union acpi_operand_object *obj_desc;
union acpi_operand_object *handler_obj = NULL; union acpi_operand_object *handler_list_head = NULL;
union acpi_generic_state *notify_info; union acpi_generic_state *info;
u8 handler_list_id = 0;
acpi_status status = AE_OK; acpi_status status = AE_OK;
ACPI_FUNCTION_NAME(ev_queue_notify_request); ACPI_FUNCTION_NAME(ev_queue_notify_request);
/* /* Are Notifies allowed on this object? */
* 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));
/* 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) {
/* Notify is allowed only on these types */ if (!acpi_ev_is_notify_object(node)) {
return (AE_TYPE);
}
case ACPI_TYPE_DEVICE: /* Get the correct notify list type (System or Device) */
case ACPI_TYPE_THERMAL:
case ACPI_TYPE_PROCESSOR:
if (notify_value <= ACPI_MAX_SYS_NOTIFY) { if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
handler_obj = handler_list_id = ACPI_SYSTEM_HANDLER_LIST;
obj_desc->common_notify.system_notify;
} else { } else {
handler_obj = handler_list_id = ACPI_DEVICE_HANDLER_LIST;
obj_desc->common_notify.device_notify;
} }
break;
default: /* Get the notify object attached to the namespace Node */
/* All other types are not supported */ obj_desc = acpi_ns_get_attached_object(node);
if (obj_desc) {
return (AE_TYPE); /* We have an attached object, Get the correct handler list */
}
handler_list_head =
obj_desc->common_notify.notify_list[handler_list_id];
} }
/* /*
* If there is a handler to run, schedule the dispatcher. * If there is no notify handler (Global or Local)
* Check for: * for this object, just ignore the notify
* 1) Global system notify handler
* 2) Global device notify handler
* 3) Per-device notify handler
*/ */
if ((acpi_gbl_system_notify.handler && if (!acpi_gbl_global_notify[handler_list_id].handler
(notify_value <= ACPI_MAX_SYS_NOTIFY)) || && !handler_list_head) {
(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 (!handler_obj) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Executing system notify handler for Notify (%4.4s, %X) " "No notify handler for Notify, ignoring (%4.4s, %X) node %p\n",
"node %p\n", acpi_ut_get_node_name(node), notify_value,
acpi_ut_get_node_name(node), node));
notify_value, node));
return (AE_OK);
} }
notify_info->common.descriptor_type = /* Setup notify info and schedule the notify dispatcher */
ACPI_DESC_TYPE_STATE_NOTIFY;
notify_info->notify.node = node;
notify_info->notify.value = (u16) notify_value;
notify_info->notify.handler_obj = handler_obj;
status = info = acpi_ut_create_generic_state();
acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch, if (!info) {
notify_info); return (AE_NO_MEMORY);
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->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, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"No notify handler for Notify (%4.4s, %X) node %p\n", "Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n",
acpi_ut_get_node_name(node), notify_value, acpi_ut_get_node_name(node),
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); return (status);
...@@ -217,60 +192,34 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, ...@@ -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) static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
{ {
union acpi_generic_state *notify_info = union acpi_generic_state *info = (union acpi_generic_state *)context;
(union acpi_generic_state *)context;
acpi_notify_handler global_handler = NULL;
void *global_context = NULL;
union acpi_operand_object *handler_obj; union acpi_operand_object *handler_obj;
ACPI_FUNCTION_ENTRY(); ACPI_FUNCTION_ENTRY();
/* /* Invoke a global notify handler if installed */
* 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) { if (info->notify.global->handler) {
global_handler = acpi_gbl_system_notify.handler; info->notify.global->handler(info->notify.node,
global_context = acpi_gbl_system_notify.context; info->notify.value,
info->notify.global->context);
} }
} else {
/* Global driver notification handler */
if (acpi_gbl_device_notify.handler) { /* Now invoke the local notify handler(s) if any are installed */
global_handler = acpi_gbl_device_notify.handler;
global_context = acpi_gbl_device_notify.context;
}
}
/* Invoke the system handler first, if present */
if (global_handler) {
global_handler(notify_info->notify.node,
notify_info->notify.value, global_context);
}
/* Now invoke the per-device handler, if present */ handler_obj = info->notify.handler_list_head;
while (handler_obj) {
handler_obj->notify.handler(info->notify.node,
info->notify.value,
handler_obj->notify.context);
handler_obj = notify_info->notify.handler_obj; handler_obj =
if (handler_obj) { handler_obj->notify.next[info->notify.handler_list_id];
struct acpi_object_notify_handler *notifier;
notifier = &handler_obj->notify;
while (notifier) {
notifier->handler(notify_info->notify.node,
notify_info->notify.value,
notifier->context);
notifier = notifier->next;
}
} }
/* All done with the info object */ /* All done with the info object */
acpi_ut_delete_generic_state(notify_info); acpi_ut_delete_generic_state(info);
} }
#if (!ACPI_REDUCED_HARDWARE) #if (!ACPI_REDUCED_HARDWARE)
......
This diff is collapsed.
...@@ -109,9 +109,9 @@ static struct acpi_exdump_info acpi_ex_dump_package[5] = { ...@@ -109,9 +109,9 @@ static struct acpi_exdump_info acpi_ex_dump_package[5] = {
static struct acpi_exdump_info acpi_ex_dump_device[4] = { static struct acpi_exdump_info acpi_ex_dump_device[4] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_device), NULL}, {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_device), NULL},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.handler), "Handler"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.handler), "Handler"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.system_notify), {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.notify_list[0]),
"System Notify"}, "System Notify"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.device_notify), {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.notify_list[1]),
"Device Notify"} "Device Notify"}
}; };
...@@ -158,9 +158,9 @@ static struct acpi_exdump_info acpi_ex_dump_power[5] = { ...@@ -158,9 +158,9 @@ static struct acpi_exdump_info acpi_ex_dump_power[5] = {
"System Level"}, "System Level"},
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(power_resource.resource_order), {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(power_resource.resource_order),
"Resource Order"}, "Resource Order"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.system_notify), {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.notify_list[0]),
"System Notify"}, "System Notify"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.device_notify), {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.notify_list[1]),
"Device Notify"} "Device Notify"}
}; };
...@@ -169,18 +169,18 @@ static struct acpi_exdump_info acpi_ex_dump_processor[7] = { ...@@ -169,18 +169,18 @@ static struct acpi_exdump_info acpi_ex_dump_processor[7] = {
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.proc_id), "Processor ID"}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.proc_id), "Processor ID"},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.length), "Length"}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.length), "Length"},
{ACPI_EXD_ADDRESS, ACPI_EXD_OFFSET(processor.address), "Address"}, {ACPI_EXD_ADDRESS, ACPI_EXD_OFFSET(processor.address), "Address"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.system_notify), {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.notify_list[0]),
"System Notify"}, "System Notify"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.device_notify), {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.notify_list[1]),
"Device Notify"}, "Device Notify"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.handler), "Handler"} {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.handler), "Handler"}
}; };
static struct acpi_exdump_info acpi_ex_dump_thermal[4] = { static struct acpi_exdump_info acpi_ex_dump_thermal[4] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_thermal), NULL}, {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_thermal), NULL},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(thermal_zone.system_notify), {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(thermal_zone.notify_list[0]),
"System Notify"}, "System Notify"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(thermal_zone.device_notify), {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(thermal_zone.notify_list[1]),
"Device Notify"}, "Device Notify"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(thermal_zone.handler), "Handler"} {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(thermal_zone.handler), "Handler"}
}; };
...@@ -241,10 +241,15 @@ static struct acpi_exdump_info acpi_ex_dump_address_handler[6] = { ...@@ -241,10 +241,15 @@ static struct acpi_exdump_info acpi_ex_dump_address_handler[6] = {
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(address_space.context), "Context"} {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(address_space.context), "Context"}
}; };
static struct acpi_exdump_info acpi_ex_dump_notify[3] = { static struct acpi_exdump_info acpi_ex_dump_notify[7] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_notify), NULL}, {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_notify), NULL},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.node), "Node"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.node), "Node"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.context), "Context"} {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(notify.handler_type), "Handler Type"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.handler), "Handler"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.context), "Context"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.next[0]),
"Next System Notify"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.next[1]), "Next Device Notify"}
}; };
/* Miscellaneous tables */ /* Miscellaneous tables */
......
...@@ -152,7 +152,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) ...@@ -152,7 +152,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
case ACPI_TYPE_PROCESSOR: case ACPI_TYPE_PROCESSOR:
case ACPI_TYPE_THERMAL: case ACPI_TYPE_THERMAL:
/* Walk the notify handler list for this object */ /* Walk the address handler list for this object */
handler_desc = object->common_notify.handler; handler_desc = object->common_notify.handler;
while (handler_desc) { while (handler_desc) {
...@@ -480,6 +480,7 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action) ...@@ -480,6 +480,7 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
acpi_status status = AE_OK; acpi_status status = AE_OK;
union acpi_generic_state *state_list = NULL; union acpi_generic_state *state_list = NULL;
union acpi_operand_object *next_object = NULL; union acpi_operand_object *next_object = NULL;
union acpi_operand_object *prev_object;
union acpi_generic_state *state; union acpi_generic_state *state;
u32 i; u32 i;
...@@ -505,12 +506,21 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action) ...@@ -505,12 +506,21 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
case ACPI_TYPE_POWER: case ACPI_TYPE_POWER:
case ACPI_TYPE_THERMAL: case ACPI_TYPE_THERMAL:
/* Update the notify objects for these types (if present) */ /*
* Update the notify objects for these types (if present)
acpi_ut_update_ref_count(object->common_notify. * Two lists, system and device notify handlers.
system_notify, action); */
acpi_ut_update_ref_count(object->common_notify. for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
device_notify, action); prev_object =
object->common_notify.notify_list[i];
while (prev_object) {
next_object =
prev_object->notify.next[i];
acpi_ut_update_ref_count(prev_object,
action);
prev_object = next_object;
}
}
break; break;
case ACPI_TYPE_PACKAGE: case ACPI_TYPE_PACKAGE:
......
...@@ -304,8 +304,8 @@ acpi_status acpi_ut_init_globals(void) ...@@ -304,8 +304,8 @@ acpi_status acpi_ut_init_globals(void)
/* Global handlers */ /* Global handlers */
acpi_gbl_system_notify.handler = NULL; acpi_gbl_global_notify[0].handler = NULL;
acpi_gbl_device_notify.handler = NULL; acpi_gbl_global_notify[1].handler = NULL;
acpi_gbl_exception_handler = NULL; acpi_gbl_exception_handler = NULL;
acpi_gbl_init_handler = NULL; acpi_gbl_init_handler = NULL;
acpi_gbl_table_handler = NULL; acpi_gbl_table_handler = NULL;
......
...@@ -706,10 +706,14 @@ typedef u32 acpi_event_status; ...@@ -706,10 +706,14 @@ typedef u32 acpi_event_status;
#define ACPI_DEVICE_NOTIFY 0x2 #define ACPI_DEVICE_NOTIFY 0x2
#define ACPI_ALL_NOTIFY (ACPI_SYSTEM_NOTIFY | ACPI_DEVICE_NOTIFY) #define ACPI_ALL_NOTIFY (ACPI_SYSTEM_NOTIFY | ACPI_DEVICE_NOTIFY)
#define ACPI_MAX_NOTIFY_HANDLER_TYPE 0x3 #define ACPI_MAX_NOTIFY_HANDLER_TYPE 0x3
#define ACPI_NUM_NOTIFY_TYPES 2
#define ACPI_MAX_SYS_NOTIFY 0x7F #define ACPI_MAX_SYS_NOTIFY 0x7F
#define ACPI_MAX_DEVICE_SPECIFIC_NOTIFY 0xBF #define ACPI_MAX_DEVICE_SPECIFIC_NOTIFY 0xBF
#define ACPI_SYSTEM_HANDLER_LIST 0 /* Used as index, must be SYSTEM_NOTIFY -1 */
#define ACPI_DEVICE_HANDLER_LIST 1 /* Used as index, must be DEVICE_NOTIFY -1 */
/* Address Space (Operation Region) Types */ /* Address Space (Operation Region) Types */
typedef u8 acpi_adr_space_type; typedef u8 acpi_adr_space_type;
......
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