Skip to content

Commit

Permalink
drm/i915/pxp: interfaces for using protected objects
Browse files Browse the repository at this point in the history
This api allow user mode to create protected buffers and to mark
contexts as making use of such objects. Only when using contexts
marked in such a way is the execution guaranteed to work as expected.

Contexts can only be marked as using protected content at creation time
(i.e. the parameter is immutable) and they must be both bannable and not
recoverable. Given that the protected session gets invalidated on
suspend, contexts created this way hold a runtime pm wakeref until
they're either destroyed or invalidated.

All protected objects and contexts will be considered invalid when the
PXP session is destroyed and all new submissions using them will be
rejected. All intel contexts within the invalidated gem contexts will be
marked banned. Userspace can detect that an invalidation has occurred via
the RESET_STATS ioctl, where we report it the same way as a ban due to a
hang.

v5: squash patches, rebase on proto_ctx, update kerneldoc

v6: rebase on obj create_ext changes

v7: Use session counter to check if an object it valid, hold wakeref in
    context, don't add a new flag to RESET_STATS (Daniel)

v8: don't increase guilty count for contexts banned during pxp
    invalidation (Rodrigo)

v9: better comments, avoid wakeref put race between pxp_inval and
    context_close, add usage examples (Rodrigo)

v10: modify internal set/get-protected-context functions to not
     return -ENODEV when setting PXP param to false or getting param
     when running on pxp-unsupported hw or getting param when i915
     was built with CONFIG_PXP off

Signed-off-by: Alan Previn <[email protected]>
Signed-off-by: Daniele Ceraolo Spurio <[email protected]>
Signed-off-by: Bommu Krishnaiah <[email protected]>
Cc: Rodrigo Vivi <[email protected]>
Cc: Chris Wilson <[email protected]>
Cc: Lionel Landwerlin <[email protected]>
Cc: Jason Ekstrand <[email protected]>
Cc: Daniel Vetter <[email protected]>
Reviewed-by: Rodrigo Vivi <[email protected]>
Signed-off-by: Rodrigo Vivi <[email protected]>
Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
  • Loading branch information
dceraolo authored and rodrigovivi committed Oct 4, 2021
1 parent 2ae0968 commit d3ac8d4
Show file tree
Hide file tree
Showing 14 changed files with 402 additions and 35 deletions.
95 changes: 81 additions & 14 deletions drivers/gpu/drm/i915/gem/i915_gem_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@
#include "gt/intel_gpu_commands.h"
#include "gt/intel_ring.h"

#include "pxp/intel_pxp.h"

#include "i915_gem_context.h"
#include "i915_trace.h"
#include "i915_user_extensions.h"
Expand Down Expand Up @@ -186,10 +188,13 @@ static int validate_priority(struct drm_i915_private *i915,
return 0;
}

