xref: /aosp_15_r20/external/igt-gpu-tools/tests/i915/gem_exec_capture.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 <zlib.h>
25 
26 #include "igt.h"
27 #include "igt_device.h"
28 #include "igt_rand.h"
29 #include "igt_sysfs.h"
30 
31 #define LOCAL_OBJECT_CAPTURE (1 << 7)
32 #define LOCAL_PARAM_HAS_EXEC_CAPTURE 45
33 
34 IGT_TEST_DESCRIPTION("Check that we capture the user specified objects on a hang");
35 
check_error_state(int dir,struct drm_i915_gem_exec_object2 * obj)36 static void check_error_state(int dir, struct drm_i915_gem_exec_object2 *obj)
37 {
38 	char *error, *str;
39 	bool found = false;
40 
41 	error = igt_sysfs_get(dir, "error");
42 	igt_sysfs_set(dir, "error", "Begone!");
43 
44 	igt_assert(error);
45 	igt_debug("%s\n", error);
46 
47 	/* render ring --- user = 0x00000000 ffffd000 */
48 	for (str = error; (str = strstr(str, "--- user = ")); str++) {
49 		uint64_t addr;
50 		uint32_t hi, lo;
51 
52 		igt_assert(sscanf(str, "--- user = 0x%x %x", &hi, &lo) == 2);
53 		addr = hi;
54 		addr <<= 32;
55 		addr |= lo;
56 		igt_assert_eq_u64(addr, obj->offset);
57 		found = true;
58 	}
59 
60 	free(error);
61 	igt_assert(found);
62 }
63 
__capture1(int fd,int dir,unsigned ring,uint32_t target)64 static void __capture1(int fd, int dir, unsigned ring, uint32_t target)
65 {
66 	const int gen = intel_gen(intel_get_drm_devid(fd));
67 	struct drm_i915_gem_exec_object2 obj[4];
68 #define SCRATCH 0
69 #define CAPTURE 1
70 #define NOCAPTURE 2
71 #define BATCH 3
72 	struct drm_i915_gem_relocation_entry reloc[2];
73 	struct drm_i915_gem_execbuffer2 execbuf;
74 	uint32_t *batch, *seqno;
75 	int i;
76 
77 	memset(obj, 0, sizeof(obj));
78 	obj[SCRATCH].handle = gem_create(fd, 4096);
79 	obj[CAPTURE].handle = target;
80 	obj[CAPTURE].flags = LOCAL_OBJECT_CAPTURE;
81 	obj[NOCAPTURE].handle = gem_create(fd, 4096);
82 
83 	obj[BATCH].handle = gem_create(fd, 4096);
84 	obj[BATCH].relocs_ptr = (uintptr_t)reloc;
85 	obj[BATCH].relocation_count = ARRAY_SIZE(reloc);
86 
87 	memset(reloc, 0, sizeof(reloc));
88 	reloc[0].target_handle = obj[BATCH].handle; /* recurse */
89 	reloc[0].presumed_offset = 0;
90 	reloc[0].offset = 5*sizeof(uint32_t);
91 	reloc[0].delta = 0;
92 	reloc[0].read_domains = I915_GEM_DOMAIN_COMMAND;
93 	reloc[0].write_domain = 0;
94 
95 	reloc[1].target_handle = obj[SCRATCH].handle; /* breadcrumb */
96 	reloc[1].presumed_offset = 0;
97 	reloc[1].offset = sizeof(uint32_t);
98 	reloc[1].delta = 0;
99 	reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;
100 	reloc[1].write_domain = I915_GEM_DOMAIN_RENDER;
101 
102 	seqno = gem_mmap__wc(fd, obj[SCRATCH].handle, 0, 4096, PROT_READ);
103 	gem_set_domain(fd, obj[SCRATCH].handle,
104 			I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
105 
106 	batch = gem_mmap__cpu(fd, obj[BATCH].handle, 0, 4096, PROT_WRITE);
107 	gem_set_domain(fd, obj[BATCH].handle,
108 			I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
109 
110 	i = 0;
111 	batch[i] = MI_STORE_DWORD_IMM | (gen < 6 ? 1 << 22 : 0);
112 	if (gen >= 8) {
113 		batch[++i] = 0;
114 		batch[++i] = 0;
115 	} else if (gen >= 4) {
116 		batch[++i] = 0;
117 		batch[++i] = 0;
118 		reloc[1].offset += sizeof(uint32_t);
119 	} else {
120 		batch[i]--;
121 		batch[++i] = 0;
122 	}
123 	batch[++i] = 0xc0ffee;
124 	if (gen < 4)
125 		batch[++i] = MI_NOOP;
126 
127 	batch[++i] = MI_BATCH_BUFFER_START; /* not crashed? try again! */
128 	if (gen >= 8) {
129 		batch[i] |= 1 << 8 | 1;
130 		batch[++i] = 0;
131 		batch[++i] = 0;
132 	} else if (gen >= 6) {
133 		batch[i] |= 1 << 8;
134 		batch[++i] = 0;
135 	} else {
136 		batch[i] |= 2 << 6;
137 		batch[++i] = 0;
138 		if (gen < 4) {
139 			batch[i] |= 1;
140 			reloc[0].delta = 1;
141 		}
142 	}
143 	munmap(batch, 4096);
144 
145 	memset(&execbuf, 0, sizeof(execbuf));
146 	execbuf.buffers_ptr = (uintptr_t)obj;
147 	execbuf.buffer_count = ARRAY_SIZE(obj);
148 	execbuf.flags = ring;
149 	if (gen > 3 && gen < 6)
150 		execbuf.flags |= I915_EXEC_SECURE;
151 
152 	igt_assert(!READ_ONCE(*seqno));
153 	gem_execbuf(fd, &execbuf);
154 
155 	/* Wait for the request to start */
156 	while (READ_ONCE(*seqno) != 0xc0ffee)
157 		igt_assert(gem_bo_busy(fd, obj[SCRATCH].handle));
158 	munmap(seqno, 4096);
159 
160 	/* Check that only the buffer we marked is reported in the error */
161 	igt_force_gpu_reset(fd);
162 	check_error_state(dir, &obj[CAPTURE]);
163 
164 	gem_sync(fd, obj[BATCH].handle);
165 
166 	gem_close(fd, obj[BATCH].handle);
167 	gem_close(fd, obj[NOCAPTURE].handle);
168 	gem_close(fd, obj[SCRATCH].handle);
169 }
170 
capture(int fd,int dir,unsigned ring)171 static void capture(int fd, int dir, unsigned ring)
172 {
173 	uint32_t handle;
174 
175 	handle = gem_create(fd, 4096);
176 	__capture1(fd, dir, ring, handle);
177 	gem_close(fd, handle);
178 }
179 
cmp(const void * A,const void * B)180 static int cmp(const void *A, const void *B)
181 {
182 	const uint64_t *a = A, *b = B;
183 
184 	if (*a < *b)
185 		return -1;
186 
187 	if (*a > *b)
188 		return 1;
189 
190 	return 0;
191 }
192 
193 static struct offset {
194 	uint64_t addr;
195 	unsigned long idx;
__captureN(int fd,int dir,unsigned ring,unsigned int size,int count,unsigned int flags)196 } *__captureN(int fd, int dir, unsigned ring,
197 	      unsigned int size, int count,
198 	      unsigned int flags)
199 #define INCREMENTAL 0x1
200 {
201 	const int gen = intel_gen(intel_get_drm_devid(fd));
202 	struct drm_i915_gem_exec_object2 *obj;
203 	struct drm_i915_gem_relocation_entry reloc[2];
204 	struct drm_i915_gem_execbuffer2 execbuf;
205 	uint32_t *batch, *seqno;
206 	struct offset *offsets;
207 	int i;
208 
209 	offsets = calloc(count , sizeof(*offsets));
210 	igt_assert(offsets);
211 
212 	obj = calloc(count + 2, sizeof(*obj));
213 	igt_assert(obj);
214 
215 	obj[0].handle = gem_create(fd, 4096);
216 	for (i = 0; i < count; i++) {
217 		obj[i + 1].handle = gem_create(fd, size);
218 		obj[i + 1].flags =
219 			LOCAL_OBJECT_CAPTURE | EXEC_OBJECT_SUPPORTS_48B_ADDRESS;
220 		if (flags & INCREMENTAL) {
221 			uint32_t *ptr;
222 
223 			ptr = gem_mmap__cpu(fd, obj[i + 1].handle,
224 					    0, size, PROT_WRITE);
225 			for (unsigned int n = 0; n < size / sizeof(*ptr); n++)
226 				ptr[n] = i * size + n;
227 			munmap(ptr, size);
228 		}
229 	}
230 
231 	obj[count + 1].handle = gem_create(fd, 4096);
232 	obj[count + 1].relocs_ptr = (uintptr_t)reloc;
233 	obj[count + 1].relocation_count = ARRAY_SIZE(reloc);
234 
235 	memset(reloc, 0, sizeof(reloc));
236 	reloc[0].target_handle = obj[count + 1].handle; /* recurse */
237 	reloc[0].presumed_offset = 0;
238 	reloc[0].offset = 5*sizeof(uint32_t);
239 	reloc[0].delta = 0;
240 	reloc[0].read_domains = I915_GEM_DOMAIN_COMMAND;
241 	reloc[0].write_domain = 0;
242 
243 	reloc[1].target_handle = obj[0].handle; /* breadcrumb */
244 	reloc[1].presumed_offset = 0;
245 	reloc[1].offset = sizeof(uint32_t);
246 	reloc[1].delta = 0;
247 	reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;
248 	reloc[1].write_domain = I915_GEM_DOMAIN_RENDER;
249 
250 	seqno = gem_mmap__wc(fd, obj[0].handle, 0, 4096, PROT_READ);
251 	gem_set_domain(fd, obj[0].handle,
252 			I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
253 
254 	batch = gem_mmap__cpu(fd, obj[count + 1].handle, 0, 4096, PROT_WRITE);
255 	gem_set_domain(fd, obj[count + 1].handle,
256 			I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
257 
258 	i = 0;
259 	batch[i] = MI_STORE_DWORD_IMM | (gen < 6 ? 1 << 22 : 0);
260 	if (gen >= 8) {
261 		batch[++i] = 0;
262 		batch[++i] = 0;
263 	} else if (gen >= 4) {
264 		batch[++i] = 0;
265 		batch[++i] = 0;
266 		reloc[1].offset += sizeof(uint32_t);
267 	} else {
268 		batch[i]--;
269 		batch[++i] = 0;
270 	}
271 	batch[++i] = 0xc0ffee;
272 	if (gen < 4)
273 		batch[++i] = MI_NOOP;
274 
275 	batch[++i] = MI_BATCH_BUFFER_START; /* not crashed? try again! */
276 	if (gen >= 8) {
277 		batch[i] |= 1 << 8 | 1;
278 		batch[++i] = 0;
279 		batch[++i] = 0;
280 	} else if (gen >= 6) {
281 		batch[i] |= 1 << 8;
282 		batch[++i] = 0;
283 	} else {
284 		batch[i] |= 2 << 6;
285 		batch[++i] = 0;
286 		if (gen < 4) {
287 			batch[i] |= 1;
288 			reloc[0].delta = 1;
289 		}
290 	}
291 	munmap(batch, 4096);
292 
293 	memset(&execbuf, 0, sizeof(execbuf));
294 	execbuf.buffers_ptr = (uintptr_t)obj;
295 	execbuf.buffer_count = count + 2;
296 	execbuf.flags = ring;
297 	if (gen > 3 && gen < 6)
298 		execbuf.flags |= I915_EXEC_SECURE;
299 
300 	igt_assert(!READ_ONCE(*seqno));
301 	gem_execbuf(fd, &execbuf);
302 
303 	/* Wait for the request to start */
304 	while (READ_ONCE(*seqno) != 0xc0ffee)
305 		igt_assert(gem_bo_busy(fd, obj[0].handle));
306 	munmap(seqno, 4096);
307 
308 	igt_force_gpu_reset(fd);
309 
310 	gem_sync(fd, obj[count + 1].handle);
311 	gem_close(fd, obj[count + 1].handle);
312 	for (i = 0; i < count; i++) {
313 		offsets[i].addr = obj[i + 1].offset;
314 		offsets[i].idx = i;
315 		gem_close(fd, obj[i + 1].handle);
316 	}
317 	gem_close(fd, obj[0].handle);
318 
319 	qsort(offsets, count, sizeof(*offsets), cmp);
320 	igt_assert(offsets[0].addr <= offsets[count-1].addr);
321 	return offsets;
322 }
323 
zlib_inflate(uint32_t ** ptr,unsigned long len)324 static unsigned long zlib_inflate(uint32_t **ptr, unsigned long len)
325 {
326 	struct z_stream_s zstream;
327 	void *out;
328 
329 	memset(&zstream, 0, sizeof(zstream));
330 
331 	zstream.next_in = (unsigned char *)*ptr;
332 	zstream.avail_in = 4*len;
333 
334 	if (inflateInit(&zstream) != Z_OK)
335 		return 0;
336 
337 	out = malloc(128*4096); /* approximate obj size */
338 	zstream.next_out = out;
339 	zstream.avail_out = 128*4096;
340 
341 	do {
342 		switch (inflate(&zstream, Z_SYNC_FLUSH)) {
343 		case Z_STREAM_END:
344 			goto end;
345 		case Z_OK:
346 			break;
347 		default:
348 			inflateEnd(&zstream);
349 			return 0;
350 		}
351 
352 		if (zstream.avail_out)
353 			break;
354 
355 		out = realloc(out, 2*zstream.total_out);
356 		if (out == NULL) {
357 			inflateEnd(&zstream);
358 			return 0;
359 		}
360 
361 		zstream.next_out = (unsigned char *)out + zstream.total_out;
362 		zstream.avail_out = zstream.total_out;
363 	} while (1);
364 end:
365 	inflateEnd(&zstream);
366 	free(*ptr);
367 	*ptr = out;
368 	return zstream.total_out / 4;
369 }
370 
371 static unsigned long
ascii85_decode(char * in,uint32_t ** out,bool inflate,char ** end)372 ascii85_decode(char *in, uint32_t **out, bool inflate, char **end)
373 {
374 	unsigned long len = 0, size = 1024;
375 
376 	*out = realloc(*out, sizeof(uint32_t)*size);
377 	if (*out == NULL)
378 		return 0;
379 
380 	while (*in >= '!' && *in <= 'z') {
381 		uint32_t v = 0;
382 
383 		if (len == size) {
384 			size *= 2;
385 			*out = realloc(*out, sizeof(uint32_t)*size);
386 			if (*out == NULL)
387 				return 0;
388 		}
389 
390 		if (*in == 'z') {
391 			in++;
392 		} else {
393 			v += in[0] - 33; v *= 85;
394 			v += in[1] - 33; v *= 85;
395 			v += in[2] - 33; v *= 85;
396 			v += in[3] - 33; v *= 85;
397 			v += in[4] - 33;
398 			in += 5;
399 		}
400 		(*out)[len++] = v;
401 	}
402 	*end = in;
403 
404 	if (!inflate)
405 		return len;
406 
407 	return zlib_inflate(out, len);
408 }
409 
many(int fd,int dir,uint64_t size,unsigned int flags)410 static void many(int fd, int dir, uint64_t size, unsigned int flags)
411 {
412 	uint64_t ram, gtt;
413 	unsigned long count, blobs;
414 	struct offset *offsets;
415 	char *error, *str;
416 
417 	gtt = gem_aperture_size(fd) / size;
418 	ram = (intel_get_avail_ram_mb() << 20) / size;
419 	igt_debug("Available objects in GTT:%"PRIu64", RAM:%"PRIu64"\n",
420 		  gtt, ram);
421 
422 	count = min(gtt, ram) / 4;
423 	igt_require(count > 1);
424 
425 	intel_require_memory(count, size, CHECK_RAM);
426 
427 	offsets = __captureN(fd, dir, 0, size, count, flags);
428 
429 	error = igt_sysfs_get(dir, "error");
430 	igt_sysfs_set(dir, "error", "Begone!");
431 	igt_assert(error);
432 
433 	blobs = 0;
434 	/* render ring --- user = 0x00000000 ffffd000 */
435 	str = strstr(error, "--- user = ");
436 	while (str) {
437 		uint32_t *data = NULL;
438 		unsigned long i, sz;
439 		uint64_t addr;
440 
441 		if (strncmp(str, "--- user = 0x", 13))
442 			break;
443 
444 		str += 13;
445 		addr = strtoul(str, &str, 16);
446 		addr <<= 32;
447 		addr |= strtoul(str + 1, &str, 16);
448 		igt_assert(*str++ == '\n');
449 
450 		if (!(*str == ':' || *str == '~'))
451 			continue;
452 
453 		igt_debug("blob:%.64s\n", str);
454 		sz = ascii85_decode(str + 1, &data, *str == ':', &str);
455 		igt_assert_eq(4 * sz, size);
456 		igt_assert(*str++ == '\n');
457 		str = strchr(str, '-');
458 
459 		if (flags & INCREMENTAL) {
460 			unsigned long start = 0;
461 			unsigned long end = count;
462 			uint32_t expect;
463 
464 			while (end > start) {
465 				i = (end - start) / 2 + start;
466 				if (offsets[i].addr < addr)
467 					start = i + 1;
468 				else if (offsets[i].addr > addr)
469 					end = i;
470 				else
471 					break;
472 			}
473 			igt_assert(offsets[i].addr == addr);
474 			igt_debug("offset:%"PRIx64", index:%ld\n",
475 				  addr, offsets[i].idx);
476 
477 			expect = offsets[i].idx * size;
478 			for (i = 0; i < sz; i++)
479 				igt_assert_eq(data[i], expect++);
480 		} else {
481 			for (i = 0; i < sz; i++)
482 				igt_assert_eq(data[i], 0);
483 		}
484 
485 		blobs++;
486 		free(data);
487 	}
488 	igt_info("Captured %lu %"PRId64"-blobs out of a total of %lu\n",
489 		 blobs, size >> 12, count);
490 	igt_assert(count);
491 
492 	free(error);
493 	free(offsets);
494 }
495 
userptr(int fd,int dir)496 static void userptr(int fd, int dir)
497 {
498 	uint32_t handle;
499 	void *ptr;
500 
501 	igt_assert(posix_memalign(&ptr, 4096, 4096) == 0);
502 	igt_require(__gem_userptr(fd, ptr, 4096, 0, 0, &handle) == 0);
503 
504 	__capture1(fd, dir, 0, handle);
505 
506 	gem_close(fd, handle);
507 	free(ptr);
508 }
509 
has_capture(int fd)510 static bool has_capture(int fd)
511 {
512 	drm_i915_getparam_t gp;
513 	int async = -1;
514 
515 	gp.param = LOCAL_PARAM_HAS_EXEC_CAPTURE;
516 	gp.value = &async;
517 	drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp);
518 
519 	return async > 0;
520 }
521 
safer_strlen(const char * s)522 static size_t safer_strlen(const char *s)
523 {
524 	return s ? strlen(s) : 0;
525 }
526 
527 igt_main
528 {
529 	const struct intel_execution_engine *e;
530 	igt_hang_t hang;
531 	int fd = -1;
532 	int dir = -1;
533 
534 	igt_skip_on_simulation();
535 
536 	igt_fixture {
537 		int gen;
538 
539 		fd = drm_open_driver(DRIVER_INTEL);
540 
541 		gen = intel_gen(intel_get_drm_devid(fd));
542 		if (gen > 3 && gen < 6) /* ctg and ilk need secure batches */
543 			igt_device_set_master(fd);
544 
545 		igt_require_gem(fd);
546 		gem_require_mmap_wc(fd);
547 		igt_require(has_capture(fd));
548 		igt_allow_hang(fd, 0, HANG_ALLOW_CAPTURE);
549 
550 		dir = igt_sysfs_open(fd);
551 		igt_require(igt_sysfs_set(dir, "error", "Begone!"));
552 		igt_require(safer_strlen(igt_sysfs_get(dir, "error")) > 0);
553 	}
554 
555 	for (e = intel_execution_engines; e->name; e++) {
556 		/* default exec-id is purely symbolic */
557 		if (e->exec_id == 0)
558 			continue;
559 
560 		igt_subtest_f("capture-%s", e->name) {
561 			igt_require(gem_ring_has_physical_engine(fd, e->exec_id | e->flags));
562 			igt_require(gem_can_store_dword(fd, e->exec_id | e->flags));
563 			capture(fd, dir, e->exec_id | e->flags);
564 		}
565 	}
566 
567 	igt_subtest_f("many-4K-zero") {
568 		igt_require(gem_can_store_dword(fd, 0));
569 		many(fd, dir, 1<<12, 0);
570 	}
571 
572 	igt_subtest_f("many-4K-incremental") {
573 		igt_require(gem_can_store_dword(fd, 0));
574 		many(fd, dir, 1<<12, INCREMENTAL);
575 	}
576 
577 	igt_subtest_f("many-2M-zero") {
578 		igt_require(gem_can_store_dword(fd, 0));
579 		many(fd, dir, 2<<20, 0);
580 	}
581 
582 	igt_subtest_f("many-2M-incremental") {
583 		igt_require(gem_can_store_dword(fd, 0));
584 		many(fd, dir, 2<<20, INCREMENTAL);
585 	}
586 
587 	igt_subtest_f("many-256M-incremental") {
588 		igt_require(gem_can_store_dword(fd, 0));
589 		many(fd, dir, 256<<20, INCREMENTAL);
590 	}
591 
592 	/* And check we can read from different types of objects */
593 
594 	igt_subtest_f("userptr") {
595 		igt_require(gem_can_store_dword(fd, 0));
596 		userptr(fd, dir);
597 	}
598 
599 	igt_fixture {
600 		close(dir);
601 		igt_disallow_hang(fd, hang);
602 		close(fd);
603 	}
604 }
605