diff options
Diffstat (limited to 'sys')
-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); } |