nouveau: allocate drm-use vram buffers from end of vram.
authorBen Skeggs <skeggsb@nisroch.keine.ath.cx>
Sun, 22 Jun 2008 15:00:42 +0000 (01:00 +1000)
committerMaarten Maathuis <madman2003@gmail.com>
Wed, 25 Jun 2008 07:55:14 +0000 (09:55 +0200)
This avoids seeing garbage from engine setup etc before X gets around
to pointing the CRTCs at a new scanout buffer.  Not actually a noticable
problem before G80 as PRAMIN is forced to the end of VRAM by the hardware
already.

shared-core/nouveau_drm.h
shared-core/nouveau_drv.h
shared-core/nouveau_mem.c
shared-core/nouveau_notifier.c
shared-core/nouveau_object.c

index cf76205..bbb51bc 100644 (file)
@@ -88,9 +88,11 @@ struct drm_nouveau_gpuobj_free {
 #define NOUVEAU_MEM_INSTANCE           0x00000200 /* internal */
 #define NOUVEAU_MEM_NOTIFIER            0x00000400 /* internal */
 #define NOUVEAU_MEM_NOVM               0x00000800 /* internal */
+#define NOUVEAU_MEM_USER               0x00001000 /* internal */
 #define NOUVEAU_MEM_INTERNAL (NOUVEAU_MEM_INSTANCE | \
                              NOUVEAU_MEM_NOTIFIER | \
-                             NOUVEAU_MEM_NOVM)
+                             NOUVEAU_MEM_NOVM | \
+                             NOUVEAU_MEM_USER)
 
 struct drm_nouveau_mem_alloc {
        int flags;
index 20aa6b8..33e2a5b 100644 (file)
@@ -375,7 +375,7 @@ 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 *);
+                                                struct drm_file *, int tail);
 extern void nouveau_mem_takedown(struct mem_block **heap);
 extern void nouveau_mem_free_block(struct mem_block *);
 extern struct mem_block* find_block_by_handle(struct mem_block *heap, drm_handle_t handle);
index 810eaf9..51ac48d 100644 (file)
@@ -35,8 +35,9 @@
 #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)
+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) {
@@ -77,10 +78,9 @@ out:
        return p;
 }
 
-struct mem_block *nouveau_mem_alloc_block(struct mem_block *heap,
-                                         uint64_t size,
-                                         int align2,
-                                         struct drm_file *file_priv)
+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;
@@ -88,10 +88,22 @@ struct mem_block *nouveau_mem_alloc_block(struct mem_block *heap,
        if (!heap)
                return NULL;
 
-       list_for_each(p, heap) {
-               uint64_t start = (p->start + mask) & ~mask;
-               if (p->file_priv == 0 && start + size <= p->start + p->size)
-                       return split_block(p, start, size, file_priv);
+       if (tail) {
+               list_for_each_prev(p, heap) {
+                       uint64_t start = ((p->start + p->size) - size) & ~mask;
+
+                       if (p->file_priv == 0 && 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 == 0 &&
+                           start + size <= p->start + p->size)
+                               return split_block(p, start, size, file_priv);
+               }
        }
 
        return NULL;
@@ -574,13 +586,13 @@ int nouveau_mem_init(struct drm_device *dev)
        return 0;
 }
 
-struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment,
-                                   uint64_t size, int flags,
-                                   struct drm_file *file_priv)
+struct mem_block *
+nouveau_mem_alloc(struct drm_device *dev, int alignment, uint64_t size,
+                 int flags, struct drm_file *file_priv)
 {
-       struct mem_block *block;
-       int type;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct mem_block *block;
+       int type, tail = !(flags & NOUVEAU_MEM_USER);
 
        /*
         * Make things easier on ourselves: all allocations are page-aligned.
@@ -611,14 +623,14 @@ struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment,
 #define NOUVEAU_MEM_ALLOC_AGP {\
                type=NOUVEAU_MEM_AGP;\
                 block = nouveau_mem_alloc_block(dev_priv->agp_heap, size,\
-                                                alignment, file_priv); \
+                                                alignment, file_priv, tail); \
                 if (block) goto alloc_ok;\
                }
 
 #define NOUVEAU_MEM_ALLOC_PCI {\
                 type = NOUVEAU_MEM_PCI;\
                 block = nouveau_mem_alloc_block(dev_priv->pci_heap, size, \
-                                               alignment, file_priv); \
+                                               alignment, file_priv, tail); \
                 if ( block ) goto alloc_ok;\
                }
 
@@ -627,11 +639,11 @@ struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment,
                 if (!(flags&NOUVEAU_MEM_MAPPED)) {\
                         block = nouveau_mem_alloc_block(dev_priv->fb_nomap_heap,\
                                                         size, alignment, \
-                                                       file_priv); \
+                                                       file_priv, tail); \
                         if (block) goto alloc_ok;\
                 }\
                 block = nouveau_mem_alloc_block(dev_priv->fb_heap, size,\
-                                                alignment, file_priv);\
+                                                alignment, file_priv, tail);\
                 if (block) goto alloc_ok;\
                }
 
@@ -749,7 +761,9 @@ out_free:
  * Ioctls
  */
 
-int nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv)
+int
+nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
 {
        struct drm_nouveau_mem_alloc *alloc = data;
        struct mem_block *block;
@@ -759,8 +773,8 @@ int nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data, struct drm_file
        if (alloc->flags & NOUVEAU_MEM_INTERNAL)
                return -EINVAL;
 
-       block=nouveau_mem_alloc(dev, alloc->alignment, alloc->size,
-                               alloc->flags, file_priv);
+       block = nouveau_mem_alloc(dev, alloc->alignment, alloc->size,
+                                 alloc->flags | NOUVEAU_MEM_USER, file_priv);
        if (!block)
                return -ENOMEM;
        alloc->map_handle=block->map_handle;
index 82c8ab7..edece4d 100644 (file)
@@ -94,7 +94,7 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
        }
 
        mem = nouveau_mem_alloc_block(chan->notifier_heap, count*32, 0,
-                                     (struct drm_file *)-2);
+                                     (struct drm_file *)-2, 0);
        if (!mem) {
                DRM_ERROR("Channel %d notifier block full\n", chan->id);
                return -ENOMEM;
index 09f9027..5664bfc 100644 (file)
@@ -248,7 +248,7 @@ 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);
+                                                   (struct drm_file *)-2, 0);
        if (!gpuobj->im_pramin) {
                nouveau_gpuobj_del(dev, &gpuobj);
                return -ENOMEM;