Blob Blame History Raw
From: Erik Schmauss <erik.schmauss@intel.com>
Date: Wed, 14 Mar 2018 16:12:59 -0700
Subject: ACPICA: Events: Dispatch GPEs after enabling for the first time
Patch-mainline: v4.17-rc1
Git-commit: 87cd826b5979d91d4f2ba189e0652820f2da417f
References: bsc#1117419

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>
Acked-by: Lee, Chun-Yi <jlee@suse.com>
---
 drivers/acpi/acpica/acevents.h  |   14 ++++++++++++++
 drivers/acpi/acpica/evgpeblk.c  |   18 ++++++------------
 drivers/acpi/acpica/evxface.c   |    9 +++++++++
 drivers/acpi/acpica/evxfgpe.c   |   21 ++++++++++++++++++++-
 include/acpi/actypes.h          |    1 +
 include/acpi/platform/aclinux.h |    1 +
 6 files changed, 51 insertions(+), 13 deletions(-)

--- a/drivers/acpi/acpica/acevents.h
+++ b/drivers/acpi/acpica/acevents.h
@@ -45,6 +45,20 @@
 #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
  */
 acpi_status acpi_ev_initialize_events(void);
--- a/drivers/acpi/acpica/evgpeblk.c
+++ b/drivers/acpi/acpica/evgpeblk.c
@@ -437,16 +437,16 @@ acpi_ev_create_gpe_block(struct acpi_nam
 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_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
 				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_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++;
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -1006,6 +1006,15 @@ acpi_remove_gpe_handler(acpi_handle gpe_
 	     (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);
--- a/drivers/acpi/acpica/evxfgpe.c
+++ b/drivers/acpi/acpica/evxfgpe.c
@@ -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
 		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;
 		}
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -798,6 +798,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
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -63,6 +63,7 @@
 #ifdef __KERNEL__
 
 #define ACPI_USE_SYSTEM_INTTYPES
+#define ACPI_USE_GPE_POLLING
 
 /* Kernel specific ACPICA configuration */