summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Widawsky <benjamin.widawsky@intel.com>2013-10-24 17:23:57 -0700
committerBen Widawsky <benjamin.widawsky@intel.com>2013-12-06 10:55:31 -0800
commita81b3021823486e81f115a2816439577398e7372 (patch)
treecc5d5bab82833a2410133e29a061d71c3d4d2bfb
parent48ddb449d2536a458e6d57a08026699d92cdbb2f (diff)
drm/i915: Add VM to context
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>
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h8
-rw-r--r--drivers/gpu/drm/i915/i915_gem_context.c12
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c7
3 files changed, 24 insertions, 3 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index a29ab5ed98e1..cf3c98c6c3ce 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -654,6 +654,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 {
@@ -703,6 +704,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;
};
@@ -2289,6 +2291,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 */
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index f5b0b8007594..80064aab6584 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -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);
}
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 6e9a43e57572..f9f7267e09a0 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -904,9 +904,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;
}
@@ -919,7 +921,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;
}