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.

v2: rebased on top of Thomas work
v3: rebased again
v4: rebased, fixed locks of already-reserved buffers being dropped

Signed-off-by: Christian König <[email protected]>
Signed-off-by: Natalie Vock <[email protected]>
---
 drivers/gpu/drm/ttm/ttm_bo_util.c | 30 ++++++++++++++++++++++--------
 include/drm/ttm/ttm_bo.h          |  5 +++++
 2 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c 
b/drivers/gpu/drm/ttm/ttm_bo_util.c
index a53b25e8c2967..96699532817c2 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -38,6 +38,7 @@
 #include <drm/ttm/ttm_tt.h>
 
 #include <drm/drm_cache.h>
+#include <drm/drm_exec.h>
 
 #include "ttm_bo_internal.h"
 
@@ -837,6 +838,8 @@ static bool ttm_lru_walk_trylock(struct ttm_bo_lru_cursor 
*curs,
        struct ttm_operation_ctx *ctx = curs->arg->ctx;
 
        curs->needs_unlock = false;
+       if (ctx->exec)
+               return false;
 
        if (dma_resv_trylock(bo->base.resv)) {
                curs->needs_unlock = true;
@@ -857,7 +860,9 @@ static int ttm_lru_walk_ticketlock(struct ttm_bo_lru_cursor 
*curs,
        struct ttm_lru_walk_arg *arg = curs->arg;
        int ret;
 
-       if (arg->ctx->interruptible)
+       if (arg->ctx->exec)
+               ret = drm_exec_lock_obj_report_dup(arg->ctx->exec, &bo->base);
+       else if (arg->ctx->interruptible)
                ret = dma_resv_lock_interruptible(bo->base.resv, arg->ticket);
        else
                ret = dma_resv_lock(bo->base.resv, arg->ticket);
@@ -871,7 +876,11 @@ static int ttm_lru_walk_ticketlock(struct 
ttm_bo_lru_cursor *curs,
                 * trylocking for this walk.
                 */
                arg->ticket = NULL;
-       } else if (ret == -EDEADLK) {
+
+       } else if (arg->ctx->exec && arg->ctx->allow_res_evict &&
+                  ret == -EALREADY) {
+               ret = 0;
+       } else if (!arg->ctx->exec && ret == -EDEADLK) {
                /* Caller needs to exit the ww transaction. */
                ret = -ENOSPC;
        }
@@ -937,12 +946,17 @@ static void ttm_bo_lru_cursor_cleanup_bo(struct 
ttm_bo_lru_cursor *curs)
 {
        struct ttm_buffer_object *bo = curs->bo;
 
-       if (bo) {
-               if (curs->needs_unlock)
+       if (!bo)
+               return;
+
+       if (curs->needs_unlock) {
+               if (curs->arg->ctx->exec)
+                       drm_exec_unlock_obj(curs->arg->ctx->exec, &bo->base);
+               else
                        dma_resv_unlock(bo->base.resv);
-               ttm_bo_put(bo);
-               curs->bo = NULL;
        }
+       ttm_bo_put(bo);
+       curs->bo = NULL;
 }
 
 /**
@@ -1016,8 +1030,8 @@ __ttm_bo_lru_cursor_next(struct ttm_bo_lru_cursor *curs)
                if (ttm_lru_walk_trylock(curs, bo)) {
                        bo_locked = true;
 
-               } else if (!arg->ticket || arg->ctx->no_wait_gpu ||
-                          arg->trylock_only) {
+               } else if ((!arg->ticket || arg->ctx->no_wait_gpu ||
+                           arg->trylock_only) && !arg->ctx->exec) {
                        spin_unlock(lru_lock);
                        ttm_bo_put(bo);
                        spin_lock(lru_lock);
diff --git a/include/drm/ttm/ttm_bo.h b/include/drm/ttm/ttm_bo.h
index a4060e44d23d0..156444b5e85d8 100644
--- a/include/drm/ttm/ttm_bo.h
+++ b/include/drm/ttm/ttm_bo.h
@@ -187,6 +187,11 @@ struct ttm_operation_ctx {
         * @bytes_moved: Statistics on how many bytes have been moved.
         */
        uint64_t bytes_moved;
+       /**
+        * @exec: optional drm_exec object to use for locking BOs and
+        * tracking which are locked.
+        */
+       struct drm_exec *exec;
 };
 
 /**

-- 
2.55.0

Reply via email to