drm/i915/selftests: Check known register values within the context
authorChris Wilson <chris@chris-wilson.co.uk>
Mon, 14 Oct 2019 09:07:48 +0000 (10:07 +0100)
committerChris Wilson <chris@chris-wilson.co.uk>
Mon, 14 Oct 2019 10:10:18 +0000 (11:10 +0100)
Check the logical ring context by asserting that the registers hold
expected start during execution. (It's a bit chicken-and-egg for how
could we manage to execute our request if the registers were not being
updated. Still, it's nice to verify that the HW is working as expected.)

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191014090757.32111-6-chris@chris-wilson.co.uk
drivers/gpu/drm/i915/gt/selftest_lrc.c

index a691e429ca01225131ee0609a6d56fd671253d1e..0aa36b1b238921c5a89e301230284919a8136b37 100644 (file)
@@ -2599,10 +2599,136 @@ static int live_lrc_layout(void *arg)
        return err;
 }
 
+static int __live_lrc_state(struct i915_gem_context *fixme,
+                           struct intel_engine_cs *engine,
+                           struct i915_vma *scratch)
+{
+       struct intel_context *ce;
+       struct i915_request *rq;
+       enum {
+               RING_START_IDX = 0,
+               RING_TAIL_IDX,
+               MAX_IDX
+       };
+       u32 expected[MAX_IDX];
+       u32 *cs;
+       int err;
+       int n;
+
+       ce = intel_context_create(fixme, engine);
+       if (IS_ERR(ce))
+               return PTR_ERR(ce);
+
+       err = intel_context_pin(ce);
+       if (err)
+               goto err_put;
+
+       rq = i915_request_create(ce);
+       if (IS_ERR(rq)) {
+               err = PTR_ERR(rq);
+               goto err_unpin;
+       }
+
+       cs = intel_ring_begin(rq, 4 * MAX_IDX);
+       if (IS_ERR(cs)) {
+               err = PTR_ERR(cs);
+               i915_request_add(rq);
+               goto err_unpin;
+       }
+
+       *cs++ = MI_STORE_REGISTER_MEM_GEN8 | MI_USE_GGTT;
+       *cs++ = i915_mmio_reg_offset(RING_START(engine->mmio_base));
+       *cs++ = i915_ggtt_offset(scratch) + RING_START_IDX * sizeof(u32);
+       *cs++ = 0;
+
+       expected[RING_START_IDX] = i915_ggtt_offset(ce->ring->vma);
+
+       *cs++ = MI_STORE_REGISTER_MEM_GEN8 | MI_USE_GGTT;
+       *cs++ = i915_mmio_reg_offset(RING_TAIL(engine->mmio_base));
+       *cs++ = i915_ggtt_offset(scratch) + RING_TAIL_IDX * sizeof(u32);
+       *cs++ = 0;
+
+       i915_request_get(rq);
+       i915_request_add(rq);
+
+       intel_engine_flush_submission(engine);
+       expected[RING_TAIL_IDX] = ce->ring->tail;
+
+       if (i915_request_wait(rq, 0, HZ / 5) < 0) {
+               err = -ETIME;
+               goto err_rq;
+       }
+
+       cs = i915_gem_object_pin_map(scratch->obj, I915_MAP_WB);
+       if (IS_ERR(cs)) {
+               err = PTR_ERR(cs);
+               goto err_rq;
+       }
+
+       for (n = 0; n < MAX_IDX; n++) {
+               if (cs[n] != expected[n]) {
+                       pr_err("%s: Stored register[%d] value[0x%x] did not match expected[0x%x]\n",
+                              engine->name, n, cs[n], expected[n]);
+                       err = -EINVAL;
+                       break;
+               }
+       }
+
+       i915_gem_object_unpin_map(scratch->obj);
+
+err_rq:
+       i915_request_put(rq);
+err_unpin:
+       intel_context_unpin(ce);
+err_put:
+       intel_context_put(ce);
+       return err;
+}
+
+static int live_lrc_state(void *arg)
+{
+       struct intel_gt *gt = arg;
+       struct intel_engine_cs *engine;
+       struct i915_gem_context *fixme;
+       struct i915_vma *scratch;
+       enum intel_engine_id id;
+       int err = 0;
+
+       /*
+        * Check the live register state matches what we expect for this
+        * intel_context.
+        */
+
+       fixme = kernel_context(gt->i915);
+       if (!fixme)
+               return -ENOMEM;
+
+       scratch = create_scratch(gt);
+       if (IS_ERR(scratch)) {
+               err = PTR_ERR(scratch);
+               goto out_close;
+       }
+
+       for_each_engine(engine, gt->i915, id) {
+               err = __live_lrc_state(fixme, engine, scratch);
+               if (err)
+                       break;
+       }
+
+       if (igt_flush_test(gt->i915))
+               err = -EIO;
+
+       i915_vma_unpin_and_release(&scratch, 0);
+out_close:
+       kernel_context_close(fixme);
+       return err;
+}
+
 int intel_lrc_live_selftests(struct drm_i915_private *i915)
 {
        static const struct i915_subtest tests[] = {
                SUBTEST(live_lrc_layout),
+               SUBTEST(live_lrc_state),
        };
 
        if (!HAS_LOGICAL_RING_CONTEXTS(i915))