503579448d
The GSC CS is not exposed to the user, so we skipped assigning a uabi class number for it. However, the trace logs use the uabi class and instance to identify the engine, so leaving uabi class unset makes the GSC CS show up as the RCS in those logs. Given that the engine is not exposed to the user, we can't add a new case in the uabi enum, so we insted internally define a kernel internal class as -1. At the same time remove special handling for the name and complete the uabi_classes array so internal class is automatically correctly assigned. Engine will show as 65535:0 other0 in the logs/traces which should be unique enough. v2: * Fix uabi class u8 vs u16 type confusion. Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Fixes:194babe26b
("drm/i915/mtl: don't expose GSC command streamer to the user") Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> Cc: Alan Previn <alan.previn.teres.alexis@intel.com> Cc: Matt Roper <matthew.d.roper@intel.com> Reviewed-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20231116084456.291533-1-tvrtko.ursulin@linux.intel.com (cherry picked from commitdfed6b58d5
) Signed-off-by: Jani Nikula <jani.nikula@intel.com>
327 lines
8.3 KiB
C
327 lines
8.3 KiB
C
// SPDX-License-Identifier: MIT
|
|
/*
|
|
* Copyright © 2019 Intel Corporation
|
|
*/
|
|
|
|
#include <linux/list.h>
|
|
#include <linux/list_sort.h>
|
|
#include <linux/llist.h>
|
|
|
|
#include "i915_drv.h"
|
|
#include "intel_engine.h"
|
|
#include "intel_engine_user.h"
|
|
#include "intel_gt.h"
|
|
#include "uc/intel_guc_submission.h"
|
|
|
|
struct intel_engine_cs *
|
|
intel_engine_lookup_user(struct drm_i915_private *i915, u8 class, u8 instance)
|
|
{
|
|
struct rb_node *p = i915->uabi_engines.rb_node;
|
|
|
|
while (p) {
|
|
struct intel_engine_cs *it =
|
|
rb_entry(p, typeof(*it), uabi_node);
|
|
|
|
if (class < it->uabi_class)
|
|
p = p->rb_left;
|
|
else if (class > it->uabi_class ||
|
|
instance > it->uabi_instance)
|
|
p = p->rb_right;
|
|
else if (instance < it->uabi_instance)
|
|
p = p->rb_left;
|
|
else
|
|
return it;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void intel_engine_add_user(struct intel_engine_cs *engine)
|
|
{
|
|
llist_add(&engine->uabi_llist, &engine->i915->uabi_engines_llist);
|
|
}
|
|
|
|
#define I915_NO_UABI_CLASS ((u16)(-1))
|
|
|
|
static const u16 uabi_classes[] = {
|
|
[RENDER_CLASS] = I915_ENGINE_CLASS_RENDER,
|
|
[COPY_ENGINE_CLASS] = I915_ENGINE_CLASS_COPY,
|
|
[VIDEO_DECODE_CLASS] = I915_ENGINE_CLASS_VIDEO,
|
|
[VIDEO_ENHANCEMENT_CLASS] = I915_ENGINE_CLASS_VIDEO_ENHANCE,
|
|
[COMPUTE_CLASS] = I915_ENGINE_CLASS_COMPUTE,
|
|
[OTHER_CLASS] = I915_NO_UABI_CLASS, /* Not exposed to users, no uabi class. */
|
|
};
|
|
|
|
static int engine_cmp(void *priv, const struct list_head *A,
|
|
const struct list_head *B)
|
|
{
|
|
const struct intel_engine_cs *a =
|
|
container_of(A, typeof(*a), uabi_list);
|
|
const struct intel_engine_cs *b =
|
|
container_of(B, typeof(*b), uabi_list);
|
|
|
|
if (uabi_classes[a->class] < uabi_classes[b->class])
|
|
return -1;
|
|
if (uabi_classes[a->class] > uabi_classes[b->class])
|
|
return 1;
|
|
|
|
if (a->instance < b->instance)
|
|
return -1;
|
|
if (a->instance > b->instance)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct llist_node *get_engines(struct drm_i915_private *i915)
|
|
{
|
|
return llist_del_all(&i915->uabi_engines_llist);
|
|
}
|
|
|
|
static void sort_engines(struct drm_i915_private *i915,
|
|
struct list_head *engines)
|
|
{
|
|
struct llist_node *pos, *next;
|
|
|
|
llist_for_each_safe(pos, next, get_engines(i915)) {
|
|
struct intel_engine_cs *engine =
|
|
container_of(pos, typeof(*engine), uabi_llist);
|
|
list_add(&engine->uabi_list, engines);
|
|
}
|
|
list_sort(NULL, engines, engine_cmp);
|
|
}
|
|
|
|
static void set_scheduler_caps(struct drm_i915_private *i915)
|
|
{
|
|
static const struct {
|
|
u8 engine;
|
|
u8 sched;
|
|
} map[] = {
|
|
#define MAP(x, y) { ilog2(I915_ENGINE_##x), ilog2(I915_SCHEDULER_CAP_##y) }
|
|
MAP(HAS_PREEMPTION, PREEMPTION),
|
|
MAP(HAS_SEMAPHORES, SEMAPHORES),
|
|
MAP(SUPPORTS_STATS, ENGINE_BUSY_STATS),
|
|
#undef MAP
|
|
};
|
|
struct intel_engine_cs *engine;
|
|
u32 enabled, disabled;
|
|
|
|
enabled = 0;
|
|
disabled = 0;
|
|
for_each_uabi_engine(engine, i915) { /* all engines must agree! */
|
|
int i;
|
|
|
|
if (engine->sched_engine->schedule)
|
|
enabled |= (I915_SCHEDULER_CAP_ENABLED |
|
|
I915_SCHEDULER_CAP_PRIORITY);
|
|
else
|
|
disabled |= (I915_SCHEDULER_CAP_ENABLED |
|
|
I915_SCHEDULER_CAP_PRIORITY);
|
|
|
|
if (intel_uc_uses_guc_submission(&engine->gt->uc))
|
|
enabled |= I915_SCHEDULER_CAP_STATIC_PRIORITY_MAP;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(map); i++) {
|
|
if (engine->flags & BIT(map[i].engine))
|
|
enabled |= BIT(map[i].sched);
|
|
else
|
|
disabled |= BIT(map[i].sched);
|
|
}
|
|
}
|
|
|
|
i915->caps.scheduler = enabled & ~disabled;
|
|
if (!(i915->caps.scheduler & I915_SCHEDULER_CAP_ENABLED))
|
|
i915->caps.scheduler = 0;
|
|
}
|
|
|
|
const char *intel_engine_class_repr(u8 class)
|
|
{
|
|
static const char * const uabi_names[] = {
|
|
[RENDER_CLASS] = "rcs",
|
|
[COPY_ENGINE_CLASS] = "bcs",
|
|
[VIDEO_DECODE_CLASS] = "vcs",
|
|
[VIDEO_ENHANCEMENT_CLASS] = "vecs",
|
|
[OTHER_CLASS] = "other",
|
|
[COMPUTE_CLASS] = "ccs",
|
|
};
|
|
|
|
if (class >= ARRAY_SIZE(uabi_names) || !uabi_names[class])
|
|
return "xxx";
|
|
|
|
return uabi_names[class];
|
|
}
|
|
|
|
struct legacy_ring {
|
|
struct intel_gt *gt;
|
|
u8 class;
|
|
u8 instance;
|
|
};
|
|
|
|
static int legacy_ring_idx(const struct legacy_ring *ring)
|
|
{
|
|
static const struct {
|
|
u8 base, max;
|
|
} map[] = {
|
|
[RENDER_CLASS] = { RCS0, 1 },
|
|
[COPY_ENGINE_CLASS] = { BCS0, 1 },
|
|
[VIDEO_DECODE_CLASS] = { VCS0, I915_MAX_VCS },
|
|
[VIDEO_ENHANCEMENT_CLASS] = { VECS0, I915_MAX_VECS },
|
|
[COMPUTE_CLASS] = { CCS0, I915_MAX_CCS },
|
|
};
|
|
|
|
if (GEM_DEBUG_WARN_ON(ring->class >= ARRAY_SIZE(map)))
|
|
return INVALID_ENGINE;
|
|
|
|
if (GEM_DEBUG_WARN_ON(ring->instance >= map[ring->class].max))
|
|
return INVALID_ENGINE;
|
|
|
|
return map[ring->class].base + ring->instance;
|
|
}
|
|
|
|
static void add_legacy_ring(struct legacy_ring *ring,
|
|
struct intel_engine_cs *engine)
|
|
{
|
|
if (engine->gt != ring->gt || engine->class != ring->class) {
|
|
ring->gt = engine->gt;
|
|
ring->class = engine->class;
|
|
ring->instance = 0;
|
|
}
|
|
|
|
engine->legacy_idx = legacy_ring_idx(ring);
|
|
if (engine->legacy_idx != INVALID_ENGINE)
|
|
ring->instance++;
|
|
}
|
|
|
|
static void engine_rename(struct intel_engine_cs *engine, const char *name, u16 instance)
|
|
{
|
|
char old[sizeof(engine->name)];
|
|
|
|
memcpy(old, engine->name, sizeof(engine->name));
|
|
scnprintf(engine->name, sizeof(engine->name), "%s%u", name, instance);
|
|
drm_dbg(&engine->i915->drm, "renamed %s to %s\n", old, engine->name);
|
|
}
|
|
|
|
void intel_engines_driver_register(struct drm_i915_private *i915)
|
|
{
|
|
u16 name_instance, other_instance = 0;
|
|
struct legacy_ring ring = {};
|
|
struct list_head *it, *next;
|
|
struct rb_node **p, *prev;
|
|
LIST_HEAD(engines);
|
|
|
|
sort_engines(i915, &engines);
|
|
|
|
prev = NULL;
|
|
p = &i915->uabi_engines.rb_node;
|
|
list_for_each_safe(it, next, &engines) {
|
|
struct intel_engine_cs *engine =
|
|
container_of(it, typeof(*engine), uabi_list);
|
|
|
|
if (intel_gt_has_unrecoverable_error(engine->gt))
|
|
continue; /* ignore incomplete engines */
|
|
|
|
GEM_BUG_ON(engine->class >= ARRAY_SIZE(uabi_classes));
|
|
engine->uabi_class = uabi_classes[engine->class];
|
|
if (engine->uabi_class == I915_NO_UABI_CLASS) {
|
|
name_instance = other_instance++;
|
|
} else {
|
|
GEM_BUG_ON(engine->uabi_class >=
|
|
ARRAY_SIZE(i915->engine_uabi_class_count));
|
|
name_instance =
|
|
i915->engine_uabi_class_count[engine->uabi_class]++;
|
|
}
|
|
engine->uabi_instance = name_instance;
|
|
|
|
/*
|
|
* Replace the internal name with the final user and log facing
|
|
* name.
|
|
*/
|
|
engine_rename(engine,
|
|
intel_engine_class_repr(engine->class),
|
|
name_instance);
|
|
|
|
if (engine->uabi_class == I915_NO_UABI_CLASS)
|
|
continue;
|
|
|
|
rb_link_node(&engine->uabi_node, prev, p);
|
|
rb_insert_color(&engine->uabi_node, &i915->uabi_engines);
|
|
|
|
GEM_BUG_ON(intel_engine_lookup_user(i915,
|
|
engine->uabi_class,
|
|
engine->uabi_instance) != engine);
|
|
|
|
/* Fix up the mapping to match default execbuf::user_map[] */
|
|
add_legacy_ring(&ring, engine);
|
|
|
|
prev = &engine->uabi_node;
|
|
p = &prev->rb_right;
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_DRM_I915_SELFTESTS) &&
|
|
IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) {
|
|
struct intel_engine_cs *engine;
|
|
unsigned int isolation;
|
|
int class, inst;
|
|
int errors = 0;
|
|
|
|
for (class = 0; class < ARRAY_SIZE(i915->engine_uabi_class_count); class++) {
|
|
for (inst = 0; inst < i915->engine_uabi_class_count[class]; inst++) {
|
|
engine = intel_engine_lookup_user(i915,
|
|
class, inst);
|
|
if (!engine) {
|
|
pr_err("UABI engine not found for { class:%d, instance:%d }\n",
|
|
class, inst);
|
|
errors++;
|
|
continue;
|
|
}
|
|
|
|
if (engine->uabi_class != class ||
|
|
engine->uabi_instance != inst) {
|
|
pr_err("Wrong UABI engine:%s { class:%d, instance:%d } found for { class:%d, instance:%d }\n",
|
|
engine->name,
|
|
engine->uabi_class,
|
|
engine->uabi_instance,
|
|
class, inst);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Make sure that classes with multiple engine instances all
|
|
* share the same basic configuration.
|
|
*/
|
|
isolation = intel_engines_has_context_isolation(i915);
|
|
for_each_uabi_engine(engine, i915) {
|
|
unsigned int bit = BIT(engine->uabi_class);
|
|
unsigned int expected = engine->default_state ? bit : 0;
|
|
|
|
if ((isolation & bit) != expected) {
|
|
pr_err("mismatching default context state for class %d on engine %s\n",
|
|
engine->uabi_class, engine->name);
|
|
errors++;
|
|
}
|
|
}
|
|
|
|
if (drm_WARN(&i915->drm, errors,
|
|
"Invalid UABI engine mapping found"))
|
|
i915->uabi_engines = RB_ROOT;
|
|
}
|
|
|
|
set_scheduler_caps(i915);
|
|
}
|
|
|
|
unsigned int intel_engines_has_context_isolation(struct drm_i915_private *i915)
|
|
{
|
|
struct intel_engine_cs *engine;
|
|
unsigned int which;
|
|
|
|
which = 0;
|
|
for_each_uabi_engine(engine, i915)
|
|
if (engine->default_state)
|
|
which |= BIT(engine->uabi_class);
|
|
|
|
return which;
|
|
}
|