Skip to content

Commit

Permalink
drm/i915: Remove logical HW ID
Browse files Browse the repository at this point in the history
With the introduction of ctx->engines[] we allow multiple logical
contexts to be used on the same engine (e.g. with virtual engines).
According to bspec, aach logical context requires a unique tag in order
for context-switching to occur correctly between them. [Simple
experiments show that it is not so easy to trick the HW into performing
a lite-restore with matching logical IDs, though my memory from early
Broadwell experiments do suggest that it should be generating
lite-restores.]

We only need to keep a unique tag for the active lifetime of the
context, and for as long as we need to identify that context. The HW
uses the tag to determine if it should use a lite-restore (why not the
LRCA?) and passes the tag back for various status identifies. The only
status we need to track is for OA, so when using perf, we assign the
specific context a unique tag.

v2: Calculate required number of tags to fill ELSP.

Fixes: 976b55f ("drm/i915: Allow a context to define its set of engines")
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=111895
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Acked-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191004134015.13204-14-chris@chris-wilson.co.uk
  • Loading branch information
ickle committed Oct 4, 2019
1 parent a2b4dea commit 2935ed5
Show file tree
Hide file tree
Showing 18 changed files with 57 additions and 302 deletions.
153 changes: 0 additions & 153 deletions drivers/gpu/drm/i915/gem/i915_gem_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,97 +167,6 @@ lookup_user_engine(struct i915_gem_context *ctx,
return i915_gem_context_get_engine(ctx, idx);
}

static inline int new_hw_id(struct drm_i915_private *i915, gfp_t gfp)
{
unsigned int max;

lockdep_assert_held(&i915->contexts.mutex);

if (INTEL_GEN(i915) >= 12)
max = GEN12_MAX_CONTEXT_HW_ID;
else if (INTEL_GEN(i915) >= 11)
max = GEN11_MAX_CONTEXT_HW_ID;
else if (USES_GUC_SUBMISSION(i915))
/*
* When using GuC in proxy submission, GuC consumes the
* highest bit in the context id to indicate proxy submission.
*/
max = MAX_GUC_CONTEXT_HW_ID;
else
max = MAX_CONTEXT_HW_ID;

return ida_simple_get(&i915->contexts.hw_ida, 0, max, gfp);
}

static int steal_hw_id(struct drm_i915_private *i915)
{
struct i915_gem_context *ctx, *cn;
LIST_HEAD(pinned);
int id = -ENOSPC;

lockdep_assert_held(&i915->contexts.mutex);

list_for_each_entry_safe(ctx, cn,
&i915->contexts.hw_id_list, hw_id_link) {
if (atomic_read(&ctx->hw_id_pin_count)) {
list_move_tail(&ctx->hw_id_link, &pinned);
continue;
}

GEM_BUG_ON(!ctx->hw_id); /* perma-pinned kernel context */
list_del_init(&ctx->hw_id_link);
id = ctx->hw_id;
break;
}

/*
* Remember how far we got up on the last repossesion scan, so the
* list is kept in a "least recently scanned" order.
*/
list_splice_tail(&pinned, &i915->contexts.hw_id_list);
return id;
}

static int assign_hw_id(struct drm_i915_private *i915, unsigned int *out)
{
int ret;

lockdep_assert_held(&i915->contexts.mutex);

/*
* We prefer to steal/stall ourselves and our users over that of the
* entire system. That may be a little unfair to our users, and
* even hurt high priority clients. The choice is whether to oomkill
* something else, or steal a context id.
*/
ret = new_hw_id(i915, GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN);
if (unlikely(ret < 0)) {
ret = steal_hw_id(i915);
if (ret < 0) /* once again for the correct errno code */
ret = new_hw_id(i915, GFP_KERNEL);
if (ret < 0)
return ret;
}

*out = ret;
return 0;
}

static void release_hw_id(struct i915_gem_context *ctx)
{
struct drm_i915_private *i915 = ctx->i915;

if (list_empty(&ctx->hw_id_link))
return;

mutex_lock(&i915->contexts.mutex);
if (!list_empty(&ctx->hw_id_link)) {
ida_simple_remove(&i915->contexts.hw_ida, ctx->hw_id);
list_del_init(&ctx->hw_id_link);
}
mutex_unlock(&i915->contexts.mutex);
}

