mm.c revision 573a2a37e8648a3249426c816f51e7ef50f6f73e
1573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs/*
2573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs * Copyright 2010 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
25573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs#include "drmP.h"
26573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs#include "nouveau_drv.h"
27573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs#include "nouveau_mm.h"
28573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
29573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggsstatic inline void
30573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggsregion_put(struct nouveau_mm *rmm, struct nouveau_mm_node *a)
31573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs{
32573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	list_del(&a->nl_entry);
33573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	list_del(&a->fl_entry);
34573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	kfree(a);
35573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs}
36573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
37573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggsstatic struct nouveau_mm_node *
38573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggsregion_split(struct nouveau_mm *rmm, struct nouveau_mm_node *a, u32 size)
39573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs{
40573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	struct nouveau_mm_node *b;
41573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
42573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	if (a->length == size)
43573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		return a;
44573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
45573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	b = kmalloc(sizeof(*b), GFP_KERNEL);
46573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	if (unlikely(b == NULL))
47573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		return NULL;
48573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
49573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	b->offset = a->offset;
50573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	b->length = size;
51573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	b->free   = a->free;
52573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	b->type   = a->type;
53573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	a->offset += size;
54573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	a->length -= size;
55573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	list_add_tail(&b->nl_entry, &a->nl_entry);
56573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	if (b->free)
57573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		list_add_tail(&b->fl_entry, &a->fl_entry);
58573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	return b;
59573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs}
60573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
61573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggsstatic struct nouveau_mm_node *
62573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggsnouveau_mm_merge(struct nouveau_mm *rmm, struct nouveau_mm_node *this)
63573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs{
64573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	struct nouveau_mm_node *prev, *next;
65573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
66573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	/* try to merge with free adjacent entries of same type */
67573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	prev = list_entry(this->nl_entry.prev, struct nouveau_mm_node, nl_entry);
68573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	if (this->nl_entry.prev != &rmm->nodes) {
69573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		if (prev->free && prev->type == this->type) {
70573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			prev->length += this->length;
71573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			region_put(rmm, this);
72573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			this = prev;
73573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		}
74573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	}
75573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
76573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	next = list_entry(this->nl_entry.next, struct nouveau_mm_node, nl_entry);
77573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	if (this->nl_entry.next != &rmm->nodes) {
78573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		if (next->free && next->type == this->type) {
79573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			next->offset  = this->offset;
80573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			next->length += this->length;
81573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			region_put(rmm, this);
82573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			this = next;
83573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		}
84573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	}
85573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
86573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	return this;
87573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs}
88573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
89573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggsvoid
90573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggsnouveau_mm_put(struct nouveau_mm *rmm, struct nouveau_mm_node *this)
91573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs{
92573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	u32 block_s, block_l;
93573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
94573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	this->free = true;
95573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	list_add(&this->fl_entry, &rmm->free);
96573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	this = nouveau_mm_merge(rmm, this);
97573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
98573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	/* any entirely free blocks now?  we'll want to remove typing
99573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	 * on them now so they can be use for any memory allocation
100573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	 */
101573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	block_s = roundup(this->offset, rmm->block_size);
102573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	if (block_s + rmm->block_size > this->offset + this->length)
103573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		return;
104573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
105573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	/* split off any still-typed region at the start */
106573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	if (block_s != this->offset) {
107573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		if (!region_split(rmm, this, block_s - this->offset))
108573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			return;
109573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	}
110573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
111573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	/* split off the soon-to-be-untyped block(s) */
112573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	block_l = rounddown(this->length, rmm->block_size);
113573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	if (block_l != this->length) {
114573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		this = region_split(rmm, this, block_l);
115573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		if (!this)
116573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			return;
117573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	}
118573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
119573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	/* mark as having no type, and retry merge with any adjacent
120573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	 * untyped blocks
121573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	 */
122573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	this->type = 0;
123573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	nouveau_mm_merge(rmm, this);
124573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs}
125573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
126573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggsint
127573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggsnouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc,
128573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	       u32 align, struct nouveau_mm_node **pnode)
129573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs{
130573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	struct nouveau_mm_node *this, *tmp, *next;
131573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	u32 splitoff, avail, alloc;
132573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
133573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	list_for_each_entry_safe(this, tmp, &rmm->free, fl_entry) {
134573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		next = list_entry(this->nl_entry.next, struct nouveau_mm_node, nl_entry);
135573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		if (this->nl_entry.next == &rmm->nodes)
136573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			next = NULL;
137573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
138573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		/* skip wrongly typed blocks */
139573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		if (this->type && this->type != type)
140573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			continue;
141573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
142573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		/* account for alignment */
143573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		splitoff = this->offset & (align - 1);
144573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		if (splitoff)
145573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			splitoff = align - splitoff;
146573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
147573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		if (this->length <= splitoff)
148573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			continue;
149573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
150573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		/* determine total memory available from this, and
151573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		 * the next block (if appropriate)
152573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		 */
153573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		avail = this->length;
154573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		if (next && next->free && (!next->type || next->type == type))
155573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			avail += next->length;
156573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
157573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		avail -= splitoff;
158573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
159573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		/* determine allocation size */
160573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		if (size_nc) {
161573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			alloc = min(avail, size);
162573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			alloc = rounddown(alloc, size_nc);
163573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			if (alloc == 0)
164573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs				continue;
165573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		} else {
166573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			alloc = size;
167573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			if (avail < alloc)
168573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs				continue;
169573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		}
170573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
171573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		/* untyped block, split off a chunk that's a multiple
172573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		 * of block_size and type it
173573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		 */
174573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		if (!this->type) {
175573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			u32 block = roundup(alloc + splitoff, rmm->block_size);
176573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			if (this->length < block)
177573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs				continue;
178573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
179573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			this = region_split(rmm, this, block);
180573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			if (!this)
181573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs				return -ENOMEM;
182573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
183573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			this->type = type;
184573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		}
185573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
186573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		/* stealing memory from adjacent block */
187573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		if (alloc > this->length) {
188573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			u32 amount = alloc - (this->length - splitoff);
189573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
190573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			if (!next->type) {
191573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs				amount = roundup(amount, rmm->block_size);
192573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
193573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs				next = region_split(rmm, next, amount);
194573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs				if (!next)
195573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs					return -ENOMEM;
196573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
197573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs				next->type = type;
198573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			}
199573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
200573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			this->length += amount;
201573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			next->offset += amount;
202573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			next->length -= amount;
203573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			if (!next->length) {
204573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs				list_del(&next->nl_entry);
205573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs				list_del(&next->fl_entry);
206573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs				kfree(next);
207573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			}
208573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		}
209573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
210573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		if (splitoff) {
211573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			if (!region_split(rmm, this, splitoff))
212573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs				return -ENOMEM;
213573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		}
214573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
215573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		this = region_split(rmm, this, alloc);
216573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		if (this == NULL)
217573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs			return -ENOMEM;
218573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
219573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		this->free = false;
220573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		list_del(&this->fl_entry);
221573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		*pnode = this;
222573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		return 0;
223573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	}
224573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
225573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	return -ENOMEM;
226573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs}
227573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
228573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggsint
229573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggsnouveau_mm_init(struct nouveau_mm **prmm, u32 offset, u32 length, u32 block)
230573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs{
231573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	struct nouveau_mm *rmm;
232573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	struct nouveau_mm_node *heap;
233573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
234573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	heap = kzalloc(sizeof(*heap), GFP_KERNEL);
235573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	if (!heap)
236573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		return -ENOMEM;
237573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	heap->free = true;
238573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	heap->offset = roundup(offset, block);
239573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	heap->length = rounddown(offset + length, block) - heap->offset;
240573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
241573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	rmm = kzalloc(sizeof(*rmm), GFP_KERNEL);
242573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	if (!rmm) {
243573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		kfree(heap);
244573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		return -ENOMEM;
245573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	}
246573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	rmm->block_size = block;
247573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	mutex_init(&rmm->mutex);
248573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	INIT_LIST_HEAD(&rmm->nodes);
249573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	INIT_LIST_HEAD(&rmm->free);
250573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	list_add(&heap->nl_entry, &rmm->nodes);
251573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	list_add(&heap->fl_entry, &rmm->free);
252573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
253573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	*prmm = rmm;
254573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	return 0;
255573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs}
256573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
257573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggsint
258573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggsnouveau_mm_fini(struct nouveau_mm **prmm)
259573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs{
260573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	struct nouveau_mm *rmm = *prmm;
261573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	struct nouveau_mm_node *heap =
262573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		list_first_entry(&rmm->nodes, struct nouveau_mm_node, nl_entry);
263573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
264573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	if (!list_is_singular(&rmm->nodes))
265573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs		return -EBUSY;
266573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs
267573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	kfree(heap);
268573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	kfree(rmm);
269573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	*prmm = NULL;
270573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs	return 0;
271573a2a37e8648a3249426c816f51e7ef50f6f73eBen Skeggs}
272