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.koe...@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 --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;
 };
 
 /**
-- 
2.34.1

Reply via email to