Skip to content

Commit 0ce792d

Browse files
committed
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=206629 Tested-by: Ondřej Caletka <[email protected]> Cc: 5.4+ <[email protected]> # 5.4+ Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 243a988 commit 0ce792d

File tree

5 files changed

+53
-17
lines changed

5 files changed

+53
-17
lines changed

drivers/acpi/acpica/achware.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ acpi_status acpi_hw_enable_all_runtime_gpes(void);
101101

102102
acpi_status acpi_hw_enable_all_wakeup_gpes(void);
103103

104-
u8 acpi_hw_check_all_gpes(void);
104+
u8 acpi_hw_check_all_gpes(acpi_handle gpe_skip_device, u32 gpe_skip_number);
105105

106106
acpi_status
107107
acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,

drivers/acpi/acpica/evxfgpe.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -799,17 +799,19 @@ ACPI_EXPORT_SYMBOL(acpi_enable_all_wakeup_gpes)
799799
*
800800
* FUNCTION: acpi_any_gpe_status_set
801801
*
802-
* PARAMETERS: None
802+
* PARAMETERS: gpe_skip_number - Number of the GPE to skip
803803
*
804804
* RETURN: Whether or not the status bit is set for any GPE
805805
*
806-
* DESCRIPTION: Check the status bits of all enabled GPEs and return TRUE if any
807-
* of them is set or FALSE otherwise.
806+
* DESCRIPTION: Check the status bits of all enabled GPEs, except for the one
807+
* represented by the "skip" argument, and return TRUE if any of
808+
* them is set or FALSE otherwise.
808809
*
809810
******************************************************************************/
810-
u32 acpi_any_gpe_status_set(void)
811+
u32 acpi_any_gpe_status_set(u32 gpe_skip_number)
811812
{
812813
acpi_status status;
814+
acpi_handle gpe_device;
813815
u8 ret;
814816

815817
ACPI_FUNCTION_TRACE(acpi_any_gpe_status_set);
@@ -819,7 +821,12 @@ u32 acpi_any_gpe_status_set(void)
819821
return (FALSE);
820822
}
821823

822-
ret = acpi_hw_check_all_gpes();
824+
status = acpi_get_gpe_device(gpe_skip_number, &gpe_device);
825+
if (ACPI_FAILURE(status)) {
826+
gpe_device = NULL;
827+
}
828+
829+
ret = acpi_hw_check_all_gpes(gpe_device, gpe_skip_number);
823830
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
824831

825832
return (ret);

drivers/acpi/acpica/hwgpe.c

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -444,12 +444,19 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
444444
return (AE_OK);
445445
}
446446

447+
struct acpi_gpe_block_status_context {
448+
struct acpi_gpe_register_info *gpe_skip_register_info;
449+
u8 gpe_skip_mask;
450+
u8 retval;
451+
};
452+
447453
/******************************************************************************
448454
*
449455
* FUNCTION: acpi_hw_get_gpe_block_status
450456
*
451457
* PARAMETERS: gpe_xrupt_info - GPE Interrupt info
452458
* gpe_block - Gpe Block info
459+
* context - GPE list walk context data
453460
*
454461
* RETURN: Success
455462
*
@@ -460,12 +467,13 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
460467
static acpi_status
461468
acpi_hw_get_gpe_block_status(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
462469
struct acpi_gpe_block_info *gpe_block,
463-
void *ret_ptr)
470+
void *context)
464471
{
472+
struct acpi_gpe_block_status_context *c = context;
465473
struct acpi_gpe_register_info *gpe_register_info;
466474
u64 in_enable, in_status;
467475
acpi_status status;
468-
u8 *ret = ret_ptr;
476+
u8 ret_mask;
469477
u32 i;
470478

471479
/* 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,
485493
continue;
486494
}
487495

488-
*ret |= in_enable & in_status;
496+
ret_mask = in_enable & in_status;
497+
if (ret_mask && c->gpe_skip_register_info == gpe_register_info) {
498+
ret_mask &= ~c->gpe_skip_mask;
499+
}
500+
c->retval |= ret_mask;
489501
}
490502

491503
return (AE_OK);
@@ -561,24 +573,41 @@ acpi_status acpi_hw_enable_all_wakeup_gpes(void)
561573
*
562574
* FUNCTION: acpi_hw_check_all_gpes
563575
*
564-
* PARAMETERS: None
576+
* PARAMETERS: gpe_skip_device - GPE devoce of the GPE to skip
577+
* gpe_skip_number - Number of the GPE to skip
565578
*
566579
* RETURN: Combined status of all GPEs
567580
*
568-
* DESCRIPTION: Check all enabled GPEs in all GPE blocks and return TRUE if the
581+
* DESCRIPTION: Check all enabled GPEs in all GPE blocks, except for the one
582+
* represented by the "skip" arguments, and return TRUE if the
569583
* status bit is set for at least one of them of FALSE otherwise.
570584
*
571585
******************************************************************************/
572586

573-
u8 acpi_hw_check_all_gpes(void)
587+
u8 acpi_hw_check_all_gpes(acpi_handle gpe_skip_device, u32 gpe_skip_number)
574588
{
575-
u8 ret = 0;
589+
struct acpi_gpe_block_status_context context = {
590+
.gpe_skip_register_info = NULL,
591+
.retval = 0,
592+
};
593+
struct acpi_gpe_event_info *gpe_event_info;
594+
acpi_cpu_flags flags;
576595

577596
ACPI_FUNCTION_TRACE(acpi_hw_check_all_gpes);
578597

579-
(void)acpi_ev_walk_gpe_list(acpi_hw_get_gpe_block_status, &ret);
598+
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
599+
600+
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_skip_device,
601+
gpe_skip_number);
602+
if (gpe_event_info) {
603+
context.gpe_skip_register_info = gpe_event_info->register_info;
604+
context.gpe_skip_mask = acpi_hw_get_gpe_register_bit(gpe_event_info);
605+
}
606+
607+
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
580608

581-
return (ret != 0);
609+
(void)acpi_ev_walk_gpe_list(acpi_hw_get_gpe_block_status, &context);
610+
return (context.retval != 0);
582611
}
583612

584613
#endif /* !ACPI_REDUCED_HARDWARE */

drivers/acpi/sleep.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,7 @@ static bool acpi_s2idle_wake(void)
10191019
* status bit from unset to set between the checks with the
10201020
* status bits of all the other GPEs unset.
10211021
*/
1022-
if (acpi_any_gpe_status_set() && !acpi_ec_dispatch_gpe())
1022+
if (acpi_any_gpe_status_set(U32_MAX) && !acpi_ec_dispatch_gpe())
10231023
return true;
10241024

10251025
/*

include/acpi/acpixf.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -752,7 +752,7 @@ ACPI_HW_DEPENDENT_RETURN_UINT32(u32 acpi_dispatch_gpe(acpi_handle gpe_device, u3
752752
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable_all_gpes(void))
753753
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_runtime_gpes(void))
754754
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_wakeup_gpes(void))
755-
ACPI_HW_DEPENDENT_RETURN_UINT32(u32 acpi_any_gpe_status_set(void))
755+
ACPI_HW_DEPENDENT_RETURN_UINT32(u32 acpi_any_gpe_status_set(u32 gpe_skip_number))
756756
ACPI_HW_DEPENDENT_RETURN_UINT32(u32 acpi_any_fixed_event_status_set(void))
757757

758758
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status

0 commit comments

Comments
 (0)