Author: bryanv
Date: Fri Aug 23 20:47:16 2013
New Revision: 254738
URL: http://svnweb.freebsd.org/changeset/base/254738

Log:
  Add vmx(4), a VMware VMXNET3 ethernet driver ported from OpenBSD

Added:
  head/share/man/man4/vmx.4   (contents, props changed)
  head/sys/dev/vmware/
  head/sys/dev/vmware/vmxnet3/
  head/sys/dev/vmware/vmxnet3/if_vmx.c   (contents, props changed)
  head/sys/dev/vmware/vmxnet3/if_vmxreg.h   (contents, props changed)
  head/sys/dev/vmware/vmxnet3/if_vmxvar.h   (contents, props changed)
  head/sys/modules/vmware/
  head/sys/modules/vmware/Makefile   (contents, props changed)
  head/sys/modules/vmware/vmxnet3/
  head/sys/modules/vmware/vmxnet3/Makefile   (contents, props changed)
Modified:
  head/share/man/man4/Makefile
  head/sys/conf/files.amd64
  head/sys/conf/files.i386
  head/sys/modules/Makefile

Modified: head/share/man/man4/Makefile
==============================================================================
--- head/share/man/man4/Makefile        Fri Aug 23 20:39:41 2013        
(r254737)
+++ head/share/man/man4/Makefile        Fri Aug 23 20:47:16 2013        
(r254738)
@@ -539,6 +539,7 @@ MAN=        aac.4 \
        ${_virtio_scsi.4} \
        vkbd.4 \
        vlan.4 \
+       ${_vmx.4} \
        vpo.4 \
        vr.4 \
        vte.4 \
@@ -706,6 +707,7 @@ MLINKS+=ural.4 if_ural.4
 MLINKS+=${_urtw.4} ${_if_urtw.4}
 MLINKS+=vge.4 if_vge.4
 MLINKS+=vlan.4 if_vlan.4
+MLINKS+=${_vmx.4} ${_if_vmx.4}
 MLINKS+=vpo.4 imm.4
 MLINKS+=vr.4 if_vr.4
 MLINKS+=vte.4 if_vte.4
@@ -758,6 +760,7 @@ _if_nfe.4=  if_nfe.4
 _if_nve.4=     if_nve.4
 _if_nxge.4=    if_nxge.4
 _if_urtw.4=    if_urtw.4
+_if_vmx.4=     if_vmx.4
 _if_vtnet.4=   if_vtnet.4
 _if_vxge.4=    if_vxge.4
 _if_wpi.4=     if_wpi.4
@@ -777,6 +780,7 @@ _virtio.4=  virtio.4
 _virtio_balloon.4=virtio_balloon.4
 _virtio_blk.4= virtio_blk.4
 _virtio_scsi.4= virtio_scsi.4
+_vmx.4=                vmx.4
 _vtnet.4=      vtnet.4
 _vxge.4=       vxge.4
 _padlock.4=    padlock.4

