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>