summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shared-core/nouveau_drm.h4
-rw-r--r--shared-core/nouveau_drv.h2
-rw-r--r--shared-core/nouveau_mem.c58
-rw-r--r--shared-core/nouveau_notifier.c2
-rw-r--r--shared-core/nouveau_object.c2
5 files changed, 42 insertions, 26 deletions
diff --git a/shared-core/nouveau_drm.h b/shared-core/nouveau_drm.h
index cf762052..bbb51bc4 100644
--- a/shared-core/nouveau_drm.h
+++ b/shared-core/nouveau_drm.h
@@ -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;
diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h
index a51e552c..1aaf1d74 100644
--- a/shared-core/nouveau_drv.h
+++ b/shared-core/nouveau_drv.h
@@ -350,7 +350,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 uint64_t nouveau_mem_fb_amount(struct drm_device *);
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;
diff --git a/shared-core/nouveau_notifier.c b/shared-core/nouveau_notifier.c
index 82c8ab7d..edece4da 100644
--- a/shared-core/nouveau_notifier.c
+++ b/shared-core/nouveau_notifier.c
@@ -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;
diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c
index 09f9027a..5664bfc8 100644
--- a/shared-core/nouveau_object.c
+++ b/shared-core/nouveau_object.c
@@ -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;