drm/i915: Allow userspace to specify ringsize on construction
authorChris Wilson <chris@chris-wilson.co.uk>
Tue, 25 Feb 2020 19:22:05 +0000 (19:22 +0000)
committerChris Wilson <chris@chris-wilson.co.uk>
Tue, 25 Feb 2020 19:23:19 +0000 (19:23 +0000)
No good reason why we must always use a static ringsize, so let
userspace select one during construction.

Link: https://github.com/intel/compute-runtime/pull/261
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Steve Carbonari <steven.carbonari@intel.com>
Reviewed-by: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200225192206.1107336-2-chris@chris-wilson.co.uk
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/gem/i915_gem_context.c
drivers/gpu/drm/i915/gt/intel_context_param.c [new file with mode: 0644]
drivers/gpu/drm/i915/gt/intel_context_param.h [new file with mode: 0644]
drivers/gpu/drm/i915/gt/intel_lrc.c
include/uapi/drm/i915_drm.h

index bc28c31..9db81b9 100644 (file)
@@ -82,6 +82,7 @@ gt-y += \
        gt/gen8_ppgtt.o \
        gt/intel_breadcrumbs.o \
        gt/intel_context.o \
+       gt/intel_context_param.o \
        gt/intel_context_sseu.o \
        gt/intel_engine_cs.o \
        gt/intel_engine_heartbeat.o \
index adcebf2..b24ee8e 100644 (file)
@@ -71,6 +71,7 @@
 
 #include "gt/gen6_ppgtt.h"
 #include "gt/intel_context.h"
+#include "gt/intel_context_param.h"
 #include "gt/intel_engine_heartbeat.h"
 #include "gt/intel_engine_user.h"
 #include "gt/intel_ring.h"
@@ -668,23 +669,30 @@ err_free:
        return ERR_PTR(err);
 }
 
-static void
+static int
 context_apply_all(struct i915_gem_context *ctx,
-                 void (*fn)(struct intel_context *ce, void *data),
+                 int (*fn)(struct intel_context *ce, void *data),
                  void *data)
 {
        struct i915_gem_engines_iter it;
        struct intel_context *ce;
+       int err = 0;
 
-       for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it)
-               fn(ce, data);
+       for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) {
+               err = fn(ce, data);
+               if (err)
+                       break;
+       }
        i915_gem_context_unlock_engines(ctx);
+
+       return err;
 }
 
-static void __apply_ppgtt(struct intel_context *ce, void *vm)
+static int __apply_ppgtt(struct intel_context *ce, void *vm)
 {
        i915_vm_put(ce->vm);
        ce->vm = i915_vm_get(vm);
+       return 0;
 }
 
 static struct i915_address_space *
@@ -722,9 +730,10 @@ static void __set_timeline(struct intel_timeline **dst,
                intel_timeline_put(old);
 }
 
-static void __apply_timeline(struct intel_context *ce, void *timeline)
+static int __apply_timeline(struct intel_context *ce, void *timeline)
 {
        __set_timeline(&ce->timeline, timeline);
+       return 0;
 }
 
 static void __assign_timeline(struct i915_gem_context *ctx,
@@ -1215,6 +1224,63 @@ out:
        return err;
 }
 