Added: head/share/man/man4/vmx.4
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/share/man/man4/vmx.4   Fri Aug 23 20:47:16 2013        (r254738)
@@ -0,0 +1,224 @@
+.\"
+.\" Copyright (c) 2006,2013 Reyk Floeter <r...@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" $OpenBSD: src/share/man/man4/vmx.4,v 1.1 2013/05/31 20:18:44 reyk Exp $
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 4, 2013
+.Dt VMX 4
+.Os
+.Sh NAME
+.Nm vmx
+.Nd VMware VMXNET3 Virtual Interface Controller device
+.Sh SYNOPSIS
+To compile this driver into the kernel,
+place the following line in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device vmx"
+.Ed
+.Pp
+Alternatively, to load the driver as a
+module at boot time, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+if_vmx_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for the VMXNET3 virtual NIC available in virtual
+machines by VMware.
+It appears as a simple Ethernet device but is actually a virtual network
+interface to the underlying host operating system.
+.Pp
+This driver supports the
+.Ic VMXNET3
+driver protocol, as an alternative to the emulated
+.Xr pcn 4 ,
+.Xr em 4
+interfaces also available in the VMware environment.
+The
+.Nm
+driver is optimized for the virtual machine, it can provide advanced
+capabilities depending on the underlying host operating system and
+the physical network interface controller of the host.
+The
+.Nm
+driver supports features like multiqueue support, IPv6
+checksum offloading, MSI/MSI-X support and hardware VLAN tagging in
+VMware's VLAN Guest Tagging (VGT) mode.
+.Pp
+The
+.Nm
+driver supports VMXNET3 VMware virtual NICs provided by the virtual
+machine hardware version 7 or newer, as provided by the following
+products:
+.Pp
+.Bl -bullet -compact -offset indent
+.It
+VMware ESX/ESXi 4.0 and newer
+.It
+VMware Server 2.0 and newer
+.It
+VMware Workstation 6.5 and newer
+.It
+VMware Fusion 2.0 and newer
+.El
+.Pp
+For more information on configuring this device, see
+.Xr ifconfig 8 .
+.Sh EXAMPLES
+The following entry must be added to the VMware configuration file
+to provide the
+.Nm
+device:
+.Bd -literal -offset indent
+ethernet0.virtualDev = "vmxnet3"
+.Ed
+.Sh SEE ALSO
+.Xr altq 4 ,
+.Xr arp 4 ,
+.Xr em 4 ,
+.Xr netintro 4 ,
+.Xr ng_ether 4 ,
+.Xr pcn 4 ,
+.Xr vlan 4 ,
+.Xr ifconfig 8
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was ported from
+.Ox
+by
+.An Bryan Venteicher Aq bry...@freebsd.org .
+The
+.Ox
+driver was written by
+.An Tsubai Masanari .
+.\"
+.\" Copyright (c) 2006,2013 Reyk Floeter <r...@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" $OpenBSD: src/share/man/man4/vmx.4,v 1.1 2013/05/31 20:18:44 reyk Exp $
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 4, 2013
+.Dt VMX 4
+.Os
+.Sh NAME
+.Nm vmx
+.Nd VMware VMXNET3 Virtual Interface Controller device
+.Sh SYNOPSIS
+To compile this driver into the kernel,
+place the following line in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device vmx"
+.Ed
+.Pp
+Alternatively, to load the driver as a
+module at boot time, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+if_vmx_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for the VMXNET3 virtual NIC available in virtual
+machines by VMware.
+It appears as a simple Ethernet device but is actually a virtual network
+interface to the underlying host operating system.
+.Pp
+This driver supports the
+.Ic VMXNET3
+driver protocol, as an alternative to the emulated
+.Xr pcn 4 ,
+.Xr em 4
+interfaces also available in the VMware environment.
+The
+.Nm
+driver is optimized for the virtual machine, it can provide advanced
+capabilities depending on the underlying host operating system and
+the physical network interface controller of the host.
+The
+.Nm
+driver supports features like multiqueue support, IPv6
+checksum offloading, MSI/MSI-X support and hardware VLAN tagging in
+VMware's VLAN Guest Tagging (VGT) mode.
+.Pp
+The
+.Nm
+driver supports VMXNET3 VMware virtual NICs provided by the virtual
+machine hardware version 7 or newer, as provided by the following
+products:
+.Pp
+.Bl -bullet -compact -offset indent
+.It
+VMware ESX/ESXi 4.0 and newer
+.It
+VMware Server 2.0 and newer
+.It
+VMware Workstation 6.5 and newer
+.It
+VMware Fusion 2.0 and newer
+.El
+.Pp
+For more information on configuring this device, see
+.Xr ifconfig 8 .
+.Sh EXAMPLES
+The following entry must be added to the VMware configuration file
+to provide the
+.Nm
+device:
+.Bd -literal -offset indent
+ethernet0.virtualDev = "vmxnet3"
+.Ed
+.Sh SEE ALSO
+.Xr altq 4 ,
+.Xr arp 4 ,
+.Xr em 4 ,
+.Xr netintro 4 ,
+.Xr ng_ether 4 ,
+.Xr pcn 4 ,
+.Xr vlan 4 ,
+.Xr ifconfig 8
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was ported from
+.Ox
+by
+.An Bryan Venteicher Aq bry...@freebsd.org .
+The
+.Ox
+driver was written by
+.An Tsubai Masanari .

