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