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
6 Signed-off-by: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
\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
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
23 #include <linux/slab.h>
25 +#define MM_UNUSED_TARGET 4
27 unsigned long drm_mm_tail_space(struct drm_mm *mm)
29 struct list_head *tail_node;
34 +static struct drm_mm_node *drm_mm_kmalloc(struct drm_mm *mm, int atomic)
36 + struct drm_mm_node *child;
40 + (struct drm_mm_node *)kmalloc(sizeof(*child), GFP_ATOMIC);
43 + (struct drm_mm_node *)kmalloc(sizeof(*child), GFP_KERNEL);
46 + if (unlikely(child == NULL)) {
47 + spin_lock(&mm->unused_lock);
48 + if (list_empty(&mm->unused_nodes))
52 + list_entry(mm->unused_nodes.next,
53 + struct drm_mm_node, fl_entry);
54 + list_del(&child->fl_entry);
57 + spin_unlock(&mm->unused_lock);
62 +int drm_mm_pre_get(struct drm_mm *mm)
64 + struct drm_mm_node *node;
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);
72 + if (unlikely(node == NULL)) {
73 + int ret = (mm->num_unused < 2) ? -ENOMEM : 0;
74 + spin_unlock(&mm->unused_lock);
78 + list_add_tail(&node->fl_entry, &mm->unused_nodes);
80 + spin_unlock(&mm->unused_lock);
84 +EXPORT_SYMBOL(drm_mm_pre_get);
86 static int drm_mm_create_tail_node(struct drm_mm *mm,
87 - unsigned long start,
89 + unsigned long start,
90 + unsigned long size, int atomic)
92 struct drm_mm_node *child;
94 - child = (struct drm_mm_node *)
95 - drm_alloc(sizeof(*child), DRM_MEM_MM);
97 + child = drm_mm_kmalloc(mm, atomic);
98 + if (unlikely(child == NULL))
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)
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);
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,
124 static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent,
125 - unsigned long size)
126 + unsigned long size,
129 struct drm_mm_node *child;
131 - child = (struct drm_mm_node *)
132 - drm_alloc(sizeof(*child), DRM_MEM_MM);
134 + child = drm_mm_kmalloc(parent->mm, atomic);
135 + if (unlikely(child == NULL))
138 INIT_LIST_HEAD(&child->fl_entry);
140 tmp = parent->start % alignment;
143 - align_splitoff = drm_mm_split_at_start(parent, alignment - tmp);
144 - if (!align_splitoff)
146 + drm_mm_split_at_start(parent, alignment - tmp, 0);
147 + if (unlikely(align_splitoff == NULL))
155 - child = drm_mm_split_at_start(parent, size);
156 + child = drm_mm_split_at_start(parent, size, 0);
160 @@ -169,14 +224,50 @@
165 EXPORT_SYMBOL(drm_mm_get_block);
167 +struct drm_mm_node *drm_mm_get_block_atomic(struct drm_mm_node *parent,
168 + unsigned long size,
169 + unsigned alignment)
172 + struct drm_mm_node *align_splitoff = NULL;
173 + struct drm_mm_node *child;
177 + tmp = parent->start % alignment;
181 + drm_mm_split_at_start(parent, alignment - tmp, 1);
182 + if (unlikely(align_splitoff == NULL))
186 + if (parent->size == size) {
187 + list_del_init(&parent->fl_entry);
191 + child = drm_mm_split_at_start(parent, size, 1);
194 + if (align_splitoff)
195 + drm_mm_put_block(align_splitoff);
200 +EXPORT_SYMBOL(drm_mm_get_block_atomic);
203 * Put a block. Merge with the previous and / or next block if they are free.
204 * Otherwise add to the free stack.
207 -void drm_mm_put_block(struct drm_mm_node * cur)
208 +void drm_mm_put_block(struct drm_mm_node *cur)
211 struct drm_mm *mm = cur->mm;
212 @@ -188,21 +279,27 @@
215 if (cur_head->prev != root_head) {
216 - prev_node = list_entry(cur_head->prev, struct drm_mm_node, ml_entry);
218 + list_entry(cur_head->prev, struct drm_mm_node, ml_entry);
219 if (prev_node->free) {
220 prev_node->size += cur->size;
224 if (cur_head->next != root_head) {
225 - next_node = list_entry(cur_head->next, struct drm_mm_node, ml_entry);
227 + list_entry(cur_head->next, struct drm_mm_node, ml_entry);
228 if (next_node->free) {
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),
235 + if (mm->num_unused < MM_UNUSED_TARGET) {
236 + list_add(&next_node->fl_entry,
237 + &mm->unused_nodes);
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);
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);
257 EXPORT_SYMBOL(drm_mm_put_block);
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)
266 struct list_head *list;
267 const struct list_head *free_stack = &mm->fl_entry;
269 wasted += alignment - tmp;
273 if (entry->size >= size + wasted) {
280 +EXPORT_SYMBOL(drm_mm_search_free);
282 int drm_mm_clean(struct drm_mm * mm)
284 @@ -267,14 +369,17 @@
286 return (head->next->next == head);
288 -EXPORT_SYMBOL(drm_mm_search_free);
289 +EXPORT_SYMBOL(drm_mm_clean);
291 int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
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);
299 - return drm_mm_create_tail_node(mm, start, size);
300 + return drm_mm_create_tail_node(mm, start, size, 0);
302 EXPORT_SYMBOL(drm_mm_init);
306 struct list_head *bnode = mm->fl_entry.next;
307 struct drm_mm_node *entry;
308 + struct drm_mm_node *next;
310 entry = list_entry(bnode, struct drm_mm_node, fl_entry);
314 list_del(&entry->fl_entry);
315 list_del(&entry->ml_entry);
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);
324 + spin_unlock(&mm->unused_lock);
326 - drm_free(entry, sizeof(*entry), DRM_MEM_MM);
327 + BUG_ON(mm->num_unused != 0);
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
336 #include "drm_os_linux.h"
337 #include "drm_hashtab.h"
340 /***********************************************************************/
341 /** \name DRM template customization defaults */
347 - * Generic memory manager structs
350 -struct drm_mm_node {
351 - struct list_head fl_entry;
352 - struct list_head ml_entry;
354 - unsigned long start;
355 - unsigned long size;
361 - struct list_head fl_entry;
362 - struct list_head ml_entry;
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);
374 - * Basic memory manager support (drm_mm.c)
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);
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
397 +/**************************************************************************
399 + * Copyright 2006-2008 Tungsten Graphics, Inc., Cedar Park, TX. USA.
400 + * All Rights Reserved.
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:
410 + * The above copyright notice and this permission notice (including the
411 + * next paragraph) shall be included in all copies or substantial portions
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.
423 + **************************************************************************/
426 + * Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
433 + * Generic range manager structs
435 +#include <linux/list.h>
437 +struct drm_mm_node {
438 + struct list_head fl_entry;
439 + struct list_head ml_entry;
441 + unsigned long start;
442 + unsigned long size;
448 + struct list_head fl_entry;
449 + struct list_head ml_entry;
450 + struct list_head unused_nodes;
452 + spinlock_t unused_lock;
456 + * Basic range manager support (drm_mm.c)
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,
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);
481 +static inline struct drm_mm *drm_get_mm(struct drm_mm_node *block)