summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/ttm/ttm_bo.c
diff options
context:
space:
mode:
authorMaarten Lankhorst <maarten.lankhorst@canonical.com>2014-04-02 19:14:48 +0400
committerMaarten Lankhorst <maarten.lankhorst@canonical.com>2014-09-02 18:41:50 +0400
commitf2c24b83ae90292d315aa7ac029c6ce7929e01aa (patch)
tree4ef7d29d97cee6231becd7565056d630770d0845 /drivers/gpu/drm/ttm/ttm_bo.c
parent2f453ed4038526172292fb3250b638b3782c7f2b (diff)
downloadlinux-f2c24b83ae90292d315aa7ac029c6ce7929e01aa.tar.xz
drm/ttm: flip the switch, and convert to dma_fence
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@canonical.com>
Diffstat (limited to 'drivers/gpu/drm/ttm/ttm_bo.c')
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c171
1 files changed, 119 insertions, 52 deletions
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 195386f16ca4..66707be386f7 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -40,6 +40,7 @@
#include <linux/file.h>
#include <linux/module.h>
#include <linux/atomic.h>
+#include <linux/reservation.h>
#define TTM_ASSERT_LOCKED(param)
#define TTM_DEBUG(fmt, arg...)
@@ -142,7 +143,6 @@ static void ttm_bo_release_list(struct kref *list_kref)
BUG_ON(atomic_read(&bo->list_kref.refcount));
BUG_ON(atomic_read(&bo->kref.refcount));
BUG_ON(atomic_read(&bo->cpu_writers));
- BUG_ON(bo->sync_obj != NULL);
BUG_ON(bo->mem.mm_node != NULL);
BUG_ON(!list_empty(&bo->lru));
BUG_ON(!list_empty(&bo->ddestroy));
@@ -403,12 +403,30 @@ static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo)
ww_mutex_unlock (&bo->resv->lock);
}
+static void ttm_bo_flush_all_fences(struct ttm_buffer_object *bo)
+{
+ struct reservation_object_list *fobj;
+ struct fence *fence;
+ int i;
+
+ fobj = reservation_object_get_list(bo->resv);
+ fence = reservation_object_get_excl(bo->resv);
+ if (fence && !fence->ops->signaled)
+ fence_enable_sw_signaling(fence);
+
+ for (i = 0; fobj && i < fobj->shared_count; ++i) {
+ fence = rcu_dereference_protected(fobj->shared[i],
+ reservation_object_held(bo->resv));
+
+ if (!fence->ops->signaled)
+ fence_enable_sw_signaling(fence);
+ }
+}
+
static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
{
struct ttm_bo_device *bdev = bo->bdev;
struct ttm_bo_global *glob = bo->glob;
- struct ttm_bo_driver *driver = bdev->driver;
- void *sync_obj = NULL;
int put_count;
int ret;
@@ -416,9 +434,7 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
ret = __ttm_bo_reserve(bo, false, true, false, NULL);
if (!ret) {
- (void) ttm_bo_wait(bo, false, false, true);
-
- if (!bo->sync_obj) {
+ if (!ttm_bo_wait(bo, false, false, true)) {
put_count = ttm_bo_del_from_lru(bo);
spin_unlock(&glob->lru_lock);
@@ -427,8 +443,8 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
ttm_bo_list_ref_sub(bo, put_count, true);
return;
- }
- sync_obj = driver->sync_obj_ref(bo->sync_obj);
+ } else
+ ttm_bo_flush_all_fences(bo);
/*
* Make NO_EVICT bos immediately available to
@@ -447,14 +463,70 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
list_add_tail(&bo->ddestroy, &bdev->ddestroy);
spin_unlock(&glob->lru_lock);
- if (sync_obj) {
- driver->sync_obj_flush(sync_obj);
- driver->sync_obj_unref(&sync_obj);
- }
schedule_delayed_work(&bdev->wq,
((HZ / 100) < 1) ? 1 : HZ / 100);
}
+static int ttm_bo_unreserve_and_wait(struct ttm_buffer_object *bo,
+ bool interruptible)
+{
+ struct ttm_bo_global *glob = bo->glob;
+ struct reservation_object_list *fobj;
+ struct fence *excl = NULL;
+ struct fence **shared = NULL;
+ u32 shared_count = 0, i;
+ int ret = 0;
+
+ fobj = reservation_object_get_list(bo->resv);
+ if (fobj && fobj->shared_count) {
+ shared = kmalloc(sizeof(*shared) * fobj->shared_count,
+ GFP_KERNEL);
+
+ if (!shared) {
+ ret = -ENOMEM;
+ __ttm_bo_unreserve(bo);
+ spin_unlock(&glob->lru_lock);
+ return ret;
+ }
+
+ for (i = 0; i < fobj->shared_count; ++i) {
+ if (!fence_is_signaled(fobj->shared[i])) {
+ fence_get(fobj->shared[i]);
+ shared[shared_count++] = fobj->shared[i];
+ }
+ }
+ if (!shared_count) {
+ kfree(shared);
+ shared = NULL;
+ }
+ }
+
+ excl = reservation_object_get_excl(bo->resv);
+ if (excl && !fence_is_signaled(excl))
+ fence_get(excl);
+ else
+ excl = NULL;
+
+ __ttm_bo_unreserve(bo);
+ spin_unlock(&glob->lru_lock);
+
+ if (excl) {
+ ret = fence_wait(excl, interruptible);
+ fence_put(excl);
+ }
+
+ if (shared_count > 0) {
+ for (i = 0; i < shared_count; ++i) {
+ if (!ret)
+ ret = fence_wait(shared[i], interruptible);
+ fence_put(shared[i]);
+ }
+ kfree(shared);
+ }
+
+ return ret;
+}
+
/**
* function ttm_bo_cleanup_refs_and_unlock
* If bo idle, remove from delayed- and lru lists, and unref.
@@ -471,8 +543,6 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo,
bool interruptible,
bool no_wait_gpu)
{
- struct ttm_bo_device *bdev = bo->bdev;
- struct ttm_bo_driver *driver = bdev->driver;
struct ttm_bo_global *glob = bo->glob;
int put_count;
int ret;
@@ -480,20 +550,7 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo,
ret = ttm_bo_wait(bo, false, false, true);
if (ret && !no_wait_gpu) {
- void *sync_obj;
-
- /*
- * Take a reference to the fence and unreserve,
- * at this point the buffer should be dead, so
- * no new sync objects can be attached.
- */
- sync_obj = driver->sync_obj_ref(bo->sync_obj);
-
- __ttm_bo_unreserve(bo);
- spin_unlock(&glob->lru_lock);
-
- ret = driver->sync_obj_wait(sync_obj, false, interruptible);
- driver->sync_obj_unref(&sync_obj);
+ ret = ttm_bo_unreserve_and_wait(bo, interruptible);
if (ret)
return ret;
@@ -1498,41 +1555,51 @@ void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo)
EXPORT_SYMBOL(ttm_bo_unmap_virtual);
-
int ttm_bo_wait(struct ttm_buffer_object *bo,
bool lazy, bool interruptible, bool no_wait)
{
- struct ttm_bo_driver *driver = bo->bdev->driver;
- void *sync_obj;
- int ret = 0;
-
- lockdep_assert_held(&bo->resv->lock.base);
+ struct reservation_object_list *fobj;
+ struct reservation_object *resv;
+ struct fence *excl;
+ long timeout = 15 * HZ;
+ int i;
- if (likely(bo->sync_obj == NULL))
- return 0;
+ resv = bo->resv;
+ fobj = reservation_object_get_list(resv);
+ excl = reservation_object_get_excl(resv);
+ if (excl) {
+ if (!fence_is_signaled(excl)) {
+ if (no_wait)
+ return -EBUSY;
- if (bo->sync_obj) {
- if (driver->sync_obj_signaled(bo->sync_obj)) {
- driver->sync_obj_unref(&bo->sync_obj);
- clear_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags);
- return 0;
+ timeout = fence_wait_timeout(excl,
+ interruptible, timeout);
}
+ }
- if (no_wait)
- return -EBUSY;
+ for (i = 0; fobj && timeout > 0 && i < fobj->shared_count; ++i) {
+ struct fence *fence;
+ fence = rcu_dereference_protected(fobj->shared[i],
+ reservation_object_held(resv));
- sync_obj = driver->sync_obj_ref(bo->sync_obj);
- ret = driver->sync_obj_wait(sync_obj,
- lazy, interruptible);
+ if (!fence_is_signaled(fence)) {
+ if (no_wait)
+ return -EBUSY;
- if (likely(ret == 0)) {
- clear_bit(TTM_BO_PRIV_FLAG_MOVING,
- &bo->priv_flags);
- driver->sync_obj_unref(&bo->sync_obj);
+ timeout = fence_wait_timeout(fence,
+ interruptible, timeout);
}
- driver->sync_obj_unref(&sync_obj);
}
- return ret;
+
+ if (timeout < 0)
+ return timeout;
+
+ if (timeout == 0)
+ return -EBUSY;
+
+ reservation_object_add_excl_fence(resv, NULL);
+ clear_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags);
+ return 0;
}
EXPORT_SYMBOL(ttm_bo_wait);