Index: if_vge.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_vge.c,v retrieving revision 1.65 diff -u -p -r1.65 if_vge.c --- if_vge.c 25 Oct 2015 13:04:28 -0000 1.65 +++ if_vge.c 12 Nov 2015 03:19:44 -0000 @@ -620,8 +620,8 @@ vge_allocmem(struct vge_softc *sc) /* Create DMA maps for TX buffers */ for (i = 0; i < VGE_TX_DESC_CNT; i++) { - error = bus_dmamap_create(sc->sc_dmat, MCLBYTES * nseg, nseg, - MCLBYTES, 0, BUS_DMA_ALLOCNOW, + error = bus_dmamap_create(sc->sc_dmat, MCLBYTES * nseg, + VGE_TX_FRAGS, MCLBYTES, 0, BUS_DMA_ALLOCNOW, &sc->vge_ldata.vge_tx_dmamap[i]); if (error) { printf("%s: can't create DMA map for TX\n", @@ -1321,13 +1321,12 @@ vge_intr(void *arg) int vge_encap(struct vge_softc *sc, struct mbuf *m_head, int idx) { - struct ifnet *ifp = &sc->arpcom.ac_if; bus_dmamap_t txmap; struct vge_tx_desc *d = NULL; struct vge_tx_frag *f; - struct mbuf *mnew = NULL; int error, frag; u_int32_t vge_flags; + unsigned int len; vge_flags = 0; @@ -1339,14 +1338,19 @@ vge_encap(struct vge_softc *sc, struct m vge_flags |= VGE_TDCTL_UDPCSUM; txmap = sc->vge_ldata.vge_tx_dmamap[idx]; -repack: error = bus_dmamap_load_mbuf(sc->sc_dmat, txmap, m_head, BUS_DMA_NOWAIT); - if (error) { - printf("%s: can't map mbuf (error %d)\n", - sc->vge_dev.dv_xname, error); - return (ENOBUFS); - } + switch (error) { + case 0: + break; + case EFBIG: /* mbuf chain is too fragmented */ + if ((error = m_defrag(m_head, M_DONTWAIT)) == 0 && + (error = bus_dmamap_load_mbuf(sc->sc_dmat, txmap, m_head, + BUS_DMA_NOWAIT)) == 0) + break; + default: + return (error); + } d = &sc->vge_ldata.vge_tx_list[idx]; /* If owned by chip, fail */ @@ -1354,40 +1358,12 @@ repack: return (ENOBUFS); for (frag = 0; frag < txmap->dm_nsegs; frag++) { - /* Check if we have used all 7 fragments. */ - if (frag == VGE_TX_FRAGS) - break; f = &d->vge_frag[frag]; f->vge_buflen = htole16(VGE_BUFLEN(txmap->dm_segs[frag].ds_len)); f->vge_addrlo = htole32(VGE_ADDR_LO(txmap->dm_segs[frag].ds_addr)); f->vge_addrhi = htole16(VGE_ADDR_HI(txmap->dm_segs[frag].ds_addr) & 0xFFFF); } - /* - * We used up all 7 fragments! Now what we have to do is - * copy the data into a mbuf cluster and map that. - */ - if (frag == VGE_TX_FRAGS) { - MGETHDR(mnew, M_DONTWAIT, MT_DATA); - if (mnew == NULL) - return (ENOBUFS); - - if (m_head->m_pkthdr.len > MHLEN) { - MCLGET(mnew, M_DONTWAIT); - if (!(mnew->m_flags & M_EXT)) { - m_freem(mnew); - return (ENOBUFS); - } - } - m_copydata(m_head, 0, m_head->m_pkthdr.len, - mtod(mnew, caddr_t)); - mnew->m_pkthdr.len = mnew->m_len = m_head->m_pkthdr.len; - IFQ_DEQUEUE(&ifp->if_snd, m_head); - m_freem(m_head); - m_head = mnew; - goto repack; - } - /* This chip does not do auto-padding */ if (m_head->m_pkthdr.len < VGE_MIN_FRAMELEN) { f = &d->vge_frag[frag]; @@ -1396,19 +1372,21 @@ repack: m_head->m_pkthdr.len)); f->vge_addrlo = htole32(VGE_ADDR_LO(txmap->dm_segs[0].ds_addr)); f->vge_addrhi = htole16(VGE_ADDR_HI(txmap->dm_segs[0].ds_addr) & 0xFFFF); - m_head->m_pkthdr.len = VGE_MIN_FRAMELEN; + len = VGE_MIN_FRAMELEN; frag++; - } + } else + len = m_head->m_pkthdr.len; + /* For some reason, we need to tell the card fragment + 1 */ frag++; bus_dmamap_sync(sc->sc_dmat, txmap, 0, txmap->dm_mapsize, BUS_DMASYNC_PREWRITE); - d->vge_sts = htole32(m_head->m_pkthdr.len << 16); + d->vge_sts = htole32(len << 16); d->vge_ctl = htole32(vge_flags|(frag << 28) | VGE_TD_LS_NORM); - if (m_head->m_pkthdr.len > ETHERMTU + ETHER_HDR_LEN) + if (len > ETHERMTU + ETHER_HDR_LEN) d->vge_ctl |= htole32(VGE_TDCTL_JUMBO); #if NVLAN > 0 @@ -1425,10 +1403,6 @@ repack: sc->vge_ldata.vge_tx_list[idx].vge_sts |= htole32(VGE_TDSTS_OWN); idx++; - if (mnew == NULL) { - /* if mbuf is coalesced, it is already dequeued */ - IFQ_DEQUEUE(&ifp->if_snd, m_head); - } return (0); } @@ -1456,11 +1430,21 @@ vge_start(struct ifnet *ifp) if (pidx < 0) pidx = VGE_TX_DESC_CNT - 1; - while (sc->vge_ldata.vge_tx_mbuf[idx] == NULL) { - IFQ_POLL(&ifp->if_snd, m_head); + for (;;) { + if (sc->vge_ldata.vge_tx_mbuf[idx] != NULL) { + ifp->if_flags |= IFF_OACTIVE; + break; + } + + IFQ_DEQUEUE(&ifp->if_snd, m_head); if (m_head == NULL) break; + if (vge_encap(sc, m_head, idx)) { + m_freem(m_head); + continue; + } + /* * If there's a BPF listener, bounce a copy of this frame * to him. @@ -1469,11 +1453,6 @@ vge_start(struct ifnet *ifp) if (ifp->if_bpf) bpf_mtap_ether(ifp->if_bpf, m_head, BPF_DIRECTION_OUT); #endif - - if (vge_encap(sc, m_head, idx)) { - ifp->if_flags |= IFF_OACTIVE; - break; - } sc->vge_ldata.vge_tx_list[pidx].vge_frag[0].vge_buflen |= htole16(VGE_TXDESC_Q);