static void proto_context_close(struct i915_gem_proto_context *pc)
static void proto_context_close(struct drm_i915_private *i915,
struct i915_gem_proto_context *pc)
{
int i;

if (pc->pxp_wakeref)
intel_runtime_pm_put(&i915->runtime_pm, pc->pxp_wakeref);
if (pc->vm)
i915_vm_put(pc->vm);
if (pc->user_engines) {
Expand Down Expand Up @@ -241,6 +246,33 @@ static int proto_context_set_persistence(struct drm_i915_private *i915,
return 0;
}

static int proto_context_set_protected(struct drm_i915_private *i915,
struct i915_gem_proto_context *pc,
bool protected)
{
int ret = 0;

if (!protected) {
pc->uses_protected_content = false;
} else if (!intel_pxp_is_enabled(&i915->gt.pxp)) {
ret = -ENODEV;
} else if ((pc->user_flags & BIT(UCONTEXT_RECOVERABLE)) ||
!(pc->user_flags & BIT(UCONTEXT_BANNABLE))) {
ret = -EPERM;
} else {
pc->uses_protected_content = true;

/*
* protected context usage requires the PXP session to be up,
* which in turn requires the device to be active.
*/
pc->pxp_wakeref = intel_runtime_pm_get(&i915->runtime_pm);
ret = intel_pxp_wait_for_arb_start(&i915->gt.pxp);
}

return ret;
}

static struct i915_gem_proto_context *
proto_context_create(struct drm_i915_private *i915, unsigned int flags)
{
Expand Down Expand Up @@ -269,7 +301,7 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
return pc;

proto_close:
proto_context_close(pc);
proto_context_close(i915, pc);
return err;
}

Expand Down Expand Up @@ -693,17 +725,21 @@ static int set_proto_ctx_param(struct drm_i915_file_private *fpriv,
ret = -EPERM;
else if (args->value)
pc->user_flags |= BIT(UCONTEXT_BANNABLE);
else if (pc->uses_protected_content)
ret = -EPERM;
else
pc->user_flags &= ~BIT(UCONTEXT_BANNABLE);
break;

case I915_CONTEXT_PARAM_RECOVERABLE:
if (args->size)
ret = -EINVAL;
else if (args->value)
pc->user_flags |= BIT(UCONTEXT_RECOVERABLE);
else
else if (!args->value)
pc->user_flags &= ~BIT(UCONTEXT_RECOVERABLE);
else if (pc->uses_protected_content)
ret = -EPERM;
else
pc->user_flags |= BIT(UCONTEXT_RECOVERABLE);
break;

case I915_CONTEXT_PARAM_PRIORITY:
Expand Down Expand Up @@ -731,6 +767,11 @@ static int set_proto_ctx_param(struct drm_i915_file_private *fpriv,
args->value);
break;

case I915_CONTEXT_PARAM_PROTECTED_CONTENT:
ret = proto_context_set_protected(fpriv->dev_priv, pc,
args->value);
break;

case I915_CONTEXT_PARAM_NO_ZEROMAP:
case I915_CONTEXT_PARAM_BAN_PERIOD:
case I915_CONTEXT_PARAM_RINGSIZE:
Expand Down Expand Up @@ -956,6 +997,9 @@ static void i915_gem_context_release_work(struct work_struct *work)
if (vm)
i915_vm_put(vm);

if (ctx->pxp_wakeref)
intel_runtime_pm_put(&ctx->i915->runtime_pm, ctx->pxp_wakeref);

mutex_destroy(&ctx->engines_mutex);
mutex_destroy(&ctx->lut_mutex);

Expand Down Expand Up @@ -1338,6 +1382,11 @@ i915_gem_create_context(struct drm_i915_private *i915,
goto err_engines;
}

if (pc->uses_protected_content) {
ctx->pxp_wakeref = intel_runtime_pm_get(&i915->runtime_pm);
ctx->uses_protected_content = true;
}

trace_i915_context_create(ctx);

return ctx;
Expand Down Expand Up @@ -1409,7 +1458,7 @@ int i915_gem_context_open(struct drm_i915_private *i915,
}

ctx = i915_gem_create_context(i915, pc);
proto_context_close(pc);
proto_context_close(i915, pc);
if (IS_ERR(ctx)) {
err = PTR_ERR(ctx);
goto err;
Expand All @@ -1436,7 +1485,7 @@ void i915_gem_context_close(struct drm_file *file)
unsigned long idx;

xa_for_each(&file_priv->proto_context_xa, idx, pc)
proto_context_close(pc);
proto_context_close(file_priv->dev_priv, pc);
xa_destroy(&file_priv->proto_context_xa);
mutex_destroy(&file_priv->proto_context_lock);

Expand Down Expand Up @@ -1731,6 +1780,15 @@ static int set_priority(struct i915_gem_context *ctx,
return 0;
}

static int get_protected(struct i915_gem_context *ctx,
struct drm_i915_gem_context_param *args)
{
args->size = 0;
args->value = i915_gem_context_uses_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)
Expand All @@ -1754,17 +1812,21 @@ 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_uses_protected_content(ctx))
ret = -EPERM; /* can't clear this for protected contexts */
else
i915_gem_context_clear_bannable(ctx);
break;

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_uses_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:
Expand All @@ -1779,6 +1841,7 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
ret = set_persistence(ctx, args);
break;

case I915_CONTEXT_PARAM_PROTECTED_CONTENT:
case I915_CONTEXT_PARAM_NO_ZEROMAP:
case I915_CONTEXT_PARAM_BAN_PERIOD:
case I915_CONTEXT_PARAM_RINGSIZE:
Expand Down Expand Up @@ -1857,7 +1920,7 @@ finalize_create_context_locked(struct drm_i915_file_private *file_priv,

old = xa_erase(&file_priv->proto_context_xa, id);
GEM_BUG_ON(old != pc);
proto_context_close(pc);
proto_context_close(file_priv->dev_priv, pc);

/* One for the xarray and one for the caller */
return i915_gem_context_get(ctx);
Expand Down Expand Up @@ -1943,7 +2006,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
goto err_pc;
}

proto_context_close(ext_data.pc);
proto_context_close(i915, ext_data.pc);
gem_context_register(ctx, ext_data.fpriv, id);
} else {
ret = proto_context_register(ext_data.fpriv, ext_data.pc, &id);
Expand All @@ -1957,7 +2020,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
return 0;

err_pc:
proto_context_close(ext_data.pc);
proto_context_close(i915, ext_data.pc);
return ret;
}

Expand Down Expand Up @@ -1988,7 +2051,7 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
GEM_WARN_ON(ctx && pc);

if (pc)
proto_context_close(pc);
proto_context_close(file_priv->dev_priv, pc);

if (ctx)
context_close(ctx);
Expand Down Expand Up @@ -2106,6 +2169,10 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
args->value = i915_gem_context_is_persistent(ctx);
break;

case I915_CONTEXT_PARAM_PROTECTED_CONTENT:
ret = get_protected(ctx, args);
break;

case I915_CONTEXT_PARAM_NO_ZEROMAP:
case I915_CONTEXT_PARAM_BAN_PERIOD:
case I915_CONTEXT_PARAM_ENGINES:
Expand Down
6 changes: 6 additions & 0 deletions drivers/gpu/drm/i915/gem/i915_gem_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ i915_gem_context_clear_user_engines(struct i915_gem_context *ctx)
clear_bit(CONTEXT_USER_ENGINES, &ctx->flags);
}

static inline bool
i915_gem_context_uses_protected_content(const struct i915_gem_context *ctx)
{
return ctx->uses_protected_content;
}

/* i915_gem_context.c */
void i915_gem_init__contexts(struct drm_i915_private *i915);

Expand Down
28 changes: 28 additions & 0 deletions drivers/gpu/drm/i915/gem/i915_gem_context_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,12 @@ struct i915_gem_proto_context {

/** @single_timeline: See See &i915_gem_context.syncobj */
bool single_timeline;

/** @uses_protected_content: See &i915_gem_context.uses_protected_content */
bool uses_protected_content;

/** @pxp_wakeref: See &i915_gem_context.pxp_wakeref */
intel_wakeref_t pxp_wakeref;
};

/**
Expand Down Expand Up @@ -321,6 +327,28 @@ struct i915_gem_context {
#define CONTEXT_CLOSED 0
#define CONTEXT_USER_ENGINES 1

/**
* @uses_protected_content: context uses PXP-encrypted objects.
*
* This flag can only be set at ctx creation time and it's immutable for
* the lifetime of the context. See I915_CONTEXT_PARAM_PROTECTED_CONTENT
* in uapi/drm/i915_drm.h for more info on setting restrictions and
* expected behaviour of marked contexts.
*/
bool uses_protected_content;

/**
* @pxp_wakeref: wakeref to keep the device awake when PXP is in use
*
* PXP sessions are invalidated when the device is suspended, which in
* turns invalidates all contexts and objects using it. To keep the
* flow simple, we keep the device awake when contexts using PXP objects
* are in use. It is expected that the userspace application only uses
* PXP when the display is on, so taking a wakeref here shouldn't worsen
* our power metrics.
*/
intel_wakeref_t pxp_wakeref;

/** @mutex: guards everything that isn't engines or handles_vma */
struct mutex mutex;

Expand Down
Loading

0 comments on commit d3ac8d4

Please sign in to comment.