[PATCH 08/14] unwind-legacy-ctx
Chris Wilson
chris at chris-wilson.co.uk
Fri Nov 17 17:43:22 UTC 2017
---
drivers/gpu/drm/i915/i915_gem_context.c | 149 ++++++++++++--------------------
drivers/gpu/drm/i915/i915_gem_request.c | 14 +--
drivers/gpu/drm/i915/intel_ringbuffer.h | 1 +
3 files changed, 62 insertions(+), 102 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index 6ca56e482d79..1c3eac354f21 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -507,6 +507,7 @@ void i915_gem_contexts_lost(struct drm_i915_private *dev_priv)
for_each_engine(engine, dev_priv, id) {
engine->legacy_active_context = NULL;
+ engine->legacy_active_ppgtt = NULL;
if (!engine->last_retired_context)
continue;
@@ -688,61 +689,66 @@ static inline bool skip_rcs_switch(struct i915_hw_ppgtt *ppgtt,
if (to->remap_slice)
return false;
- if (ppgtt && (intel_engine_flag(engine) & ppgtt->pd_dirty_rings))
- return false;
-
return to == engine->legacy_active_context;
}
static bool
-needs_pd_load_pre(struct i915_hw_ppgtt *ppgtt, struct intel_engine_cs *engine)
+needs_pd_load(struct i915_hw_ppgtt *ppgtt, struct intel_engine_cs *engine)
{
- struct i915_gem_context *from = engine->legacy_active_context;
+ struct i915_hw_ppgtt *from = engine->legacy_active_ppgtt;
if (!ppgtt)
return false;
- /* Always load the ppgtt on first use */
- if (!from)
- return true;
-
- /* Same context without new entries, skip */
- if ((!from->ppgtt || from->ppgtt == ppgtt) &&
+ if (from == ppgtt &&
!(intel_engine_flag(engine) & ppgtt->pd_dirty_rings))
return false;
- if (engine->id != RCS)
- return true;
-
return true;
}
-static int do_rcs_switch(struct drm_i915_gem_request *req)
+/**
+ * i915_switch_context() - perform a GPU context switch.
+ * @rq: request for which we'll execute the context switch
+ *
+ * The context life cycle is simple. The context refcount is incremented and
+ * decremented by 1 and create and destroy. If the context is in use by the GPU,
+ * it will have a refcount > 1. This allows us to destroy the context abstract
+ * object while letting the normal object tracking destroy the backing BO.
+ *
+ * This function should not be used in execlists mode. Instead the context is
+ * switched by writing to the ELSP and requests keep a reference to their
+ * context.
+ */
+int i915_switch_context(struct drm_i915_gem_request *rq)
{
- struct i915_gem_context *to = req->ctx;
- struct intel_engine_cs *engine = req->engine;
- struct i915_hw_ppgtt *ppgtt = to->ppgtt ?: req->i915->mm.aliasing_ppgtt;
- struct i915_gem_context *from = engine->legacy_active_context;
- u32 hw_flags;
+ struct intel_engine_cs *engine = rq->engine;
+ struct i915_gem_context *to = rq->ctx;
+ struct i915_hw_ppgtt *ppgtt = to->ppgtt ?: rq->i915->mm.aliasing_ppgtt;
+ struct i915_gem_context *saved_ctx = engine->legacy_active_context;
+ struct i915_hw_ppgtt *saved_mm = engine->legacy_active_ppgtt;
+ u32 hw_flags = 0;
int ret, i;
- GEM_BUG_ON(engine->id != RCS);
-
- if (skip_rcs_switch(ppgtt, engine, to))
- return 0;
+ lockdep_assert_held(&rq->i915->drm.struct_mutex);
+ GEM_BUG_ON(HAS_EXECLISTS(rq->i915));
- if (needs_pd_load_pre(ppgtt, engine)) {
- /* Older GENs and non render rings still want the load first,
- * "PP_DCLV followed by PP_DIR_BASE register through Load
- * Register Immediate commands in Ring Buffer before submitting
- * a context."*/
+ if (needs_pd_load(ppgtt, engine)) {
trace_switch_mm(engine, to);
- ret = ppgtt->switch_mm(ppgtt, req);
+ ret = ppgtt->switch_mm(ppgtt, rq);
if (ret)
- return ret;
+ goto err;
+
+ ppgtt->pd_dirty_rings &= ~intel_engine_flag(engine);
+ engine->legacy_active_ppgtt = ppgtt;
+ hw_flags = MI_FORCE_RESTORE;
}
- if (i915_gem_context_is_kernel(to))
+ if (rq->ctx->engine[engine->id].state &&
+ (to != engine->legacy_active_context ||
+ hw_flags & MI_FORCE_RESTORE)) {
+ GEM_BUG_ON(engine->id != RCS);
+
/*
* The kernel context(s) is treated as pure scratch and is not
* expected to retain any state (as we sacrifice it during
@@ -750,78 +756,37 @@ static int do_rcs_switch(struct drm_i915_gem_request *req)
* as nothing actually executes using the kernel context; it
* is purely used for flushing user contexts.
*/
- hw_flags = MI_RESTORE_INHIBIT;
- else if (ppgtt && intel_engine_flag(engine) & ppgtt->pd_dirty_rings)
- hw_flags = MI_FORCE_RESTORE;
- else
- hw_flags = 0;
+ if (i915_gem_context_is_kernel(to))
+ hw_flags = MI_RESTORE_INHIBIT;
- if (to != from || (hw_flags & MI_FORCE_RESTORE)) {
- ret = mi_set_context(req, hw_flags);
+ ret = mi_set_context(rq, hw_flags);
if (ret)
- return ret;
+ goto err_mm;
engine->legacy_active_context = to;
}
- if (ppgtt)
- ppgtt->pd_dirty_rings &= ~intel_engine_flag(engine);
-
- for (i = 0; i < MAX_L3_SLICES; i++) {
- if (!(to->remap_slice & (1<<i)))
- continue;
+ if (to->remap_slice) {
+ for (i = 0; i < MAX_L3_SLICES; i++) {
+ if (!(to->remap_slice & (1<<i)))
+ continue;
- ret = remap_l3(req, i);
- if (ret)
- return ret;
-
- to->remap_slice &= ~(1<<i);
- }
-
- return 0;
-}
-
-/**
- * i915_switch_context() - perform a GPU context switch.
- * @req: request for which we'll execute the context switch
- *
- * The context life cycle is simple. The context refcount is incremented and
- * decremented by 1 and create and destroy. If the context is in use by the GPU,
- * it will have a refcount > 1. This allows us to destroy the context abstract
- * object while letting the normal object tracking destroy the backing BO.
- *
- * This function should not be used in execlists mode. Instead the context is
- * switched by writing to the ELSP and requests keep a reference to their
- * context.
- */
-int i915_switch_context(struct drm_i915_gem_request *req)
-{
- struct intel_engine_cs *engine = req->engine;
-
- lockdep_assert_held(&req->i915->drm.struct_mutex);
- GEM_BUG_ON(HAS_EXECLISTS(req->i915));
-
- if (!req->ctx->engine[engine->id].state) {
- struct i915_gem_context *to = req->ctx;
- struct i915_hw_ppgtt *ppgtt =
- to->ppgtt ?: req->i915->mm.aliasing_ppgtt;
-
- if (needs_pd_load_pre(ppgtt, engine)) {
- int ret;
-
- trace_switch_mm(engine, to);
- ret = ppgtt->switch_mm(ppgtt, req);
+ ret = remap_l3(rq, i);
if (ret)
- return ret;
-
- ppgtt->pd_dirty_rings &= ~intel_engine_flag(engine);
+ goto err_ctx;
}
- engine->legacy_active_context = to;
- return 0;
+ to->remap_slice = 0;
}
- return do_rcs_switch(req);
+ return 0;
+
+err_ctx:
+ engine->legacy_active_context = saved_ctx;
+err_mm:
+ engine->legacy_active_ppgtt = saved_mm;
+err:
+ return ret;
}
static bool engine_has_idle_kernel_context(struct intel_engine_cs *engine)
diff --git a/drivers/gpu/drm/i915/i915_gem_request.c b/drivers/gpu/drm/i915/i915_gem_request.c
index 86e2346357cf..60bc762b4549 100644
--- a/drivers/gpu/drm/i915/i915_gem_request.c
+++ b/drivers/gpu/drm/i915/i915_gem_request.c
@@ -721,21 +721,15 @@ i915_gem_request_alloc(struct intel_engine_cs *engine,
goto err_ctx;
ret = engine->request_alloc(req);
- if (ret) {
- /*
- * Past the point-of-no-return. Since we may have updated
- * global state after partially completing the request alloc,
- * we need to commit any commands so far emitted in the
- * request to the HW.
- */
- __i915_add_request(req, false);
- return ERR_PTR(ret);
- }
+ if (ret)
+ goto err_unwind;
/* Check that we didn't interrupt ourselves with a new request */
GEM_BUG_ON(req->timeline->seqno != req->fence.seqno);
return req;
+err_unwind:
+ req->ring->emit = req->head;
err_ctx:
/* Make sure we didn't add ourselves to external state before freeing */
GEM_BUG_ON(!list_empty(&req->active_list));
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index ee9f294b99da..ecc27dd0dc49 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -493,6 +493,7 @@ struct intel_engine_cs {
* stream (ring).
*/
struct i915_gem_context *legacy_active_context;
+ struct i915_hw_ppgtt *legacy_active_ppgtt;
/* status_notifier: list of callbacks for context-switch changes */
struct atomic_notifier_head context_status_notifier;
--
2.15.0
More information about the Intel-gfx-trybot
mailing list