0001
0002
0003
0004
0005
0006 #include <linux/list.h>
0007 #include <linux/list_sort.h>
0008 #include <linux/llist.h>
0009
0010 #include "i915_drv.h"
0011 #include "intel_engine.h"
0012 #include "intel_engine_user.h"
0013 #include "intel_gt.h"
0014 #include "uc/intel_guc_submission.h"
0015
0016 struct intel_engine_cs *
0017 intel_engine_lookup_user(struct drm_i915_private *i915, u8 class, u8 instance)
0018 {
0019 struct rb_node *p = i915->uabi_engines.rb_node;
0020
0021 while (p) {
0022 struct intel_engine_cs *it =
0023 rb_entry(p, typeof(*it), uabi_node);
0024
0025 if (class < it->uabi_class)
0026 p = p->rb_left;
0027 else if (class > it->uabi_class ||
0028 instance > it->uabi_instance)
0029 p = p->rb_right;
0030 else if (instance < it->uabi_instance)
0031 p = p->rb_left;
0032 else
0033 return it;
0034 }
0035
0036 return NULL;
0037 }
0038
0039 void intel_engine_add_user(struct intel_engine_cs *engine)
0040 {
0041 llist_add((struct llist_node *)&engine->uabi_node,
0042 (struct llist_head *)&engine->i915->uabi_engines);
0043 }
0044
0045 static const u8 uabi_classes[] = {
0046 [RENDER_CLASS] = I915_ENGINE_CLASS_RENDER,
0047 [COPY_ENGINE_CLASS] = I915_ENGINE_CLASS_COPY,
0048 [VIDEO_DECODE_CLASS] = I915_ENGINE_CLASS_VIDEO,
0049 [VIDEO_ENHANCEMENT_CLASS] = I915_ENGINE_CLASS_VIDEO_ENHANCE,
0050 [COMPUTE_CLASS] = I915_ENGINE_CLASS_COMPUTE,
0051 };
0052
0053 static int engine_cmp(void *priv, const struct list_head *A,
0054 const struct list_head *B)
0055 {
0056 const struct intel_engine_cs *a =
0057 container_of((struct rb_node *)A, typeof(*a), uabi_node);
0058 const struct intel_engine_cs *b =
0059 container_of((struct rb_node *)B, typeof(*b), uabi_node);
0060
0061 if (uabi_classes[a->class] < uabi_classes[b->class])
0062 return -1;
0063 if (uabi_classes[a->class] > uabi_classes[b->class])
0064 return 1;
0065
0066 if (a->instance < b->instance)
0067 return -1;
0068 if (a->instance > b->instance)
0069 return 1;
0070
0071 return 0;
0072 }
0073
0074 static struct llist_node *get_engines(struct drm_i915_private *i915)
0075 {
0076 return llist_del_all((struct llist_head *)&i915->uabi_engines);
0077 }
0078
0079 static void sort_engines(struct drm_i915_private *i915,
0080 struct list_head *engines)
0081 {
0082 struct llist_node *pos, *next;
0083
0084 llist_for_each_safe(pos, next, get_engines(i915)) {
0085 struct intel_engine_cs *engine =
0086 container_of((struct rb_node *)pos, typeof(*engine),
0087 uabi_node);
0088 list_add((struct list_head *)&engine->uabi_node, engines);
0089 }
0090 list_sort(NULL, engines, engine_cmp);
0091 }
0092
0093 static void set_scheduler_caps(struct drm_i915_private *i915)
0094 {
0095 static const struct {
0096 u8 engine;
0097 u8 sched;
0098 } map[] = {
0099 #define MAP(x, y) { ilog2(I915_ENGINE_##x), ilog2(I915_SCHEDULER_CAP_##y) }
0100 MAP(HAS_PREEMPTION, PREEMPTION),
0101 MAP(HAS_SEMAPHORES, SEMAPHORES),
0102 MAP(SUPPORTS_STATS, ENGINE_BUSY_STATS),
0103 #undef MAP
0104 };
0105 struct intel_engine_cs *engine;
0106 u32 enabled, disabled;
0107
0108 enabled = 0;
0109 disabled = 0;
0110 for_each_uabi_engine(engine, i915) {
0111 int i;
0112
0113 if (engine->sched_engine->schedule)
0114 enabled |= (I915_SCHEDULER_CAP_ENABLED |
0115 I915_SCHEDULER_CAP_PRIORITY);
0116 else
0117 disabled |= (I915_SCHEDULER_CAP_ENABLED |
0118 I915_SCHEDULER_CAP_PRIORITY);
0119
0120 if (intel_uc_uses_guc_submission(&to_gt(i915)->uc))
0121 enabled |= I915_SCHEDULER_CAP_STATIC_PRIORITY_MAP;
0122
0123 for (i = 0; i < ARRAY_SIZE(map); i++) {
0124 if (engine->flags & BIT(map[i].engine))
0125 enabled |= BIT(map[i].sched);
0126 else
0127 disabled |= BIT(map[i].sched);
0128 }
0129 }
0130
0131 i915->caps.scheduler = enabled & ~disabled;
0132 if (!(i915->caps.scheduler & I915_SCHEDULER_CAP_ENABLED))
0133 i915->caps.scheduler = 0;
0134 }
0135
0136 const char *intel_engine_class_repr(u8 class)
0137 {
0138 static const char * const uabi_names[] = {
0139 [RENDER_CLASS] = "rcs",
0140 [COPY_ENGINE_CLASS] = "bcs",
0141 [VIDEO_DECODE_CLASS] = "vcs",
0142 [VIDEO_ENHANCEMENT_CLASS] = "vecs",
0143 [COMPUTE_CLASS] = "ccs",
0144 };
0145
0146 if (class >= ARRAY_SIZE(uabi_names) || !uabi_names[class])
0147 return "xxx";
0148
0149 return uabi_names[class];
0150 }
0151
0152 struct legacy_ring {
0153 struct intel_gt *gt;
0154 u8 class;
0155 u8 instance;
0156 };
0157
0158 static int legacy_ring_idx(const struct legacy_ring *ring)
0159 {
0160 static const struct {
0161 u8 base, max;
0162 } map[] = {
0163 [RENDER_CLASS] = { RCS0, 1 },
0164 [COPY_ENGINE_CLASS] = { BCS0, 1 },
0165 [VIDEO_DECODE_CLASS] = { VCS0, I915_MAX_VCS },
0166 [VIDEO_ENHANCEMENT_CLASS] = { VECS0, I915_MAX_VECS },
0167 [COMPUTE_CLASS] = { CCS0, I915_MAX_CCS },
0168 };
0169
0170 if (GEM_DEBUG_WARN_ON(ring->class >= ARRAY_SIZE(map)))
0171 return INVALID_ENGINE;
0172
0173 if (GEM_DEBUG_WARN_ON(ring->instance >= map[ring->class].max))
0174 return INVALID_ENGINE;
0175
0176 return map[ring->class].base + ring->instance;
0177 }
0178
0179 static void add_legacy_ring(struct legacy_ring *ring,
0180 struct intel_engine_cs *engine)
0181 {
0182 if (engine->gt != ring->gt || engine->class != ring->class) {
0183 ring->gt = engine->gt;
0184 ring->class = engine->class;
0185 ring->instance = 0;
0186 }
0187
0188 engine->legacy_idx = legacy_ring_idx(ring);
0189 if (engine->legacy_idx != INVALID_ENGINE)
0190 ring->instance++;
0191 }
0192
0193 void intel_engines_driver_register(struct drm_i915_private *i915)
0194 {
0195 struct legacy_ring ring = {};
0196 struct list_head *it, *next;
0197 struct rb_node **p, *prev;
0198 LIST_HEAD(engines);
0199
0200 sort_engines(i915, &engines);
0201
0202 prev = NULL;
0203 p = &i915->uabi_engines.rb_node;
0204 list_for_each_safe(it, next, &engines) {
0205 struct intel_engine_cs *engine =
0206 container_of((struct rb_node *)it, typeof(*engine),
0207 uabi_node);
0208 char old[sizeof(engine->name)];
0209
0210 if (intel_gt_has_unrecoverable_error(engine->gt))
0211 continue;
0212
0213 GEM_BUG_ON(engine->class >= ARRAY_SIZE(uabi_classes));
0214 engine->uabi_class = uabi_classes[engine->class];
0215
0216 GEM_BUG_ON(engine->uabi_class >=
0217 ARRAY_SIZE(i915->engine_uabi_class_count));
0218 engine->uabi_instance =
0219 i915->engine_uabi_class_count[engine->uabi_class]++;
0220
0221
0222 memcpy(old, engine->name, sizeof(engine->name));
0223 scnprintf(engine->name, sizeof(engine->name), "%s%u",
0224 intel_engine_class_repr(engine->class),
0225 engine->uabi_instance);
0226 DRM_DEBUG_DRIVER("renamed %s to %s\n", old, engine->name);
0227
0228 rb_link_node(&engine->uabi_node, prev, p);
0229 rb_insert_color(&engine->uabi_node, &i915->uabi_engines);
0230
0231 GEM_BUG_ON(intel_engine_lookup_user(i915,
0232 engine->uabi_class,
0233 engine->uabi_instance) != engine);
0234
0235
0236 add_legacy_ring(&ring, engine);
0237
0238 prev = &engine->uabi_node;
0239 p = &prev->rb_right;
0240 }
0241
0242 if (IS_ENABLED(CONFIG_DRM_I915_SELFTESTS) &&
0243 IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) {
0244 struct intel_engine_cs *engine;
0245 unsigned int isolation;
0246 int class, inst;
0247 int errors = 0;
0248
0249 for (class = 0; class < ARRAY_SIZE(i915->engine_uabi_class_count); class++) {
0250 for (inst = 0; inst < i915->engine_uabi_class_count[class]; inst++) {
0251 engine = intel_engine_lookup_user(i915,
0252 class, inst);
0253 if (!engine) {
0254 pr_err("UABI engine not found for { class:%d, instance:%d }\n",
0255 class, inst);
0256 errors++;
0257 continue;
0258 }
0259
0260 if (engine->uabi_class != class ||
0261 engine->uabi_instance != inst) {
0262 pr_err("Wrong UABI engine:%s { class:%d, instance:%d } found for { class:%d, instance:%d }\n",
0263 engine->name,
0264 engine->uabi_class,
0265 engine->uabi_instance,
0266 class, inst);
0267 errors++;
0268 continue;
0269 }
0270 }
0271 }
0272
0273
0274
0275
0276
0277 isolation = intel_engines_has_context_isolation(i915);
0278 for_each_uabi_engine(engine, i915) {
0279 unsigned int bit = BIT(engine->uabi_class);
0280 unsigned int expected = engine->default_state ? bit : 0;
0281
0282 if ((isolation & bit) != expected) {
0283 pr_err("mismatching default context state for class %d on engine %s\n",
0284 engine->uabi_class, engine->name);
0285 errors++;
0286 }
0287 }
0288
0289 if (drm_WARN(&i915->drm, errors,
0290 "Invalid UABI engine mapping found"))
0291 i915->uabi_engines = RB_ROOT;
0292 }
0293
0294 set_scheduler_caps(i915);
0295 }
0296
0297 unsigned int intel_engines_has_context_isolation(struct drm_i915_private *i915)
0298 {
0299 struct intel_engine_cs *engine;
0300 unsigned int which;
0301
0302 which = 0;
0303 for_each_uabi_engine(engine, i915)
0304 if (engine->default_state)
0305 which |= BIT(engine->uabi_class);
0306
0307 return which;
0308 }