Skip to content

Commit

Permalink
ACPICA: Events: Introduce acpi_set_gpe()/acpi_finish_gpe() to reduce …
Browse files Browse the repository at this point in the history
…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>
  • Loading branch information
Lv Zheng authored and Rafael J. Wysocki committed Feb 5, 2015
1 parent 0d0988a commit eb3d80f
Showing 1 changed file with 105 additions and 0 deletions.
105 changes: 105 additions & 0 deletions drivers/acpi/acpica/evxfgpe.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)

/*******************************************************************************
*
Expand Down Expand Up @@ -530,6 +592,49 @@ acpi_get_gpe_status(acpi_handle gpe_device,

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
Expand Down

0 comments on commit eb3d80f

Please sign in to comment.