basically check for space on the ring before dequeuing the packet. any errors we hit after that cause us to drop the mbuf.
ok? Index: if_bge.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_bge.c,v retrieving revision 1.371 diff -u -p -r1.371 if_bge.c --- if_bge.c 25 Oct 2015 13:04:28 -0000 1.371 +++ if_bge.c 11 Nov 2015 03:25:30 -0000 @@ -3985,7 +3985,7 @@ bge_cksum_pad(struct mbuf *m) * pointers to descriptors. */ int -bge_encap(struct bge_softc *sc, struct mbuf *m_head, int *txinc) +bge_encap(struct bge_softc *sc, struct mbuf *m, int *txinc) { struct bge_tx_bd *f = NULL; u_int32_t frag, cur; @@ -3995,20 +3995,20 @@ bge_encap(struct bge_softc *sc, struct m cur = frag = (sc->bge_tx_prodidx + *txinc) % BGE_TX_RING_CNT; - if (m_head->m_pkthdr.csum_flags) { - if (m_head->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT) + if (m->m_pkthdr.csum_flags) { + if (m->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT) csum_flags |= BGE_TXBDFLAG_IP_CSUM; - if (m_head->m_pkthdr.csum_flags & (M_TCP_CSUM_OUT | - M_UDP_CSUM_OUT)) { + if (m->m_pkthdr.csum_flags & + (M_TCP_CSUM_OUT | M_UDP_CSUM_OUT)) { csum_flags |= BGE_TXBDFLAG_TCP_UDP_CSUM; - if (m_head->m_pkthdr.len < ETHER_MIN_NOPAD && - bge_cksum_pad(m_head) != 0) + if (m->m_pkthdr.len < ETHER_MIN_NOPAD && + bge_cksum_pad(m) != 0) return (ENOBUFS); } } if (sc->bge_flags & BGE_JUMBO_FRAME && - m_head->m_pkthdr.len > ETHER_MAX_LEN) + m->m_pkthdr.len > ETHER_MAX_LEN) csum_flags |= BGE_TXBDFLAG_JUMBO_FRAME; if (!(BGE_CHIPREV(sc->bge_chipid) == BGE_CHIPREV_5700_BX)) @@ -4019,7 +4019,7 @@ bge_encap(struct bge_softc *sc, struct m * less than eight bytes. If we encounter a teeny mbuf * at the end of a chain, we can pad. Otherwise, copy. */ - if (bge_compact_dma_runt(m_head) != 0) + if (bge_compact_dma_runt(m) != 0) return (ENOBUFS); doit: @@ -4030,13 +4030,13 @@ doit: * the fragment pointers. Stop when we run out * of fragments or hit the end of the mbuf chain. */ - switch (bus_dmamap_load_mbuf(sc->bge_dmatag, dmamap, m_head, + switch (bus_dmamap_load_mbuf(sc->bge_dmatag, dmamap, m, BUS_DMA_NOWAIT)) { case 0: break; case EFBIG: - if (m_defrag(m_head, M_DONTWAIT) == 0 && - bus_dmamap_load_mbuf(sc->bge_dmatag, dmamap, m_head, + if (m_defrag(m, M_DONTWAIT) == 0 && + bus_dmamap_load_mbuf(sc->bge_dmatag, dmamap, m, BUS_DMA_NOWAIT) == 0) break; @@ -4045,10 +4045,6 @@ doit: return (ENOBUFS); } - /* Check if we have enough free send BDs. */ - if (sc->bge_txcnt + *txinc + dmamap->dm_nsegs >= BGE_TX_RING_CNT) - goto fail_unload; - for (i = 0; i < dmamap->dm_nsegs; i++) { f = &sc->bge_rdata->bge_tx_ring[frag]; if (sc->bge_cdata.bge_tx_chain[frag] != NULL) @@ -4058,9 +4054,9 @@ doit: f->bge_flags = csum_flags; f->bge_vlan_tag = 0; #if NVLAN > 0 - if (m_head->m_flags & M_VLANTAG) { + if (m->m_flags & M_VLANTAG) { f->bge_flags |= BGE_TXBDFLAG_VLAN_TAG; - f->bge_vlan_tag = m_head->m_pkthdr.ether_vtag; + f->bge_vlan_tag = m->m_pkthdr.ether_vtag; } #endif cur = frag; @@ -4077,7 +4073,7 @@ doit: goto fail_unload; sc->bge_rdata->bge_tx_ring[cur].bge_flags |= BGE_TXBDFLAG_END; - sc->bge_cdata.bge_tx_chain[cur] = m_head; + sc->bge_cdata.bge_tx_chain[cur] = m; sc->bge_cdata.bge_tx_map[cur] = dmamap; *txinc += dmamap->dm_nsegs; @@ -4098,7 +4094,7 @@ void bge_start(struct ifnet *ifp) { struct bge_softc *sc; - struct mbuf *m_head; + struct mbuf *m; int txinc; sc = ifp->if_softc; @@ -4110,25 +4106,28 @@ bge_start(struct ifnet *ifp) txinc = 0; while (1) { - IFQ_POLL(&ifp->if_snd, m_head); - if (m_head == NULL) + /* Check if we have enough free send BDs. */ + if (sc->bge_txcnt + txinc + BGE_NTXSEG >= BGE_TX_RING_CNT) { + ifp->if_flags |= IFF_OACTIVE; break; + } - if (bge_encap(sc, m_head, &txinc)) + IFQ_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) break; - /* now we are committed to transmit the packet */ - IFQ_DEQUEUE(&ifp->if_snd, m_head); + if (bge_encap(sc, m, &txinc) != 0) { + m_freem(m); + continue; + } #if NBPFILTER > 0 if (ifp->if_bpf) - bpf_mtap_ether(ifp->if_bpf, m_head, BPF_DIRECTION_OUT); + bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT); #endif } if (txinc != 0) { - int txcnt; - /* Transmit */ sc->bge_tx_prodidx = (sc->bge_tx_prodidx + txinc) % BGE_TX_RING_CNT; @@ -4137,9 +4136,7 @@ bge_start(struct ifnet *ifp) bge_writembx(sc, BGE_MBX_TX_HOST_PROD0_LO, sc->bge_tx_prodidx); - txcnt = atomic_add_int_nv(&sc->bge_txcnt, txinc); - if (txcnt > BGE_TX_RING_CNT - 16) - ifp->if_flags |= IFF_OACTIVE; + atomic_add_int(&sc->bge_txcnt, txinc); /* * Set a timeout in case the chip goes out to lunch.