aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/drm
diff options
context:
space:
mode:
authorThomas Hellstrom <thomas-at-tungstengraphics-dot-com>2007-01-08 06:25:47 -0500
committerDave Airlie <airlied@linux.ie>2007-02-07 21:24:26 -0500
commit1d58420bad15d08f93bf1e0342c1b1d1234d69b7 (patch)
tree0894a496155dd8cda01427fce9f5351f1981d7ea /drivers/char/drm
parent004a7727421fd202bbdfcc0231a3359085199a52 (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/char/drm')
-rw-r--r--drivers/char/drm/drmP.h10
-rw-r--r--drivers/char/drm/drm_mm.c183
-rw-r--r--drivers/char/drm/drm_sman.c3
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
538typedef struct drm_mm { 539typedef 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);
1050extern drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, 1052extern 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);
1053extern void drm_mm_put_block(drm_mm_t *mm, drm_mm_node_t *cur); 1055void drm_mm_put_block(drm_mm_node_t * cur);
1054extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size, 1056extern 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);
1056extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size); 1058extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size);
1057extern void drm_mm_takedown(drm_mm_t *mm); 1059extern void drm_mm_takedown(drm_mm_t *mm);
1060extern int drm_mm_clean(drm_mm_t *mm);
1061extern unsigned long drm_mm_tail_space(drm_mm_t *mm);
1062extern int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size);
1063extern int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size);
1058 1064
1059extern void drm_core_ioremap(struct drm_map *map, struct drm_device *dev); 1065extern void drm_core_ioremap(struct drm_map *map, struct drm_device *dev);
1060extern void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev); 1066extern 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
47unsigned 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
60int 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
78static 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
101int 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
115static 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
46drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, 142drm_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
83void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur) 178void 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
157int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) 262int 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); 269int 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
180EXPORT_SYMBOL(drm_mm_init); 277EXPORT_SYMBOL(drm_mm_init);
181 278
182void drm_mm_takedown(drm_mm_t * mm) 279void 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
102static void drm_sman_mm_free(void *private, void *ref) 102static 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
110static void drm_sman_mm_destroy(void *private) 109static void drm_sman_mm_destroy(void *private)