RUNTIME_PM_STATUS_UNKNOWN,
};
+enum pc8_status {
+ PC8_ENABLED,
+ PC8_DISABLED
+};
+
enum screen_type {
SCREEN_TYPE_LPSP,
SCREEN_TYPE_NON_LPSP,
SCREEN_TYPE_ANY,
};
-enum residency_wait {
- WAIT,
- DONT_WAIT,
-};
+/* Wait flags */
+#define DONT_WAIT 0
+#define WAIT_STATUS 1
+#define WAIT_PC8_RES 2
-int drm_fd, msr_fd, pm_status_fd;
+int drm_fd, msr_fd, pm_status_fd, pc8_status_fd;
bool has_runtime_pm, has_pc8;
struct mode_set_data ms_data;
return false;
}
-/* Checks not only if PC8+ is allowed, but also if we're reaching it.
- * We call this when we expect this function to return quickly since PC8 is
- * actually enabled, so the 30s timeout we use shouldn't matter. */
-static bool pc8_plus_enabled(void)
+static enum pc8_status get_pc8_status(void)
{
- return pc8_plus_residency_changed(30);
+ ssize_t n_read;
+ char buf[150]; /* The whole file has less than 100 chars. */
+
+ lseek(pc8_status_fd, 0, SEEK_SET);
+ n_read = read(pc8_status_fd, buf, ARRAY_SIZE(buf));
+ igt_assert(n_read >= 0);
+ buf[n_read] = '\0';
+
+ if (strstr(buf, "\nEnabled: yes\n"))
+ return PC8_ENABLED;
+ else
+ return PC8_DISABLED;
}
-/* We call this when we expect PC8+ to be actually disabled, so we should not
- * return until the 5s timeout expires. In other words: in the "happy case",
- * every time we call this function the program will take 5s more to finish. */
-static bool pc8_plus_disabled(void)
+static bool wait_for_pc8_status(enum pc8_status status)
{
- return !pc8_plus_residency_changed(5);
+ int i;
+ int hundred_ms = 100 * 1000, ten_s = 10 * 1000 * 1000;
+
+ for (i = 0; i < ten_s; i += hundred_ms) {
+ if (get_pc8_status() == status)
+ return true;
+
+ usleep(hundred_ms);
+ }
+
+ return false;
}
static enum runtime_pm_status get_runtime_pm_status(void)
static bool wait_for_suspended(void)
{
if (has_pc8 && !has_runtime_pm)
- return pc8_plus_enabled();
+ return wait_for_pc8_status(PC8_ENABLED);
else
return wait_for_pm_status(RUNTIME_PM_STATUS_SUSPENDED);
}
static bool wait_for_active(void)
{
if (has_pc8 && !has_runtime_pm)
- return pc8_plus_disabled();
+ return wait_for_pc8_status(PC8_DISABLED);
else
return wait_for_pm_status(RUNTIME_PM_STATUS_ACTIVE);
}
if (!supports_pc8_plus_residencies())
return;
+ pc8_status_fd = open("/sys/kernel/debug/dri/0/i915_pc8_status",
+ O_RDONLY);
+ igt_assert_f(pc8_status_fd >= 0,
+ "Can't open /sys/kernel/debug/dri/0/i915_pc8_status");
+
has_pc8 = true;
}
close(msr_fd);
if (has_runtime_pm)
close(pm_status_fd);
+ if (has_pc8)
+ close(pc8_status_fd);
}
static void basic_subtest(void)
{
+ disable_all_screens(&ms_data);
+ igt_assert(wait_for_suspended());
+
+ enable_one_screen(&ms_data);
+ igt_assert(wait_for_active());
+}
+
+static void pc8_residency_subtest(void)
+{
+ igt_require(has_pc8);
+
/* Make sure PC8+ residencies move! */
disable_all_screens(&ms_data);
- igt_assert_f(pc8_plus_enabled(),
+ igt_assert_f(pc8_plus_residency_changed(120),
"Machine is not reaching PC8+ states, please check its "
"configuration.\n");
/* Make sure PC8+ residencies stop! */
enable_one_screen(&ms_data);
- igt_assert_f(pc8_plus_disabled(),
+ igt_assert_f(!pc8_plus_residency_changed(10),
"PC8+ residency didn't stop with screen enabled.\n");
}
-static void modeset_subtest(enum screen_type type, int rounds,
- enum residency_wait wait)
+static void modeset_subtest(enum screen_type type, int rounds, int wait_flags)
{
int i;
+ if (wait_flags & WAIT_PC8_RES)
+ igt_require(has_pc8);
+
for (i = 0; i < rounds; i++) {
disable_all_screens(&ms_data);
- if (wait == WAIT)
+ if (wait_flags & WAIT_STATUS)
igt_assert(wait_for_suspended());
+ if (wait_flags & WAIT_PC8_RES)
+ igt_assert(pc8_plus_residency_changed(120));
/* If we skip this line it's because the type of screen we want
* is not connected. */
igt_require(enable_one_screen_with_type(&ms_data, type));
- if (wait == WAIT)
+ if (wait_flags & WAIT_STATUS)
igt_assert(wait_for_active());
+ if (wait_flags & WAIT_PC8_RES)
+ igt_assert(!pc8_plus_residency_changed(5));
}
}
/* Basic modeset */
igt_subtest("modeset-lpsp")
- modeset_subtest(SCREEN_TYPE_LPSP, 1, WAIT);
+ modeset_subtest(SCREEN_TYPE_LPSP, 1, WAIT_STATUS);
igt_subtest("modeset-non-lpsp")
- modeset_subtest(SCREEN_TYPE_NON_LPSP, 1, WAIT);
+ modeset_subtest(SCREEN_TYPE_NON_LPSP, 1, WAIT_STATUS);
/* GEM */
igt_subtest("gem-mmap-cpu")
/* Misc */
igt_subtest("i2c")
i2c_subtest();
+ igt_subtest("pc8-residency")
+ pc8_residency_subtest();
igt_subtest("debugfs-read")
debugfs_read_subtest();
igt_subtest("debugfs-forcewake-user")
/* Modeset stress */
igt_subtest("modeset-lpsp-stress")
- modeset_subtest(SCREEN_TYPE_LPSP, 50, WAIT);
+ modeset_subtest(SCREEN_TYPE_LPSP, 50, WAIT_STATUS);
igt_subtest("modeset-non-lpsp-stress")
- modeset_subtest(SCREEN_TYPE_NON_LPSP, 50, WAIT);
+ modeset_subtest(SCREEN_TYPE_NON_LPSP, 50, WAIT_STATUS);
igt_subtest("modeset-lpsp-stress-no-wait")
modeset_subtest(SCREEN_TYPE_LPSP, 50, DONT_WAIT);
igt_subtest("modeset-non-lpsp-stress-no-wait")
modeset_subtest(SCREEN_TYPE_NON_LPSP, 50, DONT_WAIT);
+ igt_subtest("modeset-pc8-residency-stress")
+ modeset_subtest(SCREEN_TYPE_ANY, 50, WAIT_PC8_RES);
/* GEM stress */
igt_subtest("gem-execbuf-stress")