[Intel-gfx] [PATCH 31/49] drm/i915/bdw: Introduce dependent contexts

Mateo Lozano, Oscar oscar.mateo at intel.com
Thu Mar 27 18:21:25 CET 2014


I already got a fair review comment from Brad Volkin on this: he proposes to do this instead

	struct i915_hw_context {
		struct i915_address_space *vm;
		struct {
			struct drm_i915_gem_object *ctx_obj;
			struct intel_ringbuffer *ringbuf;
		} engine[I915_MAX_RINGS];
		...
	};

This is: instead of creating extra contexts with the same Context ID, modify the current i915_hw_context to work with all engines. I agree this alternative looks less *hackish*, but I want to get eyes on it (several things need careful consideration if we do this, e.g.: should the hang_stats also be per-engine?)

> -----Original Message-----
> From: Mateo Lozano, Oscar
> Sent: Thursday, March 27, 2014 6:00 PM
> To: intel-gfx at lists.freedesktop.org
> Cc: Mateo Lozano, Oscar
> Subject: [PATCH 31/49] drm/i915/bdw: Introduce dependent contexts
> 
> From: Oscar Mateo <oscar.mateo at intel.com>
> 
> From here on, we define a stand-alone context as the first context with a given
> ID to be created for a new fd or a new context create ioctl. This is the one we
> can easily find using integer ID management. On the other hand, dependent
> contexts are subsequently created with the same ID and simply hang from the
> stand-alone one.
> 
> This patch, together with the two previous and the next, are meant to solve a
> big problem we have: with execlists, we need contexts to work with all engines,
> and we cannot reuse one context for more than one engine.
> 
> Because, on a new fd or a context create ioctl, we really don't know which
> engine is going to be used later on, we are going to create at that point a
> "blank" context and assign it to an engine on a deferred way (during the
> execbuffer, to be precise). If later on, we execbuffer on a different engine, we
> create a new dependent context on the previous.
> 
> Note: I have tried to colour this patch in a different way, using a different struct
> (a "context group") to hold the context ID from where the per-engine contexts
> hang, but it makes legacy contexts unnecessary complex.
> 
> Signed-off-by: Oscar Mateo <oscar.mateo at intel.com>
> ---
>  drivers/gpu/drm/i915/i915_drv.h         |  6 +++++-
>  drivers/gpu/drm/i915/i915_gem_context.c | 17 +++++++++++++--
>  drivers/gpu/drm/i915/i915_lrc.c         | 37
> ++++++++++++++++++++++++++++++---
>  3 files changed, 54 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h
> b/drivers/gpu/drm/i915/i915_drv.h index 91b0886..d9470a4 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -602,6 +602,9 @@ struct i915_hw_context {
>  	struct i915_address_space *vm;
> 
>  	struct list_head link;
> +
> +	/* Advanced contexts only */
> +	struct list_head dependent_contexts;
>  };
> 
>  struct i915_fbc {
> @@ -2321,7 +2324,8 @@ int gen8_gem_context_init(struct drm_device *dev);
> void gen8_gem_context_fini(struct drm_device *dev);  struct i915_hw_context
> *gen8_gem_create_context(struct drm_device *dev,
>  			struct intel_engine *ring,
> -			struct drm_i915_file_private *file_priv, bool
> create_vm);
> +			struct drm_i915_file_private *file_priv,
> +			struct i915_hw_context *standalone_ctx, bool
> create_vm);
>  void gen8_gem_context_free(struct i915_hw_context *ctx);
> 
>  /* 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 6baa5ab..17015b2 100644
> --- a/drivers/gpu/drm/i915/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/i915_gem_context.c
> @@ -271,6 +271,8 @@ __create_hw_context(struct drm_device *dev,
>  	 * is no remap info, it will be a NOP. */
>  	ctx->remap_slice = (1 << NUM_L3_SLICES(dev)) - 1;
> 
> +	INIT_LIST_HEAD(&ctx->dependent_contexts);
> +
>  	return ctx;
> 
>  err_out:
> @@ -511,6 +513,12 @@ int i915_gem_context_enable(struct
> drm_i915_private *dev_priv)  static int context_idr_cleanup(int id, void *p, void
> *data)  {
>  	struct i915_hw_context *ctx = p;
> +	struct i915_hw_context *cursor, *tmp;
> +
> +	list_for_each_entry_safe(cursor, tmp, &ctx->dependent_contexts,
> dependent_contexts) {
> +		list_del(&cursor->dependent_contexts);
> +		i915_gem_context_unreference(cursor);
> +	}
> 
>  	/* Ignore the default context because close will handle it */
>  	if (i915_gem_context_is_default(ctx))
> @@ -543,7 +551,7 @@ int i915_gem_context_open(struct drm_device *dev,
> struct drm_file *file)
>  	if (dev_priv->lrc_enabled)
>  		file_priv->private_default_ctx =
> gen8_gem_create_context(dev,
>  						&dev_priv->ring[RCS],
> file_priv,
> -						USES_FULL_PPGTT(dev));
> +						NULL,
> USES_FULL_PPGTT(dev));
>  	else
>  		file_priv->private_default_ctx = i915_gem_create_context(dev,
>  						file_priv,
> USES_FULL_PPGTT(dev)); @@ -805,7 +813,7 @@ int
> i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> 
>  	if (dev_priv->lrc_enabled)
>  		ctx = gen8_gem_create_context(dev, &dev_priv->ring[RCS],
> -					file_priv, USES_FULL_PPGTT(dev));
> +					file_priv, NULL,
> USES_FULL_PPGTT(dev));
>  	else
>  		ctx = i915_gem_create_context(dev, file_priv,
>  					USES_FULL_PPGTT(dev));
> @@ -825,6 +833,7 @@ int i915_gem_context_destroy_ioctl(struct drm_device
> *dev, void *data,
>  	struct drm_i915_gem_context_destroy *args = data;
>  	struct drm_i915_file_private *file_priv = file->driver_priv;
>  	struct i915_hw_context *ctx;
> +	struct i915_hw_context *cursor, *tmp;
>  	int ret;
> 
>  	if (args->ctx_id == DEFAULT_CONTEXT_ID) @@ -841,6 +850,10 @@ int
> i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
>  	}
> 
>  	idr_remove(&ctx->file_priv->context_idr, ctx->id);
> +	list_for_each_entry_safe(cursor, tmp, &ctx->dependent_contexts,
> dependent_contexts) {
> +		list_del(&cursor->dependent_contexts);
> +		i915_gem_context_unreference(cursor);
> +	}
>  	i915_gem_context_unreference(ctx);
>  	mutex_unlock(&dev->struct_mutex);
> 
> diff --git a/drivers/gpu/drm/i915/i915_lrc.c b/drivers/gpu/drm/i915/i915_lrc.c
> index 124e5f2..99011cc 100644
> --- a/drivers/gpu/drm/i915/i915_lrc.c
> +++ b/drivers/gpu/drm/i915/i915_lrc.c
> @@ -195,23 +195,54 @@ intel_populate_lrc(struct i915_hw_context *ctx,
>  	return 0;
>  }
> 
> +static void assert_on_ppgtt_release(struct kref *kref) {
> +	WARN(1, "Are we trying to free the aliasing PPGTT?\n"); }
> +
>  struct i915_hw_context *
>  gen8_gem_create_context(struct drm_device *dev,
>  			struct intel_engine *ring,
>  			struct drm_i915_file_private *file_priv,
> +			struct i915_hw_context *standalone_ctx,
>  			bool create_vm)
>  {
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  	struct i915_hw_context *ctx = NULL;
>  	struct drm_i915_gem_object *ring_obj = NULL;
>  	struct intel_ringbuffer *ringbuf = NULL;
> +	bool is_dependent;
>  	int ret;
> 
> -	ctx = i915_gem_create_context(dev, file_priv, create_vm);
> +	/* NB: a standalone context is the first context with a given id to be
> +	 * created for a new fd. Dependent contexts simply hang from the
> stand-alone,
> +	 * sharing their ID and their PPGTT */
> +	is_dependent = (file_priv != NULL) && (standalone_ctx != NULL);
> +
> +	ctx = i915_gem_create_context(dev, is_dependent? NULL : file_priv,
> +					is_dependent? false : create_vm);
>  	if (IS_ERR_OR_NULL(ctx))
>  		return ctx;
> 
> -	if (file_priv) {
> +	if (is_dependent) {
> +		struct i915_hw_ppgtt *ppgtt;
> +
> +		/* We take the same PPGTT as the standalone */
> +		ppgtt = ctx_to_ppgtt(ctx);
> +		kref_put(&ppgtt->ref, assert_on_ppgtt_release);
> +		ppgtt = ctx_to_ppgtt(standalone_ctx);
> +		ctx->vm = &ppgtt->base;
> +		kref_get(&ppgtt->ref);
> +
> +		ctx->file_priv = file_priv;
> +		ctx->id = standalone_ctx->id;
> +		ctx->remap_slice = standalone_ctx->remap_slice;
> +
> +		list_add_tail(&ctx->dependent_contexts,
> +				&standalone_ctx->dependent_contexts);
> +	}
> +
> +	if (file_priv && !is_dependent) {
>  		ret = i915_gem_obj_ggtt_pin(ctx->obj, GEN8_CONTEXT_ALIGN,
> 0);
>  		if (ret) {
>  			DRM_DEBUG_DRIVER("Couldn't pin %d\n", ret); @@ -
> 337,7 +368,7 @@ int gen8_gem_context_init(struct drm_device *dev)
> 
>  	for_each_ring(ring, dev_priv, ring_id) {
>  		ring->default_context = gen8_gem_create_context(dev, ring,
> -						NULL, (ring_id == RCS));
> +					NULL, NULL, (ring_id == RCS));
>  		if (IS_ERR_OR_NULL(ring->default_context)) {
>  			ret = PTR_ERR(ring->default_context);
>  			DRM_DEBUG_DRIVER("Create ctx failed: %d\n", ret);
> --
> 1.9.0




More information about the Intel-gfx mailing list