Minimal state of engine is saved before resetting it, this state includes head, current active request. A consistency check is performed on the active request to make sure that the context HW is executing is same as the one for the active request. This check is important because engine recovery in execlist mode relies on the context resubmission after reset. If the state is inconsistent, resubmission can cause unforseen side-effects such as unexpected preemptions. Engine is restarted after reset with this state. Signed-off-by: Tomas Elf <tomas.elf@xxxxxxxxx> Signed-off-by: Arun Siluvery <arun.siluvery@xxxxxxxxxxxxxxx> --- drivers/gpu/drm/i915/intel_lrc.c | 85 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_lrc.h | 3 ++ drivers/gpu/drm/i915/intel_ringbuffer.h | 10 ++++ 3 files changed, 98 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index edae3ed..5bfc93d 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1188,6 +1188,87 @@ void intel_lr_context_unpin(struct intel_context *ctx, } } +/** + * intel_execlist_get_current_request() - returns request currently processed + * by the given engine + * + * @engine: Engine currently running context to be returned. + * + * Returns: + * req - if a valid req is found in the execlist queue and HW also agrees. + * caller has to dereference at the end of its lifecycle. + * NULL - otherwise + */ +static struct drm_i915_gem_request * +intel_execlist_get_current_request(struct intel_engine_cs *engine) +{ + struct drm_i915_private *dev_priv; + struct drm_i915_gem_request *req; + unsigned long flags; + + dev_priv = engine->dev->dev_private; + + spin_lock_irqsave(&engine->execlist_lock, flags); + + req = list_first_entry_or_null(&engine->execlist_queue, + struct drm_i915_gem_request, + execlist_link); + /* + * Only acknowledge the request in the execlist queue if it's actually + * been submitted to hardware, otherwise there's the risk of + * inconsistency between the (unsubmitted) request and the idle + * hardware state. + */ + if (req && req->ctx && req->elsp_submitted) { + u32 execlist_status; + u32 hw_context; + u32 hw_active; + u32 sw_context; + + hw_context = I915_READ(RING_EXECLIST_STATUS_CTX_ID(engine)); + execlist_status = I915_READ(RING_EXECLIST_STATUS_LO(engine)); + hw_active = ((execlist_status & EXECLIST_STATUS_ELEMENT0_ACTIVE) || + (execlist_status & EXECLIST_STATUS_ELEMENT1_ACTIVE)); + + sw_context = intel_execlists_ctx_id(req->ctx, engine); + + /* If both HW and driver agrees then we found it */ + if (hw_active && hw_context == sw_context) + i915_gem_request_reference(req); + } else { + req = NULL; + WARN(1, "No active request for %s\n", engine->name); + } + + spin_unlock_irqrestore(&engine->execlist_lock, flags); + + return req; +} + +/** + * gen8_engine_state_save() - save minimum engine state + * @engine: engine whose state is to be saved + * @state: location where the state is saved + * + * captured engine state includes head, tail, active request. After reset, + * engine is restarted with this state. + * + * Returns: + * 0 if ok, otherwise propagates error codes. + */ +static int gen8_engine_state_save(struct intel_engine_cs *engine, + struct intel_engine_cs_state *state) +{ + struct drm_i915_private *dev_priv = engine->dev->dev_private; + + state->head = I915_READ_HEAD(engine); + state->req = intel_execlist_get_current_request(engine); + if (!state->req) + return -EINVAL; + + return 0; +} + static int intel_logical_ring_workarounds_emit(struct drm_i915_gem_request *req) { int ret, i; @@ -2091,6 +2172,10 @@ logical_ring_default_vfuncs(struct drm_device *dev, engine->emit_bb_start = gen8_emit_bb_start; engine->get_seqno = gen8_get_seqno; engine->set_seqno = gen8_set_seqno; + + /* engine reset supporting functions */ + engine->save = gen8_engine_state_save; + if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) { engine->irq_seqno_barrier = bxt_a_seqno_barrier; engine->set_seqno = bxt_a_set_seqno; diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 0b0853e..d7e22fc 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -29,7 +29,10 @@ /* Execlists regs */ #define RING_ELSP(ring) _MMIO((ring)->mmio_base + 0x230) #define RING_EXECLIST_STATUS_LO(ring) _MMIO((ring)->mmio_base + 0x234) +#define EXECLIST_STATUS_ELEMENT0_ACTIVE (1 << 14) +#define EXECLIST_STATUS_ELEMENT1_ACTIVE (1 << 15) #define RING_EXECLIST_STATUS_HI(ring) _MMIO((ring)->mmio_base + 0x234 + 4) +#define RING_EXECLIST_STATUS_CTX_ID(ring) RING_EXECLIST_STATUS_HI(ring) #define RING_CONTEXT_CONTROL(ring) _MMIO((ring)->mmio_base + 0x244) #define CTX_CTRL_INHIBIT_SYN_CTX_SWITCH (1 << 3) #define CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT (1 << 0) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 78dc468..62f9fb4 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -144,6 +144,12 @@ struct i915_ctx_workarounds { struct drm_i915_gem_object *obj; }; +struct intel_engine_cs_state { + u32 head; + u32 tail; + struct drm_i915_gem_request *req; +}; + struct intel_engine_cs { const char *name; enum intel_engine_id { @@ -206,6 +212,10 @@ struct intel_engine_cs { #define I915_DISPATCH_RS 0x4 void (*cleanup)(struct intel_engine_cs *ring); + /* engine reset supporting functions */ + int (*save)(struct intel_engine_cs *engine, + struct intel_engine_cs_state *state); + /* GEN8 signal/wait table - never trust comments! * signal to signal to signal to signal to signal to * RCS VCS BCS VECS VCS2 -- 1.9.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx