[Intel-gfx] [PATCH v2 11/16] drm/i915/pxp: interface for creation of protected contexts

Chris Wilson chris at chris-wilson.co.uk
Wed Mar 3 23:16:51 UTC 2021


Quoting Daniele Ceraolo Spurio (2021-03-01 19:31:55)
> Usage of protected objects, coming in a follow-up patch, will be
> restricted to protected contexts. Contexts can only be marked as
> protected at creation time and they must be both bannable and not
> recoverable.
> 
> When a PXP teardown occurs, all gem contexts marked as protected that
> have been used at least once will be marked as invalid and all new
> submissions using them will be rejected. All intel contexts within the
> invalidated gem contexts will be marked banned.
> A new flag has been added to the RESET_STATS ioctl to report the
> invalidation to userspace.
> 
> v2: split to its own patch and improve doc (Chris), invalidate contexts
> on teardown
> 
> Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio at intel.com>
> Cc: Chris Wilson <chris at chris-wilson.co.uk>
> Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio at intel.com>
> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 59 ++++++++++++++++++-
>  drivers/gpu/drm/i915/gem/i915_gem_context.h   | 18 ++++++
>  .../gpu/drm/i915/gem/i915_gem_context_types.h |  2 +
>  .../gpu/drm/i915/gem/i915_gem_execbuffer.c    | 13 ++++
>  drivers/gpu/drm/i915/pxp/intel_pxp.c          | 38 ++++++++++++
>  drivers/gpu/drm/i915/pxp/intel_pxp.h          |  1 +
>  drivers/gpu/drm/i915/pxp/intel_pxp_session.c  |  3 +
>  include/uapi/drm/i915_drm.h                   | 19 ++++++
>  8 files changed, 150 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index ca37d93ef5e7..19ac24a3c42c 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -76,6 +76,8 @@
>  #include "gt/intel_gpu_commands.h"
>  #include "gt/intel_ring.h"
>  
> +#include "pxp/intel_pxp.h"
> +
>  #include "i915_drm_client.h"
>  #include "i915_gem_context.h"
>  #include "i915_globals.h"
> @@ -2006,6 +2008,40 @@ static int set_priority(struct i915_gem_context *ctx,
>         return 0;
>  }
>  
> +static int set_protected(struct i915_gem_context *ctx,
> +                        const struct drm_i915_gem_context_param *args)
> +{
> +       int ret = 0;
> +
> +       if (!intel_pxp_is_enabled(&ctx->i915->gt.pxp))
> +               ret = -ENODEV;
> +       else if (ctx->client) /* can't change this after creation! */
> +               ret = -EEXIST;
> +       else if (args->size)
> +               ret = -EINVAL;
> +       else if (!args->value)
> +               clear_bit(UCONTEXT_PROTECTED, &ctx->user_flags);
> +       else if (i915_gem_context_is_recoverable(ctx) ||
> +                !i915_gem_context_is_bannable(ctx))
> +               ret = -EPERM;
> +       else
> +               set_bit(UCONTEXT_PROTECTED, &ctx->user_flags);
> +
> +       return ret;
> +}
> +
> +static int get_protected(struct i915_gem_context *ctx,
> +                        struct drm_i915_gem_context_param *args)
> +{
> +       if (!intel_pxp_is_enabled(&ctx->i915->gt.pxp))
> +               return -ENODEV;
> +
> +       args->size = 0;
> +       args->value = i915_gem_context_can_use_protected_content(ctx);
> +
> +       return 0;
> +}
> +
>  static int ctx_setparam(struct drm_i915_file_private *fpriv,
>                         struct i915_gem_context *ctx,
>                         struct drm_i915_gem_context_param *args)
> @@ -2038,6 +2074,8 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
>                         ret = -EPERM;
>                 else if (args->value)
>                         i915_gem_context_set_bannable(ctx);
> +               else if (i915_gem_context_can_use_protected_content(ctx))
> +                       ret = -EPERM; /* can't clear this for protected contexts */
>                 else
>                         i915_gem_context_clear_bannable(ctx);
>                 break;
> @@ -2045,10 +2083,12 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
>         case I915_CONTEXT_PARAM_RECOVERABLE:
>                 if (args->size)
>                         ret = -EINVAL;
> -               else if (args->value)
> -                       i915_gem_context_set_recoverable(ctx);
> -               else
> +               else if (!args->value)
>                         i915_gem_context_clear_recoverable(ctx);
> +               else if (i915_gem_context_can_use_protected_content(ctx))
> +                       ret = -EPERM; /* can't set this for protected contexts */
> +               else
> +                       i915_gem_context_set_recoverable(ctx);
>                 break;
>  
>         case I915_CONTEXT_PARAM_PRIORITY:
> @@ -2075,6 +2115,10 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
>                 ret = set_ringsize(ctx, args);
>                 break;
>  
> +       case I915_CONTEXT_PARAM_PROTECTED_CONTENT:
> +               ret = set_protected(ctx, args);
> +               break;
> +
>         case I915_CONTEXT_PARAM_BAN_PERIOD:
>         default:
>                 ret = -EINVAL;
> @@ -2532,6 +2576,10 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
>                 ret = get_ringsize(ctx, args);
>                 break;
>  
> +       case I915_CONTEXT_PARAM_PROTECTED_CONTENT:
> +               ret = get_protected(ctx, args);
> +               break;
> +
>         case I915_CONTEXT_PARAM_BAN_PERIOD:
>         default:
>                 ret = -EINVAL;
> @@ -2592,6 +2640,11 @@ int i915_gem_context_reset_stats_ioctl(struct drm_device *dev,
>         args->batch_active = atomic_read(&ctx->guilty_count);
>         args->batch_pending = atomic_read(&ctx->active_count);
>  
> +       /* re-use args->flags for output flags */
> +       args->flags = 0;
> +       if (i915_gem_context_invalidated(ctx))
> +               args->flags |= I915_CONTEXT_INVALIDATED;
> +
>         ret = 0;
>  out:
>         rcu_read_unlock();
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.h b/drivers/gpu/drm/i915/gem/i915_gem_context.h
> index b5c908f3f4f2..b04d4eeb0500 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.h
> @@ -108,6 +108,24 @@ i915_gem_context_clear_user_engines(struct i915_gem_context *ctx)
>         clear_bit(CONTEXT_USER_ENGINES, &ctx->flags);
>  }
>  
> +static inline bool
> +i915_gem_context_invalidated(const struct i915_gem_context *ctx)
> +{
> +       return test_bit(CONTEXT_INVALID, &ctx->flags);
> +}
> +
> +static inline void
> +i915_gem_context_set_invalid(struct i915_gem_context *ctx)
> +{
> +       set_bit(CONTEXT_INVALID, &ctx->flags);
> +}
> +
> +static inline bool
> +i915_gem_context_can_use_protected_content(const struct i915_gem_context *ctx)
> +{
> +       return test_bit(UCONTEXT_PROTECTED, &ctx->user_flags);
> +}
> +
>  /* i915_gem_context.c */
>  void i915_gem_init__contexts(struct drm_i915_private *i915);
>  
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> index d5bc75508048..79a87268b8da 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> @@ -130,6 +130,7 @@ struct i915_gem_context {
>  #define UCONTEXT_BANNABLE              2
>  #define UCONTEXT_RECOVERABLE           3
>  #define UCONTEXT_PERSISTENCE           4
> +#define UCONTEXT_PROTECTED             5
>  
>         /**
>          * @flags: small set of booleans
> @@ -137,6 +138,7 @@ struct i915_gem_context {
>         unsigned long flags;
>  #define CONTEXT_CLOSED                 0
>  #define CONTEXT_USER_ENGINES           1
> +#define CONTEXT_INVALID                        2
>  
>         struct mutex mutex;
>  
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> index fe170186dd42..e503c9f789c0 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> @@ -21,6 +21,8 @@
>  #include "gt/intel_gt_pm.h"
>  #include "gt/intel_ring.h"
>  
> +#include "pxp/intel_pxp.h"
> +
>  #include "i915_drv.h"
>  #include "i915_gem_clflush.h"
>  #include "i915_gem_context.h"
> @@ -726,6 +728,11 @@ static int eb_select_context(struct i915_execbuffer *eb)
>         if (unlikely(!ctx))
>                 return -ENOENT;
>  
> +       if (i915_gem_context_invalidated(ctx)) {
> +               i915_gem_context_put(ctx);
> +               return -EIO;
> +       }
> +
>         eb->gem_context = ctx;
>         if (rcu_access_pointer(ctx->vm))
>                 eb->invalid_flags |= EXEC_OBJECT_NEEDS_GTT;
> @@ -2761,6 +2768,12 @@ eb_select_engine(struct i915_execbuffer *eb)
>  
>         intel_gt_pm_get(ce->engine->gt);
>  
> +       if (i915_gem_context_can_use_protected_content(eb->gem_context)) {
> +               err = intel_pxp_wait_for_termination_completion(&ce->engine->gt->pxp);
> +               if (err)
> +                       goto err;

This should check for context_invalidated

> +       }
> +
>         if (!test_bit(CONTEXT_ALLOC_BIT, &ce->flags)) {
>                 err = intel_context_alloc_state(ce);
>                 if (err)
> diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.c b/drivers/gpu/drm/i915/pxp/intel_pxp.c
> index 0ca1c2c16972..5912e4a12d94 100644
> --- a/drivers/gpu/drm/i915/pxp/intel_pxp.c
> +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.c
> @@ -6,6 +6,7 @@
>  #include "intel_pxp.h"
>  #include "intel_pxp_irq.h"
>  #include "intel_pxp_tee.h"
> +#include "gem/i915_gem_context.h"
>  #include "gt/intel_context.h"
>  #include "i915_drv.h"
>  
> @@ -135,3 +136,40 @@ int intel_pxp_wait_for_termination_completion(struct intel_pxp *pxp)
>         return ret;
>  }
>  
> +void intel_pxp_invalidate(struct intel_pxp *pxp)
> +{
> +       struct drm_i915_private *i915 = pxp_to_gt(pxp)->i915;
> +       struct i915_gem_context *ctx, *cn;
> +
> +       /* ban all contexts marked as protected */
> +       spin_lock_irq(&i915->gem.contexts.lock);
> +       list_for_each_entry_safe(ctx, cn, &i915->gem.contexts.list, link) {
> +               struct i915_gem_engines_iter it;
> +               struct intel_context *ce;
> +
> +               if (!kref_get_unless_zero(&ctx->ref))
> +                       continue;
> +
> +               if (likely(!i915_gem_context_can_use_protected_content(ctx)))
> +                       continue;
> +
> +               if (i915_gem_context_invalidated(ctx))
> +                       continue;
> +
> +               spin_unlock_irq(&i915->gem.contexts.lock);
> +
> +               for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) {

> +                       if (test_bit(CONTEXT_ALLOC_BIT, &ce->flags)) {
> +                               intel_context_set_banned(ce);

That's a pair of unserialised operations. However, you can just set
banned before we even try to alloc. But at the moment, it's very
spurious to call intel_context_set_banned() as no action is performed to
flush the ban to the backend, and execbuf is primarily checking the GEM
context invalid bit. It looks a bit flimsy...

The impact of this loop would be to cancel all pending requests (but not
the inflight request), sounds like you should just call revoke_context
to remove the inflight context and pending requests from the HW.

> +                               i915_gem_context_set_invalid(ctx);
> +                       }
> +               }
> +               i915_gem_context_unlock_engines(ctx);
> +
> +               spin_lock_irq(&i915->gem.contexts.lock);
> +               list_safe_reset_next(ctx, cn, link);
> +               i915_gem_context_put(ctx);
> +       }
> +       spin_unlock_irq(&i915->gem.contexts.lock);

