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