| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 1 | /************************************************************************** | 
|  | 2 | * | 
|  | 3 | * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA. | 
|  | 4 | * All Rights Reserved. | 
|  | 5 | * | 
|  | 6 | * Permission is hereby granted, free of charge, to any person obtaining a | 
|  | 7 | * copy of this software and associated documentation files (the | 
|  | 8 | * "Software"), to deal in the Software without restriction, including | 
|  | 9 | * without limitation the rights to use, copy, modify, merge, publish, | 
|  | 10 | * distribute, sub license, and/or sell copies of the Software, and to | 
|  | 11 | * permit persons to whom the Software is furnished to do so, subject to | 
|  | 12 | * the following conditions: | 
|  | 13 | * | 
|  | 14 | * The above copyright notice and this permission notice (including the | 
|  | 15 | * next paragraph) shall be included in all copies or substantial portions | 
|  | 16 | * of the Software. | 
|  | 17 | * | 
|  | 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
|  | 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
|  | 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | 
|  | 21 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | 
|  | 22 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | 
|  | 23 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | 
|  | 24 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | 
|  | 25 | * | 
|  | 26 | * | 
|  | 27 | **************************************************************************/ | 
|  | 28 |  | 
|  | 29 | /* | 
|  | 30 | * Generic simple memory manager implementation. Intended to be used as a base | 
|  | 31 | * class implementation for more advanced memory managers. | 
|  | 32 | * | 
|  | 33 | * Note that the algorithm used is quite simple and there might be substantial | 
|  | 34 | * performance gains if a smarter free list is implemented. Currently it is just an | 
|  | 35 | * unordered stack of free regions. This could easily be improved if an RB-tree | 
|  | 36 | * is used instead. At least if we expect heavy fragmentation. | 
|  | 37 | * | 
|  | 38 | * Aligned allocations can also see improvement. | 
|  | 39 | * | 
|  | 40 | * Authors: | 
| Jan Engelhardt | 96de0e2 | 2007-10-19 23:21:04 +0200 | [diff] [blame] | 41 | * Thomas Hellström <thomas-at-tungstengraphics-dot-com> | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 42 | */ | 
|  | 43 |  | 
|  | 44 | #include "drmP.h" | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 45 | #include <linux/slab.h> | 
|  | 46 |  | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 47 | unsigned long drm_mm_tail_space(struct drm_mm *mm) | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 48 | { | 
|  | 49 | struct list_head *tail_node; | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 50 | struct drm_mm_node *entry; | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 51 |  | 
|  | 52 | tail_node = mm->ml_entry.prev; | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 53 | entry = list_entry(tail_node, struct drm_mm_node, ml_entry); | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 54 | if (!entry->free) | 
|  | 55 | return 0; | 
|  | 56 |  | 
|  | 57 | return entry->size; | 
|  | 58 | } | 
|  | 59 |  | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 60 | int drm_mm_remove_space_from_tail(struct drm_mm *mm, unsigned long size) | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 61 | { | 
|  | 62 | struct list_head *tail_node; | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 63 | struct drm_mm_node *entry; | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 64 |  | 
|  | 65 | tail_node = mm->ml_entry.prev; | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 66 | entry = list_entry(tail_node, struct drm_mm_node, ml_entry); | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 67 | if (!entry->free) | 
|  | 68 | return -ENOMEM; | 
|  | 69 |  | 
|  | 70 | if (entry->size <= size) | 
|  | 71 | return -ENOMEM; | 
|  | 72 |  | 
|  | 73 | entry->size -= size; | 
|  | 74 | return 0; | 
|  | 75 | } | 
|  | 76 |  | 
|  | 77 |  | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 78 | static int drm_mm_create_tail_node(struct drm_mm *mm, | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 79 | unsigned long start, | 
|  | 80 | unsigned long size) | 
|  | 81 | { | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 82 | struct drm_mm_node *child; | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 83 |  | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 84 | child = (struct drm_mm_node *) | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 85 | drm_alloc(sizeof(*child), DRM_MEM_MM); | 
|  | 86 | if (!child) | 
|  | 87 | return -ENOMEM; | 
|  | 88 |  | 
|  | 89 | child->free = 1; | 
|  | 90 | child->size = size; | 
|  | 91 | child->start = start; | 
|  | 92 | child->mm = mm; | 
|  | 93 |  | 
|  | 94 | list_add_tail(&child->ml_entry, &mm->ml_entry); | 
|  | 95 | list_add_tail(&child->fl_entry, &mm->fl_entry); | 
|  | 96 |  | 
|  | 97 | return 0; | 
|  | 98 | } | 
|  | 99 |  | 
|  | 100 |  | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 101 | int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size) | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 102 | { | 
|  | 103 | struct list_head *tail_node; | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 104 | struct drm_mm_node *entry; | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 105 |  | 
|  | 106 | tail_node = mm->ml_entry.prev; | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 107 | entry = list_entry(tail_node, struct drm_mm_node, ml_entry); | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 108 | if (!entry->free) { | 
|  | 109 | return drm_mm_create_tail_node(mm, entry->start + entry->size, size); | 
|  | 110 | } | 
|  | 111 | entry->size += size; | 
|  | 112 | return 0; | 
|  | 113 | } | 
|  | 114 |  | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 115 | static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent, | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 116 | unsigned long size) | 
|  | 117 | { | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 118 | struct drm_mm_node *child; | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 119 |  | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 120 | child = (struct drm_mm_node *) | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 121 | drm_alloc(sizeof(*child), DRM_MEM_MM); | 
|  | 122 | if (!child) | 
|  | 123 | return NULL; | 
|  | 124 |  | 
|  | 125 | INIT_LIST_HEAD(&child->fl_entry); | 
|  | 126 |  | 
|  | 127 | child->free = 0; | 
|  | 128 | child->size = size; | 
|  | 129 | child->start = parent->start; | 
|  | 130 | child->mm = parent->mm; | 
|  | 131 |  | 
|  | 132 | list_add_tail(&child->ml_entry, &parent->ml_entry); | 
|  | 133 | INIT_LIST_HEAD(&child->fl_entry); | 
|  | 134 |  | 
|  | 135 | parent->size -= size; | 
|  | 136 | parent->start += size; | 
|  | 137 | return child; | 
|  | 138 | } | 
|  | 139 |  | 
|  | 140 |  | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 141 |  | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 142 | struct drm_mm_node *drm_mm_get_block(struct drm_mm_node * parent, | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 143 | unsigned long size, unsigned alignment) | 
|  | 144 | { | 
|  | 145 |  | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 146 | struct drm_mm_node *align_splitoff = NULL; | 
|  | 147 | struct drm_mm_node *child; | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 148 | unsigned tmp = 0; | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 149 |  | 
|  | 150 | if (alignment) | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 151 | tmp = parent->start % alignment; | 
|  | 152 |  | 
|  | 153 | if (tmp) { | 
|  | 154 | align_splitoff = drm_mm_split_at_start(parent, alignment - tmp); | 
|  | 155 | if (!align_splitoff) | 
|  | 156 | return NULL; | 
|  | 157 | } | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 158 |  | 
|  | 159 | if (parent->size == size) { | 
|  | 160 | list_del_init(&parent->fl_entry); | 
| Andrew Morton | a1d0fcf | 2006-08-14 11:35:15 +1000 | [diff] [blame] | 161 | parent->free = 0; | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 162 | return parent; | 
|  | 163 | } else { | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 164 | child = drm_mm_split_at_start(parent, size); | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 165 | } | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 166 |  | 
|  | 167 | if (align_splitoff) | 
|  | 168 | drm_mm_put_block(align_splitoff); | 
|  | 169 |  | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 170 | return child; | 
|  | 171 | } | 
| Eric Anholt | 673a394 | 2008-07-30 12:06:12 -0700 | [diff] [blame] | 172 | EXPORT_SYMBOL(drm_mm_get_block); | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 173 |  | 
|  | 174 | /* | 
|  | 175 | * Put a block. Merge with the previous and / or next block if they are free. | 
|  | 176 | * Otherwise add to the free stack. | 
|  | 177 | */ | 
|  | 178 |  | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 179 | void drm_mm_put_block(struct drm_mm_node * cur) | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 180 | { | 
|  | 181 |  | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 182 | struct drm_mm *mm = cur->mm; | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 183 | struct list_head *cur_head = &cur->ml_entry; | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 184 | struct list_head *root_head = &mm->ml_entry; | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 185 | struct drm_mm_node *prev_node = NULL; | 
|  | 186 | struct drm_mm_node *next_node; | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 187 |  | 
| Andrew Morton | a1d0fcf | 2006-08-14 11:35:15 +1000 | [diff] [blame] | 188 | int merged = 0; | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 189 |  | 
|  | 190 | if (cur_head->prev != root_head) { | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 191 | prev_node = list_entry(cur_head->prev, struct drm_mm_node, ml_entry); | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 192 | if (prev_node->free) { | 
|  | 193 | prev_node->size += cur->size; | 
| Andrew Morton | a1d0fcf | 2006-08-14 11:35:15 +1000 | [diff] [blame] | 194 | merged = 1; | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 195 | } | 
|  | 196 | } | 
|  | 197 | if (cur_head->next != root_head) { | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 198 | next_node = list_entry(cur_head->next, struct drm_mm_node, ml_entry); | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 199 | if (next_node->free) { | 
|  | 200 | if (merged) { | 
|  | 201 | prev_node->size += next_node->size; | 
|  | 202 | list_del(&next_node->ml_entry); | 
|  | 203 | list_del(&next_node->fl_entry); | 
|  | 204 | drm_free(next_node, sizeof(*next_node), | 
|  | 205 | DRM_MEM_MM); | 
|  | 206 | } else { | 
|  | 207 | next_node->size += cur->size; | 
|  | 208 | next_node->start = cur->start; | 
| Andrew Morton | a1d0fcf | 2006-08-14 11:35:15 +1000 | [diff] [blame] | 209 | merged = 1; | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 210 | } | 
|  | 211 | } | 
|  | 212 | } | 
|  | 213 | if (!merged) { | 
| Andrew Morton | a1d0fcf | 2006-08-14 11:35:15 +1000 | [diff] [blame] | 214 | cur->free = 1; | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 215 | list_add(&cur->fl_entry, &mm->fl_entry); | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 216 | } else { | 
|  | 217 | list_del(&cur->ml_entry); | 
|  | 218 | drm_free(cur, sizeof(*cur), DRM_MEM_MM); | 
|  | 219 | } | 
|  | 220 | } | 
| Eric Anholt | 673a394 | 2008-07-30 12:06:12 -0700 | [diff] [blame] | 221 | EXPORT_SYMBOL(drm_mm_put_block); | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 222 |  | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 223 | struct drm_mm_node *drm_mm_search_free(const struct drm_mm * mm, | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 224 | unsigned long size, | 
|  | 225 | unsigned alignment, int best_match) | 
|  | 226 | { | 
|  | 227 | struct list_head *list; | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 228 | const struct list_head *free_stack = &mm->fl_entry; | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 229 | struct drm_mm_node *entry; | 
|  | 230 | struct drm_mm_node *best; | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 231 | unsigned long best_size; | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 232 | unsigned wasted; | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 233 |  | 
|  | 234 | best = NULL; | 
|  | 235 | best_size = ~0UL; | 
|  | 236 |  | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 237 | list_for_each(list, free_stack) { | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 238 | entry = list_entry(list, struct drm_mm_node, fl_entry); | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 239 | wasted = 0; | 
|  | 240 |  | 
|  | 241 | if (entry->size < size) | 
|  | 242 | continue; | 
|  | 243 |  | 
|  | 244 | if (alignment) { | 
|  | 245 | register unsigned tmp = entry->start % alignment; | 
|  | 246 | if (tmp) | 
|  | 247 | wasted += alignment - tmp; | 
|  | 248 | } | 
|  | 249 |  | 
|  | 250 |  | 
|  | 251 | if (entry->size >= size + wasted) { | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 252 | if (!best_match) | 
|  | 253 | return entry; | 
|  | 254 | if (size < best_size) { | 
|  | 255 | best = entry; | 
|  | 256 | best_size = entry->size; | 
|  | 257 | } | 
|  | 258 | } | 
|  | 259 | } | 
|  | 260 |  | 
|  | 261 | return best; | 
|  | 262 | } | 
|  | 263 |  | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 264 | int drm_mm_clean(struct drm_mm * mm) | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 265 | { | 
|  | 266 | struct list_head *head = &mm->ml_entry; | 
|  | 267 |  | 
|  | 268 | return (head->next->next == head); | 
|  | 269 | } | 
| Eric Anholt | 673a394 | 2008-07-30 12:06:12 -0700 | [diff] [blame] | 270 | EXPORT_SYMBOL(drm_mm_search_free); | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 271 |  | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 272 | int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size) | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 273 | { | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 274 | INIT_LIST_HEAD(&mm->ml_entry); | 
|  | 275 | INIT_LIST_HEAD(&mm->fl_entry); | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 276 |  | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 277 | return drm_mm_create_tail_node(mm, start, size); | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 278 | } | 
| Eric Anholt | 673a394 | 2008-07-30 12:06:12 -0700 | [diff] [blame] | 279 | EXPORT_SYMBOL(drm_mm_init); | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 280 |  | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 281 | void drm_mm_takedown(struct drm_mm * mm) | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 282 | { | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 283 | struct list_head *bnode = mm->fl_entry.next; | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 284 | struct drm_mm_node *entry; | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 285 |  | 
| Dave Airlie | 5591051 | 2007-07-11 16:53:40 +1000 | [diff] [blame] | 286 | entry = list_entry(bnode, struct drm_mm_node, fl_entry); | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 287 |  | 
| Thomas Hellstrom | 1d58420 | 2007-01-08 22:25:47 +1100 | [diff] [blame] | 288 | if (entry->ml_entry.next != &mm->ml_entry || | 
|  | 289 | entry->fl_entry.next != &mm->fl_entry) { | 
| Thomas Hellstrom | 3a1bd92 | 2006-08-07 21:30:28 +1000 | [diff] [blame] | 290 | DRM_ERROR("Memory manager not clean. Delaying takedown\n"); | 
|  | 291 | return; | 
|  | 292 | } | 
|  | 293 |  | 
|  | 294 | list_del(&entry->fl_entry); | 
|  | 295 | list_del(&entry->ml_entry); | 
|  | 296 |  | 
|  | 297 | drm_free(entry, sizeof(*entry), DRM_MEM_MM); | 
|  | 298 | } | 
| Dave Airlie | f453ba0 | 2008-11-07 14:05:41 -0800 | [diff] [blame] | 299 | EXPORT_SYMBOL(drm_mm_takedown); |