static void __free_engines(struct i915_gem_engines *e, unsigned int count)
{
while (count--) {
Expand Down Expand Up @@ -312,8 +221,6 @@ static void i915_gem_context_free(struct i915_gem_context *ctx)
lockdep_assert_held(&ctx->i915->drm.struct_mutex);
GEM_BUG_ON(!i915_gem_context_is_closed(ctx));

release_hw_id(ctx);

free_engines(rcu_access_pointer(ctx->engines));
mutex_destroy(&ctx->engines_mutex);

Expand Down Expand Up @@ -386,12 +293,6 @@ static void context_close(struct i915_gem_context *ctx)

ctx->file_priv = ERR_PTR(-EBADF);

/*
* This context will never again be assinged to HW, so we can
* reuse its ID for the next context.
*/
release_hw_id(ctx);

/*
* The LUT uses the VMA as a backpointer to unref the object,
* so we need to clear the LUT before we close all the VMA (inside
Expand Down Expand Up @@ -430,7 +331,6 @@ __create_context(struct drm_i915_private *i915)
RCU_INIT_POINTER(ctx->engines, e);

INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL);
INIT_LIST_HEAD(&ctx->hw_id_link);

/* NB: Mark all slices as needing a remap so that when the context first
* loads it will restore whatever remap state already exists. If there
Expand Down Expand Up @@ -584,18 +484,11 @@ struct i915_gem_context *
i915_gem_context_create_kernel(struct drm_i915_private *i915, int prio)
{
struct i915_gem_context *ctx;
int err;

ctx = i915_gem_create_context(i915, 0);
if (IS_ERR(ctx))
return ctx;

err = i915_gem_context_pin_hw_id(ctx);
if (err) {
destroy_kernel_context(&ctx);
return ERR_PTR(err);
}

i915_gem_context_clear_bannable(ctx);
ctx->sched.priority = I915_USER_PRIORITY(prio);

Expand All @@ -609,12 +502,6 @@ static void init_contexts(struct drm_i915_private *i915)
mutex_init(&i915->contexts.mutex);
INIT_LIST_HEAD(&i915->contexts.list);

/* Using the simple ida interface, the max is limited by sizeof(int) */
BUILD_BUG_ON(MAX_CONTEXT_HW_ID > INT_MAX);
BUILD_BUG_ON(GEN11_MAX_CONTEXT_HW_ID > INT_MAX);
ida_init(&i915->contexts.hw_ida);
INIT_LIST_HEAD(&i915->contexts.hw_id_list);

INIT_WORK(&i915->contexts.free_work, contexts_free_worker);
init_llist_head(&i915->contexts.free_list);
}
Expand All @@ -634,15 +521,6 @@ int i915_gem_contexts_init(struct drm_i915_private *dev_priv)
DRM_ERROR("Failed to create default global context\n");
return PTR_ERR(ctx);
}
/*
* For easy recognisablity, we want the kernel context to be 0 and then
* all user contexts will have non-zero hw_id. Kernel contexts are
* permanently pinned, so that we never suffer a stall and can
* use them from any allocation context (e.g. for evicting other
* contexts and from inside the shrinker).
*/
GEM_BUG_ON(ctx->hw_id);
GEM_BUG_ON(!atomic_read(&ctx->hw_id_pin_count));
dev_priv->kernel_context = ctx;

DRM_DEBUG_DRIVER("%s context support initialized\n",
Expand All @@ -656,10 +534,6 @@ void i915_gem_contexts_fini(struct drm_i915_private *i915)
lockdep_assert_held(&i915->drm.struct_mutex);

destroy_kernel_context(&i915->kernel_context);

/* Must free all deferred contexts (via flush_workqueue) first */
GEM_BUG_ON(!list_empty(&i915->contexts.hw_id_list));
ida_destroy(&i915->contexts.hw_ida);
}

static int context_idr_cleanup(int id, void *p, void *data)
Expand Down Expand Up @@ -2316,33 +2190,6 @@ int i915_gem_context_reset_stats_ioctl(struct drm_device *dev,
return ret;
}

int __i915_gem_context_pin_hw_id(struct i915_gem_context *ctx)
{
struct drm_i915_private *i915 = ctx->i915;
int err = 0;

mutex_lock(&i915->contexts.mutex);

GEM_BUG_ON(i915_gem_context_is_closed(ctx));

if (list_empty(&ctx->hw_id_link)) {
GEM_BUG_ON(atomic_read(&ctx->hw_id_pin_count));

err = assign_hw_id(i915, &ctx->hw_id);
if (err)
goto out_unlock;

list_add_tail(&ctx->hw_id_link, &i915->contexts.hw_id_list);
}

GEM_BUG_ON(atomic_read(&ctx->hw_id_pin_count) == ~0u);
atomic_inc(&ctx->hw_id_pin_count);

out_unlock:
mutex_unlock(&i915->contexts.mutex);
return err;
}

/* GEM context-engines iterator: for_each_gem_engine() */
struct intel_context *
i915_gem_engines_iter_next(struct i915_gem_engines_iter *it)
Expand Down
15 changes: 0 additions & 15 deletions drivers/gpu/drm/i915/gem/i915_gem_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,21 +112,6 @@ i915_gem_context_clear_user_engines(struct i915_gem_context *ctx)
clear_bit(CONTEXT_USER_ENGINES, &ctx->flags);
}

int __i915_gem_context_pin_hw_id(struct i915_gem_context *ctx);
static inline int i915_gem_context_pin_hw_id(struct i915_gem_context *ctx)
{
if (atomic_inc_not_zero(&ctx->hw_id_pin_count))
return 0;

return __i915_gem_context_pin_hw_id(ctx);
}