And then there's a race condition where we can create a new protect
context, submit an execbuf using the global session between the call to
intel_pxp_invalidate and terminate_session_and_global. That's covered by
irq_handler calling mark_termination_in_progress and execbuf waiting
for that termination to complete. Almost.

This will result in userspace context lost upon runtime suspend? That
can be quite catastrophic for the system...

> +}
> +
> diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.h b/drivers/gpu/drm/i915/pxp/intel_pxp.h
> index 89cf66c9bef3..e36200833095 100644
> --- a/drivers/gpu/drm/i915/pxp/intel_pxp.h
> +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.h
> @@ -38,6 +38,7 @@ void intel_pxp_init(struct intel_pxp *pxp);
>  void intel_pxp_fini(struct intel_pxp *pxp);
>  
>  int intel_pxp_wait_for_termination_completion(struct intel_pxp *pxp);
> +void intel_pxp_invalidate(struct intel_pxp *pxp);
>  #else
>  static inline void intel_pxp_init(struct intel_pxp *pxp)
>  {
> diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c
> index bb981d38c2fe..527217b3db23 100644
> --- a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c
> +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c
> @@ -111,6 +111,9 @@ int intel_pxp_arb_terminate_session_with_global_terminate(struct intel_pxp *pxp)
>  
>         lockdep_assert_held(&pxp->mutex);
>  
> +       /* invalidate protected objects */
> +       intel_pxp_invalidate(pxp);
> +
>         /* terminate the hw sessions */
>         ret = intel_pxp_submit_session_termination(pxp, ARB_SESSION);
>         if (ret) {
> diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
> index 56c6bfe6c2d0..0f5456046c4c 100644
> --- a/include/uapi/drm/i915_drm.h
> +++ b/include/uapi/drm/i915_drm.h
> @@ -1694,6 +1694,24 @@ struct drm_i915_gem_context_param {
>   * Default is 16 KiB.
>   */
>  #define I915_CONTEXT_PARAM_RINGSIZE    0xc
> +
> +/*
> + * I915_CONTEXT_PARAM_PROTECTED_CONTENT:
> + *
> + * Enable usage of protected content with the context. This flag can only be
> + * set at context creation time and, when set to true, must be preceded by
> + * an explicit setting of I915_CONTEXT_PARAM_RECOVERABLE to false. This flag
> + * can't be set to true in conjunction with setting the
> + * I915_CONTEXT_PARAM_BANNABLE flag to false.

I haven't seen any interaction with bannable here. Since you just ignore
the bannable flag.

> + *
> + * Given the numerous restriction on this flag, there are several unique 
> + * failure cases:
> + *
> + * -ENODEV: feature not available
> + * -EEXIST: trying to modify an existing context
> + * -EPERM: trying to mark a recoverable or not bannable context as protected

Also -EIO from execbuf. Do we want to pick EACCES?

> + */
> +#define I915_CONTEXT_PARAM_PROTECTED_CONTENT    0xd
>  /* Must be kept compact -- no holes and well documented */
>  
>         __u64 value;
> @@ -1924,6 +1942,7 @@ struct drm_i915_reg_read {
>  struct drm_i915_reset_stats {
>         __u32 ctx_id;
>         __u32 flags;
> +#define I915_CONTEXT_INVALIDATED 0x1

Mention the side effect for protected content contexts.

>  
>         /* All resets since boot/module reload, for all contexts */
>         __u32 reset_count;
> -- 
> 2.29.2
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
>


More information about the Intel-gfx mailing list