summaryrefslogtreecommitdiff
path: root/tests/kms_busy.c
diff options
context:
space:
mode:
authorMaarten Lankhorst <maarten.lankhorst@linux.intel.com>2017-01-26 11:35:50 +0100
committerMaarten Lankhorst <maarten.lankhorst@linux.intel.com>2017-01-26 11:58:24 +0100
commit24bfa3e89da0e3cbd7f752ac0bfe4c47d006ded7 (patch)
tree9422ffa1c85a59e337e4c65e8fcf7b79352aefc6 /tests/kms_busy.c
parent35afbb0e3bfda8fdb9bbb2b981af7c661ebdf440 (diff)
kms_busy: Add extended tests that force a hang.
The intel driver adds a timeout to each atomic update of 10s for the new fb. Make sure this works as intended, and also test what happens when hanging the old framebuffer, with and without modeset. The driver waits indefinitely on the old framebuffer, but another blocking update will wait at most 10 seconds for it. Abuse this fact in a testcase. For added bonus also add some tests that make sure this works on older gens that perform a display reset during gpu reset. Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Diffstat (limited to 'tests/kms_busy.c')
-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);
+ }
}
}
}