To have a more accurate idea about any suspend/resume issues we can perform the s/r until various phases in the s/r sequence. This way we can isolate the given problem as being a device driver, kernel core or BIOS related issue. Actual subtests using these new s/r phases will be added as follow-up. While at it also add the freeze suspend target, it's something we also would need to test. Signed-off-by: Imre Deak <imre.deak@xxxxxxxxx> --- lib/igt_aux.c | 172 ++++++++++++++++++++++++++++++--------- lib/igt_aux.h | 24 +++++- tests/drv_suspend.c | 24 ++++-- tests/gem_exec_suspend.c | 6 +- tests/gem_mocs_settings.c | 24 ++++-- tests/gem_ringfill.c | 6 +- tests/gem_softpin.c | 6 +- tests/gem_stolen.c | 2 +- tests/gem_workarounds.c | 2 +- tests/kms_cursor_crc.c | 3 +- tests/kms_fbcon_fbt.c | 6 +- tests/kms_flip.c | 3 +- tests/kms_frontbuffer_tracking.c | 4 +- tests/kms_pipe_crc_basic.c | 3 +- tests/kms_plane.c | 3 +- tests/kms_psr_sink_crc.c | 6 +- tests/pm_rpm.c | 6 +- 17 files changed, 224 insertions(+), 76 deletions(-) diff --git a/lib/igt_aux.c b/lib/igt_aux.c index 5eaf35e..ba4dbf7 100644 --- a/lib/igt_aux.c +++ b/lib/igt_aux.c @@ -63,6 +63,7 @@ #include "ioctl_wrappers.h" #include "igt_kms.h" #include "igt_stats.h" +#include "igt_sysfs.h" /** * SECTION:igt_aux @@ -625,60 +626,157 @@ void igt_cleanup_aperture_trashers(void) free(trash_bos); } +static const char *suspend_state_name[] = { + [SUSPEND_STATE_FREEZE] = "freeze", + [SUSPEND_STATE_MEM] = "mem", + [SUSPEND_STATE_DISK] = "disk", +}; + +static const char *suspend_test_name[] = { + [SUSPEND_TEST_NONE] = "none", + [SUSPEND_TEST_FREEZER] = "freezer", + [SUSPEND_TEST_DEVICES] = "devices", + [SUSPEND_TEST_PLATFORM] = "platform", + [SUSPEND_TEST_PROCESSORS] = "processors", + [SUSPEND_TEST_CORE] = "core", +}; + +static enum igt_suspend_test get_suspend_test(int power_dir) +{ + char *test_line; + char *test_name; + enum igt_suspend_test test; + + if (faccessat(power_dir, "pm_test", R_OK, 0)) + return SUSPEND_TEST_NONE; + + igt_assert((test_line = igt_sysfs_get(power_dir, "pm_test"))); + for (test_name = strtok(test_line, " "); test_name; + test_name = strtok(NULL, " ")) + if (test_name[0] == '[') { + test_name[strlen(test_name) - 1] = '\0'; + test_name++; + break; + } + + for (test = SUSPEND_TEST_NONE; test < SUSPEND_TEST_NUM; test++) + if (strcmp(suspend_test_name[test], test_name) == 0) + break; + + igt_assert(test < SUSPEND_TEST_NUM); + + free(test_line); + + return test; +} + +static void set_suspend_test(int power_dir, enum igt_suspend_test test) +{ + igt_assert(test < SUSPEND_TEST_NUM); + + if (faccessat(power_dir, "pm_test", W_OK, 0)) { + igt_require(test == SUSPEND_TEST_NONE); + return; + } + + igt_assert(igt_sysfs_set(power_dir, "pm_test", suspend_test_name[test])); +} + #define SQUELCH ">/dev/null 2>&1" +static void suspend_via_rtcwake(enum igt_suspend_state state) +{ + char cmd[128]; + int delay; + + igt_assert(state < SUSPEND_STATE_NUM); + + delay = state == SUSPEND_STATE_DISK ? 30 : 15; + + /* + * Skip if rtcwake would fail for a reason not related to the kernel's + * suspend functionality. + */ + snprintf(cmd, sizeof(cmd), "rtcwake -n -s %d -m %s " SQUELCH, + delay, suspend_state_name[state]); + igt_require(system(cmd) == 0); + + snprintf(cmd, sizeof(cmd), "rtcwake -s %d -m %s ", + delay, suspend_state_name[state]); + igt_assert_f(system(cmd) == 0, + "This failure means that something is wrong with " + "the rtcwake tool or how your distro is set up. " + "This is not a i915.ko or i-g-t bug.\n"); +} + +static void suspend_via_sysfs(int power_dir, enum igt_suspend_state state) +{ + igt_assert(state < SUSPEND_STATE_NUM); + igt_assert(igt_sysfs_set(power_dir, "state", + suspend_state_name[state])); +} + +static uint32_t get_supported_suspend_states(int power_dir) +{ + char *states; + char *state_name; + uint32_t state_mask; + + igt_assert((states = igt_sysfs_get(power_dir, "state"))); + state_mask = 0; + for (state_name = strtok(states, " "); state_name; + state_name = strtok(NULL, " ")) { + enum igt_suspend_state state; + + for (state = SUSPEND_STATE_FREEZE; state < SUSPEND_STATE_NUM; + state++) + if (strcmp(state_name, suspend_state_name[state]) == 0) + break; + igt_assert(state < SUSPEND_STATE_NUM); + state_mask |= 1 << state; + } + + free(states); + + return state_mask; +} + /** * igt_system_suspend_autoresume: * - * Execute a system suspend-to-mem cycle and automatically wake up again using - * the firmware's resume timer. + * Execute a system suspend (to idle, memory, disk) cycle optionally + * completing the cycle at a given test point and automaically wake up again. + * Waking up is either achieved using the RTC wake-up alarm for a full suspend + * cycle or a kernel timer for a suspend test cycle. * * This is very handy for implementing any kind of suspend/resume test. */ -void igt_system_suspend_autoresume(void) +void igt_system_suspend_autoresume(enum igt_suspend_state state, + enum igt_suspend_test test) { + int power_dir; + enum igt_suspend_test orig_test; + /* FIXME: Simulation doesn't like suspend/resume, and not even a lighter * approach using /sys/power/pm_test to just test our driver's callbacks * seems to fare better. We need to investigate what's going on. */ igt_skip_on_simulation(); - /* skip if system doesn't support suspend-to-mem */ - igt_require(system("rtcwake -n -s 15 -m mem" SQUELCH) == 0); - - igt_assert_f(system("rtcwake -s 15 -m mem") == 0, - "This failure means that something is wrong with the " - "rtcwake tool or how your distro is set up. This is not " - "a i915.ko or i-g-t bug.\n"); -} + igt_require((power_dir = open("/sys/power", O_RDONLY)) >= 0); + igt_require(get_supported_suspend_states(power_dir) & (1 << state)); + igt_require(test == SUSPEND_TEST_NONE || + faccessat(power_dir, "pm_test", R_OK | W_OK, 0) == 0); -/** - * igt_system_hibernate_autoresume: - * - * Execute a system suspend-to-disk cycle and automatically wake up again using - * the firmware's resume timer. - * - * This is very handy for implementing any kind of hibernate/resume test. - */ -void igt_system_hibernate_autoresume(void) -{ - /* FIXME: I'm guessing simulation behaves the same way as with - * suspend/resume, but it might be prudent to make sure - */ - /* FIXME: Simulation doesn't like suspend/resume, and not even a lighter - * approach using /sys/power/pm_test to just test our driver's callbacks - * seems to fare better. We need to investigate what's going on. */ - igt_skip_on_simulation(); + orig_test = get_suspend_test(power_dir); + set_suspend_test(power_dir, test); - /* skip if system doesn't support suspend-to-disk */ - igt_require(system("rtcwake -n -s 30 -m disk" SQUELCH) == 0); + if (test == SUSPEND_TEST_NONE) + suspend_via_rtcwake(state); + else + suspend_via_sysfs(power_dir, state); - /* The timeout might need to be adjusted if hibernation takes too long - * or if we have to wait excessively long before resume - */ - igt_assert_f(system("rtcwake -s 30 -m disk") == 0, - "This failure means that something is wrong with the " - "rtcwake tool or how your distro is set up. This is not " - "a i915.ko or i-g-t bug.\n"); + set_suspend_test(power_dir, orig_test); + close(power_dir); } /** diff --git a/lib/igt_aux.h b/lib/igt_aux.h index 7f5a7cf..f338504 100644 --- a/lib/igt_aux.h +++ b/lib/igt_aux.h @@ -115,8 +115,28 @@ void igt_trash_aperture(void); void igt_cleanup_aperture_trashers(void); /* suspend/hibernate and auto-resume system */ -void igt_system_suspend_autoresume(void); -void igt_system_hibernate_autoresume(void); + +enum igt_suspend_state { + SUSPEND_STATE_FREEZE, + SUSPEND_STATE_MEM, + SUSPEND_STATE_DISK, + + SUSPEND_STATE_NUM, +}; + +enum igt_suspend_test { + SUSPEND_TEST_NONE, + SUSPEND_TEST_FREEZER, + SUSPEND_TEST_DEVICES, + SUSPEND_TEST_PLATFORM, + SUSPEND_TEST_PROCESSORS, + SUSPEND_TEST_CORE, + + SUSPEND_TEST_NUM, +}; + +void igt_system_suspend_autoresume(enum igt_suspend_state state, + enum igt_suspend_test test); /* dropping priviledges */ void igt_drop_root(void); diff --git a/tests/drv_suspend.c b/tests/drv_suspend.c index 601a32e..0a459e3 100644 --- a/tests/drv_suspend.c +++ b/tests/drv_suspend.c @@ -77,9 +77,11 @@ test_fence_restore(int fd, bool tiled2untiled, bool hibernate) gem_set_tiling(fd, handle_tiled, I915_TILING_X, 2048); if (hibernate) - igt_system_hibernate_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_DISK, + SUSPEND_TEST_NONE); else - igt_system_suspend_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); igt_info("checking the first canary object\n"); for (i = 0; i < OBJECT_SIZE/sizeof(uint32_t); i++) @@ -117,9 +119,11 @@ test_debugfs_reader(bool hibernate) sleep(1); if (hibernate) - igt_system_hibernate_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_DISK, + SUSPEND_TEST_NONE); else - igt_system_suspend_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); sleep(1); @@ -145,9 +149,11 @@ test_sysfs_reader(bool hibernate) sleep(1); if (hibernate) - igt_system_hibernate_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_DISK, + SUSPEND_TEST_NONE); else - igt_system_suspend_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); sleep(1); @@ -163,9 +169,11 @@ test_forcewake(bool hibernate) igt_assert_lte(0, fw_fd); if (hibernate) - igt_system_hibernate_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_DISK, + SUSPEND_TEST_NONE); else - igt_system_suspend_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); close (fw_fd); } diff --git a/tests/gem_exec_suspend.c b/tests/gem_exec_suspend.c index a45082e..b953afb 100644 --- a/tests/gem_exec_suspend.c +++ b/tests/gem_exec_suspend.c @@ -206,11 +206,13 @@ static void run_test(int fd, unsigned engine, unsigned flags) break; case SUSPEND: - igt_system_suspend_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); break; case HIBERNATE: - igt_system_hibernate_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_DISK, + SUSPEND_TEST_NONE); break; } diff --git a/tests/gem_mocs_settings.c b/tests/gem_mocs_settings.c index 2b85749..7c7a9af 100644 --- a/tests/gem_mocs_settings.c +++ b/tests/gem_mocs_settings.c @@ -384,8 +384,10 @@ static void default_context_tests(unsigned mode) switch (mode) { case NONE: break; case RESET: igt_force_gpu_reset(); break; - case SUSPEND: igt_system_suspend_autoresume(); break; - case HIBERNATE: igt_system_hibernate_autoresume(); break; + case SUSPEND: igt_system_suspend_autoresume(SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); break; + case HIBERNATE: igt_system_suspend_autoresume(SUSPEND_STATE_DISK, + SUSPEND_TEST_NONE); break; } test_mocs_values(fd); @@ -423,8 +425,10 @@ static void default_dirty_tests(unsigned mode) switch (mode) { case NONE: break; case RESET: igt_force_gpu_reset(); break; - case SUSPEND: igt_system_suspend_autoresume(); break; - case HIBERNATE: igt_system_hibernate_autoresume(); break; + case SUSPEND: igt_system_suspend_autoresume(SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); break; + case HIBERNATE: igt_system_suspend_autoresume(SUSPEND_STATE_DISK, + SUSPEND_TEST_NONE); break; } close(fd); @@ -446,8 +450,10 @@ static void context_save_restore_test(unsigned mode) switch (mode) { case NONE: break; case RESET: igt_force_gpu_reset(); break; - case SUSPEND: igt_system_suspend_autoresume(); break; - case HIBERNATE: igt_system_hibernate_autoresume(); break; + case SUSPEND: igt_system_suspend_autoresume(SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); break; + case HIBERNATE: igt_system_suspend_autoresume(SUSPEND_STATE_DISK, + SUSPEND_TEST_NONE); break; } check_control_registers(fd, I915_EXEC_RENDER, ctx_id, false); @@ -489,8 +495,10 @@ static void context_dirty_test(unsigned mode) switch (mode) { case NONE: break; case RESET: igt_force_gpu_reset(); break; - case SUSPEND: igt_system_suspend_autoresume(); break; - case HIBERNATE: igt_system_hibernate_autoresume(); break; + case SUSPEND: igt_system_suspend_autoresume(SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); break; + case HIBERNATE: igt_system_suspend_autoresume(SUSPEND_STATE_DISK, + SUSPEND_TEST_NONE); break; } check_control_registers(fd, I915_EXEC_RENDER, ctx_id, true); diff --git a/tests/gem_ringfill.c b/tests/gem_ringfill.c index 8047042..eff0775 100644 --- a/tests/gem_ringfill.c +++ b/tests/gem_ringfill.c @@ -175,10 +175,12 @@ static void run_test(int fd, unsigned ring, unsigned flags) fill_ring(fd, &execbuf, flags); if (flags & SUSPEND) - igt_system_suspend_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); if (flags & HIBERNATE) - igt_system_hibernate_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_DISK, + SUSPEND_TEST_NONE); igt_waitchildren(); } else diff --git a/tests/gem_softpin.c b/tests/gem_softpin.c index cac4669..ea162c8 100644 --- a/tests/gem_softpin.c +++ b/tests/gem_softpin.c @@ -451,10 +451,12 @@ static void test_noreloc(int fd, enum sleep sleep) case NOSLEEP: break; case SUSPEND: - igt_system_suspend_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); break; case HIBERNATE: - igt_system_hibernate_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_DISK, + SUSPEND_TEST_NONE); break; } } diff --git a/tests/gem_stolen.c b/tests/gem_stolen.c index 7d329dd..1d48997 100644 --- a/tests/gem_stolen.c +++ b/tests/gem_stolen.c @@ -359,7 +359,7 @@ static void stolen_hibernate(int fd) drm_intel_bo_unreference(src); - igt_system_hibernate_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_DISK, SUSPEND_TEST_NONE); /* Check if the object's memory contents are intact * across hibernation. */ diff --git a/tests/gem_workarounds.c b/tests/gem_workarounds.c index d15cf91..e512dd3 100644 --- a/tests/gem_workarounds.c +++ b/tests/gem_workarounds.c @@ -60,7 +60,7 @@ static void test_hang_gpu(void) static void test_suspend_resume(void) { igt_info("Suspending the device ...\n"); - igt_system_suspend_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_MEM, SUSPEND_TEST_NONE); } static int workaround_fail_count(void) diff --git a/tests/kms_cursor_crc.c b/tests/kms_cursor_crc.c index d1de450..926579d 100644 --- a/tests/kms_cursor_crc.c +++ b/tests/kms_cursor_crc.c @@ -140,7 +140,8 @@ static void do_single_test(data_t *data, int x, int y) } if (data->flags & TEST_SUSPEND) - igt_system_suspend_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); igt_pipe_crc_collect_crc(pipe_crc, &crc_after); igt_assert_crc_equal(&crc, &crc_after); diff --git a/tests/kms_fbcon_fbt.c b/tests/kms_fbcon_fbt.c index 586cdf5..6342289 100644 --- a/tests/kms_fbcon_fbt.c +++ b/tests/kms_fbcon_fbt.c @@ -217,7 +217,8 @@ static void subtest(struct feature *feature, bool suspend) igt_assert(feature->wait_until_enabled()); if (suspend) { - igt_system_suspend_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); sleep(5); igt_assert(feature->wait_until_enabled()); } @@ -232,7 +233,8 @@ static void subtest(struct feature *feature, bool suspend) igt_assert(!feature->wait_until_enabled()); if (suspend) { - igt_system_suspend_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); sleep(5); igt_assert(!feature->wait_until_enabled()); } diff --git a/tests/kms_flip.c b/tests/kms_flip.c index 065ad66..7646aaf 100644 --- a/tests/kms_flip.c +++ b/tests/kms_flip.c @@ -1013,7 +1013,8 @@ static unsigned int run_test_step(struct test_output *o) igt_assert(igt_wait_for_pm_status(IGT_RUNTIME_PM_STATUS_SUSPENDED)); if (o->flags & TEST_SUSPEND) - igt_system_suspend_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); if (do_vblank && (o->flags & TEST_EINVAL) && o->vblank_state.count > 0) igt_assert(do_wait_for_vblank(o, o->pipe, target_seq, &vbl_reply) diff --git a/tests/kms_frontbuffer_tracking.c b/tests/kms_frontbuffer_tracking.c index 02ccbeb..3a8b458 100644 --- a/tests/kms_frontbuffer_tracking.c +++ b/tests/kms_frontbuffer_tracking.c @@ -2865,13 +2865,13 @@ static void suspend_subtest(const struct test_mode *t) prepare_subtest(t, NULL); sleep(5); - igt_system_suspend_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_MEM, SUSPEND_TEST_NONE); sleep(5); do_assertions(0); unset_all_crtcs(); sleep(5); - igt_system_suspend_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_MEM, SUSPEND_TEST_NONE); sleep(5); do_assertions(ASSERT_FBC_DISABLED | ASSERT_PSR_DISABLED | DONT_ASSERT_CRC); diff --git a/tests/kms_pipe_crc_basic.c b/tests/kms_pipe_crc_basic.c index 2d2f2d6..04d5a13 100644 --- a/tests/kms_pipe_crc_basic.c +++ b/tests/kms_pipe_crc_basic.c @@ -223,7 +223,8 @@ igt_main igt_subtest_f("suspend-read-crc-pipe-%c", 'A'+i) { igt_skip_on(i >= data.display.n_pipes); - igt_system_suspend_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); test_read_crc(&data, i, 0); } diff --git a/tests/kms_plane.c b/tests/kms_plane.c index 7c01fe9..ce5e310 100644 --- a/tests/kms_plane.c +++ b/tests/kms_plane.c @@ -328,7 +328,8 @@ test_plane_panning_with_output(data_t *data, igt_display_commit(&data->display); if (flags & TEST_SUSPEND_RESUME) - igt_system_suspend_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); igt_pipe_crc_collect_crc(data->pipe_crc, &crc); diff --git a/tests/kms_psr_sink_crc.c b/tests/kms_psr_sink_crc.c index 68310d8..224e63c 100644 --- a/tests/kms_psr_sink_crc.c +++ b/tests/kms_psr_sink_crc.c @@ -604,7 +604,8 @@ int main(int argc, char *argv[]) setup_test_plane(&data); igt_assert(wait_psr_entry(&data)); - igt_system_suspend_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); run_test(&data); test_cleanup(&data); @@ -615,7 +616,8 @@ int main(int argc, char *argv[]) data.op = PLANE_ONOFF; setup_test_plane(&data); - igt_system_suspend_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_MEM, + SUSPEND_TEST_NONE); igt_assert(wait_psr_entry(&data)); run_test(&data); diff --git a/tests/pm_rpm.c b/tests/pm_rpm.c index 8297207..d0600d5 100644 --- a/tests/pm_rpm.c +++ b/tests/pm_rpm.c @@ -1369,7 +1369,7 @@ static void __attribute__((noreturn)) stay_subtest(void) static void system_suspend_subtest(void) { disable_all_screens_and_wait(&ms_data); - igt_system_suspend_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_MEM, SUSPEND_TEST_NONE); igt_assert(wait_for_suspended()); } @@ -1401,7 +1401,7 @@ static void system_suspend_execbuf_subtest(void) i915_execbuffer2_set_context_id(execbuf, 0); disable_all_screens_and_wait(&ms_data); - igt_system_suspend_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_MEM, SUSPEND_TEST_NONE); igt_assert(wait_for_suspended()); for (i = 0; i < 20; i++) { @@ -1415,7 +1415,7 @@ static void system_suspend_execbuf_subtest(void) static void system_suspend_modeset_subtest(void) { disable_all_screens_and_wait(&ms_data); - igt_system_suspend_autoresume(); + igt_system_suspend_autoresume(SUSPEND_STATE_MEM, SUSPEND_TEST_NONE); igt_assert(wait_for_suspended()); enable_one_screen_and_wait(&ms_data); -- 2.5.0 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx