15ca02815Sjsg // SPDX-License-Identifier: MIT 2c349dbc7Sjsg /* 3c349dbc7Sjsg * Copyright © 2019 Intel Corporation 4c349dbc7Sjsg */ 5c349dbc7Sjsg 6c349dbc7Sjsg #include <linux/list.h> 7c349dbc7Sjsg #include <linux/list_sort.h> 8c349dbc7Sjsg #include <linux/llist.h> 9c349dbc7Sjsg 10c349dbc7Sjsg #include "i915_drv.h" 11c349dbc7Sjsg #include "intel_engine.h" 12c349dbc7Sjsg #include "intel_engine_user.h" 13c349dbc7Sjsg #include "intel_gt.h" 145ca02815Sjsg #include "uc/intel_guc_submission.h" 15c349dbc7Sjsg 16c349dbc7Sjsg struct intel_engine_cs * 17c349dbc7Sjsg intel_engine_lookup_user(struct drm_i915_private *i915, u8 class, u8 instance) 18c349dbc7Sjsg { 19c349dbc7Sjsg struct rb_node *p = i915->uabi_engines.rb_node; 20c349dbc7Sjsg 21c349dbc7Sjsg while (p) { 22c349dbc7Sjsg struct intel_engine_cs *it = 23c349dbc7Sjsg rb_entry(p, typeof(*it), uabi_node); 24c349dbc7Sjsg 25c349dbc7Sjsg if (class < it->uabi_class) 26c349dbc7Sjsg p = p->rb_left; 27c349dbc7Sjsg else if (class > it->uabi_class || 28c349dbc7Sjsg instance > it->uabi_instance) 29c349dbc7Sjsg p = p->rb_right; 30c349dbc7Sjsg else if (instance < it->uabi_instance) 31c349dbc7Sjsg p = p->rb_left; 32c349dbc7Sjsg else 33c349dbc7Sjsg return it; 34c349dbc7Sjsg } 35c349dbc7Sjsg 36c349dbc7Sjsg return NULL; 37c349dbc7Sjsg } 38c349dbc7Sjsg 39c349dbc7Sjsg void intel_engine_add_user(struct intel_engine_cs *engine) 40c349dbc7Sjsg { 41c349dbc7Sjsg llist_add((struct llist_node *)&engine->uabi_node, 42c349dbc7Sjsg (struct llist_head *)&engine->i915->uabi_engines); 43c349dbc7Sjsg } 44c349dbc7Sjsg 45f005ef32Sjsg #define I915_NO_UABI_CLASS ((u16)(-1)) 46f005ef32Sjsg 47f005ef32Sjsg static const u16 uabi_classes[] = { 48c349dbc7Sjsg [RENDER_CLASS] = I915_ENGINE_CLASS_RENDER, 49c349dbc7Sjsg [COPY_ENGINE_CLASS] = I915_ENGINE_CLASS_COPY, 50c349dbc7Sjsg [VIDEO_DECODE_CLASS] = I915_ENGINE_CLASS_VIDEO, 51c349dbc7Sjsg [VIDEO_ENHANCEMENT_CLASS] = I915_ENGINE_CLASS_VIDEO_ENHANCE, 521bb76ff1Sjsg [COMPUTE_CLASS] = I915_ENGINE_CLASS_COMPUTE, 53f005ef32Sjsg [OTHER_CLASS] = I915_NO_UABI_CLASS, /* Not exposed to users, no uabi class. */ 54c349dbc7Sjsg }; 55c349dbc7Sjsg 566dafb210Sjsg static int engine_cmp(void *priv, const struct list_head *A, 576dafb210Sjsg const struct list_head *B) 58c349dbc7Sjsg { 59c349dbc7Sjsg const struct intel_engine_cs *a = 60c349dbc7Sjsg container_of((struct rb_node *)A, typeof(*a), uabi_node); 61c349dbc7Sjsg const struct intel_engine_cs *b = 62c349dbc7Sjsg container_of((struct rb_node *)B, typeof(*b), uabi_node); 63c349dbc7Sjsg 64c349dbc7Sjsg if (uabi_classes[a->class] < uabi_classes[b->class]) 65c349dbc7Sjsg return -1; 66c349dbc7Sjsg if (uabi_classes[a->class] > uabi_classes[b->class]) 67c349dbc7Sjsg return 1; 68c349dbc7Sjsg 69c349dbc7Sjsg if (a->instance < b->instance) 70c349dbc7Sjsg return -1; 71c349dbc7Sjsg if (a->instance > b->instance) 72c349dbc7Sjsg return 1; 73c349dbc7Sjsg 74c349dbc7Sjsg return 0; 75c349dbc7Sjsg } 76c349dbc7Sjsg 77c349dbc7Sjsg static struct llist_node *get_engines(struct drm_i915_private *i915) 78c349dbc7Sjsg { 79c349dbc7Sjsg return llist_del_all((struct llist_head *)&i915->uabi_engines); 80c349dbc7Sjsg } 81c349dbc7Sjsg 82c349dbc7Sjsg static void sort_engines(struct drm_i915_private *i915, 83c349dbc7Sjsg struct list_head *engines) 84c349dbc7Sjsg { 85c349dbc7Sjsg struct llist_node *pos, *next; 86c349dbc7Sjsg 87c349dbc7Sjsg llist_for_each_safe(pos, next, get_engines(i915)) { 88c349dbc7Sjsg struct intel_engine_cs *engine = 89c349dbc7Sjsg container_of((struct rb_node *)pos, typeof(*engine), 90c349dbc7Sjsg uabi_node); 91c349dbc7Sjsg list_add((struct list_head *)&engine->uabi_node, engines); 92c349dbc7Sjsg } 93c349dbc7Sjsg list_sort(NULL, engines, engine_cmp); 94c349dbc7Sjsg } 95c349dbc7Sjsg 96c349dbc7Sjsg #ifdef __linux__ 97c349dbc7Sjsg static void set_scheduler_caps(struct drm_i915_private *i915) 98c349dbc7Sjsg { 99c349dbc7Sjsg static const struct { 100c349dbc7Sjsg u8 engine; 101c349dbc7Sjsg u8 sched; 102c349dbc7Sjsg } map[] = { 103c349dbc7Sjsg #define MAP(x, y) { ilog2(I915_ENGINE_##x), ilog2(I915_SCHEDULER_CAP_##y) } 104c349dbc7Sjsg MAP(HAS_PREEMPTION, PREEMPTION), 105c349dbc7Sjsg MAP(HAS_SEMAPHORES, SEMAPHORES), 106c349dbc7Sjsg MAP(SUPPORTS_STATS, ENGINE_BUSY_STATS), 107c349dbc7Sjsg #undef MAP 108c349dbc7Sjsg }; 109c349dbc7Sjsg struct intel_engine_cs *engine; 110c349dbc7Sjsg u32 enabled, disabled; 111c349dbc7Sjsg 112c349dbc7Sjsg enabled = 0; 113c349dbc7Sjsg disabled = 0; 114c349dbc7Sjsg for_each_uabi_engine(engine, i915) { /* all engines must agree! */ 115c349dbc7Sjsg int i; 116c349dbc7Sjsg 1175ca02815Sjsg if (engine->sched_engine->schedule) 118c349dbc7Sjsg enabled |= (I915_SCHEDULER_CAP_ENABLED | 119c349dbc7Sjsg I915_SCHEDULER_CAP_PRIORITY); 120c349dbc7Sjsg else 121c349dbc7Sjsg disabled |= (I915_SCHEDULER_CAP_ENABLED | 122c349dbc7Sjsg I915_SCHEDULER_CAP_PRIORITY); 123c349dbc7Sjsg 124f005ef32Sjsg if (intel_uc_uses_guc_submission(&engine->gt->uc)) 1255ca02815Sjsg enabled |= I915_SCHEDULER_CAP_STATIC_PRIORITY_MAP; 1265ca02815Sjsg 127c349dbc7Sjsg for (i = 0; i < ARRAY_SIZE(map); i++) { 128c349dbc7Sjsg if (engine->flags & BIT(map[i].engine)) 129c349dbc7Sjsg enabled |= BIT(map[i].sched); 130c349dbc7Sjsg else 131c349dbc7Sjsg disabled |= BIT(map[i].sched); 132c349dbc7Sjsg } 133c349dbc7Sjsg } 134c349dbc7Sjsg 135c349dbc7Sjsg i915->caps.scheduler = enabled & ~disabled; 136c349dbc7Sjsg if (!(i915->caps.scheduler & I915_SCHEDULER_CAP_ENABLED)) 137c349dbc7Sjsg i915->caps.scheduler = 0; 138c349dbc7Sjsg } 139c349dbc7Sjsg #else 140c349dbc7Sjsg /* without the pointless ilog2 -> BIT() */ 141c349dbc7Sjsg static void set_scheduler_caps(struct drm_i915_private *i915) 142c349dbc7Sjsg { 143c349dbc7Sjsg static const struct { 144c349dbc7Sjsg u8 engine; 145c349dbc7Sjsg u8 sched; 146c349dbc7Sjsg } map[] = { 147c349dbc7Sjsg #define MAP(x, y) { I915_ENGINE_##x, I915_SCHEDULER_CAP_##y } 148c349dbc7Sjsg MAP(HAS_PREEMPTION, PREEMPTION), 149c349dbc7Sjsg MAP(HAS_SEMAPHORES, SEMAPHORES), 150c349dbc7Sjsg MAP(SUPPORTS_STATS, ENGINE_BUSY_STATS), 151c349dbc7Sjsg #undef MAP 152c349dbc7Sjsg }; 153c349dbc7Sjsg struct intel_engine_cs *engine; 154c349dbc7Sjsg u32 enabled, disabled; 155c349dbc7Sjsg 156c349dbc7Sjsg enabled = 0; 157c349dbc7Sjsg disabled = 0; 158c349dbc7Sjsg for_each_uabi_engine(engine, i915) { /* all engines must agree! */ 159c349dbc7Sjsg int i; 160c349dbc7Sjsg 1615ca02815Sjsg if (engine->sched_engine->schedule) 162c349dbc7Sjsg enabled |= (I915_SCHEDULER_CAP_ENABLED | 163c349dbc7Sjsg I915_SCHEDULER_CAP_PRIORITY); 164c349dbc7Sjsg else 165c349dbc7Sjsg disabled |= (I915_SCHEDULER_CAP_ENABLED | 166c349dbc7Sjsg I915_SCHEDULER_CAP_PRIORITY); 167c349dbc7Sjsg 168*88ee63d7Sjsg if (intel_uc_uses_guc_submission(&engine->gt->uc)) 1695ca02815Sjsg enabled |= I915_SCHEDULER_CAP_STATIC_PRIORITY_MAP; 1705ca02815Sjsg 171c349dbc7Sjsg for (i = 0; i < ARRAY_SIZE(map); i++) { 172c349dbc7Sjsg if (engine->flags & map[i].engine) 173c349dbc7Sjsg enabled |= map[i].sched; 174c349dbc7Sjsg else 175c349dbc7Sjsg disabled |= map[i].sched; 176c349dbc7Sjsg } 177c349dbc7Sjsg } 178c349dbc7Sjsg 179c349dbc7Sjsg i915->caps.scheduler = enabled & ~disabled; 180c349dbc7Sjsg if (!(i915->caps.scheduler & I915_SCHEDULER_CAP_ENABLED)) 181c349dbc7Sjsg i915->caps.scheduler = 0; 182c349dbc7Sjsg } 183c349dbc7Sjsg #endif 184c349dbc7Sjsg 185c349dbc7Sjsg const char *intel_engine_class_repr(u8 class) 186c349dbc7Sjsg { 187c349dbc7Sjsg static const char * const uabi_names[] = { 188c349dbc7Sjsg [RENDER_CLASS] = "rcs", 189c349dbc7Sjsg [COPY_ENGINE_CLASS] = "bcs", 190c349dbc7Sjsg [VIDEO_DECODE_CLASS] = "vcs", 191c349dbc7Sjsg [VIDEO_ENHANCEMENT_CLASS] = "vecs", 192f005ef32Sjsg [OTHER_CLASS] = "other", 1931bb76ff1Sjsg [COMPUTE_CLASS] = "ccs", 194c349dbc7Sjsg }; 195c349dbc7Sjsg 196c349dbc7Sjsg if (class >= ARRAY_SIZE(uabi_names) || !uabi_names[class]) 197c349dbc7Sjsg return "xxx"; 198c349dbc7Sjsg 199c349dbc7Sjsg return uabi_names[class]; 200c349dbc7Sjsg } 201c349dbc7Sjsg 202c349dbc7Sjsg struct legacy_ring { 203c349dbc7Sjsg struct intel_gt *gt; 204c349dbc7Sjsg u8 class; 205c349dbc7Sjsg u8 instance; 206c349dbc7Sjsg }; 207c349dbc7Sjsg 208c349dbc7Sjsg static int legacy_ring_idx(const struct legacy_ring *ring) 209c349dbc7Sjsg { 210c349dbc7Sjsg static const struct { 211c349dbc7Sjsg u8 base, max; 212c349dbc7Sjsg } map[] = { 213c349dbc7Sjsg [RENDER_CLASS] = { RCS0, 1 }, 214c349dbc7Sjsg [COPY_ENGINE_CLASS] = { BCS0, 1 }, 215c349dbc7Sjsg [VIDEO_DECODE_CLASS] = { VCS0, I915_MAX_VCS }, 216c349dbc7Sjsg [VIDEO_ENHANCEMENT_CLASS] = { VECS0, I915_MAX_VECS }, 2171bb76ff1Sjsg [COMPUTE_CLASS] = { CCS0, I915_MAX_CCS }, 218c349dbc7Sjsg }; 219c349dbc7Sjsg 220c349dbc7Sjsg if (GEM_DEBUG_WARN_ON(ring->class >= ARRAY_SIZE(map))) 221c349dbc7Sjsg return INVALID_ENGINE; 222c349dbc7Sjsg 223c349dbc7Sjsg if (GEM_DEBUG_WARN_ON(ring->instance >= map[ring->class].max)) 224c349dbc7Sjsg return INVALID_ENGINE; 225c349dbc7Sjsg 226c349dbc7Sjsg return map[ring->class].base + ring->instance; 227c349dbc7Sjsg } 228c349dbc7Sjsg 229c349dbc7Sjsg static void add_legacy_ring(struct legacy_ring *ring, 230c349dbc7Sjsg struct intel_engine_cs *engine) 231c349dbc7Sjsg { 232c349dbc7Sjsg if (engine->gt != ring->gt || engine->class != ring->class) { 233c349dbc7Sjsg ring->gt = engine->gt; 234c349dbc7Sjsg ring->class = engine->class; 235c349dbc7Sjsg ring->instance = 0; 236c349dbc7Sjsg } 237c349dbc7Sjsg 238c349dbc7Sjsg engine->legacy_idx = legacy_ring_idx(ring); 239c349dbc7Sjsg if (engine->legacy_idx != INVALID_ENGINE) 240c349dbc7Sjsg ring->instance++; 241c349dbc7Sjsg } 242c349dbc7Sjsg 243f005ef32Sjsg static void engine_rename(struct intel_engine_cs *engine, const char *name, u16 instance) 244f005ef32Sjsg { 245f005ef32Sjsg char old[sizeof(engine->name)]; 246f005ef32Sjsg 247f005ef32Sjsg memcpy(old, engine->name, sizeof(engine->name)); 248f005ef32Sjsg scnprintf(engine->name, sizeof(engine->name), "%s%u", name, instance); 249f005ef32Sjsg drm_dbg(&engine->i915->drm, "renamed %s to %s\n", old, engine->name); 250f005ef32Sjsg } 251f005ef32Sjsg 252c349dbc7Sjsg void intel_engines_driver_register(struct drm_i915_private *i915) 253c349dbc7Sjsg { 254f005ef32Sjsg u16 name_instance, other_instance = 0; 255c349dbc7Sjsg struct legacy_ring ring = {}; 256c349dbc7Sjsg struct list_head *it, *next; 257c349dbc7Sjsg struct rb_node **p, *prev; 258c349dbc7Sjsg DRM_LIST_HEAD(engines); 259c349dbc7Sjsg 260c349dbc7Sjsg sort_engines(i915, &engines); 261c349dbc7Sjsg 262c349dbc7Sjsg prev = NULL; 263c349dbc7Sjsg p = &i915->uabi_engines.rb_node; 264c349dbc7Sjsg list_for_each_safe(it, next, &engines) { 265c349dbc7Sjsg struct intel_engine_cs *engine = 266c349dbc7Sjsg container_of((struct rb_node *)it, typeof(*engine), 267c349dbc7Sjsg uabi_node); 268c349dbc7Sjsg 269ad8b1aafSjsg if (intel_gt_has_unrecoverable_error(engine->gt)) 270c349dbc7Sjsg continue; /* ignore incomplete engines */ 271c349dbc7Sjsg 272c349dbc7Sjsg GEM_BUG_ON(engine->class >= ARRAY_SIZE(uabi_classes)); 273c349dbc7Sjsg engine->uabi_class = uabi_classes[engine->class]; 274f005ef32Sjsg if (engine->uabi_class == I915_NO_UABI_CLASS) { 275f005ef32Sjsg name_instance = other_instance++; 276f005ef32Sjsg } else { 2771bb76ff1Sjsg GEM_BUG_ON(engine->uabi_class >= 2781bb76ff1Sjsg ARRAY_SIZE(i915->engine_uabi_class_count)); 279f005ef32Sjsg name_instance = 2801bb76ff1Sjsg i915->engine_uabi_class_count[engine->uabi_class]++; 281f005ef32Sjsg } 282f005ef32Sjsg engine->uabi_instance = name_instance; 283c349dbc7Sjsg 284f005ef32Sjsg /* 285f005ef32Sjsg * Replace the internal name with the final user and log facing 286f005ef32Sjsg * name. 287f005ef32Sjsg */ 288f005ef32Sjsg engine_rename(engine, 289c349dbc7Sjsg intel_engine_class_repr(engine->class), 290f005ef32Sjsg name_instance); 291f005ef32Sjsg 292f005ef32Sjsg if (engine->uabi_class == I915_NO_UABI_CLASS) 293f005ef32Sjsg continue; 294c349dbc7Sjsg 295c349dbc7Sjsg rb_link_node(&engine->uabi_node, prev, p); 296c349dbc7Sjsg rb_insert_color(&engine->uabi_node, &i915->uabi_engines); 297c349dbc7Sjsg 298c349dbc7Sjsg GEM_BUG_ON(intel_engine_lookup_user(i915, 299c349dbc7Sjsg engine->uabi_class, 300c349dbc7Sjsg engine->uabi_instance) != engine); 301c349dbc7Sjsg 302c349dbc7Sjsg /* Fix up the mapping to match default execbuf::user_map[] */ 303c349dbc7Sjsg add_legacy_ring(&ring, engine); 304c349dbc7Sjsg 305c349dbc7Sjsg prev = &engine->uabi_node; 306c349dbc7Sjsg p = &prev->rb_right; 307c349dbc7Sjsg } 308c349dbc7Sjsg 309c349dbc7Sjsg if (IS_ENABLED(CONFIG_DRM_I915_SELFTESTS) && 310c349dbc7Sjsg IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) { 311c349dbc7Sjsg struct intel_engine_cs *engine; 312c349dbc7Sjsg unsigned int isolation; 313c349dbc7Sjsg int class, inst; 314c349dbc7Sjsg int errors = 0; 315c349dbc7Sjsg 3161bb76ff1Sjsg for (class = 0; class < ARRAY_SIZE(i915->engine_uabi_class_count); class++) { 3171bb76ff1Sjsg for (inst = 0; inst < i915->engine_uabi_class_count[class]; inst++) { 318c349dbc7Sjsg engine = intel_engine_lookup_user(i915, 319c349dbc7Sjsg class, inst); 320c349dbc7Sjsg if (!engine) { 321c349dbc7Sjsg pr_err("UABI engine not found for { class:%d, instance:%d }\n", 322c349dbc7Sjsg class, inst); 323c349dbc7Sjsg errors++; 324c349dbc7Sjsg continue; 325c349dbc7Sjsg } 326c349dbc7Sjsg 327c349dbc7Sjsg if (engine->uabi_class != class || 328c349dbc7Sjsg engine->uabi_instance != inst) { 329c349dbc7Sjsg pr_err("Wrong UABI engine:%s { class:%d, instance:%d } found for { class:%d, instance:%d }\n", 330c349dbc7Sjsg engine->name, 331c349dbc7Sjsg engine->uabi_class, 332c349dbc7Sjsg engine->uabi_instance, 333c349dbc7Sjsg class, inst); 334c349dbc7Sjsg errors++; 335c349dbc7Sjsg continue; 336c349dbc7Sjsg } 337c349dbc7Sjsg } 338c349dbc7Sjsg } 339c349dbc7Sjsg 340c349dbc7Sjsg /* 341c349dbc7Sjsg * Make sure that classes with multiple engine instances all 342c349dbc7Sjsg * share the same basic configuration. 343c349dbc7Sjsg */ 344c349dbc7Sjsg isolation = intel_engines_has_context_isolation(i915); 345c349dbc7Sjsg for_each_uabi_engine(engine, i915) { 346c349dbc7Sjsg unsigned int bit = BIT(engine->uabi_class); 347c349dbc7Sjsg unsigned int expected = engine->default_state ? bit : 0; 348c349dbc7Sjsg 349c349dbc7Sjsg if ((isolation & bit) != expected) { 350c349dbc7Sjsg pr_err("mismatching default context state for class %d on engine %s\n", 351c349dbc7Sjsg engine->uabi_class, engine->name); 352c349dbc7Sjsg errors++; 353c349dbc7Sjsg } 354c349dbc7Sjsg } 355c349dbc7Sjsg 356c349dbc7Sjsg if (drm_WARN(&i915->drm, errors, 357c349dbc7Sjsg "Invalid UABI engine mapping found")) 358c349dbc7Sjsg i915->uabi_engines = RB_ROOT; 359c349dbc7Sjsg } 360c349dbc7Sjsg 361c349dbc7Sjsg set_scheduler_caps(i915); 362c349dbc7Sjsg } 363c349dbc7Sjsg 364c349dbc7Sjsg unsigned int intel_engines_has_context_isolation(struct drm_i915_private *i915) 365c349dbc7Sjsg { 366c349dbc7Sjsg struct intel_engine_cs *engine; 367c349dbc7Sjsg unsigned int which; 368c349dbc7Sjsg 369c349dbc7Sjsg which = 0; 370c349dbc7Sjsg for_each_uabi_engine(engine, i915) 371c349dbc7Sjsg if (engine->default_state) 372c349dbc7Sjsg which |= BIT(engine->uabi_class); 373c349dbc7Sjsg 374c349dbc7Sjsg return which; 375c349dbc7Sjsg } 376