+static int __apply_ringsize(struct intel_context *ce, void *sz)
+{
+       return intel_context_set_ring_size(ce, (unsigned long)sz);
+}
+
+static int set_ringsize(struct i915_gem_context *ctx,
+                       struct drm_i915_gem_context_param *args)
+{
+       if (!HAS_LOGICAL_RING_CONTEXTS(ctx->i915))
+               return -ENODEV;
+
+       if (args->size)
+               return -EINVAL;
+
+       if (!IS_ALIGNED(args->value, I915_GTT_PAGE_SIZE))
+               return -EINVAL;
+
+       if (args->value < I915_GTT_PAGE_SIZE)
+               return -EINVAL;
+
+       if (args->value > 128 * I915_GTT_PAGE_SIZE)
+               return -EINVAL;
+
+       return context_apply_all(ctx,
+                                __apply_ringsize,
+                                __intel_context_ring_size(args->value));
+}
+
+static int __get_ringsize(struct intel_context *ce, void *arg)
+{
+       long sz;
+
+       sz = intel_context_get_ring_size(ce);
+       GEM_BUG_ON(sz > INT_MAX);
+
+       return sz; /* stop on first engine */
+}
+
+static int get_ringsize(struct i915_gem_context *ctx,
+                       struct drm_i915_gem_context_param *args)
+{
+       int sz;
+
+       if (!HAS_LOGICAL_RING_CONTEXTS(ctx->i915))
+               return -ENODEV;
+
+       if (args->size)
+               return -EINVAL;
+
+       sz = context_apply_all(ctx, __get_ringsize, NULL);
+       if (sz < 0)
+               return sz;
+
+       args->value = sz;
+       return 0;
+}
+
 static int
 user_to_context_sseu(struct drm_i915_private *i915,
                     const struct drm_i915_gem_context_param_sseu *user,
@@ -1852,17 +1918,19 @@ set_persistence(struct i915_gem_context *ctx,
        return __context_set_persistence(ctx, args->value);
 }
 
-static void __apply_priority(struct intel_context *ce, void *arg)
+static int __apply_priority(struct intel_context *ce, void *arg)
 {
        struct i915_gem_context *ctx = arg;
 
        if (!intel_engine_has_semaphores(ce->engine))
-               return;
+               return 0;
 
        if (ctx->sched.priority >= I915_PRIORITY_NORMAL)
                intel_context_set_use_semaphores(ce);
        else
                intel_context_clear_use_semaphores(ce);
+
+       return 0;
 }
 
 static int set_priority(struct i915_gem_context *ctx,
@@ -1955,6 +2023,10 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
                ret = set_persistence(ctx, args);
                break;
 
+       case I915_CONTEXT_PARAM_RINGSIZE:
+               ret = set_ringsize(ctx, args);
+               break;
+
        case I915_CONTEXT_PARAM_BAN_PERIOD:
        default:
                ret = -EINVAL;
@@ -1983,6 +2055,18 @@ static int create_setparam(struct i915_user_extension __user *ext, void *data)
        return ctx_setparam(arg->fpriv, arg->ctx, &local.param);
 }
 
+static int copy_ring_size(struct intel_context *dst,
+                         struct intel_context *src)
+{
+       long sz;
+
+       sz = intel_context_get_ring_size(src);
+       if (sz < 0)
+               return sz;
+
+       return intel_context_set_ring_size(dst, sz);
+}
+
 static int clone_engines(struct i915_gem_context *dst,
                         struct i915_gem_context *src)
 {
@@ -2026,6 +2110,12 @@ static int clone_engines(struct i915_gem_context *dst,
                }
 
                intel_context_set_gem(clone->engines[n], dst);
+
+               /* Copy across the preferred ringsize */
+               if (copy_ring_size(clone->engines[n], e->engines[n])) {
+                       __free_engines(clone, n + 1);
+                       goto err_unlock;
+               }
        }
        clone->num_engines = n;
 
@@ -2388,6 +2478,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_RINGSIZE:
+               ret = get_ringsize(ctx, args);
+               break;
+
        case I915_CONTEXT_PARAM_BAN_PERIOD:
        default:
                ret = -EINVAL;
diff --git a/drivers/gpu/drm/i915/gt/intel_context_param.c b/drivers/gpu/drm/i915/gt/intel_context_param.c
new file mode 100644 (file)
index 0000000..65dcd09
--- /dev/null
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#include "i915_active.h"
+#include "intel_context.h"
+#include "intel_context_param.h"
+#include "intel_ring.h"
+
+int intel_context_set_ring_size(struct intel_context *ce, long sz)
+{
+       int err;
+
+       if (intel_context_lock_pinned(ce))
+               return -EINTR;
+
+       err = i915_active_wait(&ce->active);
+       if (err < 0)
+               goto unlock;
+
+       if (intel_context_is_pinned(ce)) {
+               err = -EBUSY; /* In active use, come back later! */
+               goto unlock;
+       }
+
+       if (test_bit(CONTEXT_ALLOC_BIT, &ce->flags)) {
+               struct intel_ring *ring;
+
+               /* Replace the existing ringbuffer */
+               ring = intel_engine_create_ring(ce->engine, sz);
+               if (IS_ERR(ring)) {
+                       err = PTR_ERR(ring);
+                       goto unlock;
+               }
+
+               intel_ring_put(ce->ring);
+               ce->ring = ring;
+
+               /* Context image will be updated on next pin */
+       } else {
+               ce->ring = __intel_context_ring_size(sz);
+       }
+
+unlock:
+       intel_context_unlock_pinned(ce);
+       return err;
+}
+
+long intel_context_get_ring_size(struct intel_context *ce)
+{
+       long sz = (unsigned long)READ_ONCE(ce->ring);
+
+       if (test_bit(CONTEXT_ALLOC_BIT, &ce->flags)) {
+               if (intel_context_lock_pinned(ce))
+                       return -EINTR;
+
+               sz = ce->ring->size;
+               intel_context_unlock_pinned(ce);
+       }
+
+       return sz;
+}
diff --git a/drivers/gpu/drm/i915/gt/intel_context_param.h b/drivers/gpu/drm/i915/gt/intel_context_param.h
new file mode 100644 (file)
index 0000000..f053d86
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#ifndef INTEL_CONTEXT_PARAM_H
+#define INTEL_CONTEXT_PARAM_H
+
+struct intel_context;
+
+int intel_context_set_ring_size(struct intel_context *ce, long sz);
+long intel_context_get_ring_size(struct intel_context *ce);
+
+#endif /* INTEL_CONTEXT_PARAM_H */
index 47561dc..39b0125 100644 (file)
@@ -2966,6 +2966,7 @@ __execlists_update_reg_state(const struct intel_context *ce,
        regs[CTX_RING_START] = i915_ggtt_offset(ring->vma);
        regs[CTX_RING_HEAD] = head;
        regs[CTX_RING_TAIL] = ring->tail;
+       regs[CTX_RING_CTL] = RING_CTL_SIZE(ring->size) | RING_VALID;
 
        /* RPCS */
        if (engine->class == RENDER_CLASS) {
index 829c0a4..2813e57 100644 (file)
@@ -1619,6 +1619,27 @@ struct drm_i915_gem_context_param {
  * By default, new contexts allow persistence.
  */
 #define I915_CONTEXT_PARAM_PERSISTENCE 0xb
+
+/*
+ * I915_CONTEXT_PARAM_RINGSIZE:
+ *
+ * Sets the size of the CS ringbuffer to use for logical ring contexts. This
+ * applies a limit of how many batches can be queued to HW before the caller
+ * is blocked due to lack of space for more commands.
+ *
+ * Only reliably possible to be set prior to first use, i.e. during
+ * construction. At any later point, the current execution must be flushed as
+ * the ring can only be changed while the context is idle. Note, the ringsize
+ * can be specified as a constructor property, see
+ * I915_CONTEXT_CREATE_EXT_SETPARAM, but can also be set later if required.
+ *
+ * Only applies to the current set of engine and lost when those engines
+ * are replaced by a new mapping (see I915_CONTEXT_PARAM_ENGINES).
+ *
+ * Must be between 4 - 512 KiB, in intervals of page size [4 KiB].
+ * Default is 16 KiB.
+ */
+#define I915_CONTEXT_PARAM_RINGSIZE    0xc
 /* Must be kept compact -- no holes and well documented */
 
        __u64 value;