This diff switches re(4) over to MCLGETI, bringing goodies like lower memory usage and livelock mitigation. Getting this right usually takes some effort. So please help me with getting this tested if you have any machines with re(4).
Thanks, Mark Index: re.c =================================================================== RCS file: /cvs/src/sys/dev/ic/re.c,v retrieving revision 1.112 diff -u -p -r1.112 re.c --- re.c 18 Jul 2009 13:21:32 -0000 1.112 +++ re.c 22 Jul 2009 21:14:18 -0000 @@ -162,8 +162,9 @@ static inline void re_set_bufaddr(struct int re_encap(struct rl_softc *, struct mbuf *, int *); -int re_newbuf(struct rl_softc *, int, struct mbuf *); +int re_newbuf(struct rl_softc *); 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 *); @@ -1099,6 +1100,8 @@ re_attach(struct rl_softc *sc, const cha 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; @@ -1201,28 +1204,24 @@ fail_0: int -re_newbuf(struct rl_softc *sc, int idx, struct mbuf *m) +re_newbuf(struct rl_softc *sc) { - struct mbuf *n = NULL; + struct mbuf *m; bus_dmamap_t map; struct rl_desc *d; struct rl_rxsoft *rxs; u_int32_t cmdstat; - int error; + int error, idx; - 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; + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) + return (ENOBUFS); + + MCLGETI(m, M_DONTWAIT, &sc->sc_arpcom.ac_if, MCLBYTES); + if ((m->m_flags & M_EXT) == 0) { + m_freem(m); + return (ENOBUFS); + } /* * Initialize mbuf length fields and fixup @@ -1232,13 +1231,15 @@ re_newbuf(struct rl_softc *sc, int idx, 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) - goto out; + if (error) { + m_freem(m); + return (ENOBUFS); + } bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, BUS_DMASYNC_PREREAD); @@ -1250,7 +1251,8 @@ re_newbuf(struct rl_softc *sc, int idx, if (cmdstat & RL_RDESC_STAT_OWN) { printf("%s: tried to map busy RX descriptor\n", sc->sc_dev.dv_xname); - goto out; + m_freem(m); + return (ENOBUFS); } rxs->rxs_mbuf = m; @@ -1266,11 +1268,10 @@ re_newbuf(struct rl_softc *sc, int idx, 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); } @@ -1299,21 +1300,27 @@ re_tx_list_init(struct rl_softc *sc) int re_rx_list_init(struct rl_softc *sc) { - 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); - } + bzero(sc->rl_ldata.rl_rx_list, RL_RX_LIST_SZ); 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 @@ -1331,7 +1338,8 @@ re_rxeof(struct rl_softc *sc) ifp = &sc->sc_arpcom.ac_if; - for (i = sc->rl_ldata.rl_rx_prodidx;; i = RL_NEXT_RX_DESC(sc, i)) { + for (i = sc->rl_ldata.rl_rx_considx; sc->rl_ldata.rl_rx_cnt > 0; + 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); @@ -1343,6 +1351,8 @@ 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 */ @@ -1361,7 +1371,6 @@ re_rxeof(struct rl_softc *sc) sc->rl_tail->m_next = m; sc->rl_tail = m; } - re_newbuf(sc, i, NULL); continue; } @@ -1399,22 +1408,6 @@ 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; } @@ -1492,7 +1485,8 @@ re_rxeof(struct rl_softc *sc) ether_input_mbuf(ifp, m); } - sc->rl_ldata.rl_rx_prodidx = i; + sc->rl_ldata.rl_rx_considx = i; + re_rx_list_fill(sc); return (rx); } Index: rtl81x9reg.h =================================================================== RCS file: /cvs/src/sys/dev/ic/rtl81x9reg.h,v retrieving revision 1.65 diff -u -p -r1.65 rtl81x9reg.h --- rtl81x9reg.h 11 Jul 2009 16:51:58 -0000 1.65 +++ rtl81x9reg.h 22 Jul 2009 21:14:19 -0000 @@ -785,7 +785,9 @@ 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; };