ACPICA: Events: Introduce acpi_set_gpe()/acpi_finish_gpe() to reduce divergences

This can help to reduce source code differences between Linux and ACPICA
upstream. Further driver cleanups also require these APIs to eliminate GPE
storms.
1. acpi_set_gpe(): An API that driver should invoke in the case it wants
                   to disable/enable IRQ without honoring the reference
                   count implemented in the acpi_disable_gpe() and
                   acpi_enable_gpe(). Note that this API should only be
                   invoked inside a acpi_enable_gpe()/acpi_disable_gpe()
                   pair.
2. acpi_finish_gpe(): Drivers returned ACPI_REENABLE_GPE unset from the
                      GPE handler should use this API instead of
                      invoking acpi_set_gpe()/acpi_enable_gpe() to
                      re-enable the GPE.
The GPE APIs can be invoked inside of a GPE handler or in the task context
with a driver provided lock held. This driver provided lock is safe to be
held in the GPE handler by the driver.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
Lv Zheng 2015-02-05 16:27:09 +08:00 committed by Rafael J. Wysocki
parent 0d0988af81
commit eb3d80f729
1 changed files with 105 additions and 0 deletions

View File

@ -183,6 +183,68 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number)
ACPI_EXPORT_SYMBOL(acpi_disable_gpe)
/*******************************************************************************
*
* FUNCTION: acpi_set_gpe
*
* PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
* gpe_number - GPE level within the GPE block
* action - ACPI_GPE_ENABLE or ACPI_GPE_DISABLE
*
* RETURN: Status
*
* DESCRIPTION: Enable or disable an individual GPE. This function bypasses
* the reference count mechanism used in the acpi_enable_gpe and
* acpi_disable_gpe interfaces -- and should be used with care.
*
* Note: Typically used to disable a runtime GPE for short period of time,
* then re-enable it, without disturbing the existing reference counts. This
* is useful, for example, in the Embedded Controller (EC) driver.
*
******************************************************************************/
acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action)
{
struct acpi_gpe_event_info *gpe_event_info;
acpi_status status;
acpi_cpu_flags flags;
ACPI_FUNCTION_TRACE(acpi_set_gpe);
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
/* Ensure that we have a valid GPE number */
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
if (!gpe_event_info) {
status = AE_BAD_PARAMETER;
goto unlock_and_exit;
}
/* Perform the action */
switch (action) {
case ACPI_GPE_ENABLE:
status = acpi_ev_enable_gpe(gpe_event_info);
break;
case ACPI_GPE_DISABLE:
status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
break;
default:
status = AE_BAD_PARAMETER;
break;
}
unlock_and_exit:
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
return_ACPI_STATUS(status);
}
ACPI_EXPORT_SYMBOL(acpi_set_gpe)
/*******************************************************************************
*
@ -530,6 +592,49 @@ unlock_and_exit:
ACPI_EXPORT_SYMBOL(acpi_get_gpe_status)
/*******************************************************************************
*
* FUNCTION: acpi_finish_gpe
*
* PARAMETERS: gpe_device - Namespace node for the GPE Block
* (NULL for FADT defined GPEs)
* gpe_number - GPE level within the GPE block
*
* RETURN: Status
*
* DESCRIPTION: Clear and conditionally reenable a GPE. This completes the GPE
* processing. Intended for use by asynchronous host-installed
* GPE handlers. The GPE is only reenabled if the enable_for_run bit
* is set in the GPE info.
*
******************************************************************************/
acpi_status acpi_finish_gpe(acpi_handle gpe_device, u32 gpe_number)
{
struct acpi_gpe_event_info *gpe_event_info;
acpi_status status;
acpi_cpu_flags flags;
ACPI_FUNCTION_TRACE(acpi_finish_gpe);
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
/* Ensure that we have a valid GPE number */
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
if (!gpe_event_info) {
status = AE_BAD_PARAMETER;
goto unlock_and_exit;
}
status = acpi_ev_finish_gpe(gpe_event_info);
unlock_and_exit:
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
return_ACPI_STATUS(status);
}
ACPI_EXPORT_SYMBOL(acpi_finish_gpe)
/******************************************************************************
*
* FUNCTION: acpi_disable_all_gpes