diff options
author | Stuart Henderson <sthen@cvs.openbsd.org> | 2010-11-12 22:17:31 +0000 |
---|---|---|
committer | Stuart Henderson <sthen@cvs.openbsd.org> | 2010-11-12 22:17:31 +0000 |
commit | a4b25181b366373237fce8135d5a46f63251346e (patch) | |
tree | 10a8ac820e2b57b299f825fed851fd64a5b83665 /sys/dev/ic/re.c | |
parent | ed7f9f9073ff56b852d481e94e86acad136ed9ec (diff) |
revert MCLGETI for re(4) for now, it is causing hangs (in some cases
temporary, in others apparently permanent) with high rates of input
packets.
ok deraadt@
Diffstat (limited to 'sys/dev/ic/re.c')
-rw-r--r-- | sys/dev/ic/re.c | 94 |
1 files changed, 53 insertions, 41 deletions
diff --git a/sys/dev/ic/re.c b/sys/dev/ic/re.c index 0fdd6260187..ca949d503ea 100644 --- a/sys/dev/ic/re.c +++ b/sys/dev/ic/re.c @@ -1,4 +1,4 @@ -/* $OpenBSD: re.c,v 1.129 2010/10/05 08:57:34 mikeb Exp $ */ +/* $OpenBSD: re.c,v 1.130 2010/11/12 22:17:30 sthen Exp $ */ /* $FreeBSD: if_re.c,v 1.31 2004/09/04 07:54:05 ru Exp $ */ /* * Copyright (c) 1997, 1998-2003 @@ -162,9 +162,8 @@ static inline void re_set_bufaddr(struct rl_desc *, bus_addr_t); int re_encap(struct rl_softc *, struct mbuf *, int *); -int re_newbuf(struct rl_softc *); +int re_newbuf(struct rl_softc *, int, struct mbuf *); int re_rx_list_init(struct rl_softc *); -void re_rx_list_fill(struct rl_softc *); int re_tx_list_init(struct rl_softc *); int re_rxeof(struct rl_softc *); int re_txeof(struct rl_softc *); @@ -1109,8 +1108,6 @@ re_attach(struct rl_softc *sc, const char *intrstr) IFQ_SET_MAXLEN(&ifp->if_snd, RL_TX_QLEN); IFQ_SET_READY(&ifp->if_snd); - m_clsetwms(ifp, MCLBYTES, 2, RL_RX_DESC_CNT); - ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4; @@ -1215,18 +1212,28 @@ fail_0: int -re_newbuf(struct rl_softc *sc) +re_newbuf(struct rl_softc *sc, int idx, struct mbuf *m) { - struct mbuf *m; + struct mbuf *n = NULL; bus_dmamap_t map; struct rl_desc *d; struct rl_rxsoft *rxs; u_int32_t cmdstat; - int error, idx; + int error; - m = MCLGETI(NULL, M_DONTWAIT, &sc->sc_arpcom.ac_if, MCLBYTES); - if (!m) - return (ENOBUFS); + if (m == NULL) { + MGETHDR(n, M_DONTWAIT, MT_DATA); + if (n == NULL) + return (ENOBUFS); + + MCLGET(n, M_DONTWAIT); + if (!(n->m_flags & M_EXT)) { + m_freem(n); + return (ENOBUFS); + } + m = n; + } else + m->m_data = m->m_ext.ext_buf; /* * Initialize mbuf length fields and fixup @@ -1236,15 +1243,13 @@ re_newbuf(struct rl_softc *sc) m->m_len = m->m_pkthdr.len = RE_RX_DESC_BUFLEN; m->m_data += RE_ETHER_ALIGN; - idx = sc->rl_ldata.rl_rx_prodidx; rxs = &sc->rl_ldata.rl_rxsoft[idx]; map = rxs->rxs_dmamap; error = bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_READ|BUS_DMA_NOWAIT); - if (error) { - m_freem(m); - return (ENOBUFS); - } + + if (error) + goto out; bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, BUS_DMASYNC_PREREAD); @@ -1256,8 +1261,7 @@ re_newbuf(struct rl_softc *sc) if (cmdstat & RL_RDESC_STAT_OWN) { printf("%s: tried to map busy RX descriptor\n", sc->sc_dev.dv_xname); - m_freem(m); - return (ENOBUFS); + goto out; } rxs->rxs_mbuf = m; @@ -1273,10 +1277,11 @@ re_newbuf(struct rl_softc *sc) d->rl_cmdstat = htole32(cmdstat); RL_RXDESCSYNC(sc, idx, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); - sc->rl_ldata.rl_rx_prodidx = RL_NEXT_RX_DESC(sc, idx); - sc->rl_ldata.rl_rx_cnt++; - return (0); + out: + if (n != NULL) + m_freem(n); + return (ENOMEM); } @@ -1305,27 +1310,21 @@ re_tx_list_init(struct rl_softc *sc) int re_rx_list_init(struct rl_softc *sc) { - bzero(sc->rl_ldata.rl_rx_list, RL_RX_LIST_SZ); + int i; + + memset((char *)sc->rl_ldata.rl_rx_list, 0, RL_RX_LIST_SZ); + + for (i = 0; i < RL_RX_DESC_CNT; i++) { + if (re_newbuf(sc, i, NULL) == ENOBUFS) + return (ENOBUFS); + } sc->rl_ldata.rl_rx_prodidx = 0; - sc->rl_ldata.rl_rx_considx = 0; - sc->rl_ldata.rl_rx_cnt = 0; sc->rl_head = sc->rl_tail = NULL; - re_rx_list_fill(sc); - return (0); } -void -re_rx_list_fill(struct rl_softc *sc) -{ - while (sc->rl_ldata.rl_rx_cnt < RL_RX_DESC_CNT) { - if (re_newbuf(sc) == ENOBUFS) - break; - } -} - /* * RX handler for C+ and 8169. For the gigE chips, we support * the reception of jumbo frames that have been fragmented @@ -1343,8 +1342,7 @@ re_rxeof(struct rl_softc *sc) ifp = &sc->sc_arpcom.ac_if; - for (i = sc->rl_ldata.rl_rx_considx; sc->rl_ldata.rl_rx_cnt > 0; - i = RL_NEXT_RX_DESC(sc, i)) { + for (i = sc->rl_ldata.rl_rx_prodidx;; i = RL_NEXT_RX_DESC(sc, i)) { cur_rx = &sc->rl_ldata.rl_rx_list[i]; RL_RXDESCSYNC(sc, i, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); @@ -1356,8 +1354,6 @@ re_rxeof(struct rl_softc *sc) total_len = rxstat & sc->rl_rxlenmask; rxs = &sc->rl_ldata.rl_rxsoft[i]; m = rxs->rxs_mbuf; - rxs->rxs_mbuf = NULL; - sc->rl_ldata.rl_rx_cnt--; rx = 1; /* Invalidate the RX mbuf and unload its map */ @@ -1376,6 +1372,7 @@ re_rxeof(struct rl_softc *sc) sc->rl_tail->m_next = m; sc->rl_tail = m; } + re_newbuf(sc, i, NULL); continue; } @@ -1413,6 +1410,22 @@ re_rxeof(struct rl_softc *sc) m_freem(sc->rl_head); sc->rl_head = sc->rl_tail = NULL; } + re_newbuf(sc, i, m); + continue; + } + + /* + * If allocating a replacement mbuf fails, + * reload the current one. + */ + + if (re_newbuf(sc, i, NULL)) { + ifp->if_ierrors++; + if (sc->rl_head != NULL) { + m_freem(sc->rl_head); + sc->rl_head = sc->rl_tail = NULL; + } + re_newbuf(sc, i, m); continue; } @@ -1490,8 +1503,7 @@ re_rxeof(struct rl_softc *sc) ether_input_mbuf(ifp, m); } - sc->rl_ldata.rl_rx_considx = i; - re_rx_list_fill(sc); + sc->rl_ldata.rl_rx_prodidx = i; return (rx); } |