Branch data Line data Source code
1 : : // SPDX-License-Identifier: MIT
2 : : /*
3 : : * Copyright © 2019 Intel Corporation
4 : : */
5 : :
6 : : #include "i915_drv.h"
7 : : #include "gt/intel_context.h"
8 : : #include "gt/intel_engine_pm.h"
9 : : #include "gt/intel_engine_pool.h"
10 : : #include "gt/intel_gt.h"
11 : : #include "gt/intel_ring.h"
12 : : #include "i915_gem_clflush.h"
13 : : #include "i915_gem_object_blt.h"
14 : :
15 : 0 : struct i915_vma *intel_emit_vma_fill_blt(struct intel_context *ce,
16 : : struct i915_vma *vma,
17 : : u32 value)
18 : : {
19 : 0 : struct drm_i915_private *i915 = ce->vm->i915;
20 : 0 : const u32 block_size = SZ_8M; /* ~1ms at 8GiB/s preemption delay */
21 : 0 : struct intel_engine_pool_node *pool;
22 : 0 : struct i915_vma *batch;
23 : 0 : u64 offset;
24 : 0 : u64 count;
25 : 0 : u64 rem;
26 : 0 : u32 size;
27 : 0 : u32 *cmd;
28 : 0 : int err;
29 : :
30 : 0 : GEM_BUG_ON(intel_engine_is_virtual(ce->engine));
31 : 0 : intel_engine_pm_get(ce->engine);
32 : :
33 : 0 : count = div_u64(round_up(vma->size, block_size), block_size);
34 : 0 : size = (1 + 8 * count) * sizeof(u32);
35 : 0 : size = round_up(size, PAGE_SIZE);
36 : 0 : pool = intel_engine_get_pool(ce->engine, size);
37 [ # # ]: 0 : if (IS_ERR(pool)) {
38 : 0 : err = PTR_ERR(pool);
39 : 0 : goto out_pm;
40 : : }
41 : :
42 : 0 : cmd = i915_gem_object_pin_map(pool->obj, I915_MAP_WC);
43 [ # # ]: 0 : if (IS_ERR(cmd)) {
44 : 0 : err = PTR_ERR(cmd);
45 : 0 : goto out_put;
46 : : }
47 : :
48 : 0 : rem = vma->size;
49 : 0 : offset = vma->node.start;
50 : :
51 : 0 : do {
52 : 0 : u32 size = min_t(u64, rem, block_size);
53 : :
54 : 0 : GEM_BUG_ON(size >> PAGE_SHIFT > S16_MAX);
55 : :
56 [ # # ]: 0 : if (INTEL_GEN(i915) >= 8) {
57 : 0 : *cmd++ = XY_COLOR_BLT_CMD | BLT_WRITE_RGBA | (7 - 2);
58 : 0 : *cmd++ = BLT_DEPTH_32 | BLT_ROP_COLOR_COPY | PAGE_SIZE;
59 : 0 : *cmd++ = 0;
60 : 0 : *cmd++ = size >> PAGE_SHIFT << 16 | PAGE_SIZE / 4;
61 : 0 : *cmd++ = lower_32_bits(offset);
62 : 0 : *cmd++ = upper_32_bits(offset);
63 : 0 : *cmd++ = value;
64 : : } else {
65 : 0 : *cmd++ = XY_COLOR_BLT_CMD | BLT_WRITE_RGBA | (6 - 2);
66 : 0 : *cmd++ = BLT_DEPTH_32 | BLT_ROP_COLOR_COPY | PAGE_SIZE;
67 : 0 : *cmd++ = 0;
68 : 0 : *cmd++ = size >> PAGE_SHIFT << 16 | PAGE_SIZE / 4;
69 : 0 : *cmd++ = offset;
70 : 0 : *cmd++ = value;
71 : : }
72 : :
73 : : /* Allow ourselves to be preempted in between blocks. */
74 : 0 : *cmd++ = MI_ARB_CHECK;
75 : :
76 : 0 : offset += size;
77 : 0 : rem -= size;
78 [ # # ]: 0 : } while (rem);
79 : :
80 : 0 : *cmd = MI_BATCH_BUFFER_END;
81 : 0 : intel_gt_chipset_flush(ce->vm->gt);
82 : :
83 : 0 : i915_gem_object_unpin_map(pool->obj);
84 : :
85 : 0 : batch = i915_vma_instance(pool->obj, ce->vm, NULL);
86 [ # # ]: 0 : if (IS_ERR(batch)) {
87 : 0 : err = PTR_ERR(batch);
88 : 0 : goto out_put;
89 : : }
90 : :
91 : 0 : err = i915_vma_pin(batch, 0, 0, PIN_USER);
92 [ # # ]: 0 : if (unlikely(err))
93 : 0 : goto out_put;
94 : :
95 : 0 : batch->private = pool;
96 : 0 : return batch;
97 : :
98 : 0 : out_put:
99 : 0 : intel_engine_pool_put(pool);
100 : 0 : out_pm:
101 : 0 : intel_engine_pm_put(ce->engine);
102 : 0 : return ERR_PTR(err);
103 : : }
104 : :
105 : 0 : int intel_emit_vma_mark_active(struct i915_vma *vma, struct i915_request *rq)
106 : : {
107 : 0 : int err;
108 : :
109 : 0 : i915_vma_lock(vma);
110 : 0 : err = i915_request_await_object(rq, vma->obj, false);
111 [ # # ]: 0 : if (err == 0)
112 : 0 : err = i915_vma_move_to_active(vma, rq, 0);
113 : 0 : i915_vma_unlock(vma);
114 [ # # ]: 0 : if (unlikely(err))
115 : : return err;
116 : :
117 : 0 : return intel_engine_pool_mark_active(vma->private, rq);
118 : : }
119 : :
120 : 0 : void intel_emit_vma_release(struct intel_context *ce, struct i915_vma *vma)
121 : : {
122 : 0 : i915_vma_unpin(vma);
123 : 0 : intel_engine_pool_put(vma->private);
124 : 0 : intel_engine_pm_put(ce->engine);
125 : 0 : }
126 : :
127 : 0 : int i915_gem_object_fill_blt(struct drm_i915_gem_object *obj,
128 : : struct intel_context *ce,
129 : : u32 value)
130 : : {
131 : 0 : struct i915_request *rq;
132 : 0 : struct i915_vma *batch;
133 : 0 : struct i915_vma *vma;
134 : 0 : int err;
135 : :
136 : 0 : vma = i915_vma_instance(obj, ce->vm, NULL);
137 [ # # ]: 0 : if (IS_ERR(vma))
138 : 0 : return PTR_ERR(vma);
139 : :
140 : 0 : err = i915_vma_pin(vma, 0, 0, PIN_USER);
141 [ # # ]: 0 : if (unlikely(err))
142 : : return err;
143 : :
144 [ # # ]: 0 : if (obj->cache_dirty & ~obj->cache_coherent) {
145 : 0 : i915_gem_object_lock(obj);
146 : 0 : i915_gem_clflush_object(obj, 0);
147 : 0 : i915_gem_object_unlock(obj);
148 : : }
149 : :
150 : 0 : batch = intel_emit_vma_fill_blt(ce, vma, value);
151 [ # # ]: 0 : if (IS_ERR(batch)) {
152 : 0 : err = PTR_ERR(batch);
153 : 0 : goto out_unpin;
154 : : }
155 : :
156 : 0 : rq = intel_context_create_request(ce);
157 [ # # ]: 0 : if (IS_ERR(rq)) {
158 : 0 : err = PTR_ERR(rq);
159 : 0 : goto out_batch;
160 : : }
161 : :
162 : 0 : err = intel_emit_vma_mark_active(batch, rq);
163 [ # # ]: 0 : if (unlikely(err))
164 : 0 : goto out_request;
165 : :
166 : 0 : err = i915_request_await_object(rq, obj, true);
167 [ # # ]: 0 : if (unlikely(err))
168 : 0 : goto out_request;
169 : :
170 [ # # ]: 0 : if (ce->engine->emit_init_breadcrumb) {
171 : 0 : err = ce->engine->emit_init_breadcrumb(rq);
172 [ # # ]: 0 : if (unlikely(err))
173 : 0 : goto out_request;
174 : : }
175 : :
176 : 0 : i915_vma_lock(vma);
177 : 0 : err = i915_request_await_object(rq, vma->obj, true);
178 [ # # ]: 0 : if (err == 0)
179 : 0 : err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
180 : 0 : i915_vma_unlock(vma);
181 [ # # ]: 0 : if (unlikely(err))
182 : 0 : goto out_request;
183 : :
184 : 0 : err = ce->engine->emit_bb_start(rq,
185 : 0 : batch->node.start, batch->node.size,
186 : : 0);
187 : 0 : out_request:
188 [ # # ]: 0 : if (unlikely(err))
189 : 0 : i915_request_skip(rq, err);
190 : :
191 : 0 : i915_request_add(rq);
192 : 0 : out_batch:
193 : 0 : intel_emit_vma_release(ce, batch);
194 : 0 : out_unpin:
195 : 0 : i915_vma_unpin(vma);
196 : 0 : return err;
197 : : }
198 : :
199 : 0 : struct i915_vma *intel_emit_vma_copy_blt(struct intel_context *ce,
200 : : struct i915_vma *src,
201 : : struct i915_vma *dst)
202 : : {
203 : 0 : struct drm_i915_private *i915 = ce->vm->i915;
204 : 0 : const u32 block_size = SZ_8M; /* ~1ms at 8GiB/s preemption delay */
205 : 0 : struct intel_engine_pool_node *pool;
206 : 0 : struct i915_vma *batch;
207 : 0 : u64 src_offset, dst_offset;
208 : 0 : u64 count, rem;
209 : 0 : u32 size, *cmd;
210 : 0 : int err;
211 : :
212 : 0 : GEM_BUG_ON(src->size != dst->size);
213 : :
214 : 0 : GEM_BUG_ON(intel_engine_is_virtual(ce->engine));
215 : 0 : intel_engine_pm_get(ce->engine);
216 : :
217 : 0 : count = div_u64(round_up(dst->size, block_size), block_size);
218 : 0 : size = (1 + 11 * count) * sizeof(u32);
219 : 0 : size = round_up(size, PAGE_SIZE);
220 : 0 : pool = intel_engine_get_pool(ce->engine, size);
221 [ # # ]: 0 : if (IS_ERR(pool)) {
222 : 0 : err = PTR_ERR(pool);
223 : 0 : goto out_pm;
224 : : }
225 : :
226 : 0 : cmd = i915_gem_object_pin_map(pool->obj, I915_MAP_WC);
227 [ # # ]: 0 : if (IS_ERR(cmd)) {
228 : 0 : err = PTR_ERR(cmd);
229 : 0 : goto out_put;
230 : : }
231 : :
232 : 0 : rem = src->size;
233 : 0 : src_offset = src->node.start;
234 : 0 : dst_offset = dst->node.start;
235 : :
236 : 0 : do {
237 : 0 : size = min_t(u64, rem, block_size);
238 : 0 : GEM_BUG_ON(size >> PAGE_SHIFT > S16_MAX);
239 : :
240 [ # # ]: 0 : if (INTEL_GEN(i915) >= 9) {
241 : 0 : *cmd++ = GEN9_XY_FAST_COPY_BLT_CMD | (10 - 2);
242 : 0 : *cmd++ = BLT_DEPTH_32 | PAGE_SIZE;
243 : 0 : *cmd++ = 0;
244 : 0 : *cmd++ = size >> PAGE_SHIFT << 16 | PAGE_SIZE / 4;
245 : 0 : *cmd++ = lower_32_bits(dst_offset);
246 : 0 : *cmd++ = upper_32_bits(dst_offset);
247 : 0 : *cmd++ = 0;
248 : 0 : *cmd++ = PAGE_SIZE;
249 : 0 : *cmd++ = lower_32_bits(src_offset);
250 : 0 : *cmd++ = upper_32_bits(src_offset);
251 [ # # ]: 0 : } else if (INTEL_GEN(i915) >= 8) {
252 : 0 : *cmd++ = XY_SRC_COPY_BLT_CMD | BLT_WRITE_RGBA | (10 - 2);
253 : 0 : *cmd++ = BLT_DEPTH_32 | BLT_ROP_SRC_COPY | PAGE_SIZE;
254 : 0 : *cmd++ = 0;
255 : 0 : *cmd++ = size >> PAGE_SHIFT << 16 | PAGE_SIZE / 4;
256 : 0 : *cmd++ = lower_32_bits(dst_offset);
257 : 0 : *cmd++ = upper_32_bits(dst_offset);
258 : 0 : *cmd++ = 0;
259 : 0 : *cmd++ = PAGE_SIZE;
260 : 0 : *cmd++ = lower_32_bits(src_offset);
261 : 0 : *cmd++ = upper_32_bits(src_offset);
262 : : } else {
263 : 0 : *cmd++ = SRC_COPY_BLT_CMD | BLT_WRITE_RGBA | (6 - 2);
264 : 0 : *cmd++ = BLT_DEPTH_32 | BLT_ROP_SRC_COPY | PAGE_SIZE;
265 : 0 : *cmd++ = size >> PAGE_SHIFT << 16 | PAGE_SIZE;
266 : 0 : *cmd++ = dst_offset;
267 : 0 : *cmd++ = PAGE_SIZE;
268 : 0 : *cmd++ = src_offset;
269 : : }
270 : :
271 : : /* Allow ourselves to be preempted in between blocks. */
272 : 0 : *cmd++ = MI_ARB_CHECK;
273 : :
274 : 0 : src_offset += size;
275 : 0 : dst_offset += size;
276 : 0 : rem -= size;
277 [ # # ]: 0 : } while (rem);
278 : :
279 : 0 : *cmd = MI_BATCH_BUFFER_END;
280 : 0 : intel_gt_chipset_flush(ce->vm->gt);
281 : :
282 : 0 : i915_gem_object_unpin_map(pool->obj);
283 : :
284 : 0 : batch = i915_vma_instance(pool->obj, ce->vm, NULL);
285 [ # # ]: 0 : if (IS_ERR(batch)) {
286 : 0 : err = PTR_ERR(batch);
287 : 0 : goto out_put;
288 : : }
289 : :
290 : 0 : err = i915_vma_pin(batch, 0, 0, PIN_USER);
291 [ # # ]: 0 : if (unlikely(err))
292 : 0 : goto out_put;
293 : :
294 : 0 : batch->private = pool;
295 : 0 : return batch;
296 : :
297 : 0 : out_put:
298 : 0 : intel_engine_pool_put(pool);
299 : 0 : out_pm:
300 : 0 : intel_engine_pm_put(ce->engine);
301 : 0 : return ERR_PTR(err);
302 : : }
303 : :
304 : 0 : static int move_to_gpu(struct i915_vma *vma, struct i915_request *rq, bool write)
305 : : {
306 : 0 : struct drm_i915_gem_object *obj = vma->obj;
307 : :
308 [ # # ]: 0 : if (obj->cache_dirty & ~obj->cache_coherent)
309 : 0 : i915_gem_clflush_object(obj, 0);
310 : :
311 : 0 : return i915_request_await_object(rq, obj, write);
312 : : }
313 : :
314 : 0 : int i915_gem_object_copy_blt(struct drm_i915_gem_object *src,
315 : : struct drm_i915_gem_object *dst,
316 : : struct intel_context *ce)
317 : : {
318 : 0 : struct drm_gem_object *objs[] = { &src->base, &dst->base };
319 : 0 : struct i915_address_space *vm = ce->vm;
320 : 0 : struct i915_vma *vma[2], *batch;
321 : 0 : struct ww_acquire_ctx acquire;
322 : 0 : struct i915_request *rq;
323 : 0 : int err, i;
324 : :
325 : 0 : vma[0] = i915_vma_instance(src, vm, NULL);
326 [ # # ]: 0 : if (IS_ERR(vma[0]))
327 : 0 : return PTR_ERR(vma[0]);
328 : :
329 : 0 : err = i915_vma_pin(vma[0], 0, 0, PIN_USER);
330 [ # # ]: 0 : if (unlikely(err))
331 : : return err;
332 : :
333 : 0 : vma[1] = i915_vma_instance(dst, vm, NULL);
334 [ # # ]: 0 : if (IS_ERR(vma[1]))
335 : 0 : goto out_unpin_src;
336 : :
337 : 0 : err = i915_vma_pin(vma[1], 0, 0, PIN_USER);
338 [ # # ]: 0 : if (unlikely(err))
339 : 0 : goto out_unpin_src;
340 : :
341 : 0 : batch = intel_emit_vma_copy_blt(ce, vma[0], vma[1]);
342 [ # # ]: 0 : if (IS_ERR(batch)) {
343 : 0 : err = PTR_ERR(batch);
344 : 0 : goto out_unpin_dst;
345 : : }
346 : :
347 : 0 : rq = intel_context_create_request(ce);
348 [ # # ]: 0 : if (IS_ERR(rq)) {
349 : 0 : err = PTR_ERR(rq);
350 : 0 : goto out_batch;
351 : : }
352 : :
353 : 0 : err = intel_emit_vma_mark_active(batch, rq);
354 [ # # ]: 0 : if (unlikely(err))
355 : 0 : goto out_request;
356 : :
357 : 0 : err = drm_gem_lock_reservations(objs, ARRAY_SIZE(objs), &acquire);
358 [ # # ]: 0 : if (unlikely(err))
359 : 0 : goto out_request;
360 : :
361 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(vma); i++) {
362 : 0 : err = move_to_gpu(vma[i], rq, i);
363 [ # # ]: 0 : if (unlikely(err))
364 : 0 : goto out_unlock;
365 : : }
366 : :
367 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(vma); i++) {
368 [ # # ]: 0 : unsigned int flags = i ? EXEC_OBJECT_WRITE : 0;
369 : :
370 : 0 : err = i915_vma_move_to_active(vma[i], rq, flags);
371 [ # # ]: 0 : if (unlikely(err))
372 : 0 : goto out_unlock;
373 : : }
374 : :
375 [ # # ]: 0 : if (rq->engine->emit_init_breadcrumb) {
376 : 0 : err = rq->engine->emit_init_breadcrumb(rq);
377 [ # # ]: 0 : if (unlikely(err))
378 : 0 : goto out_unlock;
379 : : }
380 : :
381 : 0 : err = rq->engine->emit_bb_start(rq,
382 : 0 : batch->node.start, batch->node.size,
383 : : 0);
384 : 0 : out_unlock:
385 : 0 : drm_gem_unlock_reservations(objs, ARRAY_SIZE(objs), &acquire);
386 : 0 : out_request:
387 [ # # ]: 0 : if (unlikely(err))
388 : 0 : i915_request_skip(rq, err);
389 : :
390 : 0 : i915_request_add(rq);
391 : 0 : out_batch:
392 : 0 : intel_emit_vma_release(ce, batch);
393 : 0 : out_unpin_dst:
394 : 0 : i915_vma_unpin(vma[1]);
395 : 0 : out_unpin_src:
396 : 0 : i915_vma_unpin(vma[0]);
397 : 0 : return err;
398 : : }
399 : :
400 : : #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
401 : : #include "selftests/i915_gem_object_blt.c"
402 : : #endif
|