• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2011,2013 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  *    Daniel Vetter <daniel.vetter@ffwll.ch>
25  *
26  */
27 
28 #include "igt.h"
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <inttypes.h>
34 #include <errno.h>
35 #include <sys/stat.h>
36 #include <sys/time.h>
37 #include <signal.h>
38 #include <sys/wait.h>
39 
40 #include <drm.h>
41 
42 
43 IGT_TEST_DESCRIPTION("Test kernel relocations vs. gpu races.");
44 
45 /*
46  * Testcase: Kernel relocations vs. gpu races
47  *
48  */
49 
50 static drm_intel_bufmgr *bufmgr;
51 struct intel_batchbuffer *batch;
52 
53 uint32_t blob[2048*2048];
54 #define NUM_TARGET_BOS 16
55 drm_intel_bo *pc_target_bo[NUM_TARGET_BOS];
56 drm_intel_bo *dummy_bo;
57 drm_intel_bo *special_bo;
58 uint32_t devid;
59 int special_reloc_ofs;
60 int special_batch_len;
61 
create_special_bo(void)62 static void create_special_bo(void)
63 {
64 	uint32_t data[1024];
65 	int len = 0;
66 	int small_pitch = 64;
67 #define BATCH(dw) data[len++] = (dw);
68 
69 	memset(data, 0, 4096);
70 	special_bo = drm_intel_bo_alloc(bufmgr, "special batch", 4096, 4096);
71 
72 	if (intel_gen(devid) >= 8) {
73 		BATCH(MI_NOOP);
74 		BATCH(XY_COLOR_BLT_CMD_NOLEN | 5 |
75 				COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB);
76 	} else {
77 		BATCH(XY_COLOR_BLT_CMD_NOLEN | 4 |
78 				COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB);
79 	}
80 
81 	BATCH((3 << 24) | (0xf0 << 16) | small_pitch);
82 	BATCH(0);
83 	BATCH(1 << 16 | 1);
84 	special_reloc_ofs = 4*len;
85 	BATCH(0);
86 	if (intel_gen(devid) >= 8)
87 		BATCH(0);
88 	BATCH(0xdeadbeef);
89 
90 #define CMD_POLY_STIPPLE_OFFSET       0x7906
91 	/* batchbuffer end */
92 	if (IS_GEN5(batch->devid)) {
93 		BATCH(CMD_POLY_STIPPLE_OFFSET << 16);
94 		BATCH(0);
95 	}
96 	igt_assert_eq(len % 2, 0);
97 	BATCH(MI_NOOP);
98 	BATCH(MI_BATCH_BUFFER_END);
99 
100 	drm_intel_bo_subdata(special_bo, 0, 4096, data);
101 	special_batch_len = len*4;
102 }
103 
emit_dummy_load(int pitch)104 static void emit_dummy_load(int pitch)
105 {
106 	int i;
107 	uint32_t tile_flags = 0;
108 
109 	if (IS_965(devid)) {
110 		pitch /= 4;
111 		tile_flags = XY_SRC_COPY_BLT_SRC_TILED |
112 			XY_SRC_COPY_BLT_DST_TILED;
113 	}
114 
115 	for (i = 0; i < 10; i++) {
116 		BLIT_COPY_BATCH_START(tile_flags);
117 		OUT_BATCH((3 << 24) | /* 32 bits */
118 			  (0xcc << 16) | /* copy ROP */
119 			  pitch);
120 		OUT_BATCH(0 << 16 | 1024);
121 		OUT_BATCH((2048) << 16 | (2048));
122 		OUT_RELOC_FENCED(dummy_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
123 		OUT_BATCH(0 << 16 | 0);
124 		OUT_BATCH(pitch);
125 		OUT_RELOC_FENCED(dummy_bo, I915_GEM_DOMAIN_RENDER, 0, 0);
126 		ADVANCE_BATCH();
127 
128 		if (batch->gen >= 6) {
129 			BEGIN_BATCH(3, 0);
130 			OUT_BATCH(XY_SETUP_CLIP_BLT_CMD);
131 			OUT_BATCH(0);
132 			OUT_BATCH(0);
133 			ADVANCE_BATCH();
134 		}
135 	}
136 	intel_batchbuffer_flush(batch);
137 }
138 
reloc_and_emit(int fd,drm_intel_bo * target_bo,bool faulting_reloc)139 static void reloc_and_emit(int fd, drm_intel_bo *target_bo, bool faulting_reloc)
140 {
141 	struct drm_i915_gem_execbuffer2 execbuf;
142 	struct drm_i915_gem_exec_object2 exec[2];
143 	struct drm_i915_gem_relocation_entry reloc[1];
144 	uint32_t handle_relocs;
145 	void *gtt_relocs;
146 
147 	memset(&execbuf, 0, sizeof(execbuf));
148 	memset(exec, 0, sizeof(exec));
149 	memset(reloc, 0, sizeof(reloc));
150 
151 	exec[0].handle = target_bo->handle;
152 
153 	reloc[0].offset = special_reloc_ofs;
154 	reloc[0].target_handle = target_bo->handle;
155 	reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;
156 	reloc[0].write_domain = I915_GEM_DOMAIN_RENDER;
157 	/* We do not track the last patched value, so force the relocation
158 	 * every time.
159 	 */
160 	reloc[0].presumed_offset = -1;
161 
162 	handle_relocs = gem_create(fd, 4096);
163 	gem_write(fd, handle_relocs, 0, reloc, sizeof(reloc));
164 	gtt_relocs = gem_mmap__gtt(fd, handle_relocs, 4096,
165 				   PROT_READ | PROT_WRITE);
166 
167 	exec[1].handle = special_bo->handle;
168 	exec[1].relocation_count = 1;
169 	/* A newly mmap gtt bo will fault on first access. */
170 	if (faulting_reloc)
171 		exec[1].relocs_ptr = to_user_pointer(gtt_relocs);
172 	else
173 		exec[1].relocs_ptr = to_user_pointer(reloc);
174 
175 	execbuf.buffers_ptr = to_user_pointer(exec);
176 	execbuf.buffer_count = 2;
177 	execbuf.batch_len = special_batch_len;
178 	if (intel_gen(devid) >= 6)
179 		execbuf.flags |= I915_EXEC_BLT;
180 
181 	gem_execbuf(fd, &execbuf);
182 
183 	gem_close(fd, handle_relocs);
184 }
185 
no_hang(int fd)186 static igt_hang_t no_hang(int fd)
187 {
188 	return (igt_hang_t){0};
189 }
190 
bcs_hang(int fd)191 static igt_hang_t bcs_hang(int fd)
192 {
193 	return igt_hang_ring(fd, I915_EXEC_BLT);
194 }
195 
do_test(int fd,bool faulting_reloc,igt_hang_t (* do_hang)(int fd))196 static void do_test(int fd, bool faulting_reloc,
197 		    igt_hang_t (*do_hang)(int fd))
198 {
199 	uint32_t tiling_mode = I915_TILING_X;
200 	unsigned long pitch, act_size;
201 	uint32_t test;
202 	int i;
203 
204 	if (faulting_reloc)
205 		igt_disable_prefault();
206 
207 	act_size = 2048;
208 	dummy_bo = drm_intel_bo_alloc_tiled(bufmgr, "tiled dummy_bo", act_size, act_size,
209 				      4, &tiling_mode, &pitch, 0);
210 
211 	drm_intel_bo_subdata(dummy_bo, 0, act_size*act_size*4, blob);
212 
213 	create_special_bo();
214 
215 	for (i = 0; i < NUM_TARGET_BOS; i++) {
216 		igt_hang_t hang;
217 
218 		pc_target_bo[i] = drm_intel_bo_alloc(bufmgr, "special batch", 4096, 4096);
219 		emit_dummy_load(pitch);
220 		igt_assert(pc_target_bo[i]->offset == 0);
221 		hang = do_hang(fd);
222 
223 		reloc_and_emit(fd, pc_target_bo[i], faulting_reloc);
224 
225 		igt_post_hang_ring(fd, hang);
226 	}
227 
228 	/* Only check at the end to avoid unnecessary synchronous behaviour. */
229 	for (i = 0; i < NUM_TARGET_BOS; i++) {
230 		drm_intel_bo_get_subdata(pc_target_bo[i], 0, 4, &test);
231 		igt_assert_f(test == 0xdeadbeef,
232 			     "mismatch in buffer %i: 0x%08x instead of 0xdeadbeef\n", i, test);
233 		drm_intel_bo_unreference(pc_target_bo[i]);
234 	}
235 
236 	drm_intel_gem_bo_map_gtt(dummy_bo);
237 	drm_intel_gem_bo_unmap_gtt(dummy_bo);
238 
239 	drm_intel_bo_unreference(special_bo);
240 	drm_intel_bo_unreference(dummy_bo);
241 
242 	if (faulting_reloc)
243 		igt_enable_prefault();
244 }
245 
246 #define INTERRUPT	(1 << 0)
247 #define FAULTING	(1 << 1)
248 #define THRASH		(1 << 2)
249 #define THRASH_INACTIVE	(1 << 3)
250 #define HANG		(1 << 4)
251 #define ALL_FLAGS	(HANG | INTERRUPT | FAULTING | THRASH | THRASH_INACTIVE)
do_forked_test(int fd,unsigned flags)252 static void do_forked_test(int fd, unsigned flags)
253 {
254 	int num_threads = sysconf(_SC_NPROCESSORS_ONLN);
255 	struct igt_helper_process thrasher = {};
256 
257 	if (flags & HANG)
258 		igt_require_hang_ring(fd, I915_EXEC_BLT);
259 
260 	if (flags & (THRASH | THRASH_INACTIVE)) {
261 		igt_fork_helper(&thrasher) {
262 			uint64_t val;
263 
264 			val = DROP_RETIRE | DROP_BOUND | DROP_UNBOUND;
265 			if (!(flags & THRASH_INACTIVE))
266 				val |= DROP_ACTIVE | DROP_SHRINK_ALL;
267 
268 			while (1) {
269 				usleep(1000);
270 				igt_drop_caches_set(fd, val);
271 			}
272 		}
273 	}
274 
275 	igt_fork(i, num_threads * 4) {
276 		/* re-create process local data */
277 		fd = drm_open_driver(DRIVER_INTEL);
278 		bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
279 		batch = intel_batchbuffer_alloc(bufmgr, devid);
280 
281 		if (flags & INTERRUPT)
282 			igt_fork_signal_helper();
283 
284 		do_test(fd, flags & FAULTING, flags & HANG ? bcs_hang : no_hang);
285 
286 		if (flags & INTERRUPT)
287 			igt_stop_signal_helper();
288 	}
289 
290 	igt_waitchildren();
291 	if (flags & (THRASH | THRASH_INACTIVE))
292 		igt_stop_helper(&thrasher);
293 }
294 
295 int fd;
296 
297 #define MAX_BLT_SIZE 128
298 igt_main
299 {
300 	igt_skip_on_simulation();
301 
302 	memset(blob, 'A', sizeof(blob));
303 
304 	igt_fixture {
305 		fd = drm_open_driver(DRIVER_INTEL);
306 		igt_require_gem(fd);
307 		bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
308 		/* disable reuse, otherwise the test fails */
309 		//drm_intel_bufmgr_gem_enable_reuse(bufmgr);
310 		devid = intel_get_drm_devid(fd);
311 		batch = intel_batchbuffer_alloc(bufmgr, devid);
312 	}
313 
314 	igt_subtest("normal")
315 		do_test(fd, false, no_hang);
316 
317 	igt_subtest("faulting-reloc")
318 		do_test(fd, true, no_hang);
319 
320 	igt_fork_signal_helper();
321 	igt_subtest("interruptible")
322 		do_test(fd, false, no_hang);
323 
324 	igt_subtest("interruptible-hang")
325 		do_test(fd, false, bcs_hang);
326 
327 	igt_subtest("faulting-reloc-interruptible")
328 		do_test(fd, true, no_hang);
329 
330 	igt_subtest("faulting-reloc-interruptible-hang")
331 		do_test(fd, true, bcs_hang);
332 	igt_stop_signal_helper();
333 
334 	for (unsigned flags = 0; flags <= ALL_FLAGS; flags++) {
335 		if ((flags & THRASH) && (flags & THRASH_INACTIVE))
336 			continue;
337 
338 		igt_subtest_f("forked%s%s%s%s%s",
339 			      flags & INTERRUPT ? "-interruptible" : "",
340 			      flags & FAULTING ? "-faulting-reloc" : "",
341 			      flags & THRASH ? "-thrashing" : "",
342 			      flags & THRASH_INACTIVE ? "-thrash-inactive" : "",
343 			      flags & HANG ? "-hang": "")
344 			do_forked_test(fd, flags);
345 	}
346 
347 	igt_fixture {
348 		intel_batchbuffer_free(batch);
349 		drm_intel_bufmgr_destroy(bufmgr);
350 
351 		close(fd);
352 	}
353 }
354