Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a16a4052 authored by Chris Wilson's avatar Chris Wilson
Browse files

drm/i915: Track the previous pinned context inside the request



As the contexts are accessed by the hardware until the switch is completed
to a new context, the hardware may still be writing to the context object
after the breadcrumb is visible. We must not unpin/unbind/prune that
object whilst still active and so we keep the previous context pinned until
the following request. We can generalise the tracking we already do via
the engine->last_context and move it to the request so that it works
equally for execlists and GuC.

v2: Drop the execlists double pin as that exposes a race inside the lrc
irq handler as it tries to access the context after it may be retired.

Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Reviewed-by: default avatarJoonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1461833819-3991-22-git-send-email-chris@chris-wilson.co.uk
parent 73db04cf
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -2305,6 +2305,17 @@ struct drm_i915_gem_request {
	struct intel_context *ctx;
	struct intel_ringbuffer *ringbuf;

	/**
	 * Context related to the previous request.
	 * As the contexts are accessed by the hardware until the switch is
	 * completed to a new context, the hardware may still be writing
	 * to the context object after the breadcrumb is visible. We must
	 * not unpin/unbind/prune that object whilst still active and so
	 * we keep the previous context pinned until the following (this)
	 * request is retired.
	 */
	struct intel_context *previous_context;

	/** Batch buffer related to this request if any (used for
	    error state dump only) */
	struct drm_i915_gem_object *batch_obj;
+4 −4
Original line number Diff line number Diff line
@@ -1413,13 +1413,13 @@ static void i915_gem_request_retire(struct drm_i915_gem_request *request)
	list_del_init(&request->list);
	i915_gem_request_remove_from_client(request);

	if (request->ctx) {
	if (request->previous_context) {
		if (i915.enable_execlists)
			intel_lr_context_unpin(request->ctx, request->engine);

		i915_gem_context_unreference(request->ctx);
			intel_lr_context_unpin(request->previous_context,
					       request->engine);
	}

	i915_gem_context_unreference(request->ctx);
	i915_gem_request_unreference(request);
}

+8 −6
Original line number Diff line number Diff line
@@ -771,12 +771,14 @@ intel_logical_ring_advance_and_submit(struct drm_i915_gem_request *request)
	if (intel_engine_stopped(engine))
		return 0;

	if (engine->last_context != request->ctx) {
		if (engine->last_context)
			intel_lr_context_unpin(engine->last_context, engine);
		intel_lr_context_pin(request->ctx, engine);
	/* We keep the previous context alive until we retire the following
	 * request. This ensures that any the context object is still pinned
	 * for any residual writes the HW makes into it on the context switch
	 * into the next object following the breadcrumb. Otherwise, we may
	 * retire the context too early.
	 */
	request->previous_context = engine->last_context;
	engine->last_context = request->ctx;
	}

	if (dev_priv->guc.execbuf_client)
		i915_guc_submit(dev_priv->guc.execbuf_client, request);