summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/drm/drmP.h19
-rw-r--r--sys/dev/pci/drm/drm_heap.c148
-rw-r--r--sys/dev/pci/drm/files.drm3
-rw-r--r--sys/dev/pci/drm/i915_dma.c5
-rw-r--r--sys/dev/pci/drm/i915_drv.c1
-rw-r--r--sys/dev/pci/drm/i915_drv.h14
-rw-r--r--sys/dev/pci/drm/i915_mem.c228
-rw-r--r--sys/dev/pci/drm/radeon_drv.c3
-rw-r--r--sys/dev/pci/drm/radeon_drv.h17
-rw-r--r--sys/dev/pci/drm/radeon_mem.c224
-rw-r--r--sys/dev/pci/drm/radeon_state.c4
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);
}