Use a spinner to create a fence, and then use that as to synchronise
another batch to cancel the spinner.

Signed-off-by: Chris Wilson <ch...@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursu...@intel.com>
---
 tests/i915/gem_exec_schedule.c | 121 +++++++++++++++++++++++++++++++--
 1 file changed, 116 insertions(+), 5 deletions(-)

diff --git a/tests/i915/gem_exec_schedule.c b/tests/i915/gem_exec_schedule.c
index 62e387cc1..0a7deb5a1 100644
--- a/tests/i915/gem_exec_schedule.c
+++ b/tests/i915/gem_exec_schedule.c
@@ -65,6 +65,11 @@
 
 IGT_TEST_DESCRIPTION("Check that we can control the order of execution");
 
+static unsigned int offset_in_page(void *addr)
+{
+       return (uintptr_t)addr & 4095;
+}
+
 static inline
 uint32_t __sync_read_u32(int fd, uint32_t handle, uint64_t offset)
 {
@@ -670,6 +675,110 @@ static void lateslice(int i915, unsigned int engine)
        igt_spin_free(i915, spin[1]);
 }
 
+static void cancel_spinner(int i915,
+                          uint32_t ctx, unsigned int engine,
+                          igt_spin_t *spin)
+{
+       struct drm_i915_gem_exec_object2 obj = {
+               .handle = gem_create(i915, 4096),
+       };
+       struct drm_i915_gem_execbuffer2 execbuf = {
+               .buffers_ptr = to_user_pointer(&obj),
+               .buffer_count = 1,
+               .flags = engine | I915_EXEC_FENCE_SUBMIT,
+               .rsvd1 = ctx, /* same vm */
+               .rsvd2 = spin->out_fence,
+       };
+       uint32_t *map, *cs;
+
+       map = gem_mmap__device_coherent(i915, obj.handle, 0, 4096, PROT_WRITE);
+       cs = map;
+
+       *cs++ = MI_STORE_DWORD_IMM;
+       *cs++ = spin->obj[IGT_SPIN_BATCH].offset +
+               offset_in_page(spin->condition);
+       *cs++ = spin->obj[IGT_SPIN_BATCH].offset >> 32;
+       *cs++ = MI_BATCH_BUFFER_END;
+
+       *cs++ = MI_BATCH_BUFFER_END;
+       munmap(map, 4096);
+
+       gem_execbuf(i915, &execbuf);
+       gem_close(i915, obj.handle);
+}
+
+static void submit_slice(int i915,
+                        const struct intel_execution_engine2 *e,
+                        unsigned int flags)
+#define EARLY_SUBMIT 0x1
+#define LATE_SUBMIT 0x2
+{
+       I915_DEFINE_CONTEXT_PARAM_ENGINES(engines , 1) = {};
+       const struct intel_execution_engine2 *cancel;
+       struct drm_i915_gem_context_param param = {
+               .ctx_id = gem_context_create(i915),
+               .param = I915_CONTEXT_PARAM_ENGINES,
+               .value = to_user_pointer(&engines),
+               .size = sizeof(engines),
+       };
+
+       /*
+        * When using a submit fence, we do not want to block concurrent work,
+        * especially when that work is coperating with the spinner.
+        */
+
+       igt_require(gem_scheduler_has_semaphores(i915));
+       igt_require(gem_scheduler_has_preemption(i915));
+       igt_require(intel_gen(intel_get_drm_devid(i915)) >= 8);
+
+       __for_each_physical_engine(i915, cancel) {
+               igt_spin_t *bg, *spin;
+               int timeline = -1;
+               int fence = -1;
+
+               if (!gem_class_can_store_dword(i915, cancel->class))
+                       continue;
+
+               igt_debug("Testing cancellation from %s\n", e->name);
+
+               bg = igt_spin_new(i915, .engine = e->flags);
+
+               if (flags & LATE_SUBMIT) {
+                       timeline = sw_sync_timeline_create();
+                       fence = sw_sync_timeline_create_fence(timeline, 1);
+               }
+
+               engines.engines[0].engine_class = e->class;
+               engines.engines[0].engine_instance = e->instance;
+               gem_context_set_param(i915, &param);
+               spin = igt_spin_new(i915, .ctx = param.ctx_id,
+                                   .fence = fence,
+                                   .flags =
+                                   IGT_SPIN_POLL_RUN |
+                                   (flags & LATE_SUBMIT ? IGT_SPIN_FENCE_IN : 
0) |
+                                   IGT_SPIN_FENCE_OUT);
+               if (fence != -1)
+                       close(fence);
+
+               if (flags & EARLY_SUBMIT)
+                       igt_spin_busywait_until_started(spin);
+
+               engines.engines[0].engine_class = cancel->class;
+               engines.engines[0].engine_instance = cancel->instance;
+               gem_context_set_param(i915, &param);
+               cancel_spinner(i915, param.ctx_id, 0, spin);
+
+               if (timeline != -1)
+                       close(timeline);
+
+               gem_sync(i915, spin->handle);
+               igt_spin_free(i915, spin);
+               igt_spin_free(i915, bg);
+       }
+
+       gem_context_destroy(i915, param.ctx_id);
+}
+
 static uint32_t __batch_create(int i915, uint32_t offset)
 {
        const uint32_t bbe = MI_BATCH_BUFFER_END;
@@ -812,11 +921,6 @@ static void semaphore_codependency(int i915)
        }
 }
 
-static unsigned int offset_in_page(void *addr)
-{
-       return (uintptr_t)addr & 4095;
-}
-
 static void semaphore_resolve(int i915)
 {
        const struct intel_execution_engine2 *e;
@@ -2454,6 +2558,13 @@ igt_main
                test_each_engine("lateslice", fd, e)
                        lateslice(fd, e->flags);
 
+               test_each_engine("submit-early-slice", fd, e)
+                       submit_slice(fd, e, EARLY_SUBMIT);
+               test_each_engine("submit-golden-slice", fd, e)
+                       submit_slice(fd, e, 0);
+               test_each_engine("submit-late-slice", fd, e)
+                       submit_slice(fd, e, LATE_SUBMIT);
+
                igt_subtest("semaphore-user")
                        semaphore_userlock(fd);
                igt_subtest("semaphore-codependency")
-- 
2.27.0.rc0

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

Reply via email to