diff options
-rw-r--r-- | include/power.h | 5 | ||||
-rw-r--r-- | power/common.c | 28 | ||||
-rw-r--r-- | power/intel_x86.c | 18 |
3 files changed, 39 insertions, 12 deletions
diff --git a/include/power.h b/include/power.h index 2c57209e84..2688852e44 100644 --- a/include/power.h +++ b/include/power.h @@ -145,6 +145,11 @@ void power_set_state(enum power_state new_state); */ enum power_state power_get_state(void); +/* + * Set the wake mask according to the current power state. + */ +void power_update_wake_mask(void); + /** * Chipset-specific initialization * diff --git a/power/common.c b/power/common.c index 2e2e9e3cc5..6d7fb7869d 100644 --- a/power/common.c +++ b/power/common.c @@ -221,30 +221,22 @@ enum power_state power_get_state(void) /* If host doesn't program s0ix lazy wake mask, use default s0ix mask */ #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 after power state has stabilized (5ms after power state - * change): + * Set the wake mask according to the current power state: * 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 * for the current power state. * 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. - * - * Reason for making this a deferred call is to avoid race conditions occurring - * from S0ix periodic wakes on the SoC. */ -static void power_update_wake_mask_deferred(void); -DECLARE_DEFERRED(power_update_wake_mask_deferred); - -static void power_update_wake_mask_deferred(void) +void power_update_wake_mask(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) @@ -260,6 +252,20 @@ static void power_update_wake_mask_deferred(void) lpc_set_host_event_mask(LPC_HOST_EVENT_WAKE, wake_mask); } + /* + * Set wake mask after power state has stabilized, 5ms after power state + * change. The reason for making this a deferred call is to avoid race + * conditions occurring from S0ix periodic wakes on the SoC. + */ + +static void power_update_wake_mask_deferred(void); +DECLARE_DEFERRED(power_update_wake_mask_deferred); + +static void power_update_wake_mask_deferred(void) +{ + hook_call_deferred(&power_update_wake_mask_deferred_data, -1); + power_update_wake_mask(); +} static void power_set_active_wake_mask(void) { diff --git a/power/intel_x86.c b/power/intel_x86.c index 4e7230d395..838935777f 100644 --- a/power/intel_x86.c +++ b/power/intel_x86.c @@ -271,8 +271,17 @@ static void s0ix_transition_timeout(void) /* * Wake up the AP so they don't just chill in a non-suspended state and * burn power. Overload a vaguely related event bit since event bits are - * at a premium. + * at a premium. If the system never entered S0ix, then manually set the + * wake mask to pretend it did, so that the hang detect event wakes the + * system. */ + if (power_get_state() == POWER_S0) { + host_event_t s0ix_wake_mask; + + get_lazy_wake_mask(POWER_S0ix, &s0ix_wake_mask); + lpc_set_host_event_mask(LPC_HOST_EVENT_WAKE, s0ix_wake_mask); + } + host_set_single_event(EC_HOST_EVENT_HANG_DETECT); } @@ -300,6 +309,13 @@ static void s0ix_complete_resume(struct host_sleep_event_context *ctx) { hook_call_deferred(&s0ix_transition_timeout_data, -1); ctx->sleep_transitions = slp_s0ix_transitions; + + /* + * If s0ix timed out and never transitioned, then the wake mask was + * modified to its s0ix state, so that the event wakes the system. + * Explicitly restore the wake mask to its S0 state now. + */ + power_update_wake_mask(); } static void s0ix_reset_tracking(void) |