mm.c revision 13dfe1286d1ea1af4c9330b039c2316d0d92c484
1573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs/*
2496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs * Copyright 2012 Red Hat Inc.
3573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs *
4573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs * Permission is hereby granted, free of charge, to any person obtaining a
5573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs * copy of this software and associated documentation files (the "Software"),
6573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs * to deal in the Software without restriction, including without limitation
7573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs * and/or sell copies of the Software, and to permit persons to whom the
9573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs * Software is furnished to do so, subject to the following conditions:
10573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs *
11573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs * The above copyright notice and this permission notice shall be included in
12573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs * all copies or substantial portions of the Software.
13573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs *
14573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs * OTHER DEALINGS IN THE SOFTWARE.
21573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs *
22573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs * Authors: Ben Skeggs
23573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs */
24573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
25496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs#include "core/os.h"
26496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs#include "core/mm.h"
27573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
28496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs#define node(root, dir) ((root)->nl_entry.dir == &mm->nodes) ? NULL : \
29496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs	list_entry((root)->nl_entry.dir, struct nouveau_mm_node, nl_entry)
30496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs
31d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggsstatic void
32d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggsnouveau_mm_dump(struct nouveau_mm *mm, const char *header)
33d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs{
34d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs	struct nouveau_mm_node *node;
35d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs
36d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs	printk(KERN_ERR "nouveau: %s\n", header);
37d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs	printk(KERN_ERR "nouveau: node list:\n");
38d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs	list_for_each_entry(node, &mm->nodes, nl_entry) {
39d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs		printk(KERN_ERR "nouveau: \t%08x %08x %d\n",
40d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs		       node->offset, node->length, node->type);
41d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs	}
42d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs	printk(KERN_ERR "nouveau: free list:\n");
43d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs	list_for_each_entry(node, &mm->free, fl_entry) {
44d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs		printk(KERN_ERR "nouveau: \t%08x %08x %d\n",
45d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs		       node->offset, node->length, node->type);
46d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs	}
47d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs}
48d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs
49496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggsvoid
50496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggsnouveau_mm_free(struct nouveau_mm *mm, struct nouveau_mm_node **pthis)
51573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs{
52496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs	struct nouveau_mm_node *this = *pthis;
53496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs
54496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs	if (this) {
55496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		struct nouveau_mm_node *prev = node(this, prev);
56496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		struct nouveau_mm_node *next = node(this, next);
57496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs
5879456e1a10d5f4e708822287ed0e97af469bf49bBen Skeggs		if (prev && prev->type == NVKM_MM_TYPE_NONE) {
59496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs			prev->length += this->length;
60496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs			list_del(&this->nl_entry);
61496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs			kfree(this); this = prev;
62496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		}
63496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs
6479456e1a10d5f4e708822287ed0e97af469bf49bBen Skeggs		if (next && next->type == NVKM_MM_TYPE_NONE) {
65496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs			next->offset  = this->offset;
66496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs			next->length += this->length;
6779456e1a10d5f4e708822287ed0e97af469bf49bBen Skeggs			if (this->type == NVKM_MM_TYPE_NONE)
68496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs				list_del(&this->fl_entry);
69496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs			list_del(&this->nl_entry);
70496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs			kfree(this); this = NULL;
71496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		}
72496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs
7379456e1a10d5f4e708822287ed0e97af469bf49bBen Skeggs		if (this && this->type != NVKM_MM_TYPE_NONE) {
74496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs			list_for_each_entry(prev, &mm->free, fl_entry) {
75496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs				if (this->offset < prev->offset)
76496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs					break;
77496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs			}
78496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs
79496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs			list_add_tail(&this->fl_entry, &prev->fl_entry);
8079456e1a10d5f4e708822287ed0e97af469bf49bBen Skeggs			this->type = NVKM_MM_TYPE_NONE;
81496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		}
82496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs	}
83496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs
84496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs	*pthis = NULL;
85573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs}
86573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
87573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggsstatic struct nouveau_mm_node *
88496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggsregion_head(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size)
89573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs{
90573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	struct nouveau_mm_node *b;
91573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
92573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	if (a->length == size)
93573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		return a;
94573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
95573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	b = kmalloc(sizeof(*b), GFP_KERNEL);
96573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	if (unlikely(b == NULL))
97573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		return NULL;
98573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
99573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	b->offset = a->offset;
100573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	b->length = size;
101573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	b->type   = a->type;
102573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	a->offset += size;
103573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	a->length -= size;
104573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	list_add_tail(&b->nl_entry, &a->nl_entry);
10579456e1a10d5f4e708822287ed0e97af469bf49bBen Skeggs	if (b->type == NVKM_MM_TYPE_NONE)
106573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		list_add_tail(&b->fl_entry, &a->fl_entry);
107573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	return b;
108573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs}
109573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
110573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggsint
111496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggsnouveau_mm_head(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min,
112496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		u32 align, struct nouveau_mm_node **pnode)
113573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs{
1148b464bfed674fc25d39d8a686010ebe509c8f62aBen Skeggs	struct nouveau_mm_node *prev, *this, *next;
115496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs	u32 mask = align - 1;
1168b464bfed674fc25d39d8a686010ebe509c8f62aBen Skeggs	u32 splitoff;
1178b464bfed674fc25d39d8a686010ebe509c8f62aBen Skeggs	u32 s, e;
1188b464bfed674fc25d39d8a686010ebe509c8f62aBen Skeggs
11913dfe1286d1ea1af4c9330b039c2316d0d92c484Ben Skeggs	BUG_ON(type == NVKM_MM_TYPE_NONE || type == NVKM_MM_TYPE_HOLE);
12018902bbf06a93ea497be2f177a6323ed9e5f30beMaarten Lankhorst
121987eec10dd76624d0edacdc7ecc7e1a6fc877373Ben Skeggs	list_for_each_entry(this, &mm->free, fl_entry) {
1228b464bfed674fc25d39d8a686010ebe509c8f62aBen Skeggs		e = this->offset + this->length;
1238b464bfed674fc25d39d8a686010ebe509c8f62aBen Skeggs		s = this->offset;
1248b464bfed674fc25d39d8a686010ebe509c8f62aBen Skeggs
1258b464bfed674fc25d39d8a686010ebe509c8f62aBen Skeggs		prev = node(this, prev);
1268b464bfed674fc25d39d8a686010ebe509c8f62aBen Skeggs		if (prev && prev->type != type)
127987eec10dd76624d0edacdc7ecc7e1a6fc877373Ben Skeggs			s = roundup(s, mm->block_size);
1288b464bfed674fc25d39d8a686010ebe509c8f62aBen Skeggs
1298b464bfed674fc25d39d8a686010ebe509c8f62aBen Skeggs		next = node(this, next);
1308b464bfed674fc25d39d8a686010ebe509c8f62aBen Skeggs		if (next && next->type != type)
131987eec10dd76624d0edacdc7ecc7e1a6fc877373Ben Skeggs			e = rounddown(e, mm->block_size);
1328b464bfed674fc25d39d8a686010ebe509c8f62aBen Skeggs
133496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		s  = (s + mask) & ~mask;
134496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		e &= ~mask;
135496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		if (s > e || e - s < size_min)
136573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			continue;
137573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
1388b464bfed674fc25d39d8a686010ebe509c8f62aBen Skeggs		splitoff = s - this->offset;
139496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		if (splitoff && !region_head(mm, this, splitoff))
140496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs			return -ENOMEM;
141496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs
142496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		this = region_head(mm, this, min(size_max, e - s));
143496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		if (!this)
144496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs			return -ENOMEM;
145496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs
146496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		this->type = type;
147496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		list_del(&this->fl_entry);
148496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		*pnode = this;
149496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		return 0;
150496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs	}
151496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs
152496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs	return -ENOSPC;
153496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs}
154496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs
155496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggsstatic struct nouveau_mm_node *
156496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggsregion_tail(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size)
157496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs{
158496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs	struct nouveau_mm_node *b;
159496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs
160496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs	if (a->length == size)
161496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		return a;
162496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs
163496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs	b = kmalloc(sizeof(*b), GFP_KERNEL);
164496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs	if (unlikely(b == NULL))
165496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		return NULL;
166496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs
167496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs	a->length -= size;
168496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs	b->offset  = a->offset + a->length;
169496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs	b->length  = size;
170496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs	b->type    = a->type;
171496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs
172496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs	list_add(&b->nl_entry, &a->nl_entry);
17379456e1a10d5f4e708822287ed0e97af469bf49bBen Skeggs	if (b->type == NVKM_MM_TYPE_NONE)
174496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		list_add(&b->fl_entry, &a->fl_entry);
175496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs	return b;
176496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs}
177496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs
178496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggsint
179496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggsnouveau_mm_tail(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min,
180496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		u32 align, struct nouveau_mm_node **pnode)
181496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs{
182496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs	struct nouveau_mm_node *prev, *this, *next;
183496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs	u32 mask = align - 1;
184496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs
18513dfe1286d1ea1af4c9330b039c2316d0d92c484Ben Skeggs	BUG_ON(type == NVKM_MM_TYPE_NONE || type == NVKM_MM_TYPE_HOLE);
18618902bbf06a93ea497be2f177a6323ed9e5f30beMaarten Lankhorst
187496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs	list_for_each_entry_reverse(this, &mm->free, fl_entry) {
188496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		u32 e = this->offset + this->length;
189496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		u32 s = this->offset;
190496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		u32 c = 0, a;
191496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs
192496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		prev = node(this, prev);
193496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		if (prev && prev->type != type)
194496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs			s = roundup(s, mm->block_size);
195496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs
196496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		next = node(this, next);
197496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		if (next && next->type != type) {
198496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs			e = rounddown(e, mm->block_size);
199496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs			c = next->offset - e;
200496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		}
201496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs
202496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		s = (s + mask) & ~mask;
203496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		a = e - s;
204496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		if (s > e || a < size_min)
205496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs			continue;
206496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs
207496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		a  = min(a, size_max);
208496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		s  = (e - a) & ~mask;
209496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		c += (e - s) - a;
210496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs
211496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		if (c && !region_tail(mm, this, c))
2128b464bfed674fc25d39d8a686010ebe509c8f62aBen Skeggs			return -ENOMEM;
213573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
214496734bf0391f38c196e16dbbfaaeda8e6ec5845Ben Skeggs		this = region_tail(mm, this, a);
2158b464bfed674fc25d39d8a686010ebe509c8f62aBen Skeggs		if (!this)
216573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			return -ENOMEM;
217573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
2188b464bfed674fc25d39d8a686010ebe509c8f62aBen Skeggs		this->type = type;
219573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		list_del(&this->fl_entry);
220573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		*pnode = this;
221573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		return 0;
222573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	}
223573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
224ef1b287169cd3d1e428c8ed8222e0bbf733d5dbbBen Skeggs	return -ENOSPC;
225573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs}
226573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
227573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggsint
228987eec10dd76624d0edacdc7ecc7e1a6fc877373Ben Skeggsnouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block)
229573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs{
23013dfe1286d1ea1af4c9330b039c2316d0d92c484Ben Skeggs	struct nouveau_mm_node *node, *prev;
23113dfe1286d1ea1af4c9330b039c2316d0d92c484Ben Skeggs	u32 next;
232a12036ba2c0a190c93e5238c5f32fdb8c023c068Ben Skeggs
233d979ab975ecdb336ed4da77a808be813a293b59eBen Skeggs	if (nouveau_mm_initialised(mm)) {
23413dfe1286d1ea1af4c9330b039c2316d0d92c484Ben Skeggs		prev = list_last_entry(&mm->nodes, typeof(*node), nl_entry);
23513dfe1286d1ea1af4c9330b039c2316d0d92c484Ben Skeggs		next = prev->offset + prev->length;
23613dfe1286d1ea1af4c9330b039c2316d0d92c484Ben Skeggs		if (next != offset) {
23713dfe1286d1ea1af4c9330b039c2316d0d92c484Ben Skeggs			BUG_ON(next > offset);
23813dfe1286d1ea1af4c9330b039c2316d0d92c484Ben Skeggs			if (!(node = kzalloc(sizeof(*node), GFP_KERNEL)))
23913dfe1286d1ea1af4c9330b039c2316d0d92c484Ben Skeggs				return -ENOMEM;
24013dfe1286d1ea1af4c9330b039c2316d0d92c484Ben Skeggs			node->type   = NVKM_MM_TYPE_HOLE;
24113dfe1286d1ea1af4c9330b039c2316d0d92c484Ben Skeggs			node->offset = next;
24213dfe1286d1ea1af4c9330b039c2316d0d92c484Ben Skeggs			node->length = offset - next;
24313dfe1286d1ea1af4c9330b039c2316d0d92c484Ben Skeggs			list_add_tail(&node->nl_entry, &mm->nodes);
24413dfe1286d1ea1af4c9330b039c2316d0d92c484Ben Skeggs		}
245d979ab975ecdb336ed4da77a808be813a293b59eBen Skeggs		BUG_ON(block != mm->block_size);
246d979ab975ecdb336ed4da77a808be813a293b59eBen Skeggs	} else {
247a12036ba2c0a190c93e5238c5f32fdb8c023c068Ben Skeggs		INIT_LIST_HEAD(&mm->nodes);
248a12036ba2c0a190c93e5238c5f32fdb8c023c068Ben Skeggs		INIT_LIST_HEAD(&mm->free);
249a12036ba2c0a190c93e5238c5f32fdb8c023c068Ben Skeggs		mm->block_size = block;
250a12036ba2c0a190c93e5238c5f32fdb8c023c068Ben Skeggs		mm->heap_nodes = 0;
251a12036ba2c0a190c93e5238c5f32fdb8c023c068Ben Skeggs	}
252573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
253a12036ba2c0a190c93e5238c5f32fdb8c023c068Ben Skeggs	node = kzalloc(sizeof(*node), GFP_KERNEL);
254a12036ba2c0a190c93e5238c5f32fdb8c023c068Ben Skeggs	if (!node)
255573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		return -ENOMEM;
256a7dbf00433fa9dc6f4a3828a17d56a9df2bd06b1Ben Skeggs
257a7dbf00433fa9dc6f4a3828a17d56a9df2bd06b1Ben Skeggs	if (length) {
258a7dbf00433fa9dc6f4a3828a17d56a9df2bd06b1Ben Skeggs		node->offset  = roundup(offset, mm->block_size);
259a7dbf00433fa9dc6f4a3828a17d56a9df2bd06b1Ben Skeggs		node->length  = rounddown(offset + length, mm->block_size);
260a7dbf00433fa9dc6f4a3828a17d56a9df2bd06b1Ben Skeggs		node->length -= node->offset;
261a7dbf00433fa9dc6f4a3828a17d56a9df2bd06b1Ben Skeggs	}
262987eec10dd76624d0edacdc7ecc7e1a6fc877373Ben Skeggs
263a12036ba2c0a190c93e5238c5f32fdb8c023c068Ben Skeggs	list_add_tail(&node->nl_entry, &mm->nodes);
264a12036ba2c0a190c93e5238c5f32fdb8c023c068Ben Skeggs	list_add_tail(&node->fl_entry, &mm->free);
265a12036ba2c0a190c93e5238c5f32fdb8c023c068Ben Skeggs	mm->heap_nodes++;
266573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	return 0;
267573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs}
268573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
269573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggsint
270987eec10dd76624d0edacdc7ecc7e1a6fc877373Ben Skeggsnouveau_mm_fini(struct nouveau_mm *mm)
271573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs{
272d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs	struct nouveau_mm_node *node, *temp;
273d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs	int nodes = 0;
2747e0f992b796e102d32b75392fba38be7cab1c5a9Ben Skeggs
275d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs	if (!nouveau_mm_initialised(mm))
276d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs		return 0;
277a12036ba2c0a190c93e5238c5f32fdb8c023c068Ben Skeggs
278d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs	list_for_each_entry(node, &mm->nodes, nl_entry) {
27913dfe1286d1ea1af4c9330b039c2316d0d92c484Ben Skeggs		if (node->type != NVKM_MM_TYPE_HOLE) {
28013dfe1286d1ea1af4c9330b039c2316d0d92c484Ben Skeggs			if (++nodes > mm->heap_nodes) {
28113dfe1286d1ea1af4c9330b039c2316d0d92c484Ben Skeggs				nouveau_mm_dump(mm, "mm not clean!");
28213dfe1286d1ea1af4c9330b039c2316d0d92c484Ben Skeggs				return -EBUSY;
28313dfe1286d1ea1af4c9330b039c2316d0d92c484Ben Skeggs			}
284d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs		}
285ad9ac437a500f8c0822bd5fe139af8ee2c132e15Ben Skeggs	}
286573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
287d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs	list_for_each_entry_safe(node, temp, &mm->nodes, nl_entry) {
288d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs		list_del(&node->nl_entry);
289d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs		kfree(node);
290d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs	}
291d7bda18c9102b65078c132fd7d7ffd835058f021Ben Skeggs	mm->heap_nodes = 0;
292573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	return 0;
293573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs}
294