summaryrefslogtreecommitdiff
path: root/shared-core/nouveau_mem.c
diff options
context:
space:
mode:
Diffstat (limited to 'shared-core/nouveau_mem.c')
-rw-r--r--shared-core/nouveau_mem.c58
1 files changed, 36 insertions, 22 deletions
diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c
index 2cf8807d..5511e5b6 100644
--- a/shared-core/nouveau_mem.c
+++ b/shared-core/nouveau_mem.c
@@ -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;
@@ -563,13 +575,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.
@@ -600,14 +612,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;\
}
@@ -616,11 +628,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;\
}
@@ -738,7 +750,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;
@@ -748,8 +762,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;