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