[Intel-gfx] [PATCH 1/2] [v3] drm/i915: reference count for i915_hw_contexts
Ben Widawsky
ben at bwidawsk.net
Wed Apr 3 03:27:00 CEST 2013
On Tue, Apr 02, 2013 at 03:45:42PM -0700, Ben Widawsky wrote:
> From: Mika Kuoppala <mika.kuoppala at linux.intel.com>
>
> In preparation to do analysis of which context was
> guilty of gpu hung, store kreffed context pointer
> into request struct.
>
> This allows us to inspect contexts when gpu is reset
> even if those contexts would already be released
> by userspace.
>
> v2: track i915_hw_context pointers instead of using ctx_ids
> (from Chris Wilson)
>
> v3 (Ben): Get rid of do_release() and handle refcounting more compactly.
> (recommended by Chris)
>
> Signed-off-by: Mika Kuoppala <mika.kuoppala at intel.com>
> Signed-off-by: Ben Widawsky <ben at bwidawsk.net>
Now I remember why my version of reference counting was so much more
complicated. In my case, I want to keep the last context around instead
of the last context object. To do this we can't do a kref_put until
we've switched to the next context (similar to how we manage the context
object). I want to do this since the context stores the PPGTT which will
currently be in use. I need to switch PDEs at context switch time.
So the below isn't really useful to me, I think, and I believe I need a
more complex refcounting mechanism as I described on IRC earlier today.
Daniel, Chris, thoughts?
> ---
> drivers/gpu/drm/i915/i915_drv.h | 10 ++++++++--
> drivers/gpu/drm/i915/i915_gem.c | 16 +++++++++++++++-
> drivers/gpu/drm/i915/i915_gem_context.c | 17 +++++++++++++----
> drivers/gpu/drm/i915/i915_gem_execbuffer.c | 7 ++++---
> 4 files changed, 40 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 5b0c699..b88b67d 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -437,6 +437,7 @@ struct i915_hw_ppgtt {
> /* 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;
> @@ -1240,6 +1241,9 @@ struct drm_i915_gem_request {
> /** Postion in the ringbuffer of the end of the request */
> u32 tail;
>
> + /** Context related to this request */
> + struct i915_hw_context *ctx;
> +
> /** Time at which this request was emitted, in jiffies. */
> unsigned long emitted_jiffies;
>
> @@ -1630,9 +1634,10 @@ int __must_check i915_gpu_idle(struct drm_device *dev);
> int __must_check i915_gem_idle(struct drm_device *dev);
> int i915_do_add_request(struct intel_ring_buffer *ring,
> u32 *seqno,
> - struct drm_file *file);
> + struct drm_file *file,
> + struct i915_hw_context *ctx);
> #define i915_add_request(ring, seqno) \
> - i915_do_add_request(ring, seqno, NULL)
> + i915_do_add_request(ring, seqno, NULL, NULL)
> int __must_check i915_wait_seqno(struct intel_ring_buffer *ring,
> uint32_t seqno);
> int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
> @@ -1676,6 +1681,7 @@ void i915_gem_context_close(struct drm_device *dev, struct drm_file *file);
> struct i915_hw_context * __must_check
> i915_switch_context(struct intel_ring_buffer *ring,
> struct drm_file *file, int to_id);
> +void i915_gem_context_free(struct kref *ctx_ref);
> int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> struct drm_file *file);
> int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index fbbe7d9..e55c4a8 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -1997,7 +1997,8 @@ i915_gem_get_seqno(struct drm_device *dev, u32 *seqno)
> int
> i915_do_add_request(struct intel_ring_buffer *ring,
> u32 *out_seqno,
> - struct drm_file *file)
> + struct drm_file *file,
> + struct i915_hw_context *ctx)
> {
> drm_i915_private_t *dev_priv = ring->dev->dev_private;
> struct drm_i915_gem_request *request;
> @@ -2037,6 +2038,11 @@ i915_do_add_request(struct intel_ring_buffer *ring,
> request->seqno = intel_ring_get_seqno(ring);
> request->ring = ring;
> request->tail = request_ring_position;
> + 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);
> @@ -2101,6 +2107,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);
> }
>
> @@ -2195,6 +2205,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);
> }
>
> diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
> index ddf26a6..19feeb6 100644
> --- a/drivers/gpu/drm/i915/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/i915_gem_context.c
> @@ -126,11 +126,18 @@ static int get_context_size(struct drm_device *dev)
>
> static void do_destroy(struct i915_hw_context *ctx)
> {
> + drm_gem_object_unreference(&ctx->obj->base);
> + kfree(ctx);
> +}
> +
> +void i915_gem_context_free(struct kref *ctx_ref)
> +{
> + struct i915_hw_context *ctx = container_of(ctx_ref,
> + typeof(*ctx), ref);
> if (ctx->file_priv)
> idr_remove(&ctx->file_priv->context_idr, ctx->id);
>
> - drm_gem_object_unreference(&ctx->obj->base);
> - kfree(ctx);
> + do_destroy(ctx);
> }
>
> static struct i915_hw_context *
> @@ -145,6 +152,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);
> @@ -275,7 +283,8 @@ static int context_idr_cleanup(int id, void *p, void *data)
>
> BUG_ON(id == DEFAULT_CONTEXT_ID);
>
> - do_destroy(ctx);
> + ctx->file_priv = NULL;
> + kref_put(&ctx->ref, i915_gem_context_free);
>
> return 0;
> }
> @@ -511,7 +520,7 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
> return -ENOENT;
> }
>
> - do_destroy(ctx);
> + kref_put(&ctx->ref, i915_gem_context_free);
>
> mutex_unlock(&dev->struct_mutex);
>
> diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
> index d87b94b..7f58b2e 100644
> --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
> +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
> @@ -794,13 +794,14 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects,
> static void
> i915_gem_execbuffer_retire_commands(struct drm_device *dev,
> struct drm_file *file,
> - struct intel_ring_buffer *ring)
> + struct intel_ring_buffer *ring,
> + struct i915_hw_context *ctx)
> {
> /* Unconditionally force add_request to emit a full flush. */
> ring->gpu_caches_dirty = true;
>
> /* Add a breadcrumb for the completion of the batch buffer */
> - (void)i915_do_add_request(ring, NULL, file);
> + (void)i915_do_add_request(ring, NULL, file, ctx);
> }
>
> static int
> @@ -1076,7 +1077,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
> trace_i915_gem_ring_dispatch(ring, intel_ring_get_seqno(ring), flags);
>
> i915_gem_execbuffer_move_to_active(&eb->objects, ring);
> - i915_gem_execbuffer_retire_commands(dev, file, ring);
> + i915_gem_execbuffer_retire_commands(dev, file, ring, ctx);
>
> err:
> eb_destroy(eb);
> --
> 1.8.2
>
--
Ben Widawsky, Intel Open Source Technology Center
More information about the Intel-gfx
mailing list