Bounce page fixes
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Sat, 17 Jan 2009 02:14:38 +0000 (10:14 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Tue, 17 Feb 2009 10:35:06 +0000 (18:35 +0800)
- Free accumulated bounce pages in the bus dma map if we could not
  reserved enough bounce pages.
- In bus_dmamap_load_mbuf(), if _bus_dmamap_load_buffer() returns
  ENOMEM on non-first mbuf fragment, we adjust the error to EFBIG:
  o  There is at least one bounce page available, so we could expect
     that after mbuf defragmentation, enough bounce pages (normally
     one bounce page for non-jumbo frame) may be available.
  o  Most callers defragment the mbuf chain only if error is EFBIG.

sys/platform/pc32/i386/busdma_machdep.c

index ce8a7c1..e82ff36 100644 (file)
@@ -555,7 +555,8 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dmat,
                if (flags & BUS_DMA_NOWAIT) {
                        if (reserve_bounce_pages(dmat, map, 0) != 0) {
                                BZ_UNLOCK(bz);
-                               return (ENOMEM);
+                               error = ENOMEM;
+                               goto free_bounce;
                        }
                } else {
                        if (reserve_bounce_pages(dmat, map, 1) != 0) {
@@ -668,6 +669,7 @@ fail:
        *segp = seg;
        *lastpaddrp = nextpaddr;
 
+free_bounce:
        if (error && (dmat->flags & BUS_DMA_COULD_BOUNCE) &&
            map != &nobounce_dmamap) {
                _bus_dmamap_unload(dmat, map);
@@ -745,6 +747,14 @@ bus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map,
                                        m->m_data, m->m_len,
                                        NULL, flags, &lastaddr,
                                        &nsegs, first);
+                       if (error == ENOMEM && !first) {
+                               /*
+                                * Out of bounce pages due to too many
+                                * fragments in the mbuf chain; return
+                                * EFBIG instead.
+                                */
+                               error = EFBIG;
+                       }
                        first = 0;
                }
        } else {