#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) {
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;
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;
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.
#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;\
}
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;\
}
* 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;
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;