]> code.ossystems Code Review - openembedded-core.git/blob
2655acfaa51f648e4a330ddc7e78ff8fdb9156fa
[openembedded-core.git] /
1 From 84e7ccff650b8f124585ba7d5b9a1544f53457e7 Mon Sep 17 00:00:00 2001\r
2 From: Thomas Hellstrom <thellstrom-at-vmware-dot-com>\r
3 Date: Fri, 27 Feb 2009 16:53:11 +0100\r
4 Subject: [PATCH 1/8] drm: Split out the mm declarations in a separate header. Add atomic operations.\r
5 \r
6 Signed-off-by: Thomas Hellstrom <thellstrom-at-vmware-dot-com>\r
7 ---\r
8  drivers/gpu/drm/drm_mm.c |  173 ++++++++++++++++++++++++++++++++++++++--------\r
9  include/drm/drmP.h       |   37 +----------\r
10  include/drm/drm_mm.h     |   90 ++++++++++++++++++++++++\r
11  3 files changed, 235 insertions(+), 65 deletions(-)\r
12  create mode 100644 include/drm/drm_mm.h\r
13 \r
14 Index: linux-2.6.28/drivers/gpu/drm/drm_mm.c
15 ===================================================================
16 --- linux-2.6.28.orig/drivers/gpu/drm/drm_mm.c  2009-03-09 19:19:52.000000000 +0000
17 +++ linux-2.6.28/drivers/gpu/drm/drm_mm.c       2009-03-12 13:15:05.000000000 +0000
18 @@ -42,8 +43,11 @@
19   */
20  
21  #include "drmP.h"
22 +#include "drm_mm.h"
23  #include <linux/slab.h>
24  
25 +#define MM_UNUSED_TARGET 4
26 +
27  unsigned long drm_mm_tail_space(struct drm_mm *mm)
28  {
29         struct list_head *tail_node;
30 @@ -74,16 +78,66 @@
31         return 0;
32  }
33  
34 +static struct drm_mm_node *drm_mm_kmalloc(struct drm_mm *mm, int atomic)
35 +{
36 +       struct drm_mm_node *child;
37 +
38 +       if (atomic) {
39 +               child =
40 +                   (struct drm_mm_node *)kmalloc(sizeof(*child), GFP_ATOMIC);
41 +       } else {
42 +               child =
43 +                   (struct drm_mm_node *)kmalloc(sizeof(*child), GFP_KERNEL);
44 +       }
45 +
46 +       if (unlikely(child == NULL)) {
47 +               spin_lock(&mm->unused_lock);
48 +               if (list_empty(&mm->unused_nodes))
49 +                       child = NULL;
50 +               else {
51 +                       child =
52 +                           list_entry(mm->unused_nodes.next,
53 +                                      struct drm_mm_node, fl_entry);
54 +                       list_del(&child->fl_entry);
55 +                       --mm->num_unused;
56 +               }
57 +               spin_unlock(&mm->unused_lock);
58 +       }
59 +       return child;
60 +}
61 +
62 +int drm_mm_pre_get(struct drm_mm *mm)
63 +{
64 +       struct drm_mm_node *node;
65 +
66 +       spin_lock(&mm->unused_lock);
67 +       while (mm->num_unused < MM_UNUSED_TARGET) {
68 +               spin_unlock(&mm->unused_lock);
69 +               node = kmalloc(sizeof(*node), GFP_KERNEL);
70 +               spin_lock(&mm->unused_lock);
71 +
72 +               if (unlikely(node == NULL)) {
73 +                       int ret = (mm->num_unused < 2) ? -ENOMEM : 0;
74 +                       spin_unlock(&mm->unused_lock);
75 +                       return ret;
76 +               }
77 +               ++mm->num_unused;
78 +               list_add_tail(&node->fl_entry, &mm->unused_nodes);
79 +       }
80 +       spin_unlock(&mm->unused_lock);
81 +       return 0;
82 +}
83 +
84 +EXPORT_SYMBOL(drm_mm_pre_get);
85  
86  static int drm_mm_create_tail_node(struct drm_mm *mm,
87 -                           unsigned long start,
88 -                           unsigned long size)
89 +                                  unsigned long start,
90 +                                  unsigned long size, int atomic)
91  {
92         struct drm_mm_node *child;
93  
94 -       child = (struct drm_mm_node *)
95 -               drm_alloc(sizeof(*child), DRM_MEM_MM);
96 -       if (!child)
97 +       child = drm_mm_kmalloc(mm, atomic);
98 +       if (unlikely(child == NULL))
99                 return -ENOMEM;
100  
101         child->free = 1;
102 @@ -97,8 +151,7 @@
103         return 0;
104  }
105  
106 -
107 -int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size)
108 +int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size, int atomic)
109  {
110         struct list_head *tail_node;
111         struct drm_mm_node *entry;
112 @@ -106,20 +159,21 @@
113         tail_node = mm->ml_entry.prev;
114         entry = list_entry(tail_node, struct drm_mm_node, ml_entry);
115         if (!entry->free) {
116 -               return drm_mm_create_tail_node(mm, entry->start + entry->size, size);
117 +               return drm_mm_create_tail_node(mm, entry->start + entry->size,
118 +                                              size, atomic);
119         }
120         entry->size += size;
121         return 0;
122  }
123  
124  static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent,
125 -                                           unsigned long size)
126 +                                                unsigned long size,
127 +                                                int atomic)
128  {
129         struct drm_mm_node *child;
130  
131 -       child = (struct drm_mm_node *)
132 -               drm_alloc(sizeof(*child), DRM_MEM_MM);
133 -       if (!child)
134 +       child = drm_mm_kmalloc(parent->mm, atomic);
135 +       if (unlikely(child == NULL))
136                 return NULL;
137  
138         INIT_LIST_HEAD(&child->fl_entry);
139 @@ -151,8 +205,9 @@
140                 tmp = parent->start % alignment;
141  
142         if (tmp) {
143 -               align_splitoff = drm_mm_split_at_start(parent, alignment - tmp);
144 -               if (!align_splitoff)
145 +               align_splitoff =
146 +                   drm_mm_split_at_start(parent, alignment - tmp, 0);
147 +               if (unlikely(align_splitoff == NULL))
148                         return NULL;
149         }
150  
151 @@ -161,7 +216,7 @@
152                 parent->free = 0;
153                 return parent;
154         } else {
155 -               child = drm_mm_split_at_start(parent, size);
156 +               child = drm_mm_split_at_start(parent, size, 0);
157         }
158  
159         if (align_splitoff)
160 @@ -169,14 +224,50 @@
161  
162         return child;
163  }
164 +
165  EXPORT_SYMBOL(drm_mm_get_block);
166  
167 +struct drm_mm_node *drm_mm_get_block_atomic(struct drm_mm_node *parent,
168 +                                           unsigned long size,
169 +                                           unsigned alignment)
170 +{
171 +
172 +       struct drm_mm_node *align_splitoff = NULL;
173 +       struct drm_mm_node *child;
174 +       unsigned tmp = 0;
175 +
176 +       if (alignment)
177 +               tmp = parent->start % alignment;
178 +
179 +       if (tmp) {
180 +               align_splitoff =
181 +                   drm_mm_split_at_start(parent, alignment - tmp, 1);
182 +               if (unlikely(align_splitoff == NULL))
183 +                       return NULL;
184 +       }
185 +
186 +       if (parent->size == size) {
187 +               list_del_init(&parent->fl_entry);
188 +               parent->free = 0;
189 +               return parent;
190 +       } else {
191 +               child = drm_mm_split_at_start(parent, size, 1);
192 +       }
193 +
194 +       if (align_splitoff)
195 +               drm_mm_put_block(align_splitoff);
196 +
197 +       return child;
198 +}
199 +
200 +EXPORT_SYMBOL(drm_mm_get_block_atomic);
201 +
202  /*
203   * Put a block. Merge with the previous and / or next block if they are free.
204   * Otherwise add to the free stack.
205   */
206  
207 -void drm_mm_put_block(struct drm_mm_node * cur)
208 +void drm_mm_put_block(struct drm_mm_node *cur)
209  {
210  
211         struct drm_mm *mm = cur->mm;
212 @@ -188,21 +279,27 @@
213         int merged = 0;
214  
215         if (cur_head->prev != root_head) {
216 -               prev_node = list_entry(cur_head->prev, struct drm_mm_node, ml_entry);
217 +               prev_node =
218 +                   list_entry(cur_head->prev, struct drm_mm_node, ml_entry);
219                 if (prev_node->free) {
220                         prev_node->size += cur->size;
221                         merged = 1;
222                 }
223         }
224         if (cur_head->next != root_head) {
225 -               next_node = list_entry(cur_head->next, struct drm_mm_node, ml_entry);
226 +               next_node =
227 +                   list_entry(cur_head->next, struct drm_mm_node, ml_entry);
228                 if (next_node->free) {
229                         if (merged) {
230                                 prev_node->size += next_node->size;
231                                 list_del(&next_node->ml_entry);
232                                 list_del(&next_node->fl_entry);
233 -                               drm_free(next_node, sizeof(*next_node),
234 -                                        DRM_MEM_MM);
235 +                               if (mm->num_unused < MM_UNUSED_TARGET) {
236 +                                       list_add(&next_node->fl_entry,
237 +                                                &mm->unused_nodes);
238 +                                       ++mm->num_unused;
239 +                               } else
240 +                                       kfree(next_node);
241                         } else {
242                                 next_node->size += cur->size;
243                                 next_node->start = cur->start;
244 @@ -215,14 +312,19 @@
245                 list_add(&cur->fl_entry, &mm->fl_entry);
246         } else {
247                 list_del(&cur->ml_entry);
248 -               drm_free(cur, sizeof(*cur), DRM_MEM_MM);
249 +               if (mm->num_unused < MM_UNUSED_TARGET) {
250 +                       list_add(&cur->fl_entry, &mm->unused_nodes);
251 +                       ++mm->num_unused;
252 +               } else
253 +                       kfree(cur);
254         }
255  }
256 +
257  EXPORT_SYMBOL(drm_mm_put_block);
258  
259 -struct drm_mm_node *drm_mm_search_free(const struct drm_mm * mm,
260 -                                 unsigned long size,
261 -                                 unsigned alignment, int best_match)
262 +struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm,
263 +                                      unsigned long size,
264 +                                      unsigned alignment, int best_match)
265  {
266         struct list_head *list;
267         const struct list_head *free_stack = &mm->fl_entry;
268 @@ -247,7 +349,6 @@
269                                 wasted += alignment - tmp;
270                 }
271  
272 -
273                 if (entry->size >= size + wasted) {
274                         if (!best_match)
275                                 return entry;
276 @@ -260,6 +361,7 @@
277  
278         return best;
279  }
280 +EXPORT_SYMBOL(drm_mm_search_free);
281  
282  int drm_mm_clean(struct drm_mm * mm)
283  {
284 @@ -267,14 +369,17 @@
285  
286         return (head->next->next == head);
287  }
288 -EXPORT_SYMBOL(drm_mm_search_free);
289 +EXPORT_SYMBOL(drm_mm_clean);
290  
291  int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
292  {
293         INIT_LIST_HEAD(&mm->ml_entry);
294         INIT_LIST_HEAD(&mm->fl_entry);
295 +       INIT_LIST_HEAD(&mm->unused_nodes);
296 +       mm->num_unused = 0;
297 +       spin_lock_init(&mm->unused_lock);
298  
299 -       return drm_mm_create_tail_node(mm, start, size);
300 +       return drm_mm_create_tail_node(mm, start, size, 0);
301  }
302  EXPORT_SYMBOL(drm_mm_init);
303  
304 @@ -282,6 +387,7 @@
305  {
306         struct list_head *bnode = mm->fl_entry.next;
307         struct drm_mm_node *entry;
308 +       struct drm_mm_node *next;
309  
310         entry = list_entry(bnode, struct drm_mm_node, fl_entry);
311  
312 @@ -293,7 +399,16 @@
313  
314         list_del(&entry->fl_entry);
315         list_del(&entry->ml_entry);
316 +       kfree(entry);
317 +
318 +       spin_lock(&mm->unused_lock);
319 +       list_for_each_entry_safe(entry, next, &mm->unused_nodes, fl_entry) {
320 +               list_del(&entry->fl_entry);
321 +               kfree(entry);
322 +               --mm->num_unused;
323 +       }
324 +       spin_unlock(&mm->unused_lock);
325  
326 -       drm_free(entry, sizeof(*entry), DRM_MEM_MM);
327 +       BUG_ON(mm->num_unused != 0);
328  }
329  EXPORT_SYMBOL(drm_mm_takedown);
330 Index: linux-2.6.28/include/drm/drmP.h
331 ===================================================================
332 --- linux-2.6.28.orig/include/drm/drmP.h        2009-03-12 13:13:54.000000000 +0000
333 +++ linux-2.6.28/include/drm/drmP.h     2009-03-12 13:37:59.000000000 +0000
334 @@ -86,6 +86,7 @@
335  
336  #include "drm_os_linux.h"
337  #include "drm_hashtab.h"
338 +#include "drm_mm.h"
339  
340  /***********************************************************************/
341  /** \name DRM template customization defaults */
342 @@ -502,26 +503,6 @@
343  };
344  
345  
346 -/*
347 - * Generic memory manager structs
348 - */
349 -
350 -struct drm_mm_node {
351 -       struct list_head fl_entry;
352 -       struct list_head ml_entry;
353 -       int free;
354 -       unsigned long start;
355 -       unsigned long size;
356 -       struct drm_mm *mm;
357 -       void *private;
358 -};
359 -
360 -struct drm_mm {
361 -       struct list_head fl_entry;
362 -       struct list_head ml_entry;
363 -};
364 -
365 -
366  /**
367   * Mappings list
368   */
369 @@ -1307,22 +1288,6 @@
370  extern int drm_sysfs_connector_add(struct drm_connector *connector);
371  extern void drm_sysfs_connector_remove(struct drm_connector *connector);
372  
373 -/*
374 - * Basic memory manager support (drm_mm.c)
375 - */
376 -extern struct drm_mm_node *drm_mm_get_block(struct drm_mm_node * parent,
377 -                                      unsigned long size,
378 -                                      unsigned alignment);
379 -extern void drm_mm_put_block(struct drm_mm_node * cur);
380 -extern struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm, unsigned long size,
381 -                                        unsigned alignment, int best_match);
382 -extern int drm_mm_init(struct drm_mm *mm, unsigned long start, unsigned long size);
383 -extern void drm_mm_takedown(struct drm_mm *mm);
384 -extern int drm_mm_clean(struct drm_mm *mm);
385 -extern unsigned long drm_mm_tail_space(struct drm_mm *mm);
386 -extern int drm_mm_remove_space_from_tail(struct drm_mm *mm, unsigned long size);
387 -extern int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size);
388 -
389  /* Graphics Execution Manager library functions (drm_gem.c) */
390  int drm_gem_init(struct drm_device *dev);
391  void drm_gem_destroy(struct drm_device *dev);
392 Index: linux-2.6.28/include/drm/drm_mm.h
393 ===================================================================
394 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
395 +++ linux-2.6.28/include/drm/drm_mm.h   2009-03-12 13:15:05.000000000 +0000
396 @@ -0,0 +1,90 @@
397 +/**************************************************************************
398 + *
399 + * Copyright 2006-2008 Tungsten Graphics, Inc., Cedar Park, TX. USA.
400 + * All Rights Reserved.
401 + *
402 + * Permission is hereby granted, free of charge, to any person obtaining a
403 + * copy of this software and associated documentation files (the
404 + * "Software"), to deal in the Software without restriction, including
405 + * without limitation the rights to use, copy, modify, merge, publish,
406 + * distribute, sub license, and/or sell copies of the Software, and to
407 + * permit persons to whom the Software is furnished to do so, subject to
408 + * the following conditions:
409 + *
410 + * The above copyright notice and this permission notice (including the
411 + * next paragraph) shall be included in all copies or substantial portions
412 + * of the Software.
413 + *
414 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
415 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
416 + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
417 + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
418 + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
419 + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
420 + * USE OR OTHER DEALINGS IN THE SOFTWARE.
421 + *
422 + *
423 + **************************************************************************/
424 +/*
425 + * Authors:
426 + * Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
427 + */
428 +
429 +#ifndef _DRM_MM_H_
430 +#define _DRM_MM_H_
431 +
432 +/*
433 + * Generic range manager structs
434 + */
435 +#include <linux/list.h>
436 +
437 +struct drm_mm_node {
438 +       struct list_head fl_entry;
439 +       struct list_head ml_entry;
440 +       int free;
441 +       unsigned long start;
442 +       unsigned long size;
443 +       struct drm_mm *mm;
444 +       void *private;
445 +};
446 +
447 +struct drm_mm {
448 +       struct list_head fl_entry;
449 +       struct list_head ml_entry;
450 +       struct list_head unused_nodes;
451 +       int num_unused;
452 +       spinlock_t unused_lock;
453 +};
454 +
455 +/*
456 + * Basic range manager support (drm_mm.c)
457 + */
458 +
459 +extern struct drm_mm_node *drm_mm_get_block(struct drm_mm_node *parent,
460 +                                           unsigned long size,
461 +                                           unsigned alignment);
462 +extern struct drm_mm_node *drm_mm_get_block_atomic(struct drm_mm_node *parent,
463 +                                                  unsigned long size,
464 +                                                  unsigned alignment);
465 +extern void drm_mm_put_block(struct drm_mm_node *cur);
466 +extern struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm,
467 +                                             unsigned long size,
468 +                                             unsigned alignment,
469 +                                             int best_match);
470 +extern int drm_mm_init(struct drm_mm *mm, unsigned long start,
471 +                      unsigned long size);
472 +extern void drm_mm_takedown(struct drm_mm *mm);
473 +extern int drm_mm_clean(struct drm_mm *mm);
474 +extern unsigned long drm_mm_tail_space(struct drm_mm *mm);
475 +extern int drm_mm_remove_space_from_tail(struct drm_mm *mm,
476 +                                        unsigned long size);
477 +extern int drm_mm_add_space_to_tail(struct drm_mm *mm,
478 +                                   unsigned long size, int atomic);
479 +extern int drm_mm_pre_get(struct drm_mm *mm);
480 +
481 +static inline struct drm_mm *drm_get_mm(struct drm_mm_node *block)
482 +{
483 +       return block->mm;
484 +}
485 +
486 +#endif