diff options
author | Len Brown <len.brown@intel.com> | 2010-08-15 06:25:40 +0200 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2010-08-15 06:25:40 +0200 |
commit | c172cb73bc79fe69915b1a1a48e374aa4b1f8a59 (patch) | |
tree | eb3d6415914968441c063f7282e824b14b5a5edb /drivers/acpi/acpica/evxfevnt.c | |
parent | Merge branch 'bugzilla-16422' into release (diff) | |
parent | ACPI / ACPICA: Fix reference counting problems with GPE handlers (diff) | |
download | linux-c172cb73bc79fe69915b1a1a48e374aa4b1f8a59.tar.xz linux-c172cb73bc79fe69915b1a1a48e374aa4b1f8a59.zip |
Merge branch 'acpica-gpe' into release
Diffstat (limited to 'drivers/acpi/acpica/evxfevnt.c')
-rw-r--r-- | drivers/acpi/acpica/evxfevnt.c | 233 |
1 files changed, 74 insertions, 159 deletions
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index 18b3f1468b7d..304825528d48 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -213,101 +213,71 @@ ACPI_EXPORT_SYMBOL(acpi_enable_event) /******************************************************************************* * - * FUNCTION: acpi_clear_and_enable_gpe - * - * PARAMETERS: gpe_event_info - GPE to enable - * - * RETURN: Status - * - * DESCRIPTION: Clear the given GPE from stale events and enable it. - * - ******************************************************************************/ -static acpi_status -acpi_clear_and_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) -{ - acpi_status status; - - /* - * 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. - */ - if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)) { - return_ACPI_STATUS(AE_NO_HANDLER); - } - - /* 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); - - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_set_gpe + * FUNCTION: acpi_gpe_wakeup * * 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 + * Action - Enable or 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. + * DESCRIPTION: Set or clear the GPE's wakeup enable mask bit. * ******************************************************************************/ -acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action) +acpi_status acpi_gpe_wakeup(acpi_handle gpe_device, u32 gpe_number, u8 action) { + acpi_status status = AE_OK; struct acpi_gpe_event_info *gpe_event_info; - acpi_status status; + struct acpi_gpe_register_info *gpe_register_info; acpi_cpu_flags flags; + u32 register_bit; - ACPI_FUNCTION_TRACE(acpi_set_gpe); + ACPI_FUNCTION_TRACE(acpi_gpe_wakeup); 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) { + if (!gpe_event_info || !(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } + gpe_register_info = gpe_event_info->register_info; + if (!gpe_register_info) { + status = AE_NOT_EXIST; + goto unlock_and_exit; + } + + register_bit = + acpi_hw_get_gpe_register_bit(gpe_event_info, gpe_register_info); + /* Perform the action */ switch (action) { case ACPI_GPE_ENABLE: - status = acpi_clear_and_enable_gpe(gpe_event_info); + ACPI_SET_BIT(gpe_register_info->enable_for_wake, + (u8)register_bit); break; case ACPI_GPE_DISABLE: - status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); + ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake, + (u8)register_bit); break; default: + ACPI_ERROR((AE_INFO, "%u, Invalid action", action)); status = AE_BAD_PARAMETER; break; } - unlock_and_exit: +unlock_and_exit: acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return_ACPI_STATUS(status); } -ACPI_EXPORT_SYMBOL(acpi_set_gpe) +ACPI_EXPORT_SYMBOL(acpi_gpe_wakeup) /******************************************************************************* * @@ -315,84 +285,30 @@ ACPI_EXPORT_SYMBOL(acpi_set_gpe) * * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 * gpe_number - GPE level within the GPE block - * gpe_type - ACPI_GPE_TYPE_RUNTIME or ACPI_GPE_TYPE_WAKE - * or both * * RETURN: Status * * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is - * hardware-enabled (for runtime GPEs), or the GPE register mask - * is updated (for wake GPEs). + * hardware-enabled. * ******************************************************************************/ -acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type) +acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number) { - acpi_status status = AE_OK; + acpi_status status = AE_BAD_PARAMETER; struct acpi_gpe_event_info *gpe_event_info; acpi_cpu_flags flags; ACPI_FUNCTION_TRACE(acpi_enable_gpe); - /* Parameter validation */ - - if (!gpe_type || (gpe_type & ~ACPI_GPE_TYPE_WAKE_RUN)) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - 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; - } - - if (gpe_type & ACPI_GPE_TYPE_RUNTIME) { - if (gpe_event_info->runtime_count == ACPI_UINT8_MAX) { - status = AE_LIMIT; /* Too many references */ - goto unlock_and_exit; - } - - gpe_event_info->runtime_count++; - if (gpe_event_info->runtime_count == 1) { - status = acpi_ev_update_gpe_enable_masks(gpe_event_info); - if (ACPI_SUCCESS(status)) { - status = acpi_clear_and_enable_gpe(gpe_event_info); - } - - if (ACPI_FAILURE(status)) { - gpe_event_info->runtime_count--; - goto unlock_and_exit; - } - } - } - - if (gpe_type & ACPI_GPE_TYPE_WAKE) { - /* The GPE must have the ability to wake the system */ - - if (!(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) { - status = AE_TYPE; - goto unlock_and_exit; - } - - if (gpe_event_info->wakeup_count == ACPI_UINT8_MAX) { - status = AE_LIMIT; /* Too many references */ - goto unlock_and_exit; - } - - /* - * Update the enable mask on the first wakeup reference. Wake GPEs - * are only hardware-enabled just before sleeping. - */ - gpe_event_info->wakeup_count++; - if (gpe_event_info->wakeup_count == 1) { - status = acpi_ev_update_gpe_enable_masks(gpe_event_info); - } + if (gpe_event_info) { + status = acpi_raw_enable_gpe(gpe_event_info); } -unlock_and_exit: acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return_ACPI_STATUS(status); } @@ -404,8 +320,6 @@ ACPI_EXPORT_SYMBOL(acpi_enable_gpe) * * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 * gpe_number - GPE level within the GPE block - * gpe_type - ACPI_GPE_TYPE_RUNTIME or ACPI_GPE_TYPE_WAKE - * or both * * RETURN: Status * @@ -414,20 +328,52 @@ ACPI_EXPORT_SYMBOL(acpi_enable_gpe) * the GPE mask bit disabled (for wake GPEs) * ******************************************************************************/ -acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type) +acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number) { - acpi_status status = AE_OK; + acpi_status status = AE_BAD_PARAMETER; struct acpi_gpe_event_info *gpe_event_info; acpi_cpu_flags flags; ACPI_FUNCTION_TRACE(acpi_disable_gpe); - /* Parameter validation */ + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); + + /* Ensure that we have a valid GPE number */ - if (!gpe_type || (gpe_type & ~ACPI_GPE_TYPE_WAKE_RUN)) { - return_ACPI_STATUS(AE_BAD_PARAMETER); + gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); + if (gpe_event_info) { + status = acpi_raw_disable_gpe(gpe_event_info) ; } + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); + return_ACPI_STATUS(status); +} +ACPI_EXPORT_SYMBOL(acpi_disable_gpe) + +/******************************************************************************* + * + * FUNCTION: acpi_gpe_can_wake + * + * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 + * gpe_number - GPE level within the GPE block + * + * RETURN: Status + * + * DESCRIPTION: Set the ACPI_GPE_CAN_WAKE flag for the given GPE. If the GPE + * has a corresponding method and is currently enabled, disable it + * (GPEs with corresponding methods are enabled unconditionally + * during initialization, but GPEs that can wake up are expected + * to be initially disabled). + * + ******************************************************************************/ +acpi_status acpi_gpe_can_wake(acpi_handle gpe_device, u32 gpe_number) +{ + acpi_status status = AE_OK; + struct acpi_gpe_event_info *gpe_event_info; + acpi_cpu_flags flags; + + ACPI_FUNCTION_TRACE(acpi_gpe_can_wake); + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); /* Ensure that we have a valid GPE number */ @@ -438,51 +384,20 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type goto unlock_and_exit; } - /* Hardware-disable a runtime GPE on removal of the last reference */ - - if (gpe_type & ACPI_GPE_TYPE_RUNTIME) { - if (!gpe_event_info->runtime_count) { - status = AE_LIMIT; /* There are no references to remove */ - goto unlock_and_exit; - } - - gpe_event_info->runtime_count--; - if (!gpe_event_info->runtime_count) { - status = acpi_ev_update_gpe_enable_masks(gpe_event_info); - if (ACPI_SUCCESS(status)) { - status = acpi_hw_low_set_gpe(gpe_event_info, - ACPI_GPE_DISABLE); - } - - if (ACPI_FAILURE(status)) { - gpe_event_info->runtime_count++; - goto unlock_and_exit; - } - } + if (gpe_event_info->flags & ACPI_GPE_CAN_WAKE) { + goto unlock_and_exit; } - /* - * Update masks for wake GPE on removal of the last reference. - * No need to hardware-disable wake GPEs here, they are not currently - * enabled. - */ - if (gpe_type & ACPI_GPE_TYPE_WAKE) { - if (!gpe_event_info->wakeup_count) { - status = AE_LIMIT; /* There are no references to remove */ - goto unlock_and_exit; - } - - gpe_event_info->wakeup_count--; - if (!gpe_event_info->wakeup_count) { - status = acpi_ev_update_gpe_enable_masks(gpe_event_info); - } + gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; + if (gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD) { + (void)acpi_raw_disable_gpe(gpe_event_info); } unlock_and_exit: acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return_ACPI_STATUS(status); } -ACPI_EXPORT_SYMBOL(acpi_disable_gpe) +ACPI_EXPORT_SYMBOL(acpi_gpe_can_wake) /******************************************************************************* * @@ -800,7 +715,7 @@ acpi_install_gpe_block(acpi_handle gpe_device, obj_desc->device.gpe_block = gpe_block; - /* Run the _PRW methods and enable the runtime GPEs in the new block */ + /* Enable the runtime GPEs in the new block */ status = acpi_ev_initialize_gpe_block(node, gpe_block); |