diff options
| author | Lv Zheng <lv.zheng@intel.com> | 2015-02-05 03:27:09 -0500 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-02-05 09:34:51 -0500 |
| commit | eb3d80f729e07394685239ddd137fbee5c13a2ea (patch) | |
| tree | 55c7193f2abc208f824b6909cd91fbc20bb77776 | |
| parent | 0d0988af81ac809b30f818f0c0f065327ff6423b (diff) | |
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>
| -rw-r--r-- | drivers/acpi/acpica/evxfgpe.c | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index b8af53bce74b..caaeb1a7bf4b 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c | |||
| @@ -183,6 +183,68 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number) | |||
| 183 | 183 | ||
| 184 | ACPI_EXPORT_SYMBOL(acpi_disable_gpe) | 184 | ACPI_EXPORT_SYMBOL(acpi_disable_gpe) |
| 185 | 185 | ||
| 186 | /******************************************************************************* | ||
| 187 | * | ||
| 188 | * FUNCTION: acpi_set_gpe | ||
| 189 | * | ||
| 190 | * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 | ||
| 191 | * gpe_number - GPE level within the GPE block | ||
| 192 | * action - ACPI_GPE_ENABLE or ACPI_GPE_DISABLE | ||
| 193 | * | ||
| 194 | * RETURN: Status | ||
| 195 | * | ||
| 196 | * DESCRIPTION: Enable or disable an individual GPE. This function bypasses | ||
| 197 | * the reference count mechanism used in the acpi_enable_gpe and | ||
| 198 | * acpi_disable_gpe interfaces -- and should be used with care. | ||
| 199 | * | ||
| 200 | * Note: Typically used to disable a runtime GPE for short period of time, | ||
| 201 | * then re-enable it, without disturbing the existing reference counts. This | ||
| 202 | * is useful, for example, in the Embedded Controller (EC) driver. | ||
| 203 | * | ||
| 204 | ******************************************************************************/ | ||
| 205 | acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action) | ||
| 206 | { | ||
| 207 | struct acpi_gpe_event_info *gpe_event_info; | ||
| 208 | acpi_status status; | ||
| 209 | acpi_cpu_flags flags; | ||
| 210 | |||
| 211 | ACPI_FUNCTION_TRACE(acpi_set_gpe); | ||
| 212 | |||
| 213 | flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); | ||
| 214 | |||
| 215 | /* Ensure that we have a valid GPE number */ | ||
| 216 | |||
| 217 | gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); | ||
| 218 | if (!gpe_event_info) { | ||
| 219 | status = AE_BAD_PARAMETER; | ||
| 220 | goto unlock_and_exit; | ||
| 221 | } | ||
| 222 | |||
| 223 | /* Perform the action */ | ||
| 224 | |||
| 225 | switch (action) { | ||
| 226 | case ACPI_GPE_ENABLE: | ||
| 227 | |||
| 228 | status = acpi_ev_enable_gpe(gpe_event_info); | ||
| 229 | break; | ||
| 230 | |||
| 231 | case ACPI_GPE_DISABLE: | ||
| 232 | |||
| 233 | status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); | ||
| 234 | break; | ||
| 235 | |||
| 236 | default: | ||
| 237 | |||
| 238 | status = AE_BAD_PARAMETER; | ||
| 239 | break; | ||
| 240 | } | ||
| 241 | |||
| 242 | unlock_and_exit: | ||
| 243 | acpi_os_release_lock(acpi_gbl_gpe_lock, flags); | ||
| 244 | return_ACPI_STATUS(status); | ||
| 245 | } | ||
| 246 | |||
| 247 | ACPI_EXPORT_SYMBOL(acpi_set_gpe) | ||
| 186 | 248 | ||
| 187 | /******************************************************************************* | 249 | /******************************************************************************* |
| 188 | * | 250 | * |
| @@ -530,6 +592,49 @@ unlock_and_exit: | |||
| 530 | 592 | ||
| 531 | ACPI_EXPORT_SYMBOL(acpi_get_gpe_status) | 593 | ACPI_EXPORT_SYMBOL(acpi_get_gpe_status) |
| 532 | 594 | ||
| 595 | /******************************************************************************* | ||
| 596 | * | ||
| 597 | * FUNCTION: acpi_finish_gpe | ||
| 598 | * | ||
| 599 | * PARAMETERS: gpe_device - Namespace node for the GPE Block | ||
| 600 | * (NULL for FADT defined GPEs) | ||
| 601 | * gpe_number - GPE level within the GPE block | ||
| 602 | * | ||
| 603 | * RETURN: Status | ||
| 604 | * | ||
| 605 | * DESCRIPTION: Clear and conditionally reenable a GPE. This completes the GPE | ||
| 606 | * processing. Intended for use by asynchronous host-installed | ||
| 607 | * GPE handlers. The GPE is only reenabled if the enable_for_run bit | ||
| 608 | * is set in the GPE info. | ||
| 609 | * | ||
| 610 | ******************************************************************************/ | ||
| 611 | acpi_status acpi_finish_gpe(acpi_handle gpe_device, u32 gpe_number) | ||
| 612 | { | ||
| 613 | struct acpi_gpe_event_info *gpe_event_info; | ||
| 614 | acpi_status status; | ||
| 615 | acpi_cpu_flags flags; | ||
| 616 | |||
| 617 | ACPI_FUNCTION_TRACE(acpi_finish_gpe); | ||
| 618 | |||
| 619 | flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); | ||
| 620 | |||
| 621 | /* Ensure that we have a valid GPE number */ | ||
| 622 | |||
| 623 | gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); | ||
| 624 | if (!gpe_event_info) { | ||
| 625 | status = AE_BAD_PARAMETER; | ||
| 626 | goto unlock_and_exit; | ||
| 627 | } | ||
| 628 | |||
| 629 | status = acpi_ev_finish_gpe(gpe_event_info); | ||
| 630 | |||
| 631 | unlock_and_exit: | ||
| 632 | acpi_os_release_lock(acpi_gbl_gpe_lock, flags); | ||
| 633 | return_ACPI_STATUS(status); | ||
| 634 | } | ||
| 635 | |||
| 636 | ACPI_EXPORT_SYMBOL(acpi_finish_gpe) | ||
| 637 | |||
| 533 | /****************************************************************************** | 638 | /****************************************************************************** |
| 534 | * | 639 | * |
| 535 | * FUNCTION: acpi_disable_all_gpes | 640 | * FUNCTION: acpi_disable_all_gpes |
