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 * Authors:
24 * Eric Anholt <[email protected]>
25 *
26 */
27
28 /** @file gem_ringfill.c
29 *
30 * This is a test of doing many tiny batchbuffer operations, in the hope of
31 * catching failure to manage the ring properly near full.
32 */
33
34 #include "igt.h"
35 #include "igt_device.h"
36 #include "igt_gt.h"
37 #include "igt_vgem.h"
38 #include "i915/gem_ring.h"
39
40 #include <signal.h>
41 #include <sys/ioctl.h>
42
43 #define INTERRUPTIBLE 0x1
44 #define HANG 0x2
45 #define CHILD 0x8
46 #define FORKED 0x8
47 #define BOMB 0x10
48 #define SUSPEND 0x20
49 #define HIBERNATE 0x40
50 #define NEWFD 0x80
51
52 static unsigned int ring_size;
53
check_bo(int fd,uint32_t handle)54 static void check_bo(int fd, uint32_t handle)
55 {
56 uint32_t *map;
57 int i;
58
59 igt_debug("Verifying result\n");
60 map = gem_mmap__cpu(fd, handle, 0, 4096, PROT_READ);
61 gem_set_domain(fd, handle, I915_GEM_DOMAIN_CPU, 0);
62 for (i = 0; i < 1024; i++)
63 igt_assert_eq(map[i], i);
64 munmap(map, 4096);
65 }
66
fill_ring(int fd,struct drm_i915_gem_execbuffer2 * execbuf,unsigned flags,unsigned timeout)67 static void fill_ring(int fd,
68 struct drm_i915_gem_execbuffer2 *execbuf,
69 unsigned flags, unsigned timeout)
70 {
71 /* The ring we've been using is 128k, and each rendering op
72 * will use at least 8 dwords:
73 *
74 * BATCH_START
75 * BATCH_START offset
76 * MI_FLUSH
77 * STORE_DATA_INDEX
78 * STORE_DATA_INDEX offset
79 * STORE_DATA_INDEX value
80 * MI_USER_INTERRUPT
81 * (padding)
82 *
83 * So iterate just a little more than that -- if we don't fill the ring
84 * doing this, we aren't likely to with this test.
85 */
86 igt_debug("Executing execbuf %d times\n", 128*1024/(8*4));
87 igt_until_timeout(timeout) {
88 igt_while_interruptible(flags & INTERRUPTIBLE) {
89 for (typeof(ring_size) i = 0; i < ring_size; i++)
90 gem_execbuf(fd, execbuf);
91 }
92 }
93 }
94
setup_execbuf(int fd,struct drm_i915_gem_execbuffer2 * execbuf,struct drm_i915_gem_exec_object2 * obj,struct drm_i915_gem_relocation_entry * reloc,unsigned int ring)95 static int setup_execbuf(int fd,
96 struct drm_i915_gem_execbuffer2 *execbuf,
97 struct drm_i915_gem_exec_object2 *obj,
98 struct drm_i915_gem_relocation_entry *reloc,
99 unsigned int ring)
100 {
101 const int gen = intel_gen(intel_get_drm_devid(fd));
102 const uint32_t bbe = MI_BATCH_BUFFER_END;
103 uint32_t *batch, *b;
104 int ret;
105 int i;
106
107 memset(execbuf, 0, sizeof(*execbuf));
108 memset(obj, 0, 2*sizeof(*obj));
109 memset(reloc, 0, 1024*sizeof(*reloc));
110
111 execbuf->buffers_ptr = to_user_pointer(obj);
112 execbuf->flags = ring | (1 << 11) | (1 << 12);
113
114 if (gen > 3 && gen < 6)
115 execbuf->flags |= I915_EXEC_SECURE;
116
117 obj[0].handle = gem_create(fd, 4096);
118 gem_write(fd, obj[0].handle, 0, &bbe, sizeof(bbe));
119 execbuf->buffer_count = 1;
120 ret = __gem_execbuf(fd, execbuf);
121 if (ret)
122 return ret;
123
124 obj[0].flags |= EXEC_OBJECT_WRITE;
125 obj[1].handle = gem_create(fd, 1024*16 + 4096);
126
127 obj[1].relocs_ptr = to_user_pointer(reloc);
128 obj[1].relocation_count = 1024;
129
130 batch = gem_mmap__cpu(fd, obj[1].handle, 0, 16*1024 + 4096,
131 PROT_WRITE | PROT_READ);
132 gem_set_domain(fd, obj[1].handle,
133 I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
134
135 b = batch;
136 for (i = 0; i < 1024; i++) {
137 uint64_t offset;
138
139 reloc[i].presumed_offset = obj[0].offset;
140 reloc[i].offset = (b - batch + 1) * sizeof(*batch);
141 reloc[i].delta = i * sizeof(uint32_t);
142 reloc[i].read_domains = I915_GEM_DOMAIN_INSTRUCTION;
143 reloc[i].write_domain = I915_GEM_DOMAIN_INSTRUCTION;
144
145 offset = obj[0].offset + reloc[i].delta;
146 *b++ = MI_STORE_DWORD_IMM;
147 if (gen >= 8) {
148 *b++ = offset;
149 *b++ = offset >> 32;
150 } else if (gen >= 4) {
151 if (gen < 6)
152 b[-1] |= 1 << 22;
153 *b++ = 0;
154 *b++ = offset;
155 reloc[i].offset += sizeof(*batch);
156 } else {
157 b[-1] |= 1 << 22;
158 b[-1] -= 1;
159 *b++ = offset;
160 }
161 *b++ = i;
162 }
163 *b++ = MI_BATCH_BUFFER_END;
164 munmap(batch, 16*1024+4096);
165
166 execbuf->buffer_count = 2;
167 gem_execbuf(fd, execbuf);
168
169 check_bo(fd, obj[0].handle);
170 return 0;
171 }
172
run_test(int fd,unsigned ring,unsigned flags,unsigned timeout)173 static void run_test(int fd, unsigned ring, unsigned flags, unsigned timeout)
174 {
175 struct drm_i915_gem_exec_object2 obj[2];
176 struct drm_i915_gem_relocation_entry reloc[1024];
177 struct drm_i915_gem_execbuffer2 execbuf;
178 igt_hang_t hang;
179
180 gem_require_ring(fd, ring);
181 igt_require(gem_can_store_dword(fd, ring));
182
183 if (flags & (SUSPEND | HIBERNATE))
184 run_test(fd, ring, 0, 0);
185
186 gem_quiescent_gpu(fd);
187 igt_require(setup_execbuf(fd, &execbuf, obj, reloc, ring) == 0);
188
189 memset(&hang, 0, sizeof(hang));
190 if (flags & HANG)
191 hang = igt_hang_ring(fd, ring & ~(3<<13));
192
193 if (flags & (CHILD | FORKED | BOMB)) {
194 int nchild;
195
196 if (flags & FORKED)
197 nchild = sysconf(_SC_NPROCESSORS_ONLN);
198 else if (flags & BOMB)
199 nchild = 8*sysconf(_SC_NPROCESSORS_ONLN);
200 else
201 nchild = 1;
202
203 igt_debug("Forking %d children\n", nchild);
204 igt_fork(child, nchild) {
205 if (flags & NEWFD) {
206 fd = drm_open_driver(DRIVER_INTEL);
207 setup_execbuf(fd, &execbuf, obj, reloc, ring);
208 }
209 fill_ring(fd, &execbuf, flags, timeout);
210 }
211
212 if (flags & SUSPEND)
213 igt_system_suspend_autoresume(SUSPEND_STATE_MEM,
214 SUSPEND_TEST_NONE);
215
216 if (flags & HIBERNATE)
217 igt_system_suspend_autoresume(SUSPEND_STATE_DISK,
218 SUSPEND_TEST_NONE);
219
220 if (flags & NEWFD)
221 fill_ring(fd, &execbuf, flags, timeout);
222
223 igt_waitchildren();
224 } else
225 fill_ring(fd, &execbuf, flags, timeout);
226
227 if (flags & HANG)
228 igt_post_hang_ring(fd, hang);
229 else
230 check_bo(fd, obj[0].handle);
231
232 gem_close(fd, obj[1].handle);
233 gem_close(fd, obj[0].handle);
234
235 gem_quiescent_gpu(fd);
236
237 if (flags & (SUSPEND | HIBERNATE))
238 run_test(fd, ring, 0, 0);
239 }
240
241 igt_main
242 {
243 const struct {
244 const char *suffix;
245 unsigned flags;
246 unsigned timeout;
247 bool basic;
248 } modes[] = {
249 { "", 0, 0, true},
250 { "-interruptible", INTERRUPTIBLE, 1, true },
251 { "-hang", HANG, 10, true },
252 { "-child", CHILD, 0 },
253 { "-forked", FORKED, 0, true },
254 { "-fd", FORKED | NEWFD, 0, true },
255 { "-bomb", BOMB | NEWFD | INTERRUPTIBLE, 150 },
256 { "-S3", BOMB | SUSPEND, 30 },
257 { "-S4", BOMB | HIBERNATE, 30 },
258 { NULL }
259 }, *m;
260 bool master = false;
261 int fd = -1;
262
263 igt_fixture {
264 int gen;
265
266 fd = drm_open_driver(DRIVER_INTEL);
267 igt_require_gem(fd);
268 igt_require(gem_can_store_dword(fd, 0));
269 gen = intel_gen(intel_get_drm_devid(fd));
270 if (gen > 3 && gen < 6) { /* ctg and ilk need secure batches */
271 igt_device_set_master(fd);
272 master = true;
273 }
274
275 ring_size = gem_measure_ring_inflight(fd, ALL_ENGINES, 0);
276 igt_info("Ring size: %d batches\n", ring_size);
277 igt_require(ring_size);
278 }
279
280 for (m = modes; m->suffix; m++) {
281 const struct intel_execution_engine *e;
282
283 for (e = intel_execution_engines; e->name; e++) {
284 igt_subtest_f("%s%s%s",
285 m->basic && !e->exec_id ? "basic-" : "",
286 e->name,
287 m->suffix) {
288 igt_skip_on(m->flags & NEWFD && master);
289 if (m->flags & (HANG|SUSPEND|HIBERNATE))
290 igt_skip_on_simulation();
291 run_test(fd, e->exec_id | e->flags,
292 m->flags, m->timeout);
293 }
294 }
295 }
296
297 igt_fixture
298 close(fd);
299 }
300