Commit 13dfe128 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau/core/mm: fill in holes with "allocated" nodes



The allocation algorithm doesn't expect there to be holes in the mm, which
causes its alignment/cutoff calculations to choke (and go negative) when
encountering the last chunk of a block before a hole.

The least expensive solution is to simply fill in any holes with nodes
that are pre-marked as being allocated.

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent d7bda18c
Loading
Loading
Loading
Loading
+20 −6
Original line number Diff line number Diff line
@@ -116,7 +116,7 @@ nouveau_mm_head(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min,
	u32 splitoff;
	u32 s, e;

	BUG_ON(type == NVKM_MM_TYPE_NONE);
	BUG_ON(type == NVKM_MM_TYPE_NONE || type == NVKM_MM_TYPE_HOLE);

	list_for_each_entry(this, &mm->free, fl_entry) {
		e = this->offset + this->length;
@@ -182,7 +182,7 @@ nouveau_mm_tail(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min,
	struct nouveau_mm_node *prev, *this, *next;
	u32 mask = align - 1;

	BUG_ON(type == NVKM_MM_TYPE_NONE);
	BUG_ON(type == NVKM_MM_TYPE_NONE || type == NVKM_MM_TYPE_HOLE);

	list_for_each_entry_reverse(this, &mm->free, fl_entry) {
		u32 e = this->offset + this->length;
@@ -227,9 +227,21 @@ nouveau_mm_tail(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min,
int
nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block)
{
	struct nouveau_mm_node *node;
	struct nouveau_mm_node *node, *prev;
	u32 next;

	if (nouveau_mm_initialised(mm)) {
		prev = list_last_entry(&mm->nodes, typeof(*node), nl_entry);
		next = prev->offset + prev->length;
		if (next != offset) {
			BUG_ON(next > offset);
			if (!(node = kzalloc(sizeof(*node), GFP_KERNEL)))
				return -ENOMEM;
			node->type   = NVKM_MM_TYPE_HOLE;
			node->offset = next;
			node->length = offset - next;
			list_add_tail(&node->nl_entry, &mm->nodes);
		}
		BUG_ON(block != mm->block_size);
	} else {
		INIT_LIST_HEAD(&mm->nodes);
@@ -264,11 +276,13 @@ nouveau_mm_fini(struct nouveau_mm *mm)
		return 0;

	list_for_each_entry(node, &mm->nodes, nl_entry) {
		if (node->type != NVKM_MM_TYPE_HOLE) {
			if (++nodes > mm->heap_nodes) {
				nouveau_mm_dump(mm, "mm not clean!");
				return -EBUSY;
			}
		}
	}

	list_for_each_entry_safe(node, temp, &mm->nodes, nl_entry) {
		list_del(&node->nl_entry);
+1 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ struct nouveau_mm_node {
	struct list_head rl_entry;

#define NVKM_MM_TYPE_NONE 0x00
#define NVKM_MM_TYPE_HOLE 0xff
	u8  type;
	u32 offset;
	u32 length;