drm/i915: Add VM to context
authorBen Widawsky <benjamin.widawsky@intel.com>
Fri, 6 Dec 2013 22:11:15 +0000 (14:11 -0800)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Wed, 18 Dec 2013 14:31:20 +0000 (15:31 +0100)
Pretty straightforward so far except for the bit about the refcounting.
The PPGTT will potentially be shared amongst multiple contexts. Because
contexts themselves have a refcounted lifecycle, the easiest way to
manage this will be to refcount the PPGTT. To acheive this, we piggy
back off of the existing context refcount, and will increment and
decrement the PPGTT refcount with context creation, and destruction.

To put it more clearly, if context A, and context B both use PPGTT 0, we
can't free the PPGTT until both A, and B are destroyed.

Note that because the PPGTT is permanently pinned (for now), it really
just matters for the PPGTT destruction, as opposed to making space under
memory pressure.

Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem_context.c
drivers/gpu/drm/i915/i915_gem_gtt.c

index dbea50a0a45996d79b098bf51e166d40ad00a19f..a47a43e8e8e911d0d0d1261ec63c39245a661716 100644 (file)
@@ -655,6 +655,7 @@ struct i915_gtt {
 
 struct i915_hw_ppgtt {
        struct i915_address_space base;
+       struct kref ref;
        struct drm_mm_node node;
        unsigned num_pd_entries;
        union {
@@ -704,6 +705,7 @@ struct i915_hw_context {
        struct intel_ring_buffer *last_ring;
        struct drm_i915_gem_object *obj;
        struct i915_ctx_hang_stats hang_stats;
+       struct i915_address_space *vm;
 
        struct list_head link;
 };
@@ -2292,6 +2294,12 @@ static inline bool intel_enable_ppgtt(struct drm_device *dev, bool full)
        return HAS_ALIASING_PPGTT(dev);
 }
 
+static inline void ppgtt_release(struct kref *kref)
+{
+       struct i915_hw_ppgtt *ppgtt = container_of(kref, struct i915_hw_ppgtt, ref);
+
+       ppgtt->base.cleanup(&ppgtt->base);
+}
 
 
 /* i915_gem_evict.c */
index 149cf007c38eadf9f81e4c08398e600e0dc32f5c..0b32bcff5d66479a5bccdc2331f4c2496ae6e839 100644 (file)
@@ -141,9 +141,19 @@ void i915_gem_context_free(struct kref *ctx_ref)
 {
        struct i915_hw_context *ctx = container_of(ctx_ref,
                                                   typeof(*ctx), ref);
+       struct i915_hw_ppgtt *ppgtt = NULL;
 
-       list_del(&ctx->link);
+       /* We refcount even the aliasing PPGTT to keep the code symmetric */
+       if (USES_ALIASING_PPGTT(ctx->obj->base.dev))
+               ppgtt = container_of(ctx->vm, struct i915_hw_ppgtt, base);
+
+       /* XXX: Free up the object before tearing down the address space, in
+        * case we're bound in the PPGTT */
        drm_gem_object_unreference(&ctx->obj->base);
+
+       if (ppgtt)
+               kref_put(&ppgtt->ref, ppgtt_release);
+       list_del(&ctx->link);
        kfree(ctx);
 }
 
index c69fa2c72c1501dfc9acca2c6bf678480fed26a8..bd9228888aeb10aec4ef2c489833a37f656286d6 100644 (file)
@@ -902,9 +902,11 @@ int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
        else
                BUG();
 
-       if (!ret)
+       if (!ret) {
+               kref_init(&ppgtt->ref);
                drm_mm_init(&ppgtt->base.mm, ppgtt->base.start,
                            ppgtt->base.total);
+       }
 
        return ret;
 }
@@ -917,7 +919,8 @@ void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev)
        if (!ppgtt)
                return;
 
-       ppgtt->base.cleanup(&ppgtt->base);
+       kref_put(&dev_priv->mm.aliasing_ppgtt->ref, ppgtt_release);
+
        dev_priv->mm.aliasing_ppgtt = NULL;
 }