@@ -609,14 +609,18 @@ mi_set_context(struct intel_engine_cs *ring,
return ret;
}
-static void do_switch_fini_common(struct intel_engine_cs *ring,
- struct intel_context *from,
- struct intel_context *to)
+static struct intel_context *do_switch_fini_common(struct intel_engine_cs *ring,
+ struct intel_context *from,
+ struct intel_context *to)
{
+ struct intel_context *ret;
if (likely(from))
i915_gem_context_unreference(from);
i915_gem_context_reference(to);
+ ret = ring->last_context;
ring->last_context = to;
+
+ return ret;
}
static int do_switch_xcs(struct intel_engine_cs *ring,
@@ -762,14 +766,20 @@ static int do_switch_rcs(struct intel_engine_cs *ring,
*/
from->legacy_hw_ctx.rcs_state->dirty = 1;
BUG_ON(from->legacy_hw_ctx.rcs_state->ring != ring);
-
- /* obj is kept alive until the next request by its active ref */
- i915_gem_object_ggtt_unpin(from->legacy_hw_ctx.rcs_state);
}
uninitialized = !to->legacy_hw_ctx.initialized && from == NULL;
to->legacy_hw_ctx.initialized = true;
- do_switch_fini_common(ring, from, to);
+ /* From may have disappeared again after the context unref */
+ from = do_switch_fini_common(ring, from, to);
+ if (from != NULL) {
+ /* obj is kept alive until the next request by its active ref.
+ * XXX: The context needs to be unpinned last, or else we risk
+ * hitting evict/idle on the ppgtt free, which will call back
+ * into this, and we'll get a double unpin on this context
+ */
+ i915_gem_object_ggtt_unpin(from->legacy_hw_ctx.rcs_state);
+ }
if (uninitialized) {
ret = i915_gem_render_state_init(ring);