ACPICA: Clear status of GPEs on first direct enable
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 17 Jun 2019 11:31:45 +0000 (13:31 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 26 Jul 2019 07:14:09 +0000 (09:14 +0200)
[ Upstream commit 44758bafa53602f2581a6857bb20b55d4d8ad5b2 ]

ACPI GPEs (other than the EC one) can be enabled in two situations.
First, the GPEs with existing _Lxx and _Exx methods are enabled
implicitly by ACPICA during system initialization.  Second, the
GPEs without these methods (like GPEs listed by _PRW objects for
wakeup devices) need to be enabled directly by the code that is
going to use them (e.g. ACPI power management or device drivers).

In the former case, if the status of a given GPE is set to start
with, its handler method (either _Lxx or _Exx) needs to be invoked
to take care of the events (possibly) signaled before the GPE was
enabled.  In the latter case, however, the first caller of
acpi_enable_gpe() for a given GPE should not be expected to care
about any events that might be signaled through it earlier.  In
that case, it is better to clear the status of the GPE before
enabling it, to prevent stale events from triggering unwanted
actions (like spurious system resume, for example).

For this reason, modify acpi_ev_add_gpe_reference() to take an
additional boolean argument indicating whether or not the GPE
status needs to be cleared when its reference counter changes from
zero to one and make acpi_enable_gpe() pass TRUE to it through
that new argument.

Fixes: 18996f2db918 ("ACPICA: Events: Stop unconditionally clearing ACPI IRQs during suspend/resume")
Reported-by: Furquan Shaikh <furquan@google.com>
Tested-by: Furquan Shaikh <furquan@google.com>
Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/acpi/acpica/acevents.h
drivers/acpi/acpica/evgpe.c
drivers/acpi/acpica/evgpeblk.c
drivers/acpi/acpica/evxface.c
drivers/acpi/acpica/evxfgpe.c

index 704bebbd35b06adc0d9faeb98f22535586330d61..298180bf7e3c16d73ac3d71d2d4d208633ba44f5 100644 (file)
@@ -69,7 +69,8 @@ acpi_status
 acpi_ev_mask_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 is_masked);
 
 acpi_status
-acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info);
+acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info,
+                         u8 clear_on_enable);
 
 acpi_status
 acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info);
index e10fec99a182eca363167e27e1a6338e42586c09..4b5d3b4c627a723f931bc94713f3cacbb799e1bb 100644 (file)
@@ -146,6 +146,7 @@ acpi_ev_mask_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 is_masked)
  * FUNCTION:    acpi_ev_add_gpe_reference
  *
  * PARAMETERS:  gpe_event_info          - Add a reference to this GPE
+ *              clear_on_enable         - Clear GPE status before enabling it
  *
  * RETURN:      Status
  *
@@ -155,7 +156,8 @@ acpi_ev_mask_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 is_masked)
  ******************************************************************************/
 
 acpi_status
-acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info)
+acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info,
+                         u8 clear_on_enable)
 {
        acpi_status status = AE_OK;
 
@@ -170,6 +172,10 @@ acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info)
 
                /* Enable on first reference */
 
+               if (clear_on_enable) {
+                       (void)acpi_hw_clear_gpe(gpe_event_info);
+               }
+
                status = acpi_ev_update_gpe_enable_mask(gpe_event_info);
                if (ACPI_SUCCESS(status)) {
                        status = acpi_ev_enable_gpe(gpe_event_info);
index b253063b09d39c1c3c5bb3c81a375c8cec8756cf..8d96270ed8c738e6376280877562745238a801cf 100644 (file)
@@ -453,7 +453,7 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
                                continue;
                        }
 
-                       status = acpi_ev_add_gpe_reference(gpe_event_info);
+                       status = acpi_ev_add_gpe_reference(gpe_event_info, FALSE);
                        if (ACPI_FAILURE(status)) {
                                ACPI_EXCEPTION((AE_INFO, status,
                                        "Could not enable GPE 0x%02X",
index febc332b00ac1313716b96e01c6fc3cc977e3ac3..841557bda64191602f2766425ee19d85a6d8f88b 100644 (file)
@@ -971,7 +971,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
              ACPI_GPE_DISPATCH_METHOD) ||
             (ACPI_GPE_DISPATCH_TYPE(handler->original_flags) ==
              ACPI_GPE_DISPATCH_NOTIFY)) && handler->originally_enabled) {
-               (void)acpi_ev_add_gpe_reference(gpe_event_info);
+               (void)acpi_ev_add_gpe_reference(gpe_event_info, FALSE);
                if (ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {
 
                        /* Poll edge triggered GPEs to handle existing events */
index b2d5f66cc1b055863492567007fee2444bfa1150..4188731e7c406ea20d4be04c65eb3a478e121d40 100644 (file)
@@ -108,7 +108,7 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
        if (gpe_event_info) {
                if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
                    ACPI_GPE_DISPATCH_NONE) {
-                       status = acpi_ev_add_gpe_reference(gpe_event_info);
+                       status = acpi_ev_add_gpe_reference(gpe_event_info, TRUE);
                        if (ACPI_SUCCESS(status) &&
                            ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {