1 /**************************************************************************
3 * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
27 **************************************************************************/
30 * Generic simple memory manager implementation. Intended to be used as a base
31 * class implementation for more advanced memory managers.
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.
38 * Aligned allocations can also see improvement.
41 * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
46 drm_mm_node_t
*drm_mm_get_block(drm_mm_node_t
* parent
,
47 unsigned long size
, unsigned alignment
)
53 size
+= alignment
- 1;
55 if (parent
->size
== size
) {
56 list_del_init(&parent
->fl_entry
);
60 child
= (drm_mm_node_t
*) drm_alloc(sizeof(*child
), DRM_MEM_MM
);
64 INIT_LIST_HEAD(&child
->ml_entry
);
65 INIT_LIST_HEAD(&child
->fl_entry
);
69 child
->start
= parent
->start
;
71 list_add_tail(&child
->ml_entry
, &parent
->ml_entry
);
73 parent
->start
+= size
;
79 * Put a block. Merge with the previous and / or next block if they are free.
80 * Otherwise add to the free stack.
83 void drm_mm_put_block(drm_mm_t
* mm
, drm_mm_node_t
* cur
)
86 drm_mm_node_t
*list_root
= &mm
->root_node
;
87 struct list_head
*cur_head
= &cur
->ml_entry
;
88 struct list_head
*root_head
= &list_root
->ml_entry
;
89 drm_mm_node_t
*prev_node
= NULL
;
90 drm_mm_node_t
*next_node
;
94 if (cur_head
->prev
!= root_head
) {
95 prev_node
= list_entry(cur_head
->prev
, drm_mm_node_t
, ml_entry
);
96 if (prev_node
->free
) {
97 prev_node
->size
+= cur
->size
;
101 if (cur_head
->next
!= root_head
) {
102 next_node
= list_entry(cur_head
->next
, drm_mm_node_t
, ml_entry
);
103 if (next_node
->free
) {
105 prev_node
->size
+= next_node
->size
;
106 list_del(&next_node
->ml_entry
);
107 list_del(&next_node
->fl_entry
);
108 drm_free(next_node
, sizeof(*next_node
),
111 next_node
->size
+= cur
->size
;
112 next_node
->start
= cur
->start
;
119 list_add(&cur
->fl_entry
, &list_root
->fl_entry
);
121 list_del(&cur
->ml_entry
);
122 drm_free(cur
, sizeof(*cur
), DRM_MEM_MM
);
126 drm_mm_node_t
*drm_mm_search_free(const drm_mm_t
* mm
,
128 unsigned alignment
, int best_match
)
130 struct list_head
*list
;
131 const struct list_head
*free_stack
= &mm
->root_node
.fl_entry
;
132 drm_mm_node_t
*entry
;
134 unsigned long best_size
;
140 size
+= alignment
- 1;
142 list_for_each(list
, free_stack
) {
143 entry
= list_entry(list
, drm_mm_node_t
, fl_entry
);
144 if (entry
->size
>= size
) {
147 if (size
< best_size
) {
149 best_size
= entry
->size
;
157 int drm_mm_init(drm_mm_t
* mm
, unsigned long start
, unsigned long size
)
159 drm_mm_node_t
*child
;
161 INIT_LIST_HEAD(&mm
->root_node
.ml_entry
);
162 INIT_LIST_HEAD(&mm
->root_node
.fl_entry
);
163 child
= (drm_mm_node_t
*) drm_alloc(sizeof(*child
), DRM_MEM_MM
);
167 INIT_LIST_HEAD(&child
->ml_entry
);
168 INIT_LIST_HEAD(&child
->fl_entry
);
170 child
->start
= start
;
174 list_add(&child
->fl_entry
, &mm
->root_node
.fl_entry
);
175 list_add(&child
->ml_entry
, &mm
->root_node
.ml_entry
);
180 EXPORT_SYMBOL(drm_mm_init
);
182 void drm_mm_takedown(drm_mm_t
* mm
)
184 struct list_head
*bnode
= mm
->root_node
.fl_entry
.next
;
185 drm_mm_node_t
*entry
;
187 entry
= list_entry(bnode
, drm_mm_node_t
, fl_entry
);
189 if (entry
->ml_entry
.next
!= &mm
->root_node
.ml_entry
||
190 entry
->fl_entry
.next
!= &mm
->root_node
.fl_entry
) {
191 DRM_ERROR("Memory manager not clean. Delaying takedown\n");
195 list_del(&entry
->fl_entry
);
196 list_del(&entry
->ml_entry
);
198 drm_free(entry
, sizeof(*entry
), DRM_MEM_MM
);
201 EXPORT_SYMBOL(drm_mm_takedown
);