Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b833ac26 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau: use drm_mm in preference to custom code doing the same thing



Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent d17f395c
Loading
Loading
Loading
Loading
+4 −20
Original line number Diff line number Diff line
@@ -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
@@ -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;
@@ -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;
@@ -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 */

@@ -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;
@@ -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 *);
+2 −174
Original line number Diff line number Diff line
@@ -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
 */
@@ -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;

+12 −17
Original line number Diff line number Diff line
@@ -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;

@@ -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
@@ -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
@@ -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;
@@ -144,7 +139,7 @@ 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;
	}
@@ -154,7 +149,7 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
	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;
	}
@@ -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;
+14 −14
Original line number Diff line number Diff line
@@ -209,7 +209,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_engine *engine = &dev_priv->engine;
	struct nouveau_gpuobj *gpuobj;
	struct mem_block *pramin = NULL;
	struct drm_mm *pramin = NULL;
	int ret;

	NV_DEBUG(dev, "ch%d size=%u align=%d flags=0x%08x\n",
@@ -233,17 +233,17 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
	 * available.
	 */
	if (chan) {
		if (chan->ramin_heap) {
		if (chan->ramin_heap.ml_entry.next) {
			NV_DEBUG(dev, "private heap\n");
			pramin = chan->ramin_heap;
			pramin = &chan->ramin_heap;
		} else
		if (dev_priv->card_type < NV_50) {
			NV_DEBUG(dev, "global heap fallback\n");
			pramin = dev_priv->ramin_heap;
			pramin = &dev_priv->ramin_heap;
		}
	} else {
		NV_DEBUG(dev, "global heap\n");
		pramin = dev_priv->ramin_heap;
		pramin = &dev_priv->ramin_heap;
	}

	if (!pramin) {
@@ -260,9 +260,10 @@ 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, 0);
	gpuobj->im_pramin = drm_mm_search_free(pramin, size, align, 0);
	if (gpuobj->im_pramin)
		gpuobj->im_pramin = drm_mm_get_block(gpuobj->im_pramin, size, align);

	if (!gpuobj->im_pramin) {
		nouveau_gpuobj_del(dev, &gpuobj);
		return -ENOMEM;
@@ -386,7 +387,7 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
		if (gpuobj->flags & NVOBJ_FLAG_FAKE)
			kfree(gpuobj->im_pramin);
		else
			nouveau_mem_free_block(gpuobj->im_pramin);
			drm_mm_put_block(gpuobj->im_pramin);
	}

	list_del(&gpuobj->list);
@@ -589,7 +590,7 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset,
	list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);

	if (p_offset != ~0) {
		gpuobj->im_pramin = kzalloc(sizeof(struct mem_block),
		gpuobj->im_pramin = kzalloc(sizeof(struct drm_mm_node),
					    GFP_KERNEL);
		if (!gpuobj->im_pramin) {
			nouveau_gpuobj_del(dev, &gpuobj);
@@ -944,8 +945,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
	}
	pramin = chan->ramin->gpuobj;

	ret = nouveau_mem_init_heap(&chan->ramin_heap,
				    pramin->im_pramin->start + base, size);
	ret = drm_mm_init(&chan->ramin_heap, pramin->im_pramin->start + base, size);
	if (ret) {
		NV_ERROR(dev, "Error creating PRAMIN heap: %d\n", ret);
		nouveau_gpuobj_ref_del(dev, &chan->ramin);
@@ -1130,8 +1130,8 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan)
	for (i = 0; i < dev_priv->vm_vram_pt_nr; i++)
		nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]);

	if (chan->ramin_heap)
		nouveau_mem_takedown(&chan->ramin_heap);
	if (chan->ramin_heap.free_stack.next)
		drm_mm_takedown(&chan->ramin_heap);
	if (chan->ramin)
		nouveau_gpuobj_ref_del(dev, &chan->ramin);

+6 −6
Original line number Diff line number Diff line
@@ -106,7 +106,7 @@ int nv04_instmem_init(struct drm_device *dev)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	uint32_t offset;
	int ret = 0;
	int ret;

	nv04_instmem_determine_amount(dev);
	nv04_instmem_configure_fixed_tables(dev);
@@ -129,14 +129,14 @@ int nv04_instmem_init(struct drm_device *dev)
			offset = 0x40000;
	}

	ret = nouveau_mem_init_heap(&dev_priv->ramin_heap,
				    offset, dev_priv->ramin_rsvd_vram - offset);
	ret = drm_mm_init(&dev_priv->ramin_heap, offset,
			  dev_priv->ramin_rsvd_vram - offset);
	if (ret) {
		dev_priv->ramin_heap = NULL;
		NV_ERROR(dev, "Failed to init RAMIN heap\n");
		NV_ERROR(dev, "Failed to init RAMIN heap: %d\n", ret);
		return ret;
	}

	return ret;
	return 0;
}

void
Loading