xref: /aosp_15_r20/external/igt-gpu-tools/tests/i915/gem_ctx_engines.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
1 /*
2  * Copyright © 2018 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  */
24 
25 #include "igt.h"
26 
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <inttypes.h>
34 #include <errno.h>
35 #include <sys/stat.h>
36 #include <sys/ioctl.h>
37 #include <sys/time.h>
38 
39 #include <drm.h>
40 
41 #include "i915/gem_context.h"
42 #include "sw_sync.h"
43 
44 #define engine_class(e, n) ((e)->engines[(n)].engine_class)
45 #define engine_instance(e, n) ((e)->engines[(n)].engine_instance)
46 
has_context_engines(int i915)47 static bool has_context_engines(int i915)
48 {
49 	struct drm_i915_gem_context_param param = {
50 		.ctx_id = 0,
51 		.param = I915_CONTEXT_PARAM_ENGINES,
52 	};
53 	return __gem_context_set_param(i915, &param) == 0;
54 }
55 
invalid_engines(int i915)56 static void invalid_engines(int i915)
57 {
58 	struct i915_context_param_engines stack = {}, *engines;
59 	struct drm_i915_gem_context_param param = {
60 		.ctx_id = gem_context_create(i915),
61 		.param = I915_CONTEXT_PARAM_ENGINES,
62 		.value = to_user_pointer(&stack),
63 	};
64 	uint32_t handle;
65 	void *ptr;
66 
67 	param.size = 0;
68 	igt_assert_eq(__gem_context_set_param(i915, &param), 0);
69 
70 	param.size = 1;
71 	igt_assert_eq(__gem_context_set_param(i915, &param), -EINVAL);
72 
73 	param.size = sizeof(stack) - 1;
74 	igt_assert_eq(__gem_context_set_param(i915, &param), -EINVAL);
75 
76 	param.size = sizeof(stack) + 1;
77 	igt_assert_eq(__gem_context_set_param(i915, &param), -EINVAL);
78 
79 	param.size = 0;
80 	igt_assert_eq(__gem_context_set_param(i915, &param), 0);
81 
82 	/* Create a single page surrounded by inaccessible nothingness */
83 	ptr = mmap(NULL, 3 * 4096, PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
84 	igt_assert(ptr != MAP_FAILED);
85 
86 	munmap(ptr, 4096);
87 	engines = ptr + 4096;
88 	munmap(ptr + 2 *4096, 4096);
89 
90 	param.size = sizeof(*engines) + sizeof(*engines->engines);
91 	param.value = to_user_pointer(engines);
92 
93 	engines->engines[0].engine_class = -1;
94 	igt_assert_eq(__gem_context_set_param(i915, &param), -ENOENT);
95 
96 	mprotect(engines, 4096, PROT_READ);
97 	igt_assert_eq(__gem_context_set_param(i915, &param), -ENOENT);
98 
99 	mprotect(engines, 4096, PROT_WRITE);
100 	engines->engines[0].engine_class = 0;
101 	if (__gem_context_set_param(i915, &param)) /* XXX needs RCS */
102 		goto out;
103 
104 	engines->extensions = to_user_pointer(ptr);
105 	igt_assert_eq(__gem_context_set_param(i915, &param), -EFAULT);
106 
107 	engines->extensions = 0;
108 	igt_assert_eq(__gem_context_set_param(i915, &param), 0);
109 
110 	param.value = to_user_pointer(engines - 1);
111 	igt_assert_eq(__gem_context_set_param(i915, &param), -EFAULT);
112 
113 	param.value = to_user_pointer(engines) - 1;
114 	igt_assert_eq(__gem_context_set_param(i915, &param), -EFAULT);
115 
116 	param.value = to_user_pointer(engines) - param.size +  1;
117 	igt_assert_eq(__gem_context_set_param(i915, &param), -EFAULT);
118 
119 	param.value = to_user_pointer(engines) + 4096;
120 	igt_assert_eq(__gem_context_set_param(i915, &param), -EFAULT);
121 
122 	param.value = to_user_pointer(engines) - param.size + 4096;
123 	igt_assert_eq(__gem_context_set_param(i915, &param), 0);
124 
125 	param.value = to_user_pointer(engines) - param.size + 4096 + 1;
126 	igt_assert_eq(__gem_context_set_param(i915, &param), -EFAULT);
127 
128 	param.value = to_user_pointer(engines) + 4096;
129 	igt_assert_eq(__gem_context_set_param(i915, &param), -EFAULT);
130 
131 	param.value = to_user_pointer(engines) + 4096 - 1;
132 	igt_assert_eq(__gem_context_set_param(i915, &param), -EFAULT);
133 
134 	param.value = to_user_pointer(engines) - 1;
135 	igt_assert_eq(__gem_context_set_param(i915, &param), -EFAULT);
136 
137 	param.value = to_user_pointer(engines - 1);
138 	igt_assert_eq(__gem_context_set_param(i915, &param), -EFAULT);
139 
140 	param.value = to_user_pointer(engines - 1) + 4096;
141 	igt_assert_eq(__gem_context_set_param(i915, &param), -EFAULT);
142 
143 	param.value = to_user_pointer(engines - 1) + 4096 - sizeof(*engines->engines) / 2;
144 	igt_assert_eq(__gem_context_set_param(i915, &param), -EFAULT);
145 
146 	handle = gem_create(i915, 4096 * 3);
147 	ptr = gem_mmap__gtt(i915, handle, 4096 * 3, PROT_READ);
148 	gem_close(i915, handle);
149 
150 	munmap(ptr, 4096);
151 	munmap(ptr + 8192, 4096);
152 
153 	param.value = to_user_pointer(ptr + 4096);
154 	igt_assert_eq(__gem_context_set_param(i915, &param), 0);
155 
156 	param.value = to_user_pointer(ptr);
157 	igt_assert_eq(__gem_context_set_param(i915, &param), -EFAULT);
158 
159 	param.value = to_user_pointer(ptr) + 4095;
160 	igt_assert_eq(__gem_context_set_param(i915, &param), -EFAULT);
161 
162 	param.value = to_user_pointer(ptr) + 8192;
163 	igt_assert_eq(__gem_context_set_param(i915, &param), -EFAULT);
164 
165 	param.value = to_user_pointer(ptr) + 12287;
166 	igt_assert_eq(__gem_context_set_param(i915, &param), -EFAULT);
167 
168 	munmap(ptr + 4096, 4096);
169 
170 out:
171 	munmap(engines, 4096);
172 	gem_context_destroy(i915, param.ctx_id);
173 }
174 
idempotent(int i915)175 static void idempotent(int i915)
176 {
177 	I915_DEFINE_CONTEXT_PARAM_ENGINES(engines , I915_EXEC_RING_MASK + 1);
178 	I915_DEFINE_CONTEXT_PARAM_ENGINES(expected , I915_EXEC_RING_MASK + 1);
179 	struct drm_i915_gem_context_param p = {
180 		.ctx_id = gem_context_create(i915),
181 		.param = I915_CONTEXT_PARAM_ENGINES,
182 		.value = to_user_pointer(&engines),
183 		.size = sizeof(engines),
184 	};
185 	const size_t base = sizeof(struct i915_context_param_engines);
186 	const struct intel_execution_engine2 *e;
187 	int idx;
188 
189 	/* What goes in, must come out. And what comes out, must go in */
190 
191 	gem_context_get_param(i915, &p);
192 	igt_assert_eq(p.size, 0); /* atm default is to use legacy ring mask */
193 
194 	idx = 0;
195 	memset(&engines, 0, sizeof(engines));
196 	__for_each_physical_engine(i915, e) {
197 		engines.engines[idx].engine_class = e->class;
198 		engines.engines[idx].engine_instance = e->instance;
199 		idx++;
200 	}
201 	idx *= sizeof(*engines.engines);
202 	p.size = base + idx;
203 	gem_context_set_param(i915, &p);
204 
205 	memcpy(&expected, &engines, sizeof(expected));
206 
207 	gem_context_get_param(i915, &p);
208 	igt_assert_eq(p.size, base + idx);
209 	igt_assert(!memcmp(&expected, &engines, idx));
210 
211 	p.size = base;
212 	gem_context_set_param(i915, &p);
213 	gem_context_get_param(i915, &p);
214 	igt_assert_eq(p.size, base);
215 
216 	/* and it should not have overwritten the previous contents */
217 	igt_assert(!memcmp(&expected, &engines, idx));
218 
219 	memset(&engines, 0, sizeof(engines));
220 	engines.engines[0].engine_class = I915_ENGINE_CLASS_INVALID;
221 	engines.engines[0].engine_instance = I915_ENGINE_CLASS_INVALID_NONE;
222 	idx = sizeof(*engines.engines);
223 	p.size = base + idx;
224 	gem_context_set_param(i915, &p);
225 
226 	memcpy(&expected, &engines, sizeof(expected));
227 
228 	gem_context_get_param(i915, &p);
229 	igt_assert_eq(p.size, base + idx);
230 	igt_assert(!memcmp(&expected, &engines, idx));
231 
232 	memset(&engines, 0, sizeof(engines));
233 	p.size = sizeof(engines);
234 	gem_context_set_param(i915, &p);
235 
236 	memcpy(&expected, &engines, sizeof(expected));
237 
238 	gem_context_get_param(i915, &p);
239 	igt_assert_eq(p.size, sizeof(engines));
240 	igt_assert(!memcmp(&expected, &engines, idx));
241 
242 	gem_context_destroy(i915, p.ctx_id);
243 }
244 
execute_one(int i915)245 static void execute_one(int i915)
246 {
247 	I915_DEFINE_CONTEXT_PARAM_ENGINES(engines , I915_EXEC_RING_MASK + 1);
248 	struct drm_i915_gem_context_param param = {
249 		.ctx_id = gem_context_create(i915),
250 		.param = I915_CONTEXT_PARAM_ENGINES,
251 		.value = to_user_pointer(&engines),
252 		/* .size to be filled in later */
253 	};
254 	struct drm_i915_gem_exec_object2 obj = {
255 		.handle = gem_create(i915, 4096),
256 	};
257 	struct drm_i915_gem_execbuffer2 execbuf = {
258 		.buffers_ptr = to_user_pointer(&obj),
259 		.buffer_count = 1,
260 		.rsvd1 = param.ctx_id,
261 	};
262 	const uint32_t bbe = MI_BATCH_BUFFER_END;
263 	const struct intel_execution_engine2 *e;
264 
265 	gem_write(i915, obj.handle, 0, &bbe, sizeof(bbe));
266 
267 	/* Unadulterated I915_EXEC_DEFAULT should work */
268 	execbuf.flags = 0;
269 	gem_execbuf(i915, &execbuf);
270 	gem_sync(i915, obj.handle);
271 
272 	__for_each_physical_engine(i915, e) {
273 		struct drm_i915_gem_busy busy = { .handle = obj.handle };
274 
275 		for (int i = -1; i <= I915_EXEC_RING_MASK; i++) {
276 			igt_spin_t *spin;
277 
278 			memset(&engines, 0, sizeof(engines));
279 			engine_class(&engines, 0) = e->class;
280 			engine_instance(&engines, 0) = e->instance;
281 			param.size = offsetof(typeof(engines), engines[1]);
282 			gem_context_set_param(i915, &param);
283 
284 			spin = igt_spin_new(i915,
285 					    .ctx = param.ctx_id,
286 					    .engine = 0,
287 					    .flags = (IGT_SPIN_NO_PREEMPTION |
288 						      IGT_SPIN_POLL_RUN));
289 
290 			igt_debug("Testing with map of %d engines\n", i + 1);
291 			memset(&engines.engines, -1, sizeof(engines.engines));
292 			if (i != -1) {
293 				engine_class(&engines, i) = e->class;
294 				engine_instance(&engines, i) = e->instance;
295 			}
296 			param.size = sizeof(uint64_t) + (i + 1) * sizeof(uint32_t);
297 			gem_context_set_param(i915, &param);
298 
299 			igt_spin_busywait_until_started(spin);
300 			for (int j = 0; j <= I915_EXEC_RING_MASK; j++) {
301 				int expected = j == i ? 0 : -EINVAL;
302 
303 				execbuf.flags = j;
304 				igt_assert_f(__gem_execbuf(i915, &execbuf) == expected,
305 					     "Failed to report the %s engine for slot %d (valid at %d)\n",
306 					     j == i ? "valid" : "invalid", j, i);
307 			}
308 
309 			do_ioctl(i915, DRM_IOCTL_I915_GEM_BUSY, &busy);
310 			igt_assert_eq(busy.busy, i != -1 ? 1 << (e->class + 16) : 0);
311 
312 			igt_spin_free(i915, spin);
313 
314 			gem_sync(i915, obj.handle);
315 			do_ioctl(i915, DRM_IOCTL_I915_GEM_BUSY, &busy);
316 			igt_assert_eq(busy.busy, 0);
317 		}
318 	}
319 
320 	/* Restore the defaults and check I915_EXEC_DEFAULT works again. */
321 	param.size = 0;
322 	gem_context_set_param(i915, &param);
323 	execbuf.flags = 0;
324 	gem_execbuf(i915, &execbuf);
325 
326 	gem_close(i915, obj.handle);
327 	gem_context_destroy(i915, param.ctx_id);
328 }
329 
execute_oneforall(int i915)330 static void execute_oneforall(int i915)
331 {
332 	I915_DEFINE_CONTEXT_PARAM_ENGINES(engines , I915_EXEC_RING_MASK + 1);
333 	struct drm_i915_gem_context_param param = {
334 		.ctx_id = gem_context_create(i915),
335 		.param = I915_CONTEXT_PARAM_ENGINES,
336 		.value = to_user_pointer(&engines),
337 		.size = sizeof(engines),
338 	};
339 	const struct intel_execution_engine2 *e;
340 
341 	__for_each_physical_engine(i915, e) {
342 		memset(&engines, 0, sizeof(engines));
343 		for (int i = 0; i <= I915_EXEC_RING_MASK; i++) {
344 			engine_class(&engines, i) = e->class;
345 			engine_instance(&engines, i) = e->instance;
346 		}
347 		gem_context_set_param(i915, &param);
348 
349 		for (int i = 0; i <= I915_EXEC_RING_MASK; i++) {
350 			struct drm_i915_gem_busy busy = {};
351 			igt_spin_t *spin;
352 
353 			spin = __igt_spin_new(i915,
354 					      .ctx = param.ctx_id,
355 					      .engine = i);
356 
357 			busy.handle = spin->handle;
358 			do_ioctl(i915, DRM_IOCTL_I915_GEM_BUSY, &busy);
359 			igt_assert_eq(busy.busy, 1 << (e->class + 16));
360 
361 			igt_spin_free(i915, spin);
362 		}
363 	}
364 
365 	gem_context_destroy(i915, param.ctx_id);
366 }
367 
execute_allforone(int i915)368 static void execute_allforone(int i915)
369 {
370 	I915_DEFINE_CONTEXT_PARAM_ENGINES(engines , I915_EXEC_RING_MASK + 1);
371 	struct drm_i915_gem_context_param param = {
372 		.ctx_id = gem_context_create(i915),
373 		.param = I915_CONTEXT_PARAM_ENGINES,
374 		.value = to_user_pointer(&engines),
375 	};
376 	const struct intel_execution_engine2 *e;
377 	int i;
378 
379 	i = 0;
380 	memset(&engines, 0, sizeof(engines));
381 	__for_each_physical_engine(i915, e) {
382 		engine_class(&engines, i) = e->class;
383 		engine_instance(&engines, i) = e->instance;
384 		i++;
385 	}
386 	param.size = sizeof(uint64_t) + i * sizeof(uint32_t);
387 	gem_context_set_param(i915, &param);
388 
389 	i = 0;
390 	__for_each_physical_engine(i915, e) {
391 		struct drm_i915_gem_busy busy = {};
392 		igt_spin_t *spin;
393 
394 		spin = __igt_spin_new(i915,
395 				      .ctx = param.ctx_id,
396 				      .engine = i++);
397 
398 		busy.handle = spin->handle;
399 		do_ioctl(i915, DRM_IOCTL_I915_GEM_BUSY, &busy);
400 		igt_assert_eq(busy.busy, 1 << (e->class + 16));
401 
402 		igt_spin_free(i915, spin);
403 	}
404 
405 	gem_context_destroy(i915, param.ctx_id);
406 }
407 
read_result(int timeline,uint32_t * map,int idx)408 static uint32_t read_result(int timeline, uint32_t *map, int idx)
409 {
410 	sw_sync_timeline_inc(timeline, 1);
411 	while (!READ_ONCE(map[idx]))
412 		;
413 	return map[idx];
414 }
415 
independent(int i915)416 static void independent(int i915)
417 {
418 #define RCS_TIMESTAMP (0x2000 + 0x358)
419 	const int gen = intel_gen(intel_get_drm_devid(i915));
420 	const int has_64bit_reloc = gen >= 8;
421 	I915_DEFINE_CONTEXT_PARAM_ENGINES(engines , I915_EXEC_RING_MASK + 1);
422 	struct drm_i915_gem_context_param param = {
423 		.ctx_id = gem_context_create(i915),
424 		.param = I915_CONTEXT_PARAM_ENGINES,
425 		.value = to_user_pointer(&engines),
426 		.size = sizeof(engines),
427 	};
428 	struct drm_i915_gem_exec_object2 results = { .handle = gem_create(i915, 4096) };
429 	const uint32_t bbe = MI_BATCH_BUFFER_END;
430 	int timeline = sw_sync_timeline_create();
431 	uint32_t last, *map;
432 
433 	igt_require(gen >= 6); /* No per-engine TIMESTAMP on older gen */
434 	igt_require(gem_scheduler_enabled(i915));
435 
436 	{
437 		struct drm_i915_gem_execbuffer2 execbuf = {
438 			.buffers_ptr = to_user_pointer(&results),
439 			.buffer_count = 1,
440 			.rsvd1 = param.ctx_id,
441 		};
442 		gem_write(i915, results.handle, 0, &bbe, sizeof(bbe));
443 		gem_execbuf(i915, &execbuf);
444 		results.flags = EXEC_OBJECT_PINNED;
445 	}
446 
447 	memset(&engines, 0, sizeof(engines)); /* All rcs0 */
448 	gem_context_set_param(i915, &param);
449 
450 	gem_set_caching(i915, results.handle, I915_CACHING_CACHED);
451 	map = gem_mmap__cpu(i915, results.handle, 0, 4096, PROT_READ);
452 	gem_set_domain(i915, results.handle,
453 		       I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
454 	memset(map, 0, 4096);
455 
456 	for (int i = 0; i < I915_EXEC_RING_MASK + 1; i++) {
457 		struct drm_i915_gem_exec_object2 obj[2] = {
458 			results, /* write hazard lies! */
459 			{ .handle = gem_create(i915, 4096) },
460 		};
461 		struct drm_i915_gem_execbuffer2 execbuf = {
462 			.buffers_ptr = to_user_pointer(obj),
463 			.buffer_count = 2,
464 			.rsvd1 = param.ctx_id,
465 			.rsvd2 = sw_sync_timeline_create_fence(timeline, i + 1),
466 			.flags = (I915_EXEC_RING_MASK - i) | I915_EXEC_FENCE_IN,
467 		};
468 		uint64_t offset = results.offset + 4 * i;
469 		uint32_t *cs;
470 		int j = 0;
471 
472 		cs = gem_mmap__cpu(i915, obj[1].handle, 0, 4096, PROT_WRITE);
473 
474 		cs[j] = 0x24 << 23 | 1; /* SRM */
475 		if (has_64bit_reloc)
476 			cs[j]++;
477 		j++;
478 		cs[j++] = RCS_TIMESTAMP;
479 		cs[j++] = offset;
480 		if (has_64bit_reloc)
481 			cs[j++] = offset >> 32;
482 		cs[j++] = MI_BATCH_BUFFER_END;
483 
484 		munmap(cs, 4096);
485 
486 		gem_execbuf(i915, &execbuf);
487 		gem_close(i915, obj[1].handle);
488 		close(execbuf.rsvd2);
489 	}
490 
491 	last = read_result(timeline, map, 0);
492 	for (int i = 1; i < I915_EXEC_RING_MASK + 1; i++) {
493 		uint32_t t = read_result(timeline, map, i);
494 		igt_assert_f(t - last > 0,
495 			     "Engine instance [%d] executed too late, previous timestamp %08x, now %08x\n",
496 			     i, last, t);
497 		last = t;
498 	}
499 	munmap(map, 4096);
500 
501 	close(timeline);
502 	gem_sync(i915, results.handle);
503 	gem_close(i915, results.handle);
504 
505 	gem_context_destroy(i915, param.ctx_id);
506 }
507 
508 igt_main
509 {
510 	int i915 = -1;
511 
512 	igt_fixture {
513 		i915 = drm_open_driver_render(DRIVER_INTEL);
514 		igt_require_gem(i915);
515 
516 		gem_require_contexts(i915);
517 		igt_require(has_context_engines(i915));
518 
519 		igt_fork_hang_detector(i915);
520 	}
521 
522 	igt_subtest("invalid-engines")
523 		invalid_engines(i915);
524 
525 	igt_subtest("idempotent")
526 		idempotent(i915);
527 
528 	igt_subtest("execute-one")
529 		execute_one(i915);
530 
531 	igt_subtest("execute-oneforall")
532 		execute_oneforall(i915);
533 
534 	igt_subtest("execute-allforone")
535 		execute_allforone(i915);
536 
537 	igt_subtest("independent")
538 		independent(i915);
539 
540 	igt_fixture
541 		igt_stop_hang_detector();
542 }
543