Signed-off-by: Chris Wilson <ch...@chris-wilson.co.uk>
---
 include/drm-uapi/i915_drm.h |  37 +++
 lib/igt_dummyload.c         |   2 +
 lib/igt_dummyload.h         |   5 +-
 tests/Makefile.sources      |   3 +
 tests/i915/gem_vm_wait.c    | 523 ++++++++++++++++++++++++++++++++++++
 tests/meson.build           |   1 +
 6 files changed, 569 insertions(+), 2 deletions(-)
 create mode 100644 tests/i915/gem_vm_wait.c

diff --git a/include/drm-uapi/i915_drm.h b/include/drm-uapi/i915_drm.h
index b94e991be..62e5ccd2c 100644
--- a/include/drm-uapi/i915_drm.h
+++ b/include/drm-uapi/i915_drm.h
@@ -359,6 +359,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_I915_QUERY                 0x39
 #define DRM_I915_GEM_VM_CREATE         0x3a
 #define DRM_I915_GEM_VM_DESTROY                0x3b
+#define DRM_I915_GEM_VM_WAIT           0x3c
 /* Must be kept compact -- no holes */
 
 #define DRM_IOCTL_I915_INIT            DRM_IOW( DRM_COMMAND_BASE + 
DRM_I915_INIT, drm_i915_init_t)
@@ -422,6 +423,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_QUERY                   DRM_IOWR(DRM_COMMAND_BASE + 
DRM_I915_QUERY, struct drm_i915_query)
 #define DRM_IOCTL_I915_GEM_VM_CREATE   DRM_IOWR(DRM_COMMAND_BASE + 
DRM_I915_GEM_VM_CREATE, struct drm_i915_gem_vm_control)
 #define DRM_IOCTL_I915_GEM_VM_DESTROY  DRM_IOW (DRM_COMMAND_BASE + 
DRM_I915_GEM_VM_DESTROY, struct drm_i915_gem_vm_control)
+#define DRM_IOCTL_I915_GEM_VM_WAIT     DRM_IOWR(DRM_COMMAND_BASE + 
DRM_I915_GEM_VM_WAIT, struct drm_i915_gem_vm_wait)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
@@ -1824,6 +1826,41 @@ struct drm_i915_gem_vm_control {
        __u32 vm_id;
 };
 
