svn commit: r253334 - projects/vmxnet/sys/dev/vmware/vmxnet3

Bryan Venteicher bryanv at FreeBSD.org
Sun Jul 14 03:45:04 UTC 2013


Author: bryanv
Date: Sun Jul 14 03:45:03 2013
New Revision: 253334
URL: http://svnweb.freebsd.org/changeset/base/253334

Log:
  Various WIP improvements to the vmxnet3 driver

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

Modified: projects/vmxnet/sys/dev/vmware/vmxnet3/if_vmx.c
==============================================================================
--- projects/vmxnet/sys/dev/vmware/vmxnet3/if_vmx.c	Sun Jul 14 03:08:52 2013	(r253333)
+++ projects/vmxnet/sys/dev/vmware/vmxnet3/if_vmx.c	Sun Jul 14 03:45:03 2013	(r253334)
@@ -35,10 +35,13 @@ __FBSDID("$FreeBSD$");
 #include <vm/vm.h>
 #include <vm/pmap.h>
 
-#include <net/if.h>
 #include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
 #include <net/if_dl.h>
+#include <net/if_types.h>
 #include <net/if_media.h>
+#include <net/if_vlan_var.h>
 
 #include <net/bpf.h>
 
@@ -47,6 +50,11 @@ __FBSDID("$FreeBSD$");
 
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
 
 #include <machine/bus.h>
 #include <machine/resource.h>
@@ -59,6 +67,9 @@ __FBSDID("$FreeBSD$");
 #include "if_vmxreg.h"
 #include "if_vmxvar.h"
 
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
 static int	vmxnet3_probe(device_t);
 static int	vmxnet3_attach(device_t);
 static int	vmxnet3_detach(device_t);
@@ -66,7 +77,15 @@ static int	vmxnet3_shutdown(device_t);
 
 static int	vmxnet3_alloc_resources(struct vmxnet3_softc *);
 static void	vmxnet3_free_resources(struct vmxnet3_softc *);
-static int	vmxnet3_query(struct vmxnet3_softc *);
+static int	vmxnet3_check_version(struct vmxnet3_softc *);
+static void	vmxnet3_initial_config(struct vmxnet3_softc *);
+
+static int	vmxnet3_init_rxq(struct vmxnet3_softc *, int);
+static int	vmxnet3_init_txq(struct vmxnet3_softc *, int);
+static int	vmxnet3_alloc_rxtx_queues(struct vmxnet3_softc *);
+static void	vmxnet3_destroy_rxq(struct vmxnet3_rxqueue *);
+static void 	vmxnet3_destroy_txq(struct vmxnet3_txqueue *);
+static void	vmxnet3_free_rxtx_queues(struct vmxnet3_softc *);
 
 static int	vmxnet3_alloc_shared_data(struct vmxnet3_softc *);
 static void	vmxnet3_free_shared_data(struct vmxnet3_softc *);
@@ -88,7 +107,8 @@ static void	vmxnet3_txeof(struct vmxnet3
 static void	vmxnet3_rx_csum(struct vmxnet3_rxcompdesc *, struct mbuf *);
 static int	vmxnet3_newbuf(struct vmxnet3_softc *, struct vmxnet3_rxring *);
 static void	vmxnet3_rxeof(struct vmxnet3_softc *, struct vmxnet3_rxqueue *);
-static void	vmxnet3_intr(void *);
+static void	vmxnet3_legacy_intr(void *);
+static int	vmxnet3_setup_interrupts(struct vmxnet3_softc *);
 
 static void	vmxnet3_txstop(struct vmxnet3_softc *, struct vmxnet3_txqueue *);
 static void	vmxnet3_rxstop(struct vmxnet3_softc *, struct vmxnet3_rxqueue *);
@@ -96,7 +116,10 @@ static void	vmxnet3_stop(struct vmxnet3_
 
 static void	vmxnet3_txinit(struct vmxnet3_softc *, struct vmxnet3_txqueue *);
 static int	vmxnet3_rxinit(struct vmxnet3_softc *, struct vmxnet3_rxqueue *);
-static int	vmxnet3_reset_queues(struct vmxnet3_softc *);
+static int	vmxnet3_reinit_queues(struct vmxnet3_softc *);
+static int	vmxnet3_enable_device(struct vmxnet3_softc *);
+static void	vmxnet3_reinit_rxfilters(struct vmxnet3_softc *);
+static int 	vmxnet3_reinit(struct vmxnet3_softc *);
 static void	vmxnet3_init_locked(struct vmxnet3_softc *);
 static void	vmxnet3_init(void *);
 
@@ -104,17 +127,24 @@ static int	vmxnet3_encap_offload_ctx(str
 static int	vmxnet3_encap_load_mbuf(struct vmxnet3_softc *,
 		    struct vmxnet3_txring *, struct mbuf **, bus_dmamap_t,
 		    bus_dma_segment_t [], int *);
-static int	vmxnet3_encap(struct vmxnet3_softc *, struct mbuf **);
+static void	vmxnet3_encap_unload_mbuf(struct vmxnet3_softc *,
+		    struct vmxnet3_txring *, bus_dmamap_t);
+static int	vmxnet3_encap(struct vmxnet3_softc *, struct vmxnet3_txqueue *,
+		    struct mbuf **);
 static void	vmxnet3_start_locked(struct ifnet *);
 static void	vmxnet3_start(struct ifnet *);
 
+static void	vmxnet3_update_vlan_filter(struct vmxnet3_softc *, int,
+		    uint16_t);
+static void 	vmxnet3_register_vlan(void *, struct ifnet *, uint16_t);
+static void 	vmxnet3_unregister_vlan(void *, struct ifnet *, uint16_t);
 static void	vmxnet3_set_rxfilter(struct vmxnet3_softc *);
 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 void	vmxnet3_tick(void *);
-static void	vmxnet3_link_state(struct vmxnet3_softc *);
+static void	vmxnet3_link_status(struct vmxnet3_softc *);
 static void	vmxnet3_media_status(struct ifnet *, struct ifmediareq *);
 static int	vmxnet3_media_change(struct ifnet *);
 static void	vmxnet3_set_lladdr(struct vmxnet3_softc *);
@@ -185,15 +215,19 @@ vmxnet3_attach(device_t dev)
 	sc->vmx_dev = dev;
 
 	VMXNET3_CORE_LOCK_INIT(sc, device_get_nameunit(dev));
-	VMXNET3_RX_LOCK_INIT(sc, device_get_nameunit(dev));
-	VMXNET3_TX_LOCK_INIT(sc, device_get_nameunit(dev));
 	callout_init_mtx(&sc->vmx_tick, &sc->vmx_mtx, 0);
 
+	vmxnet3_initial_config(sc);
+
 	error = vmxnet3_alloc_resources(sc);
 	if (error)
 		goto fail;
 
-	error = vmxnet3_query(sc);
+	error = vmxnet3_check_version(sc);
+	if (error)
+		goto fail;
+
+	error = vmxnet3_alloc_rxtx_queues(sc);
 	if (error)
 		goto fail;
 
@@ -205,15 +239,14 @@ vmxnet3_attach(device_t dev)
 	if (error)
 		goto fail;
 
-	error = bus_setup_intr(dev, sc->vmx_irq, INTR_TYPE_NET | INTR_MPSAFE,
-	    NULL, vmxnet3_intr, sc, &sc->vmx_intrhand);
+	error = vmxnet3_setup_interrupts(sc);
 	if (error) {
 		ether_ifdetach(sc->vmx_ifp);
 		device_printf(dev, "could not set up interrupt\n");
 		goto fail;
 	}
 
-	vmxnet3_link_state(sc);
+	vmxnet3_link_status(sc);
 
 fail:
 	if (error)
@@ -244,11 +277,22 @@ vmxnet3_detach(device_t dev)
 		sc->vmx_intrhand = NULL;
 	}
 
+	if (sc->vmx_vlan_attach != NULL) {
+		EVENTHANDLER_DEREGISTER(vlan_config, sc->vmx_vlan_attach);
+		sc->vmx_vlan_attach = NULL;
+	}
+	if (sc->vmx_vlan_detach != NULL) {
+		EVENTHANDLER_DEREGISTER(vlan_config, sc->vmx_vlan_detach);
+		sc->vmx_vlan_detach = NULL;
+	}
+
 	if (ifp != NULL) {
 		if_free(ifp);
 		sc->vmx_ifp = NULL;
 	}
 
+	ifmedia_removeall(&sc->vmx_media);
+
 	if (sc->vmx_irq != NULL) {
 		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vmx_irq);
 		sc->vmx_irq = NULL;
@@ -256,10 +300,9 @@ vmxnet3_detach(device_t dev)
 
 	vmxnet3_free_data(sc);
 	vmxnet3_free_resources(sc);
+	vmxnet3_free_rxtx_queues(sc);
 
 	VMXNET3_CORE_LOCK_DESTROY(sc);
-	VMXNET3_TX_LOCK_DESTROY(sc);
-	VMXNET3_RX_LOCK_DESTROY(sc);
 
 	return (0);
 }
@@ -303,6 +346,10 @@ vmxnet3_alloc_resources(struct vmxnet3_s
 	sc->vmx_iot1 = rman_get_bustag(sc->vmx_res1);
 	sc->vmx_ioh1 = rman_get_bushandle(sc->vmx_res1);
 
+	/*
+	 * XXX This really doesn't belong here, but is fine until
+	 * we support MSI/MSIX.
+	 */
 	rid = 0;
 	sc->vmx_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
 	   RF_SHAREABLE | RF_ACTIVE);
@@ -336,7 +383,7 @@ vmxnet3_free_resources(struct vmxnet3_so
 }
 
 static int
-vmxnet3_query(struct vmxnet3_softc *sc)
+vmxnet3_check_version(struct vmxnet3_softc *sc)
 {
 	device_t dev;
 	uint32_t version;
@@ -348,22 +395,149 @@ vmxnet3_query(struct vmxnet3_softc *sc)
 		device_printf(dev, "unsupported hardware version %#x\n",
 		    version);
 		return (ENOTSUP);
-	}
-	vmxnet3_write_bar1(sc, VMXNET3_BAR1_VRRS, 1);
+	} else
+		vmxnet3_write_bar1(sc, VMXNET3_BAR1_VRRS, 1);
 
 	version = vmxnet3_read_bar1(sc, VMXNET3_BAR1_UVRS);
 	if ((version & 0x01) == 0) {
 		device_printf(dev, "unsupported UPT version %#x\n", version);
 		return (ENOTSUP);
+	} else 
+		vmxnet3_write_bar1(sc, VMXNET3_BAR1_UVRS, 1);
+
+	return (0);
+}
+
+static void
+vmxnet3_initial_config(struct vmxnet3_softc *sc)
+{
+
+	sc->vmx_ntxqueues = 1;
+	sc->vmx_nrxqueues = 1;
+	sc->vmx_ntxdescs = VMXNET3_MAX_TX_NDESC;
+	sc->vmx_nrxdescs = VMXNET3_MAX_RX_NDESC;
+	sc->vmx_max_rxsegs = 1;
+}
+
+static int
+vmxnet3_init_rxq(struct vmxnet3_softc *sc, int q)
+{
+	struct vmxnet3_rxqueue *rxq;
+	struct vmxnet3_rxring *rxr;
+	int i;
+
+	rxq = &sc->vmx_rxq[q];
+
+	snprintf(rxq->vxrxq_name, sizeof(rxq->vxrxq_name), "%s-rx%d",
+	    device_get_nameunit(sc->vmx_dev), q);
+	mtx_init(&rxq->vxrxq_mtx, rxq->vxrxq_name, NULL, MTX_DEF);
+
+	rxq->vxrxq_sc = sc;
+	rxq->vxrxq_id = q;
+
+	for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) {
+		rxr = &rxq->vxrxq_cmd_ring[i];
+		rxr->vxrxr_rid = i;
+		rxr->vxrxr_ndesc = sc->vmx_nrxdescs;
 	}
