summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiana Z <dzigterman@chromium.org>2023-03-15 15:50:45 -0600
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2023-03-23 13:21:11 +0000
commitc832e6eae34bc169685c394353db2ab1903d88e9 (patch)
tree60338f4445cee5fa9161024c8f6984afb365d00c
parent45c25c16ae0d66204eb8bc4a6991bbaeae29b4e5 (diff)
downloadchrome-ec-c832e6eae34bc169685c394353db2ab1903d88e9.tar.gz
Host sleep: Consider a reboot after suspend to be a resume
When we try to wake the host during a failed resume, the host may reboot rather than actually following the resume path. In this case, we will receive events of "0" indicating we're on a fresh boot and the chipset RESUME hooks never run. Instead, we should treat this new boot as a resume in order to ensure the previous SUSPEND hooks get a RESUME call to go with them. BRANCH=None BUG=b:273327518 TEST=on whiterun, run suspend with bad AP FW version and ensure the backlight turns on after we wake the host Change-Id: I9c8e7ad70dbca5245844a31772e99097256e592f Signed-off-by: Diana Z <dzigterman@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4344029 Reviewed-by: Wai-Hong Tam <waihong@google.com> Commit-Queue: Wai-Hong Tam <waihong@google.com> (cherry picked from commit a63d9b0134000bff51dd3eaeca6898f1f671d768) Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4363221 Reviewed-by: Chao Gui <chaogui@google.com> Tested-by: Chao Gui <chaogui@google.com> Code-Coverage: Chao Gui <chaogui@google.com> Commit-Queue: Chao Gui <chaogui@google.com>
-rw-r--r--power/host_sleep.c7
-rw-r--r--zephyr/test/drivers/power_host_sleep/src/test_power_host_sleep.c91
2 files changed, 98 insertions, 0 deletions
diff --git a/power/host_sleep.c b/power/host_sleep.c
index 7dc83ca8e9..b0b8b624e3 100644
--- a/power/host_sleep.c
+++ b/power/host_sleep.c
@@ -36,6 +36,13 @@ host_command_host_sleep_event(struct host_cmd_handler_args *args)
struct host_sleep_event_context ctx;
enum host_sleep_event state = p->sleep_event;
+ /*
+ * Treat a reboot after suspend as a resume for notification purposes
+ * (see b/273327518 for more details)
+ */
+ if (host_sleep_state == HOST_SLEEP_EVENT_S0IX_SUSPEND && state == 0)
+ state = HOST_SLEEP_EVENT_S0IX_RESUME;
+
host_sleep_state = state;
ctx.sleep_transitions = 0;
switch (state) {
diff --git a/zephyr/test/drivers/power_host_sleep/src/test_power_host_sleep.c b/zephyr/test/drivers/power_host_sleep/src/test_power_host_sleep.c
index 616951c558..28617e2d59 100644
--- a/zephyr/test/drivers/power_host_sleep/src/test_power_host_sleep.c
+++ b/zephyr/test/drivers/power_host_sleep/src/test_power_host_sleep.c
@@ -256,6 +256,97 @@ ZTEST(power_host_sleep, test_suspend_then_resume_with_timeout)
zassert_true(context.sleep_transitions & EC_HOST_RESUME_SLEEP_TIMEOUT);
}
+ZTEST(power_host_sleep, test_suspend_then_resume_with_reboot)
+{
+ struct ec_params_host_sleep_event_v1 p;
+ struct ec_response_host_sleep_event_v1 r;
+ struct host_cmd_handler_args args;
+ struct host_sleep_event_context context = {
+ .sleep_timeout_ms = EC_HOST_SLEEP_TIMEOUT_DEFAULT,
+ .sleep_transitions = 0.
+ };
+
+ /* Start then suspend process like the OS would */
+ p.sleep_event = HOST_SLEEP_EVENT_S0IX_SUSPEND;
+ zassert_ok(ec_cmd_host_sleep_event_v1(&args, &p, &r));
+
+ /* Verify we notified the chipset */
+ zassert_equal(power_chipset_handle_host_sleep_event_fake.call_count, 1);
+ zassert_equal(power_chipset_handle_host_sleep_event_fake.arg0_val,
+ p.sleep_event);
+
+ /* Now kick the internals as if we suspend and then fail to resume */
+ sleep_start_suspend(&context);
+ /* Register the suspend transition (cancels timeout hook) */
+ sleep_suspend_transition();
+ k_sleep(K_MSEC(CONFIG_SLEEP_TIMEOUT_MS * 2));
+
+ /* No timeout hooks should've fired */
+ zassert_equal(power_chipset_handle_sleep_hang_fake.call_count, 0);
+ zassert_equal(power_board_handle_sleep_hang_fake.call_count, 0);
+
+ /* Transition to resume state and wait for hang timeout */
+ sleep_resume_transition();
+ k_sleep(K_MSEC(CONFIG_SLEEP_TIMEOUT_MS * 2));
+
+ /* Resume state transition timeout hook should've fired */
+ zassert_equal(power_chipset_handle_sleep_hang_fake.call_count, 1);
+ zassert_equal(power_board_handle_sleep_hang_fake.call_count, 1);
+ zassert_equal(power_chipset_handle_sleep_hang_fake.arg0_val,
+ SLEEP_HANG_S0IX_RESUME);
+ zassert_equal(power_board_handle_sleep_hang_fake.arg0_val,
+ SLEEP_HANG_S0IX_RESUME);
+
+ /* But now the OS says it's actually rebooted */
+ p.sleep_event = 0;
+ zassert_ok(ec_cmd_host_sleep_event_v1(&args, &p, &r));
+
+ /* Verify we alerted as if this was a resume */
+ zassert_equal(power_chipset_handle_host_sleep_event_fake.call_count, 2);
+ zassert_equal(power_chipset_handle_host_sleep_event_fake.arg0_val,
+ HOST_SLEEP_EVENT_S0IX_RESUME);
+}
+
+ZTEST(power_host_sleep, test_suspend_then_reboot)
+{
+ struct ec_params_host_sleep_event_v1 p;
+ struct ec_response_host_sleep_event_v1 r;
+ struct host_cmd_handler_args args;
+ struct host_sleep_event_context context = {
+ .sleep_timeout_ms = EC_HOST_SLEEP_TIMEOUT_DEFAULT,
+ .sleep_transitions = 0.
+ };
+
+ /* Start then suspend process like the OS would */
+ p.sleep_event = HOST_SLEEP_EVENT_S0IX_SUSPEND;
+ zassert_ok(ec_cmd_host_sleep_event_v1(&args, &p, &r));
+
+ /* Verify we notified the chipset */
+ zassert_equal(power_chipset_handle_host_sleep_event_fake.call_count, 1);
+ zassert_equal(power_chipset_handle_host_sleep_event_fake.arg0_val,
+ p.sleep_event);
+
+ /* Now kick the internals as if we suspend and then fail to resume */
+ sleep_start_suspend(&context);
+ /* Register the suspend transition (cancels timeout hook) */
+ sleep_suspend_transition();
+ k_sleep(K_MSEC(CONFIG_SLEEP_TIMEOUT_MS * 2));
+
+ /* No timeout hooks should've fired */
+ zassert_equal(power_chipset_handle_sleep_hang_fake.call_count, 0);
+ zassert_equal(power_board_handle_sleep_hang_fake.call_count, 0);
+
+ /* Transition to resume state and then send that we rebooted instead */
+ sleep_resume_transition();
+ p.sleep_event = 0;
+ zassert_ok(ec_cmd_host_sleep_event_v1(&args, &p, &r));
+
+ /* Verify we alerted as if this was a resume */
+ zassert_equal(power_chipset_handle_host_sleep_event_fake.call_count, 2);
+ zassert_equal(power_chipset_handle_host_sleep_event_fake.arg0_val,
+ HOST_SLEEP_EVENT_S0IX_RESUME);
+}
+
/* Only used in test_sleep_set_notify */
static bool _test_host_sleep_hook_called;