1 /*
2 * Copyright © 2016 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 #include "igt.h"
25 #include "igt_sysfs.h"
26 #include "igt_vgem.h"
27 #include "sw_sync.h"
28 #include "i915/gem_ring.h"
29
30 #include <sys/ioctl.h>
31 #include <sys/poll.h>
32 #include <sys/signal.h>
33
34 IGT_TEST_DESCRIPTION("Check that execbuf waits for explicit fences");
35
36 #define LOCAL_EXEC_FENCE_IN (1 << 16)
37 #define LOCAL_EXEC_FENCE_OUT (1 << 17)
38 #define LOCAL_EXEC_FENCE_SUBMIT (1 << 20)
39
40 #define LOCAL_EXEC_FENCE_ARRAY (1 << 19)
41 struct local_gem_exec_fence {
42 uint32_t handle;
43 uint32_t flags;
44 #define LOCAL_EXEC_FENCE_WAIT (1 << 0)
45 #define LOCAL_EXEC_FENCE_SIGNAL (1 << 1)
46 };
47
48 #ifndef SYNC_IOC_MERGE
49 struct sync_merge_data {
50 char name[32];
51 int32_t fd2;
52 int32_t fence;
53 uint32_t flags;
54 uint32_t pad;
55 };
56 #define SYNC_IOC_MAGIC '>'
57 #define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data)
58 #endif
59
store(int fd,unsigned ring,int fence,uint32_t target,unsigned offset_value)60 static void store(int fd, unsigned ring, int fence, uint32_t target, unsigned offset_value)
61 {
62 const int SCRATCH = 0;
63 const int BATCH = 1;
64 const int gen = intel_gen(intel_get_drm_devid(fd));
65 struct drm_i915_gem_exec_object2 obj[2];
66 struct drm_i915_gem_relocation_entry reloc;
67 struct drm_i915_gem_execbuffer2 execbuf;
68 uint32_t batch[16];
69 int i;
70
71 memset(&execbuf, 0, sizeof(execbuf));
72 execbuf.buffers_ptr = to_user_pointer(obj);
73 execbuf.buffer_count = 2;
74 execbuf.flags = ring | LOCAL_EXEC_FENCE_IN;
75 execbuf.rsvd2 = fence;
76 if (gen < 6)
77 execbuf.flags |= I915_EXEC_SECURE;
78
79 memset(obj, 0, sizeof(obj));
80 obj[SCRATCH].handle = target;
81
82 obj[BATCH].handle = gem_create(fd, 4096);
83 obj[BATCH].relocs_ptr = to_user_pointer(&reloc);
84 obj[BATCH].relocation_count = 1;
85 memset(&reloc, 0, sizeof(reloc));
86
87 i = 0;
88 reloc.target_handle = obj[SCRATCH].handle;
89 reloc.presumed_offset = -1;
90 reloc.offset = sizeof(uint32_t) * (i + 1);
91 reloc.delta = sizeof(uint32_t) * offset_value;
92 reloc.read_domains = I915_GEM_DOMAIN_INSTRUCTION;
93 reloc.write_domain = I915_GEM_DOMAIN_INSTRUCTION;
94 batch[i] = MI_STORE_DWORD_IMM | (gen < 6 ? 1 << 22 : 0);
95 if (gen >= 8) {
96 batch[++i] = reloc.delta;
97 batch[++i] = 0;
98 } else if (gen >= 4) {
99 batch[++i] = 0;
100 batch[++i] = reloc.delta;
101 reloc.offset += sizeof(uint32_t);
102 } else {
103 batch[i]--;
104 batch[++i] = reloc.delta;
105 }
106 batch[++i] = offset_value;
107 batch[++i] = MI_BATCH_BUFFER_END;
108 gem_write(fd, obj[BATCH].handle, 0, batch, sizeof(batch));
109 gem_execbuf(fd, &execbuf);
110 gem_close(fd, obj[BATCH].handle);
111 }
112
fence_busy(int fence)113 static bool fence_busy(int fence)
114 {
115 return poll(&(struct pollfd){fence, POLLIN}, 1, 0) == 0;
116 }
117
118 #define HANG 0x1
119 #define NONBLOCK 0x2
120 #define WAIT 0x4
121
test_fence_busy(int fd,unsigned ring,unsigned flags)122 static void test_fence_busy(int fd, unsigned ring, unsigned flags)
123 {
124 const int gen = intel_gen(intel_get_drm_devid(fd));
125 struct drm_i915_gem_exec_object2 obj;
126 struct drm_i915_gem_relocation_entry reloc;
127 struct drm_i915_gem_execbuffer2 execbuf;
128 struct timespec tv;
129 uint32_t *batch;
130 int fence, i, timeout;
131
132 gem_quiescent_gpu(fd);
133
134 memset(&execbuf, 0, sizeof(execbuf));
135 execbuf.buffers_ptr = to_user_pointer(&obj);
136 execbuf.buffer_count = 1;
137 execbuf.flags = ring | LOCAL_EXEC_FENCE_OUT;
138
139 memset(&obj, 0, sizeof(obj));
140 obj.handle = gem_create(fd, 4096);
141
142 obj.relocs_ptr = to_user_pointer(&reloc);
143 obj.relocation_count = 1;
144 memset(&reloc, 0, sizeof(reloc));
145
146 batch = gem_mmap__wc(fd, obj.handle, 0, 4096, PROT_WRITE);
147 gem_set_domain(fd, obj.handle,
148 I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
149
150 reloc.target_handle = obj.handle; /* recurse */
151 reloc.presumed_offset = 0;
152 reloc.offset = sizeof(uint32_t);
153 reloc.delta = 0;
154 reloc.read_domains = I915_GEM_DOMAIN_COMMAND;
155 reloc.write_domain = 0;
156
157 i = 0;
158 batch[i] = MI_BATCH_BUFFER_START;
159 if (gen >= 8) {
160 batch[i] |= 1 << 8 | 1;
161 batch[++i] = 0;
162 batch[++i] = 0;
163 } else if (gen >= 6) {
164 batch[i] |= 1 << 8;
165 batch[++i] = 0;
166 } else {
167 batch[i] |= 2 << 6;
168 batch[++i] = 0;
169 if (gen < 4) {
170 batch[i] |= 1;
171 reloc.delta = 1;
172 }
173 }
174 i++;
175
176 execbuf.rsvd2 = -1;
177 gem_execbuf_wr(fd, &execbuf);
178 fence = execbuf.rsvd2 >> 32;
179 igt_assert(fence != -1);
180
181 igt_assert(gem_bo_busy(fd, obj.handle));
182 igt_assert(fence_busy(fence));
183
184 timeout = 120;
185 if ((flags & HANG) == 0) {
186 *batch = MI_BATCH_BUFFER_END;
187 __sync_synchronize();
188 timeout = 1;
189 }
190 munmap(batch, 4096);
191
192 if (flags & WAIT) {
193 struct pollfd pfd = { .fd = fence, .events = POLLIN };
194 igt_assert(poll(&pfd, 1, timeout*1000) == 1);
195 } else {
196 memset(&tv, 0, sizeof(tv));
197 while (fence_busy(fence))
198 igt_assert(igt_seconds_elapsed(&tv) < timeout);
199 }
200
201 igt_assert(!gem_bo_busy(fd, obj.handle));
202 igt_assert_eq(sync_fence_status(fence),
203 flags & HANG ? -EIO : SYNC_FENCE_OK);
204
205 close(fence);
206 gem_close(fd, obj.handle);
207
208 gem_quiescent_gpu(fd);
209 }
210
test_fence_busy_all(int fd,unsigned flags)211 static void test_fence_busy_all(int fd, unsigned flags)
212 {
213 const int gen = intel_gen(intel_get_drm_devid(fd));
214 struct drm_i915_gem_exec_object2 obj;
215 struct drm_i915_gem_relocation_entry reloc;
216 struct drm_i915_gem_execbuffer2 execbuf;
217 struct timespec tv;
218 uint32_t *batch;
219 unsigned int engine;
220 int all, i, timeout;
221
222 gem_quiescent_gpu(fd);
223
224 memset(&execbuf, 0, sizeof(execbuf));
225 execbuf.buffers_ptr = to_user_pointer(&obj);
226 execbuf.buffer_count = 1;
227
228 memset(&obj, 0, sizeof(obj));
229 obj.handle = gem_create(fd, 4096);
230
231 obj.relocs_ptr = to_user_pointer(&reloc);
232 obj.relocation_count = 1;
233 memset(&reloc, 0, sizeof(reloc));
234
235 batch = gem_mmap__wc(fd, obj.handle, 0, 4096, PROT_WRITE);
236 gem_set_domain(fd, obj.handle,
237 I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
238
239 reloc.target_handle = obj.handle; /* recurse */
240 reloc.presumed_offset = 0;
241 reloc.offset = sizeof(uint32_t);
242 reloc.delta = 0;
243 reloc.read_domains = I915_GEM_DOMAIN_COMMAND;
244 reloc.write_domain = 0;
245
246 i = 0;
247 batch[i] = MI_BATCH_BUFFER_START;
248 if (gen >= 8) {
249 batch[i] |= 1 << 8 | 1;
250 batch[++i] = 0;
251 batch[++i] = 0;
252 } else if (gen >= 6) {
253 batch[i] |= 1 << 8;
254 batch[++i] = 0;
255 } else {
256 batch[i] |= 2 << 6;
257 batch[++i] = 0;
258 if (gen < 4) {
259 batch[i] |= 1;
260 reloc.delta = 1;
261 }
262 }
263 i++;
264
265 all = -1;
266 for_each_engine(fd, engine) {
267 int fence, new;
268
269 execbuf.flags = engine | LOCAL_EXEC_FENCE_OUT;
270 execbuf.rsvd2 = -1;
271 gem_execbuf_wr(fd, &execbuf);
272 fence = execbuf.rsvd2 >> 32;
273 igt_assert(fence != -1);
274
275 if (all < 0) {
276 all = fence;
277 continue;
278 }
279
280 new = sync_fence_merge(all, fence);
281 igt_assert_lte(0, new);
282 close(all);
283 close(fence);
284
285 all = new;
286 }
287
288 igt_assert(gem_bo_busy(fd, obj.handle));
289 igt_assert(fence_busy(all));
290
291 timeout = 120;
292 if ((flags & HANG) == 0) {
293 *batch = MI_BATCH_BUFFER_END;
294 __sync_synchronize();
295 timeout = 1;
296 }
297 munmap(batch, 4096);
298
299 if (flags & WAIT) {
300 struct pollfd pfd = { .fd = all, .events = POLLIN };
301 igt_assert(poll(&pfd, 1, timeout*1000) == 1);
302 } else {
303 memset(&tv, 0, sizeof(tv));
304 while (fence_busy(all))
305 igt_assert(igt_seconds_elapsed(&tv) < timeout);
306 }
307
308 igt_assert(!gem_bo_busy(fd, obj.handle));
309 igt_assert_eq(sync_fence_status(all),
310 flags & HANG ? -EIO : SYNC_FENCE_OK);
311
312 close(all);
313 gem_close(fd, obj.handle);
314
315 gem_quiescent_gpu(fd);
316 }
317
test_fence_await(int fd,unsigned ring,unsigned flags)318 static void test_fence_await(int fd, unsigned ring, unsigned flags)
319 {
320 uint32_t scratch = gem_create(fd, 4096);
321 igt_spin_t *spin;
322 unsigned engine;
323 uint32_t *out;
324 int i;
325
326 igt_require(gem_can_store_dword(fd, 0));
327
328 out = gem_mmap__wc(fd, scratch, 0, 4096, PROT_WRITE);
329 gem_set_domain(fd, scratch,
330 I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
331
332 spin = igt_spin_new(fd,
333 .engine = ring,
334 .flags = IGT_SPIN_FENCE_OUT);
335 igt_assert(spin->out_fence != -1);
336
337 i = 0;
338 for_each_physical_engine(fd, engine) {
339 if (!gem_can_store_dword(fd, engine))
340 continue;
341
342 if (flags & NONBLOCK) {
343 store(fd, engine, spin->out_fence, scratch, i);
344 } else {
345 igt_fork(child, 1)
346 store(fd, engine, spin->out_fence, scratch, i);
347 }
348
349 i++;
350 }
351
352 sleep(1);
353
354 /* Check for invalidly completing the task early */
355 igt_assert(fence_busy(spin->out_fence));
356 for (int n = 0; n < i; n++)
357 igt_assert_eq_u32(out[n], 0);
358
359 if ((flags & HANG) == 0)
360 igt_spin_end(spin);
361
362 igt_waitchildren();
363
364 gem_set_domain(fd, scratch, I915_GEM_DOMAIN_GTT, 0);
365 while (i--)
366 igt_assert_eq_u32(out[i], i);
367 munmap(out, 4096);
368
369 igt_spin_free(fd, spin);
370 gem_close(fd, scratch);
371 }
372
resubmit(int fd,uint32_t handle,unsigned int ring,int count)373 static void resubmit(int fd, uint32_t handle, unsigned int ring, int count)
374 {
375 struct drm_i915_gem_exec_object2 obj = { .handle = handle };
376 struct drm_i915_gem_execbuffer2 execbuf = {
377 .buffers_ptr = to_user_pointer(&obj),
378 .buffer_count = 1,
379 .flags = ring,
380 };
381 while (count--)
382 gem_execbuf(fd, &execbuf);
383 }
384
alarm_handler(int sig)385 static void alarm_handler(int sig)
386 {
387 }
388
__execbuf(int fd,struct drm_i915_gem_execbuffer2 * execbuf)389 static int __execbuf(int fd, struct drm_i915_gem_execbuffer2 *execbuf)
390 {
391 int err;
392
393 err = 0;
394 if (ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2_WR, execbuf))
395 err = -errno;
396
397 errno = 0;
398 return err;
399 }
400
test_parallel(int fd,unsigned int master)401 static void test_parallel(int fd, unsigned int master)
402 {
403 const int SCRATCH = 0;
404 const int BATCH = 1;
405 const int gen = intel_gen(intel_get_drm_devid(fd));
406 struct drm_i915_gem_exec_object2 obj[2];
407 struct drm_i915_gem_relocation_entry reloc[2];
408 struct drm_i915_gem_execbuffer2 execbuf;
409 uint32_t scratch = gem_create(fd, 4096);
410 uint32_t *out = gem_mmap__wc(fd, scratch, 0, 4096, PROT_READ);
411 uint32_t handle[16];
412 uint32_t batch[16];
413 igt_spin_t *spin;
414 unsigned engine;
415 IGT_CORK_HANDLE(c);
416 uint32_t plug;
417 int i, x = 0;
418
419 plug = igt_cork_plug(&c, fd);
420
421 /* Fill the queue with many requests so that the next one has to
422 * wait before it can be executed by the hardware.
423 */
424 spin = igt_spin_new(fd, .engine = master, .dependency = plug);
425 resubmit(fd, spin->handle, master, 16);
426
427 /* Now queue the master request and its secondaries */
428 memset(&execbuf, 0, sizeof(execbuf));
429 execbuf.buffers_ptr = to_user_pointer(obj);
430 execbuf.buffer_count = 2;
431 execbuf.flags = master | LOCAL_EXEC_FENCE_OUT;
432 if (gen < 6)
433 execbuf.flags |= I915_EXEC_SECURE;
434
435 memset(obj, 0, sizeof(obj));
436 obj[SCRATCH].handle = scratch;
437
438 obj[BATCH].handle = gem_create(fd, 4096);
439 handle[x] = obj[BATCH].handle;
440 obj[BATCH].relocs_ptr = to_user_pointer(&reloc);
441 obj[BATCH].relocation_count = 2;
442 memset(reloc, 0, sizeof(reloc));
443
444 i = 0;
445
446 reloc[0].target_handle = obj[SCRATCH].handle;
447 reloc[0].presumed_offset = -1;
448 reloc[0].offset = sizeof(uint32_t) * (i + 1);
449 reloc[0].delta = sizeof(uint32_t) * x++;
450 reloc[0].read_domains = I915_GEM_DOMAIN_INSTRUCTION;
451 reloc[0].write_domain = 0; /* lies */
452
453 batch[i] = MI_STORE_DWORD_IMM | (gen < 6 ? 1 << 22 : 0);
454 if (gen >= 8) {
455 batch[++i] = reloc[0].presumed_offset + reloc[0].delta;
456 batch[++i] = (reloc[0].presumed_offset + reloc[0].delta) >> 32;
457 } else if (gen >= 4) {
458 batch[++i] = 0;
459 batch[++i] = reloc[0].presumed_offset + reloc[0].delta;
460 reloc[0].offset += sizeof(uint32_t);
461 } else {
462 batch[i]--;
463 batch[++i] = reloc[0].presumed_offset + reloc[0].delta;
464 }
465 batch[++i] = ~0u ^ x;
466
467 reloc[1].target_handle = obj[BATCH].handle; /* recurse */
468 reloc[1].presumed_offset = 0;
469 reloc[1].offset = sizeof(uint32_t) * (i + 2);
470 reloc[1].delta = 0;
471 reloc[1].read_domains = I915_GEM_DOMAIN_COMMAND;
472 reloc[1].write_domain = 0;
473
474 batch[++i] = MI_BATCH_BUFFER_START;
475 if (gen >= 8) {
476 batch[i] |= 1 << 8 | 1;
477 batch[++i] = 0;
478 batch[++i] = 0;
479 } else if (gen >= 6) {
480 batch[i] |= 1 << 8;
481 batch[++i] = 0;
482 } else {
483 batch[i] |= 2 << 6;
484 batch[++i] = 0;
485 if (gen < 4) {
486 batch[i] |= 1;
487 reloc[1].delta = 1;
488 }
489 }
490 batch[++i] = MI_BATCH_BUFFER_END;
491 igt_assert(i < sizeof(batch)/sizeof(batch[0]));
492 gem_write(fd, obj[BATCH].handle, 0, batch, sizeof(batch));
493 gem_execbuf_wr(fd, &execbuf);
494
495 igt_assert(execbuf.rsvd2);
496 execbuf.rsvd2 >>= 32; /* out fence -> in fence */
497 obj[BATCH].relocation_count = 1;
498
499 /* Queue all secondaries */
500 for_each_physical_engine(fd, engine) {
501 if (engine == master)
502 continue;
503
504 execbuf.flags = engine | LOCAL_EXEC_FENCE_SUBMIT;
505 if (gen < 6)
506 execbuf.flags |= I915_EXEC_SECURE;
507
508 obj[BATCH].handle = gem_create(fd, 4096);
509 handle[x] = obj[BATCH].handle;
510
511 i = 0;
512 reloc[0].delta = sizeof(uint32_t) * x++;
513 batch[i] = MI_STORE_DWORD_IMM | (gen < 6 ? 1 << 22 : 0);
514 if (gen >= 8) {
515 batch[++i] = reloc[0].presumed_offset + reloc[0].delta;
516 batch[++i] = (reloc[0].presumed_offset + reloc[0].delta) >> 32;
517 } else if (gen >= 4) {
518 batch[++i] = 0;
519 batch[++i] = reloc[0].presumed_offset + reloc[0].delta;
520 } else {
521 batch[i]--;
522 batch[++i] = reloc[0].presumed_offset + reloc[0].delta;
523 }
524 batch[++i] = ~0u ^ x;
525 batch[++i] = MI_BATCH_BUFFER_END;
526 gem_write(fd, obj[BATCH].handle, 0, batch, sizeof(batch));
527 gem_execbuf(fd, &execbuf);
528 }
529 igt_assert(gem_bo_busy(fd, spin->handle));
530 close(execbuf.rsvd2);
531
532 /* No secondary should be executed since master is stalled. If there
533 * was no dependency chain at all, the secondaries would start
534 * immediately.
535 */
536 for (i = 0; i < x; i++) {
537 igt_assert_eq_u32(out[i], 0);
538 igt_assert(gem_bo_busy(fd, handle[i]));
539 }
540
541 /* Unblock the master */
542 igt_cork_unplug(&c);
543 gem_close(fd, plug);
544 igt_spin_end(spin);
545
546 /* Wait for all secondaries to complete. If we used a regular fence
547 * then the secondaries would not start until the master was complete.
548 * In this case that can only happen with a GPU reset, and so we run
549 * under the hang detector and double check that the master is still
550 * running afterwards.
551 */
552 for (i = 1; i < x; i++) {
553 while (gem_bo_busy(fd, handle[i]))
554 sleep(0);
555
556 igt_assert_f(out[i], "Missing output from engine %d\n", i);
557 gem_close(fd, handle[i]);
558 }
559 munmap(out, 4096);
560 gem_close(fd, obj[SCRATCH].handle);
561
562 /* Master should still be spinning, but all output should be written */
563 igt_assert(gem_bo_busy(fd, handle[0]));
564 out = gem_mmap__wc(fd, handle[0], 0, 4096, PROT_WRITE);
565 out[0] = MI_BATCH_BUFFER_END;
566 munmap(out, 4096);
567 gem_close(fd, handle[0]);
568 }
569
batch_create(int fd)570 static uint32_t batch_create(int fd)
571 {
572 const uint32_t bbe = MI_BATCH_BUFFER_END;
573 uint32_t handle;
574
575 handle = gem_create(fd, 4096);
576 gem_write(fd, handle, 0, &bbe, sizeof(bbe));
577
578 return handle;
579 }
580
lower_32_bits(uint64_t x)581 static inline uint32_t lower_32_bits(uint64_t x)
582 {
583 return x & 0xffffffff;
584 }
585
upper_32_bits(uint64_t x)586 static inline uint32_t upper_32_bits(uint64_t x)
587 {
588 return x >> 32;
589 }
590
test_keep_in_fence(int fd,unsigned int engine,unsigned int flags)591 static void test_keep_in_fence(int fd, unsigned int engine, unsigned int flags)
592 {
593 struct sigaction sa = { .sa_handler = alarm_handler };
594 struct drm_i915_gem_exec_object2 obj = {
595 .handle = batch_create(fd),
596 };
597 struct drm_i915_gem_execbuffer2 execbuf = {
598 .buffers_ptr = to_user_pointer(&obj),
599 .buffer_count = 1,
600 .flags = engine | LOCAL_EXEC_FENCE_OUT,
601 };
602 unsigned long count, last;
603 struct itimerval itv;
604 igt_spin_t *spin;
605 int fence;
606
607 spin = igt_spin_new(fd, .engine = engine);
608
609 gem_execbuf_wr(fd, &execbuf);
610 fence = upper_32_bits(execbuf.rsvd2);
611
612 sigaction(SIGALRM, &sa, NULL);
613 itv.it_interval.tv_sec = 0;
614 itv.it_interval.tv_usec = 1000;
615 itv.it_value.tv_sec = 0;
616 itv.it_value.tv_usec = 10000;
617 setitimer(ITIMER_REAL, &itv, NULL);
618
619 execbuf.flags |= LOCAL_EXEC_FENCE_IN;
620 execbuf.rsvd2 = fence;
621
622 last = -1;
623 count = 0;
624 do {
625 int err = __execbuf(fd, &execbuf);
626
627 igt_assert_eq(lower_32_bits(execbuf.rsvd2), fence);
628
629 if (err == 0) {
630 close(fence);
631
632 fence = upper_32_bits(execbuf.rsvd2);
633 execbuf.rsvd2 = fence;
634
635 count++;
636 continue;
637 }
638
639 igt_assert_eq(err, -EINTR);
640 igt_assert_eq(upper_32_bits(execbuf.rsvd2), 0);
641
642 if (last == count)
643 break;
644
645 last = count;
646 } while (1);
647
648 memset(&itv, 0, sizeof(itv));
649 setitimer(ITIMER_REAL, &itv, NULL);
650
651 gem_close(fd, obj.handle);
652 close(fence);
653
654 igt_spin_free(fd, spin);
655 gem_quiescent_gpu(fd);
656 }
657
658 #define EXPIRED 0x10000
test_long_history(int fd,long ring_size,unsigned flags)659 static void test_long_history(int fd, long ring_size, unsigned flags)
660 {
661 const uint32_t sz = 1 << 20;
662 const uint32_t bbe = MI_BATCH_BUFFER_END;
663 struct drm_i915_gem_exec_object2 obj[2];
664 struct drm_i915_gem_execbuffer2 execbuf;
665 unsigned int engines[16], engine;
666 unsigned int nengine, n, s;
667 unsigned long limit;
668 int all_fences;
669 IGT_CORK_HANDLE(c);
670
671 limit = -1;
672 if (!gem_uses_full_ppgtt(fd))
673 limit = ring_size / 3;
674
675 nengine = 0;
676 for_each_physical_engine(fd, engine)
677 engines[nengine++] = engine;
678 igt_require(nengine);
679
680 gem_quiescent_gpu(fd);
681
682 memset(obj, 0, sizeof(obj));
683 obj[1].handle = gem_create(fd, sz);
684 gem_write(fd, obj[1].handle, sz - sizeof(bbe), &bbe, sizeof(bbe));
685
686 memset(&execbuf, 0, sizeof(execbuf));
687 execbuf.buffers_ptr = to_user_pointer(&obj[1]);
688 execbuf.buffer_count = 1;
689 execbuf.flags = LOCAL_EXEC_FENCE_OUT;
690
691 gem_execbuf_wr(fd, &execbuf);
692 all_fences = execbuf.rsvd2 >> 32;
693
694 execbuf.buffers_ptr = to_user_pointer(obj);
695 execbuf.buffer_count = 2;
696
697 obj[0].handle = igt_cork_plug(&c, fd);
698
699 igt_until_timeout(5) {
700 execbuf.rsvd1 = gem_context_create(fd);
701
702 for (n = 0; n < nengine; n++) {
703 struct sync_merge_data merge;
704
705 execbuf.flags = engines[n] | LOCAL_EXEC_FENCE_OUT;
706 if (__gem_execbuf_wr(fd, &execbuf))
707 continue;
708
709 memset(&merge, 0, sizeof(merge));
710 merge.fd2 = execbuf.rsvd2 >> 32;
711 strcpy(merge.name, "igt");
712
713 do_ioctl(all_fences, SYNC_IOC_MERGE, &merge);
714
715 close(all_fences);
716 close(merge.fd2);
717
718 all_fences = merge.fence;
719 }
720
721 gem_context_destroy(fd, execbuf.rsvd1);
722 if (!--limit)
723 break;
724 }
725 igt_cork_unplug(&c);
726
727 igt_info("History depth = %d\n", sync_fence_count(all_fences));
728
729 if (flags & EXPIRED)
730 gem_sync(fd, obj[1].handle);
731
732 execbuf.buffers_ptr = to_user_pointer(&obj[1]);
733 execbuf.buffer_count = 1;
734 execbuf.rsvd2 = all_fences;
735 execbuf.rsvd1 = 0;
736
737 for (s = 0; s < ring_size; s++) {
738 for (n = 0; n < nengine; n++) {
739 execbuf.flags = engines[n] | LOCAL_EXEC_FENCE_IN;
740 if (__gem_execbuf_wr(fd, &execbuf))
741 continue;
742 }
743 }
744
745 close(all_fences);
746
747 gem_sync(fd, obj[1].handle);
748 gem_close(fd, obj[1].handle);
749 gem_close(fd, obj[0].handle);
750 }
751
test_fence_flip(int i915)752 static void test_fence_flip(int i915)
753 {
754 igt_skip_on_f(1, "no fence-in for atomic flips\n");
755 }
756
has_submit_fence(int fd)757 static bool has_submit_fence(int fd)
758 {
759 struct drm_i915_getparam gp;
760 int value = 0;
761
762 memset(&gp, 0, sizeof(gp));
763 gp.param = 0xdeadbeef ^ 51; /* I915_PARAM_HAS_EXEC_SUBMIT_FENCE */
764 gp.value = &value;
765
766 ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp, sizeof(gp));
767 errno = 0;
768
769 return value;
770 }
771
has_syncobj(int fd)772 static bool has_syncobj(int fd)
773 {
774 struct drm_get_cap cap = { .capability = 0x13 };
775 ioctl(fd, DRM_IOCTL_GET_CAP, &cap);
776 return cap.value;
777 }
778
exec_has_fence_array(int fd)779 static bool exec_has_fence_array(int fd)
780 {
781 struct drm_i915_getparam gp;
782 int value = 0;
783
784 memset(&gp, 0, sizeof(gp));
785 gp.param = 49; /* I915_PARAM_HAS_EXEC_FENCE_ARRAY */
786 gp.value = &value;
787
788 ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp, sizeof(gp));
789 errno = 0;
790
791 return value;
792 }
793
test_invalid_fence_array(int fd)794 static void test_invalid_fence_array(int fd)
795 {
796 const uint32_t bbe = MI_BATCH_BUFFER_END;
797 struct drm_i915_gem_execbuffer2 execbuf;
798 struct drm_i915_gem_exec_object2 obj;
799 struct local_gem_exec_fence fence;
800 void *ptr;
801
802 /* create an otherwise valid execbuf */
803 memset(&obj, 0, sizeof(obj));
804 obj.handle = gem_create(fd, 4096);
805 gem_write(fd, obj.handle, 0, &bbe, sizeof(bbe));
806 memset(&execbuf, 0, sizeof(execbuf));
807 execbuf.buffers_ptr = to_user_pointer(&obj);
808 execbuf.buffer_count = 1;
809 gem_execbuf(fd, &execbuf);
810
811 execbuf.flags |= LOCAL_EXEC_FENCE_ARRAY;
812 gem_execbuf(fd, &execbuf);
813
814 /* Now add a few invalid fence-array pointers */
815 if (sizeof(execbuf.num_cliprects) == sizeof(size_t)) {
816 execbuf.num_cliprects = -1;
817 igt_assert_eq(__gem_execbuf(fd, &execbuf), -EINVAL);
818 }
819
820 execbuf.num_cliprects = 1;
821 execbuf.cliprects_ptr = -1;
822 igt_assert_eq(__gem_execbuf(fd, &execbuf), -EFAULT);
823
824 memset(&fence, 0, sizeof(fence));
825 execbuf.cliprects_ptr = to_user_pointer(&fence);
826 igt_assert_eq(__gem_execbuf(fd, &execbuf), -ENOENT);
827
828 ptr = mmap(NULL, 4096, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
829 igt_assert(ptr != MAP_FAILED);
830 execbuf.cliprects_ptr = to_user_pointer(ptr);
831 igt_assert_eq(__gem_execbuf(fd, &execbuf), -ENOENT);
832
833 do_or_die(mprotect(ptr, 4096, PROT_READ));
834 igt_assert_eq(__gem_execbuf(fd, &execbuf), -ENOENT);
835
836 do_or_die(mprotect(ptr, 4096, PROT_NONE));
837 igt_assert_eq(__gem_execbuf(fd, &execbuf), -EFAULT);
838
839 munmap(ptr, 4096);
840 }
841
__syncobj_create(int fd)842 static uint32_t __syncobj_create(int fd)
843 {
844 struct local_syncobj_create {
845 uint32_t handle, flags;
846 } arg;
847 #define LOCAL_IOCTL_SYNCOBJ_CREATE DRM_IOWR(0xBF, struct local_syncobj_create)
848
849 memset(&arg, 0, sizeof(arg));
850 igt_ioctl(fd, LOCAL_IOCTL_SYNCOBJ_CREATE, &arg);
851
852 return arg.handle;
853 }
854
syncobj_create(int fd)855 static uint32_t syncobj_create(int fd)
856 {
857 uint32_t ret;
858
859 igt_assert_neq((ret = __syncobj_create(fd)), 0);
860
861 return ret;
862 }
863
__syncobj_destroy(int fd,uint32_t handle)864 static int __syncobj_destroy(int fd, uint32_t handle)
865 {
866 struct local_syncobj_destroy {
867 uint32_t handle, flags;
868 } arg;
869 #define LOCAL_IOCTL_SYNCOBJ_DESTROY DRM_IOWR(0xC0, struct local_syncobj_destroy)
870 int err = 0;
871
872 memset(&arg, 0, sizeof(arg));
873 arg.handle = handle;
874 if (igt_ioctl(fd, LOCAL_IOCTL_SYNCOBJ_DESTROY, &arg))
875 err = -errno;
876
877 errno = 0;
878 return err;
879 }
880
syncobj_destroy(int fd,uint32_t handle)881 static void syncobj_destroy(int fd, uint32_t handle)
882 {
883 igt_assert_eq(__syncobj_destroy(fd, handle), 0);
884 }
885
__syncobj_to_sync_file(int fd,uint32_t handle)886 static int __syncobj_to_sync_file(int fd, uint32_t handle)
887 {
888 struct local_syncobj_handle {
889 uint32_t handle;
890 uint32_t flags;
891 int32_t fd;
892 uint32_t pad;
893 } arg;
894 #define LOCAL_IOCTL_SYNCOBJ_HANDLE_TO_FD DRM_IOWR(0xC1, struct local_syncobj_handle)
895
896 memset(&arg, 0, sizeof(arg));
897 arg.handle = handle;
898 arg.flags = 1 << 0; /* EXPORT_SYNC_FILE */
899 if (igt_ioctl(fd, LOCAL_IOCTL_SYNCOBJ_HANDLE_TO_FD, &arg))
900 arg.fd = -errno;
901
902 errno = 0;
903 return arg.fd;
904 }
905
syncobj_to_sync_file(int fd,uint32_t handle)906 static int syncobj_to_sync_file(int fd, uint32_t handle)
907 {
908 int ret;
909
910 igt_assert_lte(0, (ret = __syncobj_to_sync_file(fd, handle)));
911
912 return ret;
913 }
914
__syncobj_from_sync_file(int fd,uint32_t handle,int sf)915 static int __syncobj_from_sync_file(int fd, uint32_t handle, int sf)
916 {
917 struct local_syncobj_handle {
918 uint32_t handle;
919 uint32_t flags;
920 int32_t fd;
921 uint32_t pad;
922 } arg;
923 #define LOCAL_IOCTL_SYNCOBJ_FD_TO_HANDLE DRM_IOWR(0xC2, struct local_syncobj_handle)
924 int err = 0;
925
926 memset(&arg, 0, sizeof(arg));
927 arg.handle = handle;
928 arg.fd = sf;
929 arg.flags = 1 << 0; /* IMPORT_SYNC_FILE */
930 if (igt_ioctl(fd, LOCAL_IOCTL_SYNCOBJ_FD_TO_HANDLE, &arg))
931 err = -errno;
932
933 errno = 0;
934 return err;
935 }
936
syncobj_from_sync_file(int fd,uint32_t handle,int sf)937 static void syncobj_from_sync_file(int fd, uint32_t handle, int sf)
938 {
939 igt_assert_eq(__syncobj_from_sync_file(fd, handle, sf), 0);
940 }
941
__syncobj_export(int fd,uint32_t handle,int * syncobj)942 static int __syncobj_export(int fd, uint32_t handle, int *syncobj)
943 {
944 struct local_syncobj_handle {
945 uint32_t handle;
946 uint32_t flags;
947 int32_t fd;
948 uint32_t pad;
949 } arg;
950 int err;
951
952 memset(&arg, 0, sizeof(arg));
953 arg.handle = handle;
954
955 err = 0;
956 if (igt_ioctl(fd, LOCAL_IOCTL_SYNCOBJ_HANDLE_TO_FD, &arg))
957 err = -errno;
958
959 errno = 0;
960 *syncobj = arg.fd;
961 return err;
962 }
963
syncobj_export(int fd,uint32_t handle)964 static int syncobj_export(int fd, uint32_t handle)
965 {
966 int syncobj;
967
968 igt_assert_eq(__syncobj_export(fd, handle, &syncobj), 0);
969
970 return syncobj;
971 }
972
__syncobj_import(int fd,int syncobj,uint32_t * handle)973 static int __syncobj_import(int fd, int syncobj, uint32_t *handle)
974 {
975 struct local_syncobj_handle {
976 uint32_t handle;
977 uint32_t flags;
978 int32_t fd;
979 uint32_t pad;
980 } arg;
981 #define LOCAL_IOCTL_SYNCOBJ_FD_TO_HANDLE DRM_IOWR(0xC2, struct local_syncobj_handle)
982 int err;
983
984 memset(&arg, 0, sizeof(arg));
985 arg.fd = syncobj;
986
987 err = 0;
988 if (igt_ioctl(fd, LOCAL_IOCTL_SYNCOBJ_FD_TO_HANDLE, &arg))
989 err = -errno;
990
991 errno = 0;
992 *handle = arg.handle;
993 return err;
994 }
995
syncobj_import(int fd,int syncobj)996 static uint32_t syncobj_import(int fd, int syncobj)
997 {
998 uint32_t handle;
999
1000 igt_assert_eq(__syncobj_import(fd, syncobj, &handle), 0);
1001
1002
1003 return handle;
1004 }
1005
syncobj_busy(int fd,uint32_t handle)1006 static bool syncobj_busy(int fd, uint32_t handle)
1007 {
1008 bool result;
1009 int sf;
1010
1011 sf = syncobj_to_sync_file(fd, handle);
1012 result = poll(&(struct pollfd){sf, POLLIN}, 1, 0) == 0;
1013 close(sf);
1014
1015 return result;
1016 }
1017
test_syncobj_unused_fence(int fd)1018 static void test_syncobj_unused_fence(int fd)
1019 {
1020 const uint32_t bbe = MI_BATCH_BUFFER_END;
1021 struct drm_i915_gem_exec_object2 obj;
1022 struct drm_i915_gem_execbuffer2 execbuf;
1023 struct local_gem_exec_fence fence = {
1024 .handle = syncobj_create(fd),
1025 };
1026 igt_spin_t *spin = igt_spin_new(fd);
1027
1028 /* sanity check our syncobj_to_sync_file interface */
1029 igt_assert_eq(__syncobj_to_sync_file(fd, 0), -ENOENT);
1030
1031 memset(&execbuf, 0, sizeof(execbuf));
1032 execbuf.buffers_ptr = to_user_pointer(&obj);
1033 execbuf.buffer_count = 1;
1034 execbuf.flags = LOCAL_EXEC_FENCE_ARRAY;
1035 execbuf.cliprects_ptr = to_user_pointer(&fence);
1036 execbuf.num_cliprects = 1;
1037
1038 memset(&obj, 0, sizeof(obj));
1039 obj.handle = gem_create(fd, 4096);
1040 gem_write(fd, obj.handle, 0, &bbe, sizeof(bbe));
1041
1042 gem_execbuf(fd, &execbuf);
1043
1044 /* no flags, the fence isn't created */
1045 igt_assert_eq(__syncobj_to_sync_file(fd, fence.handle), -EINVAL);
1046 igt_assert(gem_bo_busy(fd, obj.handle));
1047
1048 gem_close(fd, obj.handle);
1049 syncobj_destroy(fd, fence.handle);
1050
1051 igt_spin_free(fd, spin);
1052 }
1053
test_syncobj_invalid_wait(int fd)1054 static void test_syncobj_invalid_wait(int fd)
1055 {
1056 const uint32_t bbe = MI_BATCH_BUFFER_END;
1057 struct drm_i915_gem_exec_object2 obj;
1058 struct drm_i915_gem_execbuffer2 execbuf;
1059 struct local_gem_exec_fence fence = {
1060 .handle = syncobj_create(fd),
1061 };
1062
1063 memset(&execbuf, 0, sizeof(execbuf));
1064 execbuf.buffers_ptr = to_user_pointer(&obj);
1065 execbuf.buffer_count = 1;
1066 execbuf.flags = LOCAL_EXEC_FENCE_ARRAY;
1067 execbuf.cliprects_ptr = to_user_pointer(&fence);
1068 execbuf.num_cliprects = 1;
1069
1070 memset(&obj, 0, sizeof(obj));
1071 obj.handle = gem_create(fd, 4096);
1072 gem_write(fd, obj.handle, 0, &bbe, sizeof(bbe));
1073
1074 /* waiting before the fence is set is invalid */
1075 fence.flags = LOCAL_EXEC_FENCE_WAIT;
1076 igt_assert_eq(__gem_execbuf(fd, &execbuf), -EINVAL);
1077
1078 gem_close(fd, obj.handle);
1079 syncobj_destroy(fd, fence.handle);
1080 }
1081
test_syncobj_invalid_flags(int fd)1082 static void test_syncobj_invalid_flags(int fd)
1083 {
1084 const uint32_t bbe = MI_BATCH_BUFFER_END;
1085 struct drm_i915_gem_exec_object2 obj;
1086 struct drm_i915_gem_execbuffer2 execbuf;
1087 struct local_gem_exec_fence fence = {
1088 .handle = syncobj_create(fd),
1089 };
1090
1091 memset(&execbuf, 0, sizeof(execbuf));
1092 execbuf.buffers_ptr = to_user_pointer(&obj);
1093 execbuf.buffer_count = 1;
1094 execbuf.flags = LOCAL_EXEC_FENCE_ARRAY;
1095 execbuf.cliprects_ptr = to_user_pointer(&fence);
1096 execbuf.num_cliprects = 1;
1097
1098 memset(&obj, 0, sizeof(obj));
1099 obj.handle = gem_create(fd, 4096);
1100 gem_write(fd, obj.handle, 0, &bbe, sizeof(bbe));
1101
1102 /* set all flags to hit an invalid one */
1103 fence.flags = ~0;
1104 igt_assert_eq(__gem_execbuf(fd, &execbuf), -EINVAL);
1105
1106 gem_close(fd, obj.handle);
1107 syncobj_destroy(fd, fence.handle);
1108 }
1109
test_syncobj_signal(int fd)1110 static void test_syncobj_signal(int fd)
1111 {
1112 const uint32_t bbe = MI_BATCH_BUFFER_END;
1113 struct drm_i915_gem_exec_object2 obj;
1114 struct drm_i915_gem_execbuffer2 execbuf;
1115 struct local_gem_exec_fence fence = {
1116 .handle = syncobj_create(fd),
1117 };
1118 igt_spin_t *spin = igt_spin_new(fd);
1119
1120 /* Check that the syncobj is signaled only when our request/fence is */
1121
1122 memset(&execbuf, 0, sizeof(execbuf));
1123 execbuf.buffers_ptr = to_user_pointer(&obj);
1124 execbuf.buffer_count = 1;
1125 execbuf.flags = LOCAL_EXEC_FENCE_ARRAY;
1126 execbuf.cliprects_ptr = to_user_pointer(&fence);
1127 execbuf.num_cliprects = 1;
1128
1129 memset(&obj, 0, sizeof(obj));
1130 obj.handle = gem_create(fd, 4096);
1131 gem_write(fd, obj.handle, 0, &bbe, sizeof(bbe));
1132
1133 fence.flags = LOCAL_EXEC_FENCE_SIGNAL;
1134 gem_execbuf(fd, &execbuf);
1135
1136 igt_assert(gem_bo_busy(fd, obj.handle));
1137 igt_assert(syncobj_busy(fd, fence.handle));
1138
1139 igt_spin_free(fd, spin);
1140
1141 gem_sync(fd, obj.handle);
1142 igt_assert(!gem_bo_busy(fd, obj.handle));
1143 igt_assert(!syncobj_busy(fd, fence.handle));
1144
1145 gem_close(fd, obj.handle);
1146 syncobj_destroy(fd, fence.handle);
1147 }
1148
test_syncobj_wait(int fd)1149 static void test_syncobj_wait(int fd)
1150 {
1151 const uint32_t bbe = MI_BATCH_BUFFER_END;
1152 struct drm_i915_gem_exec_object2 obj;
1153 struct drm_i915_gem_execbuffer2 execbuf;
1154 struct local_gem_exec_fence fence = {
1155 .handle = syncobj_create(fd),
1156 };
1157 igt_spin_t *spin;
1158 unsigned engine;
1159 unsigned handle[16];
1160 int n;
1161
1162 /* Check that we can use the syncobj to asynchronous wait prior to
1163 * execution.
1164 */
1165
1166 gem_quiescent_gpu(fd);
1167
1168 spin = igt_spin_new(fd);
1169
1170 memset(&execbuf, 0, sizeof(execbuf));
1171 execbuf.buffers_ptr = to_user_pointer(&obj);
1172 execbuf.buffer_count = 1;
1173
1174 memset(&obj, 0, sizeof(obj));
1175 obj.handle = gem_create(fd, 4096);
1176 gem_write(fd, obj.handle, 0, &bbe, sizeof(bbe));
1177
1178 /* Queue a signaler from the blocked engine */
1179 execbuf.flags = LOCAL_EXEC_FENCE_ARRAY;
1180 execbuf.cliprects_ptr = to_user_pointer(&fence);
1181 execbuf.num_cliprects = 1;
1182 fence.flags = LOCAL_EXEC_FENCE_SIGNAL;
1183 gem_execbuf(fd, &execbuf);
1184 igt_assert(gem_bo_busy(fd, spin->handle));
1185
1186 gem_close(fd, obj.handle);
1187 obj.handle = gem_create(fd, 4096);
1188 gem_write(fd, obj.handle, 0, &bbe, sizeof(bbe));
1189
1190 n = 0;
1191 for_each_engine(fd, engine) {
1192 obj.handle = gem_create(fd, 4096);
1193 gem_write(fd, obj.handle, 0, &bbe, sizeof(bbe));
1194
1195 /* No inter-engine synchronisation, will complete */
1196 if (engine == I915_EXEC_BLT) {
1197 execbuf.flags = engine;
1198 execbuf.cliprects_ptr = 0;
1199 execbuf.num_cliprects = 0;
1200 gem_execbuf(fd, &execbuf);
1201 gem_sync(fd, obj.handle);
1202 igt_assert(gem_bo_busy(fd, spin->handle));
1203 }
1204 igt_assert(gem_bo_busy(fd, spin->handle));
1205
1206 /* Now wait upon the blocked engine */
1207 execbuf.flags = LOCAL_EXEC_FENCE_ARRAY | engine;
1208 execbuf.cliprects_ptr = to_user_pointer(&fence);
1209 execbuf.num_cliprects = 1;
1210 fence.flags = LOCAL_EXEC_FENCE_WAIT;
1211 gem_execbuf(fd, &execbuf);
1212
1213 igt_assert(gem_bo_busy(fd, obj.handle));
1214 handle[n++] = obj.handle;
1215 }
1216 syncobj_destroy(fd, fence.handle);
1217
1218 for (int i = 0; i < n; i++)
1219 igt_assert(gem_bo_busy(fd, handle[i]));
1220
1221 igt_spin_free(fd, spin);
1222
1223 for (int i = 0; i < n; i++) {
1224 gem_sync(fd, handle[i]);
1225 gem_close(fd, handle[i]);
1226 }
1227 }
1228
test_syncobj_export(int fd)1229 static void test_syncobj_export(int fd)
1230 {
1231 const uint32_t bbe = MI_BATCH_BUFFER_END;
1232 struct drm_i915_gem_exec_object2 obj;
1233 struct drm_i915_gem_execbuffer2 execbuf;
1234 struct local_gem_exec_fence fence = {
1235 .handle = syncobj_create(fd),
1236 };
1237 int export[2];
1238 igt_spin_t *spin = igt_spin_new(fd);
1239
1240 /* Check that if we export the syncobj prior to use it picks up
1241 * the later fence. This allows a syncobj to establish a channel
1242 * between clients that may be updated to a later fence by either
1243 * end.
1244 */
1245 for (int n = 0; n < ARRAY_SIZE(export); n++)
1246 export[n] = syncobj_export(fd, fence.handle);
1247
1248 memset(&execbuf, 0, sizeof(execbuf));
1249 execbuf.buffers_ptr = to_user_pointer(&obj);
1250 execbuf.buffer_count = 1;
1251 execbuf.flags = LOCAL_EXEC_FENCE_ARRAY;
1252 execbuf.cliprects_ptr = to_user_pointer(&fence);
1253 execbuf.num_cliprects = 1;
1254
1255 memset(&obj, 0, sizeof(obj));
1256 obj.handle = gem_create(fd, 4096);
1257 gem_write(fd, obj.handle, 0, &bbe, sizeof(bbe));
1258
1259 fence.flags = LOCAL_EXEC_FENCE_SIGNAL;
1260 gem_execbuf(fd, &execbuf);
1261
1262 igt_assert(syncobj_busy(fd, fence.handle));
1263 igt_assert(gem_bo_busy(fd, obj.handle));
1264
1265 for (int n = 0; n < ARRAY_SIZE(export); n++) {
1266 uint32_t import = syncobj_import(fd, export[n]);
1267 igt_assert(syncobj_busy(fd, import));
1268 syncobj_destroy(fd, import);
1269 }
1270
1271 igt_spin_free(fd, spin);
1272
1273 gem_sync(fd, obj.handle);
1274 igt_assert(!gem_bo_busy(fd, obj.handle));
1275 igt_assert(!syncobj_busy(fd, fence.handle));
1276
1277 gem_close(fd, obj.handle);
1278 syncobj_destroy(fd, fence.handle);
1279
1280 for (int n = 0; n < ARRAY_SIZE(export); n++) {
1281 uint32_t import = syncobj_import(fd, export[n]);
1282 igt_assert(!syncobj_busy(fd, import));
1283 syncobj_destroy(fd, import);
1284 close(export[n]);
1285 }
1286 }
1287
test_syncobj_repeat(int fd)1288 static void test_syncobj_repeat(int fd)
1289 {
1290 const uint32_t bbe = MI_BATCH_BUFFER_END;
1291 const unsigned nfences = 4096;
1292 struct drm_i915_gem_exec_object2 obj;
1293 struct drm_i915_gem_execbuffer2 execbuf;
1294 struct local_gem_exec_fence *fence;
1295 int export;
1296 igt_spin_t *spin = igt_spin_new(fd);
1297
1298 /* Check that we can wait on the same fence multiple times */
1299 fence = calloc(nfences, sizeof(*fence));
1300 fence->handle = syncobj_create(fd);
1301 export = syncobj_export(fd, fence->handle);
1302 for (int i = 1; i < nfences; i++)
1303 fence[i].handle = syncobj_import(fd, export);
1304 close(export);
1305
1306 memset(&execbuf, 0, sizeof(execbuf));
1307 execbuf.buffers_ptr = to_user_pointer(&obj);
1308 execbuf.buffer_count = 1;
1309 execbuf.flags = LOCAL_EXEC_FENCE_ARRAY;
1310 execbuf.cliprects_ptr = to_user_pointer(fence);
1311 execbuf.num_cliprects = nfences;
1312
1313 memset(&obj, 0, sizeof(obj));
1314 obj.handle = gem_create(fd, 4096);
1315 gem_write(fd, obj.handle, 0, &bbe, sizeof(bbe));
1316
1317 for (int i = 0; i < nfences; i++)
1318 fence[i].flags = LOCAL_EXEC_FENCE_SIGNAL;
1319
1320 gem_execbuf(fd, &execbuf);
1321
1322 for (int i = 0; i < nfences; i++) {
1323 igt_assert(syncobj_busy(fd, fence[i].handle));
1324 fence[i].flags |= LOCAL_EXEC_FENCE_WAIT;
1325 }
1326 igt_assert(gem_bo_busy(fd, obj.handle));
1327
1328 gem_execbuf(fd, &execbuf);
1329
1330 for (int i = 0; i < nfences; i++)
1331 igt_assert(syncobj_busy(fd, fence[i].handle));
1332 igt_assert(gem_bo_busy(fd, obj.handle));
1333
1334 igt_spin_free(fd, spin);
1335
1336 gem_sync(fd, obj.handle);
1337 gem_close(fd, obj.handle);
1338
1339 for (int i = 0; i < nfences; i++) {
1340 igt_assert(!syncobj_busy(fd, fence[i].handle));
1341 syncobj_destroy(fd, fence[i].handle);
1342 }
1343 free(fence);
1344 }
1345
test_syncobj_import(int fd)1346 static void test_syncobj_import(int fd)
1347 {
1348 const uint32_t bbe = MI_BATCH_BUFFER_END;
1349 struct drm_i915_gem_exec_object2 obj;
1350 struct drm_i915_gem_execbuffer2 execbuf;
1351 igt_spin_t *spin = igt_spin_new(fd);
1352 uint32_t sync = syncobj_create(fd);
1353 int fence;
1354
1355 /* Check that we can create a syncobj from an explicit fence (which
1356 * uses sync_file) and that it acts just like a regular fence.
1357 */
1358
1359 memset(&execbuf, 0, sizeof(execbuf));
1360 execbuf.buffers_ptr = to_user_pointer(&obj);
1361 execbuf.buffer_count = 1;
1362 execbuf.flags = LOCAL_EXEC_FENCE_OUT;
1363 execbuf.rsvd2 = -1;
1364
1365 memset(&obj, 0, sizeof(obj));
1366 obj.handle = gem_create(fd, 4096);
1367 gem_write(fd, obj.handle, 0, &bbe, sizeof(bbe));
1368
1369 gem_execbuf_wr(fd, &execbuf);
1370
1371 fence = execbuf.rsvd2 >> 32;
1372 igt_assert(fence_busy(fence));
1373 syncobj_from_sync_file(fd, sync, fence);
1374 close(fence);
1375
1376 igt_assert(gem_bo_busy(fd, obj.handle));
1377 igt_assert(syncobj_busy(fd, sync));
1378
1379 igt_spin_free(fd, spin);
1380
1381 gem_sync(fd, obj.handle);
1382 igt_assert(!gem_bo_busy(fd, obj.handle));
1383 igt_assert(!syncobj_busy(fd, sync));
1384
1385 gem_close(fd, obj.handle);
1386 syncobj_destroy(fd, sync);
1387 }
1388
test_syncobj_channel(int fd)1389 static void test_syncobj_channel(int fd)
1390 {
1391 const uint32_t bbe = MI_BATCH_BUFFER_END;
1392 struct drm_i915_gem_exec_object2 obj;
1393 struct drm_i915_gem_execbuffer2 execbuf;
1394 unsigned int *control;
1395 int syncobj[3];
1396
1397 /* Create a pair of channels (like a pipe) between two clients
1398 * and try to create races on the syncobj.
1399 */
1400
1401 control = mmap(NULL, 4096, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
1402 igt_assert(control != MAP_FAILED);
1403
1404 memset(&execbuf, 0, sizeof(execbuf));
1405 execbuf.buffers_ptr = to_user_pointer(&obj);
1406 execbuf.buffer_count = 1;
1407 execbuf.flags = LOCAL_EXEC_FENCE_OUT;
1408 execbuf.rsvd2 = -1;
1409
1410 memset(&obj, 0, sizeof(obj));
1411 obj.handle = gem_create(fd, 4096);
1412 gem_write(fd, obj.handle, 0, &bbe, sizeof(bbe));
1413
1414 for (int i = 0; i < ARRAY_SIZE(syncobj); i++) {
1415 struct local_gem_exec_fence fence;
1416
1417 execbuf.flags = LOCAL_EXEC_FENCE_ARRAY;
1418 execbuf.cliprects_ptr = to_user_pointer(&fence);
1419 execbuf.num_cliprects = 1;
1420
1421 /* Create a primed fence */
1422 fence.handle = syncobj_create(fd);
1423 fence.flags = LOCAL_EXEC_FENCE_SIGNAL;
1424
1425 gem_execbuf(fd, &execbuf);
1426
1427 syncobj[i] = fence.handle;
1428 }
1429
1430 /* Two processes in ping-pong unison (pipe), one out of sync */
1431 igt_fork(child, 1) {
1432 struct local_gem_exec_fence fence[3];
1433 unsigned long count;
1434
1435 execbuf.flags = LOCAL_EXEC_FENCE_ARRAY;
1436 execbuf.cliprects_ptr = to_user_pointer(fence);
1437 execbuf.num_cliprects = 3;
1438
1439 fence[0].handle = syncobj[0];
1440 fence[0].flags = LOCAL_EXEC_FENCE_SIGNAL;
1441
1442 fence[1].handle = syncobj[1];
1443 fence[1].flags = LOCAL_EXEC_FENCE_WAIT;
1444
1445 fence[2].handle = syncobj[2];
1446 fence[2].flags = LOCAL_EXEC_FENCE_WAIT;
1447
1448 count = 0;
1449 while (!*(volatile unsigned *)control) {
1450 gem_execbuf(fd, &execbuf);
1451 count++;
1452 }
1453
1454 control[1] = count;
1455 }
1456 igt_fork(child, 1) {
1457 struct local_gem_exec_fence fence[3];
1458 unsigned long count;
1459
1460 execbuf.flags = LOCAL_EXEC_FENCE_ARRAY;
1461 execbuf.cliprects_ptr = to_user_pointer(fence);
1462 execbuf.num_cliprects = 3;
1463
1464 fence[0].handle = syncobj[0];
1465 fence[0].flags = LOCAL_EXEC_FENCE_WAIT;
1466
1467 fence[1].handle = syncobj[1];
1468 fence[1].flags = LOCAL_EXEC_FENCE_SIGNAL;
1469
1470 fence[2].handle = syncobj[2];
1471 fence[2].flags = LOCAL_EXEC_FENCE_WAIT;
1472
1473 count = 0;
1474 while (!*(volatile unsigned *)control) {
1475 gem_execbuf(fd, &execbuf);
1476 count++;
1477 }
1478 control[2] = count;
1479 }
1480 igt_fork(child, 1) {
1481 struct local_gem_exec_fence fence;
1482 unsigned long count;
1483
1484 execbuf.flags = LOCAL_EXEC_FENCE_ARRAY;
1485 execbuf.cliprects_ptr = to_user_pointer(&fence);
1486 execbuf.num_cliprects = 1;
1487
1488 fence.handle = syncobj[2];
1489 fence.flags = LOCAL_EXEC_FENCE_SIGNAL;
1490
1491 count = 0;
1492 while (!*(volatile unsigned *)control) {
1493 gem_execbuf(fd, &execbuf);
1494 count++;
1495 }
1496 control[3] = count;
1497 }
1498
1499 sleep(1);
1500 *control = 1;
1501 igt_waitchildren();
1502
1503 igt_info("Pipe=[%u, %u], gooseberry=%u\n",
1504 control[1], control[2], control[3]);
1505 munmap(control, 4096);
1506
1507 gem_sync(fd, obj.handle);
1508 gem_close(fd, obj.handle);
1509
1510 for (int i = 0; i < ARRAY_SIZE(syncobj); i++)
1511 syncobj_destroy(fd, syncobj[i]);
1512 }
1513
1514 igt_main
1515 {
1516 const struct intel_execution_engine *e;
1517 int i915 = -1;
1518
1519 igt_fixture {
1520 i915 = drm_open_driver_master(DRIVER_INTEL);
1521 igt_require_gem(i915);
1522 igt_require(gem_has_exec_fence(i915));
1523 gem_require_mmap_wc(i915);
1524
1525 gem_submission_print_method(i915);
1526 }
1527
1528 igt_subtest_group {
1529 igt_fixture {
1530 igt_fork_hang_detector(i915);
1531 }
1532
1533 igt_subtest("basic-busy-all")
1534 test_fence_busy_all(i915, 0);
1535 igt_subtest("basic-wait-all")
1536 test_fence_busy_all(i915, WAIT);
1537
1538 igt_fixture {
1539 igt_stop_hang_detector();
1540 }
1541
1542 igt_subtest("busy-hang-all")
1543 test_fence_busy_all(i915, HANG);
1544 igt_subtest("wait-hang-all")
1545 test_fence_busy_all(i915, WAIT | HANG);
1546 }
1547
1548 for (e = intel_execution_engines; e->name; e++) {
1549 igt_subtest_group {
1550 igt_fixture {
1551 igt_require(gem_has_ring(i915, e->exec_id | e->flags));
1552 igt_require(gem_can_store_dword(i915, e->exec_id | e->flags));
1553 }
1554
1555 igt_subtest_group {
1556 igt_fixture {
1557 igt_fork_hang_detector(i915);
1558 }
1559
1560 igt_subtest_f("%sbusy-%s",
1561 e->exec_id == 0 ? "basic-" : "",
1562 e->name)
1563 test_fence_busy(i915, e->exec_id | e->flags, 0);
1564 igt_subtest_f("%swait-%s",
1565 e->exec_id == 0 ? "basic-" : "",
1566 e->name)
1567 test_fence_busy(i915, e->exec_id | e->flags, WAIT);
1568 igt_subtest_f("%sawait-%s",
1569 e->exec_id == 0 ? "basic-" : "",
1570 e->name)
1571 test_fence_await(i915, e->exec_id | e->flags, 0);
1572 igt_subtest_f("nb-await-%s", e->name)
1573 test_fence_await(i915, e->exec_id | e->flags, NONBLOCK);
1574
1575 igt_subtest_f("keep-in-fence-%s", e->name)
1576 test_keep_in_fence(i915, e->exec_id | e->flags, 0);
1577
1578 if (e->exec_id &&
1579 !(e->exec_id == I915_EXEC_BSD && !e->flags)) {
1580 igt_subtest_f("parallel-%s", e->name) {
1581 igt_require(has_submit_fence(i915));
1582 igt_until_timeout(2)
1583 test_parallel(i915, e->exec_id | e->flags);
1584 }
1585 }
1586
1587 igt_fixture {
1588 igt_stop_hang_detector();
1589 }
1590 }
1591
1592 igt_subtest_group {
1593 igt_hang_t hang;
1594
1595 igt_skip_on_simulation();
1596
1597 igt_fixture {
1598 hang = igt_allow_hang(i915, 0, 0);
1599 }
1600
1601 igt_subtest_f("busy-hang-%s", e->name)
1602 test_fence_busy(i915, e->exec_id | e->flags, HANG);
1603 igt_subtest_f("wait-hang-%s", e->name)
1604 test_fence_busy(i915, e->exec_id | e->flags, HANG | WAIT);
1605 igt_subtest_f("await-hang-%s", e->name)
1606 test_fence_await(i915, e->exec_id | e->flags, HANG);
1607 igt_subtest_f("nb-await-hang-%s", e->name)
1608 test_fence_await(i915, e->exec_id | e->flags, NONBLOCK | HANG);
1609 igt_fixture {
1610 igt_disallow_hang(i915, hang);
1611 }
1612 }
1613 }
1614 }
1615
1616 igt_subtest_group {
1617 long ring_size = 0;
1618
1619 igt_fixture {
1620 ring_size = gem_measure_ring_inflight(i915, ALL_ENGINES, 0) - 1;
1621 igt_info("Ring size: %ld batches\n", ring_size);
1622 igt_require(ring_size);
1623
1624 gem_require_contexts(i915);
1625 }
1626
1627 igt_subtest("long-history")
1628 test_long_history(i915, ring_size, 0);
1629
1630 igt_subtest("expired-history")
1631 test_long_history(i915, ring_size, EXPIRED);
1632 }
1633
1634 igt_subtest("flip") {
1635 gem_quiescent_gpu(i915);
1636 test_fence_flip(i915);
1637 }
1638
1639 igt_subtest_group { /* syncobj */
1640 igt_fixture {
1641 igt_require(exec_has_fence_array(i915));
1642 igt_assert(has_syncobj(i915));
1643 igt_fork_hang_detector(i915);
1644 }
1645
1646 igt_subtest("invalid-fence-array")
1647 test_invalid_fence_array(i915);
1648
1649 igt_subtest("syncobj-unused-fence")
1650 test_syncobj_unused_fence(i915);
1651
1652 igt_subtest("syncobj-invalid-wait")
1653 test_syncobj_invalid_wait(i915);
1654
1655 igt_subtest("syncobj-invalid-flags")
1656 test_syncobj_invalid_flags(i915);
1657
1658 igt_subtest("syncobj-signal")
1659 test_syncobj_signal(i915);
1660
1661 igt_subtest("syncobj-wait")
1662 test_syncobj_wait(i915);
1663
1664 igt_subtest("syncobj-export")
1665 test_syncobj_export(i915);
1666
1667 igt_subtest("syncobj-repeat")
1668 test_syncobj_repeat(i915);
1669
1670 igt_subtest("syncobj-import")
1671 test_syncobj_import(i915);
1672
1673 igt_subtest("syncobj-channel")
1674 test_syncobj_channel(i915);
1675
1676 igt_fixture {
1677 igt_stop_hang_detector();
1678 }
1679 }
1680
1681 igt_fixture {
1682 close(i915);
1683 }
1684 }
1685