ACPICA: Implicit notify support
This feature provides an automatic device notification for wake devices when a wakeup GPE occurs and there is no corresponding GPE method or handler. Rather than ignoring such a GPE, an implicit AML Notify operation is performed on the parent device object. This feature is not part of the ACPI specification and is provided for Windows compatibility only. Signed-off-by: Lin Ming <ming.m.lin@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
此提交包含在:
@@ -115,12 +115,13 @@ acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
|
||||
ACPI_FUNCTION_TRACE(ev_enable_gpe);
|
||||
|
||||
/*
|
||||
* We will only allow a GPE to be enabled if it has either an
|
||||
* associated method (_Lxx/_Exx) or a handler. Otherwise, the
|
||||
* GPE will be immediately disabled by acpi_ev_gpe_dispatch the
|
||||
* first time it fires.
|
||||
* We will only allow a GPE to be enabled if it has either an associated
|
||||
* method (_Lxx/_Exx) or a handler, or is using the implicit notify
|
||||
* feature. Otherwise, the GPE will be immediately disabled by
|
||||
* acpi_ev_gpe_dispatch the first time it fires.
|
||||
*/
|
||||
if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)) {
|
||||
if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
|
||||
ACPI_GPE_DISPATCH_NONE) {
|
||||
return_ACPI_STATUS(AE_NO_HANDLER);
|
||||
}
|
||||
|
||||
@@ -486,12 +487,26 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
|
||||
return_VOID;
|
||||
}
|
||||
|
||||
/*
|
||||
* Must check for control method type dispatch one more time to avoid a
|
||||
* race with ev_gpe_install_handler
|
||||
*/
|
||||
if ((local_gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
|
||||
ACPI_GPE_DISPATCH_METHOD) {
|
||||
/* Do the correct dispatch - normal method or implicit notify */
|
||||
|
||||
switch (local_gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
|
||||
case ACPI_GPE_DISPATCH_NOTIFY:
|
||||
|
||||
/*
|
||||
* Implicit notify.
|
||||
* Dispatch a DEVICE_WAKE notify to the appropriate handler.
|
||||
* NOTE: the request is queued for execution after this method
|
||||
* completes. The notify handlers are NOT invoked synchronously
|
||||
* from this thread -- because handlers may in turn run other
|
||||
* control methods.
|
||||
*/
|
||||
status =
|
||||
acpi_ev_queue_notify_request(local_gpe_event_info->dispatch.
|
||||
device_node,
|
||||
ACPI_NOTIFY_DEVICE_WAKE);
|
||||
break;
|
||||
|
||||
case ACPI_GPE_DISPATCH_METHOD:
|
||||
|
||||
/* Allocate the evaluation information block */
|
||||
|
||||
@@ -518,6 +533,11 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
|
||||
(local_gpe_event_info->dispatch.
|
||||
method_node)));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return_VOID; /* Should never happen */
|
||||
}
|
||||
|
||||
/* Defer enabling of GPE until all notify handlers are done */
|
||||
@@ -531,6 +551,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
|
||||
return_VOID;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ev_asynch_enable_gpe
|
||||
@@ -541,38 +562,60 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
|
||||
* RETURN: None
|
||||
*
|
||||
* DESCRIPTION: Asynchronous clear/enable for GPE. This allows the GPE to
|
||||
* complete.
|
||||
* complete (i.e., finish execution of Notify)
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context)
|
||||
{
|
||||
struct acpi_gpe_event_info *gpe_event_info = context;
|
||||
|
||||
(void)acpi_ev_finish_gpe(gpe_event_info);
|
||||
|
||||
ACPI_FREE(gpe_event_info);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ev_finish_gpe
|
||||
*
|
||||
* PARAMETERS: gpe_event_info - Info for this GPE
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Clear/Enable a GPE. Common code that is used after execution
|
||||
* of a GPE method or a synchronous or asynchronous GPE handler.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
|
||||
ACPI_GPE_LEVEL_TRIGGERED) {
|
||||
/*
|
||||
* GPE is level-triggered, we clear the GPE status bit after handling
|
||||
* the event.
|
||||
* GPE is level-triggered, we clear the GPE status bit after
|
||||
* handling the event.
|
||||
*/
|
||||
status = acpi_hw_clear_gpe(gpe_event_info);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto exit;
|
||||
return (status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable this GPE, conditionally. This means that the GPE will only be
|
||||
* physically enabled if the enable_for_run bit is set in the event_info
|
||||
* Enable this GPE, conditionally. This means that the GPE will
|
||||
* only be physically enabled if the enable_for_run bit is set
|
||||
* in the event_info.
|
||||
*/
|
||||
(void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_CONDITIONAL_ENABLE);
|
||||
|
||||
exit:
|
||||
ACPI_FREE(gpe_event_info);
|
||||
return;
|
||||
return (AE_OK);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ev_gpe_dispatch
|
||||
@@ -595,6 +638,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
|
||||
struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
|
||||
{
|
||||
acpi_status status;
|
||||
u32 return_value;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ev_gpe_dispatch);
|
||||
|
||||
@@ -616,54 +660,49 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
|
||||
}
|
||||
|
||||
/*
|
||||
* Dispatch the GPE to either an installed handler, or the control method
|
||||
* associated with this GPE (_Lxx or _Exx). If a handler exists, we invoke
|
||||
* it and do not attempt to run the method. If there is neither a handler
|
||||
* nor a method, we disable this GPE to prevent further such pointless
|
||||
* events from firing.
|
||||
* Always disable the GPE so that it does not keep firing before
|
||||
* any asynchronous activity completes (either from the execution
|
||||
* of a GPE method or an asynchronous GPE handler.)
|
||||
*
|
||||
* If there is no handler or method to run, just disable the
|
||||
* GPE and leave it disabled permanently to prevent further such
|
||||
* pointless events from firing.
|
||||
*/
|
||||
status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status,
|
||||
"Unable to disable GPE%02X", gpe_number));
|
||||
return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dispatch the GPE to either an installed handler or the control
|
||||
* method associated with this GPE (_Lxx or _Exx). If a handler
|
||||
* exists, we invoke it and do not attempt to run the method.
|
||||
* If there is neither a handler nor a method, leave the GPE
|
||||
* disabled.
|
||||
*/
|
||||
switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
|
||||
case ACPI_GPE_DISPATCH_HANDLER:
|
||||
|
||||
/*
|
||||
* Invoke the installed handler (at interrupt level)
|
||||
* Ignore return status for now.
|
||||
* TBD: leave GPE disabled on error?
|
||||
*/
|
||||
(void)gpe_event_info->dispatch.handler->address(gpe_device,
|
||||
gpe_number,
|
||||
gpe_event_info->
|
||||
dispatch.
|
||||
handler->
|
||||
context);
|
||||
/* Invoke the installed handler (at interrupt level) */
|
||||
|
||||
/* It is now safe to clear level-triggered events. */
|
||||
return_value =
|
||||
gpe_event_info->dispatch.handler->address(gpe_device,
|
||||
gpe_number,
|
||||
gpe_event_info->
|
||||
dispatch.handler->
|
||||
context);
|
||||
|
||||
if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
|
||||
ACPI_GPE_LEVEL_TRIGGERED) {
|
||||
status = acpi_hw_clear_gpe(gpe_event_info);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status,
|
||||
"Unable to clear GPE[0x%2X]",
|
||||
gpe_number));
|
||||
return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
|
||||
}
|
||||
/* If requested, clear (if level-triggered) and reenable the GPE */
|
||||
|
||||
if (return_value & ACPI_REENABLE_GPE) {
|
||||
(void)acpi_ev_finish_gpe(gpe_event_info);
|
||||
}
|
||||
break;
|
||||
|
||||
case ACPI_GPE_DISPATCH_METHOD:
|
||||
|
||||
/*
|
||||
* Disable the GPE, so it doesn't keep firing before the method has a
|
||||
* chance to run (it runs asynchronously with interrupts enabled).
|
||||
*/
|
||||
status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status,
|
||||
"Unable to disable GPE[0x%2X]",
|
||||
gpe_number));
|
||||
return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
|
||||
}
|
||||
case ACPI_GPE_DISPATCH_NOTIFY:
|
||||
|
||||
/*
|
||||
* Execute the method associated with the GPE
|
||||
@@ -690,17 +729,6 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
|
||||
"No handler or method for GPE[0x%2X], disabling event",
|
||||
gpe_number));
|
||||
|
||||
/*
|
||||
* Disable the GPE. The GPE will remain disabled a handler
|
||||
* is installed or ACPICA is restarted.
|
||||
*/
|
||||
status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status,
|
||||
"Unable to disable GPE[0x%2X]",
|
||||
gpe_number));
|
||||
return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
新增問題並參考
封鎖使用者