1 /*
2 * Copyright © 2017-2019 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 "igt_rand.h"
42 #include "igt_vgem.h"
43 #include "sync_file.h"
44
45 #define LO 0
46 #define HI 1
47 #define NOISE 2
48
49 #define MAX_PRIO LOCAL_I915_CONTEXT_MAX_USER_PRIORITY
50 #define MIN_PRIO LOCAL_I915_CONTEXT_MIN_USER_PRIORITY
51
52 static int priorities[] = {
53 [LO] = MIN_PRIO / 2,
54 [HI] = MAX_PRIO / 2,
55 };
56
57 #define MAX_ELSP_QLEN 16
58
59 IGT_TEST_DESCRIPTION("Test shared contexts.");
60
create_shared_gtt(int i915,unsigned int flags)61 static void create_shared_gtt(int i915, unsigned int flags)
62 #define DETACHED 0x1
63 {
64 const uint32_t bbe = MI_BATCH_BUFFER_END;
65 struct drm_i915_gem_exec_object2 obj = {
66 .handle = gem_create(i915, 4096),
67 };
68 struct drm_i915_gem_execbuffer2 execbuf = {
69 .buffers_ptr = to_user_pointer(&obj),
70 .buffer_count = 1,
71 };
72 uint32_t parent, child;
73
74 gem_write(i915, obj.handle, 0, &bbe, sizeof(bbe));
75 gem_execbuf(i915, &execbuf);
76 gem_sync(i915, obj.handle);
77
78 child = flags & DETACHED ? gem_context_create(i915) : 0;
79 igt_until_timeout(2) {
80 parent = flags & DETACHED ? child : 0;
81 child = gem_context_clone(i915,
82 parent, I915_CONTEXT_CLONE_VM,
83 0);
84 execbuf.rsvd1 = child;
85 gem_execbuf(i915, &execbuf);
86
87 if (flags & DETACHED) {
88 gem_context_destroy(i915, parent);
89 gem_execbuf(i915, &execbuf);
90 } else {
91 parent = child;
92 gem_context_destroy(i915, parent);
93 }
94
95 execbuf.rsvd1 = parent;
96 igt_assert_eq(__gem_execbuf(i915, &execbuf), -ENOENT);
97 igt_assert_eq(__gem_context_clone(i915,
98 parent, I915_CONTEXT_CLONE_VM,
99 0, &parent), -ENOENT);
100 }
101 if (flags & DETACHED)
102 gem_context_destroy(i915, child);
103
104 gem_sync(i915, obj.handle);
105 gem_close(i915, obj.handle);
106 }
107
disjoint_timelines(int i915)108 static void disjoint_timelines(int i915)
109 {
110 IGT_CORK_HANDLE(cork);
111 igt_spin_t *spin[2];
112 uint32_t plug, child;
113
114 igt_require(gem_has_execlists(i915));
115
116 /*
117 * Each context, although they share a vm, are expected to be
118 * distinct timelines. A request queued to one context should be
119 * independent of any shared contexts.
120 */
121 child = gem_context_clone(i915, 0, I915_CONTEXT_CLONE_VM, 0);
122 plug = igt_cork_plug(&cork, i915);
123
124 spin[0] = __igt_spin_new(i915, .ctx = 0, .dependency = plug);
125 spin[1] = __igt_spin_new(i915, .ctx = child);
126
127 /* Wait for the second spinner, will hang if stuck behind the first */
128 igt_spin_end(spin[1]);
129 gem_sync(i915, spin[1]->handle);
130
131 igt_cork_unplug(&cork);
132
133 igt_spin_free(i915, spin[1]);
134 igt_spin_free(i915, spin[0]);
135 }
136
exhaust_shared_gtt(int i915,unsigned int flags)137 static void exhaust_shared_gtt(int i915, unsigned int flags)
138 #define EXHAUST_LRC 0x1
139 {
140 i915 = gem_reopen_driver(i915);
141
142 igt_fork(pid, 1) {
143 const uint32_t bbe = MI_BATCH_BUFFER_END;
144 struct drm_i915_gem_exec_object2 obj = {
145 .handle = gem_create(i915, 4096)
146 };
147 struct drm_i915_gem_execbuffer2 execbuf = {
148 .buffers_ptr = to_user_pointer(&obj),
149 .buffer_count = 1,
150 };
151 uint32_t parent, child;
152 unsigned long count = 0;
153 int err;
154
155 gem_write(i915, obj.handle, 0, &bbe, sizeof(bbe));
156
157 child = 0;
158 for (;;) {
159 parent = child;
160 err = __gem_context_clone(i915,
161 parent, I915_CONTEXT_CLONE_VM,
162 0, &child);
163 if (err)
164 break;
165
166 if (flags & EXHAUST_LRC) {
167 execbuf.rsvd1 = child;
168 err = __gem_execbuf(i915, &execbuf);
169 if (err)
170 break;
171 }
172
173 count++;
174 }
175 gem_sync(i915, obj.handle);
176
177 igt_info("Created %lu shared contexts, before %d (%s)\n",
178 count, err, strerror(-err));
179 }
180 close(i915);
181 igt_waitchildren();
182 }
183
exec_shared_gtt(int i915,unsigned int ring)184 static void exec_shared_gtt(int i915, unsigned int ring)
185 {
186 const int gen = intel_gen(intel_get_drm_devid(i915));
187 const uint32_t bbe = MI_BATCH_BUFFER_END;
188 struct drm_i915_gem_exec_object2 obj = {};
189 struct drm_i915_gem_execbuffer2 execbuf = {
190 .buffers_ptr = to_user_pointer(&obj),
191 .buffer_count = 1,
192 .flags = ring,
193 };
194 uint32_t scratch, *s;
195 uint32_t batch, cs[16];
196 uint64_t offset;
197 int i;
198
199 gem_require_ring(i915, ring);
200 igt_require(gem_can_store_dword(i915, ring));
201
202 /* Find a hole big enough for both objects later */
203 scratch = gem_create(i915, 16384);
204 gem_write(i915, scratch, 0, &bbe, sizeof(bbe));
205 obj.handle = scratch;
206 gem_execbuf(i915, &execbuf);
207 gem_close(i915, scratch);
208 obj.flags |= EXEC_OBJECT_PINNED; /* reuse this address */
209
210 scratch = gem_create(i915, 4096);
211 s = gem_mmap__wc(i915, scratch, 0, 4096, PROT_WRITE);
212
213 gem_set_domain(i915, scratch, I915_GEM_DOMAIN_WC, I915_GEM_DOMAIN_WC);
214 s[0] = bbe;
215 s[64] = bbe;
216
217 /* Load object into place in the GTT */
218 obj.handle = scratch;
219 gem_execbuf(i915, &execbuf);
220 offset = obj.offset;
221
222 /* Presume nothing causes an eviction in the meantime! */
223
224 batch = gem_create(i915, 4096);
225
226 i = 0;
227 cs[i] = MI_STORE_DWORD_IMM | (gen < 6 ? 1 << 22 : 0);
228 if (gen >= 8) {
229 cs[++i] = obj.offset;
230 cs[++i] = obj.offset >> 32;
231 } else if (gen >= 4) {
232 cs[++i] = 0;
233 cs[++i] = obj.offset;
234 } else {
235 cs[i]--;
236 cs[++i] = obj.offset;
237 }
238 cs[++i] = 0xc0ffee;
239 cs[++i] = bbe;
240 gem_write(i915, batch, 0, cs, sizeof(cs));
241
242 obj.handle = batch;
243 obj.offset += 8192; /* make sure we don't cause an eviction! */
244 execbuf.rsvd1 = gem_context_clone(i915, 0, I915_CONTEXT_CLONE_VM, 0);
245 if (gen > 3 && gen < 6)
246 execbuf.flags |= I915_EXEC_SECURE;
247 gem_execbuf(i915, &execbuf);
248
249 /* Check the scratch didn't move */
250 obj.handle = scratch;
251 obj.offset = -1;
252 obj.flags &= ~EXEC_OBJECT_PINNED;
253 execbuf.batch_start_offset = 64 * sizeof(s[0]);
254 gem_execbuf(i915, &execbuf);
255 igt_assert_eq_u64(obj.offset, offset);
256 gem_context_destroy(i915, execbuf.rsvd1);
257
258 gem_sync(i915, batch); /* write hazard lies */
259 gem_close(i915, batch);
260
261 /*
262 * If we created the new context with the old GTT, the write
263 * into the stale location of scratch will have landed in the right
264 * object. Otherwise, it should read the previous value of
265 * MI_BATCH_BUFFER_END.
266 */
267 igt_assert_eq_u32(*s, 0xc0ffee);
268
269 munmap(s, 4096);
270 gem_close(i915, scratch);
271 }
272
nop_sync(int i915,uint32_t ctx,unsigned int ring,int64_t timeout)273 static int nop_sync(int i915, uint32_t ctx, unsigned int ring, int64_t timeout)
274 {
275 const uint32_t bbe = MI_BATCH_BUFFER_END;
276 struct drm_i915_gem_exec_object2 obj = {
277 .handle = gem_create(i915, 4096),
278 };
279 struct drm_i915_gem_execbuffer2 execbuf = {
280 .buffers_ptr = to_user_pointer(&obj),
281 .buffer_count = 1,
282 .flags = ring,
283 .rsvd1 = ctx,
284 };
285 int err;
286
287 gem_write(i915, obj.handle, 0, &bbe, sizeof(bbe));
288 gem_execbuf(i915, &execbuf);
289 err = gem_wait(i915, obj.handle, &timeout);
290 gem_close(i915, obj.handle);
291
292 return err;
293 }
294
has_single_timeline(int i915)295 static bool has_single_timeline(int i915)
296 {
297 uint32_t ctx;
298
299 __gem_context_clone(i915, 0, 0,
300 I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE,
301 &ctx);
302 if (ctx)
303 gem_context_destroy(i915, ctx);
304
305 return ctx != 0;
306 }
307
single_timeline(int i915)308 static void single_timeline(int i915)
309 {
310 const uint32_t bbe = MI_BATCH_BUFFER_END;
311 struct drm_i915_gem_exec_object2 obj = {
312 .handle = gem_create(i915, 4096),
313 };
314 struct drm_i915_gem_execbuffer2 execbuf = {
315 .buffers_ptr = to_user_pointer(&obj),
316 .buffer_count = 1,
317 };
318 struct sync_fence_info rings[16];
319 struct sync_file_info sync_file_info = {
320 .num_fences = 1,
321 };
322 unsigned int engine;
323 int n;
324
325 igt_require(has_single_timeline(i915));
326
327 gem_write(i915, obj.handle, 0, &bbe, sizeof(bbe));
328 gem_execbuf(i915, &execbuf);
329 gem_sync(i915, obj.handle);
330
331 /*
332 * For a "single timeline" context, each ring is on the common
333 * timeline, unlike a normal context where each ring has an
334 * independent timeline. That is no matter which engine we submit
335 * to, it reports the same timeline name and fence context. However,
336 * the fence context is not reported through the sync_fence_info.
337 */
338 execbuf.rsvd1 =
339 gem_context_clone(i915, 0, 0,
340 I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE);
341 execbuf.flags = I915_EXEC_FENCE_OUT;
342 n = 0;
343 for_each_engine(i915, engine) {
344 gem_execbuf_wr(i915, &execbuf);
345 sync_file_info.sync_fence_info = to_user_pointer(&rings[n]);
346 do_ioctl(execbuf.rsvd2 >> 32, SYNC_IOC_FILE_INFO, &sync_file_info);
347 close(execbuf.rsvd2 >> 32);
348
349 igt_info("ring[%d] fence: %s %s\n",
350 n, rings[n].driver_name, rings[n].obj_name);
351 n++;
352 }
353 gem_sync(i915, obj.handle);
354 gem_close(i915, obj.handle);
355
356 for (int i = 1; i < n; i++) {
357 igt_assert(!strcmp(rings[0].driver_name, rings[i].driver_name));
358 igt_assert(!strcmp(rings[0].obj_name, rings[i].obj_name));
359 }
360 }
361
exec_single_timeline(int i915,unsigned int engine)362 static void exec_single_timeline(int i915, unsigned int engine)
363 {
364 unsigned int other;
365 igt_spin_t *spin;
366 uint32_t ctx;
367
368 igt_require(gem_ring_has_physical_engine(i915, engine));
369 igt_require(has_single_timeline(i915));
370
371 /*
372 * On an ordinary context, a blockage on one engine doesn't prevent
373 * execution on an other.
374 */
375 ctx = 0;
376 spin = NULL;
377 for_each_physical_engine(i915, other) {
378 if (other == engine)
379 continue;
380
381 if (spin == NULL) {
382 spin = __igt_spin_new(i915, .ctx = ctx, .engine = other);
383 } else {
384 struct drm_i915_gem_execbuffer2 execbuf = {
385 .buffers_ptr = spin->execbuf.buffers_ptr,
386 .buffer_count = spin->execbuf.buffer_count,
387 .flags = other,
388 .rsvd1 = ctx,
389 };
390 gem_execbuf(i915, &execbuf);
391 }
392 }
393 igt_require(spin);
394 igt_assert_eq(nop_sync(i915, ctx, engine, NSEC_PER_SEC), 0);
395 igt_spin_free(i915, spin);
396
397 /*
398 * But if we create a context with just a single shared timeline,
399 * then it will block waiting for the earlier requests on the
400 * other engines.
401 */
402 ctx = gem_context_clone(i915, 0, 0,
403 I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE);
404 spin = NULL;
405 for_each_physical_engine(i915, other) {
406 if (other == engine)
407 continue;
408
409 if (spin == NULL) {
410 spin = __igt_spin_new(i915, .ctx = ctx, .engine = other);
411 } else {
412 struct drm_i915_gem_execbuffer2 execbuf = {
413 .buffers_ptr = spin->execbuf.buffers_ptr,
414 .buffer_count = spin->execbuf.buffer_count,
415 .flags = other,
416 .rsvd1 = ctx,
417 };
418 gem_execbuf(i915, &execbuf);
419 }
420 }
421 igt_assert(spin);
422 igt_assert_eq(nop_sync(i915, ctx, engine, NSEC_PER_SEC), -ETIME);
423 igt_spin_free(i915, spin);
424 }
425
store_dword(int i915,uint32_t ctx,unsigned ring,uint32_t target,uint32_t offset,uint32_t value,uint32_t cork,unsigned write_domain)426 static void store_dword(int i915, uint32_t ctx, unsigned ring,
427 uint32_t target, uint32_t offset, uint32_t value,
428 uint32_t cork, unsigned write_domain)
429 {
430 const int gen = intel_gen(intel_get_drm_devid(i915));
431 struct drm_i915_gem_exec_object2 obj[3];
432 struct drm_i915_gem_relocation_entry reloc;
433 struct drm_i915_gem_execbuffer2 execbuf;
434 uint32_t batch[16];
435 int i;
436
437 memset(&execbuf, 0, sizeof(execbuf));
438 execbuf.buffers_ptr = to_user_pointer(obj + !cork);
439 execbuf.buffer_count = 2 + !!cork;
440 execbuf.flags = ring;
441 if (gen < 6)
442 execbuf.flags |= I915_EXEC_SECURE;
443 execbuf.rsvd1 = ctx;
444
445 memset(obj, 0, sizeof(obj));
446 obj[0].handle = cork;
447 obj[1].handle = target;
448 obj[2].handle = gem_create(i915, 4096);
449
450 memset(&reloc, 0, sizeof(reloc));
451 reloc.target_handle = obj[1].handle;
452 reloc.presumed_offset = 0;
453 reloc.offset = sizeof(uint32_t);
454 reloc.delta = offset;
455 reloc.read_domains = I915_GEM_DOMAIN_INSTRUCTION;
456 reloc.write_domain = write_domain;
457 obj[2].relocs_ptr = to_user_pointer(&reloc);
458 obj[2].relocation_count = 1;
459
460 i = 0;
461 batch[i] = MI_STORE_DWORD_IMM | (gen < 6 ? 1 << 22 : 0);
462 if (gen >= 8) {
463 batch[++i] = offset;
464 batch[++i] = 0;
465 } else if (gen >= 4) {
466 batch[++i] = 0;
467 batch[++i] = offset;
468 reloc.offset += sizeof(uint32_t);
469 } else {
470 batch[i]--;
471 batch[++i] = offset;
472 }
473 batch[++i] = value;
474 batch[++i] = MI_BATCH_BUFFER_END;
475 gem_write(i915, obj[2].handle, 0, batch, sizeof(batch));
476 gem_execbuf(i915, &execbuf);
477 gem_close(i915, obj[2].handle);
478 }
479
create_highest_priority(int i915)480 static uint32_t create_highest_priority(int i915)
481 {
482 uint32_t ctx = gem_context_create(i915);
483
484 /*
485 * If there is no priority support, all contexts will have equal
486 * priority (and therefore the max user priority), so no context
487 * can overtake us, and we effectively can form a plug.
488 */
489 __gem_context_set_priority(i915, ctx, MAX_PRIO);
490
491 return ctx;
492 }
493
unplug_show_queue(int i915,struct igt_cork * c,unsigned int engine)494 static void unplug_show_queue(int i915, struct igt_cork *c, unsigned int engine)
495 {
496 igt_spin_t *spin[MAX_ELSP_QLEN];
497
498 for (int n = 0; n < ARRAY_SIZE(spin); n++) {
499 const struct igt_spin_factory opts = {
500 .ctx = create_highest_priority(i915),
501 .engine = engine,
502 };
503 spin[n] = __igt_spin_factory(i915, &opts);
504 gem_context_destroy(i915, opts.ctx);
505 }
506
507 igt_cork_unplug(c); /* batches will now be queued on the engine */
508 igt_debugfs_dump(i915, "i915_engine_info");
509
510 for (int n = 0; n < ARRAY_SIZE(spin); n++)
511 igt_spin_free(i915, spin[n]);
512 }
513
store_timestamp(int i915,uint32_t ctx,unsigned ring,unsigned mmio_base,int offset)514 static uint32_t store_timestamp(int i915,
515 uint32_t ctx, unsigned ring,
516 unsigned mmio_base,
517 int offset)
518 {
519 const bool r64b = intel_gen(intel_get_drm_devid(i915)) >= 8;
520 struct drm_i915_gem_exec_object2 obj = {
521 .handle = gem_create(i915, 4096),
522 .relocation_count = 1,
523 };
524 struct drm_i915_gem_relocation_entry reloc = {
525 .target_handle = obj.handle,
526 .offset = 2 * sizeof(uint32_t),
527 .delta = offset * sizeof(uint32_t),
528 .read_domains = I915_GEM_DOMAIN_INSTRUCTION,
529 };
530 struct drm_i915_gem_execbuffer2 execbuf = {
531 .buffers_ptr = to_user_pointer(&obj),
532 .buffer_count = 1,
533 .flags = ring,
534 .rsvd1 = ctx,
535 };
536 uint32_t batch[] = {
537 0x24 << 23 | (1 + r64b), /* SRM */
538 mmio_base + 0x358,
539 offset * sizeof(uint32_t),
540 0,
541 MI_BATCH_BUFFER_END
542 };
543
544 igt_require(intel_gen(intel_get_drm_devid(i915)) >= 7);
545
546 gem_write(i915, obj.handle, 0, batch, sizeof(batch));
547 obj.relocs_ptr = to_user_pointer(&reloc);
548
549 gem_execbuf(i915, &execbuf);
550
551 return obj.handle;
552 }
553
independent(int i915,unsigned ring,unsigned flags)554 static void independent(int i915, unsigned ring, unsigned flags)
555 {
556 const int TIMESTAMP = 1023;
557 uint32_t handle[ARRAY_SIZE(priorities)];
558 igt_spin_t *spin[MAX_ELSP_QLEN];
559 unsigned int mmio_base;
560
561 /* XXX i915_query()! */
562 switch (ring) {
563 case I915_EXEC_DEFAULT:
564 case I915_EXEC_RENDER:
565 mmio_base = 0x2000;
566 break;
567 #if 0
568 case I915_EXEC_BSD:
569 mmio_base = 0x12000;
570 break;
571 #endif
572 case I915_EXEC_BLT:
573 mmio_base = 0x22000;
574 break;
575
576 #define GEN11_VECS0_BASE 0x1c8000
577 #define GEN11_VECS1_BASE 0x1d8000
578 case I915_EXEC_VEBOX:
579 if (intel_gen(intel_get_drm_devid(i915)) >= 11)
580 mmio_base = GEN11_VECS0_BASE;
581 else
582 mmio_base = 0x1a000;
583 break;
584
585 default:
586 igt_skip("mmio base not known\n");
587 }
588
589 for (int n = 0; n < ARRAY_SIZE(spin); n++) {
590 const struct igt_spin_factory opts = {
591 .ctx = create_highest_priority(i915),
592 .engine = ring,
593 };
594 spin[n] = __igt_spin_factory(i915, &opts);
595 gem_context_destroy(i915, opts.ctx);
596 }
597
598 for (int i = 0; i < ARRAY_SIZE(priorities); i++) {
599 uint32_t ctx = gem_queue_create(i915);
600 gem_context_set_priority(i915, ctx, priorities[i]);
601 handle[i] = store_timestamp(i915, ctx, ring, mmio_base, TIMESTAMP);
602 gem_context_destroy(i915, ctx);
603 }
604
605 for (int n = 0; n < ARRAY_SIZE(spin); n++)
606 igt_spin_free(i915, spin[n]);
607
608 for (int i = 0; i < ARRAY_SIZE(priorities); i++) {
609 uint32_t *ptr;
610
611 ptr = gem_mmap__gtt(i915, handle[i], 4096, PROT_READ);
612 gem_set_domain(i915, handle[i], /* no write hazard lies! */
613 I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
614 gem_close(i915, handle[i]);
615
616 handle[i] = ptr[TIMESTAMP];
617 munmap(ptr, 4096);
618
619 igt_debug("ctx[%d] .prio=%d, timestamp=%u\n",
620 i, priorities[i], handle[i]);
621 }
622
623 igt_assert((int32_t)(handle[HI] - handle[LO]) < 0);
624 }
625
reorder(int i915,unsigned ring,unsigned flags)626 static void reorder(int i915, unsigned ring, unsigned flags)
627 #define EQUAL 1
628 {
629 IGT_CORK_HANDLE(cork);
630 uint32_t scratch;
631 uint32_t *ptr;
632 uint32_t ctx[2];
633 uint32_t plug;
634
635 ctx[LO] = gem_queue_create(i915);
636 gem_context_set_priority(i915, ctx[LO], MIN_PRIO);
637
638 ctx[HI] = gem_queue_create(i915);
639 gem_context_set_priority(i915, ctx[HI], flags & EQUAL ? MIN_PRIO : 0);
640
641 scratch = gem_create(i915, 4096);
642 plug = igt_cork_plug(&cork, i915);
643
644 /* We expect the high priority context to be executed first, and
645 * so the final result will be value from the low priority context.
646 */
647 store_dword(i915, ctx[LO], ring, scratch, 0, ctx[LO], plug, 0);
648 store_dword(i915, ctx[HI], ring, scratch, 0, ctx[HI], plug, 0);
649
650 unplug_show_queue(i915, &cork, ring);
651 gem_close(i915, plug);
652
653 gem_context_destroy(i915, ctx[LO]);
654 gem_context_destroy(i915, ctx[HI]);
655
656 ptr = gem_mmap__gtt(i915, scratch, 4096, PROT_READ);
657 gem_set_domain(i915, scratch, /* no write hazard lies! */
658 I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
659 gem_close(i915, scratch);
660
661 if (flags & EQUAL) /* equal priority, result will be fifo */
662 igt_assert_eq_u32(ptr[0], ctx[HI]);
663 else
664 igt_assert_eq_u32(ptr[0], ctx[LO]);
665 munmap(ptr, 4096);
666 }
667
promotion(int i915,unsigned ring)668 static void promotion(int i915, unsigned ring)
669 {
670 IGT_CORK_HANDLE(cork);
671 uint32_t result, dep;
672 uint32_t *ptr;
673 uint32_t ctx[3];
674 uint32_t plug;
675
676 ctx[LO] = gem_queue_create(i915);
677 gem_context_set_priority(i915, ctx[LO], MIN_PRIO);
678
679 ctx[HI] = gem_queue_create(i915);
680 gem_context_set_priority(i915, ctx[HI], 0);
681
682 ctx[NOISE] = gem_queue_create(i915);
683 gem_context_set_priority(i915, ctx[NOISE], MIN_PRIO/2);
684
685 result = gem_create(i915, 4096);
686 dep = gem_create(i915, 4096);
687
688 plug = igt_cork_plug(&cork, i915);
689
690 /* Expect that HI promotes LO, so the order will be LO, HI, NOISE.
691 *
692 * fifo would be NOISE, LO, HI.
693 * strict priority would be HI, NOISE, LO
694 */
695 store_dword(i915, ctx[NOISE], ring, result, 0, ctx[NOISE], plug, 0);
696 store_dword(i915, ctx[LO], ring, result, 0, ctx[LO], plug, 0);
697
698 /* link LO <-> HI via a dependency on another buffer */
699 store_dword(i915, ctx[LO], ring, dep, 0, ctx[LO], 0, I915_GEM_DOMAIN_INSTRUCTION);
700 store_dword(i915, ctx[HI], ring, dep, 0, ctx[HI], 0, 0);
701
702 store_dword(i915, ctx[HI], ring, result, 0, ctx[HI], 0, 0);
703
704 unplug_show_queue(i915, &cork, ring);
705 gem_close(i915, plug);
706
707 gem_context_destroy(i915, ctx[NOISE]);
708 gem_context_destroy(i915, ctx[LO]);
709 gem_context_destroy(i915, ctx[HI]);
710
711 ptr = gem_mmap__gtt(i915, dep, 4096, PROT_READ);
712 gem_set_domain(i915, dep, /* no write hazard lies! */
713 I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
714 gem_close(i915, dep);
715
716 igt_assert_eq_u32(ptr[0], ctx[HI]);
717 munmap(ptr, 4096);
718
719 ptr = gem_mmap__gtt(i915, result, 4096, PROT_READ);
720 gem_set_domain(i915, result, /* no write hazard lies! */
721 I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
722 gem_close(i915, result);
723
724 igt_assert_eq_u32(ptr[0], ctx[NOISE]);
725 munmap(ptr, 4096);
726 }
727
smoketest(int i915,unsigned ring,unsigned timeout)728 static void smoketest(int i915, unsigned ring, unsigned timeout)
729 {
730 const int ncpus = sysconf(_SC_NPROCESSORS_ONLN);
731 unsigned engines[16];
732 unsigned nengine;
733 unsigned engine;
734 uint32_t scratch;
735 uint32_t *ptr;
736
737 nengine = 0;
738 for_each_physical_engine(i915, engine)
739 engines[nengine++] = engine;
740 igt_require(nengine);
741
742 scratch = gem_create(i915, 4096);
743 igt_fork(child, ncpus) {
744 unsigned long count = 0;
745 uint32_t ctx;
746
747 hars_petruska_f54_1_random_perturb(child);
748
749 ctx = gem_queue_create(i915);
750 igt_until_timeout(timeout) {
751 int prio;
752
753 prio = hars_petruska_f54_1_random_unsafe_max(MAX_PRIO - MIN_PRIO) + MIN_PRIO;
754 gem_context_set_priority(i915, ctx, prio);
755
756 engine = engines[hars_petruska_f54_1_random_unsafe_max(nengine)];
757 store_dword(i915, ctx, engine, scratch,
758 8*child + 0, ~child,
759 0, 0);
760 for (unsigned int step = 0; step < 8; step++)
761 store_dword(i915, ctx, engine, scratch,
762 8*child + 4, count++,
763 0, 0);
764 }
765 gem_context_destroy(i915, ctx);
766 }
767 igt_waitchildren();
768
769 ptr = gem_mmap__gtt(i915, scratch, 4096, PROT_READ);
770 gem_set_domain(i915, scratch, /* no write hazard lies! */
771 I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
772 gem_close(i915, scratch);
773
774 for (unsigned n = 0; n < ncpus; n++) {
775 igt_assert_eq_u32(ptr[2*n], ~n);
776 /*
777 * Note this count is approximate due to unconstrained
778 * ordering of the dword writes between engines.
779 *
780 * Take the result with a pinch of salt.
781 */
782 igt_info("Child[%d] completed %u cycles\n", n, ptr[2*n+1]);
783 }
784 munmap(ptr, 4096);
785 }
786
787 igt_main
788 {
789 const struct intel_execution_engine *e;
790 int i915 = -1;
791
792 igt_fixture {
793 i915 = drm_open_driver(DRIVER_INTEL);
794 igt_require_gem(i915);
795 }
796
797 igt_subtest_group {
798 igt_fixture {
799 igt_require(gem_contexts_has_shared_gtt(i915));
800 igt_fork_hang_detector(i915);
801 }
802
803 igt_subtest("create-shared-gtt")
804 create_shared_gtt(i915, 0);
805
806 igt_subtest("detached-shared-gtt")
807 create_shared_gtt(i915, DETACHED);
808
809 igt_subtest("disjoint-timelines")
810 disjoint_timelines(i915);
811
812 igt_subtest("single-timeline")
813 single_timeline(i915);
814
815 igt_subtest("exhaust-shared-gtt")
816 exhaust_shared_gtt(i915, 0);
817
818 igt_subtest("exhaust-shared-gtt-lrc")
819 exhaust_shared_gtt(i915, EXHAUST_LRC);
820
821 for (e = intel_execution_engines; e->name; e++) {
822 igt_subtest_f("exec-shared-gtt-%s", e->name)
823 exec_shared_gtt(i915, e->exec_id | e->flags);
824
825 igt_subtest_f("exec-single-timeline-%s", e->name)
826 exec_single_timeline(i915,
827 e->exec_id | e->flags);
828
829 /*
830 * Check that the shared contexts operate independently,
831 * that is requests on one ("queue") can be scheduled
832 * around another queue. We only check the basics here,
833 * enough to reduce the queue into just another context,
834 * and so rely on gem_exec_schedule to prove the rest.
835 */
836 igt_subtest_group {
837 igt_fixture {
838 gem_require_ring(i915, e->exec_id | e->flags);
839 igt_require(gem_can_store_dword(i915, e->exec_id | e->flags));
840 igt_require(gem_scheduler_enabled(i915));
841 igt_require(gem_scheduler_has_ctx_priority(i915));
842 }
843
844 igt_subtest_f("Q-independent-%s", e->name)
845 independent(i915, e->exec_id | e->flags, 0);
846
847 igt_subtest_f("Q-in-order-%s", e->name)
848 reorder(i915, e->exec_id | e->flags, EQUAL);
849
850 igt_subtest_f("Q-out-order-%s", e->name)
851 reorder(i915, e->exec_id | e->flags, 0);
852
853 igt_subtest_f("Q-promotion-%s", e->name)
854 promotion(i915, e->exec_id | e->flags);
855
856 igt_subtest_f("Q-smoketest-%s", e->name)
857 smoketest(i915, e->exec_id | e->flags, 5);
858 }
859 }
860
861 igt_subtest("Q-smoketest-all") {
862 igt_require(gem_scheduler_enabled(i915));
863 igt_require(gem_scheduler_has_ctx_priority(i915));
864 smoketest(i915, -1, 30);
865 }
866
867 igt_fixture {
868 igt_stop_hang_detector();
869 }
870 }
871 }
872