+
+ for (i = 0; i < deps->num_deps; ++i, ++fences) {
+ if (ctx->no_wait_gpu) {
+ ret = -EBUSY;
+ goto unref;
+ }
+
+ ret = dma_fence_wait(*fences, ctx->interruptible);
+ if (ret)
+ goto unref;
+
+ ret = (*fences)->error;
+ if (ret)
+ goto unref;
+ }
+
+ i915_deps_fini(deps);
+ return 0;
+
+unref:
+ i915_deps_fini(deps);
+ return ret;
+}
+
+static int i915_deps_add_dependency(struct i915_deps *deps,
+ struct dma_fence *fence,
+ const struct ttm_operation_ctx *ctx)
+{
+ unsigned int i;
+ int ret;
+
+ if (!fence)
+ return 0;
+
+ if (dma_fence_is_signaled(fence)) {
+ ret = fence->error;
+ if (ret)
+ i915_deps_fini(deps);
+ return ret;
+ }
+
+ for (i = 0; i < deps->num_deps; ++i) {
+ struct dma_fence *entry = deps->fences[i];
+
+ if (!entry->context || entry->context != fence->context)
+ continue;
+
+ if (dma_fence_is_later(fence, entry)) {
+ dma_fence_put(entry);
+ deps->fences[i] = dma_fence_get(fence);
+ }
+
+ return 0;
+ }
+
+ return i915_deps_grow(deps, fence, ctx);
+}
+
+static struct dma_fence *i915_deps_to_fence(struct i915_deps *deps,
+ const struct ttm_operation_ctx *ctx)
+{
+ struct dma_fence_array *array;
+
+ if (deps->num_deps == 0)
+ return NULL;
+
+ if (deps->num_deps == 1) {
+ deps->num_deps = 0;
+ return deps->fences[0];
+ }
+
+ /*
+ * TODO: Alter the allocation mode here to not try too hard to
+ * make things async.
+ */
+ array = dma_fence_array_create(deps->num_deps, deps->fences, 0, 0,
+ false);
+ if (!array)
+ return ERR_PTR(i915_deps_sync(deps, ctx));
+
+ deps->fences = NULL;
+ i915_deps_reset_fences(deps);
+
+ return &array->base;
+}
+
+static int i915_deps_add_resv(struct i915_deps *deps, struct dma_resv *resv,
+ bool all, const bool no_excl,
+ const struct ttm_operation_ctx *ctx)
+{
+ struct dma_resv_iter iter;
+ struct dma_fence *fence;
+
+ dma_resv_assert_held(resv);
+ dma_resv_for_each_fence(&iter, resv, all, fence) {
+ int ret;
+
+ if (no_excl && !iter.index)
+ continue;
+
+ ret = i915_deps_add_dependency(deps, fence, ctx);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static enum i915_cache_level
i915_ttm_cache_level(struct drm_i915_private *i915, struct ttm_resource *res,
struct ttm_tt *ttm)
@@ -156,7 +380,8 @@ static struct dma_fence *i915_ttm_accel_move(struct ttm_buffer_object *bo,
bool clear,
struct ttm_resource *dst_mem,
struct ttm_tt *dst_ttm,
- struct sg_table *dst_st)
+ struct sg_table *dst_st,
+ struct dma_fence *dep)
{
struct drm_i915_private *i915 = container_of(bo->bdev, typeof(*i915),
bdev);
@@ -180,7 +405,7 @@ static struct dma_fence *i915_ttm_accel_move(struct ttm_buffer_object *bo,
return ERR_PTR(-EINVAL);
intel_engine_pm_get(i915->gt.migrate.context->engine);
- ret = intel_context_migrate_clear(i915->gt.migrate.context, NULL,
+ ret = intel_context_migrate_clear(i915->gt.migrate.context, dep,
dst_st->sgl, dst_level,
i915_ttm_gtt_binds_lmem(dst_mem),
0, &rq);
@@ -194,7 +419,7 @@ static struct dma_fence *i915_ttm_accel_move(struct ttm_buffer_object *bo,
src_level = i915_ttm_cache_level(i915, bo->resource, src_ttm);
intel_engine_pm_get(i915->gt.migrate.context->engine);
ret = intel_context_migrate_copy(i915->gt.migrate.context,
- NULL, src_rsgt->table.sgl,
+ dep, src_rsgt->table.sgl,
src_level,
i915_ttm_gtt_binds_lmem(bo->resource),
dst_st->sgl, dst_level,
@@ -378,10 +603,11 @@ i915_ttm_memcpy_work_arm(struct i915_ttm_memcpy_work *work,
return &work->fence;
}
-static void __i915_ttm_move(struct ttm_buffer_object *bo, bool clear,
- struct ttm_resource *dst_mem,
- struct ttm_tt *dst_ttm,
- struct i915_refct_sgt *dst_rsgt, bool allow_accel)
+static struct dma_fence *
+__i915_ttm_move(struct ttm_buffer_object *bo, bool clear,
+ struct ttm_resource *dst_mem, struct ttm_tt *dst_ttm,
+ struct i915_refct_sgt *dst_rsgt, bool allow_accel,
+ struct dma_fence *move_dep)
{
struct i915_ttm_memcpy_work *copy_work = NULL;
struct i915_ttm_memcpy_arg _arg, *arg = &_arg;
@@ -389,7 +615,7 @@ static void __i915_ttm_move(struct ttm_buffer_object *bo, bool clear,
if (allow_accel) {
fence = i915_ttm_accel_move(bo, clear, dst_mem, dst_ttm,
- &dst_rsgt->table);
+ &dst_rsgt->table, move_dep);
/*
* We only need to intercept the error when moving to lmem.
@@ -423,6 +649,11 @@ static void __i915_ttm_move(struct ttm_buffer_object *bo, bool clear,
if (!IS_ERR(fence))
goto out;
+ } else if (move_dep) {
+ int err = dma_fence_wait(move_dep, true);
+
+ if (err)
+ return ERR_PTR(err);
}
/* Error intercept failed or no accelerated migration to start with */
@@ -433,16 +664,35 @@ static void __i915_ttm_move(struct ttm_buffer_object *bo, bool clear,
i915_ttm_memcpy_release(arg);
kfree(copy_work);
- return;
+ return NULL;
out:
- /* Sync here for now, forward the fence to caller when fully async. */
- if (fence) {
- dma_fence_wait(fence, false);
- dma_fence_put(fence);
- } else if (copy_work) {
+ if (!fence && copy_work) {
i915_ttm_memcpy_release(arg);
kfree(copy_work);
}
+
+ return fence;
+}
+
+static struct dma_fence *prev_fence(struct ttm_buffer_object *bo,
+ struct ttm_operation_ctx *ctx)
+{
+ struct i915_deps deps;
+ int ret;
+
+ /*
+ * Instead of trying hard with GFP_KERNEL to allocate memory,
+ * the dependency collection will just sync if it doesn't
+ * succeed.
+ */
+ i915_deps_init(&deps, GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN);
+ ret = i915_deps_add_dependency(&deps, bo->moving, ctx);
+ if (!ret)
+ ret = i915_deps_add_resv(&deps, bo->base.resv, false, false, ctx);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return i915_deps_to_fence(&deps, ctx);
}
/**
@@ -462,16 +712,12 @@ int i915_ttm_move(struct ttm_buffer_object *bo, bool evict,
struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
struct ttm_resource_manager *dst_man =
ttm_manager_type(bo->bdev, dst_mem->mem_type);
+ struct dma_fence *migration_fence = NULL;
struct ttm_tt *ttm = bo->ttm;
struct i915_refct_sgt *dst_rsgt;
bool clear;
int ret;
- /* Sync for now. We could do the actual copy async. */
- ret = ttm_bo_wait_ctx(bo, ctx);
- if (ret)
- return ret;
-
ret = i915_ttm_move_notify(bo);
if (ret)
return ret;
@@ -494,10 +740,37 @@ int i915_ttm_move(struct ttm_buffer_object *bo, bool evict,
return PTR_ERR(dst_rsgt);
clear = !i915_ttm_cpu_maps_iomem(bo->resource) && (!ttm || !ttm_tt_is_populated(ttm));
- if (!(clear && ttm && !(ttm->page_flags & TTM_TT_FLAG_ZERO_ALLOC)))
- __i915_ttm_move(bo, clear, dst_mem, bo->ttm, dst_rsgt, true);
+ if (!(clear && ttm && !(ttm->page_flags & TTM_TT_FLAG_ZERO_ALLOC))) {
+ struct dma_fence *dep = prev_fence(bo, ctx);
+
+ if (IS_ERR(dep)) {
+ i915_refct_sgt_put(dst_rsgt);
+ return PTR_ERR(dep);
+ }
+
+ migration_fence = __i915_ttm_move(bo, clear, dst_mem, bo->ttm,
+ dst_rsgt, true, dep);
+ dma_fence_put(dep);
+ }
+
+ /* We can possibly get an -ERESTARTSYS here */
+ if (IS_ERR(migration_fence)) {
+ i915_refct_sgt_put(dst_rsgt);
+ return PTR_ERR(migration_fence);
+ }
+
+ if (migration_fence) {
+ ret = ttm_bo_move_accel_cleanup(bo, migration_fence, evict,
+ true, dst_mem);
+ if (ret) {
+ dma_fence_wait(migration_fence, false);
+ ttm_bo_move_sync_cleanup(bo, dst_mem);
+ }
+ dma_fence_put(migration_fence);
+ } else {
+ ttm_bo_move_sync_cleanup(bo, dst_mem);
+ }
- ttm_bo_move_sync_cleanup(bo, dst_mem);
i915_ttm_adjust_domains_after_move(obj);
i915_ttm_free_cached_io_rsgt(obj);
@@ -538,6 +811,7 @@ int i915_gem_obj_copy_ttm(struct drm_i915_gem_object *dst,
.interruptible = intr,
};
struct i915_refct_sgt *dst_rsgt;
+ struct dma_fence *copy_fence;
int ret;
assert_object_held(dst);
@@ -553,10 +827,17 @@ int i915_gem_obj_copy_ttm(struct drm_i915_gem_object *dst,
return ret;
dst_rsgt = i915_ttm_resource_get_st(dst, dst_bo->resource);
- __i915_ttm_move(src_bo, false, dst_bo->resource, dst_bo->ttm,
- dst_rsgt, allow_accel);
+ copy_fence = __i915_ttm_move(src_bo, false, dst_bo->resource,
+ dst_bo->ttm, dst_rsgt, allow_accel, NULL);
i915_refct_sgt_put(dst_rsgt);
+ if (IS_ERR(copy_fence))
+ return PTR_ERR(copy_fence);
+
+ if (copy_fence) {
+ dma_fence_wait(copy_fence, false);
+ dma_fence_put(copy_fence);
+ }
return 0;
}
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_wait.c b/drivers/gpu/drm/i915/gem/i915_gem_wait.c
index f909aaa09d9c..bae65796a6cc 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_wait.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_wait.c
@@ -306,6 +306,6 @@ int i915_gem_object_wait_migration(struct drm_i915_gem_object *obj,
unsigned int flags)
{
might_sleep();
- /* NOP for now. */
- return 0;
+
+ return i915_gem_object_wait_moving_fence(obj, !!(flags & I915_WAIT_INTERRUPTIBLE));
}