Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 2 Mar 2008 23:20:28 GMT
From:      Andrew Thompson <thompsa@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 136701 for review
Message-ID:  <200803022320.m22NKSW5046748@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=136701

Change 136701 by thompsa@thompsa_heff on 2008/03/02 23:20:12

	MF //depot/user/benjsc/wpi/sys/dev/wpi/if_wpi.c@131137
	
	Perform memory allocation differently in contig_alloc, fix bug in
	config_free.

Affected files ...

.. //depot/projects/wifi/sys/dev/wpi/if_wpi.c#12 edit
.. //depot/projects/wifi/sys/dev/wpi/if_wpivar.h#3 edit

Differences ...

==== //depot/projects/wifi/sys/dev/wpi/if_wpi.c#12 (text+ko) ====

@@ -16,7 +16,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#define VERSION "20071127"
+#define VERSION "20071218-p4"
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/sys/dev/wpi/if_wpi.c,v 1.8 2008/02/01 19:36:25 phk Exp $");
@@ -832,31 +832,46 @@
 	*(bus_addr_t *)arg = segs[0].ds_addr;
 }
 
+/*
+ * Allocates a contiguous block of dma memory of the requested size and
+ * alignment. Due to limitations of the FreeBSD dma subsystem as of 20071217,
+ * allocations greater than 4096 may fail. Hence if the requested alignment is
+ * greater we allocate 'alignment' size extra memory and shift the vaddr and
+ * paddr after the dma load. This bypasses the problem at the cost of a little
+ * more memory.
+ */
 static int
 wpi_dma_contig_alloc(struct wpi_softc *sc, struct wpi_dma_info *dma,
     void **kvap, bus_size_t size, bus_size_t alignment, int flags)
 {
 	int error;
-	int count = 0;
+	bus_size_t align;
+	bus_size_t reqsize;
 
 	DPRINTFN(WPI_DEBUG_DMA,
-	    ("Size: %zd - alignement %zd\n", size, alignment));
+	    ("Size: %zd - alignment %zd\n", size, alignment));
 
 	dma->size = size;
 	dma->tag = NULL;
 
-again:
-	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), alignment,
+	if (alignment > 4096) {
+		align = PAGE_SIZE;
+		reqsize = size + alignment;
+	} else {
+		align = alignment;
+		reqsize = size;
+	}
+	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), align,
 	    0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
-	    NULL, NULL, size,
-	    1, size, flags,
+	    NULL, NULL, reqsize,
+	    1, reqsize, flags,
 	    NULL, NULL, &dma->tag);
 	if (error != 0) {
 		device_printf(sc->sc_dev,
 		    "could not create shared page DMA tag\n");
 		goto fail;
 	}
-	error = bus_dmamem_alloc(dma->tag, (void **)&dma->vaddr,
+	error = bus_dmamem_alloc(dma->tag, (void **)&dma->vaddr_start,
 	    flags | BUS_DMA_ZERO, &dma->map);
 	if (error != 0) {
 		device_printf(sc->sc_dev,
@@ -864,31 +879,34 @@
 		goto fail;
 	}
 
-	/**
-	 * Sadly FreeBSD can't always align on a 16k boundary, hence we give it
-	 * 10 attempts increasing the size of the allocation by 4k each time.
-	 * This should eventually align us on a 16k boundary at the cost
-	 * of chewing up dma memory
+	error = bus_dmamap_load(dma->tag, dma->map, dma->vaddr_start,
+	    reqsize,  wpi_dma_map_addr, &dma->paddr_start, flags);
+
+	/* Save the original pointers so we can free all the memory */
+	dma->paddr = dma->paddr_start;
+	dma->vaddr = dma->vaddr_start;
+
+	/*
+	 * Check the alignment and increment by 4096 until we get the
+	 * requested alignment. Fail if can't obtain the alignment
+	 * we requested.
 	 */
-	if ((((uintptr_t)dma->vaddr) & (alignment-1)) && count < 10) {
-		DPRINTFN(WPI_DEBUG_DMA,
-		    ("Memory Unaligned, trying again: %d\n", count++));
-		wpi_dma_contig_free(dma);
-		size += 4096;
-		goto again;
-	}
+	if ((dma->paddr & (alignment -1 )) != 0) {
+		int i;
 
-	DPRINTFN(WPI_DEBUG_DMA,("Memory, allocated & %s Aligned!\n",
-		    count == 10 ? "FAILED" : ""));
-	if (count == 10) {
-		device_printf(sc->sc_dev, "Unable to align memory\n");
-		error = ENOMEM;
-		goto fail;
+		for (i = 0; i < alignment / 4096; i++) {
+			if ((dma->paddr & (alignment - 1 )) == 0)
+				break;
+			dma->paddr += 4096;
+			dma->vaddr += 4096;
+		}
+		if (i == alignment / 4096) {
+			device_printf(sc->sc_dev,
+			    "alignment requirement was not satisfied\n");
+			goto fail;
+		}
 	}
 
-	error = bus_dmamap_load(dma->tag, dma->map, dma->vaddr,
-	    size,  wpi_dma_map_addr, &dma->paddr, flags);
-
 	if (error != 0) {
 		device_printf(sc->sc_dev,
 		    "could not load shared page DMA map\n");
@@ -910,12 +928,12 @@
 {
 	if (dma->tag) {
 		if (dma->map != NULL) {
-			if (dma->paddr == 0) {
+			if (dma->paddr_start != 0) {
 				bus_dmamap_sync(dma->tag, dma->map,
 				    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 				bus_dmamap_unload(dma->tag, dma->map);
 			}
-			bus_dmamem_free(dma->tag, &dma->vaddr, dma->map);
+			bus_dmamem_free(dma->tag, &dma->vaddr_start, dma->map);
 		}
 		bus_dma_tag_destroy(dma->tag);
 	}

==== //depot/projects/wifi/sys/dev/wpi/if_wpivar.h#3 (text+ko) ====

@@ -62,8 +62,10 @@
 struct wpi_dma_info {
 	bus_dma_tag_t		tag;
 	bus_dmamap_t            map;
-	bus_addr_t		paddr;
-	caddr_t			vaddr;
+	bus_addr_t		paddr;	      /* aligned p address */
+	bus_addr_t		paddr_start;  /* possibly unaligned p start*/
+	caddr_t			vaddr;	      /* aligned v address */
+	caddr_t			vaddr_start;  /* possibly unaligned v start */
 	bus_size_t		size;
 };
 



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