On Mon, May 7, 2012 at 7:42 AM, Christian K?nig <deathsimple at vodafone.de> wrote: > A startover with a new idea for a multiple ring allocator. > Should perform as well as a normal ring allocator as long > as only one ring does somthing, but falls back to a more > complex algorithm if more complex things start to happen. > > We store the last allocated bo in last, we always try to allocate > after the last allocated bo. Principle is that in a linear GPU ring > progression was is after last is the oldest bo we allocated and thus > the first one that should no longer be in use by the GPU. > > If it's not the case we skip over the bo after last to the closest > done bo if such one exist. If none exist and we are not asked to > block we report failure to allocate. > > 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. > > v2: We need to be able to let hole point to the list_head, otherwise > ? ?try free will never free the first allocation of the list. Also > ? ?stop calling radeon_fence_signalled more than necessary. > > Signed-off-by: Christian K?nig <deathsimple at vodafone.de> > Signed-off-by: Jerome Glisse <jglisse at redhat.com>
This one is NAK please use my patch. Yes in my patch we never try to free anything if there is only on sa_bo in the list if you really care about this it's a one line change: http://people.freedesktop.org/~glisse/reset5/0001-drm-radeon-multiple-ring-allocator-v2.patch Your patch here can enter in infinite loop and never return holding the lock. See below. Cheers, Jerome > --- > ?drivers/gpu/drm/radeon/radeon.h ? ? ?| ? ?7 +- > ?drivers/gpu/drm/radeon/radeon_ring.c | ? 19 +-- > ?drivers/gpu/drm/radeon/radeon_sa.c ? | ?292 > +++++++++++++++++++++++----------- > ?3 files changed, 210 insertions(+), 108 deletions(-) > > diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h > index 37a7459..cc7f16a 100644 > --- a/drivers/gpu/drm/radeon/radeon.h > +++ b/drivers/gpu/drm/radeon/radeon.h > @@ -385,7 +385,9 @@ struct radeon_bo_list { > ?struct radeon_sa_manager { > ? ? ? ?spinlock_t ? ? ? ? ? ? ?lock; > ? ? ? ?struct radeon_bo ? ? ? ?*bo; > - ? ? ? struct list_head ? ? ? ?sa_bo; > + ? ? ? struct list_head ? ? ? ?*hole; > + ? ? ? struct list_head ? ? ? ?flist[RADEON_NUM_RINGS]; > + ? ? ? struct list_head ? ? ? ?olist; > ? ? ? ?unsigned ? ? ? ? ? ? ? ?size; > ? ? ? ?uint64_t ? ? ? ? ? ? ? ?gpu_addr; > ? ? ? ?void ? ? ? ? ? ? ? ? ? ?*cpu_ptr; > @@ -396,7 +398,8 @@ struct radeon_sa_bo; > > ?/* sub-allocation buffer */ > ?struct radeon_sa_bo { > - ? ? ? struct list_head ? ? ? ? ? ? ? ?list; > + ? ? ? struct list_head ? ? ? ? ? ? ? ?olist; > + ? ? ? struct list_head ? ? ? ? ? ? ? ?flist; > ? ? ? ?struct radeon_sa_manager ? ? ? ?*manager; > ? ? ? ?unsigned ? ? ? ? ? ? ? ? ? ? ? ?soffset; > ? ? ? ?unsigned ? ? ? ? ? ? ? ? ? ? ? ?eoffset; > diff --git a/drivers/gpu/drm/radeon/radeon_ring.c > b/drivers/gpu/drm/radeon/radeon_ring.c > index 1748d93..e074ff5 100644 > --- a/drivers/gpu/drm/radeon/radeon_ring.c > +++ b/drivers/gpu/drm/radeon/radeon_ring.c > @@ -204,25 +204,22 @@ int radeon_ib_schedule(struct radeon_device *rdev, > struct radeon_ib *ib) > > ?int radeon_ib_pool_init(struct radeon_device *rdev) > ?{ > - ? ? ? struct radeon_sa_manager tmp; > ? ? ? ?int i, r; > > - ? ? ? r = radeon_sa_bo_manager_init(rdev, &tmp, > - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? RADEON_IB_POOL_SIZE*64*1024, > - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? RADEON_GEM_DOMAIN_GTT); > - ? ? ? if (r) { > - ? ? ? ? ? ? ? return r; > - ? ? ? } > - > ? ? ? ?radeon_mutex_lock(&rdev->ib_pool.mutex); > ? ? ? ?if (rdev->ib_pool.ready) { > ? ? ? ? ? ? ? ?radeon_mutex_unlock(&rdev->ib_pool.mutex); > - ? ? ? ? ? ? ? radeon_sa_bo_manager_fini(rdev, &tmp); > ? ? ? ? ? ? ? ?return 0; > ? ? ? ?} > > - ? ? ? rdev->ib_pool.sa_manager = tmp; > - ? ? ? INIT_LIST_HEAD(&rdev->ib_pool.sa_manager.sa_bo); > + ? ? ? r = radeon_sa_bo_manager_init(rdev, &rdev->ib_pool.sa_manager, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? RADEON_IB_POOL_SIZE*64*1024, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? RADEON_GEM_DOMAIN_GTT); > + ? ? ? if (r) { > + ? ? ? ? ? ? ? radeon_mutex_unlock(&rdev->ib_pool.mutex); > + ? ? ? ? ? ? ? return r; > + ? ? ? } > + > ? ? ? ?for (i = 0; i < RADEON_IB_POOL_SIZE; i++) { > ? ? ? ? ? ? ? ?rdev->ib_pool.ibs[i].fence = NULL; > ? ? ? ? ? ? ? ?rdev->ib_pool.ibs[i].idx = i; > diff --git a/drivers/gpu/drm/radeon/radeon_sa.c > b/drivers/gpu/drm/radeon/radeon_sa.c > index 90ee8ad..757a9d4 100644 > --- a/drivers/gpu/drm/radeon/radeon_sa.c > +++ b/drivers/gpu/drm/radeon/radeon_sa.c > @@ -27,21 +27,42 @@ > ?* Authors: > ?* ? ?Jerome Glisse <glisse at freedesktop.org> > ?*/ > +/* Algorithm: > + * > + * We store the last allocated bo in "hole", we always try to allocate > + * after the last allocated bo. Principle is that in a linear GPU ring > + * progression was is after last is the oldest bo we allocated and thus > + * the first one that should no longer be in use by the GPU. > + * > + * If it's not the case we skip over the bo after last to the closest > + * done bo if such one exist. If none exist and we are not asked to > + * block we report failure to allocate. > + * > + * 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 "radeon.h" > > +static void radeon_sa_bo_remove_locked(struct radeon_sa_bo *sa_bo); > +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) > ?{ > - ? ? ? int r; > + ? ? ? int i, r; > > ? ? ? ?spin_lock_init(&sa_manager->lock); > ? ? ? ?sa_manager->bo = NULL; > ? ? ? ?sa_manager->size = size; > ? ? ? ?sa_manager->domain = domain; > - ? ? ? INIT_LIST_HEAD(&sa_manager->sa_bo); > + ? ? ? 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, &sa_manager->bo); > @@ -58,11 +79,15 @@ 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"); > + ? ? ? if (!list_empty(&sa_manager->olist)) { > + ? ? ? ? ? ? ? sa_manager->hole = &sa_manager->olist, > + ? ? ? ? ? ? ? radeon_sa_bo_try_free(sa_manager); > + ? ? ? ? ? ? ? if (!list_empty(&sa_manager->olist)) { > + ? ? ? ? ? ? ? ? ? ? ? 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); > + ? ? ? list_for_each_entry_safe(sa_bo, tmp, &sa_manager->olist, olist) { > + ? ? ? ? ? ? ? radeon_sa_bo_remove_locked(sa_bo); > ? ? ? ?} > ? ? ? ?radeon_bo_unref(&sa_manager->bo); > ? ? ? ?sa_manager->size = 0; > @@ -114,111 +139,181 @@ int radeon_sa_bo_manager_suspend(struct radeon_device > *rdev, > ? ? ? ?return r; > ?} > > -/* > - * Principe is simple, we keep a list of sub allocation in offset > - * order (first entry has offset == 0, last entry has the highest > - * offset). > - * > - * When allocating new object we first check if there is room at > - * the end total_size - (last_object_offset + last_object_size) >= > - * alloc_size. If so we allocate new object there. > - * > - * When there is not enough room at the end, we start waiting for > - * each sub object until we reach object_offset+object_size >= > - * alloc_size, this object then become the sub object we return. > - * > - * Alignment can't be bigger than page size > - */ > - > ?static void radeon_sa_bo_remove_locked(struct radeon_sa_bo *sa_bo) > ?{ > - ? ? ? list_del(&sa_bo->list); > + ? ? ? struct radeon_sa_manager *sa_manager = sa_bo->manager; > + ? ? ? if (sa_manager->hole == &sa_bo->olist) { > + ? ? ? ? ? ? ? sa_manager->hole = sa_bo->olist.prev; > + ? ? ? } > + ? ? ? list_del_init(&sa_bo->olist); > + ? ? ? list_del_init(&sa_bo->flist); > ? ? ? ?radeon_fence_unref(&sa_bo->fence); > ? ? ? ?kfree(sa_bo); > ?} > > +static void radeon_sa_bo_try_free(struct radeon_sa_manager *sa_manager) > +{ > + ? ? ? struct radeon_sa_bo *sa_bo, *tmp; > + > + ? ? ? if (sa_manager->hole->next == &sa_manager->olist) > + ? ? ? ? ? ? ? return; > + > + ? ? ? sa_bo = list_entry(sa_manager->hole->next, struct radeon_sa_bo, > olist); > + ? ? ? list_for_each_entry_safe_from(sa_bo, tmp, &sa_manager->olist, olist) { > + ? ? ? ? ? ? ? if (sa_bo->fence == NULL || > !radeon_fence_signaled(sa_bo->fence)) { > + ? ? ? ? ? ? ? ? ? ? ? return; > + ? ? ? ? ? ? ? } > + ? ? ? ? ? ? ? radeon_sa_bo_remove_locked(sa_bo); > + ? ? ? } > +} > + > +static inline unsigned radeon_sa_bo_hole_soffset(struct radeon_sa_manager > *sa_manager) > +{ > + ? ? ? struct list_head *hole = sa_manager->hole; > + > + ? ? ? if (hole != &sa_manager->olist) { > + ? ? ? ? ? ? ? return list_entry(hole, struct radeon_sa_bo, olist)->eoffset; > + ? ? ? } > + ? ? ? return 0; > +} > + > +static inline unsigned radeon_sa_bo_hole_eoffset(struct radeon_sa_manager > *sa_manager) > +{ > + ? ? ? struct list_head *hole = sa_manager->hole; > + > + ? ? ? if (hole->next != &sa_manager->olist) { > + ? ? ? ? ? ? ? return list_entry(hole->next, struct radeon_sa_bo, > olist)->soffset; > + ? ? ? } > + ? ? ? return sa_manager->size; > +} > + > +static bool radeon_sa_bo_try_alloc(struct radeon_sa_manager *sa_manager, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?struct radeon_sa_bo *sa_bo, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned size, unsigned align) > +{ > + ? ? ? unsigned soffset, eoffset, wasted; > + > + ? ? ? 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)) { > + ? ? ? ? ? ? ? soffset += wasted; > + > + ? ? ? ? ? ? ? sa_bo->manager = sa_manager; > + ? ? ? ? ? ? ? sa_bo->soffset = soffset; > + ? ? ? ? ? ? ? sa_bo->eoffset = soffset + size; > + ? ? ? ? ? ? ? list_add(&sa_bo->olist, sa_manager->hole); > + ? ? ? ? ? ? ? INIT_LIST_HEAD(&sa_bo->flist); > + ? ? ? ? ? ? ? sa_manager->hole = &sa_bo->olist; > + ? ? ? ? ? ? ? return true; > + ? ? ? } > + ? ? ? return false; > +} > + > +static bool radeon_sa_bo_next_hole(struct radeon_sa_manager *sa_manager, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?struct radeon_fence **fences) > +{ > + ? ? ? unsigned i, soffset, best, tmp; > + > + ? ? ? /* if hole points to the end of the buffer */ > + ? ? ? if (sa_manager->hole->next == &sa_manager->olist) { > + ? ? ? ? ? ? ? /* try again with its beginning */ > + ? ? ? ? ? ? ? sa_manager->hole = &sa_manager->olist; > + ? ? ? ? ? ? ? return true; > + ? ? ? } > + > + ? ? ? soffset = radeon_sa_bo_hole_soffset(sa_manager); > + ? ? ? /* to handle wrap around we add sa_manager->size */ > + ? ? ? best = sa_manager->size * 2; > + ? ? ? /* go over all fence list and try to find the closest sa_bo > + ? ? ? ?* of the current last > + ? ? ? ?*/ > + ? ? ? for (i = 0; i < RADEON_NUM_RINGS; ++i) { > + ? ? ? ? ? ? ? struct radeon_sa_bo *sa_bo; > + > + ? ? ? ? ? ? ? if (list_empty(&sa_manager->flist[i])) { > + ? ? ? ? ? ? ? ? ? ? ? fences[i] = NULL; > + ? ? ? ? ? ? ? ? ? ? ? continue; > + ? ? ? ? ? ? ? } > + > + ? ? ? ? ? ? ? sa_bo = list_first_entry(&sa_manager->flist[i], > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?struct radeon_sa_bo, flist); > + > + ? ? ? ? ? ? ? if (!radeon_fence_signaled(sa_bo->fence)) { > + ? ? ? ? ? ? ? ? ? ? ? fences[i] = sa_bo->fence; > + ? ? ? ? ? ? ? ? ? ? ? continue; > + ? ? ? ? ? ? ? } > + > + ? ? ? ? ? ? ? tmp = sa_bo->soffset; > + ? ? ? ? ? ? ? if (tmp < soffset) { > + ? ? ? ? ? ? ? ? ? ? ? /* wrap around, pretend it's after */ > + ? ? ? ? ? ? ? ? ? ? ? tmp += sa_manager->size; > + ? ? ? ? ? ? ? } > + ? ? ? ? ? ? ? tmp -= soffset; > + ? ? ? ? ? ? ? if (tmp < best) { > + ? ? ? ? ? ? ? ? ? ? ? /* this sa bo is the closest one */ > + ? ? ? ? ? ? ? ? ? ? ? best = tmp; > + ? ? ? ? ? ? ? ? ? ? ? sa_manager->hole = sa_bo->olist.prev; > + ? ? ? ? ? ? ? } > + > + ? ? ? ? ? ? ? /* we knew that this one is signaled, > + ? ? ? ? ? ? ? ? ?so it's save to remote it */ > + ? ? ? ? ? ? ? radeon_sa_bo_remove_locked(sa_bo); > + ? ? ? } > + ? ? ? return best != sa_manager->size * 2; > +} > + > ?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) > ?{ > - ? ? ? struct radeon_fence *fence = NULL; > - ? ? ? struct radeon_sa_bo *tmp, *next; > - ? ? ? struct list_head *head; > - ? ? ? unsigned offset = 0, wasted = 0; > - ? ? ? int r; > + ? ? ? struct radeon_fence *fences[RADEON_NUM_RINGS]; > + ? ? ? int r = -ENOMEM; > > ? ? ? ?BUG_ON(align > RADEON_GPU_PAGE_SIZE); > ? ? ? ?BUG_ON(size > sa_manager->size); > > ? ? ? ?*sa_bo = kmalloc(sizeof(struct radeon_sa_bo), GFP_KERNEL); > - > -retry: > + ? ? ? if ((*sa_bo) == NULL) { > + ? ? ? ? ? ? ? return -ENOMEM; > + ? ? ? } > + ? ? ? (*sa_bo)->manager = sa_manager; > + ? ? ? (*sa_bo)->fence = NULL; > + ? ? ? INIT_LIST_HEAD(&(*sa_bo)->olist); > + ? ? ? INIT_LIST_HEAD(&(*sa_bo)->flist); > > ? ? ? ?spin_lock(&sa_manager->lock); > + ? ? ? do { > + ? ? ? ? ? ? ? /* try to allocate couple time before going to wait */ > + ? ? ? ? ? ? ? do { > + ? ? ? ? ? ? ? ? ? ? ? radeon_sa_bo_try_free(sa_manager); > > - ? ? ? /* no one ? */ > - ? ? ? head = sa_manager->sa_bo.prev; > - ? ? ? if (list_empty(&sa_manager->sa_bo)) { > - ? ? ? ? ? ? ? goto out; > - ? ? ? } > - > - ? ? ? /* look for a hole big enough */ > - ? ? ? offset = 0; > - ? ? ? list_for_each_entry_safe(tmp, next, &sa_manager->sa_bo, list) { > - ? ? ? ? ? ? ? /* try to free this object */ > - ? ? ? ? ? ? ? if (tmp->fence) { > - ? ? ? ? ? ? ? ? ? ? ? if (radeon_fence_signaled(tmp->fence)) { > - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? radeon_sa_bo_remove_locked(tmp); > - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue; > - ? ? ? ? ? ? ? ? ? ? ? } else { > - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? fence = tmp->fence; > + ? ? ? ? ? ? ? ? ? ? ? if (radeon_sa_bo_try_alloc(sa_manager, *sa_bo, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?size, align)) { > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? spin_unlock(&sa_manager->lock); > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return 0; > ? ? ? ? ? ? ? ? ? ? ? ?} > - ? ? ? ? ? ? ? } > > - ? ? ? ? ? ? ? /* room before this object ? */ > - ? ? ? ? ? ? ? if (offset < tmp->soffset && (tmp->soffset - offset) >= size) > { > - ? ? ? ? ? ? ? ? ? ? ? head = tmp->list.prev; > - ? ? ? ? ? ? ? ? ? ? ? goto out; > - ? ? ? ? ? ? ? } > - ? ? ? ? ? ? ? offset = tmp->eoffset; > - ? ? ? ? ? ? ? wasted = offset % align; > - ? ? ? ? ? ? ? if (wasted) { > - ? ? ? ? ? ? ? ? ? ? ? wasted = align - wasted; > - ? ? ? ? ? ? ? } > - ? ? ? ? ? ? ? offset += wasted; > - ? ? ? } > - ? ? ? /* room at the end ? */ > - ? ? ? head = sa_manager->sa_bo.prev; > - ? ? ? tmp = list_entry(head, struct radeon_sa_bo, list); > - ? ? ? offset = tmp->eoffset; > - ? ? ? wasted = offset % align; > - ? ? ? if (wasted) { > - ? ? ? ? ? ? ? wasted = align - wasted; > - ? ? ? } > - ? ? ? offset += wasted; > - ? ? ? if ((sa_manager->size - offset) < size) { > - ? ? ? ? ? ? ? /* failed to find somethings big enough */ > - ? ? ? ? ? ? ? spin_unlock(&sa_manager->lock); > - ? ? ? ? ? ? ? if (block && fence) { > - ? ? ? ? ? ? ? ? ? ? ? r = radeon_fence_wait(fence, false); > - ? ? ? ? ? ? ? ? ? ? ? if (r) > - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return r; > - > - ? ? ? ? ? ? ? ? ? ? ? goto retry; > + ? ? ? ? ? ? ? ? ? ? ? /* see if we can skip over some allocations */ > + ? ? ? ? ? ? ? } while (radeon_sa_bo_next_hole(sa_manager, fences)); Here you can infinite loop, in the case there is a bunch of hole in the allocator but none of them allow to full fill the allocation. radeon_sa_bo_next_hole will keep returning true looping over and over on all the all. That's why i only restrict my patch to 2 hole skeeping and then fails the allocation or try to wait. I believe sadly we need an heuristic and 2 hole skeeping at most sounded like a good one. > + > + ? ? ? ? ? ? ? if (block) { > + ? ? ? ? ? ? ? ? ? ? ? spin_unlock(&sa_manager->lock); > + ? ? ? ? ? ? ? ? ? ? ? r = radeon_fence_wait_any(rdev, fences, false); > + ? ? ? ? ? ? ? ? ? ? ? spin_lock(&sa_manager->lock); > + ? ? ? ? ? ? ? ? ? ? ? if (r) { > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? goto out_err; > + ? ? ? ? ? ? ? ? ? ? ? } > ? ? ? ? ? ? ? ?} > - ? ? ? ? ? ? ? kfree(*sa_bo); > - ? ? ? ? ? ? ? *sa_bo = NULL; > - ? ? ? ? ? ? ? return -ENOMEM; > - ? ? ? } > + ? ? ? } while (block); > > -out: > - ? ? ? (*sa_bo)->manager = sa_manager; > - ? ? ? (*sa_bo)->soffset = offset; > - ? ? ? (*sa_bo)->eoffset = offset + size; > - ? ? ? list_add(&(*sa_bo)->list, head); > +out_err: > ? ? ? ?spin_unlock(&sa_manager->lock); > - ? ? ? return 0; > + ? ? ? kfree(*sa_bo); > + ? ? ? *sa_bo = NULL; > + ? ? ? return r; > ?} > > ?void radeon_sa_bo_free(struct radeon_device *rdev, struct radeon_sa_bo > **sa_bo, > @@ -226,13 +321,16 @@ void radeon_sa_bo_free(struct radeon_device *rdev, > struct radeon_sa_bo **sa_bo, > ?{ > ? ? ? ?struct radeon_sa_manager *sa_manager; > > - ? ? ? if (!sa_bo || !*sa_bo) > + ? ? ? if (sa_bo == NULL || *sa_bo == NULL) { > ? ? ? ? ? ? ? ?return; > + ? ? ? } > > ? ? ? ?sa_manager = (*sa_bo)->manager; > ? ? ? ?spin_lock(&sa_manager->lock); > ? ? ? ?if (fence && fence->seq && fence->seq < RADEON_FENCE_NOTEMITED_SEQ) { > ? ? ? ? ? ? ? ?(*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); > ? ? ? ?} > @@ -247,15 +345,19 @@ void radeon_sa_bo_dump_debug_info(struct > radeon_sa_manager *sa_manager, > ? ? ? ?struct radeon_sa_bo *i; > > ? ? ? ?spin_lock(&sa_manager->lock); > - ? ? ? list_for_each_entry(i, &sa_manager->sa_bo, list) { > - ? ? ? ? ? ? ? seq_printf(m, "[%08x %08x] size %4d (%p)", > - ? ? ? ? ? ? ? ? ? ? ? ? ?i->soffset, i->eoffset, i->eoffset - i->soffset, > i); > - ? ? ? ? ? ? ? if (i->fence) { > - ? ? ? ? ? ? ? ? ? ? ? seq_printf(m, " protected by %Ld (%p) on ring %d\n", > - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?i->fence->seq, i->fence, i->fence->ring); > + ? ? ? list_for_each_entry(i, &sa_manager->olist, olist) { > + ? ? ? ? ? ? ? if (&i->olist == sa_manager->hole) { > + ? ? ? ? ? ? ? ? ? ? ? seq_printf(m, ">"); > ? ? ? ? ? ? ? ?} else { > - ? ? ? ? ? ? ? ? ? ? ? seq_printf(m, "\n"); > + ? ? ? ? ? ? ? ? ? ? ? seq_printf(m, " "); > + ? ? ? ? ? ? ? } > + ? ? ? ? ? ? ? seq_printf(m, "[0x%08x 0x%08x] size %8d", > + ? ? ? ? ? ? ? ? ? ? ? ? ?i->soffset, i->eoffset, i->eoffset - i->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); > ?} > -- > 1.7.5.4 >