xref: /aosp_15_r20/external/igt-gpu-tools/tests/i915/gem_exec_fence.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
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