Skip to content

Commit

Permalink
drm/nouveau: use drm_mm in preference to custom code doing the same t…
Browse files Browse the repository at this point in the history
…hing

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
  • Loading branch information
Ben Skeggs committed Jul 13, 2010
1 parent d17f395 commit b833ac2
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 240 deletions.
24 changes: 4 additions & 20 deletions drivers/gpu/drm/nouveau/nouveau_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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 */

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 *);
Expand Down
176 changes: 2 additions & 174 deletions drivers/gpu/drm/nouveau/nouveau_mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,162 +35,6 @@
#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
*/
Expand Down Expand Up @@ -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;

Expand Down
29 changes: 12 additions & 17 deletions drivers/gpu/drm/nouveau/nouveau_notifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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
Expand All @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
Expand Down
Loading

0 comments on commit b833ac2

Please sign in to comment.