diff options
-rw-r--r-- | power/intel_x86.c | 41 |
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]); |