Skip to content

Commit 87cd826

Browse files
Erik Schmaussrafaeljw
authored andcommitted
ACPICA: Events: Dispatch GPEs after enabling for the first time
After being enabled for the first time, the GPEs may have STS bits already set. Setting EN bits is not sufficient to trigger the GPEs again, so this patch polls GPEs after enabling them for the first time. This is a cleaner version on top of the "GPE clear" fix generated according to Mika's report and Rafael's original Linux based fix. Based on Linux commit originated from Rafael J. Wysocki, fixed by Lv Zheng. Signed-off-by: Lv Zheng <[email protected]> Signed-off-by: Erik Schmauss <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 8d59349 commit 87cd826

File tree

6 files changed

+51
-13
lines changed

6 files changed

+51
-13
lines changed

drivers/acpi/acpica/acevents.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,20 @@
4444
#ifndef __ACEVENTS_H__
4545
#define __ACEVENTS_H__
4646

47+
/*
48+
* Conditions to trigger post enabling GPE polling:
49+
* It is not sufficient to trigger edge-triggered GPE with specific GPE
50+
* chips, software need to poll once after enabling.
51+
*/
52+
#ifdef ACPI_USE_GPE_POLLING
53+
#define ACPI_GPE_IS_POLLING_NEEDED(__gpe__) \
54+
((__gpe__)->runtime_count == 1 && \
55+
(__gpe__)->flags & ACPI_GPE_INITIALIZED && \
56+
((__gpe__)->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_EDGE_TRIGGERED)
57+
#else
58+
#define ACPI_GPE_IS_POLLING_NEEDED(__gpe__) FALSE
59+
#endif
60+
4761
/*
4862
* evevent
4963
*/

drivers/acpi/acpica/evgpeblk.c

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -437,16 +437,16 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
437437
acpi_status
438438
acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
439439
struct acpi_gpe_block_info *gpe_block,
440-
void *ignored)
440+
void *context)
441441
{
442442
acpi_status status;
443-
acpi_event_status event_status;
444443
struct acpi_gpe_event_info *gpe_event_info;
445444
u32 gpe_enabled_count;
446445
u32 gpe_index;
447446
u32 gpe_number;
448447
u32 i;
449448
u32 j;
449+
u8 *is_polling_needed = context;
450450

451451
ACPI_FUNCTION_TRACE(ev_initialize_gpe_block);
452452

@@ -473,6 +473,7 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
473473
gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j;
474474
gpe_event_info = &gpe_block->event_info[gpe_index];
475475
gpe_number = gpe_block->block_base_number + gpe_index;
476+
gpe_event_info->flags |= ACPI_GPE_INITIALIZED;
476477

477478
/*
478479
* Ignore GPEs that have no corresponding _Lxx/_Exx method
@@ -484,10 +485,6 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
484485
continue;
485486
}
486487

487-
event_status = 0;
488-
(void)acpi_hw_get_gpe_status(gpe_event_info,
489-
&event_status);
490-
491488
status = acpi_ev_add_gpe_reference(gpe_event_info);
492489
if (ACPI_FAILURE(status)) {
493490
ACPI_EXCEPTION((AE_INFO, status,
@@ -498,12 +495,9 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
498495

499496
gpe_event_info->flags |= ACPI_GPE_AUTO_ENABLED;
500497

501-
if (event_status & ACPI_EVENT_FLAG_STATUS_SET) {
502-
ACPI_INFO(("GPE 0x%02X active on init",
503-
gpe_number));
504-
(void)acpi_ev_gpe_dispatch(gpe_block->node,
505-
gpe_event_info,
506-
gpe_number);
498+
if (is_polling_needed &&
499+
ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {
500+
*is_polling_needed = TRUE;
507501
}
508502

509503
gpe_enabled_count++;

drivers/acpi/acpica/evxface.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,6 +1006,15 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
10061006
(ACPI_GPE_DISPATCH_TYPE(handler->original_flags) ==
10071007
ACPI_GPE_DISPATCH_NOTIFY)) && handler->originally_enabled) {
10081008
(void)acpi_ev_add_gpe_reference(gpe_event_info);
1009+
if (ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {
1010+
1011+
/* Poll edge triggered GPEs to handle existing events */
1012+
1013+
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
1014+
(void)acpi_ev_detect_gpe(gpe_device, gpe_event_info,
1015+
gpe_number);
1016+
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
1017+
}
10091018
}
10101019

10111020
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);

drivers/acpi/acpica/evxfgpe.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ ACPI_MODULE_NAME("evxfgpe")
7777
acpi_status acpi_update_all_gpes(void)
7878
{
7979
acpi_status status;
80+
u8 is_polling_needed = FALSE;
8081

8182
ACPI_FUNCTION_TRACE(acpi_update_all_gpes);
8283

@@ -89,14 +90,21 @@ acpi_status acpi_update_all_gpes(void)
8990
goto unlock_and_exit;
9091
}
9192

92-
status = acpi_ev_walk_gpe_list(acpi_ev_initialize_gpe_block, NULL);
93+
status = acpi_ev_walk_gpe_list(acpi_ev_initialize_gpe_block,
94+
&is_polling_needed);
9395
if (ACPI_SUCCESS(status)) {
9496
acpi_gbl_all_gpes_initialized = TRUE;
9597
}
9698

9799
unlock_and_exit:
98100
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
99101

102+
if (is_polling_needed && acpi_gbl_all_gpes_initialized) {
103+
104+
/* Poll GPEs to handle already triggered events */
105+
106+
acpi_ev_gpe_detect(acpi_gbl_gpe_xrupt_list_head);
107+
}
100108
return_ACPI_STATUS(status);
101109
}
102110

@@ -135,6 +143,17 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
135143
if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
136144
ACPI_GPE_DISPATCH_NONE) {
137145
status = acpi_ev_add_gpe_reference(gpe_event_info);
146+
if (ACPI_SUCCESS(status) &&
147+
ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {
148+
149+
/* Poll edge-triggered GPEs to handle existing events */
150+
151+
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
152+
(void)acpi_ev_detect_gpe(gpe_device,
153+
gpe_event_info,
154+
gpe_number);
155+
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
156+
}
138157
} else {
139158
status = AE_NO_HANDLER;
140159
}

include/acpi/actypes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,7 @@ typedef u32 acpi_event_status;
802802

803803
#define ACPI_GPE_CAN_WAKE (u8) 0x10
804804
#define ACPI_GPE_AUTO_ENABLED (u8) 0x20
805+
#define ACPI_GPE_INITIALIZED (u8) 0x40
805806

806807
/*
807808
* Flags for GPE and Lock interfaces

include/acpi/platform/aclinux.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
#ifdef __KERNEL__
6464

6565
#define ACPI_USE_SYSTEM_INTTYPES
66+
#define ACPI_USE_GPE_POLLING
6667

6768
/* Kernel specific ACPICA configuration */
6869

0 commit comments

Comments
 (0)