summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Lo <kevlo@cvs.openbsd.org>2011-09-13 08:12:52 +0000
committerKevin Lo <kevlo@cvs.openbsd.org>2011-09-13 08:12:52 +0000
commit3937e18c70e0094571184a9e9f79629c3b25624e (patch)
treea855491eb41aa03e172108cfef2334332ff474e5
parent6fbae48bb69bb3c93ca0701289e1ad7286f014ea (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.c57
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;
}