@@ -438,6 +438,7 @@ struct i915_reset_stats {
/* This must match up with the value previously used for execbuf2.rsvd1. */
#define DEFAULT_CONTEXT_ID 0
struct i915_hw_context {
+ struct kref ref;
int id;
bool is_initialized;
struct drm_i915_file_private *file_priv;
@@ -1688,7 +1689,8 @@ void i915_gem_context_init(struct drm_device *dev);
void i915_gem_context_fini(struct drm_device *dev);
void i915_gem_context_close(struct drm_device *dev, struct drm_file *file);
int i915_switch_context(struct intel_ring_buffer *ring,
- struct drm_file *file, int to_id);
+ struct drm_file *file, int to_id,
+ struct i915_hw_context **ctx_out);
void i915_gem_context_free(struct kref *ctx_ref);
int i915_gem_context_get_reset_stats(struct intel_ring_buffer *ring,
struct drm_file *file,
@@ -2036,6 +2036,10 @@ i915_add_request(struct intel_ring_buffer *ring,
request->tail = request_ring_position;
request->batch_obj = obj;
request->ctx = ctx;
+
+ if (request->ctx)
+ kref_get(&request->ctx->ref);
+
request->emitted_jiffies = jiffies;
was_empty = list_empty(&ring->request_list);
list_add_tail(&request->list, &ring->request_list);
@@ -2100,6 +2104,10 @@ static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv,
list_del(&request->list);
i915_gem_request_remove_from_client(request);
+
+ if (request->ctx)
+ kref_put(&request->ctx->ref, i915_gem_context_free);
+
kfree(request);
}
@@ -2194,6 +2202,10 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
list_del(&request->list);
i915_gem_request_remove_from_client(request);
+
+ if (request->ctx)
+ kref_put(&request->ctx->ref, i915_gem_context_free);
+
kfree(request);
}
@@ -2516,7 +2528,7 @@ int i915_gpu_idle(struct drm_device *dev)
/* Flush everything onto the inactive list. */
for_each_ring(ring, dev_priv, i) {
- ret = i915_switch_context(ring, NULL, DEFAULT_CONTEXT_ID);
+ ret = i915_switch_context(ring, NULL, DEFAULT_CONTEXT_ID, NULL);
if (ret)
return ret;
@@ -124,7 +124,14 @@ static int get_context_size(struct drm_device *dev)
return ret;
}
-static void do_destroy(struct i915_hw_context *ctx)
+void i915_gem_context_free(struct kref *ctx_ref)
+{
+ struct i915_hw_context *ctx = container_of(ctx_ref,
+ typeof(*ctx), ref);
+ kfree(ctx);
+}
+
+static void do_release(struct i915_hw_context *ctx)
{
struct drm_device *dev = ctx->obj->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -135,6 +142,11 @@ static void do_destroy(struct i915_hw_context *ctx)
BUG_ON(ctx != dev_priv->ring[RCS].default_context);
drm_gem_object_unreference(&ctx->obj->base);
+}
+
+static void do_destroy(struct i915_hw_context *ctx)
+{
+ do_release(ctx);
kfree(ctx);
}
@@ -150,6 +162,7 @@ create_hw_context(struct drm_device *dev,
if (ctx == NULL)
return ERR_PTR(-ENOMEM);
+ kref_init(&ctx->ref);
ctx->obj = i915_gem_alloc_object(dev, dev_priv->hw_context_size);
if (ctx->obj == NULL) {
kfree(ctx);
@@ -294,8 +307,8 @@ static int context_idr_cleanup(int id, void *p, void *data)
BUG_ON(id == DEFAULT_CONTEXT_ID);
- do_destroy(ctx);
-
+ do_release(ctx);
+ kref_put(&ctx->ref, i915_gem_context_free);
return 0;
}
@@ -481,10 +494,12 @@ static int do_switch(struct i915_hw_context *to)
*/
int i915_switch_context(struct intel_ring_buffer *ring,
struct drm_file *file,
- int to_id)
+ int to_id,
+ struct i915_hw_context **ctx_out)
{
struct drm_i915_private *dev_priv = ring->dev->dev_private;
struct i915_hw_context *to;
+ int ret;
if (dev_priv->hw_contexts_disabled)
return 0;
@@ -503,7 +518,14 @@ int i915_switch_context(struct intel_ring_buffer *ring,
return -ENOENT;
}
- return do_switch(to);
+ ret = do_switch(to);
+ if (ret)
+ return ret;
+
+ if (ctx_out)
+ *ctx_out = to;
+
+ return 0;
}
int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
@@ -557,7 +579,8 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
return -ENOENT;
}
- do_destroy(ctx);
+ do_release(ctx);
+ kref_put(&ctx->ref, i915_gem_context_free);
mutex_unlock(&dev->struct_mutex);
@@ -999,7 +999,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
if (ret)
goto err;
- ret = i915_switch_context(ring, file, ctx_id);
+ ret = i915_switch_context(ring, file, ctx_id, &ctx);
if (ret)
goto err;
When using i915_hw_context pointer in request struct, we need to use reference counts as context might be released before request processing takes place. v2: track i915_hw_context pointers instead of using ctx_ids (from Chris Wilson) Signed-off-by: Mika Kuoppala <mika.kuoppala@intel.com> --- drivers/gpu/drm/i915/i915_drv.h | 4 +++- drivers/gpu/drm/i915/i915_gem.c | 14 ++++++++++- drivers/gpu/drm/i915/i915_gem_context.c | 35 +++++++++++++++++++++++----- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- 4 files changed, 46 insertions(+), 9 deletions(-)