[igt-dev] [RFC i-g-t] igt/kms_cursor_legacy: Add single atomic 2x flip vs cursor tests

sunpeng.li at amd.com sunpeng.li at amd.com
Fri Oct 12 00:46:28 UTC 2018


From: Leo Li <sunpeng.li at amd.com>

This test executes flips on both CRTCs by using a single atomic commit,
while running cursor updates in parallel.

It tests the problem as described by this DRM patch:
https://patchwork.freedesktop.org/patch/256297/

This is a rough test that I c-and-p'd together with existing code,
just to showcase the issue. The 2x-nonblocking-modeset-vs-cursor-atomic
test might have been sufficient, but amdgpu currently doesn't like
non-blocking modesets. I can't try it on i915 either, since the issue is
being masked by commit_hw_done() being done after wait_for_flip_done().

It's currently quite flakey. On my system, it usually causes the
protection fault on second run, regardless of the test duration. I'm not
yet sure how to write something that can test this reliably.

It also isn't verifying the vblank counts. Interestingly, it seems to
reproduce less when I do verify them. So for the sake of showcasing
the problem, I left it out.

Needless to say, lots of wrong things being done here. Any input on how
to structure this test and make it more reliable will be much
appreciated :)

Signed-off-by: Leo Li <sunpeng.li at amd.com>
---
 tests/kms_cursor_legacy.c | 97 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 97 insertions(+)

diff --git a/tests/kms_cursor_legacy.c b/tests/kms_cursor_legacy.c
index 79df79a3..64d6545d 100644
--- a/tests/kms_cursor_legacy.c
+++ b/tests/kms_cursor_legacy.c
@@ -266,6 +266,27 @@ static void flip_nonblocking(igt_display_t *display, enum pipe pipe_id, bool ato
 	igt_reset_timeout();
 }
 
+static void flip_two_pipes_nonblocking(igt_display_t *display,
+				      enum pipe pipe1_id, enum pipe pipe2_id,
+				      struct igt_fb *fb1, struct igt_fb *fb2,
+				      void *data)
+{
+	igt_pipe_t *pipe1 = &display->pipes[pipe1_id];
+	igt_pipe_t *pipe2 = &display->pipes[pipe2_id];
+	igt_plane_t *primary1 = igt_pipe_get_plane_type(pipe1, DRM_PLANE_TYPE_PRIMARY);
+	igt_plane_t *primary2 = igt_pipe_get_plane_type(pipe2, DRM_PLANE_TYPE_PRIMARY);
+	int ret;
+
+	igt_set_timeout(1, "Scheduling page flip\n");
+	igt_plane_set_fb(primary1, fb1);
+	igt_plane_set_fb(primary2, fb2);
+	do {
+		ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT, data);
+	} while (ret == -EBUSY);
+	igt_assert(!ret);
+	igt_reset_timeout();
+}
+
 enum flip_test {
 	flip_test_legacy = 0,
 	flip_test_varying_size,
@@ -1022,6 +1043,76 @@ done:
 	igt_remove_fb(display->drm_fd, &cursor_fb);
 }
 
+static void two_screens_single_atomic_flip_vs_cursor(igt_display_t *display,
+						     int nloops)
+{
+	struct drm_mode_cursor arg1[2], arg2[2];
+	struct igt_fb fb_info, fb2_info, cursor_fb;
+	enum pipe pipe = find_connected_pipe(display, false);
+	enum pipe pipe2 = find_connected_pipe(display, true);
+	igt_output_t *output, *output2;
+	volatile unsigned long *shared;
+	struct drm_event_vblank vbl;
+
+	shared = mmap(NULL, 4096, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
+	igt_assert(shared != MAP_FAILED);
+
+	igt_require(display->is_atomic);
+
+	igt_require((output = set_fb_on_crtc(display, pipe, &fb_info)));
+	igt_require((output2 = set_fb_on_crtc(display, pipe2, &fb2_info)));
+
+	igt_create_color_fb(display->drm_fd, 64, 64, DRM_FORMAT_ARGB8888, 0, 1., 1., 1., &cursor_fb);
+	set_cursor_on_pipe(display, pipe, &cursor_fb);
+	populate_cursor_args(display, pipe, arg1, &cursor_fb);
+
+	arg1[1].x = arg1[1].y = 192;
+
+	set_cursor_on_pipe(display, pipe2, &cursor_fb);
+	populate_cursor_args(display, pipe2, arg2, &cursor_fb);
+
+	arg2[1].x = arg2[1].y = 192;
+
+
+	igt_display_commit2(display, COMMIT_ATOMIC);
+
+	igt_fork(child, 2) {
+		struct drm_mode_cursor *arg = child ? arg2 : arg1;
+
+		while (!shared[0])
+			do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR,
+				 &arg[!shared[1]]);
+	}
+
+	flip_two_pipes_nonblocking(display, pipe, pipe2, &fb_info, &fb2_info, NULL);
+
+	while (nloops) {
+		shared[1] = nloops & 1;
+
+		igt_set_timeout(1, "Stuck page flip");
+		igt_assert_eq(read(display->drm_fd, &vbl, sizeof(vbl)), sizeof(vbl));
+		igt_assert_eq(read(display->drm_fd, &vbl, sizeof(vbl)), sizeof(vbl));
+		igt_reset_timeout();
+
+		/* Do not requeue on the last 2 events. */
+		if (nloops <= 1) {
+			nloops--;
+			continue;
+		}
+
+		flip_two_pipes_nonblocking(display, pipe, pipe2, &fb_info, &fb2_info, NULL);
+		nloops--;
+
+	}
+
+	shared[0] = 1;
+	igt_waitchildren();
+
+	igt_remove_fb(display->drm_fd, &fb_info);
+	igt_remove_fb(display->drm_fd, &fb2_info);
+	igt_remove_fb(display->drm_fd, &cursor_fb);
+}
+
 static void cursor_vs_flip(igt_display_t *display, enum flip_test mode, int nloops)
 {
 	struct drm_mode_cursor arg[2];
@@ -1445,6 +1536,12 @@ igt_main
 	igt_subtest("2x-long-cursor-vs-flip-atomic")
 		two_screens_cursor_vs_flip(&display, 50, true);
 
+	igt_subtest("2x-mirrored-flip-vs-cursor-atomic")
+		two_screens_single_atomic_flip_vs_cursor(&display, 8);
+
+	igt_subtest("2x-long-mirrored-flip-vs-cursor-atomic")
+		two_screens_single_atomic_flip_vs_cursor(&display, 150);
+
 	igt_subtest("flip-vs-cursor-crc-legacy")
 		flip_vs_cursor_crc(&display, false);
 
-- 
2.17.1



More information about the igt-dev mailing list