diff options
author | Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> | 2007-01-08 06:25:47 -0500 |
---|---|---|
committer | Dave Airlie <airlied@linux.ie> | 2007-02-07 21:24:26 -0500 |
commit | 1d58420bad15d08f93bf1e0342c1b1d1234d69b7 (patch) | |
tree | 0894a496155dd8cda01427fce9f5351f1981d7ea /drivers | |
parent | 004a7727421fd202bbdfcc0231a3359085199a52 (diff) |
drm: update core memory manager from git drm tree
Remove the memory manager parameter from the put_block function, as this
makes the client code a lot cleaner. Prepare buffer manager for lock and
unlock calls.
Fix buggy aligned allocations.
Remove the stupid root_node field from the core memory manager.
Support multi-page buffer offset alignments
Add improved alignment functionality to the core memory manager.
This makes an allocated block actually align itself and returns any
wasted space to the manager.
Signed-off-by: Dave Airlie <airlied@linux.ie>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/char/drm/drmP.h | 10 | ||||
-rw-r--r-- | drivers/char/drm/drm_mm.c | 183 | ||||
-rw-r--r-- | drivers/char/drm/drm_sman.c | 3 |
3 files changed, 149 insertions, 47 deletions
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 63042ca9fffe..85d99e21e188 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h | |||
@@ -532,11 +532,13 @@ typedef struct drm_mm_node { | |||
532 | int free; | 532 | int free; |
533 | unsigned long start; | 533 | unsigned long start; |
534 | unsigned long size; | 534 | unsigned long size; |
535 | struct drm_mm *mm; | ||
535 | void *private; | 536 | void *private; |
536 | } drm_mm_node_t; | 537 | } drm_mm_node_t; |
537 | 538 | ||
538 | typedef struct drm_mm { | 539 | typedef struct drm_mm { |
539 | drm_mm_node_t root_node; | 540 | struct list_head fl_entry; |
541 | struct list_head ml_entry; | ||
540 | } drm_mm_t; | 542 | } drm_mm_t; |
541 | 543 | ||
542 | /** | 544 | /** |
@@ -1050,11 +1052,15 @@ extern void drm_sysfs_device_remove(struct class_device *class_dev); | |||
1050 | extern drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, | 1052 | extern drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, |
1051 | unsigned long size, | 1053 | unsigned long size, |
1052 | unsigned alignment); | 1054 | unsigned alignment); |
1053 | extern void drm_mm_put_block(drm_mm_t *mm, drm_mm_node_t *cur); | 1055 | void drm_mm_put_block(drm_mm_node_t * cur); |
1054 | extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size, | 1056 | extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size, |
1055 | unsigned alignment, int best_match); | 1057 | unsigned alignment, int best_match); |
1056 | extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size); | 1058 | extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size); |
1057 | extern void drm_mm_takedown(drm_mm_t *mm); | 1059 | extern void drm_mm_takedown(drm_mm_t *mm); |
1060 | extern int drm_mm_clean(drm_mm_t *mm); | ||
1061 | extern unsigned long drm_mm_tail_space(drm_mm_t *mm); | ||
1062 | extern int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size); | ||
1063 | extern int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size); | ||
1058 | 1064 | ||
1059 | extern void drm_core_ioremap(struct drm_map *map, struct drm_device *dev); | 1065 | extern void drm_core_ioremap(struct drm_map *map, struct drm_device *dev); |
1060 | extern void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev); | 1066 | extern void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev); |
diff --git a/drivers/char/drm/drm_mm.c b/drivers/char/drm/drm_mm.c index 617526bd5b0c..9b46b85027d0 100644 --- a/drivers/char/drm/drm_mm.c +++ b/drivers/char/drm/drm_mm.c | |||
@@ -42,36 +42,131 @@ | |||
42 | */ | 42 | */ |
43 | 43 | ||
44 | #include "drmP.h" | 44 | #include "drmP.h" |
45 | #include <linux/slab.h> | ||
46 | |||
47 | unsigned long drm_mm_tail_space(drm_mm_t *mm) | ||
48 | { | ||
49 | struct list_head *tail_node; | ||
50 | drm_mm_node_t *entry; | ||
51 | |||
52 | tail_node = mm->ml_entry.prev; | ||
53 | entry = list_entry(tail_node, drm_mm_node_t, ml_entry); | ||
54 | if (!entry->free) | ||
55 | return 0; | ||
56 | |||
57 | return entry->size; | ||
58 | } | ||
59 | |||
60 | int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size) | ||
61 | { | ||
62 | struct list_head *tail_node; | ||
63 | drm_mm_node_t *entry; | ||
64 | |||
65 | tail_node = mm->ml_entry.prev; | ||
66 | entry = list_entry(tail_node, drm_mm_node_t, ml_entry); | ||
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 | |||
78 | static int drm_mm_create_tail_node(drm_mm_t *mm, | ||
79 | unsigned long start, | ||
80 | unsigned long size) | ||
81 | { | ||
82 | drm_mm_node_t *child; | ||
83 | |||
84 | child = (drm_mm_node_t *) | ||
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 | |||
101 | int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size) | ||
102 | { | ||
103 | struct list_head *tail_node; | ||
104 | drm_mm_node_t *entry; | ||
105 | |||
106 | tail_node = mm->ml_entry.prev; | ||
107 | entry = list_entry(tail_node, drm_mm_node_t, ml_entry); | ||
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 | |||
115 | static drm_mm_node_t *drm_mm_split_at_start(drm_mm_node_t *parent, | ||
116 | unsigned long size) | ||
117 | { | ||
118 | drm_mm_node_t *child; | ||
119 | |||
120 | child = (drm_mm_node_t *) | ||
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 | |||
45 | 141 | ||
46 | drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, | 142 | drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, |
47 | unsigned long size, unsigned alignment) | 143 | unsigned long size, unsigned alignment) |
48 | { | 144 | { |
49 | 145 | ||
146 | drm_mm_node_t *align_splitoff = NULL; | ||
50 | drm_mm_node_t *child; | 147 | drm_mm_node_t *child; |
148 | unsigned tmp = 0; | ||
51 | 149 | ||
52 | if (alignment) | 150 | if (alignment) |
53 | size += alignment - 1; | 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 | } | ||
54 | 158 | ||
55 | if (parent->size == size) { | 159 | if (parent->size == size) { |
56 | list_del_init(&parent->fl_entry); | 160 | list_del_init(&parent->fl_entry); |
57 | parent->free = 0; | 161 | parent->free = 0; |
58 | return parent; | 162 | return parent; |
59 | } else { | 163 | } else { |
60 | child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM); | 164 | child = drm_mm_split_at_start(parent, size); |
61 | if (!child) | 165 | } |
62 | return NULL; | ||
63 | |||
64 | INIT_LIST_HEAD(&child->ml_entry); | ||
65 | INIT_LIST_HEAD(&child->fl_entry); | ||
66 | 166 | ||
67 | child->free = 0; | 167 | if (align_splitoff) |
68 | child->size = size; | 168 | drm_mm_put_block(align_splitoff); |
69 | child->start = parent->start; | ||
70 | 169 | ||
71 | list_add_tail(&child->ml_entry, &parent->ml_entry); | ||
72 | parent->size -= size; | ||
73 | parent->start += size; | ||
74 | } | ||
75 | return child; | 170 | return child; |
76 | } | 171 | } |
77 | 172 | ||
@@ -80,12 +175,12 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, | |||
80 | * Otherwise add to the free stack. | 175 | * Otherwise add to the free stack. |
81 | */ | 176 | */ |
82 | 177 | ||
83 | void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur) | 178 | void drm_mm_put_block(drm_mm_node_t * cur) |
84 | { | 179 | { |
85 | 180 | ||
86 | drm_mm_node_t *list_root = &mm->root_node; | 181 | drm_mm_t *mm = cur->mm; |
87 | struct list_head *cur_head = &cur->ml_entry; | 182 | struct list_head *cur_head = &cur->ml_entry; |
88 | struct list_head *root_head = &list_root->ml_entry; | 183 | struct list_head *root_head = &mm->ml_entry; |
89 | drm_mm_node_t *prev_node = NULL; | 184 | drm_mm_node_t *prev_node = NULL; |
90 | drm_mm_node_t *next_node; | 185 | drm_mm_node_t *next_node; |
91 | 186 | ||
@@ -116,7 +211,7 @@ void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur) | |||
116 | } | 211 | } |
117 | if (!merged) { | 212 | if (!merged) { |
118 | cur->free = 1; | 213 | cur->free = 1; |
119 | list_add(&cur->fl_entry, &list_root->fl_entry); | 214 | list_add(&cur->fl_entry, &mm->fl_entry); |
120 | } else { | 215 | } else { |
121 | list_del(&cur->ml_entry); | 216 | list_del(&cur->ml_entry); |
122 | drm_free(cur, sizeof(*cur), DRM_MEM_MM); | 217 | drm_free(cur, sizeof(*cur), DRM_MEM_MM); |
@@ -128,20 +223,30 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm, | |||
128 | unsigned alignment, int best_match) | 223 | unsigned alignment, int best_match) |
129 | { | 224 | { |
130 | struct list_head *list; | 225 | struct list_head *list; |
131 | const struct list_head *free_stack = &mm->root_node.fl_entry; | 226 | const struct list_head *free_stack = &mm->fl_entry; |
132 | drm_mm_node_t *entry; | 227 | drm_mm_node_t *entry; |
133 | drm_mm_node_t *best; | 228 | drm_mm_node_t *best; |
134 | unsigned long best_size; | 229 | unsigned long best_size; |
230 | unsigned wasted; | ||
135 | 231 | ||
136 | best = NULL; | 232 | best = NULL; |
137 | best_size = ~0UL; | 233 | best_size = ~0UL; |
138 | 234 | ||
139 | if (alignment) | ||
140 | size += alignment - 1; | ||
141 | |||
142 | list_for_each(list, free_stack) { | 235 | list_for_each(list, free_stack) { |
143 | entry = list_entry(list, drm_mm_node_t, fl_entry); | 236 | entry = list_entry(list, drm_mm_node_t, fl_entry); |
144 | if (entry->size >= size) { | 237 | wasted = 0; |
238 | |||
239 | if (entry->size < size) | ||
240 | continue; | ||
241 | |||
242 | if (alignment) { | ||
243 | register unsigned tmp = entry->start % alignment; | ||
244 | if (tmp) | ||
245 | wasted += alignment - tmp; | ||
246 | } | ||
247 | |||
248 | |||
249 | if (entry->size >= size + wasted) { | ||
145 | if (!best_match) | 250 | if (!best_match) |
146 | return entry; | 251 | return entry; |
147 | if (size < best_size) { | 252 | if (size < best_size) { |
@@ -154,40 +259,32 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm, | |||
154 | return best; | 259 | return best; |
155 | } | 260 | } |
156 | 261 | ||
157 | int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) | 262 | int drm_mm_clean(drm_mm_t * mm) |
158 | { | 263 | { |
159 | drm_mm_node_t *child; | 264 | struct list_head *head = &mm->ml_entry; |
160 | |||
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); | ||
164 | if (!child) | ||
165 | return -ENOMEM; | ||
166 | |||
167 | INIT_LIST_HEAD(&child->ml_entry); | ||
168 | INIT_LIST_HEAD(&child->fl_entry); | ||
169 | 265 | ||
170 | child->start = start; | 266 | return (head->next->next == head); |
171 | child->size = size; | 267 | } |
172 | child->free = 1; | ||
173 | 268 | ||
174 | list_add(&child->fl_entry, &mm->root_node.fl_entry); | 269 | int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) |
175 | list_add(&child->ml_entry, &mm->root_node.ml_entry); | 270 | { |
271 | INIT_LIST_HEAD(&mm->ml_entry); | ||
272 | INIT_LIST_HEAD(&mm->fl_entry); | ||
176 | 273 | ||
177 | return 0; | 274 | return drm_mm_create_tail_node(mm, start, size); |
178 | } | 275 | } |
179 | 276 | ||
180 | EXPORT_SYMBOL(drm_mm_init); | 277 | EXPORT_SYMBOL(drm_mm_init); |
181 | 278 | ||
182 | void drm_mm_takedown(drm_mm_t * mm) | 279 | void drm_mm_takedown(drm_mm_t * mm) |
183 | { | 280 | { |
184 | struct list_head *bnode = mm->root_node.fl_entry.next; | 281 | struct list_head *bnode = mm->fl_entry.next; |
185 | drm_mm_node_t *entry; | 282 | drm_mm_node_t *entry; |
186 | 283 | ||
187 | entry = list_entry(bnode, drm_mm_node_t, fl_entry); | 284 | entry = list_entry(bnode, drm_mm_node_t, fl_entry); |
188 | 285 | ||
189 | if (entry->ml_entry.next != &mm->root_node.ml_entry || | 286 | if (entry->ml_entry.next != &mm->ml_entry || |
190 | entry->fl_entry.next != &mm->root_node.fl_entry) { | 287 | entry->fl_entry.next != &mm->fl_entry) { |
191 | DRM_ERROR("Memory manager not clean. Delaying takedown\n"); | 288 | DRM_ERROR("Memory manager not clean. Delaying takedown\n"); |
192 | return; | 289 | return; |
193 | } | 290 | } |
diff --git a/drivers/char/drm/drm_sman.c b/drivers/char/drm/drm_sman.c index 19c81d2e13d0..e15db6d6bea9 100644 --- a/drivers/char/drm/drm_sman.c +++ b/drivers/char/drm/drm_sman.c | |||
@@ -101,10 +101,9 @@ static void *drm_sman_mm_allocate(void *private, unsigned long size, | |||
101 | 101 | ||
102 | static void drm_sman_mm_free(void *private, void *ref) | 102 | static void drm_sman_mm_free(void *private, void *ref) |
103 | { | 103 | { |
104 | drm_mm_t *mm = (drm_mm_t *) private; | ||
105 | drm_mm_node_t *node = (drm_mm_node_t *) ref; | 104 | drm_mm_node_t *node = (drm_mm_node_t *) ref; |
106 | 105 | ||
107 | drm_mm_put_block(mm, node); | 106 | drm_mm_put_block(node); |
108 | } | 107 | } |
109 | 108 | ||
110 | static void drm_sman_mm_destroy(void *private) | 109 | static void drm_sman_mm_destroy(void *private) |