kms_cursor_legacy: Add cursor update vs busy page flip test.
This is a test for the issue exposed by 97888, we perform a busy
bo update followed by a cursor update.
The page flip and cursor update should complete without hanging,
and the new fb should not be flipped yet as a result of the cursor
update.
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
diff --git a/tests/kms_cursor_legacy.c b/tests/kms_cursor_legacy.c
index 2e2602c..4a5556f 100644
--- a/tests/kms_cursor_legacy.c
+++ b/tests/kms_cursor_legacy.c
@@ -1040,11 +1040,87 @@
igt_skip("Nonblocking modeset is not supported by this kernel\n");
}
-static void flip_vs_cursor_crc(igt_display_t *display, bool atomic)
+static uint32_t *
+make_fb_busy(int fd, const struct igt_fb *fb)
+{
+ const int gen = intel_gen(intel_get_drm_devid(fd));
+ struct drm_i915_gem_exec_object2 obj[2];
+#define SCRATCH 0
+#define BATCH 1
+ struct drm_i915_gem_relocation_entry reloc[2];
+ struct drm_i915_gem_execbuffer2 execbuf;
+ uint32_t *batch;
+ int i;
+ unsigned ring;
+
+ for_each_engine(fd, ring)
+ break;
+
+ memset(&execbuf, 0, sizeof(execbuf));
+ execbuf.buffers_ptr = (uintptr_t)obj;
+ execbuf.buffer_count = 2;
+ execbuf.flags = ring;
+
+ memset(obj, 0, sizeof(obj));
+ obj[SCRATCH].handle = fb->gem_handle;
+
+ obj[BATCH].handle = gem_create(fd, 4096);
+ obj[BATCH].relocs_ptr = (uintptr_t)reloc;
+ obj[BATCH].relocation_count = 2;
+ memset(reloc, 0, sizeof(reloc));
+ reloc[0].target_handle = obj[BATCH].handle; /* recurse */
+ reloc[0].presumed_offset = 0;
+ reloc[0].offset = sizeof(uint32_t);
+ reloc[0].delta = 0;
+ reloc[0].read_domains = I915_GEM_DOMAIN_COMMAND;
+ reloc[0].write_domain = 0;
+
+ batch = gem_mmap__wc(fd, obj[BATCH].handle, 0, 4096, PROT_WRITE);
+ gem_set_domain(fd, obj[BATCH].handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+
+ batch[i = 0] = MI_BATCH_BUFFER_START;
+ if (gen >= 8) {
+ batch[i] |= 1 << 8 | 1;
+ batch[++i] = 0;
+ batch[++i] = 0;
+ } else if (gen >= 6) {
+ batch[i] |= 1 << 8;
+ batch[++i] = 0;
+ } else {
+ batch[i] |= 2 << 6;
+ batch[++i] = 0;
+ if (gen < 4) {
+ batch[i] |= 1;
+ reloc[0].delta = 1;
+ }
+ }
+
+ /* dummy write to fb */
+ reloc[1].target_handle = obj[SCRATCH].handle;
+ reloc[1].presumed_offset = 0;
+ reloc[1].offset = 1024;
+ reloc[1].delta = 0;
+ reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;
+ reloc[1].write_domain = I915_GEM_DOMAIN_RENDER;
+
+ gem_execbuf(fd, &execbuf);
+ gem_close(fd, obj[BATCH].handle);
+
+ return batch;
+}
+
+static void finish_fb_busy(uint32_t *batch)
+{
+ batch[0] = MI_BATCH_BUFFER_END;
+ __sync_synchronize();
+ munmap(batch, 4096);
+}
+
+static void flip_vs_cursor_crc(igt_display_t *display, bool atomic, bool busy_wait)
{
struct drm_mode_cursor arg[2];
struct drm_event_vblank vbl;
- struct igt_fb fb_info, cursor_fb;
+ struct igt_fb fb_info[2], cursor_fb;
unsigned vblank_start;
enum pipe pipe = find_connected_pipe(display, false);
igt_pipe_crc_t *pipe_crc;
@@ -1053,12 +1129,14 @@
if (atomic)
igt_require(display->is_atomic);
- igt_require(set_fb_on_crtc(display, pipe, &fb_info));
+ igt_require(set_fb_on_crtc(display, pipe, &fb_info[0]));
+ igt_create_color_pattern_fb(display->drm_fd, fb_info[0].width, fb_info[0].height,
+ DRM_FORMAT_XRGB8888, LOCAL_I915_FORMAT_MOD_X_TILED, .1, .1, .1, &fb_info[1]);
igt_create_color_fb(display->drm_fd, 64, 64, DRM_FORMAT_ARGB8888, 0, 1., 1., 1., &cursor_fb);
populate_cursor_args(display, pipe, arg, &cursor_fb);
- arg[0].flags = arg[1].flags = DRM_MODE_CURSOR_BO;
+ arg[0].flags = arg[1].flags |= DRM_MODE_CURSOR_BO;
arg[1].handle = 0;
arg[1].width = arg[1].height = 0;
@@ -1074,33 +1152,67 @@
do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg[0]);
- get_vblank(display->drm_fd, pipe, DRM_VBLANK_NEXTONMISS);
-
/* Collect reference crc with cursor enabled. */
igt_pipe_crc_collect_crc(pipe_crc, &crcs[0]);
+ if (busy_wait) {
+ /*
+ * Set fb 1 on primary at least once before flipping to force
+ * setting the correct cache level, else we get a stall in the
+ * page flip handler.
+ */
+ igt_plane_set_fb(&display->pipes[pipe].planes[IGT_PLANE_PRIMARY], &fb_info[1]);
+ igt_display_commit2(display, COMMIT_UNIVERSAL);
+
+ igt_plane_set_fb(&display->pipes[pipe].planes[IGT_PLANE_PRIMARY], &fb_info[0]);
+ igt_display_commit2(display, COMMIT_UNIVERSAL);
+ }
+
/* Disable cursor, and immediately queue a flip. Check if resulting crc is correct. */
for (int i = 1; i >= 0; i--) {
+ uint32_t *batch;
+
+ if (busy_wait) {
+ batch = make_fb_busy(display->drm_fd, &fb_info[1]);
+ igt_assert(gem_bo_busy(display->drm_fd, fb_info[1].gem_handle));
+ }
+
vblank_start = get_vblank(display->drm_fd, pipe, DRM_VBLANK_NEXTONMISS);
- flip_nonblocking(display, pipe, atomic, &fb_info);
+ flip_nonblocking(display, pipe, atomic, &fb_info[busy_wait]);
do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg[i]);
igt_assert_eq(get_vblank(display->drm_fd, pipe, 0), vblank_start);
- igt_set_timeout(1, "Stuck page flip");
- igt_ignore_warn(read(display->drm_fd, &vbl, sizeof(vbl)));
- igt_assert_eq(get_vblank(display->drm_fd, pipe, 0), vblank_start + 1);
- igt_reset_timeout();
+ if (busy_wait) {
+ igt_pipe_crc_collect_crc(pipe_crc, &crcs[2]);
- igt_debug("Checking for cursor %s\n", i ? "disabled" : "enabled");
- igt_pipe_crc_collect_crc(pipe_crc, &crcs[2]);
+ finish_fb_busy(batch);
+
+ igt_set_timeout(1, "Stuck page flip");
+ igt_ignore_warn(read(display->drm_fd, &vbl, sizeof(vbl)));
+ igt_reset_timeout();
+
+ igt_assert_lte(vblank_start + 1, get_vblank(display->drm_fd, pipe, 0));
+
+ igt_plane_set_fb(&display->pipes[pipe].planes[IGT_PLANE_PRIMARY], &fb_info[0]);
+ igt_display_commit2(display, COMMIT_UNIVERSAL);
+ } else {
+ igt_set_timeout(1, "Stuck page flip");
+ igt_ignore_warn(read(display->drm_fd, &vbl, sizeof(vbl)));
+ igt_reset_timeout();
+
+ igt_assert_eq(get_vblank(display->drm_fd, pipe, 0), vblank_start + 1);
+
+ igt_pipe_crc_collect_crc(pipe_crc, &crcs[2]);
+ }
igt_assert_crc_equal(&crcs[i], &crcs[2]);
}
do_cleanup_display(display);
- igt_remove_fb(display->drm_fd, &fb_info);
+ igt_remove_fb(display->drm_fd, &fb_info[1]);
+ igt_remove_fb(display->drm_fd, &fb_info[0]);
igt_remove_fb(display->drm_fd, &cursor_fb);
igt_pipe_crc_free(pipe_crc);
}
@@ -1187,10 +1299,16 @@
two_screens_cursor_vs_flip(&display, 150, true);
igt_subtest("flip-vs-cursor-crc-legacy")
- flip_vs_cursor_crc(&display, false);
+ flip_vs_cursor_crc(&display, false, false);
igt_subtest("flip-vs-cursor-crc-atomic")
- flip_vs_cursor_crc(&display, true);
+ flip_vs_cursor_crc(&display, true, false);
+
+ igt_subtest("flip-vs-cursor-busy-crc-legacy")
+ flip_vs_cursor_crc(&display, false, true);
+
+ igt_subtest("flip-vs-cursor-busy-crc-atomic")
+ flip_vs_cursor_crc(&display, true, true);
for (i = 0; i <= flip_test_last; i++) {
const char *modes[flip_test_last+1] = {