[igt-dev] [RFC 1/1] tests/psr: PSR H/W tracking validation

Anshuman Gupta
2019-10-05T04:48:25Z

Validate the PSR PRE_ENTRY and PST_EXIT PSR IIR
interrupts in order to validate PSR H/W tracking.

Signed-off-by: Anshuman Gupta <anshuman.gupta@intel.com>
---
lib/igt_psr.c | 14 ++++++
lib/igt_psr.h | 3 ++
tests/kms_psr.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 129 insertions(+)

diff --git a/lib/igt_psr.c b/lib/igt_psr.c
index b92ea73f..3c2fbce0 100644
--- a/lib/igt_psr.c
+++ b/lib/igt_psr.c
@@ -163,6 +163,20 @@ bool psr_disable(int debugfs_fd)
return psr_set(debugfs_fd, -1);
}

+void psr_enable_irq_debug(int debugfs_fd)
+{
+ char buf[PSR_DEBUG_MAX_LEN];
+ int psr_debug, ret;
+
+ igt_debugfs_simple_read(debugfs_fd, "i915_edp_psr_debug", buf,
+ sizeof(buf));
+ ret = sscanf(buf, "%d", &psr_debug);
+ igt_assert_eq(ret, 1);
+ psr_debug |= PSR_DEBUG_IRQ;
+ snprintf(buf, sizeof(buf), "%d", psr_debug);
+ psr_write(debugfs_fd, buf);
+}
+
bool psr_sink_support(int debugfs_fd, enum psr_mode mode)
{
char buf[PSR_STATUS_MAX_LEN];
diff --git a/lib/igt_psr.h b/lib/igt_psr.h
index ca385736..2843e99c 100644
--- a/lib/igt_psr.h
+++ b/lib/igt_psr.h
@@ -29,6 +29,8 @@
#include "igt_aux.h"

#define PSR_STATUS_MAX_LEN 512
+#define PSR_DEBUG_MAX_LEN 64
+#define PSR_DEBUG_IRQ 0x10

enum psr_mode {
PSR_MODE_1,
@@ -39,6 +41,7 @@ bool psr_wait_entry(int debugfs_fd, enum psr_mode mode);
bool psr_wait_update(int debugfs_fd, enum psr_mode mode);
bool psr_long_wait_update(int debugfs_fd, enum psr_mode mode);
bool psr_enable(int debugfs_fd, enum psr_mode);
+void psr_enable_irq_debug(int debugfs_fd);
bool psr_disable(int debugfs_fd);
bool psr_sink_support(int debugfs_fd, enum psr_mode);
bool psr2_wait_su(int debugfs_fd, uint16_t *num_su_blocks);
diff --git a/tests/kms_psr.c b/tests/kms_psr.c
index 39de0112..2eb4411b 100644
--- a/tests/kms_psr.c
+++ b/tests/kms_psr.c
@@ -30,9 +30,11 @@
#include <stdio.h>
#include <string.h>
#include "intel_bufmgr.h"
+#include "limits.h"

enum operations {
PAGE_FLIP,
+ PAGE_FLIP_HW_TRACKING,
MMAP_GTT,
MMAP_CPU,
BLT,
@@ -41,10 +43,16 @@ enum operations {
PLANE_ONOFF,
};

+enum psr_irq_type {
+ IRQ_PRE_ENTRY,
+ IRQ_POST_EXIT,
+};
+
static const char *op_str(enum operations op)
{
static const char * const name[] = {
[PAGE_FLIP] = "page_flip",
+ [PAGE_FLIP_HW_TRACKING] = "page_flip_hw_tracking",
[MMAP_GTT] = "mmap_gtt",
[MMAP_CPU] = "mmap_cpu",
[BLT] = "blt",
@@ -62,6 +70,7 @@ typedef struct {
enum operations op;
int test_plane_id;
enum psr_mode op_psr_mode;
+ bool psr_irq_debug;
uint32_t devid;
uint32_t crtc_id;
igt_display_t display;
@@ -206,6 +215,55 @@ static bool psr_wait_entry_if_enabled(data_t *data)
return psr_wait_entry(data->debugfs_fd, data->op_psr_mode);
}

+static uint64_t read_psr_irq_ktime(const char *irq_ktime)
+{
+ char *e;
+ unsigned long ret;
+ char *s = strchr(irq_ktime, ':');
+
+ assert(s);
+ s++;
+ ret = strtol(s, &e, 10);
+ assert(((ret != LONG_MIN && ret != ULONG_MAX) || errno != ERANGE) &&
+ e > s && *e == '\n' && ret >= 0);
+ return ret;
+}
+
+static uint64_t get_psr_irq_time(int debugfs_fd, enum psr_irq_type type)
+{
+ char buf[PSR_STATUS_MAX_LEN];
+ char *str;
+ const char *irq = type == IRQ_PRE_ENTRY ? "Last attempted entry at"
+ : "Last exit at";
+
+ igt_debugfs_simple_read(debugfs_fd, "i915_edp_psr_status", buf,
+ sizeof(buf));
+ str = strstr(buf, irq);
+ return read_psr_irq_ktime(str);
+}
+
+static bool psr_pre_entry_irq_check(int debugfs_fd, uint64_t prev_entry_time)
+{
+ uint64_t irq_entry_time;
+
+ irq_entry_time = get_psr_irq_time(debugfs_fd, IRQ_PRE_ENTRY);
+ igt_debug("PSR IRQ pre entry time %lu\n", irq_entry_time);
+ return (irq_entry_time > prev_entry_time);
+}
+
+static bool psr_wait_pre_entry(int debugfs_fd, uint64_t ktime)
+{
+ return igt_wait(psr_pre_entry_irq_check(debugfs_fd, ktime), 500, 20);
+}
+
+static bool psr_wait_pre_entry_if_enabled(data_t *data, uint64_t ktime)
+{
+ if (data->with_psr_disabled)
+ return true;
+
+ return psr_wait_pre_entry(data->debugfs_fd, ktime);
+}
+
static bool psr_wait_update_if_enabled(data_t *data)
{
if (data->with_psr_disabled)
@@ -214,6 +272,28 @@ static bool psr_wait_update_if_enabled(data_t *data)
return psr_wait_update(data->debugfs_fd, data->op_psr_mode);
}

+static bool psr_post_exit_irq_check(int debugfs_fd, uint64_t prev_exit_time)
+{
+ uint64_t irq_exit_time;
+
+ irq_exit_time = get_psr_irq_time(debugfs_fd, IRQ_POST_EXIT);
+ igt_debug("PSR IRQ posr exit time %lu\n", irq_exit_time);
+ return (irq_exit_time > prev_exit_time);
+}
+
+static bool psr_wait_post_exit(int debugfs_fd, uint64_t ktime)
+{
+ return igt_wait(psr_post_exit_irq_check(debugfs_fd, ktime), 40, 10);
+}
+
+static bool psr_wait_post_exit_if_enabled(data_t *data, uint64_t ktime)
+{
+ if (data->with_psr_disabled)
+ return true;
+
+ return psr_wait_post_exit(data->debugfs_fd, ktime);
+}
+
static bool psr_enable_if_enabled(data_t *data)
{
if (data->with_psr_disabled)
@@ -222,6 +302,14 @@ static bool psr_enable_if_enabled(data_t *data)
return psr_enable(data->debugfs_fd, data->op_psr_mode);
}

+static void psr_enable_irq_debug_if_enabled(data_t *data)
+{
+ if (data->with_psr_disabled)
+ return;
+
+ psr_enable_irq_debug(data->debugfs_fd);
+}
+
static inline void manual(const char *expected)
{
igt_debug_manual_check("all", expected);
@@ -243,10 +331,14 @@ static void run_test(data_t *data)
igt_plane_t *test_plane = data->test_plane;
void *ptr;
const char *expected = "";
+ uint64_t ktime;

/* Confirm that screen became Green */
manual("screen GREEN");

+ if (data->op == PAGE_FLIP_HW_TRACKING)
+ ktime = get_psr_irq_time(data->debugfs_fd, IRQ_PRE_ENTRY);
+
/* Confirm screen stays Green after PSR got active */
igt_assert(psr_wait_entry_if_enabled(data));
manual("screen GREEN");
@@ -261,9 +353,17 @@ static void run_test(data_t *data)
else
manual("GREEN background with WHITE box");

+ if (data->op == PAGE_FLIP_HW_TRACKING)
+ igt_assert(psr_wait_pre_entry_if_enabled(data, ktime));
+
igt_assert(psr_wait_entry_if_enabled(data));
+
+ if (data->op == PAGE_FLIP_HW_TRACKING)
+ ktime = get_psr_irq_time(data->debugfs_fd, IRQ_POST_EXIT);
+
switch (data->op) {
case PAGE_FLIP:
+ case PAGE_FLIP_HW_TRACKING:
/* Only in use when testing primary plane */
igt_assert(drmModePageFlip(data->drm_fd, data->crtc_id,
data->fb_green.fb_id, 0, NULL) == 0);
@@ -310,6 +410,10 @@ static void run_test(data_t *data)
break;
}
igt_assert(psr_wait_update_if_enabled(data));
+
+ if (data->op == PAGE_FLIP_HW_TRACKING)
+ igt_assert(psr_wait_post_exit_if_enabled(data, ktime));
+
manual(expected);
}

@@ -390,6 +494,10 @@ static void test_setup(data_t *data)
if (data->op_psr_mode == PSR_MODE_2)
igt_require(data->supports_psr2);
psr_enable_if_enabled(data);
+
+ if (data->psr_irq_debug)
+ psr_enable_irq_debug_if_enabled(data);
+
setup_test_plane(data, data->test_plane_id);
igt_assert(psr_wait_entry_if_enabled(data));
}
@@ -475,6 +583,10 @@ igt_main_args("", long_options, help_str, opt_handler, &data)
op_str(op)) {
data.op = op;
data.test_plane_id = DRM_PLANE_TYPE_PRIMARY;
+
+ if (data.op == PAGE_FLIP_HW_TRACKING)
+ data.psr_irq_debug = true;
+
test_setup(&data);
run_test(&data);
test_cleanup(&data);
--
2.21.0