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