Exercise issuing a lite-restore (a continuation of the same active context with a new request) while the HW is blocked on a semaphore. We expect the HW to ACK immediately after the lite-restore from the next failed semaphore poll. Signed-off-by: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx> --- drivers/gpu/drm/i915/gt/selftest_lrc.c | 175 +++++++++++++++++++++++++ 1 file changed, 175 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/selftest_lrc.c b/drivers/gpu/drm/i915/gt/selftest_lrc.c index 6f06ba750a0a..44c694ddbddc 100644 --- a/drivers/gpu/drm/i915/gt/selftest_lrc.c +++ b/drivers/gpu/drm/i915/gt/selftest_lrc.c @@ -350,6 +350,180 @@ static int live_unlite_preempt(void *arg) return live_unlite_restore(arg, I915_USER_PRIORITY(I915_PRIORITY_MAX)); } +static struct i915_request * +create_lite_semaphore(struct intel_context *ce, void *slot) +{ + const u32 offset = + i915_ggtt_offset(ce->engine->status_page.vma) + + offset_in_page(slot); + struct i915_request *rq; + u32 *cs; + int err; + + rq = intel_context_create_request(ce); + if (IS_ERR(rq)) + return rq; + + if (rq->engine->emit_init_breadcrumb) { + err = rq->engine->emit_init_breadcrumb(rq); + if (err) + goto err; + } + + cs = intel_ring_begin(rq, 10); + if (IS_ERR(cs)) { + err = PTR_ERR(cs); + goto err; + } + + *cs++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT; + *cs++ = offset; + *cs++ = 0; + *cs++ = 1; + + *cs++ = MI_ARB_ON_OFF | MI_ARB_ENABLE; + *cs++ = MI_ARB_CHECK; + + *cs++ = MI_SEMAPHORE_WAIT | + MI_SEMAPHORE_GLOBAL_GTT | + MI_SEMAPHORE_POLL | + MI_SEMAPHORE_SAD_EQ_SDD; + *cs++ = 0; + *cs++ = offset; + *cs++ = 0; + + intel_ring_advance(rq, cs); + + err = 0; +err: + i915_request_get(rq); + i915_request_add(rq); + if (err) { + i915_request_put(rq); + return ERR_PTR(err); + } + + return rq; +} + +static inline bool +ring_is_paused(const struct intel_engine_cs *engine) +{ + return engine->status_page.addr[I915_GEM_HWS_PREEMPT]; +} + +static int live_lite_semaphore(void *arg) +{ + struct intel_gt *gt = arg; + struct intel_engine_cs *engine; + enum intel_engine_id id; + int err = -ENOMEM; + + /* + * Exercise issuing a lite-restore (a continuation of the same + * active context with a new request) while the HW is blocked + * on a semaphore. We expect the HW to ACK immediately after the + * lite-restore from the next failed semaphore poll. + */ + + err = 0; + for_each_engine(engine, gt, id) { + struct intel_context *ce; + struct i915_request *rq; + struct igt_live_test t; + unsigned long saved; + u32 *slot; + + if (!intel_engine_has_semaphores(engine)) + continue; + + if (!intel_engine_can_store_dword(engine)) + continue; + + if (igt_live_test_begin(&t, gt->i915, __func__, engine->name)) { + err = -EIO; + break; + } + engine_heartbeat_disable(engine, &saved); + + slot = memset32(engine->status_page.addr + 1000, 0, 4); + + ce = intel_context_create(engine); + if (IS_ERR(ce)) { + err = PTR_ERR(ce); + goto err; + } + + rq = create_lite_semaphore(ce, slot); + if (IS_ERR(rq)) { + err = PTR_ERR(rq); + goto err_ce; + } + + if (wait_for(READ_ONCE(*slot), 50)) { + GEM_TRACE_ERR("%s: failed to submit request\n", + engine->name); + err = -ETIME; + goto err_rq; + } + + intel_engine_flush_submission(engine); + GEM_BUG_ON(engine->execlists.pending[0]); + + /* Switch from the inner semaphore to the preempt-to-busy one */ + ring_set_paused(engine, 1); + WRITE_ONCE(*slot, 0); + + if (i915_request_wait(rq, 0, HZ / 2) < 0) { + GEM_TRACE_ERR("%s: failed to complete request\n", + engine->name); + err = -ETIME; + goto err_rq; + } + + i915_request_put(rq); + + rq = intel_context_create_request(ce); + if (IS_ERR(rq)) { + err = PTR_ERR(rq); + goto err_ce; + } + + /* + * The ring_is_paused() should only be cleared on the HW ACK + * following the preemption request (see process_csb()). We + * depend on the HW processing that ACK even if it is currently + * inside a semaphore. + */ + GEM_BUG_ON(!ring_is_paused(engine)); + GEM_BUG_ON(engine->execlists.pending[0]); + GEM_BUG_ON(execlists_active(&engine->execlists)->context != ce); + + i915_request_get(rq); + i915_request_add(rq); + + if (i915_request_wait(rq, 0, HZ / 2) < 0) { + GEM_TRACE_ERR("%s: failed to complete lite-restore\n", + engine->name); + err = -ETIME; + goto err_rq; + } + +err_rq: + i915_request_put(rq); +err_ce: + intel_context_put(ce); +err: + engine_heartbeat_enable(engine, saved); + if (igt_live_test_end(&t)) + err = -EIO; + if (err) + break; + } + + return err; +} + static int live_pin_rewind(void *arg) { struct intel_gt *gt = arg; @@ -3954,6 +4128,7 @@ int intel_execlists_live_selftests(struct drm_i915_private *i915) SUBTEST(live_sanitycheck), SUBTEST(live_unlite_switch), SUBTEST(live_unlite_preempt), + SUBTEST(live_lite_semaphore), SUBTEST(live_pin_rewind), SUBTEST(live_hold_reset), SUBTEST(live_error_interrupt), -- 2.20.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx