diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_sa.c')
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_sa.c | 99 |
1 files changed, 66 insertions, 33 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c index 32059b74572..adcf3e2f07d 100644 --- a/drivers/gpu/drm/radeon/radeon_sa.c +++ b/drivers/gpu/drm/radeon/radeon_sa.c @@ -41,8 +41,7 @@ * If we are asked to block we wait on all the oldest fence of all * rings. We just wait for any of those fence to complete. */ -#include "drmP.h" -#include "drm.h" +#include <drm/drmP.h> #include "radeon.h" static void radeon_sa_bo_remove_locked(struct radeon_sa_bo *sa_bo); @@ -50,22 +49,23 @@ static void radeon_sa_bo_try_free(struct radeon_sa_manager *sa_manager); int radeon_sa_bo_manager_init(struct radeon_device *rdev, struct radeon_sa_manager *sa_manager, - unsigned size, u32 domain) + unsigned size, u32 align, u32 domain) { int i, r; - spin_lock_init(&sa_manager->lock); + init_waitqueue_head(&sa_manager->wq); sa_manager->bo = NULL; sa_manager->size = size; sa_manager->domain = domain; + sa_manager->align = align; sa_manager->hole = &sa_manager->olist; INIT_LIST_HEAD(&sa_manager->olist); for (i = 0; i < RADEON_NUM_RINGS; ++i) { INIT_LIST_HEAD(&sa_manager->flist[i]); } - r = radeon_bo_create(rdev, size, RADEON_GPU_PAGE_SIZE, true, - RADEON_GEM_DOMAIN_CPU, NULL, &sa_manager->bo); + r = radeon_bo_create(rdev, size, align, true, + domain, NULL, &sa_manager->bo); if (r) { dev_err(rdev->dev, "(%d) failed to allocate bo for manager\n", r); return r; @@ -211,6 +211,39 @@ static bool radeon_sa_bo_try_alloc(struct radeon_sa_manager *sa_manager, return false; } +/** + * radeon_sa_event - Check if we can stop waiting + * + * @sa_manager: pointer to the sa_manager + * @size: number of bytes we want to allocate + * @align: alignment we need to match + * + * Check if either there is a fence we can wait for or + * enough free memory to satisfy the allocation directly + */ +static bool radeon_sa_event(struct radeon_sa_manager *sa_manager, + unsigned size, unsigned align) +{ + unsigned soffset, eoffset, wasted; + int i; + + for (i = 0; i < RADEON_NUM_RINGS; ++i) { + if (!list_empty(&sa_manager->flist[i])) { + return true; + } + } + + soffset = radeon_sa_bo_hole_soffset(sa_manager); + eoffset = radeon_sa_bo_hole_eoffset(sa_manager); + wasted = (align - (soffset % align)) % align; + + if ((eoffset - soffset) >= (size + wasted)) { + return true; + } + + return false; +} + static bool radeon_sa_bo_next_hole(struct radeon_sa_manager *sa_manager, struct radeon_fence **fences, unsigned *tries) @@ -279,13 +312,13 @@ static bool radeon_sa_bo_next_hole(struct radeon_sa_manager *sa_manager, 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, bool block) + unsigned size, unsigned align) { struct radeon_fence *fences[RADEON_NUM_RINGS]; unsigned tries[RADEON_NUM_RINGS]; - int i, r = -ENOMEM; + int i, r; - BUG_ON(align > RADEON_GPU_PAGE_SIZE); + BUG_ON(align > sa_manager->align); BUG_ON(size > sa_manager->size); *sa_bo = kmalloc(sizeof(struct radeon_sa_bo), GFP_KERNEL); @@ -297,7 +330,7 @@ int radeon_sa_bo_new(struct radeon_device *rdev, INIT_LIST_HEAD(&(*sa_bo)->olist); INIT_LIST_HEAD(&(*sa_bo)->flist); - spin_lock(&sa_manager->lock); + spin_lock(&sa_manager->wq.lock); do { for (i = 0; i < RADEON_NUM_RINGS; ++i) { fences[i] = NULL; @@ -309,30 +342,27 @@ int radeon_sa_bo_new(struct radeon_device *rdev, if (radeon_sa_bo_try_alloc(sa_manager, *sa_bo, size, align)) { - spin_unlock(&sa_manager->lock); + spin_unlock(&sa_manager->wq.lock); return 0; } /* see if we can skip over some allocations */ } while (radeon_sa_bo_next_hole(sa_manager, fences, tries)); - if (block) { - spin_unlock(&sa_manager->lock); - r = radeon_fence_wait_any(rdev, fences, false); - spin_lock(&sa_manager->lock); - if (r) { - /* if we have nothing to wait for we - are practically out of memory */ - if (r == -ENOENT) { - r = -ENOMEM; - } - goto out_err; - } + spin_unlock(&sa_manager->wq.lock); + r = radeon_fence_wait_any(rdev, fences, false); + spin_lock(&sa_manager->wq.lock); + /* if we have nothing to wait for block */ + if (r == -ENOENT) { + r = wait_event_interruptible_locked( + sa_manager->wq, + radeon_sa_event(sa_manager, size, align) + ); } - } while (block); -out_err: - spin_unlock(&sa_manager->lock); + } while (!r); + + spin_unlock(&sa_manager->wq.lock); kfree(*sa_bo); *sa_bo = NULL; return r; @@ -348,15 +378,16 @@ void radeon_sa_bo_free(struct radeon_device *rdev, struct radeon_sa_bo **sa_bo, } sa_manager = (*sa_bo)->manager; - spin_lock(&sa_manager->lock); - if (fence && fence->seq && fence->seq < RADEON_FENCE_NOTEMITED_SEQ) { + spin_lock(&sa_manager->wq.lock); + if (fence && !radeon_fence_signaled(fence)) { (*sa_bo)->fence = radeon_fence_ref(fence); list_add_tail(&(*sa_bo)->flist, &sa_manager->flist[fence->ring]); } else { radeon_sa_bo_remove_locked(*sa_bo); } - spin_unlock(&sa_manager->lock); + wake_up_all_locked(&sa_manager->wq); + spin_unlock(&sa_manager->wq.lock); *sa_bo = NULL; } @@ -366,21 +397,23 @@ void radeon_sa_bo_dump_debug_info(struct radeon_sa_manager *sa_manager, { struct radeon_sa_bo *i; - spin_lock(&sa_manager->lock); + spin_lock(&sa_manager->wq.lock); list_for_each_entry(i, &sa_manager->olist, olist) { + uint64_t soffset = i->soffset + sa_manager->gpu_addr; + uint64_t eoffset = i->eoffset + sa_manager->gpu_addr; if (&i->olist == sa_manager->hole) { seq_printf(m, ">"); } else { seq_printf(m, " "); } - seq_printf(m, "[0x%08x 0x%08x] size %8d", - i->soffset, i->eoffset, i->eoffset - i->soffset); + seq_printf(m, "[0x%010llx 0x%010llx] size %8lld", + soffset, eoffset, eoffset - soffset); if (i->fence) { seq_printf(m, " protected by 0x%016llx on ring %d", i->fence->seq, i->fence->ring); } seq_printf(m, "\n"); } - spin_unlock(&sa_manager->lock); + spin_unlock(&sa_manager->wq.lock); } #endif |
