• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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