aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_mm.c
diff options
context:
space:
mode:
authorJerome Glisse <jglisse@redhat.com>2009-12-07 09:52:56 -0500
committerDave Airlie <airlied@redhat.com>2009-12-10 00:09:01 -0500
commita2e68e92d384d37c8cc6bb7206d43b1eb9bc3f08 (patch)
tree5050cb18d00830a3f80ad650f8c16ed40953399c /drivers/gpu/drm/drm_mm.c
parentcf2f05d30dacab32e6866347be6cbfa4030b33b7 (diff)
drm: Add search/get functions to get a block in a specific range
These are required for changes to TTM. Signed-off-by: Jerome Glisse <jglisse@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/drm_mm.c')
-rw-r--r--drivers/gpu/drm/drm_mm.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
index 1f0d717dbad6..a5c2773ccf27 100644
--- a/drivers/gpu/drm/drm_mm.c
+++ b/drivers/gpu/drm/drm_mm.c
@@ -226,6 +226,44 @@ struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node,
226} 226}
227EXPORT_SYMBOL(drm_mm_get_block_generic); 227EXPORT_SYMBOL(drm_mm_get_block_generic);
228 228
229struct drm_mm_node *drm_mm_get_block_range_generic(struct drm_mm_node *node,
230 unsigned long size,
231 unsigned alignment,
232 unsigned long start,
233 unsigned long end,
234 int atomic)
235{
236 struct drm_mm_node *align_splitoff = NULL;
237 unsigned tmp = 0;
238 unsigned wasted = 0;
239
240 if (node->start < start)
241 wasted += start - node->start;
242 if (alignment)
243 tmp = ((node->start + wasted) % alignment);
244
245 if (tmp)
246 wasted += alignment - tmp;
247 if (wasted) {
248 align_splitoff = drm_mm_split_at_start(node, wasted, atomic);
249 if (unlikely(align_splitoff == NULL))
250 return NULL;
251 }
252
253 if (node->size == size) {
254 list_del_init(&node->fl_entry);
255 node->free = 0;
256 } else {
257 node = drm_mm_split_at_start(node, size, atomic);
258 }
259
260 if (align_splitoff)
261 drm_mm_put_block(align_splitoff);
262
263 return node;
264}
265EXPORT_SYMBOL(drm_mm_get_block_range_generic);
266
229/* 267/*
230 * Put a block. Merge with the previous and / or next block if they are free. 268 * Put a block. Merge with the previous and / or next block if they are free.
231 * Otherwise add to the free stack. 269 * Otherwise add to the free stack.
@@ -331,6 +369,56 @@ struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm,
331} 369}
332EXPORT_SYMBOL(drm_mm_search_free); 370EXPORT_SYMBOL(drm_mm_search_free);
333 371
372struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm,
373 unsigned long size,
374 unsigned alignment,
375 unsigned long start,
376 unsigned long end,
377 int best_match)
378{
379 struct list_head *list;
380 const struct list_head *free_stack = &mm->fl_entry;
381 struct drm_mm_node *entry;
382 struct drm_mm_node *best;
383 unsigned long best_size;
384 unsigned wasted;
385
386 best = NULL;
387 best_size = ~0UL;
388
389 list_for_each(list, free_stack) {
390 entry = list_entry(list, struct drm_mm_node, fl_entry);
391 wasted = 0;
392
393 if (entry->size < size)
394 continue;
395
396 if (entry->start > end || (entry->start+entry->size) < start)
397 continue;
398
399 if (entry->start < start)
400 wasted += start - entry->start;
401
402 if (alignment) {
403 register unsigned tmp = (entry->start + wasted) % alignment;
404 if (tmp)
405 wasted += alignment - tmp;
406 }
407
408 if (entry->size >= size + wasted) {
409 if (!best_match)
410 return entry;
411 if (size < best_size) {
412 best = entry;
413 best_size = entry->size;
414 }
415 }
416 }
417
418 return best;
419}
420EXPORT_SYMBOL(drm_mm_search_free_in_range);
421
334int drm_mm_clean(struct drm_mm * mm) 422int drm_mm_clean(struct drm_mm * mm)
335{ 423{
336 struct list_head *head = &mm->ml_entry; 424 struct list_head *head = &mm->ml_entry;