[PATCH 13/13] drm/radeon: add fence and retry to sa allocator v2
j.glisse at gmail.com
j.glisse at gmail.com
Tue May 1 21:00:58 PDT 2012
From: Jerome Glisse <jglisse at redhat.com>
This allow to associate a fence with sa bo and retry and
wait if sa bo alloc can block.
v2: bug fixes
Signed-off-by: Jerome Glisse <jglisse at redhat.com>
---
drivers/gpu/drm/radeon/radeon.h | 10 ++-
drivers/gpu/drm/radeon/radeon_cs.c | 4 +-
drivers/gpu/drm/radeon/radeon_gart.c | 14 ++--
drivers/gpu/drm/radeon/radeon_object.h | 10 ++--
drivers/gpu/drm/radeon/radeon_ring.c | 14 ++--
drivers/gpu/drm/radeon/radeon_sa.c | 102 ++++++++++++++++++++++++++---
drivers/gpu/drm/radeon/radeon_semaphore.c | 4 +-
7 files changed, 122 insertions(+), 36 deletions(-)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 59bcfb9..4815ebe 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -379,6 +379,8 @@ struct radeon_bo_list {
* Assumption is that there won't be hole (all object on same
* alignment).
*/
+struct radeon_sa_bo;
+
struct radeon_sa_manager {
spinlock_t lock;
struct radeon_bo *bo;
@@ -390,8 +392,6 @@ struct radeon_sa_manager {
uint32_t domain;
};
-struct radeon_sa_bo;
-
/* sub-allocation buffer */
struct radeon_sa_bo {
struct list_head list;
@@ -399,6 +399,8 @@ struct radeon_sa_bo {
unsigned soffset;
unsigned eoffset;
unsigned size;
+ struct radeon_fence *fence;
+ bool free;
};
/*
@@ -626,7 +628,7 @@ void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc);
*/
struct radeon_ib {
- struct radeon_sa_bo sa_bo;
+ struct radeon_sa_bo *sa_bo;
unsigned idx;
uint32_t length_dw;
uint64_t gpu_addr;
@@ -680,7 +682,7 @@ struct radeon_vm {
unsigned last_pfn;
u64 pt_gpu_addr;
u64 *pt;
- struct radeon_sa_bo sa_bo;
+ struct radeon_sa_bo *sa_bo;
struct mutex mutex;
/* last fence for cs using this vm */
struct radeon_fence *fence;
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c
index 8de6b3a..b39f22e 100644
--- a/drivers/gpu/drm/radeon/radeon_cs.c
+++ b/drivers/gpu/drm/radeon/radeon_cs.c
@@ -476,7 +476,7 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,
/* ib pool is bind at 0 in virtual address space to gpu_addr is the
* offset inside the pool bo
*/
- parser->const_ib->gpu_addr = parser->const_ib->sa_bo.soffset;
+ parser->const_ib->gpu_addr = parser->const_ib->sa_bo->soffset;
r = radeon_ib_schedule(rdev, parser->const_ib);
if (r)
goto out;
@@ -486,7 +486,7 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,
/* ib pool is bind at 0 in virtual address space to gpu_addr is the
* offset inside the pool bo
*/
- parser->ib->gpu_addr = parser->ib->sa_bo.soffset;
+ parser->ib->gpu_addr = parser->ib->sa_bo->soffset;
parser->ib->is_const_ib = false;
r = radeon_ib_schedule(rdev, parser->ib);
out:
diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c
index 4a5d9d4..89328e3 100644
--- a/drivers/gpu/drm/radeon/radeon_gart.c
+++ b/drivers/gpu/drm/radeon/radeon_gart.c
@@ -393,19 +393,19 @@ int radeon_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm)
}
retry:
- r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager, &vm->sa_bo,
- RADEON_GPU_PAGE_ALIGN(vm->last_pfn * 8),
- RADEON_GPU_PAGE_SIZE);
- if (r) {
+ vm->sa_bo = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager,
+ RADEON_GPU_PAGE_ALIGN(vm->last_pfn * 8),
+ RADEON_GPU_PAGE_SIZE, false, NULL);
+ if (vm->sa_bo == NULL) {
if (list_empty(&rdev->vm_manager.lru_vm)) {
- return r;
+ return -ENOMEM;
}
vm_evict = list_first_entry(&rdev->vm_manager.lru_vm, struct radeon_vm, list);
radeon_vm_unbind(rdev, vm_evict);
goto retry;
}
- vm->pt = radeon_sa_bo_cpu_addr(&vm->sa_bo);
- vm->pt_gpu_addr = radeon_sa_bo_gpu_addr(&vm->sa_bo);
+ vm->pt = radeon_sa_bo_cpu_addr(vm->sa_bo);
+ vm->pt_gpu_addr = radeon_sa_bo_gpu_addr(vm->sa_bo);
memset(vm->pt, 0, RADEON_GPU_PAGE_ALIGN(vm->last_pfn * 8));
retry_id:
diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h
index 99ab46a..7bbc319 100644
--- a/drivers/gpu/drm/radeon/radeon_object.h
+++ b/drivers/gpu/drm/radeon/radeon_object.h
@@ -166,12 +166,12 @@ extern int radeon_sa_bo_manager_start(struct radeon_device *rdev,
struct radeon_sa_manager *sa_manager);
extern int radeon_sa_bo_manager_suspend(struct radeon_device *rdev,
struct radeon_sa_manager *sa_manager);
-extern int radeon_sa_bo_new(struct radeon_device *rdev,
- struct radeon_sa_manager *sa_manager,
- struct radeon_sa_bo *sa_bo,
- unsigned size, unsigned align);
+extern struct radeon_sa_bo *radeon_sa_bo_new(struct radeon_device *rdev,
+ struct radeon_sa_manager *sa_manager,
+ unsigned size, unsigned align,
+ bool block, struct radeon_fence *fence);
extern void radeon_sa_bo_free(struct radeon_device *rdev,
- struct radeon_sa_bo *sa_bo);
+ struct radeon_sa_bo **sa_bo);
#if defined(CONFIG_DEBUG_FS)
extern void radeon_sa_bo_dump_debug_info(struct radeon_sa_manager *sa_manager,
struct seq_file *m);
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
index 981ab95..b646bdb 100644
--- a/drivers/gpu/drm/radeon/radeon_ring.c
+++ b/drivers/gpu/drm/radeon/radeon_ring.c
@@ -122,13 +122,12 @@ retry:
for (i = 0; i < RADEON_IB_POOL_SIZE; i++) {
radeon_ib_try_free(rdev, &rdev->ib_pool.ibs[idx]);
if (rdev->ib_pool.ibs[idx].fence == NULL) {
- r = radeon_sa_bo_new(rdev, &rdev->ib_pool.sa_manager,
- &rdev->ib_pool.ibs[idx].sa_bo,
- size, 256);
- if (!r) {
+ rdev->ib_pool.ibs[idx].sa_bo = radeon_sa_bo_new(rdev, &rdev->ib_pool.sa_manager,
+ size, 256, false, NULL);
+ if (rdev->ib_pool.ibs[idx].sa_bo) {
*ib = &rdev->ib_pool.ibs[idx];
- (*ib)->ptr = radeon_sa_bo_cpu_addr(&(*ib)->sa_bo);
- (*ib)->gpu_addr = radeon_sa_bo_gpu_addr(&(*ib)->sa_bo);
+ (*ib)->ptr = radeon_sa_bo_cpu_addr((*ib)->sa_bo);
+ (*ib)->gpu_addr = radeon_sa_bo_gpu_addr((*ib)->sa_bo);
(*ib)->fence = fence;
(*ib)->vm_id = 0;
(*ib)->is_const_ib = false;
@@ -146,6 +145,7 @@ retry:
}
/* this should be rare event, ie all ib scheduled none signaled yet.
*/
+ r = -ENOMEM;
for (i = 0; i < RADEON_IB_POOL_SIZE; i++) {
if (rdev->ib_pool.ibs[idx].fence && rdev->ib_pool.ibs[idx].fence->emitted) {
r = radeon_fence_wait(rdev->ib_pool.ibs[idx].fence, false);
@@ -226,7 +226,7 @@ int radeon_ib_pool_init(struct radeon_device *rdev)
rdev->ib_pool.ibs[i].fence = NULL;
rdev->ib_pool.ibs[i].idx = i;
rdev->ib_pool.ibs[i].length_dw = 0;
- INIT_LIST_HEAD(&rdev->ib_pool.ibs[i].sa_bo.list);
+ rdev->ib_pool.ibs[i].sa_bo = NULL;
}
rdev->ib_pool.head_id = 0;
rdev->ib_pool.ready = true;
diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c
index 63b0cd2..d7d7b7e 100644
--- a/drivers/gpu/drm/radeon/radeon_sa.c
+++ b/drivers/gpu/drm/radeon/radeon_sa.c
@@ -122,6 +122,12 @@ static void radeon_sa_bo_free_locked(struct radeon_device *rdev, struct radeon_s
struct radeon_sa_manager *sa_manager = sa_bo->manager;
struct list_head *prev;
+ if (sa_bo->fence) {
+ if (!radeon_fence_signaled(sa_bo->fence)) {
+ return;
+ }
+ radeon_fence_unref(&sa_bo->fence);
+ }
prev = sa_bo->list.prev;
list_del_init(&sa_bo->list);
if (list_empty(&sa_manager->sa_bo)) {
@@ -138,6 +144,25 @@ static void radeon_sa_bo_free_locked(struct radeon_device *rdev, struct radeon_s
sa_manager->last = list_entry(prev, struct radeon_sa_bo, list);
}
}
+ /* in case try free already free the sa_bo but radeon_sa_bo_free
+ * wasn't yet call, the free bool protect us from freeing to
+ * early the structure
+ */
+ if (sa_bo->free) {
+ kfree(sa_bo);
+ }
+}
+
+static bool radeon_sa_manager_try_free(struct radeon_device *rdev,
+ struct radeon_sa_bo *oldest)
+{
+ if (oldest->fence && oldest->fence->emitted) {
+ if (radeon_fence_signaled(oldest->fence)) {
+ radeon_sa_bo_free_locked(rdev, oldest);
+ return true;
+ }
+ }
+ return false;
}
/*
@@ -151,25 +176,32 @@ static void radeon_sa_bo_free_locked(struct radeon_device *rdev, struct radeon_s
*
* Alignment can't be bigger than page size
*/
-int radeon_sa_bo_new(struct radeon_device *rdev,
- struct radeon_sa_manager *sa_manager,
- struct radeon_sa_bo *sa_bo,
- unsigned size, unsigned align)
+struct radeon_sa_bo *radeon_sa_bo_new(struct radeon_device *rdev,
+ struct radeon_sa_manager *sa_manager,
+ unsigned size, unsigned align,
+ bool block, struct radeon_fence *fence)
{
- struct radeon_sa_bo *next, *oldest;
+ struct radeon_sa_bo *sa_bo, *next, *oldest;
unsigned offset, wasted, hole_offset, hole_size;
bool try_begining = false, add_begining = false;
BUG_ON(align > RADEON_GPU_PAGE_SIZE);
BUG_ON(size > sa_manager->size);
+ sa_bo = kmalloc(sizeof(struct radeon_sa_bo), GFP_KERNEL);
+ if (sa_bo == NULL) {
+ return NULL;
+ }
sa_bo->manager = sa_manager;
+ sa_bo->fence = NULL;
+ sa_bo->free = false;
sa_bo->soffset = 0;
sa_bo->eoffset = 0;
sa_bo->size = 0;
INIT_LIST_HEAD(&sa_bo->list);
spin_lock(&sa_manager->lock);
+retry:
if (sa_manager->last == NULL) {
offset = 0;
add_begining = true;
@@ -186,6 +218,7 @@ int radeon_sa_bo_new(struct radeon_device *rdev,
} else {
next = list_entry(sa_manager->last->list.next, struct radeon_sa_bo, list);
hole_size = next->soffset - hole_offset;
+ oldest = next;
}
if ((size + wasted) >= hole_size) {
offset = hole_offset + wasted;
@@ -201,9 +234,44 @@ int radeon_sa_bo_new(struct radeon_device *rdev,
goto out;
}
}
+ /* try to be optimist and free the oldest one */
+ if (radeon_sa_manager_try_free(rdev, oldest)) {
+ goto retry;
+ }
+
+ /* if block is used all the sa_bo must be associated with a
+ * fence, we perform sanity check but expect things to go
+ * berserk if you don't follow this
+ */
+ if (block) {
+ struct radeon_fence *fence = NULL;
+ int r;
+
+ if (oldest->fence) {
+ fence = radeon_fence_ref(oldest->fence);
+ }
+ spin_unlock(&sa_manager->lock);
+
+ if (fence == NULL) {
+ /* this should never happen */
+ dev_warn(rdev->dev, "sa allocator nothing we can wait for\n");
+ goto out_err;
+ }
+ r = radeon_fence_wait(fence, false);
+ radeon_fence_unref(&fence);
+ if (r) {
+ goto out_err;
+ }
+
+ spin_lock(&sa_manager->lock);
+ goto retry;
+ }
spin_unlock(&sa_manager->lock);
- return -ENOMEM;
+
+out_err:
+ kfree(sa_bo);
+ return NULL;
out:
if (add_begining) {
@@ -212,22 +280,38 @@ out:
list_add(&sa_bo->list, &sa_manager->last->list);
}
sa_manager->last = sa_bo;
+ if (fence) {
+ sa_bo->fence = radeon_fence_ref(fence);
+ }
sa_bo->soffset = offset;
sa_bo->eoffset = offset + size;
sa_bo->size = size;
spin_unlock(&sa_manager->lock);
- return 0;
+ return sa_bo;
}
-void radeon_sa_bo_free(struct radeon_device *rdev, struct radeon_sa_bo *sa_bo)
+void radeon_sa_bo_free(struct radeon_device *rdev, struct radeon_sa_bo **tmp)
{
- struct radeon_sa_manager *sa_manager = sa_bo->manager;
+ struct radeon_sa_bo *sa_bo;
+ struct radeon_sa_manager *sa_manager;
+ if (tmp == NULL || *tmp == NULL) {
+ return;
+ }
+
+ sa_bo = *tmp;
+ sa_manager = sa_bo->manager;
+ *tmp = NULL;
spin_lock(&sa_manager->lock);
+ sa_bo->free = true;
if (list_empty(&sa_bo->list)) {
/* it has already been free */
+ kfree(sa_bo);
goto out;
}
+ if (sa_bo->fence && !sa_bo->fence->emitted) {
+ radeon_fence_unref(&sa_bo->fence);
+ }
radeon_sa_bo_free_locked(rdev, sa_bo);
out:
diff --git a/drivers/gpu/drm/radeon/radeon_semaphore.c b/drivers/gpu/drm/radeon/radeon_semaphore.c
index c3763e4..d79afb3 100644
--- a/drivers/gpu/drm/radeon/radeon_semaphore.c
+++ b/drivers/gpu/drm/radeon/radeon_semaphore.c
@@ -55,9 +55,9 @@ static int radeon_semaphore_add_bo(struct radeon_device *rdev)
return r;
}
gpu_addr = rdev->ib_pool.sa_manager.gpu_addr;
- gpu_addr += bo->ib->sa_bo.soffset;
+ gpu_addr += bo->ib->sa_bo->soffset;
cpu_ptr = rdev->ib_pool.sa_manager.cpu_ptr;
- cpu_ptr += (bo->ib->sa_bo.soffset >> 2);
+ cpu_ptr += (bo->ib->sa_bo->soffset >> 2);
for (i = 0; i < (RADEON_SEMAPHORE_BO_SIZE/8); i++) {
bo->semaphores[i].gpu_addr = gpu_addr;
bo->semaphores[i].cpu_ptr = cpu_ptr;
--
1.7.7.6
More information about the dri-devel
mailing list