Signed-off-by: Maarten Lankhorst <maarten.lankho...@linux.intel.com>
---
 drivers/gpu/drm/i915/gem/i915_gem_object.h   | 39 +++++++++++++++++++-
 drivers/gpu/drm/i915/gem/i915_gem_shrinker.c | 10 ++++-
 drivers/gpu/drm/i915/i915_gem.c              | 29 ++++++++++++++-
 drivers/gpu/drm/i915/i915_gem.h              |  5 ++-
 4 files changed, 78 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h 
b/drivers/gpu/drm/i915/gem/i915_gem_object.h
index f6ccd05010df..3cafe8985034 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h
@@ -126,12 +126,43 @@ static inline void assert_object_held_shared(struct 
drm_i915_gem_object *obj)
                assert_object_held(obj);
 }
 
+static inline int
+i915_gem_object_lock_to_evict(struct drm_i915_gem_object *obj,
+                             struct i915_gem_ww_ctx *ww)
+{
+       int ret;
+
+       if (ww->intr)
+               ret = dma_resv_lock_interruptible(obj->base.resv, &ww->ctx);
+       else
+               ret = dma_resv_lock(obj->base.resv, &ww->ctx);
+
+       if (!ret) {
+               list_add_tail(&obj->obj_link, &ww->eviction_list);
+               i915_gem_object_get(obj);
+       }
+
+       if (ret == -EALREADY &&
+           obj == list_first_entry(&ww->eviction_list, struct 
drm_i915_gem_object, obj_link))
+               ret = 0;
+
+       ww->evicting = true;
+
+       if (ret == -EDEADLK)
+               ww->contended = i915_gem_object_get(obj);
+
+       return ret;
+}
+
 static inline int __i915_gem_object_lock(struct drm_i915_gem_object *obj,
                                         struct i915_gem_ww_ctx *ww,
                                         bool intr)
 {
        int ret;
 
+       if (ww && GEM_WARN_ON(ww->evicting))
+               ww->evicting = false;
+
        if (intr)
                ret = dma_resv_lock_interruptible(obj->base.resv, ww ? &ww->ctx 
: NULL);
        else
@@ -139,8 +170,14 @@ static inline int __i915_gem_object_lock(struct 
drm_i915_gem_object *obj,
 
        if (!ret && ww)
                list_add_tail(&obj->obj_link, &ww->obj_list);
-       if (ret == -EALREADY)
+       if (ret == -EALREADY) {
                ret = 0;
+               if (obj == list_first_entry(&ww->eviction_list, struct 
drm_i915_gem_object, obj_link)) {
+                       i915_gem_object_put(obj);
+                       list_del(&obj->obj_link);
+                       list_add_tail(&obj->obj_link, &ww->obj_list);
+               }
+       }
 
        if (ret == -EDEADLK)
                ww->contended = obj;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c 
b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
index e42192834c88..075cdd7718c4 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
@@ -99,6 +99,7 @@ i915_gem_shrink(struct i915_gem_ww_ctx *ww,
                unsigned long *nr_scanned,
                unsigned int shrink)
 {
+       struct drm_i915_gem_object *obj;
        const struct {
                struct list_head *list;
                unsigned int bit;
@@ -163,7 +164,6 @@ i915_gem_shrink(struct i915_gem_ww_ctx *ww,
         */
        for (phase = phases; phase->list; phase++) {
                struct list_head still_in_list;
-               struct drm_i915_gem_object *obj;
                unsigned long flags;
 
                if ((shrink & phase->bit) == 0)
@@ -208,7 +208,11 @@ i915_gem_shrink(struct i915_gem_ww_ctx *ww,
                                        if (!i915_gem_object_trylock(obj))
                                                goto skip;
                                } else {
-                                       err = i915_gem_object_lock(obj, ww);
+                                       err = 
i915_gem_object_lock_to_evict(obj, ww);
+                                       if (err == -EALREADY) {
+                                               err = 0;
+                                               goto skip;
+                                       }
                                        if (err)
                                                goto skip;
                                }
@@ -234,6 +238,8 @@ i915_gem_shrink(struct i915_gem_ww_ctx *ww,
                if (err)
                        return err;
        }
+       if (ww)
+               i915_gem_ww_ctx_unlock_evictions(ww);
 
        if (shrink & I915_SHRINK_BOUND)
                intel_runtime_pm_put(&i915->runtime_pm, wakeref);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 5a497576614c..4f6fcdae1457 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1370,10 +1370,25 @@ void i915_gem_ww_ctx_init(struct i915_gem_ww_ctx *ww, 
bool intr)
 {
        ww_acquire_init(&ww->ctx, &reservation_ww_class);
        INIT_LIST_HEAD(&ww->obj_list);
+       INIT_LIST_HEAD(&ww->eviction_list);
        ww->intr = intr;
+       ww->evicting = false;
        ww->contended = NULL;
 }
 
+void i915_gem_ww_ctx_unlock_evictions(struct i915_gem_ww_ctx *ww)
+{
+       struct drm_i915_gem_object *obj;
+
+       while ((obj = list_first_entry_or_null(&ww->eviction_list, struct 
drm_i915_gem_object, obj_link))) {
+               list_del(&obj->obj_link);
+               i915_gem_object_unlock(obj);
+               i915_gem_object_put(obj);
+       }
+
+       ww->evicting = false;
+}
+
 static void i915_gem_ww_ctx_unlock_all(struct i915_gem_ww_ctx *ww)
 {
        struct drm_i915_gem_object *obj;
@@ -1382,6 +1397,12 @@ static void i915_gem_ww_ctx_unlock_all(struct 
i915_gem_ww_ctx *ww)
                list_del(&obj->obj_link);
                i915_gem_object_unlock(obj);
        }
+
+       while ((obj = list_first_entry_or_null(&ww->eviction_list, struct 
drm_i915_gem_object, obj_link))) {
+               list_del(&obj->obj_link);
+               i915_gem_object_unlock(obj);
+               i915_gem_object_put(obj);
+       }
 }
 
 void i915_gem_ww_unlock_single(struct drm_i915_gem_object *obj)
@@ -1411,9 +1432,15 @@ int __must_check i915_gem_ww_ctx_backoff(struct 
i915_gem_ww_ctx *ww)
                dma_resv_lock_slow(ww->contended->base.resv, &ww->ctx);
 
        if (!ret)
-               list_add_tail(&ww->contended->obj_link, &ww->obj_list);
+               list_add_tail(&ww->contended->obj_link,
+                             ww->evicting ? &ww->eviction_list :
+                             &ww->obj_list);
+       else if (ret && ww->evicting) {
+             i915_gem_object_put(ww->contended);
+       }
 
        ww->contended = NULL;
+       ww->evicting = false;
 
        return ret;
 }
diff --git a/drivers/gpu/drm/i915/i915_gem.h b/drivers/gpu/drm/i915/i915_gem.h
index a4cad3f154ca..52b19ebffab1 100644
--- a/drivers/gpu/drm/i915/i915_gem.h
+++ b/drivers/gpu/drm/i915/i915_gem.h
@@ -119,7 +119,8 @@ static inline bool __tasklet_is_scheduled(struct 
tasklet_struct *t)
 struct i915_gem_ww_ctx {
        struct ww_acquire_ctx ctx;
        struct list_head obj_list;
-       bool intr;
+       struct list_head eviction_list;
+       bool intr, evicting;
        struct drm_i915_gem_object *contended;
 };
 
@@ -128,4 +129,6 @@ void i915_gem_ww_ctx_fini(struct i915_gem_ww_ctx *ctx);
 int __must_check i915_gem_ww_ctx_backoff(struct i915_gem_ww_ctx *ctx);
 void i915_gem_ww_unlock_single(struct drm_i915_gem_object *obj);
 
+void i915_gem_ww_ctx_unlock_evictions(struct i915_gem_ww_ctx *ww);
+
 #endif /* __I915_GEM_H__ */
-- 
2.28.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to