PERFORCE change 136701 for review
Andrew Thompson
thompsa at FreeBSD.org
Sun Mar 2 23:20:29 UTC 2008
http://perforce.freebsd.org/chv.cgi?CH=136701
Change 136701 by thompsa at thompsa_heff on 2008/03/02 23:20:12
MF //depot/user/benjsc/wpi/sys/dev/wpi/if_wpi.c at 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;
};
More information about the p4-projects
mailing list