summaryrefslogtreecommitdiff
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
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@
-rw-r--r--sys/dev/ic/re.c94
-rw-r--r--sys/dev/ic/rtl81x9reg.h4
2 files changed, 54 insertions, 44 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);
}
diff --git a/sys/dev/ic/rtl81x9reg.h b/sys/dev/ic/rtl81x9reg.h
index 0902e84fc79..ec140f01054 100644
--- a/sys/dev/ic/rtl81x9reg.h
+++ b/sys/dev/ic/rtl81x9reg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtl81x9reg.h,v 1.70 2010/09/07 16:21:43 deraadt Exp $ */
+/* $OpenBSD: rtl81x9reg.h,v 1.71 2010/11/12 22:17:30 sthen Exp $ */
/*
* Copyright (c) 1997, 1998
@@ -787,9 +787,7 @@ struct rl_list_data {
struct rl_rxsoft rl_rxsoft[RL_RX_DESC_CNT];
bus_dmamap_t rl_rx_list_map;
struct rl_desc *rl_rx_list;
- int rl_rx_considx;
int rl_rx_prodidx;
- int rl_rx_cnt;
bus_dma_segment_t rl_rx_listseg;
int rl_rx_listnseg;
};