diff options
-rw-r--r-- | sys/dev/pci/drm/drmP.h | 45 | ||||
-rw-r--r-- | sys/dev/pci/drm/drm_bufs.c | 24 | ||||
-rw-r--r-- | sys/dev/pci/drm/drm_drv.c | 12 | ||||
-rw-r--r-- | sys/dev/pci/drm/drm_memrange.c | 270 | ||||
-rw-r--r-- | sys/dev/pci/drm/drm_scatter.c | 2 | ||||
-rw-r--r-- | sys/dev/pci/drm/drm_vm.c | 13 | ||||
-rw-r--r-- | sys/dev/pci/drm/files.drm | 3 |
7 files changed, 357 insertions, 12 deletions
diff --git a/sys/dev/pci/drm/drmP.h b/sys/dev/pci/drm/drmP.h index c9ffa6c4bfa..9186a79698f 100644 --- a/sys/dev/pci/drm/drmP.h +++ b/sys/dev/pci/drm/drmP.h @@ -186,6 +186,7 @@ typedef struct drm_file drm_file_t; #define DRM_MEM_STUB 18 #define DRM_MEM_SGLISTS 19 #define DRM_MEM_DRAWABLE 20 +#define DRM_MEM_MM 21 #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) @@ -707,6 +708,26 @@ typedef struct drm_sg_mem { #endif } drm_sg_mem_t; +/* + * Generic memory range manager structs + */ + +struct drm_memrange_node { + TAILQ_ENTRY(drm_memrange_node) ml_entry; + TAILQ_ENTRY(drm_memrange_node) fl_entry; + struct drm_memrange *mm; + void *private; + int free; + unsigned long start; + unsigned long size; +}; + +TAILQ_HEAD(drm_mmq, drm_memrange_node); +struct drm_memrange { + struct drm_mmq ml; + struct drm_mmq fl; +}; + typedef TAILQ_HEAD(drm_map_list, drm_local_map) drm_map_list_t; typedef struct drm_local_map { @@ -728,6 +749,7 @@ typedef struct drm_local_map { bus_space_handle_t bsh; drm_dma_handle_t *dmah; TAILQ_ENTRY(drm_local_map) link; + struct drm_memrange_node *mm; } drm_local_map_t; TAILQ_HEAD(drm_vbl_sig_list, drm_vbl_sig); @@ -881,6 +903,7 @@ struct drm_device { SPLAY_HEAD(drm_magic_tree, drm_magic_entry) magiclist; /* Linked list of mappable regions. Protected by dev_lock */ + struct drm_memrange handle_mm; drm_map_list_t maplist; drm_local_map_t **context_sareas; @@ -1040,6 +1063,8 @@ unsigned long drm_get_resource_start(drm_device_t *dev, unsigned int resource); unsigned long drm_get_resource_len(drm_device_t *dev, unsigned int resource); void drm_rmmap(drm_device_t *dev, drm_local_map_t *map); int drm_order(unsigned long size); +drm_local_map_t + *drm_find_matching_map(struct drm_device *, drm_local_map_t *); int drm_addmap(drm_device_t * dev, unsigned long offset, unsigned long size, drm_map_type_t type, drm_map_flags_t flags, drm_local_map_t **map_ptr); @@ -1178,6 +1203,24 @@ drm_dma_handle_t *drm_pci_alloc(drm_device_t *dev, size_t size, size_t align, dma_addr_t maxaddr); void drm_pci_free(drm_device_t *dev, drm_dma_handle_t *dmah); +/* Memrange functions for managing aperture space */ +struct drm_memrange_node + *drm_memrange_get_block(struct drm_memrange_node *, + unsigned long, unsigned); +void drm_memrange_put_block(struct drm_memrange_node *); +struct drm_memrange_node + *drm_memrange_search_free(const struct drm_memrange *, + unsigned long, unsigned, int); +int drm_memrange_init(struct drm_memrange *, unsigned long, + unsigned long); +void drm_memrange_takedown(struct drm_memrange *); +int drm_memrange_clean(struct drm_memrange *); +unsigned long drm_memrange_tail_space(struct drm_memrange *); +int drm_memrange_remove_space_from_tail(struct drm_memrange *, + unsigned long); +int drm_memrange_add_space_to_tail(struct drm_memrange *, + unsigned long ); + /* Inline replacements for DRM_IOREMAP macros */ static __inline__ void drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev) { @@ -1195,7 +1238,7 @@ static __inline__ struct drm_local_map *drm_core_findmap(struct drm_device *dev, DRM_SPINLOCK_ASSERT(&dev->dev_lock); TAILQ_FOREACH(map, &dev->maplist, link) { - if (map->offset == offset) + if (offset == map->mm->start) return map; } return NULL; diff --git a/sys/dev/pci/drm/drm_bufs.c b/sys/dev/pci/drm/drm_bufs.c index 83e0c71f1ae..ae3a50fb351 100644 --- a/sys/dev/pci/drm/drm_bufs.c +++ b/sys/dev/pci/drm/drm_bufs.c @@ -191,6 +191,22 @@ drm_addmap(drm_device_t * dev, unsigned long offset, unsigned long size, map->type = type; map->flags = flags; + + map->mm = drm_memrange_search_free(&dev->handle_mm, map->size, + PAGE_SIZE, 0); + if (map->mm == NULL) { + DRM_ERROR("can't find free offset\n"); + free(map, M_DRM); + return ENOMEM; + } + map->mm = drm_memrange_get_block(map->mm, map->size, + PAGE_SIZE); + if (map->mm == NULL) { + DRM_ERROR("can't get block\n"); + free(map, M_DRM); + return ENOMEM; + } + switch ( map->type ) { case _DRM_REGISTERS: map->handle = drm_ioremap(dev, map); @@ -365,7 +381,7 @@ drm_addmap_ioctl(drm_device_t *dev, void *data, struct drm_file *file_priv) #ifndef __OpenBSD__ if (request->type != _DRM_SHM) #endif - request->handle = (void *)request->offset; + request->handle = (void *)map->mm->start; return 0; } @@ -421,6 +437,8 @@ drm_rmmap(drm_device_t *dev, drm_local_map_t *map) } #endif + drm_memrange_put_block(map->mm); + free(map, M_DRM); } @@ -676,7 +694,7 @@ drm_do_addbufs_pci(drm_device_t *dev, drm_buf_desc_t *request) free(entry->buflist, M_DRM); return ENOMEM; } - + memcpy(temp_pagelist, dma->pagelist, dma->page_count * sizeof(*dma->pagelist)); @@ -1184,7 +1202,7 @@ drm_mapbufs(drm_device_t *dev, void *data, struct drm_file *file_priv) goto done; } size = round_page(map->size); - foff = map->offset; + foff = map->mm->start; } else { size = round_page(dma->byte_count), foff = 0; diff --git a/sys/dev/pci/drm/drm_drv.c b/sys/dev/pci/drm/drm_drv.c index efb5e16b695..8b11eb8145d 100644 --- a/sys/dev/pci/drm/drm_drv.c +++ b/sys/dev/pci/drm/drm_drv.c @@ -517,6 +517,16 @@ drm_load(drm_device_t *dev) #endif TAILQ_INIT(&dev->files); + /* + * the dma buffers api is just weird. offset 1Gb to ensure we don't + * conflict with it. + */ + retcode = drm_memrange_init(&dev->handle_mm, 1024*1024*1024, LONG_MAX); + if (retcode != 0) { + DRM_ERROR("Failed to initialise handle memrange\n"); + goto error; + } + if (dev->driver.load != NULL) { DRM_LOCK(); /* Shared code returns -errno. */ @@ -593,6 +603,8 @@ drm_unload(drm_device_t *dev) drm_ctxbitmap_cleanup(dev); + drm_memrange_takedown(&dev->handle_mm); + #if !defined(DRM_NO_MTRR) && !defined(DRM_NO_AGP) if (dev->agp && dev->agp->mtrr) { int retcode; diff --git a/sys/dev/pci/drm/drm_memrange.c b/sys/dev/pci/drm/drm_memrange.c new file mode 100644 index 00000000000..5b4a9658aa4 --- /dev/null +++ b/sys/dev/pci/drm/drm_memrange.c @@ -0,0 +1,270 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + **************************************************************************/ + +/* + * Generic simple memory manager implementation. Intended to be used as a base + * class implementation for more advanced memory managers. + * + * Note that the algorithm used is quite simple and there might be substantial + * performance gains if a smarter free list is implemented. Currently it is just an + * unordered stack of free regions. This could easily be improved if an RB-tree + * is used instead. At least if we expect heavy fragmentation. + * + * Aligned allocations can also see improvement. + * + * Authors: + * Thomas Hellström <thomas-at-tungstengraphics-dot-com> + * Ported to OpenBSD by: + * Owain Ainsworth <oga@openbsd.org> + */ + +#include "drmP.h" + +int drm_memrange_create_tail_node(struct drm_memrange *, unsigned long, unsigned long); +struct drm_memrange_node *drm_memrange_split_at_start(struct + drm_memrange_node *, unsigned long); + +unsigned long +drm_memrange_tail_space(struct drm_memrange *mm) +{ + struct drm_memrange_node *entry = TAILQ_LAST(&mm->ml, drm_mmq); + + if (!entry->free) + return (0); + + return (entry->size); +} + +int +drm_memrange_remove_space_from_tail(struct drm_memrange *mm, unsigned long size) +{ + struct drm_memrange_node *entry = TAILQ_LAST(&mm->ml, drm_mmq); + + if (!entry->free) + return (ENOMEM); + + if (entry->size <= size) + return (ENOMEM); + + entry->size -=size; + return (0); +} + +int +drm_memrange_create_tail_node(struct drm_memrange *mm, unsigned long start, + unsigned long size) +{ + struct drm_memrange_node *child; + + child = (struct drm_memrange_node *)drm_calloc(1, sizeof(*child), + DRM_MEM_MM); + if (child == NULL) + return (ENOMEM); + + child->free = 1; + child->size = size; + child->start = start; + child->mm = mm; + + TAILQ_INSERT_TAIL(&mm->ml, child, ml_entry); + TAILQ_INSERT_TAIL(&mm->fl, child, fl_entry); + + return (0); +} + +int +drm_memrange_add_space_to_tail(struct drm_memrange *mm, unsigned long size) +{ + struct drm_memrange_node *entry = TAILQ_LAST(&mm->ml, drm_mmq); + + if (!entry->free) + return (drm_memrange_create_tail_node(mm, + entry->start + entry->size, size)); + entry->size += size; + return (0); + + +} + +struct drm_memrange_node * +drm_memrange_split_at_start(struct drm_memrange_node *parent, unsigned long size) +{ + struct drm_memrange_node *child; + + child = (struct drm_memrange_node *)drm_calloc(1, sizeof(*child), + DRM_MEM_MM); + if (child == NULL) + return (NULL); + + child->size = size; + child->start = parent->start; + child->mm = parent->mm; + + TAILQ_INSERT_TAIL(&child->mm->ml, child, ml_entry); + + parent->size -= size; + parent->start += size; + return (child); +} + +struct drm_memrange_node * +drm_memrange_get_block(struct drm_memrange_node *parent, unsigned long size, + unsigned alignment) +{ + struct drm_memrange_node *child, *align_splitoff = NULL; + unsigned tmp = 0; + + if (alignment) + tmp = parent->start & alignment; + + if (tmp) { + align_splitoff = drm_memrange_split_at_start(parent, + alignment - tmp); + if (align_splitoff == NULL) + return (NULL); + } + + if (parent->size == size) { + TAILQ_REMOVE(&parent->mm->fl, parent, fl_entry); + parent->free = 0; + return (parent); + } else + child = drm_memrange_split_at_start(parent, size); + + if (align_splitoff) + drm_memrange_put_block(align_splitoff); + + return (child); + +} + + +void +drm_memrange_put_block(struct drm_memrange_node *cur) +{ + struct drm_memrange *mm = cur->mm; + struct drm_memrange_node *prev_node = NULL; + struct drm_memrange_node *next_node; + int merged = 0; + + if ((prev_node = TAILQ_PREV(cur, drm_mmq, ml_entry)) != NULL) { + if (prev_node->free) { + prev_node->size += cur->size; + merged = 1; + } + } + if ((next_node = TAILQ_NEXT(cur, ml_entry)) != NULL) { + if (next_node ->free) { + if (merged) { + prev_node->size += next_node->size; + TAILQ_REMOVE(&mm->ml, next_node, + ml_entry); + TAILQ_REMOVE(&mm->fl, next_node, + fl_entry); + drm_free(next_node, sizeof(*next_node), + DRM_MEM_MM); + } + } + } + if (!merged) { + cur->free = 1; + TAILQ_INSERT_TAIL(&mm->fl, cur, fl_entry); + } else { + TAILQ_REMOVE(&mm->ml, cur, ml_entry); + drm_free(cur, sizeof(*cur), DRM_MEM_MM); + } +} + +struct drm_memrange_node * +drm_memrange_search_free(const struct drm_memrange *mm, unsigned long size, + unsigned alignment, int best_match) +{ + struct drm_memrange_node *entry, *best; + unsigned long best_size; + unsigned wasted; + + best = NULL; + best_size = ~0UL; + + TAILQ_FOREACH(entry, &mm->fl, fl_entry ) { + wasted = 0; + + if (entry->size < size) + continue; + + if (alignment) { + unsigned tmp = entry->start % alignment; + if (tmp) + wasted += alignment - tmp; + } + + if (entry->size >= size + wasted) { + if (!best_match) { + return (entry); + } + if (size < best_size) { + best = entry; + best_size = entry->size; + } + } + } + return (best); +} + +int +drm_memrange_clean(struct drm_memrange *mm) +{ + return (TAILQ_FIRST(&mm->ml) == TAILQ_LAST(&mm->ml,drm_mmq)); +} + +int +drm_memrange_init(struct drm_memrange *mm, unsigned long start, + unsigned long size) +{ + TAILQ_INIT(&mm->ml); + TAILQ_INIT(&mm->fl); + + return (drm_memrange_create_tail_node(mm, start, size)); +} + +void +drm_memrange_takedown(struct drm_memrange *mm) +{ + struct drm_memrange_node *entry; + + entry = TAILQ_FIRST(&mm->ml); + + if (!TAILQ_EMPTY(&mm->ml) || !TAILQ_EMPTY(&mm->fl)) { + DRM_ERROR("Memory manager not clean, Delaying takedown\n"); + return; + } + + TAILQ_INIT(&mm->ml); + TAILQ_INIT(&mm->fl); + drm_free(entry, sizeof(*entry), DRM_MEM_MM); +} diff --git a/sys/dev/pci/drm/drm_scatter.c b/sys/dev/pci/drm/drm_scatter.c index 3f9a691b610..705604c46a0 100644 --- a/sys/dev/pci/drm/drm_scatter.c +++ b/sys/dev/pci/drm/drm_scatter.c @@ -166,8 +166,6 @@ drm_sg_dmamem_alloc(drm_device_t *dev, size_t pages) bus_size_t size = pages << PAGE_SHIFT; int ret = 0; - printf("size = %d\n", size); - dsd = malloc(sizeof(*dsd), M_DRM, M_NOWAIT | M_ZERO); if (dsd == NULL) return (NULL); diff --git a/sys/dev/pci/drm/drm_vm.c b/sys/dev/pci/drm/drm_vm.c index 427a549fb5b..3e03157c537 100644 --- a/sys/dev/pci/drm/drm_vm.c +++ b/sys/dev/pci/drm/drm_vm.c @@ -98,8 +98,11 @@ drm_mmap(dev_t kdev, off_t offset, int prot) */ DRM_LOCK(); TAILQ_FOREACH(map, &dev->maplist, link) { - if (offset >= map->offset && offset < map->offset + map->size) + if (offset >= map->mm->start && + offset < map->mm->start + map->size) { + offset -= map->mm->start; break; + } } if (map == NULL) { @@ -123,7 +126,7 @@ drm_mmap(dev_t kdev, off_t offset, int prot) case _DRM_FRAME_BUFFER: case _DRM_REGISTERS: case _DRM_AGP: - phys = offset; + phys = offset + map->offset; break; #ifdef __FreeBSD__ case _DRM_CONSISTENT: @@ -137,12 +140,12 @@ drm_mmap(dev_t kdev, off_t offset, int prot) /* XXX unify all the bus_dmamem_mmap bits */ case _DRM_SCATTER_GATHER: return bus_dmamem_mmap(dev->pa.pa_dmat, dev->sg->mem->sg_segs, - dev->sg->mem->sg_nsegs, offset - dev->sg->handle, prot, - BUS_DMA_NOWAIT); + dev->sg->mem->sg_nsegs, map->offset - dev->sg->handle + + offset, prot, BUS_DMA_NOWAIT); case _DRM_SHM: case _DRM_CONSISTENT: return bus_dmamem_mmap(dev->pa.pa_dmat, &map->dmah->seg, 1, - offset - map->offset, prot, BUS_DMA_NOWAIT); + offset, prot, BUS_DMA_NOWAIT); #endif default: DRM_ERROR("bad map type %d\n", type); diff --git a/sys/dev/pci/drm/files.drm b/sys/dev/pci/drm/files.drm index 8e7f99e492c..1032f492cef 100644 --- a/sys/dev/pci/drm/files.drm +++ b/sys/dev/pci/drm/files.drm @@ -1,5 +1,5 @@ # $NetBSD: files.drm,v 1.2 2007/03/28 11:29:37 jmcneill Exp $ -# $OpenBSD: files.drm,v 1.1 2007/11/28 23:56:04 deraadt Exp $ +# $OpenBSD: files.drm,v 1.2 2008/06/12 19:14:53 oga Exp $ # direct rendering modules define drmbase @@ -15,6 +15,7 @@ file dev/pci/drm/drm_ioctl.c drmbase file dev/pci/drm/drm_irq.c drmbase file dev/pci/drm/drm_lock.c drmbase file dev/pci/drm/drm_memory.c drmbase +file dev/pci/drm/drm_memrange.c drmbase file dev/pci/drm/drm_pci.c drmbase file dev/pci/drm/drm_scatter.c drmbase file dev/pci/drm/drm_sysctl.c drmbase |