xref: /aosp_15_r20/external/igt-gpu-tools/tests/i915/gem_exec_store.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
1 /*
2  * Copyright © 2009 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 
25 /** @file gem_exec_store.c
26  *
27  * Simplest non-NOOP only batch with verification.
28  */
29 
30 #include "igt.h"
31 #include "igt_device.h"
32 #include "igt_gt.h"
33 #include <strings.h>
34 
35 #define LOCAL_I915_EXEC_BSD_SHIFT      (13)
36 #define LOCAL_I915_EXEC_BSD_MASK       (3 << LOCAL_I915_EXEC_BSD_SHIFT)
37 
38 #define ENGINE_MASK  (I915_EXEC_RING_MASK | LOCAL_I915_EXEC_BSD_MASK)
39 
store_dword(int fd,const struct intel_execution_engine2 * e)40 static void store_dword(int fd, const struct intel_execution_engine2 *e)
41 {
42 	const int gen = intel_gen(intel_get_drm_devid(fd));
43 	struct drm_i915_gem_exec_object2 obj[2];
44 	struct drm_i915_gem_relocation_entry reloc;
45 	struct drm_i915_gem_execbuffer2 execbuf;
46 	uint32_t batch[16];
47 	int i;
48 
49 	igt_require(gem_class_can_store_dword(fd, e->class));
50 
51 	intel_detect_and_clear_missed_interrupts(fd);
52 	memset(&execbuf, 0, sizeof(execbuf));
53 	execbuf.buffers_ptr = to_user_pointer(obj);
54 	execbuf.buffer_count = 2;
55 	execbuf.flags = e->flags;
56 	if (gen > 3 && gen < 6)
57 		execbuf.flags |= I915_EXEC_SECURE;
58 
59 	memset(obj, 0, sizeof(obj));
60 	obj[0].handle = gem_create(fd, 4096);
61 	obj[1].handle = gem_create(fd, 4096);
62 
63 	memset(&reloc, 0, sizeof(reloc));
64 	reloc.target_handle = obj[0].handle;
65 	reloc.presumed_offset = 0;
66 	reloc.offset = sizeof(uint32_t);
67 	reloc.delta = 0;
68 	reloc.read_domains = I915_GEM_DOMAIN_INSTRUCTION;
69 	reloc.write_domain = I915_GEM_DOMAIN_INSTRUCTION;
70 	obj[1].relocs_ptr = to_user_pointer(&reloc);
71 	obj[1].relocation_count = 1;
72 
73 	i = 0;
74 	batch[i] = MI_STORE_DWORD_IMM | (gen < 6 ? 1 << 22 : 0);
75 	if (gen >= 8) {
76 		batch[++i] = 0;
77 		batch[++i] = 0;
78 	} else if (gen >= 4) {
79 		batch[++i] = 0;
80 		batch[++i] = 0;
81 		reloc.offset += sizeof(uint32_t);
82 	} else {
83 		batch[i]--;
84 		batch[++i] = 0;
85 	}
86 	batch[++i] = 0xc0ffee;
87 	batch[++i] = MI_BATCH_BUFFER_END;
88 	gem_write(fd, obj[1].handle, 0, batch, sizeof(batch));
89 	gem_execbuf(fd, &execbuf);
90 	gem_close(fd, obj[1].handle);
91 
92 	gem_read(fd, obj[0].handle, 0, batch, sizeof(batch));
93 	gem_close(fd, obj[0].handle);
94 	igt_assert_eq(*batch, 0xc0ffee);
95 	igt_assert_eq(intel_detect_and_clear_missed_interrupts(fd), 0);
96 }
97 
98 #define PAGES 1
store_cachelines(int fd,const struct intel_execution_engine2 * e,unsigned int flags)99 static void store_cachelines(int fd, const struct intel_execution_engine2 *e,
100 			     unsigned int flags)
101 {
102 	const int gen = intel_gen(intel_get_drm_devid(fd));
103 	struct drm_i915_gem_exec_object2 *obj;
104 	struct drm_i915_gem_relocation_entry *reloc;
105 	struct drm_i915_gem_execbuffer2 execbuf;
106 #define NCACHELINES (4096/64)
107 	uint32_t *batch;
108 	int i;
109 
110 	reloc = calloc(NCACHELINES, sizeof(*reloc));
111 	igt_assert(reloc);
112 
113 	igt_require(gem_class_can_store_dword(fd, e->class));
114 
115 	intel_detect_and_clear_missed_interrupts(fd);
116 	memset(&execbuf, 0, sizeof(execbuf));
117 	execbuf.buffer_count = flags & PAGES ? NCACHELINES + 1 : 2;
118 	execbuf.flags = e->flags;
119 	if (gen > 3 && gen < 6)
120 		execbuf.flags |= I915_EXEC_SECURE;
121 
122 	obj = calloc(execbuf.buffer_count, sizeof(*obj));
123 	igt_assert(obj);
124 	for (i = 0; i < execbuf.buffer_count; i++)
125 		obj[i].handle = gem_create(fd, 4096);
126 	obj[i-1].relocs_ptr = to_user_pointer(reloc);
127 	obj[i-1].relocation_count = NCACHELINES;
128 	execbuf.buffers_ptr = to_user_pointer(obj);
129 
130 	batch = gem_mmap__cpu(fd, obj[i-1].handle, 0, 4096, PROT_WRITE);
131 
132 	i = 0;
133 	for (unsigned n = 0; n < NCACHELINES; n++) {
134 		reloc[n].target_handle = obj[n % (execbuf.buffer_count-1)].handle;
135 		reloc[n].presumed_offset = -1;
136 		reloc[n].offset = (i + 1)*sizeof(uint32_t);
137 		reloc[n].delta = 4 * (n * 16 + n % 16);
138 		reloc[n].read_domains = I915_GEM_DOMAIN_INSTRUCTION;
139 		reloc[n].write_domain = I915_GEM_DOMAIN_INSTRUCTION;
140 
141 		batch[i] = MI_STORE_DWORD_IMM | (gen < 6 ? 1 << 22 : 0);
142 		if (gen >= 8) {
143 			batch[++i] = 0;
144 			batch[++i] = 0;
145 		} else if (gen >= 4) {
146 			batch[++i] = 0;
147 			batch[++i] = 0;
148 			reloc[n].offset += sizeof(uint32_t);
149 		} else {
150 			batch[i]--;
151 			batch[++i] = 0;
152 		}
153 		batch[++i] = n | ~n << 16;
154 		i++;
155 	}
156 	batch[i++] = MI_BATCH_BUFFER_END;
157 	igt_assert(i < 4096 / sizeof(*batch));
158 	munmap(batch, 4096);
159 	gem_execbuf(fd, &execbuf);
160 
161 	for (unsigned n = 0; n < NCACHELINES; n++) {
162 		uint32_t result;
163 
164 		gem_read(fd, reloc[n].target_handle, reloc[n].delta,
165 			 &result, sizeof(result));
166 
167 		igt_assert_eq_u32(result, n | ~n << 16);
168 	}
169 	free(reloc);
170 
171 	for (unsigned n = 0; n < execbuf.buffer_count; n++)
172 		gem_close(fd, obj[n].handle);
173 	free(obj);
174 
175 	igt_assert_eq(intel_detect_and_clear_missed_interrupts(fd), 0);
176 }
177 
store_all(int fd)178 static void store_all(int fd)
179 {
180 	const int gen = intel_gen(intel_get_drm_devid(fd));
181 	struct drm_i915_gem_exec_object2 obj[2];
182 	struct intel_execution_engine2 *engine;
183 	struct drm_i915_gem_relocation_entry reloc[32];
184 	struct drm_i915_gem_execbuffer2 execbuf;
185 	unsigned engines[16], permuted[16];
186 	uint32_t batch[16];
187 	uint64_t offset;
188 	unsigned nengine;
189 	int value;
190 	int i, j;
191 
192 	memset(&execbuf, 0, sizeof(execbuf));
193 	execbuf.buffers_ptr = to_user_pointer(obj);
194 	execbuf.buffer_count = 2;
195 	if (gen < 6)
196 		execbuf.flags |= I915_EXEC_SECURE;
197 
198 	memset(reloc, 0, sizeof(reloc));
199 	memset(obj, 0, sizeof(obj));
200 	obj[0].handle = gem_create(fd, 4096);
201 	obj[1].handle = gem_create(fd, 4096);
202 	obj[1].relocation_count = 1;
203 
204 	offset = sizeof(uint32_t);
205 	i = 0;
206 	batch[i] = MI_STORE_DWORD_IMM | (gen < 6 ? 1 << 22 : 0);
207 	if (gen >= 8) {
208 		batch[++i] = 0;
209 		batch[++i] = 0;
210 	} else if (gen >= 4) {
211 		batch[++i] = 0;
212 		batch[++i] = 0;
213 		offset += sizeof(uint32_t);
214 	} else {
215 		batch[i]--;
216 		batch[++i] = 0;
217 	}
218 	batch[value = ++i] = 0xc0ffee;
219 	batch[++i] = MI_BATCH_BUFFER_END;
220 
221 	nengine = 0;
222 	intel_detect_and_clear_missed_interrupts(fd);
223 	__for_each_physical_engine(fd, engine) {
224 		if (!gem_class_can_store_dword(fd, engine->class))
225 			continue;
226 
227 		igt_assert(2*(nengine+1)*sizeof(batch) <= 4096);
228 
229 		execbuf.flags &= ~ENGINE_MASK;
230 		execbuf.flags |= engine->flags;
231 
232 		j = 2*nengine;
233 		reloc[j].target_handle = obj[0].handle;
234 		reloc[j].presumed_offset = ~0;
235 		reloc[j].offset = j*sizeof(batch) + offset;
236 		reloc[j].delta = nengine*sizeof(uint32_t);
237 		reloc[j].read_domains = I915_GEM_DOMAIN_INSTRUCTION;
238 		reloc[j].write_domain = I915_GEM_DOMAIN_INSTRUCTION;
239 		obj[1].relocs_ptr = to_user_pointer(&reloc[j]);
240 
241 		batch[value] = 0xdeadbeef;
242 		gem_write(fd, obj[1].handle, j*sizeof(batch),
243 			  batch, sizeof(batch));
244 		execbuf.batch_start_offset = j*sizeof(batch);
245 		gem_execbuf(fd, &execbuf);
246 
247 		j = 2*nengine + 1;
248 		reloc[j].target_handle = obj[0].handle;
249 		reloc[j].presumed_offset = ~0;
250 		reloc[j].offset = j*sizeof(batch) + offset;
251 		reloc[j].delta = nengine*sizeof(uint32_t);
252 		reloc[j].read_domains = I915_GEM_DOMAIN_INSTRUCTION;
253 		reloc[j].write_domain = I915_GEM_DOMAIN_INSTRUCTION;
254 		obj[1].relocs_ptr = to_user_pointer(&reloc[j]);
255 
256 		batch[value] = nengine;
257 		gem_write(fd, obj[1].handle, j*sizeof(batch),
258 			  batch, sizeof(batch));
259 		execbuf.batch_start_offset = j*sizeof(batch);
260 		gem_execbuf(fd, &execbuf);
261 
262 		engines[nengine++] = engine->flags;
263 	}
264 	gem_sync(fd, obj[1].handle);
265 
266 	for (i = 0; i < nengine; i++) {
267 		obj[1].relocs_ptr = to_user_pointer(&reloc[2*i]);
268 		execbuf.batch_start_offset = 2*i*sizeof(batch);
269 		memcpy(permuted, engines, nengine*sizeof(engines[0]));
270 		igt_permute_array(permuted, nengine, igt_exchange_int);
271 		for (j = 0; j < nengine; j++) {
272 			execbuf.flags &= ~ENGINE_MASK;
273 			execbuf.flags |= permuted[j];
274 			gem_execbuf(fd, &execbuf);
275 		}
276 		obj[1].relocs_ptr = to_user_pointer(&reloc[2*i+1]);
277 		execbuf.batch_start_offset = (2*i+1)*sizeof(batch);
278 		execbuf.flags &= ~ENGINE_MASK;
279 		execbuf.flags |= engines[i];
280 		gem_execbuf(fd, &execbuf);
281 	}
282 	gem_close(fd, obj[1].handle);
283 
284 	gem_read(fd, obj[0].handle, 0, engines, sizeof(engines));
285 	gem_close(fd, obj[0].handle);
286 
287 	for (i = 0; i < nengine; i++)
288 		igt_assert_eq_u32(engines[i], i);
289 	igt_assert_eq(intel_detect_and_clear_missed_interrupts(fd), 0);
290 }
291 
print_welcome(int fd)292 static int print_welcome(int fd)
293 {
294 	uint16_t devid = intel_get_drm_devid(fd);
295 	const struct intel_device_info *info = intel_get_device_info(devid);
296 	int err;
297 
298 	igt_info("Running on %s (pci-id %04x, gen %d)\n",
299 		 info->codename, devid, ffs(info->gen));
300 	igt_info("Can use MI_STORE_DWORD(virtual)? %s\n",
301 		 gem_can_store_dword(fd, 0) ? "yes" : "no");
302 
303 	err = 0;
304 	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_THROTTLE, 0))
305 		err = -errno;
306 	igt_info("GPU operation? %s [errno=%d]\n",
307 		 err == 0 ? "yes" : "no", err);
308 
309 	return ffs(info->gen);
310 }
311 
312 igt_main
313 {
314 	const struct intel_execution_engine2 *e;
315 	int fd;
316 
317 	igt_fixture {
318 		int gen;
319 
320 		fd = drm_open_driver(DRIVER_INTEL);
321 
322 		gen = print_welcome(fd);
323 		if (gen > 3 && gen < 6) /* ctg and ilk need secure batches */
324 			igt_device_set_master(fd);
325 
326 		igt_require_gem(fd);
327 		igt_require(gem_can_store_dword(fd, 0));
328 
329 		igt_fork_hang_detector(fd);
330 	}
331 
__for_each_physical_engine(fd,e)332 	__for_each_physical_engine(fd, e) {
333 		igt_subtest_f("basic-%s", e->name)
334 			store_dword(fd, e);
335 
336 		igt_subtest_f("cachelines-%s", e->name)
337 			store_cachelines(fd, e, 0);
338 
339 		igt_subtest_f("pages-%s", e->name)
340 			store_cachelines(fd, e, PAGES);
341 	}
342 
343 	igt_subtest("basic-all")
344 		store_all(fd);
345 
346 	igt_fixture {
347 		igt_stop_hang_detector();
348 		close(fd);
349 	}
350 }
351