2 * Copyright © 2012 Intel Corporation
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:
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
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
24 * Chris Wilson <chris@chris-wilson.co.uk>
29 * Testcase: Test the relocations through the CPU domain
31 * Attempt to stress test performing relocations whilst the batch is in the
34 * A freshly allocated buffer starts in the CPU domain, and the pwrite
35 * should also be performed whilst in the CPU domain and so we should
36 * execute the relocations within the CPU domain. If for any reason one of
37 * those steps should land it in the GTT domain, we take the secondary
38 * precaution of filling the mappable portion of the GATT.
40 * In order to detect whether a relocation fails, we first fill a target
41 * buffer with a sequence of invalid commands that would cause the GPU to
42 * immediate hang, and then attempt to overwrite them with a legal, if
43 * short, batchbuffer using a BLT. Then we come to execute the bo, if the
44 * relocation fail and we either copy across all zeros or garbage, then the
59 #include "ioctl_wrappers.h"
61 #include "intel_bufmgr.h"
62 #include "intel_batchbuffer.h"
64 #include "intel_chipset.h"
67 static uint32_t use_blt;
69 static void copy(int fd, uint32_t batch, uint32_t src, uint32_t dst)
71 struct drm_i915_gem_execbuffer2 execbuf;
72 struct drm_i915_gem_relocation_entry gem_reloc[2];
73 struct drm_i915_gem_exec_object2 gem_exec[3];
75 gem_reloc[0].offset = 4 * sizeof(uint32_t);
76 gem_reloc[0].delta = 0;
77 gem_reloc[0].target_handle = dst;
78 gem_reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;
79 gem_reloc[0].write_domain = I915_GEM_DOMAIN_RENDER;
80 gem_reloc[0].presumed_offset = 0;
82 gem_reloc[1].offset = 7 * sizeof(uint32_t);
83 if (intel_gen(intel_get_drm_devid(fd)) >= 8)
84 gem_reloc[1].offset += sizeof(uint32_t);
85 gem_reloc[1].delta = 0;
86 gem_reloc[1].target_handle = src;
87 gem_reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;
88 gem_reloc[1].write_domain = 0;
89 gem_reloc[1].presumed_offset = 0;
91 memset(gem_exec, 0, sizeof(gem_exec));
92 gem_exec[0].handle = src;
93 gem_exec[1].handle = dst;
94 gem_exec[2].handle = batch;
95 gem_exec[2].relocation_count = 2;
96 gem_exec[2].relocs_ptr = (uintptr_t)gem_reloc;
98 memset(&execbuf, 0, sizeof(execbuf));
99 execbuf.buffers_ptr = (uintptr_t)gem_exec;
100 execbuf.buffer_count = 3;
101 execbuf.batch_len = 4096;
102 execbuf.flags = use_blt;
104 do_or_die(drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf));
107 static void exec(int fd, uint32_t handle)
109 struct drm_i915_gem_execbuffer2 execbuf;
110 struct drm_i915_gem_exec_object2 gem_exec;
112 memset(&gem_exec, 0, sizeof(gem_exec));
113 gem_exec.handle = handle;
115 memset(&execbuf, 0, sizeof(execbuf));
116 execbuf.buffers_ptr = (uintptr_t)&gem_exec;
117 execbuf.buffer_count = 1;
118 execbuf.batch_len = 4096;
120 do_or_die(drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf));
123 uint32_t gen6_batch[] = {
124 (XY_SRC_COPY_BLT_CMD | 6 |
125 XY_SRC_COPY_BLT_WRITE_ALPHA |
126 XY_SRC_COPY_BLT_WRITE_RGB),
127 (3 << 24 | /* 32 bits */
128 0xcc << 16 | /* copy ROP */
130 0 << 16 | 0, /* dst x1, y1 */
132 0, /* dst relocation */
133 0 << 16 | 0, /* src x1, y1 */
135 0, /* src relocation */
139 uint32_t gen8_batch[] = {
140 (XY_SRC_COPY_BLT_CMD | 8 |
141 XY_SRC_COPY_BLT_WRITE_ALPHA |
142 XY_SRC_COPY_BLT_WRITE_RGB),
143 (3 << 24 | /* 32 bits */
144 0xcc << 16 | /* copy ROP */
146 0 << 16 | 0, /* dst x1, y1 */
148 0, /* dst relocation */
150 0 << 16 | 0, /* src x1, y1 */
152 0, /* src relocation */
157 uint32_t *batch = gen6_batch;
158 uint32_t batch_size = sizeof(gen6_batch);
162 const uint32_t hang[] = {-1, -1, -1, -1};
163 const uint32_t end[] = {MI_BATCH_BUFFER_END, 0};
170 noop = intel_get_drm_devid(fd);
173 if (intel_gen(noop) >= 6)
174 use_blt = I915_EXEC_BLT;
176 if (intel_gen(noop) >= 8) {
181 aper_size = gem_mappable_aperture_size();
182 igt_skip_on_f(intel_get_total_ram_mb() < aper_size / (1024*1024) * 2,
183 "not enough mem to run test\n");
185 count = aper_size / 4096 * 2;
186 if (igt_run_in_simulation())
189 handles = malloc (count * sizeof(uint32_t));
192 noop = gem_create(fd, 4096);
193 gem_write(fd, noop, 0, end, sizeof(end));
195 /* fill the entire gart with batches and run them */
196 for (i = 0; i < count; i++) {
199 handles[i] = gem_create(fd, 4096);
200 gem_write(fd, handles[i], 0, batch, batch_size);
202 bad = gem_create(fd, 4096);
203 gem_write(fd, bad, 0, hang, sizeof(hang));
205 /* launch the newly created batch */
206 copy(fd, handles[i], noop, bad);
210 igt_progress("gem_cpu_reloc: ", i, 2*count);
213 /* And again in reverse to try and catch the relocation code out */
214 for (i = 0; i < count; i++) {
217 bad = gem_create(fd, 4096);
218 gem_write(fd, bad, 0, hang, sizeof(hang));
220 /* launch the newly created batch */
221 copy(fd, handles[count-i-1], noop, bad);
225 igt_progress("gem_cpu_reloc: ", count+i, 3*count);
228 /* Third time lucky? */
229 for (i = 0; i < count; i++) {
232 bad = gem_create(fd, 4096);
233 gem_write(fd, bad, 0, hang, sizeof(hang));
235 /* launch the newly created batch */
236 gem_set_domain(fd, handles[i],
237 I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
238 copy(fd, handles[i], noop, bad);
242 igt_progress("gem_cpu_reloc: ", 2*count+i, 3*count);
245 igt_info("Test suceeded, cleanup up - this might take a while.\n");