Module Name: src Committed By: jakllsch Date: Sat Nov 19 17:01:38 UTC 2011
Modified Files: src/sys/dev/marvell: if_mvgbe.c Log Message: Add workaround for infrequently encountered DMA engine limitation. To generate a diff of this commit: cvs rdiff -u -r1.13 -r1.14 src/sys/dev/marvell/if_mvgbe.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/marvell/if_mvgbe.c diff -u src/sys/dev/marvell/if_mvgbe.c:1.13 src/sys/dev/marvell/if_mvgbe.c:1.14 --- src/sys/dev/marvell/if_mvgbe.c:1.13 Tue Sep 6 19:38:23 2011 +++ src/sys/dev/marvell/if_mvgbe.c Sat Nov 19 17:01:38 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: if_mvgbe.c,v 1.13 2011/09/06 19:38:23 rjs Exp $ */ +/* $NetBSD: if_mvgbe.c,v 1.14 2011/11/19 17:01:38 jakllsch Exp $ */ /* * Copyright (c) 2007, 2008 KIYOHARA Takashi * All rights reserved. @@ -25,7 +25,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_mvgbe.c,v 1.13 2011/09/06 19:38:23 rjs Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_mvgbe.c,v 1.14 2011/11/19 17:01:38 jakllsch Exp $"); #include "rnd.h" @@ -1517,6 +1517,7 @@ mvgbe_encap(struct mvgbe_softc *sc, stru bus_dmamap_t txmap; uint32_t first, current, last, cmdsts = 0; int m_csumflags, i; + bool needs_defrag = false; DPRINTFN(3, ("mvgbe_encap\n")); @@ -1535,6 +1536,16 @@ mvgbe_encap(struct mvgbe_softc *sc, stru */ m_csumflags = m_head->m_pkthdr.csum_flags; +do_defrag: + if (__predict_false(needs_defrag == true)) { + /* A small unaligned segment was detected. */ + struct mbuf *m_new; + m_new = m_defrag(m_head, M_DONTWAIT); + if (m_new == NULL) + return EFBIG; + m_head = m_new; + } + /* * Start packing the mbufs in this chain into * the fragment pointers. Stop when we run out @@ -1545,6 +1556,25 @@ mvgbe_encap(struct mvgbe_softc *sc, stru return ENOBUFS; } + txseg = txmap->dm_segs; + + if (__predict_true(needs_defrag == false)) { + /* + * Detect rarely encountered DMA limitation. + */ + for (i = 0; i < txmap->dm_nsegs; i++) { + if (((txseg[i].ds_addr & 7) != 0) && + (txseg[i].ds_len <= 8) && + (txseg[i].ds_len >= 1) + ) { + txseg = NULL; + bus_dmamap_unload(sc->sc_dmat, txmap); + needs_defrag = true; + goto do_defrag; + } + } + } + /* Sync the DMA map. */ bus_dmamap_sync(sc->sc_dmat, txmap, 0, txmap->dm_mapsize, BUS_DMASYNC_PREWRITE); @@ -1556,7 +1586,6 @@ mvgbe_encap(struct mvgbe_softc *sc, stru return ENOBUFS; } - txseg = txmap->dm_segs; DPRINTFN(2, ("mvgbe_encap: dm_nsegs=%d\n", txmap->dm_nsegs));