drm/nouveau: greatly simplify mm, killing some bugs in the process
authorBen Skeggs <bskeggs@redhat.com>
Fri, 14 Jan 2011 05:46:30 +0000 (15:46 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Mon, 17 Jan 2011 01:28:54 +0000 (11:28 +1000)
Reviewed-by: Francisco Jerez <currojerez@riseup.net>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nouveau_mem.c
drivers/gpu/drm/nouveau/nouveau_mm.c
drivers/gpu/drm/nouveau/nouveau_mm.h

index 69044eb104bbbffcea2241811bb0c3f93038276a..26347b7cd8722e95c70d425416b8ed40c236e15e 100644 (file)
@@ -742,30 +742,24 @@ nouveau_vram_manager_debug(struct ttm_mem_type_manager *man, const char *prefix)
 {
        struct nouveau_mm *mm = man->priv;
        struct nouveau_mm_node *r;
-       u64 total = 0, ttotal[3] = {}, tused[3] = {}, tfree[3] = {};
-       int i;
+       u32 total = 0, free = 0;
 
        mutex_lock(&mm->mutex);
        list_for_each_entry(r, &mm->nodes, nl_entry) {
-               printk(KERN_DEBUG "%s %s-%d: 0x%010llx 0x%010llx\n",
-                      prefix, r->free ? "free" : "used", r->type,
-                      ((u64)r->offset << 12),
+               printk(KERN_DEBUG "%s %d: 0x%010llx 0x%010llx\n",
+                      prefix, r->type, ((u64)r->offset << 12),
                       (((u64)r->offset + r->length) << 12));
+
                total += r->length;
-               ttotal[r->type] += r->length;
-               if (r->free)
-                       tfree[r->type] += r->length;
-               else
-                       tused[r->type] += r->length;
+               if (!r->type)
+                       free += r->length;
        }
        mutex_unlock(&mm->mutex);
 
-       printk(KERN_DEBUG "%s  total: 0x%010llx\n", prefix, total << 12);
-       for (i = 0; i < 3; i++) {
-               printk(KERN_DEBUG "%s type %d: 0x%010llx, "
-                                 "used 0x%010llx, free 0x%010llx\n", prefix,
-                      i, ttotal[i] << 12, tused[i] << 12, tfree[i] << 12);
-       }
+       printk(KERN_DEBUG "%s  total: 0x%010llx free: 0x%010llx\n",
+              prefix, (u64)total << 12, (u64)free << 12);
+       printk(KERN_DEBUG "%s  block: 0x%08x\n",
+              prefix, mm->block_size << 12);
 }
 
 const struct ttm_mem_type_manager_func nouveau_vram_manager = {
index cdbb11eb701b34525c0678cf8cab3bfb214491b3..8844b50c3e540f697b973748da96203f9a5b9993 100644 (file)
@@ -48,175 +48,76 @@ region_split(struct nouveau_mm *rmm, struct nouveau_mm_node *a, u32 size)
 
        b->offset = a->offset;
        b->length = size;
-       b->free   = a->free;
        b->type   = a->type;
        a->offset += size;
        a->length -= size;
        list_add_tail(&b->nl_entry, &a->nl_entry);
-       if (b->free)
+       if (b->type == 0)
                list_add_tail(&b->fl_entry, &a->fl_entry);
        return b;
 }
 
-static struct nouveau_mm_node *
-nouveau_mm_merge(struct nouveau_mm *rmm, struct nouveau_mm_node *this)
-{
-       struct nouveau_mm_node *prev, *next;
-
-       /* try to merge with free adjacent entries of same type */
-       prev = list_entry(this->nl_entry.prev, struct nouveau_mm_node, nl_entry);
-       if (this->nl_entry.prev != &rmm->nodes) {
-               if (prev->free && prev->type == this->type) {
-                       prev->length += this->length;
-                       region_put(rmm, this);
-                       this = prev;
-               }
-       }
-
-       next = list_entry(this->nl_entry.next, struct nouveau_mm_node, nl_entry);
-       if (this->nl_entry.next != &rmm->nodes) {
-               if (next->free && next->type == this->type) {
-                       next->offset  = this->offset;
-                       next->length += this->length;
-                       region_put(rmm, this);
-                       this = next;
-               }
-       }
-
-       return this;
-}
+#define node(root, dir) ((root)->nl_entry.dir == &rmm->nodes) ? NULL : \
+       list_entry((root)->nl_entry.dir, struct nouveau_mm_node, nl_entry)
 
 void
 nouveau_mm_put(struct nouveau_mm *rmm, struct nouveau_mm_node *this)
 {
-       u32 block_s, block_l;
+       struct nouveau_mm_node *prev = node(this, prev);
+       struct nouveau_mm_node *next = node(this, next);
 
-       this->free = true;
        list_add(&this->fl_entry, &rmm->free);
-       this = nouveau_mm_merge(rmm, this);
-
-       /* any entirely free blocks now?  we'll want to remove typing
-        * on them now so they can be use for any memory allocation
-        */
-       block_s = roundup(this->offset, rmm->block_size);
-       if (block_s + rmm->block_size > this->offset + this->length)
-               return;
+       this->type = 0;
 
-       /* split off any still-typed region at the start */
-       if (block_s != this->offset) {
-               if (!region_split(rmm, this, block_s - this->offset))
-                       return;
+       if (prev && prev->type == 0) {
+               prev->length += this->length;
+               region_put(rmm, this);
+               this = prev;
        }
 
-       /* split off the soon-to-be-untyped block(s) */
-       block_l = rounddown(this->length, rmm->block_size);
-       if (block_l != this->length) {
-               this = region_split(rmm, this, block_l);
-               if (!this)
-                       return;
+       if (next && next->type == 0) {
+               next->offset  = this->offset;
+               next->length += this->length;
+               region_put(rmm, this);
        }
-
-       /* mark as having no type, and retry merge with any adjacent
-        * untyped blocks
-        */
-       this->type = 0;
-       nouveau_mm_merge(rmm, this);
 }
 
 int
 nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc,
               u32 align, struct nouveau_mm_node **pnode)
 {
-       struct nouveau_mm_node *this, *tmp, *next;
-       u32 splitoff, avail, alloc;
-
-       list_for_each_entry_safe(this, tmp, &rmm->free, fl_entry) {
-               next = list_entry(this->nl_entry.next, struct nouveau_mm_node, nl_entry);
-               if (this->nl_entry.next == &rmm->nodes)
-                       next = NULL;
-
-               /* skip wrongly typed blocks */
-               if (this->type && this->type != type)
+       struct nouveau_mm_node *prev, *this, *next;
+       u32 min = size_nc ? size_nc : size;
+       u32 align_mask = align - 1;
+       u32 splitoff;
+       u32 s, e;
+
+       list_for_each_entry(this, &rmm->free, fl_entry) {
+               e = this->offset + this->length;
+               s = this->offset;
+
+               prev = node(this, prev);
+               if (prev && prev->type != type)
+                       s = roundup(s, rmm->block_size);
+
+               next = node(this, next);
+               if (next && next->type != type)
+                       e = rounddown(e, rmm->block_size);
+
+               s  = (s + align_mask) & ~align_mask;
+               e &= ~align_mask;
+               if (s > e || e - s < min)
                        continue;
 
-               /* account for alignment */
-               splitoff = this->offset & (align - 1);
-               if (splitoff)
-                       splitoff = align - splitoff;
-
-               if (this->length <= splitoff)
-                       continue;
-
-               /* determine total memory available from this, and
-                * the next block (if appropriate)
-                */
-               avail = this->length;
-               if (next && next->free && (!next->type || next->type == type))
-                       avail += next->length;
-
-               avail -= splitoff;
-
-               /* determine allocation size */
-               if (size_nc) {
-                       alloc = min(avail, size);
-                       alloc = rounddown(alloc, size_nc);
-                       if (alloc == 0)
-                               continue;
-               } else {
-                       alloc = size;
-                       if (avail < alloc)
-                               continue;
-               }
-
-               /* untyped block, split off a chunk that's a multiple
-                * of block_size and type it
-                */
-               if (!this->type) {
-                       u32 block = roundup(alloc + splitoff, rmm->block_size);
-                       if (this->length < block)
-                               continue;
-
-                       this = region_split(rmm, this, block);
-                       if (!this)
-                               return -ENOMEM;
-
-                       this->type = type;
-               }
-
-               /* stealing memory from adjacent block */
-               if (alloc > this->length) {
-                       u32 amount = alloc - (this->length - splitoff);
-
-                       if (!next->type) {
-                               amount = roundup(amount, rmm->block_size);
-
-                               next = region_split(rmm, next, amount);
-                               if (!next)
-                                       return -ENOMEM;
-
-                               next->type = type;
-                       }
-
-                       this->length += amount;
-                       next->offset += amount;
-                       next->length -= amount;
-                       if (!next->length) {
-                               list_del(&next->nl_entry);
-                               list_del(&next->fl_entry);
-                               kfree(next);
-                       }
-               }
-
-               if (splitoff) {
-                       if (!region_split(rmm, this, splitoff))
-                               return -ENOMEM;
-               }
+               splitoff = s - this->offset;
+               if (splitoff && !region_split(rmm, this, splitoff))
+                       return -ENOMEM;
 
-               this = region_split(rmm, this, alloc);
-               if (this == NULL)
+               this = region_split(rmm, this, min(size, e - s));
+               if (!this)
                        return -ENOMEM;
 
-               this->free = false;
+               this->type = type;
                list_del(&this->fl_entry);
                *pnode = this;
                return 0;
@@ -234,7 +135,6 @@ nouveau_mm_init(struct nouveau_mm **prmm, u32 offset, u32 length, u32 block)
        heap = kzalloc(sizeof(*heap), GFP_KERNEL);
        if (!heap)
                return -ENOMEM;
-       heap->free = true;
        heap->offset = roundup(offset, block);
        heap->length = rounddown(offset + length, block) - heap->offset;
 
index af38449330364779e28c4157b5eecacc87dbead2..798eaf39691c40e0a2740a4aa015beeb92564efa 100644 (file)
@@ -30,9 +30,7 @@ struct nouveau_mm_node {
        struct list_head fl_entry;
        struct list_head rl_entry;
 
-       bool free;
-       int  type;
-
+       u8  type;
        u32 offset;
        u32 length;
 };