@@ -748,6 +748,35 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
return 0;
}
+static int
+i915_gem_sseu_from_user_sseu(const struct sseu_dev_info *sseu,
+ const struct drm_i915_gem_context_param_sseu *user_sseu,
+ union i915_gem_sseu *ctx_sseu)
+{
+ if ((user_sseu->slice_mask & ~sseu->slice_mask) != 0 ||
+ user_sseu->slice_mask == 0)
+ return -EINVAL;
+
+ if ((user_sseu->subslice_mask & ~sseu->subslice_mask[0]) != 0 ||
+ user_sseu->subslice_mask == 0)
+ return -EINVAL;
+
+ if (user_sseu->min_eus_per_subslice > sseu->max_eus_per_subslice)
+ return -EINVAL;
+
+ if (user_sseu->max_eus_per_subslice > sseu->max_eus_per_subslice ||
+ user_sseu->max_eus_per_subslice < user_sseu->min_eus_per_subslice ||
+ user_sseu->max_eus_per_subslice == 0)
+ return -EINVAL;
+
+ ctx_sseu->slice_mask = user_sseu->slice_mask;
+ ctx_sseu->subslice_mask = user_sseu->subslice_mask;
+ ctx_sseu->min_eus_per_subslice = user_sseu->min_eus_per_subslice;
+ ctx_sseu->max_eus_per_subslice = user_sseu->max_eus_per_subslice;
+
+ return 0;
+}
+
int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
struct drm_file *file)
{
@@ -785,6 +814,37 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
case I915_CONTEXT_PARAM_PRIORITY:
args->value = ctx->sched.priority;
break;
+ case I915_CONTEXT_PARAM_SSEU: {
+ struct drm_i915_gem_context_param_sseu param_sseu;
+ struct intel_engine_cs *engine;
+ struct intel_context *ce;
+
+ if (copy_from_user(¶m_sseu, u64_to_user_ptr(args->value),
+ sizeof(param_sseu))) {
+ ret = -EFAULT;
+ break;
+ }
+
+ engine = intel_engine_lookup_user(to_i915(dev),
+ param_sseu.class,
+ param_sseu.instance);
+ if (!engine) {
+ ret = -EINVAL;
+ break;
+ }
+
+ ce = &ctx->__engine[engine->id];
+
+ param_sseu.slice_mask = ce->sseu.slice_mask;
+ param_sseu.subslice_mask = ce->sseu.subslice_mask;
+ param_sseu.min_eus_per_subslice = ce->sseu.min_eus_per_subslice;
+ param_sseu.max_eus_per_subslice = ce->sseu.max_eus_per_subslice;
+
+ if (copy_to_user(u64_to_user_ptr(args->value), ¶m_sseu,
+ sizeof(param_sseu)))
+ ret = -EFAULT;
+ break;
+ }
default:
ret = -EINVAL;
break;
@@ -840,7 +900,6 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
else
i915_gem_context_clear_bannable(ctx);
break;
-
case I915_CONTEXT_PARAM_PRIORITY:
{
s64 priority = args->value;
@@ -859,7 +918,40 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
ctx->sched.priority = priority;
}
break;
+ case I915_CONTEXT_PARAM_SSEU:
+ if (args->size) {
+ ret = -EINVAL;
+ } else if (!HAS_EXECLISTS(ctx->i915)) {
+ ret = -ENODEV;
+ } else {
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ struct drm_i915_gem_context_param_sseu user_sseu;
+ union i915_gem_sseu ctx_sseu;
+ struct intel_engine_cs *engine;
+
+ if (copy_from_user(&user_sseu, u64_to_user_ptr(args->value),
+ sizeof(user_sseu))) {
+ ret = -EFAULT;
+ break;
+ }
+
+ engine = intel_engine_lookup_user(dev_priv,
+ user_sseu.class,
+ user_sseu.instance);
+ if (!engine) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = i915_gem_sseu_from_user_sseu(
+ &INTEL_INFO(dev_priv)->sseu,
+ &user_sseu, &ctx_sseu);
+ if (ret)
+ break;
+
+ ret = intel_lr_context_set_sseu(ctx, engine, ctx_sseu);
+ }
+ break;
default:
ret = -EINVAL;
break;
@@ -2757,6 +2757,61 @@ void intel_lr_context_resume(struct drm_i915_private *dev_priv)
}
}
+int intel_lr_context_set_sseu(struct i915_gem_context *ctx,
+ struct intel_engine_cs *engine,
+ union i915_gem_sseu sseu)
+{
+ struct drm_i915_private *dev_priv = ctx->i915;
+ struct intel_context *ce;
+ enum intel_engine_id id;
+ int ret;
+
+ lockdep_assert_held(&dev_priv->drm.struct_mutex);
+
+ if (ctx->__engine[engine->id].sseu.value == sseu.value)
+ return 0;
+
+ /*
+ * We can only program this on render ring.
+ */
+ ce = &ctx->__engine[RCS];
+
+ if (ce->pin_count) { /* Assume that the context is active! */
+ ret = i915_gem_switch_to_kernel_context(dev_priv);
+ if (ret)
+ return ret;
+
+ ret = i915_gem_wait_for_idle(dev_priv,
+ I915_WAIT_INTERRUPTIBLE |
+ I915_WAIT_LOCKED);
+ if (ret)
+ return ret;
+ }
+
+ if (ce->state) {
+ void *vaddr = i915_gem_object_pin_map(ce->state->obj, I915_MAP_WB);
+ u32 *regs;
+
+ if (IS_ERR(vaddr))
+ return PTR_ERR(vaddr);
+
+ regs = vaddr + LRC_STATE_PN * PAGE_SIZE;
+
+ regs[CTX_R_PWR_CLK_STATE + 1] =
+ make_rpcs(&INTEL_INFO(dev_priv)->sseu, sseu);
+ i915_gem_object_unpin_map(ce->state->obj);
+ }
+
+ /*
+ * Apply the configuration to all engine. Our hardware doesn't
+ * currently support different configurations for each engine.
+ */
+ for_each_engine(engine, dev_priv, id)
+ ctx->__engine[id].sseu.value = sseu.value;
+
+ return 0;
+}
+
#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
#include "selftests/intel_lrc.c"
#endif
@@ -111,4 +111,8 @@ intel_lr_context_descriptor(struct i915_gem_context *ctx,
return to_intel_context(ctx, engine)->lrc_desc;
}
+int intel_lr_context_set_sseu(struct i915_gem_context *ctx,
+ struct intel_engine_cs *engine,
+ union i915_gem_sseu sseu);
+
#endif /* _INTEL_LRC_H_ */
@@ -1456,9 +1456,47 @@ struct drm_i915_gem_context_param {
#define I915_CONTEXT_MAX_USER_PRIORITY 1023 /* inclusive */
#define I915_CONTEXT_DEFAULT_PRIORITY 0
#define I915_CONTEXT_MIN_USER_PRIORITY -1023 /* inclusive */
+ /*
+ * When using the following param, value should be a pointer to
+ * drm_i915_gem_context_param_sseu.
+ */
+#define I915_CONTEXT_PARAM_SSEU 0x7
__u64 value;
};
+struct drm_i915_gem_context_param_sseu {
+ /*
+ * Engine class & instance to be configured or queried.
+ */
+ __u32 class;
+ __u32 instance;
+
+ /*
+ * Mask of slices to enable for the context. Valid values are a subset
+ * of the bitmask value returned for I915_PARAM_SLICE_MASK.
+ */
+ __u8 slice_mask;
+
+ /*
+ * Mask of subslices to enable for the context. Valid values are a
+ * subset of the bitmask value return by I915_PARAM_SUBSLICE_MASK.
+ */
+ __u8 subslice_mask;
+
+ /*
+ * Minimum/Maximum number of EUs to enable per subslice for the
+ * context. min_eus_per_subslice must be inferior or equal to
+ * max_eus_per_subslice.
+ */
+ __u8 min_eus_per_subslice;
+ __u8 max_eus_per_subslice;
+
+ /*
+ * Unused for now. Must be cleared to zero.
+ */
+ __u32 rsvd;
+};
+
enum drm_i915_oa_format {
I915_OA_FORMAT_A13 = 1, /* HSW only */
I915_OA_FORMAT_A29, /* HSW only */