summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorChristian König <christian.koenig@amd.com>2017-11-15 13:20:09 +0100
committerAlex Deucher <alexander.deucher@amd.com>2017-12-06 12:47:54 -0500
commitc0c2c3bffc946f5a44ee695c663cbca96dacc4d0 (patch)
tree949f7567fed1fe08f13b23b7b93b79d87f8220c8 /drivers
parent090528639321ab09c150603c0da3c38c26aa5ea9 (diff)
downloadlinux-stable-c0c2c3bffc946f5a44ee695c663cbca96dacc4d0.tar.gz
linux-stable-c0c2c3bffc946f5a44ee695c663cbca96dacc4d0.tar.bz2
linux-stable-c0c2c3bffc946f5a44ee695c663cbca96dacc4d0.zip
drm/ttm: completely rework ttm_bo_delayed_delete
There is no guarantee that the next entry on the ddelete list stays on the list when we drop the locks. Completely rework this mess by moving processed entries on a temporary list. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-and-Tested-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c72
1 files changed, 23 insertions, 49 deletions
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 7c1eac4f4b4b..e79c927e0075 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -572,60 +572,37 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo,
* Traverse the delayed list, and call ttm_bo_cleanup_refs on all
* encountered buffers.
*/
-
-static int ttm_bo_delayed_delete(struct ttm_bo_device *bdev, bool remove_all)
+static bool ttm_bo_delayed_delete(struct ttm_bo_device *bdev, bool remove_all)
{
struct ttm_bo_global *glob = bdev->glob;
- struct ttm_buffer_object *entry = NULL;
- int ret = 0;
-
- spin_lock(&glob->lru_lock);
- if (list_empty(&bdev->ddestroy))
- goto out_unlock;
-
- entry = list_first_entry(&bdev->ddestroy,
- struct ttm_buffer_object, ddestroy);
- kref_get(&entry->list_kref);
+ struct list_head removed;
+ bool empty;
- for (;;) {
- struct ttm_buffer_object *nentry = NULL;
-
- if (entry->ddestroy.next != &bdev->ddestroy) {
- nentry = list_first_entry(&entry->ddestroy,
- struct ttm_buffer_object, ddestroy);
- kref_get(&nentry->list_kref);
- }
+ INIT_LIST_HEAD(&removed);
- ret = reservation_object_trylock(entry->resv) ? 0 : -EBUSY;
- if (remove_all && ret) {
- spin_unlock(&glob->lru_lock);
- ret = reservation_object_lock(entry->resv, NULL);
- spin_lock(&glob->lru_lock);
- }
+ spin_lock(&glob->lru_lock);
+ while (!list_empty(&bdev->ddestroy)) {
+ struct ttm_buffer_object *bo;
- if (!ret)
- ret = ttm_bo_cleanup_refs(entry, false, !remove_all,
- true);
- else
- spin_unlock(&glob->lru_lock);
+ bo = list_first_entry(&bdev->ddestroy, struct ttm_buffer_object,
+ ddestroy);
+ kref_get(&bo->list_kref);
+ list_move_tail(&bo->ddestroy, &removed);
+ spin_unlock(&glob->lru_lock);
- kref_put(&entry->list_kref, ttm_bo_release_list);
- entry = nentry;
+ reservation_object_lock(bo->resv, NULL);
- if (ret || !entry)
- goto out;
+ spin_lock(&glob->lru_lock);
+ ttm_bo_cleanup_refs(bo, false, !remove_all, true);
+ kref_put(&bo->list_kref, ttm_bo_release_list);
spin_lock(&glob->lru_lock);
- if (list_empty(&entry->ddestroy))
- break;
}
-
-out_unlock:
+ list_splice_tail(&removed, &bdev->ddestroy);
+ empty = list_empty(&bdev->ddestroy);
spin_unlock(&glob->lru_lock);
-out:
- if (entry)
- kref_put(&entry->list_kref, ttm_bo_release_list);
- return ret;
+
+ return empty;
}
static void ttm_bo_delayed_workqueue(struct work_struct *work)
@@ -633,7 +610,7 @@ static void ttm_bo_delayed_workqueue(struct work_struct *work)
struct ttm_bo_device *bdev =
container_of(work, struct ttm_bo_device, wq.work);
- if (ttm_bo_delayed_delete(bdev, false)) {
+ if (!ttm_bo_delayed_delete(bdev, false)) {
schedule_delayed_work(&bdev->wq,
((HZ / 100) < 1) ? 1 : HZ / 100);
}
@@ -1573,13 +1550,10 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev)
cancel_delayed_work_sync(&bdev->wq);
- while (ttm_bo_delayed_delete(bdev, true))
- ;
-
- spin_lock(&glob->lru_lock);
- if (list_empty(&bdev->ddestroy))
+ if (ttm_bo_delayed_delete(bdev, true))
TTM_DEBUG("Delayed destroy list was clean\n");
+ spin_lock(&glob->lru_lock);
for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
if (list_empty(&bdev->man[0].lru[0]))
TTM_DEBUG("Swap list %d was clean\n", i);