@@ -884,6 +884,7 @@ struct intel_context {
struct {
struct drm_i915_gem_object *state;
struct intel_ringbuffer *ringbuf;
+ bool unsaved;
int pin_count;
} engine[I915_NUM_RINGS];
@@ -1385,6 +1385,13 @@ __i915_gem_request_retire__upto(struct drm_i915_gem_request *req)
tmp = list_first_entry(&engine->request_list,
typeof(*tmp), list);
+ if (i915.enable_execlists) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&engine->execlist_lock, flags);
+ intel_lr_context_complete_check(tmp);
+ spin_unlock_irqrestore(&engine->execlist_lock, flags);
+ }
i915_gem_request_retire(tmp);
} while (tmp != req);
@@ -566,13 +566,17 @@ static int execlists_context_queue(struct drm_i915_gem_request *request)
struct drm_i915_gem_request *cursor;
int num_elements = 0;
- if (request->ctx != ring->default_context)
- intel_lr_context_pin(request);
-
i915_gem_request_reference(request);
spin_lock_irq(&ring->execlist_lock);
+ if (request->ctx != ring->default_context) {
+ if (!request->ctx->engine[ring->id].unsaved) {
+ intel_lr_context_pin(request);
+ request->ctx->engine[ring->id].unsaved = true;
+ }
+ }
+
list_for_each_entry(cursor, &ring->execlist_queue, execlist_link)
if (++num_elements > 2)
break;
@@ -958,12 +962,6 @@ void intel_execlists_retire_requests(struct intel_engine_cs *ring)
spin_unlock_irq(&ring->execlist_lock);
list_for_each_entry_safe(req, tmp, &retired_list, execlist_link) {
- struct intel_context *ctx = req->ctx;
- struct drm_i915_gem_object *ctx_obj =
- ctx->engine[ring->id].state;
-
- if (ctx_obj && (ctx != ring->default_context))
- intel_lr_context_unpin(req);
list_del(&req->execlist_link);
i915_gem_request_unreference(req);
}
@@ -1073,6 +1071,31 @@ void intel_lr_context_unpin(struct drm_i915_gem_request *rq)
}
}
+void intel_lr_context_complete_check(struct drm_i915_gem_request *req)
+{
+ struct intel_engine_cs *ring = req->ring;
+
+ assert_spin_locked(&ring->execlist_lock);
+
+ if (ring->last_context && ring->last_context != req->ctx) {
+ if (req->ctx != ring->default_context
+ && ring->last_context->engine[ring->id].unsaved) {
+ /* Create fake request for unpinning the old context */
+ struct drm_i915_gem_request tmp;
+
+ tmp.ring = ring;
+ tmp.ctx = ring->last_context;
+ tmp.ringbuf =
+ ring->last_context->engine[ring->id].ringbuf;
+
+ intel_lr_context_unpin(&tmp);
+ ring->last_context->engine[ring->id].unsaved = false;
+ ring->last_context = NULL;
+ }
+ }
+ ring->last_context = req->ctx;
+}
+
static int intel_logical_ring_workarounds_emit(struct drm_i915_gem_request *req)
{
int ret, i;
@@ -2390,7 +2413,22 @@ void intel_lr_context_free(struct intel_context *ctx)
intel_unpin_ringbuffer_obj(ringbuf);
i915_gem_object_ggtt_unpin(ctx_obj);
}
- WARN_ON(ctx->engine[ring->id].pin_count);
+
+ if (ctx->engine[ring->id].unsaved) {
+ /**
+ * Create fake request for unpinning the old
+ * context
+ */
+ struct drm_i915_gem_request tmp;
+
+ tmp.ring = ring;
+ tmp.ctx = ctx;
+ tmp.ringbuf = ringbuf;
+ intel_lr_context_unpin(&tmp);
+ ctx->engine[ring->id].unsaved = false;
+ }
+
+ WARN_ON(ctx->engine[i].pin_count);
intel_ringbuffer_free(ringbuf);
drm_gem_object_unreference(&ctx_obj->base);
}
@@ -86,6 +86,7 @@ void intel_lr_context_reset(struct drm_device *dev,
struct intel_context *ctx);
uint64_t intel_lr_context_descriptor(struct intel_context *ctx,
struct intel_engine_cs *ring);
+void intel_lr_context_complete_check(struct drm_i915_gem_request *req);
/* Execlists */
int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists);
Use the first retired request on a new context to unpin the old context. This ensures that the hw context remains bound until it has been saved. Now that the context is pinned until later in the request/context lifecycle, it no longer needs to be pinned from context_queue to retire_requests. The refcount on the context also has to be extended to cover this new longer period. Signed-off-by: Nick Hoath <nicholas.hoath@intel.com> Issue: VIZ-4277 Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: David Gordon <david.s.gordon@intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Alex Dai <yu.dai@intel.com> --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem.c | 7 +++++ drivers/gpu/drm/i915/intel_lrc.c | 58 +++++++++++++++++++++++++++++++++------- drivers/gpu/drm/i915/intel_lrc.h | 1 + 4 files changed, 57 insertions(+), 10 deletions(-)