busdma: Panic if the kmalloc_powerof2() fails to meet the dma requirement
[dragonfly.git] / sys / platform / pc32 / i386 / busdma_machdep.c
index 7d3708f..ae451fb 100644 (file)
@@ -24,7 +24,6 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/i386/busdma_machdep.c,v 1.94 2008/08/15 20:51:31 kmacy Exp $
- * $DragonFly: src/sys/platform/pc32/i386/busdma_machdep.c,v 1.23 2008/06/05 18:06:32 swildner Exp $
  */
 
 #include <sys/param.h>
@@ -260,11 +259,11 @@ bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
        if (alignment == 0)
                alignment = 1;
        if (alignment & (alignment - 1))
-               panic("alignment must be power of 2\n");
+               panic("alignment must be power of 2");
 
        if (boundary != 0) {
                if (boundary & (boundary - 1))
-                       panic("boundary must be power of 2\n");
+                       panic("boundary must be power of 2");
                if (boundary < maxsegsz) {
                        kprintf("boundary < maxsegsz:\n");
                        print_backtrace(-1);
@@ -512,17 +511,17 @@ check_kmalloc(bus_dma_tag_t dmat, const void *vaddr0, int verify)
        uintptr_t vaddr = (uintptr_t)vaddr0;
 
        if ((vaddr ^ (vaddr + dmat->maxsize - 1)) & ~PAGE_MASK) {
-               if (verify || bootverbose)
-                       kprintf("boundary check failed\n");
                if (verify)
-                       print_backtrace(-1); /* XXX panic */
+                       panic("boundary check failed\n");
+               if (bootverbose)
+                       kprintf("boundary check failed\n");
                maxsize = dmat->maxsize;
        }
        if (vaddr & (dmat->alignment - 1)) {
-               if (verify || bootverbose)
-                       kprintf("alignment check failed\n");
                if (verify)
-                       print_backtrace(-1); /* XXX panic */
+                       panic("alignment check failed\n");
+               if (bootverbose)
+                       kprintf("alignment check failed\n");
                if (dmat->maxsize < dmat->alignment)
                        maxsize = dmat->alignment;
                else
@@ -574,13 +573,8 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, void **vaddr, int flags,
                 */
                maxsize = check_kmalloc(dmat, *vaddr, 0);
                if (maxsize) {
-                       size_t size;
-
                        kfree(*vaddr, M_DEVBUF);
-                       /* XXX check for overflow? */
-                       for (size = 1; size <= maxsize; size <<= 1)
-                               ;
-                       *vaddr = kmalloc(size, M_DEVBUF, mflags);
+                       *vaddr = kmalloc_powerof2(maxsize, M_DEVBUF, mflags);
                        check_kmalloc(dmat, *vaddr, 1);
                }
        } else {
@@ -609,7 +603,7 @@ bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map)
         * NULL
         */
        if (map != NULL)
-               panic("bus_dmamem_free: Invalid map freed\n");
+               panic("bus_dmamem_free: Invalid map freed");
        if (BUS_DMAMEM_KMALLOC(dmat))
                kfree(vaddr, M_DEVBUF);
        else
@@ -677,7 +671,7 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dmat,
                        paddr = _bus_dma_extract(pmap, vaddr);
                        if (run_filter(dmat, paddr) != 0)
                                map->pagesneeded++;
-                       vaddr += (PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK));
+                       vaddr += (PAGE_SIZE - (vaddr & PAGE_MASK));
                }
        }
 
@@ -849,7 +843,7 @@ bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
                         (BUS_DMA_PRIVBZONE | BUS_DMA_ALLOCALL));
 
                if (dmat->flags & BUS_DMA_PROTECTED)
-                       panic("protected dmamap callback will be defered\n");
+                       panic("protected dmamap callback will be defered");
 
                bus_dma_tag_unlock(dmat);
                return error;
@@ -905,12 +899,12 @@ bus_dmamap_load_mbuf_segment(bus_dma_tag_t dmat, bus_dmamap_t map,
 
        M_ASSERTPKTHDR(m0);
 
-       KASSERT(maxsegs >= 1, ("invalid maxsegs %d\n", maxsegs));
+       KASSERT(maxsegs >= 1, ("invalid maxsegs %d", maxsegs));
        KASSERT(maxsegs <= dmat->nsegments,
-               ("%d too many segments, dmat only support %d segments\n",
+               ("%d too many segments, dmat only supports %d segments",
                 maxsegs, dmat->nsegments));
        KASSERT(flags & BUS_DMA_NOWAIT,
-               ("only BUS_DMA_NOWAIT is supported\n"));
+               ("only BUS_DMA_NOWAIT is supported"));
 
        if (m0->m_pkthdr.len <= dmat->maxsize) {
                int first = 1;
@@ -1104,7 +1098,7 @@ alloc_bounce_zone(bus_dma_tag_t dmat)
        struct bounce_zone *bz, *new_bz;
 
        KASSERT(dmat->bounce_zone == NULL,
-               ("bounce zone was already assigned\n"));
+               ("bounce zone was already assigned"));
 
        new_bz = kmalloc(sizeof(*new_bz), M_DEVBUF, M_INTWAIT | M_ZERO);
 
@@ -1259,8 +1253,10 @@ free_bounce_pages_all(bus_dma_tag_t dmat)
                KKASSERT(bz->free_bpages > 0);
                bz->free_bpages--;
 
+               BZ_UNLOCK(bz);
                contigfree((void *)bpage->vaddr, PAGE_SIZE, M_DEVBUF);
                kfree(bpage, M_DEVBUF);
+               BZ_LOCK(bz);
        }
        if (bz->total_bpages) {
                kprintf("#%d bounce pages are still in use\n",
@@ -1370,6 +1366,11 @@ add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, vm_offset_t vaddr,
 
        BZ_UNLOCK(bz);
 
+       if (dmat->flags & BUS_DMA_KEEP_PG_OFFSET) {
+               /* Page offset needs to be preserved. */
+               bpage->vaddr |= vaddr & PAGE_MASK;
+               bpage->busaddr |= vaddr & PAGE_MASK;
+       }
        bpage->datavaddr = vaddr;
        bpage->datacount = size;
        STAILQ_INSERT_TAIL(&map->bpages, bpage, links);
@@ -1385,6 +1386,16 @@ free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage)
        bpage->datavaddr = 0;
        bpage->datacount = 0;
 
+       if (dmat->flags & BUS_DMA_KEEP_PG_OFFSET) {
+               /*
+                * Reset the bounce page to start at offset 0.  Other uses
+                * of this bounce page may need to store a full page of
+                * data and/or assume it starts on a page boundary.
+                */
+               bpage->vaddr &= ~PAGE_MASK;
+               bpage->busaddr &= ~PAGE_MASK;
+       }
+
        BZ_LOCK(bz);
 
        STAILQ_INSERT_HEAD(&bz->bounce_page_list, bpage, links);