summaryrefslogtreecommitdiff
path: root/bsd-core
diff options
context:
space:
mode:
authorEric Anholt <anholt@freebsd.org>2005-04-26 05:19:11 +0000
committerEric Anholt <anholt@freebsd.org>2005-04-26 05:19:11 +0000
commitec111d70fee0647c4c68a02c723d4a3729c93b56 (patch)
tree114a3257310a979d3dea484af62322ba007bf1e0 /bsd-core
parent31a06d0baca9e378a773ca8bd350860546dd8a79 (diff)
Convert BSD code to mostly use bus_dma, the dma abstraction for dealing
with IOMMUs and such. There is one usage of the forbidden vtophys() left in drm_scatter.c which will be fixed up soon. This required a KPI change for drm_pci_alloc/free() to return/use a drm_dma_handle_t that keeps track of os-specific bits, rather than just passing around the vaddr/busaddr/size. Submitted by: Tonnerre Lombard (partially) Tested on: FreeBSD: Rage128 AGP/PCI Linux: Savage4 AGP/PCI
Diffstat (limited to 'bsd-core')
-rw-r--r--bsd-core/ati_pcigart.c72
-rw-r--r--bsd-core/drmP.h24
-rw-r--r--bsd-core/drm_bufs.c45
-rw-r--r--bsd-core/drm_dma.c5
-rw-r--r--bsd-core/drm_pci.c93
-rw-r--r--bsd-core/drm_scatter.c15
6 files changed, 151 insertions, 103 deletions
diff --git a/bsd-core/ati_pcigart.c b/bsd-core/ati_pcigart.c
index ae18a957..2eff5be1 100644
--- a/bsd-core/ati_pcigart.c
+++ b/bsd-core/ati_pcigart.c
@@ -31,53 +31,44 @@
#include "drmP.h"
-#if PAGE_SIZE == 8192
-# define ATI_PCIGART_TABLE_ORDER 2
-# define ATI_PCIGART_TABLE_PAGES (1 << 2)
-#elif PAGE_SIZE == 4096
-# define ATI_PCIGART_TABLE_ORDER 3
-# define ATI_PCIGART_TABLE_PAGES (1 << 3)
-#elif
-# error - PAGE_SIZE not 8K or 4K
-#endif
-
-# define ATI_MAX_PCIGART_PAGES 8192 /* 32 MB aperture, 4K pages */
-# define ATI_PCIGART_PAGE_SIZE 4096 /* PCI GART page size */
+#define ATI_PCIGART_PAGE_SIZE 4096 /* PCI GART page size */
+#define ATI_MAX_PCIGART_PAGES 8192 /* 32 MB aperture, 4K pages */
+#define ATI_PCIGART_TABLE_SIZE 32768
int drm_ati_pcigart_init(drm_device_t *dev, unsigned long *addr,
dma_addr_t *bus_addr)
{
- drm_sg_mem_t *entry = dev->sg;
- unsigned long address = 0;
unsigned long pages;
- u32 *pci_gart=0, page_base, bus_address = 0;
- int i, j, ret = 0;
+ u32 *pci_gart = 0, page_base;
+ int i, j;
- if ( !entry ) {
+ *addr = 0;
+ *bus_addr = 0;
+
+ if (dev->sg == NULL) {
DRM_ERROR( "no scatter/gather memory!\n" );
- goto done;
+ return 0;
}
- address = (long)contigmalloc((1 << ATI_PCIGART_TABLE_ORDER) * PAGE_SIZE,
- M_DRM, M_NOWAIT, 0ul, 0xfffffffful, PAGE_SIZE, 0);
- if ( !address ) {
- DRM_ERROR( "cannot allocate PCI GART page!\n" );
- goto done;
+ dev->sg->dmah = drm_pci_alloc(dev, ATI_PCIGART_TABLE_SIZE, 0,
+ 0xfffffffful);
+ if (dev->sg->dmah == NULL) {
+ DRM_ERROR("cannot allocate PCI GART table!\n");
+ return 0;
}
- /* XXX: we need to busdma this */
- bus_address = vtophys( address );
+ *addr = (long)dev->sg->dmah->vaddr;
+ *bus_addr = dev->sg->dmah->busaddr;
+ pci_gart = (u32 *)dev->sg->dmah->vaddr;
- pci_gart = (u32 *)address;
+ pages = DRM_MIN(dev->sg->pages, ATI_MAX_PCIGART_PAGES);
- pages = ( entry->pages <= ATI_MAX_PCIGART_PAGES )
- ? entry->pages : ATI_MAX_PCIGART_PAGES;
+ bzero(pci_gart, ATI_PCIGART_TABLE_SIZE);
- bzero( pci_gart, ATI_MAX_PCIGART_PAGES * sizeof(u32) );
+ KASSERT(PAGE_SIZE >= ATI_PCIGART_PAGE_SIZE, "page size too small");
for ( i = 0 ; i < pages ; i++ ) {
- entry->busaddr[i] = vtophys( entry->handle + (i*PAGE_SIZE) );
- page_base = (u32) entry->busaddr[i];
+ page_base = (u32) dev->sg->busaddr[i];
for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
*pci_gart++ = cpu_to_le32( page_base );
@@ -87,29 +78,18 @@ int drm_ati_pcigart_init(drm_device_t *dev, unsigned long *addr,
DRM_MEMORYBARRIER();
- ret = 1;
-
-done:
- *addr = address;
- *bus_addr = bus_address;
- return ret;
+ return 1;
}
int drm_ati_pcigart_cleanup(drm_device_t *dev, unsigned long addr,
dma_addr_t bus_addr)
{
- drm_sg_mem_t *entry = dev->sg;
-
- /* we need to support large memory configurations */
- if ( !entry ) {
+ if (dev->sg == NULL) {
DRM_ERROR( "no scatter/gather memory!\n" );
return 0;
}
-#if __FreeBSD_version > 500000
- /* Not available on 4.x */
- contigfree((void *)addr, (1 << ATI_PCIGART_TABLE_ORDER) * PAGE_SIZE,
- M_DRM);
-#endif
+ drm_pci_free(dev, dev->sg->dmah);
+
return 1;
}
diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h
index ca28ea2c..6af29718 100644
--- a/bsd-core/drmP.h
+++ b/bsd-core/drmP.h
@@ -481,14 +481,24 @@ typedef struct drm_freelist {
int high_mark; /* High water mark */
} drm_freelist_t;
+typedef struct drm_dma_handle {
+ void *vaddr;
+ bus_addr_t busaddr;
+#if defined(__FreeBSD__)
+ bus_dma_tag_t tag;
+ bus_dmamap_t map;
+#elif defined(__NetBSD__)
+ bus_dma_segment_t seg;
+#endif
+} drm_dma_handle_t;
+
typedef struct drm_buf_entry {
int buf_size;
int buf_count;
drm_buf_t *buflist;
int seg_count;
+ drm_dma_handle_t **seglist;
int page_order;
- vm_offset_t *seglist;
- dma_addr_t *seglist_bus;
drm_freelist_t freelist;
} drm_buf_entry_t;
@@ -558,9 +568,9 @@ typedef struct drm_agp_head {
typedef struct drm_sg_mem {
unsigned long handle;
- void *virtual;
int pages;
dma_addr_t *busaddr;
+ drm_dma_handle_t *dmah; /* Handle to PCI memory for ATI PCIGART table */
} drm_sg_mem_t;
typedef TAILQ_HEAD(drm_map_list, drm_local_map) drm_map_list_t;
@@ -579,6 +589,7 @@ typedef struct drm_local_map {
struct resource *bsr;
bus_space_tag_t bst;
bus_space_handle_t bsh;
+ drm_dma_handle_t *dmah;
TAILQ_ENTRY(drm_local_map) link;
} drm_local_map_t;
@@ -910,10 +921,9 @@ int drm_sg_alloc(DRM_IOCTL_ARGS);
int drm_sg_free(DRM_IOCTL_ARGS);
/* consistent PCI memory functions (drm_pci.c) */
-void *drm_pci_alloc(drm_device_t *dev, size_t size, size_t align,
- dma_addr_t maxaddr, dma_addr_t *busaddr);
-void drm_pci_free(drm_device_t *dev, size_t size, void *vaddr,
- dma_addr_t busaddr);
+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);
/* Inline replacements for DRM_IOREMAP macros */
static __inline__ void drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev)
diff --git a/bsd-core/drm_bufs.c b/bsd-core/drm_bufs.c
index 0461ebeb..0f1b7a03 100644
--- a/bsd-core/drm_bufs.c
+++ b/bsd-core/drm_bufs.c
@@ -151,7 +151,6 @@ int drm_addmap(DRM_IOCTL_ARGS)
DRM_DEVICE;
drm_map_t request;
drm_local_map_t *map;
- dma_addr_t bus_addr;
if (!(dev->flags & (FREAD|FWRITE)))
return DRM_ERR(EACCES); /* Require read/write */
@@ -246,13 +245,14 @@ int drm_addmap(DRM_IOCTL_ARGS)
map->offset = map->offset + dev->sg->handle;
break;
case _DRM_CONSISTENT:
- map->handle = drm_pci_alloc(dev, map->size, map->size,
- 0xfffffffful, &bus_addr);
- if (map->handle == NULL) {
+ map->dmah = drm_pci_alloc(dev, map->size, map->size,
+ 0xfffffffful);
+ if (map->dmah == NULL) {
free(map, M_DRM);
return ENOMEM;
}
- map->offset = (unsigned long)bus_addr;
+ map->handle = map->dmah->vaddr;
+ map->offset = map->dmah->busaddr;
break;
default:
free(map, M_DRM);
@@ -310,7 +310,7 @@ void drm_remove_map(drm_device_t *dev, drm_local_map_t *map)
case _DRM_SCATTER_GATHER:
break;
case _DRM_CONSISTENT:
- drm_pci_free(dev, map->size, map->handle, map->offset);
+ drm_pci_free(dev, map->dmah);
break;
}
@@ -361,12 +361,9 @@ static void drm_cleanup_buf_error(drm_device_t *dev, drm_buf_entry_t *entry)
if (entry->seg_count) {
for (i = 0; i < entry->seg_count; i++) {
- drm_pci_free(dev, entry->buf_size,
- (void *)entry->seglist[i],
- entry->seglist_bus[i]);
+ drm_pci_free(dev, entry->seglist[i]);
}
free(entry->seglist, M_DRM);
- free(entry->seglist_bus, M_DRM);
entry->seg_count = 0;
}
@@ -499,7 +496,6 @@ static int drm_addbufs_pci(drm_device_t *dev, drm_buf_desc_t *request)
int total;
int page_order;
drm_buf_entry_t *entry;
- vm_offset_t vaddr;
drm_buf_t *buf;
int alignment;
unsigned long offset;
@@ -508,7 +504,6 @@ static int drm_addbufs_pci(drm_device_t *dev, drm_buf_desc_t *request)
int page_count;
unsigned long *temp_pagelist;
drm_buf_t **temp_buflist;
- dma_addr_t bus_addr;
count = request->count;
order = drm_order(request->size);
@@ -528,8 +523,6 @@ static int drm_addbufs_pci(drm_device_t *dev, drm_buf_desc_t *request)
M_NOWAIT | M_ZERO);
entry->seglist = malloc(count * sizeof(*entry->seglist), M_DRM,
M_NOWAIT | M_ZERO);
- entry->seglist_bus = malloc(count * sizeof(*entry->seglist_bus), M_DRM,
- M_NOWAIT | M_ZERO);
/* Keep the original pagelist until we know all the allocations
* have succeeded
@@ -538,10 +531,9 @@ static int drm_addbufs_pci(drm_device_t *dev, drm_buf_desc_t *request)
sizeof(*dma->pagelist), M_DRM, M_NOWAIT);
if (entry->buflist == NULL || entry->seglist == NULL ||
- entry->seglist_bus == NULL || temp_pagelist == NULL) {
+ temp_pagelist == NULL) {
free(entry->buflist, M_DRM);
free(entry->seglist, M_DRM);
- free(entry->seglist_bus, M_DRM);
return DRM_ERR(ENOMEM);
}
@@ -557,9 +549,9 @@ static int drm_addbufs_pci(drm_device_t *dev, drm_buf_desc_t *request)
page_count = 0;
while ( entry->buf_count < count ) {
- vaddr = (vm_offset_t)drm_pci_alloc(dev, size, alignment,
- 0xfffffffful, &bus_addr);
- if (vaddr == 0) {
+ drm_dma_handle_t *dmah = drm_pci_alloc(dev, size, alignment,
+ 0xfffffffful);
+ if (dmah == NULL) {
/* Set count correctly so we free the proper amount. */
entry->buf_count = count;
entry->seg_count = count;
@@ -567,15 +559,14 @@ static int drm_addbufs_pci(drm_device_t *dev, drm_buf_desc_t *request)
free(temp_pagelist, M_DRM);
return DRM_ERR(ENOMEM);
}
-
- entry->seglist_bus[entry->seg_count] = bus_addr;
- entry->seglist[entry->seg_count++] = vaddr;
+
+ entry->seglist[entry->seg_count++] = dmah;
for ( i = 0 ; i < (1 << page_order) ; i++ ) {
- DRM_DEBUG( "page %d @ 0x%08lx\n",
+ DRM_DEBUG( "page %d @ %p\n",
dma->page_count + page_count,
- (long)vaddr + PAGE_SIZE * i );
+ (char *)dmah->vaddr + PAGE_SIZE * i );
temp_pagelist[dma->page_count + page_count++] =
- vaddr + PAGE_SIZE * i;
+ (long)dmah->vaddr + PAGE_SIZE * i;
}
for ( offset = 0 ;
offset + size <= total && entry->buf_count < count ;
@@ -586,8 +577,8 @@ static int drm_addbufs_pci(drm_device_t *dev, drm_buf_desc_t *request)
buf->order = order;
buf->used = 0;
buf->offset = (dma->byte_count + byte_count + offset);
- buf->address = (void *)(vaddr + offset);
- buf->bus_address = bus_addr + offset;
+ buf->address = ((char *)dmah->vaddr + offset);
+ buf->bus_address = dmah->busaddr + offset;
buf->next = NULL;
buf->pending = 0;
buf->filp = NULL;
diff --git a/bsd-core/drm_dma.c b/bsd-core/drm_dma.c
index adc352b6..6377d71e 100644
--- a/bsd-core/drm_dma.c
+++ b/bsd-core/drm_dma.c
@@ -62,12 +62,9 @@ void drm_dma_takedown(drm_device_t *dev)
dma->bufs[i].buf_count,
dma->bufs[i].seg_count);
for (j = 0; j < dma->bufs[i].seg_count; j++) {
- drm_pci_free(dev, dma->bufs[i].buf_size,
- (void *)dma->bufs[i].seglist[j],
- dma->bufs[i].seglist_bus[j]);
+ drm_pci_free(dev, dma->bufs[i].seglist[j]);
}
free(dma->bufs[i].seglist, M_DRM);
- free(dma->bufs[i].seglist_bus, M_DRM);
}
if (dma->bufs[i].buf_count) {
diff --git a/bsd-core/drm_pci.c b/bsd-core/drm_pci.c
index 29ed4790..0f431dd6 100644
--- a/bsd-core/drm_pci.c
+++ b/bsd-core/drm_pci.c
@@ -34,34 +34,101 @@
/** \name PCI memory */
/*@{*/
+#if defined(__FreeBSD__)
+static void
+drm_pci_busdma_callback(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+ drm_dma_handle_t *dmah = arg;
+
+ if (error != 0)
+ return;
+
+ KASSERT(nsegs == 1, ("drm_pci_busdma_callback: bad dma segment count"));
+ dmah->busaddr = segs[0].ds_addr;
+}
+#endif
+
/**
* \brief Allocate a physically contiguous DMA-accessible consistent
* memory block.
*/
-void *
-drm_pci_alloc(drm_device_t *dev, size_t size, size_t align, dma_addr_t maxaddr,
- dma_addr_t *busaddr)
+drm_dma_handle_t *
+drm_pci_alloc(drm_device_t *dev, size_t size, size_t align, dma_addr_t maxaddr)
{
- void *vaddr;
+ drm_dma_handle_t *dmah;
+ int ret;
+
+ dmah = malloc(sizeof(drm_dma_handle_t), M_DRM, M_ZERO | M_NOWAIT);
+ if (dmah == NULL)
+ return NULL;
- vaddr = contigmalloc(size, M_DRM, M_NOWAIT, 0ul, maxaddr, align,
- 0);
- *busaddr = vtophys(vaddr);
-
- return vaddr;
+#ifdef __FreeBSD__
+ ret = bus_dma_tag_create(NULL, align, 0, /* tag, align, boundary */
+ maxaddr, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */
+ NULL, NULL, /* filtfunc, filtfuncargs */
+ size, 1, size, /* maxsize, nsegs, maxsegsize */
+ BUS_DMA_ALLOCNOW, NULL, NULL, /* flags, lockfunc, lockfuncargs */
+ &dmah->tag);
+ if (ret != 0) {
+ free(dmah, M_DRM);
+ return NULL;
+ }
+
+ ret = bus_dmamem_alloc(dmah->tag, &dmah->vaddr, BUS_DMA_NOWAIT,
+ &dmah->map);
+ if (ret != 0) {
+ bus_dma_tag_destroy(dmah->tag);
+ free(dmah, M_DRM);
+ return NULL;
+ }
+
+ ret = bus_dmamap_load(dmah->tag, dmah->map, dmah->vaddr, size,
+ drm_pci_busdma_callback, dmah, 0);
+ if (ret != 0) {
+ bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map);
+ bus_dma_tag_destroy(dmah->tag);
+ free(dmah, M_DRM);
+ return NULL;
+ }
+#elif defined(__NetBSD__)
+ ret = bus_dmamem_alloc(dev->dma_tag, size, align, PAGE_SIZE,
+ &dmah->seg, 1, &nsegs, BUS_DMA_NOWAIT);
+ if ((ret != 0) || (nsegs != 1)) {
+ free(dmah, M_DRM);
+ return NULL;
+ }
+
+ ret = bus_dmamem_map(dev->dma_tag, &dmah->seg, 1, size, &dmah->addr,
+ BUS_DMA_NOWAIT);
+ if (ret != 0) {
+ bus_dmamem_free(dev->dma_tag, &dmah->seg, 1);
+ free(dmah, M_DRM);
+ return NULL;
+ }
+
+ dmah->dmaaddr = h->seg.ds_addr;
+#endif
+
+ return dmah;
}
/**
* \brief Free a DMA-accessible consistent memory block.
*/
void
-drm_pci_free(drm_device_t *dev, size_t size, void *vaddr, dma_addr_t busaddr)
+drm_pci_free(drm_device_t *dev, drm_dma_handle_t *dmah)
{
-#if __FreeBSD_version > 500000
- if (vaddr == NULL)
+ if (dmah == NULL)
return;
- contigfree(vaddr, size, M_DRM); /* Not available on 4.x */
+
+#if defined(__FreeBSD__)
+ bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map);
+ bus_dma_tag_destroy(dmah->tag);
+#elif defined(__NetBSD__)
+ bus_dmamem_free(dev->dma_tag, &dmah->seg, 1);
#endif
+
+ free(dmah, M_DRM);
}
/*@}*/
diff --git a/bsd-core/drm_scatter.c b/bsd-core/drm_scatter.c
index 107905af..c26a3802 100644
--- a/bsd-core/drm_scatter.c
+++ b/bsd-core/drm_scatter.c
@@ -35,7 +35,7 @@
void drm_sg_cleanup(drm_sg_mem_t *entry)
{
- free(entry->virtual, M_DRM);
+ free((void *)entry->handle, M_DRM);
free(entry->busaddr, M_DRM);
free(entry, M_DRM);
}
@@ -46,6 +46,7 @@ int drm_sg_alloc(DRM_IOCTL_ARGS)
drm_scatter_gather_t request;
drm_sg_mem_t *entry;
unsigned long pages;
+ int i;
DRM_DEBUG( "%s\n", __FUNCTION__ );
@@ -71,16 +72,18 @@ int drm_sg_alloc(DRM_IOCTL_ARGS)
return ENOMEM;
}
- entry->virtual = malloc(pages << PAGE_SHIFT, M_DRM, M_WAITOK | M_ZERO);
- if ( !entry->virtual ) {
+ entry->handle = (long)malloc(pages << PAGE_SHIFT, M_DRM,
+ M_WAITOK | M_ZERO);
+ if (entry->handle == 0) {
drm_sg_cleanup(entry);
return ENOMEM;
}
- entry->handle = (unsigned long)entry->virtual;
+ for (i = 0; i < pages; i++) {
+ entry->busaddr[i] = vtophys(entry->handle + i * PAGE_SIZE);
+ }
DRM_DEBUG( "sg alloc handle = %08lx\n", entry->handle );
- DRM_DEBUG( "sg alloc virtual = %p\n", entry->virtual );
request.handle = entry->handle;
@@ -117,7 +120,7 @@ int drm_sg_free(DRM_IOCTL_ARGS)
if ( !entry || entry->handle != request.handle )
return EINVAL;
- DRM_DEBUG( "sg free virtual = %p\n", entry->virtual );
+ DRM_DEBUG( "sg free virtual = 0x%lx\n", entry->handle );
drm_sg_cleanup(entry);