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, ¶m) == 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, ¶m), 0);
69
70 param.size = 1;
71 igt_assert_eq(__gem_context_set_param(i915, ¶m), -EINVAL);
72
73 param.size = sizeof(stack) - 1;
74 igt_assert_eq(__gem_context_set_param(i915, ¶m), -EINVAL);
75
76 param.size = sizeof(stack) + 1;
77 igt_assert_eq(__gem_context_set_param(i915, ¶m), -EINVAL);
78
79 param.size = 0;
80 igt_assert_eq(__gem_context_set_param(i915, ¶m), 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, ¶m), -ENOENT);
95
96 mprotect(engines, 4096, PROT_READ);
97 igt_assert_eq(__gem_context_set_param(i915, ¶m), -ENOENT);
98
99 mprotect(engines, 4096, PROT_WRITE);
100 engines->engines[0].engine_class = 0;
101 if (__gem_context_set_param(i915, ¶m)) /* XXX needs RCS */
102 goto out;
103
104 engines->extensions = to_user_pointer(ptr);
105 igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
106
107 engines->extensions = 0;
108 igt_assert_eq(__gem_context_set_param(i915, ¶m), 0);
109
110 param.value = to_user_pointer(engines - 1);
111 igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
112
113 param.value = to_user_pointer(engines) - 1;
114 igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
115
116 param.value = to_user_pointer(engines) - param.size + 1;
117 igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
118
119 param.value = to_user_pointer(engines) + 4096;
120 igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
121
122 param.value = to_user_pointer(engines) - param.size + 4096;
123 igt_assert_eq(__gem_context_set_param(i915, ¶m), 0);
124
125 param.value = to_user_pointer(engines) - param.size + 4096 + 1;
126 igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
127
128 param.value = to_user_pointer(engines) + 4096;
129 igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
130
131 param.value = to_user_pointer(engines) + 4096 - 1;
132 igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
133
134 param.value = to_user_pointer(engines) - 1;
135 igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
136
137 param.value = to_user_pointer(engines - 1);
138 igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
139
140 param.value = to_user_pointer(engines - 1) + 4096;
141 igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
142
143 param.value = to_user_pointer(engines - 1) + 4096 - sizeof(*engines->engines) / 2;
144 igt_assert_eq(__gem_context_set_param(i915, ¶m), -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, ¶m), 0);
155
156 param.value = to_user_pointer(ptr);
157 igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
158
159 param.value = to_user_pointer(ptr) + 4095;
160 igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
161
162 param.value = to_user_pointer(ptr) + 8192;
163 igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
164
165 param.value = to_user_pointer(ptr) + 12287;
166 igt_assert_eq(__gem_context_set_param(i915, ¶m), -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, ¶m);
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, ¶m);
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, ¶m);
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, ¶m);
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, ¶m);
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, ¶m);
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