i started this to make it avoid IFQ_POLL, but i threw some other
changes in to make it easier.

firstly, it checks if there's space on the ring before it proceeds
to try and dequeue a packet for transmission.

rather than advertise 32 dma segments in a transmit slots dma map,
it advertises the 7 that are actually there. if the mbuf has more
segments than that, it calls m_defrag immediately, rather than
trying to fill it and handling the overflow late.

it avoids setting IFF_OACTIVE for another except ring full conditions.
this should make it more robust if the first packet on the tx ring
fails to be encapsulated for some reason.

i do not have any vge(4) hardware, so i need someone to test this.
otherwise ill put it in as is and we may end up with a nasty surprise
in the future.

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);

Reply via email to