Signed-off-by: Jerome Glisse <jgli...@redhat.com>
---
 drivers/gpu/drm/drm_mm.c |   88 ++++++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_mm.h     |   34 ++++++++++++++++++
 2 files changed, 122 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
index 97dc5a4..5a06efe 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,
 }
 EXPORT_SYMBOL(drm_mm_get_block_generic);
 
+struct drm_mm_node *drm_mm_get_block_range_generic(struct drm_mm_node *node,
+                                               unsigned long size,
+                                               unsigned alignment,
+                                               unsigned long start,
+                                               unsigned long end,
+                                               int atomic)
+{
+       struct drm_mm_node *align_splitoff = NULL;
+       unsigned tmp = 0;
+       unsigned wasted = 0;
+
+       if (node->start < start)
+               wasted += start - node->start;
+       if (alignment)
+               tmp = ((node->start + wasted) % alignment);
+
+       if (tmp)
+               wasted += alignment - tmp;
+       if (wasted) {
+               align_splitoff = drm_mm_split_at_start(node, wasted, atomic);
+               if (unlikely(align_splitoff == NULL))
+                       return NULL;
+       }
+
+       if (node->size == size) {
+               list_del_init(&node->fl_entry);
+               node->free = 0;
+       } else {
+               node = drm_mm_split_at_start(node, size, atomic);
+       }
+
+       if (align_splitoff)
+               drm_mm_put_block(align_splitoff);
+
+       return node;
+}
+EXPORT_SYMBOL(drm_mm_get_block_range_generic);
+
 /*
  * Put a block. Merge with the previous and / or next block if they are free.
  * Otherwise add to the free stack.
@@ -331,6 +369,56 @@ struct drm_mm_node *drm_mm_search_free(const struct drm_mm 
*mm,
 }
 EXPORT_SYMBOL(drm_mm_search_free);
 
+struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm,
+                                               unsigned long size,
+                                               unsigned alignment,
+                                               unsigned long start,
+                                               unsigned long end,
+                                               int best_match)
+{
+       struct list_head *list;
+       const struct list_head *free_stack = &mm->fl_entry;
+       struct drm_mm_node *entry;
+       struct drm_mm_node *best;
+       unsigned long best_size;
+       unsigned wasted;
+
+       best = NULL;
+       best_size = ~0UL;
+
+       list_for_each(list, free_stack) {
+               entry = list_entry(list, struct drm_mm_node, fl_entry);
+               wasted = 0;
+
+               if (entry->size < size)
+                       continue;
+
+               if (entry->start > end || (entry->start+entry->size) < start)
+                       continue;
+
+               if (entry->start < start)
+                       wasted += start - entry->start;
+
+               if (alignment) {
+                       register unsigned tmp = (entry->start + wasted) % 
alignment;
+                       if (tmp)
+                               wasted += alignment - tmp;
+               }
+
+               if (entry->size >= size + wasted) {
+                       if (!best_match)
+                               return entry;
+                       if (size < best_size) {
+                               best = entry;
+                               best_size = entry->size;
+                       }
+               }
+       }
+
+       return best;
+}
+EXPORT_SYMBOL(drm_mm_search_free_in_range);
+
 int drm_mm_clean(struct drm_mm * mm)
 {
        struct list_head *head = &mm->ml_entry;
diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h
index 62329f9..b40b2f0 100644
--- a/include/drm/drm_mm.h
+++ b/include/drm/drm_mm.h
@@ -66,6 +66,13 @@ extern struct drm_mm_node *drm_mm_get_block_generic(struct 
drm_mm_node *node,
                                                    unsigned long size,
                                                    unsigned alignment,
                                                    int atomic);
+extern struct drm_mm_node *drm_mm_get_block_range_generic(
+                                               struct drm_mm_node *node,
+                                               unsigned long size,
+                                               unsigned alignment,
+                                               unsigned long start,
+                                               unsigned long end,
+                                               int atomic);
 static inline struct drm_mm_node *drm_mm_get_block(struct drm_mm_node *parent,
                                                   unsigned long size,
                                                   unsigned alignment)
@@ -78,11 +85,38 @@ static inline struct drm_mm_node 
*drm_mm_get_block_atomic(struct drm_mm_node *pa
 {
        return drm_mm_get_block_generic(parent, size, alignment, 1);
 }
+static inline struct drm_mm_node *drm_mm_get_block_range(
+                                               struct drm_mm_node *parent,
+                                               unsigned long size,
+                                               unsigned alignment,
+                                               unsigned long start,
+                                               unsigned long end)
+{
+       return drm_mm_get_block_range_generic(parent, size, alignment,
+                                               start, end, 0);
+}
+static inline struct drm_mm_node *drm_mm_get_block_atomic_range(
+                                               struct drm_mm_node *parent,
+                                               unsigned long size,
+                                               unsigned alignment,
+                                               unsigned long start,
+                                               unsigned long end)
+{
+       return drm_mm_get_block_range_generic(parent, size, alignment,
+                                               start, end, 1);
+}
 extern void drm_mm_put_block(struct drm_mm_node *cur);
 extern struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm,
                                              unsigned long size,
                                              unsigned alignment,
                                              int best_match);
+extern struct drm_mm_node *drm_mm_search_free_in_range(
+                                               const struct drm_mm *mm,
+                                               unsigned long size,
+                                               unsigned alignment,
+                                               unsigned long start,
+                                               unsigned long end,
+                                               int best_match);
 extern int drm_mm_init(struct drm_mm *mm, unsigned long start,
                       unsigned long size);
 extern void drm_mm_takedown(struct drm_mm *mm);
-- 
1.6.5.2


------------------------------------------------------------------------------
Join us December 9, 2009 for the Red Hat Virtual Experience,
a free event focused on virtualization and cloud computing. 
Attend in-depth sessions from your desk. Your couch. Anywhere.
http://p.sf.net/sfu/redhat-sfdev2dev
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to