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