diff options
author | Eric Anholt <anholt@freebsd.org> | 2005-04-26 05:19:11 +0000 |
---|---|---|
committer | Eric Anholt <anholt@freebsd.org> | 2005-04-26 05:19:11 +0000 |
commit | ec111d70fee0647c4c68a02c723d4a3729c93b56 (patch) | |
tree | 114a3257310a979d3dea484af62322ba007bf1e0 /bsd-core/drm_pci.c | |
parent | 31a06d0baca9e378a773ca8bd350860546dd8a79 (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/drm_pci.c')
-rw-r--r-- | bsd-core/drm_pci.c | 93 |
1 files changed, 80 insertions, 13 deletions
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); } /*@}*/ |