Modified: head/sys/conf/files.amd64
==============================================================================
--- head/sys/conf/files.amd64   Fri Aug 23 20:39:41 2013        (r254737)
+++ head/sys/conf/files.amd64   Fri Aug 23 20:47:16 2013        (r254738)
@@ -304,6 +304,7 @@ dev/tpm/tpm_acpi.c          optional        tpm acpi
 dev/tpm/tpm_isa.c              optional        tpm isa
 dev/uart/uart_cpu_x86.c                optional        uart
 dev/viawd/viawd.c              optional        viawd
+dev/vmware/vmxnet3/if_vmx.c    optional        vmx
 dev/wbwd/wbwd.c                        optional        wbwd
 dev/wpi/if_wpi.c               optional        wpi
 dev/isci/isci.c                                                        
optional isci

Modified: head/sys/conf/files.i386
==============================================================================
--- head/sys/conf/files.i386    Fri Aug 23 20:39:41 2013        (r254737)
+++ head/sys/conf/files.i386    Fri Aug 23 20:47:16 2013        (r254738)
@@ -267,6 +267,7 @@ dev/tpm/tpm_acpi.c          optional tpm acpi
 dev/tpm/tpm_isa.c              optional tpm isa
 dev/uart/uart_cpu_x86.c                optional uart
 dev/viawd/viawd.c              optional viawd
+dev/vmware/vmxnet3/if_vmx.c    optional vmx
 dev/acpica/acpi_if.m           standard
 dev/acpi_support/acpi_wmi_if.m standard
 dev/wbwd/wbwd.c                        optional wbwd

