diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2018-04-02 11:57:58 +0300 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2018-04-02 11:57:58 +0300 |
commit | ae02168d7877daf3a8ffcc60237a64398ed943aa (patch) | |
tree | 3e3c591765217cc70db6d212d4ce3f98730d8939 /drivers/acpi/acpica/evgpe.c | |
parent | 8b29d29abc484d638213dd79a18a95ae7e5bb402 (diff) | |
parent | 4860ae7f58fa777405239e26698193801105fb2f (diff) | |
download | linux-ae02168d7877daf3a8ffcc60237a64398ed943aa.tar.xz |
Merge branch 'acpica'
* acpica: (21 commits)
ACPICA: Update version to 20180313
ACPICA: Cleanup/simplify module-level code support
ACPICA: Events: add a return on failure from acpi_hw_register_read
ACPICA: adding SPDX headers
ACPICA: Rename a global for clarity, no functional change
ACPICA: macros: fix ACPI_ERROR_NAMESPACE macro
ACPICA: Change a compile-time option to a runtime option
ACPICA: Remove calling of _STA from acpi_get_object_info()
ACPICA: AML Debug Object: Don't ignore output of zero-length strings
ACPICA: Fix memory leak on unusual memory leak
ACPICA: Events: Dispatch GPEs after enabling for the first time
ACPICA: Events: Add parallel GPE handling support to fix potential redundant _Exx evaluations
ACPICA: Events: Stop unconditionally clearing ACPI IRQs during suspend/resume
ACPICA: acpi: acpica: fix acpi operand cache leak in nseval.c
ACPICA: Update version to 20180209
ACPICA: Add option to disable Package object name resolution errors
ACPICA: Integrate package handling with module-level code
ACPICA: Revert "Fix for implicit result conversion for the To____ functions"
ACPICA: Update for some debug output. No functional change
ACPICA: Update error message, no functional change
...
Diffstat (limited to 'drivers/acpi/acpica/evgpe.c')
-rw-r--r-- | drivers/acpi/acpica/evgpe.c | 282 |
1 files changed, 132 insertions, 150 deletions
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index 410a3907c051..abbd59063906 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -1,45 +1,11 @@ +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 /****************************************************************************** * * Module Name: evgpe - General Purpose Event handling and dispatch * - *****************************************************************************/ - -/* * Copyright (C) 2000 - 2018, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ + * + *****************************************************************************/ #include <acpi/acpi.h> #include "accommon.h" @@ -105,7 +71,7 @@ acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info) * * RETURN: Status * - * DESCRIPTION: Clear a GPE of stale events and enable it. + * DESCRIPTION: Enable a GPE. * ******************************************************************************/ @@ -115,13 +81,6 @@ acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) ACPI_FUNCTION_TRACE(ev_enable_gpe); - /* Clear the GPE (of stale events) */ - - status = acpi_hw_clear_gpe(gpe_event_info); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - /* Enable the requested GPE */ status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE); @@ -381,17 +340,12 @@ struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device, u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list) { - acpi_status status; struct acpi_gpe_block_info *gpe_block; struct acpi_namespace_node *gpe_device; struct acpi_gpe_register_info *gpe_register_info; struct acpi_gpe_event_info *gpe_event_info; u32 gpe_number; - struct acpi_gpe_handler_info *gpe_handler_info; u32 int_status = ACPI_INTERRUPT_NOT_HANDLED; - u8 enabled_status_byte; - u64 status_reg; - u64 enable_reg; acpi_cpu_flags flags; u32 i; u32 j; @@ -448,49 +402,11 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list) continue; } - /* Read the Status Register */ - - status = - acpi_hw_read(&status_reg, - &gpe_register_info->status_address); - if (ACPI_FAILURE(status)) { - goto unlock_and_exit; - } - - /* Read the Enable Register */ - - status = - acpi_hw_read(&enable_reg, - &gpe_register_info->enable_address); - if (ACPI_FAILURE(status)) { - goto unlock_and_exit; - } - - ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS, - "Read registers for GPE %02X-%02X: Status=%02X, Enable=%02X, " - "RunEnable=%02X, WakeEnable=%02X\n", - gpe_register_info->base_gpe_number, - gpe_register_info->base_gpe_number + - (ACPI_GPE_REGISTER_WIDTH - 1), - (u32)status_reg, (u32)enable_reg, - gpe_register_info->enable_for_run, - gpe_register_info->enable_for_wake)); - - /* Check if there is anything active at all in this register */ - - enabled_status_byte = (u8)(status_reg & enable_reg); - if (!enabled_status_byte) { - - /* No active GPEs in this register, move on */ - - continue; - } - /* Now look at the individual GPEs in this byte register */ for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { - /* Examine one GPE bit */ + /* Detect and dispatch one GPE bit */ gpe_event_info = &gpe_block-> @@ -498,71 +414,18 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list) ACPI_GPE_REGISTER_WIDTH) + j]; gpe_number = j + gpe_register_info->base_gpe_number; - - if (enabled_status_byte & (1 << j)) { - - /* Invoke global event handler if present */ - - acpi_gpe_count++; - if (acpi_gbl_global_event_handler) { - acpi_gbl_global_event_handler - (ACPI_EVENT_TYPE_GPE, - gpe_device, gpe_number, - acpi_gbl_global_event_handler_context); - } - - /* Found an active GPE */ - - if (ACPI_GPE_DISPATCH_TYPE - (gpe_event_info->flags) == - ACPI_GPE_DISPATCH_RAW_HANDLER) { - - /* Dispatch the event to a raw handler */ - - gpe_handler_info = - gpe_event_info->dispatch. - handler; - - /* - * There is no protection around the namespace node - * and the GPE handler to ensure a safe destruction - * because: - * 1. The namespace node is expected to always - * exist after loading a table. - * 2. The GPE handler is expected to be flushed by - * acpi_os_wait_events_complete() before the - * destruction. - */ - acpi_os_release_lock - (acpi_gbl_gpe_lock, flags); - int_status |= - gpe_handler_info-> - address(gpe_device, - gpe_number, - gpe_handler_info-> - context); - flags = - acpi_os_acquire_lock - (acpi_gbl_gpe_lock); - } else { - /* - * Dispatch the event to a standard handler or - * method. - */ - int_status |= - acpi_ev_gpe_dispatch - (gpe_device, gpe_event_info, - gpe_number); - } - } + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); + int_status |= + acpi_ev_detect_gpe(gpe_device, + gpe_event_info, + gpe_number); + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); } } gpe_block = gpe_block->next; } -unlock_and_exit: - acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return (int_status); } @@ -735,6 +598,127 @@ acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info) /******************************************************************************* * + * FUNCTION: acpi_ev_detect_gpe + * + * PARAMETERS: gpe_device - Device node. NULL for GPE0/GPE1 + * gpe_event_info - Info for this GPE + * gpe_number - Number relative to the parent GPE block + * + * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED + * + * DESCRIPTION: Detect and dispatch a General Purpose Event to either a function + * (e.g. EC) or method (e.g. _Lxx/_Exx) handler. + * NOTE: GPE is W1C, so it is possible to handle a single GPE from both + * task and irq context in parallel as long as the process to + * detect and mask the GPE is atomic. + * However the atomicity of ACPI_GPE_DISPATCH_RAW_HANDLER is + * dependent on the raw handler itself. + * + ******************************************************************************/ + +u32 +acpi_ev_detect_gpe(struct acpi_namespace_node *gpe_device, + struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) +{ + u32 int_status = ACPI_INTERRUPT_NOT_HANDLED; + u8 enabled_status_byte; + u64 status_reg; + u64 enable_reg; + u32 register_bit; + struct acpi_gpe_register_info *gpe_register_info; + struct acpi_gpe_handler_info *gpe_handler_info; + acpi_cpu_flags flags; + acpi_status status; + + ACPI_FUNCTION_TRACE(ev_gpe_detect); + + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); + + /* Get the info block for the entire GPE register */ + + gpe_register_info = gpe_event_info->register_info; + + /* Get the register bitmask for this GPE */ + + register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info); + + /* GPE currently enabled (enable bit == 1)? */ + + status = acpi_hw_read(&enable_reg, &gpe_register_info->enable_address); + if (ACPI_FAILURE(status)) { + goto error_exit; + } + + /* GPE currently active (status bit == 1)? */ + + status = acpi_hw_read(&status_reg, &gpe_register_info->status_address); + if (ACPI_FAILURE(status)) { + goto error_exit; + } + + /* Check if there is anything active at all in this GPE */ + + ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS, + "Read registers for GPE %02X: Status=%02X, Enable=%02X, " + "RunEnable=%02X, WakeEnable=%02X\n", + gpe_number, + (u32)(status_reg & register_bit), + (u32)(enable_reg & register_bit), + gpe_register_info->enable_for_run, + gpe_register_info->enable_for_wake)); + + enabled_status_byte = (u8)(status_reg & enable_reg); + if (!(enabled_status_byte & register_bit)) { + goto error_exit; + } + + /* Invoke global event handler if present */ + + acpi_gpe_count++; + if (acpi_gbl_global_event_handler) { + acpi_gbl_global_event_handler(ACPI_EVENT_TYPE_GPE, + gpe_device, gpe_number, + acpi_gbl_global_event_handler_context); + } + + /* Found an active GPE */ + + if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == + ACPI_GPE_DISPATCH_RAW_HANDLER) { + + /* Dispatch the event to a raw handler */ + + gpe_handler_info = gpe_event_info->dispatch.handler; + + /* + * There is no protection around the namespace node + * and the GPE handler to ensure a safe destruction + * because: + * 1. The namespace node is expected to always + * exist after loading a table. + * 2. The GPE handler is expected to be flushed by + * acpi_os_wait_events_complete() before the + * destruction. + */ + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); + int_status |= + gpe_handler_info->address(gpe_device, gpe_number, + gpe_handler_info->context); + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); + } else { + /* Dispatch the event to a standard handler or method. */ + + int_status |= acpi_ev_gpe_dispatch(gpe_device, + gpe_event_info, gpe_number); + } + +error_exit: + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); + return (int_status); +} + +/******************************************************************************* + * * FUNCTION: acpi_ev_gpe_dispatch * * PARAMETERS: gpe_device - Device node. NULL for GPE0/GPE1 @@ -746,8 +730,6 @@ acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info) * DESCRIPTION: Dispatch a General Purpose Event to either a function (e.g. EC) * or method (e.g. _Lxx/_Exx) handler. * - * This function executes at interrupt level. - * ******************************************************************************/ u32 |