Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 4 Aug 2013 22:01:07 +0000 (UTC)
From:      Bryan Venteicher <bryanv@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r253944 - in projects/vmxnet/sys: dev/vmware/vmxnet3 modules/vmware/vmxnet3
Message-ID:  <201308042201.r74M17jv013420@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bryanv
Date: Sun Aug  4 22:01:06 2013
New Revision: 253944
URL: http://svnweb.freebsd.org/changeset/base/253944

Log:
  More minor improvements of the vmxnet3 driver
  
   - Move the dma map and mbuf pointer into a common structure, rather
     than having an array of each
   - Add ifdefs and fix gcc warnings to make compiling on 9.1/STABLE
   - Add sysctl nodes for statistics queried from the hypervisor
   - Adjust several structures/function to more multiqueue friendly
     (for whenever support is added)
   - Adjust Makefile to more likely do the right thing when built standalone

Modified:
  projects/vmxnet/sys/dev/vmware/vmxnet3/if_vmx.c
  projects/vmxnet/sys/dev/vmware/vmxnet3/if_vmxreg.h
  projects/vmxnet/sys/dev/vmware/vmxnet3/if_vmxvar.h
  projects/vmxnet/sys/modules/vmware/vmxnet3/Makefile

Modified: projects/vmxnet/sys/dev/vmware/vmxnet3/if_vmx.c
==============================================================================
--- projects/vmxnet/sys/dev/vmware/vmxnet3/if_vmx.c	Sun Aug  4 21:27:31 2013	(r253943)
+++ projects/vmxnet/sys/dev/vmware/vmxnet3/if_vmx.c	Sun Aug  4 22:01:06 2013	(r253944)
@@ -67,6 +67,16 @@ __FBSDID("$FreeBSD$");
 #include "opt_inet.h"
 #include "opt_inet6.h"
 
+/* Always enable for now - useful for queue hangs. */
+#define VMXNET3_DEBUG_SYSCTL
+
+#ifdef VMXNET3_FAILPOINTS
+#include <sys/fail.h>
+static SYSCTL_NODE(DEBUG_FP, OID_AUTO, vmxnet3, CTLFLAG_RW, 0,
+    "vmxnet3 fail points");
+#define VMXNET3_FP	_debug_fail_point_vmxnet3
+#endif
+
 static int	vmxnet3_probe(device_t);
 static int	vmxnet3_attach(device_t);
 static int	vmxnet3_detach(device_t);
