提交 0ce792d6 编写于 作者: R Rafael J. Wysocki

ACPICA: Allow acpi_any_gpe_status_set() to skip one GPE

The check carried out by acpi_any_gpe_status_set() is not precise enough
for the suspend-to-idle implementation in Linux and in some cases it is
necessary make it skip one GPE (specifically, the EC GPE) from the check
to prevent a race condition leading to a premature system resume from
occurring.

For this reason, redefine acpi_any_gpe_status_set() to take the number
of a GPE to skip as an argument.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=206629Tested-by: NOndřej Caletka <ondrej@caletka.cz>
Cc: 5.4+ <stable@vger.kernel.org> # 5.4+
Signed-off-by: NRafael J. Wysocki <rafael.j.wysocki@intel.com>
上级 243a9889
...@@ -101,7 +101,7 @@ acpi_status acpi_hw_enable_all_runtime_gpes(void); ...@@ -101,7 +101,7 @@ acpi_status acpi_hw_enable_all_runtime_gpes(void);
acpi_status acpi_hw_enable_all_wakeup_gpes(void); acpi_status acpi_hw_enable_all_wakeup_gpes(void);
u8 acpi_hw_check_all_gpes(void); u8 acpi_hw_check_all_gpes(acpi_handle gpe_skip_device, u32 gpe_skip_number);
acpi_status acpi_status
acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
......
...@@ -799,17 +799,19 @@ ACPI_EXPORT_SYMBOL(acpi_enable_all_wakeup_gpes) ...@@ -799,17 +799,19 @@ ACPI_EXPORT_SYMBOL(acpi_enable_all_wakeup_gpes)
* *
* FUNCTION: acpi_any_gpe_status_set * FUNCTION: acpi_any_gpe_status_set
* *
* PARAMETERS: None * PARAMETERS: gpe_skip_number - Number of the GPE to skip
* *
* RETURN: Whether or not the status bit is set for any GPE * RETURN: Whether or not the status bit is set for any GPE
* *
* DESCRIPTION: Check the status bits of all enabled GPEs and return TRUE if any * DESCRIPTION: Check the status bits of all enabled GPEs, except for the one
* of them is set or FALSE otherwise. * represented by the "skip" argument, and return TRUE if any of
* them is set or FALSE otherwise.
* *
******************************************************************************/ ******************************************************************************/
u32 acpi_any_gpe_status_set(void) u32 acpi_any_gpe_status_set(u32 gpe_skip_number)
{ {
acpi_status status; acpi_status status;
acpi_handle gpe_device;
u8 ret; u8 ret;
ACPI_FUNCTION_TRACE(acpi_any_gpe_status_set); ACPI_FUNCTION_TRACE(acpi_any_gpe_status_set);
...@@ -819,7 +821,12 @@ u32 acpi_any_gpe_status_set(void) ...@@ -819,7 +821,12 @@ u32 acpi_any_gpe_status_set(void)
return (FALSE); return (FALSE);
} }
ret = acpi_hw_check_all_gpes(); status = acpi_get_gpe_device(gpe_skip_number, &gpe_device);
if (ACPI_FAILURE(status)) {
gpe_device = NULL;
}
ret = acpi_hw_check_all_gpes(gpe_device, gpe_skip_number);
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
return (ret); return (ret);
......
...@@ -444,12 +444,19 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, ...@@ -444,12 +444,19 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
return (AE_OK); return (AE_OK);
} }
struct acpi_gpe_block_status_context {
struct acpi_gpe_register_info *gpe_skip_register_info;
u8 gpe_skip_mask;
u8 retval;
};
/****************************************************************************** /******************************************************************************
* *
* FUNCTION: acpi_hw_get_gpe_block_status * FUNCTION: acpi_hw_get_gpe_block_status
* *
* PARAMETERS: gpe_xrupt_info - GPE Interrupt info * PARAMETERS: gpe_xrupt_info - GPE Interrupt info
* gpe_block - Gpe Block info * gpe_block - Gpe Block info
* context - GPE list walk context data
* *
* RETURN: Success * RETURN: Success
* *
...@@ -460,12 +467,13 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, ...@@ -460,12 +467,13 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
static acpi_status static acpi_status
acpi_hw_get_gpe_block_status(struct acpi_gpe_xrupt_info *gpe_xrupt_info, acpi_hw_get_gpe_block_status(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
struct acpi_gpe_block_info *gpe_block, struct acpi_gpe_block_info *gpe_block,
void *ret_ptr) void *context)
{ {
struct acpi_gpe_block_status_context *c = context;
struct acpi_gpe_register_info *gpe_register_info; struct acpi_gpe_register_info *gpe_register_info;
u64 in_enable, in_status; u64 in_enable, in_status;
acpi_status status; acpi_status status;
u8 *ret = ret_ptr; u8 ret_mask;
u32 i; u32 i;
/* Examine each GPE Register within the block */ /* Examine each GPE Register within the block */
...@@ -485,7 +493,11 @@ acpi_hw_get_gpe_block_status(struct acpi_gpe_xrupt_info *gpe_xrupt_info, ...@@ -485,7 +493,11 @@ acpi_hw_get_gpe_block_status(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
continue; continue;
} }
*ret |= in_enable & in_status; ret_mask = in_enable & in_status;
if (ret_mask && c->gpe_skip_register_info == gpe_register_info) {
ret_mask &= ~c->gpe_skip_mask;
}
c->retval |= ret_mask;
} }
return (AE_OK); return (AE_OK);
...@@ -561,24 +573,41 @@ acpi_status acpi_hw_enable_all_wakeup_gpes(void) ...@@ -561,24 +573,41 @@ acpi_status acpi_hw_enable_all_wakeup_gpes(void)
* *
* FUNCTION: acpi_hw_check_all_gpes * FUNCTION: acpi_hw_check_all_gpes
* *
* PARAMETERS: None * PARAMETERS: gpe_skip_device - GPE devoce of the GPE to skip
* gpe_skip_number - Number of the GPE to skip
* *
* RETURN: Combined status of all GPEs * RETURN: Combined status of all GPEs
* *
* DESCRIPTION: Check all enabled GPEs in all GPE blocks and return TRUE if the * DESCRIPTION: Check all enabled GPEs in all GPE blocks, except for the one
* represented by the "skip" arguments, and return TRUE if the
* status bit is set for at least one of them of FALSE otherwise. * status bit is set for at least one of them of FALSE otherwise.
* *
******************************************************************************/ ******************************************************************************/
u8 acpi_hw_check_all_gpes(void) u8 acpi_hw_check_all_gpes(acpi_handle gpe_skip_device, u32 gpe_skip_number)
{ {
u8 ret = 0; struct acpi_gpe_block_status_context context = {
.gpe_skip_register_info = NULL,
.retval = 0,
};
struct acpi_gpe_event_info *gpe_event_info;
acpi_cpu_flags flags;
ACPI_FUNCTION_TRACE(acpi_hw_check_all_gpes); ACPI_FUNCTION_TRACE(acpi_hw_check_all_gpes);
(void)acpi_ev_walk_gpe_list(acpi_hw_get_gpe_block_status, &ret); flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_skip_device,
gpe_skip_number);
if (gpe_event_info) {
context.gpe_skip_register_info = gpe_event_info->register_info;
context.gpe_skip_mask = acpi_hw_get_gpe_register_bit(gpe_event_info);
}
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
return (ret != 0); (void)acpi_ev_walk_gpe_list(acpi_hw_get_gpe_block_status, &context);
return (context.retval != 0);
} }
#endif /* !ACPI_REDUCED_HARDWARE */ #endif /* !ACPI_REDUCED_HARDWARE */
...@@ -1019,7 +1019,7 @@ static bool acpi_s2idle_wake(void) ...@@ -1019,7 +1019,7 @@ static bool acpi_s2idle_wake(void)
* status bit from unset to set between the checks with the * status bit from unset to set between the checks with the
* status bits of all the other GPEs unset. * status bits of all the other GPEs unset.
*/ */
if (acpi_any_gpe_status_set() && !acpi_ec_dispatch_gpe()) if (acpi_any_gpe_status_set(U32_MAX) && !acpi_ec_dispatch_gpe())
return true; return true;
/* /*
......
...@@ -752,7 +752,7 @@ ACPI_HW_DEPENDENT_RETURN_UINT32(u32 acpi_dispatch_gpe(acpi_handle gpe_device, u3 ...@@ -752,7 +752,7 @@ ACPI_HW_DEPENDENT_RETURN_UINT32(u32 acpi_dispatch_gpe(acpi_handle gpe_device, u3
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable_all_gpes(void)) ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable_all_gpes(void))
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_runtime_gpes(void)) ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_runtime_gpes(void))
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_wakeup_gpes(void)) ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_wakeup_gpes(void))
ACPI_HW_DEPENDENT_RETURN_UINT32(u32 acpi_any_gpe_status_set(void)) ACPI_HW_DEPENDENT_RETURN_UINT32(u32 acpi_any_gpe_status_set(u32 gpe_skip_number))
ACPI_HW_DEPENDENT_RETURN_UINT32(u32 acpi_any_fixed_event_status_set(void)) ACPI_HW_DEPENDENT_RETURN_UINT32(u32 acpi_any_fixed_event_status_set(void))
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册