+/*
+ * (*IOVA & MASK) OP (VALUE & MASK)
+ *
+ * OP:
+ * - EQ, NEQ
+ * - GT, GTE
+ * - LT, LTE
+ * - BEFORE, AFTER
+ *
+ */
+struct drm_i915_gem_vm_wait {
+       __u64 extensions;
+       __u64 iova;
+       __u32 vm_id;
+       __u16 op;
+#define I915_VM_WAIT_EQ                0
+#define I915_VM_WAIT_NEQ       1
+#define I915_VM_WAIT_GT                2
+#define I915_VM_WAIT_GTE       3
+#define I915_VM_WAIT_LT                4
+#define I915_VM_WAIT_LTE       5
+#define I915_VM_WAIT_BEFORE    6
+#define I915_VM_WAIT_AFTER     7
+#define I915_VM_WAIT_PASSED    8
+       __u16 flags;
+#define I915_VM_WAIT_ABSTIME 0x1
+       __u64 value;
+       __u64 mask;
+#define I915_VM_WAIT_U8                0xffu
+#define I915_VM_WAIT_U16       0xffffu
+#define I915_VM_WAIT_U32       0xfffffffful
+#define I915_VM_WAIT_U64       0xffffffffffffffffull
+       __u64 timeout;
+};
+
 struct drm_i915_reg_read {
        /*
         * Register offset.
diff --git a/lib/igt_dummyload.c b/lib/igt_dummyload.c
index b7f4caca3..7bc37889b 100644
--- a/lib/igt_dummyload.c
+++ b/lib/igt_dummyload.c
@@ -176,6 +176,8 @@ emit_recursive_batch(igt_spin_t *spin,
                }
 
                *cs++ = 1;
+               if (opts->flags & IGT_SPIN_WAKE_RUN)
+                       *cs++ = 0x2 << 23;
 
                execbuf->buffer_count++;
        }
diff --git a/lib/igt_dummyload.h b/lib/igt_dummyload.h
index 421ca183b..8264834ce 100644
--- a/lib/igt_dummyload.h
+++ b/lib/igt_dummyload.h
@@ -60,8 +60,9 @@ struct igt_spin_factory {
 #define IGT_SPIN_FENCE_IN      (1 << 0)
 #define IGT_SPIN_FENCE_OUT     (1 << 1)
 #define IGT_SPIN_POLL_RUN      (1 << 2)
-#define IGT_SPIN_FAST          (1 << 3)
-#define IGT_SPIN_NO_PREEMPTION (1 << 4)
+#define IGT_SPIN_WAKE_RUN      (1 << 3)
+#define IGT_SPIN_FAST          (1 << 4)
+#define IGT_SPIN_NO_PREEMPTION (1 << 5)
 
 igt_spin_t *
 __igt_spin_factory(int fd, const struct igt_spin_factory *opts);
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 806eb02d0..08c664776 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -472,6 +472,9 @@ gem_userptr_blits_SOURCES = i915/gem_userptr_blits.c
 TESTS_progs += gem_wait
 gem_wait_SOURCES = i915/gem_wait.c
 
+TESTS_progs += gem_vm_wait
+gem_vm_wait_SOURCES = i915/gem_vm_wait.c
+
 TESTS_progs += gem_workarounds
 gem_workarounds_SOURCES = i915/gem_workarounds.c
 
diff --git a/tests/i915/gem_vm_wait.c b/tests/i915/gem_vm_wait.c
new file mode 100644
index 000000000..63107bdd1
--- /dev/null
+++ b/tests/i915/gem_vm_wait.c
@@ -0,0 +1,523 @@
+/*
+ * Copyright © 2020 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "igt.h"
+#include "i915/gem_vm.h"
+
+static int __gem_vm_wait(int i915, struct drm_i915_gem_vm_wait *w)
+{
+       int err;
+
+       err = 0;
+       if (igt_ioctl(i915, DRM_IOCTL_I915_GEM_VM_WAIT, w)) {
+               err = -errno;
+               igt_assume(err);
+       }
+
+       return err;
+}
+
+static uint32_t get_vm(int i915, uint32_t ctx)
+{
+       struct drm_i915_gem_context_param arg = {
+               .ctx_id = ctx,
+               .param = I915_CONTEXT_PARAM_VM,
+       };
+
+       gem_context_get_param(i915, &arg);
+       return arg.value;
+}
+
+static uint32_t __batch_create(int i915, uint32_t offset)
+{
+       const uint32_t bbe = MI_BATCH_BUFFER_END;
+       uint32_t handle;
+
+       handle = gem_create(i915, offset + 4);
+       gem_write(i915, handle, offset, &bbe, sizeof(bbe));
+
+       return handle;
+}
+
+static uint32_t batch_create(int i915)
+{
+       return __batch_create(i915, 0);
+}
+
+static struct drm_i915_gem_exec_object2
+vm_bind(int i915, uint32_t ctx, uint32_t handle, uint64_t offset)
+{
+       struct drm_i915_gem_exec_object2 obj[2] = {
+               {
+                       .handle = handle,
+                       .offset = offset,
+                       .flags = EXEC_OBJECT_PINNED,
+               },
+               { .handle = batch_create(i915), }
+       };
+       struct drm_i915_gem_execbuffer2 eb = {
+               .buffers_ptr = to_user_pointer(obj),
+               .buffer_count = 2,
+               .rsvd1 = ctx,
+       };
+
+       gem_execbuf(i915, &eb);
+       gem_close(i915, obj[1].handle);
+
+       igt_assert_eq_u64(obj[0].offset, offset);
+       return obj[0];
+}
+
+static void invalid_mask(int i915)
+{
+       struct drm_i915_gem_vm_wait wait;
+       uint32_t handle = gem_create(i915, 4096);
+
+       vm_bind(i915, 0, handle, 0);
+
+       memset(&wait, 0, sizeof(wait));
+       wait.vm_id = get_vm(i915, 0);
+       wait.op = I915_VM_WAIT_EQ;
+       wait.mask = I915_VM_WAIT_U32;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), 0);
+
+       /* Having proved we have an otherwise valid arg.. */
+       wait.mask = 0;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), -EINVAL);
+
+       gem_vm_destroy(i915, wait.vm_id);
+       gem_close(i915, handle);
+}
+
+static void invalid_flags(int i915)
+{
+       struct drm_i915_gem_vm_wait wait;
+       uint32_t handle = gem_create(i915, 4096);
+
+       vm_bind(i915, 0, handle, 0);
+
+       memset(&wait, 0, sizeof(wait));
+       wait.vm_id = get_vm(i915, 0);
+       wait.op = I915_VM_WAIT_EQ;
+       wait.mask = I915_VM_WAIT_U32;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), 0);
+
+       /* Having proved we have an otherwise valid arg.. */
+       wait.flags = 0xffff;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), -EINVAL);
+
+       gem_vm_destroy(i915, wait.vm_id);
+       gem_close(i915, handle);
+}
+
+static void invalid_iova(int i915)
+{
+       struct drm_i915_gem_vm_wait wait;
+       uint32_t handle = gem_create(i915, 4096);
+
+       vm_bind(i915, 0, handle, 0);
+
+       memset(&wait, 0, sizeof(wait));
+       wait.vm_id = get_vm(i915, 0);
+       wait.op = I915_VM_WAIT_EQ;
+       wait.mask = I915_VM_WAIT_U32;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), 0);
+
+       /* Natural alignments */
+       wait.mask = I915_VM_WAIT_U8;
+       wait.iova = 0x1;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), 0);
+
+       wait.mask = I915_VM_WAIT_U16;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), -EINVAL);
+       wait.iova = 0x2;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), 0);
+
+       wait.mask = I915_VM_WAIT_U32;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), -EINVAL);
+       wait.iova = 0x4;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), 0);
+
+       wait.mask = I915_VM_WAIT_U64;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), -EINVAL);
+
+       gem_vm_destroy(i915, wait.vm_id);
+       gem_close(i915, handle);
+}
+
+static const char *op_repr(int op)
+{
+       switch (op) {
+#define CASE(x) case I915_VM_WAIT_##x: return #x
+               CASE(EQ);
+               CASE(NEQ);
+               CASE(GT);
+               CASE(GTE);
+               CASE(LT);
+               CASE(LTE);
+               CASE(BEFORE);
+               CASE(AFTER);
+               CASE(PASSED);
+       default: return "unknown";
+       }
+}
+
+static void basic(int i915)
+{
+       static const struct {
+               unsigned int op;
+               uint32_t a, b;
+               int result;
+#define GOOD 0
+#define BAD -ETIME
+       } ops[] = {
+               { I915_VM_WAIT_EQ, 0, 0, GOOD },
+               { I915_VM_WAIT_EQ, 0, 1, BAD },
+               { I915_VM_WAIT_EQ, 1, 0, BAD },
+               { I915_VM_WAIT_EQ, 1, 1, GOOD },
+               { I915_VM_WAIT_EQ, 0, -1, BAD },
+               { I915_VM_WAIT_EQ, -1, 0, BAD },
+               { I915_VM_WAIT_EQ, -1, -1, GOOD },
+
+               { I915_VM_WAIT_NEQ, 0, 0, BAD },
+               { I915_VM_WAIT_NEQ, 0, 1, GOOD },
+               { I915_VM_WAIT_NEQ, 1, 0, GOOD },
+               { I915_VM_WAIT_NEQ, 1, 1, BAD },
+               { I915_VM_WAIT_NEQ, 0, -1, GOOD },
+               { I915_VM_WAIT_NEQ, -1, 0, GOOD },
+               { I915_VM_WAIT_NEQ, -1, -1, BAD },
+
+               { I915_VM_WAIT_GT, 0, 0, BAD },
+               { I915_VM_WAIT_GT, 1, 0, GOOD },
+               { I915_VM_WAIT_GT, 1, 1, BAD },
+               { I915_VM_WAIT_GT, 0, 1, BAD },
+               { I915_VM_WAIT_GT, -1, 0, GOOD },
+               { I915_VM_WAIT_GT, 0, -1, BAD },
+
+               { I915_VM_WAIT_GTE, 0, 0, GOOD },
+               { I915_VM_WAIT_GTE, 1, 0, GOOD },
+               { I915_VM_WAIT_GTE, 1, 1, GOOD },
+               { I915_VM_WAIT_GTE, 0, 1, BAD },
+               { I915_VM_WAIT_GTE, -1, 0, GOOD },
+               { I915_VM_WAIT_GTE, 0, -1, BAD },
+
+               { I915_VM_WAIT_LT, 0, 0, BAD },
+               { I915_VM_WAIT_LT, 1, 0, BAD },
+               { I915_VM_WAIT_LT, 1, 1, BAD },
+               { I915_VM_WAIT_LT, 0, 1, GOOD },
+               { I915_VM_WAIT_LT, -1, 0, BAD },
+               { I915_VM_WAIT_LT, 0, -1, GOOD },
+
+               { I915_VM_WAIT_LTE, 0, 0, GOOD },
+               { I915_VM_WAIT_LTE, 1, 0, BAD },
+               { I915_VM_WAIT_LTE, 1, 1, GOOD },
+               { I915_VM_WAIT_LTE, 0, 1, GOOD },
+               { I915_VM_WAIT_LTE, -1, 0, BAD },
+               { I915_VM_WAIT_LTE, 0, -1, GOOD },
+
+               { I915_VM_WAIT_BEFORE, 0, 0, BAD },
+               { I915_VM_WAIT_BEFORE, 1, 0, BAD },
+               { I915_VM_WAIT_BEFORE, 1, 1, BAD },
+               { I915_VM_WAIT_BEFORE, 0, 1, GOOD },
+               { I915_VM_WAIT_BEFORE, -1, 0, GOOD },
+               { I915_VM_WAIT_BEFORE, 0, -1, BAD },
+
+               { I915_VM_WAIT_AFTER, 0, 0, BAD },
+               { I915_VM_WAIT_AFTER, 1, 0, GOOD },
+               { I915_VM_WAIT_AFTER, 1, 1, BAD },
+               { I915_VM_WAIT_AFTER, 0, 1, BAD },
+               { I915_VM_WAIT_AFTER, -1, 0, BAD },
+               { I915_VM_WAIT_AFTER, 0, -1, GOOD },
+
+               { I915_VM_WAIT_PASSED, 0, 0, GOOD },
+               { I915_VM_WAIT_PASSED, 1, 0, GOOD },
+               { I915_VM_WAIT_PASSED, 1, 1, GOOD },
+               { I915_VM_WAIT_PASSED, 0, 1, BAD },
+               { I915_VM_WAIT_PASSED, -1, 0, BAD },
+               { I915_VM_WAIT_PASSED, 0, -1, GOOD },
+               { I915_VM_WAIT_PASSED, -1, -1, GOOD },
+       };
+       struct drm_i915_gem_vm_wait wait;
+       uint32_t handle = gem_create(i915, 4096);
+       uint32_t *x = gem_mmap__wc(i915, handle, 0, 4096, PROT_WRITE);
+
+       vm_bind(i915, 0, handle, 0);
+
+       memset(&wait, 0, sizeof(wait));
+       wait.vm_id = get_vm(i915, 0);
+       wait.op = I915_VM_WAIT_EQ;
+       wait.mask = I915_VM_WAIT_U32;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), 0);
+       wait.op = I915_VM_WAIT_NEQ;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), -ETIME);
+
+       for (int i = 0; i < ARRAY_SIZE(ops); i++) {
+               *x = ops[i].a;
+               wait.value = ops[i].b;
+               wait.op = ops[i].op;
+               igt_assert_f(__gem_vm_wait(i915, &wait) == ops[i].result,
+                            "*iova: %08x wait: { op:%s, value:%08x, }, result: 
%d, expected: %d\n",
+                            ops[i].a, op_repr(ops[i].op), ops[i].b,
+                            __gem_vm_wait(i915, &wait),
+                            ops[i].result);
+       }
+
+       gem_vm_destroy(i915, wait.vm_id);
+       munmap(x, 4096);
+       gem_close(i915, handle);
+}
+
+static void store_dword(int i915,
+                       const struct intel_execution_engine2 *e,
+                       const struct drm_i915_gem_exec_object2 *target,
+                       int offset, uint32_t value)
+{
+       const int gen = intel_gen(intel_get_drm_devid(i915));
+       struct drm_i915_gem_exec_object2 obj[2];
+       struct drm_i915_gem_execbuffer2 execbuf;
+       uint32_t batch[16];
+       int i;
+
+       memset(&execbuf, 0, sizeof(execbuf));
+       execbuf.buffers_ptr = to_user_pointer(obj);
+       execbuf.buffer_count = 2;
+       execbuf.flags = e->flags;
+       if (gen > 3 && gen < 6)
+               execbuf.flags |= I915_EXEC_SECURE;
+
+       memset(obj, 0, sizeof(obj));
+       memcpy(obj, target, sizeof(*target));
+       obj[1].handle = gem_create(i915, 4096);
+
+       i = 0;
+       batch[i] = MI_STORE_DWORD_IMM | (gen < 6 ? 1 << 22 : 0);
+       if (gen >= 8) {
+               batch[++i] = target->offset + offset;
+               batch[++i] = (target->offset + offset) >> 32;
+       } else if (gen >= 4) {
+               batch[++i] = 0;
+               batch[++i] = target->offset + offset;
+       } else {
+               batch[i]--;
+               batch[++i] = target->offset + offset;
+       }
+       batch[++i] = value;
+       batch[++i] = MI_BATCH_BUFFER_END;
+       gem_write(i915, obj[1].handle, 0, batch, sizeof(batch));
+
+       gem_execbuf(i915, &execbuf);
+       gem_close(i915, obj[1].handle);
+}
+
+static void signal(int i915, const struct intel_execution_engine2 *e)
+{
+       struct drm_i915_gem_vm_wait wait;
+       struct drm_i915_gem_exec_object2 obj =
+               vm_bind(i915, 0, gem_create(i915, 4096), 0);
+
+       memset(&wait, 0, sizeof(wait));
+       wait.vm_id = get_vm(i915, 0);
+       wait.iova = obj.offset;
+       wait.op = I915_VM_WAIT_EQ;
+       wait.mask = I915_VM_WAIT_U32;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), 0);
+
+       wait.op = I915_VM_WAIT_NEQ;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), -ETIME);
+
+       store_dword(i915, e, &obj, 0, 1);
+       gem_sync(i915, obj.handle);
+
+       wait.op = I915_VM_WAIT_NEQ;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), 0);
+
+       wait.op = I915_VM_WAIT_EQ;
+       wait.value = 1;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), 0);
+
+       wait.op = I915_VM_WAIT_NEQ;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), -ETIME);
+
+       igt_fork(child, 1) {
+               usleep(50000);
+               store_dword(i915, e, &obj, 0, 2);
+       }
+
+       wait.timeout = NSEC_PER_SEC;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), 0);
+       igt_waitchildren();
+
+       gem_vm_destroy(i915, wait.vm_id);
+       gem_close(i915, obj.handle);
+}
+
+static void spin(int i915, const struct intel_execution_engine2 *e)
+{
+       struct drm_i915_gem_vm_wait wait;
+       igt_spin_t *spin;
+
+       spin = igt_spin_new(i915,
+                           .engine = e->flags,
+                           .flags = IGT_SPIN_POLL_RUN | IGT_SPIN_WAKE_RUN);
+       igt_spin_busywait_until_started(spin);
+
+       memset(&wait, 0, sizeof(wait));
+       wait.vm_id = get_vm(i915, 0);;
+       wait.iova = spin->obj[0].offset;
+       wait.op = I915_VM_WAIT_NEQ;
+       wait.mask = I915_VM_WAIT_U32;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), 0);
+
+       igt_spin_end(spin);
+       igt_spin_reset(spin);
+       igt_assert_eq(__gem_vm_wait(i915, &wait), -ETIME);
+
+       igt_fork(child, 1) {
+               usleep(50000);
+               gem_execbuf(i915, &spin->execbuf);
+       }
+
+       wait.timeout = NSEC_PER_SEC;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), 0);
+
+       igt_waitchildren();
+       igt_spin_free(i915, spin);
+
+       gem_vm_destroy(i915, wait.vm_id);
+}
+
+static void hang(int i915, const struct intel_execution_engine2 *e)
+{
+       struct drm_i915_gem_vm_wait wait;
+       igt_spin_t *spin;
+
+       spin = igt_spin_new(i915,
+                           .engine = e->flags,
+                           .flags = (IGT_SPIN_POLL_RUN |
+                                     IGT_SPIN_NO_PREEMPTION));
+       igt_spin_busywait_until_started(spin);
+
+       memset(&wait, 0, sizeof(wait));
+       wait.vm_id = get_vm(i915, 0);;
+       wait.iova = spin->obj[0].offset;
+       wait.op = I915_VM_WAIT_NEQ;
+       wait.mask = I915_VM_WAIT_U32;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), 0);
+
+       igt_spin_end(spin);
+       igt_spin_reset(spin);
+       igt_assert_eq(__gem_vm_wait(i915, &wait), -ETIME);
+
+       igt_fork(child, 1) {
+               usleep(50000);
+               gem_execbuf(i915, &spin->execbuf);
+       }
+
+       wait.timeout = -1;
+       igt_assert_eq(__gem_vm_wait(i915, &wait), 0);
+
+       igt_waitchildren();
+       igt_spin_free(i915, spin);
+
+       gem_vm_destroy(i915, wait.vm_id);
+}
+
+static bool has_vm_wait(int i915)
+{
+       struct drm_i915_gem_vm_wait wait = { .mask = -1ull };
+
+       return __gem_vm_wait(i915, &wait) == -ENOENT;
+}
+
+static bool has_vm(int i915)
+{
+       struct drm_i915_gem_context_param arg = {
+               .param = I915_CONTEXT_PARAM_VM,
+       };
+
+       if (__gem_context_get_param(i915, &arg))
+               return false;
+
+       gem_vm_destroy(i915, arg.value);
+       return true;
+}
+
+igt_main
+{
+       const struct intel_execution_engine2 *e;
+       int i915 = -1;
+
+       igt_fixture {
+               i915 = drm_open_driver_master(DRIVER_INTEL);
+               igt_require(has_vm(i915));
+               igt_require(has_vm_wait(i915));
+               igt_require_gem(i915);
+       }
+
+       igt_subtest("invalid-mask")
+               invalid_mask(i915);
+
+       igt_subtest("invalid-flags")
+               invalid_flags(i915);
+
+       igt_subtest("invalid-iova")
+               invalid_iova(i915);
+
+       igt_subtest("basic")
+               basic(i915);
+
+       igt_subtest_with_dynamic("signal") {
+               __for_each_physical_engine(i915, e) {
+                       igt_dynamic_f("%s", e->name)
+                               signal(i915, e);
+               }
+       }
+
+       igt_subtest_with_dynamic("spin") {
+               __for_each_physical_engine(i915, e) {
+                       igt_dynamic_f("%s", e->name)
+                               spin(i915, e);
+               }
+       }
+
+       igt_subtest_group {
+               igt_hang_t hh;
+
+               igt_fixture
+                       hh = igt_allow_hang(i915, 0, 0);
+
+               igt_subtest_with_dynamic("hang") {
+                       __for_each_physical_engine(i915, e) {
+                               igt_dynamic_f("%s", e->name)
+                                       hang(i915, e);
+                       }
+               }
+
+               igt_fixture
+                       igt_disallow_hang(i915, hh);
+       }
+
+       igt_fixture {
+               close(i915);
+       }
+}
diff --git a/tests/meson.build b/tests/meson.build
index a79d22ba1..154b7ad16 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -223,6 +223,7 @@ i915_progs = [
        'gem_unref_active_buffers',
        'gem_userptr_blits',
        'gem_vm_create',
+       'gem_vm_wait',
        'gem_wait',
        'gem_workarounds',
        'gem_write_read_ring_switch',
-- 
2.25.0

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

Reply via email to