drm/i915/ttm: Return some errors instead of trying memcpy move
[linux-2.6-block.git] / drivers / gpu / drm / i915 / gem / i915_gem_ttm_move.c
CommitLineData
3589fdbd
TH
1// SPDX-License-Identifier: MIT
2/*
3 * Copyright © 2021 Intel Corporation
4 */
5
6#include <drm/ttm/ttm_bo_driver.h>
7
63cf4cad 8#include "i915_deps.h"
3589fdbd
TH
9#include "i915_drv.h"
10#include "intel_memory_region.h"
11#include "intel_region_ttm.h"
12
13#include "gem/i915_gem_object.h"
14#include "gem/i915_gem_region.h"
15#include "gem/i915_gem_ttm.h"
16#include "gem/i915_gem_ttm_move.h"
17
18#include "gt/intel_engine_pm.h"
19#include "gt/intel_gt.h"
20#include "gt/intel_migrate.h"
21
2b0a750c
TH
22/**
23 * DOC: Selftest failure modes for failsafe migration:
24 *
25 * For fail_gpu_migration, the gpu blit scheduled is always a clear blit
26 * rather than a copy blit, and then we force the failure paths as if
27 * the blit fence returned an error.
28 *
29 * For fail_work_allocation we fail the kmalloc of the async worker, we
30 * sync the gpu blit. If it then fails, or fail_gpu_migration is set to
31 * true, then a memcpy operation is performed sync.
32 */
33#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
34static bool fail_gpu_migration;
35static bool fail_work_allocation;
36
37void i915_ttm_migrate_set_failure_modes(bool gpu_migration,
38 bool work_allocation)
39{
40 fail_gpu_migration = gpu_migration;
41 fail_work_allocation = work_allocation;
42}
43#endif
44
3589fdbd
TH
45static enum i915_cache_level
46i915_ttm_cache_level(struct drm_i915_private *i915, struct ttm_resource *res,
47 struct ttm_tt *ttm)
48{
49 return ((HAS_LLC(i915) || HAS_SNOOP(i915)) &&
50 !i915_ttm_gtt_binds_lmem(res) &&
51 ttm->caching == ttm_cached) ? I915_CACHE_LLC :
52 I915_CACHE_NONE;
53}
54
55static struct intel_memory_region *
56i915_ttm_region(struct ttm_device *bdev, int ttm_mem_type)
57{
58 struct drm_i915_private *i915 = container_of(bdev, typeof(*i915), bdev);
59
60 /* There's some room for optimization here... */
61 GEM_BUG_ON(ttm_mem_type != I915_PL_SYSTEM &&
62 ttm_mem_type < I915_PL_LMEM0);
63 if (ttm_mem_type == I915_PL_SYSTEM)
64 return intel_memory_region_lookup(i915, INTEL_MEMORY_SYSTEM,
65 0);
66
67 return intel_memory_region_lookup(i915, INTEL_MEMORY_LOCAL,
68 ttm_mem_type - I915_PL_LMEM0);
69}
70
71/**
72 * i915_ttm_adjust_domains_after_move - Adjust the GEM domains after a
73 * TTM move
74 * @obj: The gem object
75 */
76void i915_ttm_adjust_domains_after_move(struct drm_i915_gem_object *obj)
77{
78 struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
79
80 if (i915_ttm_cpu_maps_iomem(bo->resource) || bo->ttm->caching != ttm_cached) {
81 obj->write_domain = I915_GEM_DOMAIN_WC;
82 obj->read_domains = I915_GEM_DOMAIN_WC;
83 } else {
84 obj->write_domain = I915_GEM_DOMAIN_CPU;
85 obj->read_domains = I915_GEM_DOMAIN_CPU;
86 }
87}
88
89/**
90 * i915_ttm_adjust_gem_after_move - Adjust the GEM state after a TTM move
91 * @obj: The gem object
92 *
93 * Adjusts the GEM object's region, mem_flags and cache coherency after a
94 * TTM move.
95 */
96void i915_ttm_adjust_gem_after_move(struct drm_i915_gem_object *obj)
97{
98 struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
99 unsigned int cache_level;
100 unsigned int i;
101
102 /*
103 * If object was moved to an allowable region, update the object
104 * region to consider it migrated. Note that if it's currently not
105 * in an allowable region, it's evicted and we don't update the
106 * object region.
107 */
108 if (intel_region_to_ttm_type(obj->mm.region) != bo->resource->mem_type) {
109 for (i = 0; i < obj->mm.n_placements; ++i) {
110 struct intel_memory_region *mr = obj->mm.placements[i];
111
112 if (intel_region_to_ttm_type(mr) == bo->resource->mem_type &&
113 mr != obj->mm.region) {
114 i915_gem_object_release_memory_region(obj);
115 i915_gem_object_init_memory_region(obj, mr);
116 break;
117 }
118 }
119 }
120
121 obj->mem_flags &= ~(I915_BO_FLAG_STRUCT_PAGE | I915_BO_FLAG_IOMEM);
122
123 obj->mem_flags |= i915_ttm_cpu_maps_iomem(bo->resource) ? I915_BO_FLAG_IOMEM :
124 I915_BO_FLAG_STRUCT_PAGE;
125
126 cache_level = i915_ttm_cache_level(to_i915(bo->base.dev), bo->resource,
127 bo->ttm);
128 i915_gem_object_set_cache_coherency(obj, cache_level);
129}
130
131/**
132 * i915_ttm_move_notify - Prepare an object for move
133 * @bo: The ttm buffer object.
134 *
135 * This function prepares an object for move by removing all GPU bindings,
136 * removing all CPU mapings and finally releasing the pages sg-table.
137 *
138 * Return: 0 if successful, negative error code on error.
139 */
140int i915_ttm_move_notify(struct ttm_buffer_object *bo)
141{
142 struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
143 int ret;
144
145 ret = i915_gem_object_unbind(obj, I915_GEM_OBJECT_UNBIND_ACTIVE);
146 if (ret)
147 return ret;
148
149 ret = __i915_gem_object_put_pages(obj);
150 if (ret)
151 return ret;
152
153 return 0;
154}
155
2b0a750c
TH
156static struct dma_fence *i915_ttm_accel_move(struct ttm_buffer_object *bo,
157 bool clear,
158 struct ttm_resource *dst_mem,
159 struct ttm_tt *dst_ttm,
6385eb7a 160 struct sg_table *dst_st,
11930817 161 const struct i915_deps *deps)
3589fdbd
TH
162{
163 struct drm_i915_private *i915 = container_of(bo->bdev, typeof(*i915),
164 bdev);
165 struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
166 struct i915_request *rq;
167 struct ttm_tt *src_ttm = bo->ttm;
168 enum i915_cache_level src_level, dst_level;
169 int ret;
170
1a9c4db4 171 if (!to_gt(i915)->migrate.context || intel_gt_is_wedged(to_gt(i915)))
2b0a750c
TH
172 return ERR_PTR(-EINVAL);
173
174 /* With fail_gpu_migration, we always perform a GPU clear. */
175 if (I915_SELFTEST_ONLY(fail_gpu_migration))
176 clear = true;
3589fdbd
TH
177
178 dst_level = i915_ttm_cache_level(i915, dst_mem, dst_ttm);
179 if (clear) {
2b0a750c
TH
180 if (bo->type == ttm_bo_type_kernel &&
181 !I915_SELFTEST_ONLY(fail_gpu_migration))
182 return ERR_PTR(-EINVAL);
3589fdbd 183
1a9c4db4 184 intel_engine_pm_get(to_gt(i915)->migrate.context->engine);
11930817 185 ret = intel_context_migrate_clear(to_gt(i915)->migrate.context, deps,
3589fdbd
TH
186 dst_st->sgl, dst_level,
187 i915_ttm_gtt_binds_lmem(dst_mem),
188 0, &rq);
3589fdbd
TH
189 } else {
190 struct i915_refct_sgt *src_rsgt =
191 i915_ttm_resource_get_st(obj, bo->resource);
192
193 if (IS_ERR(src_rsgt))
2b0a750c 194 return ERR_CAST(src_rsgt);
3589fdbd
TH
195
196 src_level = i915_ttm_cache_level(i915, bo->resource, src_ttm);
1a9c4db4
MW
197 intel_engine_pm_get(to_gt(i915)->migrate.context->engine);
198 ret = intel_context_migrate_copy(to_gt(i915)->migrate.context,
11930817 199 deps, src_rsgt->table.sgl,
3589fdbd
TH
200 src_level,
201 i915_ttm_gtt_binds_lmem(bo->resource),
202 dst_st->sgl, dst_level,
203 i915_ttm_gtt_binds_lmem(dst_mem),
204 &rq);
2b0a750c 205
3589fdbd 206 i915_refct_sgt_put(src_rsgt);
3589fdbd
TH
207 }
208
1a9c4db4 209 intel_engine_pm_put(to_gt(i915)->migrate.context->engine);
2b0a750c
TH
210
211 if (ret && rq) {
212 i915_request_wait(rq, 0, MAX_SCHEDULE_TIMEOUT);
213 i915_request_put(rq);
214 }
215
216 return ret ? ERR_PTR(ret) : &rq->fence;
217}
218
219/**
220 * struct i915_ttm_memcpy_arg - argument for the bo memcpy functionality.
221 * @_dst_iter: Storage space for the destination kmap iterator.
222 * @_src_iter: Storage space for the source kmap iterator.
223 * @dst_iter: Pointer to the destination kmap iterator.
224 * @src_iter: Pointer to the source kmap iterator.
225 * @clear: Whether to clear instead of copy.
226 * @src_rsgt: Refcounted scatter-gather list of source memory.
227 * @dst_rsgt: Refcounted scatter-gather list of destination memory.
228 */
229struct i915_ttm_memcpy_arg {
230 union {
231 struct ttm_kmap_iter_tt tt;
232 struct ttm_kmap_iter_iomap io;
233 } _dst_iter,
234 _src_iter;
235 struct ttm_kmap_iter *dst_iter;
236 struct ttm_kmap_iter *src_iter;
237 unsigned long num_pages;
238 bool clear;
239 struct i915_refct_sgt *src_rsgt;
240 struct i915_refct_sgt *dst_rsgt;
241};
242
243/**
244 * struct i915_ttm_memcpy_work - Async memcpy worker under a dma-fence.
245 * @fence: The dma-fence.
246 * @work: The work struct use for the memcpy work.
247 * @lock: The fence lock. Not used to protect anything else ATM.
248 * @irq_work: Low latency worker to signal the fence since it can't be done
249 * from the callback for lockdep reasons.
250 * @cb: Callback for the accelerated migration fence.
251 * @arg: The argument for the memcpy functionality.
252 */
253struct i915_ttm_memcpy_work {
254 struct dma_fence fence;
255 struct work_struct work;
256 /* The fence lock */
257 spinlock_t lock;
258 struct irq_work irq_work;
259 struct dma_fence_cb cb;
260 struct i915_ttm_memcpy_arg arg;
261};
262
263static void i915_ttm_move_memcpy(struct i915_ttm_memcpy_arg *arg)
264{
265 ttm_move_memcpy(arg->clear, arg->num_pages,
266 arg->dst_iter, arg->src_iter);
267}
268
269static void i915_ttm_memcpy_init(struct i915_ttm_memcpy_arg *arg,
270 struct ttm_buffer_object *bo, bool clear,
271 struct ttm_resource *dst_mem,
272 struct ttm_tt *dst_ttm,
273 struct i915_refct_sgt *dst_rsgt)
274{
275 struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
276 struct intel_memory_region *dst_reg, *src_reg;
277
278 dst_reg = i915_ttm_region(bo->bdev, dst_mem->mem_type);
279 src_reg = i915_ttm_region(bo->bdev, bo->resource->mem_type);
280 GEM_BUG_ON(!dst_reg || !src_reg);
281
282 arg->dst_iter = !i915_ttm_cpu_maps_iomem(dst_mem) ?
283 ttm_kmap_iter_tt_init(&arg->_dst_iter.tt, dst_ttm) :
284 ttm_kmap_iter_iomap_init(&arg->_dst_iter.io, &dst_reg->iomap,
285 &dst_rsgt->table, dst_reg->region.start);
286
287 arg->src_iter = !i915_ttm_cpu_maps_iomem(bo->resource) ?
288 ttm_kmap_iter_tt_init(&arg->_src_iter.tt, bo->ttm) :
289 ttm_kmap_iter_iomap_init(&arg->_src_iter.io, &src_reg->iomap,
290 &obj->ttm.cached_io_rsgt->table,
291 src_reg->region.start);
292 arg->clear = clear;
293 arg->num_pages = bo->base.size >> PAGE_SHIFT;
294
295 arg->dst_rsgt = i915_refct_sgt_get(dst_rsgt);
296 arg->src_rsgt = clear ? NULL :
297 i915_ttm_resource_get_st(obj, bo->resource);
298}
299
300static void i915_ttm_memcpy_release(struct i915_ttm_memcpy_arg *arg)
301{
302 i915_refct_sgt_put(arg->src_rsgt);
303 i915_refct_sgt_put(arg->dst_rsgt);
304}
305
306static void __memcpy_work(struct work_struct *work)
307{
308 struct i915_ttm_memcpy_work *copy_work =
309 container_of(work, typeof(*copy_work), work);
310 struct i915_ttm_memcpy_arg *arg = &copy_work->arg;
311 bool cookie = dma_fence_begin_signalling();
312
313 i915_ttm_move_memcpy(arg);
314 dma_fence_end_signalling(cookie);
315
316 dma_fence_signal(&copy_work->fence);
317
318 i915_ttm_memcpy_release(arg);
319 dma_fence_put(&copy_work->fence);
320}
321
322static void __memcpy_irq_work(struct irq_work *irq_work)
323{
324 struct i915_ttm_memcpy_work *copy_work =
325 container_of(irq_work, typeof(*copy_work), irq_work);
326 struct i915_ttm_memcpy_arg *arg = &copy_work->arg;
327
328 dma_fence_signal(&copy_work->fence);
329 i915_ttm_memcpy_release(arg);
330 dma_fence_put(&copy_work->fence);
331}
332
333static void __memcpy_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
334{
335 struct i915_ttm_memcpy_work *copy_work =
336 container_of(cb, typeof(*copy_work), cb);
337
338 if (unlikely(fence->error || I915_SELFTEST_ONLY(fail_gpu_migration))) {
339 INIT_WORK(&copy_work->work, __memcpy_work);
340 queue_work(system_unbound_wq, &copy_work->work);
341 } else {
342 init_irq_work(&copy_work->irq_work, __memcpy_irq_work);
343 irq_work_queue(&copy_work->irq_work);
344 }
345}
346
347static const char *get_driver_name(struct dma_fence *fence)
348{
349 return "i915_ttm_memcpy_work";
350}
351
352static const char *get_timeline_name(struct dma_fence *fence)
353{
354 return "unbound";
355}
356
357static const struct dma_fence_ops dma_fence_memcpy_ops = {
358 .get_driver_name = get_driver_name,
359 .get_timeline_name = get_timeline_name,
360};
361
362static struct dma_fence *
363i915_ttm_memcpy_work_arm(struct i915_ttm_memcpy_work *work,
364 struct dma_fence *dep)
365{
366 int ret;
367
368 spin_lock_init(&work->lock);
369 dma_fence_init(&work->fence, &dma_fence_memcpy_ops, &work->lock, 0, 0);
370 dma_fence_get(&work->fence);
371 ret = dma_fence_add_callback(dep, &work->cb, __memcpy_cb);
372 if (ret) {
373 if (ret != -ENOENT)
374 dma_fence_wait(dep, false);
375
376 return ERR_PTR(I915_SELFTEST_ONLY(fail_gpu_migration) ? -EINVAL :
377 dep->error);
378 }
379
380 return &work->fence;
3589fdbd
TH
381}
382
6385eb7a 383static struct dma_fence *
11930817
TH
384__i915_ttm_move(struct ttm_buffer_object *bo,
385 const struct ttm_operation_ctx *ctx, bool clear,
6385eb7a
TH
386 struct ttm_resource *dst_mem, struct ttm_tt *dst_ttm,
387 struct i915_refct_sgt *dst_rsgt, bool allow_accel,
11930817 388 const struct i915_deps *move_deps)
3589fdbd 389{
2b0a750c
TH
390 struct i915_ttm_memcpy_work *copy_work = NULL;
391 struct i915_ttm_memcpy_arg _arg, *arg = &_arg;
392 struct dma_fence *fence = ERR_PTR(-EINVAL);
393
394 if (allow_accel) {
395 fence = i915_ttm_accel_move(bo, clear, dst_mem, dst_ttm,
11930817 396 &dst_rsgt->table, move_deps);
2b0a750c
TH
397
398 /*
399 * We only need to intercept the error when moving to lmem.
400 * When moving to system, TTM or shmem will provide us with
401 * cleared pages.
402 */
403 if (!IS_ERR(fence) && !i915_ttm_gtt_binds_lmem(dst_mem) &&
404 !I915_SELFTEST_ONLY(fail_gpu_migration ||
405 fail_work_allocation))
406 goto out;
407 }
3589fdbd 408
2b0a750c
TH
409 /* If we've scheduled gpu migration. Try to arm error intercept. */
410 if (!IS_ERR(fence)) {
411 struct dma_fence *dep = fence;
412
413 if (!I915_SELFTEST_ONLY(fail_work_allocation))
414 copy_work = kzalloc(sizeof(*copy_work), GFP_KERNEL);
415
416 if (copy_work) {
417 arg = &copy_work->arg;
418 i915_ttm_memcpy_init(arg, bo, clear, dst_mem, dst_ttm,
419 dst_rsgt);
420 fence = i915_ttm_memcpy_work_arm(copy_work, dep);
421 } else {
422 dma_fence_wait(dep, false);
423 fence = ERR_PTR(I915_SELFTEST_ONLY(fail_gpu_migration) ?
424 -EINVAL : fence->error);
425 }
426 dma_fence_put(dep);
427
428 if (!IS_ERR(fence))
429 goto out;
3526b607
TH
430 } else {
431 int err = PTR_ERR(fence);
432
433 if (err == -EINTR || err == -ERESTARTSYS || err == -EAGAIN)
434 return fence;
6385eb7a 435
3526b607
TH
436 if (move_deps) {
437 err = i915_deps_sync(move_deps, ctx);
438 if (err)
439 return ERR_PTR(err);
440 }
2b0a750c
TH
441 }
442
443 /* Error intercept failed or no accelerated migration to start with */
444 if (!copy_work)
445 i915_ttm_memcpy_init(arg, bo, clear, dst_mem, dst_ttm,
446 dst_rsgt);
447 i915_ttm_move_memcpy(arg);
448 i915_ttm_memcpy_release(arg);
449 kfree(copy_work);
450
6385eb7a 451 return NULL;
2b0a750c 452out:
6385eb7a 453 if (!fence && copy_work) {
2b0a750c
TH
454 i915_ttm_memcpy_release(arg);
455 kfree(copy_work);
3589fdbd 456 }
6385eb7a
TH
457
458 return fence;
459}
460
11930817
TH
461static int
462prev_deps(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx,
463 struct i915_deps *deps)
6385eb7a 464{
6385eb7a
TH
465 int ret;
466
11930817 467 ret = i915_deps_add_dependency(deps, bo->moving, ctx);
6385eb7a 468 if (!ret)
33654ef4 469 ret = i915_deps_add_resv(deps, bo->base.resv, ctx);
6385eb7a 470
11930817 471 return ret;
3589fdbd
TH
472}
473
474/**
475 * i915_ttm_move - The TTM move callback used by i915.
476 * @bo: The buffer object.
477 * @evict: Whether this is an eviction.
478 * @dst_mem: The destination ttm resource.
479 * @hop: If we need multihop, what temporary memory type to move to.
480 *
481 * Return: 0 if successful, negative error code otherwise.
482 */
483int i915_ttm_move(struct ttm_buffer_object *bo, bool evict,
484 struct ttm_operation_ctx *ctx,
485 struct ttm_resource *dst_mem,
486 struct ttm_place *hop)
487{
488 struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
489 struct ttm_resource_manager *dst_man =
490 ttm_manager_type(bo->bdev, dst_mem->mem_type);
6385eb7a 491 struct dma_fence *migration_fence = NULL;
3589fdbd
TH
492 struct ttm_tt *ttm = bo->ttm;
493 struct i915_refct_sgt *dst_rsgt;
494 bool clear;
495 int ret;
496
6385eb7a
TH
497 if (GEM_WARN_ON(!obj)) {
498 ttm_bo_move_null(bo, dst_mem);
499 return 0;
500 }
3589fdbd
TH
501
502 ret = i915_ttm_move_notify(bo);
503 if (ret)
504 return ret;
505
506 if (obj->mm.madv != I915_MADV_WILLNEED) {
507 i915_ttm_purge(obj);
508 ttm_resource_free(bo, &dst_mem);
509 return 0;
510 }
511
512 /* Populate ttm with pages if needed. Typically system memory. */
513 if (ttm && (dst_man->use_tt || (ttm->page_flags & TTM_TT_FLAG_SWAPPED))) {
514 ret = ttm_tt_populate(bo->bdev, ttm, ctx);
515 if (ret)
516 return ret;
517 }
518
519 dst_rsgt = i915_ttm_resource_get_st(obj, dst_mem);
520 if (IS_ERR(dst_rsgt))
521 return PTR_ERR(dst_rsgt);
522
523 clear = !i915_ttm_cpu_maps_iomem(bo->resource) && (!ttm || !ttm_tt_is_populated(ttm));
6385eb7a 524 if (!(clear && ttm && !(ttm->page_flags & TTM_TT_FLAG_ZERO_ALLOC))) {
11930817 525 struct i915_deps deps;
6385eb7a 526
11930817
TH
527 i915_deps_init(&deps, GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN);
528 ret = prev_deps(bo, ctx, &deps);
529 if (ret) {
6385eb7a 530 i915_refct_sgt_put(dst_rsgt);
11930817 531 return ret;
6385eb7a
TH
532 }
533
11930817
TH
534 migration_fence = __i915_ttm_move(bo, ctx, clear, dst_mem, bo->ttm,
535 dst_rsgt, true, &deps);
536 i915_deps_fini(&deps);
6385eb7a
TH
537 }
538
539 /* We can possibly get an -ERESTARTSYS here */
540 if (IS_ERR(migration_fence)) {
541 i915_refct_sgt_put(dst_rsgt);
542 return PTR_ERR(migration_fence);
543 }
544
545 if (migration_fence) {
546 ret = ttm_bo_move_accel_cleanup(bo, migration_fence, evict,
547 true, dst_mem);
548 if (ret) {
549 dma_fence_wait(migration_fence, false);
550 ttm_bo_move_sync_cleanup(bo, dst_mem);
551 }
552 dma_fence_put(migration_fence);
553 } else {
554 ttm_bo_move_sync_cleanup(bo, dst_mem);
555 }
3589fdbd 556
3589fdbd
TH
557 i915_ttm_adjust_domains_after_move(obj);
558 i915_ttm_free_cached_io_rsgt(obj);
559
560 if (i915_ttm_gtt_binds_lmem(dst_mem) || i915_ttm_cpu_maps_iomem(dst_mem)) {
561 obj->ttm.cached_io_rsgt = dst_rsgt;
562 obj->ttm.get_io_page.sg_pos = dst_rsgt->table.sgl;
563 obj->ttm.get_io_page.sg_idx = 0;
564 } else {
565 i915_refct_sgt_put(dst_rsgt);
566 }
567
568 i915_ttm_adjust_lru(obj);
569 i915_ttm_adjust_gem_after_move(obj);
570 return 0;
571}
05d1c761
TH
572
573/**
574 * i915_gem_obj_copy_ttm - Copy the contents of one ttm-based gem object to
575 * another
576 * @dst: The destination object
577 * @src: The source object
578 * @allow_accel: Allow using the blitter. Otherwise TTM memcpy is used.
579 * @intr: Whether to perform waits interruptible:
580 *
581 * Note: The caller is responsible for assuring that the underlying
582 * TTM objects are populated if needed and locked.
583 *
584 * Return: Zero on success. Negative error code on error. If @intr == true,
585 * then it may return -ERESTARTSYS or -EINTR.
586 */
587int i915_gem_obj_copy_ttm(struct drm_i915_gem_object *dst,
588 struct drm_i915_gem_object *src,
589 bool allow_accel, bool intr)
590{
591 struct ttm_buffer_object *dst_bo = i915_gem_to_ttm(dst);
592 struct ttm_buffer_object *src_bo = i915_gem_to_ttm(src);
593 struct ttm_operation_ctx ctx = {
594 .interruptible = intr,
595 };
596 struct i915_refct_sgt *dst_rsgt;
11930817 597 struct dma_fence *copy_fence;
5652df82 598 struct i915_deps deps;
33654ef4 599 int ret;
05d1c761
TH
600
601 assert_object_held(dst);
602 assert_object_held(src);
5652df82 603 i915_deps_init(&deps, GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN);
05d1c761 604
33654ef4
CK
605 ret = dma_resv_reserve_shared(src_bo->base.resv, 1);
606 if (ret)
607 return ret;
608
609 ret = i915_deps_add_resv(&deps, dst_bo->base.resv, &ctx);
610 if (ret)
611 return ret;
612
613 ret = i915_deps_add_resv(&deps, src_bo->base.resv, &ctx);
05d1c761
TH
614 if (ret)
615 return ret;
616
617 dst_rsgt = i915_ttm_resource_get_st(dst, dst_bo->resource);
11930817 618 copy_fence = __i915_ttm_move(src_bo, &ctx, false, dst_bo->resource,
5652df82 619 dst_bo->ttm, dst_rsgt, allow_accel,
11930817 620 &deps);
05d1c761 621
11930817 622 i915_deps_fini(&deps);
05d1c761 623 i915_refct_sgt_put(dst_rsgt);
5652df82
TH
624 if (IS_ERR_OR_NULL(copy_fence))
625 return PTR_ERR_OR_ZERO(copy_fence);
6385eb7a 626
5652df82 627 dma_resv_add_excl_fence(dst_bo->base.resv, copy_fence);
33654ef4 628 dma_resv_add_shared_fence(src_bo->base.resv, copy_fence);
5652df82
TH
629
630 dma_fence_put(copy_fence);
05d1c761
TH
631
632 return 0;
633}