-	vmxnet3_write_bar1(sc, VMXNET3_BAR1_UVRS, 1);
 
-	vmxnet3_get_lladdr(sc);
+	rxq->vxrxq_comp_ring.vxcr_ndesc =
+	    sc->vmx_nrxdescs * VMXNET3_RXRINGS_PERQ;
+
+	return (0);
+}
+
+static int
+vmxnet3_init_txq(struct vmxnet3_softc *sc, int q)
+{
+	struct vmxnet3_txqueue *txq;
+
+	txq = &sc->vmx_txq[q];
+
+	snprintf(txq->vxtxq_name, sizeof(txq->vxtxq_name), "%s-tx%d",
+	    device_get_nameunit(sc->vmx_dev), q);
+	mtx_init(&txq->vxtxq_mtx, txq->vxtxq_name, NULL, MTX_DEF);
+
+	txq->vxtxq_sc = sc;
+	txq->vxtxq_id = q;
+
+	txq->vxtxq_cmd_ring.vxtxr_ndesc = sc->vmx_ntxdescs;
+	txq->vxtxq_comp_ring.vxcr_ndesc = sc->vmx_ntxdescs;
 
 	return (0);
 }
 
 static int
+vmxnet3_alloc_rxtx_queues(struct vmxnet3_softc *sc)
+{
+	int i, error;
+
+	sc->vmx_rxq = malloc(sizeof(struct vmxnet3_rxqueue) *
+	    sc->vmx_nrxqueues, M_DEVBUF, M_NOWAIT | M_ZERO);
+	sc->vmx_txq = malloc(sizeof(struct vmxnet3_txqueue) *
+	    sc->vmx_ntxqueues, M_DEVBUF, M_NOWAIT | M_ZERO);
+	if (sc->vmx_rxq == NULL || sc->vmx_txq == NULL)
+		return (ENOMEM);
+
+	for (i = 0; i < sc->vmx_nrxqueues; i++) {
+		error = vmxnet3_init_rxq(sc, i);
+		if (error)
+			return (error);
+	}
+
+	for (i = 0; i < sc->vmx_ntxqueues; i++) {
+		error = vmxnet3_init_txq(sc, i);
+		if (error)
+			return (error);
+	}
+
+	return (0);
+}
+
+static void
+vmxnet3_destroy_rxq(struct vmxnet3_rxqueue *rxq)
+{
+
+	rxq->vxrxq_sc = NULL;
+	rxq->vxrxq_id = -1;
+
+	if (mtx_initialized(&rxq->vxrxq_mtx) != 0)
+		mtx_destroy(&rxq->vxrxq_mtx);
+}
+
+static void
+vmxnet3_destroy_txq(struct vmxnet3_txqueue *txq)
+{
+
+	txq->vxtxq_sc = NULL;
+	txq->vxtxq_id = -1;
+
+	if (mtx_initialized(&txq->vxtxq_mtx) != 0)
+		mtx_destroy(&txq->vxtxq_mtx);
+
+}
+
+static void
+vmxnet3_free_rxtx_queues(struct vmxnet3_softc *sc)
+{
+	int i;
+
+	if (sc->vmx_rxq != NULL) {
+		for (i = 0; i < sc->vmx_nrxqueues; i++)
+			vmxnet3_destroy_rxq(&sc->vmx_rxq[i]);
+		free(sc->vmx_rxq, M_DEVBUF);
+		sc->vmx_rxq = NULL;
+	}
+
+	if (sc->vmx_txq != NULL) {
+		for (i = 0; i < sc->vmx_ntxqueues; i++)
+			vmxnet3_destroy_txq(&sc->vmx_txq[i]);
+		free(sc->vmx_txq, M_DEVBUF);
+		sc->vmx_txq = NULL;
+	}
+}
+
+static int
 vmxnet3_alloc_shared_data(struct vmxnet3_softc *sc)
 {
 	device_t dev;
@@ -381,8 +555,8 @@ vmxnet3_alloc_shared_data(struct vmxnet3
 	}
 	sc->vmx_ds = (struct vmxnet3_driver_shared *) sc->vmx_ds_dma.dma_vaddr;
 
-	size  = VMXNET3_TX_QUEUES * sizeof(struct vmxnet3_txq_shared);
-	size += VMXNET3_RX_QUEUES * sizeof(struct vmxnet3_rxq_shared);
+	size = sc->vmx_ntxqueues * sizeof(struct vmxnet3_txq_shared) +
+	    sc->vmx_nrxqueues * sizeof(struct vmxnet3_rxq_shared);
 	error = vmxnet3_dma_malloc(sc, size, 128, &sc->vmx_qs_dma);
 	if (error) {
 		device_printf(dev, "cannot alloc queue shared memory\n");
@@ -391,11 +565,11 @@ vmxnet3_alloc_shared_data(struct vmxnet3
 	sc->vmx_qs = (void *) sc->vmx_qs_dma.dma_vaddr;
 	kva = sc->vmx_qs;
 
-	for (i = 0; i < VMXNET3_TX_QUEUES; i++) {
+	for (i = 0; i < sc->vmx_ntxqueues; i++) {
 		sc->vmx_txq[i].vxtxq_ts = (struct vmxnet3_txq_shared *) kva;
 		kva += sizeof(struct vmxnet3_txq_shared);
 	}
-	for (i = 0; i < VMXNET3_RX_QUEUES; i++) {
+	for (i = 0; i < sc->vmx_nrxqueues; i++) {
 		sc->vmx_rxq[i].vxrxq_rs = (struct vmxnet3_rxq_shared *) kva;
 		kva += sizeof(struct vmxnet3_rxq_shared);
 	}
@@ -429,14 +603,18 @@ vmxnet3_alloc_txq_data(struct vmxnet3_so
 	int i, q, error;
 
 	dev = sc->vmx_dev;
-	descsz = VMXNET3_TX_NDESC * sizeof(struct vmxnet3_txdesc);
-	compsz = VMXNET3_TX_NCOMPDESC * sizeof(struct vmxnet3_txcompdesc);
+	descsz = sc->vmx_ntxdescs * sizeof(struct vmxnet3_txdesc);
+	compsz = sc->vmx_ntxdescs * sizeof(struct vmxnet3_txcompdesc);
 
-	for (q = 0; q < VMXNET3_TX_QUEUES; q++) {
+	for (q = 0; q < sc->vmx_ntxqueues; q++) {
 		txq = &sc->vmx_txq[q];
 		txr = &txq->vxtxq_cmd_ring;
 		txc = &txq->vxtxq_comp_ring;
 
+		/*
+		 * XXX BMV Need better way to determine the maximum
+		 * size/segments/segsize arguments.
+		 */
 		error = bus_dma_tag_create(bus_get_dma_tag(dev),
 		    1, 0,			/* alignment, boundary */
 		    BUS_SPACE_MAXADDR,		/* lowaddr */
@@ -472,7 +650,7 @@ vmxnet3_alloc_txq_data(struct vmxnet3_so
 		txc->vxcr_u.txcd =
 		    (struct vmxnet3_txcompdesc *) txc->vxcr_dma.dma_vaddr;
 
-		for (i = 0; i < VMXNET3_TX_NDESC; i++) {
+		for (i = 0; i < sc->vmx_ntxdescs; i++) {
 			error = bus_dmamap_create(txr->vxtxr_txtag, 0,
 			    &txr->vxtxr_dmap[i]);
 			if (error) {
@@ -497,12 +675,12 @@ vmxnet3_free_txq_data(struct vmxnet3_sof
 
 	dev = sc->vmx_dev;
 
-	for (q = 0; q < VMXNET3_TX_QUEUES; q++) {
+	for (q = 0; q < sc->vmx_ntxqueues; q++) {
 		txq = &sc->vmx_txq[q];
 		txr = &txq->vxtxq_cmd_ring;
 		txc = &txq->vxtxq_comp_ring;
 
-		for (i = 0; i < VMXNET3_TX_NDESC; i++) {
+		for (i = 0; i < txr->vxtxr_ndesc; i++) {
 			if (txr->vxtxr_dmap[i] != NULL) {
 				bus_dmamap_destroy(txr->vxtxr_txtag,
 				    txr->vxtxr_dmap[i]);
@@ -538,14 +716,15 @@ vmxnet3_alloc_rxq_data(struct vmxnet3_so
 	int i, j, q, error;
 
 	dev = sc->vmx_dev;
-	descsz = VMXNET3_RX_NDESC * sizeof(struct vmxnet3_rxdesc);
-	compsz = VMXNET3_RX_NCOMPDESC * sizeof(struct vmxnet3_rxcompdesc);
+	descsz = sc->vmx_nrxdescs * sizeof(struct vmxnet3_rxdesc);
+	compsz = sc->vmx_nrxdescs * sizeof(struct vmxnet3_rxcompdesc) *
+	    VMXNET3_RXRINGS_PERQ;
 
-	for (q = 0; q < VMXNET3_RX_QUEUES; q++) {
+	for (q = 0; q < sc->vmx_nrxqueues; q++) {
 		rxq = &sc->vmx_rxq[q];
 		rxc = &rxq->vxrxq_comp_ring;
 
-		for (i = 0; i < 2; i++) {
+		for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) {
 			rxr = &rxq->vxrxq_cmd_ring[i];
 
 			error = bus_dma_tag_create(bus_get_dma_tag(dev),
@@ -561,7 +740,8 @@ vmxnet3_alloc_rxq_data(struct vmxnet3_so
 			    &rxr->vxrxr_rxtag);
 			if (error) {
 				device_printf(dev,
-				    "unable to create Rx buffer tag for queue %d\n", q);
+				    "unable to create Rx buffer tag for "
+				    "queue %d\n", q);
 				return (error);
 			}
 
@@ -586,7 +766,7 @@ vmxnet3_alloc_rxq_data(struct vmxnet3_so
 		rxc->vxcr_u.rxcd =
 		    (struct vmxnet3_rxcompdesc *) rxc->vxcr_dma.dma_vaddr;
 
-		for (i = 0; i < 2; i++) {
+		for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) {
 			rxr = &rxq->vxrxq_cmd_ring[i];
 
 			error = bus_dmamap_create(rxr->vxrxr_rxtag, 0,
@@ -598,7 +778,7 @@ vmxnet3_alloc_rxq_data(struct vmxnet3_so
 				return (error);
 			}
 
-			for (j = 0; j < VMXNET3_RX_NDESC; j++) {
+			for (j = 0; j < sc->vmx_nrxdescs; j++) {
 				error = bus_dmamap_create(rxr->vxrxr_rxtag, 0,
 				    &rxr->vxrxr_dmap[j]);
 				if (error) {
@@ -626,11 +806,11 @@ vmxnet3_free_rxq_data(struct vmxnet3_sof
 
 	dev = sc->vmx_dev;
 
-	for (q = 0; q < VMXNET3_RX_QUEUES; q++) {
+	for (q = 0; q < sc->vmx_nrxqueues; q++) {
 		rxq = &sc->vmx_rxq[q];
 		rxc = &rxq->vxrxq_comp_ring;
 
-		for (i = 0; i < 2; i++) {
+		for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) {
 			rxr = &rxq->vxrxq_cmd_ring[i];
 
 			if (rxr->vxrxr_spare_dmap != NULL) {
@@ -639,7 +819,7 @@ vmxnet3_free_rxq_data(struct vmxnet3_sof
 				rxr->vxrxr_spare_dmap = NULL;
 			}
 
-			for (j = 0; j < VMXNET3_RX_NDESC; j++) {
+			for (j = 0; j < rxr->vxrxr_ndesc; j++) {
 				if (rxr->vxrxr_dmap[j] != NULL) {
 					bus_dmamap_destroy(rxr->vxrxr_rxtag,
 					    rxr->vxrxr_dmap[j]);
@@ -653,7 +833,7 @@ vmxnet3_free_rxq_data(struct vmxnet3_sof
 			rxc->vxcr_u.rxcd = NULL;
 		}
 
-		for (i = 0; i < 2; i++) {
+		for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) {
 			rxr = &rxq->vxrxq_cmd_ring[i];
 
 			if (rxr->vxrxr_rxd != NULL) {
@@ -726,86 +906,99 @@ vmxnet3_init_shared_data(struct vmxnet3_
 	struct vmxnet3_txq_shared *txs;
 	struct vmxnet3_rxqueue *rxq;
 	struct vmxnet3_rxq_shared *rxs;
-	u_int major, minor, release_code, rev;
 	int i;
 
 	ds = sc->vmx_ds;
+
+	/*
+	 * Initialize fields of the shared data that remains the same across
+	 * reinits. Note the shared data is zero'd when allocated.
+	 */
+
 	ds->magic = VMXNET3_REV1_MAGIC;
-	ds->version = VMXNET3_DRIVER_VERSION;
 
-	major = __FreeBSD_version / 100000;
-	minor = (__FreeBSD_version / 1000) % 100;
-	release_code = (__FreeBSD_version / 100) % 10;
-	rev = __FreeBSD_version % 100;
-	ds->guest = release_code << 30 | rev << 22 | major << 14 | minor << 6 |
-	    VMXNET3_GOS_FREEBSD;
+	/* DriverInfo */
+	ds->version = VMXNET3_DRIVER_VERSION;
+	ds->guest = VMXNET3_GOS_FREEBSD | VMXNET3_GUEST_OS_VERSION |
 #ifdef __LP64__
-	ds->guest |= VMXNET3_GOS_64BIT;
+	    VMXNET3_GOS_64BIT;
 #else
-	ds->guest |= VMXNET3_GOS_32BIT;
+	    VMXNET3_GOS_32BIT;
 #endif
-
 	ds->vmxnet3_revision = 1;
 	ds->upt_version = 1;
-	ds->upt_features = UPT1_F_CSUM | UPT1_F_VLAN;
+
+	/* Misc. conf */
 	ds->driver_data = vtophys(sc);
 	ds->driver_data_len = sizeof(struct vmxnet3_softc);
 	ds->queue_shared = sc->vmx_qs_dma.dma_paddr;
 	ds->queue_shared_len = sc->vmx_qs_dma.dma_size;
-	ds->mtu = ETHERMTU;
-	ds->ntxqueue = VMXNET3_TX_QUEUES;
-	ds->nrxqueue = VMXNET3_RX_QUEUES;
-	ds->mcast_table = sc->vmx_mcast_dma.dma_paddr;
-	ds->mcast_tablelen = sc->vmx_mcast_dma.dma_size;
+	ds->nrxsg_max = sc->vmx_max_rxsegs;
+
+	/* Interrupt control. */
 	ds->automask = 1;
 	ds->nintr = VMXNET3_NINTR;
 	ds->evintr = 0;
 	ds->ictrl = VMXNET3_ICTRL_DISABLE_ALL;
+
 	for (i = 0; i < VMXNET3_NINTR; i++)
 		ds->modlevel[i] = UPT1_IMOD_ADAPTIVE;
 
-	for (i = 0; i < VMXNET3_TX_QUEUES; i++) {
+	/* Receive filter. */
+	ds->mcast_table = sc->vmx_mcast_dma.dma_paddr;
+	ds->mcast_tablelen = sc->vmx_mcast_dma.dma_size;
+
+	/* Tx queues */
+	for (i = 0; i < sc->vmx_ntxqueues; i++) {
 		txq = &sc->vmx_txq[i];
 		txs = txq->vxtxq_ts;
 
-		txs->npending = 0;
-		txs->intr_threshold = 1;
 		txs->cmd_ring = txq->vxtxq_cmd_ring.vxtxr_dma.dma_paddr;
-		txs->cmd_ring_len = VMXNET3_TX_NDESC;
+		txs->cmd_ring_len = sc->vmx_ntxdescs;
 		txs->comp_ring = txq->vxtxq_comp_ring.vxcr_dma.dma_paddr;
-		txs->comp_ring_len = VMXNET3_TX_NCOMPDESC;
+		txs->comp_ring_len = sc->vmx_ntxdescs;
 		txs->driver_data = vtophys(txq);
 		txs->driver_data_len = sizeof(struct vmxnet3_txqueue);
-		txs->intr_idx = 0;
-		txs->stopped = 1;
-		txs->error = 0;
 	}
 
-	for (i = 0; i < VMXNET3_RX_QUEUES; i++) {
+	/* Rx queues */
+	for (i = 0; i < sc->vmx_nrxqueues; i++) {
 		rxq = &sc->vmx_rxq[i];
 		rxs = rxq->vxrxq_rs;
 
 		rxs->cmd_ring[0] = rxq->vxrxq_cmd_ring[0].vxrxr_dma.dma_paddr;
-		rxs->cmd_ring_len[0] = VMXNET3_RX_NDESC;
+		rxs->cmd_ring_len[0] = sc->vmx_nrxdescs;
 		rxs->cmd_ring[1] = rxq->vxrxq_cmd_ring[1].vxrxr_dma.dma_paddr;
-		rxs->cmd_ring_len[1] = VMXNET3_RX_NDESC;
+		rxs->cmd_ring_len[1] = sc->vmx_nrxdescs;
 		rxs->comp_ring = rxq->vxrxq_comp_ring.vxcr_dma.dma_paddr;
-		rxs->comp_ring_len = VMXNET3_RX_NCOMPDESC;
+		rxs->comp_ring_len = sc->vmx_nrxdescs * VMXNET3_RXRINGS_PERQ;
 		rxs->driver_data = vtophys(rxq);
 		rxs->driver_data_len = sizeof(struct vmxnet3_rxqueue);
-		rxs->intr_idx = 0;
-		rxs->stopped = 1;
-		rxs->error = 0;
 	}
-
-	vmxnet3_write_bar1(sc, VMXNET3_BAR1_DSL, sc->vmx_ds_dma.dma_paddr);
-	vmxnet3_write_bar1(sc, VMXNET3_BAR1_DSH,
-	    sc->vmx_ds_dma.dma_paddr >> 32);
 }
 
 static void
 vmxnet3_reinit_shared_data(struct vmxnet3_softc *sc)
 {
+	struct ifnet *ifp;
+	struct vmxnet3_driver_shared *ds;
+
+	ifp = sc->vmx_ifp;
+	ds = sc->vmx_ds;
+
+	/* Use the current MAC address. */
+	bcopy(IF_LLADDR(sc->vmx_ifp), sc->vmx_lladdr, ETHER_ADDR_LEN);
+	vmxnet3_set_lladdr(sc);
+
+	ds->upt_features = 0;
+	if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
+		ds->upt_features |= UPT1_F_VLAN;
+	if (ifp->if_capenable & IFCAP_RXCSUM)
+		ds->upt_features |= UPT1_F_CSUM;
+
+	ds->mtu = ifp->if_mtu;
+	ds->ntxqueue = sc->vmx_ntxqueues;
+	ds->nrxqueue = sc->vmx_nrxqueues;
 
 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_DSL, sc->vmx_ds_dma.dma_paddr);
 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_DSH,
@@ -864,20 +1057,28 @@ vmxnet3_setup_interface(struct vmxnet3_s
 	ifp->if_init = vmxnet3_init;
 	ifp->if_ioctl = vmxnet3_ioctl;
 	ifp->if_start = vmxnet3_start;
-	ifp->if_snd.ifq_drv_maxlen = VMXNET3_TX_NDESC - 1;
-	IFQ_SET_MAXLEN(&ifp->if_snd, VMXNET3_TX_NDESC - 1);
+	ifp->if_snd.ifq_drv_maxlen = sc->vmx_ntxdescs - 1;
+	IFQ_SET_MAXLEN(&ifp->if_snd, sc->vmx_ntxdescs - 1);
 	IFQ_SET_READY(&ifp->if_snd);
 
+	vmxnet3_get_lladdr(sc);
 	ether_ifattach(ifp, sc->vmx_lladdr);
 
-	if (sc->vmx_ds->upt_features & UPT1_F_VLAN)
-		ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING;
-	if (sc->vmx_ds->upt_features & UPT1_F_CSUM) {
-		ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_TXCSUM;
-		ifp->if_hwassist |= VMXNET3_CSUM_FEATURES;
-	}
+	ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING;
+	ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_TXCSUM;
+	ifp->if_hwassist |= VMXNET3_CSUM_FEATURES;
 
 	ifp->if_capenable = ifp->if_capabilities;
+	
+	/*
+	 * Capabilities after here are not enabled by default.
+	 */
+
+	ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
+	sc->vmx_vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
+	    vmxnet3_register_vlan, sc, EVENTHANDLER_PRI_FIRST);
+	sc->vmx_vlan_detach = EVENTHANDLER_REGISTER(vlan_config,
+	    vmxnet3_unregister_vlan, sc, EVENTHANDLER_PRI_FIRST);
 
 	ifmedia_init(&sc->vmx_media, 0, vmxnet3_media_change,
 	    vmxnet3_media_status);
@@ -905,18 +1106,21 @@ vmxnet3_evintr(struct vmxnet3_softc *sc)
 	/* Clear events. */
 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_EVENT, event);
 
+	VMXNET3_CORE_LOCK(sc);
+
 	if (event & VMXNET3_EVENT_LINK)
-		vmxnet3_link_state(sc);
+		vmxnet3_link_status(sc);
 
 	if (event & (VMXNET3_EVENT_TQERROR | VMXNET3_EVENT_RQERROR)) {
 		reset = 1;
 		vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_STATUS);
 		ts = sc->vmx_txq[0].vxtxq_ts;
 		if (ts->stopped != 0)
-			device_printf(dev, "TX queue error %#x\n", ts->error);
+			device_printf(dev, "Tx queue error %#x\n", ts->error);
 		rs = sc->vmx_rxq[0].vxrxq_rs;
 		if (rs->stopped != 0)
-			device_printf(dev, "RX queue error %#x\n", rs->error);
+			device_printf(dev, "Rx queue error %#x\n", rs->error);
+		device_printf(dev, "Rx/Tx queue error event ... resetting\n");
 	}
 
 	if (event & VMXNET3_EVENT_DIC)
@@ -926,8 +1130,10 @@ vmxnet3_evintr(struct vmxnet3_softc *sc)
 
 	if (reset != 0) {
 		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
-		vmxnet3_init(sc);
+		vmxnet3_init_locked(sc);
 	}
+
+	VMXNET3_CORE_UNLOCK(sc);
 }
 
 static void
@@ -943,14 +1149,14 @@ vmxnet3_txeof(struct vmxnet3_softc *sc, 
 	txr = &txq->vxtxq_cmd_ring;
 	txc = &txq->vxtxq_comp_ring;
 
-	VMXNET3_TX_LOCK_ASSERT(sc);
+	VMXNET3_TXQ_LOCK_ASSERT(txq);
 
 	for (;;) {
 		txcd = &txc->vxcr_u.txcd[txc->vxcr_next];
 		if (txcd->gen != txc->vxcr_gen)
 			break;
 
-		if (++txc->vxcr_next == VMXNET3_TX_NCOMPDESC) {
+		if (++txc->vxcr_next == txc->vxcr_ndesc) {
 			txc->vxcr_next = 0;
 			txc->vxcr_gen ^= 1;
 		}
@@ -968,7 +1174,7 @@ vmxnet3_txeof(struct vmxnet3_softc *sc, 
 			ifp->if_opackets++;
 		}
 
-		txr->vxtxr_next = (txcd->eop_idx + 1) % VMXNET3_TX_NDESC;
+		txr->vxtxr_next = (txcd->eop_idx + 1) % txr->vxtxr_ndesc;
 	}
 
 	if (txr->vxtxr_head == txr->vxtxr_next)
@@ -981,11 +1187,13 @@ vmxnet3_rx_csum(struct vmxnet3_rxcompdes
 
 	if (rxcd->ipv4 && rxcd->ipcsum_ok)
 		m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED | CSUM_IP_VALID;
-	if (rxcd->fragment)
-		return;
-	if (rxcd->csum_ok && (rxcd->tcp || rxcd->udp)) {
-		m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
-		m->m_pkthdr.csum_data = 0xFFFF;
+
+	if (!rxcd->fragment) {
+		if (rxcd->csum_ok && (rxcd->tcp || rxcd->udp)) {
+			m->m_pkthdr.csum_flags |= CSUM_DATA_VALID |
+			    CSUM_PSEUDO_HDR;
+			m->m_pkthdr.csum_data = 0xFFFF;
+		}
 	}
 }
 
@@ -1041,7 +1249,7 @@ vmxnet3_newbuf(struct vmxnet3_softc *sc,
 	rxd->btype = btype;
 	rxd->gen = rxr->vxrxr_gen;
 
-	if (++idx == VMXNET3_RX_NDESC) {
+	if (++idx == rxr->vxrxr_ndesc) {
 		idx = 0;
 		rxr->vxrxr_gen ^= 1;
 	}
@@ -1076,7 +1284,7 @@ vmxnet3_rxeof(struct vmxnet3_softc *sc, 
 	rxr = &rxq->vxrxq_cmd_ring[0];
 	rxc = &rxq->vxrxq_comp_ring;
 
-	VMXNET3_RX_LOCK_ASSERT(sc);
+	VMXNET3_RXQ_LOCK_ASSERT(rxq);
 
 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
 		return;
@@ -1086,14 +1294,14 @@ vmxnet3_rxeof(struct vmxnet3_softc *sc, 
 		if (rxcd->gen != rxc->vxcr_gen)
 			break;
 
-		if (++rxc->vxcr_next == VMXNET3_RX_NCOMPDESC) {
+		if (++rxc->vxcr_next == rxc->vxcr_ndesc) {
 			rxc->vxcr_next = 0;
 			rxc->vxcr_gen ^= 1;
 		}
 
 		idx = rxcd->rxd_idx;
 		length = rxcd->len;
-		if (rxcd->qid < VMXNET3_RX_QUEUES)
+		if (rxcd->qid < sc->vmx_nrxqueues)
 			rxr = &rxq->vxrxq_cmd_ring[0];
 		else
 			rxr = &rxq->vxrxq_cmd_ring[1];
@@ -1130,7 +1338,13 @@ vmxnet3_rxeof(struct vmxnet3_softc *sc, 
 		}
 
 		ifp->if_ipackets++;
+		VMXNET3_RXQ_UNLOCK(rxq);
 		(*ifp->if_input)(ifp, m);
+		VMXNET3_RXQ_LOCK(rxq);
+
+		/* Must recheck the state after dropping the Rx lock. */
+		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+			break;
 
 nextp:
 		if (rxq->vxrxq_rs->update_rxhead) {
@@ -1140,9 +1354,9 @@ nextp:
 			/*
 			 * XXX BMV This looks pretty odd.
 			 */
-			idx = (idx + 1) % VMXNET3_RX_NDESC;
-			if (qid >= VMXNET3_RX_QUEUES) {
-				qid -= VMXNET3_RX_QUEUES;
+			idx = (idx + 1) % rxr->vxrxr_ndesc;
+			if (qid >= sc->vmx_nrxqueues) {
+				qid -= sc->vmx_nrxqueues;
 				r = VMXNET3_BAR0_RXH2(qid);
 			} else
 				r = VMXNET3_BAR0_RXH1(qid);
@@ -1152,12 +1366,16 @@ nextp:
 }
 
 static void
-vmxnet3_intr(void *xsc)
+vmxnet3_legacy_intr(void *xsc)
 {
 	struct vmxnet3_softc *sc;
 	struct ifnet *ifp;
+	struct vmxnet3_rxqueue *rxq;
+	struct vmxnet3_txqueue *txq;
 
 	sc = xsc;
+	rxq = &sc->vmx_rxq[0];
+	txq = &sc->vmx_txq[0];
 	ifp = sc->vmx_ifp;
 
 	if (vmxnet3_read_bar1(sc, VMXNET3_BAR1_INTR) == 0)
@@ -1166,19 +1384,37 @@ vmxnet3_intr(void *xsc)
 	if (sc->vmx_ds->event != 0)
 		vmxnet3_evintr(sc);
 
-	VMXNET3_RX_LOCK(sc);
-	vmxnet3_rxeof(sc, &sc->vmx_rxq[0]);
-	VMXNET3_RX_UNLOCK(sc);
-
-	VMXNET3_TX_LOCK(sc);
-	vmxnet3_txeof(sc, &sc->vmx_txq[0]);
-	if (IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+	VMXNET3_RXQ_LOCK(rxq);
+	vmxnet3_rxeof(sc, rxq);
+	VMXNET3_RXQ_UNLOCK(rxq);
+
+	VMXNET3_TXQ_LOCK(txq);
+	vmxnet3_txeof(sc, txq);
+	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
 		vmxnet3_start_locked(ifp);
-	VMXNET3_TX_UNLOCK(sc);
+	VMXNET3_TXQ_UNLOCK(txq);
 
 	vmxnet3_enable_intr(sc, 0);
 }
 
+static int
+vmxnet3_setup_interrupts(struct vmxnet3_softc *sc)
+{
+	device_t dev;
+	int error;
+
+	dev = sc->vmx_dev;
+
+	/*
+	 * Only support a single legacy interrupt for now.
+	 * Add MSI/MSIx later.
+	 */
+	error = bus_setup_intr(dev, sc->vmx_irq, INTR_TYPE_NET | INTR_MPSAFE,
+	    NULL, vmxnet3_legacy_intr, sc, &sc->vmx_intrhand);
+
+	return (error);
+}
+
 static void
 vmxnet3_txstop(struct vmxnet3_softc *sc, struct vmxnet3_txqueue *txq)
 {
@@ -1187,7 +1423,7 @@ vmxnet3_txstop(struct vmxnet3_softc *sc,
 
 	txr = &txq->vxtxq_cmd_ring;
 
-	for (i = 0; i < VMXNET3_TX_NDESC; i++) {
+	for (i = 0; i < txr->vxtxr_ndesc; i++) {
 		if (txr->vxtxr_m[i] == NULL)
 			continue;
 
@@ -1205,10 +1441,10 @@ vmxnet3_rxstop(struct vmxnet3_softc *sc,
 	struct vmxnet3_rxring *rxr;
 	int i, j;
 
-	for (i = 0; i < 2; i++) {
+	for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) {
 		rxr = &rxq->vxrxq_cmd_ring[i];
 
-		for (j = 0; j < VMXNET3_RX_NDESC; j++) {
+		for (j = 0; j < rxr->vxrxr_ndesc; j++) {
 			if (rxr->vxrxr_m[j] == NULL)
 				continue;
 			bus_dmamap_sync(rxr->vxrxr_rxtag, rxr->vxrxr_dmap[j],
@@ -1221,6 +1457,26 @@ vmxnet3_rxstop(struct vmxnet3_softc *sc,
 }
 
 static void
+vmxnet3_stop_rendezvous(struct vmxnet3_softc *sc)
+{
+	struct vmxnet3_rxqueue *rxq;
+	struct vmxnet3_txqueue *txq;
+	int i;
+
+	for (i = 0; i < sc->vmx_nrxqueues; i++) {
+		rxq = &sc->vmx_rxq[i];
+		VMXNET3_RXQ_LOCK(rxq);
+		VMXNET3_RXQ_UNLOCK(rxq);
+	}
+
+	for (i = 0; i < sc->vmx_ntxqueues; i++) {
+		txq = &sc->vmx_txq[i];
+		VMXNET3_TXQ_LOCK(txq);
+		VMXNET3_TXQ_UNLOCK(txq);
+	}
+}
+
+static void
 vmxnet3_stop(struct vmxnet3_softc *sc)
 {
 	struct ifnet *ifp;
@@ -1237,9 +1493,11 @@ vmxnet3_stop(struct vmxnet3_softc *sc)
 	vmxnet3_disable_all_intrs(sc);
 	vmxnet3_write_cmd(sc, VMXNET3_CMD_DISABLE);
 
-	for (q = 0; q < VMXNET3_TX_QUEUES; q++)
+	vmxnet3_stop_rendezvous(sc);
+
+	for (q = 0; q < sc->vmx_ntxqueues; q++)
 		vmxnet3_txstop(sc, &sc->vmx_txq[q]);
-	for (q = 0; q < VMXNET3_RX_QUEUES; q++)
+	for (q = 0; q < sc->vmx_nrxqueues; q++)
 		vmxnet3_rxstop(sc, &sc->vmx_rxq[q]);
 
 	vmxnet3_write_cmd(sc, VMXNET3_CMD_RESET);
@@ -1254,15 +1512,15 @@ vmxnet3_txinit(struct vmxnet3_softc *sc,
 	txr = &txq->vxtxq_cmd_ring;
 	txr->vxtxr_head = 0;
 	txr->vxtxr_next = 0;
-	txr->vxtxr_gen = 1;
+	txr->vxtxr_gen = VMXNET3_INIT_GEN;
 	bzero(txr->vxtxr_txd,
-	    VMXNET3_TX_NDESC * sizeof(struct vmxnet3_txdesc));
+	    txr->vxtxr_ndesc * sizeof(struct vmxnet3_txdesc));
 
 	txc = &txq->vxtxq_comp_ring;
 	txc->vxcr_next = 0;
-	txc->vxcr_gen = 1;
+	txc->vxcr_gen = VMXNET3_INIT_GEN;
 	bzero(txc->vxcr_u.txcd,
-	    VMXNET3_TX_NCOMPDESC * sizeof(struct vmxnet3_txcompdesc));
+	    txc->vxcr_ndesc * sizeof(struct vmxnet3_txcompdesc));
 }
 
 static int
@@ -1272,14 +1530,14 @@ vmxnet3_rxinit(struct vmxnet3_softc *sc,
 	struct vmxnet3_comp_ring *rxc;
 	int i, idx, error;
 
-	for (i = 0; i < 2; i++) {
+	for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) {
 		rxr = &rxq->vxrxq_cmd_ring[i];
 		rxr->vxrxr_fill = 0;
-		rxr->vxrxr_gen = 1;
+		rxr->vxrxr_gen = VMXNET3_INIT_GEN;
 		bzero(rxr->vxrxr_rxd,
-		    VMXNET3_RX_NDESC * sizeof(struct vmxnet3_rxdesc));
+		    rxr->vxrxr_ndesc * sizeof(struct vmxnet3_rxdesc));
 
-		for (idx = 0; idx < VMXNET3_RX_NDESC; idx++) {
+		for (idx = 0; idx < rxr->vxrxr_ndesc; idx++) {
 			error = vmxnet3_newbuf(sc, rxr);
 			if (error)
 				return (error);
@@ -1288,61 +1546,86 @@ vmxnet3_rxinit(struct vmxnet3_softc *sc,
 
 	rxc = &rxq->vxrxq_comp_ring;
 	rxc->vxcr_next = 0;
-	rxc->vxcr_gen = 1;
+	rxc->vxcr_gen = VMXNET3_INIT_GEN;
 	bzero(rxc->vxcr_u.rxcd,
-	     VMXNET3_RX_NCOMPDESC * sizeof(struct vmxnet3_rxcompdesc));
+	     rxc->vxcr_ndesc * sizeof(struct vmxnet3_rxcompdesc));
 
 	return (0);

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


More information about the svn-src-projects mailing list