summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/i915/Kconfig.debug17
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_context.c113
-rw-r--r--drivers/gpu/drm/i915/gt/intel_context.c2
-rw-r--r--drivers/gpu/drm/i915/gt/intel_context.h22
-rw-r--r--drivers/gpu/drm/i915/gt/intel_context_types.h1
-rw-r--r--drivers/gpu/drm/i915/gt/intel_lrc.c3
-rw-r--r--drivers/gpu/drm/i915/gt/intel_ring_submission.c3
-rw-r--r--drivers/gpu/drm/i915/i915_params.c5
-rw-r--r--drivers/gpu/drm/i915/i915_params.h3
9 files changed, 166 insertions, 3 deletions
diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kconfig.debug
index d8397065c3f0..1852e0804942 100644
--- a/drivers/gpu/drm/i915/Kconfig.debug
+++ b/drivers/gpu/drm/i915/Kconfig.debug
@@ -16,6 +16,23 @@ config DRM_I915_WERROR
If in doubt, say "N".
+config DRM_I915_REPLAY_GPU_HANGS_API
+ bool "Enable GPU hang replay userspace API"
+ depends on DRM_I915
+ depends on EXPERT
+ default n
+ help
+ Choose this option if you want to enable special and unstable
+ userspace API used for replaying GPU hangs on a running system.
+
+ This API is intended to be used by userspace graphics stack developers
+ and provides no stability guarantees.
+
+ The API needs to be activated at boot time using the
+ enable_debug_only_api module parameter.
+
+ If in doubt, say "N".
+
config DRM_I915_DEBUG
bool "Enable additional driver debugging"
depends on DRM_I915
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 81f65cab1330..c0543c35cd6a 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -78,6 +78,7 @@
#include "gt/intel_engine_user.h"
#include "gt/intel_gpu_commands.h"
#include "gt/intel_ring.h"
+#include "gt/shmem_utils.h"
#include "pxp/intel_pxp.h"
@@ -957,6 +958,7 @@ static int set_proto_ctx_param(struct drm_i915_file_private *fpriv,
case I915_CONTEXT_PARAM_NO_ZEROMAP:
case I915_CONTEXT_PARAM_BAN_PERIOD:
case I915_CONTEXT_PARAM_RINGSIZE:
+ case I915_CONTEXT_PARAM_CONTEXT_IMAGE:
default:
ret = -EINVAL;
break;
@@ -2104,6 +2106,95 @@ static int get_protected(struct i915_gem_context *ctx,
return 0;
}
+static int set_context_image(struct i915_gem_context *ctx,
+ struct drm_i915_gem_context_param *args)
+{
+ struct i915_gem_context_param_context_image user;
+ struct intel_context *ce;
+ struct file *shmem_state;
+ unsigned long lookup;
+ void *state;
+ int ret = 0;
+
+ if (!IS_ENABLED(CONFIG_DRM_I915_REPLAY_GPU_HANGS_API))
+ return -EINVAL;
+
+ if (!ctx->i915->params.enable_debug_only_api)
+ return -EINVAL;
+
+ if (args->size < sizeof(user))
+ return -EINVAL;
+
+ if (copy_from_user(&user, u64_to_user_ptr(args->value), sizeof(user)))
+ return -EFAULT;
+
+ if (user.mbz)
+ return -EINVAL;
+
+ if (user.flags & ~(I915_CONTEXT_IMAGE_FLAG_ENGINE_INDEX))
+ return -EINVAL;
+
+ lookup = 0;
+ if (user.flags & I915_CONTEXT_IMAGE_FLAG_ENGINE_INDEX)
+ lookup |= LOOKUP_USER_INDEX;
+
+ ce = lookup_user_engine(ctx, lookup, &user.engine);
+ if (IS_ERR(ce))
+ return PTR_ERR(ce);
+
+ if (user.size < ce->engine->context_size) {
+ ret = -EINVAL;
+ goto out_ce;
+ }
+
+ if (drm_WARN_ON_ONCE(&ctx->i915->drm,
+ test_bit(CONTEXT_ALLOC_BIT, &ce->flags))) {
+ /*
+ * This is racy but for a debug only API, if userspace is keen
+ * to create and configure contexts, while simultaneously using
+ * them from a second thread, let them suffer by potentially not
+ * executing with the context image they just raced to apply.
+ */
+ ret = -EBUSY;
+ goto out_ce;
+ }
+
+ state = kmalloc(ce->engine->context_size, GFP_KERNEL);
+ if (!state) {
+ ret = -ENOMEM;
+ goto out_ce;
+ }
+
+ if (copy_from_user(state, u64_to_user_ptr(user.image),
+ ce->engine->context_size)) {
+ ret = -EFAULT;
+ goto out_state;
+ }
+
+ shmem_state = shmem_create_from_data(ce->engine->name,
+ state, ce->engine->context_size);
+ if (IS_ERR(shmem_state)) {
+ ret = PTR_ERR(shmem_state);
+ goto out_state;
+ }
+
+ if (intel_context_set_own_state(ce)) {
+ ret = -EBUSY;
+ fput(shmem_state);
+ goto out_state;
+ }
+
+ ce->default_state = shmem_state;
+
+ args->size = sizeof(user);
+
+out_state:
+ kfree(state);
+out_ce:
+ intel_context_put(ce);
+ return ret;
+}
+
static int ctx_setparam(struct drm_i915_file_private *fpriv,
struct i915_gem_context *ctx,
struct drm_i915_gem_context_param *args)
@@ -2156,6 +2247,10 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
ret = set_persistence(ctx, args);
break;
+ case I915_CONTEXT_PARAM_CONTEXT_IMAGE:
+ ret = set_context_image(ctx, args);
+ break;
+
case I915_CONTEXT_PARAM_PROTECTED_CONTENT:
case I915_CONTEXT_PARAM_NO_ZEROMAP:
case I915_CONTEXT_PARAM_BAN_PERIOD:
@@ -2500,6 +2595,7 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
case I915_CONTEXT_PARAM_BAN_PERIOD:
case I915_CONTEXT_PARAM_ENGINES:
case I915_CONTEXT_PARAM_RINGSIZE:
+ case I915_CONTEXT_PARAM_CONTEXT_IMAGE:
default:
ret = -EINVAL;
break;
@@ -2612,5 +2708,22 @@ int __init i915_gem_context_module_init(void)
if (!slab_luts)
return -ENOMEM;
+ if (IS_ENABLED(CONFIG_DRM_I915_REPLAY_GPU_HANGS_API)) {
+ pr_notice("**************************************************************\n");
+ pr_notice("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n");
+ pr_notice("** **\n");
+ if (i915_modparams.enable_debug_only_api)
+ pr_notice("** i915.enable_debug_only_api is intended to be set **\n");
+ else
+ pr_notice("** CONFIG_DRM_I915_REPLAY_GPU_HANGS_API builds are intended **\n");
+ pr_notice("** for specific userspace graphics stack developers only! **\n");
+ pr_notice("** **\n");
+ pr_notice("** If you are seeing this message please report this to the **\n");
+ pr_notice("** provider of your kernel build. **\n");
+ pr_notice("** **\n");
+ pr_notice("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n");
+ pr_notice("**************************************************************\n");
+ }
+
return 0;
}
diff --git a/drivers/gpu/drm/i915/gt/intel_context.c b/drivers/gpu/drm/i915/gt/intel_context.c
index a2f1245741bb..b1b8695ba7c9 100644
--- a/drivers/gpu/drm/i915/gt/intel_context.c
+++ b/drivers/gpu/drm/i915/gt/intel_context.c
@@ -27,6 +27,8 @@ static void rcu_context_free(struct rcu_head *rcu)
struct intel_context *ce = container_of(rcu, typeof(*ce), rcu);
trace_intel_context_free(ce);
+ if (intel_context_has_own_state(ce))
+ fput(ce->default_state);
kmem_cache_free(slab_ce, ce);
}
diff --git a/drivers/gpu/drm/i915/gt/intel_context.h b/drivers/gpu/drm/i915/gt/intel_context.h
index 25564c01507e..9f523999acd1 100644
--- a/drivers/gpu/drm/i915/gt/intel_context.h
+++ b/drivers/gpu/drm/i915/gt/intel_context.h
@@ -375,6 +375,28 @@ intel_context_clear_nopreempt(struct intel_context *ce)
clear_bit(CONTEXT_NOPREEMPT, &ce->flags);
}
+#if IS_ENABLED(CONFIG_DRM_I915_REPLAY_GPU_HANGS_API)
+static inline bool intel_context_has_own_state(const struct intel_context *ce)
+{
+ return test_bit(CONTEXT_OWN_STATE, &ce->flags);
+}
+
+static inline bool intel_context_set_own_state(struct intel_context *ce)
+{
+ return test_and_set_bit(CONTEXT_OWN_STATE, &ce->flags);
+}
+#else
+static inline bool intel_context_has_own_state(const struct intel_context *ce)
+{
+ return false;
+}
+
+static inline bool intel_context_set_own_state(struct intel_context *ce)
+{
+ return true;
+}
+#endif
+
u64 intel_context_get_total_runtime_ns(struct intel_context *ce);
u64 intel_context_get_avg_runtime_ns(struct intel_context *ce);
diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h
index 6ae8abfeccdb..98c7f6052069 100644
--- a/drivers/gpu/drm/i915/gt/intel_context_types.h
+++ b/drivers/gpu/drm/i915/gt/intel_context_types.h
@@ -133,6 +133,7 @@ struct intel_context {
#define CONTEXT_IS_PARKING 12
#define CONTEXT_EXITING 13
#define CONTEXT_LOW_LATENCY 14
+#define CONTEXT_OWN_STATE 15
struct {
u64 timeout_us;
diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c
index d4ffb352403c..7bd5d2c29056 100644
--- a/drivers/gpu/drm/i915/gt/intel_lrc.c
+++ b/drivers/gpu/drm/i915/gt/intel_lrc.c
@@ -1130,7 +1130,8 @@ int lrc_alloc(struct intel_context *ce, struct intel_engine_cs *engine)
GEM_BUG_ON(ce->state);
- ce->default_state = engine->default_state;
+ if (!intel_context_has_own_state(ce))
+ ce->default_state = engine->default_state;
vma = __lrc_alloc_state(ce, engine);
if (IS_ERR(vma))
diff --git a/drivers/gpu/drm/i915/gt/intel_ring_submission.c b/drivers/gpu/drm/i915/gt/intel_ring_submission.c
index 8625e88e785f..72277bc8322e 100644
--- a/drivers/gpu/drm/i915/gt/intel_ring_submission.c
+++ b/drivers/gpu/drm/i915/gt/intel_ring_submission.c
@@ -569,7 +569,8 @@ static int ring_context_alloc(struct intel_context *ce)
{
struct intel_engine_cs *engine = ce->engine;
- ce->default_state = engine->default_state;
+ if (!intel_context_has_own_state(ce))
+ ce->default_state = engine->default_state;
/* One ringbuffer to rule them all */
GEM_BUG_ON(!engine->legacy.ring);
diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
index 8c00169e3ab7..316e55f3e87b 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -131,6 +131,11 @@ i915_param_named_unsafe(lmem_size, uint, 0400,
i915_param_named_unsafe(lmem_bar_size, uint, 0400,
"Set the lmem bar size(in MiB).");
+#if IS_ENABLED(CONFIG_DRM_I915_REPLAY_GPU_HANGS_API)
+i915_param_named(enable_debug_only_api, bool, 0400,
+ "Enable support for unstable debug only userspace API. (default:false)");
+#endif
+
static void _param_print_bool(struct drm_printer *p, const char *name,
bool val)
{
diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h
index 2eb3f2115ff2..0fbcb5b6d7bf 100644
--- a/drivers/gpu/drm/i915/i915_params.h
+++ b/drivers/gpu/drm/i915/i915_params.h
@@ -63,7 +63,8 @@ struct drm_printer;
/* leave bools at the end to not create holes */ \
param(bool, enable_hangcheck, true, 0600) \
param(bool, error_capture, true, IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) ? 0600 : 0) \
- param(bool, enable_gvt, false, IS_ENABLED(CONFIG_DRM_I915_GVT) ? 0400 : 0)
+ param(bool, enable_gvt, false, IS_ENABLED(CONFIG_DRM_I915_GVT) ? 0400 : 0) \
+ param(bool, enable_debug_only_api, false, IS_ENABLED(CONFIG_DRM_I915_REPLAY_GPU_HANGS_API) ? 0400 : 0)
#define MEMBER(T, member, ...) T member;
struct i915_params {