summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/kms_busy.c204
1 files changed, 192 insertions, 12 deletions
diff --git a/tests/kms_busy.c b/tests/kms_busy.c
index 1ae5d7fb..d2be7212 100644
--- a/tests/kms_busy.c
+++ b/tests/kms_busy.c
@@ -80,7 +80,7 @@ static void do_cleanup_display(igt_display_t *dpy)
static void finish_fb_busy(igt_spin_t *spin, int msecs)
{
- struct timespec tv = { 0, msecs * 1000 * 1000 };
+ struct timespec tv = { msecs / 1000, (msecs % 1000) * 1000000ULL };
nanosleep(&tv, NULL);
igt_spin_batch_end(spin);
}
@@ -90,42 +90,64 @@ static void sighandler(int sig)
}
static void flip_to_fb(igt_display_t *dpy, int pipe,
+ igt_output_t *output,
struct igt_fb *fb, unsigned ring,
- const char *name)
+ const char *name, bool modeset)
{
struct pollfd pfd = { .fd = dpy->drm_fd, .events = POLLIN };
struct timespec tv = { 1, 0 };
struct drm_event_vblank ev;
+
igt_spin_t *t = igt_spin_batch_new(dpy->drm_fd, ring, fb->gem_handle);
igt_fork(child, 1) {
igt_assert(gem_bo_busy(dpy->drm_fd, fb->gem_handle));
- do_or_die(drmModePageFlip(dpy->drm_fd,
- dpy->pipes[pipe].crtc_id, fb->fb_id,
- DRM_MODE_PAGE_FLIP_EVENT, fb));
+ if (!modeset)
+ do_or_die(drmModePageFlip(dpy->drm_fd,
+ dpy->pipes[pipe].crtc_id, fb->fb_id,
+ DRM_MODE_PAGE_FLIP_EVENT, fb));
+ else {
+ igt_plane_set_fb(igt_output_get_plane(output, IGT_PLANE_PRIMARY), fb);
+ igt_output_set_pipe(output, PIPE_NONE);
+ igt_display_commit_atomic(dpy,
+ DRM_MODE_ATOMIC_NONBLOCK |
+ DRM_MODE_PAGE_FLIP_EVENT |
+ DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
+ }
+
kill(getppid(), SIGALRM);
igt_assert(gem_bo_busy(dpy->drm_fd, fb->gem_handle));
- igt_assert_f(poll(&pfd, 1, TIMEOUT) == 0,
+ igt_assert_f(poll(&pfd, 1, modeset ? 5000 : TIMEOUT) == 0,
"flip completed whilst %s was busy [%d]\n",
name, gem_bo_busy(dpy->drm_fd, fb->gem_handle));
}
igt_assert_f(nanosleep(&tv, NULL) == -1,
"flip to %s blocked waiting for busy fb", name);
- finish_fb_busy(t, 2*TIMEOUT);
igt_waitchildren();
+ finish_fb_busy(t, modeset ? 5000 : 2 * TIMEOUT);
igt_assert(read(dpy->drm_fd, &ev, sizeof(ev)) == sizeof(ev));
igt_assert(poll(&pfd, 1, 0) == 0);
+ if (modeset) {
+ dpy->pipes[pipe].mode_blob = 0;
+ igt_output_set_pipe(output, pipe);
+ igt_display_commit2(dpy, COMMIT_ATOMIC);
+ }
+
igt_spin_batch_free(dpy->drm_fd, t);
}
-static void test_flip(igt_display_t *dpy, unsigned ring, int pipe)
+static void test_flip(igt_display_t *dpy, unsigned ring, int pipe, bool modeset)
{
struct igt_fb fb[2];
int warmup[] = { 0, 1, 0, -1 };
+ igt_output_t *output;
+
+ if (modeset)
+ igt_require(dpy->is_atomic);
signal(SIGALRM, sighandler);
- igt_require(set_fb_on_crtc(dpy, pipe, &fb[0]));
+ igt_require((output = set_fb_on_crtc(dpy, pipe, &fb[0])));
igt_display_commit2(dpy, COMMIT_LEGACY);
igt_create_pattern_fb(dpy->drm_fd,
@@ -149,10 +171,10 @@ static void test_flip(igt_display_t *dpy, unsigned ring, int pipe)
}
/* Make the frontbuffer busy and try to flip to itself */
- flip_to_fb(dpy, pipe, &fb[0], ring, "fb[0]");
+ flip_to_fb(dpy, pipe, output, &fb[0], ring, "fb[0]", modeset);
/* Repeat for flip to second buffer */
- flip_to_fb(dpy, pipe, &fb[1], ring, "fb[1]");
+ flip_to_fb(dpy, pipe, output, &fb[1], ring, "fb[1]", modeset);
do_cleanup_display(dpy);
igt_remove_fb(dpy->drm_fd, &fb[1]);
@@ -161,6 +183,88 @@ static void test_flip(igt_display_t *dpy, unsigned ring, int pipe)
signal(SIGALRM, SIG_DFL);
}
+static void test_atomic_commit_hang(igt_display_t *dpy, igt_plane_t *primary,
+ struct igt_fb *busy_fb, unsigned ring,
+ bool completes_early)
+{
+ igt_spin_t *t = igt_spin_batch_new(dpy->drm_fd, ring, busy_fb->gem_handle);
+ struct pollfd pfd = { .fd = dpy->drm_fd, .events = POLLIN };
+ unsigned flags = 0;
+ struct drm_event_vblank ev;
+
+ flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
+ flags |= DRM_MODE_ATOMIC_NONBLOCK;
+ flags |= DRM_MODE_PAGE_FLIP_EVENT;
+
+ igt_display_commit_atomic(dpy, flags, NULL);
+
+ igt_fork(child, 1) {
+ /*
+ * bit of a hack, just set atomic commit to NULL fb to make sure
+ * that we don't wait for the new update to complete.
+ */
+ igt_plane_set_fb(primary, NULL);
+ igt_display_commit_atomic(dpy, 0, NULL);
+
+ if (completes_early)
+ igt_assert(gem_bo_busy(dpy->drm_fd, busy_fb->gem_handle));
+ else
+ igt_fail_on(gem_bo_busy(dpy->drm_fd, busy_fb->gem_handle));
+
+ igt_assert_f(poll(&pfd, 1, 1) > 0,
+ "nonblocking update completed whilst fb[%d] was still busy [%d]\n",
+ busy_fb->fb_id, gem_bo_busy(dpy->drm_fd, busy_fb->gem_handle));
+ }
+
+ igt_waitchildren();
+
+ igt_assert(read(dpy->drm_fd, &ev, sizeof(ev)) == sizeof(ev));
+
+ igt_spin_batch_end(t);
+}
+
+static void test_hang(igt_display_t *dpy, unsigned ring,
+ enum pipe pipe, bool modeset, bool hang_newfb)
+{
+ struct igt_fb fb[2];
+ igt_output_t *output;
+ igt_plane_t *primary;
+
+ igt_require((output = set_fb_on_crtc(dpy, pipe, &fb[0])));
+ igt_display_commit2(dpy, COMMIT_ATOMIC);
+ primary = igt_output_get_plane(output, IGT_PLANE_PRIMARY);
+
+ igt_create_pattern_fb(dpy->drm_fd,
+ fb[0].width, fb[0].height,
+ DRM_FORMAT_XRGB8888,
+ LOCAL_I915_FORMAT_MOD_X_TILED,
+ &fb[1]);
+
+ if (modeset) {
+ /* Test modeset disable with hang */
+ igt_output_set_pipe(output, PIPE_NONE);
+ igt_plane_set_fb(primary, &fb[1]);
+ test_atomic_commit_hang(dpy, primary, &fb[hang_newfb], ring, hang_newfb);
+
+ /* Test modeset enable with hang */
+ igt_plane_set_fb(primary, &fb[0]);
+ igt_output_set_pipe(output, pipe);
+ test_atomic_commit_hang(dpy, primary, &fb[!hang_newfb], ring, hang_newfb);
+ } else {
+ /*
+ * Test what happens with a single hanging pageflip.
+ * This always completes early, because we have some
+ * timeouts taking care of it.
+ */
+ igt_plane_set_fb(primary, &fb[1]);
+ test_atomic_commit_hang(dpy, primary, &fb[hang_newfb], ring, true);
+ }
+
+ do_cleanup_display(dpy);
+ igt_remove_fb(dpy->drm_fd, &fb[1]);
+ igt_remove_fb(dpy->drm_fd, &fb[0]);
+}
+
igt_main
{
igt_display_t display = { .drm_fd = -1, .n_pipes = I915_MAX_PIPES };
@@ -194,7 +298,83 @@ igt_main
igt_require(gem_has_ring(display.drm_fd,
e->exec_id | e->flags));
- test_flip(&display, e->exec_id | e->flags, n);
+ test_flip(&display, e->exec_id | e->flags, n, false);
+ }
+ igt_subtest_f("%smodeset-%s-%s",
+ e->exec_id == 0 ? "basic-" : "",
+ e->name, kmstest_pipe_name(n)) {
+ igt_require(gem_has_ring(display.drm_fd,
+ e->exec_id | e->flags));
+
+ test_flip(&display, e->exec_id | e->flags, n, true);
+ }
+
+ igt_subtest_group {
+ igt_hang_t hang;
+
+ igt_fixture {
+ igt_require(display.is_atomic);
+
+ hang = igt_allow_hang(display.drm_fd, 0, 0);
+ }
+
+ igt_subtest_f("extended-pageflip-hang-oldfb-%s-%s",
+ e->name, kmstest_pipe_name(n)) {
+ igt_require(gem_has_ring(display.drm_fd,
+ e->exec_id | e->flags));
+
+ test_hang(&display, e->exec_id | e->flags, n, false, false);
+ }
+
+ igt_subtest_f("extended-pageflip-hang-newfb-%s-%s",
+ e->name, kmstest_pipe_name(n)) {
+ igt_require(gem_has_ring(display.drm_fd,
+ e->exec_id | e->flags));
+
+ test_hang(&display, e->exec_id | e->flags, n, false, true);
+ }
+
+ igt_subtest_f("extended-modeset-hang-oldfb-%s-%s",
+ e->name, kmstest_pipe_name(n)) {
+ igt_require(gem_has_ring(display.drm_fd,
+ e->exec_id | e->flags));
+
+ test_hang(&display, e->exec_id | e->flags, n, true, false);
+ }
+
+ igt_subtest_f("extended-modeset-hang-newfb-%s-%s",
+ e->name, kmstest_pipe_name(n)) {
+ igt_require(gem_has_ring(display.drm_fd,
+ e->exec_id | e->flags));
+
+ test_hang(&display, e->exec_id | e->flags, n, true, true);
+ }
+
+ igt_subtest_f("extended-modeset-hang-oldfb-with-reset-%s-%s",
+ e->name, kmstest_pipe_name(n)) {
+ igt_require(gem_has_ring(display.drm_fd,
+ e->exec_id | e->flags));
+ igt_set_module_param_int("force_reset_modeset_test", 1);
+
+ test_hang(&display, e->exec_id | e->flags, n, true, false);
+
+ igt_set_module_param_int("force_reset_modeset_test", 0);
+ }
+
+ igt_subtest_f("extended-modeset-hang-newfb-with-reset-%s-%s",
+ e->name, kmstest_pipe_name(n)) {
+ igt_require(gem_has_ring(display.drm_fd,
+ e->exec_id | e->flags));
+ igt_set_module_param_int("force_reset_modeset_test", 1);
+
+ test_hang(&display, e->exec_id | e->flags, n, true, true);
+
+ igt_set_module_param_int("force_reset_modeset_test", 0);
+ }
+
+ igt_fixture {
+ igt_disallow_hang(display.drm_fd, hang);
+ }
}
}
}