static inline void i915_gem_context_unpin_hw_id(struct i915_gem_context *ctx)
{
GEM_BUG_ON(atomic_read(&ctx->hw_id_pin_count) == 0u);
atomic_dec(&ctx->hw_id_pin_count);
}

static inline bool i915_gem_context_is_kernel(struct i915_gem_context *ctx)
{
return !ctx->file_priv;
Expand Down
18 changes: 0 additions & 18 deletions drivers/gpu/drm/i915/gem/i915_gem_context_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,24 +147,6 @@ struct i915_gem_context {
#define CONTEXT_FORCE_SINGLE_SUBMISSION 2
#define CONTEXT_USER_ENGINES 3

/**
* @hw_id: - unique identifier for the context
*
* The hardware needs to uniquely identify the context for a few
* functions like fault reporting, PASID, scheduling. The
* &drm_i915_private.context_hw_ida is used to assign a unqiue
* id for the lifetime of the context.
*
* @hw_id_pin_count: - number of times this context had been pinned
* for use (should be, at most, once per engine).
*
* @hw_id_link: - all contexts with an assigned id are tracked
* for possible repossession.
*/
unsigned int hw_id;
atomic_t hw_id_pin_count;
struct list_head hw_id_link;

struct mutex mutex;

struct i915_sched_attr sched;
Expand Down
13 changes: 6 additions & 7 deletions drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -660,9 +660,9 @@ static int igt_ctx_exec(void *arg)

err = gpu_fill(ce, obj, dw);
if (err) {
pr_err("Failed to fill dword %lu [%lu/%lu] with gpu (%s) in ctx %u [full-ppgtt? %s], err=%d\n",
pr_err("Failed to fill dword %lu [%lu/%lu] with gpu (%s) [full-ppgtt? %s], err=%d\n",
ndwords, dw, max_dwords(obj),
engine->name, ctx->hw_id,
engine->name,
yesno(!!ctx->vm), err);
intel_context_put(ce);
kernel_context_close(ctx);
Expand Down Expand Up @@ -798,9 +798,9 @@ static int igt_shared_ctx_exec(void *arg)

err = gpu_fill(ce, obj, dw);
if (err) {
pr_err("Failed to fill dword %lu [%lu/%lu] with gpu (%s) in ctx %u [full-ppgtt? %s], err=%d\n",
pr_err("Failed to fill dword %lu [%lu/%lu] with gpu (%s) [full-ppgtt? %s], err=%d\n",
ndwords, dw, max_dwords(obj),
engine->name, ctx->hw_id,
engine->name,
yesno(!!ctx->vm), err);
intel_context_put(ce);
kernel_context_close(ctx);
Expand Down Expand Up @@ -1382,10 +1382,9 @@ static int igt_ctx_readonly(void *arg)

err = gpu_fill(ce, obj, dw);
if (err) {
pr_err("Failed to fill dword %lu [%lu/%lu] with gpu (%s) in ctx %u [full-ppgtt? %s], err=%d\n",
pr_err("Failed to fill dword %lu [%lu/%lu] with gpu (%s) [full-ppgtt? %s], err=%d\n",
ndwords, dw, max_dwords(obj),
ce->engine->name, ctx->hw_id,
yesno(!!ctx->vm), err);
ce->engine->name, yesno(!!ctx->vm), err);
i915_gem_context_unlock_engines(ctx);
goto out_unlock;
}
Expand Down
8 changes: 0 additions & 8 deletions drivers/gpu/drm/i915/gem/selftests/mock_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ mock_context(struct drm_i915_private *i915,
{
struct i915_gem_context *ctx;
struct i915_gem_engines *e;
int ret;

ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
Expand All @@ -30,13 +29,8 @@ mock_context(struct drm_i915_private *i915,
RCU_INIT_POINTER(ctx->engines, e);

INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL);
INIT_LIST_HEAD(&ctx->hw_id_link);
mutex_init(&ctx->mutex);

ret = i915_gem_context_pin_hw_id(ctx);
if (ret < 0)
goto err_engines;

if (name) {
struct i915_ppgtt *ppgtt;

Expand All @@ -54,8 +48,6 @@ mock_context(struct drm_i915_private *i915,

return ctx;

err_engines:
free_engines(rcu_access_pointer(ctx->engines));
err_free:
kfree(ctx);
return NULL;
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/gt/intel_context_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ struct intel_context {

u32 *lrc_reg_state;
u64 lrc_desc;
u32 tag; /* cookie passed to HW to track this context on submission */

unsigned int active_count; /* protected by timeline->mutex */

Expand Down
4 changes: 3 additions & 1 deletion drivers/gpu/drm/i915/gt/intel_engine_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -303,10 +303,12 @@ struct intel_engine_cs {
u8 uabi_class;
u8 uabi_instance;

u32 uabi_capabilities;
u32 context_size;
u32 mmio_base;

u32 uabi_capabilities;
unsigned int context_tag;
#define NUM_CONTEXT_TAG roundup_pow_of_two(2 * EXECLIST_MAX_PORTS)

struct rb_node uabi_node;

Expand Down
Loading

0 comments on commit 2935ed5

Please sign in to comment.