drm/nouveau: use drm_mm in preference to custom code doing the same thing
authorBen Skeggs <bskeggs@redhat.com>
Tue, 1 Jun 2010 05:32:24 +0000 (15:32 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Tue, 13 Jul 2010 00:12:51 +0000 (10:12 +1000)
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_mem.c
drivers/gpu/drm/nouveau/nouveau_notifier.c
drivers/gpu/drm/nouveau/nouveau_object.c
drivers/gpu/drm/nouveau/nv04_instmem.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_instmem.c

index c697191064894345efbbf76bf3bfd1fc83188270..20c54884dcb784162aaede75e06468ba13eeadd3 100644 (file)
@@ -123,14 +123,6 @@ nvbo_kmap_obj_iovirtual(struct nouveau_bo *nvbo)
        return ioptr;
 }
 
-struct mem_block {
-       struct mem_block *next;
-       struct mem_block *prev;
-       uint64_t start;
-       uint64_t size;
-       struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */
-};
-
 enum nouveau_flags {
        NV_NFORCE   = 0x10000000,
        NV_NFORCE2  = 0x20000000
@@ -149,7 +141,7 @@ struct nouveau_gpuobj {
        struct list_head list;
 
        struct nouveau_channel *im_channel;
-       struct mem_block *im_pramin;
+       struct drm_mm_node *im_pramin;
        struct nouveau_bo *im_backing;
        uint32_t im_backing_start;
        uint32_t *im_backing_suspend;
@@ -206,7 +198,7 @@ struct nouveau_channel {
 
        /* Notifier memory */
        struct nouveau_bo *notifier_bo;
-       struct mem_block *notifier_heap;
+       struct drm_mm notifier_heap;
 
        /* PFIFO context */
        struct nouveau_gpuobj_ref *ramfc;
@@ -224,7 +216,7 @@ struct nouveau_channel {
 
        /* Objects */
        struct nouveau_gpuobj_ref *ramin; /* Private instmem */
-       struct mem_block          *ramin_heap; /* Private PRAMIN heap */
+       struct drm_mm              ramin_heap; /* Private PRAMIN heap */
        struct nouveau_gpuobj_ref *ramht; /* Hash table */
        struct list_head           ramht_refs; /* Objects referenced by RAMHT */
 
@@ -595,7 +587,7 @@ struct drm_nouveau_private {
        struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR];
        int vm_vram_pt_nr;
 
-       struct mem_block *ramin_heap;
+       struct drm_mm ramin_heap;
 
        /* context table pointed to be NV_PGRAPH_CHANNEL_CTX_TABLE (0x400780) */
        uint32_t ctx_table_size;
@@ -707,15 +699,7 @@ extern bool nouveau_wait_for_idle(struct drm_device *);
 extern int  nouveau_card_init(struct drm_device *);
 
 /* nouveau_mem.c */
-extern int  nouveau_mem_init_heap(struct mem_block **, uint64_t start,
-                                uint64_t size);
-extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *,
-                                                uint64_t size, int align2,
-                                                struct drm_file *, int tail);
-extern void nouveau_mem_takedown(struct mem_block **heap);
-extern void nouveau_mem_free_block(struct mem_block *);
 extern int  nouveau_mem_detect(struct drm_device *dev);
-extern void nouveau_mem_release(struct drm_file *, struct mem_block *heap);
 extern int  nouveau_mem_init(struct drm_device *);
 extern int  nouveau_mem_init_agp(struct drm_device *);
 extern void nouveau_mem_close(struct drm_device *);
index fb6b791506b2cf7ec0f243f48b3388dd2e728f48..4274281f45ce7111075694ce0f9e56fc14607198 100644 (file)
 #include "drm_sarea.h"
 #include "nouveau_drv.h"
 
-static struct mem_block *
-split_block(struct mem_block *p, uint64_t start, uint64_t size,
-           struct drm_file *file_priv)
-{
-       /* Maybe cut off the start of an existing block */
-       if (start > p->start) {
-               struct mem_block *newblock =
-                       kmalloc(sizeof(*newblock), GFP_KERNEL);
-               if (!newblock)
-                       goto out;
-               newblock->start = start;
-               newblock->size = p->size - (start - p->start);
-               newblock->file_priv = NULL;
-               newblock->next = p->next;
-               newblock->prev = p;
-               p->next->prev = newblock;
-               p->next = newblock;
-               p->size -= newblock->size;
-               p = newblock;
-       }
-
-       /* Maybe cut off the end of an existing block */
-       if (size < p->size) {
-               struct mem_block *newblock =
-                       kmalloc(sizeof(*newblock), GFP_KERNEL);
-               if (!newblock)
-                       goto out;
-               newblock->start = start + size;
-               newblock->size = p->size - size;
-               newblock->file_priv = NULL;
-               newblock->next = p->next;
-               newblock->prev = p;
-               p->next->prev = newblock;
-               p->next = newblock;
-               p->size = size;
-       }
-
-out:
-       /* Our block is in the middle */
-       p->file_priv = file_priv;
-       return p;
-}
-
-struct mem_block *
-nouveau_mem_alloc_block(struct mem_block *heap, uint64_t size,
-                       int align2, struct drm_file *file_priv, int tail)
-{
-       struct mem_block *p;
-       uint64_t mask = (1 << align2) - 1;
-
-       if (!heap)
-               return NULL;
-
-       if (tail) {
-               list_for_each_prev(p, heap) {
-                       uint64_t start = ((p->start + p->size) - size) & ~mask;
-
-                       if (p->file_priv == NULL && start >= p->start &&
-                           start + size <= p->start + p->size)
-                               return split_block(p, start, size, file_priv);
-               }
-       } else {
-               list_for_each(p, heap) {
-                       uint64_t start = (p->start + mask) & ~mask;
-
-                       if (p->file_priv == NULL &&
-                           start + size <= p->start + p->size)
-                               return split_block(p, start, size, file_priv);
-               }
-       }
-
-       return NULL;
-}
-
-void nouveau_mem_free_block(struct mem_block *p)
-{
-       p->file_priv = NULL;
-
-       /* Assumes a single contiguous range.  Needs a special file_priv in
-        * 'heap' to stop it being subsumed.
-        */
-       if (p->next->file_priv == NULL) {
-               struct mem_block *q = p->next;
-               p->size += q->size;
-               p->next = q->next;
-               p->next->prev = p;
-               kfree(q);
-       }
-
-       if (p->prev->file_priv == NULL) {
-               struct mem_block *q = p->prev;
-               q->size += p->size;
-               q->next = p->next;
-               q->next->prev = q;
-               kfree(p);
-       }
-}
-
-/* Initialize.  How to check for an uninitialized heap?
- */
-int nouveau_mem_init_heap(struct mem_block **heap, uint64_t start,
-                         uint64_t size)
-{
-       struct mem_block *blocks = kmalloc(sizeof(*blocks), GFP_KERNEL);
-
-       if (!blocks)
-               return -ENOMEM;
-
-       *heap = kmalloc(sizeof(**heap), GFP_KERNEL);
-       if (!*heap) {
-               kfree(blocks);
-               return -ENOMEM;
-       }
-
-       blocks->start = start;
-       blocks->size = size;
-       blocks->file_priv = NULL;
-       blocks->next = blocks->prev = *heap;
-
-       memset(*heap, 0, sizeof(**heap));
-       (*heap)->file_priv = (struct drm_file *) -1;
-       (*heap)->next = (*heap)->prev = blocks;
-       return 0;
-}
-
-/*
- * Free all blocks associated with the releasing file_priv
- */
-void nouveau_mem_release(struct drm_file *file_priv, struct mem_block *heap)
-{
-       struct mem_block *p;
-
-       if (!heap || !heap->next)
-               return;
-
-       list_for_each(p, heap) {
-               if (p->file_priv == file_priv)
-                       p->file_priv = NULL;
-       }
-
-       /* Assumes a single contiguous range.  Needs a special file_priv in
-        * 'heap' to stop it being subsumed.
-        */
-       list_for_each(p, heap) {
-               while ((p->file_priv == NULL) &&
-                                       (p->next->file_priv == NULL) &&
-                                       (p->next != heap)) {
-                       struct mem_block *q = p->next;
-                       p->size += q->size;
-                       p->next = q->next;
-                       p->next->prev = p;
-                       kfree(q);
-               }
-       }
-}
-
 /*
  * NV10-NV40 tiling helpers
  */
@@ -421,24 +265,8 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
 /*
  * Cleanup everything
  */
-void nouveau_mem_takedown(struct mem_block **heap)
-{
-       struct mem_block *p;
-
-       if (!*heap)
-               return;
-
-       for (p = (*heap)->next; p != *heap;) {
-               struct mem_block *q = p;
-               p = p->next;
-               kfree(q);
-       }
-
-       kfree(*heap);
-       *heap = NULL;
-}
-
-void nouveau_mem_close(struct drm_device *dev)
+void
+nouveau_mem_close(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
 
index 9537f3e30115fb16135794aa674fa2a65da7ecb7..32f7fbd7484de9c5fe01a06b00e32582cce80354 100644 (file)
@@ -55,7 +55,7 @@ nouveau_notifier_init_channel(struct nouveau_channel *chan)
        if (ret)
                goto out_err;
 
-       ret = nouveau_mem_init_heap(&chan->notifier_heap, 0, ntfy->bo.mem.size);
+       ret = drm_mm_init(&chan->notifier_heap, 0, ntfy->bo.mem.size);
        if (ret)
                goto out_err;
 
@@ -80,7 +80,7 @@ nouveau_notifier_takedown_channel(struct nouveau_channel *chan)
        nouveau_bo_unpin(chan->notifier_bo);
        mutex_unlock(&dev->struct_mutex);
        drm_gem_object_unreference_unlocked(chan->notifier_bo->gem);
-       nouveau_mem_takedown(&chan->notifier_heap);
+       drm_mm_takedown(&chan->notifier_heap);
 }
 
 static void
@@ -90,7 +90,7 @@ nouveau_notifier_gpuobj_dtor(struct drm_device *dev,
        NV_DEBUG(dev, "\n");
 
        if (gpuobj->priv)
-               nouveau_mem_free_block(gpuobj->priv);
+               drm_mm_put_block(gpuobj->priv);
 }
 
 int
@@ -100,18 +100,13 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_gpuobj *nobj = NULL;
-       struct mem_block *mem;
+       struct drm_mm_node *mem;
        uint32_t offset;
        int target, ret;
 
-       if (!chan->notifier_heap) {
-               NV_ERROR(dev, "Channel %d doesn't have a notifier heap!\n",
-                        chan->id);
-               return -EINVAL;
-       }
-
-       mem = nouveau_mem_alloc_block(chan->notifier_heap, size, 0,
-                                     (struct drm_file *)-2, 0);
+       mem = drm_mm_search_free(&chan->notifier_heap, size, 0, 0);
+       if (mem)
+               mem = drm_mm_get_block(mem, size, 0);
        if (!mem) {
                NV_ERROR(dev, "Channel %d notifier block full\n", chan->id);
                return -ENOMEM;
@@ -144,17 +139,17 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
                                     mem->size, NV_DMA_ACCESS_RW, target,
                                     &nobj);
        if (ret) {
-               nouveau_mem_free_block(mem);
+               drm_mm_put_block(mem);
                NV_ERROR(dev, "Error creating notifier ctxdma: %d\n", ret);
                return ret;
        }
-       nobj->dtor   = nouveau_notifier_gpuobj_dtor;
-       nobj->priv   = mem;
+       nobj->dtor = nouveau_notifier_gpuobj_dtor;
+       nobj->priv = mem;
 
        ret = nouveau_gpuobj_ref_add(dev, chan, handle, nobj, NULL);
        if (ret) {
                nouveau_gpuobj_del(dev, &nobj);
-               nouveau_mem_free_block(mem);
+               drm_mm_put_block(mem);
                NV_ERROR(dev, "Error referencing notifier ctxdma: %d\n", ret);
                return ret;
        }
@@ -170,7 +165,7 @@ nouveau_notifier_offset(struct nouveau_gpuobj *nobj, uint32_t *poffset)
                return -EINVAL;
 
        if (poffset) {
-               struct mem_block *mem = nobj->priv;
+               struct drm_mm_node *mem = nobj->priv;
 
                if (*poffset >= mem->size)
                        return false;
index e7c100ba63a16d2d3b45284de22f1073767758de..d436c3c7f4f5990bcbb9bad629b1f111673d18bb 100644 (file)
@@ -209,7 +209,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_engine *engine = &dev_priv->engine;
        struct nouveau_gpuobj *gpuobj;
-       struct mem_block *pramin = NULL;
+       struct drm_mm *pramin = NULL;
        int ret;
 
        NV_DEBUG(dev, "ch%d size=%u align=%d flags=0x%08x\n",
@@ -233,17 +233,17 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
         * available.
         */
        if (chan) {
-               if (chan->ramin_heap) {
+               if (chan->ramin_heap.ml_entry.next) {
                        NV_DEBUG(dev, "private heap\n");
-                       pramin = chan->ramin_heap;
+                       pramin = &chan->ramin_heap;
                } else
                if (dev_priv->card_type < NV_50) {
                        NV_DEBUG(dev, "global heap fallback\n");
-                       pramin = dev_priv->ramin_heap;
+                       pramin = &dev_priv->ramin_heap;
                }
        } else {
                NV_DEBUG(dev, "global heap\n");
-               pramin = dev_priv->ramin_heap;
+               pramin = &dev_priv->ramin_heap;
        }
 
        if (!pramin) {
@@ -260,9 +260,10 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
        }
 
        /* Allocate a chunk of the PRAMIN aperture */
-       gpuobj->im_pramin = nouveau_mem_alloc_block(pramin, size,
-                                                   drm_order(align),
-                                                   (struct drm_file *)-2, 0);
+       gpuobj->im_pramin = drm_mm_search_free(pramin, size, align, 0);
+       if (gpuobj->im_pramin)
+               gpuobj->im_pramin = drm_mm_get_block(gpuobj->im_pramin, size, align);
+
        if (!gpuobj->im_pramin) {
                nouveau_gpuobj_del(dev, &gpuobj);
                return -ENOMEM;
@@ -386,7 +387,7 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
                if (gpuobj->flags & NVOBJ_FLAG_FAKE)
                        kfree(gpuobj->im_pramin);
                else
-                       nouveau_mem_free_block(gpuobj->im_pramin);
+                       drm_mm_put_block(gpuobj->im_pramin);
        }
 
        list_del(&gpuobj->list);
@@ -589,7 +590,7 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset,
        list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
 
        if (p_offset != ~0) {
-               gpuobj->im_pramin = kzalloc(sizeof(struct mem_block),
+               gpuobj->im_pramin = kzalloc(sizeof(struct drm_mm_node),
                                            GFP_KERNEL);
                if (!gpuobj->im_pramin) {
                        nouveau_gpuobj_del(dev, &gpuobj);
@@ -944,8 +945,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
        }
        pramin = chan->ramin->gpuobj;
 
-       ret = nouveau_mem_init_heap(&chan->ramin_heap,
-                                   pramin->im_pramin->start + base, size);
+       ret = drm_mm_init(&chan->ramin_heap, pramin->im_pramin->start + base, size);
        if (ret) {
                NV_ERROR(dev, "Error creating PRAMIN heap: %d\n", ret);
                nouveau_gpuobj_ref_del(dev, &chan->ramin);
@@ -1130,8 +1130,8 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan)
        for (i = 0; i < dev_priv->vm_vram_pt_nr; i++)
                nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]);
 
-       if (chan->ramin_heap)
-               nouveau_mem_takedown(&chan->ramin_heap);
+       if (chan->ramin_heap.free_stack.next)
+               drm_mm_takedown(&chan->ramin_heap);
        if (chan->ramin)
                nouveau_gpuobj_ref_del(dev, &chan->ramin);
 
index a3b9563a6f60c4f933cd9caf687da307eaac90ae..17af702d6ddcbc434c1c823f3907356c29c2a358 100644 (file)
@@ -106,7 +106,7 @@ int nv04_instmem_init(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        uint32_t offset;
-       int ret = 0;
+       int ret;
 
        nv04_instmem_determine_amount(dev);
        nv04_instmem_configure_fixed_tables(dev);
@@ -129,14 +129,14 @@ int nv04_instmem_init(struct drm_device *dev)
                        offset = 0x40000;
        }
 
-       ret = nouveau_mem_init_heap(&dev_priv->ramin_heap,
-                                   offset, dev_priv->ramin_rsvd_vram - offset);
+       ret = drm_mm_init(&dev_priv->ramin_heap, offset,
+                         dev_priv->ramin_rsvd_vram - offset);
        if (ret) {
-               dev_priv->ramin_heap = NULL;
-               NV_ERROR(dev, "Failed to init RAMIN heap\n");
+               NV_ERROR(dev, "Failed to init RAMIN heap: %d\n", ret);
+               return ret;
        }
 
-       return ret;
+       return 0;
 }
 
 void
index 580a5d10be9322cb581fc357a3b5215e7a3fcf10..515edde2c59fa387d50eebb9d53017d90c5cd5f4 100644 (file)
@@ -110,8 +110,8 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan)
                return ret;
        }
 
-       ret = nouveau_mem_init_heap(&chan->ramin_heap, chan->ramin->gpuobj->
-                                   im_pramin->start, 32768);
+       ret = drm_mm_init(&chan->ramin_heap,
+                         chan->ramin->gpuobj->im_pramin->start, 32768);
        if (ret) {
                NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret);
                nv50_evo_channel_del(pchan);
index 71c01b6e57319669cdaf995d1334c48375310ce8..a361d1612bd74162fdfa4686163b8e41cd221ac4 100644 (file)
@@ -147,7 +147,7 @@ nv50_instmem_init(struct drm_device *dev)
        if (ret)
                return ret;
 
-       if (nouveau_mem_init_heap(&chan->ramin_heap, c_base, c_size - c_base))
+       if (drm_mm_init(&chan->ramin_heap, c_base, c_size - c_base))
                return -ENOMEM;
 
        /* RAMFC + zero channel's PRAMIN up to start of VM pagedir */
@@ -276,9 +276,7 @@ nv50_instmem_init(struct drm_device *dev)
        nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, save_nv001700);
 
        /* Global PRAMIN heap */
-       if (nouveau_mem_init_heap(&dev_priv->ramin_heap,
-                                 c_size, dev_priv->ramin_size - c_size)) {
-               dev_priv->ramin_heap = NULL;
+       if (drm_mm_init(&dev_priv->ramin_heap, c_size, dev_priv->ramin_size - c_size)) {
                NV_ERROR(dev, "Failed to init RAMIN heap\n");
        }
 
@@ -321,7 +319,7 @@ nv50_instmem_takedown(struct drm_device *dev)
                nouveau_gpuobj_del(dev, &chan->vm_pd);
                nouveau_gpuobj_ref_del(dev, &chan->ramfc);
                nouveau_gpuobj_ref_del(dev, &chan->ramin);
-               nouveau_mem_takedown(&chan->ramin_heap);
+               drm_mm_takedown(&chan->ramin_heap);
 
                dev_priv->fifos[0] = dev_priv->fifos[127] = NULL;
                kfree(chan);
@@ -436,14 +434,14 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
        if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound)
                return -EINVAL;
 
-       NV_DEBUG(dev, "st=0x%0llx sz=0x%0llx\n",
+       NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n",
                 gpuobj->im_pramin->start, gpuobj->im_pramin->size);
 
        pte     = (gpuobj->im_pramin->start >> 12) << 1;
        pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte;
        vram    = gpuobj->im_backing_start;
 
-       NV_DEBUG(dev, "pramin=0x%llx, pte=%d, pte_end=%d\n",
+       NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n",
                 gpuobj->im_pramin->start, pte, pte_end);
        NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start);