1 /*
2 * Copyright © 2015 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 * Authors:
24 * Vinay Belgaumkar <vinay.belgaumkar@intel.com>
25 * Thomas Daniel <thomas.daniel@intel.com>
26 *
27 */
28
29 #include "igt.h"
30
31 #define EXEC_OBJECT_PINNED (1<<4)
32 #define EXEC_OBJECT_SUPPORTS_48B_ADDRESS (1<<3)
33
34 /* gen8_canonical_addr
35 * Used to convert any address into canonical form, i.e. [63:48] == [47].
36 * Based on kernel's sign_extend64 implementation.
37 * @address - a virtual address
38 */
39 #define GEN8_HIGH_ADDRESS_BIT 47
gen8_canonical_addr(uint64_t address)40 static uint64_t gen8_canonical_addr(uint64_t address)
41 {
42 __u8 shift = 63 - GEN8_HIGH_ADDRESS_BIT;
43 return (__s64)(address << shift) >> shift;
44 }
45
test_invalid(int fd)46 static void test_invalid(int fd)
47 {
48 const uint32_t bbe = MI_BATCH_BUFFER_END;
49 struct drm_i915_gem_execbuffer2 execbuf;
50 struct drm_i915_gem_exec_object2 object;
51
52 memset(&execbuf, 0, sizeof(execbuf));
53 execbuf.buffers_ptr = to_user_pointer(&object);
54 execbuf.buffer_count = 1;
55
56 memset(&object, 0, sizeof(object));
57 object.handle = gem_create(fd, 2*4096);
58 object.flags = EXEC_OBJECT_SUPPORTS_48B_ADDRESS | EXEC_OBJECT_PINNED;
59 gem_write(fd, object.handle, 0, &bbe, sizeof(bbe));
60
61 /* Check invalid alignment */
62 object.offset = 4096;
63 object.alignment = 64*1024;
64 igt_assert_eq(__gem_execbuf(fd, &execbuf), -EINVAL);
65 object.alignment = 0;
66
67 /* Check wraparound */
68 object.offset = -4096ULL;
69 igt_assert_eq(__gem_execbuf(fd, &execbuf), -EINVAL);
70
71 /* Check beyond bounds of aperture */
72 object.offset = gem_aperture_size(fd) - 4096;
73 object.offset = gen8_canonical_addr(object.offset);
74 igt_assert_eq(__gem_execbuf(fd, &execbuf), -EINVAL);
75
76 /* Check gen8 canonical addressing */
77 if (gem_aperture_size(fd) > 1ull<<GEN8_HIGH_ADDRESS_BIT) {
78 object.offset = 1ull << GEN8_HIGH_ADDRESS_BIT;
79 igt_assert_eq(__gem_execbuf(fd, &execbuf), -EINVAL);
80
81 object.offset = gen8_canonical_addr(object.offset);
82 igt_assert_eq(__gem_execbuf(fd, &execbuf), 0);
83 }
84
85 /* Check extended range */
86 if (gem_aperture_size(fd) > 1ull<<32) {
87 object.flags = EXEC_OBJECT_PINNED;
88 object.offset = 1ull<<32;
89 igt_assert_eq(__gem_execbuf(fd, &execbuf), -EINVAL);
90
91 object.offset = gen8_canonical_addr(object.offset);
92 object.flags |= EXEC_OBJECT_SUPPORTS_48B_ADDRESS;
93 igt_assert_eq(__gem_execbuf(fd, &execbuf), 0);
94 }
95 }
96
test_softpin(int fd)97 static void test_softpin(int fd)
98 {
99 const uint32_t size = 1024 * 1024;
100 const uint32_t bbe = MI_BATCH_BUFFER_END;
101 struct drm_i915_gem_execbuffer2 execbuf;
102 struct drm_i915_gem_exec_object2 object;
103 uint64_t offset, end;
104 uint32_t last_handle;
105 int loop;
106
107 last_handle = gem_create(fd, size);
108
109 memset(&execbuf, 0, sizeof(execbuf));
110 execbuf.buffers_ptr = to_user_pointer(&object);
111 execbuf.buffer_count = 1;
112 for (loop = 0; loop < 1024; loop++) {
113 memset(&object, 0, sizeof(object));
114 object.handle = gem_create(fd, 2*size);
115 gem_write(fd, object.handle, 0, &bbe, sizeof(bbe));
116
117 /* Find a hole */
118 gem_execbuf(fd, &execbuf);
119 gem_close(fd, object.handle);
120 gem_close(fd, last_handle);
121
122 igt_debug("Made a 2 MiB hole: %08llx\n",
123 object.offset);
124
125 object.handle = gem_create(fd, size);
126 gem_write(fd, object.handle, 0, &bbe, sizeof(bbe));
127 object.flags |= EXEC_OBJECT_PINNED;
128
129 end = object.offset + size;
130 for (offset = object.offset; offset <= end; offset += 4096) {
131 object.offset = offset;
132 gem_execbuf(fd, &execbuf);
133 igt_assert_eq_u64(object.offset, offset);
134 }
135
136 last_handle = object.handle;
137 }
138 }
139
test_overlap(int fd)140 static void test_overlap(int fd)
141 {
142 const uint32_t size = 1024 * 1024;
143 const uint32_t bbe = MI_BATCH_BUFFER_END;
144 struct drm_i915_gem_execbuffer2 execbuf;
145 struct drm_i915_gem_exec_object2 object[2];
146 uint64_t offset;
147 uint32_t handle;
148
149 handle = gem_create(fd, 3*size);
150 gem_write(fd, handle, 0, &bbe, sizeof(bbe));
151
152 memset(object, 0, sizeof(object));
153 object[0].handle = handle;
154
155 /* Find a hole */
156 memset(&execbuf, 0, sizeof(execbuf));
157 execbuf.buffers_ptr = to_user_pointer(object);
158 execbuf.buffer_count = 1;
159 gem_execbuf(fd, &execbuf);
160
161 igt_debug("Made a 3x1 MiB hole: %08llx\n",
162 object[0].offset);
163
164 object[0].handle = gem_create(fd, size);
165 object[0].offset += size;
166 object[0].flags |= EXEC_OBJECT_PINNED;
167 object[1].handle = gem_create(fd, size);
168 object[1].flags |= EXEC_OBJECT_PINNED;
169 gem_write(fd, object[1].handle, 0, &bbe, sizeof(bbe));
170 execbuf.buffer_count = 2;
171
172 /* Check that we fit into our hole */
173 object[1].offset = object[0].offset - size;
174 gem_execbuf(fd, &execbuf);
175 igt_assert_eq_u64(object[1].offset + size, object[0].offset);
176
177 object[1].offset = object[0].offset + size;
178 gem_execbuf(fd, &execbuf);
179 igt_assert_eq_u64(object[1].offset - size, object[0].offset);
180
181 /* Try all possible page-aligned overlaps */
182 for (offset = object[0].offset - size + 4096;
183 offset < object[0].offset + size;
184 offset += 4096) {
185 object[1].offset = offset;
186 igt_debug("[0]=[%08llx - %08llx] [1]=[%08llx - %08llx]\n",
187 (long long)object[0].offset,
188 (long long)object[0].offset + size,
189 (long long)object[1].offset,
190 (long long)object[1].offset + size);
191 igt_assert_eq(__gem_execbuf(fd, &execbuf), -EINVAL);
192 igt_assert_eq_u64(object[1].offset, offset);
193 }
194
195 gem_close(fd, object[1].handle);
196 gem_close(fd, object[0].handle);
197 gem_close(fd, handle);
198 }
199
busy_batch(int fd)200 static uint64_t busy_batch(int fd)
201 {
202 const int gen = intel_gen(intel_get_drm_devid(fd));
203 const int has_64bit_reloc = gen >= 8;
204 struct drm_i915_gem_execbuffer2 execbuf;
205 struct drm_i915_gem_exec_object2 object[2];
206 uint32_t *map;
207 int factor = 10;
208 int i = 0;
209
210 memset(object, 0, sizeof(object));
211 object[0].handle = gem_create(fd, 1024*1024);
212 object[1].handle = gem_create(fd, 4096);
213 map = gem_mmap__cpu(fd, object[1].handle, 0, 4096, PROT_WRITE);
214 gem_set_domain(fd, object[1].handle,
215 I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
216
217 *map = MI_BATCH_BUFFER_END;
218
219 memset(&execbuf, 0, sizeof(execbuf));
220 execbuf.buffers_ptr = to_user_pointer(object);
221 execbuf.buffer_count = 2;
222 if (gen >= 6)
223 execbuf.flags = I915_EXEC_BLT;
224 gem_execbuf(fd, &execbuf);
225
226 igt_debug("Active offsets = [%08llx, %08llx]\n",
227 object[0].offset, object[1].offset);
228
229 #define COPY_BLT_CMD (2<<29|0x53<<22|0x6)
230 #define BLT_WRITE_ALPHA (1<<21)
231 #define BLT_WRITE_RGB (1<<20)
232 gem_set_domain(fd, object[1].handle,
233 I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
234 while (factor--) {
235 /* XY_SRC_COPY */
236 map[i++] = COPY_BLT_CMD | BLT_WRITE_ALPHA | BLT_WRITE_RGB;
237 if (has_64bit_reloc)
238 map[i-1] += 2;
239 map[i++] = 0xcc << 16 | 1 << 25 | 1 << 24 | (4*1024);
240 map[i++] = 0;
241 map[i++] = 256 << 16 | 1024;
242 map[i++] = object[0].offset;
243 if (has_64bit_reloc)
244 map[i++] = object[0].offset >> 32;
245 map[i++] = 0;
246 map[i++] = 4096;
247 map[i++] = object[0].offset;
248 if (has_64bit_reloc)
249 map[i++] = object[0].offset >> 32;
250 }
251 map[i++] = MI_BATCH_BUFFER_END;
252 munmap(map, 4096);
253
254 object[0].flags = EXEC_OBJECT_PINNED | EXEC_OBJECT_WRITE;
255 object[1].flags = EXEC_OBJECT_PINNED;
256 gem_execbuf(fd, &execbuf);
257 gem_close(fd, object[0].handle);
258 gem_close(fd, object[1].handle);
259
260 return object[1].offset;
261 }
262
test_evict_active(int fd)263 static void test_evict_active(int fd)
264 {
265 const uint32_t bbe = MI_BATCH_BUFFER_END;
266 struct drm_i915_gem_execbuffer2 execbuf;
267 struct drm_i915_gem_exec_object2 object;
268 uint64_t expected;
269
270 memset(&object, 0, sizeof(object));
271 object.handle = gem_create(fd, 4096);
272 gem_write(fd, object.handle, 0, &bbe, sizeof(bbe));
273
274 memset(&execbuf, 0, sizeof(execbuf));
275 execbuf.buffers_ptr = to_user_pointer(&object);
276 execbuf.buffer_count = 1;
277
278 expected = busy_batch(fd);
279 object.offset = expected;
280 object.flags = EXEC_OBJECT_PINNED;
281
282 /* Replace the active batch with ourselves, forcing an eviction */
283 gem_execbuf(fd, &execbuf);
284 igt_assert_eq_u64(object.offset, expected);
285
286 gem_close(fd, object.handle);
287 }
288
test_evict_snoop(int fd)289 static void test_evict_snoop(int fd)
290 {
291 const uint32_t bbe = MI_BATCH_BUFFER_END;
292 struct drm_i915_gem_execbuffer2 execbuf;
293 struct drm_i915_gem_exec_object2 object[2];
294 uint64_t hole;
295
296 igt_require(!gem_has_llc(fd));
297 igt_require(!gem_uses_ppgtt(fd));
298
299 memset(&execbuf, 0, sizeof(execbuf));
300 execbuf.buffers_ptr = to_user_pointer(object);
301 execbuf.buffer_count = 1;
302
303 /* Find a hole */
304 memset(object, 0, sizeof(object));
305 object[0].handle = gem_create(fd, 5*4096);
306 gem_write(fd, object[0].handle, 0, &bbe, sizeof(bbe));
307 gem_execbuf(fd, &execbuf);
308 gem_close(fd, object[0].handle);
309 hole = object[0].offset + 4096;
310
311 /* Create a snoop + uncached pair */
312 object[0].handle = gem_create(fd, 4096);
313 object[0].flags = EXEC_OBJECT_PINNED;
314 gem_set_caching(fd, object[0].handle, 1);
315 object[1].handle = gem_create(fd, 4096);
316 object[1].flags = EXEC_OBJECT_PINNED;
317 gem_write(fd, object[1].handle, 4096-sizeof(bbe), &bbe, sizeof(bbe));
318 execbuf.buffer_count = 2;
319
320 /* snoop abutting before uncached -> error */
321 object[0].offset = hole;
322 object[1].offset = hole + 4096;
323 igt_assert_eq(__gem_execbuf(fd, &execbuf), -EINVAL);
324
325 /* snoop abutting after uncached -> error */
326 object[0].offset = hole + 4096;
327 object[1].offset = hole;
328 igt_assert_eq(__gem_execbuf(fd, &execbuf), -EINVAL);
329
330 /* with gap -> okay */
331 object[0].offset = hole + 2*4096;
332 object[1].offset = hole;
333 igt_assert_eq(__gem_execbuf(fd, &execbuf), 0);
334
335 /* And we should force the snoop away (or the GPU may hang) */
336 object[0].flags = 0;
337 object[1].offset = hole + 4096;
338 igt_assert_eq(__gem_execbuf(fd, &execbuf), 0);
339 igt_assert(object[0].offset != hole);
340 igt_assert(object[0].offset != hole + 2*4096);
341
342 gem_close(fd, object[0].handle);
343 gem_close(fd, object[1].handle);
344 }
345
test_evict_hang(int fd)346 static void test_evict_hang(int fd)
347 {
348 const uint32_t bbe = MI_BATCH_BUFFER_END;
349 struct drm_i915_gem_execbuffer2 execbuf;
350 struct drm_i915_gem_exec_object2 object;
351 igt_hang_t hang;
352 uint64_t expected;
353
354 memset(&object, 0, sizeof(object));
355 object.handle = gem_create(fd, 4096);
356 gem_write(fd, object.handle, 0, &bbe, sizeof(bbe));
357
358 memset(&execbuf, 0, sizeof(execbuf));
359 execbuf.buffers_ptr = to_user_pointer(&object);
360 execbuf.buffer_count = 1;
361
362 hang = igt_hang_ctx(fd, 0, 0, 0);
363 expected = hang.spin->obj[IGT_SPIN_BATCH].offset;
364
365 /* Replace the hung batch with ourselves, forcing an eviction */
366 object.offset = expected;
367 object.flags = EXEC_OBJECT_PINNED;
368 gem_execbuf(fd, &execbuf);
369 igt_assert_eq_u64(object.offset, expected);
370
371 igt_post_hang_ring(fd, hang);
372 gem_close(fd, object.handle);
373 }
374
xchg_offset(void * array,unsigned i,unsigned j)375 static void xchg_offset(void *array, unsigned i, unsigned j)
376 {
377 struct drm_i915_gem_exec_object2 *object = array;
378 uint64_t tmp = object[i].offset;
379 object[i].offset = object[j].offset;
380 object[j].offset = tmp;
381 }
382
383 enum sleep { NOSLEEP, SUSPEND, HIBERNATE };
test_noreloc(int fd,enum sleep sleep)384 static void test_noreloc(int fd, enum sleep sleep)
385 {
386 const int gen = intel_gen(intel_get_drm_devid(fd));
387 const uint32_t size = 4096;
388 const uint32_t bbe = MI_BATCH_BUFFER_END;
389 struct drm_i915_gem_execbuffer2 execbuf;
390 struct drm_i915_gem_exec_object2 object[257];
391 uint64_t offset;
392 uint32_t handle;
393 uint32_t *batch, *b;
394 int i, loop;
395
396 handle = gem_create(fd, (ARRAY_SIZE(object)+1)*size);
397 gem_write(fd, handle, 0, &bbe, sizeof(bbe));
398
399 memset(object, 0, sizeof(object));
400 object[0].handle = handle;
401
402 /* Find a hole */
403 memset(&execbuf, 0, sizeof(execbuf));
404 execbuf.buffers_ptr = to_user_pointer(object);
405 execbuf.buffer_count = 1;
406 if (gen < 6)
407 execbuf.flags |= I915_EXEC_SECURE;
408 gem_execbuf(fd, &execbuf);
409 gem_close(fd, object[0].handle);
410
411 igt_debug("Made a %dx%d KiB hole: %08llx\n",
412 (int)ARRAY_SIZE(object), size/1024, object[0].offset);
413
414 offset = object[0].offset;
415 for (i = 0; i < ARRAY_SIZE(object) - 1; i++) {
416 object[i].handle = gem_create(fd, size);
417 object[i].offset = offset + i*size;
418 object[i].flags = EXEC_OBJECT_PINNED | EXEC_OBJECT_WRITE;
419 }
420 object[i].handle = gem_create(fd, 2*size);
421 object[i].offset = offset + i*size;
422 object[i].flags = EXEC_OBJECT_PINNED;
423
424 b = batch = gem_mmap__cpu(fd, object[i].handle, 0, 2*size, PROT_WRITE);
425 gem_set_domain(fd, object[i].handle,
426 I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
427 for (i = 0; i < ARRAY_SIZE(object) - 1; i++) {
428 *b++ = MI_STORE_DWORD_IMM | (gen < 6 ? 1 << 22 : 0);
429 if (gen >= 8) {
430 *b++ = object[i].offset;
431 *b++ = object[i].offset >> 32;
432 } else if (gen >= 4) {
433 *b++ = 0;
434 *b++ = object[i].offset;
435 } else {
436 b[-1]--;
437 *b++ = object[i].offset;
438 }
439 *b++ = i;
440 }
441 *b++ = MI_BATCH_BUFFER_END;
442 igt_assert(b - batch <= 2*size/sizeof(uint32_t));
443 munmap(batch, size);
444
445 execbuf.buffer_count = ARRAY_SIZE(object);
446 for (loop = 0; loop < 1024; loop++) {
447 igt_permute_array(object, ARRAY_SIZE(object)-1, xchg_offset);
448 gem_execbuf(fd, &execbuf);
449
450 if ((loop & 127) == 0) {
451 switch (sleep) {
452 case NOSLEEP:
453 break;
454 case SUSPEND:
455 igt_system_suspend_autoresume(SUSPEND_STATE_MEM,
456 SUSPEND_TEST_NONE);
457 break;
458 case HIBERNATE:
459 igt_system_suspend_autoresume(SUSPEND_STATE_DISK,
460 SUSPEND_TEST_NONE);
461 break;
462 }
463 }
464
465 for (i = 0; i < ARRAY_SIZE(object) - 1; i++) {
466 uint32_t val;
467
468 gem_read(fd, object[i].handle, 0, &val, sizeof(val));
469 igt_assert_eq(val, (object[i].offset - offset)/size);
470 }
471 }
472
473 for (i = 0; i < ARRAY_SIZE(object); i++)
474 gem_close(fd, object[i].handle);
475 }
476
477 igt_main
478 {
479 int fd = -1;
480
481 igt_skip_on_simulation();
482
483 igt_fixture {
484 fd = drm_open_driver_master(DRIVER_INTEL);
485 igt_require_gem(fd);
486 igt_require(gem_has_softpin(fd));
487 igt_require(gem_can_store_dword(fd, 0));
488 }
489
490 igt_subtest("invalid")
491 test_invalid(fd);
492 igt_subtest("softpin")
493 test_softpin(fd);
494 igt_subtest("overlap")
495 test_overlap(fd);
496
497 igt_subtest("noreloc")
498 test_noreloc(fd, NOSLEEP);
499 igt_subtest("noreloc-interruptible")
500 igt_while_interruptible(true) test_noreloc(fd, NOSLEEP);
501 igt_subtest("noreloc-S3")
502 test_noreloc(fd, SUSPEND);
503 igt_subtest("noreloc-S4")
504 test_noreloc(fd, HIBERNATE);
505
506 for (int signal = 0; signal <= 1; signal++) {
507 igt_subtest_f("evict-active%s", signal ? "-interruptible" : "")
508 igt_while_interruptible(signal) test_evict_active(fd);
509 igt_subtest_f("evict-snoop%s", signal ? "-interruptible" : "")
510 igt_while_interruptible(signal) test_evict_snoop(fd);
511 }
512 igt_subtest("evict-hang")
513 test_evict_hang(fd);
514
515 igt_fixture
516 close(fd);
517 }
518