[PATCH] edp-DRRS test

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Idleness DRRS:
	By default the DRRS state will be at DRRS_HIGH_RR. When a Display
	content is Idle for more than 1Sec Idleness will be declared and
	DRRS_LOW_RR will be invoked, changing the refresh rate to the
	lower most refresh rate supported by the panel. As soon as there
	is a display content change there will be a DRRS state transition
	as DRRS_LOW_RR--> DRRS_HIGH_RR, changing the refresh rate to the
	highest refresh rate supported by the panel.

To test this, Idleness DRRS IGT will probe the DRRS state at below
instances and compare with the expected state.

	Instance					Expected State
1. Immediately after rendering the still image		DRRS_HIGH_RR
2. After a delay of 1.2Sec				DRRS_LOW_RR
3. After changing the frame buffer			DRRS_HIGH_RR
4. After a delay of 1.2Sec				DRRS_LOW_RR
5. After changing the frame buffer			DRRS_HIGH_RR
6. After a delay of 1.2Sec				DRRS_LOW_RR

The test checks the driver DRRS state from the debugfs entry. To check the
actual refresh-rate, the number of vblanks received per sec.
The refresh-rate calculated is checked against the expected refresh-rate
with a tolerance value of 2.

This patch is a continuation of the earlier work
https://patchwork.freedesktop.org/patch/45472/ towards igt for idleness

DRRS. The code is tested on Broxton BXT_T platform.

v2: Addressed the comments and suggestions from Vlad, Marius.
The signoff details from the earlier work are also included.

v3: Modified vblank rate calculation by using reply-sequence, provided by
drmWaitVBlank, as suggested by Chris Wilson.

v4: As suggested from Chris Wilson and Daniel Vetter
	1) Avoided using pthread for calculating vblank refresh rate,
	   instead used drmWaitVBlank reply sequence.
	2) Avoided using kernel-specific info like transitional delays,
	   instead polling mechanism with timeout is used.
	3) Included edp-DRRS as a subtest in kms_frontbuffer_tracking.c,
	   instead of having a separate test.

This is in continuation of last patch "https://patchwork.freedesktop.org/patch/117149/";

Signed-off-by: Lohith BS <lohith.bs@xxxxxxxxx>
Signed-off-by: Ramalingam C <ramalingam.c@xxxxxxxxx>
Signed-off-by: Vandana Kannan <vandana.kannan@xxxxxxxxx>
Signed-off-by: aknautiy <ankit.k.nautiyal@xxxxxxxxx>
---
 tests/kms_frontbuffer_tracking.c | 453 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 452 insertions(+), 1 deletion(-)

diff --git a/tests/kms_frontbuffer_tracking.c b/tests/kms_frontbuffer_tracking.c
index c24e4a8..4d46e1e 100644
--- a/tests/kms_frontbuffer_tracking.c
+++ b/tests/kms_frontbuffer_tracking.c
@@ -32,9 +32,18 @@
 #include <poll.h>
 #include <pthread.h>
 
