summaryrefslogtreecommitdiff
path: root/power
diff options
context:
space:
mode:
authorFurquan Shaikh <furquan@google.com>2018-06-13 15:53:08 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-06-15 10:57:14 -0700
commit0cc90679aef979faf44416eba30452a7837807eb (patch)
tree5fbb42a93048694b237ca5bfa4babcec992e55f9 /power
parent122d4f65b0c896e332baabafe88bf5087d724cd1 (diff)
downloadchrome-ec-0cc90679aef979faf44416eba30452a7837807eb.tar.gz
host_event: Handle SCI/SMI masks correctly when using S0ix
When host is using S0ix, BIOS is not involved during suspend or resume paths. Thus, until now, SCI and SMI masks were preserved across S0ix suspend/resume cycles. However, it was identified in b:78497503 that if SCI is generated after host enters S0ix, then it results in EC eSPI controller waiting for host controller to respond to the SCI virtual wire event. This prevents the EC from entering low power idle mode. In order to fix the above issue, this change ensures that SCI and SMI masks are cleared when host expresses its interest to enter S0ix. Since these masks are not re-programmed by the host on resume, EC maintains backup copies of both the masks. On resume from S0ix, backup copies are used to restore the masks for SCI and SMI. This change applies to both eSPI and LPC systems since SCI/SMI should not be generated (physical or virtual) when host is in S0ix. This implementation follows the design proposed in: https://docs.google.com/document/d/1J2VYeVXV-KZnIHvtDyOrcH4AXJipsSX6m8oZIDSdtv8/edit?usp=sharing BUG=b:78497503 BRANCH=None TEST=Verified following: 1. SCI and SMI masks are programmed correctly on boot-up. 2. SCI and SMI masks are set to 0 when host enters S0ix. 3. SCI and SMI masks are restored correctly on S0ix resume. Change-Id: Iaa3981e6545d2d3cff51649642f6926f0d4ec31f Signed-off-by: Furquan Shaikh <furquan@google.com> Reviewed-on: https://chromium-review.googlesource.com/1099968 Commit-Ready: Furquan Shaikh <furquan@chromium.org> Tested-by: Furquan Shaikh <furquan@chromium.org> Reviewed-by: Justin TerAvest <teravest@chromium.org> Reviewed-by: Jett Rink <jettrink@chromium.org>
Diffstat (limited to 'power')
-rw-r--r--power/intel_x86.c41
1 files changed, 41 insertions, 0 deletions
diff --git a/power/intel_x86.c b/power/intel_x86.c
index 4617c91394..1cc8beadf5 100644
--- a/power/intel_x86.c
+++ b/power/intel_x86.c
@@ -490,6 +490,45 @@ power_board_handle_host_sleep_event(enum host_sleep_event state)
/* Default weak implementation -- no action required. */
}
+/*
+ * Backup copies of SCI and SMI mask to preserve across S0ix suspend/resume
+ * cycle. If the host uses S0ix, BIOS is not involved during suspend and resume
+ * operations and hence SCI/SMI masks are programmed only once during boot-up.
+ *
+ * These backup variables are set whenever host expresses its interest to
+ * enter S0ix and then lpc_host_event_mask for SCI and SMI are cleared. When
+ * host resumes from S0ix, masks from backup variables are copied over to
+ * lpc_host_event_mask for SCI and SMI.
+ */
+static host_event_t backup_sci_mask;
+static host_event_t backup_smi_mask;
+
+/*
+ * Clear host event masks for SMI and SCI when host is entering S0ix. This is
+ * done to prevent any SCI/SMI interrupts when the host is in suspend. Since
+ * BIOS is not involved in the suspend path, EC needs to take care of clearing
+ * these masks.
+ */
+static void lpc_s0ix_suspend_clear_masks(void)
+{
+ backup_sci_mask = lpc_get_host_event_mask(LPC_HOST_EVENT_SCI);
+ backup_smi_mask = lpc_get_host_event_mask(LPC_HOST_EVENT_SMI);
+
+ lpc_set_host_event_mask(LPC_HOST_EVENT_SCI, 0);
+ lpc_set_host_event_mask(LPC_HOST_EVENT_SMI, 0);
+}
+
+/*
+ * Restore host event masks for SMI and SCI when host exits S0ix. This is done
+ * because BIOS is not involved in the resume path and so EC needs to restore
+ * the masks from backup variables.
+ */
+static void lpc_s0ix_resume_restore_masks(void)
+{
+ lpc_set_host_event_mask(LPC_HOST_EVENT_SCI, backup_sci_mask);
+ lpc_set_host_event_mask(LPC_HOST_EVENT_SMI, backup_smi_mask);
+}
+
void power_chipset_handle_host_sleep_event(enum host_sleep_event state)
{
power_board_handle_host_sleep_event(state);
@@ -502,6 +541,7 @@ void power_chipset_handle_host_sleep_event(enum host_sleep_event state)
* notification needs to be sent to listeners.
*/
s0ix_notify = S0IX_NOTIFY_SUSPEND;
+ lpc_s0ix_suspend_clear_masks();
power_signal_enable_interrupt(sleep_sig[SYS_SLEEP_S0IX]);
} else if (state == HOST_SLEEP_EVENT_S0IX_RESUME) {
/*
@@ -513,6 +553,7 @@ void power_chipset_handle_host_sleep_event(enum host_sleep_event state)
/* clear host events */
while (lpc_get_next_host_event() != 0)
;
+ lpc_s0ix_resume_restore_masks();
power_signal_disable_interrupt(sleep_sig[SYS_SLEEP_S0IX]);
} else if (state == HOST_SLEEP_EVENT_DEFAULT_RESET) {
power_signal_disable_interrupt(sleep_sig[SYS_SLEEP_S0IX]);