linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/9] ACPI/EC: Improve GPE handling model.
@ 2014-06-18  3:17 Lv Zheng
  2014-06-18  3:17 ` [PATCH 1/9] ACPICA: Events: Reduce indent divergences of events files Lv Zheng
                   ` (13 more replies)
  0 siblings, 14 replies; 63+ messages in thread
From: Lv Zheng @ 2014-06-18  3:17 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patchset is based on the previous ACPI/EC bug fixes series.

This patchset has fixed the following issues:
1. Enables the ideal GPE handling model.
   The ideal GPE handling model should be able to handle the following
   cases:
   1. When upper layers (the users of the driver) submit requests to the
      drivers, it means they care about the underlying hardware. For this
      case, acpi_enable_gpe() should be invoked. When the reference count
      is increased from 0 to 1, driver enables the hardware IRQ. And
      acpi_disable_gpe() is used as the reversal when the users have
      completed the submitted requests.
   2. Driver may temporarily disables the IRQ and wants to re-enable it
      later, this case is normally used in order to prevent IRQ storm.
      When a driver cannot fully solve the condition that triggered the IRQ
      in the IRQ context, in order not to trigger IRQ storm, driver has to
      disable IRQ and re-enables it in the deferred execution environment
      - which should be in a task context. The acpi_set_gpe() API should be
      used exactly for this purpose.
   The reason why this model hasn't been enabled for the current Linux ACPI
   drivers is:
     In ACPICA, the same GPE lock is held while invoking the GPE handler
     callback, it's thus impossible to invoke GPE APIs in the GPE handler
     because the APIs requires to hold the GPE lock. The recursive locking
     leads to dead locks. This is a simple design defect, callbacks should
     always be invoked in a lockless environment, normally in Linux, this
     is achieved by RCU locking, and in ACPICA, we achieve this using
     reference counting.
   After fixing the above bug and doing necessary cleanups in the ACPICA
   GPE handling code, we now can enable this ideal GPE handling model for
   the EC driver to use.
2. Enables the EC commands flushing.
   This is quite important for ACPI platforms. Some EC driven ACPI devices
   may require all submitted EC commands to be completed before they can
   be safely suspended or unplugged. Otherwise the state of such devices
   will be broken.
   When implementing IO flushing, there always need to be 2 flags to
   indicate an intermediate state - old IO submissions observe the
   (STARTED) flag to continue; new IO submissions observe the (STOPPED)
   flag to be discarded. After introducing the 2 flags, a "stop waiter"
   is implemented for the suspending/removing operations of the EC driver.

The refined patches are passed the runtime/suspend tests carried out on the
following platforms:
  "Dell Inspiron Mini 1010" - i386 kernel
  "Dell Latitude 6430u" - x86_64 kernel
In this patchset, a unit test facility is also implemented. Test results
show that the GPE APIs and EC GPE model are now safe for hotplug support.

Lv Zheng (9):
  ACPICA: Events: Reduce indent divergences of events files.
  ACPICA: Events: Fix an issue that GPE APIs cannot be invoked in
    atomic context.
  ACPICA: Events: Introduce acpi_set_gpe()/acpi_finish_gpe() to reduce
    divergences.
  ACPICA: Events: Remove acpi_ev_enable_gpe().
  ACPICA: Events: Reduce divergences to honor notify handler enabled
    GPEs.
  ACPI/EC: Introduce STARTED/STOPPED flags to replace BLOCKED flag.
  ACPI/EC: Add detailed command/query debugging information.
  ACPI/EC: Deploy the new GPE handling model.
  ACPI/EC: Add unit test support for EC driver hotplug.

 drivers/acpi/acpica/acevents.h |    1 +
 drivers/acpi/acpica/aclocal.h  |    5 +-
 drivers/acpi/acpica/evgpe.c    |  130 ++++++++++++++++--------------
 drivers/acpi/acpica/evxface.c  |   41 +++++++---
 drivers/acpi/acpica/evxfgpe.c  |  105 ++++++++++++++++++++++++
 drivers/acpi/ec.c              |  174 +++++++++++++++++++++++++++++++++-------
 6 files changed, 350 insertions(+), 106 deletions(-)

-- 
1.7.10


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH 1/9] ACPICA: Events: Reduce indent divergences of events files.
  2014-06-18  3:17 [PATCH 0/9] ACPI/EC: Improve GPE handling model Lv Zheng
@ 2014-06-18  3:17 ` Lv Zheng
  2014-06-18  3:17 ` [PATCH 2/9] ACPICA: Events: Fix an issue that GPE APIs cannot be invoked in atomic context Lv Zheng
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-06-18  3:17 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch reduces indent divergences first in order to reduce human
intervention work for the follow-up linuxized event patches.

This patch reduces indent divergences of the event files. Though the
divergences report doesn't care about these differences, they do hurt
patches maintanence.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/aclocal.h |    4 ++--
 drivers/acpi/acpica/evgpe.c   |   18 +++++++++---------
 drivers/acpi/acpica/evxface.c |    8 ++++----
 3 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 91f801a..a9fa666 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -412,8 +412,8 @@ struct acpi_gpe_handler_info {
 	acpi_gpe_handler address;	/* Address of handler, if any */
 	void *context;		/* Context to be passed to handler */
 	struct acpi_namespace_node *method_node;	/* Method node for this GPE level (saved) */
-	u8 original_flags;      /* Original (pre-handler) GPE info */
-	u8 originally_enabled;  /* True if GPE was originally enabled */
+	u8 original_flags;	/* Original (pre-handler) GPE info */
+	u8 originally_enabled;	/* True if GPE was originally enabled */
 };
 
 /* Notify info for implicit notify, multiple device objects */
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index e4ba4de..f9e6891 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -212,7 +212,7 @@ acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info)
 		if (ACPI_SUCCESS(status)) {
 			status =
 			    acpi_hw_low_set_gpe(gpe_event_info,
-						     ACPI_GPE_DISABLE);
+						ACPI_GPE_DISABLE);
 		}
 
 		if (ACPI_FAILURE(status)) {
@@ -334,7 +334,7 @@ struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device,
  *
  ******************************************************************************/
 
-u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
+u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list)
 {
 	acpi_status status;
 	struct acpi_gpe_block_info *gpe_block;
@@ -427,7 +427,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
 
 			/* Check if there is anything active at all in this register */
 
-			enabled_status_byte = (u8) (status_reg & enable_reg);
+			enabled_status_byte = (u8)(status_reg & enable_reg);
 			if (!enabled_status_byte) {
 
 				/* No active GPEs in this register, move on */
@@ -450,7 +450,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
 					    acpi_ev_gpe_dispatch(gpe_block->
 								 node,
 								 &gpe_block->
-						event_info[((acpi_size) i * ACPI_GPE_REGISTER_WIDTH) + j], j + gpe_register_info->base_gpe_number);
+								 event_info[((acpi_size) i * ACPI_GPE_REGISTER_WIDTH) + j], j + gpe_register_info->base_gpe_number);
 				}
 			}
 		}
@@ -636,7 +636,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context)
  *
  ******************************************************************************/
 
-acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info)
+acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info * gpe_event_info)
 {
 	acpi_status status;
 
@@ -666,9 +666,9 @@ acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info)
  *
  * FUNCTION:    acpi_ev_gpe_dispatch
  *
- * PARAMETERS:  gpe_device      - Device node. NULL for GPE0/GPE1
- *              gpe_event_info  - Info for this GPE
- *              gpe_number      - Number relative to the parent GPE block
+ * PARAMETERS:  gpe_device          - Device node. NULL for GPE0/GPE1
+ *              gpe_event_info      - Info for this GPE
+ *              gpe_number          - Number relative to the parent GPE block
  *
  * RETURN:      INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
  *
@@ -681,7 +681,7 @@ acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info)
 
 u32
 acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
-		    struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
+		     struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
 {
 	acpi_status status;
 	u32 return_value;
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index 11e5803..1bcb55b 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -786,7 +786,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
 	handler->method_node = gpe_event_info->dispatch.method_node;
 	handler->original_flags = (u8)(gpe_event_info->flags &
 				       (ACPI_GPE_XRUPT_TYPE_MASK |
-				        ACPI_GPE_DISPATCH_MASK));
+					ACPI_GPE_DISPATCH_MASK));
 
 	/*
 	 * If the GPE is associated with a method, it may have been enabled
@@ -808,7 +808,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
 
 	gpe_event_info->flags &=
 	    ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
-	gpe_event_info->flags |= (u8) (type | ACPI_GPE_DISPATCH_HANDLER);
+	gpe_event_info->flags |= (u8)(type | ACPI_GPE_DISPATCH_HANDLER);
 
 	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
 
@@ -893,7 +893,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
 
 	gpe_event_info->dispatch.method_node = handler->method_node;
 	gpe_event_info->flags &=
-		~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
+	    ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
 	gpe_event_info->flags |= handler->original_flags;
 
 	/*
@@ -946,7 +946,7 @@ ACPI_EXPORT_SYMBOL(acpi_remove_gpe_handler)
  * handle is returned.
  *
  ******************************************************************************/
-acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle)
+acpi_status acpi_acquire_global_lock(u16 timeout, u32 *handle)
 {
 	acpi_status status;
 
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH 2/9] ACPICA: Events: Fix an issue that GPE APIs cannot be invoked in atomic context.
  2014-06-18  3:17 [PATCH 0/9] ACPI/EC: Improve GPE handling model Lv Zheng
  2014-06-18  3:17 ` [PATCH 1/9] ACPICA: Events: Reduce indent divergences of events files Lv Zheng
@ 2014-06-18  3:17 ` Lv Zheng
  2014-06-18  3:17 ` [PATCH 3/9] ACPICA: Events: Introduce acpi_set_gpe()/acpi_finish_gpe() to reduce divergences Lv Zheng
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-06-18  3:17 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The GPE APIs should be invoked inside of an IRQ context GPE handler or in
the task context with a driver provided lock held. This driver provided
lock should be safe to be held in the GPE handler by the driver.

While currently we cannot do this, thus we can only use the GPE APIs for
limitted cases.

This patch adds reference counting for struct acpi_gpe_handler_info. Then the GPE
handler can be safely invoked without holding the GPE lock, thus
facilitates GPE APIs to be invoked in any atomic environment. Lv Zheng.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/acevents.h |    1 +
 drivers/acpi/acpica/aclocal.h  |    1 +
 drivers/acpi/acpica/evgpe.c    |   71 ++++++++++++++++++++++++++++++++--------
 drivers/acpi/acpica/evxface.c  |   14 +++++---
 4 files changed, 70 insertions(+), 17 deletions(-)

diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h
index 7a7811a..a3d5276 100644
--- a/drivers/acpi/acpica/acevents.h
+++ b/drivers/acpi/acpica/acevents.h
@@ -123,6 +123,7 @@ ACPI_HW_DEPENDENT_RETURN_OK(acpi_status
 u32
 acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
 		     struct acpi_gpe_event_info *gpe_event_info,
+		     struct acpi_gpe_handler_info *gpe_handler_info,
 		     u32 gpe_number);
 
 /*
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index a9fa666..7363e2c 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -414,6 +414,7 @@ struct acpi_gpe_handler_info {
 	struct acpi_namespace_node *method_node;	/* Method node for this GPE level (saved) */
 	u8 original_flags;	/* Original (pre-handler) GPE info */
 	u8 originally_enabled;	/* True if GPE was originally enabled */
+	u16 reference_count;	/* For deletion management */
 };
 
 /* Notify info for implicit notify, multiple device objects */
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index f9e6891..3ab56d7 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -338,6 +338,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list)
 {
 	acpi_status status;
 	struct acpi_gpe_block_info *gpe_block;
+	struct acpi_gpe_event_info *gpe_event_info;
+	struct acpi_gpe_handler_info *gpe_handler_info;
 	struct acpi_gpe_register_info *gpe_register_info;
 	u32 int_status = ACPI_INTERRUPT_NOT_HANDLED;
 	u8 enabled_status_byte;
@@ -442,15 +444,45 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list)
 				/* Examine one GPE bit */
 
 				if (enabled_status_byte & (1 << j)) {
+					gpe_event_info =
+					    &gpe_block->
+					    event_info[((acpi_size) i *
+							ACPI_GPE_REGISTER_WIDTH)
+						       + j];
+					gpe_handler_info =
+					    gpe_event_info->dispatch.handler;
+
+					/* Acquire the reference to protect the invocations */
+
+					if (gpe_handler_info) {
+						gpe_handler_info->
+						    reference_count++;
+					}
+
 					/*
 					 * Found an active GPE. Dispatch the event to a handler
-					 * or method.
+					 * or method. Invoke without GPE lock held.
 					 */
+					acpi_os_release_lock(acpi_gbl_gpe_lock,
+							     flags);
 					int_status |=
 					    acpi_ev_gpe_dispatch(gpe_block->
 								 node,
-								 &gpe_block->
-								 event_info[((acpi_size) i * ACPI_GPE_REGISTER_WIDTH) + j], j + gpe_register_info->base_gpe_number);
+								 gpe_event_info,
+								 gpe_handler_info,
+								 j +
+								 gpe_register_info->
+								 base_gpe_number);
+					flags =
+					    acpi_os_acquire_lock
+					    (acpi_gbl_gpe_lock);
+
+					/* Release the reference */
+
+					if (gpe_handler_info) {
+						gpe_handler_info->
+						    reference_count--;
+					}
 				}
 			}
 		}
@@ -675,19 +707,27 @@ acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info * gpe_event_info)
  * DESCRIPTION: Dispatch a General Purpose Event to either a function (e.g. EC)
  *              or method (e.g. _Lxx/_Exx) handler.
  *
- *              This function executes at interrupt level.
+ *              This function executes at interrupt level with handler's
+ *              reference count held.
  *
  ******************************************************************************/
 
 u32
 acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
-		     struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
+		     struct acpi_gpe_event_info *gpe_event_info,
+		     struct acpi_gpe_handler_info *gpe_handler_info,
+		     u32 gpe_number)
 {
 	acpi_status status;
 	u32 return_value;
+	acpi_cpu_flags flags;
 
 	ACPI_FUNCTION_TRACE(ev_gpe_dispatch);
 
+	/* We need to obtain the GPE lock again */
+
+	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
 	/* Invoke global event handler if present */
 
 	acpi_gpe_count++;
@@ -710,6 +750,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
 	if (ACPI_FAILURE(status)) {
 		ACPI_EXCEPTION((AE_INFO, status,
 				"Unable to disable GPE %02X", gpe_number));
+		acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
 		return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
 	}
 
@@ -726,6 +767,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
 					gpe_number));
 			(void)acpi_hw_low_set_gpe(gpe_event_info,
 						  ACPI_GPE_CONDITIONAL_ENABLE);
+			acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
 			return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
 		}
 	}
@@ -740,14 +782,16 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
 	switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
 	case ACPI_GPE_DISPATCH_HANDLER:
 
-		/* Invoke the installed handler (at interrupt level) */
-
-		return_value =
-		    gpe_event_info->dispatch.handler->address(gpe_device,
-							      gpe_number,
-							      gpe_event_info->
-							      dispatch.handler->
-							      context);
+		/*
+		 * Invoke the installed handler (at interrupt level), release
+		 * the GPE lock so that the GPE APIs can be invoked in the
+		 * dispatcher.
+		 */
+		acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+		return_value = gpe_handler_info->address(gpe_device, gpe_number,
+							 gpe_handler_info->
+							 context);
+		flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
 
 		/* If requested, clear (if level-triggered) and reenable the GPE */
 
@@ -785,6 +829,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
 		break;
 	}
 
+	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
 	return_UINT32(ACPI_INTERRUPT_HANDLED);
 }
 
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index 1bcb55b..fc075a5 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -787,6 +787,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
 	handler->original_flags = (u8)(gpe_event_info->flags &
 				       (ACPI_GPE_XRUPT_TYPE_MASK |
 					ACPI_GPE_DISPATCH_MASK));
+	handler->reference_count = 0;
 
 	/*
 	 * If the GPE is associated with a method, it may have been enabled
@@ -888,6 +889,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
 	/* Remove the handler */
 
 	handler = gpe_event_info->dispatch.handler;
+	gpe_event_info->dispatch.handler = NULL;
 
 	/* Restore Method node (if any), set dispatch flags */
 
@@ -906,12 +908,16 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
 		(void)acpi_ev_add_gpe_reference(gpe_event_info);
 	}
 
-	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
-	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+	/* Make sure all GPE handlers are completed */
 
-	/* Make sure all deferred GPE tasks are completed */
+	while (handler->reference_count != 0) {
+		acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+		acpi_os_sleep((u64)10);
+		flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+	}
 
-	acpi_os_wait_events_complete();
+	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
 
 	/* Now we can free the handler object */
 
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH 3/9] ACPICA: Events: Introduce acpi_set_gpe()/acpi_finish_gpe() to reduce divergences.
  2014-06-18  3:17 [PATCH 0/9] ACPI/EC: Improve GPE handling model Lv Zheng
  2014-06-18  3:17 ` [PATCH 1/9] ACPICA: Events: Reduce indent divergences of events files Lv Zheng
  2014-06-18  3:17 ` [PATCH 2/9] ACPICA: Events: Fix an issue that GPE APIs cannot be invoked in atomic context Lv Zheng
@ 2014-06-18  3:17 ` Lv Zheng
  2014-06-18  3:17 ` [PATCH 4/9] ACPICA: Events: Remove acpi_ev_enable_gpe() Lv Zheng
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-06-18  3:17 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This can help to reduce source code differences between Linux and ACPICA
upstream. Further driver cleanups also require these APIs to eliminate GPE
storms.
1. acpi_set_gpe(): An API that driver should invoke in the case it wants
                   to disable/enable IRQ without honoring the reference
                   count implemented in the acpi_disable_gpe() and
                   acpi_enable_gpe(). Note that this API should only be
                   invoked inside a acpi_enable_gpe()/acpi_disable_gpe()
                   pair.
2. acpi_finish_gpe(): Drivers returned ACPI_REENABLE_GPE unset from the
                      GPE handler should use this API instead of
                      invoking acpi_set_gpe()/acpi_enable_gpe() to
                      re-enable the GPE.
The GPE APIs can be invoked inside of a GPE handler or in the task context
with a driver provided lock held. This driver provided lock is safe to be
held in the GPE handler by the driver.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/evxfgpe.c |  105 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 105 insertions(+)

diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c
index cb534fa..6c53633 100644
--- a/drivers/acpi/acpica/evxfgpe.c
+++ b/drivers/acpi/acpica/evxfgpe.c
@@ -176,6 +176,68 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number)
 
 ACPI_EXPORT_SYMBOL(acpi_disable_gpe)
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_set_gpe
+ *
+ * PARAMETERS:  gpe_device          - Parent GPE Device. NULL for GPE0/GPE1
+ *              gpe_number          - GPE level within the GPE block
+ *              action              - ACPI_GPE_ENABLE or ACPI_GPE_DISABLE
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Enable or disable an individual GPE. This function bypasses
+ *              the reference count mechanism used in the acpi_enable_gpe and
+ *              acpi_disable_gpe interfaces -- and should be used with care.
+ *
+ * Note: Typically used to disable a runtime GPE for short period of time,
+ * then re-enable it, without disturbing the existing reference counts. This
+ * is useful, for example, in the Embedded Controller (EC) driver.
+ *
+ ******************************************************************************/
+acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action)
+{
+	struct acpi_gpe_event_info *gpe_event_info;
+	acpi_status status;
+	acpi_cpu_flags flags;
+
+	ACPI_FUNCTION_TRACE(acpi_set_gpe);
+
+	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+	/* Ensure that we have a valid GPE number */
+
+	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+	if (!gpe_event_info) {
+		status = AE_BAD_PARAMETER;
+		goto unlock_and_exit;
+	}
+
+	/* Perform the action */
+
+	switch (action) {
+	case ACPI_GPE_ENABLE:
+
+		status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE);
+		break;
+
+	case ACPI_GPE_DISABLE:
+
+		status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
+		break;
+
+	default:
+
+		status = AE_BAD_PARAMETER;
+		break;
+	}
+
+unlock_and_exit:
+	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+	return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_set_gpe)
 
 /*******************************************************************************
  *
@@ -479,6 +541,49 @@ unlock_and_exit:
 
 ACPI_EXPORT_SYMBOL(acpi_get_gpe_status)
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_finish_gpe
+ *
+ * PARAMETERS:  gpe_device          - Namespace node for the GPE Block
+ *                                    (NULL for FADT defined GPEs)
+ *              gpe_number          - GPE level within the GPE block
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Clear and conditionally reenable a GPE. This completes the GPE
+ *              processing. Intended for use by asynchronous host-installed
+ *              GPE handlers. The GPE is only reenabled if the enable_for_run bit
+ *              is set in the GPE info.
+ *
+ ******************************************************************************/
+acpi_status acpi_finish_gpe(acpi_handle gpe_device, u32 gpe_number)
+{
+	struct acpi_gpe_event_info *gpe_event_info;
+	acpi_status status;
+	acpi_cpu_flags flags;
+
+	ACPI_FUNCTION_TRACE(acpi_finish_gpe);
+
+	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+	/* Ensure that we have a valid GPE number */
+
+	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+	if (!gpe_event_info) {
+		status = AE_BAD_PARAMETER;
+		goto unlock_and_exit;
+	}
+
+	status = acpi_ev_finish_gpe(gpe_event_info);
+
+unlock_and_exit:
+	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+	return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_finish_gpe)
+
 /******************************************************************************
  *
  * FUNCTION:    acpi_disable_all_gpes
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH 4/9] ACPICA: Events: Remove acpi_ev_enable_gpe().
  2014-06-18  3:17 [PATCH 0/9] ACPI/EC: Improve GPE handling model Lv Zheng
                   ` (2 preceding siblings ...)
  2014-06-18  3:17 ` [PATCH 3/9] ACPICA: Events: Introduce acpi_set_gpe()/acpi_finish_gpe() to reduce divergences Lv Zheng
@ 2014-06-18  3:17 ` Lv Zheng
  2014-06-18  3:17 ` [PATCH 5/9] ACPICA: Events: Reduce divergences to honor notify handler enabled GPEs Lv Zheng
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-06-18  3:17 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The stale GPE indication is not a problem. Drivers should always check the
underlying hardware status and be ready to handle invalid status.

The GPE clearing implemented in acpi_ev_enable_gpe() on the contrary
introduces issues for acpi_enable_gpe() logic. When the usage count of GPE is
increased by suspend/resume code, GPE status shouldn't be cleared, or a GPE
loss could happen when the driver relies on the interrupt mode.

With previous cleanup, all acpi_ev_enable_gpe() usages are removed, this patch
also removes this internal API. Lv Zheng.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/evgpe.c |   45 +++----------------------------------------
 1 file changed, 3 insertions(+), 42 deletions(-)

diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index 3ab56d7..64f6d41 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -98,47 +98,6 @@ acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info)
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ev_enable_gpe
- *
- * PARAMETERS:  gpe_event_info  - GPE to enable
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Clear a GPE of stale events and enable it.
- *
- ******************************************************************************/
-acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
-{
-	acpi_status status;
-
-	ACPI_FUNCTION_TRACE(ev_enable_gpe);
-
-	/*
-	 * We will only allow a GPE to be enabled if it has either an associated
-	 * method (_Lxx/_Exx) or a handler, or is using the implicit notify
-	 * feature. Otherwise, the GPE will be immediately disabled by
-	 * acpi_ev_gpe_dispatch the first time it fires.
-	 */
-	if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
-	    ACPI_GPE_DISPATCH_NONE) {
-		return_ACPI_STATUS(AE_NO_HANDLER);
-	}
-
-	/* Clear the GPE (of stale events) */
-	status = acpi_hw_clear_gpe(gpe_event_info);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/* Enable the requested GPE */
-
-	status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE);
-	return_ACPI_STATUS(status);
-}
-
-
-/*******************************************************************************
- *
  * FUNCTION:    acpi_ev_add_gpe_reference
  *
  * PARAMETERS:  gpe_event_info          - Add a reference to this GPE
@@ -168,7 +127,9 @@ acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *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);
+			status =
+			    acpi_hw_low_set_gpe(gpe_event_info,
+						ACPI_GPE_ENABLE);
 		}
 
 		if (ACPI_FAILURE(status)) {
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH 5/9] ACPICA: Events: Reduce divergences to honor notify handler enabled GPEs.
  2014-06-18  3:17 [PATCH 0/9] ACPI/EC: Improve GPE handling model Lv Zheng
                   ` (3 preceding siblings ...)
  2014-06-18  3:17 ` [PATCH 4/9] ACPICA: Events: Remove acpi_ev_enable_gpe() Lv Zheng
@ 2014-06-18  3:17 ` Lv Zheng
  2014-06-18  3:17 ` [PATCH 6/9] ACPI/EC: Introduce STARTED/STOPPED flags to replace BLOCKED flag Lv Zheng
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-06-18  3:17 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The back port result of a divergence fix that the origianlly_enabled check
is not paired between acpi_install_gpe_handler() and
acpi_remove_gpe_handler(). Lv Zheng.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/evxface.c |   19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index fc075a5..e090dd1 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -794,11 +794,19 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
 	 * automatically during initialization, in which case it has to be
 	 * disabled now to avoid spurious execution of the handler.
 	 */
-
-	if ((handler->original_flags & ACPI_GPE_DISPATCH_METHOD)
-	    && gpe_event_info->runtime_count) {
-		handler->originally_enabled = 1;
+	if (((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) ||
+	     (handler->original_flags & ACPI_GPE_DISPATCH_NOTIFY)) &&
+	    gpe_event_info->runtime_count) {
+		handler->originally_enabled = TRUE;
 		(void)acpi_ev_remove_gpe_reference(gpe_event_info);
+
+		/* Sanity check of original type against new type */
+
+		if (type !=
+		    (u32)(gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK)) {
+			ACPI_WARNING((AE_INFO,
+				      "GPE type mismatch (level/edge)"));
+		}
 	}
 
 	/* Install the handler */
@@ -903,7 +911,8 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
 	 * enabled, it should be enabled at this point to restore the
 	 * post-initialization configuration.
 	 */
-	if ((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) &&
+	if (((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) ||
+	     (handler->original_flags & ACPI_GPE_DISPATCH_NOTIFY)) &&
 	    handler->originally_enabled) {
 		(void)acpi_ev_add_gpe_reference(gpe_event_info);
 	}
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH 6/9] ACPI/EC: Introduce STARTED/STOPPED flags to replace BLOCKED flag.
  2014-06-18  3:17 [PATCH 0/9] ACPI/EC: Improve GPE handling model Lv Zheng
                   ` (4 preceding siblings ...)
  2014-06-18  3:17 ` [PATCH 5/9] ACPICA: Events: Reduce divergences to honor notify handler enabled GPEs Lv Zheng
@ 2014-06-18  3:17 ` Lv Zheng
  2014-06-18  3:18 ` [PATCH 7/9] ACPI/EC: Add detailed command/query debugging information Lv Zheng
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-06-18  3:17 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

By using the 2 flags, we can indicate an inter-mediate state where the
current transactions should be completed while the new transactions should
be blocked.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   56 +++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 42 insertions(+), 14 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index c3299f6..6891370 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -79,7 +79,8 @@ enum {
 	EC_FLAGS_GPE_STORM,		/* GPE storm detected */
 	EC_FLAGS_HANDLERS_INSTALLED,	/* Handlers for GPE and
 					 * OpReg are installed */
-	EC_FLAGS_BLOCKED,		/* Transactions are blocked */
+	EC_FLAGS_STARTED,		/* Driver is started */
+	EC_FLAGS_STOPPED,		/* Driver is stopped */
 };
 
 #define ACPI_EC_COMMAND_POLL		0x01 /* Available for command byte */
@@ -285,15 +286,25 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 		udelay(ACPI_EC_MSI_UDELAY);
 	/* start transaction */
 	spin_lock_irqsave(&ec->lock, tmp);
+	if (!test_bit(EC_FLAGS_STARTED, &ec->flags) ||
+	    test_bit(EC_FLAGS_STOPPED, &ec->flags)) {
+		ret = -EINVAL;
+		goto unlock;
+	}
 	/* following two actions should be kept atomic */
 	ec->curr = t;
+	pr_debug("***** transaction started (cmd=0x%02x, addr=0x%02x) *****\n",
+		 t->command, t->wdata ? t->wdata[0] : 0);
 	start_transaction(ec);
 	if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
 		clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
 	spin_unlock_irqrestore(&ec->lock, tmp);
 	ret = ec_poll(ec);
 	spin_lock_irqsave(&ec->lock, tmp);
+	pr_debug("***** transaction stopped (cmd=0x%02x, addr=0x%02x) *****\n",
+		 t->command, t->wdata ? t->wdata[0] : 0);
 	ec->curr = NULL;
+unlock:
 	spin_unlock_irqrestore(&ec->lock, tmp);
 	return ret;
 }
@@ -307,10 +318,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
 	if (t->rdata)
 		memset(t->rdata, 0, t->rlen);
 	mutex_lock(&ec->mutex);
-	if (test_bit(EC_FLAGS_BLOCKED, &ec->flags)) {
-		status = -EINVAL;
-		goto unlock;
-	}
 	if (ec->global_lock) {
 		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
 		if (ACPI_FAILURE(status)) {
@@ -318,8 +325,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
 			goto unlock;
 		}
 	}
-	pr_debug("transaction start (cmd=0x%02x, addr=0x%02x)\n",
-			t->command, t->wdata ? t->wdata[0] : 0);
 	/* disable GPE during transaction if storm is detected */
 	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
 		/* It has to be disabled, so that it doesn't trigger. */
@@ -340,7 +345,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
 			t->irq_count);
 		set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
 	}
-	pr_debug("transaction end\n");
 	if (ec->global_lock)
 		acpi_release_global_lock(glk);
 unlock:
@@ -470,6 +474,30 @@ static void acpi_ec_clear(struct acpi_ec *ec)
 		pr_info("%d stale EC events cleared\n", i);
 }
 
+static void acpi_ec_start(struct acpi_ec *ec)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ec->lock, flags);
+	if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags))
+		acpi_enable_gpe(NULL, ec->gpe);
+	spin_unlock_irqrestore(&ec->lock, flags);
+}
+
+static void acpi_ec_stop(struct acpi_ec *ec)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ec->lock, flags);
+	if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
+	    !test_and_set_bit(EC_FLAGS_STOPPED, &ec->flags)) {
+		acpi_disable_gpe(NULL, ec->gpe);
+		clear_bit(EC_FLAGS_STARTED, &ec->flags);
+		clear_bit(EC_FLAGS_STOPPED, &ec->flags);
+	}
+	spin_unlock_irqrestore(&ec->lock, flags);
+}
+
 void acpi_ec_block_transactions(void)
 {
 	struct acpi_ec *ec = first_ec;
@@ -479,7 +507,7 @@ void acpi_ec_block_transactions(void)
 
 	mutex_lock(&ec->mutex);
 	/* Prevent transactions from being carried out */
-	set_bit(EC_FLAGS_BLOCKED, &ec->flags);
+	acpi_ec_stop(ec);
 	mutex_unlock(&ec->mutex);
 }
 
@@ -492,7 +520,7 @@ void acpi_ec_unblock_transactions(void)
 
 	mutex_lock(&ec->mutex);
 	/* Allow transactions to be carried out again */
-	clear_bit(EC_FLAGS_BLOCKED, &ec->flags);
+	acpi_ec_start(ec);
 
 	if (EC_FLAGS_CLEAR_ON_RESUME)
 		acpi_ec_clear(ec);
@@ -507,7 +535,7 @@ void acpi_ec_unblock_transactions_early(void)
 	 * atomic context during wakeup, so we don't need to acquire the mutex).
 	 */
 	if (first_ec)
-		clear_bit(EC_FLAGS_BLOCKED, &first_ec->flags);
+		acpi_ec_start(first_ec);
 }
 
 static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data)
@@ -774,7 +802,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
-	acpi_enable_gpe(NULL, ec->gpe);
+	acpi_ec_start(ec);
 	status = acpi_install_address_space_handler(ec->handle,
 						    ACPI_ADR_SPACE_EC,
 						    &acpi_ec_space_handler,
@@ -789,7 +817,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
 			pr_err("Fail in evaluating the _REG object"
 				" of EC device. Broken bios is suspected.\n");
 		} else {
-			acpi_disable_gpe(NULL, ec->gpe);
+			acpi_ec_stop(ec);
 			acpi_remove_gpe_handler(NULL, ec->gpe,
 				&acpi_ec_gpe_handler);
 			return -ENODEV;
@@ -802,10 +830,10 @@ static int ec_install_handlers(struct acpi_ec *ec)
 
 static void ec_remove_handlers(struct acpi_ec *ec)
 {
-	acpi_disable_gpe(NULL, ec->gpe);
 	if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
 				ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
 		pr_err("failed to remove space handler\n");
+	acpi_ec_stop(ec);
 	if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
 				&acpi_ec_gpe_handler)))
 		pr_err("failed to remove gpe handler\n");
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH 7/9] ACPI/EC: Add detailed command/query debugging information.
  2014-06-18  3:17 [PATCH 0/9] ACPI/EC: Improve GPE handling model Lv Zheng
                   ` (5 preceding siblings ...)
  2014-06-18  3:17 ` [PATCH 6/9] ACPI/EC: Introduce STARTED/STOPPED flags to replace BLOCKED flag Lv Zheng
@ 2014-06-18  3:18 ` Lv Zheng
  2014-06-18  3:18 ` [PATCH 8/9] ACPI/EC: Deploy the new GPE handling model Lv Zheng
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-06-18  3:18 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

Developers really don't need to translate EC commands in mind. This patch
adds detailed debugging information for the EC commands.
The address can be found in the follow-up sequential EC_DATA(W) accesses,
thus this patch also removes some of the redundant address information.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   29 +++++++++++++++++++++++++----
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 6891370..4799ea0 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -165,6 +165,27 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
 	outb(data, ec->data_addr);
 }
 
+#ifdef DEBUG
+static const char *acpi_ec_cmd_string(u8 cmd)
+{
+	switch (cmd) {
+	case 0x80:
+		return "RD_EC";
+	case 0x81:
+		return "WR_EC";
+	case 0x82:
+		return "BE_EC";
+	case 0x83:
+		return "BD_EC";
+	case 0x84:
+		return "QR_EC";
+	}
+	return "UNKNOWN";
+}
+#else
+#define acpi_ec_cmd_string(cmd)		"UNDEF"
+#endif
+
 static int ec_transaction_completed(struct acpi_ec *ec)
 {
 	unsigned long flags;
@@ -293,16 +314,16 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 	}
 	/* following two actions should be kept atomic */
 	ec->curr = t;
-	pr_debug("***** transaction started (cmd=0x%02x, addr=0x%02x) *****\n",
-		 t->command, t->wdata ? t->wdata[0] : 0);
+	pr_debug("***** Command(%s) started *****\n",
+		 acpi_ec_cmd_string(t->command));
 	start_transaction(ec);
 	if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
 		clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
 	spin_unlock_irqrestore(&ec->lock, tmp);
 	ret = ec_poll(ec);
 	spin_lock_irqsave(&ec->lock, tmp);
-	pr_debug("***** transaction stopped (cmd=0x%02x, addr=0x%02x) *****\n",
-		 t->command, t->wdata ? t->wdata[0] : 0);
+	pr_debug("***** Command(%s) stopped *****\n",
+		 acpi_ec_cmd_string(t->command));
 	ec->curr = NULL;
 unlock:
 	spin_unlock_irqrestore(&ec->lock, tmp);
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH 8/9] ACPI/EC: Deploy the new GPE handling model.
  2014-06-18  3:17 [PATCH 0/9] ACPI/EC: Improve GPE handling model Lv Zheng
                   ` (6 preceding siblings ...)
  2014-06-18  3:18 ` [PATCH 7/9] ACPI/EC: Add detailed command/query debugging information Lv Zheng
@ 2014-06-18  3:18 ` Lv Zheng
  2014-06-18  3:18 ` [PATCH 9/9] ACPI/EC: Add unit test support for EC driver hotplug Lv Zheng
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-06-18  3:18 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch deploys the following GPE handling model:
1. acpi_enable_gpe()/acpi_disable_gpe():
     This set of APIs are used for EC usage reference counting.
2. acpi_set_gpe(ACPI_GPE_ENABLE)/acpi_set_gpe(ACPI_GPE_DISABLE):
     This set of APIs are used for preventing GPE storm.

For the EC driver, GPE is enabled for the following users:
1. Event monitoring: If we want to query events, acpi_enable_gpe() is
                     invoked to allow EVT_SCI.
2. Command processing: when we receive an upper layer command submission,
                       acpi_enable_gpe() is invoked to allow IBF=0,OBF=1
                       IRQs.
Comments are updated to reflect this model.

For the EC driver, GPE is disabled for the following storms:
1. Command errors: If there are too many IRQs coming during a command
                   processing period and such IRQs are not related to the
                   event (EVT_SCI), acpi_set_gpe(ACPI_GPE_DISABLE) is
                   invoked to prevent further storms during the same
                   command transaction. This is not implemented in a good
                   style. Ideally, we should only enable storm prevention
                   for the current command so that the next command can try
                   the efficient interrupt mode again. This patch doesn't
                   change this much, but introduces a slight modification
                   to clear the storm flag after completing the current
                   command polling process.
2. Event errors: Note currently we haven't implemented the storm prevention
                 for EVT_SCI.

The acpi_set_gpe() should be invoked for an outstanding command,
which means it should be invoked inside of a pair of acpi_enable_gpe()/
acpi_disable_gpe() invocation. This patch thus also moves the storm
prevention logic into acpi_ec_transaction_unlocked().

With the new facility, we are able to flush outstanding commands by waiting
for the GPE to be disabled after we have stopped monitoring the EC events.
The GPE APIs are safe to be invoked with holding the driver's spin lock
which is shared with the GPE handler. Thus this patch invokes
acpi_enable_gpe()/acpi_disable_gpe() within the EC state protection lock so
that the GPE usage changes becomes a part of the EC driver state changes.

The system suspending/resuming test result is as follows:
 [   24.950829] ACPI : EC: +++++ Stopping EC +++++
 [   24.950836] ACPI : EC: +++++ EC stopped +++++

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   82 ++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 65 insertions(+), 17 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 4799ea0..92058a1 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -129,6 +129,29 @@ static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
 static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
 
 /* --------------------------------------------------------------------------
+                             GPE Enhancement
+   -------------------------------------------------------------------------- */
+
+static bool acpi_gpe_disabled(acpi_handle handle, u32 gpe_number)
+{
+	acpi_event_status event_status = 0;
+
+	(void)acpi_get_gpe_status(NULL, gpe_number, &event_status);
+	return !(event_status & ACPI_EVENT_FLAG_ENABLED);
+}
+
+static bool acpi_ec_disable_gpe(struct acpi_ec *ec)
+{
+	bool disabled;
+
+	acpi_disable_gpe(NULL, ec->gpe);
+	disabled = acpi_gpe_disabled(NULL, ec->gpe);
+	if (disabled)
+		wake_up(&ec->wait);
+	return disabled;
+}
+
+/* --------------------------------------------------------------------------
                              Transaction Management
    -------------------------------------------------------------------------- */
 
@@ -314,16 +337,33 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 	}
 	/* following two actions should be kept atomic */
 	ec->curr = t;
+	/* Enable GPE for command processing (IBF=0/OBF=1) */
+	acpi_enable_gpe(NULL, ec->gpe);
 	pr_debug("***** Command(%s) started *****\n",
 		 acpi_ec_cmd_string(t->command));
+	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
+		pr_debug("+++++ Polling enabled +++++\n");
+		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
+	}
 	start_transaction(ec);
 	if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
 		clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
 	spin_unlock_irqrestore(&ec->lock, tmp);
 	ret = ec_poll(ec);
 	spin_lock_irqsave(&ec->lock, tmp);
+	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
+		clear_bit(EC_FLAGS_GPE_STORM, &ec->flags);
+		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
+		pr_debug("+++++ Polling disabled +++++\n");
+	} else if (t->irq_count > ec_storm_threshold) {
+		pr_debug("+++++ Polling scheduled (%d GPE) +++++\n",
+			 t->irq_count);
+		set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
+	}
 	pr_debug("***** Command(%s) stopped *****\n",
 		 acpi_ec_cmd_string(t->command));
+	/* Disable GPE for command processing (IBF=0/OBF=1) */
+	acpi_ec_disable_gpe(ec);
 	ec->curr = NULL;
 unlock:
 	spin_unlock_irqrestore(&ec->lock, tmp);
@@ -346,26 +386,11 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
 			goto unlock;
 		}
 	}
-	/* disable GPE during transaction if storm is detected */
-	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
-		/* It has to be disabled, so that it doesn't trigger. */
-		acpi_disable_gpe(NULL, ec->gpe);
-	}
 
 	status = acpi_ec_transaction_unlocked(ec, t);
 
 	/* check if we received SCI during transaction */
 	ec_check_sci_sync(ec, acpi_ec_read_status(ec));
-	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
-		msleep(1);
-		/* It is safe to enable the GPE outside of the transaction. */
-		acpi_enable_gpe(NULL, ec->gpe);
-	} else if (t->irq_count > ec_storm_threshold) {
-		pr_info("GPE storm detected(%d GPEs), "
-			"transactions will use polling mode\n",
-			t->irq_count);
-		set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
-	}
 	if (ec->global_lock)
 		acpi_release_global_lock(glk);
 unlock:
@@ -500,9 +525,25 @@ static void acpi_ec_start(struct acpi_ec *ec)
 	unsigned long flags;
 
 	spin_lock_irqsave(&ec->lock, flags);
-	if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags))
+	if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags)) {
+		pr_debug("+++++ Starting EC +++++\n");
+		/* Enable GPE for event processing (EVT_SCI=1) */
 		acpi_enable_gpe(NULL, ec->gpe);
+		pr_info("+++++ EC started +++++\n");
+	}
+	spin_unlock_irqrestore(&ec->lock, flags);
+}
+
+static bool acpi_ec_stopped(struct acpi_ec *ec)
+{
+	unsigned long flags;
+	bool disabled = false;
+
+	spin_lock_irqsave(&ec->lock, flags);
+	disabled = acpi_gpe_disabled(NULL, ec->gpe);
 	spin_unlock_irqrestore(&ec->lock, flags);
+
+	return disabled;
 }
 
 static void acpi_ec_stop(struct acpi_ec *ec)
@@ -512,9 +553,16 @@ static void acpi_ec_stop(struct acpi_ec *ec)
 	spin_lock_irqsave(&ec->lock, flags);
 	if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
 	    !test_and_set_bit(EC_FLAGS_STOPPED, &ec->flags)) {
-		acpi_disable_gpe(NULL, ec->gpe);
+		pr_debug("+++++ Stopping EC +++++\n");
+		/* Disable GPE for event processing (EVT_SCI=1) */
+		if (!acpi_ec_disable_gpe(ec)) {
+			spin_unlock_irqrestore(&ec->lock, flags);
+			wait_event(ec->wait, acpi_ec_stopped(ec));
+			spin_lock_irqsave(&ec->lock, flags);
+		}
 		clear_bit(EC_FLAGS_STARTED, &ec->flags);
 		clear_bit(EC_FLAGS_STOPPED, &ec->flags);
+		pr_info("+++++ EC stopped +++++\n");
 	}
 	spin_unlock_irqrestore(&ec->lock, flags);
 }
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH 9/9] ACPI/EC: Add unit test support for EC driver hotplug.
  2014-06-18  3:17 [PATCH 0/9] ACPI/EC: Improve GPE handling model Lv Zheng
                   ` (7 preceding siblings ...)
  2014-06-18  3:18 ` [PATCH 8/9] ACPI/EC: Deploy the new GPE handling model Lv Zheng
@ 2014-06-18  3:18 ` Lv Zheng
  2014-07-15  3:07 ` [PATCH v2 0/9] ACPICA: Improve GPE handling model Lv Zheng
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-06-18  3:18 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds facility to test future EC modification.
All EC commits should enable TEST_HOTPLUG, and try a build/boot test.
Since EC is currently a built-in module, this is the only mean for us to
test the hotplug code.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 92058a1..c5d0797 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -31,6 +31,7 @@
 
 /* Uncomment next line to get verbose printout */
 /* #define DEBUG */
+/* #define TEST_HOTPLUG */
 #define pr_fmt(fmt) "ACPI : EC: " fmt
 
 #include <linux/kernel.h>
@@ -120,6 +121,9 @@ struct transaction {
 	u8 flags;
 };
 
+static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
+			       u32 gpe_number, void *data);
+
 struct acpi_ec *boot_ec, *first_ec;
 EXPORT_SYMBOL(first_ec);
 
@@ -720,6 +724,21 @@ static void acpi_ec_gpe_query(void *ec_cxt)
 	mutex_lock(&ec->mutex);
 	acpi_ec_sync_query(ec, NULL);
 	mutex_unlock(&ec->mutex);
+
+#ifdef TEST_HOTPLUG
+
+	/* Unit testing for driver hotplugging */
+
+	pr_info("Removing EC handlers...\n");
+	acpi_ec_stop(ec);
+	acpi_remove_gpe_handler(NULL, ec->gpe,
+				&acpi_ec_gpe_handler);
+	pr_info("Installing EC handlers...\n");
+	acpi_install_gpe_handler(NULL, ec->gpe,
+				  ACPI_GPE_EDGE_TRIGGERED,
+				  &acpi_ec_gpe_handler, ec);
+	acpi_ec_start(ec);
+#endif
 }
 
 static int ec_check_sci(struct acpi_ec *ec, u8 state)
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v2 0/9] ACPICA: Improve GPE handling model.
  2014-06-18  3:17 [PATCH 0/9] ACPI/EC: Improve GPE handling model Lv Zheng
                   ` (8 preceding siblings ...)
  2014-06-18  3:18 ` [PATCH 9/9] ACPI/EC: Add unit test support for EC driver hotplug Lv Zheng
@ 2014-07-15  3:07 ` Lv Zheng
  2014-07-15  3:07   ` [PATCH v2 1/9] ACPICA: Events: Reduce indent divergences of events files Lv Zheng
                     ` (9 more replies)
  2014-07-15  3:14 ` [PATCH v2 00/10] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
                   ` (3 subsequent siblings)
  13 siblings, 10 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-15  3:07 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patchset enables the ideal GPE handling model. The ideal GPE handling
model should be able to handle the following cases:

   1. When upper layers (the users of the driver) submit requests to the
      drivers, it means they care about the underlying hardware. For this
      case, acpi_enable_gpe() should be invoked. When the reference count
      is increased from 0 to 1, driver enables the hardware IRQ. And
      acpi_disable_gpe() is used as the reversal when the users have
      completed the submitted requests.
   2. Driver may temporarily disables the IRQ and wants to re-enable it
      later, this case is normally used in order to prevent IRQ storm.
      When a driver cannot fully solve the condition that triggered the IRQ
      in the IRQ context, in order not to trigger IRQ storm, driver has to
      disable IRQ and re-enables it in the deferred execution environment
      - which should be in a task context. The acpi_set_gpe() API should be
      used exactly for this purpose.

The reason why this model hasn't been enabled for the current Linux ACPI
drivers is:
  In ACPICA, the same GPE lock is held while invoking the GPE handler
  callback, it's thus impossible to invoke GPE APIs in the GPE handler
  because the APIs require to hold the GPE lock. The recursive locking
  leads to dead locks. This is a simple design defect, callbacks should
  always be invoked in a lockless environment, normally in Linux, this is
  achieved by RCU locking, and in ACPICA, we achieve this using reference
  counting.

After fixing the above bug and doing necessary cleanups in the ACPICA GPE
handling code, we now can enable this ideal GPE handling model for the EC
driver to implement "commands flushing" and "storm prevention" (the EC
driver enabling is not included in this patchset).

The refined patches are passed the runtime/suspend tests carried out on the
following platforms with EC driver enhanced:
  "Dell Inspiron Mini 1010" - i386 kernel
  "Dell Latitude 6430u" - x86_64 kernel

Lv Zheng (9):
  ACPICA: Events: Reduce indent divergences of events files.
  ACPICA: Events: Fix an issue that GPE APIs cannot be invoked in
    atomic context.
  ACPICA: Events: Fix an issue that GPE APIs cannot be invoked in
    deferred handlers.
  ACPICA: Events: Introduce acpi_set_gpe()/acpi_finish_gpe() to reduce
    divergences.
  ACPICA: Events: Fix an issue that acpi_set_gpe() cannot
    unconditionally enable GPEs.
  ACPICA: Events: Fix an issue that status of GPEs are unexpectedly
    cleared.
  ACPICA: Events: Fix an issue that originally_enabled check is not
    paired.
  ACPICA: Events: Add a flag to disable internal auto GPE clearing.
  ACPI: Update interrupt handler to honor new ACPI_REENABLE_GPE bit.

 drivers/acpi/acpica/acevents.h |    1 +
 drivers/acpi/acpica/aclocal.h  |    5 +-
 drivers/acpi/acpica/evgpe.c    |  136 +++++++++++++++++++++-------------------
 drivers/acpi/acpica/evxface.c  |   41 ++++++++----
 drivers/acpi/acpica/evxfgpe.c  |  105 +++++++++++++++++++++++++++++++
 drivers/acpi/osl.c             |    2 +-
 include/acpi/actypes.h         |   16 ++---
 7 files changed, 219 insertions(+), 87 deletions(-)

-- 
1.7.10


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v2 1/9] ACPICA: Events: Reduce indent divergences of events files.
  2014-07-15  3:07 ` [PATCH v2 0/9] ACPICA: Improve GPE handling model Lv Zheng
@ 2014-07-15  3:07   ` Lv Zheng
  2014-07-15  3:07   ` [PATCH v2 2/9] ACPICA: Events: Fix an issue that GPE APIs cannot be invoked in atomic context Lv Zheng
                     ` (8 subsequent siblings)
  9 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-15  3:07 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch reduces indent divergences first in order to reduce human
intervention work for the follow-up linuxized event patches.

This patch reduces indent divergences of the event files. Though the
divergences report doesn't care about these differences, they do hurt
patches maintanence.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/aclocal.h |    4 ++--
 drivers/acpi/acpica/evgpe.c   |   23 ++++++++++++-----------
 drivers/acpi/acpica/evxface.c |    8 ++++----
 3 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 91f801a..a9fa666 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -412,8 +412,8 @@ struct acpi_gpe_handler_info {
 	acpi_gpe_handler address;	/* Address of handler, if any */
 	void *context;		/* Context to be passed to handler */
 	struct acpi_namespace_node *method_node;	/* Method node for this GPE level (saved) */
-	u8 original_flags;      /* Original (pre-handler) GPE info */
-	u8 originally_enabled;  /* True if GPE was originally enabled */
+	u8 original_flags;	/* Original (pre-handler) GPE info */
+	u8 originally_enabled;	/* True if GPE was originally enabled */
 };
 
 /* Notify info for implicit notify, multiple device objects */
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index e4ba4de..2095dfb 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -100,13 +100,14 @@ acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info)
  *
  * FUNCTION:    acpi_ev_enable_gpe
  *
- * PARAMETERS:  gpe_event_info  - GPE to enable
+ * PARAMETERS:  gpe_event_info          - GPE to enable
  *
  * RETURN:      Status
  *
  * DESCRIPTION: Clear a GPE of stale events and enable it.
  *
  ******************************************************************************/
+
 acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
 {
 	acpi_status status;
@@ -125,6 +126,7 @@ acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
 	}
 
 	/* Clear the GPE (of stale events) */
+
 	status = acpi_hw_clear_gpe(gpe_event_info);
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
@@ -136,7 +138,6 @@ acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
 	return_ACPI_STATUS(status);
 }
 
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ev_add_gpe_reference
@@ -212,7 +213,7 @@ acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info)
 		if (ACPI_SUCCESS(status)) {
 			status =
 			    acpi_hw_low_set_gpe(gpe_event_info,
-						     ACPI_GPE_DISABLE);
+						ACPI_GPE_DISABLE);
 		}
 
 		if (ACPI_FAILURE(status)) {
@@ -334,7 +335,7 @@ struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device,
  *
  ******************************************************************************/
 
-u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
+u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list)
 {
 	acpi_status status;
 	struct acpi_gpe_block_info *gpe_block;
@@ -427,7 +428,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
 
 			/* Check if there is anything active at all in this register */
 
-			enabled_status_byte = (u8) (status_reg & enable_reg);
+			enabled_status_byte = (u8)(status_reg & enable_reg);
 			if (!enabled_status_byte) {
 
 				/* No active GPEs in this register, move on */
@@ -450,7 +451,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
 					    acpi_ev_gpe_dispatch(gpe_block->
 								 node,
 								 &gpe_block->
-						event_info[((acpi_size) i * ACPI_GPE_REGISTER_WIDTH) + j], j + gpe_register_info->base_gpe_number);
+								 event_info[((acpi_size) i * ACPI_GPE_REGISTER_WIDTH) + j], j + gpe_register_info->base_gpe_number);
 				}
 			}
 		}
@@ -636,7 +637,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context)
  *
  ******************************************************************************/
 
-acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info)
+acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info * gpe_event_info)
 {
 	acpi_status status;
 
@@ -666,9 +667,9 @@ acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info)
  *
  * FUNCTION:    acpi_ev_gpe_dispatch
  *
- * PARAMETERS:  gpe_device      - Device node. NULL for GPE0/GPE1
- *              gpe_event_info  - Info for this GPE
- *              gpe_number      - Number relative to the parent GPE block
+ * PARAMETERS:  gpe_device          - Device node. NULL for GPE0/GPE1
+ *              gpe_event_info      - Info for this GPE
+ *              gpe_number          - Number relative to the parent GPE block
  *
  * RETURN:      INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
  *
@@ -681,7 +682,7 @@ acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info)
 
 u32
 acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
-		    struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
+		     struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
 {
 	acpi_status status;
 	u32 return_value;
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index 11e5803..1bcb55b 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -786,7 +786,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
 	handler->method_node = gpe_event_info->dispatch.method_node;
 	handler->original_flags = (u8)(gpe_event_info->flags &
 				       (ACPI_GPE_XRUPT_TYPE_MASK |
-				        ACPI_GPE_DISPATCH_MASK));
+					ACPI_GPE_DISPATCH_MASK));
 
 	/*
 	 * If the GPE is associated with a method, it may have been enabled
@@ -808,7 +808,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
 
 	gpe_event_info->flags &=
 	    ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
-	gpe_event_info->flags |= (u8) (type | ACPI_GPE_DISPATCH_HANDLER);
+	gpe_event_info->flags |= (u8)(type | ACPI_GPE_DISPATCH_HANDLER);
 
 	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
 
@@ -893,7 +893,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
 
 	gpe_event_info->dispatch.method_node = handler->method_node;
 	gpe_event_info->flags &=
-		~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
+	    ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
 	gpe_event_info->flags |= handler->original_flags;
 
 	/*
@@ -946,7 +946,7 @@ ACPI_EXPORT_SYMBOL(acpi_remove_gpe_handler)
  * handle is returned.
  *
  ******************************************************************************/
-acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle)
+acpi_status acpi_acquire_global_lock(u16 timeout, u32 *handle)
 {
 	acpi_status status;
 
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v2 2/9] ACPICA: Events: Fix an issue that GPE APIs cannot be invoked in atomic context.
  2014-07-15  3:07 ` [PATCH v2 0/9] ACPICA: Improve GPE handling model Lv Zheng
  2014-07-15  3:07   ` [PATCH v2 1/9] ACPICA: Events: Reduce indent divergences of events files Lv Zheng
@ 2014-07-15  3:07   ` Lv Zheng
  2014-07-15  3:07   ` [PATCH v2 3/9] ACPICA: Events: Fix an issue that GPE APIs cannot be invoked in deferred handlers Lv Zheng
                     ` (7 subsequent siblings)
  9 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-15  3:07 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The GPE APIs should be invoked inside of an IRQ context GPE handler or in
the task context with a driver provided lock held. This driver provided
lock should be safe to be held in the GPE handler by the driver.

While currently we cannot do this, thus we can only use the GPE APIs for
limitted cases.

This patch adds reference counting for struct acpi_gpe_handler_info. Then the GPE
handler can be safely invoked without holding the GPE lock, thus
facilitates GPE APIs to be invoked in any atomic environment. Lv Zheng.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/acevents.h |    1 +
 drivers/acpi/acpica/aclocal.h  |    1 +
 drivers/acpi/acpica/evgpe.c    |   71 ++++++++++++++++++++++++++++++++--------
 drivers/acpi/acpica/evxface.c  |   10 ++++++
 4 files changed, 70 insertions(+), 13 deletions(-)

diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h
index 7a7811a..a3d5276 100644
--- a/drivers/acpi/acpica/acevents.h
+++ b/drivers/acpi/acpica/acevents.h
@@ -123,6 +123,7 @@ ACPI_HW_DEPENDENT_RETURN_OK(acpi_status
 u32
 acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
 		     struct acpi_gpe_event_info *gpe_event_info,
+		     struct acpi_gpe_handler_info *gpe_handler_info,
 		     u32 gpe_number);
 
 /*
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index a9fa666..7363e2c 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -414,6 +414,7 @@ struct acpi_gpe_handler_info {
 	struct acpi_namespace_node *method_node;	/* Method node for this GPE level (saved) */
 	u8 original_flags;	/* Original (pre-handler) GPE info */
 	u8 originally_enabled;	/* True if GPE was originally enabled */
+	u16 reference_count;	/* For deletion management */
 };
 
 /* Notify info for implicit notify, multiple device objects */
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index 2095dfb..d629a21 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -339,6 +339,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list)
 {
 	acpi_status status;
 	struct acpi_gpe_block_info *gpe_block;
+	struct acpi_gpe_event_info *gpe_event_info;
+	struct acpi_gpe_handler_info *gpe_handler_info;
 	struct acpi_gpe_register_info *gpe_register_info;
 	u32 int_status = ACPI_INTERRUPT_NOT_HANDLED;
 	u8 enabled_status_byte;
@@ -443,15 +445,45 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list)
 				/* Examine one GPE bit */
 
 				if (enabled_status_byte & (1 << j)) {
+					gpe_event_info =
+					    &gpe_block->
+					    event_info[((acpi_size) i *
+							ACPI_GPE_REGISTER_WIDTH)
+						       + j];
+					gpe_handler_info =
+					    gpe_event_info->dispatch.handler;
+
+					/* Acquire the reference to protect the invocations */
+
+					if (gpe_handler_info) {
+						gpe_handler_info->
+						    reference_count++;
+					}
+
 					/*
 					 * Found an active GPE. Dispatch the event to a handler
-					 * or method.
+					 * or method. Invoke without GPE lock held.
 					 */
+					acpi_os_release_lock(acpi_gbl_gpe_lock,
+							     flags);
 					int_status |=
 					    acpi_ev_gpe_dispatch(gpe_block->
 								 node,
-								 &gpe_block->
-								 event_info[((acpi_size) i * ACPI_GPE_REGISTER_WIDTH) + j], j + gpe_register_info->base_gpe_number);
+								 gpe_event_info,
+								 gpe_handler_info,
+								 j +
+								 gpe_register_info->
+								 base_gpe_number);
+					flags =
+					    acpi_os_acquire_lock
+					    (acpi_gbl_gpe_lock);
+
+					/* Release the reference */
+
+					if (gpe_handler_info) {
+						gpe_handler_info->
+						    reference_count--;
+					}
 				}
 			}
 		}
@@ -676,19 +708,27 @@ acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info * gpe_event_info)
  * DESCRIPTION: Dispatch a General Purpose Event to either a function (e.g. EC)
  *              or method (e.g. _Lxx/_Exx) handler.
  *
- *              This function executes at interrupt level.
+ *              This function executes at interrupt level with handler's
+ *              reference count held.
  *
  ******************************************************************************/
 
 u32
 acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
-		     struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
+		     struct acpi_gpe_event_info *gpe_event_info,
+		     struct acpi_gpe_handler_info *gpe_handler_info,
+		     u32 gpe_number)
 {
 	acpi_status status;
 	u32 return_value;
+	acpi_cpu_flags flags;
 
 	ACPI_FUNCTION_TRACE(ev_gpe_dispatch);
 
+	/* We need to obtain the GPE lock again */
+
+	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
 	/* Invoke global event handler if present */
 
 	acpi_gpe_count++;
@@ -711,6 +751,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
 	if (ACPI_FAILURE(status)) {
 		ACPI_EXCEPTION((AE_INFO, status,
 				"Unable to disable GPE %02X", gpe_number));
+		acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
 		return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
 	}
 
@@ -727,6 +768,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
 					gpe_number));
 			(void)acpi_hw_low_set_gpe(gpe_event_info,
 						  ACPI_GPE_CONDITIONAL_ENABLE);
+			acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
 			return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
 		}
 	}
@@ -741,14 +783,16 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
 	switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
 	case ACPI_GPE_DISPATCH_HANDLER:
 
-		/* Invoke the installed handler (at interrupt level) */
-
-		return_value =
-		    gpe_event_info->dispatch.handler->address(gpe_device,
-							      gpe_number,
-							      gpe_event_info->
-							      dispatch.handler->
-							      context);
+		/*
+		 * Invoke the installed handler (at interrupt level), release
+		 * the GPE lock so that the GPE APIs can be invoked in the
+		 * dispatcher.
+		 */
+		acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+		return_value = gpe_handler_info->address(gpe_device, gpe_number,
+							 gpe_handler_info->
+							 context);
+		flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
 
 		/* If requested, clear (if level-triggered) and reenable the GPE */
 
@@ -786,6 +830,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
 		break;
 	}
 
+	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
 	return_UINT32(ACPI_INTERRUPT_HANDLED);
 }
 
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index 1bcb55b..a538b03 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -787,6 +787,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
 	handler->original_flags = (u8)(gpe_event_info->flags &
 				       (ACPI_GPE_XRUPT_TYPE_MASK |
 					ACPI_GPE_DISPATCH_MASK));
+	handler->reference_count = 0;
 
 	/*
 	 * If the GPE is associated with a method, it may have been enabled
@@ -888,6 +889,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
 	/* Remove the handler */
 
 	handler = gpe_event_info->dispatch.handler;
+	gpe_event_info->dispatch.handler = NULL;
 
 	/* Restore Method node (if any), set dispatch flags */
 
@@ -906,6 +908,14 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
 		(void)acpi_ev_add_gpe_reference(gpe_event_info);
 	}
 
+	/* Make sure all GPE handlers are completed */
+
+	while (handler->reference_count != 0) {
+		acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+		acpi_os_sleep((u64)10);
+		flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+	}
+
 	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
 	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
 
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v2 3/9] ACPICA: Events: Fix an issue that GPE APIs cannot be invoked in deferred handlers.
  2014-07-15  3:07 ` [PATCH v2 0/9] ACPICA: Improve GPE handling model Lv Zheng
  2014-07-15  3:07   ` [PATCH v2 1/9] ACPICA: Events: Reduce indent divergences of events files Lv Zheng
  2014-07-15  3:07   ` [PATCH v2 2/9] ACPICA: Events: Fix an issue that GPE APIs cannot be invoked in atomic context Lv Zheng
@ 2014-07-15  3:07   ` Lv Zheng
  2014-07-15  3:07   ` [PATCH v2 4/9] ACPICA: Events: Introduce acpi_set_gpe()/acpi_finish_gpe() to reduce divergences Lv Zheng
                     ` (6 subsequent siblings)
  9 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-15  3:07 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The acpi_os_wait_events_complete() is used for flushing the deferred executed
handlers, invoking it for GPE interrupt handlers doesn't help to protect
GPE handler callback.  On the contrary, it prevents GPE APIs from being
invoked in the deferred notify handlers.

Actually, the GPE interrupt handlers' invocation is protected by the
previous implemented reference counting mechanism.

This patch fixes this GPE APIs invocation issue in a seperate commit other
than the reference counting one, so that if any regressions are reported,
this patch can be temporarily reverted before the regressions are root
caused. Lv Zheng.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/evxface.c |    4 ----
 1 file changed, 4 deletions(-)

diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index a538b03..fc075a5 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -919,10 +919,6 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
 	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
 	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
 
-	/* Make sure all deferred GPE tasks are completed */
-
-	acpi_os_wait_events_complete();
-
 	/* Now we can free the handler object */
 
 	ACPI_FREE(handler);
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v2 4/9] ACPICA: Events: Introduce acpi_set_gpe()/acpi_finish_gpe() to reduce divergences.
  2014-07-15  3:07 ` [PATCH v2 0/9] ACPICA: Improve GPE handling model Lv Zheng
                     ` (2 preceding siblings ...)
  2014-07-15  3:07   ` [PATCH v2 3/9] ACPICA: Events: Fix an issue that GPE APIs cannot be invoked in deferred handlers Lv Zheng
@ 2014-07-15  3:07   ` Lv Zheng
  2014-07-15  3:07   ` [PATCH v2 5/9] ACPICA: Events: Fix an issue that acpi_set_gpe() cannot unconditionally enable GPEs Lv Zheng
                     ` (5 subsequent siblings)
  9 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-15  3:07 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This can help to reduce source code differences between Linux and ACPICA
upstream. Further driver cleanups also require these APIs to eliminate GPE
storms.
1. acpi_set_gpe(): An API that driver should invoke in the case it wants
                   to disable/enable IRQ without honoring the reference
                   count implemented in the acpi_disable_gpe() and
                   acpi_enable_gpe(). Note that this API should only be
                   invoked inside a acpi_enable_gpe()/acpi_disable_gpe()
                   pair.
2. acpi_finish_gpe(): Drivers returned ACPI_REENABLE_GPE unset from the
                      GPE handler should use this API instead of
                      invoking acpi_set_gpe()/acpi_enable_gpe() to
                      re-enable the GPE.
The GPE APIs can be invoked inside of a GPE handler or in the task context
with a driver provided lock held. This driver provided lock is safe to be
held in the GPE handler by the driver.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/evxfgpe.c |  105 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 105 insertions(+)

diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c
index cb534fa..d66d50b 100644
--- a/drivers/acpi/acpica/evxfgpe.c
+++ b/drivers/acpi/acpica/evxfgpe.c
@@ -176,6 +176,68 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number)
 
 ACPI_EXPORT_SYMBOL(acpi_disable_gpe)
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_set_gpe
+ *
+ * PARAMETERS:  gpe_device          - Parent GPE Device. NULL for GPE0/GPE1
+ *              gpe_number          - GPE level within the GPE block
+ *              action              - ACPI_GPE_ENABLE or ACPI_GPE_DISABLE
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Enable or disable an individual GPE. This function bypasses
+ *              the reference count mechanism used in the acpi_enable_gpe and
+ *              acpi_disable_gpe interfaces -- and should be used with care.
+ *
+ * Note: Typically used to disable a runtime GPE for short period of time,
+ * then re-enable it, without disturbing the existing reference counts. This
+ * is useful, for example, in the Embedded Controller (EC) driver.
+ *
+ ******************************************************************************/
+acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action)
+{
+	struct acpi_gpe_event_info *gpe_event_info;
+	acpi_status status;
+	acpi_cpu_flags flags;
+
+	ACPI_FUNCTION_TRACE(acpi_set_gpe);
+
+	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+	/* Ensure that we have a valid GPE number */
+
+	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+	if (!gpe_event_info) {
+		status = AE_BAD_PARAMETER;
+		goto unlock_and_exit;
+	}
+
+	/* Perform the action */
+
+	switch (action) {
+	case ACPI_GPE_ENABLE:
+
+		status = acpi_ev_enable_gpe(gpe_event_info);
+		break;
+
+	case ACPI_GPE_DISABLE:
+
+		status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
+		break;
+
+	default:
+
+		status = AE_BAD_PARAMETER;
+		break;
+	}
+
+unlock_and_exit:
+	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+	return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_set_gpe)
 
 /*******************************************************************************
  *
@@ -479,6 +541,49 @@ unlock_and_exit:
 
 ACPI_EXPORT_SYMBOL(acpi_get_gpe_status)
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_finish_gpe
+ *
+ * PARAMETERS:  gpe_device          - Namespace node for the GPE Block
+ *                                    (NULL for FADT defined GPEs)
+ *              gpe_number          - GPE level within the GPE block
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Clear and conditionally reenable a GPE. This completes the GPE
+ *              processing. Intended for use by asynchronous host-installed
+ *              GPE handlers. The GPE is only reenabled if the enable_for_run bit
+ *              is set in the GPE info.
+ *
+ ******************************************************************************/
+acpi_status acpi_finish_gpe(acpi_handle gpe_device, u32 gpe_number)
+{
+	struct acpi_gpe_event_info *gpe_event_info;
+	acpi_status status;
+	acpi_cpu_flags flags;
+
+	ACPI_FUNCTION_TRACE(acpi_finish_gpe);
+
+	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+	/* Ensure that we have a valid GPE number */
+
+	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+	if (!gpe_event_info) {
+		status = AE_BAD_PARAMETER;
+		goto unlock_and_exit;
+	}
+
+	status = acpi_ev_finish_gpe(gpe_event_info);
+
+unlock_and_exit:
+	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+	return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_finish_gpe)
+
 /******************************************************************************
  *
  * FUNCTION:    acpi_disable_all_gpes
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v2 5/9] ACPICA: Events: Fix an issue that acpi_set_gpe() cannot unconditionally enable GPEs.
  2014-07-15  3:07 ` [PATCH v2 0/9] ACPICA: Improve GPE handling model Lv Zheng
                     ` (3 preceding siblings ...)
  2014-07-15  3:07   ` [PATCH v2 4/9] ACPICA: Events: Introduce acpi_set_gpe()/acpi_finish_gpe() to reduce divergences Lv Zheng
@ 2014-07-15  3:07   ` Lv Zheng
  2014-07-15  3:07   ` [PATCH v2 6/9] ACPICA: Events: Fix an issue that status of GPEs are unexpectedly cleared Lv Zheng
                     ` (4 subsequent siblings)
  9 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-15  3:07 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds unconditional GPE enabling support into acpi_set_gpe().

Originally this function checks if the GPE has been enabled with handlers
and performs acknowledging before enabling it.

First, IRQ enabling/disabling has 2 use cases:
1. When upper layers (the users of the driver) submit requests to the
   drivers, it means they care about the underlying hardware. For this
   case, acpi_enable_gpe() should be invoked. When the reference count is
   increased from 0 to 1, driver enables the hardware IRQ. And
   acpi_disable_gpe() is used as the reversal when the users have completed
   the submitted requests.
2. Driver may temporarily disables the IRQ and wants to re-enable it later,
   this case is normally used in order to prevent IRQ storm. When a driver
   cannot fully solve the condition that triggered the IRQ in the IRQ
   context, in order not to trigger IRQ storm, driver has to disable IRQ
   and re-enables it in the defered execution environment - which should be
   in a task context. This API should be used exactly for this purpose.

Second, since the acpi_set_gpe() should be invoked from an IRQ handler, the
handler check is useless for this API.

Third, given the fact that drivers should complete all outstanding requests
before putting themselves into the sleep states, as this API is executed for
outstanding requests, it should also have nothing to do with the
"RUN"/"WAKE" distinguishing. That's why the acpi_set_gpe(ACPI_GPE_ENABLE)
should not be implemented by acpi_hw_low_set_gpe(ACPI_GPE_CONDITIONAL_ENABLE).

Fourth, GPE clearing is used to acknowledge the GPE. The combination of
acknowledging and enabling may not be expected by the hardware drivers. For
GPE clearing, we have a seperate API acpi_clear_gpe(). There are cases
drivers do want the 2 operations to be split. For example, a high IO
throughput IRQ requires the IRQ to be cleared in the IRQ context. In order
to avoid GPE storm, same driver need to invoke IRQ re-enabling in the task
context. So splitting these 2 operations could facilitates drivers the
maximum possibilities to achieve success. For a combined one, we already
have acpi_finish_gpe() ready to be invoked.

This patch converts acpi_set_gpe(ACPI_GPE_ENABLE) into
acpi_hw_low_set_gpe(ACPI_GPE_ENABLE) to achieve a seperate GPE enabling API.
Drivers are encouraged to use this API when they need to handle the above
mentioned cases. Lv Zheng.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/evxfgpe.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c
index d66d50b..6c53633 100644
--- a/drivers/acpi/acpica/evxfgpe.c
+++ b/drivers/acpi/acpica/evxfgpe.c
@@ -218,7 +218,7 @@ acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action)
 	switch (action) {
 	case ACPI_GPE_ENABLE:
 
-		status = acpi_ev_enable_gpe(gpe_event_info);
+		status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE);
 		break;
 
 	case ACPI_GPE_DISABLE:
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v2 6/9] ACPICA: Events: Fix an issue that status of GPEs are unexpectedly cleared.
  2014-07-15  3:07 ` [PATCH v2 0/9] ACPICA: Improve GPE handling model Lv Zheng
                     ` (4 preceding siblings ...)
  2014-07-15  3:07   ` [PATCH v2 5/9] ACPICA: Events: Fix an issue that acpi_set_gpe() cannot unconditionally enable GPEs Lv Zheng
@ 2014-07-15  3:07   ` Lv Zheng
  2014-07-15  3:07   ` [PATCH v2 7/9] ACPICA: Events: Fix an issue that originally_enabled check is not paired Lv Zheng
                     ` (3 subsequent siblings)
  9 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-15  3:07 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The stale GPE indication is not a problem. Drivers should always check the
underlying hardware status and be ready to handle invalid status.

The GPE clearing implemented in acpi_ev_enable_gpe() on the contrary
introduces issues for acpi_enable_gpe() logic. When the usage count of GPE is
increased by suspend/resume code, GPE status shouldn't be cleared, or a GPE
loss could happen when the driver relies on the interrupt mode.

With previous cleanup, all acpi_ev_enable_gpe() usages are removed, this patch
also removes this internal API. Lv Zheng.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/evgpe.c |   46 +++----------------------------------------
 1 file changed, 3 insertions(+), 43 deletions(-)

diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index d629a21..64f6d41 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -98,48 +98,6 @@ acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info)
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ev_enable_gpe
- *
- * PARAMETERS:  gpe_event_info          - GPE to enable
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Clear a GPE of stale events and enable it.
- *
- ******************************************************************************/
-
-acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
-{
-	acpi_status status;
-
-	ACPI_FUNCTION_TRACE(ev_enable_gpe);
-
-	/*
-	 * We will only allow a GPE to be enabled if it has either an associated
-	 * method (_Lxx/_Exx) or a handler, or is using the implicit notify
-	 * feature. Otherwise, the GPE will be immediately disabled by
-	 * acpi_ev_gpe_dispatch the first time it fires.
-	 */
-	if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
-	    ACPI_GPE_DISPATCH_NONE) {
-		return_ACPI_STATUS(AE_NO_HANDLER);
-	}
-
-	/* Clear the GPE (of stale events) */
-
-	status = acpi_hw_clear_gpe(gpe_event_info);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/* Enable the requested GPE */
-
-	status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE);
-	return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
  * FUNCTION:    acpi_ev_add_gpe_reference
  *
  * PARAMETERS:  gpe_event_info          - Add a reference to this GPE
@@ -169,7 +127,9 @@ acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *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);
+			status =
+			    acpi_hw_low_set_gpe(gpe_event_info,
+						ACPI_GPE_ENABLE);
 		}
 
 		if (ACPI_FAILURE(status)) {
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v2 7/9] ACPICA: Events: Fix an issue that originally_enabled check is not paired.
  2014-07-15  3:07 ` [PATCH v2 0/9] ACPICA: Improve GPE handling model Lv Zheng
                     ` (5 preceding siblings ...)
  2014-07-15  3:07   ` [PATCH v2 6/9] ACPICA: Events: Fix an issue that status of GPEs are unexpectedly cleared Lv Zheng
@ 2014-07-15  3:07   ` Lv Zheng
  2014-07-15  3:08   ` [PATCH v2 8/9] ACPICA: Events: Add a flag to disable internal auto GPE clearing Lv Zheng
                     ` (2 subsequent siblings)
  9 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-15  3:07 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The originally_enabled check is not paired between acpi_install_gpe_handler()
and acpi_remove_gpe_handler(). Lv Zheng.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/evxface.c |   19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index fc075a5..e090dd1 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -794,11 +794,19 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
 	 * automatically during initialization, in which case it has to be
 	 * disabled now to avoid spurious execution of the handler.
 	 */
-
-	if ((handler->original_flags & ACPI_GPE_DISPATCH_METHOD)
-	    && gpe_event_info->runtime_count) {
-		handler->originally_enabled = 1;
+	if (((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) ||
+	     (handler->original_flags & ACPI_GPE_DISPATCH_NOTIFY)) &&
+	    gpe_event_info->runtime_count) {
+		handler->originally_enabled = TRUE;
 		(void)acpi_ev_remove_gpe_reference(gpe_event_info);
+
+		/* Sanity check of original type against new type */
+
+		if (type !=
+		    (u32)(gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK)) {
+			ACPI_WARNING((AE_INFO,
+				      "GPE type mismatch (level/edge)"));
+		}
 	}
 
 	/* Install the handler */
@@ -903,7 +911,8 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
 	 * enabled, it should be enabled at this point to restore the
 	 * post-initialization configuration.
 	 */
-	if ((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) &&
+	if (((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) ||
+	     (handler->original_flags & ACPI_GPE_DISPATCH_NOTIFY)) &&
 	    handler->originally_enabled) {
 		(void)acpi_ev_add_gpe_reference(gpe_event_info);
 	}
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v2 8/9] ACPICA: Events: Add a flag to disable internal auto GPE clearing.
  2014-07-15  3:07 ` [PATCH v2 0/9] ACPICA: Improve GPE handling model Lv Zheng
                     ` (6 preceding siblings ...)
  2014-07-15  3:07   ` [PATCH v2 7/9] ACPICA: Events: Fix an issue that originally_enabled check is not paired Lv Zheng
@ 2014-07-15  3:08   ` Lv Zheng
  2014-07-15  3:08   ` [PATCH v2 9/9] ACPI: Update interrupt handler to honor new ACPI_REENABLE_GPE bit Lv Zheng
  2014-07-15 12:25   ` [PATCH v2 0/9] ACPICA: Improve GPE handling model Rafael J. Wysocki
  9 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-15  3:08 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

Clearing the status bit means OSPM acknowledges the GPE and the hardware
then can bring follow-up events up. Acklowdging it too early causes OSPM
seeing level triggered GPE storms or missing edge-triggered GPEs if the
OSPM driver responds slowly. Some drivers may choose to implement GPE
condition clearing code in a position that is different from where it
should be disabled or re-enabled, in which case, the internal auto GPE
clearing operations should be abandoned.

This flag facilitates such driver designs and implementations.

Note that drivers will need to invoke acpi_clear_gpe() manually in a proper
position where the causes and conditions of the GPE have been solved and
the GPE status can be safely cleared. Lv Zheng.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/evgpe.c |    6 ++++--
 include/acpi/actypes.h      |   16 +++++++++-------
 2 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index 64f6d41..7589956 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -633,7 +633,8 @@ acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info * gpe_event_info)
 {
 	acpi_status status;
 
-	if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
+	if (!(gpe_event_info->flags & ACPI_GPE_NO_AUTO_CLEAR) &&
+	    (gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
 	    ACPI_GPE_LEVEL_TRIGGERED) {
 		/*
 		 * GPE is level-triggered, we clear the GPE status bit after
@@ -719,7 +720,8 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
 	 * If edge-triggered, clear the GPE status bit now. Note that
 	 * level-triggered events are cleared after the GPE is serviced.
 	 */
-	if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
+	if (!(gpe_event_info->flags & ACPI_GPE_NO_AUTO_CLEAR) &&
+	    (gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
 	    ACPI_GPE_EDGE_TRIGGERED) {
 		status = acpi_hw_clear_gpe(gpe_event_info);
 		if (ACPI_FAILURE(status)) {
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h
index 608a040..18f341f 100644
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -738,13 +738,14 @@ typedef u32 acpi_event_status;
 
 /*
  * GPE info flags - Per GPE
- * +-------+-+-+---+
- * |  7:4  |3|2|1:0|
- * +-------+-+-+---+
- *     |    | |  |
- *     |    | |  +-- Type of dispatch:to method, handler, notify, or none
- *     |    | +----- Interrupt type: edge or level triggered
- *     |    +------- Is a Wake GPE
+ * +-------+-+-+-+---+
+ * |  7:5  |4|3|2|1:0|
+ * +-------+-+-+-+---+
+ *     |    | | |  |
+ *     |    | | |  +-- Type of dispatch:to method, handler, notify, or none
+ *     |    | | +----- Interrupt type: edge or level triggered
+ *     |    | +------- Is a Wake GPE
+ *     |    +--------- Do not clear GPE automatically
  *     +------------ <Reserved>
  */
 #define ACPI_GPE_DISPATCH_NONE          (u8) 0x00
@@ -758,6 +759,7 @@ typedef u32 acpi_event_status;
 #define ACPI_GPE_XRUPT_TYPE_MASK        (u8) 0x04
 
 #define ACPI_GPE_CAN_WAKE               (u8) 0x08
+#define ACPI_GPE_NO_AUTO_CLEAR          (u8) 0x10
 
 /*
  * Flags for GPE and Lock interfaces
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v2 9/9] ACPI: Update interrupt handler to honor new ACPI_REENABLE_GPE bit.
  2014-07-15  3:07 ` [PATCH v2 0/9] ACPICA: Improve GPE handling model Lv Zheng
                     ` (7 preceding siblings ...)
  2014-07-15  3:08   ` [PATCH v2 8/9] ACPICA: Events: Add a flag to disable internal auto GPE clearing Lv Zheng
@ 2014-07-15  3:08   ` Lv Zheng
  2014-07-15 12:25   ` [PATCH v2 0/9] ACPICA: Improve GPE handling model Rafael J. Wysocki
  9 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-15  3:08 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The return value of ACPICA SCI will contain ACPI_REENABLE_GPE. This patch
cleans up the OSL code to reflect this change.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/osl.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index bad25b0..b524186 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -788,7 +788,7 @@ static irqreturn_t acpi_irq(int irq, void *dev_id)
 
 	handled = (*acpi_irq_handler) (acpi_irq_context);
 
-	if (handled) {
+	if (handled & ACPI_INTERRUPT_HANDLED) {
 		acpi_irq_handled++;
 		return IRQ_HANDLED;
 	} else {
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v2 00/10] ACPI/EC: Add event storm prevention and cleanup command storm prevention.
  2014-06-18  3:17 [PATCH 0/9] ACPI/EC: Improve GPE handling model Lv Zheng
                   ` (9 preceding siblings ...)
  2014-07-15  3:07 ` [PATCH v2 0/9] ACPICA: Improve GPE handling model Lv Zheng
@ 2014-07-15  3:14 ` Lv Zheng
  2014-07-15  3:14   ` [PATCH v2 01/10] ACPI/EC: Introduce STARTED/STOPPED flags to replace BLOCKED flag Lv Zheng
                     ` (9 more replies)
  2014-07-15  7:09 ` [PATCH v2] ACPI/EC: Enable storm prevention mechanisms Lv Zheng
                   ` (2 subsequent siblings)
  13 siblings, 10 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-15  3:14 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patchset is based on the previous ACPI/EC bug fixes series and the GPE
API enhancement series.

During the bug fix, there is a dmesg showing Linux EC driver doesn't
support EC event storm prevention.
  https://bugzilla.kernel.org/show_bug.cgi?id=70891
The comment 55 contains the dmesg log that shows a 0x0D event storm, for
which there is no _Q0D method provided by the ACPI table to handle. This
becomes a GPE storm and slows down the machine a lot, it tooks longer time
for Linux to boot (see comment 80).

This patchset implements event storm prevention, turning EC driver into
polling mode when the storm happens so that other tasks can be processed
by the CPU without being affected by this GPE storm.
In current EC driver, we only have command storm prevention implemented,
this patch also refines the command storm prevention support.

All of the above storm prevention support are implemented using the ideal
GPE handling model provided by the previous GPE API enhancement series.
The ideal GPE handling model should be able to handle the following cases:

This patchset also contains an EC commands flushing support. This is
required to implement event storm prevention. By utilizing the GPE APIs, we
need to invoke acpi_set_gpe() before invoking acpi_disable_gpe() to prevent
storms. Without implementing flushing, there is no such a point invoking
acpi_disable_gpe() before all commands have been completed.
By implementing EC commands flushing, we now achieve an additional benefit:
Some EC driven ACPI devices may require all submitted EC commands to be
completed before they can be safely suspended or unplugged. Otherwise the
state of such devices will be broken.
When implementing IO flushing, there always need to be 2 flags to indicate
an intermediate state - old IO submissions observe the (STARTED) flag to
continue; new IO submissions observe the (STOPPED) flag to be discarded.
After introducing the 2 flags, a "stop waiter" is implemented for the
suspending/removing operations of the EC driver.

The refined patches are also passed the runtime/suspend tests carried out
on the following platforms:
  "Dell Inspiron Mini 1010" - i386 kernel
  "Dell Latitude 6430u" - x86_64 kernel

This patchset also includes a unit test facility, I used it to test the
hotplug support code in the driver. It's useful for future EC development.

Lv Zheng (10):
  ACPI/EC: Introduce STARTED/STOPPED flags to replace BLOCKED flag.
  ACPI/EC: Add detailed command/query debugging information.
  ACPI/EC: Deploy the new GPE handling model.
  ACPI/EC: Refine command storm prevention support.
  ACPI/EC: Add reference counting for query handlers.
  ACPI/EC: Add a warning message to indicate event storms.
  ACPI/EC: Refine event/query debugging messages.
  ACPI/EC: Add command flushing support.
  ACPI/EC: Add event storm prevention support.
  ACPI/EC: Add unit test support for EC driver hotplug.

 drivers/acpi/ec.c       |  293 ++++++++++++++++++++++++++++++++++++++---------
 drivers/acpi/internal.h |    1 +
 2 files changed, 239 insertions(+), 55 deletions(-)

-- 
1.7.10


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v2 01/10] ACPI/EC: Introduce STARTED/STOPPED flags to replace BLOCKED flag.
  2014-07-15  3:14 ` [PATCH v2 00/10] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
@ 2014-07-15  3:14   ` Lv Zheng
  2014-07-15  3:14   ` [PATCH v2 02/10] ACPI/EC: Add detailed command/query debugging information Lv Zheng
                     ` (8 subsequent siblings)
  9 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-15  3:14 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

By using the 2 flags, we can indicate an inter-mediate state where the
current transactions should be completed while the new transactions should
be blocked.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   56 +++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 42 insertions(+), 14 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index a66ab65..1a94ba9 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -79,7 +79,8 @@ enum {
 	EC_FLAGS_GPE_STORM,		/* GPE storm detected */
 	EC_FLAGS_HANDLERS_INSTALLED,	/* Handlers for GPE and
 					 * OpReg are installed */
-	EC_FLAGS_BLOCKED,		/* Transactions are blocked */
+	EC_FLAGS_STARTED,		/* Driver is started */
+	EC_FLAGS_STOPPED,		/* Driver is stopped */
 };
 
 #define ACPI_EC_COMMAND_POLL		0x01 /* Available for command byte */
@@ -285,15 +286,25 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 		udelay(ACPI_EC_MSI_UDELAY);
 	/* start transaction */
 	spin_lock_irqsave(&ec->lock, tmp);
+	if (!test_bit(EC_FLAGS_STARTED, &ec->flags) ||
+	    test_bit(EC_FLAGS_STOPPED, &ec->flags)) {
+		ret = -EINVAL;
+		goto unlock;
+	}
 	/* following two actions should be kept atomic */
 	ec->curr = t;
+	pr_debug("***** transaction started (cmd=0x%02x, addr=0x%02x) *****\n",
+		 t->command, t->wdata ? t->wdata[0] : 0);
 	start_transaction(ec);
 	if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
 		clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
 	spin_unlock_irqrestore(&ec->lock, tmp);
 	ret = ec_poll(ec);
 	spin_lock_irqsave(&ec->lock, tmp);
+	pr_debug("***** transaction stopped (cmd=0x%02x, addr=0x%02x) *****\n",
+		 t->command, t->wdata ? t->wdata[0] : 0);
 	ec->curr = NULL;
+unlock:
 	spin_unlock_irqrestore(&ec->lock, tmp);
 	return ret;
 }
@@ -307,10 +318,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
 	if (t->rdata)
 		memset(t->rdata, 0, t->rlen);
 	mutex_lock(&ec->mutex);
-	if (test_bit(EC_FLAGS_BLOCKED, &ec->flags)) {
-		status = -EINVAL;
-		goto unlock;
-	}
 	if (ec->global_lock) {
 		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
 		if (ACPI_FAILURE(status)) {
@@ -318,8 +325,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
 			goto unlock;
 		}
 	}
-	pr_debug("transaction start (cmd=0x%02x, addr=0x%02x)\n",
-			t->command, t->wdata ? t->wdata[0] : 0);
 	/* disable GPE during transaction if storm is detected */
 	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
 		/* It has to be disabled, so that it doesn't trigger. */
@@ -340,7 +345,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
 			t->irq_count);
 		set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
 	}
-	pr_debug("transaction end\n");
 	if (ec->global_lock)
 		acpi_release_global_lock(glk);
 unlock:
@@ -470,6 +474,30 @@ static void acpi_ec_clear(struct acpi_ec *ec)
 		pr_info("%d stale EC events cleared\n", i);
 }
 
+static void acpi_ec_start(struct acpi_ec *ec)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ec->lock, flags);
+	if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags))
+		acpi_enable_gpe(NULL, ec->gpe);
+	spin_unlock_irqrestore(&ec->lock, flags);
+}
+
+static void acpi_ec_stop(struct acpi_ec *ec)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ec->lock, flags);
+	if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
+	    !test_and_set_bit(EC_FLAGS_STOPPED, &ec->flags)) {
+		acpi_disable_gpe(NULL, ec->gpe);
+		clear_bit(EC_FLAGS_STARTED, &ec->flags);
+		clear_bit(EC_FLAGS_STOPPED, &ec->flags);
+	}
+	spin_unlock_irqrestore(&ec->lock, flags);
+}
+
 void acpi_ec_block_transactions(void)
 {
 	struct acpi_ec *ec = first_ec;
@@ -479,7 +507,7 @@ void acpi_ec_block_transactions(void)
 
 	mutex_lock(&ec->mutex);
 	/* Prevent transactions from being carried out */
-	set_bit(EC_FLAGS_BLOCKED, &ec->flags);
+	acpi_ec_stop(ec);
 	mutex_unlock(&ec->mutex);
 }
 
@@ -492,7 +520,7 @@ void acpi_ec_unblock_transactions(void)
 
 	mutex_lock(&ec->mutex);
 	/* Allow transactions to be carried out again */
-	clear_bit(EC_FLAGS_BLOCKED, &ec->flags);
+	acpi_ec_start(ec);
 
 	if (EC_FLAGS_CLEAR_ON_RESUME)
 		acpi_ec_clear(ec);
@@ -507,7 +535,7 @@ void acpi_ec_unblock_transactions_early(void)
 	 * atomic context during wakeup, so we don't need to acquire the mutex).
 	 */
 	if (first_ec)
-		clear_bit(EC_FLAGS_BLOCKED, &first_ec->flags);
+		acpi_ec_start(first_ec);
 }
 
 static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data)
@@ -774,7 +802,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
-	acpi_enable_gpe(NULL, ec->gpe);
+	acpi_ec_start(ec);
 	status = acpi_install_address_space_handler(ec->handle,
 						    ACPI_ADR_SPACE_EC,
 						    &acpi_ec_space_handler,
@@ -789,7 +817,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
 			pr_err("Fail in evaluating the _REG object"
 				" of EC device. Broken bios is suspected.\n");
 		} else {
-			acpi_disable_gpe(NULL, ec->gpe);
+			acpi_ec_stop(ec);
 			acpi_remove_gpe_handler(NULL, ec->gpe,
 				&acpi_ec_gpe_handler);
 			return -ENODEV;
@@ -802,10 +830,10 @@ static int ec_install_handlers(struct acpi_ec *ec)
 
 static void ec_remove_handlers(struct acpi_ec *ec)
 {
-	acpi_disable_gpe(NULL, ec->gpe);
 	if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
 				ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
 		pr_err("failed to remove space handler\n");
+	acpi_ec_stop(ec);
 	if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
 				&acpi_ec_gpe_handler)))
 		pr_err("failed to remove gpe handler\n");
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v2 02/10] ACPI/EC: Add detailed command/query debugging information.
  2014-07-15  3:14 ` [PATCH v2 00/10] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
  2014-07-15  3:14   ` [PATCH v2 01/10] ACPI/EC: Introduce STARTED/STOPPED flags to replace BLOCKED flag Lv Zheng
@ 2014-07-15  3:14   ` Lv Zheng
  2014-07-15  3:14   ` [PATCH v2 03/10] ACPI/EC: Deploy the new GPE handling model Lv Zheng
                     ` (7 subsequent siblings)
  9 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-15  3:14 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

Developers really don't need to translate EC commands in mind. This patch
adds detailed debugging information for the EC commands.
The address can be found in the follow-up sequential EC_DATA(W) accesses,
thus this patch also removes some of the redundant address information.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   29 +++++++++++++++++++++++++----
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 1a94ba9..323a178 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -165,6 +165,27 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
 	outb(data, ec->data_addr);
 }
 
+#ifdef DEBUG
+static const char *acpi_ec_cmd_string(u8 cmd)
+{
+	switch (cmd) {
+	case 0x80:
+		return "RD_EC";
+	case 0x81:
+		return "WR_EC";
+	case 0x82:
+		return "BE_EC";
+	case 0x83:
+		return "BD_EC";
+	case 0x84:
+		return "QR_EC";
+	}
+	return "UNKNOWN";
+}
+#else
+#define acpi_ec_cmd_string(cmd)		"UNDEF"
+#endif
+
 static int ec_transaction_completed(struct acpi_ec *ec)
 {
 	unsigned long flags;
@@ -293,16 +314,16 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 	}
 	/* following two actions should be kept atomic */
 	ec->curr = t;
-	pr_debug("***** transaction started (cmd=0x%02x, addr=0x%02x) *****\n",
-		 t->command, t->wdata ? t->wdata[0] : 0);
+	pr_debug("***** Command(%s) started *****\n",
+		 acpi_ec_cmd_string(t->command));
 	start_transaction(ec);
 	if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
 		clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
 	spin_unlock_irqrestore(&ec->lock, tmp);
 	ret = ec_poll(ec);
 	spin_lock_irqsave(&ec->lock, tmp);
-	pr_debug("***** transaction stopped (cmd=0x%02x, addr=0x%02x) *****\n",
-		 t->command, t->wdata ? t->wdata[0] : 0);
+	pr_debug("***** Command(%s) stopped *****\n",
+		 acpi_ec_cmd_string(t->command));
 	ec->curr = NULL;
 unlock:
 	spin_unlock_irqrestore(&ec->lock, tmp);
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v2 03/10] ACPI/EC: Deploy the new GPE handling model.
  2014-07-15  3:14 ` [PATCH v2 00/10] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
  2014-07-15  3:14   ` [PATCH v2 01/10] ACPI/EC: Introduce STARTED/STOPPED flags to replace BLOCKED flag Lv Zheng
  2014-07-15  3:14   ` [PATCH v2 02/10] ACPI/EC: Add detailed command/query debugging information Lv Zheng
@ 2014-07-15  3:14   ` Lv Zheng
  2014-07-15  3:14   ` [PATCH v2 04/10] ACPI/EC: Refine command storm prevention support Lv Zheng
                     ` (6 subsequent siblings)
  9 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-15  3:14 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch deploys the following GPE handling model:
1. acpi_enable_gpe()/acpi_disable_gpe():
   This set of APIs are used for EC usage reference counting.
2. acpi_set_gpe(ACPI_GPE_ENABLE)/acpi_set_gpe(ACPI_GPE_DISABLE):
   This set of APIs are used for preventing GPE storm.
Note that this patch only converts current storm prevention implementations
using new APIs without correcting them.

For the EC driver, GPE is enabled for the following users:
1. Event monitoring (HW exception):
   If we want to query events in interrupt mode, acpi_enable_gpe() is
   invoked to allow EVT_SCI IRQs.
2. Command processing (IO request):
   When we receive an upper layer command submission, acpi_enable_gpe() is
   invoked to allow IBF=0,OBF=1 IRQs.
Comments are updated to reflect this model.

For the EC driver, GPE is disabled for the following storms:
1. Command errors:
   If there are too many IRQs coming during a command processing period and
   such IRQs are not related to the event (EVT_SCI),
   acpi_set_gpe(ACPI_GPE_DISABLE) is invoked to prevent further storms
   during the same command transaction. This is not implemented in a good
   style. Ideally, we should only enable storm prevention for the current
   command so that the next command can try the efficient interrupt mode
   again. This patch doesn't change this logic, it will be done by further
   patches. Such correction will be implemented by further patches.
2. Event errors:
   There are cases that BIOS doesn't provide _Qxx handler for the returned
   query value, in this case, acpi_set_gpe(ACPI_GPE_DISABLE) need to be
   invoked to prevent event IRQ storms. This patch doesn't implement this
   logic, it will be done by further patches. Such gap will be implemented
   by further patches.

The acpi_set_gpe() should be invoked for an outstanding command,
which means it should be invoked inside of a pair of acpi_enable_gpe()/
acpi_disable_gpe() invocation. This patch thus also moves the storm
prevention logic into acpi_ec_transaction_unlocked().

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   40 ++++++++++++++++++++++++----------------
 1 file changed, 24 insertions(+), 16 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 323a178..5049981 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -314,16 +314,32 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 	}
 	/* following two actions should be kept atomic */
 	ec->curr = t;
+	/* Enable GPE for command processing (IBF=0/OBF=1) */
+	acpi_enable_gpe(NULL, ec->gpe);
 	pr_debug("***** Command(%s) started *****\n",
 		 acpi_ec_cmd_string(t->command));
+	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
+		pr_debug("+++++ Polling enabled +++++\n");
+		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
+	}
 	start_transaction(ec);
 	if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
 		clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
 	spin_unlock_irqrestore(&ec->lock, tmp);
 	ret = ec_poll(ec);
 	spin_lock_irqsave(&ec->lock, tmp);
+	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
+		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
+		pr_debug("+++++ Polling disabled +++++\n");
+	} else if (t->irq_count > ec_storm_threshold) {
+		pr_debug("+++++ Polling scheduled (%d GPE) +++++\n",
+			 t->irq_count);
+		set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
+	}
 	pr_debug("***** Command(%s) stopped *****\n",
 		 acpi_ec_cmd_string(t->command));
+	/* Disable GPE for command processing (IBF=0/OBF=1) */
+	acpi_disable_gpe(NULL, ec->gpe);
 	ec->curr = NULL;
 unlock:
 	spin_unlock_irqrestore(&ec->lock, tmp);
@@ -346,26 +362,11 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
 			goto unlock;
 		}
 	}
-	/* disable GPE during transaction if storm is detected */
-	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
-		/* It has to be disabled, so that it doesn't trigger. */
-		acpi_disable_gpe(NULL, ec->gpe);
-	}
 
 	status = acpi_ec_transaction_unlocked(ec, t);
 
 	/* check if we received SCI during transaction */
 	ec_check_sci_sync(ec, acpi_ec_read_status(ec));
-	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
-		msleep(1);
-		/* It is safe to enable the GPE outside of the transaction. */
-		acpi_enable_gpe(NULL, ec->gpe);
-	} else if (t->irq_count > ec_storm_threshold) {
-		pr_info("GPE storm detected(%d GPEs), "
-			"transactions will use polling mode\n",
-			t->irq_count);
-		set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
-	}
 	if (ec->global_lock)
 		acpi_release_global_lock(glk);
 unlock:
@@ -500,8 +501,12 @@ static void acpi_ec_start(struct acpi_ec *ec)
 	unsigned long flags;
 
 	spin_lock_irqsave(&ec->lock, flags);
-	if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags))
+	if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags)) {
+		pr_debug("+++++ Starting EC +++++\n");
+		/* Enable GPE for event processing (EVT_SCI=1) */
 		acpi_enable_gpe(NULL, ec->gpe);
+		pr_info("+++++ EC started +++++\n");
+	}
 	spin_unlock_irqrestore(&ec->lock, flags);
 }
 
@@ -512,9 +517,12 @@ static void acpi_ec_stop(struct acpi_ec *ec)
 	spin_lock_irqsave(&ec->lock, flags);
 	if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
 	    !test_and_set_bit(EC_FLAGS_STOPPED, &ec->flags)) {
+		pr_debug("+++++ Stopping EC +++++\n");
+		/* Disable GPE for event processing (EVT_SCI=1) */
 		acpi_disable_gpe(NULL, ec->gpe);
 		clear_bit(EC_FLAGS_STARTED, &ec->flags);
 		clear_bit(EC_FLAGS_STOPPED, &ec->flags);
+		pr_info("+++++ EC stopped +++++\n");
 	}
 	spin_unlock_irqrestore(&ec->lock, flags);
 }
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v2 04/10] ACPI/EC: Refine command storm prevention support.
  2014-07-15  3:14 ` [PATCH v2 00/10] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
                     ` (2 preceding siblings ...)
  2014-07-15  3:14   ` [PATCH v2 03/10] ACPI/EC: Deploy the new GPE handling model Lv Zheng
@ 2014-07-15  3:14   ` Lv Zheng
  2014-07-15  3:14   ` [PATCH v2 05/10] ACPI/EC: Add reference counting for query handlers Lv Zheng
                     ` (5 subsequent siblings)
  9 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-15  3:14 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch refines EC command storm prevention support.

Ideally, we should only enable storm prevention for the current command so
that the next command can try the efficient interrupt mode again.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   21 +++++++++------------
 1 file changed, 9 insertions(+), 12 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 5049981..d4c07b9 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -76,7 +76,6 @@ enum ec_command {
 
 enum {
 	EC_FLAGS_QUERY_PENDING,		/* Query is pending */
-	EC_FLAGS_GPE_STORM,		/* GPE storm detected */
 	EC_FLAGS_HANDLERS_INSTALLED,	/* Handlers for GPE and
 					 * OpReg are installed */
 	EC_FLAGS_STARTED,		/* Driver is started */
@@ -243,8 +242,14 @@ err:
 	 * otherwise will take a not handled IRQ as a false one.
 	 */
 	if (!(status & ACPI_EC_FLAG_SCI)) {
-		if (in_interrupt() && t)
-			++t->irq_count;
+		if (in_interrupt() && t) {
+			if (t->irq_count < ec_storm_threshold)
+				++t->irq_count;
+			if (t->irq_count == ec_storm_threshold) {
+				pr_debug("+++++ Polling enabled +++++\n");
+				acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
+			}
+		}
 	}
 	return wakeup;
 }
@@ -318,23 +323,15 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 	acpi_enable_gpe(NULL, ec->gpe);
 	pr_debug("***** Command(%s) started *****\n",
 		 acpi_ec_cmd_string(t->command));
-	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
-		pr_debug("+++++ Polling enabled +++++\n");
-		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
-	}
 	start_transaction(ec);
 	if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
 		clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
 	spin_unlock_irqrestore(&ec->lock, tmp);
 	ret = ec_poll(ec);
 	spin_lock_irqsave(&ec->lock, tmp);
-	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
+	if (t->irq_count == ec_storm_threshold) {
 		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
 		pr_debug("+++++ Polling disabled +++++\n");
-	} else if (t->irq_count > ec_storm_threshold) {
-		pr_debug("+++++ Polling scheduled (%d GPE) +++++\n",
-			 t->irq_count);
-		set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
 	}
 	pr_debug("***** Command(%s) stopped *****\n",
 		 acpi_ec_cmd_string(t->command));
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v2 05/10] ACPI/EC: Add reference counting for query handlers.
  2014-07-15  3:14 ` [PATCH v2 00/10] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
                     ` (3 preceding siblings ...)
  2014-07-15  3:14   ` [PATCH v2 04/10] ACPI/EC: Refine command storm prevention support Lv Zheng
@ 2014-07-15  3:14   ` Lv Zheng
  2014-07-15  3:15   ` [PATCH v2 06/10] ACPI/EC: Add a warning message to indicate event storms Lv Zheng
                     ` (4 subsequent siblings)
  9 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-15  3:14 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds reference counting for query handlers in order to eliminate
kmalloc()/kfree() usage.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Tested-by: Steffen Weber <steffen.weber@gmail.com>
---
 drivers/acpi/ec.c |   46 ++++++++++++++++++++++++++++++++++++----------
 1 file changed, 36 insertions(+), 10 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index d4c07b9..cf83872 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -105,6 +105,7 @@ struct acpi_ec_query_handler {
 	acpi_handle handle;
 	void *data;
 	u8 query_bit;
+	struct kref kref;
 };
 
 struct transaction {
@@ -119,6 +120,10 @@ struct transaction {
 	u8 flags;
 };
 
+static struct acpi_ec_query_handler *
+acpi_ec_get_query_handler(struct acpi_ec_query_handler *handler);
+static void acpi_ec_put_query_handler(struct acpi_ec_query_handler *handler);
+
 struct acpi_ec *boot_ec, *first_ec;
 EXPORT_SYMBOL(first_ec);
 
@@ -590,6 +595,26 @@ static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data)
 /* --------------------------------------------------------------------------
                                 Event Management
    -------------------------------------------------------------------------- */
+static struct acpi_ec_query_handler *
+acpi_ec_get_query_handler(struct acpi_ec_query_handler *handler)
+{
+	if (handler)
+		kref_get(&handler->kref);
+	return handler;
+}
+
+static void acpi_ec_query_handler_release(struct kref *kref)
+{
+	struct acpi_ec_query_handler *handler =
+		container_of(kref, struct acpi_ec_query_handler, kref);
+	kfree(handler);
+}
+
+static void acpi_ec_put_query_handler(struct acpi_ec_query_handler *handler)
+{
+	kref_put(&handler->kref, acpi_ec_query_handler_release);
+}
+
 int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
 			      acpi_handle handle, acpi_ec_query_func func,
 			      void *data)
@@ -604,6 +629,7 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
 	handler->func = func;
 	handler->data = data;
 	mutex_lock(&ec->mutex);
+	kref_init(&handler->kref);
 	list_add(&handler->node, &ec->list);
 	mutex_unlock(&ec->mutex);
 	return 0;
@@ -614,14 +640,17 @@ EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler);
 void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
 {
 	struct acpi_ec_query_handler *handler, *tmp;
+	LIST_HEAD(free_list);
 	mutex_lock(&ec->mutex);
 	list_for_each_entry_safe(handler, tmp, &ec->list, node) {
 		if (query_bit == handler->query_bit) {
-			list_del(&handler->node);
-			kfree(handler);
+			list_del_init(&handler->node);
+			list_add(&handler->node, &free_list);
 		}
 	}
 	mutex_unlock(&ec->mutex);
+	list_for_each_entry(handler, &free_list, node)
+		acpi_ec_put_query_handler(handler);
 }
 
 EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
@@ -637,14 +666,14 @@ static void acpi_ec_run(void *cxt)
 	else if (handler->handle)
 		acpi_evaluate_object(handler->handle, NULL, NULL, NULL);
 	pr_debug("stop query execution\n");
-	kfree(handler);
+	acpi_ec_put_query_handler(handler);
 }
 
 static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data)
 {
 	u8 value = 0;
 	int status;
-	struct acpi_ec_query_handler *handler, *copy;
+	struct acpi_ec_query_handler *handler;
 
 	status = acpi_ec_query_unlocked(ec, &value);
 	if (data)
@@ -655,15 +684,12 @@ static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data)
 	list_for_each_entry(handler, &ec->list, node) {
 		if (value == handler->query_bit) {
 			/* have custom handler for this bit */
-			copy = kmalloc(sizeof(*handler), GFP_KERNEL);
-			if (!copy)
-				return -ENOMEM;
-			memcpy(copy, handler, sizeof(*copy));
+			handler = acpi_ec_get_query_handler(handler);
 			pr_debug("push query execution (0x%2x) on queue\n",
 				value);
-			return acpi_os_execute((copy->func) ?
+			return acpi_os_execute((handler->func) ?
 				OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER,
-				acpi_ec_run, copy);
+				acpi_ec_run, handler);
 		}
 	}
 	return 0;
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v2 06/10] ACPI/EC: Add a warning message to indicate event storms.
  2014-07-15  3:14 ` [PATCH v2 00/10] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
                     ` (4 preceding siblings ...)
  2014-07-15  3:14   ` [PATCH v2 05/10] ACPI/EC: Add reference counting for query handlers Lv Zheng
@ 2014-07-15  3:15   ` Lv Zheng
  2014-07-15  3:15   ` [PATCH v2 07/10] ACPI/EC: Refine event/query debugging messages Lv Zheng
                     ` (3 subsequent siblings)
  9 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-15  3:15 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch splits query handler scheduling into a new seperate function
acpi_ec_notify_query_handlers() and adds a warning message in it to
indicate a BIOS bug. It is reported that EC event storm can happen in case
there is no handler prepared for the event. No functional changes.

Reference: https://bugzilla.kernel.org/show_bug.cgi?id=78091
Reported-by: Steffen Weber <steffen.weber@gmail.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   29 ++++++++++++++++++-----------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index cf83872..8817836 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -669,32 +669,39 @@ static void acpi_ec_run(void *cxt)
 	acpi_ec_put_query_handler(handler);
 }
 
-static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data)
+static int acpi_ec_notify_query_handlers(struct acpi_ec *ec, u8 query_bit)
 {
-	u8 value = 0;
-	int status;
 	struct acpi_ec_query_handler *handler;
 
-	status = acpi_ec_query_unlocked(ec, &value);
-	if (data)
-		*data = value;
-	if (status)
-		return status;
-
 	list_for_each_entry(handler, &ec->list, node) {
-		if (value == handler->query_bit) {
+		if (query_bit == handler->query_bit) {
 			/* have custom handler for this bit */
 			handler = acpi_ec_get_query_handler(handler);
 			pr_debug("push query execution (0x%2x) on queue\n",
-				value);
+				 query_bit);
 			return acpi_os_execute((handler->func) ?
 				OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER,
 				acpi_ec_run, handler);
 		}
 	}
+	pr_warn_once("BIOS bug: no handler for query (0x%02x)\n", query_bit);
 	return 0;
 }
 
+static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data)
+{
+	u8 value = 0;
+	int status;
+
+	status = acpi_ec_query_unlocked(ec, &value);
+	if (data)
+		*data = value;
+	if (status)
+		return status;
+
+	return acpi_ec_notify_query_handlers(ec, value);
+}
+
 static void acpi_ec_gpe_query(void *ec_cxt)
 {
 	struct acpi_ec *ec = ec_cxt;
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v2 07/10] ACPI/EC: Refine event/query debugging messages.
  2014-07-15  3:14 ` [PATCH v2 00/10] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
                     ` (5 preceding siblings ...)
  2014-07-15  3:15   ` [PATCH v2 06/10] ACPI/EC: Add a warning message to indicate event storms Lv Zheng
@ 2014-07-15  3:15   ` Lv Zheng
  2014-07-15  3:15   ` [PATCH v2 08/10] ACPI/EC: Add command flushing support Lv Zheng
                     ` (2 subsequent siblings)
  9 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-15  3:15 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch refines event/query debugging messages to use a unified format
as commands. Developers can clearly find different processes by checking
different log seperators. No functional changes.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 8817836..2340ac2 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -329,8 +329,10 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 	pr_debug("***** Command(%s) started *****\n",
 		 acpi_ec_cmd_string(t->command));
 	start_transaction(ec);
-	if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
+	if (ec->curr->command == ACPI_EC_COMMAND_QUERY) {
 		clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
+		pr_debug("***** Event stopped *****\n");
+	}
 	spin_unlock_irqrestore(&ec->lock, tmp);
 	ret = ec_poll(ec);
 	spin_lock_irqsave(&ec->lock, tmp);
@@ -660,12 +662,12 @@ static void acpi_ec_run(void *cxt)
 	struct acpi_ec_query_handler *handler = cxt;
 	if (!handler)
 		return;
-	pr_debug("start query execution\n");
+	pr_debug("##### Query(0x%02x) started #####\n", handler->query_bit);
 	if (handler->func)
 		handler->func(handler->data);
 	else if (handler->handle)
 		acpi_evaluate_object(handler->handle, NULL, NULL, NULL);
-	pr_debug("stop query execution\n");
+	pr_debug("##### Query(0x%02x) stopped #####\n", handler->query_bit);
 	acpi_ec_put_query_handler(handler);
 }
 
@@ -677,8 +679,8 @@ static int acpi_ec_notify_query_handlers(struct acpi_ec *ec, u8 query_bit)
 		if (query_bit == handler->query_bit) {
 			/* have custom handler for this bit */
 			handler = acpi_ec_get_query_handler(handler);
-			pr_debug("push query execution (0x%2x) on queue\n",
-				 query_bit);
+			pr_debug("##### Query(0x%02x) scheduled #####\n",
+				 handler->query_bit);
 			return acpi_os_execute((handler->func) ?
 				OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER,
 				acpi_ec_run, handler);
@@ -716,7 +718,7 @@ static int ec_check_sci(struct acpi_ec *ec, u8 state)
 {
 	if (state & ACPI_EC_FLAG_SCI) {
 		if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
-			pr_debug("push gpe query to the queue\n");
+			pr_debug("***** Event started *****\n");
 			return acpi_os_execute(OSL_NOTIFY_HANDLER,
 				acpi_ec_gpe_query, ec);
 		}
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v2 08/10] ACPI/EC: Add command flushing support.
  2014-07-15  3:14 ` [PATCH v2 00/10] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
                     ` (6 preceding siblings ...)
  2014-07-15  3:15   ` [PATCH v2 07/10] ACPI/EC: Refine event/query debugging messages Lv Zheng
@ 2014-07-15  3:15   ` Lv Zheng
  2014-07-15  3:15   ` [PATCH v2 09/10] ACPI/EC: Add event storm prevention support Lv Zheng
  2014-07-15  3:15   ` [PATCH v2 10/10] ACPI/EC: Add unit test support for EC driver hotplug Lv Zheng
  9 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-15  3:15 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch implements command flushing support. It's better to wait all
command transactions to be completed before disabling the EC GPE when the
system is going to be suspended. By doing so, the EC hardware can be
ensured to be in the idle state when the system is resumed.

The system suspending/resuming test result is as follows:
 [   24.950829] ACPI : EC: +++++ Stopping EC +++++
 [   24.950836] ACPI : EC: +++++ EC stopped +++++

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c       |   49 +++++++++++++++++++++++++++++++++++++++++++----
 drivers/acpi/internal.h |    1 +
 2 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 2340ac2..936424a 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -133,6 +133,32 @@ static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
 static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
 
 /* --------------------------------------------------------------------------
+                             GPE Enhancement
+   -------------------------------------------------------------------------- */
+
+static bool acpi_ec_flushed(struct acpi_ec *ec)
+{
+	return !!(ec->reference_count == 1);
+}
+
+static void acpi_ec_enable_gpe(struct acpi_ec *ec)
+{
+	acpi_enable_gpe(NULL, ec->gpe);
+	ec->reference_count++;
+}
+
+static void acpi_ec_disable_gpe(struct acpi_ec *ec)
+{
+	bool flushed = false;
+
+	ec->reference_count--;
+	acpi_disable_gpe(NULL, ec->gpe);
+	flushed = acpi_ec_flushed(ec);
+	if (flushed)
+		wake_up(&ec->wait);
+}
+
+/* --------------------------------------------------------------------------
                              Transaction Management
    -------------------------------------------------------------------------- */
 
@@ -325,7 +351,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 	/* following two actions should be kept atomic */
 	ec->curr = t;
 	/* Enable GPE for command processing (IBF=0/OBF=1) */
-	acpi_enable_gpe(NULL, ec->gpe);
+	acpi_ec_enable_gpe(ec);
 	pr_debug("***** Command(%s) started *****\n",
 		 acpi_ec_cmd_string(t->command));
 	start_transaction(ec);
@@ -343,7 +369,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 	pr_debug("***** Command(%s) stopped *****\n",
 		 acpi_ec_cmd_string(t->command));
 	/* Disable GPE for command processing (IBF=0/OBF=1) */
-	acpi_disable_gpe(NULL, ec->gpe);
+	acpi_ec_disable_gpe(ec);
 	ec->curr = NULL;
 unlock:
 	spin_unlock_irqrestore(&ec->lock, tmp);
@@ -508,12 +534,24 @@ static void acpi_ec_start(struct acpi_ec *ec)
 	if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags)) {
 		pr_debug("+++++ Starting EC +++++\n");
 		/* Enable GPE for event processing (EVT_SCI=1) */
-		acpi_enable_gpe(NULL, ec->gpe);
+		acpi_ec_enable_gpe(ec);
 		pr_info("+++++ EC started +++++\n");
 	}
 	spin_unlock_irqrestore(&ec->lock, flags);
 }
 
+static bool acpi_ec_stopped(struct acpi_ec *ec)
+{
+	unsigned long flags;
+	bool flushed;
+
+	spin_lock_irqsave(&ec->lock, flags);
+	flushed = acpi_ec_flushed(ec);
+	spin_unlock_irqrestore(&ec->lock, flags);
+
+	return flushed;
+}
+
 static void acpi_ec_stop(struct acpi_ec *ec)
 {
 	unsigned long flags;
@@ -522,8 +560,11 @@ static void acpi_ec_stop(struct acpi_ec *ec)
 	if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
 	    !test_and_set_bit(EC_FLAGS_STOPPED, &ec->flags)) {
 		pr_debug("+++++ Stopping EC +++++\n");
+		spin_unlock_irqrestore(&ec->lock, flags);
+		wait_event(ec->wait, acpi_ec_stopped(ec));
+		spin_lock_irqsave(&ec->lock, flags);
 		/* Disable GPE for event processing (EVT_SCI=1) */
-		acpi_disable_gpe(NULL, ec->gpe);
+		acpi_ec_disable_gpe(ec);
 		clear_bit(EC_FLAGS_STARTED, &ec->flags);
 		clear_bit(EC_FLAGS_STOPPED, &ec->flags);
 		pr_info("+++++ EC stopped +++++\n");
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 151f3e7..2348f9c 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -118,6 +118,7 @@ struct acpi_ec {
 	unsigned long data_addr;
 	unsigned long global_lock;
 	unsigned long flags;
+	unsigned long reference_count;
 	struct mutex mutex;
 	wait_queue_head_t wait;
 	struct list_head list;
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v2 09/10] ACPI/EC: Add event storm prevention support.
  2014-07-15  3:14 ` [PATCH v2 00/10] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
                     ` (7 preceding siblings ...)
  2014-07-15  3:15   ` [PATCH v2 08/10] ACPI/EC: Add command flushing support Lv Zheng
@ 2014-07-15  3:15   ` Lv Zheng
  2014-07-15  3:15   ` [PATCH v2 10/10] ACPI/EC: Add unit test support for EC driver hotplug Lv Zheng
  9 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-15  3:15 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

There are cases that BIOS doesn't provide _Qxx handler for the returned
query value, in this case, acpi_set_gpe(ACPI_GPE_DISABLE) need to be
invoked to prevent event IRQ storms.

This patch implements such storm prevention using new GPE APIs.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   50 ++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 42 insertions(+), 8 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 936424a..b98474f 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -80,6 +80,10 @@ enum {
 					 * OpReg are installed */
 	EC_FLAGS_STARTED,		/* Driver is started */
 	EC_FLAGS_STOPPED,		/* Driver is stopped */
+	EC_FLAGS_COMMAND_STORM,		/* GPE storms occurred to the
+					 * current command processing */
+	EC_FLAGS_EVENT_STORM,		/* GPE storms occurred to the
+					 * current event processing */
 };
 
 #define ACPI_EC_COMMAND_POLL		0x01 /* Available for command byte */
@@ -158,6 +162,31 @@ static void acpi_ec_disable_gpe(struct acpi_ec *ec)
 		wake_up(&ec->wait);
 }
 
+static void acpi_ec_set_storm(struct acpi_ec *ec, u8 flag)
+{
+	if (!test_bit(flag, &ec->flags)) {
+		if (!test_bit(EC_FLAGS_EVENT_STORM, &ec->flags) &&
+		    !test_bit(EC_FLAGS_COMMAND_STORM, &ec->flags)) {
+			acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
+			pr_debug("+++++ Polling enabled +++++\n");
+		}
+		set_bit(flag, &ec->flags);
+	}
+}
+
+
+static void acpi_ec_clear_storm(struct acpi_ec *ec, u8 flag)
+{
+	if (test_bit(flag, &ec->flags)) {
+		clear_bit(flag, &ec->flags);
+		if (!test_bit(EC_FLAGS_EVENT_STORM, &ec->flags) &&
+		    !test_bit(EC_FLAGS_COMMAND_STORM, &ec->flags)) {
+			acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
+			pr_debug("+++++ Polling disabled +++++\n");
+		}
+	}
+}
+
 /* --------------------------------------------------------------------------
                              Transaction Management
    -------------------------------------------------------------------------- */
@@ -276,10 +305,8 @@ err:
 		if (in_interrupt() && t) {
 			if (t->irq_count < ec_storm_threshold)
 				++t->irq_count;
-			if (t->irq_count == ec_storm_threshold) {
-				pr_debug("+++++ Polling enabled +++++\n");
-				acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
-			}
+			if (t->irq_count == ec_storm_threshold)
+				acpi_ec_set_storm(ec, EC_FLAGS_COMMAND_STORM);
 		}
 	}
 	return wakeup;
@@ -362,10 +389,8 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 	spin_unlock_irqrestore(&ec->lock, tmp);
 	ret = ec_poll(ec);
 	spin_lock_irqsave(&ec->lock, tmp);
-	if (t->irq_count == ec_storm_threshold) {
-		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
-		pr_debug("+++++ Polling disabled +++++\n");
-	}
+	if (t->irq_count == ec_storm_threshold)
+		acpi_ec_clear_storm(ec, EC_FLAGS_COMMAND_STORM);
 	pr_debug("***** Command(%s) stopped *****\n",
 		 acpi_ec_cmd_string(t->command));
 	/* Disable GPE for command processing (IBF=0/OBF=1) */
@@ -563,6 +588,8 @@ static void acpi_ec_stop(struct acpi_ec *ec)
 		spin_unlock_irqrestore(&ec->lock, flags);
 		wait_event(ec->wait, acpi_ec_stopped(ec));
 		spin_lock_irqsave(&ec->lock, flags);
+		/* Event storm may still be indicated */
+		acpi_ec_clear_storm(ec, EC_FLAGS_EVENT_STORM);
 		/* Disable GPE for event processing (EVT_SCI=1) */
 		acpi_ec_disable_gpe(ec);
 		clear_bit(EC_FLAGS_STARTED, &ec->flags);
@@ -714,10 +741,14 @@ static void acpi_ec_run(void *cxt)
 
 static int acpi_ec_notify_query_handlers(struct acpi_ec *ec, u8 query_bit)
 {
+	unsigned long flags;
 	struct acpi_ec_query_handler *handler;
 
 	list_for_each_entry(handler, &ec->list, node) {
 		if (query_bit == handler->query_bit) {
+			spin_lock_irqsave(&ec->lock, flags);
+			acpi_ec_clear_storm(ec, EC_FLAGS_EVENT_STORM);
+			spin_unlock_irqrestore(&ec->lock, flags);
 			/* have custom handler for this bit */
 			handler = acpi_ec_get_query_handler(handler);
 			pr_debug("##### Query(0x%02x) scheduled #####\n",
@@ -728,6 +759,9 @@ static int acpi_ec_notify_query_handlers(struct acpi_ec *ec, u8 query_bit)
 		}
 	}
 	pr_warn_once("BIOS bug: no handler for query (0x%02x)\n", query_bit);
+	spin_lock_irqsave(&ec->lock, flags);
+	acpi_ec_set_storm(ec, EC_FLAGS_EVENT_STORM);
+	spin_unlock_irqrestore(&ec->lock, flags);
 	return 0;
 }
 
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v2 10/10] ACPI/EC: Add unit test support for EC driver hotplug.
  2014-07-15  3:14 ` [PATCH v2 00/10] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
                     ` (8 preceding siblings ...)
  2014-07-15  3:15   ` [PATCH v2 09/10] ACPI/EC: Add event storm prevention support Lv Zheng
@ 2014-07-15  3:15   ` Lv Zheng
  9 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-15  3:15 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds facility to test future EC modification.
All EC commits should enable TEST_HOTPLUG, and try a build/boot test.
Since EC is currently a built-in module, this is the only mean for us to
test the hotplug code.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index b98474f..d3b1bd7 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -31,6 +31,7 @@
 
 /* Uncomment next line to get verbose printout */
 /* #define DEBUG */
+/* #define TEST_HOTPLUG */
 #define pr_fmt(fmt) "ACPI : EC: " fmt
 
 #include <linux/kernel.h>
@@ -128,6 +129,9 @@ static struct acpi_ec_query_handler *
 acpi_ec_get_query_handler(struct acpi_ec_query_handler *handler);
 static void acpi_ec_put_query_handler(struct acpi_ec_query_handler *handler);
 
+static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
+			       u32 gpe_number, void *data);
+
 struct acpi_ec *boot_ec, *first_ec;
 EXPORT_SYMBOL(first_ec);
 
@@ -787,6 +791,21 @@ static void acpi_ec_gpe_query(void *ec_cxt)
 	mutex_lock(&ec->mutex);
 	acpi_ec_sync_query(ec, NULL);
 	mutex_unlock(&ec->mutex);
+
+#ifdef TEST_HOTPLUG
+
+	/* Unit testing for driver hotplugging */
+
+	pr_info("Removing EC handlers...\n");
+	acpi_ec_stop(ec);
+	acpi_remove_gpe_handler(NULL, ec->gpe,
+				&acpi_ec_gpe_handler);
+	pr_info("Installing EC handlers...\n");
+	acpi_install_gpe_handler(NULL, ec->gpe,
+				  ACPI_GPE_EDGE_TRIGGERED,
+				  &acpi_ec_gpe_handler, ec);
+	acpi_ec_start(ec);
+#endif
 }
 
 static int ec_check_sci(struct acpi_ec *ec, u8 state)
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v2] ACPI/EC: Enable storm prevention mechanisms.
  2014-06-18  3:17 [PATCH 0/9] ACPI/EC: Improve GPE handling model Lv Zheng
                   ` (10 preceding siblings ...)
  2014-07-15  3:14 ` [PATCH v2 00/10] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
@ 2014-07-15  7:09 ` Lv Zheng
  2014-07-16  0:44   ` Andi Kleen
  2014-07-21  6:04 ` [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
  2015-02-05  8:24 ` [PATCH v4 0/6] ACPI / EC: Fix GPE handling related races Lv Zheng
  13 siblings, 1 reply; 63+ messages in thread
From: Lv Zheng @ 2014-07-15  7:09 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch enables storm prevention mechanisms. After applying this patch,
when the command/event storms are actually detected, EC driver will be
switched from the IRQ mode to the polling mode.

If regressions are reported against storm prevention support, this patch
can be bisected and reverted before issues can be root caused.

By changing the storm threshold to 0 and stops returning from
advance_transaction() without increasing irq_count on non-error cases, we
can perform unit test for the storm prevention. The result is as follows:
  [    4.525321] ACPI : EC: ***** Command(RD_EC) started *****
  [    4.525321] ACPI : EC: ===== TASK =====
  [    4.525326] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
  [    4.525327] ACPI : EC: EC_SC(W) = 0x80
  [    4.525436] ACPI : EC: ===== IRQ =====
  [    4.525442] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
  [    4.525442] ACPI : EC: EC_DATA(W) = 0x23
  [    4.525448] ACPI : EC: +++++ Polling enabled +++++
  [    4.525451] ACPI : EC: EC_SC(R) = 0x02 SCI_EVT=0 BURST=0 CMD=0 IBF=1 OBF=0
# [    4.528954] ACPI : EC: ===== TASK =====
  [    4.528957] ACPI : EC: EC_SC(R) = 0x01 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=1
  [    4.528960] ACPI : EC: EC_DATA(R) = 0x2b
  [    4.528963] ACPI : EC: +++++ Polling disabled +++++
  [    4.528964] ACPI : EC: ***** Command(RD_EC) stopped *****
  [    4.528974] ACPI : EC: ===== IRQ =====
  [    4.528977] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
  [    4.528980] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
  [    4.528988] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
  [    4.529347] ACPI : EC: ***** Command(WR_EC) started *****
  [    4.529348] ACPI : EC: ===== TASK =====
  [    4.529352] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
  [    4.529353] ACPI : EC: EC_SC(W) = 0x81
* [    4.529467] ACPI : EC: ===== IRQ =====
  [    4.529473] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
  [    4.529473] ACPI : EC: EC_DATA(W) = 0x04
  [    4.529479] ACPI : EC: +++++ Polling enabled +++++
  [    4.529482] ACPI : EC: EC_SC(R) = 0x02 SCI_EVT=0 BURST=0 CMD=0 IBF=1 OBF=0
  [    4.532951] ACPI : EC: ===== TASK =====
  [    4.532957] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
  [    4.532957] ACPI : EC: EC_DATA(W) = 0x01
  [    4.536952] ACPI : EC: ===== TASK =====
  [    4.536957] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
  [    4.536964] ACPI : EC: +++++ Polling disabled +++++
  [    4.536965] ACPI : EC: ***** Command(WR_EC) stopped *****
We can see the command is advanced in the task context after enabling the
polling mode (#) and the next command can still be started from the high
performance IRQ mode (*).

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index d3b1bd7..f40144e 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -825,13 +825,17 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
 {
 	unsigned long flags;
 	struct acpi_ec *ec = data;
+	u32 enable = 0;
 
 	spin_lock_irqsave(&ec->lock, flags);
 	if (advance_transaction(ec))
 		wake_up(&ec->wait);
+	if (!test_bit(EC_FLAGS_EVENT_STORM, &ec->flags) &&
+	    !test_bit(EC_FLAGS_COMMAND_STORM, &ec->flags))
+		enable = ACPI_REENABLE_GPE;
 	spin_unlock_irqrestore(&ec->lock, flags);
 	ec_check_sci(ec, acpi_ec_read_status(ec));
-	return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE;
+	return ACPI_INTERRUPT_HANDLED | enable;
 }
 
 /* --------------------------------------------------------------------------
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* Re: [PATCH v2 0/9] ACPICA: Improve GPE handling model.
  2014-07-15  3:07 ` [PATCH v2 0/9] ACPICA: Improve GPE handling model Lv Zheng
                     ` (8 preceding siblings ...)
  2014-07-15  3:08   ` [PATCH v2 9/9] ACPI: Update interrupt handler to honor new ACPI_REENABLE_GPE bit Lv Zheng
@ 2014-07-15 12:25   ` Rafael J. Wysocki
  2014-07-16  0:36     ` Zheng, Lv
  9 siblings, 1 reply; 63+ messages in thread
From: Rafael J. Wysocki @ 2014-07-15 12:25 UTC (permalink / raw)
  To: Lv Zheng; +Cc: Rafael J. Wysocki, Len Brown, Lv Zheng, linux-kernel, linux-acpi

On Tuesday, July 15, 2014 11:07:10 AM Lv Zheng wrote:
> This patchset enables the ideal GPE handling model. The ideal GPE handling
> model should be able to handle the following cases:
> 
>    1. When upper layers (the users of the driver) submit requests to the
>       drivers, it means they care about the underlying hardware. For this
>       case, acpi_enable_gpe() should be invoked. When the reference count
>       is increased from 0 to 1, driver enables the hardware IRQ. And
>       acpi_disable_gpe() is used as the reversal when the users have
>       completed the submitted requests.
>    2. Driver may temporarily disables the IRQ and wants to re-enable it
>       later, this case is normally used in order to prevent IRQ storm.
>       When a driver cannot fully solve the condition that triggered the IRQ
>       in the IRQ context, in order not to trigger IRQ storm, driver has to
>       disable IRQ and re-enables it in the deferred execution environment
>       - which should be in a task context. The acpi_set_gpe() API should be
>       used exactly for this purpose.
> 
> The reason why this model hasn't been enabled for the current Linux ACPI
> drivers is:
>   In ACPICA, the same GPE lock is held while invoking the GPE handler
>   callback, it's thus impossible to invoke GPE APIs in the GPE handler
>   because the APIs require to hold the GPE lock. The recursive locking
>   leads to dead locks. This is a simple design defect, callbacks should
>   always be invoked in a lockless environment, normally in Linux, this is
>   achieved by RCU locking, and in ACPICA, we achieve this using reference
>   counting.
> 
> After fixing the above bug and doing necessary cleanups in the ACPICA GPE
> handling code, we now can enable this ideal GPE handling model for the EC
> driver to implement "commands flushing" and "storm prevention" (the EC
> driver enabling is not included in this patchset).

How this patch series is related to upstream ACPICA?  Is the design fixed
already upstream?

> The refined patches are passed the runtime/suspend tests carried out on the
> following platforms with EC driver enhanced:
>   "Dell Inspiron Mini 1010" - i386 kernel
>   "Dell Latitude 6430u" - x86_64 kernel
> 
> Lv Zheng (9):
>   ACPICA: Events: Reduce indent divergences of events files.
>   ACPICA: Events: Fix an issue that GPE APIs cannot be invoked in
>     atomic context.
>   ACPICA: Events: Fix an issue that GPE APIs cannot be invoked in
>     deferred handlers.
>   ACPICA: Events: Introduce acpi_set_gpe()/acpi_finish_gpe() to reduce
>     divergences.
>   ACPICA: Events: Fix an issue that acpi_set_gpe() cannot
>     unconditionally enable GPEs.
>   ACPICA: Events: Fix an issue that status of GPEs are unexpectedly
>     cleared.
>   ACPICA: Events: Fix an issue that originally_enabled check is not
>     paired.
>   ACPICA: Events: Add a flag to disable internal auto GPE clearing.
>   ACPI: Update interrupt handler to honor new ACPI_REENABLE_GPE bit.
> 
>  drivers/acpi/acpica/acevents.h |    1 +
>  drivers/acpi/acpica/aclocal.h  |    5 +-
>  drivers/acpi/acpica/evgpe.c    |  136 +++++++++++++++++++++-------------------
>  drivers/acpi/acpica/evxface.c  |   41 ++++++++----
>  drivers/acpi/acpica/evxfgpe.c  |  105 +++++++++++++++++++++++++++++++
>  drivers/acpi/osl.c             |    2 +-
>  include/acpi/actypes.h         |   16 ++---
>  7 files changed, 219 insertions(+), 87 deletions(-)
> 
> 

-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [PATCH v2 0/9] ACPICA: Improve GPE handling model.
  2014-07-15 12:25   ` [PATCH v2 0/9] ACPICA: Improve GPE handling model Rafael J. Wysocki
@ 2014-07-16  0:36     ` Zheng, Lv
  0 siblings, 0 replies; 63+ messages in thread
From: Zheng, Lv @ 2014-07-16  0:36 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Wysocki, Rafael J, Brown, Len, Lv Zheng, linux-kernel, linux-acpi

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 4332 bytes --]

Hi,

> From: Rafael J. Wysocki [mailto:rjw@rjwysocki.net]
> Sent: Tuesday, July 15, 2014 8:26 PM
> 
> On Tuesday, July 15, 2014 11:07:10 AM Lv Zheng wrote:
> > This patchset enables the ideal GPE handling model. The ideal GPE handling
> > model should be able to handle the following cases:
> >
> >    1. When upper layers (the users of the driver) submit requests to the
> >       drivers, it means they care about the underlying hardware. For this
> >       case, acpi_enable_gpe() should be invoked. When the reference count
> >       is increased from 0 to 1, driver enables the hardware IRQ. And
> >       acpi_disable_gpe() is used as the reversal when the users have
> >       completed the submitted requests.
> >    2. Driver may temporarily disables the IRQ and wants to re-enable it
> >       later, this case is normally used in order to prevent IRQ storm.
> >       When a driver cannot fully solve the condition that triggered the IRQ
> >       in the IRQ context, in order not to trigger IRQ storm, driver has to
> >       disable IRQ and re-enables it in the deferred execution environment
> >       - which should be in a task context. The acpi_set_gpe() API should be
> >       used exactly for this purpose.
> >
> > The reason why this model hasn't been enabled for the current Linux ACPI
> > drivers is:
> >   In ACPICA, the same GPE lock is held while invoking the GPE handler
> >   callback, it's thus impossible to invoke GPE APIs in the GPE handler
> >   because the APIs require to hold the GPE lock. The recursive locking
> >   leads to dead locks. This is a simple design defect, callbacks should
> >   always be invoked in a lockless environment, normally in Linux, this is
> >   achieved by RCU locking, and in ACPICA, we achieve this using reference
> >   counting.
> >
> > After fixing the above bug and doing necessary cleanups in the ACPICA GPE
> > handling code, we now can enable this ideal GPE handling model for the EC
> > driver to implement "commands flushing" and "storm prevention" (the EC
> > driver enabling is not included in this patchset).
> 
> How this patch series is related to upstream ACPICA?  Is the design fixed
> already upstream?

It hasn't been upstreamed to the ACPICA repo.

This series has been sent to ACPICA upstream as a github pull request, reviewed by David Box.
We are waiting for it to be merged.

This series is required by the EC storm fix series.
I sent both the storm fix series and the linuxized GPE series here, so that we can examine a real OSPM example to see the effect of the new APIs.

Thanks and best regards
-Lv

> 
> > The refined patches are passed the runtime/suspend tests carried out on the
> > following platforms with EC driver enhanced:
> >   "Dell Inspiron Mini 1010" - i386 kernel
> >   "Dell Latitude 6430u" - x86_64 kernel
> >
> > Lv Zheng (9):
> >   ACPICA: Events: Reduce indent divergences of events files.
> >   ACPICA: Events: Fix an issue that GPE APIs cannot be invoked in
> >     atomic context.
> >   ACPICA: Events: Fix an issue that GPE APIs cannot be invoked in
> >     deferred handlers.
> >   ACPICA: Events: Introduce acpi_set_gpe()/acpi_finish_gpe() to reduce
> >     divergences.
> >   ACPICA: Events: Fix an issue that acpi_set_gpe() cannot
> >     unconditionally enable GPEs.
> >   ACPICA: Events: Fix an issue that status of GPEs are unexpectedly
> >     cleared.
> >   ACPICA: Events: Fix an issue that originally_enabled check is not
> >     paired.
> >   ACPICA: Events: Add a flag to disable internal auto GPE clearing.
> >   ACPI: Update interrupt handler to honor new ACPI_REENABLE_GPE bit.
> >
> >  drivers/acpi/acpica/acevents.h |    1 +
> >  drivers/acpi/acpica/aclocal.h  |    5 +-
> >  drivers/acpi/acpica/evgpe.c    |  136 +++++++++++++++++++++-------------------
> >  drivers/acpi/acpica/evxface.c  |   41 ++++++++----
> >  drivers/acpi/acpica/evxfgpe.c  |  105 +++++++++++++++++++++++++++++++
> >  drivers/acpi/osl.c             |    2 +-
> >  include/acpi/actypes.h         |   16 ++---
> >  7 files changed, 219 insertions(+), 87 deletions(-)
> >
> >
> 
> --
> I speak only for myself.
> Rafael J. Wysocki, Intel Open Source Technology Center.
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v2] ACPI/EC: Enable storm prevention mechanisms.
  2014-07-15  7:09 ` [PATCH v2] ACPI/EC: Enable storm prevention mechanisms Lv Zheng
@ 2014-07-16  0:44   ` Andi Kleen
  2014-07-16  0:55     ` Zheng, Lv
  0 siblings, 1 reply; 63+ messages in thread
From: Andi Kleen @ 2014-07-16  0:44 UTC (permalink / raw)
  To: Lv Zheng; +Cc: Rafael J. Wysocki, Len Brown, Lv Zheng, linux-kernel, linux-acpi

Lv Zheng <lv.zheng@intel.com> writes:

> This patch enables storm prevention mechanisms. After applying this patch,
> when the command/event storms are actually detected, EC driver will be
> switched from the IRQ mode to the polling mode.

It would be far better to fix the root cause of the storms, instead
of just barely curing the symptoms.

The last time I investigated this the main problem was desynchronization
with the EC mailbox protocol because Linux was too fast.

At least on my laptop the old delay patch was fairly successful in
resynchronizing.

[needs some more changes to make the ACPI interrupt threaded]

Author: Andi Kleen <andi@firstfloor.org>
Date:   Fri Nov 11 13:46:22 2011 +0100

    ACPI: EC: Add a limited number of repeats after false EC interrupts
5A    
    My Acer laptop has a large number of false EC interrupts
    (interrupts when the EC indexed data register protocol is in the wrong
    state, expecting input when we should send output or vice versa)
    It seems the hardware triggers the interrupt before it actually
    sets the right status in the register.
    
    With a delay and a repeat it usually works on the second and sometimes
    on the third repeat.
    
    With the threaded interrupt we can do this safely now without
    needing a state machine.
    
    This doesn't completely fix the problem on my system, but makes the
    desynchronizations much less frequent and rare enough that passive
    trips still work.
    
    OPEN: best length of the delay. I picked an arbitary value that may
    be too long.
    
    Signed-off-by: Andi Kleen <ak@linux.intel.com>>

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index e520310..8304cdd 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -88,6 +88,16 @@ static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY;
 module_param(ec_delay, uint, 0644);
 MODULE_PARM_DESC(ec_delay, "Timeout(ms) waited until an EC command completes");
 
+static unsigned int ec_max_repeat __read_mostly = 4;
+module_param(ec_max_repeat, uint, 0644);
+MODULE_PARM_DESC(ec_max_repeat, 
+	"Maximum number of repeats after an false EC interrupt");
+
+static unsigned int ec_repeat_delay __read_mostly = 200;
+module_param(ec_repeat_delay, uint, 0644);
+MODULE_PARM_DESC(ec_repeat_delay,
+	"Delay between each repeat after an false EC interrupt (in us)");
+
 /* If we find an EC via the ECDT, we need to keep a ptr to its context */
 /* External interfaces use first EC only, so remember */
 typedef int (*acpi_ec_query_func) (void *data);
@@ -167,9 +177,13 @@ static void start_transaction(struct acpi_ec *ec)
 	acpi_ec_write_cmd(ec, ec->curr->command);
 }
 
-static void advance_transaction(struct acpi_ec *ec, u8 status)
+static void advance_transaction(struct acpi_ec *ec)
 {
 	unsigned long flags;
+	int repeat = ec_max_repeat;
+	u8 status;
+again:
+	status = acpi_ec_read_status(ec);
 	spin_lock_irqsave(&ec->curr_lock, flags);
 	if (!ec->curr)
 		goto unlock;
@@ -195,8 +209,15 @@ err:
 	trace_acpi_ec_unsynchronized(status, ec->curr->wlen, ec->curr->rlen, 
 				     ec->curr->wi, ec->curr->ri);
 	/* false interrupt, state didn't change */
-	if (in_interrupt())
+	if (in_interrupt()) {
 		++ec->curr->irq_count;
+		if (repeat == 0)
+			goto unlock;
+		spin_unlock_irqrestore(&ec->curr_lock, flags);
+		usleep_range(ec_repeat_delay, ec_repeat_delay + 10);
+		repeat--;
+		goto again;
+	}
 unlock:
 	spin_unlock_irqrestore(&ec->curr_lock, flags);
 }
@@ -231,7 +252,7 @@ static int ec_poll(struct acpi_ec *ec)
 						msecs_to_jiffies(1)))
 					return 0;
 			}
-			advance_transaction(ec, acpi_ec_read_status(ec));
+			advance_transaction(ec);
 		} while (time_before(jiffies, delay));
 		if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)
 			break;
@@ -623,7 +644,7 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
 
 	pr_debug(PREFIX "~~~> interrupt\n");
 
-	advance_transaction(ec, acpi_ec_read_status(ec));
+	advance_transaction(ec);
 	if (ec_transaction_done(ec) &&
 	    (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) {
 		wake_up(&ec->wait);






>
> If regressions are reported against storm prevention support, this patch
> can be bisected and reverted before issues can be root caused.
>
> By changing the storm threshold to 0 and stops returning from
> advance_transaction() without increasing irq_count on non-error cases, we
> can perform unit test for the storm prevention. The result is as follows:
>   [    4.525321] ACPI : EC: ***** Command(RD_EC) started *****
>   [    4.525321] ACPI : EC: ===== TASK =====
>   [    4.525326] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
>   [    4.525327] ACPI : EC: EC_SC(W) = 0x80
>   [    4.525436] ACPI : EC: ===== IRQ =====
>   [    4.525442] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
>   [    4.525442] ACPI : EC: EC_DATA(W) = 0x23
>   [    4.525448] ACPI : EC: +++++ Polling enabled +++++
>   [    4.525451] ACPI : EC: EC_SC(R) = 0x02 SCI_EVT=0 BURST=0 CMD=0 IBF=1 OBF=0
> # [    4.528954] ACPI : EC: ===== TASK =====
>   [    4.528957] ACPI : EC: EC_SC(R) = 0x01 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=1
>   [    4.528960] ACPI : EC: EC_DATA(R) = 0x2b
>   [    4.528963] ACPI : EC: +++++ Polling disabled +++++
>   [    4.528964] ACPI : EC: ***** Command(RD_EC) stopped *****
>   [    4.528974] ACPI : EC: ===== IRQ =====
>   [    4.528977] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
>   [    4.528980] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
>   [    4.528988] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
>   [    4.529347] ACPI : EC: ***** Command(WR_EC) started *****
>   [    4.529348] ACPI : EC: ===== TASK =====
>   [    4.529352] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
>   [    4.529353] ACPI : EC: EC_SC(W) = 0x81
> * [    4.529467] ACPI : EC: ===== IRQ =====
>   [    4.529473] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
>   [    4.529473] ACPI : EC: EC_DATA(W) = 0x04
>   [    4.529479] ACPI : EC: +++++ Polling enabled +++++
>   [    4.529482] ACPI : EC: EC_SC(R) = 0x02 SCI_EVT=0 BURST=0 CMD=0 IBF=1 OBF=0
>   [    4.532951] ACPI : EC: ===== TASK =====
>   [    4.532957] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
>   [    4.532957] ACPI : EC: EC_DATA(W) = 0x01
>   [    4.536952] ACPI : EC: ===== TASK =====
>   [    4.536957] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
>   [    4.536964] ACPI : EC: +++++ Polling disabled +++++
>   [    4.536965] ACPI : EC: ***** Command(WR_EC) stopped *****
> We can see the command is advanced in the task context after enabling the
> polling mode (#) and the next command can still be started from the high
> performance IRQ mode (*).
>
> Signed-off-by: Lv Zheng <lv.zheng@intel.com>
> ---
>  drivers/acpi/ec.c |    6 +++++-
>  1 file changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
> index d3b1bd7..f40144e 100644
> --- a/drivers/acpi/ec.c
> +++ b/drivers/acpi/ec.c
> @@ -825,13 +825,17 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
>  {
>  	unsigned long flags;
>  	struct acpi_ec *ec = data;
> +	u32 enable = 0;
>  
>  	spin_lock_irqsave(&ec->lock, flags);
>  	if (advance_transaction(ec))
>  		wake_up(&ec->wait);
> +	if (!test_bit(EC_FLAGS_EVENT_STORM, &ec->flags) &&
> +	    !test_bit(EC_FLAGS_COMMAND_STORM, &ec->flags))
> +		enable = ACPI_REENABLE_GPE;
>  	spin_unlock_irqrestore(&ec->lock, flags);
>  	ec_check_sci(ec, acpi_ec_read_status(ec));
> -	return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE;
> +	return ACPI_INTERRUPT_HANDLED | enable;
>  }
>  
>  /* --------------------------------------------------------------------------

-- 
ak@linux.intel.com -- Speaking for myself only

^ permalink raw reply related	[flat|nested] 63+ messages in thread

* RE: [PATCH v2] ACPI/EC: Enable storm prevention mechanisms.
  2014-07-16  0:44   ` Andi Kleen
@ 2014-07-16  0:55     ` Zheng, Lv
  0 siblings, 0 replies; 63+ messages in thread
From: Zheng, Lv @ 2014-07-16  0:55 UTC (permalink / raw)
  To: Andi Kleen
  Cc: Wysocki, Rafael J, Brown, Len, Lv Zheng, linux-kernel, linux-acpi

Hi, Andi

> From: Andi Kleen [mailto:andi@firstfloor.org]
> Sent: Wednesday, July 16, 2014 8:44 AM
> 
> Lv Zheng <lv.zheng@intel.com> writes:
> 
> > This patch enables storm prevention mechanisms. After applying this patch,
> > when the command/event storms are actually detected, EC driver will be
> > switched from the IRQ mode to the polling mode.
> 
> It would be far better to fix the root cause of the storms, instead
> of just barely curing the symptoms.
> 
> The last time I investigated this the main problem was desynchronization
> with the EC mailbox protocol because Linux was too fast.

Where could I download the specification of the EC mailbox protocol?

Recently we've fixed 2 EC driver race issues.
They could break the communications between the EC hardware and the EC driver.
It's not because Linux was too fast, just because the Linux EC driver was racy.
We can now even remove the delay itself, so why do we need to repeat the delay?
I think you should try Linux mainline to see if the problem you've encountered has already been fixed by the race fix series.

Thanks and best regards
-Lv

> 
> At least on my laptop the old delay patch was fairly successful in
> resynchronizing.
> 
> [needs some more changes to make the ACPI interrupt threaded]
> 
> Author: Andi Kleen <andi@firstfloor.org>
> Date:   Fri Nov 11 13:46:22 2011 +0100
> 
>     ACPI: EC: Add a limited number of repeats after false EC interrupts
> 5A
>     My Acer laptop has a large number of false EC interrupts
>     (interrupts when the EC indexed data register protocol is in the wrong
>     state, expecting input when we should send output or vice versa)
>     It seems the hardware triggers the interrupt before it actually
>     sets the right status in the register.
> 
>     With a delay and a repeat it usually works on the second and sometimes
>     on the third repeat.
> 
>     With the threaded interrupt we can do this safely now without
>     needing a state machine.
> 
>     This doesn't completely fix the problem on my system, but makes the
>     desynchronizations much less frequent and rare enough that passive
>     trips still work.
> 
>     OPEN: best length of the delay. I picked an arbitary value that may
>     be too long.
> 
>     Signed-off-by: Andi Kleen <ak@linux.intel.com>>
> 
> diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
> index e520310..8304cdd 100644
> --- a/drivers/acpi/ec.c
> +++ b/drivers/acpi/ec.c
> @@ -88,6 +88,16 @@ static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY;
>  module_param(ec_delay, uint, 0644);
>  MODULE_PARM_DESC(ec_delay, "Timeout(ms) waited until an EC command completes");
> 
> +static unsigned int ec_max_repeat __read_mostly = 4;
> +module_param(ec_max_repeat, uint, 0644);
> +MODULE_PARM_DESC(ec_max_repeat,
> +	"Maximum number of repeats after an false EC interrupt");
> +
> +static unsigned int ec_repeat_delay __read_mostly = 200;
> +module_param(ec_repeat_delay, uint, 0644);
> +MODULE_PARM_DESC(ec_repeat_delay,
> +	"Delay between each repeat after an false EC interrupt (in us)");
> +
>  /* If we find an EC via the ECDT, we need to keep a ptr to its context */
>  /* External interfaces use first EC only, so remember */
>  typedef int (*acpi_ec_query_func) (void *data);
> @@ -167,9 +177,13 @@ static void start_transaction(struct acpi_ec *ec)
>  	acpi_ec_write_cmd(ec, ec->curr->command);
>  }
> 
> -static void advance_transaction(struct acpi_ec *ec, u8 status)
> +static void advance_transaction(struct acpi_ec *ec)
>  {
>  	unsigned long flags;
> +	int repeat = ec_max_repeat;
> +	u8 status;
> +again:
> +	status = acpi_ec_read_status(ec);
>  	spin_lock_irqsave(&ec->curr_lock, flags);
>  	if (!ec->curr)
>  		goto unlock;
> @@ -195,8 +209,15 @@ err:
>  	trace_acpi_ec_unsynchronized(status, ec->curr->wlen, ec->curr->rlen,
>  				     ec->curr->wi, ec->curr->ri);
>  	/* false interrupt, state didn't change */
> -	if (in_interrupt())
> +	if (in_interrupt()) {
>  		++ec->curr->irq_count;
> +		if (repeat == 0)
> +			goto unlock;
> +		spin_unlock_irqrestore(&ec->curr_lock, flags);
> +		usleep_range(ec_repeat_delay, ec_repeat_delay + 10);
> +		repeat--;
> +		goto again;
> +	}
>  unlock:
>  	spin_unlock_irqrestore(&ec->curr_lock, flags);
>  }
> @@ -231,7 +252,7 @@ static int ec_poll(struct acpi_ec *ec)
>  						msecs_to_jiffies(1)))
>  					return 0;
>  			}
> -			advance_transaction(ec, acpi_ec_read_status(ec));
> +			advance_transaction(ec);
>  		} while (time_before(jiffies, delay));
>  		if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)
>  			break;
> @@ -623,7 +644,7 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
> 
>  	pr_debug(PREFIX "~~~> interrupt\n");
> 
> -	advance_transaction(ec, acpi_ec_read_status(ec));
> +	advance_transaction(ec);
>  	if (ec_transaction_done(ec) &&
>  	    (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) {
>  		wake_up(&ec->wait);
> 
> 
> 
> 
> 
> 
> >
> > If regressions are reported against storm prevention support, this patch
> > can be bisected and reverted before issues can be root caused.
> >
> > By changing the storm threshold to 0 and stops returning from
> > advance_transaction() without increasing irq_count on non-error cases, we
> > can perform unit test for the storm prevention. The result is as follows:
> >   [    4.525321] ACPI : EC: ***** Command(RD_EC) started *****
> >   [    4.525321] ACPI : EC: ===== TASK =====
> >   [    4.525326] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
> >   [    4.525327] ACPI : EC: EC_SC(W) = 0x80
> >   [    4.525436] ACPI : EC: ===== IRQ =====
> >   [    4.525442] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
> >   [    4.525442] ACPI : EC: EC_DATA(W) = 0x23
> >   [    4.525448] ACPI : EC: +++++ Polling enabled +++++
> >   [    4.525451] ACPI : EC: EC_SC(R) = 0x02 SCI_EVT=0 BURST=0 CMD=0 IBF=1 OBF=0
> > # [    4.528954] ACPI : EC: ===== TASK =====
> >   [    4.528957] ACPI : EC: EC_SC(R) = 0x01 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=1
> >   [    4.528960] ACPI : EC: EC_DATA(R) = 0x2b
> >   [    4.528963] ACPI : EC: +++++ Polling disabled +++++
> >   [    4.528964] ACPI : EC: ***** Command(RD_EC) stopped *****
> >   [    4.528974] ACPI : EC: ===== IRQ =====
> >   [    4.528977] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
> >   [    4.528980] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
> >   [    4.528988] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
> >   [    4.529347] ACPI : EC: ***** Command(WR_EC) started *****
> >   [    4.529348] ACPI : EC: ===== TASK =====
> >   [    4.529352] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
> >   [    4.529353] ACPI : EC: EC_SC(W) = 0x81
> > * [    4.529467] ACPI : EC: ===== IRQ =====
> >   [    4.529473] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
> >   [    4.529473] ACPI : EC: EC_DATA(W) = 0x04
> >   [    4.529479] ACPI : EC: +++++ Polling enabled +++++
> >   [    4.529482] ACPI : EC: EC_SC(R) = 0x02 SCI_EVT=0 BURST=0 CMD=0 IBF=1 OBF=0
> >   [    4.532951] ACPI : EC: ===== TASK =====
> >   [    4.532957] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
> >   [    4.532957] ACPI : EC: EC_DATA(W) = 0x01
> >   [    4.536952] ACPI : EC: ===== TASK =====
> >   [    4.536957] ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
> >   [    4.536964] ACPI : EC: +++++ Polling disabled +++++
> >   [    4.536965] ACPI : EC: ***** Command(WR_EC) stopped *****
> > We can see the command is advanced in the task context after enabling the
> > polling mode (#) and the next command can still be started from the high
> > performance IRQ mode (*).
> >
> > Signed-off-by: Lv Zheng <lv.zheng@intel.com>
> > ---
> >  drivers/acpi/ec.c |    6 +++++-
> >  1 file changed, 5 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
> > index d3b1bd7..f40144e 100644
> > --- a/drivers/acpi/ec.c
> > +++ b/drivers/acpi/ec.c
> > @@ -825,13 +825,17 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
> >  {
> >  	unsigned long flags;
> >  	struct acpi_ec *ec = data;
> > +	u32 enable = 0;
> >
> >  	spin_lock_irqsave(&ec->lock, flags);
> >  	if (advance_transaction(ec))
> >  		wake_up(&ec->wait);
> > +	if (!test_bit(EC_FLAGS_EVENT_STORM, &ec->flags) &&
> > +	    !test_bit(EC_FLAGS_COMMAND_STORM, &ec->flags))
> > +		enable = ACPI_REENABLE_GPE;
> >  	spin_unlock_irqrestore(&ec->lock, flags);
> >  	ec_check_sci(ec, acpi_ec_read_status(ec));
> > -	return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE;
> > +	return ACPI_INTERRUPT_HANDLED | enable;
> >  }
> >
> >  /* --------------------------------------------------------------------------
> 
> --
> ak@linux.intel.com -- Speaking for myself only

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention.
  2014-06-18  3:17 [PATCH 0/9] ACPI/EC: Improve GPE handling model Lv Zheng
                   ` (11 preceding siblings ...)
  2014-07-15  7:09 ` [PATCH v2] ACPI/EC: Enable storm prevention mechanisms Lv Zheng
@ 2014-07-21  6:04 ` Lv Zheng
  2014-07-21  6:05   ` [RFC PATCH v3 01/14] ACPI/EC: Introduce STARTED/STOPPED flags to replace BLOCKED flag Lv Zheng
                     ` (14 more replies)
  2015-02-05  8:24 ` [PATCH v4 0/6] ACPI / EC: Fix GPE handling related races Lv Zheng
  13 siblings, 15 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-21  6:04 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

Note that this patchset is very stable now, it is sent as RFC because it
depends on an ACPICA GPE enhancement series which might be merged from
ACPICA upstream.

This patchset is based on the previous ACPI/EC bug fixes series and the GPE
API enhancement series.

For the EC driver, GPE must be disabled to prevent the following storms:
1. Command errors:
   If there are too many IRQs coming during a command processing period and
   such IRQs are not related to the event (EVT_SCI),
   acpi_set_gpe(ACPI_GPE_DISABLE) is invoked to prevent further storms
   during the same command transaction. This is not implemented in a good
   style. Ideally, we should only enable storm prevention for the current
   command so that the next command can try the efficient interrupt mode
   again.
   This patchset enhances this storm prevention (PATCH 01, 03-04).
2. Event errors:
   There are cases that BIOS doesn't provide a _Qxx method for the returned
   xx query value, in this case, acpi_set_gpe(ACPI_GPE_DISABLE) need to be
   invoked to prevent event IRQ storms. This case is detected during the EC
   bug fix:
     https://bugzilla.kernel.org/show_bug.cgi?id=70891
   There is a dmesg showing a 0x0D query storm, for which there is no _Q0D
   method provided by the ACPI table to handle (comment 55), this becomes a
   GPE storm and slows down the machine a lot, it takes longer time for
   Linux to complete the bootup (comment 80).
   This patchset implements such storm prevention (PATCH 06-07 10-11),
   turning EC driver into the polling mode when the storm happens so that
   other tasks can be processed by the CPU without being affected by this
   GPE storm.
3. Pending events:
   Though GPE is edge triggered, the underlying firmware may maliciously
   trigger GPE when IRQ is indicated. This makes EC GPE more like a level
   triggered interrupt. In case of event (EVT_SCI), since the Linux EC
   driver responses it (using QR_EC command) in the task context with the
   GPE enabled, there are chances for a GPE storm to occur before QR_EC is
   executed.
   A common solution is to implement an IRQ context QR_EC issuing, this is
   also a must-take step to convert the EC GPE handler into the threaded
   IRQ model. The above bug link contains a prototype to achieve this, but
   it fails to pass the suspend/resume tests. And the reporter shows a case
   that user commands need to be executed while EVT_SCI is indicated
   because _Qxx method evaluation requires normal EC command to be executed
   by the EC driver to complete the event (EVT_SCI) handling. Without
   further investigation in ACPICA to see if this evaluation will block the
   event handler, it is better to keep the current proven task context
   style QR_EC issuing to allow user commands to compete with QR_EC to be
   executed. I'll try IRQ mode QR_EC issuing later using another patch
   series.
   If we still want to keep the task context responding logic, for such EC
   hardware/firmware, acpi_set_gpe(ACPI_GPE_DISABLE) should be invoked
   after EVT_SCI interrupt is indicated and acpi_set_gpe(ACPI_GPE_ENABLE)
   should be invoked before the first step of QR_EC has taken place.
   Since there is no real cases are reported, this patchset doesn't
   introduce such storm prevention, but only makes it possible to implement
   this for such platform by invoking acpi_enable_gpe() when EVT_SCI is
   detected and decreasing the GPE reference after QR_EC command is issued
   (PATCH 10), acpi_set_gpe() can be invoked between them as a quirk for
   such platforms. This facility has passed the unit tests of system
   suspend/resume flushing, in such cases all EC IRQs are polled by the
   task context waiters.

All of the above storm prevention supports are implemented using the ideal
GPE handling model provided by the previous GPE API enhancement series.

This patchset also contains an EC commands flushing support. By
implementing EC commands flushing, we now achieve an additional benefit:
Some EC driven ACPI devices may require all submitted EC commands to be
completed before they can be safely suspended or unplugged. Otherwise the
state of such devices will be broken.

The refined patches are also passed the runtime/suspend tests carried out
on the following platforms:
  "Dell Inspiron Mini 1010" - i386 kernel
  "Dell Latitude 6430u" - x86_64 kernel

This patchset also includes a unit test facility, I used it to test the
hotplug support code in the driver. It's useful for future EC development.

Lv Zheng (14):
  ACPI/EC: Introduce STARTED/STOPPED flags to replace BLOCKED flag.
  ACPI/EC: Add detailed command/query debugging information.
  ACPI/EC: Cleanup command storm prevention using the new GPE handling
    model.
  ACPI/EC: Refine command storm prevention support.
  ACPI/EC: Add reference counting for query handlers.
  ACPI/EC: Add command flushing support.
  ACPI/EC: Add a warning message to indicate event storms.
  ACPI/EC: Refine event/query debugging messages.
  ACPI/EC: Add CPU ID to debugging messages.
  ACPI/EC: Cleanup QR_SC command processing by adding a kernel thread
    to poll EC events.
  ACPI/EC: Add event storm prevention support.
  ACPI/EC: Add GPE reference counting debugging messages.
  ACPI/EC: Add unit test support for EC driver hotplug.
  ACPI/EC: Cleanup coding style.

 drivers/acpi/ec.c       |  566 ++++++++++++++++++++++++++++++++++++++---------
 drivers/acpi/internal.h |    3 +
 2 files changed, 462 insertions(+), 107 deletions(-)

-- 
1.7.10


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC PATCH v3 01/14] ACPI/EC: Introduce STARTED/STOPPED flags to replace BLOCKED flag.
  2014-07-21  6:04 ` [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
@ 2014-07-21  6:05   ` Lv Zheng
  2014-07-21  6:05   ` [RFC PATCH v3 02/14] ACPI/EC: Add detailed command/query debugging information Lv Zheng
                     ` (13 subsequent siblings)
  14 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-21  6:05 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

By using the 2 flags, we can indicate an inter-mediate state where the
current transactions should be completed while the new transactions should
be blocked.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   64 +++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 50 insertions(+), 14 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index a66ab65..28ce2cd 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -79,7 +79,8 @@ enum {
 	EC_FLAGS_GPE_STORM,		/* GPE storm detected */
 	EC_FLAGS_HANDLERS_INSTALLED,	/* Handlers for GPE and
 					 * OpReg are installed */
-	EC_FLAGS_BLOCKED,		/* Transactions are blocked */
+	EC_FLAGS_STARTED,		/* Driver is started */
+	EC_FLAGS_STOPPED,		/* Driver is stopped */
 };
 
 #define ACPI_EC_COMMAND_POLL		0x01 /* Available for command byte */
@@ -128,6 +129,16 @@ static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
 static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
 
 /* --------------------------------------------------------------------------
+                             Device Flags
+   -------------------------------------------------------------------------- */
+
+static bool acpi_ec_started(struct acpi_ec *ec)
+{
+	return test_bit(EC_FLAGS_STARTED, &ec->flags) &&
+	       !test_bit(EC_FLAGS_STOPPED, &ec->flags);
+}
+
+/* --------------------------------------------------------------------------
                              Transaction Management
    -------------------------------------------------------------------------- */
 
@@ -285,15 +296,24 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 		udelay(ACPI_EC_MSI_UDELAY);
 	/* start transaction */
 	spin_lock_irqsave(&ec->lock, tmp);
+	if (!acpi_ec_started(ec)) {
+		ret = -EINVAL;
+		goto unlock;
+	}
 	/* following two actions should be kept atomic */
 	ec->curr = t;
+	pr_debug("***** transaction started (cmd=0x%02x, addr=0x%02x) *****\n",
+		 t->command, t->wdata ? t->wdata[0] : 0);
 	start_transaction(ec);
 	if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
 		clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
 	spin_unlock_irqrestore(&ec->lock, tmp);
 	ret = ec_poll(ec);
 	spin_lock_irqsave(&ec->lock, tmp);
+	pr_debug("***** transaction stopped (cmd=0x%02x, addr=0x%02x) *****\n",
+		 t->command, t->wdata ? t->wdata[0] : 0);
 	ec->curr = NULL;
+unlock:
 	spin_unlock_irqrestore(&ec->lock, tmp);
 	return ret;
 }
@@ -307,10 +327,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
 	if (t->rdata)
 		memset(t->rdata, 0, t->rlen);
 	mutex_lock(&ec->mutex);
-	if (test_bit(EC_FLAGS_BLOCKED, &ec->flags)) {
-		status = -EINVAL;
-		goto unlock;
-	}
 	if (ec->global_lock) {
 		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
 		if (ACPI_FAILURE(status)) {
@@ -318,8 +334,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
 			goto unlock;
 		}
 	}
-	pr_debug("transaction start (cmd=0x%02x, addr=0x%02x)\n",
-			t->command, t->wdata ? t->wdata[0] : 0);
 	/* disable GPE during transaction if storm is detected */
 	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
 		/* It has to be disabled, so that it doesn't trigger. */
@@ -340,7 +354,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
 			t->irq_count);
 		set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
 	}
-	pr_debug("transaction end\n");
 	if (ec->global_lock)
 		acpi_release_global_lock(glk);
 unlock:
@@ -470,6 +483,29 @@ static void acpi_ec_clear(struct acpi_ec *ec)
 		pr_info("%d stale EC events cleared\n", i);
 }
 
+static void acpi_ec_start(struct acpi_ec *ec)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ec->lock, flags);
+	if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags))
+		acpi_enable_gpe(NULL, ec->gpe);
+	spin_unlock_irqrestore(&ec->lock, flags);
+}
+
+static void acpi_ec_stop(struct acpi_ec *ec)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ec->lock, flags);
+	if (acpi_ec_started(ec)) {
+		acpi_disable_gpe(NULL, ec->gpe);
+		clear_bit(EC_FLAGS_STARTED, &ec->flags);
+		clear_bit(EC_FLAGS_STOPPED, &ec->flags);
+	}
+	spin_unlock_irqrestore(&ec->lock, flags);
+}
+
 void acpi_ec_block_transactions(void)
 {
 	struct acpi_ec *ec = first_ec;
@@ -479,7 +515,7 @@ void acpi_ec_block_transactions(void)
 
 	mutex_lock(&ec->mutex);
 	/* Prevent transactions from being carried out */
-	set_bit(EC_FLAGS_BLOCKED, &ec->flags);
+	acpi_ec_stop(ec);
 	mutex_unlock(&ec->mutex);
 }
 
@@ -492,7 +528,7 @@ void acpi_ec_unblock_transactions(void)
 
 	mutex_lock(&ec->mutex);
 	/* Allow transactions to be carried out again */
-	clear_bit(EC_FLAGS_BLOCKED, &ec->flags);
+	acpi_ec_start(ec);
 
 	if (EC_FLAGS_CLEAR_ON_RESUME)
 		acpi_ec_clear(ec);
@@ -507,7 +543,7 @@ void acpi_ec_unblock_transactions_early(void)
 	 * atomic context during wakeup, so we don't need to acquire the mutex).
 	 */
 	if (first_ec)
-		clear_bit(EC_FLAGS_BLOCKED, &first_ec->flags);
+		acpi_ec_start(first_ec);
 }
 
 static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data)
@@ -774,7 +810,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
-	acpi_enable_gpe(NULL, ec->gpe);
+	acpi_ec_start(ec);
 	status = acpi_install_address_space_handler(ec->handle,
 						    ACPI_ADR_SPACE_EC,
 						    &acpi_ec_space_handler,
@@ -789,7 +825,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
 			pr_err("Fail in evaluating the _REG object"
 				" of EC device. Broken bios is suspected.\n");
 		} else {
-			acpi_disable_gpe(NULL, ec->gpe);
+			acpi_ec_stop(ec);
 			acpi_remove_gpe_handler(NULL, ec->gpe,
 				&acpi_ec_gpe_handler);
 			return -ENODEV;
@@ -802,10 +838,10 @@ static int ec_install_handlers(struct acpi_ec *ec)
 
 static void ec_remove_handlers(struct acpi_ec *ec)
 {
-	acpi_disable_gpe(NULL, ec->gpe);
 	if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
 				ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
 		pr_err("failed to remove space handler\n");
+	acpi_ec_stop(ec);
 	if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
 				&acpi_ec_gpe_handler)))
 		pr_err("failed to remove gpe handler\n");
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [RFC PATCH v3 02/14] ACPI/EC: Add detailed command/query debugging information.
  2014-07-21  6:04 ` [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
  2014-07-21  6:05   ` [RFC PATCH v3 01/14] ACPI/EC: Introduce STARTED/STOPPED flags to replace BLOCKED flag Lv Zheng
@ 2014-07-21  6:05   ` Lv Zheng
  2014-07-21  6:05   ` [RFC PATCH v3 03/14] ACPI/EC: Cleanup command storm prevention using the new GPE handling model Lv Zheng
                     ` (12 subsequent siblings)
  14 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-21  6:05 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

Developers really don't need to translate EC commands in mind. This patch
adds detailed debugging information for the EC commands.
The address can be found in the follow-up sequential EC_DATA(W) accesses,
thus this patch also removes some of the redundant address information.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   29 +++++++++++++++++++++++++----
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 28ce2cd..54bebbb 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -175,6 +175,27 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
 	outb(data, ec->data_addr);
 }
 
+#ifdef DEBUG
+static const char *acpi_ec_cmd_string(u8 cmd)
+{
+	switch (cmd) {
+	case 0x80:
+		return "RD_EC";
+	case 0x81:
+		return "WR_EC";
+	case 0x82:
+		return "BE_EC";
+	case 0x83:
+		return "BD_EC";
+	case 0x84:
+		return "QR_EC";
+	}
+	return "UNKNOWN";
+}
+#else
+#define acpi_ec_cmd_string(cmd)		"UNDEF"
+#endif
+
 static int ec_transaction_completed(struct acpi_ec *ec)
 {
 	unsigned long flags;
@@ -302,16 +323,16 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 	}
 	/* following two actions should be kept atomic */
 	ec->curr = t;
-	pr_debug("***** transaction started (cmd=0x%02x, addr=0x%02x) *****\n",
-		 t->command, t->wdata ? t->wdata[0] : 0);
+	pr_debug("***** Command(%s) started *****\n",
+		 acpi_ec_cmd_string(t->command));
 	start_transaction(ec);
 	if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
 		clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
 	spin_unlock_irqrestore(&ec->lock, tmp);
 	ret = ec_poll(ec);
 	spin_lock_irqsave(&ec->lock, tmp);
-	pr_debug("***** transaction stopped (cmd=0x%02x, addr=0x%02x) *****\n",
-		 t->command, t->wdata ? t->wdata[0] : 0);
+	pr_debug("***** Command(%s) stopped *****\n",
+		 acpi_ec_cmd_string(t->command));
 	ec->curr = NULL;
 unlock:
 	spin_unlock_irqrestore(&ec->lock, tmp);
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [RFC PATCH v3 03/14] ACPI/EC: Cleanup command storm prevention using the new GPE handling model.
  2014-07-21  6:04 ` [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
  2014-07-21  6:05   ` [RFC PATCH v3 01/14] ACPI/EC: Introduce STARTED/STOPPED flags to replace BLOCKED flag Lv Zheng
  2014-07-21  6:05   ` [RFC PATCH v3 02/14] ACPI/EC: Add detailed command/query debugging information Lv Zheng
@ 2014-07-21  6:05   ` Lv Zheng
  2014-07-21  6:05   ` [RFC PATCH v3 04/14] ACPI/EC: Refine command storm prevention support Lv Zheng
                     ` (11 subsequent siblings)
  14 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-21  6:05 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch deploys the following GPE handling model:
1. acpi_enable_gpe()/acpi_disable_gpe():
   This set of APIs are used for EC usage reference counting.
2. acpi_set_gpe(ACPI_GPE_ENABLE)/acpi_set_gpe(ACPI_GPE_DISABLE):
   This set of APIs are used for preventing GPE storm.
Note that this patch only converts current storm prevention implementations
using new APIs without correcting them.

For the EC driver, GPE is enabled for the following users:
1. Event monitoring (HW exception):
   If we want to query events in interrupt mode, acpi_enable_gpe() is
   invoked to allow EVT_SCI IRQs.
2. Command processing (IO request):
   When we receive an upper layer command submission, acpi_enable_gpe() is
   invoked to allow IBF=0,OBF=1 IRQs.
Comments are updated to reflect this model.

For the EC driver, GPE must be disabled for the following storms:
1. Command errors:
   If there are too many IRQs coming during a command processing period and
   such IRQs are not related to the event (EVT_SCI),
   acpi_set_gpe(ACPI_GPE_DISABLE) is invoked to prevent further storms
   during the same command transaction. This is not implemented in a good
   style. Currently once command storming is detected, it is enabled for
   all follow-up commands. Ideally, we should only enable storm prevention
   for the current command so that the next command can try the efficient
   interrupt mode again.
   This patch doesn't change current logic, the correction will be
   implemented by further patches.
2. Event errors:
   There are cases that BIOS doesn't provide a _Qxx method for the returned
   xx query value, in this case, acpi_set_gpe(ACPI_GPE_DISABLE) need to be
   invoked to prevent event IRQ storms.
   This patch doesn't implement this logic, such gap will be implemented by
   further patches.
3. Pending events:
   Though GPE is edge triggered, the underlying firmware may maliciously
   trigger GPE when IRQ is indicated. This makes EC GPE more like a level
   triggered interrupt. In case of event (EVT_SCI), since the Linux EC
   driver responses it (using QR_EC command) in the task context with GPE
   enabled, there are chances for a GPE storm to occur before QR_EC is
   executed.
   If we still want to keep the task context responding logic, for such EC
   hardware/firmware, acpi_set_gpe(ACPI_GPE_DISABLE) should be invoked
   after EVT_SCI interrupt is indicated and acpi_set_gpe(ACPI_GPE_ENABLE)
   should be invoked before the first step of QR_EC has taken place.
   This patch doesn't implement this logic, such gap can be implemented by
   future patches.

The acpi_set_gpe() should be invoked for an outstanding command,
which means it should be invoked inside of a pair of acpi_enable_gpe()/
acpi_disable_gpe() invocation. This patch thus also moves the storm
prevention logic into acpi_ec_transaction_unlocked(). Note that in order to
make it working, ACPI_REENABLE_GPE should be unset when the storming is
indicated.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   45 ++++++++++++++++++++++++++++-----------------
 1 file changed, 28 insertions(+), 17 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 54bebbb..4c7a81b 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -321,19 +321,35 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 		ret = -EINVAL;
 		goto unlock;
 	}
+	/* Enable GPE for command processing (IBF=0/OBF=1) */
+	acpi_enable_gpe(NULL, ec->gpe);
 	/* following two actions should be kept atomic */
 	ec->curr = t;
 	pr_debug("***** Command(%s) started *****\n",
 		 acpi_ec_cmd_string(t->command));
+	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
+		pr_debug("+++++ Polling enabled +++++\n");
+		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
+	}
 	start_transaction(ec);
 	if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
 		clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
 	spin_unlock_irqrestore(&ec->lock, tmp);
 	ret = ec_poll(ec);
 	spin_lock_irqsave(&ec->lock, tmp);
+	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
+		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
+		pr_debug("+++++ Polling disabled +++++\n");
+	} else if (t->irq_count > ec_storm_threshold) {
+		pr_debug("+++++ Polling scheduled (%d GPE) +++++\n",
+			 t->irq_count);
+		set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
+	}
 	pr_debug("***** Command(%s) stopped *****\n",
 		 acpi_ec_cmd_string(t->command));
 	ec->curr = NULL;
+	/* Disable GPE for command processing (IBF=0/OBF=1) */
+	acpi_disable_gpe(NULL, ec->gpe);
 unlock:
 	spin_unlock_irqrestore(&ec->lock, tmp);
 	return ret;
@@ -355,26 +371,11 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
 			goto unlock;
 		}
 	}
-	/* disable GPE during transaction if storm is detected */
-	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
-		/* It has to be disabled, so that it doesn't trigger. */
-		acpi_disable_gpe(NULL, ec->gpe);
-	}
 
 	status = acpi_ec_transaction_unlocked(ec, t);
 
 	/* check if we received SCI during transaction */
 	ec_check_sci_sync(ec, acpi_ec_read_status(ec));
-	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
-		msleep(1);
-		/* It is safe to enable the GPE outside of the transaction. */
-		acpi_enable_gpe(NULL, ec->gpe);
-	} else if (t->irq_count > ec_storm_threshold) {
-		pr_info("GPE storm detected(%d GPEs), "
-			"transactions will use polling mode\n",
-			t->irq_count);
-		set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
-	}
 	if (ec->global_lock)
 		acpi_release_global_lock(glk);
 unlock:
@@ -509,8 +510,12 @@ static void acpi_ec_start(struct acpi_ec *ec)
 	unsigned long flags;
 
 	spin_lock_irqsave(&ec->lock, flags);
-	if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags))
+	if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags)) {
+		pr_debug("+++++ Starting EC +++++\n");
+		/* Enable GPE for event processing (EVT_SCI=1) */
 		acpi_enable_gpe(NULL, ec->gpe);
+		pr_info("+++++ EC started +++++\n");
+	}
 	spin_unlock_irqrestore(&ec->lock, flags);
 }
 
@@ -520,9 +525,12 @@ static void acpi_ec_stop(struct acpi_ec *ec)
 
 	spin_lock_irqsave(&ec->lock, flags);
 	if (acpi_ec_started(ec)) {
+		pr_debug("+++++ Stopping EC +++++\n");
+		/* Disable GPE for event processing (EVT_SCI=1) */
 		acpi_disable_gpe(NULL, ec->gpe);
 		clear_bit(EC_FLAGS_STARTED, &ec->flags);
 		clear_bit(EC_FLAGS_STOPPED, &ec->flags);
+		pr_info("+++++ EC stopped +++++\n");
 	}
 	spin_unlock_irqrestore(&ec->lock, flags);
 }
@@ -699,13 +707,16 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
 {
 	unsigned long flags;
 	struct acpi_ec *ec = data;
+	u32 enable = 0;
 
 	spin_lock_irqsave(&ec->lock, flags);
 	if (advance_transaction(ec))
 		wake_up(&ec->wait);
+	if (!test_bit(EC_FLAGS_GPE_STORM, &ec->flags))
+		enable = ACPI_REENABLE_GPE;
 	spin_unlock_irqrestore(&ec->lock, flags);
 	ec_check_sci(ec, acpi_ec_read_status(ec));
-	return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE;
+	return ACPI_INTERRUPT_HANDLED | enable;
 }
 
 /* --------------------------------------------------------------------------
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [RFC PATCH v3 04/14] ACPI/EC: Refine command storm prevention support.
  2014-07-21  6:04 ` [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
                     ` (2 preceding siblings ...)
  2014-07-21  6:05   ` [RFC PATCH v3 03/14] ACPI/EC: Cleanup command storm prevention using the new GPE handling model Lv Zheng
@ 2014-07-21  6:05   ` Lv Zheng
  2014-07-21  6:05   ` [RFC PATCH v3 05/14] ACPI/EC: Add reference counting for query handlers Lv Zheng
                     ` (10 subsequent siblings)
  14 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-21  6:05 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch refines EC command storm prevention support.

After applying the race fixes series, we almost cannot see any
in-transaction false irqs. The out-transaction false irqs are normal, they
are triggered by EC firmware for various reasons and will become silent
sooner or later. So the out-transaction false irqs are not accounted in the
original EC driver.

The EC commands are handled by different firmware processes, storming
happening to one command doesn't mean anything to another process. So
ideally, we should only enable storm prevention for the current command so
that the next command can try the efficient interrupt mode again.

This patch improves the command storm prevention by disabling GPE right
after the detection and re-enabling it right before completing the command
transaction using the GPE storming prevention APIs.

Though now we can hardly see false irqs, unit tests can be carried out by
changing the storm threshold to 0 and deleting the 2 "return wakeup"
statements from the advance_transaction(). The test result is as follows:
  ACPI : EC: ***** Command(RD_EC) started *****
  ACPI : EC: ===== TASK =====
  ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
  ACPI : EC: EC_SC(W) = 0x80
  ACPI : EC: ===== IRQ =====
  ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
  ACPI : EC: EC_DATA(W) = 0x23
  ACPI : EC: +++++ Polling enabled +++++
  ACPI : EC: EC_SC(R) = 0x02 SCI_EVT=0 BURST=0 CMD=0 IBF=1 OBF=0
# ACPI : EC: ===== TASK =====
  ACPI : EC: EC_SC(R) = 0x01 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=1
  ACPI : EC: EC_DATA(R) = 0x2b
  ACPI : EC: +++++ Polling disabled +++++
  ACPI : EC: ***** Command(RD_EC) stopped *****
  ACPI : EC: ===== IRQ =====
  ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
  ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
  ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
  ACPI : EC: ***** Command(WR_EC) started *****
  ACPI : EC: ===== TASK =====
  ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
  ACPI : EC: EC_SC(W) = 0x81
* ACPI : EC: ===== IRQ =====
  ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
  ACPI : EC: EC_DATA(W) = 0x04
  ACPI : EC: +++++ Polling enabled +++++
  ACPI : EC: EC_SC(R) = 0x02 SCI_EVT=0 BURST=0 CMD=0 IBF=1 OBF=0
  ACPI : EC: ===== TASK =====
  ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
  ACPI : EC: EC_DATA(W) = 0x01
  ACPI : EC: ===== TASK =====
  ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
  ACPI : EC: +++++ Polling disabled +++++
  ACPI : EC: ***** Command(WR_EC) stopped *****
We can see the command is advanced in the task context after enabling the
polling mode (#) and the next command can still be started from the high
performance IRQ mode (*).

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   55 +++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 39 insertions(+), 16 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 4c7a81b..1c3704c 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -76,11 +76,12 @@ enum ec_command {
 
 enum {
 	EC_FLAGS_QUERY_PENDING,		/* Query is pending */
-	EC_FLAGS_GPE_STORM,		/* GPE storm detected */
 	EC_FLAGS_HANDLERS_INSTALLED,	/* Handlers for GPE and
 					 * OpReg are installed */
 	EC_FLAGS_STARTED,		/* Driver is started */
 	EC_FLAGS_STOPPED,		/* Driver is stopped */
+	EC_FLAGS_COMMAND_STORM,		/* GPE storms occurred to the
+					 * current command processing */
 };
 
 #define ACPI_EC_COMMAND_POLL		0x01 /* Available for command byte */
@@ -138,6 +139,33 @@ static bool acpi_ec_started(struct acpi_ec *ec)
 	       !test_bit(EC_FLAGS_STOPPED, &ec->flags);
 }
 
+static bool acpi_ec_has_gpe_storm(struct acpi_ec *ec)
+{
+	return test_bit(EC_FLAGS_COMMAND_STORM, &ec->flags);
+}
+
+/* --------------------------------------------------------------------------
+                             GPE Enhancement
+   -------------------------------------------------------------------------- */
+
+static void acpi_ec_set_storm(struct acpi_ec *ec, u8 flag)
+{
+	if (!test_bit(flag, &ec->flags)) {
+		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
+		pr_debug("+++++ Polling enabled +++++\n");
+		set_bit(flag, &ec->flags);
+	}
+}
+
+static void acpi_ec_clear_storm(struct acpi_ec *ec, u8 flag)
+{
+	if (test_bit(flag, &ec->flags)) {
+		clear_bit(flag, &ec->flags);
+		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
+		pr_debug("+++++ Polling disabled +++++\n");
+	}
+}
+
 /* --------------------------------------------------------------------------
                              Transaction Management
    -------------------------------------------------------------------------- */
@@ -253,8 +281,13 @@ err:
 	 * otherwise will take a not handled IRQ as a false one.
 	 */
 	if (!(status & ACPI_EC_FLAG_SCI)) {
-		if (in_interrupt() && t)
-			++t->irq_count;
+		if (in_interrupt() && t) {
+			if (t->irq_count < ec_storm_threshold)
+				++t->irq_count;
+			/* Allow triggering on 0 threshold */
+			if (t->irq_count == ec_storm_threshold)
+				acpi_ec_set_storm(ec, EC_FLAGS_COMMAND_STORM);
+		}
 	}
 	return wakeup;
 }
@@ -327,24 +360,14 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 	ec->curr = t;
 	pr_debug("***** Command(%s) started *****\n",
 		 acpi_ec_cmd_string(t->command));
-	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
-		pr_debug("+++++ Polling enabled +++++\n");
-		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
-	}
 	start_transaction(ec);
 	if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
 		clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
 	spin_unlock_irqrestore(&ec->lock, tmp);
 	ret = ec_poll(ec);
 	spin_lock_irqsave(&ec->lock, tmp);
-	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
-		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
-		pr_debug("+++++ Polling disabled +++++\n");
-	} else if (t->irq_count > ec_storm_threshold) {
-		pr_debug("+++++ Polling scheduled (%d GPE) +++++\n",
-			 t->irq_count);
-		set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
-	}
+	if (t->irq_count == ec_storm_threshold)
+		acpi_ec_clear_storm(ec, EC_FLAGS_COMMAND_STORM);
 	pr_debug("***** Command(%s) stopped *****\n",
 		 acpi_ec_cmd_string(t->command));
 	ec->curr = NULL;
@@ -712,7 +735,7 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
 	spin_lock_irqsave(&ec->lock, flags);
 	if (advance_transaction(ec))
 		wake_up(&ec->wait);
-	if (!test_bit(EC_FLAGS_GPE_STORM, &ec->flags))
+	if (!acpi_ec_has_gpe_storm(ec))
 		enable = ACPI_REENABLE_GPE;
 	spin_unlock_irqrestore(&ec->lock, flags);
 	ec_check_sci(ec, acpi_ec_read_status(ec));
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [RFC PATCH v3 05/14] ACPI/EC: Add reference counting for query handlers.
  2014-07-21  6:04 ` [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
                     ` (3 preceding siblings ...)
  2014-07-21  6:05   ` [RFC PATCH v3 04/14] ACPI/EC: Refine command storm prevention support Lv Zheng
@ 2014-07-21  6:05   ` Lv Zheng
  2014-07-21  6:05   ` [RFC PATCH v3 06/14] ACPI/EC: Add command flushing support Lv Zheng
                     ` (9 subsequent siblings)
  14 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-21  6:05 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds reference counting for query handlers in order to eliminate
kmalloc()/kfree() usage.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Tested-by: Steffen Weber <steffen.weber@gmail.com>
---
 drivers/acpi/ec.c |   46 ++++++++++++++++++++++++++++++++++++----------
 1 file changed, 36 insertions(+), 10 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 1c3704c..8195cd6 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -107,6 +107,7 @@ struct acpi_ec_query_handler {
 	acpi_handle handle;
 	void *data;
 	u8 query_bit;
+	struct kref kref;
 };
 
 struct transaction {
@@ -121,6 +122,10 @@ struct transaction {
 	u8 flags;
 };
 
+static struct acpi_ec_query_handler *
+acpi_ec_get_query_handler(struct acpi_ec_query_handler *handler);
+static void acpi_ec_put_query_handler(struct acpi_ec_query_handler *handler);
+
 struct acpi_ec *boot_ec, *first_ec;
 EXPORT_SYMBOL(first_ec);
 
@@ -624,6 +629,26 @@ static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data)
 /* --------------------------------------------------------------------------
                                 Event Management
    -------------------------------------------------------------------------- */
+static struct acpi_ec_query_handler *
+acpi_ec_get_query_handler(struct acpi_ec_query_handler *handler)
+{
+	if (handler)
+		kref_get(&handler->kref);
+	return handler;
+}
+
+static void acpi_ec_query_handler_release(struct kref *kref)
+{
+	struct acpi_ec_query_handler *handler =
+		container_of(kref, struct acpi_ec_query_handler, kref);
+	kfree(handler);
+}
+
+static void acpi_ec_put_query_handler(struct acpi_ec_query_handler *handler)
+{
+	kref_put(&handler->kref, acpi_ec_query_handler_release);
+}
+
 int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
 			      acpi_handle handle, acpi_ec_query_func func,
 			      void *data)
@@ -638,6 +663,7 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
 	handler->func = func;
 	handler->data = data;
 	mutex_lock(&ec->mutex);
+	kref_init(&handler->kref);
 	list_add(&handler->node, &ec->list);
 	mutex_unlock(&ec->mutex);
 	return 0;
@@ -648,14 +674,17 @@ EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler);
 void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
 {
 	struct acpi_ec_query_handler *handler, *tmp;
+	LIST_HEAD(free_list);
 	mutex_lock(&ec->mutex);
 	list_for_each_entry_safe(handler, tmp, &ec->list, node) {
 		if (query_bit == handler->query_bit) {
-			list_del(&handler->node);
-			kfree(handler);
+			list_del_init(&handler->node);
+			list_add(&handler->node, &free_list);
 		}
 	}
 	mutex_unlock(&ec->mutex);
+	list_for_each_entry(handler, &free_list, node)
+		acpi_ec_put_query_handler(handler);
 }
 
 EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
@@ -671,14 +700,14 @@ static void acpi_ec_run(void *cxt)
 	else if (handler->handle)
 		acpi_evaluate_object(handler->handle, NULL, NULL, NULL);
 	pr_debug("stop query execution\n");
-	kfree(handler);
+	acpi_ec_put_query_handler(handler);
 }
 
 static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data)
 {
 	u8 value = 0;
 	int status;
-	struct acpi_ec_query_handler *handler, *copy;
+	struct acpi_ec_query_handler *handler;
 
 	status = acpi_ec_query_unlocked(ec, &value);
 	if (data)
@@ -689,15 +718,12 @@ static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data)
 	list_for_each_entry(handler, &ec->list, node) {
 		if (value == handler->query_bit) {
 			/* have custom handler for this bit */
-			copy = kmalloc(sizeof(*handler), GFP_KERNEL);
-			if (!copy)
-				return -ENOMEM;
-			memcpy(copy, handler, sizeof(*copy));
+			handler = acpi_ec_get_query_handler(handler);
 			pr_debug("push query execution (0x%2x) on queue\n",
 				value);
-			return acpi_os_execute((copy->func) ?
+			return acpi_os_execute((handler->func) ?
 				OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER,
-				acpi_ec_run, copy);
+				acpi_ec_run, handler);
 		}
 	}
 	return 0;
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [RFC PATCH v3 06/14] ACPI/EC: Add command flushing support.
  2014-07-21  6:04 ` [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
                     ` (4 preceding siblings ...)
  2014-07-21  6:05   ` [RFC PATCH v3 05/14] ACPI/EC: Add reference counting for query handlers Lv Zheng
@ 2014-07-21  6:05   ` Lv Zheng
  2014-07-21  6:05   ` [RFC PATCH v3 07/14] ACPI/EC: Add a warning message to indicate event storms Lv Zheng
                     ` (8 subsequent siblings)
  14 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-21  6:05 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch implements command flushing support. It's better to wait all
command transactions to be completed before disabling the EC GPE when the
system is going to be suspended. By doing so, the EC hardware can be
ensured to be in the idle state when the system is resumed.

There is a good indicator for flush support:
All acpi_ec_enable_gpe() is invoked after checking driver state with
acpi_ec_started() except the first one. This means all code paths can be
flushed as fast as possible by discarding the requests occurred after the
flush operation. This kind of GPE enabling is wrapped by
acpi_ec_enable_gpe_flushable().

The system suspending/resuming test result is as follows:
  ACPI : EC: +++++ Stopping EC +++++
* ACPI : EC: +++++ EC stopped +++++
  ACPI : EC: +++++ Starting EC +++++
# ACPI : EC: +++++ EC started +++++
This is performed by "switching wireless switch on/off" and "plugging power
cord in/out" frequently during the suspending/resuming. The above dmesg
shows that the EC driver is stopped during suspending (*) and is restarted
during resuming (#) correctly.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c       |   66 ++++++++++++++++++++++++++++++++++++++++++-----
 drivers/acpi/internal.h |    1 +
 2 files changed, 61 insertions(+), 6 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 8195cd6..c8d205c 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -171,6 +171,46 @@ static void acpi_ec_clear_storm(struct acpi_ec *ec, u8 flag)
 	}
 }
 
+static bool acpi_ec_flushed(struct acpi_ec *ec)
+{
+	return ec->reference_count == 1;
+}
+
+static void acpi_ec_enable_gpe(struct acpi_ec *ec)
+{
+	acpi_enable_gpe(NULL, ec->gpe);
+	ec->reference_count++;
+}
+
+static void acpi_ec_disable_gpe(struct acpi_ec *ec)
+{
+	bool flushed = false;
+
+	ec->reference_count--;
+	acpi_disable_gpe(NULL, ec->gpe);
+	flushed = acpi_ec_flushed(ec);
+	if (flushed)
+		wake_up(&ec->wait);
+}
+
+/*
+ * acpi_ec_enable_gpe_flushable() - Increase the flushable GPE reference
+ * @ec: the EC device
+ *
+ * This function must be used for the references of the operations that can
+ * be flushed, i.e., all references other than the first reference which is
+ * is reversely decreased after the flush operation must be increased using
+ * this flush safe API so that flushable operations occurred after the
+ * flush will not be initiated.
+ */
+static bool acpi_ec_enable_gpe_flushable(struct acpi_ec *ec)
+{
+	if (!acpi_ec_started(ec))
+		return false;
+	acpi_ec_enable_gpe(ec);
+	return true;
+}
+
 /* --------------------------------------------------------------------------
                              Transaction Management
    -------------------------------------------------------------------------- */
@@ -355,12 +395,11 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 		udelay(ACPI_EC_MSI_UDELAY);
 	/* start transaction */
 	spin_lock_irqsave(&ec->lock, tmp);
-	if (!acpi_ec_started(ec)) {
+	/* Enable GPE for command processing (IBF=0/OBF=1) */
+	if (!acpi_ec_enable_gpe_flushable(ec)) {
 		ret = -EINVAL;
 		goto unlock;
 	}
-	/* Enable GPE for command processing (IBF=0/OBF=1) */
-	acpi_enable_gpe(NULL, ec->gpe);
 	/* following two actions should be kept atomic */
 	ec->curr = t;
 	pr_debug("***** Command(%s) started *****\n",
@@ -377,7 +416,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 		 acpi_ec_cmd_string(t->command));
 	ec->curr = NULL;
 	/* Disable GPE for command processing (IBF=0/OBF=1) */
-	acpi_disable_gpe(NULL, ec->gpe);
+	acpi_ec_disable_gpe(ec);
 unlock:
 	spin_unlock_irqrestore(&ec->lock, tmp);
 	return ret;
@@ -541,12 +580,24 @@ static void acpi_ec_start(struct acpi_ec *ec)
 	if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags)) {
 		pr_debug("+++++ Starting EC +++++\n");
 		/* Enable GPE for event processing (EVT_SCI=1) */
-		acpi_enable_gpe(NULL, ec->gpe);
+		acpi_ec_enable_gpe(ec);
 		pr_info("+++++ EC started +++++\n");
 	}
 	spin_unlock_irqrestore(&ec->lock, flags);
 }
 
+static bool acpi_ec_stopped(struct acpi_ec *ec)
+{
+	unsigned long flags;
+	bool flushed;
+
+	spin_lock_irqsave(&ec->lock, flags);
+	flushed = acpi_ec_flushed(ec);
+	spin_unlock_irqrestore(&ec->lock, flags);
+
+	return flushed;
+}
+
 static void acpi_ec_stop(struct acpi_ec *ec)
 {
 	unsigned long flags;
@@ -554,8 +605,11 @@ static void acpi_ec_stop(struct acpi_ec *ec)
 	spin_lock_irqsave(&ec->lock, flags);
 	if (acpi_ec_started(ec)) {
 		pr_debug("+++++ Stopping EC +++++\n");
+		spin_unlock_irqrestore(&ec->lock, flags);
+		wait_event(ec->wait, acpi_ec_stopped(ec));
+		spin_lock_irqsave(&ec->lock, flags);
 		/* Disable GPE for event processing (EVT_SCI=1) */
-		acpi_disable_gpe(NULL, ec->gpe);
+		acpi_ec_disable_gpe(ec);
 		clear_bit(EC_FLAGS_STARTED, &ec->flags);
 		clear_bit(EC_FLAGS_STOPPED, &ec->flags);
 		pr_info("+++++ EC stopped +++++\n");
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 151f3e7..2348f9c 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -118,6 +118,7 @@ struct acpi_ec {
 	unsigned long data_addr;
 	unsigned long global_lock;
 	unsigned long flags;
+	unsigned long reference_count;
 	struct mutex mutex;
 	wait_queue_head_t wait;
 	struct list_head list;
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [RFC PATCH v3 07/14] ACPI/EC: Add a warning message to indicate event storms.
  2014-07-21  6:04 ` [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
                     ` (5 preceding siblings ...)
  2014-07-21  6:05   ` [RFC PATCH v3 06/14] ACPI/EC: Add command flushing support Lv Zheng
@ 2014-07-21  6:05   ` Lv Zheng
  2014-07-21  6:05   ` [RFC PATCH v3 08/14] ACPI/EC: Refine event/query debugging messages Lv Zheng
                     ` (7 subsequent siblings)
  14 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-21  6:05 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch splits query handler scheduling into a new seperate function
acpi_ec_notify_query_handlers() and adds a warning message in it to
indicate a BIOS bug. It is reported that EC event storm can happen in case
there is no _Qxx method prepared for the event. No functional changes.

Reference: https://bugzilla.kernel.org/show_bug.cgi?id=78091
Reported-by: Steffen Weber <steffen.weber@gmail.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   29 ++++++++++++++++++-----------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index c8d205c..81f4b17 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -757,32 +757,39 @@ static void acpi_ec_run(void *cxt)
 	acpi_ec_put_query_handler(handler);
 }
 
-static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data)
+static int acpi_ec_notify_query_handlers(struct acpi_ec *ec, u8 query_bit)
 {
-	u8 value = 0;
-	int status;
 	struct acpi_ec_query_handler *handler;
 
-	status = acpi_ec_query_unlocked(ec, &value);
-	if (data)
-		*data = value;
-	if (status)
-		return status;
-
 	list_for_each_entry(handler, &ec->list, node) {
-		if (value == handler->query_bit) {
+		if (query_bit == handler->query_bit) {
 			/* have custom handler for this bit */
 			handler = acpi_ec_get_query_handler(handler);
 			pr_debug("push query execution (0x%2x) on queue\n",
-				value);
+				 query_bit);
 			return acpi_os_execute((handler->func) ?
 				OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER,
 				acpi_ec_run, handler);
 		}
 	}
+	pr_warn_once("BIOS bug: no handler for query (0x%02x)\n", query_bit);
 	return 0;
 }
 
+static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data)
+{
+	u8 value = 0;
+	int status;
+
+	status = acpi_ec_query_unlocked(ec, &value);
+	if (data)
+		*data = value;
+	if (status)
+		return status;
+
+	return acpi_ec_notify_query_handlers(ec, value);
+}
+
 static void acpi_ec_gpe_query(void *ec_cxt)
 {
 	struct acpi_ec *ec = ec_cxt;
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [RFC PATCH v3 08/14] ACPI/EC: Refine event/query debugging messages.
  2014-07-21  6:04 ` [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
                     ` (6 preceding siblings ...)
  2014-07-21  6:05   ` [RFC PATCH v3 07/14] ACPI/EC: Add a warning message to indicate event storms Lv Zheng
@ 2014-07-21  6:05   ` Lv Zheng
  2014-07-21  6:06   ` [RFC PATCH v3 09/14] ACPI/EC: Add CPU ID to " Lv Zheng
                     ` (6 subsequent siblings)
  14 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-21  6:05 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch refines event/query debugging messages to use a unified format
as commands. Developers can clearly find different processes by checking
different log seperators. No functional changes.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 81f4b17..a729f31 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -405,8 +405,10 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 	pr_debug("***** Command(%s) started *****\n",
 		 acpi_ec_cmd_string(t->command));
 	start_transaction(ec);
-	if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
+	if (ec->curr->command == ACPI_EC_COMMAND_QUERY) {
 		clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
+		pr_debug("***** Event stopped *****\n");
+	}
 	spin_unlock_irqrestore(&ec->lock, tmp);
 	ret = ec_poll(ec);
 	spin_lock_irqsave(&ec->lock, tmp);
@@ -748,12 +750,12 @@ static void acpi_ec_run(void *cxt)
 	struct acpi_ec_query_handler *handler = cxt;
 	if (!handler)
 		return;
-	pr_debug("start query execution\n");
+	pr_debug("##### Query(0x%02x) started #####\n", handler->query_bit);
 	if (handler->func)
 		handler->func(handler->data);
 	else if (handler->handle)
 		acpi_evaluate_object(handler->handle, NULL, NULL, NULL);
-	pr_debug("stop query execution\n");
+	pr_debug("##### Query(0x%02x) stopped #####\n", handler->query_bit);
 	acpi_ec_put_query_handler(handler);
 }
 
@@ -765,8 +767,8 @@ static int acpi_ec_notify_query_handlers(struct acpi_ec *ec, u8 query_bit)
 		if (query_bit == handler->query_bit) {
 			/* have custom handler for this bit */
 			handler = acpi_ec_get_query_handler(handler);
-			pr_debug("push query execution (0x%2x) on queue\n",
-				 query_bit);
+			pr_debug("##### Query(0x%02x) scheduled #####\n",
+				 handler->query_bit);
 			return acpi_os_execute((handler->func) ?
 				OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER,
 				acpi_ec_run, handler);
@@ -804,7 +806,7 @@ static int ec_check_sci(struct acpi_ec *ec, u8 state)
 {
 	if (state & ACPI_EC_FLAG_SCI) {
 		if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
-			pr_debug("push gpe query to the queue\n");
+			pr_debug("***** Event started *****\n");
 			return acpi_os_execute(OSL_NOTIFY_HANDLER,
 				acpi_ec_gpe_query, ec);
 		}
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [RFC PATCH v3 09/14] ACPI/EC: Add CPU ID to debugging messages.
  2014-07-21  6:04 ` [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
                     ` (7 preceding siblings ...)
  2014-07-21  6:05   ` [RFC PATCH v3 08/14] ACPI/EC: Refine event/query debugging messages Lv Zheng
@ 2014-07-21  6:06   ` Lv Zheng
  2014-07-21  6:06   ` [RFC PATCH v3 10/14] ACPI/EC: Cleanup QR_SC command processing by adding a kernel thread to poll EC events Lv Zheng
                     ` (5 subsequent siblings)
  14 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-21  6:06 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds CPU ID to the context entries' debugging output. no
functional changes.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index a729f31..065aabc 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -286,7 +286,8 @@ static bool advance_transaction(struct acpi_ec *ec)
 	u8 status;
 	bool wakeup = false;
 
-	pr_debug("===== %s =====\n", in_interrupt() ? "IRQ" : "TASK");
+	pr_debug("===== %s (%d) =====\n",
+		 in_interrupt() ? "IRQ" : "TASK", smp_processor_id());
 	status = acpi_ec_read_status(ec);
 	t = ec->curr;
 	if (!t)
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [RFC PATCH v3 10/14] ACPI/EC: Cleanup QR_SC command processing by adding a kernel thread to poll EC events.
  2014-07-21  6:04 ` [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
                     ` (8 preceding siblings ...)
  2014-07-21  6:06   ` [RFC PATCH v3 09/14] ACPI/EC: Add CPU ID to " Lv Zheng
@ 2014-07-21  6:06   ` Lv Zheng
  2014-07-21  6:06   ` [RFC PATCH v3 11/14] ACPI/EC: Add event storm prevention support Lv Zheng
                     ` (4 subsequent siblings)
  14 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-21  6:06 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

There is wait code in the QR_SC command processing, which makes it not
suitable to be put into a work queue item. This patch cleans up QR_SC
command processing by using an IRQ polling thread as the replacement for
the queued work item. Using thread allows us to change the EC GPE handler
into the threaded IRQ model when possible.

This poller is also useful for implementing event storm prevention. It is
reported that when the BIOS doesn't provide a _Qxx method to handle the
certain query event, the EVT_SCI interrupt can become a GPE storm hurting
the system performance (see link below, comment 55 and 80). The poller
thread thus can be used to poll EVT_SCI when storm prevention code swiches
EC driver into the polling mode.

The reasons why we do not put a loop in the event poller to poll event
until the returned query value is 0:
  Some platforms return non 0 query value even when EVT_SCI=0, if we put a
  loop in the poller, our command flush mechanism could never execute to
  an end thus the system suspending process could be blocked. One EVT_SCI
  triggering one QR_EC is current logic and has been proven to be working
  for so long time.

The reasons why it is not implemented directly using threaded IRQ are:
1. ACPICA doesn't support threaded IRQ as not all of the OSPMs support
   threaded IRQ while GPE handler registerations are done through ACPICA.
2. The IRQ processing code need to be identical for both the IRQ handler
   and the thread callback, while currently, though the command GPE
   handling is ready for both IRQ and polling mode, the event GPE is only
   handled in the polling mode.
So we use a standalone kernel thread, if the above situations are changed
in the future, we can easily convert the code into the threaded IRQ style.

The old EC_FLAGS_QUERY_PENDING is converted to EC_FLAGS_EVENT_ENABLED in
this patch, so that its naming is consistent with EC_FLAGS_EVENT_PENDING.
The original flag doesn't co-work with EVT_SCI well, this patch refines
its usage by enforcing a event polling wakeup indication as:
  EC_FLAGS_EVENT_ENABLED && EC_FLAGS_EVENT_PENDING
So unless the both of the flags are set, the threaded event poller will
not be woken up.

This patch invokes acpi_enable_gpe() after having detected EVT_SCI and
invokes acpi_disable_gpe() before having the QR_EC command processed.
This is useful for implementing GPE storm prevention for malicous "level
triggered" EVT_SCI. But the storm prevention is not implemented in this
patch.

Since the paired acpi_disable_gpe() invoked for EVT_SCI detection can only
hanppen after a QR_EC command, this patch modifies
acpi_ec_enable_gpe_flushable() to allow such QR_EC command to be proceeded
if the acpi_enable_gpe() has been invoked, which can be determined by the
event polling indication:
  EC_FLAGS_EVENT_ENABLED && EC_FLAGS_EVENT_PENDING
Without checking this reference increment for commands, QR_EC command will
not be executed to decrease the one added for EVT_SCI, thus the system
suspending will be blocked because the reference count equals to 2. Such
check is also common for flushing code.

Reference: https://bugzilla.kernel.org/show_bug.cgi?id=78091
Reported-by: Steffen Weber <steffen.weber@gmail.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c       |  195 ++++++++++++++++++++++++++++++++++-------------
 drivers/acpi/internal.h |    1 +
 2 files changed, 145 insertions(+), 51 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 065aabc..f9531ee 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -44,6 +44,7 @@
 #include <linux/slab.h>
 #include <linux/acpi.h>
 #include <linux/dmi.h>
+#include <linux/kthread.h>
 #include <asm/io.h>
 
 #include "internal.h"
@@ -75,7 +76,8 @@ enum ec_command {
 					 * when trying to clear the EC */
 
 enum {
-	EC_FLAGS_QUERY_PENDING,		/* Query is pending */
+	EC_FLAGS_EVENT_ENABLED,		/* Event is enabled */
+	EC_FLAGS_EVENT_PENDING,		/* Event is pending */
 	EC_FLAGS_HANDLERS_INSTALLED,	/* Handlers for GPE and
 					 * OpReg are installed */
 	EC_FLAGS_STARTED,		/* Driver is started */
@@ -125,6 +127,7 @@ struct transaction {
 static struct acpi_ec_query_handler *
 acpi_ec_get_query_handler(struct acpi_ec_query_handler *handler);
 static void acpi_ec_put_query_handler(struct acpi_ec_query_handler *handler);
+static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data);
 
 struct acpi_ec *boot_ec, *first_ec;
 EXPORT_SYMBOL(first_ec);
@@ -149,6 +152,12 @@ static bool acpi_ec_has_gpe_storm(struct acpi_ec *ec)
 	return test_bit(EC_FLAGS_COMMAND_STORM, &ec->flags);
 }
 
+static bool acpi_ec_has_pending_event(struct acpi_ec *ec)
+{
+	return test_bit(EC_FLAGS_EVENT_ENABLED, &ec->flags) &&
+	       test_bit(EC_FLAGS_EVENT_PENDING, &ec->flags);
+}
+
 /* --------------------------------------------------------------------------
                              GPE Enhancement
    -------------------------------------------------------------------------- */
@@ -196,6 +205,7 @@ static void acpi_ec_disable_gpe(struct acpi_ec *ec)
 /*
  * acpi_ec_enable_gpe_flushable() - Increase the flushable GPE reference
  * @ec: the EC device
+ * @check_event: whether event flushing should be taken into accounted
  *
  * This function must be used for the references of the operations that can
  * be flushed, i.e., all references other than the first reference which is
@@ -203,14 +213,83 @@ static void acpi_ec_disable_gpe(struct acpi_ec *ec)
  * this flush safe API so that flushable operations occurred after the
  * flush will not be initiated.
  */
-static bool acpi_ec_enable_gpe_flushable(struct acpi_ec *ec)
+static bool acpi_ec_enable_gpe_flushable(struct acpi_ec *ec,
+					 bool check_event)
 {
-	if (!acpi_ec_started(ec))
-		return false;
+	if (!acpi_ec_started(ec)) {
+		if (!check_event || !acpi_ec_has_pending_event(ec))
+			return false;
+	}
 	acpi_ec_enable_gpe(ec);
 	return true;
 }
 
+static void acpi_ec_enable_event(struct acpi_ec *ec)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ec->lock, flags);
+	/* Hold GPE reference for pending event */
+	if (!acpi_ec_enable_gpe_flushable(ec, false)) {
+		spin_unlock_irqrestore(&ec->lock, flags);
+		return;
+	}
+	set_bit(EC_FLAGS_EVENT_ENABLED, &ec->flags);
+	if (test_bit(EC_FLAGS_EVENT_PENDING, &ec->flags)) {
+		pr_debug("***** Event pending *****\n");
+		wake_up_process(ec->thread);
+		spin_unlock_irqrestore(&ec->lock, flags);
+		return;
+	}
+	acpi_ec_disable_gpe(ec);
+	spin_unlock_irqrestore(&ec->lock, flags);
+}
+
+static void __acpi_ec_set_event(struct acpi_ec *ec)
+{
+	/* Hold GPE reference for pending event */
+	if (!acpi_ec_enable_gpe_flushable(ec, false))
+		return;
+	if (!test_and_set_bit(EC_FLAGS_EVENT_PENDING, &ec->flags)) {
+		pr_debug("***** Event pending *****\n");
+		if (test_bit(EC_FLAGS_EVENT_ENABLED, &ec->flags)) {
+			wake_up_process(ec->thread);
+			return;
+		}
+	}
+	acpi_ec_disable_gpe(ec);
+}
+
+static void __acpi_ec_complete_event(struct acpi_ec *ec)
+{
+	if (test_and_clear_bit(EC_FLAGS_EVENT_PENDING, &ec->flags)) {
+		/* Unhold GPE reference for pending event */
+		acpi_ec_disable_gpe(ec);
+		pr_debug("***** Event running *****\n");
+	}
+}
+
+int acpi_ec_wait_for_event(struct acpi_ec *ec)
+{
+	unsigned long flags;
+
+	set_current_state(TASK_INTERRUPTIBLE);
+	while (!kthread_should_stop()) {
+		spin_lock_irqsave(&ec->lock, flags);
+		if (acpi_ec_has_pending_event(ec)) {
+			spin_unlock_irqrestore(&ec->lock, flags);
+			__set_current_state(TASK_RUNNING);
+			return 0;
+		}
+		spin_unlock_irqrestore(&ec->lock, flags);
+		schedule();
+		set_current_state(TASK_INTERRUPTIBLE);
+	}
+	__set_current_state(TASK_RUNNING);
+
+	return -1;
+}
+
 /* --------------------------------------------------------------------------
                              Transaction Management
    -------------------------------------------------------------------------- */
@@ -312,14 +391,16 @@ static bool advance_transaction(struct acpi_ec *ec)
 			t->flags |= ACPI_EC_COMMAND_COMPLETE;
 			wakeup = true;
 		}
-		return wakeup;
+		goto out;
 	} else {
 		if ((status & ACPI_EC_FLAG_IBF) == 0) {
 			acpi_ec_write_cmd(ec, t->command);
 			t->flags |= ACPI_EC_COMMAND_POLL;
+			if (t->command == ACPI_EC_COMMAND_QUERY)
+				__acpi_ec_complete_event(ec);
 		} else
 			goto err;
-		return wakeup;
+		goto out;
 	}
 err:
 	/*
@@ -335,6 +416,11 @@ err:
 				acpi_ec_set_storm(ec, EC_FLAGS_COMMAND_STORM);
 		}
 	}
+
+out:
+	if (status & ACPI_EC_FLAG_SCI &&
+	    (!t || t->flags & ACPI_EC_COMMAND_COMPLETE))
+		__acpi_ec_set_event(ec);
 	return wakeup;
 }
 
@@ -345,17 +431,6 @@ static void start_transaction(struct acpi_ec *ec)
 	(void)advance_transaction(ec);
 }
 
-static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data);
-
-static int ec_check_sci_sync(struct acpi_ec *ec, u8 state)
-{
-	if (state & ACPI_EC_FLAG_SCI) {
-		if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
-			return acpi_ec_sync_query(ec, NULL);
-	}
-	return 0;
-}
-
 static int ec_poll(struct acpi_ec *ec)
 {
 	unsigned long flags;
@@ -392,12 +467,14 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 {
 	unsigned long tmp;
 	int ret = 0;
+	bool is_query = !!(t->command == ACPI_EC_COMMAND_QUERY);
+
 	if (EC_FLAGS_MSI)
 		udelay(ACPI_EC_MSI_UDELAY);
 	/* start transaction */
 	spin_lock_irqsave(&ec->lock, tmp);
 	/* Enable GPE for command processing (IBF=0/OBF=1) */
-	if (!acpi_ec_enable_gpe_flushable(ec)) {
+	if (!acpi_ec_enable_gpe_flushable(ec, is_query)) {
 		ret = -EINVAL;
 		goto unlock;
 	}
@@ -406,10 +483,6 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 	pr_debug("***** Command(%s) started *****\n",
 		 acpi_ec_cmd_string(t->command));
 	start_transaction(ec);
-	if (ec->curr->command == ACPI_EC_COMMAND_QUERY) {
-		clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
-		pr_debug("***** Event stopped *****\n");
-	}
 	spin_unlock_irqrestore(&ec->lock, tmp);
 	ret = ec_poll(ec);
 	spin_lock_irqsave(&ec->lock, tmp);
@@ -444,8 +517,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
 
 	status = acpi_ec_transaction_unlocked(ec, t);
 
-	/* check if we received SCI during transaction */
-	ec_check_sci_sync(ec, acpi_ec_read_status(ec));
 	if (ec->global_lock)
 		acpi_release_global_lock(glk);
 unlock:
@@ -789,32 +860,9 @@ static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data)
 		*data = value;
 	if (status)
 		return status;
-
 	return acpi_ec_notify_query_handlers(ec, value);
 }
 
-static void acpi_ec_gpe_query(void *ec_cxt)
-{
-	struct acpi_ec *ec = ec_cxt;
-	if (!ec)
-		return;
-	mutex_lock(&ec->mutex);
-	acpi_ec_sync_query(ec, NULL);
-	mutex_unlock(&ec->mutex);
-}
-
-static int ec_check_sci(struct acpi_ec *ec, u8 state)
-{
-	if (state & ACPI_EC_FLAG_SCI) {
-		if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
-			pr_debug("***** Event started *****\n");
-			return acpi_os_execute(OSL_NOTIFY_HANDLER,
-				acpi_ec_gpe_query, ec);
-		}
-	}
-	return 0;
-}
-
 static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
 	u32 gpe_number, void *data)
 {
@@ -828,10 +876,47 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
 	if (!acpi_ec_has_gpe_storm(ec))
 		enable = ACPI_REENABLE_GPE;
 	spin_unlock_irqrestore(&ec->lock, flags);
-	ec_check_sci(ec, acpi_ec_read_status(ec));
 	return ACPI_INTERRUPT_HANDLED | enable;
 }
 
+static int acpi_ec_event_poller(void *context)
+{
+	struct acpi_ec *ec = context;
+
+	while (!acpi_ec_wait_for_event(ec)) {
+		pr_debug("***** Event poller started *****\n");
+		mutex_lock(&ec->mutex);
+		(void)acpi_ec_sync_query(ec, NULL);
+		mutex_unlock(&ec->mutex);
+		pr_debug("***** Event poller stopped *****\n");
+	}
+
+	return 0;
+}
+
+static int ec_create_event_poller(struct acpi_ec *ec)
+{
+	struct task_struct *t;
+
+	t = kthread_run(acpi_ec_event_poller, ec, "ec/gpe-%lu", ec->gpe);
+	if (IS_ERR(t)) {
+		pr_err("failed to create event poller %lu\n", ec->gpe);
+		return PTR_ERR(t);
+	}
+	get_task_struct(t);
+	ec->thread = t;
+	return 0;
+}
+
+static void ec_delete_event_poller(struct acpi_ec *ec)
+{
+	struct task_struct *t = ec->thread;
+
+	ec->thread = NULL;
+	kthread_stop(t);
+	put_task_struct(t);
+}
+
 /* --------------------------------------------------------------------------
                              Address Space Management
    -------------------------------------------------------------------------- */
@@ -888,7 +973,6 @@ static struct acpi_ec *make_acpi_ec(void)
 	struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
 	if (!ec)
 		return NULL;
-	ec->flags = 1 << EC_FLAGS_QUERY_PENDING;
 	mutex_init(&ec->mutex);
 	init_waitqueue_head(&ec->wait);
 	INIT_LIST_HEAD(&ec->list);
@@ -946,14 +1030,21 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
 
 static int ec_install_handlers(struct acpi_ec *ec)
 {
+	int ret;
 	acpi_status status;
+
 	if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags))
 		return 0;
+	ret = ec_create_event_poller(ec);
+	if (ret)
+		return ret;
 	status = acpi_install_gpe_handler(NULL, ec->gpe,
 				  ACPI_GPE_EDGE_TRIGGERED,
 				  &acpi_ec_gpe_handler, ec);
-	if (ACPI_FAILURE(status))
+	if (ACPI_FAILURE(status)) {
+		ec_delete_event_poller(ec);
 		return -ENODEV;
+	}
 
 	acpi_ec_start(ec);
 	status = acpi_install_address_space_handler(ec->handle,
@@ -973,6 +1064,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
 			acpi_ec_stop(ec);
 			acpi_remove_gpe_handler(NULL, ec->gpe,
 				&acpi_ec_gpe_handler);
+			ec_delete_event_poller(ec);
 			return -ENODEV;
 		}
 	}
@@ -990,6 +1082,7 @@ static void ec_remove_handlers(struct acpi_ec *ec)
 	if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
 				&acpi_ec_gpe_handler)))
 		pr_err("failed to remove gpe handler\n");
+	ec_delete_event_poller(ec);
 	clear_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags);
 }
 
@@ -1037,7 +1130,7 @@ static int acpi_ec_add(struct acpi_device *device)
 	ret = ec_install_handlers(ec);
 
 	/* EC is fully operational, allow queries */
-	clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
+	acpi_ec_enable_event(ec);
 
 	/* Clear stale _Q events if hardware might require that */
 	if (EC_FLAGS_CLEAR_ON_RESUME) {
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 2348f9c..b2eef49 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -124,6 +124,7 @@ struct acpi_ec {
 	struct list_head list;
 	struct transaction *curr;
 	spinlock_t lock;
+	struct task_struct *thread;
 };
 
 extern struct acpi_ec *first_ec;
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [RFC PATCH v3 11/14] ACPI/EC: Add event storm prevention support.
  2014-07-21  6:04 ` [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
                     ` (9 preceding siblings ...)
  2014-07-21  6:06   ` [RFC PATCH v3 10/14] ACPI/EC: Cleanup QR_SC command processing by adding a kernel thread to poll EC events Lv Zheng
@ 2014-07-21  6:06   ` Lv Zheng
  2014-07-21  6:06   ` [RFC PATCH v3 12/14] ACPI/EC: Add GPE reference counting debugging messages Lv Zheng
                     ` (3 subsequent siblings)
  14 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-21  6:06 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

There are cases that BIOS doesn't provide a _Qxx method for the returned
xx query value, in this case, acpi_set_gpe(ACPI_GPE_DISABLE) need to be
invoked to prevent event IRQ storms. See comment 55 and 80 in the bug link
below.

This patch implements such storm prevention using new GPE APIs.

By always enabling EC event storm prevention, we can perform a unit test,
the test shows that:
1. When EC_FLAGS_EVENT_STORM is indicated, all transactions are handled in
   the task context:
   # ACPI : EC: ===== TASK =====
     ACPI : EC: EC_SC(R) = 0x01 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=1
     ACPI : EC: EC_DATA(R) = 0x66
     ACPI : EC: ***** Command(QR_EC) stopped *****
     ACPI : EC: ##### Query(0x66) scheduled #####
     ACPI : EC: ##### Query(0x66) started #####
     ACPI : EC: ***** Command(RD_EC) started *****
   * ACPI : EC: ===== TASK =====
     ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
     ACPI : EC: EC_SC(W) = 0x80
     ACPI : EC: ===== TASK =====
   * ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
     ACPI : EC: EC_DATA(W) = 0x07
   * ACPI : EC: ===== TASK =====
     ACPI : EC: EC_SC(R) = 0x01 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=1
     ACPI : EC: EC_DATA(R) = 0x88
     ACPI : EC: ***** Command(RD_EC) stopped *****
   When the event storm prevention is enabled, EVT_SCI is polled in the
   task context (#), and the further commands are also handled using the
   polling mode (*) before the storming has been recovered.
2. The event poller thread will poll EVT_SCI every 5 minutes:
   [   35.233628] ACPI : EC: ***** Event poller started *****
   [   40.241432] ACPI : EC: ***** Event poller started *****
   [   45.249182] ACPI : EC: ***** Event poller started *****
   [   50.257009] ACPI : EC: ***** Event poller started *****
   [   55.264782] ACPI : EC: ***** Event poller started *****
   So the timeout facility is functioning correctly.
3. System suspend/resume test is also passed.

Note that this storm is *VERY RARE*, and we even:
1. add a threshold to prevent the event storm prevention from being false
   triggered,
2. allow recovery from first non-false query value.
So this patch doesn't affect the normal EC driver behaviors, all EC
transactions are still handled in the IRQ mode and the storming situation
can be easily recovered if the firmware doesn't maliciously trigger such
storms.

Reference: https://bugzilla.kernel.org/show_bug.cgi?id=78091
Reported-by: Steffen Weber <steffen.weber@gmail.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c       |   45 ++++++++++++++++++++++++++++++++++++++-------
 drivers/acpi/internal.h |    1 +
 2 files changed, 39 insertions(+), 7 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index f9531ee..2a1eb2a 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -74,6 +74,7 @@ enum ec_command {
 #define ACPI_EC_MSI_UDELAY	550	/* Wait 550us for MSI EC */
 #define ACPI_EC_CLEAR_MAX	100	/* Maximum number of events to query
 					 * when trying to clear the EC */
+#define ACPI_EC_POLL_TIMEOUT	5000	/* Polling event every 5000ms */
 
 enum {
 	EC_FLAGS_EVENT_ENABLED,		/* Event is enabled */
@@ -84,6 +85,8 @@ enum {
 	EC_FLAGS_STOPPED,		/* Driver is stopped */
 	EC_FLAGS_COMMAND_STORM,		/* GPE storms occurred to the
 					 * current command processing */
+	EC_FLAGS_EVENT_STORM,		/* GPE storms occurred to the
+					 * current event processing */
 };
 
 #define ACPI_EC_COMMAND_POLL		0x01 /* Available for command byte */
@@ -149,7 +152,8 @@ static bool acpi_ec_started(struct acpi_ec *ec)
 
 static bool acpi_ec_has_gpe_storm(struct acpi_ec *ec)
 {
-	return test_bit(EC_FLAGS_COMMAND_STORM, &ec->flags);
+	return test_bit(EC_FLAGS_COMMAND_STORM, &ec->flags) ||
+	       test_bit(EC_FLAGS_EVENT_STORM, &ec->flags);
 }
 
 static bool acpi_ec_has_pending_event(struct acpi_ec *ec)
@@ -165,8 +169,10 @@ static bool acpi_ec_has_pending_event(struct acpi_ec *ec)
 static void acpi_ec_set_storm(struct acpi_ec *ec, u8 flag)
 {
 	if (!test_bit(flag, &ec->flags)) {
-		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
-		pr_debug("+++++ Polling enabled +++++\n");
+		if (!acpi_ec_has_gpe_storm(ec)) {
+			acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
+			pr_debug("+++++ Polling enabled +++++\n");
+		}
 		set_bit(flag, &ec->flags);
 	}
 }
@@ -175,8 +181,10 @@ static void acpi_ec_clear_storm(struct acpi_ec *ec, u8 flag)
 {
 	if (test_bit(flag, &ec->flags)) {
 		clear_bit(flag, &ec->flags);
-		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
-		pr_debug("+++++ Polling disabled +++++\n");
+		if (!acpi_ec_has_gpe_storm(ec)) {
+			acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
+			pr_debug("+++++ Polling disabled +++++\n");
+		}
 	}
 }
 
@@ -272,18 +280,25 @@ static void __acpi_ec_complete_event(struct acpi_ec *ec)
 int acpi_ec_wait_for_event(struct acpi_ec *ec)
 {
 	unsigned long flags;
+	signed long timeout;
+	int storming;
 
 	set_current_state(TASK_INTERRUPTIBLE);
+	timeout = msecs_to_jiffies(ACPI_EC_POLL_TIMEOUT);
 	while (!kthread_should_stop()) {
 		spin_lock_irqsave(&ec->lock, flags);
-		if (acpi_ec_has_pending_event(ec)) {
+		storming = test_bit(EC_FLAGS_EVENT_STORM, &ec->flags);
+		if (acpi_ec_has_pending_event(ec) ||
+		    (storming && !timeout)) {
 			spin_unlock_irqrestore(&ec->lock, flags);
 			__set_current_state(TASK_RUNNING);
 			return 0;
 		}
 		spin_unlock_irqrestore(&ec->lock, flags);
-		schedule();
+		timeout = schedule_timeout(timeout);
 		set_current_state(TASK_INTERRUPTIBLE);
+		if (!storming)
+			timeout = msecs_to_jiffies(ACPI_EC_POLL_TIMEOUT);
 	}
 	__set_current_state(TASK_RUNNING);
 
@@ -682,6 +697,8 @@ static void acpi_ec_stop(struct acpi_ec *ec)
 		spin_unlock_irqrestore(&ec->lock, flags);
 		wait_event(ec->wait, acpi_ec_stopped(ec));
 		spin_lock_irqsave(&ec->lock, flags);
+		/* Event storm may still be indicated */
+		acpi_ec_clear_storm(ec, EC_FLAGS_EVENT_STORM);
 		/* Disable GPE for event processing (EVT_SCI=1) */
 		acpi_ec_disable_gpe(ec);
 		clear_bit(EC_FLAGS_STARTED, &ec->flags);
@@ -833,10 +850,17 @@ static void acpi_ec_run(void *cxt)
 
 static int acpi_ec_notify_query_handlers(struct acpi_ec *ec, u8 query_bit)
 {
+	unsigned long flags;
 	struct acpi_ec_query_handler *handler;
 
 	list_for_each_entry(handler, &ec->list, node) {
 		if (query_bit == handler->query_bit) {
+			spin_lock_irqsave(&ec->lock, flags);
+			if (ec->event_count == ec_storm_threshold) {
+				acpi_ec_clear_storm(ec, EC_FLAGS_EVENT_STORM);
+				ec->event_count = 0;
+			}
+			spin_unlock_irqrestore(&ec->lock, flags);
 			/* have custom handler for this bit */
 			handler = acpi_ec_get_query_handler(handler);
 			pr_debug("##### Query(0x%02x) scheduled #####\n",
@@ -847,6 +871,13 @@ static int acpi_ec_notify_query_handlers(struct acpi_ec *ec, u8 query_bit)
 		}
 	}
 	pr_warn_once("BIOS bug: no handler for query (0x%02x)\n", query_bit);
+	spin_lock_irqsave(&ec->lock, flags);
+	if (ec->event_count < ec_storm_threshold)
+		++ec->event_count;
+	/* Allow triggering on 0 threshold */
+	if (ec->event_count == ec_storm_threshold)
+		acpi_ec_set_storm(ec, EC_FLAGS_EVENT_STORM);
+	spin_unlock_irqrestore(&ec->lock, flags);
 	return 0;
 }
 
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index b2eef49..e72ae6a 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -125,6 +125,7 @@ struct acpi_ec {
 	struct transaction *curr;
 	spinlock_t lock;
 	struct task_struct *thread;
+	unsigned long event_count;
 };
 
 extern struct acpi_ec *first_ec;
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [RFC PATCH v3 12/14] ACPI/EC: Add GPE reference counting debugging messages.
  2014-07-21  6:04 ` [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
                     ` (10 preceding siblings ...)
  2014-07-21  6:06   ` [RFC PATCH v3 11/14] ACPI/EC: Add event storm prevention support Lv Zheng
@ 2014-07-21  6:06   ` Lv Zheng
  2014-07-21  6:06   ` [RFC PATCH v3 13/14] ACPI/EC: Add unit test support for EC driver hotplug Lv Zheng
                     ` (2 subsequent siblings)
  14 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-21  6:06 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch enhances debugging with the GPE reference count messages added.
No functional changes.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 2a1eb2a..c2e276f 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -31,6 +31,7 @@
 
 /* Uncomment next line to get verbose printout */
 /* #define DEBUG */
+#define DEBUG_REF 0
 #define pr_fmt(fmt) "ACPI : EC: " fmt
 
 #include <linux/kernel.h>
@@ -92,6 +93,13 @@ enum {
 #define ACPI_EC_COMMAND_POLL		0x01 /* Available for command byte */
 #define ACPI_EC_COMMAND_COMPLETE	0x02 /* Completed last byte */
 
+#define ec_debug_ref(ec, fmt, ...)					\
+	do {								\
+		if (DEBUG_REF)						\
+			pr_debug("%lu: " fmt, ec->reference_count,	\
+				 ## __VA_ARGS__);			\
+	} while (0)
+
 /* ec.c is compiled in acpi namespace so this shows up as acpi.ec_delay param */
 static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY;
 module_param(ec_delay, uint, 0644);
@@ -242,6 +250,7 @@ static void acpi_ec_enable_event(struct acpi_ec *ec)
 		spin_unlock_irqrestore(&ec->lock, flags);
 		return;
 	}
+	ec_debug_ref(ec, "Increase poller(enable)\n");
 	set_bit(EC_FLAGS_EVENT_ENABLED, &ec->flags);
 	if (test_bit(EC_FLAGS_EVENT_PENDING, &ec->flags)) {
 		pr_debug("***** Event pending *****\n");
@@ -250,6 +259,7 @@ static void acpi_ec_enable_event(struct acpi_ec *ec)
 		return;
 	}
 	acpi_ec_disable_gpe(ec);
+	ec_debug_ref(ec, "Decrease poller(enable)\n");
 	spin_unlock_irqrestore(&ec->lock, flags);
 }
 
@@ -258,6 +268,7 @@ static void __acpi_ec_set_event(struct acpi_ec *ec)
 	/* Hold GPE reference for pending event */
 	if (!acpi_ec_enable_gpe_flushable(ec, false))
 		return;
+	ec_debug_ref(ec, "Increase poller(set)\n");
 	if (!test_and_set_bit(EC_FLAGS_EVENT_PENDING, &ec->flags)) {
 		pr_debug("***** Event pending *****\n");
 		if (test_bit(EC_FLAGS_EVENT_ENABLED, &ec->flags)) {
@@ -266,6 +277,7 @@ static void __acpi_ec_set_event(struct acpi_ec *ec)
 		}
 	}
 	acpi_ec_disable_gpe(ec);
+	ec_debug_ref(ec, "Decrease poller(set)\n");
 }
 
 static void __acpi_ec_complete_event(struct acpi_ec *ec)
@@ -273,6 +285,7 @@ static void __acpi_ec_complete_event(struct acpi_ec *ec)
 	if (test_and_clear_bit(EC_FLAGS_EVENT_PENDING, &ec->flags)) {
 		/* Unhold GPE reference for pending event */
 		acpi_ec_disable_gpe(ec);
+		ec_debug_ref(ec, "Decrease poller\n");
 		pr_debug("***** Event running *****\n");
 	}
 }
@@ -493,6 +506,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 		ret = -EINVAL;
 		goto unlock;
 	}
+	ec_debug_ref(ec, "Increase command\n");
 	/* following two actions should be kept atomic */
 	ec->curr = t;
 	pr_debug("***** Command(%s) started *****\n",
@@ -508,6 +522,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 	ec->curr = NULL;
 	/* Disable GPE for command processing (IBF=0/OBF=1) */
 	acpi_ec_disable_gpe(ec);
+	ec_debug_ref(ec, "Decrease command\n");
 unlock:
 	spin_unlock_irqrestore(&ec->lock, tmp);
 	return ret;
@@ -670,6 +685,7 @@ static void acpi_ec_start(struct acpi_ec *ec)
 		pr_debug("+++++ Starting EC +++++\n");
 		/* Enable GPE for event processing (EVT_SCI=1) */
 		acpi_ec_enable_gpe(ec);
+		ec_debug_ref(ec, "Increase event\n");
 		pr_info("+++++ EC started +++++\n");
 	}
 	spin_unlock_irqrestore(&ec->lock, flags);
@@ -701,6 +717,7 @@ static void acpi_ec_stop(struct acpi_ec *ec)
 		acpi_ec_clear_storm(ec, EC_FLAGS_EVENT_STORM);
 		/* Disable GPE for event processing (EVT_SCI=1) */
 		acpi_ec_disable_gpe(ec);
+		ec_debug_ref(ec, "Decrease event\n");
 		clear_bit(EC_FLAGS_STARTED, &ec->flags);
 		clear_bit(EC_FLAGS_STOPPED, &ec->flags);
 		pr_info("+++++ EC stopped +++++\n");
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [RFC PATCH v3 13/14] ACPI/EC: Add unit test support for EC driver hotplug.
  2014-07-21  6:04 ` [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
                     ` (11 preceding siblings ...)
  2014-07-21  6:06   ` [RFC PATCH v3 12/14] ACPI/EC: Add GPE reference counting debugging messages Lv Zheng
@ 2014-07-21  6:06   ` Lv Zheng
  2014-07-21  6:06   ` [RFC PATCH v3 14/14] ACPI/EC: Cleanup coding style Lv Zheng
  2014-07-22  1:11   ` [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention Rafael J. Wysocki
  14 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-21  6:06 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch adds facility to test future EC modification.
All EC commits should enable TEST_HOTPLUG, and try a build/boot test.
Since EC is currently a built-in module, this is the only mean for us to
test the hotplug code.
The following is the result of the flushing tests:
  ACPI : EC: ===== IRQ (0) =====
  ACPI : EC: EC_SC(R) = 0x20 SCI_EVT=1 BURST=0 CMD=0 IBF=0 OBF=0
# ACPI : EC: 2: Increase poller(set)
  ACPI : EC: ***** Event pending *****
  ACPI : EC: ***** Event poller started *****
* ACPI : EC: 3: Increase command
  ACPI : EC: ***** Command(QR_EC) started *****
  ACPI : EC: ===== TASK (0) =====
  ACPI : EC: EC_SC(R) = 0x20 SCI_EVT=1 BURST=0 CMD=0 IBF=0 OBF=0
  ACPI : EC: EC_SC(W) = 0x84
# ACPI : EC: 2: Decrease poller
  ACPI : EC: ***** Event running *****
  ACPI : EC: ===== IRQ (2) =====
  ACPI : EC: EC_SC(R) = 0x01 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=1
  ACPI : EC: EC_DATA(R) = 0x66
  ACPI : EC: ***** Command(QR_EC) stopped *****
* ACPI : EC: 1: Decrease command
  ACPI : EC: ##### Query(0x66) scheduled #####
  ACPI : EC: ***** Event poller stopped *****
  ACPI : EC: ##### Query(0x66) started #####
$ ACPI : EC: 2: Increase command
  ACPI : EC: ***** Command(RD_EC) started *****
  ACPI : EC: ===== TASK (0) =====
  ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
  ACPI : EC: EC_SC(W) = 0x80
  ACPI : EC: ===== IRQ (0) =====
  ACPI : EC: EC_SC(R) = 0x00 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=0
  ACPI : EC: EC_DATA(W) = 0x07
  ACPI : EC: ===== TASK (0) =====
  ACPI : EC: EC_SC(R) = 0x02 SCI_EVT=0 BURST=0 CMD=0 IBF=1 OBF=0
  ACPI : EC: ===== IRQ (2) =====
  ACPI : EC: EC_SC(R) = 0x01 SCI_EVT=0 BURST=0 CMD=0 IBF=0 OBF=1
  ACPI : EC: EC_DATA(R) = 0x00
  ACPI : EC: ***** Command(RD_EC) stopped *****
$ ACPI : EC: 1: Decrease command
  ACPI : EC: Removing EC handlers...
  ACPI : EC: +++++ Stopping EC +++++
  ACPI : EC: 0: Decrease event
@ ACPI : EC: +++++ EC stopped +++++
  ACPI : EC: Installing EC handlers...
  ACPI : EC: +++++ Starting EC +++++
  ACPI : EC: 1: Increase event
  ACPI : EC: +++++ EC started +++++
  ... (other RD_EC commands for _Q66 evaluation)
  ACPI : EC: ##### Query(0x66) stopped #####
We can see the hot plugging succeeded (@) after a command transaction
issued by the EC address space handleri ($). We can also see the reference
count triggered by the EVT_SCI event is correctly flushed (#) across a
QR_EC command issued in the event poller thread (*).

And the tests to trigger EVT_SCI on the fly with system powering on/off,
system suspending/resuming also have passed.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index c2e276f..ea8d3c3 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -32,6 +32,7 @@
 /* Uncomment next line to get verbose printout */
 /* #define DEBUG */
 #define DEBUG_REF 0
+/* #define TEST_HOTPLUG */
 #define pr_fmt(fmt) "ACPI : EC: " fmt
 
 #include <linux/kernel.h>
@@ -139,6 +140,11 @@ static struct acpi_ec_query_handler *
 acpi_ec_get_query_handler(struct acpi_ec_query_handler *handler);
 static void acpi_ec_put_query_handler(struct acpi_ec_query_handler *handler);
 static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data);
+#ifdef TEST_HOTPLUG
+static void acpi_ec_test(struct acpi_ec *ec);
+#else
+static inline void acpi_ec_test(struct acpi_ec *ec) {}
+#endif
 
 struct acpi_ec *boot_ec, *first_ec;
 EXPORT_SYMBOL(first_ec);
@@ -551,6 +557,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
 		acpi_release_global_lock(glk);
 unlock:
 	mutex_unlock(&ec->mutex);
+	acpi_ec_test(ec);
 	return status;
 }
 
@@ -1248,6 +1255,22 @@ int __init acpi_boot_ec_enable(void)
 	return -EFAULT;
 }
 
+#ifdef TEST_HOTPLUG
+static void acpi_ec_test(struct acpi_ec *ec)
+{
+	/* Unit testing for driver hotplugging */
+	pr_info("Removing EC handlers...\n");
+	acpi_ec_stop(ec);
+	acpi_remove_gpe_handler(NULL, ec->gpe,
+				&acpi_ec_gpe_handler);
+	pr_info("Installing EC handlers...\n");
+	acpi_install_gpe_handler(NULL, ec->gpe,
+				  ACPI_GPE_EDGE_TRIGGERED,
+				  &acpi_ec_gpe_handler, ec);
+	acpi_ec_start(ec);
+}
+#endif
+
 static const struct acpi_device_id ec_device_ids[] = {
 	{"PNP0C09", 0},
 	{"", 0},
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [RFC PATCH v3 14/14] ACPI/EC: Cleanup coding style.
  2014-07-21  6:04 ` [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
                     ` (12 preceding siblings ...)
  2014-07-21  6:06   ` [RFC PATCH v3 13/14] ACPI/EC: Add unit test support for EC driver hotplug Lv Zheng
@ 2014-07-21  6:06   ` Lv Zheng
  2014-07-22  1:11   ` [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention Rafael J. Wysocki
  14 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2014-07-21  6:06 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch cleans up the following coding style issues that are detected by
scripts/checkpatch.pl:
 ERROR: code indent should use tabs where possible
 WARNING: Missing a blank line after declarations
No functional changes.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   33 ++++++++++++++++++++-------------
 1 file changed, 20 insertions(+), 13 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index ea8d3c3..0e7472b 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -155,8 +155,8 @@ static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
 static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
 
 /* --------------------------------------------------------------------------
-                             Device Flags
-   -------------------------------------------------------------------------- */
+ *                           Device Flags
+ * -------------------------------------------------------------------------- */
 
 static bool acpi_ec_started(struct acpi_ec *ec)
 {
@@ -177,8 +177,8 @@ static bool acpi_ec_has_pending_event(struct acpi_ec *ec)
 }
 
 /* --------------------------------------------------------------------------
-                             GPE Enhancement
-   -------------------------------------------------------------------------- */
+ *                           GPE Enhancement
+ * -------------------------------------------------------------------------- */
 
 static void acpi_ec_set_storm(struct acpi_ec *ec, u8 flag)
 {
@@ -325,8 +325,8 @@ int acpi_ec_wait_for_event(struct acpi_ec *ec)
 }
 
 /* --------------------------------------------------------------------------
-                             Transaction Management
-   -------------------------------------------------------------------------- */
+ *                           Transaction Management
+ * -------------------------------------------------------------------------- */
 
 static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
 {
@@ -386,6 +386,7 @@ static int ec_transaction_completed(struct acpi_ec *ec)
 {
 	unsigned long flags;
 	int ret = 0;
+
 	spin_lock_irqsave(&ec->lock, flags);
 	if (ec->curr && (ec->curr->flags & ACPI_EC_COMMAND_COMPLETE))
 		ret = 1;
@@ -469,6 +470,7 @@ static int ec_poll(struct acpi_ec *ec)
 {
 	unsigned long flags;
 	int repeat = 5; /* number of command restarts */
+
 	while (repeat--) {
 		unsigned long delay = jiffies +
 			msecs_to_jiffies(ec_delay);
@@ -779,6 +781,7 @@ static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data)
 	struct transaction t = {.command = ACPI_EC_COMMAND_QUERY,
 				.wdata = NULL, .rdata = &d,
 				.wlen = 0, .rlen = 1};
+
 	if (!ec || !data)
 		return -EINVAL;
 	/*
@@ -796,8 +799,9 @@ static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data)
 }
 
 /* --------------------------------------------------------------------------
-                                Event Management
-   -------------------------------------------------------------------------- */
+ *                              Event Management
+ * -------------------------------------------------------------------------- */
+
 static struct acpi_ec_query_handler *
 acpi_ec_get_query_handler(struct acpi_ec_query_handler *handler)
 {
@@ -824,6 +828,7 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
 {
 	struct acpi_ec_query_handler *handler =
 	    kzalloc(sizeof(struct acpi_ec_query_handler), GFP_KERNEL);
+
 	if (!handler)
 		return -ENOMEM;
 
@@ -844,6 +849,7 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
 {
 	struct acpi_ec_query_handler *handler, *tmp;
 	LIST_HEAD(free_list);
+
 	mutex_lock(&ec->mutex);
 	list_for_each_entry_safe(handler, tmp, &ec->list, node) {
 		if (query_bit == handler->query_bit) {
@@ -861,6 +867,7 @@ EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
 static void acpi_ec_run(void *cxt)
 {
 	struct acpi_ec_query_handler *handler = cxt;
+
 	if (!handler)
 		return;
 	pr_debug("##### Query(0x%02x) started #####\n", handler->query_bit);
@@ -973,8 +980,8 @@ static void ec_delete_event_poller(struct acpi_ec *ec)
 }
 
 /* --------------------------------------------------------------------------
-                             Address Space Management
-   -------------------------------------------------------------------------- */
+ *                           Address Space Management
+ * -------------------------------------------------------------------------- */
 
 static acpi_status
 acpi_ec_space_handler(u32 function, acpi_physical_address address,
@@ -1018,8 +1025,9 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
 }
 
 /* --------------------------------------------------------------------------
-                               Driver Interface
-   -------------------------------------------------------------------------- */
+ *                             Driver Interface
+ * -------------------------------------------------------------------------- */
+
 static acpi_status
 ec_parse_io_ports(struct acpi_resource *resource, void *context);
 
@@ -1058,7 +1066,6 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
 {
 	acpi_status status;
 	unsigned long long tmp = 0;
-
 	struct acpi_ec *ec = context;
 
 	/* clear addr values, ec_parse_io_ports depend on it */
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* Re: [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention.
  2014-07-21  6:04 ` [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
                     ` (13 preceding siblings ...)
  2014-07-21  6:06   ` [RFC PATCH v3 14/14] ACPI/EC: Cleanup coding style Lv Zheng
@ 2014-07-22  1:11   ` Rafael J. Wysocki
  2014-07-22  1:25     ` Zheng, Lv
  14 siblings, 1 reply; 63+ messages in thread
From: Rafael J. Wysocki @ 2014-07-22  1:11 UTC (permalink / raw)
  To: Lv Zheng
  Cc: Rafael J. Wysocki, Len Brown, Lv Zheng, linux-kernel, linux-acpi,
	Robert Moore

On Monday, July 21, 2014 02:04:51 PM Lv Zheng wrote:
> Note that this patchset is very stable now, it is sent as RFC because it
> depends on an ACPICA GPE enhancement series which might be merged from
> ACPICA upstream.

Do I remember correctly that this is the plan?

So I'm expecting to receive the Linux versions of the relevant ACPICA changes
from you and then I'll apply this material on top of them.

We don't need to wait for the next ACPICA release with this I think, but
I'd like the GPE changes to be applied to upstream ACPICA at least before
I get them.

Rafael


^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention.
  2014-07-22  1:11   ` [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention Rafael J. Wysocki
@ 2014-07-22  1:25     ` Zheng, Lv
  2014-07-22 22:15       ` Rafael J. Wysocki
  0 siblings, 1 reply; 63+ messages in thread
From: Zheng, Lv @ 2014-07-22  1:25 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Wysocki, Rafael J, Brown, Len, Lv Zheng, linux-kernel,
	linux-acpi, Moore, Robert

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 2006 bytes --]

Hi, Rafael

> From: Rafael J. Wysocki [mailto:rjw@rjwysocki.net]
> Sent: Tuesday, July 22, 2014 9:12 AM
> 
> On Monday, July 21, 2014 02:04:51 PM Lv Zheng wrote:
> > Note that this patchset is very stable now, it is sent as RFC because it
> > depends on an ACPICA GPE enhancement series which might be merged from
> > ACPICA upstream.
> 
> Do I remember correctly that this is the plan?
> 
> So I'm expecting to receive the Linux versions of the relevant ACPICA changes
> from you and then I'll apply this material on top of them.
> 
> We don't need to wait for the next ACPICA release with this I think, but
> I'd like the GPE changes to be applied to upstream ACPICA at least before
> I get them.

Yes, I'm trying.
I'll re-send this series after an ACPICA release cycle that contains the dependent GPE series.

Let me highlight the real value of this EC series:
This is a good IO driver material to demonstrate:
1. runtime idle: this is not implemented yet because of ACPICA issues that are not root caused, let me show this possibility this below.
2. storming safe: can also deal with all kinds of silicon without worrying about IRQ storming.

On top of this, after
1. making sure that acpi_evaluate_object(_Qxx) won't be a blocking point, and extending the referenced period to the end of the evaluation,
2. adding 1 more patch to the ACPICA series, using a flag to bypass the automatic GPE disabling/enabling,
3. adding 1 more patch to make EC event poller  to disable GPE when sleeping,
Linux EC driver can run without GPE enabled when idle.
Which means GPE is enabled only when:
1. there is an EC command issued from the EC space handler or
2. the event poller thread is timed out or woken up by the EVT_SCI.

So I hope this IO driver enhancement can be a good material to show such possibility.

Thanks and best regards
-Lv

> 
> Rafael

ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention.
  2014-07-22  1:25     ` Zheng, Lv
@ 2014-07-22 22:15       ` Rafael J. Wysocki
  2014-07-23  1:31         ` Zheng, Lv
  0 siblings, 1 reply; 63+ messages in thread
From: Rafael J. Wysocki @ 2014-07-22 22:15 UTC (permalink / raw)
  To: Zheng, Lv
  Cc: Wysocki, Rafael J, Brown, Len, Lv Zheng, linux-kernel,
	linux-acpi, Moore, Robert

On Tuesday, July 22, 2014 01:25:00 AM Zheng, Lv wrote:
> Hi, Rafael
> 
> > From: Rafael J. Wysocki [mailto:rjw@rjwysocki.net]
> > Sent: Tuesday, July 22, 2014 9:12 AM
> > 
> > On Monday, July 21, 2014 02:04:51 PM Lv Zheng wrote:
> > > Note that this patchset is very stable now, it is sent as RFC because it
> > > depends on an ACPICA GPE enhancement series which might be merged from
> > > ACPICA upstream.
> > 
> > Do I remember correctly that this is the plan?
> > 
> > So I'm expecting to receive the Linux versions of the relevant ACPICA changes
> > from you and then I'll apply this material on top of them.
> > 
> > We don't need to wait for the next ACPICA release with this I think, but
> > I'd like the GPE changes to be applied to upstream ACPICA at least before
> > I get them.
> 
> Yes, I'm trying.
> I'll re-send this series after an ACPICA release cycle that contains the dependent GPE series.
> 
> Let me highlight the real value of this EC series:
> This is a good IO driver material to demonstrate:
> 1. runtime idle: this is not implemented yet because of ACPICA issues that are not root caused, let me show this possibility this below.
> 2. storming safe: can also deal with all kinds of silicon without worrying about IRQ storming.
> 
> On top of this, after
> 1. making sure that acpi_evaluate_object(_Qxx) won't be a blocking point, and extending the referenced period to the end of the evaluation,
> 2. adding 1 more patch to the ACPICA series, using a flag to bypass the automatic GPE disabling/enabling,
> 3. adding 1 more patch to make EC event poller  to disable GPE when sleeping,
> Linux EC driver can run without GPE enabled when idle.
> Which means GPE is enabled only when:
> 1. there is an EC command issued from the EC space handler or
> 2. the event poller thread is timed out or woken up by the EVT_SCI.
> 
> So I hope this IO driver enhancement can be a good material to show such possibility.

Yes, it is a good patchset, but I'd like to merge it in an ordered way.
That is, ACPICA upstream first, patches for Linux from that, the EC series on
top of this.  OK?

Rafael


^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention.
  2014-07-22 22:15       ` Rafael J. Wysocki
@ 2014-07-23  1:31         ` Zheng, Lv
  0 siblings, 0 replies; 63+ messages in thread
From: Zheng, Lv @ 2014-07-23  1:31 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Wysocki, Rafael J, Brown, Len, Lv Zheng, linux-kernel,
	linux-acpi, Moore, Robert

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 2492 bytes --]

Hi,

> From: Rafael J. Wysocki [mailto:rjw@rjwysocki.net]
> Sent: Wednesday, July 23, 2014 6:15 AM
> 
> On Tuesday, July 22, 2014 01:25:00 AM Zheng, Lv wrote:
> > Hi, Rafael
> >
> > > From: Rafael J. Wysocki [mailto:rjw@rjwysocki.net]
> > > Sent: Tuesday, July 22, 2014 9:12 AM
> > >
> > > On Monday, July 21, 2014 02:04:51 PM Lv Zheng wrote:
> > > > Note that this patchset is very stable now, it is sent as RFC because it
> > > > depends on an ACPICA GPE enhancement series which might be merged from
> > > > ACPICA upstream.
> > >
> > > Do I remember correctly that this is the plan?
> > >
> > > So I'm expecting to receive the Linux versions of the relevant ACPICA changes
> > > from you and then I'll apply this material on top of them.
> > >
> > > We don't need to wait for the next ACPICA release with this I think, but
> > > I'd like the GPE changes to be applied to upstream ACPICA at least before
> > > I get them.
> >
> > Yes, I'm trying.
> > I'll re-send this series after an ACPICA release cycle that contains the dependent GPE series.
> >
> > Let me highlight the real value of this EC series:
> > This is a good IO driver material to demonstrate:
> > 1. runtime idle: this is not implemented yet because of ACPICA issues that are not root caused, let me show this possibility this
> below.
> > 2. storming safe: can also deal with all kinds of silicon without worrying about IRQ storming.
> >
> > On top of this, after
> > 1. making sure that acpi_evaluate_object(_Qxx) won't be a blocking point, and extending the referenced period to the end of the
> evaluation,
> > 2. adding 1 more patch to the ACPICA series, using a flag to bypass the automatic GPE disabling/enabling,
> > 3. adding 1 more patch to make EC event poller  to disable GPE when sleeping,
> > Linux EC driver can run without GPE enabled when idle.
> > Which means GPE is enabled only when:
> > 1. there is an EC command issued from the EC space handler or
> > 2. the event poller thread is timed out or woken up by the EVT_SCI.
> >
> > So I hope this IO driver enhancement can be a good material to show such possibility.
> 
> Yes, it is a good patchset, but I'd like to merge it in an ordered way.
> That is, ACPICA upstream first, patches for Linux from that, the EC series on
> top of this.  OK?

Sure.

Thanks and best regards
-Lv

> 
> Rafael

ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v4 0/6] ACPI / EC: Fix GPE handling related races.
  2014-06-18  3:17 [PATCH 0/9] ACPI/EC: Improve GPE handling model Lv Zheng
                   ` (12 preceding siblings ...)
  2014-07-21  6:04 ` [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
@ 2015-02-05  8:24 ` Lv Zheng
  2015-02-05  8:27   ` [PATCH v4 1/6] ACPICA: Events: Introduce ACPI_GPE_DISPATCH_RAW_HANDLER to fix 2 issues for the current GPE APIs Lv Zheng
                     ` (6 more replies)
  13 siblings, 7 replies; 63+ messages in thread
From: Lv Zheng @ 2015-02-05  8:24 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patchset is based on ACPICA 20150204 release.

This patchset introduces a GPE raw handler mode and switches EC driver into
a GPE raw handler mode user.

The EC driver is a kind of the hardware driver that wants to control the
interrupt handling itself (for example, implementing the storming
prevention or the burst mode). But it has no mean to do so using the EC
firmware provided commands. The EC driver has to rely on the GPE APIs to
achieve the interrupt controlling.
Due to the shortcoming of the current ACPICA GPE APIs, the EC driver is
using the GPE APIs in a racy way. We then can see many issues between the
ACPICA internal GPE controlling and the EC driver's GPE handling. Such
races prevents us from correctly root causing other EC issues. This
patchset fixes the GPE related race issues by holding the EC state machine
lock for the whole EC GPE handling process:
  Lock(EC)        <- EC lock
  if (STS==1)     <- GPE API
    STS=0         <- GPE API
  EC_SC read      <- EC GPE handler
  EC_SC handled   <- EC GPE handler
  Unlock(EC)      <- EC lock

We can see several GPE handling stuffs improved by applying this patchset
because of EC/GPE races fixed:
1. Some platforms may suffer from GPE loss, which is because GPE is handled
   in the polling mode with its GPE indication left uncleared, the
   uncleared indication may stop further GPEs from being triggered.
   This patchset can make sure the indication has been cleared before
   handling, thus it may have fixed the potential root cause of the bugs
   that were originally fixed by the MSI quirk.
2. We originally can see many no-op EC GPE handler invocations, which is
   becaue GPE can be handled in the task context after the GPE IRQ handler
   is invoked, then when the driver goes back to the handler, there is no
   indication left for it to handle.
   This patchset can reduce the number of no-op EC GPE handler invocations
   to almost 0 by fixing the races, thus it may have fixed the potential
   root cause of the issues that were originally fixed by the storming
   condition threshold quirk.

Lv Zheng (6):
  ACPICA: Events: Introduce ACPI_GPE_DISPATCH_RAW_HANDLER to fix 2
    issues for the current GPE APIs.
  ACPICA: Events: Introduce acpi_set_gpe()/acpi_finish_gpe() to reduce
    divergences.
  ACPICA: Events: Enable APIs to allow interrupt/polling adaptive
    request based GPE handling model.
  ACPI / EC: Fix several GPE handling issues by deploying
    ACPI_GPE_DISPATCH_RAW_HANDLER mode.
  ACPI / EC: Reduce ec_poll() by referencing the last register access
    timestamp.
  ACPI / EC: Update revision due to raw handler mode.

 drivers/acpi/acpica/evgpe.c     |   52 +++++++++++++++---
 drivers/acpi/acpica/evgpeblk.c  |    2 +
 drivers/acpi/acpica/evgpeinit.c |    6 +-
 drivers/acpi/acpica/evgpeutil.c |    6 +-
 drivers/acpi/acpica/evxface.c   |  115 +++++++++++++++++++++++++++++++++++----
 drivers/acpi/acpica/evxfgpe.c   |  114 ++++++++++++++++++++++++++++++++++++++
 drivers/acpi/ec.c               |  104 ++++++++++++++++++++++++++++++-----
 include/acpi/acpixf.h           |    8 +++
 include/acpi/actypes.h          |   11 ++--
 9 files changed, 375 insertions(+), 43 deletions(-)

-- 
1.7.10


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v4 1/6] ACPICA: Events: Introduce ACPI_GPE_DISPATCH_RAW_HANDLER to fix 2 issues for the current GPE APIs.
  2015-02-05  8:24 ` [PATCH v4 0/6] ACPI / EC: Fix GPE handling related races Lv Zheng
@ 2015-02-05  8:27   ` Lv Zheng
  2015-02-05  8:27   ` [PATCH v4 2/6] ACPICA: Events: Introduce acpi_set_gpe()/acpi_finish_gpe() to reduce divergences Lv Zheng
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2015-02-05  8:27 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, Bob Moore

ACPICA commit 199cad16530a45aea2bec98e528866e20c5927e1

Since whether the GPE should be disabled/enabled/cleared should only be
determined by the GPE driver's state machine:
1. GPE should be disabled if the driver wants to switch to the GPE polling
   mode when a GPE storm condition is indicated and should be enabled if
   the driver wants to switch back to the GPE interrupt mode when all of
   the storm conditions are cleared. The conditions should be protected by
   the driver's specific lock.
2. GPE should be enabled if the driver has accepted more than one request
   and should be disabled if the driver has completed all of the requests.
   The request count should be protected by the driver's specific lock.
3. GPE should be cleared either when the driver is about to handle an edge
   triggered GPE or when the driver has completed to handle a level
   triggered GPE. The handling code should be protected by the driver's
   specific lock.
Thus the GPE enabling/disabling/clearing operations are likely to be
performed with the driver's specific lock held while we currently cannot do
this. This is because:
1. We have the acpi_gbl_gpe_lock held before invoking the GPE driver's
   handler. Driver's specific lock is likely to be held inside of the
   handler, thus we can see some dead lock issues due to the reversed
   locking order or recursive locking. In order to solve such dead lock
   issues, we need to unlock the acpi_gbl_gpe_lock before invoking the
   handler. BZ 1100.
2. Since GPE disabling/enabling/clearing should be determined by the GPE
   driver's state machine, we shouldn't perform such operations inside of
   ACPICA for a GPE handler to mess up the driver's state machine. BZ 1101.

Originally this patch includes a logic to flush GPE handlers, it is dropped
due to the following reasons:
1. This is a different issue;
2. Linux OSL has fixed this by flushing SCI in acpi_os_wait_events_complete().
We will pick up this topic when the Linux OSL fix turns out to be not
sufficient.

Note that currently the internal operations and the acpi_gbl_gpe_lock are
also used by ACPI_GPE_DISPATCH_METHOD and ACPI_GPE_DISPATCH_NOTIFY. In
order not to introduce regressions, we add one
ACPI_GPE_DISPATCH_RAW_HANDLER type to be distiguished from
ACPI_GPE_DISPATCH_HANDLER. For which the acpi_gbl_gpe_lock is unlocked before
invoking the GPE handler and the internal enabling/disabling operations are
bypassed to allow drivers to perform them at a proper position using the
GPE APIs and ACPI_GPE_DISPATCH_RAW_HANDLER users should invoke acpi_set_gpe()
instead of acpi_enable_gpe()/acpi_disable_gpe() to bypass the internal GPE
clearing code in acpi_enable_gpe(). Lv Zheng.

Known issues:
1. Edge-triggered GPE lost for frequent enablings
   On some buggy silicon platforms, GPE enable line may not be directly
   wired to the GPE trigger line. In that case, when GPE enabling is
   frequently performed for edge-triggered GPEs, GPE status may stay set
   without being triggered.
   This patch may maginify this problem as it allows GPE enabling to be
   parallel performed during the process the GPEs are handled.
   This is an existing issue, because:
   1. For task context:
      Current ACPI_GPE_DISPATCH_METHOD practices have proven that this
      isn't a real issue - we can re-enable edge-triggered GPE in a work
      queue where the GPE status bit might already be set.
   2. For IRQ context:
      This can even happen when the GPE enabling occurs before returning
      from the GPE handler and after unlocking the GPE lock.
   Thus currently no code is included to protect this.

Link: https://github.com/acpica/acpica/commit/199cad16
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
---
 drivers/acpi/acpica/evgpe.c     |   52 +++++++++++++++---
 drivers/acpi/acpica/evgpeblk.c  |    2 +
 drivers/acpi/acpica/evgpeinit.c |    6 +-
 drivers/acpi/acpica/evgpeutil.c |    6 +-
 drivers/acpi/acpica/evxface.c   |  115 +++++++++++++++++++++++++++++++++++----
 include/acpi/acpixf.h           |    8 +++
 include/acpi/actypes.h          |   11 ++--
 7 files changed, 171 insertions(+), 29 deletions(-)

diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index 836c79b..5ed064e 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -332,6 +332,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list)
 	struct acpi_gpe_register_info *gpe_register_info;
 	struct acpi_gpe_event_info *gpe_event_info;
 	u32 gpe_number;
+	struct acpi_gpe_handler_info *gpe_handler_info;
 	u32 int_status = ACPI_INTERRUPT_NOT_HANDLED;
 	u8 enabled_status_byte;
 	u32 status_reg;
@@ -455,14 +456,49 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list)
 						     acpi_gbl_global_event_handler_context);
 					}
 
-					/*
-					 * Found an active GPE. Dispatch the event to a handler
-					 * or method.
-					 */
-					int_status |=
-					    acpi_ev_gpe_dispatch(gpe_device,
-								 gpe_event_info,
-								 gpe_number);
+					/* Found an active GPE */
+
+					if (ACPI_GPE_DISPATCH_TYPE
+					    (gpe_event_info->flags) ==
+					    ACPI_GPE_DISPATCH_RAW_HANDLER) {
+
+						/* Dispatch the event to a raw handler */
+
+						gpe_handler_info =
+						    gpe_event_info->dispatch.
+						    handler;
+
+						/*
+						 * There is no protection around the namespace node
+						 * and the GPE handler to ensure a safe destruction
+						 * because:
+						 * 1. The namespace node is expected to always
+						 *    exist after loading a table.
+						 * 2. The GPE handler is expected to be flushed by
+						 *    acpi_os_wait_events_complete() before the
+						 *    destruction.
+						 */
+						acpi_os_release_lock
+						    (acpi_gbl_gpe_lock, flags);
+						int_status |=
+						    gpe_handler_info->
+						    address(gpe_device,
+							    gpe_number,
+							    gpe_handler_info->
+							    context);
+						flags =
+						    acpi_os_acquire_lock
+						    (acpi_gbl_gpe_lock);
+					} else {
+						/*
+						 * Dispatch the event to a standard handler or
+						 * method.
+						 */
+						int_status |=
+						    acpi_ev_gpe_dispatch
+						    (gpe_device, gpe_event_info,
+						     gpe_number);
+					}
 				}
 			}
 		}
diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c
index ce2a7cf..e0f24c5 100644
--- a/drivers/acpi/acpica/evgpeblk.c
+++ b/drivers/acpi/acpica/evgpeblk.c
@@ -478,6 +478,8 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
 			     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)
 			    || (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
 				continue;
 			}
diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c
index 7670508..8840296 100644
--- a/drivers/acpi/acpica/evgpeinit.c
+++ b/drivers/acpi/acpica/evgpeinit.c
@@ -401,8 +401,10 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle,
 		return_ACPI_STATUS(AE_OK);
 	}
 
-	if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
-	    ACPI_GPE_DISPATCH_HANDLER) {
+	if ((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 there is already a handler, ignore this GPE method */
 
diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c
index c369b19..3a958f3 100644
--- a/drivers/acpi/acpica/evgpeutil.c
+++ b/drivers/acpi/acpica/evgpeutil.c
@@ -324,8 +324,10 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
 								 ACPI_GPE_REGISTER_WIDTH)
 								+ j];
 
-			if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
-			    ACPI_GPE_DISPATCH_HANDLER) {
+			if ((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)) {
 
 				/* Delete an installed handler block */
 
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index 6d04ae9..81f2d9e 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -51,6 +51,16 @@
 
 #define _COMPONENT          ACPI_EVENTS
 ACPI_MODULE_NAME("evxface")
+#if (!ACPI_REDUCED_HARDWARE)
+/* Local prototypes */
+static acpi_status
+acpi_ev_install_gpe_handler(acpi_handle gpe_device,
+			    u32 gpe_number,
+			    u32 type,
+			    u8 is_raw_handler,
+			    acpi_gpe_handler address, void *context);
+
+#endif
 
 
 /*******************************************************************************
@@ -76,6 +86,7 @@ ACPI_MODULE_NAME("evxface")
  *              handlers.
  *
  ******************************************************************************/
+
 acpi_status
 acpi_install_notify_handler(acpi_handle device,
 			    u32 handler_type,
@@ -717,32 +728,37 @@ ACPI_EXPORT_SYMBOL(acpi_remove_fixed_event_handler)
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_install_gpe_handler
+ * FUNCTION:    acpi_ev_install_gpe_handler
  *
  * PARAMETERS:  gpe_device      - Namespace node for the GPE (NULL for FADT
  *                                defined GPEs)
  *              gpe_number      - The GPE number within the GPE block
  *              type            - Whether this GPE should be treated as an
  *                                edge- or level-triggered interrupt.
+ *              is_raw_handler  - Whether this GPE should be handled using
+ *                                the special GPE handler mode.
  *              address         - Address of the handler
  *              context         - Value passed to the handler on each GPE
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Install a handler for a General Purpose Event.
+ * DESCRIPTION: Internal function to install a handler for a General Purpose
+ *              Event.
  *
  ******************************************************************************/
-acpi_status
-acpi_install_gpe_handler(acpi_handle gpe_device,
-			 u32 gpe_number,
-			 u32 type, acpi_gpe_handler address, void *context)
+static acpi_status
+acpi_ev_install_gpe_handler(acpi_handle gpe_device,
+			    u32 gpe_number,
+			    u32 type,
+			    u8 is_raw_handler,
+			    acpi_gpe_handler address, void *context)
 {
 	struct acpi_gpe_event_info *gpe_event_info;
 	struct acpi_gpe_handler_info *handler;
 	acpi_status status;
 	acpi_cpu_flags flags;
 
-	ACPI_FUNCTION_TRACE(acpi_install_gpe_handler);
+	ACPI_FUNCTION_TRACE(ev_install_gpe_handler);
 
 	/* Parameter validation */
 
@@ -775,8 +791,10 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
 
 	/* Make sure that there isn't a handler there already */
 
-	if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
-	    ACPI_GPE_DISPATCH_HANDLER) {
+	if ((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)) {
 		status = AE_ALREADY_EXISTS;
 		goto free_and_exit;
 	}
@@ -817,7 +835,10 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
 
 	gpe_event_info->flags &=
 	    ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
-	gpe_event_info->flags |= (u8)(type | ACPI_GPE_DISPATCH_HANDLER);
+	gpe_event_info->flags |=
+	    (u8)(type |
+		 (is_raw_handler ? ACPI_GPE_DISPATCH_RAW_HANDLER :
+		  ACPI_GPE_DISPATCH_HANDLER));
 
 	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
 
@@ -831,10 +852,78 @@ free_and_exit:
 	goto unlock_and_exit;
 }
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_install_gpe_handler
+ *
+ * PARAMETERS:  gpe_device      - Namespace node for the GPE (NULL for FADT
+ *                                defined GPEs)
+ *              gpe_number      - The GPE number within the GPE block
+ *              type            - Whether this GPE should be treated as an
+ *                                edge- or level-triggered interrupt.
+ *              address         - Address of the handler
+ *              context         - Value passed to the handler on each GPE
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Install a handler for a General Purpose Event.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_install_gpe_handler(acpi_handle gpe_device,
+			 u32 gpe_number,
+			 u32 type, acpi_gpe_handler address, void *context)
+{
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE(acpi_install_gpe_handler);
+
+	status =
+	    acpi_ev_install_gpe_handler(gpe_device, gpe_number, type, FALSE,
+					address, context);
+
+	return_ACPI_STATUS(status);
+}
+
 ACPI_EXPORT_SYMBOL(acpi_install_gpe_handler)
 
 /*******************************************************************************
  *
+ * FUNCTION:    acpi_install_gpe_raw_handler
+ *
+ * PARAMETERS:  gpe_device      - Namespace node for the GPE (NULL for FADT
+ *                                defined GPEs)
+ *              gpe_number      - The GPE number within the GPE block
+ *              type            - Whether this GPE should be treated as an
+ *                                edge- or level-triggered interrupt.
+ *              address         - Address of the handler
+ *              context         - Value passed to the handler on each GPE
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Install a handler for a General Purpose Event.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_install_gpe_raw_handler(acpi_handle gpe_device,
+			     u32 gpe_number,
+			     u32 type, acpi_gpe_handler address, void *context)
+{
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE(acpi_install_gpe_raw_handler);
+
+	status = acpi_ev_install_gpe_handler(gpe_device, gpe_number, type, TRUE,
+					     address, context);
+
+	return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_install_gpe_raw_handler)
+
+/*******************************************************************************
+ *
  * FUNCTION:    acpi_remove_gpe_handler
  *
  * PARAMETERS:  gpe_device      - Namespace node for the GPE (NULL for FADT
@@ -881,8 +970,10 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
 
 	/* Make sure that a handler is indeed installed */
 
-	if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
-	    ACPI_GPE_DISPATCH_HANDLER) {
+	if ((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)) {
 		status = AE_NOT_EXIST;
 		goto unlock_and_exit;
 	}
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 96e4ef3..d56f5d7 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -569,6 +569,14 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
 							  address,
 							  void *context))
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
+				 acpi_install_gpe_raw_handler(acpi_handle
+							      gpe_device,
+							      u32 gpe_number,
+							      u32 type,
+							      acpi_gpe_handler
+							      address,
+							      void *context))
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
 				 acpi_remove_gpe_handler(acpi_handle gpe_device,
 							 u32 gpe_number,
 							 acpi_gpe_handler
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h
index 453cebb..b034f10 100644
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -744,7 +744,7 @@ typedef u32 acpi_event_status;
 /*
  * GPE info flags - Per GPE
  * +-------+-+-+---+
- * |  7:4  |3|2|1:0|
+ * |  7:5  |4|3|2:0|
  * +-------+-+-+---+
  *     |    | |  |
  *     |    | |  +-- Type of dispatch:to method, handler, notify, or none
@@ -756,14 +756,15 @@ typedef u32 acpi_event_status;
 #define ACPI_GPE_DISPATCH_METHOD        (u8) 0x01
 #define ACPI_GPE_DISPATCH_HANDLER       (u8) 0x02
 #define ACPI_GPE_DISPATCH_NOTIFY        (u8) 0x03
-#define ACPI_GPE_DISPATCH_MASK          (u8) 0x03
+#define ACPI_GPE_DISPATCH_RAW_HANDLER   (u8) 0x04
+#define ACPI_GPE_DISPATCH_MASK          (u8) 0x07
 #define ACPI_GPE_DISPATCH_TYPE(flags)   ((u8) ((flags) & ACPI_GPE_DISPATCH_MASK))
 
-#define ACPI_GPE_LEVEL_TRIGGERED        (u8) 0x04
+#define ACPI_GPE_LEVEL_TRIGGERED        (u8) 0x08
 #define ACPI_GPE_EDGE_TRIGGERED         (u8) 0x00
-#define ACPI_GPE_XRUPT_TYPE_MASK        (u8) 0x04
+#define ACPI_GPE_XRUPT_TYPE_MASK        (u8) 0x08
 
-#define ACPI_GPE_CAN_WAKE               (u8) 0x08
+#define ACPI_GPE_CAN_WAKE               (u8) 0x10
 
 /*
  * Flags for GPE and Lock interfaces
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v4 2/6] ACPICA: Events: Introduce acpi_set_gpe()/acpi_finish_gpe() to reduce divergences.
  2015-02-05  8:24 ` [PATCH v4 0/6] ACPI / EC: Fix GPE handling related races Lv Zheng
  2015-02-05  8:27   ` [PATCH v4 1/6] ACPICA: Events: Introduce ACPI_GPE_DISPATCH_RAW_HANDLER to fix 2 issues for the current GPE APIs Lv Zheng
@ 2015-02-05  8:27   ` Lv Zheng
  2015-02-05  8:27   ` [PATCH v4 3/6] ACPICA: Events: Enable APIs to allow interrupt/polling adaptive request based GPE handling model Lv Zheng
                     ` (4 subsequent siblings)
  6 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2015-02-05  8:27 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This can help to reduce source code differences between Linux and ACPICA
upstream. Further driver cleanups also require these APIs to eliminate GPE
storms.
1. acpi_set_gpe(): An API that driver should invoke in the case it wants
                   to disable/enable IRQ without honoring the reference
                   count implemented in the acpi_disable_gpe() and
                   acpi_enable_gpe(). Note that this API should only be
                   invoked inside a acpi_enable_gpe()/acpi_disable_gpe()
                   pair.
2. acpi_finish_gpe(): Drivers returned ACPI_REENABLE_GPE unset from the
                      GPE handler should use this API instead of
                      invoking acpi_set_gpe()/acpi_enable_gpe() to
                      re-enable the GPE.
The GPE APIs can be invoked inside of a GPE handler or in the task context
with a driver provided lock held. This driver provided lock is safe to be
held in the GPE handler by the driver.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/acpica/evxfgpe.c |  105 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 105 insertions(+)

diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c
index b8af53b..caaeb1a 100644
--- a/drivers/acpi/acpica/evxfgpe.c
+++ b/drivers/acpi/acpica/evxfgpe.c
@@ -183,6 +183,68 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number)
 
 ACPI_EXPORT_SYMBOL(acpi_disable_gpe)
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_set_gpe
+ *
+ * PARAMETERS:  gpe_device          - Parent GPE Device. NULL for GPE0/GPE1
+ *              gpe_number          - GPE level within the GPE block
+ *              action              - ACPI_GPE_ENABLE or ACPI_GPE_DISABLE
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Enable or disable an individual GPE. This function bypasses
+ *              the reference count mechanism used in the acpi_enable_gpe and
+ *              acpi_disable_gpe interfaces -- and should be used with care.
+ *
+ * Note: Typically used to disable a runtime GPE for short period of time,
+ * then re-enable it, without disturbing the existing reference counts. This
+ * is useful, for example, in the Embedded Controller (EC) driver.
+ *
+ ******************************************************************************/
+acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action)
+{
+	struct acpi_gpe_event_info *gpe_event_info;
+	acpi_status status;
+	acpi_cpu_flags flags;
+
+	ACPI_FUNCTION_TRACE(acpi_set_gpe);
+
+	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+	/* Ensure that we have a valid GPE number */
+
+	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+	if (!gpe_event_info) {
+		status = AE_BAD_PARAMETER;
+		goto unlock_and_exit;
+	}
+
+	/* Perform the action */
+
+	switch (action) {
+	case ACPI_GPE_ENABLE:
+
+		status = acpi_ev_enable_gpe(gpe_event_info);
+		break;
+
+	case ACPI_GPE_DISABLE:
+
+		status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
+		break;
+
+	default:
+
+		status = AE_BAD_PARAMETER;
+		break;
+	}
+
+unlock_and_exit:
+	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+	return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_set_gpe)
 
 /*******************************************************************************
  *
@@ -530,6 +592,49 @@ unlock_and_exit:
 
 ACPI_EXPORT_SYMBOL(acpi_get_gpe_status)
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_finish_gpe
+ *
+ * PARAMETERS:  gpe_device          - Namespace node for the GPE Block
+ *                                    (NULL for FADT defined GPEs)
+ *              gpe_number          - GPE level within the GPE block
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Clear and conditionally reenable a GPE. This completes the GPE
+ *              processing. Intended for use by asynchronous host-installed
+ *              GPE handlers. The GPE is only reenabled if the enable_for_run bit
+ *              is set in the GPE info.
+ *
+ ******************************************************************************/
+acpi_status acpi_finish_gpe(acpi_handle gpe_device, u32 gpe_number)
+{
+	struct acpi_gpe_event_info *gpe_event_info;
+	acpi_status status;
+	acpi_cpu_flags flags;
+
+	ACPI_FUNCTION_TRACE(acpi_finish_gpe);
+
+	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+	/* Ensure that we have a valid GPE number */
+
+	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+	if (!gpe_event_info) {
+		status = AE_BAD_PARAMETER;
+		goto unlock_and_exit;
+	}
+
+	status = acpi_ev_finish_gpe(gpe_event_info);
+
+unlock_and_exit:
+	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+	return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_finish_gpe)
+
 /******************************************************************************
  *
  * FUNCTION:    acpi_disable_all_gpes
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v4 3/6] ACPICA: Events: Enable APIs to allow interrupt/polling adaptive request based GPE handling model.
  2015-02-05  8:24 ` [PATCH v4 0/6] ACPI / EC: Fix GPE handling related races Lv Zheng
  2015-02-05  8:27   ` [PATCH v4 1/6] ACPICA: Events: Introduce ACPI_GPE_DISPATCH_RAW_HANDLER to fix 2 issues for the current GPE APIs Lv Zheng
  2015-02-05  8:27   ` [PATCH v4 2/6] ACPICA: Events: Introduce acpi_set_gpe()/acpi_finish_gpe() to reduce divergences Lv Zheng
@ 2015-02-05  8:27   ` Lv Zheng
  2015-02-05  8:27   ` [PATCH v4 4/6] ACPI / EC: Fix several GPE handling issues by deploying ACPI_GPE_DISPATCH_RAW_HANDLER mode Lv Zheng
                     ` (3 subsequent siblings)
  6 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2015-02-05  8:27 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown
  Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi, David E. Box, Bob Moore

ACPICA commit da9a83e1a845f2d7332bdbc0632466b2595e5424

For acpi_set_gpe()/acpi_enable_gpe(), our target is to purify them to be APIs
that can be used for various GPE handling models, so we need them to be
pure GPE enabling APIs. GPE enabling/disabling has 2 use cases:
1. Driver may permanently enable/disable GPEs according to the usage
   counts.
   1. When upper layers (the users of the driver) submit requests to the
      driver, it means they care about the underlying hardware. GPE need
      to be enabled for the first request submission and disabled for the
      last request completion.
   2. When the GPE is shared between 2+ silicon logics. GPE need to be
      enabled for either silicon logic's driver and disabled when all of
      the drivers are not started.
   For these cases, acpi_enable_gpe()/acpi_disable_gpe() should be used. When
   the usage count is increased from 0 to 1, the GPE is enabled and it is
   disabled when the usage count is decrased from 1 to 0.
2. Driver may temporarily disables the GPE to enter an GPE polling mode and
   wants to re-enable it later.
   1. Prevent GPE storming: when a driver cannot fully solve the condition
      that triggered the GPE in the GPE context, in order not to trigger
      GPE storm, driver has to disable GPE to switch into the polling mode
      and re-enables it in the non interrupt context after the storming
      condition is cleared.
   2. Meet throughput requirement: some IO drivers need to poll hardware
      again and again until nothing indicated instead of just handling once
      for one interruption, this need to be done in the polling mode or the
      IO flood may prevent the GPE handler from returning.
   3. Meet realtime requirement: in order not to block CPU to handle higher
      realtime prioritized GPEs, lower priority GPEs can be handled in the
      polling mode.
   For these cases, acpi_set_gpe() should be used to switch to/from the
   polling mode.

This patch adds unconditional GPE enabling support into acpi_set_gpe() so
that this API can be used by the drivers to switch back from the GPE
polling mode unconditionally.

Originally this function includes GPE clearing logic in it.
First, the GPE clearing is typically used in the GPE handling code to:
1. Acknowledge the GPE when we know there is an edge triggered GPE raised
   and is about to handle it, otherwise the unexpected clearing may lead to
   a GPE loss;
2. Issue actions after we have handled a level triggered GPE, otherwise
   the unexpected clearing may trigger unwanted OSPM actions to the
   hardware (for example, clocking in out-dated write FIFO data).
Thus the GPE clearing is not suitable to be used in the GPE enabling APIs.
Second, the combination of acknowledging and enabling may also not be
expected by the hardware drivers. For GPE clearing, we have a seperate API
acpi_clear_gpe(). There are cases drivers do want the 2 operations to be
split. So splitting these 2 operations could facilitates drivers the
maximum possibilities to achieve success. For a combined one, we already
have acpi_finish_gpe() ready to be invoked.

Given the fact that drivers should complete all outstanding requests before
putting themselves into the sleep states, as this API is executed for
outstanding requests, it should also have nothing to do with the
"RUN"/"WAKE" distinguishing. That's why the acpi_set_gpe(ACPI_GPE_ENABLE)
should not be implemented by acpi_hw_low_set_gpe(ACPI_GPE_CONDITIONAL_ENABLE).

This patch thus converts acpi_set_gpe(ACPI_GPE_ENABLE) into
acpi_hw_low_set_gpe(ACPI_GPE_ENABLE) to achieve a seperate GPE enabling API.
Drivers then are encouraged to use this API when they need to switch
to/from the GPE polling mode.

Note that the acpi_set_gpe()/acpi_finish_gpe() should be first introduced to
Linux using a divergence reduction patch before sending a linuxized version
of this patch. Lv Zheng.

Link: https://github.com/acpica/acpica/commit/da9a83e1
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: David E. Box <david.e.box@linux.intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
---
 drivers/acpi/acpica/evxfgpe.c |   23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c
index caaeb1a..70eb47e 100644
--- a/drivers/acpi/acpica/evxfgpe.c
+++ b/drivers/acpi/acpica/evxfgpe.c
@@ -194,12 +194,21 @@ ACPI_EXPORT_SYMBOL(acpi_disable_gpe)
  * RETURN:      Status
  *
  * DESCRIPTION: Enable or disable an individual GPE. This function bypasses
- *              the reference count mechanism used in the acpi_enable_gpe and
- *              acpi_disable_gpe interfaces -- and should be used with care.
- *
- * Note: Typically used to disable a runtime GPE for short period of time,
- * then re-enable it, without disturbing the existing reference counts. This
- * is useful, for example, in the Embedded Controller (EC) driver.
+ *              the reference count mechanism used in the acpi_enable_gpe(),
+ *              acpi_disable_gpe() interfaces.
+ *              This API is typically used by the GPE raw handler mode driver
+ *              to switch between the polling mode and the interrupt mode after
+ *              the driver has enabled the GPE.
+ *              The APIs should be invoked in this order:
+ *               acpi_enable_gpe()            <- Ensure the reference count > 0
+ *               acpi_set_gpe(ACPI_GPE_DISABLE) <- Enter polling mode
+ *               acpi_set_gpe(ACPI_GPE_ENABLE) <- Leave polling mode
+ *               acpi_disable_gpe()           <- Decrease the reference count
+ *
+ * Note: If a GPE is shared by 2 silicon components, then both the drivers
+ *       should support GPE polling mode or disabling the GPE for long period
+ *       for one driver may break the other. So use it with care since all
+ *       firmware _Lxx/_Exx handlers currently rely on the GPE interrupt mode.
  *
  ******************************************************************************/
 acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action)
@@ -225,7 +234,7 @@ acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action)
 	switch (action) {
 	case ACPI_GPE_ENABLE:
 
-		status = acpi_ev_enable_gpe(gpe_event_info);
+		status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE);
 		break;
 
 	case ACPI_GPE_DISABLE:
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v4 4/6] ACPI / EC: Fix several GPE handling issues by deploying ACPI_GPE_DISPATCH_RAW_HANDLER mode.
  2015-02-05  8:24 ` [PATCH v4 0/6] ACPI / EC: Fix GPE handling related races Lv Zheng
                     ` (2 preceding siblings ...)
  2015-02-05  8:27   ` [PATCH v4 3/6] ACPICA: Events: Enable APIs to allow interrupt/polling adaptive request based GPE handling model Lv Zheng
@ 2015-02-05  8:27   ` Lv Zheng
  2015-02-05  8:27   ` [PATCH v4 5/6] ACPI / EC: Reduce ec_poll() by referencing the last register access timestamp Lv Zheng
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2015-02-05  8:27 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

This patch switches EC driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode where
the GPE lock is not held for acpi_ec_gpe_handler() and the ACPICA internal
GPE enabling/disabling/clearing operations are bypassed so that further
improvements are possible with the GPE APIs.

There are 2 strong reasons for deploying raw GPE handler mode in the EC
driver:
1. Some hardware logics can control their interrupts via their own
   registers, so their interrupts can be disabled/enabled/acknowledged
   without using the super IRQ controller provided functions. While there
   is no mean (EC commands) for the EC driver to achieve this.
2. During suspending, the EC driver is still working for a while to
   complete the platform firmware provided functionailities using ec_poll()
   after all GPEs are disabled (see acpi_ec_block_transactions()), which
   means the EC driver will drive the EC GPE out of the GPE core's control.

Without deploying the raw GPE handler mode, we can see many races between
the EC driver and the GPE core due to the above restrictions:
1. There is a race condition due to ACPICA internal GPE
   disabling/clearing/enabling logics in acpi_ev_gpe_dispatch():
     Orignally EC GPE is disabled (EN=0), cleared (STS=0) before invoking a
     GPE handler and re-enabled (EN=1) after invoking a GPE handler in
     acpi_ev_gpe_dispatch(). When re-enabling appears, GPE may be flagged
     (STS=1).
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_dispatch()    ec_poll()
         EN=0
         STS=0
         acpi_ec_gpe_handler()
       *****************************************************************
       (event handling A)
           Lock(EC)
           advance_transaction()
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
           Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                   advance_transaction()
                                     EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                     EC_SC handled
                                   Unlock(EC)
       *****************************************************************
           EN=1
   This race condition is the root cause of different issues on different
   silicon variations.
   A. Silicon variation A:
      On some platforms, GPE will be triggered due to "writing 1 to EN when
      STS=1". This is because both EN and STS lines are wired to the GPE
      trigger line.
      1. Issue 1:
         We can see no-op acpi_ec_gpe_handler() invoked on such platforms.
         This is because:
         a. event pending B: An event can arrive after ACPICA's GPE
            clearing performed in acpi_ev_gpe_dispatch(), this event may
            fail to be detected by EC_SC read that is performed before its
            arrival;
         b. event handling B: The event can be handled in ec_poll() because
            EC lock is released after acpi_ec_gpe_handler() invocation;
         c. There is no code in ec_poll() to clear STS but the GPE can
            still be triggered by the EN=1 write performed in
            acpi_ev_finish_gpe(), this leads to a no-op EC GPE handler
            invocation;
         d. As no-op GPE handler invocations are counted by the EC driver
            to trigger the command storming conditions, the wrong no-op
            GPE handler invocations thus can easily trigger wrong command
            storming conditions.
         Note 1:
         If we removed GPE disabling/enabling code from
         acpi_ev_gpe_dispatch(), we could still see no-op GPE handlers
         triggered by the event arriving after the GPE clearing and before
         the GPE handling on both silicon variation A and B. This can only
         occur if the CPU is very slow (timing slice between STS=0 write
         and EC_SC read should be short enough before hardware sets another
         GPE indication). Thus this is very rare and is not what we need to
         fix.
   B. Silicon variation B:
      On other platforms, GPE may not be triggered due to "writing 1 to EN
      when STS=1". This is because only STS line is wired to the GPE
      trigger line.
      2. Issue 2:
         We can see GPE loss on such platforms. This is because:
         a. event pending B vs. event handling A: An event can arrive after
            ACPICA's GPE handling performed in acpi_ev_gpe_dispatch(), or
            event pending C vs. event handling B: An event can arrive after
            Linux's GPE handling performed in ec_poll(),
            these events may fail to be detected by EC_SC read that is
            performed before their arrival;
         b. The GPE cannot be triggered by EN=1 write performed in
            acpi_ev_finish_gpe();
         c. If no polling mechanism is implemented in the driver for the
            pending event (for example, SCI_EVT), this event is lost due to
            no GPE being triggered.
         Note 2:
         On most platforms, there might be another rule that GPE may not be
         triggered due to "writing 1 to STS when STS=1 and EN=1".
         Then on silicon variation B, an even worse case is if the issue 2
         event loss happens, further events may never trigger GPE again on
         such platforms due to being blocked by the current STS=1. Unless
         someone clears STS, all events have to be polled.
2. There is a race condition due to lacking in GPE status checking in EC
   driver:
     Originally, GPE status is checked in ACPICA core but not checked in
     the GPE handler. Thus since the status checking and handling is not
     locked, it can be interrupted by another handling path.
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_detect()        ec_poll()
         if (EN==1 && STS==1)
       *****************************************************************
       (event handling A)
                                     Lock(EC)
                                     advance_transaction()
                                       EC_SC read
                                       EC_SC handled
                                     Unlock(EC)
       *****************************************************************
         acpi_ev_gpe_dispatch()
           EN=0
           STS=0
           acpi_ec_gpe_handler()
       *****************************************************************
       (event handling B)
             Lock(EC)
             advance_transaction()
               EC_SC read
             Unlock(EC)
       *****************************************************************
      3. Issue 3:
         We can see no-op acpi_ec_gpe_handler() invoked on both silicon
         variation A and B. This is because:
         a. event pending A: An event can arrive to trigger an EC GPE and
            ACPICA checks it and is about to invoke the EC GPE handler;
         b. event handling A: The event can be handled in ec_poll() because
            EC lock is not held after the GPE status checking;
         c. event handling B: Then when the EC GPE handler is invoked, it
            becomes a no-op GPE handler invocation.
         d. As no-op GPE handler invocations are counted by the EC driver
            to trigger the command storming conditions, the wrong no-op
            GPE handler invocations thus can easily trigger wrong command
            storming conditions.
      Note 3:
      This no-op GPE handler invocation is rare because the time between
      the IRQ arrival and the acpi_ec_gpe_handler() invocation is less than
      the timeout value waited in ec_poll(). So most of the no-op GPE
      handler invocations are caused by the reason described in issue 1.
3. There is a race condition due to ACPICA internal GPE clearing logic in
   acpi_enable_gpe():
     During runtime, acpi_enable_gpe() can be invoked by the EC storming
     prevention code. When it is invoked, GPE may be flagged (STS=1).
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_dispatch()    acpi_ec_transaction()
         EN=0
         STS=0
         acpi_ec_gpe_handler()
       *****************************************************************
       (event handling A)
           Lock(EC)
           advance_transaction()
             EC_SC read
             EC_SC handled
           Unlock(EC)
       *****************************************************************
         EN=1 ?
                                   Lock(EC)
                                   Unlock(EC)
       =================================================================
       (event pending B)
       =================================================================
                                   acpi_enable_gpe()
                                     STS=0
                                     EN=1
    4. Issue 4:
       We can see GPE loss on both silicon variation A and B platforms.
       This is because:
       a. event pending B: An event can arrive right before ACPICA's GPE
          clearing performed in acpi_enable_gpe();
       b. If the GPE is cleared when GPE is disabled, then EN=1 write in
          acpi_enable_gpe() cannot trigger this GPE;
       c. If no polling mechanism is implemented in the driver for this
          event (for example, SCI_EVT), this event is lost due to no GPE
          being triggered.
       Note 4:
       Currently we don't have this issue, but after we switch the EC
       driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode, we need to take care
       of handling this because the EN=1 write in acpi_ev_gpe_dispatch()
       will be abandoned.

There might be more race issues for the current GPE handler usages. This is
because the EC IRQ's enabling/disabling/checking/clearing/handling
operations should be locked by a single lock that is under the EC driver's
control to achieve the serialization. Which means we need to invoke GPE
APIs with EC driver's lock held and all ACPICA internal GPE operations
related to the GPE handler should be abandoned. Invoking GPE APIs inside of
the EC driver lock and bypassing ACPICA internal GPE operations requires
the ACPI_GPE_DISPATCH_RAW_HANDLER mode where the same lock used by the APIs
are released prior than invoking the handlers. Otherwise, we can see dead
locks due to circular locking dependencies (see Reference below).

This patch then switches the EC driver into the
ACPI_GPE_DISPATCH_RAW_HANDLER mode so that it can perform correct GPE
operations using the GPE APIs:
1. Bypasses EN modifications performed in acpi_ev_gpe_dispatch() by
   using acpi_install_gpe_raw_handler() and invoking all GPE APIs with EC
   spin lock held. This can fix issue 1 as it makes a non frequent GPE
   enabling/disabling environment.
2. Bypasses STS clearing performed in acpi_enable_gpe() by replacing
   acpi_enable_gpe()/acpi_disable_gpe() with acpi_set_gpe(). This can fix
   issue 4. And this can also help to fix issue 1 as it makes a no sudden
   GPE clearing environment when GPE is frequently enabled/disabled.
3. Ensures STS acknowledged before handling by invoking acpi_clear_gpe()
   in advance_transaction(). This can finally fix issue 1 even in a
   frequent GPE enabling/disabling environment. And this can also finally
   fix issue 3 when issue 2 is fixed.
   Note 3:
   GPE clearing is edge triggered W1C, which means we can clear it right
   before handling it. Since all EC GPE indications are handled in
   advance_transaction() by previous commits, we can now move GPE clearing
   into it to implement the correct GPE clearing.
   Note 4:
   We can use acpi_set_gpe() which is not shared GPE safer instead of
   acpi_enable_gpe()/acpi_disable_gpe() because EC GPE is not shared by
   other hardware, which is mentioned in the ACPI specification 5.0, 12.6
   Interrupt Model: "OSPM driver treats this as an edge event (the EC SCI
   cannot be shared)". So we can stop using shared GPE safer APIs
   acpi_enable_gpe()/acpi_disable_gpe() in the EC driver. Otherwise
   cleanups need to be made in acpi_ev_enable_gpe() to bypass the GPE
   clearing logic before keeping acpi_enable_gpe().
This patch also invokes advance_transaction() when GPE is re-enabled in the
task context which:
1. Ensures EN=1 can trigger GPE by checking and handling EC status register
   right after EN=1 writes. This can fix issue 2.

After applying this patch, without frequent GPE enablings considered:
       =================================================================
       (event pending A)
       =================================================================
       acpi_ec_gpe_handler()     ec_poll()
       *****************************************************************
       (event handling A)
         Lock(EC)
           advance_transaction()
             if STS==1
               STS=0
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
         Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                     advance_transaction()
                                       if STS==1
                                         STS=0
                                       EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                       EC_SC handled
                                   Unlock(EC)
       *****************************************************************
The event pending for issue 1 (event pending B) can arrive as a next GPE
due to the previous IRQ context STS=0 write. And if it is handled by
ec_poll() (event handling B), as it is also acknowledged by ec_poll(), the
event pending for issue 2 (event pending C) can properly arrive as a next
GPE after the task context STS=0 write. So no GPE will be lost and never
triggered due to GPE clearing performed in the wrong position. And since
all GPE handling is performed after a locked GPE status checking, we can
hardly see no-op GPE handler invocations due to issue 1 and 3. We may still
see no-op GPE handler invocations due to "Note 1", but as it is inevitable,
it needn't be fixed.

After applying this patch, with frequent GPE enablings considered:
       =================================================================
       (event pending A)
       =================================================================
       acpi_ec_gpe_handler()     acpi_ec_transaction()
       *****************************************************************
       (event handling A)
         Lock(EC)
           advance_transaction()
             if STS==1
               STS=0
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
         Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                     EN=1
                                     if STS==1
                                       advance_transaction()
                                         if STS==1
                                           STS=0
                                         EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                         EC_SC handled
                                   Unlock(EC)
       *****************************************************************
The event pending for issue 2 can be manually handled by
advance_transaction(). And after the STS=0 write performed in the manual
triggered advance_transaction(), GPE can always arrive. So no GPE will be
lost due to frequent GPE disabling/enabling performed in the driver like
issue 4.
Note 5:
It's ideally when EN=1 write occurred, an IRQ thread should be woken up to
handle the GPE when the GPE was raised. But this requires the IRQ thread to
contain the poller code for all EC GPE indications, while currently some of
the indications are handled in the user tasks. It then is very hard for the
code to determine whether a user task should be invoked or the poller work
item should be scheduled. So we have to invoke advance_transaction()
directly now and it leaves us such a restriction for the GPE re-enabling:
it must be performed in the task context to avoid starving the GPEs.

As a conclusion: we can see the EC GPE is always handled in serial after
deploying the raw GPE handler mode:
  Lock(EC)
  if (STS==1)
    STS=0
  EC_SC read
  EC_SC handled
  Unlock(EC)
The EC driver specific lock is responsible to make the EC GPE handling
processes serialized so that EC can handle its GPE from both IRQ and task
contexts and the next IRQ can be ensured to arrive after this process.

Note 6:
We have many EC_FLAGS_MSI qurik users in the current driver. They all seem
to be suffering from unexpected GPE triggering source lost. And they are
false root caused to a timing issue. Since EC communication protocol has
already flow control defined, timing shouldn't be the root cause, while
this fix might be fixing the root cause of the old bugs.

Reference: https://lkml.org/lkml/2014/11/4/974
           https://lkml.org/lkml/2014/11/18/316
           https://www.spinics.net/lists/linux-acpi/msg54340.html
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   81 +++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 73 insertions(+), 8 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index c385606..2540870 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -121,6 +121,7 @@ struct transaction {
 };
 
 static int acpi_ec_query(struct acpi_ec *ec, u8 *data);
+static void advance_transaction(struct acpi_ec *ec);
 
 struct acpi_ec *boot_ec, *first_ec;
 EXPORT_SYMBOL(first_ec);
@@ -132,7 +133,7 @@ static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
 static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */
 
 /* --------------------------------------------------------------------------
- *                           Transaction Management
+ *                           EC Registers
  * -------------------------------------------------------------------------- */
 
 static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
@@ -191,6 +192,64 @@ static const char *acpi_ec_cmd_string(u8 cmd)
 #define acpi_ec_cmd_string(cmd)		"UNDEF"
 #endif
 
+/* --------------------------------------------------------------------------
+ *                           GPE Registers
+ * -------------------------------------------------------------------------- */
+
+static inline bool acpi_ec_is_gpe_raised(struct acpi_ec *ec)
+{
+	acpi_event_status gpe_status = 0;
+
+	(void)acpi_get_gpe_status(NULL, ec->gpe, &gpe_status);
+	return (gpe_status & ACPI_EVENT_FLAG_SET) ? true : false;
+}
+
+static inline void acpi_ec_enable_gpe(struct acpi_ec *ec, bool open)
+{
+	if (open)
+		acpi_enable_gpe(NULL, ec->gpe);
+	else
+		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
+	if (acpi_ec_is_gpe_raised(ec)) {
+		/*
+		 * On some platforms, EN=1 writes cannot trigger GPE. So
+		 * software need to manually trigger a pseudo GPE event on
+		 * EN=1 writes.
+		 */
+		pr_debug("***** Polling quirk *****\n");
+		advance_transaction(ec);
+	}
+}
+
+static inline void acpi_ec_disable_gpe(struct acpi_ec *ec, bool close)
+{
+	if (close)
+		acpi_disable_gpe(NULL, ec->gpe);
+	else
+		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
+}
+
+static inline void acpi_ec_clear_gpe(struct acpi_ec *ec)
+{
+	/*
+	 * GPE STS is a W1C register, which means:
+	 * 1. Software can clear it without worrying about clearing other
+	 *    GPEs' STS bits when the hardware sets them in parallel.
+	 * 2. As long as software can ensure only clearing it when it is
+	 *    set, hardware won't set it in parallel.
+	 * So software can clear GPE in any contexts.
+	 * Warning: do not move the check into advance_transaction() as the
+	 * EC commands will be sent without GPE raised.
+	 */
+	if (!acpi_ec_is_gpe_raised(ec))
+		return;
+	acpi_clear_gpe(NULL, ec->gpe);
+}
+
+/* --------------------------------------------------------------------------
+ *                           Transaction Management
+ * -------------------------------------------------------------------------- */
+
 static void acpi_ec_submit_query(struct acpi_ec *ec)
 {
 	if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
@@ -227,6 +286,12 @@ static void advance_transaction(struct acpi_ec *ec)
 
 	pr_debug("===== %s (%d) =====\n",
 		 in_interrupt() ? "IRQ" : "TASK", smp_processor_id());
+	/*
+	 * By always clearing STS before handling all indications, we can
+	 * ensure a hardware STS 0->1 change after this clearing can always
+	 * trigger a GPE interrupt.
+	 */
+	acpi_ec_clear_gpe(ec);
 	status = acpi_ec_read_status(ec);
 	t = ec->curr;
 	if (!t)
@@ -378,7 +443,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
 	/* disable GPE during transaction if storm is detected */
 	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
 		/* It has to be disabled, so that it doesn't trigger. */
-		acpi_disable_gpe(NULL, ec->gpe);
+		acpi_ec_disable_gpe(ec, false);
 	}
 
 	status = acpi_ec_transaction_unlocked(ec, t);
@@ -386,7 +451,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
 	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
 		msleep(1);
 		/* It is safe to enable the GPE outside of the transaction. */
-		acpi_enable_gpe(NULL, ec->gpe);
+		acpi_ec_enable_gpe(ec, false);
 	} else if (t->irq_count > ec_storm_threshold) {
 		pr_info("GPE storm detected(%d GPEs), "
 			"transactions will use polling mode\n",
@@ -693,7 +758,7 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
 	spin_lock_irqsave(&ec->lock, flags);
 	advance_transaction(ec);
 	spin_unlock_irqrestore(&ec->lock, flags);
-	return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE;
+	return ACPI_INTERRUPT_HANDLED;
 }
 
 /* --------------------------------------------------------------------------
@@ -812,13 +877,13 @@ static int ec_install_handlers(struct acpi_ec *ec)
 
 	if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags))
 		return 0;
-	status = acpi_install_gpe_handler(NULL, ec->gpe,
+	status = acpi_install_gpe_raw_handler(NULL, ec->gpe,
 				  ACPI_GPE_EDGE_TRIGGERED,
 				  &acpi_ec_gpe_handler, ec);
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
-	acpi_enable_gpe(NULL, ec->gpe);
+	acpi_ec_enable_gpe(ec, true);
 	status = acpi_install_address_space_handler(ec->handle,
 						    ACPI_ADR_SPACE_EC,
 						    &acpi_ec_space_handler,
@@ -833,7 +898,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
 			pr_err("Fail in evaluating the _REG object"
 				" of EC device. Broken bios is suspected.\n");
 		} else {
-			acpi_disable_gpe(NULL, ec->gpe);
+			acpi_ec_disable_gpe(ec, true);
 			acpi_remove_gpe_handler(NULL, ec->gpe,
 				&acpi_ec_gpe_handler);
 			return -ENODEV;
@@ -848,7 +913,7 @@ static void ec_remove_handlers(struct acpi_ec *ec)
 {
 	if (!test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags))
 		return;
-	acpi_disable_gpe(NULL, ec->gpe);
+	acpi_ec_disable_gpe(ec, true);
 	if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
 				ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
 		pr_err("failed to remove space handler\n");
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v4 5/6] ACPI / EC: Reduce ec_poll() by referencing the last register access timestamp.
  2015-02-05  8:24 ` [PATCH v4 0/6] ACPI / EC: Fix GPE handling related races Lv Zheng
                     ` (3 preceding siblings ...)
  2015-02-05  8:27   ` [PATCH v4 4/6] ACPI / EC: Fix several GPE handling issues by deploying ACPI_GPE_DISPATCH_RAW_HANDLER mode Lv Zheng
@ 2015-02-05  8:27   ` Lv Zheng
  2015-02-05  8:27   ` [PATCH v4 6/6] ACPI / EC: Update revision due to raw handler mode Lv Zheng
  2015-02-05 15:19   ` [PATCH v4 0/6] ACPI / EC: Fix GPE handling related races Rafael J. Wysocki
  6 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2015-02-05  8:27 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

Timeout in the ec_poll() doesn't refer to the last register access time. It
thus can win the competition against the acpi_ec_gpe_handler() if a
transaction takes longer than 1ms but individual register accesses are less
than 1ms.  In some cases, it can make the following silicon bug easier to
be triggered:
 GPE EN is not wired to the GPE trigger line, so when GPE STS is already
 set when 1 is written to GPE EN, no GPE can be triggered.

This patch adds register access timestamp reference support for ec_poll()
to reduce the number of ec_poll() invocations.

Reported-by: Venkat Raghavulu <venkat.raghavulu@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |   17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 2540870..e000cf7 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -71,6 +71,7 @@ enum ec_command {
 #define ACPI_EC_DELAY		500	/* Wait 500ms max. during EC ops */
 #define ACPI_EC_UDELAY_GLK	1000	/* Wait 1ms max. to get global lock */
 #define ACPI_EC_MSI_UDELAY	550	/* Wait 550us for MSI EC */
+#define ACPI_EC_UDELAY_POLL	1000	/* Wait 1ms for EC transaction polling */
 #define ACPI_EC_CLEAR_MAX	100	/* Maximum number of events to query
 					 * when trying to clear the EC */
 
@@ -118,6 +119,7 @@ struct transaction {
 	u8 wlen;
 	u8 rlen;
 	u8 flags;
+	unsigned long timestamp;
 };
 
 static int acpi_ec_query(struct acpi_ec *ec, u8 *data);
@@ -155,6 +157,7 @@ static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
 {
 	u8 x = inb(ec->data_addr);
 
+	ec->curr->timestamp = jiffies;
 	pr_debug("EC_DATA(R) = 0x%2.2x\n", x);
 	return x;
 }
@@ -163,12 +166,14 @@ static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
 {
 	pr_debug("EC_SC(W) = 0x%2.2x\n", command);
 	outb(command, ec->command_addr);
+	ec->curr->timestamp = jiffies;
 }
 
 static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
 {
 	pr_debug("EC_DATA(W) = 0x%2.2x\n", data);
 	outb(data, ec->data_addr);
+	ec->curr->timestamp = jiffies;
 }
 
 #ifdef DEBUG
@@ -359,6 +364,7 @@ static void start_transaction(struct acpi_ec *ec)
 {
 	ec->curr->irq_count = ec->curr->wi = ec->curr->ri = 0;
 	ec->curr->flags = 0;
+	ec->curr->timestamp = jiffies;
 	advance_transaction(ec);
 }
 
@@ -370,20 +376,25 @@ static int ec_poll(struct acpi_ec *ec)
 	while (repeat--) {
 		unsigned long delay = jiffies +
 			msecs_to_jiffies(ec_delay);
+		unsigned long usecs = ACPI_EC_UDELAY_POLL;
 		do {
 			/* don't sleep with disabled interrupts */
 			if (EC_FLAGS_MSI || irqs_disabled()) {
-				udelay(ACPI_EC_MSI_UDELAY);
+				usecs = ACPI_EC_MSI_UDELAY;
+				udelay(usecs);
 				if (ec_transaction_completed(ec))
 					return 0;
 			} else {
 				if (wait_event_timeout(ec->wait,
 						ec_transaction_completed(ec),
-						msecs_to_jiffies(1)))
+						usecs_to_jiffies(usecs)))
 					return 0;
 			}
 			spin_lock_irqsave(&ec->lock, flags);
-			advance_transaction(ec);
+			if (time_after(jiffies,
+					ec->curr->timestamp +
+					usecs_to_jiffies(usecs)))
+				advance_transaction(ec);
 			spin_unlock_irqrestore(&ec->lock, flags);
 		} while (time_before(jiffies, delay));
 		pr_debug("controller reset, restart transaction\n");
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v4 6/6] ACPI / EC: Update revision due to raw handler mode.
  2015-02-05  8:24 ` [PATCH v4 0/6] ACPI / EC: Fix GPE handling related races Lv Zheng
                     ` (4 preceding siblings ...)
  2015-02-05  8:27   ` [PATCH v4 5/6] ACPI / EC: Reduce ec_poll() by referencing the last register access timestamp Lv Zheng
@ 2015-02-05  8:27   ` Lv Zheng
  2015-02-05 15:19   ` [PATCH v4 0/6] ACPI / EC: Fix GPE handling related races Rafael J. Wysocki
  6 siblings, 0 replies; 63+ messages in thread
From: Lv Zheng @ 2015-02-05  8:27 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown; +Cc: Lv Zheng, Lv Zheng, linux-kernel, linux-acpi

The bug fixes around GPE races have been done to the EC driver by the
previous commits. This patch increases the revision to 3 to indicate the
behavior differences between the old and the new drivers. The
copyright/authorship notices are also updated.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
---
 drivers/acpi/ec.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index e000cf7..5563253 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1,8 +1,8 @@
 /*
- *  ec.c - ACPI Embedded Controller Driver (v2.2)
+ *  ec.c - ACPI Embedded Controller Driver (v3)
  *
- *  Copyright (C) 2001-2014 Intel Corporation
- *    Author: 2014       Lv Zheng <lv.zheng@intel.com>
+ *  Copyright (C) 2001-2015 Intel Corporation
+ *    Author: 2014, 2015 Lv Zheng <lv.zheng@intel.com>
  *            2006, 2007 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
  *            2006       Denis Sadykov <denis.m.sadykov@intel.com>
  *            2004       Luming Yu <luming.yu@intel.com>
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* Re: [PATCH v4 0/6] ACPI / EC: Fix GPE handling related races.
  2015-02-05  8:24 ` [PATCH v4 0/6] ACPI / EC: Fix GPE handling related races Lv Zheng
                     ` (5 preceding siblings ...)
  2015-02-05  8:27   ` [PATCH v4 6/6] ACPI / EC: Update revision due to raw handler mode Lv Zheng
@ 2015-02-05 15:19   ` Rafael J. Wysocki
  6 siblings, 0 replies; 63+ messages in thread
From: Rafael J. Wysocki @ 2015-02-05 15:19 UTC (permalink / raw)
  To: Lv Zheng; +Cc: Rafael J. Wysocki, Len Brown, Lv Zheng, linux-kernel, linux-acpi

On Thursday, February 05, 2015 04:24:29 PM Lv Zheng wrote:
> This patchset is based on ACPICA 20150204 release.
> 
> This patchset introduces a GPE raw handler mode and switches EC driver into
> a GPE raw handler mode user.
> 
> The EC driver is a kind of the hardware driver that wants to control the
> interrupt handling itself (for example, implementing the storming
> prevention or the burst mode). But it has no mean to do so using the EC
> firmware provided commands. The EC driver has to rely on the GPE APIs to
> achieve the interrupt controlling.
> Due to the shortcoming of the current ACPICA GPE APIs, the EC driver is
> using the GPE APIs in a racy way. We then can see many issues between the
> ACPICA internal GPE controlling and the EC driver's GPE handling. Such
> races prevents us from correctly root causing other EC issues. This
> patchset fixes the GPE related race issues by holding the EC state machine
> lock for the whole EC GPE handling process:
>   Lock(EC)        <- EC lock
>   if (STS==1)     <- GPE API
>     STS=0         <- GPE API
>   EC_SC read      <- EC GPE handler
>   EC_SC handled   <- EC GPE handler
>   Unlock(EC)      <- EC lock
> 
> We can see several GPE handling stuffs improved by applying this patchset
> because of EC/GPE races fixed:
> 1. Some platforms may suffer from GPE loss, which is because GPE is handled
>    in the polling mode with its GPE indication left uncleared, the
>    uncleared indication may stop further GPEs from being triggered.
>    This patchset can make sure the indication has been cleared before
>    handling, thus it may have fixed the potential root cause of the bugs
>    that were originally fixed by the MSI quirk.
> 2. We originally can see many no-op EC GPE handler invocations, which is
>    becaue GPE can be handled in the task context after the GPE IRQ handler
>    is invoked, then when the driver goes back to the handler, there is no
>    indication left for it to handle.
>    This patchset can reduce the number of no-op EC GPE handler invocations
>    to almost 0 by fixing the races, thus it may have fixed the potential
>    root cause of the issues that were originally fixed by the storming
>    condition threshold quirk.
> 
> Lv Zheng (6):
>   ACPICA: Events: Introduce ACPI_GPE_DISPATCH_RAW_HANDLER to fix 2
>     issues for the current GPE APIs.
>   ACPICA: Events: Introduce acpi_set_gpe()/acpi_finish_gpe() to reduce
>     divergences.
>   ACPICA: Events: Enable APIs to allow interrupt/polling adaptive
>     request based GPE handling model.
>   ACPI / EC: Fix several GPE handling issues by deploying
>     ACPI_GPE_DISPATCH_RAW_HANDLER mode.
>   ACPI / EC: Reduce ec_poll() by referencing the last register access
>     timestamp.
>   ACPI / EC: Update revision due to raw handler mode.
> 
>  drivers/acpi/acpica/evgpe.c     |   52 +++++++++++++++---
>  drivers/acpi/acpica/evgpeblk.c  |    2 +
>  drivers/acpi/acpica/evgpeinit.c |    6 +-
>  drivers/acpi/acpica/evgpeutil.c |    6 +-
>  drivers/acpi/acpica/evxface.c   |  115 +++++++++++++++++++++++++++++++++++----
>  drivers/acpi/acpica/evxfgpe.c   |  114 ++++++++++++++++++++++++++++++++++++++
>  drivers/acpi/ec.c               |  104 ++++++++++++++++++++++++++++++-----
>  include/acpi/acpixf.h           |    8 +++
>  include/acpi/actypes.h          |   11 ++--
>  9 files changed, 375 insertions(+), 43 deletions(-)

Whole series queued up for 3.20, thanks!


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 63+ messages in thread

end of thread, other threads:[~2015-02-05 14:56 UTC | newest]

Thread overview: 63+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-18  3:17 [PATCH 0/9] ACPI/EC: Improve GPE handling model Lv Zheng
2014-06-18  3:17 ` [PATCH 1/9] ACPICA: Events: Reduce indent divergences of events files Lv Zheng
2014-06-18  3:17 ` [PATCH 2/9] ACPICA: Events: Fix an issue that GPE APIs cannot be invoked in atomic context Lv Zheng
2014-06-18  3:17 ` [PATCH 3/9] ACPICA: Events: Introduce acpi_set_gpe()/acpi_finish_gpe() to reduce divergences Lv Zheng
2014-06-18  3:17 ` [PATCH 4/9] ACPICA: Events: Remove acpi_ev_enable_gpe() Lv Zheng
2014-06-18  3:17 ` [PATCH 5/9] ACPICA: Events: Reduce divergences to honor notify handler enabled GPEs Lv Zheng
2014-06-18  3:17 ` [PATCH 6/9] ACPI/EC: Introduce STARTED/STOPPED flags to replace BLOCKED flag Lv Zheng
2014-06-18  3:18 ` [PATCH 7/9] ACPI/EC: Add detailed command/query debugging information Lv Zheng
2014-06-18  3:18 ` [PATCH 8/9] ACPI/EC: Deploy the new GPE handling model Lv Zheng
2014-06-18  3:18 ` [PATCH 9/9] ACPI/EC: Add unit test support for EC driver hotplug Lv Zheng
2014-07-15  3:07 ` [PATCH v2 0/9] ACPICA: Improve GPE handling model Lv Zheng
2014-07-15  3:07   ` [PATCH v2 1/9] ACPICA: Events: Reduce indent divergences of events files Lv Zheng
2014-07-15  3:07   ` [PATCH v2 2/9] ACPICA: Events: Fix an issue that GPE APIs cannot be invoked in atomic context Lv Zheng
2014-07-15  3:07   ` [PATCH v2 3/9] ACPICA: Events: Fix an issue that GPE APIs cannot be invoked in deferred handlers Lv Zheng
2014-07-15  3:07   ` [PATCH v2 4/9] ACPICA: Events: Introduce acpi_set_gpe()/acpi_finish_gpe() to reduce divergences Lv Zheng
2014-07-15  3:07   ` [PATCH v2 5/9] ACPICA: Events: Fix an issue that acpi_set_gpe() cannot unconditionally enable GPEs Lv Zheng
2014-07-15  3:07   ` [PATCH v2 6/9] ACPICA: Events: Fix an issue that status of GPEs are unexpectedly cleared Lv Zheng
2014-07-15  3:07   ` [PATCH v2 7/9] ACPICA: Events: Fix an issue that originally_enabled check is not paired Lv Zheng
2014-07-15  3:08   ` [PATCH v2 8/9] ACPICA: Events: Add a flag to disable internal auto GPE clearing Lv Zheng
2014-07-15  3:08   ` [PATCH v2 9/9] ACPI: Update interrupt handler to honor new ACPI_REENABLE_GPE bit Lv Zheng
2014-07-15 12:25   ` [PATCH v2 0/9] ACPICA: Improve GPE handling model Rafael J. Wysocki
2014-07-16  0:36     ` Zheng, Lv
2014-07-15  3:14 ` [PATCH v2 00/10] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
2014-07-15  3:14   ` [PATCH v2 01/10] ACPI/EC: Introduce STARTED/STOPPED flags to replace BLOCKED flag Lv Zheng
2014-07-15  3:14   ` [PATCH v2 02/10] ACPI/EC: Add detailed command/query debugging information Lv Zheng
2014-07-15  3:14   ` [PATCH v2 03/10] ACPI/EC: Deploy the new GPE handling model Lv Zheng
2014-07-15  3:14   ` [PATCH v2 04/10] ACPI/EC: Refine command storm prevention support Lv Zheng
2014-07-15  3:14   ` [PATCH v2 05/10] ACPI/EC: Add reference counting for query handlers Lv Zheng
2014-07-15  3:15   ` [PATCH v2 06/10] ACPI/EC: Add a warning message to indicate event storms Lv Zheng
2014-07-15  3:15   ` [PATCH v2 07/10] ACPI/EC: Refine event/query debugging messages Lv Zheng
2014-07-15  3:15   ` [PATCH v2 08/10] ACPI/EC: Add command flushing support Lv Zheng
2014-07-15  3:15   ` [PATCH v2 09/10] ACPI/EC: Add event storm prevention support Lv Zheng
2014-07-15  3:15   ` [PATCH v2 10/10] ACPI/EC: Add unit test support for EC driver hotplug Lv Zheng
2014-07-15  7:09 ` [PATCH v2] ACPI/EC: Enable storm prevention mechanisms Lv Zheng
2014-07-16  0:44   ` Andi Kleen
2014-07-16  0:55     ` Zheng, Lv
2014-07-21  6:04 ` [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention Lv Zheng
2014-07-21  6:05   ` [RFC PATCH v3 01/14] ACPI/EC: Introduce STARTED/STOPPED flags to replace BLOCKED flag Lv Zheng
2014-07-21  6:05   ` [RFC PATCH v3 02/14] ACPI/EC: Add detailed command/query debugging information Lv Zheng
2014-07-21  6:05   ` [RFC PATCH v3 03/14] ACPI/EC: Cleanup command storm prevention using the new GPE handling model Lv Zheng
2014-07-21  6:05   ` [RFC PATCH v3 04/14] ACPI/EC: Refine command storm prevention support Lv Zheng
2014-07-21  6:05   ` [RFC PATCH v3 05/14] ACPI/EC: Add reference counting for query handlers Lv Zheng
2014-07-21  6:05   ` [RFC PATCH v3 06/14] ACPI/EC: Add command flushing support Lv Zheng
2014-07-21  6:05   ` [RFC PATCH v3 07/14] ACPI/EC: Add a warning message to indicate event storms Lv Zheng
2014-07-21  6:05   ` [RFC PATCH v3 08/14] ACPI/EC: Refine event/query debugging messages Lv Zheng
2014-07-21  6:06   ` [RFC PATCH v3 09/14] ACPI/EC: Add CPU ID to " Lv Zheng
2014-07-21  6:06   ` [RFC PATCH v3 10/14] ACPI/EC: Cleanup QR_SC command processing by adding a kernel thread to poll EC events Lv Zheng
2014-07-21  6:06   ` [RFC PATCH v3 11/14] ACPI/EC: Add event storm prevention support Lv Zheng
2014-07-21  6:06   ` [RFC PATCH v3 12/14] ACPI/EC: Add GPE reference counting debugging messages Lv Zheng
2014-07-21  6:06   ` [RFC PATCH v3 13/14] ACPI/EC: Add unit test support for EC driver hotplug Lv Zheng
2014-07-21  6:06   ` [RFC PATCH v3 14/14] ACPI/EC: Cleanup coding style Lv Zheng
2014-07-22  1:11   ` [RFC PATCH v3 00/14] ACPI/EC: Add event storm prevention and cleanup command storm prevention Rafael J. Wysocki
2014-07-22  1:25     ` Zheng, Lv
2014-07-22 22:15       ` Rafael J. Wysocki
2014-07-23  1:31         ` Zheng, Lv
2015-02-05  8:24 ` [PATCH v4 0/6] ACPI / EC: Fix GPE handling related races Lv Zheng
2015-02-05  8:27   ` [PATCH v4 1/6] ACPICA: Events: Introduce ACPI_GPE_DISPATCH_RAW_HANDLER to fix 2 issues for the current GPE APIs Lv Zheng
2015-02-05  8:27   ` [PATCH v4 2/6] ACPICA: Events: Introduce acpi_set_gpe()/acpi_finish_gpe() to reduce divergences Lv Zheng
2015-02-05  8:27   ` [PATCH v4 3/6] ACPICA: Events: Enable APIs to allow interrupt/polling adaptive request based GPE handling model Lv Zheng
2015-02-05  8:27   ` [PATCH v4 4/6] ACPI / EC: Fix several GPE handling issues by deploying ACPI_GPE_DISPATCH_RAW_HANDLER mode Lv Zheng
2015-02-05  8:27   ` [PATCH v4 5/6] ACPI / EC: Reduce ec_poll() by referencing the last register access timestamp Lv Zheng
2015-02-05  8:27   ` [PATCH v4 6/6] ACPI / EC: Update revision due to raw handler mode Lv Zheng
2015-02-05 15:19   ` [PATCH v4 0/6] ACPI / EC: Fix GPE handling related races Rafael J. Wysocki

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).