RE: [PATCH 1/3] ACPICA: Dispatch active GPEs at init time

From: Zheng, Lv
Date: Wed Aug 09 2017 - 21:49:12 EST


Hi, Rafael

> From: Rafael J. Wysocki [mailto:rjw@xxxxxxxxxxxxx]
> Subject: [PATCH 1/3] ACPICA: Dispatch active GPEs at init time
>
> From: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>
>
> In some cases GPEs are already active when they are enabled by
> acpi_ev_initialize_gpe_block() and whatever happens next may depend
> on the result of handling the events signaled by them, so the
> events should not be discarded (which is what happens currently) and
> they should be handled as soon as reasonably possible.
>
> For this reason, modify acpi_ev_initialize_gpe_block() to
> dispatch GPEs with the status flag set in-band right after
> enabling them.

In fact, what we need seems to be invoking acpi_ev_gpe_dispatch()
right after enabling an GPE. So there are 2 conditions related:
1. GPE is enabled for the first time.
2. GPE is initialized.

And we need to make sure that before acpi_update_all_gpes() is invoked,
all GPE EN bits are actually disabled.
What if we do this in this way:

Index: linux-acpica/drivers/acpi/acpica/evxfgpe.c
===================================================================
--- linux-acpica.orig/drivers/acpi/acpica/evxfgpe.c
+++ linux-acpica/drivers/acpi/acpica/evxfgpe.c
@@ -97,6 +97,14 @@ acpi_status acpi_update_all_gpes(void)
unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);

+ /*
+ * Poll GPEs to handle already triggered events.
+ * It is not sufficient to trigger edge-triggered GPE with specific
+ * GPE chips, software need to poll once after enabling.
+ */
+ if (acpi_gbl_all_gpes_initialized) {
+ acpi_ev_gpe_detect(acpi_gbl_gpe_xrupt_list_head);
+ }
return_ACPI_STATUS(status);
}

@@ -120,6 +128,7 @@ acpi_status acpi_enable_gpe(acpi_handle
acpi_status status = AE_BAD_PARAMETER;
struct acpi_gpe_event_info *gpe_event_info;
acpi_cpu_flags flags;
+ u8 poll_gpes = FALSE;

ACPI_FUNCTION_TRACE(acpi_enable_gpe);

@@ -135,12 +144,25 @@ acpi_status acpi_enable_gpe(acpi_handle
if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
ACPI_GPE_DISPATCH_NONE) {
status = acpi_ev_add_gpe_reference(gpe_event_info);
+ if (ACPI_SUCCESS(status) &&
+ gpe_event_info->runtime_count == 1) {
+ poll_gpes = TRUE;
+ }
} else {
status = AE_NO_HANDLER;
}
}

acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+
+ /*
+ * Poll GPEs to handle already triggered events.
+ * It is not sufficient to trigger edge-triggered GPE with specific
+ * GPE chips, software need to poll once after enabling.
+ */
+ if (poll_gpes && acpi_gbl_all_gpes_initialized) {
+ acpi_ev_gpe_detect(acpi_gbl_gpe_xrupt_list_head);
+ }
return_ACPI_STATUS(status);
}
ACPI_EXPORT_SYMBOL(acpi_enable_gpe)
Index: linux-acpica/drivers/acpi/acpica/utxfinit.c
===================================================================
--- linux-acpica.orig/drivers/acpi/acpica/utxfinit.c
+++ linux-acpica/drivers/acpi/acpica/utxfinit.c
@@ -284,6 +284,13 @@ acpi_status ACPI_INIT_FUNCTION acpi_init
}

/*
+ * Cleanup GPE enabling status to make sure that the GPE settings are
+ * as what the OSPMs expect. This should be done before enumerating
+ * ACPI devices and operation region drivers.
+ */
+ (void)acpi_hw_disable_all_gpes();
+
+ /*
* Initialize all device/region objects in the namespace. This runs
* the device _STA and _INI methods and region _REG methods.
*/

Thanks and best regards
Lv

>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>
> ---
> drivers/acpi/acpica/evgpeblk.c | 28 +++++++++++++++++++---------
> 1 file changed, 19 insertions(+), 9 deletions(-)
>
> Index: linux-pm/drivers/acpi/acpica/evgpeblk.c
> ===================================================================
> --- linux-pm.orig/drivers/acpi/acpica/evgpeblk.c
> +++ linux-pm/drivers/acpi/acpica/evgpeblk.c
> @@ -440,9 +440,11 @@ acpi_ev_initialize_gpe_block(struct acpi
> void *ignored)
> {
> acpi_status status;
> + acpi_event_status event_status;
> struct acpi_gpe_event_info *gpe_event_info;
> u32 gpe_enabled_count;
> u32 gpe_index;
> + u32 gpe_number;
> u32 i;
> u32 j;
>
> @@ -470,30 +472,38 @@ acpi_ev_initialize_gpe_block(struct acpi
>
> gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j;
> gpe_event_info = &gpe_block->event_info[gpe_index];
> + gpe_number = gpe_block->block_base_number + gpe_index;
>
> /*
> * Ignore GPEs that have no corresponding _Lxx/_Exx method
> - * and GPEs that are used to wake the system
> + * and GPEs that are used for wakeup
> */
> - if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
> - ACPI_GPE_DISPATCH_NONE)
> - || (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
> - ACPI_GPE_DISPATCH_HANDLER)
> - || (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
> - ACPI_GPE_DISPATCH_RAW_HANDLER)
> + if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
> + ACPI_GPE_DISPATCH_METHOD)
> || (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
> continue;
> }
>
> + event_status = 0;
> + (void)acpi_hw_get_gpe_status(gpe_event_info,
> + &event_status);
> +
> status = acpi_ev_add_gpe_reference(gpe_event_info);
> if (ACPI_FAILURE(status)) {
> ACPI_EXCEPTION((AE_INFO, status,
> "Could not enable GPE 0x%02X",
> - gpe_index +
> - gpe_block->block_base_number));
> + gpe_number));
> continue;
> }
>
> + if (event_status & ACPI_EVENT_FLAG_STATUS_SET) {
> + ACPI_INFO(("GPE 0x%02X active on init",
> + gpe_number));
> + (void)acpi_ev_gpe_dispatch(gpe_block->node,
> + gpe_event_info,
> + gpe_number);
> + }
> +
> gpe_enabled_count++;
> }
> }