drm/i915: cleanup context fini
authorBen Widawsky <ben@bwidawsk.net>
Mon, 14 Oct 2013 17:01:37 +0000 (10:01 -0700)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Wed, 16 Oct 2013 09:08:30 +0000 (11:08 +0200)
I had this lying around from he original PPGTT series, and thought we
might try to get it in by itself.

With the introduction of context refcounting we never explicitly
ref/unref the backing object. As such, the previous fix was a bit wonky.

Aside from fixing the above, this patch also puts us in good shape for
an upcoming patch which allows a failure to occur in between
context_init and the first do_switch.

CC: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/i915_gem_context.c

index 1a877a547290a52f53d7df9c5116fb2e758e604c..cc619c138777165b8e05550b4d09cf43e2281135 100644 (file)
@@ -220,7 +220,6 @@ static int create_default_context(struct drm_i915_private *dev_priv)
         * may not be available. To avoid this we always pin the
         * default context.
         */
-       dev_priv->ring[RCS].default_context = ctx;
        ret = i915_gem_obj_ggtt_pin(ctx->obj, CONTEXT_ALIGN, false, false);
        if (ret) {
                DRM_DEBUG_DRIVER("Couldn't pin %d\n", ret);
@@ -233,6 +232,8 @@ static int create_default_context(struct drm_i915_private *dev_priv)
                goto err_unpin;
        }
 
+       dev_priv->ring[RCS].default_context = ctx;
+
        DRM_DEBUG_DRIVER("Default HW context loaded\n");
        return 0;
 
@@ -288,16 +289,24 @@ void i915_gem_context_fini(struct drm_device *dev)
         * other code, leading to spurious errors. */
        intel_gpu_reset(dev);
 
-       i915_gem_object_unpin(dctx->obj);
-
        /* When default context is created and switched to, base object refcount
         * will be 2 (+1 from object creation and +1 from do_switch()).
         * i915_gem_context_fini() will be called after gpu_idle() has switched
         * to default context. So we need to unreference the base object once
         * to offset the do_switch part, so that i915_gem_context_unreference()
         * can then free the base object correctly. */
-       drm_gem_object_unreference(&dctx->obj->base);
+       WARN_ON(!dev_priv->ring[RCS].last_context);
+       if (dev_priv->ring[RCS].last_context == dctx) {
+               /* Fake switch to NULL context */
+               WARN_ON(dctx->obj->active);
+               i915_gem_object_unpin(dctx->obj);
+               i915_gem_context_unreference(dctx);
+       }
+
+       i915_gem_object_unpin(dctx->obj);
        i915_gem_context_unreference(dctx);
+       dev_priv->ring[RCS].default_context = NULL;
+       dev_priv->ring[RCS].last_context = NULL;
 }
 
 static int context_idr_cleanup(int id, void *p, void *data)