summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_object.c28
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_object.h3
-rw-r--r--drivers/gpu/drm/i915/i915_gem_evict.c22
-rw-r--r--drivers/gpu/drm/i915/i915_gem_ww.c19
4 files changed, 64 insertions, 8 deletions
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c
index fd34b1a115c4..101d4f60157b 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
@@ -89,6 +89,7 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
mutex_init(&obj->mm.get_page.lock);
INIT_RADIX_TREE(&obj->mm.get_dma_page.radix, GFP_KERNEL | __GFP_NOWARN);
mutex_init(&obj->mm.get_dma_page.lock);
+ kref_init(&i915_gem_to_ttm(obj)->kref);
}
/**
@@ -319,6 +320,29 @@ void __i915_gem_free_object(struct drm_i915_gem_object *obj)
__i915_gem_object_fini(obj);
}
+static void __i915_gem_free_object_free_destroy(struct kref *kref)
+{
+ struct drm_i915_gem_object *obj = container_of(kref, struct drm_i915_gem_object, __do_not_access.kref);
+
+ __i915_gem_free_object(obj);
+
+ /* But keep the pointer alive for RCU-protected lookups */
+ call_rcu(&obj->rcu, __i915_gem_free_object_rcu);
+}
+
+void i915_gem_object_free_get(struct drm_i915_gem_object *obj)
+{
+ kref_get(&i915_gem_to_ttm(obj)->kref);
+}
+
+void i915_gem_object_free_put(struct drm_i915_gem_object *obj)
+{
+ if (obj->ops->delayed_free)
+ ttm_bo_put(i915_gem_to_ttm(obj));
+ else
+ kref_put(&i915_gem_to_ttm(obj)->kref, __i915_gem_free_object_free_destroy);
+}
+
static void __i915_gem_free_objects(struct drm_i915_private *i915,
struct llist_node *freed)
{
@@ -340,10 +364,8 @@ static void __i915_gem_free_objects(struct drm_i915_private *i915,
__i915_gem_object_pages_fini(obj);
i915_gem_object_unlock(obj);
- __i915_gem_free_object(obj);
- /* But keep the pointer alive for RCU-protected lookups */
- call_rcu(&obj->rcu, __i915_gem_free_object_rcu);
+ i915_gem_object_free_put(obj);
cond_resched();
}
}
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h
index 08db9af75a62..1b7ee6cd65bf 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h
@@ -123,6 +123,9 @@ i915_gem_object_get_rcu(struct drm_i915_gem_object *obj)
return obj;
}
+void i915_gem_object_free_get(struct drm_i915_gem_object *obj);
+void i915_gem_object_free_put(struct drm_i915_gem_object *obj);
+
static inline struct drm_i915_gem_object *
i915_gem_object_lookup(struct drm_file *file, u32 handle)
{
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c
index ec1423e60516..d66f60493522 100644
--- a/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -422,18 +422,32 @@ retry:
if (dma_resv_locking_ctx(vma->obj->base.resv) != &ww->ctx &&
!i915_gem_object_trylock_to_evict(vma->obj, ww)) {
struct drm_i915_gem_object *obj;
+ bool dead = false;
if (i915_vma_is_pinned(vma))
continue;
obj = i915_gem_object_get_rcu(vma->obj);
- if (!obj)
- /* Object's dead, can't drop vm->mutex safely */
- continue;
+ if (!obj) {
+ obj = vma->obj;
+ i915_gem_object_free_get(obj);
+ dead = true;
+ }
mutex_unlock(&vm->mutex);
ret = i915_gem_object_lock_to_evict(obj, ww);
- i915_gem_object_put(obj);
+
+
+ if (dead) {
+ if (!ret) {
+ __i915_gem_object_pages_fini(obj);
+ list_del(&obj->obj_link);
+ i915_gem_object_unlock(obj);
+ }
+ i915_gem_object_free_put(obj);
+ } else {
+ i915_gem_object_put(obj);
+ }
if (ret) {
i915_gem_ww_ctx_unlock_evictions(ww);
diff --git a/drivers/gpu/drm/i915/i915_gem_ww.c b/drivers/gpu/drm/i915/i915_gem_ww.c
index 5e7c14cb43d0..b4eef420807d 100644
--- a/drivers/gpu/drm/i915/i915_gem_ww.c
+++ b/drivers/gpu/drm/i915/i915_gem_ww.c
@@ -5,6 +5,7 @@
#include <linux/dma-resv.h>
#include "i915_gem_ww.h"
#include "gem/i915_gem_object.h"
+#include "gem/i915_gem_ttm.h"
void i915_gem_ww_ctx_init(struct i915_gem_ww_ctx *ww, bool intr)
{
@@ -72,6 +73,19 @@ int __must_check i915_gem_ww_ctx_backoff(struct i915_gem_ww_ctx *ww)
else
dma_resv_lock_slow(ww->contended->base.resv, &ww->ctx);
+ if (ww->contended_evict && !kref_read(&i915_gem_to_ttm(ww->contended)->kref)) {
+ /* dead object, reap it */
+ if (!ret) {
+ __i915_gem_object_pages_fini(ww->contended);
+ i915_gem_object_unlock(ww->contended);
+ }
+
+ i915_gem_object_free_put(ww->contended);
+ ww->contended_evict = false;
+ ww->contended = NULL;
+ return ret;
+ }
+
if (!ret) {
list_add_tail(&ww->contended->obj_link,
!ww->contended_evict ? &ww->obj_list : &ww->eviction_list);
@@ -112,7 +126,10 @@ static inline int __i915_gem_object_lock(struct drm_i915_gem_object *obj,
ret = 0;
if (ret == -EDEADLK) {
- i915_gem_object_get(obj);
+ if (!evict)
+ i915_gem_object_get(obj);
+ else if (!i915_gem_object_get_rcu(obj))
+ i915_gem_object_free_get(obj);
ww->contended = obj;
ww->contended_evict = evict;
}