From owner-svn-src-projects@FreeBSD.ORG Sun Jul 14 03:45:04 2013 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 65C1C99F; Sun, 14 Jul 2013 03:45:04 +0000 (UTC) (envelope-from bryanv@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id 56AC012D; Sun, 14 Jul 2013 03:45:04 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id r6E3j3Dv068431; Sun, 14 Jul 2013 03:45:03 GMT (envelope-from bryanv@svn.freebsd.org) Received: (from bryanv@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id r6E3j3Hs068429; Sun, 14 Jul 2013 03:45:03 GMT (envelope-from bryanv@svn.freebsd.org) Message-Id: <201307140345.r6E3j3Hs068429@svn.freebsd.org> From: Bryan Venteicher Date: Sun, 14 Jul 2013 03:45:03 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r253334 - projects/vmxnet/sys/dev/vmware/vmxnet3 X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 14 Jul 2013 03:45:04 -0000 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 #include -#include #include +#include +#include #include +#include #include +#include #include @@ -47,6 +50,11 @@ __FBSDID("$FreeBSD$"); #include #include +#include +#include +#include +#include +#include #include #include @@ -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 ***