[PATCH 4/4] drm/radeon: improve sa allocator to agressivly free idle bo

j.glisse at gmail.com j.glisse at gmail.com
Wed May 2 13:20:13 PDT 2012


From: Jerome Glisse <jglisse at redhat.com>

With fence rework it's now easier to agressivly free idle bo
when there is no hole to satisfy current allocation request.
The hit of some cs ioctl to have to go through the sa bo list
and free them is minimal, it happens once in while and avoid
some fence waiting.

Signed-off-by: Jerome Glisse <jglisse at redhat.com>
---
 drivers/gpu/drm/radeon/radeon.h       |    1 +
 drivers/gpu/drm/radeon/radeon_fence.c |    2 +-
 drivers/gpu/drm/radeon/radeon_sa.c    |   51 +++++++++++++++++++++++++++++---
 3 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 141aee2..5459722 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -314,6 +314,7 @@ int radeon_fence_wait_empty(struct radeon_device *rdev, int ring);
 struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence);
 void radeon_fence_unref(struct radeon_fence **fence);
 unsigned radeon_fence_count_emitted(struct radeon_device *rdev, int ring);
+bool radeon_fence_poll(struct radeon_device *rdev, int ring);
 
 /*
  * Tiling registers
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c
index 3f34f7b..043f431 100644
--- a/drivers/gpu/drm/radeon/radeon_fence.c
+++ b/drivers/gpu/drm/radeon/radeon_fence.c
@@ -78,7 +78,7 @@ int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence)
 	return 0;
 }
 
-static bool radeon_fence_poll(struct radeon_device *rdev, int ring)
+bool radeon_fence_poll(struct radeon_device *rdev, int ring)
 {
 	uint64_t seq;
 
diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c
index e758aaa..2cbf5ba 100644
--- a/drivers/gpu/drm/radeon/radeon_sa.c
+++ b/drivers/gpu/drm/radeon/radeon_sa.c
@@ -48,6 +48,10 @@
 #include "drm.h"
 #include "radeon.h"
 
+static bool radeon_sa_manager_try_free(struct radeon_device *rdev,
+				       struct radeon_sa_manager *sa_manager,
+				       struct radeon_sa_bo *oldest);
+
 int radeon_sa_bo_manager_init(struct radeon_device *rdev,
 			      struct radeon_sa_manager *sa_manager,
 			      unsigned size, u32 domain)
@@ -77,7 +81,16 @@ void radeon_sa_bo_manager_fini(struct radeon_device *rdev,
 	struct radeon_sa_bo *sa_bo, *tmp;
 
 	if (!list_empty(&sa_manager->sa_bo)) {
-		dev_err(rdev->dev, "sa_manager is not empty, clearing anyway\n");
+		struct radeon_sa_bo *oldest;
+
+		/* try to free them */
+		oldest =  list_entry(sa_manager->sa_bo.next, struct radeon_sa_bo, list);
+		radeon_sa_manager_try_free(rdev, sa_manager, oldest);
+
+		if (!list_empty(&sa_manager->sa_bo)) {
+			/* something went wrong */
+			dev_err(rdev->dev, "sa_manager is not empty, clearing anyway\n");
+		}
 	}
 	list_for_each_entry_safe(sa_bo, tmp, &sa_manager->sa_bo, list) {
 		list_del_init(&sa_bo->list);
@@ -171,15 +184,43 @@ static void radeon_sa_bo_free_locked(struct radeon_device *rdev, struct radeon_s
 }
 
 static bool radeon_sa_manager_try_free(struct radeon_device *rdev,
+				       struct radeon_sa_manager *sa_manager,
 				       struct radeon_sa_bo *oldest)
 {
-	if (oldest->fence && oldest->fence->emitted) {
-		if (radeon_fence_signaled(oldest->fence)) {
+	struct radeon_sa_bo *tmp, *sa_bo;
+	unsigned ring, free_count = 0;
+
+	if (oldest->fence == NULL || !oldest->fence->emitted) {
+		return false;
+	}
+	ring = oldest->fence->ring;
+	radeon_fence_poll(rdev, ring);
+	if (rdev->fence_drv[ring].last_seq < oldest->fence->seq) {
+		return false;
+	}
+	free_count++;
+	/* go over the remaining of the list and try to free as much
+	 * as possible
+	 */
+	sa_bo = oldest;
+	list_for_each_entry_safe_continue(sa_bo, tmp, &sa_manager->sa_bo, list) {
+		if (sa_bo->fence == NULL || !sa_bo->fence->emitted) {
+			radeon_sa_bo_free_locked(rdev, oldest);
+			return true;
+		}
+		if (ring != sa_bo->fence->ring) {
+			ring = sa_bo->fence->ring;
+			radeon_fence_poll(rdev, ring);
+		}
+		if (rdev->fence_drv[ring].last_seq < sa_bo->fence->seq) {
 			radeon_sa_bo_free_locked(rdev, oldest);
 			return true;
 		}
+		radeon_sa_bo_free_locked(rdev, sa_bo);
+		free_count++;
 	}
-	return false;
+	radeon_sa_bo_free_locked(rdev, oldest);
+	return true;
 }
 
 /*
@@ -260,7 +301,7 @@ retry:
 		}
 	}
 	/* try to be optimist and free the oldest one */
-	if (radeon_sa_manager_try_free(rdev, oldest)) {
+	if (radeon_sa_manager_try_free(rdev, sa_manager, oldest)) {
 		goto retry;
 	}
 
-- 
1.7.7.6



More information about the dri-devel mailing list