drm/i915: Allow userspace to specify ringsize on construction

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
This commit is contained in:
Chris Wilson 2020-02-25 19:22:05 +00:00
parent d13a317700
commit 88be76cdaf
6 changed files with 202 additions and 8 deletions

View File

@ -82,6 +82,7 @@ gt-y += \
gt/gen8_ppgtt.o \ gt/gen8_ppgtt.o \
gt/intel_breadcrumbs.o \ gt/intel_breadcrumbs.o \
gt/intel_context.o \ gt/intel_context.o \
gt/intel_context_param.o \
gt/intel_context_sseu.o \ gt/intel_context_sseu.o \
gt/intel_engine_cs.o \ gt/intel_engine_cs.o \
gt/intel_engine_heartbeat.o \ gt/intel_engine_heartbeat.o \

View File

@ -71,6 +71,7 @@
#include "gt/gen6_ppgtt.h" #include "gt/gen6_ppgtt.h"
#include "gt/intel_context.h" #include "gt/intel_context.h"
#include "gt/intel_context_param.h"
#include "gt/intel_engine_heartbeat.h" #include "gt/intel_engine_heartbeat.h"
#include "gt/intel_engine_user.h" #include "gt/intel_engine_user.h"
#include "gt/intel_ring.h" #include "gt/intel_ring.h"
@ -668,23 +669,30 @@ err_free:
return ERR_PTR(err); return ERR_PTR(err);
} }
static void static int
context_apply_all(struct i915_gem_context *ctx, 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) void *data)
{ {
struct i915_gem_engines_iter it; struct i915_gem_engines_iter it;
struct intel_context *ce; struct intel_context *ce;
int err = 0;
for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) {
fn(ce, data); err = fn(ce, data);
if (err)
break;
}
i915_gem_context_unlock_engines(ctx); 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); i915_vm_put(ce->vm);
ce->vm = i915_vm_get(vm); ce->vm = i915_vm_get(vm);
return 0;
} }
static struct i915_address_space * static struct i915_address_space *
@ -722,9 +730,10 @@ static void __set_timeline(struct intel_timeline **dst,
intel_timeline_put(old); 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); __set_timeline(&ce->timeline, timeline);
return 0;
} }
static void __assign_timeline(struct i915_gem_context *ctx, static void __assign_timeline(struct i915_gem_context *ctx,
@ -1215,6 +1224,63 @@ out:
return err; 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 static int
user_to_context_sseu(struct drm_i915_private *i915, user_to_context_sseu(struct drm_i915_private *i915,
const struct drm_i915_gem_context_param_sseu *user, 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); 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; struct i915_gem_context *ctx = arg;
if (!intel_engine_has_semaphores(ce->engine)) if (!intel_engine_has_semaphores(ce->engine))
return; return 0;
if (ctx->sched.priority >= I915_PRIORITY_NORMAL) if (ctx->sched.priority >= I915_PRIORITY_NORMAL)
intel_context_set_use_semaphores(ce); intel_context_set_use_semaphores(ce);
else else
intel_context_clear_use_semaphores(ce); intel_context_clear_use_semaphores(ce);
return 0;
} }
static int set_priority(struct i915_gem_context *ctx, 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); ret = set_persistence(ctx, args);
break; break;
case I915_CONTEXT_PARAM_RINGSIZE:
ret = set_ringsize(ctx, args);
break;
case I915_CONTEXT_PARAM_BAN_PERIOD: case I915_CONTEXT_PARAM_BAN_PERIOD:
default: default:
ret = -EINVAL; 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); 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, static int clone_engines(struct i915_gem_context *dst,
struct i915_gem_context *src) 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); 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; 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); args->value = i915_gem_context_is_persistent(ctx);
break; break;
case I915_CONTEXT_PARAM_RINGSIZE:
ret = get_ringsize(ctx, args);
break;
case I915_CONTEXT_PARAM_BAN_PERIOD: case I915_CONTEXT_PARAM_BAN_PERIOD:
default: default:
ret = -EINVAL; ret = -EINVAL;

View File

@ -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;
}

View File

@ -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 */

View 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_START] = i915_ggtt_offset(ring->vma);
regs[CTX_RING_HEAD] = head; regs[CTX_RING_HEAD] = head;
regs[CTX_RING_TAIL] = ring->tail; regs[CTX_RING_TAIL] = ring->tail;
regs[CTX_RING_CTL] = RING_CTL_SIZE(ring->size) | RING_VALID;
/* RPCS */ /* RPCS */
if (engine->class == RENDER_CLASS) { if (engine->class == RENDER_CLASS) {

View File

@ -1619,6 +1619,27 @@ struct drm_i915_gem_context_param {
* By default, new contexts allow persistence. * By default, new contexts allow persistence.
*/ */
#define I915_CONTEXT_PARAM_PERSISTENCE 0xb #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 */ /* Must be kept compact -- no holes and well documented */
__u64 value; __u64 value;