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

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
...@@ -116,7 +116,7 @@ nouveau_mm_head(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min, ...@@ -116,7 +116,7 @@ nouveau_mm_head(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min,
u32 splitoff; u32 splitoff;
u32 s, e; 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) { list_for_each_entry(this, &mm->free, fl_entry) {
e = this->offset + this->length; e = this->offset + this->length;
...@@ -182,7 +182,7 @@ nouveau_mm_tail(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min, ...@@ -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; struct nouveau_mm_node *prev, *this, *next;
u32 mask = align - 1; 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) { list_for_each_entry_reverse(this, &mm->free, fl_entry) {
u32 e = this->offset + this->length; 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, ...@@ -227,9 +227,21 @@ nouveau_mm_tail(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min,
int int
nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block) 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)) { 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); BUG_ON(block != mm->block_size);
} else { } else {
INIT_LIST_HEAD(&mm->nodes); INIT_LIST_HEAD(&mm->nodes);
...@@ -264,11 +276,13 @@ nouveau_mm_fini(struct nouveau_mm *mm) ...@@ -264,11 +276,13 @@ nouveau_mm_fini(struct nouveau_mm *mm)
return 0; return 0;
list_for_each_entry(node, &mm->nodes, nl_entry) { list_for_each_entry(node, &mm->nodes, nl_entry) {
if (node->type != NVKM_MM_TYPE_HOLE) {
if (++nodes > mm->heap_nodes) { if (++nodes > mm->heap_nodes) {
nouveau_mm_dump(mm, "mm not clean!"); nouveau_mm_dump(mm, "mm not clean!");
return -EBUSY; return -EBUSY;
} }
} }
}
list_for_each_entry_safe(node, temp, &mm->nodes, nl_entry) { list_for_each_entry_safe(node, temp, &mm->nodes, nl_entry) {
list_del(&node->nl_entry); list_del(&node->nl_entry);
......
...@@ -7,6 +7,7 @@ struct nouveau_mm_node { ...@@ -7,6 +7,7 @@ struct nouveau_mm_node {
struct list_head rl_entry; struct list_head rl_entry;
#define NVKM_MM_TYPE_NONE 0x00 #define NVKM_MM_TYPE_NONE 0x00
#define NVKM_MM_TYPE_HOLE 0xff
u8 type; u8 type;
u32 offset; u32 offset;
u32 length; u32 length;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment