diff options
author | jhb <jhb@FreeBSD.org> | 2012-08-03 13:50:29 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2012-08-03 13:50:29 +0000 |
commit | f9289f9fa2c7c57477d2badf22ce93fa88d40980 (patch) | |
tree | 0def93a0647d8081690c1b834995b33f80c45d5e /sys/x86 | |
parent | 10741a6f2e055da1e3257fa5200824b2204cca4d (diff) | |
download | FreeBSD-src-f9289f9fa2c7c57477d2badf22ce93fa88d40980.zip FreeBSD-src-f9289f9fa2c7c57477d2badf22ce93fa88d40980.tar.gz |
Improve the handling of static DMA buffers that use non-default memory
attributes (currently just BUS_DMA_NOCACHE):
- Don't call pmap_change_attr() on the returned address, instead use
kmem_alloc_contig() to ask the VM system for memory with the requested
attribute.
- As a result, always use kmem_alloc_contig() for non-default memory
attributes, even for sub-page allocations. This requires adjusting
bus_dmamem_free()'s logic for determining which free routine to use.
- For x86, add a new dummy bus_dmamap that is used for static DMA
buffers allocated via kmem_alloc_contig(). bus_dmamem_free() can then
use the map pointer to determine which free routine to use.
- For powerpc, add a new flag to the allocated map (bus_dmamem_alloc()
always creates a real map on powerpc) to indicate which free routine
should be used.
Note that the BUS_DMA_NOCACHE handling in powerpc is currently #ifdef'd out.
I have left it disabled but updated it to match x86.
Reviewed by: scottl
MFC after: 1 month
Diffstat (limited to 'sys/x86')
-rw-r--r-- | sys/x86/x86/busdma_machdep.c | 43 |
1 files changed, 23 insertions, 20 deletions
diff --git a/sys/x86/x86/busdma_machdep.c b/sys/x86/x86/busdma_machdep.c index 76d4926..8735b15 100644 --- a/sys/x86/x86/busdma_machdep.c +++ b/sys/x86/x86/busdma_machdep.c @@ -42,6 +42,8 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <vm/vm.h> +#include <vm/vm_extern.h> +#include <vm/vm_kern.h> #include <vm/vm_page.h> #include <vm/vm_map.h> @@ -131,7 +133,7 @@ struct bus_dmamap { static STAILQ_HEAD(, bus_dmamap) bounce_map_waitinglist; static STAILQ_HEAD(, bus_dmamap) bounce_map_callbacklist; -static struct bus_dmamap nobounce_dmamap; +static struct bus_dmamap nobounce_dmamap, contig_dmamap; static void init_bounce_pages(void *dummy); static int alloc_bounce_zone(bus_dma_tag_t dmat); @@ -465,7 +467,7 @@ bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp) int bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map) { - if (map != NULL && map != &nobounce_dmamap) { + if (map != NULL && map != &nobounce_dmamap && map != &contig_dmamap) { if (STAILQ_FIRST(&map->bpages) != NULL) { CTR3(KTR_BUSDMA, "%s: tag %p error %d", __func__, dmat, EBUSY); @@ -490,6 +492,7 @@ int bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags, bus_dmamap_t *mapp) { + vm_memattr_t attr; int mflags; if (flags & BUS_DMA_NOWAIT) @@ -512,6 +515,10 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags, } if (flags & BUS_DMA_ZERO) mflags |= M_ZERO; + if (flags & BUS_DMA_NOCACHE) + attr = VM_MEMATTR_UNCACHEABLE; + else + attr = VM_MEMATTR_DEFAULT; /* * XXX: @@ -523,7 +530,8 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags, */ if ((dmat->maxsize <= PAGE_SIZE) && (dmat->alignment < dmat->maxsize) && - dmat->lowaddr >= ptoa((vm_paddr_t)Maxmem)) { + dmat->lowaddr >= ptoa((vm_paddr_t)Maxmem) && + attr == VM_MEMATTR_DEFAULT) { *vaddr = malloc(dmat->maxsize, M_DEVBUF, mflags); } else { /* @@ -532,9 +540,10 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags, * multi-seg allocations yet though. * XXX Certain AGP hardware does. */ - *vaddr = contigmalloc(dmat->maxsize, M_DEVBUF, mflags, - 0ul, dmat->lowaddr, dmat->alignment? dmat->alignment : 1ul, - dmat->boundary); + *vaddr = (void *)kmem_alloc_contig(kernel_map, dmat->maxsize, + mflags, 0ul, dmat->lowaddr, dmat->alignment ? + dmat->alignment : 1ul, dmat->boundary, attr); + *mapp = &contig_dmamap; } if (*vaddr == NULL) { CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", @@ -543,9 +552,6 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags, } else if (vtophys(*vaddr) & (dmat->alignment - 1)) { printf("bus_dmamem_alloc failed to align memory properly.\n"); } - if (flags & BUS_DMA_NOCACHE) - pmap_change_attr((vm_offset_t)*vaddr, dmat->maxsize, - PAT_UNCACHEABLE); CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", __func__, dmat, dmat->flags, 0); return (0); @@ -560,18 +566,15 @@ bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map) { /* * dmamem does not need to be bounced, so the map should be - * NULL + * NULL if malloc() was used and contig_dmamap if + * contigmalloc() was used. */ - if (map != NULL) + if (!(map == NULL || map == &contig_dmamap)) panic("bus_dmamem_free: Invalid map freed\n"); - pmap_change_attr((vm_offset_t)vaddr, dmat->maxsize, PAT_WRITE_BACK); - if ((dmat->maxsize <= PAGE_SIZE) && - (dmat->alignment < dmat->maxsize) && - dmat->lowaddr >= ptoa((vm_paddr_t)Maxmem)) + if (map == NULL) free(vaddr, M_DEVBUF); - else { - contigfree(vaddr, dmat->maxsize, M_DEVBUF); - } + else + kmem_free(kernel_map, (vm_offset_t)vaddr, dmat->maxsize); CTR3(KTR_BUSDMA, "%s: tag %p flags 0x%x", __func__, dmat, dmat->flags); } @@ -662,7 +665,7 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dmat, vm_offset_t vaddr; int seg, error; - if (map == NULL) + if (map == NULL || map == &contig_dmamap) map = &nobounce_dmamap; if ((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) { @@ -1139,7 +1142,7 @@ add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, vm_offset_t vaddr, struct bounce_page *bpage; KASSERT(dmat->bounce_zone != NULL, ("no bounce zone in dma tag")); - KASSERT(map != NULL && map != &nobounce_dmamap, + KASSERT(map != NULL && map != &nobounce_dmamap && map != &contig_dmamap, ("add_bounce_page: bad map %p", map)); bz = dmat->bounce_zone; |