diff mbox series

[4/5] drm/ttm: support using drm_exec during eviction

Message ID 20240703132602.4756-5-christian.koenig@amd.com (mailing list archive)
State New, archived
Headers show
Series [1/5] dma-buf/dma-resv: Introduce dma_resv_trylock_ctx() | expand

Commit Message

Christian König July 3, 2024, 1:26 p.m. UTC
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(-)
diff mbox series

Patch

diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 6396dece0db1..785763405b87 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -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;
 }
diff --git a/include/drm/ttm/ttm_bo.h b/include/drm/ttm/ttm_bo.h
index ef0f52f56ebc..b9e598ee13d2 100644
--- a/include/drm/ttm/ttm_bo.h
+++ b/include/drm/ttm/ttm_bo.h
@@ -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;
 };
 
 /**