diff options
author | Owain Ainsworth <oga@cvs.openbsd.org> | 2009-02-05 00:25:52 +0000 |
---|---|---|
committer | Owain Ainsworth <oga@cvs.openbsd.org> | 2009-02-05 00:25:52 +0000 |
commit | 48ebf84cb1cf60450fb5790980135ca5b130f99c (patch) | |
tree | 943303f793368fefc00aaf0150bba2f429e58907 | |
parent | 9f999dadd4b348d0252c59054ddcc0c0e62a97ff (diff) |
Merge the static block allocation code from {i915,radeon}_mem.c into
non-static code that's shared between both. While i'm here convert them
to TAILQ.
Eventually, both of these will die, but until then I'd rather shave the
space in the kernel.
Tested on radeon and intel.
-rw-r--r-- | sys/dev/pci/drm/drmP.h | 19 | ||||
-rw-r--r-- | sys/dev/pci/drm/drm_heap.c | 148 | ||||
-rw-r--r-- | sys/dev/pci/drm/files.drm | 3 | ||||
-rw-r--r-- | sys/dev/pci/drm/i915_dma.c | 5 | ||||
-rw-r--r-- | sys/dev/pci/drm/i915_drv.c | 1 | ||||
-rw-r--r-- | sys/dev/pci/drm/i915_drv.h | 14 | ||||
-rw-r--r-- | sys/dev/pci/drm/i915_mem.c | 228 | ||||
-rw-r--r-- | sys/dev/pci/drm/radeon_drv.c | 3 | ||||
-rw-r--r-- | sys/dev/pci/drm/radeon_drv.h | 17 | ||||
-rw-r--r-- | sys/dev/pci/drm/radeon_mem.c | 224 | ||||
-rw-r--r-- | sys/dev/pci/drm/radeon_state.c | 4 |
11 files changed, 288 insertions, 378 deletions
diff --git a/sys/dev/pci/drm/drmP.h b/sys/dev/pci/drm/drmP.h index 6996284f636..7b50ea58ab5 100644 --- a/sys/dev/pci/drm/drmP.h +++ b/sys/dev/pci/drm/drmP.h @@ -417,6 +417,16 @@ struct drm_vblank { int vbl_inmodeset; /* is the DDX currently modesetting */ }; +/* Heap implementation for radeon and i915 legacy */ +TAILQ_HEAD(drm_heap, drm_mem); + +struct drm_mem { + TAILQ_ENTRY(drm_mem) link; + struct drm_file *file_priv; /* NULL: free, other: real files */ + int start; + int size; +}; + /* location of GART table */ #define DRM_ATI_GART_MAIN 1 #define DRM_ATI_GART_FB 2 @@ -581,6 +591,15 @@ void drm_ioremapfree(drm_local_map_t *); int drm_mtrr_add(unsigned long, size_t, int); int drm_mtrr_del(int, unsigned long, size_t, int); +/* Heap interface (DEPRECATED) */ +int drm_init_heap(struct drm_heap *, int, int); +struct drm_mem * + drm_alloc_block(struct drm_heap *, int, int, struct drm_file *); +struct drm_mem * + drm_find_block(struct drm_heap *, int); +void drm_free_block(struct drm_heap *, struct drm_mem *); + + int drm_ctxbitmap_init(struct drm_device *); void drm_ctxbitmap_cleanup(struct drm_device *); void drm_ctxbitmap_free(struct drm_device *, int); diff --git a/sys/dev/pci/drm/drm_heap.c b/sys/dev/pci/drm/drm_heap.c new file mode 100644 index 00000000000..ed55f2401be --- /dev/null +++ b/sys/dev/pci/drm/drm_heap.c @@ -0,0 +1,148 @@ +/* + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. + * + * The Weather Channel (TM) funded Tungsten Graphics to develop the + * initial release of the Radeon 8500 driver under the XFree86 license. + * This notice must be preserved. + * + * 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, sublicense, + * 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 NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT 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. + * + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "drmP.h" +#include "drm.h" + +struct drm_mem *drm_split_block(struct drm_heap *, struct drm_mem *, int, + int, struct drm_file *); +/* + * Very simple allocator for GART memory, working on a static range + * already mapped into each client's address space. + */ +struct drm_mem * +drm_split_block(struct drm_heap *heap, struct drm_mem *p, int start, + int size, struct drm_file *file_priv) +{ + /* Maybe cut off the start of an existing block */ + if (start > p->start) { + struct drm_mem *newblock = + drm_alloc(sizeof(*newblock), DRM_MEM_BUFS); + if (newblock == NULL) + goto out; + newblock->start = start; + newblock->size = p->size - (start - p->start); + newblock->file_priv = NULL; + TAILQ_INSERT_AFTER(heap, p, newblock, link); + p->size -= newblock->size; + p = newblock; + } + + /* Maybe cut off the end of an existing block */ + if (size < p->size) { + struct drm_mem *newblock = + drm_alloc(sizeof(*newblock), DRM_MEM_BUFS); + if (newblock == NULL) + goto out; + newblock->start = start + size; + newblock->size = p->size - size; + newblock->file_priv = NULL; + TAILQ_INSERT_AFTER(heap, p, newblock, link); + p->size = size; + } + + out: + /* Our block is in the middle */ + p->file_priv = file_priv; + return p; +} + +struct drm_mem * +drm_alloc_block(struct drm_heap *heap, int size, int align2, + struct drm_file *file_priv) +{ + struct drm_mem *p; + int mask = (1 << align2) - 1; + + TAILQ_FOREACH(p, heap, link) { + int start = (p->start + mask) & ~mask; + if (p->file_priv == NULL && start + size <= p->start + p->size) + return (drm_split_block(heap, p, start, + size, file_priv)); + } + + return NULL; +} + +struct drm_mem * +drm_find_block(struct drm_heap *heap, int start) +{ + struct drm_mem *p; + + TAILQ_FOREACH(p, heap, link) + if (p->start == start) + return p; + + return NULL; +} + +void +drm_free_block(struct drm_heap *heap, struct drm_mem *p) +{ + struct drm_mem *q; + + p->file_priv = NULL; + + if ((q = TAILQ_NEXT(p, link)) != TAILQ_END(heap) && + q->file_priv == NULL) { + p->size += q->size; + TAILQ_REMOVE(heap, q, link); + drm_free(q, sizeof(*q), DRM_MEM_BUFS); + } + + if ((q = TAILQ_PREV(p, drm_heap, link)) != TAILQ_END(heap) && + q->file_priv == NULL) { + q->size += p->size; + TAILQ_REMOVE(heap, p, link); + drm_free(p, sizeof(*p), DRM_MEM_BUFS); + } +} + +/* Initialize. + */ +int +drm_init_heap(struct drm_heap *heap, int start, int size) +{ + struct drm_mem *blocks; + + if (!TAILQ_EMPTY(heap)) + return (EBUSY); + + if ((blocks = drm_alloc(sizeof(*blocks), DRM_MEM_BUFS)) == NULL) + return (ENOMEM); + + blocks->start = start; + blocks->size = size; + blocks->file_priv = NULL; + TAILQ_INSERT_HEAD(heap, blocks, link); + + return (0); +} diff --git a/sys/dev/pci/drm/files.drm b/sys/dev/pci/drm/files.drm index 5b2267feb08..8a0df35cdf8 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.10 2009/01/29 11:50:16 oga Exp $ +# $OpenBSD: files.drm,v 1.11 2009/02/05 00:25:51 oga Exp $ # direct rendering modules define drmbase {} @@ -11,6 +11,7 @@ file dev/pci/drm/drm_bufs.c drm file dev/pci/drm/drm_context.c drm file dev/pci/drm/drm_dma.c drm file dev/pci/drm/drm_drv.c drm needs-flag +file dev/pci/drm/drm_heap.c inteldrm | radeondrm file dev/pci/drm/drm_irq.c drm file dev/pci/drm/drm_lock.c drm file dev/pci/drm/drm_memory.c drm diff --git a/sys/dev/pci/drm/i915_dma.c b/sys/dev/pci/drm/i915_dma.c index adb5b0484d0..e3cd3022165 100644 --- a/sys/dev/pci/drm/i915_dma.c +++ b/sys/dev/pci/drm/i915_dma.c @@ -808,8 +808,7 @@ void i915_driver_lastclose(struct drm_device * dev) dev_priv->sarea_priv = NULL; - if (dev_priv->agp_heap) - i915_mem_takedown(&(dev_priv->agp_heap)); + i915_mem_takedown(&dev_priv->agp_heap); i915_dma_cleanup(dev); } @@ -817,5 +816,5 @@ void i915_driver_lastclose(struct drm_device * dev) void i915_driver_close(struct drm_device * dev, struct drm_file *file_priv) { drm_i915_private_t *dev_priv = dev->dev_private; - i915_mem_release(dev, file_priv, dev_priv->agp_heap); + i915_mem_release(dev, file_priv, &dev_priv->agp_heap); } diff --git a/sys/dev/pci/drm/i915_drv.c b/sys/dev/pci/drm/i915_drv.c index 6a966387da4..a711a999857 100644 --- a/sys/dev/pci/drm/i915_drv.c +++ b/sys/dev/pci/drm/i915_drv.c @@ -164,6 +164,7 @@ inteldrm_attach(struct device *parent, struct device *self, void *aux) printf(": %s\n", pci_intr_string(pa->pa_pc, dev_priv->ih)); mtx_init(&dev_priv->user_irq_lock, IPL_BIO); + TAILQ_INIT(&dev_priv->agp_heap); /* All intel chipsets need to be treated as agp, so just pass one */ dev_priv->drmdev = drm_attach_pci(&inteldrm_driver, pa, 1, self); diff --git a/sys/dev/pci/drm/i915_drv.h b/sys/dev/pci/drm/i915_drv.h index 1433df78243..469457256c4 100644 --- a/sys/dev/pci/drm/i915_drv.h +++ b/sys/dev/pci/drm/i915_drv.h @@ -68,14 +68,6 @@ typedef struct _drm_i915_ring_buffer { drm_local_map_t map; } drm_i915_ring_buffer_t; -struct mem_block { - struct mem_block *next; - struct mem_block *prev; - int start; - int size; - struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */ -}; - typedef struct drm_i915_private { struct device dev; struct device *drmdev; @@ -117,7 +109,7 @@ typedef struct drm_i915_private { int tex_lru_log_granularity; int allow_batchbuffer; - struct mem_block *agp_heap; + struct drm_heap agp_heap; unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; /* Register state */ @@ -274,10 +266,10 @@ extern int i915_mem_init_heap(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int i915_mem_destroy_heap(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern void i915_mem_takedown(struct mem_block **heap); +extern void i915_mem_takedown(struct drm_heap *heap); extern void i915_mem_release(struct drm_device * dev, struct drm_file *file_priv, - struct mem_block *heap); + struct drm_heap *heap); /* i915_suspend.c */ extern int i915_save_state(struct drm_device *dev); diff --git a/sys/dev/pci/drm/i915_mem.c b/sys/dev/pci/drm/i915_mem.c index bd188485e1d..536e969da0d 100644 --- a/sys/dev/pci/drm/i915_mem.c +++ b/sys/dev/pci/drm/i915_mem.c @@ -31,6 +31,9 @@ #include "i915_drm.h" #include "i915_drv.h" +struct drm_heap *intel_get_heap(drm_i915_private_t *, int); +void intel_mark_block(struct drm_device *, struct drm_mem *, int); + /* This memory manager is integrated into the global/local lru * mechanisms used by the clients. Specifically, it operates by * setting the 'in_use' fields of the global LRU to indicate whether @@ -43,7 +46,8 @@ * block to allocate, and the ring is drained prior to allocations -- * in other words allocation is expensive. */ -static void mark_block(struct drm_device * dev, struct mem_block *p, int in_use) +void +intel_mark_block(struct drm_device * dev, struct drm_mem *p, int in_use) { drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; @@ -84,179 +88,53 @@ static void mark_block(struct drm_device * dev, struct mem_block *p, int in_use) } } -/* Very simple allocator for agp memory, working on a static range - * already mapped into each client's address space. - */ - -static struct mem_block *split_block(struct mem_block *p, int start, int size, - struct drm_file *file_priv) -{ - /* Maybe cut off the start of an existing block */ - if (start > p->start) { - struct mem_block *newblock = - drm_alloc(sizeof(*newblock), DRM_MEM_BUFLISTS); - if (!newblock) - goto out; - newblock->start = start; - newblock->size = p->size - (start - p->start); - newblock->file_priv = NULL; - newblock->next = p->next; - newblock->prev = p; - p->next->prev = newblock; - p->next = newblock; - p->size -= newblock->size; - p = newblock; - } - - /* Maybe cut off the end of an existing block */ - if (size < p->size) { - struct mem_block *newblock = - drm_alloc(sizeof(*newblock), DRM_MEM_BUFLISTS); - if (!newblock) - goto out; - newblock->start = start + size; - newblock->size = p->size - size; - newblock->file_priv = NULL; - newblock->next = p->next; - newblock->prev = p; - p->next->prev = newblock; - p->next = newblock; - p->size = size; - } - - out: - /* Our block is in the middle */ - p->file_priv = file_priv; - return p; -} - -static struct mem_block *alloc_block(struct mem_block *heap, int size, - int align2, struct drm_file *file_priv) -{ - struct mem_block *p; - int mask = (1 << align2) - 1; - - for (p = heap->next; p != heap; p = p->next) { - int start = (p->start + mask) & ~mask; - if (p->file_priv == NULL && start + size <= p->start + p->size) - return split_block(p, start, size, file_priv); - } - - return NULL; -} - -static struct mem_block *find_block(struct mem_block *heap, int start) -{ - struct mem_block *p; - - for (p = heap->next; p != heap; p = p->next) - if (p->start == start) - return p; - - return NULL; -} - -static void free_block(struct mem_block *p) -{ - p->file_priv = NULL; - - /* Assumes a single contiguous range. Needs a special file_priv in - * 'heap' to stop it being subsumed. - */ - if (p->next->file_priv == NULL) { - struct mem_block *q = p->next; - p->size += q->size; - p->next = q->next; - p->next->prev = p; - drm_free(q, sizeof(*q), DRM_MEM_BUFLISTS); - } - - if (p->prev->file_priv == NULL) { - struct mem_block *q = p->prev; - q->size += p->size; - q->next = p->next; - q->next->prev = q; - drm_free(p, sizeof(*q), DRM_MEM_BUFLISTS); - } -} - -/* Initialize. How to check for an uninitialized heap? - */ -static int init_heap(struct mem_block **heap, int start, int size) -{ - struct mem_block *blocks = drm_alloc(sizeof(*blocks), DRM_MEM_BUFLISTS); - - if (!blocks) - return ENOMEM; - - *heap = drm_alloc(sizeof(**heap), DRM_MEM_BUFLISTS); - if (!*heap) { - drm_free(blocks, sizeof(*blocks), DRM_MEM_BUFLISTS); - return ENOMEM; - } - - blocks->start = start; - blocks->size = size; - blocks->file_priv = NULL; - blocks->next = blocks->prev = *heap; - - memset(*heap, 0, sizeof(**heap)); - (*heap)->file_priv = (struct drm_file *) - 1; - (*heap)->next = (*heap)->prev = blocks; - return 0; -} - /* Free all blocks associated with the releasing file. */ void i915_mem_release(struct drm_device * dev, struct drm_file *file_priv, - struct mem_block *heap) + struct drm_heap *heap) { - struct mem_block *p; + struct drm_mem *p, *q; - if (!heap || !heap->next) + if (heap == NULL || TAILQ_EMPTY(heap)) return; - for (p = heap->next; p != heap; p = p->next) { + TAILQ_FOREACH(p, heap, link) { if (p->file_priv == file_priv) { + intel_mark_block(dev, p, 0); p->file_priv = NULL; - mark_block(dev, p, 0); } } - /* Assumes a single contiguous range. Needs a special file_priv in - * 'heap' to stop it being subsumed. - */ - for (p = heap->next; p != heap; p = p->next) { - while (p->file_priv == NULL && p->next->file_priv == NULL) { - struct mem_block *q = p->next; + /* Coalesce the entries. ugh... */ + for (p = TAILQ_FIRST(heap); p != TAILQ_END(heap); p = q) { + q = p; + while (p->file_priv == NULL && + (q = TAILQ_NEXT(p, link)) != TAILQ_END(heap) && + q->file_priv == NULL) { p->size += q->size; - p->next = q->next; - p->next->prev = p; - drm_free(q, sizeof(*q), DRM_MEM_BUFLISTS); + TAILQ_REMOVE(heap, q, link); + drm_free(q, sizeof(*q), DRM_MEM_DRIVER); } } } /* Shutdown. */ -void i915_mem_takedown(struct mem_block **heap) +void i915_mem_takedown(struct drm_heap *heap) { - struct mem_block *p; + struct drm_mem *p; - if (!*heap) + if (heap == NULL) return; - for (p = (*heap)->next; p != *heap;) { - struct mem_block *q = p; - p = p->next; - drm_free(q, sizeof(*q), DRM_MEM_BUFLISTS); + while ((p = TAILQ_FIRST(heap)) != NULL) { + TAILQ_REMOVE(heap, p, link); + drm_free(p, sizeof(*p), DRM_MEM_BUFLISTS); } - - drm_free(*heap, sizeof(**heap), DRM_MEM_BUFLISTS); - *heap = NULL; } -static struct mem_block **get_heap(drm_i915_private_t * dev_priv, int region) +struct drm_heap * +intel_get_heap(drm_i915_private_t * dev_priv, int region) { switch (region) { case I915_MEM_REGION_AGP: @@ -273,15 +151,16 @@ int i915_mem_alloc(struct drm_device *dev, void *data, { drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_mem_alloc_t *alloc = data; - struct mem_block *block, **heap; + struct drm_heap *heap; + struct drm_mem *block; if (!dev_priv) { DRM_ERROR("called with no initialization\n"); return EINVAL; } - heap = get_heap(dev_priv, alloc->region); - if (!heap || !*heap) + heap = intel_get_heap(dev_priv, alloc->region); + if (heap == NULL) return EFAULT; /* Make things easier on ourselves: all allocations at least @@ -290,12 +169,12 @@ int i915_mem_alloc(struct drm_device *dev, void *data, if (alloc->alignment < 12) alloc->alignment = 12; - block = alloc_block(*heap, alloc->size, alloc->alignment, file_priv); + block = drm_alloc_block(heap, alloc->size, alloc->alignment, file_priv); - if (!block) + if (block == NULL) return ENOMEM; - mark_block(dev, block, 1); + intel_mark_block(dev, block, 1); if (DRM_COPY_TO_USER(alloc->region_offset, &block->start, sizeof(int))) { @@ -311,26 +190,27 @@ int i915_mem_free(struct drm_device *dev, void *data, { drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_mem_free_t *memfree = data; - struct mem_block *block, **heap; + struct drm_heap *heap; + struct drm_mem *block; if (!dev_priv) { DRM_ERROR("called with no initialization\n"); return EINVAL; } - heap = get_heap(dev_priv, memfree->region); - if (!heap || !*heap) + heap = intel_get_heap(dev_priv, memfree->region); + if (heap == NULL) return EFAULT; - block = find_block(*heap, memfree->region_offset); - if (!block) + block = drm_find_block(heap, memfree->region_offset); + if (block == NULL) return EFAULT; if (block->file_priv != file_priv) return EPERM; - mark_block(dev, block, 0); - free_block(block); + intel_mark_block(dev, block, 0); + drm_free_block(heap, block); return 0; } @@ -339,23 +219,19 @@ int i915_mem_init_heap(struct drm_device *dev, void *data, { drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_mem_init_heap_t *initheap = data; - struct mem_block **heap; + struct drm_heap *heap; if (!dev_priv) { DRM_ERROR("called with no initialization\n"); return EINVAL; } - heap = get_heap(dev_priv, initheap->region); - if (!heap) + /* Make sure it's valid and initialised */ + heap = intel_get_heap(dev_priv, initheap->region); + if (heap == NULL || !TAILQ_EMPTY(heap)) return EFAULT; - if (*heap) { - DRM_ERROR("heap already initialized?"); - return EFAULT; - } - - return init_heap(heap, initheap->start, initheap->size); + return drm_init_heap(heap, initheap->start, initheap->size); } int i915_mem_destroy_heap( struct drm_device *dev, void *data, @@ -363,24 +239,24 @@ int i915_mem_destroy_heap( struct drm_device *dev, void *data, { drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_mem_destroy_heap_t *destroyheap = data; - struct mem_block **heap; + struct drm_heap *heap; - if ( !dev_priv ) { + if (!dev_priv) { DRM_ERROR( "called with no initialization\n" ); return EINVAL; } - heap = get_heap( dev_priv, destroyheap->region ); + heap = intel_get_heap( dev_priv, destroyheap->region ); if (!heap) { - DRM_ERROR("get_heap failed"); + DRM_ERROR("intel_get_heap failed"); return EFAULT; } - if (!*heap) { + if (TAILQ_EMPTY(heap)) { DRM_ERROR("heap not initialized?"); return EFAULT; } - i915_mem_takedown( heap ); + i915_mem_takedown(heap); return 0; } diff --git a/sys/dev/pci/drm/radeon_drv.c b/sys/dev/pci/drm/radeon_drv.c index d287e850d0a..eccdcc09f87 100644 --- a/sys/dev/pci/drm/radeon_drv.c +++ b/sys/dev/pci/drm/radeon_drv.c @@ -587,6 +587,9 @@ radeondrm_attach(struct device *parent, struct device *self, void *aux) is_agp = pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_AGP, NULL, NULL); + TAILQ_INIT(&dev_priv->gart_heap); + TAILQ_INIT(&dev_priv->fb_heap); + dev_priv->drmdev = drm_attach_pci(&radeondrm_driver, pa, is_agp, self); } diff --git a/sys/dev/pci/drm/radeon_drv.h b/sys/dev/pci/drm/radeon_drv.h index 7fd88de58dc..d71fb3fe537 100644 --- a/sys/dev/pci/drm/radeon_drv.h +++ b/sys/dev/pci/drm/radeon_drv.h @@ -195,14 +195,6 @@ struct drm_radeon_file { int64_t radeon_fb_delta; }; -struct mem_block { - struct mem_block *next; - struct mem_block *prev; - int start; - int size; - struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */ -}; - struct radeon_surface { int refcount; u32 lower; @@ -292,8 +284,8 @@ typedef struct drm_radeon_private { drm_local_map_t *ring_rptr; drm_local_map_t *gart_textures; - struct mem_block *gart_heap; - struct mem_block *fb_heap; + struct drm_heap gart_heap; + struct drm_heap fb_heap; /* SW interrupt */ atomic_t swi_emitted; @@ -389,9 +381,8 @@ extern int radeon_do_cp_idle(drm_radeon_private_t * dev_priv); extern int radeon_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int radeon_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int radeon_mem_init_heap(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern void radeon_mem_takedown(struct mem_block **heap); -extern void radeon_mem_release(struct drm_file *file_priv, - struct mem_block *heap); +extern void radeon_mem_takedown(struct drm_heap *heap); +extern void radeon_mem_release(struct drm_file *, struct drm_heap *); /* radeon_irq.c */ extern void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state); diff --git a/sys/dev/pci/drm/radeon_mem.c b/sys/dev/pci/drm/radeon_mem.c index 7d4e1e1fa75..3efdea78353 100644 --- a/sys/dev/pci/drm/radeon_mem.c +++ b/sys/dev/pci/drm/radeon_mem.c @@ -1,4 +1,3 @@ -/* radeon_mem.c -- Simple GART/fb memory manager for radeon -*- linux-c -*- */ /* * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. * @@ -34,150 +33,31 @@ #include "radeon_drm.h" #include "radeon_drv.h" -/* Very simple allocator for GART memory, working on a static range - * already mapped into each client's address space. - */ - -static struct mem_block *split_block(struct mem_block *p, int start, int size, - struct drm_file *file_priv) -{ - /* Maybe cut off the start of an existing block */ - if (start > p->start) { - struct mem_block *newblock = - drm_alloc(sizeof(*newblock), DRM_MEM_BUFS); - if (!newblock) - goto out; - newblock->start = start; - newblock->size = p->size - (start - p->start); - newblock->file_priv = NULL; - newblock->next = p->next; - newblock->prev = p; - p->next->prev = newblock; - p->next = newblock; - p->size -= newblock->size; - p = newblock; - } - - /* Maybe cut off the end of an existing block */ - if (size < p->size) { - struct mem_block *newblock = - drm_alloc(sizeof(*newblock), DRM_MEM_BUFS); - if (!newblock) - goto out; - newblock->start = start + size; - newblock->size = p->size - size; - newblock->file_priv = NULL; - newblock->next = p->next; - newblock->prev = p; - p->next->prev = newblock; - p->next = newblock; - p->size = size; - } - - out: - /* Our block is in the middle */ - p->file_priv = file_priv; - return p; -} - -static struct mem_block *alloc_block(struct mem_block *heap, int size, - int align2, struct drm_file *file_priv) -{ - struct mem_block *p; - int mask = (1 << align2) - 1; - - list_for_each(p, heap) { - int start = (p->start + mask) & ~mask; - if (p->file_priv == NULL && start + size <= p->start + p->size) - return split_block(p, start, size, file_priv); - } - - return NULL; -} - -static struct mem_block *find_block(struct mem_block *heap, int start) -{ - struct mem_block *p; - - list_for_each(p, heap) - if (p->start == start) - return p; - - return NULL; -} - -static void free_block(struct mem_block *p) -{ - p->file_priv = NULL; - - /* Assumes a single contiguous range. Needs a special file_priv in - * 'heap' to stop it being subsumed. - */ - if (p->next->file_priv == NULL) { - struct mem_block *q = p->next; - p->size += q->size; - p->next = q->next; - p->next->prev = p; - drm_free(q, sizeof(*q), DRM_MEM_BUFS); - } - - if (p->prev->file_priv == NULL) { - struct mem_block *q = p->prev; - q->size += p->size; - q->next = p->next; - q->next->prev = q; - drm_free(p, sizeof(*q), DRM_MEM_BUFS); - } -} - -/* Initialize. How to check for an uninitialized heap? - */ -static int init_heap(struct mem_block **heap, int start, int size) -{ - struct mem_block *blocks = drm_alloc(sizeof(*blocks), DRM_MEM_BUFS); - - if (!blocks) - return ENOMEM; - - *heap = drm_calloc(1, sizeof(**heap), DRM_MEM_BUFS); - if (!*heap) { - drm_free(blocks, sizeof(*blocks), DRM_MEM_BUFS); - return ENOMEM; - } - - blocks->start = start; - blocks->size = size; - blocks->file_priv = NULL; - blocks->next = blocks->prev = *heap; - - (*heap)->file_priv = (struct drm_file *) - 1; - (*heap)->next = (*heap)->prev = blocks; - return 0; -} +struct drm_heap *radeon_get_heap(drm_radeon_private_t *, int); /* Free all blocks associated with the releasing file. */ -void radeon_mem_release(struct drm_file *file_priv, struct mem_block *heap) +void +radeon_mem_release(struct drm_file *file_priv, struct drm_heap *heap) { - struct mem_block *p; + struct drm_mem *p, *q; - if (!heap || !heap->next) + if (heap == NULL || TAILQ_EMPTY(heap)) return; - list_for_each(p, heap) { + TAILQ_FOREACH(p, heap, link) { if (p->file_priv == file_priv) p->file_priv = NULL; } - /* Assumes a single contiguous range. Needs a special file_priv in - * 'heap' to stop it being subsumed. - */ - list_for_each(p, heap) { - while (p->file_priv == NULL && p->next->file_priv == NULL) { - struct mem_block *q = p->next; + /* Coalesce the entries. ugh... */ + for (p = TAILQ_FIRST(heap); p != TAILQ_END(heap); p = q) { + q = p; + while (p->file_priv == NULL && + (q = TAILQ_NEXT(p, link)) != TAILQ_END(heap) && + q->file_priv == NULL) { p->size += q->size; - p->next = q->next; - p->next->prev = p; + TAILQ_REMOVE(heap, q, link); drm_free(q, sizeof(*q), DRM_MEM_DRIVER); } } @@ -185,26 +65,24 @@ void radeon_mem_release(struct drm_file *file_priv, struct mem_block *heap) /* Shutdown. */ -void radeon_mem_takedown(struct mem_block **heap) +void +radeon_mem_takedown(struct drm_heap *heap) { - struct mem_block *p; + struct drm_mem *p; - if (!*heap) + if (heap == NULL) return; - for (p = (*heap)->next; p != *heap;) { - struct mem_block *q = p; - p = p->next; - drm_free(q, sizeof(*q), DRM_MEM_DRIVER); + while ((p = TAILQ_FIRST(heap)) != NULL) { + TAILQ_REMOVE(heap, p, link); + drm_free(p, sizeof(*p), DRM_MEM_DRIVER); } - - drm_free(*heap, sizeof(**heap), DRM_MEM_DRIVER); - *heap = NULL; } /* IOCTL HANDLERS */ -static struct mem_block **get_heap(drm_radeon_private_t * dev_priv, int region) +struct drm_heap * +radeon_get_heap(drm_radeon_private_t * dev_priv, int region) { switch (region) { case RADEON_MEM_REGION_GART: @@ -216,19 +94,21 @@ static struct mem_block **get_heap(drm_radeon_private_t * dev_priv, int region) } } -int radeon_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) +int +radeon_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) { - drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_mem_alloc_t *alloc = data; - struct mem_block *block, **heap; + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_radeon_mem_alloc_t *alloc = data; + struct drm_heap *heap; + struct drm_mem *block; if (!dev_priv) { DRM_ERROR("called with no initialization\n"); return EINVAL; } - heap = get_heap(dev_priv, alloc->region); - if (!heap || !*heap) + heap = radeon_get_heap(dev_priv, alloc->region); + if (heap == NULL) return EFAULT; /* Make things easier on ourselves: all allocations at least @@ -237,65 +117,65 @@ int radeon_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_p if (alloc->alignment < 12) alloc->alignment = 12; - block = alloc_block(*heap, alloc->size, alloc->alignment, file_priv); + block = drm_alloc_block(heap, alloc->size, alloc->alignment, file_priv); - if (!block) + if (block == NULL) return ENOMEM; - if (DRM_COPY_TO_USER(alloc->region_offset, &block->start, - sizeof(int))) { - DRM_ERROR("copy_to_user\n"); + if (DRM_COPY_TO_USER(alloc->region_offset, &block->start, sizeof(int))) return EFAULT; - } return 0; } -int radeon_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv) +int +radeon_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_mem_free_t *memfree = data; - struct mem_block *block, **heap; + struct drm_heap *heap; + struct drm_mem *block; if (!dev_priv) { DRM_ERROR("called with no initialization\n"); return EINVAL; } - heap = get_heap(dev_priv, memfree->region); - if (!heap || !*heap) + heap = radeon_get_heap(dev_priv, memfree->region); + if (heap == NULL) return EFAULT; - block = find_block(*heap, memfree->region_offset); - if (!block) + block = drm_find_block(heap, memfree->region_offset); + if (block == NULL) return EFAULT; if (block->file_priv != file_priv) return EPERM; - free_block(block); + drm_free_block(heap, block); return 0; } -int radeon_mem_init_heap(struct drm_device *dev, void *data, struct drm_file *file_priv) +int +radeon_mem_init_heap(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_mem_init_heap_t *initheap = data; - struct mem_block **heap; + struct drm_heap *heap; if (!dev_priv) { DRM_ERROR("called with no initialization\n"); return EINVAL; } - heap = get_heap(dev_priv, initheap->region); - if (!heap) - return EFAULT; + DRM_ERROR("region: %d start: %d size: %d\n", initheap->region, + initheap->start, initheap->size); - if (*heap) { - DRM_ERROR("heap already initialized?"); + /* Make sure it's valid and initialised */ + heap = radeon_get_heap(dev_priv, initheap->region); + if (heap == NULL || !TAILQ_EMPTY(heap)) return EFAULT; - } - return init_heap(heap, initheap->start, initheap->size); + return drm_init_heap(heap, initheap->start, initheap->size); } diff --git a/sys/dev/pci/drm/radeon_state.c b/sys/dev/pci/drm/radeon_state.c index 4b33d8c3a33..a2e318bfef6 100644 --- a/sys/dev/pci/drm/radeon_state.c +++ b/sys/dev/pci/drm/radeon_state.c @@ -3232,8 +3232,8 @@ radeon_driver_close(struct drm_device *dev, struct drm_file *file_priv) drm_radeon_private_t *dev_priv = dev->dev_private; dev_priv->page_flipping = 0; - radeon_mem_release(file_priv, dev_priv->gart_heap); - radeon_mem_release(file_priv, dev_priv->fb_heap); + radeon_mem_release(file_priv, &dev_priv->gart_heap); + radeon_mem_release(file_priv, &dev_priv->fb_heap); if (dev_priv->cp_running) radeon_surfaces_release(file_priv, dev_priv); } |