diff options
-rw-r--r-- | include/power.h | 61 | ||||
-rw-r--r-- | power/host_sleep.c | 143 | ||||
-rw-r--r-- | power/intel_x86.c | 122 |
3 files changed, 204 insertions, 122 deletions
diff --git a/include/power.h b/include/power.h index 8801250951..4a267ed8ad 100644 --- a/include/power.h +++ b/include/power.h @@ -278,6 +278,67 @@ __override_proto void power_board_handle_host_sleep_event( */ #define HOST_SLEEP_EVENT_DEFAULT_RESET 0 +enum sleep_notify_type { + SLEEP_NOTIFY_NONE, + SLEEP_NOTIFY_SUSPEND, + SLEEP_NOTIFY_RESUME, +}; + +/** + * Set the sleep notify + * + * It is called in power_chipset_handle_host_sleep_event(), to set the sleep + * notify. The sleep notify is assigned based on the host sleep state. + * + * @param notify The sleep notify to set. + */ +void sleep_set_notify(enum sleep_notify_type notify); + +/** + * Notify the given hook is the sleep notify is matched. + * + * @param check_state: The sleep notify to check. + * @param hook_id: The hook to notify. + */ +void sleep_notify_transition(int check_state, int hook_id); + +/** + * Called during the suspend transition, to increase the transition counter. + */ +void sleep_suspend_transition(void); + +/** + * Called during the resume transition, to increase the transition counter. + */ +void sleep_resume_transition(void); + +/** + * Start the suspend process. + * + * It is called in power_chipset_handle_host_sleep_event(), after it receives + * a host sleep event to hint that the suspend process starts. + * + * @param ctx Possible sleep parameters and return values, depending on state. + * @param callback Will be called if timed out, i.e. suspend hang. + */ +void sleep_start_suspend(struct host_sleep_event_context *ctx, + void (*callback)(void)); + +/** + * Complete the resume process. + * + * It is called in power_chipset_handle_host_sleep_event(), after it receives + * a host sleep event to hint that the resume process completes. + * + * @param ctx Possible sleep parameters and return values, depending on state. + */ +void sleep_complete_resume(struct host_sleep_event_context *ctx); + +/** + * Reset the transition counter and timer. + */ +void sleep_reset_tracking(void); + #ifdef CONFIG_POWER_S0IX /** * Reset the sleep state reported by the host. diff --git a/power/host_sleep.c b/power/host_sleep.c index 673d421ca7..54a308d6c3 100644 --- a/power/host_sleep.c +++ b/power/host_sleep.c @@ -4,8 +4,14 @@ */ #include "ec_commands.h" +#include "hooks.h" #include "host_command.h" #include "power.h" +#include "util.h" + +/* Console output macros */ +#define CPRINTS(format, args...) cprints(CC_CHIPSET, format, ## args) +#define CPRINTF(format, args...) cprintf(CC_CHIPSET, format, ## args) /* Track last reported sleep event */ static enum host_sleep_event host_sleep_state; @@ -77,3 +83,140 @@ void power_set_host_sleep_state(enum host_sleep_event state) host_sleep_state = state; } +#ifdef CONFIG_POWER_SLEEP_FAILURE_DETECTION +/* Flag to notify listeners about suspend/resume events. */ +enum sleep_notify_type sleep_notify = SLEEP_NOTIFY_NONE; + +/* + * Note: the following sleep_ functions do not get called in the S3 path on + * Intel devices. On Intel devices, they are called in the S0ix path. + */ +void sleep_set_notify(enum sleep_notify_type notify) +{ + sleep_notify = notify; +} + +void sleep_notify_transition(int check_state, int hook_id) +{ + if (sleep_notify != check_state) + return; + + hook_notify(hook_id); + sleep_set_notify(SLEEP_NOTIFY_NONE); +} + +static uint16_t sleep_signal_timeout; +static uint32_t sleep_signal_transitions; +static void (*sleep_timeout_callback)(void); + +static void sleep_transition_timeout(void); +DECLARE_DEFERRED(sleep_transition_timeout); + +static void sleep_increment_transition(void) +{ + if ((sleep_signal_transitions & EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK) < + EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK) + sleep_signal_transitions += 1; +} + +void sleep_suspend_transition(void) +{ + sleep_increment_transition(); + hook_call_deferred(&sleep_transition_timeout_data, -1); +} + +void sleep_resume_transition(void) +{ + sleep_increment_transition(); + + /* + * Start the timer again to ensure the AP doesn't get itself stuck in + * a state where it's no longer in a sleep state (S0ix/S3), but from + * the Linux perspective is still suspended. Perhaps a bug in the SoC- + * internal periodic housekeeping code might result in a situation + * like this. + */ + if (sleep_signal_timeout) + hook_call_deferred(&sleep_transition_timeout_data, + (uint32_t)sleep_signal_timeout * 1000); +} + +static void sleep_transition_timeout(void) +{ + /* Mark the timeout. */ + sleep_signal_transitions |= EC_HOST_RESUME_SLEEP_TIMEOUT; + hook_call_deferred(&sleep_transition_timeout_data, -1); + + /* Call the custom callback */ + if (sleep_timeout_callback) + sleep_timeout_callback(); +} + +void sleep_start_suspend(struct host_sleep_event_context *ctx, + void (*callback)(void)) +{ + uint16_t timeout = ctx->sleep_timeout_ms; + + sleep_timeout_callback = callback; + sleep_signal_transitions = 0; + + /* Use zero internally to indicate no timeout. */ + if (timeout == EC_HOST_SLEEP_TIMEOUT_DEFAULT) { + timeout = CONFIG_SLEEP_TIMEOUT_MS; + + } else if (timeout == EC_HOST_SLEEP_TIMEOUT_INFINITE) { + sleep_signal_timeout = 0; + return; + } + + sleep_signal_timeout = timeout; + hook_call_deferred(&sleep_transition_timeout_data, + (uint32_t)timeout * 1000); +} + +void sleep_complete_resume(struct host_sleep_event_context *ctx) +{ + hook_call_deferred(&sleep_transition_timeout_data, -1); + ctx->sleep_transitions = sleep_signal_transitions; +} + +void sleep_reset_tracking(void) +{ + sleep_signal_transitions = 0; + sleep_signal_timeout = 0; + sleep_timeout_callback = NULL; +} + +#else /* !CONFIG_POWER_SLEEP_FAILURE_DETECTION */ + +/* No action */ +void sleep_set_notify(enum sleep_notify_type notify) +{ +} + +void sleep_notify_transition(int check_state, int hook_id) +{ +} + +void sleep_suspend_transition(void) +{ +} + +void sleep_resume_transition(void) +{ +} + +void sleep_start_suspend(struct host_sleep_event_context *ctx, + void (*callback)(void)) +{ +} + +void sleep_complete_resume(struct host_sleep_event_context *ctx) +{ +} + +void sleep_reset_tracking(void) +{ +} + +#endif /* CONFIG_POWER_SLEEP_FAILURE_DETECTION */ diff --git a/power/intel_x86.c b/power/intel_x86.c index 4fdfbdfb9c..1fdf1b96ea 100644 --- a/power/intel_x86.c +++ b/power/intel_x86.c @@ -196,38 +196,10 @@ static void lpc_s0ix_hang_detected(void) host_set_single_event(EC_HOST_EVENT_HANG_DETECT); } -enum sleep_notify_type { - SLEEP_NOTIFY_NONE, - SLEEP_NOTIFY_SUSPEND, - SLEEP_NOTIFY_RESUME, -}; - -/* Flag to notify listeners about suspend/resume events. */ -enum sleep_notify_type sleep_notify = SLEEP_NOTIFY_NONE; - -/* - * Note: the following sleep_ functions do not get called in the S3 path on - * Intel devices. On Intel devices, they are called in the S0ix path. - */ -static void sleep_set_notify(enum sleep_notify_type notify) -{ - sleep_notify = notify; -} - -static void sleep_notify_transition(int check_state, int hook_id) -{ - if (sleep_notify != check_state) - return; - - hook_notify(hook_id); - sleep_set_notify(SLEEP_NOTIFY_NONE); -} - static void handle_chipset_suspend(void) { /* Clear masks before any hooks are run for suspend. */ lpc_s0ix_suspend_clear_masks(); - } DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, handle_chipset_suspend, HOOK_PRIO_FIRST); @@ -241,100 +213,6 @@ static void handle_chipset_reset(void) } DECLARE_HOOK(HOOK_CHIPSET_RESET, handle_chipset_reset, HOOK_PRIO_FIRST); -#ifdef CONFIG_POWER_SLEEP_FAILURE_DETECTION - -static uint16_t sleep_signal_timeout; -static uint32_t sleep_signal_transitions; -static void (*sleep_timeout_callback)(void); - -static void sleep_transition_timeout(void); -DECLARE_DEFERRED(sleep_transition_timeout); - -static void sleep_increment_transition(void) -{ - if ((sleep_signal_transitions & EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK) < - EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK) - sleep_signal_transitions += 1; -} - -static void sleep_suspend_transition(void) -{ - sleep_increment_transition(); - hook_call_deferred(&sleep_transition_timeout_data, -1); -} - -static void sleep_resume_transition(void) -{ - sleep_increment_transition(); - - /* - * Start the timer again to ensure the AP doesn't get itself stuck in - * a state where it's no longer in a sleep state (S0ix/S3), but from - * the Linux perspective is still suspended. Perhaps a bug in the SoC- - * internal periodic housekeeping code might result in a situation - * like this. - */ - if (sleep_signal_timeout) - hook_call_deferred(&sleep_transition_timeout_data, - (uint32_t)sleep_signal_timeout * 1000); -} - -static void sleep_transition_timeout(void) -{ - /* Mark the timeout. */ - sleep_signal_transitions |= EC_HOST_RESUME_SLEEP_TIMEOUT; - hook_call_deferred(&sleep_transition_timeout_data, -1); - - /* Call the custom callback */ - if (sleep_timeout_callback) - sleep_timeout_callback(); -} - -static void sleep_start_suspend(struct host_sleep_event_context *ctx, - void (*callback)(void)) -{ - uint16_t timeout = ctx->sleep_timeout_ms; - - sleep_timeout_callback = callback; - sleep_signal_transitions = 0; - - /* Use zero internally to indicate no timeout. */ - if (timeout == EC_HOST_SLEEP_TIMEOUT_DEFAULT) { - timeout = CONFIG_SLEEP_TIMEOUT_MS; - - } else if (timeout == EC_HOST_SLEEP_TIMEOUT_INFINITE) { - sleep_signal_timeout = 0; - return; - } - - sleep_signal_timeout = timeout; - hook_call_deferred(&sleep_transition_timeout_data, - (uint32_t)timeout * 1000); -} - -static void sleep_complete_resume(struct host_sleep_event_context *ctx) -{ - hook_call_deferred(&sleep_transition_timeout_data, -1); - ctx->sleep_transitions = sleep_signal_transitions; -} - -static void sleep_reset_tracking(void) -{ - sleep_signal_transitions = 0; - sleep_signal_timeout = 0; - sleep_timeout_callback = NULL; -} - -#else /* !CONFIG_POWER_SLEEP_FAILURE_DETECTION */ - -#define sleep_suspend_transition() -#define sleep_resume_transition() -#define sleep_start_suspend(_ctx) -#define sleep_complete_resume(_ctx) -#define sleep_reset_tracking() - -#endif /* CONFIG_POWER_SLEEP_FAILURE_DETECTION */ - void power_reset_host_sleep_state(void) { power_set_host_sleep_state(HOST_SLEEP_EVENT_DEFAULT_RESET); |