Hi, with further encouragement, I decided to give tl(4) a try. It's a very interesting ethernet chip, and even under heavy tcpbench the mbuf usage is at most 6. As usual, feedback and comments are welcomed.
//Logan C-x-C-c Index: src/sys/dev/pci/if_tl.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_tl.c,v retrieving revision 1.50 diff -u -p -r1.50 if_tl.c --- src/sys/dev/pci/if_tl.c 19 May 2010 15:27:35 -0000 1.50 +++ src/sys/dev/pci/if_tl.c 14 Dec 2010 19:15:28 -0000 @@ -252,8 +252,8 @@ int tl_intvec_rxeof(void *, u_int32_t); int tl_intvec_adchk(void *, u_int32_t); int tl_intvec_netsts(void *, u_int32_t); -int tl_newbuf(struct tl_softc *, - struct tl_chain_onefrag *); +int tl_newbuf(struct tl_softc *, struct tl_chain_onefrag *); +void tl_fill_rx_ring(struct tl_softc *); void tl_stats_update(void *); int tl_encap(struct tl_softc *, struct tl_chain *, struct mbuf *); @@ -1034,8 +1034,6 @@ int tl_list_rx_init(sc) for (i = 0; i < TL_RX_LIST_CNT; i++) { cd->tl_rx_chain[i].tl_ptr = (struct tl_list_onefrag *)&ld->tl_rx_list[i]; - if (tl_newbuf(sc, &cd->tl_rx_chain[i]) == ENOBUFS) - return(ENOBUFS); if (i == (TL_RX_LIST_CNT - 1)) { cd->tl_rx_chain[i].tl_next = NULL; ld->tl_rx_list[i].tlist_fptr = 0; @@ -1047,34 +1045,45 @@ int tl_list_rx_init(sc) } cd->tl_rx_head = &cd->tl_rx_chain[0]; + cd->tl_rx_cons = &cd->tl_rx_chain[0]; cd->tl_rx_tail = &cd->tl_rx_chain[TL_RX_LIST_CNT - 1]; - + cd->tl_rx_cnt = 0; + tl_fill_rx_ring(sc); return(0); } +void tl_fill_rx_ring(sc) + struct tl_softc *sc; +{ + struct tl_list_data *ld; + struct tl_chain_data *cd; + + cd = &sc->tl_cdata; + ld = sc->tl_ldata; + + while (cd->tl_rx_cnt < TL_RX_LIST_CNT) { + if(tl_newbuf(sc, cd->tl_rx_head) == ENOBUFS) + break; + cd->tl_rx_head = cd->tl_rx_head->tl_next; + cd->tl_rx_cnt++; + } +} + int tl_newbuf(sc, c) struct tl_softc *sc; struct tl_chain_onefrag *c; { struct mbuf *m_new = NULL; - MGETHDR(m_new, M_DONTWAIT, MT_DATA); - if (m_new == NULL) { + m_new = MCLGETI(NULL, M_DONTWAIT, &sc->arpcom.ac_if, MCLBYTES); + if (!m_new) return(ENOBUFS); - } - - MCLGET(m_new, M_DONTWAIT); - if (!(m_new->m_flags & M_EXT)) { - m_freem(m_new); - return(ENOBUFS); - } #ifdef __alpha__ m_new->m_data += 2; #endif c->tl_mbuf = m_new; - c->tl_next = NULL; c->tl_ptr->tlist_frsize = MCLBYTES; c->tl_ptr->tlist_fptr = 0; c->tl_ptr->tl_frag.tlist_dadr = VTOPHYS(mtod(m_new, caddr_t)); @@ -1120,23 +1129,17 @@ int tl_intvec_rxeof(xsc, type) sc = xsc; ifp = &sc->arpcom.ac_if; - while(sc->tl_cdata.tl_rx_head != NULL) { - cur_rx = sc->tl_cdata.tl_rx_head; + while(sc->tl_cdata.tl_rx_cnt > 0) { + cur_rx = sc->tl_cdata.tl_rx_cons; if (!(cur_rx->tl_ptr->tlist_cstat & TL_CSTAT_FRAMECMP)) break; r++; - sc->tl_cdata.tl_rx_head = cur_rx->tl_next; + sc->tl_cdata.tl_rx_cons = cur_rx->tl_next; m = cur_rx->tl_mbuf; + cur_rx->tl_mbuf = NULL; + sc->tl_cdata.tl_rx_cnt--; total_len = cur_rx->tl_ptr->tlist_frsize; - if (tl_newbuf(sc, cur_rx) == ENOBUFS) { - ifp->if_ierrors++; - cur_rx->tl_ptr->tlist_frsize = MCLBYTES; - cur_rx->tl_ptr->tlist_cstat = TL_CSTAT_READY; - cur_rx->tl_ptr->tl_frag.tlist_dcnt = MCLBYTES; - continue; - } - sc->tl_cdata.tl_rx_tail->tl_ptr->tlist_fptr = VTOPHYS(cur_rx->tl_ptr); sc->tl_cdata.tl_rx_tail->tl_next = cur_rx; @@ -1175,7 +1178,7 @@ int tl_intvec_rxeof(xsc, type) /* pass it on. */ ether_input_mbuf(ifp, m); } - + tl_fill_rx_ring(sc); return(r); } @@ -1201,9 +1204,7 @@ int tl_intvec_rxeoc(xsc, type) r = tl_intvec_rxeof(xsc, type); CMD_PUT(sc, TL_CMD_ACK | r | (type & ~(0x00100000))); r = 1; - cd->tl_rx_head = &cd->tl_rx_chain[0]; - cd->tl_rx_tail = &cd->tl_rx_chain[TL_RX_LIST_CNT - 1]; - CSR_WRITE_4(sc, TL_CH_PARM, VTOPHYS(sc->tl_cdata.tl_rx_head->tl_ptr)); + CSR_WRITE_4(sc, TL_CH_PARM, VTOPHYS(sc->tl_cdata.tl_rx_cons->tl_ptr)); r |= (TL_CMD_GO|TL_CMD_RT); return(r); } @@ -2130,6 +2131,7 @@ tl_attach(parent, self, aux) ifp->if_baudrate = 10000000; IFQ_SET_MAXLEN(&ifp->if_snd, TL_TX_LIST_CNT - 1); IFQ_SET_READY(&ifp->if_snd); + m_clsetwms(ifp, MCLBYTES, 2, TL_RX_LIST_CNT - 1); bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); /* Index: src/sys/dev/pci/if_tlreg.h =================================================================== RCS file: /cvs/src/sys/dev/pci/if_tlreg.h,v retrieving revision 1.9 diff -u -p -r1.9 if_tlreg.h --- src/sys/dev/pci/if_tlreg.h 17 Dec 2005 07:31:27 -0000 1.9 +++ src/sys/dev/pci/if_tlreg.h 14 Dec 2010 19:15:28 -0000 @@ -104,6 +104,8 @@ struct tl_chain_data { struct tl_chain_onefrag *tl_rx_head; struct tl_chain_onefrag *tl_rx_tail; + struct tl_chain_onefrag *tl_rx_cons; + int tl_rx_cnt; struct tl_chain *tl_tx_head; struct tl_chain *tl_tx_tail;