diff options
author | Kevin Lo <kevlo@cvs.openbsd.org> | 2011-09-13 08:12:52 +0000 |
---|---|---|
committer | Kevin Lo <kevlo@cvs.openbsd.org> | 2011-09-13 08:12:52 +0000 |
commit | 3937e18c70e0094571184a9e9f79629c3b25624e (patch) | |
tree | a855491eb41aa03e172108cfef2334332ff474e5 | |
parent | 6fbae48bb69bb3c93ca0701289e1ad7286f014ea (diff) |
Fix up alc_encap() / alc_start():
- Remove unnecessary nsegs variable from alc_encap() and
use map->dm_nsegs. Also remove unnecessary FreeBSD check
for 0 DMA segments check.
- Remove printfs in alc_encap() failure paths that shouldn't
be there.
- Add missing IF_PREPEND() from failure path coming off of
alc_encap() within alc_start().
- Fix error handling within alc_encap(). Previously alc_encap()
was attempting to unload a DMA map upon failure from
bus_dmamap_load_mbuf() even though one wasn't loaded at that
point and then always forcing mbufs through the EFBIG path.
Tested by Gabriel Linder.
From Brad
-rw-r--r-- | sys/dev/pci/if_alc.c | 57 |
1 files changed, 23 insertions, 34 deletions
diff --git a/sys/dev/pci/if_alc.c b/sys/dev/pci/if_alc.c index e8ecac8e3ce..3d4f834a4a2 100644 --- a/sys/dev/pci/if_alc.c +++ b/sys/dev/pci/if_alc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_alc.c,v 1.18 2011/09/03 14:33:51 kevlo Exp $ */ +/* $OpenBSD: if_alc.c,v 1.19 2011/09/13 08:12:51 kevlo Exp $ */ /*- * Copyright (c) 2009, Pyun YongHyeon <yongari@FreeBSD.org> * All rights reserved. @@ -1283,7 +1283,7 @@ alc_encap(struct alc_softc *sc, struct mbuf **m_head) struct mbuf *m; bus_dmamap_t map; uint32_t cflags, poff, vtag; - int error, idx, nsegs, prod; + int error, idx, prod; m = *m_head; cflags = vtag = 0; @@ -1295,46 +1295,25 @@ alc_encap(struct alc_softc *sc, struct mbuf **m_head) map = txd->tx_dmamap; error = bus_dmamap_load_mbuf(sc->sc_dmat, map, *m_head, BUS_DMA_NOWAIT); - + if (error != 0 && error != EFBIG) + goto drop; if (error != 0) { - bus_dmamap_unload(sc->sc_dmat, map); - error = EFBIG; - } - if (error == EFBIG) { if (m_defrag(*m_head, M_DONTWAIT)) { - printf("%s: can't defrag TX mbuf\n", - sc->sc_dev.dv_xname); - m_freem(*m_head); - *m_head = NULL; - return (ENOBUFS); + error = ENOBUFS; + goto drop; } error = bus_dmamap_load_mbuf(sc->sc_dmat, map, *m_head, BUS_DMA_NOWAIT); - if (error != 0) { - printf("%s: could not load defragged TX mbuf\n", - sc->sc_dev.dv_xname); - m_freem(*m_head); - *m_head = NULL; - return (error); - } - } else if (error) { - printf("%s: could not load TX mbuf\n", sc->sc_dev.dv_xname); - return (error); - } - - nsegs = map->dm_nsegs; - - if (nsegs == 0) { - m_freem(*m_head); - *m_head = NULL; - return (EIO); + if (error != 0) + goto drop; } /* Check descriptor overrun. */ - if (sc->alc_cdata.alc_tx_cnt + nsegs >= ALC_TX_RING_CNT - 3) { + if (sc->alc_cdata.alc_tx_cnt + map->dm_nsegs >= ALC_TX_RING_CNT - 3) { bus_dmamap_unload(sc->sc_dmat, map); return (ENOBUFS); } + bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, BUS_DMASYNC_PREWRITE); @@ -1355,8 +1334,9 @@ alc_encap(struct alc_softc *sc, struct mbuf **m_head) /* Set checksum start offset. */ cflags |= ((poff >> 1) << TD_PLOAD_OFFSET_SHIFT) & TD_PLOAD_OFFSET_MASK; - } - for (; idx < nsegs; idx++) { + } + + for (; idx < map->dm_nsegs; idx++) { desc = &sc->alc_rdata.alc_tx_ring[prod]; desc->len = htole32(TX_BYTES(map->dm_segs[idx].ds_len) | vtag); @@ -1365,6 +1345,7 @@ alc_encap(struct alc_softc *sc, struct mbuf **m_head) sc->alc_cdata.alc_tx_cnt++; ALC_DESC_INC(prod, ALC_TX_RING_CNT); } + /* Update producer index. */ sc->alc_cdata.alc_tx_prod = prod; @@ -1381,6 +1362,11 @@ alc_encap(struct alc_softc *sc, struct mbuf **m_head) txd->tx_m = m; return (0); + + drop: + m_freem(*m_head); + *m_head = NULL; + return (error); } void @@ -1412,8 +1398,11 @@ alc_start(struct ifnet *ifp) * for the NIC to drain the ring. */ if (alc_encap(sc, &m_head)) { - if (m_head == NULL) + if (m_head == NULL) { + ifp->if_oerrors++; break; + } + IF_PREPEND(&ifp->if_snd, m_head); ifp->if_flags |= IFF_OACTIVE; break; } |