@@ -656,6 +656,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 {
@@ -705,6 +706,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;
};
@@ -2310,6 +2312,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 */
@@ -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);
}
@@ -906,9 +906,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;
}
@@ -921,7 +923,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;
}