Added: head/sys/dev/vmware/vmxnet3/if_vmx.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/dev/vmware/vmxnet3/if_vmx.c        Fri Aug 23 20:47:16 2013        
(r254738)
@@ -0,0 +1,3305 @@
+/*-
+ * Copyright (c) 2013 Tsubai Masanari
+ * Copyright (c) 2013 Bryan Venteicher <bry...@freebsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: src/sys/dev/pci/if_vmx.c,v 1.11 2013/06/22 00:28:10 uebayasi Exp $
+ */
+
+/* Driver for VMware vmxnet3 virtual ethernet devices. */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/endian.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <vm/vm.h>
+#include <vm/pmap.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>
+
+#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>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include "if_vmxreg.h"
+#include "if_vmxvar.h"
+
+#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);
+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_check_version(struct vmxnet3_softc *);
+static void    vmxnet3_initial_config(struct vmxnet3_softc *);
+
+static int     vmxnet3_alloc_msix_interrupts(struct vmxnet3_softc *);
+static int     vmxnet3_alloc_msi_interrupts(struct vmxnet3_softc *);
+static int     vmxnet3_alloc_legacy_interrupts(struct vmxnet3_softc *);
+static int     vmxnet3_alloc_interrupt(struct vmxnet3_softc *, int, int,
+                   struct vmxnet3_interrupt *);
+static int     vmxnet3_alloc_intr_resources(struct vmxnet3_softc *);
+static int     vmxnet3_setup_msix_interrupts(struct vmxnet3_softc *);
+static int     vmxnet3_setup_legacy_interrupt(struct vmxnet3_softc *);
+static int     vmxnet3_setup_interrupts(struct vmxnet3_softc *);
+static int     vmxnet3_alloc_interrupts(struct vmxnet3_softc *);
+
+static void    vmxnet3_free_interrupt(struct vmxnet3_softc *,
+                   struct vmxnet3_interrupt *);
+static void    vmxnet3_free_interrupts(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 *);
+static int     vmxnet3_alloc_txq_data(struct vmxnet3_softc *);
+static void    vmxnet3_free_txq_data(struct vmxnet3_softc *);
+static int     vmxnet3_alloc_rxq_data(struct vmxnet3_softc *);
+static void    vmxnet3_free_rxq_data(struct vmxnet3_softc *);
+static int     vmxnet3_alloc_queue_data(struct vmxnet3_softc *);
+static void    vmxnet3_free_queue_data(struct vmxnet3_softc *);
+static int     vmxnet3_alloc_mcast_table(struct vmxnet3_softc *);
+static void    vmxnet3_init_shared_data(struct vmxnet3_softc *);
+static void    vmxnet3_reinit_interface(struct vmxnet3_softc *);
+static void    vmxnet3_reinit_shared_data(struct vmxnet3_softc *);
+static int     vmxnet3_alloc_data(struct vmxnet3_softc *);
+static void    vmxnet3_free_data(struct vmxnet3_softc *);
+static int     vmxnet3_setup_interface(struct vmxnet3_softc *);
+
+static void    vmxnet3_evintr(struct vmxnet3_softc *);
+static void    vmxnet3_txq_eof(struct vmxnet3_txqueue *);
+static void    vmxnet3_rx_csum(struct vmxnet3_rxcompdesc *, struct mbuf *);
+static int     vmxnet3_newbuf(struct vmxnet3_softc *, struct vmxnet3_rxring *);
+static void    vmxnet3_rxq_eof_discard(struct vmxnet3_rxqueue *,
+                   struct vmxnet3_rxring *, int);
+static void    vmxnet3_rxq_eof(struct vmxnet3_rxqueue *);
+static void    vmxnet3_legacy_intr(void *);
+static void    vmxnet3_txq_intr(void *);
+static void    vmxnet3_rxq_intr(void *);
+static void    vmxnet3_event_intr(void *);
+
+static void    vmxnet3_txstop(struct vmxnet3_softc *, struct vmxnet3_txqueue 
*);
+static void    vmxnet3_rxstop(struct vmxnet3_softc *, struct vmxnet3_rxqueue 
*);
+static void    vmxnet3_stop(struct vmxnet3_softc *);
+
+static void    vmxnet3_txinit(struct vmxnet3_softc *, struct vmxnet3_txqueue 
*);
+static int     vmxnet3_rxinit(struct vmxnet3_softc *, struct vmxnet3_rxqueue 
*);
+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 *);
+
+static int     vmxnet3_txq_offload_ctx(struct mbuf *, int *, int *, int *);
+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_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 *);
+
+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 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 *);
+static int     vmxnet3_media_change(struct ifnet *);
+static void    vmxnet3_set_lladdr(struct vmxnet3_softc *);
+static void    vmxnet3_get_lladdr(struct vmxnet3_softc *);
+
+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);
+static void    vmxnet3_write_bar1(struct vmxnet3_softc *, bus_size_t,
+                   uint32_t);
+static void    vmxnet3_write_cmd(struct vmxnet3_softc *, uint32_t);
+static uint32_t        vmxnet3_read_cmd(struct vmxnet3_softc *, uint32_t);
+
+static void    vmxnet3_enable_intr(struct vmxnet3_softc *, int);
+static void    vmxnet3_disable_intr(struct vmxnet3_softc *, int);
+static void    vmxnet3_enable_all_intrs(struct vmxnet3_softc *);
+static void    vmxnet3_disable_all_intrs(struct vmxnet3_softc *);
+
+static int     vmxnet3_dma_malloc(struct vmxnet3_softc *, bus_size_t,
+                   bus_size_t, struct vmxnet3_dma_alloc *);
+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),
+       DEVMETHOD(device_attach,        vmxnet3_attach),
+       DEVMETHOD(device_detach,        vmxnet3_detach),
+       DEVMETHOD(device_shutdown,      vmxnet3_shutdown),
+
+       DEVMETHOD_END
+};
+
+static driver_t vmxnet3_driver = {
+       "vmx", vmxnet3_methods, sizeof(struct vmxnet3_softc)
+};
+
+static devclass_t vmxnet3_devclass;
+DRIVER_MODULE(vmx, pci, vmxnet3_driver, vmxnet3_devclass, 0, 0);
+
+MODULE_DEPEND(vmx, pci, 1, 1, 1);
+MODULE_DEPEND(vmx, ether, 1, 1, 1);
+
+#define VMXNET3_VMWARE_VENDOR_ID       0x15AD
+#define VMXNET3_VMWARE_DEVICE_ID       0x07B0
+
+static int
+vmxnet3_probe(device_t dev)
+{
+
+       if (pci_get_vendor(dev) == VMXNET3_VMWARE_VENDOR_ID &&
+           pci_get_device(dev) == VMXNET3_VMWARE_DEVICE_ID) {
+               device_set_desc(dev, "VMware VMXNET3 Ethernet Adapter");
+               return (BUS_PROBE_DEFAULT);
+       }
+
+       return (ENXIO);
+}
+
+static int
+vmxnet3_attach(device_t dev)
+{
+       struct vmxnet3_softc *sc;
+       int error;
+
+       sc = device_get_softc(dev);
+       sc->vmx_dev = dev;
+
+       pci_enable_busmaster(dev);
+
+       VMXNET3_CORE_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_check_version(sc);
+       if (error)
+               goto fail;
+
+       error = vmxnet3_alloc_rxtx_queues(sc);
+       if (error)
+               goto fail;
+
+       error = vmxnet3_alloc_interrupts(sc);
+       if (error)
+               goto fail;
+
+       error = vmxnet3_alloc_data(sc);
+       if (error)
+               goto fail;
+
+       error = vmxnet3_setup_interface(sc);
+       if (error)
+               goto fail;
+
+       error = vmxnet3_setup_interrupts(sc);
+       if (error) {
+               ether_ifdetach(sc->vmx_ifp);
+               device_printf(dev, "could not set up interrupt\n");
+               goto fail;
+       }
+
+       vmxnet3_setup_sysctl(sc);
+       vmxnet3_link_status(sc);
+
+fail:
+       if (error)
+               vmxnet3_detach(dev);
+
+       return (error);
+}
+
+static int
+vmxnet3_detach(device_t dev)
+{
+       struct vmxnet3_softc *sc;
+       struct ifnet *ifp;
+
+       sc = device_get_softc(dev);
+       ifp = sc->vmx_ifp;
+
+       if (device_is_attached(dev)) {
+               ether_ifdetach(ifp);
+               VMXNET3_CORE_LOCK(sc);
+               vmxnet3_stop(sc);
+               VMXNET3_CORE_UNLOCK(sc);
+               callout_drain(&sc->vmx_tick);
+       }
+
+       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;
+       }
+
+       vmxnet3_free_interrupts(sc);
+
+       if (ifp != NULL) {
+               if_free(ifp);
+               sc->vmx_ifp = NULL;
+       }
+
+       ifmedia_removeall(&sc->vmx_media);
+
+       vmxnet3_free_data(sc);
+       vmxnet3_free_resources(sc);
+       vmxnet3_free_rxtx_queues(sc);
+
+       VMXNET3_CORE_LOCK_DESTROY(sc);
+
+       return (0);
+}
+
+static int
+vmxnet3_shutdown(device_t dev)
+{
+
+       return (0);
+}
+
+static int
+vmxnet3_alloc_resources(struct vmxnet3_softc *sc)
+{
+       device_t dev;
+       int rid;
+
+       dev = sc->vmx_dev;
+
+       rid = PCIR_BAR(0);
+       sc->vmx_res0 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+           RF_ACTIVE);
+       if (sc->vmx_res0 == NULL) {
+               device_printf(dev,
+                   "could not map BAR0 memory\n");
+               return (ENXIO);
+       }
+
+       sc->vmx_iot0 = rman_get_bustag(sc->vmx_res0);
+       sc->vmx_ioh0 = rman_get_bushandle(sc->vmx_res0);
+
+       rid = PCIR_BAR(1);
+       sc->vmx_res1 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+           RF_ACTIVE);
+       if (sc->vmx_res1 == NULL) {
+               device_printf(dev,
+                   "could not map BAR1 memory\n");
+               return (ENXIO);
+       }
+
+       sc->vmx_iot1 = rman_get_bustag(sc->vmx_res1);
+       sc->vmx_ioh1 = rman_get_bushandle(sc->vmx_res1);
+
+       if (pci_find_cap(dev, PCIY_MSIX, NULL) == 0) {
+               rid = PCIR_BAR(2);
+               sc->vmx_msix_res = bus_alloc_resource_any(dev,
+                   SYS_RES_MEMORY, &rid, RF_ACTIVE);
+       }
+
+       if (sc->vmx_msix_res == NULL)
+               sc->vmx_flags |= VMXNET3_FLAG_NO_MSIX;
+
+       return (0);
+}
+
+static void
+vmxnet3_free_resources(struct vmxnet3_softc *sc)
+{
+       device_t dev;
+       int rid;
+
+       dev = sc->vmx_dev;
+
+       if (sc->vmx_res0 != NULL) {
+               rid = PCIR_BAR(0);
+               bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->vmx_res0);
+               sc->vmx_res0 = NULL;
+       }
+
+       if (sc->vmx_res1 != NULL) {
+               rid = PCIR_BAR(1);
+               bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->vmx_res1);
+               sc->vmx_res1 = NULL;
+       }
+
+       if (sc->vmx_msix_res != NULL) {
+               rid = PCIR_BAR(2);
+               bus_release_resource(dev, SYS_RES_MEMORY, rid,
+                   sc->vmx_msix_res);
+               sc->vmx_msix_res = NULL;
+       }
+}
+
+static int
+vmxnet3_check_version(struct vmxnet3_softc *sc)
+{
+       device_t dev;
+       uint32_t version;
+
+       dev = sc->vmx_dev;
+
+       version = vmxnet3_read_bar1(sc, VMXNET3_BAR1_VRRS);
+       if ((version & 0x01) == 0) {
+               device_printf(dev, "unsupported hardware version %#x\n",
+                   version);
+               return (ENOTSUP);
+       } 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 = VMXNET3_MAX_RX_SEGS;
+}
+
+static int
+vmxnet3_alloc_msix_interrupts(struct vmxnet3_softc *sc)
+{
+       device_t dev;
+       int nmsix, cnt, required;
+
+       dev = sc->vmx_dev;
+
+       if (sc->vmx_flags & VMXNET3_FLAG_NO_MSIX)
+               return (1);
+
+       /* Allocate an additional vector for the events interrupt. */
+       required = sc->vmx_nrxqueues + sc->vmx_ntxqueues + 1;
+
+       nmsix = pci_msix_count(dev);
+       if (nmsix < required)
+               return (1);
+
+       cnt = required;
+       if (pci_alloc_msix(dev, &cnt) == 0 && cnt >= required) {
+               sc->vmx_nintrs = required;
+               return (0);
+       } else
+               pci_release_msi(dev);
+
+       return (1);
+}
+
+static int
+vmxnet3_alloc_msi_interrupts(struct vmxnet3_softc *sc)
+{
+       device_t dev;
+       int nmsi, cnt, required;
+
+       dev = sc->vmx_dev;
+       required = 1;
+
+       nmsi = pci_msi_count(dev);
+       if (nmsi < required)
+               return (1);
+
+       cnt = required;
+       if (pci_alloc_msi(dev, &cnt) == 0 && cnt >= required) {
+               sc->vmx_nintrs = 1;
+               return (0);
+       } else
+               pci_release_msi(dev);
+
+       return (1);
+}
+
+static int
+vmxnet3_alloc_legacy_interrupts(struct vmxnet3_softc *sc)
+{
+
+       sc->vmx_nintrs = 1;
+       return (0);
+}
+
+static int
+vmxnet3_alloc_interrupt(struct vmxnet3_softc *sc, int rid, int flags,
+    struct vmxnet3_interrupt *intr)
+{
+       struct resource *irq;
+
+       irq = bus_alloc_resource_any(sc->vmx_dev, SYS_RES_IRQ, &rid, flags);
+       if (irq == NULL)
+               return (ENXIO);
+
+       intr->vmxi_irq = irq;
+       intr->vmxi_rid = rid;
+
+       return (0);
+}
+
+static int
+vmxnet3_alloc_intr_resources(struct vmxnet3_softc *sc)
+{
+       int i, rid, flags, error;
+
+       rid = 0;
+       flags = RF_ACTIVE;
+
+       if (sc->vmx_intr_type == VMXNET3_IT_LEGACY)
+               flags |= RF_SHAREABLE;
+       else
+               rid = 1;
+
+       for (i = 0; i < sc->vmx_nintrs; i++, rid++) {
+               error = vmxnet3_alloc_interrupt(sc, rid, flags,
+                   &sc->vmx_intrs[i]);
+               if (error)
+                       return (error);
+       }
+
+       return (0);
+}
+
+/*
+ * NOTE: We only support the simple case of each Rx and Tx queue on its
+ * own MSIX vector. This is good enough until we support mulitqueue.
+ */
+static int
+vmxnet3_setup_msix_interrupts(struct vmxnet3_softc *sc)
+{
+       device_t dev;
+       struct vmxnet3_txqueue *txq;
+       struct vmxnet3_rxqueue *rxq;
+       struct vmxnet3_interrupt *intr;
+       enum intr_type type;
+       int i, error;
+
+       dev = sc->vmx_dev;
+       intr = &sc->vmx_intrs[0];
+       type = INTR_TYPE_NET | INTR_MPSAFE;
+
+       for (i = 0; i < sc->vmx_ntxqueues; i++, intr++) {
+               txq = &sc->vmx_txq[i];
+               error = bus_setup_intr(dev, intr->vmxi_irq, type, NULL,
+                    vmxnet3_txq_intr, txq, &intr->vmxi_handler);
+               if (error)
+                       return (error);
+               txq->vxtxq_intr_idx = intr->vmxi_rid - 1;
+       }
+
+       for (i = 0; i < sc->vmx_nrxqueues; i++, intr++) {
+               rxq = &sc->vmx_rxq[i];
+               error = bus_setup_intr(dev, intr->vmxi_irq, type, NULL,
+                   vmxnet3_rxq_intr, rxq, &intr->vmxi_handler);
+               if (error)
+                       return (error);
+               rxq->vxrxq_intr_idx = intr->vmxi_rid - 1;
+       }
+
+       error = bus_setup_intr(dev, intr->vmxi_irq, type, NULL,
+           vmxnet3_event_intr, sc, &intr->vmxi_handler);
+       if (error)
+               return (error);
+       sc->vmx_event_intr_idx = intr->vmxi_rid - 1;
+
+       return (0);
+}
+
+static int
+vmxnet3_setup_legacy_interrupt(struct vmxnet3_softc *sc)
+{
+       struct vmxnet3_interrupt *intr;
+       int i, error;
+
+       intr = &sc->vmx_intrs[0];
+       error = bus_setup_intr(sc->vmx_dev, intr->vmxi_irq,
+           INTR_TYPE_NET | INTR_MPSAFE, NULL, vmxnet3_legacy_intr, sc,
+           &intr->vmxi_handler);
+
+       for (i = 0; i < sc->vmx_ntxqueues; i++)
+               sc->vmx_txq[i].vxtxq_intr_idx = 0;
+       for (i = 0; i < sc->vmx_nrxqueues; i++)
+               sc->vmx_rxq[i].vxrxq_intr_idx = 0;
+       sc->vmx_event_intr_idx = 0;
+
+       return (error);
+}
+
+/*
+ * XXX BMV Should probably reorganize the attach and just do
+ * this in vmxnet3_init_shared_data().
+ */
+static void
+vmxnet3_set_interrupt_idx(struct vmxnet3_softc *sc)
+{
+       struct vmxnet3_txqueue *txq;
+       struct vmxnet3_txq_shared *txs;
+       struct vmxnet3_rxqueue *rxq;
+       struct vmxnet3_rxq_shared *rxs;
+       int i;
+
+       sc->vmx_ds->evintr = sc->vmx_event_intr_idx;
+
+       for (i = 0; i < sc->vmx_ntxqueues; i++) {
+               txq = &sc->vmx_txq[i];
+               txs = txq->vxtxq_ts;
+               txs->intr_idx = txq->vxtxq_intr_idx;
+       }
+
+       for (i = 0; i < sc->vmx_nrxqueues; i++) {
+               rxq = &sc->vmx_rxq[i];
+               rxs = rxq->vxrxq_rs;
+               rxs->intr_idx = rxq->vxrxq_intr_idx;
+       }
+}
+
+static int
+vmxnet3_setup_interrupts(struct vmxnet3_softc *sc)
+{
+       int error;
+
+       error = vmxnet3_alloc_intr_resources(sc);
+       if (error)
+               return (error);
+
+       switch (sc->vmx_intr_type) {
+       case VMXNET3_IT_MSIX:
+               error = vmxnet3_setup_msix_interrupts(sc);
+               break;
+       case VMXNET3_IT_MSI:
+       case VMXNET3_IT_LEGACY:
+               error = vmxnet3_setup_legacy_interrupt(sc);
+               break;
+       default:
+               panic("%s: invalid interrupt type %d", __func__,
+                   sc->vmx_intr_type);
+       }
+
+       if (error == 0)
+               vmxnet3_set_interrupt_idx(sc);
+
+       return (error);
+}
+
+static int
+vmxnet3_alloc_interrupts(struct vmxnet3_softc *sc)
+{
+       device_t dev;
+       uint32_t config;
+       int error;
+
+       dev = sc->vmx_dev;
+       config = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_INTRCFG);
+
+       sc->vmx_intr_type = config & 0x03;
+       sc->vmx_intr_mask_mode = (config >> 2) & 0x03;
+
+       switch (sc->vmx_intr_type) {
+       case VMXNET3_IT_AUTO:
+               sc->vmx_intr_type = VMXNET3_IT_MSIX;
+               /* FALLTHROUGH */
+       case VMXNET3_IT_MSIX:
+               error = vmxnet3_alloc_msix_interrupts(sc);
+               if (error == 0)
+                       break;
+               sc->vmx_intr_type = VMXNET3_IT_MSI;
+               /* FALLTHROUGH */
+       case VMXNET3_IT_MSI:
+               error = vmxnet3_alloc_msi_interrupts(sc);
+               if (error == 0)
+                       break;
+               sc->vmx_intr_type = VMXNET3_IT_LEGACY;
+               /* FALLTHROUGH */
+       case VMXNET3_IT_LEGACY:
+               error = vmxnet3_alloc_legacy_interrupts(sc);
+               if (error == 0)
+                       break;
+               /* FALLTHROUGH */

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to