@@ -31,6 +31,8 @@
#define pr_fmt(fmt) "[TTM] " fmt
+#include <drm/drm_exec.h>
+
#include <drm/ttm/ttm_bo.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_tt.h>
@@ -529,13 +531,21 @@ static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,
return false;
}
- if (bo->base.resv == ctx->resv) {
+ if (ctx->exec) {
+ ret = drm_exec_trylock_obj(ctx->exec, &bo->base);
+
+ *locked = false;
+ if (!ret && busy)
+ *busy = true;
+
+ } else if (bo->base.resv == ctx->resv) {
dma_resv_assert_held(bo->base.resv);
if (ctx->allow_res_evict)
ret = true;
*locked = false;
if (busy)
*busy = false;
+
} else {
ret = dma_resv_trylock(bo->base.resv);
*locked = ret;
@@ -545,11 +555,13 @@ static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,
if (ret && place && (bo->resource->mem_type != place->mem_type ||
!bo->bdev->funcs->eviction_valuable(bo, place))) {
- ret = false;
- if (*locked) {
+
+ if (ctx->exec)
+ drm_exec_drop_trylocked_obj(ctx->exec, &bo->base);
+ else if (*locked)
dma_resv_unlock(bo->base.resv);
- *locked = false;
- }
+ ret = false;
+ *locked = false;
}
return ret;
@@ -573,21 +585,32 @@ static int ttm_mem_evict_wait_busy(struct ttm_buffer_object *busy_bo,
if (!busy_bo || !ticket)
return -EBUSY;
- if (ctx->interruptible)
+ if (ctx->exec)
+ r = drm_exec_lock_obj(ctx->exec, &busy_bo->base);
+
+ else if (ctx->interruptible)
r = dma_resv_lock_interruptible(busy_bo->base.resv,
ticket);
else
r = dma_resv_lock(busy_bo->base.resv, ticket);
+ if (!ctx->exec && r == -EDEADLK)
+ r = -EBUSY;
+
+ if (r)
+ return r;
+
/*
* TODO: It would be better to keep the BO locked until allocation is at
* least tried one more time, but that would mean a much larger rework
* of TTM.
*/
- if (!r)
+ if (ctx->exec)
+ drm_exec_unlock_obj(ctx->exec, &busy_bo->base);
+ else
dma_resv_unlock(busy_bo->base.resv);
- return r == -EDEADLK ? -EBUSY : r;
+ return 0;
}
int ttm_mem_evict_first(struct ttm_device *bdev,
@@ -618,7 +641,10 @@ int ttm_mem_evict_first(struct ttm_device *bdev,
bo = res->bo;
break;
}
- if (locked)
+
+ if (ctx->exec)
+ drm_exec_drop_trylocked_obj(ctx->exec, &bo->base);
+ else if (locked)
dma_resv_unlock(res->bo->base.resv);
}
@@ -635,18 +661,30 @@ int ttm_mem_evict_first(struct ttm_device *bdev,
if (bo->deleted) {
ret = ttm_bo_cleanup_refs(bo, ctx->interruptible,
ctx->no_wait_gpu, locked);
+ if (ctx->exec)
+ drm_exec_drop_trylocked_obj(ctx->exec, &bo->base);
+
ttm_bo_put(bo);
return ret;
}
spin_unlock(&bdev->lru_lock);
+ if (ctx->exec) {
+ ret = drm_exec_keep_trylocked_obj(ctx->exec, &bo->base);
+ if (ret)
+ goto error_drop;
+ }
+
ret = ttm_bo_evict(bo, ctx);
- if (locked)
+ if (ctx->exec)
+ drm_exec_unlock_obj(ctx->exec, &bo->base);
+ else if (locked)
ttm_bo_unreserve(bo);
else
ttm_bo_move_to_lru_tail_unlocked(bo);
+error_drop:
ttm_bo_put(bo);
return ret;
}
@@ -1139,13 +1177,17 @@ int ttm_bo_swapout(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx,
bo->ttm->page_flags & TTM_TT_FLAG_EXTERNAL ||
bo->ttm->page_flags & TTM_TT_FLAG_SWAPPED ||
!ttm_bo_get_unless_zero(bo)) {
- if (locked)
+ if (ctx->exec)
+ drm_exec_drop_trylocked_obj(ctx->exec, &bo->base);
+ else if (locked)
dma_resv_unlock(bo->base.resv);
return -EBUSY;
}
if (bo->deleted) {
ret = ttm_bo_cleanup_refs(bo, false, false, locked);
+ if (ctx->exec)
+ drm_exec_drop_trylocked_obj(ctx->exec, &bo->base);
ttm_bo_put(bo);
return ret == -EBUSY ? -ENOSPC : ret;
}
@@ -1193,13 +1235,10 @@ int ttm_bo_swapout(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx,
if (ttm_tt_is_populated(bo->ttm))
ret = ttm_tt_swapout(bo->bdev, bo->ttm, gfp_flags);
out:
-
- /*
- * Unreserve without putting on LRU to avoid swapping out an
- * already swapped buffer.
- */
- if (locked)
- dma_resv_unlock(bo->base.resv);
+ if (ctx->exec)
+ drm_exec_drop_trylocked_obj(ctx->exec, &bo->base);
+ else if (locked)
+ ttm_bo_unreserve(bo);
ttm_bo_put(bo);
return ret == -EBUSY ? -ENOSPC : ret;
}
@@ -180,6 +180,8 @@ struct ttm_bo_kmap_obj {
* faults. Should only be used by TTM internally.
* @resv: Reservation object to allow reserved evictions with.
* @bytes_moved: Statistics on how many bytes have been moved.
+ * @exec: optional drm_exec object to use for locking BOs and tracking which are
+ * locked.
*
* Context for TTM operations like changing buffer placement or general memory
* allocation.
@@ -192,6 +194,7 @@ struct ttm_operation_ctx {
bool force_alloc;
struct dma_resv *resv;
uint64_t bytes_moved;
+ struct drm_exec *exec;
};
/**
Allow specifying a drm_exec object in TTMs operation context which is used to lock objects during eviction. This allows to handle deadlocks much more gracefully and with that avoid returning -ENOMEM on heavily contended domains. Signed-off-by: Christian König <christian.koenig@amd.com> --- drivers/gpu/drm/ttm/ttm_bo.c | 75 +++++++++++++++++++++++++++--------- include/drm/ttm/ttm_bo.h | 3 ++ 2 files changed, 60 insertions(+), 18 deletions(-)