Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 3 Aug 2012 13:50:29 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r239008 - in head/sys: powerpc/powerpc x86/x86
Message-ID:  <201208031350.q73DoT8v029267@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Fri Aug  3 13:50:29 2012
New Revision: 239008
URL: http://svn.freebsd.org/changeset/base/239008

Log:
  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

Modified:
  head/sys/powerpc/powerpc/busdma_machdep.c
  head/sys/x86/x86/busdma_machdep.c

Modified: head/sys/powerpc/powerpc/busdma_machdep.c
==============================================================================
--- head/sys/powerpc/powerpc/busdma_machdep.c	Fri Aug  3 12:55:31 2012	(r239007)
+++ head/sys/powerpc/powerpc/busdma_machdep.c	Fri Aug  3 13:50:29 2012	(r239008)
@@ -46,6 +46,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>
 
@@ -130,6 +132,7 @@ struct bus_dmamap {
 	bus_dmamap_callback_t *callback;
 	void		      *callback_arg;
 	STAILQ_ENTRY(bus_dmamap) links;
+	int		       contigalloc;
 };
 
 static STAILQ_HEAD(, bus_dmamap) bounce_map_waitinglist;
@@ -489,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)
@@ -500,6 +504,12 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, voi
 
 	if (flags & BUS_DMA_ZERO)
 		mflags |= M_ZERO;
+#ifdef NOTYET
+	if (flags & BUS_DMA_NOCACHE)
+		attr = VM_MEMATTR_UNCACHEABLE;
+	else
+#endif
+		attr = VM_MEMATTR_DEFAULT;
 
 	/* 
 	 * XXX:
@@ -511,7 +521,8 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, voi
 	 */
 	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 {
 		/*
@@ -520,9 +531,10 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, voi
 		 *     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)->contigalloc = 1;
 	}
 	if (*vaddr == NULL) {
 		CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
@@ -531,11 +543,6 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, voi
 	} else if (vtophys(*vaddr) & (dmat->alignment - 1)) {
 		printf("bus_dmamem_alloc failed to align memory properly.\n");
 	}
-#ifdef NOTYET
-	if (flags & BUS_DMA_NOCACHE)
-		pmap_change_attr((vm_offset_t)*vaddr, dmat->maxsize,
-		    VM_MEMATTR_UNCACHEABLE);
-#endif
 	CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
 	    __func__, dmat, dmat->flags, 0);
 	return (0);
@@ -548,18 +555,12 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, voi
 void
 bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map)
 {
-	bus_dmamap_destroy(dmat, map);
 
-#ifdef NOTYET
-	pmap_change_attr((vm_offset_t)vaddr, dmat->maxsize, VM_MEMATTR_DEFAULT);
-#endif
-	if ((dmat->maxsize <= PAGE_SIZE) &&
-	   (dmat->alignment < dmat->maxsize) &&
-	    dmat->lowaddr >= ptoa((vm_paddr_t)Maxmem))
+	if (!map->contigalloc)
 		free(vaddr, M_DEVBUF);
-	else {
-		contigfree(vaddr, dmat->maxsize, M_DEVBUF);
-	}
+	else
+		kmem_free(kernel_map, (vm_offset_t)vaddr, dmat->maxsize);
+	bus_dmamap_destroy(dmat, map);
 	CTR3(KTR_BUSDMA, "%s: tag %p flags 0x%x", __func__, dmat, dmat->flags);
 }
 

Modified: head/sys/x86/x86/busdma_machdep.c
==============================================================================
--- head/sys/x86/x86/busdma_machdep.c	Fri Aug  3 12:55:31 2012	(r239007)
+++ head/sys/x86/x86/busdma_machdep.c	Fri Aug  3 13:50:29 2012	(r239008)
@@ -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, in
 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, voi
 	}
 	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, voi
 	 */
 	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, voi
 		 *     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, voi
 	} 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
 {
 	/*
 	 * 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 dm
 	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_
 	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;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201208031350.q73DoT8v029267>