From: <th...@ke...> - 2006-10-27 09:30:19
|
libdrm/xf86drm.c | 7 +- libdrm/xf86mm.h | 10 ++- linux-core/drmP.h | 8 +- linux-core/drm_bo.c | 8 +- linux-core/drm_mm.c | 170 ++++++++++++++++++++++++++++++++++++++------------- linux-core/drm_ttm.c | 10 ++- shared-core/drm.h | 2 7 files changed, 161 insertions(+), 54 deletions(-) New commits: diff-tree f6d5fecdd20b9fd9e8744d8f43fa276b73a1da78 (from e09544a2d3f44e96d01ed2bdcb4a4eb8eec26225) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Fri Oct 27 11:28:37 2006 +0200 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. diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 9047c8d..ebf3f83 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2613,12 +2613,14 @@ static void drmBOCopyReply(const drm_bo_ buf->start = rep->buffer_start; buf->fenceFlags = rep->fence_flags; buf->replyFlags = rep->rep_flags; + buf->pageAlignment = rep->page_alignment; } -int drmBOCreate(int fd, void *ttm, unsigned long start, unsigned long size, - void *user_buffer, drm_bo_type_t type, unsigned mask, +int drmBOCreate(int fd, unsigned long start, unsigned long size, + unsigned pageAlignment, void *user_buffer, drm_bo_type_t type, + unsigned mask, unsigned hint, drmBO *buf) { drm_bo_arg_t arg; @@ -2632,6 +2634,7 @@ int drmBOCreate(int fd, void *ttm, unsig req->hint = hint; req->size = size; req->type = type; + req->page_alignment = pageAlignment; buf->virtual = NULL; diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index da868fe..bd0d281 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -99,6 +99,7 @@ typedef struct _drmFence{ unsigned type; unsigned flags; unsigned signaled; + unsigned pad[4]; /* for future expansion */ } drmFence; typedef struct _drmBO{ @@ -113,9 +114,11 @@ typedef struct _drmBO{ unsigned long start; unsigned replyFlags; unsigned fenceFlags; + unsigned pageAlignment; void *virtual; void *mapVirtual; int mapCount; + unsigned pad[8]; /* for future expansion */ } drmBO; @@ -168,9 +171,10 @@ extern int drmBOCreateList(int numTarget * Buffer object functions. */ -extern int drmBOCreate(int fd, void *ttm, unsigned long start, unsigned long size, - void *user_buffer, drm_bo_type_t type, unsigned mask, - unsigned hint, drmBO *buf); +extern int drmBOCreate(int fd, unsigned long start, unsigned long size, + unsigned pageAlignment,void *user_buffer, + drm_bo_type_t type, unsigned mask, + unsigned hint, drmBO *buf); extern int drmBODestroy(int fd, drmBO *buf); extern int drmBOReference(int fd, unsigned handle, drmBO *buf); extern int drmBOUnReference(int fd, drmBO *buf); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 1ed20b0..d02184c 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1016,7 +1016,7 @@ typedef struct drm_buffer_object{ unsigned long buffer_start; drm_bo_type_t type; unsigned long offset; - + uint32_t page_alignment; atomic_t mapped; uint32_t flags; uint32_t mask; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 954b7a0..65e24fb 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -571,7 +571,7 @@ int drm_bo_alloc_space(drm_buffer_object mutex_lock(&dev->struct_mutex); do { - node = drm_mm_search_free(mm, size, 0, 1); + node = drm_mm_search_free(mm, size, buf->page_alignment, 1); if (node) break; @@ -599,7 +599,7 @@ int drm_bo_alloc_space(drm_buffer_object return -ENOMEM; } - node = drm_mm_get_block(node, size, 0); + node = drm_mm_get_block(node, size, buf->page_alignment); mutex_unlock(&dev->struct_mutex); BUG_ON(!node); node->private = (void *)buf; @@ -959,6 +959,7 @@ static void drm_bo_fill_rep_arg(drm_buff rep->buffer_start = bo->buffer_start; rep->fence_flags = bo->fence_type; rep->rep_flags = 0; + rep->page_alignment = bo->page_alignment; if ((bo->priv_flags & _DRM_BO_FLAG_UNFENCED) || drm_bo_quick_busy(bo)) { DRM_FLAG_MASKED(rep->rep_flags, DRM_BO_REP_BUSY, @@ -1387,6 +1388,7 @@ int drm_buffer_object_create(drm_file_t drm_bo_type_t type, uint32_t mask, uint32_t hint, + uint32_t page_alignment, unsigned long buffer_start, drm_buffer_object_t ** buf_obj) { @@ -1426,6 +1428,7 @@ int drm_buffer_object_create(drm_file_t bo->num_pages = num_pages; bo->node_card = NULL; bo->node_ttm = NULL; + bo->page_alignment = page_alignment; if (bo->type == drm_bo_type_fake) { bo->offset = buffer_start; bo->buffer_start = 0; @@ -1516,6 +1519,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) req->type, req->mask, req->hint, + req->page_alignment, req->buffer_start, &entry); if (rep.ret) break; diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index dcd5520..a5566b2 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_n 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); diff --git a/shared-core/drm.h b/shared-core/drm.h index 5784e59..330aa3f 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -770,6 +770,7 @@ typedef struct drm_bo_arg_request { drm_bo_type_t type; unsigned arg_handle; drm_u64_t buffer_start; + unsigned page_alignment; unsigned expand_pad[4]; /*Future expansion */ enum { drm_bo_create, @@ -804,6 +805,7 @@ typedef struct drm_bo_arg_reply { drm_u64_t buffer_start; unsigned fence_flags; unsigned rep_flags; + unsigned page_alignment; unsigned expand_pad[4]; /*Future expansion */ }drm_bo_arg_reply_t; diff-tree e09544a2d3f44e96d01ed2bdcb4a4eb8eec26225 (from 47dbfc4e4a3e8ce2ec468bc3874f74f7e2b13476) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Thu Oct 26 21:20:34 2006 +0200 New mm function names. Update header. diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 4ce5a3e..1ed20b0 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1368,7 +1368,11 @@ extern drm_mm_node_t *drm_mm_search_free extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size); extern void drm_mm_takedown(drm_mm_t *mm); extern int drm_mm_clean(drm_mm_t *mm); -static inline drm_mm_t *drm_get_mm(drm_mm_node_t *block) +extern unsigned long drm_mm_tail_space(drm_mm_t *mm); +extern int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size); +extern int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size); + +static inline drm_mm_t *drm_get_mm(drm_mm_node_t *block) { return block->mm; } diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index 5e0ba5e..dcd5520 100644 --- a/linux-core/drm_mm.c +++ b/linux-core/drm_mm.c @@ -44,7 +44,7 @@ #include "drmP.h" #include <linux/slab.h> -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_m } -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; diff-tree 47dbfc4e4a3e8ce2ec468bc3874f74f7e2b13476 (from b4fba1679b6156e3ca6f053b44cae0b003febe7f) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Thu Oct 26 21:17:43 2006 +0200 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. diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index 4af33bd..5e0ba5e 100644 --- a/linux-core/drm_mm.c +++ b/linux-core/drm_mm.c @@ -44,39 +44,132 @@ #include "drmP.h" #include <linux/slab.h> -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; + + 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); - if (alignment) - size += alignment - 1; + 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_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); diff-tree b4fba1679b6156e3ca6f053b44cae0b003febe7f (from 7ea059ae076c50f2012dee2ccbb8d41745705383) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Thu Oct 26 21:14:23 2006 +0200 Add a one-page hole in the file offset space between buffers. diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 7344acc..13bec48 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -489,14 +489,20 @@ int drm_ttm_object_create(drm_device_t * map->size = ttm->num_pages * PAGE_SIZE; map->handle = (void *)object; + /* + * Add a one-page "hole" to the block size to avoid the mm subsystem + * merging vmas. + * FIXME: Is this really needed? + */ + list->file_offset_node = drm_mm_search_free(&dev->offset_manager, - ttm->num_pages, 0, 0); + ttm->num_pages + 1, 0, 0); if (!list->file_offset_node) { drm_ttm_object_remove(dev, object); return -ENOMEM; } list->file_offset_node = drm_mm_get_block(list->file_offset_node, - ttm->num_pages, 0); + ttm->num_pages + 1, 0); list->hash.key = list->file_offset_node->start; |