@@ -141,9 +151,9 @@ static void	vmxnet3_init_locked(struct v
 static void	vmxnet3_init(void *);
 
 static int	vmxnet3_txq_offload_ctx(struct mbuf *, int *, int *, int *);
-static int	vmxnet3_txq_load_mbuf(struct vmxnet3_txring *, struct mbuf **,
+static int	vmxnet3_txq_load_mbuf(struct vmxnet3_txqueue *, struct mbuf **,
 		    bus_dmamap_t, bus_dma_segment_t [], int *);
-static void	vmxnet3_txq_unload_mbuf(struct vmxnet3_txring *, bus_dmamap_t);
+static void	vmxnet3_txq_unload_mbuf(struct vmxnet3_txqueue *, bus_dmamap_t);
 static int	vmxnet3_txq_encap(struct vmxnet3_txqueue *, struct mbuf **);
 static void	vmxnet3_start_locked(struct ifnet *);
 static void	vmxnet3_start(struct ifnet *);
@@ -156,7 +166,7 @@ static void	vmxnet3_set_rxfilter(struct 
 static int	vmxnet3_change_mtu(struct vmxnet3_softc *, int);
 static int	vmxnet3_ioctl(struct ifnet *, u_long, caddr_t);
 
-static void	vmxnet3_watchdog(struct vmxnet3_softc *);
+static int	vmxnet3_watchdog(struct vmxnet3_txqueue *);
 static void	vmxnet3_tick(void *);
 static void	vmxnet3_link_status(struct vmxnet3_softc *);
 static void	vmxnet3_media_status(struct ifnet *, struct ifmediareq *);
@@ -164,7 +174,14 @@ static int	vmxnet3_media_change(struct i
 static void	vmxnet3_set_lladdr(struct vmxnet3_softc *);
 static void	vmxnet3_get_lladdr(struct vmxnet3_softc *);
 
-static uint32_t	vmxnet3_read_bar0(struct vmxnet3_softc *, bus_size_t);
+static void	vmxnet3_setup_txq_sysctl(struct vmxnet3_txqueue *,
+		    struct sysctl_ctx_list *, struct sysctl_oid_list *);
+static void	vmxnet3_setup_rxq_sysctl(struct vmxnet3_rxqueue *,
+		    struct sysctl_ctx_list *, struct sysctl_oid_list *);
+static void	vmxnet3_setup_queue_sysctl(struct vmxnet3_softc *,
+		    struct sysctl_ctx_list *, struct sysctl_oid_list *);
+static void	vmxnet3_setup_sysctl(struct vmxnet3_softc *);
+
 static void	vmxnet3_write_bar0(struct vmxnet3_softc *, bus_size_t,
 		    uint32_t);
 static uint32_t	vmxnet3_read_bar1(struct vmxnet3_softc *, bus_size_t);
@@ -183,6 +200,14 @@ static int	vmxnet3_dma_malloc(struct vmx
 static void	vmxnet3_dma_free(struct vmxnet3_softc *,
 		    struct vmxnet3_dma_alloc *);
 
+typedef enum {
+	VMXNET3_BARRIER_RD,
+	VMXNET3_BARRIER_WR,
+	VMXNET3_BARRIER_RDWR,
+} vmxnet3_barrier_t;
+
+static void	vmxnet3_barrier(struct vmxnet3_softc *, vmxnet3_barrier_t);
+
 static device_method_t vmxnet3_methods[] = {
 	/* Device interface. */
 	DEVMETHOD(device_probe,		vmxnet3_probe),
@@ -266,6 +291,7 @@ vmxnet3_attach(device_t dev)
 		goto fail;
 	}
 
+	vmxnet3_setup_sysctl(sc);
 	vmxnet3_link_status(sc);
 
 fail:
@@ -457,9 +483,9 @@ vmxnet3_alloc_msix_interrupts(struct vmx
 	if (pci_alloc_msix(dev, &cnt) == 0 && cnt >= required) {
 		sc->vmx_nintrs = required;
 		return (0);
-	}
+	} else
+		pci_release_msi(dev);
 
-	pci_release_msi(dev);
 	return (1);
 }
 
@@ -480,9 +506,9 @@ vmxnet3_alloc_msi_interrupts(struct vmxn
 	if (pci_alloc_msi(dev, &cnt) == 0 && cnt >= required) {
 		sc->vmx_nintrs = 1;
 		return (0);
-	}
+	} else
+		pci_release_msi(dev);
 
-	pci_release_msi(dev);
 	return (1);
 }
 
@@ -751,6 +777,10 @@ vmxnet3_init_rxq(struct vmxnet3_softc *s
 		rxr = &rxq->vxrxq_cmd_ring[i];
 		rxr->vxrxr_rid = i;
 		rxr->vxrxr_ndesc = sc->vmx_nrxdescs;
+		rxr->vxrxr_rxbuf = malloc(rxr->vxrxr_ndesc *
+		    sizeof(struct vmxnet3_rxbuf), M_DEVBUF, M_NOWAIT | M_ZERO);
+		if (rxr->vxrxr_rxbuf == NULL)
+			return (ENOMEM);
 	}
 
 	rxq->vxrxq_comp_ring.vxcr_ndesc =
@@ -763,8 +793,10 @@ static int
 vmxnet3_init_txq(struct vmxnet3_softc *sc, int q)
 {
 	struct vmxnet3_txqueue *txq;
+	struct vmxnet3_txring *txr;
 
 	txq = &sc->vmx_txq[q];
+	txr = &txq->vxtxq_cmd_ring;
 
 	snprintf(txq->vxtxq_name, sizeof(txq->vxtxq_name), "%s-tx%d",
 	    device_get_nameunit(sc->vmx_dev), q);
@@ -773,7 +805,12 @@ vmxnet3_init_txq(struct vmxnet3_softc *s
 	txq->vxtxq_sc = sc;
 	txq->vxtxq_id = q;
 
-	txq->vxtxq_cmd_ring.vxtxr_ndesc = sc->vmx_ntxdescs;
+	txr->vxtxr_ndesc = sc->vmx_ntxdescs;
+	txr->vxtxr_txbuf = malloc(txr->vxtxr_ndesc *
+	    sizeof(struct vmxnet3_txbuf), M_DEVBUF, M_NOWAIT | M_ZERO);
+	if (txr->vxtxr_txbuf == NULL)
+		return (ENOMEM);
+
 	txq->vxtxq_comp_ring.vxcr_ndesc = sc->vmx_ntxdescs;
 
 	return (0);
@@ -809,10 +846,21 @@ vmxnet3_alloc_rxtx_queues(struct vmxnet3
 static void
 vmxnet3_destroy_rxq(struct vmxnet3_rxqueue *rxq)
 {
+	struct vmxnet3_rxring *rxr;
+	int i;
 
 	rxq->vxrxq_sc = NULL;
 	rxq->vxrxq_id = -1;
 
+	for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) {
+		rxr = &rxq->vxrxq_cmd_ring[i];
+
+		if (rxr->vxrxr_rxbuf != NULL) {
+			free(rxr->vxrxr_rxbuf, M_DEVBUF);
+			rxr->vxrxr_rxbuf = NULL;
+		}
+	}
+
 	if (mtx_initialized(&rxq->vxrxq_mtx) != 0)
 		mtx_destroy(&rxq->vxrxq_mtx);
 }
@@ -820,13 +868,20 @@ vmxnet3_destroy_rxq(struct vmxnet3_rxque
 static void
 vmxnet3_destroy_txq(struct vmxnet3_txqueue *txq)
 {
+	struct vmxnet3_txring *txr;
+
+	txr = &txq->vxtxq_cmd_ring;
 
 	txq->vxtxq_sc = NULL;
 	txq->vxtxq_id = -1;
 
+	if (txr->vxtxr_txbuf != NULL) {
+		free(txr->vxtxr_txbuf, M_DEVBUF);
+		txr->vxtxr_txbuf = NULL;
+	}
+
 	if (mtx_initialized(&txq->vxtxq_mtx) != 0)
 		mtx_destroy(&txq->vxtxq_mtx);
-
 }
 
 static void
@@ -915,14 +970,15 @@ vmxnet3_alloc_txq_data(struct vmxnet3_so
 	int i, q, error;
 
 	dev = sc->vmx_dev;
-	descsz = sc->vmx_ntxdescs * sizeof(struct vmxnet3_txdesc);
-	compsz = sc->vmx_ntxdescs * sizeof(struct vmxnet3_txcompdesc);
 
 	for (q = 0; q < sc->vmx_ntxqueues; q++) {
 		txq = &sc->vmx_txq[q];
 		txr = &txq->vxtxq_cmd_ring;
 		txc = &txq->vxtxq_comp_ring;
 
+		descsz = txr->vxtxr_ndesc * sizeof(struct vmxnet3_txdesc);
+		compsz = txr->vxtxr_ndesc * sizeof(struct vmxnet3_txcompdesc);
+
 		error = bus_dma_tag_create(bus_get_dma_tag(dev),
 		    1, 0,			/* alignment, boundary */
 		    BUS_SPACE_MAXADDR,		/* lowaddr */
@@ -958,9 +1014,9 @@ vmxnet3_alloc_txq_data(struct vmxnet3_so
 		txc->vxcr_u.txcd =
 		    (struct vmxnet3_txcompdesc *) txc->vxcr_dma.dma_vaddr;
 
-		for (i = 0; i < sc->vmx_ntxdescs; i++) {
+		for (i = 0; i < txr->vxtxr_ndesc; i++) {
 			error = bus_dmamap_create(txr->vxtxr_txtag, 0,
-			    &txr->vxtxr_dmap[i]);
+			    &txr->vxtxr_txbuf[i].vtxb_dmamap);
 			if (error) {
 				device_printf(dev, "unable to create Tx buf "
 				    "dmamap for queue %d idx %d\n", q, i);
@@ -979,6 +1035,7 @@ vmxnet3_free_txq_data(struct vmxnet3_sof
 	struct vmxnet3_txqueue *txq;
 	struct vmxnet3_txring *txr;
 	struct vmxnet3_comp_ring *txc;
+	struct vmxnet3_txbuf *txb;
 	int i, q;
 
 	dev = sc->vmx_dev;
@@ -989,10 +1046,11 @@ vmxnet3_free_txq_data(struct vmxnet3_sof
 		txc = &txq->vxtxq_comp_ring;
 
 		for (i = 0; i < txr->vxtxr_ndesc; i++) {
-			if (txr->vxtxr_dmap[i] != NULL) {
+			txb = &txr->vxtxr_txbuf[i];
+			if (txb->vtxb_dmamap != NULL) {
 				bus_dmamap_destroy(txr->vxtxr_txtag,
-				    txr->vxtxr_dmap[i]);
-				txr->vxtxr_dmap[i] = NULL;
+				    txb->vtxb_dmamap);
+				txb->vtxb_dmamap = NULL;
 			}
 		}
 
@@ -1024,9 +1082,7 @@ vmxnet3_alloc_rxq_data(struct vmxnet3_so
 	int i, j, q, error;
 
 	dev = sc->vmx_dev;
-	descsz = sc->vmx_nrxdescs * sizeof(struct vmxnet3_rxdesc);
-	compsz = sc->vmx_nrxdescs * sizeof(struct vmxnet3_rxcompdesc) *
-	    VMXNET3_RXRINGS_PERQ;
+	compsz = 0;
 
 	for (q = 0; q < sc->vmx_nrxqueues; q++) {
 		rxq = &sc->vmx_rxq[q];
@@ -1035,6 +1091,11 @@ vmxnet3_alloc_rxq_data(struct vmxnet3_so
 		for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) {
 			rxr = &rxq->vxrxq_cmd_ring[i];
 
+			descsz = rxr->vxrxr_ndesc *
+			    sizeof(struct vmxnet3_rxdesc);
+			compsz += rxr->vxrxr_ndesc *
+			    sizeof(struct vmxnet3_rxcompdesc);
+
 			error = bus_dma_tag_create(bus_get_dma_tag(dev),
 			    1, 0,		/* alignment, boundary */
 			    BUS_SPACE_MAXADDR,	/* lowaddr */
@@ -1086,9 +1147,9 @@ vmxnet3_alloc_rxq_data(struct vmxnet3_so
 				return (error);
 			}
 
-			for (j = 0; j < sc->vmx_nrxdescs; j++) {
+			for (j = 0; j < rxr->vxrxr_ndesc; j++) {
 				error = bus_dmamap_create(rxr->vxrxr_rxtag, 0,
-				    &rxr->vxrxr_dmap[j]);
+				    &rxr->vxrxr_rxbuf[j].vrxb_dmamap);
 				if (error) {
 					device_printf(dev, "unable to create "
 					    "dmamap for queue %d/%d slot %d "
@@ -1110,6 +1171,7 @@ vmxnet3_free_rxq_data(struct vmxnet3_sof
 	struct vmxnet3_rxqueue *rxq;
 	struct vmxnet3_rxring *rxr;
 	struct vmxnet3_comp_ring *rxc;
+	struct vmxnet3_rxbuf *rxb;
 	int i, j, q;
 
 	dev = sc->vmx_dev;
@@ -1128,10 +1190,11 @@ vmxnet3_free_rxq_data(struct vmxnet3_sof
 			}
 
 			for (j = 0; j < rxr->vxrxr_ndesc; j++) {
-				if (rxr->vxrxr_dmap[j] != NULL) {
+				rxb = &rxr->vxrxr_rxbuf[j];
+				if (rxb->vrxb_dmamap != NULL) {
 					bus_dmamap_destroy(rxr->vxrxr_rxtag,
-					    rxr->vxrxr_dmap[j]);
-					rxr->vxrxr_dmap[j] = NULL;
+					    rxb->vrxb_dmamap);
+					rxb->vrxb_dmamap = NULL;
 				}
 			}
 		}
@@ -1275,11 +1338,12 @@ vmxnet3_init_shared_data(struct vmxnet3_
 		rxs = rxq->vxrxq_rs;
 
 		rxs->cmd_ring[0] = rxq->vxrxq_cmd_ring[0].vxrxr_dma.dma_paddr;
-		rxs->cmd_ring_len[0] = sc->vmx_nrxdescs;
+		rxs->cmd_ring_len[0] = rxq->vxrxq_cmd_ring[0].vxrxr_ndesc;
 		rxs->cmd_ring[1] = rxq->vxrxq_cmd_ring[1].vxrxr_dma.dma_paddr;
-		rxs->cmd_ring_len[1] = sc->vmx_nrxdescs;
+		rxs->cmd_ring_len[1] = rxq->vxrxq_cmd_ring[1].vxrxr_ndesc;
 		rxs->comp_ring = rxq->vxrxq_comp_ring.vxcr_dma.dma_paddr;
-		rxs->comp_ring_len = sc->vmx_nrxdescs * VMXNET3_RXRINGS_PERQ;
+		rxs->comp_ring_len = rxq->vxrxq_cmd_ring[0].vxrxr_ndesc +
+		    rxq->vxrxq_cmd_ring[1].vxrxr_ndesc;
 		rxs->driver_data = vtophys(rxq);
 		rxs->driver_data_len = sizeof(struct vmxnet3_rxqueue);
 	}
@@ -1379,7 +1443,11 @@ vmxnet3_setup_interface(struct vmxnet3_s
 	}
 
 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
-	if_initbaudrate(ifp, IF_Gbps(10)); /* Approx. */
+#if __FreeBSD_version < 1000025
+	ifp->if_baudrate = 1000000000;
+#else
+	if_initbaudrate(ifp, IF_Gbps(10));
+#endif
 	ifp->if_softc = sc;
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 	ifp->if_init = vmxnet3_init;
@@ -1476,6 +1544,7 @@ vmxnet3_txq_eof(struct vmxnet3_txqueue *
 	struct vmxnet3_txring *txr;
 	struct vmxnet3_comp_ring *txc;
 	struct vmxnet3_txcompdesc *txcd;
+	struct vmxnet3_txbuf *txb;
 	u_int sop;
 
 	sc = txq->vxtxq_sc;
@@ -1496,14 +1565,15 @@ vmxnet3_txq_eof(struct vmxnet3_txqueue *
 		}
 
 		sop = txr->vxtxr_next;
-		if (txr->vxtxr_m[sop] != NULL) {
-			bus_dmamap_sync(txr->vxtxr_txtag, txr->vxtxr_dmap[sop],
-				BUS_DMASYNC_POSTWRITE);
-			bus_dmamap_unload(txr->vxtxr_txtag,
-			    txr->vxtxr_dmap[sop]);
+		txb = &txr->vxtxr_txbuf[sop];
 
-			m_freem(txr->vxtxr_m[sop]);
-			txr->vxtxr_m[sop] = NULL;
+		if (txb->vtxb_m != NULL) {
+			bus_dmamap_sync(txr->vxtxr_txtag, txb->vtxb_dmamap,
+			    BUS_DMASYNC_POSTWRITE);
+			bus_dmamap_unload(txr->vxtxr_txtag, txb->vtxb_dmamap);
+
+			m_freem(txb->vtxb_m);
+			txb->vtxb_m = NULL;
 
 			ifp->if_opackets++;
 		}
@@ -1512,7 +1582,7 @@ vmxnet3_txq_eof(struct vmxnet3_txqueue *
 	}
 
 	if (txr->vxtxr_head == txr->vxtxr_next)
-		sc->vmx_watchdog_timer = 0;
+		txq->vxtxq_watchdog = 0;
 }
 
 static int
@@ -1521,6 +1591,7 @@ vmxnet3_newbuf(struct vmxnet3_softc *sc,
 	struct ifnet *ifp;
 	struct mbuf *m;
 	struct vmxnet3_rxdesc *rxd;
+	struct vmxnet3_rxbuf *rxb;
 	bus_dma_tag_t tag;
 	bus_dmamap_t dmap;
 	bus_dma_segment_t segs[1];
@@ -1531,13 +1602,31 @@ vmxnet3_newbuf(struct vmxnet3_softc *sc,
 	dmap = rxr->vxrxr_spare_dmap;
 	idx = rxr->vxrxr_fill;
 	rxd = &rxr->vxrxr_rxd[idx];
+	rxb = &rxr->vxrxr_rxbuf[idx];
+
+#ifdef VMXNET3_FAILPOINTS
+	KFAIL_POINT_CODE(VMXNET3_FP, newbuf, return ENOBUFS);
+	if (rxr->vxrxr_rid != 0)
+		KFAIL_POINT_CODE(VMXNET3_FP, newbuf_body_only, return ENOBUFS);
+#endif
 
 	if (rxr->vxrxr_rid == 0 && (idx % sc->vmx_rx_max_chain) == 0) {
 		flags = M_PKTHDR;
 		clsize = MCLBYTES;
 		btype = VMXNET3_BTYPE_HEAD;
 	} else {
+#if __FreeBSD_version < 902001
+		/*
+		 * These mbufs will never be used for the start of a
+		 * frame. However, roughly prior to branching releng/9.2,
+		 * bus_dmamap_load_mbuf_sg() required the mbuf to always be
+		 * a packet header. Avoid unnecessary mbuf initialization
+		 * in newer versions where that is not the case.
+		 */
+		flags = M_PKTHDR;
+#else
 		flags = 0;
+#endif
 		clsize = MJUMPAGESIZE;
 		btype = VMXNET3_BTYPE_BODY;
 	}
@@ -1546,7 +1635,7 @@ vmxnet3_newbuf(struct vmxnet3_softc *sc,
 	if (m == NULL)
 		return (ENOBUFS);
 
-	if (flags == M_PKTHDR) {
+	if (btype == VMXNET3_BTYPE_HEAD) {
 		m->m_len = m->m_pkthdr.len = clsize;
 		m_adj(m, ETHER_ALIGN);
 	} else
@@ -1561,15 +1650,14 @@ vmxnet3_newbuf(struct vmxnet3_softc *sc,
 	KASSERT(nsegs == 1,
 	    ("%s: mbuf %p with too many segments %d", __func__, m, nsegs));
 
-	if (rxr->vxrxr_m[idx] != NULL) {
-		bus_dmamap_sync(tag, rxr->vxrxr_dmap[idx],
-		    BUS_DMASYNC_POSTREAD);
-		bus_dmamap_unload(tag, rxr->vxrxr_dmap[idx]);
+	if (rxb->vrxb_m != NULL) {
+		bus_dmamap_sync(tag, rxb->vrxb_dmamap, BUS_DMASYNC_POSTREAD);
+		bus_dmamap_unload(tag, rxb->vrxb_dmamap);
 	}
 
-	rxr->vxrxr_spare_dmap = rxr->vxrxr_dmap[idx];
-	rxr->vxrxr_dmap[idx] = dmap;
-	rxr->vxrxr_m[idx] = m;
+	rxr->vxrxr_spare_dmap = rxb->vrxb_dmamap;
+	rxb->vrxb_dmamap = dmap;
+	rxb->vrxb_m = m;
 
 	rxd->addr = segs[0].ds_addr;
 	rxd->len = segs[0].ds_len;
@@ -1607,6 +1695,7 @@ vmxnet3_rxq_discard_chain(struct vmxnet3
 		rxcd = &rxc->vxcr_u.rxcd[rxc->vxcr_next];
 		if (rxcd->gen != rxc->vxcr_gen)
 			break;		/* Not expected. */
+		vmxnet3_barrier(sc, VMXNET3_BARRIER_RD);
 
 		if (++rxc->vxcr_next == rxc->vxcr_ndesc) {
 			rxc->vxcr_next = 0;
@@ -1686,7 +1775,7 @@ vmxnet3_rxq_eof(struct vmxnet3_rxqueue *
 	sc = rxq->vxrxq_sc;
 	ifp = sc->vmx_ifp;
 	rxc = &rxq->vxrxq_comp_ring;
-	m_head = NULL;
+	m_head = m_tail = NULL;
 
 	VMXNET3_RXQ_LOCK_ASSERT(rxq);
 
@@ -1697,6 +1786,7 @@ vmxnet3_rxq_eof(struct vmxnet3_rxqueue *
 		rxcd = &rxc->vxcr_u.rxcd[rxc->vxcr_next];
 		if (rxcd->gen != rxc->vxcr_gen)
 			break;
+		vmxnet3_barrier(sc, VMXNET3_BARRIER_RD);
 
 		if (++rxc->vxcr_next == rxc->vxcr_ndesc) {
 			rxc->vxcr_next = 0;
@@ -1711,7 +1801,7 @@ vmxnet3_rxq_eof(struct vmxnet3_rxqueue *
 			rxr = &rxq->vxrxq_cmd_ring[1];
 		rxd = &rxr->vxrxr_rxd[idx];
 
-		m = rxr->vxrxr_m[idx];
+		m = rxr->vxrxr_rxbuf[idx].vrxb_m;
 		KASSERT(m != NULL, ("%s: queue %d idx %d without mbuf",
 		    __func__, rxcd->qid, idx));
 
@@ -1790,7 +1880,7 @@ vmxnet3_rxq_eof(struct vmxnet3_rxqueue *
 		}
 
 nextp:
-		if (rxq->vxrxq_rs->update_rxhead) {
+		if (__predict_false(rxq->vxrxq_rs->update_rxhead)) {
 			int qid = rxcd->qid;
 			bus_size_t r;
 
@@ -1809,9 +1899,9 @@ static void
 vmxnet3_legacy_intr(void *xsc)
 {
 	struct vmxnet3_softc *sc;
-	struct ifnet *ifp;
 	struct vmxnet3_rxqueue *rxq;
 	struct vmxnet3_txqueue *txq;
+	struct ifnet *ifp;
 
 	sc = xsc;
 	rxq = &sc->vmx_rxq[0];
@@ -1892,19 +1982,22 @@ static void
 vmxnet3_txstop(struct vmxnet3_softc *sc, struct vmxnet3_txqueue *txq)
 {
 	struct vmxnet3_txring *txr;
+	struct vmxnet3_txbuf *txb;
 	int i;
 
 	txr = &txq->vxtxq_cmd_ring;
 
 	for (i = 0; i < txr->vxtxr_ndesc; i++) {
-		if (txr->vxtxr_m[i] == NULL)
+		txb = &txr->vxtxr_txbuf[i];
+
+		if (txb->vtxb_m == NULL)
 			continue;
 
-		bus_dmamap_sync(txr->vxtxr_txtag, txr->vxtxr_dmap[i],
+		bus_dmamap_sync(txr->vxtxr_txtag, txb->vtxb_dmamap,
 		    BUS_DMASYNC_POSTWRITE);
-		bus_dmamap_unload(txr->vxtxr_txtag, txr->vxtxr_dmap[i]);
-		m_freem(txr->vxtxr_m[i]);
-		txr->vxtxr_m[i] = NULL;
+		bus_dmamap_unload(txr->vxtxr_txtag, txb->vtxb_dmamap);
+		m_freem(txb->vtxb_m);
+		txb->vtxb_m = NULL;
 	}
 }
 
@@ -1912,19 +2005,22 @@ static void
 vmxnet3_rxstop(struct vmxnet3_softc *sc, struct vmxnet3_rxqueue *rxq)
 {
 	struct vmxnet3_rxring *rxr;
+	struct vmxnet3_rxbuf *rxb;
 	int i, j;
 
 	for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) {
 		rxr = &rxq->vxrxq_cmd_ring[i];
 
 		for (j = 0; j < rxr->vxrxr_ndesc; j++) {
-			if (rxr->vxrxr_m[j] == NULL)
+			rxb = &rxr->vxrxr_rxbuf[j];
+
+			if (rxb->vrxb_m == NULL)
 				continue;
-			bus_dmamap_sync(rxr->vxrxr_rxtag, rxr->vxrxr_dmap[j],
+			bus_dmamap_sync(rxr->vxrxr_rxtag, rxb->vrxb_dmamap,
 			    BUS_DMASYNC_POSTREAD);
-			bus_dmamap_unload(rxr->vxrxr_rxtag, rxr->vxrxr_dmap[j]);
-			m_freem(rxr->vxrxr_m[j]);
-			rxr->vxrxr_m[j] = NULL;
+			bus_dmamap_unload(rxr->vxrxr_rxtag, rxb->vrxb_dmamap);
+			m_freem(rxb->vrxb_m);
+			rxb->vrxb_m = NULL;
 		}
 	}
 }
@@ -2012,8 +2108,13 @@ vmxnet3_rxinit(struct vmxnet3_softc *sc,
 	 * can handle, we allocate a second MJUMPAGESIZE cluster after
 	 * it in ring 0. Ring 1 always contains MJUMPAGESIZE clusters.
 	 *
-	 * XXX BMV Keep rx_man_chain a divisor of the maximum Rx ring
-	 * size to make our life easier.
+	 * Keep rx_max_chain a divisor of the maximum Rx ring size to
+	 * to make our life easier. We do not support changing the ring
+	 * size after the attach.
+	 *
+	 * TODO If LRO is not enabled, there is little point of even
+	 * populating the second ring.
+	 *
 	 */
 	if (frame_size <= MCLBYTES)
 		sc->vmx_rx_max_chain = 1;
@@ -2231,13 +2332,15 @@ vmxnet3_txq_offload_ctx(struct mbuf *m, 
 }
 
 static int
-vmxnet3_txq_load_mbuf(struct vmxnet3_txring *txr, struct mbuf **m0,
+vmxnet3_txq_load_mbuf(struct vmxnet3_txqueue *txq, struct mbuf **m0,
     bus_dmamap_t dmap, bus_dma_segment_t segs[], int *nsegs)
 {
+	struct vmxnet3_txring *txr;
 	struct mbuf *m;
 	bus_dma_tag_t tag;
 	int maxsegs, error;
 
+	txr = &txq->vxtxq_cmd_ring;
 	m = *m0;
 	tag = txr->vxtxr_txtag;
 	maxsegs = VMXNET3_TX_MAXSEGS;
@@ -2256,15 +2359,18 @@ vmxnet3_txq_load_mbuf(struct vmxnet3_txr
 	if (error) {
 		m_freem(*m0);
 		*m0 = NULL;
-	}
+	} else
+		txq->vxtxq_sc->vmx_stats.vmst_collapsed++;
 
 	return (error);
 }
 
 static void
-vmxnet3_txq_unload_mbuf(struct vmxnet3_txring *txr, bus_dmamap_t dmap)
+vmxnet3_txq_unload_mbuf(struct vmxnet3_txqueue *txq, bus_dmamap_t dmap)
 {
+	struct vmxnet3_txring *txr;
 
+	txr = &txq->vxtxq_cmd_ring;
 	bus_dmamap_unload(txr->vxtxr_txtag, dmap);
 }
 
@@ -2282,10 +2388,12 @@ vmxnet3_txq_encap(struct vmxnet3_txqueue
 
 	sc = txq->vxtxq_sc;
 	ifp = sc->vmx_ifp;
+	start = 0;
+	txd = NULL;
 	txr = &txq->vxtxq_cmd_ring;
-	dmap = txr->vxtxr_dmap[txr->vxtxr_head];
+	dmap = txr->vxtxr_txbuf[txr->vxtxr_head].vtxb_dmamap;
 
-	error = vmxnet3_txq_load_mbuf(txr, m0, dmap, segs, &nsegs);
+	error = vmxnet3_txq_load_mbuf(txq, m0, dmap, segs, &nsegs);
 	if (error)
 		return (error);
 
@@ -2295,19 +2403,20 @@ vmxnet3_txq_encap(struct vmxnet3_txqueue
 	    ("%s: mbuf %p with too many segments %d", __func__, m, nsegs));
 
 	if (VMXNET3_TXRING_AVAIL(txr) < nsegs) {
-		vmxnet3_txq_unload_mbuf(txr, dmap);
+		txq->vxtxq_stats.vtxrs_full++;
+		vmxnet3_txq_unload_mbuf(txq, dmap);
 		return (ENOSPC);
 	} else if (m->m_pkthdr.csum_flags & VMXNET3_CSUM_ALL_OFFLOAD) {
 		error = vmxnet3_txq_offload_ctx(m, &etype, &proto, &start);
 		if (error) {
-			vmxnet3_txq_unload_mbuf(txr, dmap);
+			vmxnet3_txq_unload_mbuf(txq, dmap);
 			m_freem(m);
 			*m0 = NULL;
 			return (error);
 		}
 	}
 
-	txr->vxtxr_m[txr->vxtxr_head] = m = *m0;
+	txr->vxtxr_txbuf[txr->vxtxr_head].vtxb_m = m = *m0;
 	sop = &txr->vxtxr_txd[txr->vxtxr_head];
 	gen = txr->vxtxr_gen ^ 1;	/* Owned by cpu (yet) */
 
@@ -2352,8 +2461,15 @@ vmxnet3_txq_encap(struct vmxnet3_txqueue
 	}
 
 	/* Finally, change the ownership. */
+	vmxnet3_barrier(sc, VMXNET3_BARRIER_WR);
 	sop->gen ^= 1;
 
+	if (++txq->vxtxq_ts->npending >= txq->vxtxq_ts->intr_threshold) {
+		txq->vxtxq_ts->npending = 0;
+		vmxnet3_write_bar0(sc, VMXNET3_BAR0_TXH(txq->vxtxq_id),
+		    txr->vxtxr_head);
+	}
+
 	return (0);
 }
 
@@ -2383,9 +2499,8 @@ vmxnet3_start_locked(struct ifnet *ifp)
 			break;
 
 		if (vmxnet3_txq_encap(txq, &m_head) != 0) {
-			if (m_head == NULL)
-				break;
-			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
+			if (m_head != NULL)
+				IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
 			break;
 		}
 
@@ -2394,9 +2509,12 @@ vmxnet3_start_locked(struct ifnet *ifp)
 	}
 
 	if (tx > 0) {
-		/* bus_dmamap_sync() ? */
-		vmxnet3_write_bar0(sc, VMXNET3_BAR0_TXH(0), txr->vxtxr_head);
-		sc->vmx_watchdog_timer = VMXNET3_WATCHDOG_TIMEOUT;
+		if (txq->vxtxq_ts->npending > 0) {
+			txq->vxtxq_ts->npending = 0;
+			vmxnet3_write_bar0(sc, VMXNET3_BAR0_TXH(txq->vxtxq_id),
+			    txr->vxtxr_head);
+		}
+		txq->vxtxq_watchdog = VMXNET3_WATCHDOG_TIMEOUT;
 	}
 }
 
@@ -2506,8 +2624,9 @@ vmxnet3_set_rxfilter(struct vmxnet3_soft
 		ds->mcast_tablelen = cnt * ETHER_ADDR_LEN;
 	}
 
-	vmxnet3_write_cmd(sc, VMXNET3_CMD_SET_FILTER);
 	ds->rxmode = mode;
+
+	vmxnet3_write_cmd(sc, VMXNET3_CMD_SET_FILTER);
 	vmxnet3_write_cmd(sc, VMXNET3_CMD_SET_RXMODE);
 }
 
@@ -2635,37 +2754,54 @@ vmxnet3_ioctl(struct ifnet *ifp, u_long 
 	return (error);
 }
 
-static void
-vmxnet3_watchdog(struct vmxnet3_softc *sc)
+static int
+vmxnet3_watchdog(struct vmxnet3_txqueue *txq)
 {
-	struct ifnet *ifp;
-	struct vmxnet3_txqueue *txq;
+	struct vmxnet3_softc *sc;
 
-	ifp = sc->vmx_ifp;
-	txq = &sc->vmx_txq[0];
+	sc = txq->vxtxq_sc;
 
 	VMXNET3_TXQ_LOCK(txq);
-	if (sc->vmx_watchdog_timer == 0 || --sc->vmx_watchdog_timer) {
+	if (txq->vxtxq_watchdog == 0 || --txq->vxtxq_watchdog) {
 		VMXNET3_TXQ_UNLOCK(txq);
-		return;
+		return (0);
 	}
 	VMXNET3_TXQ_UNLOCK(txq);
 
-	if_printf(ifp, "watchdog timeout -- resetting\n");
-	ifp->if_oerrors++;
-	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
-	vmxnet3_init_locked(sc);
+	if_printf(sc->vmx_ifp, "watchdog timeout on queue %d\n",
+	    txq->vxtxq_id);
+	return (1);
+}
+
+static void
+vmxnet3_refresh_stats(struct vmxnet3_softc *sc)
+{
+
+	vmxnet3_write_cmd(sc, VMXNET3_CMD_GET_STATS);
 }
 
 static void
 vmxnet3_tick(void *xsc)
 {
 	struct vmxnet3_softc *sc;
+	struct ifnet *ifp;
+	int i, timedout;
 
 	sc = xsc;
+	ifp = sc->vmx_ifp;
+	timedout = 0;
 
-	vmxnet3_watchdog(sc);
-	callout_reset(&sc->vmx_tick, hz, vmxnet3_tick, sc);
+	VMXNET3_CORE_LOCK_ASSERT(sc);
+	vmxnet3_refresh_stats(sc);
+
+	for (i = 0; i < sc->vmx_ntxqueues; i++)
+		timedout |= vmxnet3_watchdog(&sc->vmx_txq[i]);
+
+	if (timedout != 0) {
+		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+		vmxnet3_init_locked(sc);
+	} else
+		callout_reset(&sc->vmx_tick, hz, vmxnet3_tick, sc);
 }
 
 static int
@@ -2718,6 +2854,7 @@ vmxnet3_media_status(struct ifnet *ifp, 
 static int
 vmxnet3_media_change(struct ifnet *ifp)
 {
+
 	/* Ignore. */
 	return (0);
 }
@@ -2754,13 +2891,201 @@ vmxnet3_get_lladdr(struct vmxnet3_softc 
 	sc->vmx_lladdr[5] = mh >> 8;
 }
 
-static uint32_t __unused
-vmxnet3_read_bar0(struct vmxnet3_softc *sc, bus_size_t r)
+static void
+vmxnet3_setup_txq_sysctl(struct vmxnet3_txqueue *txq,
+    struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
+{
+	struct sysctl_oid *node, *txsnode;
+	struct sysctl_oid_list *list, *txslist;
+	struct vmxnet3_txq_stats *stats;
+	struct UPT1_TxStats *txstats;
+	char namebuf[16];
+
+	stats = &txq->vxtxq_stats;
+	txstats = &txq->vxtxq_ts->stats;
+
+	snprintf(namebuf, sizeof(namebuf), "txq%d", txq->vxtxq_id);
+	node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, CTLFLAG_RD,
+	    NULL, "Transmit Queue");
+	txq->vxtxq_sysctl = list = SYSCTL_CHILDREN(node);
+
+	SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "ringfull", CTLFLAG_RD,
+	    &stats->vtxrs_full, "Tx ring full");
+
+	/*
+	 * Add statistics reported by the host. These are updated once
+	 * per second.
+	 */
+	txsnode = SYSCTL_ADD_NODE(ctx, list, OID_AUTO, "hstats", CTLFLAG_RD,
+	    NULL, "Host Statistics");
+	txslist = SYSCTL_CHILDREN(txsnode);
+	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "tso_packets", CTLFLAG_RD,
+	    &txstats->TSO_packets, "TSO packets");
+	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "tso_bytes", CTLFLAG_RD,
+	    &txstats->TSO_bytes, "TSO bytes");
+	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "ucast_packets", CTLFLAG_RD,
+	    &txstats->ucast_packets, "Unicast packets");
+	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "unicast_bytes", CTLFLAG_RD,
+	    &txstats->ucast_bytes, "Unicast bytes");
+	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "mcast_packets", CTLFLAG_RD,
+	    &txstats->mcast_packets, "Multicast packets");
+	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "mcast_bytes", CTLFLAG_RD,
+	    &txstats->mcast_bytes, "Multicast bytes");
+	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "error", CTLFLAG_RD,
+	    &txstats->error, "Errors");
+	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "discard", CTLFLAG_RD,
+	    &txstats->discard, "Discards");
+}
+
+static void
+vmxnet3_setup_rxq_sysctl(struct vmxnet3_rxqueue *rxq,
+    struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
+{
+	struct sysctl_oid *node, *rxsnode;
+	struct sysctl_oid_list *list, *rxslist;
+	struct vmxnet3_rxq_stats *stats;
+	struct UPT1_RxStats *rxstats;
+	char namebuf[16];
+
+	stats = &rxq->vxrxq_stats;
+	rxstats = &rxq->vxrxq_rs->stats;
+
+	snprintf(namebuf, sizeof(namebuf), "rxq%d", rxq->vxrxq_id);
+	node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, CTLFLAG_RD,
+	    NULL, "Receive Queue");
+	rxq->vxrxq_sysctl = list = SYSCTL_CHILDREN(node);
+
+	/*
+	 * Add statistics reported by the host. These are updated once
+	 * per second.
+	 */
+	rxsnode = SYSCTL_ADD_NODE(ctx, list, OID_AUTO, "hstats", CTLFLAG_RD,
+	    NULL, "Host Statistics");
+	rxslist = SYSCTL_CHILDREN(rxsnode);
+	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "lro_packets", CTLFLAG_RD,
+	    &rxstats->LRO_packets, "LRO packets");
+	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "lro_bytes", CTLFLAG_RD,
+	    &rxstats->LRO_bytes, "LRO bytes");
+	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "ucast_packets", CTLFLAG_RD,
+	    &rxstats->ucast_packets, "Unicast packets");
+	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "unicast_bytes", CTLFLAG_RD,
+	    &rxstats->ucast_bytes, "Unicast bytes");
+	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "mcast_packets", CTLFLAG_RD,
+	    &rxstats->mcast_packets, "Multicast packets");
+	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "mcast_bytes", CTLFLAG_RD,
+	    &rxstats->mcast_bytes, "Multicast bytes");
+	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "bcast_packets", CTLFLAG_RD,
+	    &rxstats->bcast_packets, "Broadcast packets");
+	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "bcast_bytes", CTLFLAG_RD,
+	    &rxstats->bcast_bytes, "Broadcast bytes");
+	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "nobuffer", CTLFLAG_RD,
+	    &rxstats->nobuffer, "No buffer");
+	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "error", CTLFLAG_RD,
+	    &rxstats->error, "Errors");
+}
+
+#ifdef VMXNET3_DEBUG_SYSCTL
+static void
+vmxnet3_setup_debug_sysctl(struct vmxnet3_softc *sc,
+    struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
+{
+	struct sysctl_oid *node;
+	struct sysctl_oid_list *list;
+	int i;
+
+	for (i = 0; i < sc->vmx_ntxqueues; i++) {
+		struct vmxnet3_txqueue *txq = &sc->vmx_txq[i];
+
+		node = SYSCTL_ADD_NODE(ctx, txq->vxtxq_sysctl, OID_AUTO,
+		    "debug", CTLFLAG_RD, NULL, "");
+		list = SYSCTL_CHILDREN(node);
+
+		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd_head", CTLFLAG_RD,
+		    &txq->vxtxq_cmd_ring.vxtxr_head, 0, "");
+		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd_next", CTLFLAG_RD,
+		    &txq->vxtxq_cmd_ring.vxtxr_next, 0, "");
+		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd_ndesc", CTLFLAG_RD,
+		    &txq->vxtxq_cmd_ring.vxtxr_ndesc, 0, "");
+		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd_gen", CTLFLAG_RD,
+		    &txq->vxtxq_cmd_ring.vxtxr_gen, 0, "");
+		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_next", CTLFLAG_RD,
+		    &txq->vxtxq_comp_ring.vxcr_next, 0, "");
+		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_ndesc", CTLFLAG_RD,
+		    &txq->vxtxq_comp_ring.vxcr_ndesc, 0,"");
+		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "comp_gen", CTLFLAG_RD,
+		    &txq->vxtxq_comp_ring.vxcr_gen, 0, "");
+	}
+
+	for (i = 0; i < sc->vmx_nrxqueues; i++) {
+		struct vmxnet3_rxqueue *rxq = &sc->vmx_rxq[i];
+
+		node = SYSCTL_ADD_NODE(ctx, rxq->vxrxq_sysctl, OID_AUTO,
+		    "debug", CTLFLAG_RD, NULL, "");
+		list = SYSCTL_CHILDREN(node);
+
+		/* Assumes VMXNET3_RXRINGS_PERQ == 2. */
+		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd0_fill", CTLFLAG_RD,
+		    &rxq->vxrxq_cmd_ring[0].vxrxr_fill, 0, "");
+		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd0_ndesc", CTLFLAG_RD,
+		    &rxq->vxrxq_cmd_ring[0].vxrxr_ndesc, 0, "");
+		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd0_gen", CTLFLAG_RD,
+		    &rxq->vxrxq_cmd_ring[0].vxrxr_gen, 0, "");
+		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd1_fill", CTLFLAG_RD,
+		    &rxq->vxrxq_cmd_ring[1].vxrxr_fill, 0, "");
+		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd1_ndesc", CTLFLAG_RD,
+		    &rxq->vxrxq_cmd_ring[1].vxrxr_ndesc, 0, "");
+		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd1_gen", CTLFLAG_RD,
+		    &rxq->vxrxq_cmd_ring[1].vxrxr_gen, 0, "");
+		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_next", CTLFLAG_RD,
+		    &rxq->vxrxq_comp_ring.vxcr_next, 0, "");
+		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_ndesc", CTLFLAG_RD,
+		    &rxq->vxrxq_comp_ring.vxcr_ndesc, 0,"");
+		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "comp_gen", CTLFLAG_RD,
+		    &rxq->vxrxq_comp_ring.vxcr_gen, 0, "");
+	}
+}
+#endif
+
+static void
+vmxnet3_setup_queue_sysctl(struct vmxnet3_softc *sc,
+    struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
+{
+	int i;
+
+	for (i = 0; i < sc->vmx_ntxqueues; i++)
+		vmxnet3_setup_txq_sysctl(&sc->vmx_txq[i], ctx, child);
+	for (i = 0; i < sc->vmx_nrxqueues; i++)
+		vmxnet3_setup_rxq_sysctl(&sc->vmx_rxq[i], ctx, child);
+
+#ifdef VMXNET3_DEBUG_SYSCTL
+	vmxnet3_setup_debug_sysctl(sc, ctx, child);
+#endif
+}
+
+static void
+vmxnet3_setup_sysctl(struct vmxnet3_softc *sc)
 {
+	device_t dev;
+	struct vmxnet3_statistics *stats;
+	struct sysctl_ctx_list *ctx;
+	struct sysctl_oid *tree;
+	struct sysctl_oid_list *child;
 
-	bus_space_barrier(sc->vmx_iot0, sc->vmx_ioh0, r, 4,
-	    BUS_SPACE_BARRIER_READ);
-	return (bus_space_read_4(sc->vmx_iot0, sc->vmx_ioh0, r));
+	dev = sc->vmx_dev;
+	ctx = device_get_sysctl_ctx(dev);
+	tree = device_get_sysctl_tree(dev);
+	child = SYSCTL_CHILDREN(tree);
+
+	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "ntxqueues", CTLFLAG_RD,
+	    &sc->vmx_ntxqueues, 0, "Number of Tx queues");
+	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "nrxqueues", CTLFLAG_RD,
+	    &sc->vmx_nrxqueues, 0, "Number of Rx queues");
+
+	stats = &sc->vmx_stats;
+	SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "collapsed", CTLFLAG_RD,
+	    &stats->vmst_collapsed, "Tx mbuf chains collapsed");
+
+	vmxnet3_setup_queue_sysctl(sc, ctx, child);
 }
 
 static void
@@ -2768,16 +3093,12 @@ vmxnet3_write_bar0(struct vmxnet3_softc 
 {
 
 	bus_space_write_4(sc->vmx_iot0, sc->vmx_ioh0, r, v);
-	bus_space_barrier(sc->vmx_iot0, sc->vmx_ioh0, r, 4,
-	    BUS_SPACE_BARRIER_WRITE);
 }
 
 static uint32_t
 vmxnet3_read_bar1(struct vmxnet3_softc *sc, bus_size_t r)
 {
 
-	bus_space_barrier(sc->vmx_iot1, sc->vmx_ioh1, r, 4,
-	    BUS_SPACE_BARRIER_READ);
 	return (bus_space_read_4(sc->vmx_iot1, sc->vmx_ioh1, r));
 }
 
@@ -2786,8 +3107,6 @@ vmxnet3_write_bar1(struct vmxnet3_softc 
 {
 
 	bus_space_write_4(sc->vmx_iot1, sc->vmx_ioh1, r, v);
-	bus_space_barrier(sc->vmx_iot1, sc->vmx_ioh1, r, 4,
-	    BUS_SPACE_BARRIER_WRITE);
 }

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201308042201.r74M17jv013420>