+#include "drmtest.h"
+#include "igt_debugfs.h"
+#include "igt_kms.h"
+#include "intel_chipset.h"
+#include "intel_batchbuffer.h"
+#include "ioctl_wrappers.h"
+#include <time.h>
+#include <stdlib.h>
+#include <sys/time.h>
 
 IGT_TEST_DESCRIPTION("Test the Kernel's frontbuffer tracking mechanism and "
-		     "its related features: FBC and PSR");
+		     "its related features: DRRS, FBC and PSR");
 
 /*
  * One of the aspects of this test is that, for every subtest, we try different
@@ -327,6 +336,41 @@ drmModeModeInfo std_1024_mode = {
 	.name = "Custom 1024x768",
 };
 
+#define DRRS_TOLERANCE_THRESHOLD 2
+#define DRRS_POLL_TIMEOUT_PERIOD_MS 5000
+#define DRRS_STATUS_BYTES_CNT 1000
+#define DRRS_MAX_ITERATION 3
+
+/*
+ * Struct to hold drrs test related data
+ */
+typedef struct {
+	uint32_t devid;
+	uint32_t handle[2];
+	igt_display_t display;
+	igt_output_t *output;
+	enum pipe pipe;
+	igt_plane_t *primary;
+	struct igt_fb fb[2];
+	uint32_t fb_id[2];
+} drrs_data_t;
+
+/*
+ * Structure to count vblank and note the starting time of the counter
+ */
+typedef struct {
+	unsigned int vbl_count;
+	struct timeval start;
+} vbl_info;
+
+/*
+ * Structure for refresh rate type
+ */
+typedef struct{
+	int rate;
+	const char *name;
+} refresh_rate_t;
+
 static drmModeModeInfoPtr get_connector_smallest_mode(drmModeConnectorPtr c)
 {
 	int i;
@@ -3415,6 +3459,410 @@ static const char *flip_str(enum flip_type flip)
 
 #define TEST_MODE_ITER_END } } } } } }
 
+static inline uint32_t pipe_select(int pipe)
+{
+	if (pipe > 1)
+		return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
+	else if (pipe > 0)
+		return DRM_VBLANK_SECONDARY;
+	else
+		return DRM_VBLANK_ABSOLUTE;
+}
+
+/*
+ * Calculates the total no. of millisec elapsed since timeval start
+ */
+static double igt_millisec_elapsed(const struct timeval *start)
+{
+	struct timeval curr;
+
+	gettimeofday(&curr, NULL);
+	return (1e3*(curr.tv_sec - start->tv_sec) +
+				(curr.tv_usec - start->tv_usec)/1000.00);
+}
+
+/*
+ * Func to read the DRRS status from debugfs
+ */
+static bool read_drrs_status(char *str)
+{
+	FILE *fp;
+	int fd;
+	int cnt;
+
+	fd = igt_debugfs_open(drm.fd, "i915_drrs_status", O_RDONLY);
+	igt_assert(fd);
+	fp = fdopen(fd, "r");
+	igt_require(fp);
+	cnt = fread(str, DRRS_STATUS_BYTES_CNT - 1, 1, fp);
+
+	if (!cnt) {
+		if (!feof(fp)) {
+			igt_critical("Failed to read i915_drrs_status:%d \n",
+				ferror(fp));
+			return false;
+		}
+		clearerr(fp);
+	}
+	fclose(fp);
+
+	return true;
+}
+
+/*
+ * Func to check for DRRS support
+ */
+static bool is_drrs_supported(void)
+{
+	char str[DRRS_STATUS_BYTES_CNT] = {};
+
+	if (!read_drrs_status(str))
+		return false;
+
+	return strstr(str, "DRRS Supported: Yes") != NULL;
+}
+
+/*
+ * Func to check if DRRS is enabled by driver.
+ */
+static bool is_drrs_enabled(void)
+{
+	char str[DRRS_STATUS_BYTES_CNT] = {};
+
+	if (!read_drrs_status(str))
+		return false;
+
+	return strstr(str, "Idleness DRRS: Disabled") == NULL;
+}
+
+
+/*
+ * vbl_rate = vbl_count/time taken
+ */
+static double vbl_rate(const union drm_wait_vblank *start,
+				const union drm_wait_vblank *end)
+{
+	double s, e;
+
+	s = start->reply.tval_sec + 1e-6 * start->reply.tval_usec;
+	e = end->reply.tval_sec + 1e-6 * end->reply.tval_usec;
+	return ((end->reply.sequence - start->reply.sequence) / (e - s));
+}
+
+/*
+ * refresh_rate = (20 vblanks) /(time for 20vblanks)
+ */
+int calculate_refresh_rate(drrs_data_t *data)
+{
+	union drm_wait_vblank start, end;
+	struct timeval start_tv;
+	int refresh_rate;
+
+	memset(&start, 0, sizeof(start));
+	start.request.type = DRM_VBLANK_RELATIVE | pipe_select(data->pipe);
+
+	if (drmWaitVBlank(drm.fd, &start) != 0) {
+		igt_critical("drmWaitVBlank Failed!\n");
+		return -1;
+	}
+	gettimeofday(&start_tv, NULL);
+	memset(&end, 0, sizeof(end));
+	end.request.type = DRM_VBLANK_RELATIVE | pipe_select(data->pipe);
+
+	/* Configured to wait for 20 vblank events*/
+	end.request.sequence = 20;
+
+	if (drmWaitVBlank(drm.fd, &end) != 0) {
+		igt_critical("drmWaitVBlank Failed!\n");
+		return -1;
+	}
+	refresh_rate = vbl_rate(&start, &end);
+
+	return refresh_rate;
+}
+
+/*
+ * Poll for DRRS transition from high to low with 5 seconds time out.
+ */
+int wait_for_drrs_switch_to_low(drrs_data_t *data)
+{
+	char drrs_status[DRRS_STATUS_BYTES_CNT] = {};
+	const char *drrs_low_name = "DRRS_LOW_RR";
+	int status = 1;
+	struct timeval start_tv;
+
+	gettimeofday(&start_tv, NULL);
+
+	while (igt_millisec_elapsed(&start_tv) < DRRS_POLL_TIMEOUT_PERIOD_MS) {
+
+		if (!read_drrs_status(drrs_status)) {
+			status = -1;
+			break;
+		}
+
+		if (strstr(drrs_status, drrs_low_name) != NULL)
+			break;
+	}
+
+	if (igt_millisec_elapsed(&start_tv) > DRRS_POLL_TIMEOUT_PERIOD_MS) {
+
+		igt_critical("DRRS failed to switch refresh rate from "
+			"higher to lower\n");
+
+		status = -1;
+	}
+
+	return status;
+}
+
+/*
+ * Check if calulated refresh rate is same as expected refresh rate
+ * Returns 0 in case of pass , 1 in case of failure, and -1 for error.
+ */
+static int check_refresh_rate(drrs_data_t *data, refresh_rate_t *expected_rr)
+{
+	int refresh_rate = -1;
+	char drrs_status[DRRS_STATUS_BYTES_CNT] = {};
+
+	/* Get the DRRS Status from the debugfs entry */
+	if (!read_drrs_status(drrs_status))
+		return -1;
+
+	refresh_rate = calculate_refresh_rate(data);
+
+	if (refresh_rate < 0) {
+		igt_critical("Refresh rate calculation FAILED\n");
+		return -1;
+	}
+
+	/* Compare with Expected Refresh Rate */
+	if (strstr(drrs_status, expected_rr->name) != NULL
+	&& abs(refresh_rate - expected_rr->rate) <= DRRS_TOLERANCE_THRESHOLD) {
+		return 0;
+	}
+	igt_critical("Expected %s : FAILED.\n", expected_rr->name);
+
+	return 1;
+}
+
+/*
+ * This function
+ * 1. Creates framebuffers
+ * 2. Apply framebuffers alternatively and count the vblank refresh rate
+ *    which should be equal to highest refresh rate supported.
+ * 3. Poll for DRRS to toggle from DRRS_HIGH_RR -> DRRS_LOW_RR with 5sec
+ *    timeout using kernel debugfs entry(i915_drrs_status).
+ * 4. Once DRRS switches to LOW we count the vblank refresh rate which
+ *    should be equal to lowest refresh rate supported.
+ * 5. The above calculated vblank refresh rates can have a tolerance of 2.
+ */
+static int execute_test(drrs_data_t *data)
+{
+	igt_display_t *display = &data->display;
+	igt_output_t *output = data->output;
+	drmModeModeInfo *mode, *supported_modes;
+	int test_failed = 0;
+	int ret, i, i_mod, count_modes;
+	refresh_rate_t high_rr, low_rr;
+
+	high_rr.name = "DRRS_HIGH_RR";
+	high_rr.rate = 0;
+	low_rr.name = "DRRS_LOW_RR";
+	low_rr.rate = 0;
+
+	/* get the max and min supported refresh rates for the display */
+	supported_modes = output->config.connector->modes;
+	count_modes = output->config.connector->count_modes;
+
+	/* minimum 2 modes are required for DRRS */
+	igt_assert_f(count_modes >= 2, "Minimum 2 modes required for DRRS\n");
+
+	for (i = 0; i < count_modes; i++) {
+		int rr = supported_modes[i].vrefresh;
+
+		if (i == 0) {
+			high_rr.rate = low_rr.rate = rr;
+			continue;
+		}
+
+		if (high_rr.rate < rr)
+			high_rr.rate = rr;
+
+		if (low_rr.rate > rr)
+			low_rr.rate = rr;
+	}
+
+	igt_output_set_pipe(output, data->pipe);
+	data->primary = igt_output_get_plane(data->output,
+				DRM_PLANE_TYPE_OVERLAY);
+	mode = igt_output_get_mode(data->output);
+	data->fb_id[0] = igt_create_color_fb(drm.fd, mode->hdisplay,
+						mode->vdisplay,
+						DRM_FORMAT_XRGB8888,
+						LOCAL_DRM_FORMAT_MOD_NONE,
+						0.0, 100.1, 0.0, &data->fb[0]);
+
+	igt_assert(data->fb_id[0]);
+	data->fb_id[1] = igt_create_color_fb(drm.fd, mode->hdisplay,
+						mode->vdisplay,
+						DRM_FORMAT_XRGB8888,
+						LOCAL_DRM_FORMAT_MOD_NONE,
+						100.1, 0.0, 0.0,
+						&data->fb[1]);
+
+	igt_assert(data->fb_id[1]);
+	data->handle[0] = data->fb[0].gem_handle;
+	data->handle[1] = data->fb[1].gem_handle;
+
+	for (i = 1; i <= DRRS_MAX_ITERATION; i++) {
+		i_mod = i % 2;
+		igt_plane_set_fb(data->primary, &data->fb[i_mod]);
+		igt_display_commit(display);
+
+		if (!is_drrs_enabled()) {
+			igt_critical("DRRS not enabled\n");
+			igt_plane_set_fb(data->primary, NULL);
+			igt_output_set_pipe(output, PIPE_ANY);
+			igt_display_commit(display);
+			igt_remove_fb(drm.fd, &data->fb[0]);
+			igt_remove_fb(drm.fd, &data->fb[1]);
+			return -1;
+		}
+
+		/* expecting High RR */
+		ret =  check_refresh_rate(data, &high_rr);
+
+		if (ret == -1)
+			return -1;
+
+		if (ret == 1)
+			test_failed = 1;
+
+		/*
+		 * Poll kernel debugfs entry for DRRS
+		 * transition from High to Low
+		 */
+		ret = wait_for_drrs_switch_to_low(data);
+
+		if (ret == -1)
+			return 1;
+
+		/* expecting Low RR */
+		ret = check_refresh_rate(data, &low_rr);
+
+		if (ret == -1)
+			return -1;
+
+		if (ret == 1)
+			test_failed = 1;
+	}
+
+	return test_failed;
+}
+
+/*
+ * Func to free the framebuffers after the test completion.
+ */
+static void finish_crtc(drrs_data_t *data)
+{
+	igt_plane_set_fb(data->primary, NULL);
+	igt_output_set_pipe(data->output, PIPE_ANY);
+	igt_display_commit(&data->display);
+
+	igt_remove_fb(drm.fd, &data->fb[0]);
+	igt_remove_fb(drm.fd, &data->fb[1]);
+}
+
+/*
+ * Func to reset the display structures after the test completion.
+ */
+static void reset_display(drrs_data_t *data)
+{
+	igt_display_t *display = &data->display;
+	enum pipe pipe_id;
+
+	for_each_pipe(display, pipe_id) {
+		igt_pipe_t *pipe = &display->pipes[pipe_id];
+		igt_plane_t *plane = igt_pipe_get_plane_type(pipe,
+					DRM_PLANE_TYPE_PRIMARY);
+
+		if (plane->fb)
+			igt_plane_set_fb(plane, NULL);
+	}
+
+	for_each_connected_output(display, data->output)
+		igt_output_set_pipe(data->output, PIPE_ANY);
+}
+
+/*
+ * Func to run the drrs test for the eDP display.
+ */
+static void run_test(drrs_data_t *data)
+{
+	int ret;
+	igt_display_t *display = &data->display;
+
+	reset_display(data);
+
+	for_each_pipe_with_valid_output(display, data->pipe, data->output) {
+		drmModeConnectorPtr c = data->output->config.connector;
+
+		if (c->connector_type != DRM_MODE_CONNECTOR_eDP ||
+			c->connection != DRM_MODE_CONNECTED)
+			continue;
+
+		ret = execute_test(data);
+
+		igt_skip_on_f(ret == -1,
+				"%s on pipe %s, connector %s:SKIPPED\n",
+					igt_subtest_name(),
+					kmstest_pipe_name(data->pipe),
+					igt_output_name(data->output));
+
+		igt_fail_on_f(ret == 1,
+				"%s on pipe %s, connector %s:FAILED\n",
+					igt_subtest_name(),
+					kmstest_pipe_name(data->pipe),
+					igt_output_name(data->output));
+
+		igt_assert_f(ret == 0,
+				"%s on pipe %s, connector %s: PASSED\n",
+					igt_subtest_name(),
+					kmstest_pipe_name(data->pipe),
+					igt_output_name(data->output));
+
+		finish_crtc(data);
+	}
+}
+
+/*
+ * Function to test edp-DRRS feature.Exits from the function if PSR is enabled
+ */
+void edp_drrs_test(void)
+{
+	drrs_data_t data = {};
+
+	igt_assert_f(!psr.can_test,
+			"DRRS cannot be tested as PSR is enabled\n");
+	igt_skip_on_simulation();
+
+	/*
+	 * Using the same drm.fd which was opened during setup_environment
+	 */
+	igt_assert_f(drm.fd != -1, "Invalid fd\n");
+	data.devid = intel_get_drm_devid(drm.fd);
+	igt_assert_f(data.devid >= 0, "Invalid dev id\n");
+
+	/*
+	 * Check if the DRRS is supported.If yes call the Idleness DRRS test
+	 */
+	igt_require_f(is_drrs_supported(),
+			"DRRS not supported:check VBT/panel caps\n");
+	igt_display_init(&data.display, drm.fd);
+	run_test(&data);
+	igt_display_fini(&data.display);
+}
+
 int main(int argc, char *argv[])
 {
 	struct test_mode t;
@@ -3628,6 +4076,9 @@ int main(int argc, char *argv[])
 			suspend_subtest(&t);
 	TEST_MODE_ITER_END
 
+	igt_subtest_f("edp-DRRS")
+		edp_drrs_test();
+
 	t.pipes = PIPE_SINGLE;
 	t.screen = SCREEN_PRIM;
 	t.plane = PLANE_PRI;
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/intel-gfx




[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux