summaryrefslogtreecommitdiff
path: root/sys/dev/ic/re.c
diff options
context:
space:
mode:
authorStuart Henderson <sthen@cvs.openbsd.org>2010-11-12 22:17:31 +0000
committerStuart Henderson <sthen@cvs.openbsd.org>2010-11-12 22:17:31 +0000
commita4b25181b366373237fce8135d5a46f63251346e (patch)
tree10a8ac820e2b57b299f825fed851fd64a5b83665 /sys/dev/ic/re.c
parented7f9f9073ff56b852d481e94e86acad136ed9ec (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.c94
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);
}