From 11f51a9a877d1231551e8c6482a6f70daf380cdd Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 1 Sep 2006 15:41:55 +0200 Subject: Bugfixes, Memory allocation optimizations. Buffer manager takedown. --- linux-core/drm_mm.c | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) (limited to 'linux-core/drm_mm.c') diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index 617526bd..6e2da81a 100644 --- a/linux-core/drm_mm.c +++ b/linux-core/drm_mm.c @@ -42,6 +42,9 @@ */ #include "drmP.h" +#include + +static kmem_cache_t *mm_cache = NULL; drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, unsigned long size, unsigned alignment) @@ -57,7 +60,9 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, parent->free = 0; return parent; } else { - child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM); + + child = (drm_mm_node_t *) kmem_cache_alloc(mm_cache, + GFP_KERNEL); if (!child) return NULL; @@ -105,8 +110,8 @@ void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur) prev_node->size += next_node->size; list_del(&next_node->ml_entry); list_del(&next_node->fl_entry); - drm_free(next_node, sizeof(*next_node), - DRM_MEM_MM); + kmem_cache_free(mm_cache, next_node); + } else { next_node->size += cur->size; next_node->start = cur->start; @@ -119,7 +124,7 @@ void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur) list_add(&cur->fl_entry, &list_root->fl_entry); } else { list_del(&cur->ml_entry); - drm_free(cur, sizeof(*cur), DRM_MEM_MM); + kmem_cache_free(mm_cache, cur); } } @@ -154,13 +159,34 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm, return best; } +void drm_mm_set_cache(kmem_cache_t *cache) +{ + mm_cache = cache; +} + +int drm_mm_clean(drm_mm_t *mm) +{ + struct list_head *head = &mm->root_node.ml_entry; + + return (head->next->next == head); +} + int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) { drm_mm_node_t *child; + if (!mm_cache) { + DRM_ERROR("Memory manager memory cache " + "is not initialized.\n"); + return -EINVAL; + } + INIT_LIST_HEAD(&mm->root_node.ml_entry); INIT_LIST_HEAD(&mm->root_node.fl_entry); - child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM); + + + child = (drm_mm_node_t *) kmem_cache_alloc(mm_cache, GFP_KERNEL); + if (!child) return -ENOMEM; @@ -194,8 +220,7 @@ void drm_mm_takedown(drm_mm_t * mm) list_del(&entry->fl_entry); list_del(&entry->ml_entry); - - drm_free(entry, sizeof(*entry), DRM_MEM_MM); + kmem_cache_free(mm_cache, entry); } EXPORT_SYMBOL(drm_mm_takedown); -- cgit v1.2.3 From a6b8e3eaf49044e135a0b9288192525f301458d5 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 4 Sep 2006 16:57:20 +0200 Subject: Make memory caches global so that they can be used with multiple heads. --- linux-core/drm_mm.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) (limited to 'linux-core/drm_mm.c') diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index 6e2da81a..debac9d9 100644 --- a/linux-core/drm_mm.c +++ b/linux-core/drm_mm.c @@ -44,8 +44,6 @@ #include "drmP.h" #include -static kmem_cache_t *mm_cache = NULL; - drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, unsigned long size, unsigned alignment) { @@ -61,7 +59,7 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, return parent; } else { - child = (drm_mm_node_t *) kmem_cache_alloc(mm_cache, + child = (drm_mm_node_t *) kmem_cache_alloc(drm_cache.mm, GFP_KERNEL); if (!child) return NULL; @@ -110,7 +108,7 @@ void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur) prev_node->size += next_node->size; list_del(&next_node->ml_entry); list_del(&next_node->fl_entry); - kmem_cache_free(mm_cache, next_node); + kmem_cache_free(drm_cache.mm, next_node); } else { next_node->size += cur->size; @@ -124,7 +122,7 @@ void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur) list_add(&cur->fl_entry, &list_root->fl_entry); } else { list_del(&cur->ml_entry); - kmem_cache_free(mm_cache, cur); + kmem_cache_free(drm_cache.mm, cur); } } @@ -159,11 +157,6 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm, return best; } -void drm_mm_set_cache(kmem_cache_t *cache) -{ - mm_cache = cache; -} - int drm_mm_clean(drm_mm_t *mm) { struct list_head *head = &mm->root_node.ml_entry; @@ -175,17 +168,11 @@ int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) { drm_mm_node_t *child; - if (!mm_cache) { - DRM_ERROR("Memory manager memory cache " - "is not initialized.\n"); - return -EINVAL; - } - INIT_LIST_HEAD(&mm->root_node.ml_entry); INIT_LIST_HEAD(&mm->root_node.fl_entry); - child = (drm_mm_node_t *) kmem_cache_alloc(mm_cache, GFP_KERNEL); + child = (drm_mm_node_t *) kmem_cache_alloc(drm_cache.mm, GFP_KERNEL); if (!child) return -ENOMEM; @@ -220,7 +207,7 @@ void drm_mm_takedown(drm_mm_t * mm) list_del(&entry->fl_entry); list_del(&entry->ml_entry); - kmem_cache_free(mm_cache, entry); + kmem_cache_free(drm_cache.mm, entry); } EXPORT_SYMBOL(drm_mm_takedown); -- cgit v1.2.3 From db5c671e86c3db8c99ce5a4954632248e6f849aa Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 11:28:48 +0200 Subject: 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. --- linux-core/drm_mm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'linux-core/drm_mm.c') diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index debac9d9..ef8bd7e9 100644 --- a/linux-core/drm_mm.c +++ b/linux-core/drm_mm.c @@ -70,6 +70,7 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, child->free = 0; child->size = size; child->start = parent->start; + child->mm = parent->mm; list_add_tail(&child->ml_entry, &parent->ml_entry); parent->size -= size; @@ -83,9 +84,10 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, * Otherwise add to the free stack. */ -void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur) +void drm_mm_put_block(drm_mm_node_t * cur) { + drm_mm_t *mm = cur->mm; drm_mm_node_t *list_root = &mm->root_node; struct list_head *cur_head = &cur->ml_entry; struct list_head *root_head = &list_root->ml_entry; @@ -183,6 +185,7 @@ int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) child->start = start; child->size = size; child->free = 1; + child->mm = mm; list_add(&child->fl_entry, &mm->root_node.fl_entry); list_add(&child->ml_entry, &mm->root_node.ml_entry); -- cgit v1.2.3 From d515936ea7f98f6aaa9217699796beadef9d664b Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 19:40:57 +0200 Subject: Add memory usage accounting to avoid DOS problems. --- linux-core/drm_mm.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'linux-core/drm_mm.c') diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index ef8bd7e9..6ab13af3 100644 --- a/linux-core/drm_mm.c +++ b/linux-core/drm_mm.c @@ -59,8 +59,9 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, return parent; } else { - child = (drm_mm_node_t *) kmem_cache_alloc(drm_cache.mm, - GFP_KERNEL); + child = (drm_mm_node_t *) + drm_ctl_cache_alloc(drm_cache.mm, sizeof(*child), + GFP_KERNEL); if (!child) return NULL; @@ -110,8 +111,9 @@ void drm_mm_put_block(drm_mm_node_t * cur) prev_node->size += next_node->size; list_del(&next_node->ml_entry); list_del(&next_node->fl_entry); - kmem_cache_free(drm_cache.mm, next_node); - + drm_ctl_cache_free(drm_cache.mm, + sizeof(*next_node), + next_node); } else { next_node->size += cur->size; next_node->start = cur->start; @@ -124,7 +126,7 @@ void drm_mm_put_block(drm_mm_node_t * cur) list_add(&cur->fl_entry, &list_root->fl_entry); } else { list_del(&cur->ml_entry); - kmem_cache_free(drm_cache.mm, cur); + drm_ctl_cache_free(drm_cache.mm, sizeof(*cur), cur); } } @@ -174,7 +176,8 @@ int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) INIT_LIST_HEAD(&mm->root_node.fl_entry); - child = (drm_mm_node_t *) kmem_cache_alloc(drm_cache.mm, GFP_KERNEL); + child = (drm_mm_node_t *) + drm_ctl_cache_alloc(drm_cache.mm, sizeof(*child), GFP_KERNEL); if (!child) return -ENOMEM; @@ -210,7 +213,7 @@ void drm_mm_takedown(drm_mm_t * mm) list_del(&entry->fl_entry); list_del(&entry->ml_entry); - kmem_cache_free(drm_cache.mm, entry); + drm_ctl_cache_free(drm_cache.mm, sizeof(*entry), entry); } EXPORT_SYMBOL(drm_mm_takedown); -- cgit v1.2.3 From 89b944179856fadf8667587eff142129c2c6b826 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 19:57:06 +0200 Subject: Lindent. --- linux-core/drm_mm.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'linux-core/drm_mm.c') diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index 6ab13af3..4af33bde 100644 --- a/linux-core/drm_mm.c +++ b/linux-core/drm_mm.c @@ -59,9 +59,9 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, return parent; } else { - child = (drm_mm_node_t *) - drm_ctl_cache_alloc(drm_cache.mm, sizeof(*child), - GFP_KERNEL); + child = (drm_mm_node_t *) + drm_ctl_cache_alloc(drm_cache.mm, sizeof(*child), + GFP_KERNEL); if (!child) return NULL; @@ -111,8 +111,8 @@ void drm_mm_put_block(drm_mm_node_t * cur) prev_node->size += next_node->size; list_del(&next_node->ml_entry); list_del(&next_node->fl_entry); - drm_ctl_cache_free(drm_cache.mm, - sizeof(*next_node), + drm_ctl_cache_free(drm_cache.mm, + sizeof(*next_node), next_node); } else { next_node->size += cur->size; @@ -161,9 +161,9 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm, return best; } -int drm_mm_clean(drm_mm_t *mm) +int drm_mm_clean(drm_mm_t * mm) { - struct list_head *head = &mm->root_node.ml_entry; + struct list_head *head = &mm->root_node.ml_entry; return (head->next->next == head); } @@ -175,9 +175,8 @@ int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) INIT_LIST_HEAD(&mm->root_node.ml_entry); INIT_LIST_HEAD(&mm->root_node.fl_entry); - - child = (drm_mm_node_t *) - drm_ctl_cache_alloc(drm_cache.mm, sizeof(*child), GFP_KERNEL); + child = (drm_mm_node_t *) + drm_ctl_cache_alloc(drm_cache.mm, sizeof(*child), GFP_KERNEL); if (!child) return -ENOMEM; -- cgit v1.2.3 From 47dbfc4e4a3e8ce2ec468bc3874f74f7e2b13476 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 26 Oct 2006 21:17:43 +0200 Subject: 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. Also add some functions to grow and shrink the managed area. This will be used in the future to manage the buffer object swap cache. --- linux-core/drm_mm.c | 171 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 126 insertions(+), 45 deletions(-) (limited to 'linux-core/drm_mm.c') diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index 4af33bde..5e0ba5e4 100644 --- a/linux-core/drm_mm.c +++ b/linux-core/drm_mm.c @@ -44,39 +44,132 @@ #include "drmP.h" #include -drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, - unsigned long size, unsigned alignment) +unsigned long tail_space(drm_mm_t *mm) { + struct list_head *tail_node; + drm_mm_node_t *entry; + + tail_node = mm->root_node.ml_entry.prev; + entry = list_entry(tail_node, drm_mm_node_t, ml_entry); + if (!entry->free) + return 0; + + return entry->size; +} + +int remove_space_from_tail(drm_mm_t *mm, unsigned long size) +{ + struct list_head *tail_node; + drm_mm_node_t *entry; + + tail_node = mm->root_node.ml_entry.prev; + entry = list_entry(tail_node, drm_mm_node_t, ml_entry); + if (!entry->free) + return -ENOMEM; + + if (entry->size <= size) + return -ENOMEM; + entry->size -= size; + return 0; +} + + +static int drm_mm_create_tail_node(drm_mm_t *mm, + unsigned long start, + unsigned long size) +{ drm_mm_node_t *child; + + child = (drm_mm_node_t *) + drm_ctl_cache_alloc(drm_cache.mm, sizeof(*child), + GFP_KERNEL); + if (!child) + return -ENOMEM; - if (alignment) - size += alignment - 1; + child->free = 1; + child->size = size; + child->start = start; + child->mm = mm; + + list_add_tail(&child->ml_entry, &mm->root_node.ml_entry); + list_add_tail(&child->fl_entry, &mm->root_node.fl_entry); + + return 0; +} + + +int add_space_to_tail(drm_mm_t *mm, unsigned long size) +{ + struct list_head *tail_node; + drm_mm_node_t *entry; + + tail_node = mm->root_node.ml_entry.prev; + entry = list_entry(tail_node, drm_mm_node_t, ml_entry); + if (!entry->free) { + return drm_mm_create_tail_node(mm, entry->start + entry->size, size); + } + entry->size += size; + return 0; +} + +static drm_mm_node_t *drm_mm_split_at_start(drm_mm_node_t *parent, + unsigned long size) +{ + drm_mm_node_t *child; + + child = (drm_mm_node_t *) + drm_ctl_cache_alloc(drm_cache.mm, sizeof(*child), + GFP_KERNEL); + if (!child) + return NULL; + INIT_LIST_HEAD(&child->fl_entry); + + child->free = 0; + child->size = size; + child->start = parent->start; + child->mm = parent->mm; + + list_add_tail(&child->ml_entry, &parent->ml_entry); + INIT_LIST_HEAD(&child->fl_entry); + + parent->size -= size; + parent->start += size; + return child; +} + + + +drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, + unsigned long size, unsigned alignment) +{ + + drm_mm_node_t *align_splitoff = NULL; + drm_mm_node_t *child; + unsigned tmp = size % alignment; + + if (tmp) { + align_splitoff = drm_mm_split_at_start(parent, alignment - tmp); + if (!align_splitoff) + return NULL; + } + if (parent->size == size) { list_del_init(&parent->fl_entry); parent->free = 0; return parent; } else { - - child = (drm_mm_node_t *) - drm_ctl_cache_alloc(drm_cache.mm, sizeof(*child), - GFP_KERNEL); - if (!child) + child = drm_mm_split_at_start(parent, size); + if (!child) { + if (align_splitoff) + drm_mm_put_block(align_splitoff); return NULL; - - INIT_LIST_HEAD(&child->ml_entry); - INIT_LIST_HEAD(&child->fl_entry); - - child->free = 0; - child->size = size; - child->start = parent->start; - child->mm = parent->mm; - - list_add_tail(&child->ml_entry, &parent->ml_entry); - parent->size -= size; - parent->start += size; + } } + if (align_splitoff) + drm_mm_put_block(align_splitoff); + return child; } @@ -139,16 +232,23 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm, drm_mm_node_t *entry; drm_mm_node_t *best; unsigned long best_size; + unsigned wasted; best = NULL; best_size = ~0UL; - if (alignment) - size += alignment - 1; - list_for_each(list, free_stack) { entry = list_entry(list, drm_mm_node_t, fl_entry); - if (entry->size >= size) { + wasted = 0; + + if (alignment) { + register unsigned tmp = size % alignment; + if (tmp) + wasted += alignment - tmp; + } + + + if (entry->size >= size + wasted) { if (!best_match) return entry; if (size < best_size) { @@ -170,29 +270,10 @@ int drm_mm_clean(drm_mm_t * mm) int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) { - drm_mm_node_t *child; - INIT_LIST_HEAD(&mm->root_node.ml_entry); INIT_LIST_HEAD(&mm->root_node.fl_entry); - child = (drm_mm_node_t *) - drm_ctl_cache_alloc(drm_cache.mm, sizeof(*child), GFP_KERNEL); - - if (!child) - return -ENOMEM; - - INIT_LIST_HEAD(&child->ml_entry); - INIT_LIST_HEAD(&child->fl_entry); - - child->start = start; - child->size = size; - child->free = 1; - child->mm = mm; - - list_add(&child->fl_entry, &mm->root_node.fl_entry); - list_add(&child->ml_entry, &mm->root_node.ml_entry); - - return 0; + return drm_mm_create_tail_node(mm, start, size); } EXPORT_SYMBOL(drm_mm_init); -- cgit v1.2.3 From e09544a2d3f44e96d01ed2bdcb4a4eb8eec26225 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 26 Oct 2006 21:20:34 +0200 Subject: New mm function names. Update header. --- linux-core/drm_mm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'linux-core/drm_mm.c') diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index 5e0ba5e4..dcd55209 100644 --- a/linux-core/drm_mm.c +++ b/linux-core/drm_mm.c @@ -44,7 +44,7 @@ #include "drmP.h" #include -unsigned long tail_space(drm_mm_t *mm) +unsigned long drm_mm_tail_space(drm_mm_t *mm) { struct list_head *tail_node; drm_mm_node_t *entry; @@ -57,7 +57,7 @@ unsigned long tail_space(drm_mm_t *mm) return entry->size; } -int remove_space_from_tail(drm_mm_t *mm, unsigned long size) +int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size) { struct list_head *tail_node; drm_mm_node_t *entry; @@ -99,7 +99,7 @@ static int drm_mm_create_tail_node(drm_mm_t *mm, } -int add_space_to_tail(drm_mm_t *mm, unsigned long size) +int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size) { struct list_head *tail_node; drm_mm_node_t *entry; -- cgit v1.2.3 From f6d5fecdd20b9fd9e8744d8f43fa276b73a1da78 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 27 Oct 2006 11:28:37 +0200 Subject: Last minute changes to support multi-page size buffer offset alignments. This will come in very handy for tiled buffers on intel hardware. Also add some padding to interface structures to allow future binary backwards compatible changes. --- linux-core/drm_mm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'linux-core/drm_mm.c') diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index dcd55209..a5566b2f 100644 --- a/linux-core/drm_mm.c +++ b/linux-core/drm_mm.c @@ -147,7 +147,10 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, drm_mm_node_t *align_splitoff = NULL; drm_mm_node_t *child; - unsigned tmp = size % alignment; + unsigned tmp = 0; + + if (alignment) + tmp = size % alignment; if (tmp) { align_splitoff = drm_mm_split_at_start(parent, alignment - tmp); -- cgit v1.2.3