Re: [PATCH 31/49] drm/i915/bdw: Introduce dependent contexts

Mateo Lozano, Oscar
2014-03-27T17:27:31Z

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@lists.freedesktop.org
> Cc: Mateo Lozano, Oscar
> Subject: [PATCH 31/49] drm/i915/bdw: Introduce dependent contexts
>
> From: Oscar Mateo <oscar.mateo@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@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