ACPICA: Events: Dispatch GPEs after enabling for the first time
authorErik Schmauss <erik.schmauss@intel.com>
Wed, 14 Mar 2018 23:12:59 +0000 (16:12 -0700)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Sun, 18 Mar 2018 17:52:00 +0000 (18:52 +0100)
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 <lv.zheng@intel.com>
Signed-off-by: Erik Schmauss <erik.schmauss@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/acpi/acpica/acevents.h
drivers/acpi/acpica/evgpeblk.c
drivers/acpi/acpica/evxface.c
drivers/acpi/acpica/evxfgpe.c
include/acpi/actypes.h
include/acpi/platform/aclinux.h

index fa68544c7c0757c52726d9533b7387dc9dc4536f..1ad1608cc88057e9788537970b6d1d2381383c62 100644 (file)
 #ifndef __ACEVENTS_H__
 #define __ACEVENTS_H__
 
+/*
+ * Conditions to trigger post enabling GPE polling:
+ * It is not sufficient to trigger edge-triggered GPE with specific GPE
+ * chips, software need to poll once after enabling.
+ */
+#ifdef ACPI_USE_GPE_POLLING
+#define ACPI_GPE_IS_POLLING_NEEDED(__gpe__)             \
+       ((__gpe__)->runtime_count == 1 &&                   \
+        (__gpe__)->flags & ACPI_GPE_INITIALIZED &&         \
+        ((__gpe__)->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_EDGE_TRIGGERED)
+#else
+#define ACPI_GPE_IS_POLLING_NEEDED(__gpe__)             FALSE
+#endif
+
 /*
  * evevent
  */
index 7ce756cc28abb4189dc6cae94d01f19f11d37f50..107f3ec5dee6787da2fbda1812f825476e9ac2be 100644 (file)
@@ -437,16 +437,16 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
 acpi_status
 acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
                             struct acpi_gpe_block_info *gpe_block,
-                            void *ignored)
+                            void *context)
 {
        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;
+       u8 *is_polling_needed = context;
 
        ACPI_FUNCTION_TRACE(ev_initialize_gpe_block);
 
@@ -473,6 +473,7 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
                        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;
+                       gpe_event_info->flags |= ACPI_GPE_INITIALIZED;
 
                        /*
                         * 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,
                                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,
@@ -498,12 +495,9 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
 
                        gpe_event_info->flags |= ACPI_GPE_AUTO_ENABLED;
 
-                       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);
+                       if (is_polling_needed &&
+                           ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {
+                               *is_polling_needed = TRUE;
                        }
 
                        gpe_enabled_count++;
index 9b3c01bf1438ec44fd1ef683e72c8d05e9da7ea5..b6e462f33b0d0b1e18fc4e45ace46df1ecf1142a 100644 (file)
@@ -1006,6 +1006,15 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
             (ACPI_GPE_DISPATCH_TYPE(handler->original_flags) ==
              ACPI_GPE_DISPATCH_NOTIFY)) && handler->originally_enabled) {
                (void)acpi_ev_add_gpe_reference(gpe_event_info);
+               if (ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {
+
+                       /* Poll edge triggered GPEs to handle existing events */
+
+                       acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+                       (void)acpi_ev_detect_gpe(gpe_device, gpe_event_info,
+                                                gpe_number);
+                       flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+               }
        }
 
        acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
index cbb1598df9dcfc915b58088f2d3cf71f9171c07c..f9303444f7f75b0023a8b6541c5d60f08774eee0 100644 (file)
@@ -77,6 +77,7 @@ ACPI_MODULE_NAME("evxfgpe")
 acpi_status acpi_update_all_gpes(void)
 {
        acpi_status status;
+       u8 is_polling_needed = FALSE;
 
        ACPI_FUNCTION_TRACE(acpi_update_all_gpes);
 
@@ -89,7 +90,8 @@ acpi_status acpi_update_all_gpes(void)
                goto unlock_and_exit;
        }
 
-       status = acpi_ev_walk_gpe_list(acpi_ev_initialize_gpe_block, NULL);
+       status = acpi_ev_walk_gpe_list(acpi_ev_initialize_gpe_block,
+                                      &is_polling_needed);
        if (ACPI_SUCCESS(status)) {
                acpi_gbl_all_gpes_initialized = TRUE;
        }
@@ -97,6 +99,12 @@ acpi_status acpi_update_all_gpes(void)
 unlock_and_exit:
        (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
 
+       if (is_polling_needed && acpi_gbl_all_gpes_initialized) {
+
+               /* Poll GPEs to handle already triggered events */
+
+               acpi_ev_gpe_detect(acpi_gbl_gpe_xrupt_list_head);
+       }
        return_ACPI_STATUS(status);
 }
 
@@ -135,6 +143,17 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
                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) &&
+                           ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {
+
+                               /* Poll edge-triggered GPEs to handle existing events */
+
+                               acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+                               (void)acpi_ev_detect_gpe(gpe_device,
+                                                        gpe_event_info,
+                                                        gpe_number);
+                               flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+                       }
                } else {
                        status = AE_NO_HANDLER;
                }
index 310b542abe238e2ec674f4bf1a32591d751892b6..a894ea13dcba00fbe31a7531e5493a55cc19afc6 100644 (file)
@@ -802,6 +802,7 @@ typedef u32 acpi_event_status;
 
 #define ACPI_GPE_CAN_WAKE               (u8) 0x10
 #define ACPI_GPE_AUTO_ENABLED           (u8) 0x20
+#define ACPI_GPE_INITIALIZED            (u8) 0x40
 
 /*
  * Flags for GPE and Lock interfaces
index e6e7572541387406c0d05c797ebb1c6a32c7614e..88c50bbcc4d0a7158ad7c3dea5dd704524e6456b 100644 (file)
@@ -63,6 +63,7 @@
 #ifdef __KERNEL__
 
 #define ACPI_USE_SYSTEM_INTTYPES
+#define ACPI_USE_GPE_POLLING
 
 /* Kernel specific ACPICA configuration */