Author: bryanv
Date: Sat May  3 19:40:41 2014
New Revision: 265286
URL: http://svnweb.freebsd.org/changeset/base/265286

Log:
  MFC r261150, r261151, r261164, r261166, r261167, r261168, r261394, r261395:
  
   - Read and write the MAC address in the config space byte by byte
   - Also include the mbuf's csum_flags in an assert message
   - Remove stray space
   - Move duplicated transmit start code into a single function
   - Avoid queue unlock followed by relock when the enable interrupt race
     is lost
   - Check for a full virtqueue in the multiqueue transmit path
   - Do not place the sglist used for Rx/Tx on the stack
   - Use m_defrag() instead of m_collapse() to compact a long mbuf chain

Modified:
  stable/10/sys/dev/virtio/network/if_vtnet.c
  stable/10/sys/dev/virtio/network/if_vtnetvar.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/dev/virtio/network/if_vtnet.c
==============================================================================
--- stable/10/sys/dev/virtio/network/if_vtnet.c Sat May  3 18:50:47 2014        
(r265285)
+++ stable/10/sys/dev/virtio/network/if_vtnet.c Sat May  3 19:40:41 2014        
(r265286)
@@ -145,6 +145,7 @@ static int  vtnet_txq_mq_start_locked(str
 static int     vtnet_txq_mq_start(struct ifnet *, struct mbuf *);
 static void    vtnet_txq_tq_deferred(void *, int);
 #endif
+static void    vtnet_txq_start(struct vtnet_txq *);
 static void    vtnet_txq_tq_intr(void *, int);
 static void    vtnet_txq_eof(struct vtnet_txq *);
 static void    vtnet_tx_vq_intr(void *);
@@ -606,6 +607,20 @@ vtnet_setup_features(struct vtnet_softc 
        } else
                sc->vtnet_hdr_size = sizeof(struct virtio_net_hdr);
 
+       if (sc->vtnet_flags & VTNET_FLAG_MRG_RXBUFS)
+               sc->vtnet_rx_nsegs = VTNET_MRG_RX_SEGS;
+       else if (sc->vtnet_flags & VTNET_FLAG_LRO_NOMRG)
+               sc->vtnet_rx_nsegs = VTNET_MAX_RX_SEGS;
+       else
+               sc->vtnet_rx_nsegs = VTNET_MIN_RX_SEGS;
+
+       if (virtio_with_feature(dev, VIRTIO_NET_F_GSO) ||
+           virtio_with_feature(dev, VIRTIO_NET_F_HOST_TSO4) ||
+           virtio_with_feature(dev, VIRTIO_NET_F_HOST_TSO6))
+               sc->vtnet_tx_nsegs = VTNET_MAX_TX_SEGS;
+       else
+               sc->vtnet_tx_nsegs = VTNET_MIN_TX_SEGS;
+
        if (virtio_with_feature(dev, VIRTIO_NET_F_CTRL_VQ)) {
                sc->vtnet_flags |= VTNET_FLAG_CTRL_VQ;
 
@@ -661,6 +676,10 @@ vtnet_init_rxq(struct vtnet_softc *sc, i
        rxq->vtnrx_sc = sc;
        rxq->vtnrx_id = id;
 
+       rxq->vtnrx_sg = sglist_alloc(sc->vtnet_rx_nsegs, M_NOWAIT);
+       if (rxq->vtnrx_sg == NULL)
+               return (ENOMEM);
+
        TASK_INIT(&rxq->vtnrx_intrtask, 0, vtnet_rxq_tq_intr, rxq);
        rxq->vtnrx_tq = taskqueue_create(rxq->vtnrx_name, M_NOWAIT,
            taskqueue_thread_enqueue, &rxq->vtnrx_tq);
@@ -682,6 +701,10 @@ vtnet_init_txq(struct vtnet_softc *sc, i
        txq->vtntx_sc = sc;
        txq->vtntx_id = id;
 
+       txq->vtntx_sg = sglist_alloc(sc->vtnet_tx_nsegs, M_NOWAIT);
+       if (txq->vtntx_sg == NULL)
+               return (ENOMEM);
+
 #ifndef VTNET_LEGACY_TX
        txq->vtntx_br = buf_ring_alloc(VTNET_DEFAULT_BUFRING_SIZE, M_DEVBUF,
            M_NOWAIT, &txq->vtntx_mtx);
@@ -734,6 +757,11 @@ vtnet_destroy_rxq(struct vtnet_rxq *rxq)
        rxq->vtnrx_sc = NULL;
        rxq->vtnrx_id = -1;
 
+       if (rxq->vtnrx_sg != NULL) {
+               sglist_free(rxq->vtnrx_sg);
+               rxq->vtnrx_sg = NULL;
+       }
+
        if (mtx_initialized(&rxq->vtnrx_mtx) != 0)
                mtx_destroy(&rxq->vtnrx_mtx);
 }
@@ -745,6 +773,11 @@ vtnet_destroy_txq(struct vtnet_txq *txq)
        txq->vtntx_sc = NULL;
        txq->vtntx_id = -1;
 
+       if (txq->vtntx_sg != NULL) {
+               sglist_free(txq->vtntx_sg);
+               txq->vtntx_sg = NULL;
+       }
+
 #ifndef VTNET_LEGACY_TX
        if (txq->vtntx_br != NULL) {
                buf_ring_free(txq->vtntx_br, M_DEVBUF);
@@ -819,40 +852,27 @@ vtnet_alloc_virtqueues(struct vtnet_soft
        struct vq_alloc_info *info;
        struct vtnet_rxq *rxq;
        struct vtnet_txq *txq;
-       int i, idx, flags, nvqs, rxsegs, error;
+       int i, idx, flags, nvqs, error;
 
        dev = sc->vtnet_dev;
        flags = 0;
 
-       /*
-        * Indirect descriptors are not needed for the Rx virtqueue when
-        * mergeable buffers are negotiated. The header is placed inline
-        * with the data, not in a separate descriptor, and mbuf clusters
-        * are always physically contiguous.
-        */
-       if (sc->vtnet_flags & VTNET_FLAG_MRG_RXBUFS)
-               rxsegs = 0;
-       else if (sc->vtnet_flags & VTNET_FLAG_LRO_NOMRG)
-               rxsegs = VTNET_MAX_RX_SEGS;
-       else
-               rxsegs = VTNET_MIN_RX_SEGS;
-
        nvqs = sc->vtnet_max_vq_pairs * 2;
        if (sc->vtnet_flags & VTNET_FLAG_CTRL_VQ)
                nvqs++;
 
-       info = malloc(sizeof(struct vq_alloc_info) * nvqs , M_TEMP, M_NOWAIT);
+       info = malloc(sizeof(struct vq_alloc_info) * nvqs, M_TEMP, M_NOWAIT);
        if (info == NULL)
                return (ENOMEM);
 
        for (i = 0, idx = 0; i < sc->vtnet_max_vq_pairs; i++, idx+=2) {
                rxq = &sc->vtnet_rxqs[i];
-               VQ_ALLOC_INFO_INIT(&info[idx], rxsegs,
+               VQ_ALLOC_INFO_INIT(&info[idx], sc->vtnet_rx_nsegs,
                    vtnet_rx_vq_intr, rxq, &rxq->vtnrx_vq,
                    "%s-%d rx", device_get_nameunit(dev), rxq->vtnrx_id);
 
                txq = &sc->vtnet_txqs[i];
-               VQ_ALLOC_INFO_INIT(&info[idx+1], VTNET_MAX_TX_SEGS,
+               VQ_ALLOC_INFO_INIT(&info[idx+1], sc->vtnet_tx_nsegs,
                    vtnet_tx_vq_intr, txq, &txq->vtntx_vq,
                    "%s-%d tx", device_get_nameunit(dev), txq->vtntx_id);
        }
@@ -1359,14 +1379,14 @@ vtnet_rxq_replace_buf(struct vtnet_rxq *
 static int
 vtnet_rxq_enqueue_buf(struct vtnet_rxq *rxq, struct mbuf *m)
 {
-       struct sglist sg;
-       struct sglist_seg segs[VTNET_MAX_RX_SEGS];
        struct vtnet_softc *sc;
+       struct sglist *sg;
        struct vtnet_rx_header *rxhdr;
        uint8_t *mdata;
        int offset, error;
 
        sc = rxq->vtnrx_sc;
+       sg = rxq->vtnrx_sg;
        mdata = mtod(m, uint8_t *);
 
        VTNET_RXQ_LOCK_ASSERT(rxq);
@@ -1376,22 +1396,22 @@ vtnet_rxq_enqueue_buf(struct vtnet_rxq *
            ("%s: unexpected cluster size %d/%d", __func__, m->m_len,
             sc->vtnet_rx_clsize));
 
-       sglist_init(&sg, VTNET_MAX_RX_SEGS, segs);
+       sglist_reset(sg);
        if ((sc->vtnet_flags & VTNET_FLAG_MRG_RXBUFS) == 0) {
                MPASS(sc->vtnet_hdr_size == sizeof(struct virtio_net_hdr));
                rxhdr = (struct vtnet_rx_header *) mdata;
-               sglist_append(&sg, &rxhdr->vrh_hdr, sc->vtnet_hdr_size);
+               sglist_append(sg, &rxhdr->vrh_hdr, sc->vtnet_hdr_size);
                offset = sizeof(struct vtnet_rx_header);
        } else
                offset = 0;
 
-       sglist_append(&sg, mdata + offset, m->m_len - offset);
+       sglist_append(sg, mdata + offset, m->m_len - offset);
        if (m->m_next != NULL) {
-               error = sglist_append_mbuf(&sg, m->m_next);
+               error = sglist_append_mbuf(sg, m->m_next);
                MPASS(error == 0);
        }
 
-       error = virtqueue_enqueue(rxq->vtnrx_vq, m, &sg, 0, sg.sg_nseg);
+       error = virtqueue_enqueue(rxq->vtnrx_vq, m, sg, 0, sg->sg_nseg);
 
        return (error);
 }
@@ -1818,9 +1838,9 @@ vtnet_rx_vq_intr(void *xrxq)
                return;
        }
 
-again:
        VTNET_RXQ_LOCK(rxq);
 
+again:
        if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
                VTNET_RXQ_UNLOCK(rxq);
                return;
@@ -1834,10 +1854,11 @@ again:
                 * This is an occasional condition or race (when !more),
                 * so retry a few times before scheduling the taskqueue.
                 */
-               rxq->vtnrx_stats.vrxs_rescheduled++;
-               VTNET_RXQ_UNLOCK(rxq);
                if (tries++ < VTNET_INTR_DISABLE_RETRIES)
                        goto again;
+
+               VTNET_RXQ_UNLOCK(rxq);
+               rxq->vtnrx_stats.vrxs_rescheduled++;
                taskqueue_enqueue(rxq->vtnrx_tq, &rxq->vtnrx_intrtask);
        } else
                VTNET_RXQ_UNLOCK(rxq);
@@ -2025,7 +2046,8 @@ vtnet_txq_offload(struct vtnet_txq *txq,
                }
 
                KASSERT(hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM,
-                   ("%s: mbuf %p TSO without checksum offload", __func__, m));
+                   ("%s: mbuf %p TSO without checksum offload %#x",
+                   __func__, m, flags));
 
                error = vtnet_txq_offload_tso(txq, m, etype, csum_start, hdr);
                if (error)
@@ -2043,45 +2065,43 @@ static int
 vtnet_txq_enqueue_buf(struct vtnet_txq *txq, struct mbuf **m_head,
     struct vtnet_tx_header *txhdr)
 {
-       struct sglist sg;
-       struct sglist_seg segs[VTNET_MAX_TX_SEGS];
        struct vtnet_softc *sc;
        struct virtqueue *vq;
+       struct sglist *sg;
        struct mbuf *m;
-       int collapsed, error;
+       int error;
 
-       vq = txq->vtntx_vq;
        sc = txq->vtntx_sc;
+       vq = txq->vtntx_vq;
+       sg = txq->vtntx_sg;
        m = *m_head;
-       collapsed = 0;
 
-       sglist_init(&sg, VTNET_MAX_TX_SEGS, segs);
-       error = sglist_append(&sg, &txhdr->vth_uhdr, sc->vtnet_hdr_size);
-       KASSERT(error == 0 && sg.sg_nseg == 1,
+       sglist_reset(sg);
+       error = sglist_append(sg, &txhdr->vth_uhdr, sc->vtnet_hdr_size);
+       KASSERT(error == 0 && sg->sg_nseg == 1,
            ("%s: error %d adding header to sglist", __func__, error));
 
-again:
-       error = sglist_append_mbuf(&sg, m);
+       error = sglist_append_mbuf(sg, m);
        if (error) {
-               if (collapsed)
-                       goto fail;
-
-               m = m_collapse(m, M_NOWAIT, VTNET_MAX_TX_SEGS - 1);
+               m = m_defrag(m, M_NOWAIT);
                if (m == NULL)
                        goto fail;
 
                *m_head = m;
-               collapsed = 1;
-               txq->vtntx_stats.vtxs_collapsed++;
-               goto again;
+               sc->vtnet_stats.tx_defragged++;
+
+               error = sglist_append_mbuf(sg, m);
+               if (error)
+                       goto fail;
        }
 
        txhdr->vth_mbuf = m;
-       error = virtqueue_enqueue(vq, txhdr, &sg, sg.sg_nseg, 0);
+       error = virtqueue_enqueue(vq, txhdr, sg, sg->sg_nseg, 0);
 
        return (error);
 
 fail:
+       sc->vtnet_stats.tx_defrag_failed++;
        m_freem(*m_head);
        *m_head = NULL;
 
@@ -2238,6 +2258,12 @@ vtnet_txq_mq_start_locked(struct vtnet_t
        vtnet_txq_eof(txq);
 
        while ((m = drbr_peek(ifp, br)) != NULL) {
+               if (virtqueue_full(vq)) {
+                       drbr_putback(ifp, br, m);
+                       error = ENOBUFS;
+                       break;
+               }
+
                error = vtnet_txq_encap(txq, &m);
                if (error) {
                        if (m != NULL)
@@ -2306,6 +2332,24 @@ vtnet_txq_tq_deferred(void *xtxq, int pe
 #endif /* VTNET_LEGACY_TX */
 
 static void
+vtnet_txq_start(struct vtnet_txq *txq)
+{
+       struct vtnet_softc *sc;
+       struct ifnet *ifp;
+
+       sc = txq->vtntx_sc;
+       ifp = sc->vtnet_ifp;
+
+#ifdef VTNET_LEGACY_TX
+       if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+               vtnet_start_locked(txq, ifp);
+#else
+       if (!drbr_empty(ifp, txq->vtntx_br))
+               vtnet_txq_mq_start_locked(txq, NULL);
+#endif
+}
+
+static void
 vtnet_txq_tq_intr(void *xtxq, int pending)
 {
        struct vtnet_softc *sc;
@@ -2325,13 +2369,7 @@ vtnet_txq_tq_intr(void *xtxq, int pendin
 
        vtnet_txq_eof(txq);
 
-#ifdef VTNET_LEGACY_TX
-       if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
-               vtnet_start_locked(txq, ifp);
-#else
-       if (!drbr_empty(ifp, txq->vtntx_br))
-               vtnet_txq_mq_start_locked(txq, NULL);
-#endif
+       vtnet_txq_start(txq);
 
        if (vtnet_txq_enable_intr(txq) != 0) {
                vtnet_txq_disable_intr(txq);
@@ -2392,9 +2430,9 @@ vtnet_tx_vq_intr(void *xtxq)
                return;
        }
 
-again:
        VTNET_TXQ_LOCK(txq);
 
+again:
        if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
                VTNET_TXQ_UNLOCK(txq);
                return;
@@ -2402,13 +2440,7 @@ again:
 
        vtnet_txq_eof(txq);
 
-#ifdef VTNET_LEGACY_TX
-       if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
-               vtnet_start_locked(txq, ifp);
-#else
-       if (!drbr_empty(ifp, txq->vtntx_br))
-               vtnet_txq_mq_start_locked(txq, NULL);
-#endif
+       vtnet_txq_start(txq);
 
        if (vtnet_txq_enable_intr(txq) != 0) {
                vtnet_txq_disable_intr(txq);
@@ -2416,9 +2448,10 @@ again:
                 * This is an occasional race, so retry a few times
                 * before scheduling the taskqueue.
                 */
-               VTNET_TXQ_UNLOCK(txq);
                if (tries++ < VTNET_INTR_DISABLE_RETRIES)
                        goto again;
+
+               VTNET_TXQ_UNLOCK(txq);
                txq->vtntx_stats.vtxs_rescheduled++;
                taskqueue_enqueue(txq->vtntx_tq, &txq->vtntx_intrtask);
        } else
@@ -2428,24 +2461,16 @@ again:
 static void
 vtnet_tx_start_all(struct vtnet_softc *sc)
 {
-       struct ifnet *ifp;
        struct vtnet_txq *txq;
        int i;
 
-       ifp = sc->vtnet_ifp;
        VTNET_CORE_LOCK_ASSERT(sc);
 
        for (i = 0; i < sc->vtnet_act_vq_pairs; i++) {
                txq = &sc->vtnet_txqs[i];
 
                VTNET_TXQ_LOCK(txq);
-#ifdef VTNET_LEGACY_TX
-               if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
-                       vtnet_start_locked(txq, ifp);
-#else
-               if (!drbr_empty(ifp, txq->vtntx_br))
-                       vtnet_txq_mq_start_locked(txq, NULL);
-#endif
+               vtnet_txq_start(txq);
                VTNET_TXQ_UNLOCK(txq);
        }
 }
@@ -2521,7 +2546,6 @@ vtnet_txq_accum_stats(struct vtnet_txq *
        accum->vtxs_obytes += st->vtxs_obytes;
        accum->vtxs_csum += st->vtxs_csum;
        accum->vtxs_tso += st->vtxs_tso;
-       accum->vtxs_collapsed += st->vtxs_collapsed;
        accum->vtxs_rescheduled += st->vtxs_rescheduled;
 }
 
@@ -2839,9 +2863,10 @@ vtnet_init_rx_queues(struct vtnet_softc 
        sc->vtnet_rx_clsize = clsize;
        sc->vtnet_rx_nmbufs = VTNET_NEEDED_RX_MBUFS(sc, clsize);
 
-       /* The first segment is reserved for the header. */
-       KASSERT(sc->vtnet_rx_nmbufs < VTNET_MAX_RX_SEGS,
-           ("%s: too many rx mbufs %d", __func__, sc->vtnet_rx_nmbufs));
+       KASSERT(sc->vtnet_flags & VTNET_FLAG_MRG_RXBUFS ||
+           sc->vtnet_rx_nmbufs < sc->vtnet_rx_nsegs,
+           ("%s: too many rx mbufs %d for %d segments", __func__,
+           sc->vtnet_rx_nmbufs, sc->vtnet_rx_nsegs));
 
        for (i = 0; i < sc->vtnet_act_vq_pairs; i++) {
                rxq = &sc->vtnet_rxqs[i];
@@ -3483,6 +3508,7 @@ static void
 vtnet_set_hwaddr(struct vtnet_softc *sc)
 {
        device_t dev;
+       int i;
 
        dev = sc->vtnet_dev;
 
@@ -3490,9 +3516,11 @@ vtnet_set_hwaddr(struct vtnet_softc *sc)
                if (vtnet_ctrl_mac_cmd(sc, sc->vtnet_hwaddr) != 0)
                        device_printf(dev, "unable to set MAC address\n");
        } else if (sc->vtnet_flags & VTNET_FLAG_MAC) {
-               virtio_write_device_config(dev,
-                   offsetof(struct virtio_net_config, mac),
-                   sc->vtnet_hwaddr, ETHER_ADDR_LEN);
+               for (i = 0; i < ETHER_ADDR_LEN; i++) {
+                       virtio_write_dev_config_1(dev,
+                           offsetof(struct virtio_net_config, mac) + i,
+                           sc->vtnet_hwaddr[i]);
+               }
        }
 }
 
@@ -3500,6 +3528,7 @@ static void
 vtnet_get_hwaddr(struct vtnet_softc *sc)
 {
        device_t dev;
+       int i;
 
        dev = sc->vtnet_dev;
 
@@ -3517,8 +3546,10 @@ vtnet_get_hwaddr(struct vtnet_softc *sc)
                return;
        }
 
-       virtio_read_device_config(dev, offsetof(struct virtio_net_config, mac),
-           sc->vtnet_hwaddr, ETHER_ADDR_LEN);
+       for (i = 0; i < ETHER_ADDR_LEN; i++) {
+               sc->vtnet_hwaddr[i] = virtio_read_dev_config_1(dev,
+                   offsetof(struct virtio_net_config, mac) + i);
+       }
 }
 
 static void
@@ -3595,8 +3626,6 @@ vtnet_setup_txq_sysctl(struct sysctl_ctx
            &stats->vtxs_csum, "Transmit checksum offloaded");
        SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "tso", CTLFLAG_RD,
            &stats->vtxs_tso, "Transmit segmentation offloaded");
-       SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "collapsed", CTLFLAG_RD,
-           &stats->vtxs_collapsed, "Transmit mbufs collapsed");
        SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "rescheduled", CTLFLAG_RD,
            &stats->vtxs_rescheduled,
            "Transmit interrupt handler rescheduled");
@@ -3676,6 +3705,12 @@ vtnet_setup_stat_sysctl(struct sysctl_ct
        SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "tx_tso_not_tcp",
            CTLFLAG_RD, &stats->tx_tso_not_tcp,
            "Aborted transmit of TSO buffer with non TCP protocol");
+       SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "tx_defragged",
+           CTLFLAG_RD, &stats->tx_defragged,
+           "Transmit mbufs defragged");
+       SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "tx_defrag_failed",
+           CTLFLAG_RD, &stats->tx_defrag_failed,
+           "Aborted transmit of buffer because defrag failed");
        SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "tx_csum_offloaded",
            CTLFLAG_RD, &stats->tx_csum_offloaded,
            "Offloaded checksum of transmitted buffer");

Modified: stable/10/sys/dev/virtio/network/if_vtnetvar.h
==============================================================================
--- stable/10/sys/dev/virtio/network/if_vtnetvar.h      Sat May  3 18:50:47 
2014        (r265285)
+++ stable/10/sys/dev/virtio/network/if_vtnetvar.h      Sat May  3 19:40:41 
2014        (r265286)
@@ -44,6 +44,8 @@ struct vtnet_statistics {
        uint64_t        tx_csum_bad_ethtype;
        uint64_t        tx_tso_bad_ethtype;
        uint64_t        tx_tso_not_tcp;
+       uint64_t        tx_defragged;
+       uint64_t        tx_defrag_failed;
 
        /*
         * These are accumulated from each Rx/Tx queue.
@@ -70,6 +72,7 @@ struct vtnet_rxq {
        struct mtx               vtnrx_mtx;
        struct vtnet_softc      *vtnrx_sc;
        struct virtqueue        *vtnrx_vq;
+       struct sglist           *vtnrx_sg;
        int                      vtnrx_id;
        int                      vtnrx_process_limit;
        struct vtnet_rxq_stats   vtnrx_stats;
@@ -91,7 +94,6 @@ struct vtnet_txq_stats {
        uint64_t vtxs_omcasts;  /* if_omcasts */
        uint64_t vtxs_csum;
        uint64_t vtxs_tso;
-       uint64_t vtxs_collapsed;
        uint64_t vtxs_rescheduled;
 };
 
@@ -99,6 +101,7 @@ struct vtnet_txq {
        struct mtx               vtntx_mtx;
        struct vtnet_softc      *vtntx_sc;
        struct virtqueue        *vtntx_vq;
+       struct sglist           *vtntx_sg;
 #ifndef VTNET_LEGACY_TX
        struct buf_ring         *vtntx_br;
 #endif
@@ -143,9 +146,11 @@ struct vtnet_softc {
        int                      vtnet_link_active;
        int                      vtnet_hdr_size;
        int                      vtnet_rx_process_limit;
+       int                      vtnet_rx_nsegs;
        int                      vtnet_rx_nmbufs;
        int                      vtnet_rx_clsize;
        int                      vtnet_rx_new_clsize;
+       int                      vtnet_tx_nsegs;
        int                      vtnet_if_flags;
        int                      vtnet_act_vq_pairs;
        int                      vtnet_max_vq_pairs;
@@ -293,11 +298,14 @@ CTASSERT(sizeof(struct vtnet_mac_filter)
 
 /*
  * Used to preallocate the Vq indirect descriptors. The first segment
- * is reserved for the header.
+ * is reserved for the header, except for mergeable buffers since the
+ * header is placed inline with the data.
  */
+#define VTNET_MRG_RX_SEGS      1
 #define VTNET_MIN_RX_SEGS      2
 #define VTNET_MAX_RX_SEGS      34
-#define VTNET_MAX_TX_SEGS      34
+#define VTNET_MIN_TX_SEGS      4
+#define VTNET_MAX_TX_SEGS      64
 
 /*
  * Assert we can receive and transmit the maximum with regular
@@ -314,7 +322,7 @@ CTASSERT(((VTNET_MAX_TX_SEGS - 1) * MCLB
 
 /*
  * Determine how many mbufs are in each receive buffer. For LRO without
- * mergeable descriptors, we must allocate an mbuf chain large enough to
+ * mergeable buffers, we must allocate an mbuf chain large enough to
  * hold both the vtnet_rx_header and the maximum receivable data.
  */
 #define VTNET_NEEDED_RX_MBUFS(_sc, _clsize)                            \
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to