summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFurquan Shaikh <furquan@google.com>2018-10-26 14:13:37 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-10-30 01:04:55 -0700
commitc334a73787bb869ddae19c5787a191062b5918ca (patch)
tree2e10b42db55953cd98c92b77a55cd42df1fd4059
parent8a0ba88f26d5b806a503fc931c3fca5794a1d5c3 (diff)
downloadchrome-ec-c334a73787bb869ddae19c5787a191062b5918ca.tar.gz
power/common: Wait some time before updating wake masks
On platforms like KBL, the device keeps waking up periodically for very short intervals to allow some SoC components to do book-keeping activities. If the user happens to trigger EC-related wake event during this short window, then the wakeup event could be missed because it looks like the host is in S0 to the EC. In order to avoid the race condition, update wake mask using a deferred call to allow the system state to stabilize. BUG=b:118490626 BRANCH=nocturne TEST=No more lid open failures observed on nocturne. Change-Id: I13f9f5760aaf7e54c676f43c48f9fc8de572fd01 Signed-off-by: Furquan Shaikh <furquan@google.com> Reviewed-on: https://chromium-review.googlesource.com/1303133 Commit-Ready: Furquan Shaikh <furquan@chromium.org> Tested-by: Furquan Shaikh <furquan@chromium.org> Reviewed-by: Aaron Durbin <adurbin@chromium.org>
-rw-r--r--power/common.c40
1 files changed, 35 insertions, 5 deletions
diff --git a/power/common.c b/power/common.c
index ddbfaebded..8a2770e03b 100644
--- a/power/common.c
+++ b/power/common.c
@@ -220,7 +220,8 @@ enum power_state power_get_state(void)
#define DEFAULT_WAKE_MASK_S0IX (EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN) | \
EC_HOST_EVENT_MASK(EC_HOST_EVENT_MODE_CHANGE))
/*
- * Set wake mask on edge of sleep state entry
+ * Set wake mask after power state has stabilized (5ms after power state
+ * change):
* 1. On transition to S0, wake mask is reset.
* 2. In non-S0 states, active mask set by host gets a higher preference.
* 3. If host has not set any active mask, then check if a lazy mask exists
@@ -228,11 +229,21 @@ enum power_state power_get_state(void)
* 4. If state is S0ix and no lazy or active wake mask is set, then use default
* S0ix mask to be compatible with older BIOS versions.
*
- * @param state New sleep state
+ * Reason for making this a deferred call is to avoid race conditions occurring
+ * from S0ix periodic wakes on the SoC.
*/
-static void power_set_active_wake_mask(enum power_state state)
+
+static void power_update_wake_mask_deferred(void);
+DECLARE_DEFERRED(power_update_wake_mask_deferred);
+
+static void power_update_wake_mask_deferred(void)
{
host_event_t wake_mask;
+ enum power_state state;
+
+ hook_call_deferred(&power_update_wake_mask_deferred_data, -1);
+
+ state = power_get_state();
if (state == POWER_S0)
wake_mask = 0;
@@ -247,8 +258,27 @@ static void power_set_active_wake_mask(enum power_state state)
lpc_set_host_event_mask(LPC_HOST_EVENT_WAKE, wake_mask);
}
+
+static void power_set_active_wake_mask(void)
+{
+ /*
+ * Allow state machine to stabilize and update wake mask after 5msec. It
+ * was observed that on platforms where host wakes up periodically from
+ * S0ix for hardware book-keeping activities, there is a small window
+ * where host is not really up and running software, but still SLP_S0#
+ * is de-asserted and hence setting wake mask right away can cause user
+ * wake events to be missed.
+ *
+ * Time for deferred callback was chosen to be 5msec based on the fact
+ * that it takes ~2msec for the periodic wake cycle to complete on the
+ * host for KBL.
+ */
+ hook_call_deferred(&power_update_wake_mask_deferred_data,
+ 5 * MSEC);
+}
+
#else
-static void power_set_active_wake_mask(enum power_state state) { }
+static void power_set_active_wake_mask(void) { }
#endif
/**
@@ -502,7 +532,7 @@ void chipset_task(void *u)
/* Handle state changes */
if (new_state != state) {
power_set_state(new_state);
- power_set_active_wake_mask(new_state);
+ power_set_active_wake_mask();
}
}
}