From ec111d70fee0647c4c68a02c723d4a3729c93b56 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 26 Apr 2005 05:19:11 +0000 Subject: 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 --- bsd-core/ati_pcigart.c | 72 ++++++++++++++------------------------ bsd-core/drmP.h | 24 +++++++++---- bsd-core/drm_bufs.c | 45 ++++++++++-------------- bsd-core/drm_dma.c | 5 +-- bsd-core/drm_pci.c | 93 +++++++++++++++++++++++++++++++++++++++++++------- bsd-core/drm_scatter.c | 15 ++++---- 6 files changed, 151 insertions(+), 103 deletions(-) (limited to 'bsd-core') 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); -- cgit v1.2.3