Module Name:    src
Committed By:   hikaru
Date:           Tue Jun 10 01:42:39 UTC 2014

Modified Files:
        src/distrib/sets/lists/man: mi
        src/share/man/man4/man4.x86: Makefile
        src/sys/arch/amd64/conf: ALL GENERIC
        src/sys/arch/i386/conf: ALL GENERIC
        src/sys/arch/x86/pci: files.pci
Added Files:
        src/share/man/man4/man4.x86: vmx.4
        src/sys/arch/x86/pci: if_vmx.c if_vmxreg.h

Log Message:
Add VMware VMXNET3 ethernet driver from OpenBSD, vmx(4).


To generate a diff of this commit:
cvs rdiff -u -r1.1474 -r1.1475 src/distrib/sets/lists/man/mi
cvs rdiff -u -r1.14 -r1.15 src/share/man/man4/man4.x86/Makefile
cvs rdiff -u -r0 -r1.1 src/share/man/man4/man4.x86/vmx.4
cvs rdiff -u -r1.8 -r1.9 src/sys/arch/amd64/conf/ALL
cvs rdiff -u -r1.387 -r1.388 src/sys/arch/amd64/conf/GENERIC
cvs rdiff -u -r1.375 -r1.376 src/sys/arch/i386/conf/ALL
cvs rdiff -u -r1.1104 -r1.1105 src/sys/arch/i386/conf/GENERIC
cvs rdiff -u -r1.15 -r1.16 src/sys/arch/x86/pci/files.pci
cvs rdiff -u -r0 -r1.1 src/sys/arch/x86/pci/if_vmx.c \
    src/sys/arch/x86/pci/if_vmxreg.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/distrib/sets/lists/man/mi
diff -u src/distrib/sets/lists/man/mi:1.1474 src/distrib/sets/lists/man/mi:1.1475
--- src/distrib/sets/lists/man/mi:1.1474	Sun May 18 18:24:16 2014
+++ src/distrib/sets/lists/man/mi	Tue Jun 10 01:42:38 2014
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.1474 2014/05/18 18:24:16 jakllsch Exp $
+# $NetBSD: mi,v 1.1475 2014/06/10 01:42:38 hikaru Exp $
 #
 # Note: don't delete entries from here - mark them as "obsolete" instead.
 #
@@ -1970,6 +1970,7 @@
 ./usr/share/man/cat4/x86/tprof_amdpmi.0		man-sys-catman		.cat
 ./usr/share/man/cat4/x86/tprof_pmi.0		man-sys-catman		.cat
 ./usr/share/man/cat4/x86/vmt.0			man-sys-catman		.cat
+./usr/share/man/cat4/x86/vmx.0			man-sys-catman		.cat
 ./usr/share/man/cat4/xbd.0			man-sys-catman		.cat
 ./usr/share/man/cat4/xbdback.0			man-sys-catman		.cat
 ./usr/share/man/cat4/xbox.0			man-sys-catman		.cat
@@ -4929,6 +4930,7 @@
 ./usr/share/man/html4/x86/tprof_amdpmi.html	man-sys-htmlman		html
 ./usr/share/man/html4/x86/tprof_pmi.html	man-sys-htmlman		html
 ./usr/share/man/html4/x86/vmt.html		man-sys-htmlman		html
+./usr/share/man/html4/x86/vmx.html		man-sys-htmlman		html
 ./usr/share/man/html4/xbd.html			man-sys-htmlman		html
 ./usr/share/man/html4/xbdback.html		man-sys-htmlman		html
 ./usr/share/man/html4/xbox.html			man-sys-htmlman		html
@@ -7818,6 +7820,7 @@
 ./usr/share/man/man4/x86/tprof_amdpmi.4		man-sys-man		.man
 ./usr/share/man/man4/x86/tprof_pmi.4		man-sys-man		.man
 ./usr/share/man/man4/x86/vmt.4			man-sys-man		.man
+./usr/share/man/man4/x86/vmx.4			man-sys-man		.man
 ./usr/share/man/man4/xbd.4			man-sys-man		.man
 ./usr/share/man/man4/xbdback.4			man-sys-man		.man
 ./usr/share/man/man4/xbox.4			man-sys-man		.man

Index: src/share/man/man4/man4.x86/Makefile
diff -u src/share/man/man4/man4.x86/Makefile:1.14 src/share/man/man4/man4.x86/Makefile:1.15
--- src/share/man/man4/man4.x86/Makefile:1.14	Mon Jun 10 07:14:01 2013
+++ src/share/man/man4/man4.x86/Makefile	Tue Jun 10 01:42:39 2014
@@ -1,8 +1,8 @@
-#	$NetBSD: Makefile,v 1.14 2013/06/10 07:14:01 kardel Exp $
+#	$NetBSD: Makefile,v 1.15 2014/06/10 01:42:39 hikaru Exp $
 
 MAN=	amdpcib.4 apic.4 balloon.4 coretemp.4 est.4 fdc.4 \
 	fwhrng.4 hpet.4 ichlpcib.4 lpt.4 mem.4 odcm.4 powernow.4 \
-	soekrisgpio.4 tprof_amdpmi.4 tprof_pmi.4 vmt.4
+	soekrisgpio.4 tprof_amdpmi.4 tprof_pmi.4 vmt.4 vmx.4
 
 MLINKS+=apic.4 ioapic.4 \
 	apic.4 lapic.4

Index: src/sys/arch/amd64/conf/ALL
diff -u src/sys/arch/amd64/conf/ALL:1.8 src/sys/arch/amd64/conf/ALL:1.9
--- src/sys/arch/amd64/conf/ALL:1.8	Mon Jun  2 02:11:51 2014
+++ src/sys/arch/amd64/conf/ALL	Tue Jun 10 01:42:39 2014
@@ -1,4 +1,4 @@
-# $NetBSD: ALL,v 1.8 2014/06/02 02:11:51 dholland Exp $
+# $NetBSD: ALL,v 1.9 2014/06/10 01:42:39 hikaru Exp $
 # From NetBSD: GENERIC,v 1.787 2006/10/01 18:37:54 bouyer Exp
 #
 # ALL machine description file
@@ -17,7 +17,7 @@ include 	"arch/amd64/conf/std.amd64"
 
 options 	INCLUDE_CONFIG_FILE	# embed config file in kernel binary
 
-#ident 		"ALL-$Revision: 1.8 $"
+#ident 		"ALL-$Revision: 1.9 $"
 
 maxusers	64		# estimated number of users
 
@@ -928,6 +928,7 @@ tl*	at pci? dev ? function ?	# ThunderLA
 tlp*	at pci? dev ? function ?	# DECchip 21x4x and clones
 txp*	at pci? dev ? function ?	# 3com 3cr990
 vge*	at pci? dev ? function ?	# VIATech VT612X Gigabit Ethernet
+vmx*	at pci? dev ? function ?	# VMware VMXNET3
 vr*	at pci? dev ? function ?	# VIA Rhine Fast Ethernet
 vte*	at pci? dev ? function ?	# Vortex86 RDC R6040 Fast Ethernet
 wi*	at pci? dev ? function ?	# Intersil Prism Mini-PCI (802.11b)

Index: src/sys/arch/amd64/conf/GENERIC
diff -u src/sys/arch/amd64/conf/GENERIC:1.387 src/sys/arch/amd64/conf/GENERIC:1.388
--- src/sys/arch/amd64/conf/GENERIC:1.387	Thu May 29 14:49:35 2014
+++ src/sys/arch/amd64/conf/GENERIC	Tue Jun 10 01:42:39 2014
@@ -1,4 +1,4 @@
-# $NetBSD: GENERIC,v 1.387 2014/05/29 14:49:35 christos Exp $
+# $NetBSD: GENERIC,v 1.388 2014/06/10 01:42:39 hikaru Exp $
 #
 # GENERIC machine description file
 #
@@ -22,7 +22,7 @@ include	"arch/amd64/conf/std.amd64"
 
 options 	INCLUDE_CONFIG_FILE	# embed config file in kernel binary
 
-#ident 		"GENERIC-$Revision: 1.387 $"
+#ident 		"GENERIC-$Revision: 1.388 $"
 
 maxusers	64		# estimated number of users
 
@@ -740,6 +740,7 @@ tl*	at pci? dev ? function ?	# ThunderLA
 tlp*	at pci? dev ? function ?	# DECchip 21x4x and clones
 txp*	at pci? dev ? function ?	# 3com 3cr990
 vge*	at pci? dev ? function ?	# VIATech VT612X Gigabit Ethernet
+vmx*	at pci? dev ? function ?	# VMware VMXNET3
 vr*	at pci? dev ? function ?	# VIA Rhine Fast Ethernet
 wi*	at pci? dev ? function ?	# Intersil Prism Mini-PCI (802.11b)
 wm*	at pci? dev ? function ?	# Intel 82543/82544 gigabit

Index: src/sys/arch/i386/conf/ALL
diff -u src/sys/arch/i386/conf/ALL:1.375 src/sys/arch/i386/conf/ALL:1.376
--- src/sys/arch/i386/conf/ALL:1.375	Mon Jun  2 02:11:52 2014
+++ src/sys/arch/i386/conf/ALL	Tue Jun 10 01:42:39 2014
@@ -1,4 +1,4 @@
-# $NetBSD: ALL,v 1.375 2014/06/02 02:11:52 dholland Exp $
+# $NetBSD: ALL,v 1.376 2014/06/10 01:42:39 hikaru Exp $
 # From NetBSD: GENERIC,v 1.787 2006/10/01 18:37:54 bouyer Exp
 #
 # ALL machine description file
@@ -17,7 +17,7 @@ include 	"arch/i386/conf/std.i386"
 
 options 	INCLUDE_CONFIG_FILE	# embed config file in kernel binary
 
-#ident 		"ALL-$Revision: 1.375 $"
+#ident 		"ALL-$Revision: 1.376 $"
 
 maxusers	64		# estimated number of users
 
@@ -1052,6 +1052,7 @@ tl*	at pci? dev ? function ?	# ThunderLA
 tlp*	at pci? dev ? function ?	# DECchip 21x4x and clones
 txp*	at pci? dev ? function ?	# 3com 3cr990
 vge*	at pci? dev ? function ?	# VIATech VT612X Gigabit Ethernet
+vmx*	at pci? dev ? function ?	# VMware VMXNET3
 vr*	at pci? dev ? function ?	# VIA Rhine Fast Ethernet
 vte*	at pci? dev ? function ?	# Vortex86 RDC R6040 Fast Ethernet
 wi*	at pci? dev ? function ?	# Intersil Prism Mini-PCI (802.11b)

Index: src/sys/arch/i386/conf/GENERIC
diff -u src/sys/arch/i386/conf/GENERIC:1.1104 src/sys/arch/i386/conf/GENERIC:1.1105
--- src/sys/arch/i386/conf/GENERIC:1.1104	Thu May 29 14:48:40 2014
+++ src/sys/arch/i386/conf/GENERIC	Tue Jun 10 01:42:39 2014
@@ -1,4 +1,4 @@
-# $NetBSD: GENERIC,v 1.1104 2014/05/29 14:48:40 christos Exp $
+# $NetBSD: GENERIC,v 1.1105 2014/06/10 01:42:39 hikaru Exp $
 #
 # GENERIC machine description file
 #
@@ -22,7 +22,7 @@ include 	"arch/i386/conf/std.i386"
 
 options 	INCLUDE_CONFIG_FILE	# embed config file in kernel binary
 
-#ident 		"GENERIC-$Revision: 1.1104 $"
+#ident 		"GENERIC-$Revision: 1.1105 $"
 
 maxusers	64		# estimated number of users
 
@@ -992,6 +992,7 @@ tlp*	at pci? dev ? function ?	# DECchip 
 txp*	at pci? dev ? function ?	# 3com 3cr990
 vte*	at pci? dev ? function ?	# RDC R6040 10/100 Ethernet
 vge*	at pci? dev ? function ?	# VIATech VT612X Gigabit Ethernet
+vmx*	at pci? dev ? function ?	# VMware VMXNET3
 vr*	at pci? dev ? function ?	# VIA Rhine Fast Ethernet
 wi*	at pci? dev ? function ?	# Intersil Prism Mini-PCI (802.11b)
 wm*	at pci? dev ? function ?	# Intel 8254x gigabit

Index: src/sys/arch/x86/pci/files.pci
diff -u src/sys/arch/x86/pci/files.pci:1.15 src/sys/arch/x86/pci/files.pci:1.16
--- src/sys/arch/x86/pci/files.pci:1.15	Wed Dec  5 16:19:46 2012
+++ src/sys/arch/x86/pci/files.pci	Tue Jun 10 01:42:39 2014
@@ -1,4 +1,4 @@
-#	$NetBSD: files.pci,v 1.15 2012/12/05 16:19:46 christos Exp $
+#	$NetBSD: files.pci,v 1.16 2014/06/10 01:42:39 hikaru Exp $
 
 device 	aapic
 attach 	aapic at pci
@@ -59,3 +59,8 @@ file	arch/x86/pci/tcpcib.c		tcpcib
 device	fwhrng
 attach	fwhrng at fwhichbus
 file	arch/x86/pci/fwhrng.c		fwhrng needs-flag
+
+# VMware VMXNET3 virtual interface
+device	vmx: ether, ifnet, arp
+attach	vmx at pci
+file	arch/x86/pci/if_vmx.c		vmx

Added files:

Index: src/share/man/man4/man4.x86/vmx.4
diff -u /dev/null src/share/man/man4/man4.x86/vmx.4:1.1
--- /dev/null	Tue Jun 10 01:42:39 2014
+++ src/share/man/man4/man4.x86/vmx.4	Tue Jun 10 01:42:39 2014
@@ -0,0 +1,113 @@
+.\"	$NetBSD: vmx.4,v 1.1 2014/06/10 01:42:39 hikaru Exp $
+.\"	$OpenBSD: vmx.4,v 1.1 2013/05/31 20:18:44 reyk Exp $
+.\"
+.\" 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.
+.\"
+.Dd June 7, 2014
+.Dt VMX 4
+.Os
+.Sh NAME
+.Nm vmx
+.Nd VMware VMXNET3 Virtual Interface Controller device
+.Sh SYNOPSIS
+.Cd "vmx* at pci? dev ? function ?"
+.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 wm 4
+interfaces also available in the VMware environment.
+The
+.Nm vmx
+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.
+In comparison to the earlier VMXNET versions,
+VMXNET3 supports additional 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
+The
+.Nm
+driver supports the following media types:
+.Bl -tag -width autoselect
+.It autoselect
+Enable autoselection of the media type and options.
+The driver always uses the fastest available speed and the media
+options provided by the underlying host of the virtual machine.
+.It 10GbaseT mediaopt full-duplex
+Set 10Gbps operation.
+.It 1000baseT mediaopt full-duplex
+Set 1000Mbps operation.
+.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 arp 4 ,
+.Xr wm 4 ,
+.Xr ifmedia 4 ,
+.Xr intro 4 ,
+.Xr netintro 4 ,
+.Xr pci 4 ,
+.Xr pcn 4 ,
+.Xr ifconfig 8
+.Sh HISTORY
+The
+.Nm
+device driver first appeared in
+.Ox 5.5 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was originally written by
+.An Tsubai Masanari .
+.Nx porting was done by
+.An Hikaru ABE
+.Aq Mt hik...@netbsd.org .

Index: src/sys/arch/x86/pci/if_vmx.c
diff -u /dev/null src/sys/arch/x86/pci/if_vmx.c:1.1
--- /dev/null	Tue Jun 10 01:42:39 2014
+++ src/sys/arch/x86/pci/if_vmx.c	Tue Jun 10 01:42:39 2014
@@ -0,0 +1,1246 @@
+/*	$NetBSD: if_vmx.c,v 1.1 2014/06/10 01:42:39 hikaru Exp $	*/
+/*	$OpenBSD: if_vmx.c,v 1.16 2014/01/22 06:04:17 brad Exp $	*/
+
+/*
+ * Copyright (c) 2013 Tsubai Masanari
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: if_vmx.c,v 1.1 2014/06/10 01:42:39 hikaru Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/mbuf.h>
+#include <sys/sockio.h>
+
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_ether.h>
+#include <net/if_media.h>
+
+#include <netinet/if_inarp.h>
+#include <netinet/in_systm.h>	/* for <netinet/ip.h> */
+#include <netinet/in.h>		/* for <netinet/ip.h> */
+#include <netinet/ip.h>		/* for struct ip */
+#include <netinet/tcp.h>	/* for struct tcphdr */
+#include <netinet/udp.h>	/* for struct udphdr */
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcidevs.h>
+
+#include <arch/x86/pci/if_vmxreg.h>
+
+#define NRXQUEUE 1
+#define NTXQUEUE 1
+
+#define NTXDESC 128 /* tx ring size */
+#define NTXSEGS 8 /* tx descriptors per packet */
+#define NRXDESC 128
+#define NTXCOMPDESC NTXDESC
+#define NRXCOMPDESC (NRXDESC * 2)	/* ring1 + ring2 */
+
+#define VMXNET3_DRIVER_VERSION 0x00010000
+
+struct vmxnet3_txring {
+	struct mbuf *m[NTXDESC];
+	bus_dmamap_t dmap[NTXDESC];
+	struct vmxnet3_txdesc *txd;
+	u_int head;
+	u_int next;
+	uint8_t gen;
+};
+
+struct vmxnet3_rxring {
+	struct mbuf *m[NRXDESC];
+	bus_dmamap_t dmap[NRXDESC];
+	struct vmxnet3_rxdesc *rxd;
+	u_int fill;
+	uint8_t gen;
+	uint8_t rid;
+};
+
+struct vmxnet3_comp_ring {
+	union {
+		struct vmxnet3_txcompdesc *txcd;
+		struct vmxnet3_rxcompdesc *rxcd;
+	};
+	u_int next;
+	uint8_t gen;
+};
+
+struct vmxnet3_txqueue {
+	struct vmxnet3_txring cmd_ring;
+	struct vmxnet3_comp_ring comp_ring;
+	struct vmxnet3_txq_shared *ts;
+};
+
+struct vmxnet3_rxqueue {
+	struct vmxnet3_rxring cmd_ring[2];
+	struct vmxnet3_comp_ring comp_ring;
+	struct vmxnet3_rxq_shared *rs;
+};
+
+struct vmxnet3_softc {
+	device_t sc_dev;
+	struct ethercom sc_ethercom;
+	struct ifmedia sc_media;
+
+	bus_space_tag_t	sc_iot0;
+	bus_space_tag_t	sc_iot1;
+	bus_space_handle_t sc_ioh0;
+	bus_space_handle_t sc_ioh1;
+	bus_dma_tag_t sc_dmat;
+
+	struct vmxnet3_txqueue sc_txq[NTXQUEUE];
+	struct vmxnet3_rxqueue sc_rxq[NRXQUEUE];
+	struct vmxnet3_driver_shared *sc_ds;
+	uint8_t *sc_mcast;
+};
+
+#define VMXNET3_STAT
+
+#ifdef VMXNET3_STAT
+struct {
+	u_int ntxdesc;
+	u_int nrxdesc;
+	u_int txhead;
+	u_int txdone;
+	u_int maxtxlen;
+	u_int rxdone;
+	u_int rxfill;
+	u_int intr;
+} vmxstat = {
+	.ntxdesc = NTXDESC,
+	.nrxdesc = NRXDESC
+};
+#endif
+
+#define JUMBO_LEN (MCLBYTES - ETHER_ALIGN)	/* XXX */
+#define DMAADDR(map) ((map)->dm_segs[0].ds_addr)
+
+#define READ_BAR0(sc, reg) bus_space_read_4((sc)->sc_iot0, (sc)->sc_ioh0, reg)
+#define READ_BAR1(sc, reg) bus_space_read_4((sc)->sc_iot1, (sc)->sc_ioh1, reg)
+#define WRITE_BAR0(sc, reg, val) \
+	bus_space_write_4((sc)->sc_iot0, (sc)->sc_ioh0, reg, val)
+#define WRITE_BAR1(sc, reg, val) \
+	bus_space_write_4((sc)->sc_iot1, (sc)->sc_ioh1, reg, val)
+#define WRITE_CMD(sc, cmd) WRITE_BAR1(sc, VMXNET3_BAR1_CMD, cmd)
+#define vtophys(va) 0		/* XXX ok? */
+
+int vmxnet3_match(device_t, cfdata_t, void *);
+void vmxnet3_attach(device_t, device_t, void *);
+int vmxnet3_dma_init(struct vmxnet3_softc *);
+int vmxnet3_alloc_txring(struct vmxnet3_softc *, int);
+int vmxnet3_alloc_rxring(struct vmxnet3_softc *, int);
+void vmxnet3_txinit(struct vmxnet3_softc *, struct vmxnet3_txqueue *);
+void vmxnet3_rxinit(struct vmxnet3_softc *, struct vmxnet3_rxqueue *);
+void vmxnet3_txstop(struct vmxnet3_softc *, struct vmxnet3_txqueue *);
+void vmxnet3_rxstop(struct vmxnet3_softc *, struct vmxnet3_rxqueue *);
+void vmxnet3_link_state(struct vmxnet3_softc *);
+void vmxnet3_enable_all_intrs(struct vmxnet3_softc *);
+void vmxnet3_disable_all_intrs(struct vmxnet3_softc *);
+int vmxnet3_intr(void *);
+void vmxnet3_evintr(struct vmxnet3_softc *);
+void vmxnet3_txintr(struct vmxnet3_softc *, struct vmxnet3_txqueue *);
+void vmxnet3_rxintr(struct vmxnet3_softc *, struct vmxnet3_rxqueue *);
+void vmxnet3_iff(struct vmxnet3_softc *);
+void vmxnet3_rx_csum(struct vmxnet3_rxcompdesc *, struct mbuf *);
+int vmxnet3_getbuf(struct vmxnet3_softc *, struct vmxnet3_rxring *);
+void vmxnet3_stop(struct ifnet *);
+void vmxnet3_reset(struct ifnet *);
+int vmxnet3_init(struct ifnet *);
+int vmxnet3_ioctl(struct ifnet *, u_long, void *);
+int vmxnet3_change_mtu(struct vmxnet3_softc *, int);
+void vmxnet3_start(struct ifnet *);
+int vmxnet3_load_mbuf(struct vmxnet3_softc *, struct mbuf *);
+void vmxnet3_watchdog(struct ifnet *);
+void vmxnet3_media_status(struct ifnet *, struct ifmediareq *);
+int vmxnet3_media_change(struct ifnet *);
+void *vmxnet3_dma_allocmem(struct vmxnet3_softc *, u_int, u_int, bus_addr_t *);
+
+CFATTACH_DECL3_NEW(vmx, sizeof(struct vmxnet3_softc),
+    vmxnet3_match, vmxnet3_attach, NULL, NULL, NULL, NULL, 0);
+
+int
+vmxnet3_match(device_t parent, cfdata_t match, void *aux)
+{
+	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
+
+	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_VMWARE &&
+	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_VMWARE_VMXNET3)
+		return 1;
+
+	return 0;
+}
+
+void
+vmxnet3_attach(device_t parent, device_t self, void *aux)
+{
+	struct vmxnet3_softc *sc = device_private(self);
+	struct pci_attach_args *pa = aux;
+	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+	pci_intr_handle_t ih;
+	const char *intrstr;
+	void *vih;
+	u_int memtype, ver, macl, mach;
+	pcireg_t preg;
+	u_char enaddr[ETHER_ADDR_LEN];
+	char intrbuf[PCI_INTRSTR_LEN];
+
+	sc->sc_dev = self;
+
+	pci_aprint_devinfo_fancy(pa, "Ethernet controller", "vmxnet3", 1);
+
+	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, 0x10);
+	if (pci_mapreg_map(pa, 0x10, memtype, 0, &sc->sc_iot0, &sc->sc_ioh0,
+	    NULL, NULL)) {
+		aprint_error_dev(sc->sc_dev, "failed to map BAR0\n");
+		return;
+	}
+	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, 0x14);
+	if (pci_mapreg_map(pa, 0x14, memtype, 0, &sc->sc_iot1, &sc->sc_ioh1,
+	    NULL, NULL)) {
+		aprint_error_dev(sc->sc_dev, "failed to map BAR1\n");
+		return;
+	}
+
+	ver = READ_BAR1(sc, VMXNET3_BAR1_VRRS);
+	if ((ver & 0x1) == 0) {
+		aprint_error_dev(sc->sc_dev,
+		    "unsupported hardware version 0x%x\n", ver);
+		return;
+	}
+	WRITE_BAR1(sc, VMXNET3_BAR1_VRRS, 1);
+
+	ver = READ_BAR1(sc, VMXNET3_BAR1_UVRS);
+	if ((ver & 0x1) == 0) {
+		aprint_error_dev(sc->sc_dev,
+		    "incompatiable UPT version 0x%x\n", ver);
+		return;
+	}
+	WRITE_BAR1(sc, VMXNET3_BAR1_UVRS, 1);
+
+	preg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
+	preg |= PCI_COMMAND_MASTER_ENABLE;
+	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, preg);
+
+	sc->sc_dmat = pa->pa_dmat;
+	if (vmxnet3_dma_init(sc)) {
+		aprint_error_dev(sc->sc_dev, "failed to setup DMA\n");
+		return;
+	}
+
+	if (pci_intr_map(pa, &ih)) {
+		aprint_error_dev(sc->sc_dev, "failed to map interrupt\n");
+		return;
+	}
+	intrstr = pci_intr_string(pa->pa_pc, ih, intrbuf, sizeof(intrbuf));
+	vih = pci_intr_establish(pa->pa_pc, ih, IPL_NET, vmxnet3_intr, sc);
+	if (vih == NULL) {
+		aprint_error_dev(sc->sc_dev,
+		    "unable to establish interrupt%s%s\n",
+		    intrstr ? " at " : "", intrstr ? intrstr : "");
+		return;
+	}
+	aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr);
+
+	WRITE_CMD(sc, VMXNET3_CMD_GET_MACL);
+	macl = READ_BAR1(sc, VMXNET3_BAR1_CMD);
+	enaddr[0] = macl;
+	enaddr[1] = macl >> 8;
+	enaddr[2] = macl >> 16;
+	enaddr[3] = macl >> 24;
+	WRITE_CMD(sc, VMXNET3_CMD_GET_MACH);
+	mach = READ_BAR1(sc, VMXNET3_BAR1_CMD);
+	enaddr[4] = mach;
+	enaddr[5] = mach >> 8;
+
+	WRITE_BAR1(sc, VMXNET3_BAR1_MACL, macl);
+	WRITE_BAR1(sc, VMXNET3_BAR1_MACH, mach);
+	aprint_normal_dev(sc->sc_dev, "Ethernet address %s\n",
+	    ether_sprintf(enaddr));
+
+	strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
+	ifp->if_softc = sc;
+	ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX;
+	ifp->if_ioctl = vmxnet3_ioctl;
+	ifp->if_start = vmxnet3_start;
+	ifp->if_watchdog = vmxnet3_watchdog;
+	ifp->if_init = vmxnet3_init;
+	sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU;
+	if (sc->sc_ds->upt_features & UPT1_F_CSUM)
+		sc->sc_ethercom.ec_if.if_capabilities |=
+		    IFCAP_CSUM_IPv4_Rx |
+		    IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx |
+		    IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx;
+	if (sc->sc_ds->upt_features & UPT1_F_VLAN)
+		sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_HWTAGGING;
+
+	IFQ_SET_MAXLEN(&ifp->if_snd, NTXDESC);
+	IFQ_SET_READY(&ifp->if_snd);
+
+	ifmedia_init(&sc->sc_media, IFM_IMASK, vmxnet3_media_change,
+	    vmxnet3_media_status);
+	ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_AUTO, 0, NULL);
+	ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_10G_T|IFM_FDX, 0, NULL);
+	ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_10G_T, 0, NULL);
+	ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_1000_T|IFM_FDX, 0, NULL);
+	ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_1000_T, 0, NULL);
+	ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_AUTO);
+
+	if_attach(ifp);
+	ether_ifattach(ifp, enaddr);
+	vmxnet3_link_state(sc);
+}
+
+int
+vmxnet3_dma_init(struct vmxnet3_softc *sc)
+{
+	struct vmxnet3_driver_shared *ds;
+	struct vmxnet3_txq_shared *ts;
+	struct vmxnet3_rxq_shared *rs;
+	bus_addr_t ds_pa, qs_pa, mcast_pa;
+	int i, queue, qs_len;
+	u_int major, minor, release_code, rev;
+
+	qs_len = NTXQUEUE * sizeof *ts + NRXQUEUE * sizeof *rs;
+	ts = vmxnet3_dma_allocmem(sc, qs_len, VMXNET3_DMADESC_ALIGN, &qs_pa);
+	if (ts == NULL)
+		return -1;
+	for (queue = 0; queue < NTXQUEUE; queue++)
+		sc->sc_txq[queue].ts = ts++;
+	rs = (void *)ts;
+	for (queue = 0; queue < NRXQUEUE; queue++)
+		sc->sc_rxq[queue].rs = rs++;
+
+	for (queue = 0; queue < NTXQUEUE; queue++)
+		if (vmxnet3_alloc_txring(sc, queue))
+			return -1;
+	for (queue = 0; queue < NRXQUEUE; queue++)
+		if (vmxnet3_alloc_rxring(sc, queue))
+			return -1;
+
+	sc->sc_mcast = vmxnet3_dma_allocmem(sc, 682 * ETHER_ADDR_LEN, 32, &mcast_pa);
+	if (sc->sc_mcast == NULL)
+		return -1;
+
+	ds = vmxnet3_dma_allocmem(sc, sizeof *sc->sc_ds, 8, &ds_pa);
+	if (ds == NULL)
+		return -1;
+	sc->sc_ds = ds;
+	ds->magic = VMXNET3_REV1_MAGIC;
+	ds->version = VMXNET3_DRIVER_VERSION;
+
+	/*
+	 * XXX FreeBSD version uses following values:
+	 * (Does the device behavior depend on them?)
+	 *
+	 * major = __FreeBSD_version / 100000;
+	 * minor = (__FreeBSD_version / 1000) % 100;
+	 * release_code = (__FreeBSD_version / 100) % 10;
+	 * rev = __FreeBSD_version % 100;
+	 */
+	major = 0;
+	minor = 0;
+	release_code = 0;
+	rev = 0;
+#ifdef __LP64__
+	ds->guest = release_code << 30 | rev << 22 | major << 14 | minor << 6
+	    | VMXNET3_GOS_FREEBSD | VMXNET3_GOS_64BIT;
+#else
+	ds->guest = release_code << 30 | rev << 22 | major << 14 | minor << 6
+	    | VMXNET3_GOS_FREEBSD | VMXNET3_GOS_32BIT;
+#endif
+	ds->vmxnet3_revision = 1;
+	ds->upt_version = 1;
+	ds->upt_features = UPT1_F_CSUM | UPT1_F_VLAN;
+	ds->driver_data = vtophys(sc);
+	ds->driver_data_len = sizeof(struct vmxnet3_softc);
+	ds->queue_shared = qs_pa;
+	ds->queue_shared_len = qs_len;
+	ds->mtu = ETHERMTU;
+	ds->ntxqueue = NTXQUEUE;
+	ds->nrxqueue = NRXQUEUE;
+	ds->mcast_table = mcast_pa;
+	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;
+	WRITE_BAR1(sc, VMXNET3_BAR1_DSL, ds_pa);
+	WRITE_BAR1(sc, VMXNET3_BAR1_DSH, (uint64_t)ds_pa >> 32);
+	return 0;
+}
+
+int
+vmxnet3_alloc_txring(struct vmxnet3_softc *sc, int queue)
+{
+	struct vmxnet3_txqueue *tq = &sc->sc_txq[queue];
+	struct vmxnet3_txq_shared *ts;
+	struct vmxnet3_txring *ring = &tq->cmd_ring;
+	struct vmxnet3_comp_ring *comp_ring = &tq->comp_ring;
+	bus_addr_t pa, comp_pa;
+	int idx;
+
+	ring->txd = vmxnet3_dma_allocmem(sc, NTXDESC * sizeof ring->txd[0], 512, &pa);
+	if (ring->txd == NULL)
+		return -1;
+	comp_ring->txcd = vmxnet3_dma_allocmem(sc,
+	    NTXCOMPDESC * sizeof comp_ring->txcd[0], 512, &comp_pa);
+	if (comp_ring->txcd == NULL)
+		return -1;
+
+	for (idx = 0; idx < NTXDESC; idx++) {
+		if (bus_dmamap_create(sc->sc_dmat, JUMBO_LEN, NTXSEGS,
+		    JUMBO_LEN, 0, BUS_DMA_NOWAIT, &ring->dmap[idx]))
+			return -1;
+	}
+
+	ts = tq->ts;
+	memset(ts, 0, sizeof *ts);
+	ts->npending = 0;
+	ts->intr_threshold = 1;
+	ts->cmd_ring = pa;
+	ts->cmd_ring_len = NTXDESC;
+	ts->comp_ring = comp_pa;
+	ts->comp_ring_len = NTXCOMPDESC;
+	ts->driver_data = vtophys(tq);
+	ts->driver_data_len = sizeof *tq;
+	ts->intr_idx = 0;
+	ts->stopped = 1;
+	ts->error = 0;
+	return 0;
+}
+
+int
+vmxnet3_alloc_rxring(struct vmxnet3_softc *sc, int queue)
+{
+	struct vmxnet3_rxqueue *rq = &sc->sc_rxq[queue];
+	struct vmxnet3_rxq_shared *rs;
+	struct vmxnet3_rxring *ring;
+	struct vmxnet3_comp_ring *comp_ring;
+	bus_addr_t pa[2], comp_pa;
+	int i, idx;
+
+	for (i = 0; i < 2; i++) {
+		ring = &rq->cmd_ring[i];
+		ring->rxd = vmxnet3_dma_allocmem(sc, NRXDESC * sizeof ring->rxd[0],
+		    512, &pa[i]);
+		if (ring->rxd == NULL)
+			return -1;
+	}
+	comp_ring = &rq->comp_ring;
+	comp_ring->rxcd = vmxnet3_dma_allocmem(sc,
+	    NRXCOMPDESC * sizeof comp_ring->rxcd[0], 512, &comp_pa);
+	if (comp_ring->rxcd == NULL)
+		return -1;
+
+	for (i = 0; i < 2; i++) {
+		ring = &rq->cmd_ring[i];
+		ring->rid = i;
+		for (idx = 0; idx < NRXDESC; idx++) {
+			if (bus_dmamap_create(sc->sc_dmat, JUMBO_LEN, 1,
+			    JUMBO_LEN, 0, BUS_DMA_NOWAIT, &ring->dmap[idx]))
+				return -1;
+		}
+	}
+
+	rs = rq->rs;
+	memset(rs, 0, sizeof *rs);
+	rs->cmd_ring[0] = pa[0];
+	rs->cmd_ring[1] = pa[1];
+	rs->cmd_ring_len[0] = NRXDESC;
+	rs->cmd_ring_len[1] = NRXDESC;
+	rs->comp_ring = comp_pa;
+	rs->comp_ring_len = NRXCOMPDESC;
+	rs->driver_data = vtophys(rq);
+	rs->driver_data_len = sizeof *rq;
+	rs->intr_idx = 0;
+	rs->stopped = 1;
+	rs->error = 0;
+	return 0;
+}
+
+void
+vmxnet3_txinit(struct vmxnet3_softc *sc, struct vmxnet3_txqueue *tq)
+{
+	struct vmxnet3_txring *ring = &tq->cmd_ring;
+	struct vmxnet3_comp_ring *comp_ring = &tq->comp_ring;
+
+	ring->head = ring->next = 0;
+	ring->gen = 1;
+	comp_ring->next = 0;
+	comp_ring->gen = 1;
+	memset(ring->txd, 0, NTXDESC * sizeof ring->txd[0]);
+	memset(comp_ring->txcd, 0, NTXCOMPDESC * sizeof comp_ring->txcd[0]);
+}
+
+void
+vmxnet3_rxinit(struct vmxnet3_softc *sc, struct vmxnet3_rxqueue *rq)
+{
+	struct vmxnet3_rxring *ring;
+	struct vmxnet3_comp_ring *comp_ring;
+	int i, idx;
+
+	for (i = 0; i < 2; i++) {
+		ring = &rq->cmd_ring[i];
+		ring->fill = 0;
+		ring->gen = 1;
+		memset(ring->rxd, 0, NRXDESC * sizeof ring->rxd[0]);
+		for (idx = 0; idx < NRXDESC; idx++) {
+			if (vmxnet3_getbuf(sc, ring))
+				break;
+		}
+	}
+	comp_ring = &rq->comp_ring;
+	comp_ring->next = 0;
+	comp_ring->gen = 1;
+	memset(comp_ring->rxcd, 0, NRXCOMPDESC * sizeof comp_ring->rxcd[0]);
+}
+
+void
+vmxnet3_txstop(struct vmxnet3_softc *sc, struct vmxnet3_txqueue *tq)
+{
+	struct vmxnet3_txring *ring = &tq->cmd_ring;
+	int idx;
+
+	for (idx = 0; idx < NTXDESC; idx++) {
+		if (ring->m[idx]) {
+			bus_dmamap_unload(sc->sc_dmat, ring->dmap[idx]);
+			m_freem(ring->m[idx]);
+			ring->m[idx] = NULL;
+		}
+	}
+}
+
+void
+vmxnet3_rxstop(struct vmxnet3_softc *sc, struct vmxnet3_rxqueue *rq)
+{
+	struct vmxnet3_rxring *ring;
+	int i, idx;
+
+	for (i = 0; i < 2; i++) {
+		ring = &rq->cmd_ring[i];
+		for (idx = 0; idx < NRXDESC; idx++) {
+			if (ring->m[idx]) {
+				m_freem(ring->m[idx]);
+				ring->m[idx] = NULL;
+			}
+		}
+	}
+}
+
+void
+vmxnet3_link_state(struct vmxnet3_softc *sc)
+{
+	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+	u_int x, link, speed;
+
+	WRITE_CMD(sc, VMXNET3_CMD_GET_LINK);
+	x = READ_BAR1(sc, VMXNET3_BAR1_CMD);
+	speed = x >> 16;
+	if (x & 1) {
+		ifp->if_baudrate = IF_Mbps(speed);
+		link = LINK_STATE_UP;
+	} else
+		link = LINK_STATE_DOWN;
+
+	if_link_state_change(ifp, link);
+}
+
+static inline void
+vmxnet3_enable_intr(struct vmxnet3_softc *sc, int irq)
+{
+	WRITE_BAR0(sc, VMXNET3_BAR0_IMASK(irq), 0);
+}
+
+static inline void
+vmxnet3_disable_intr(struct vmxnet3_softc *sc, int irq)
+{
+	WRITE_BAR0(sc, VMXNET3_BAR0_IMASK(irq), 1);
+}
+
+void
+vmxnet3_enable_all_intrs(struct vmxnet3_softc *sc)
+{
+	int i;
+
+	sc->sc_ds->ictrl &= ~VMXNET3_ICTRL_DISABLE_ALL;
+	for (i = 0; i < VMXNET3_NINTR; i++)
+		vmxnet3_enable_intr(sc, i);
+}
+
+void
+vmxnet3_disable_all_intrs(struct vmxnet3_softc *sc)
+{
+	int i;
+
+	sc->sc_ds->ictrl |= VMXNET3_ICTRL_DISABLE_ALL;
+	for (i = 0; i < VMXNET3_NINTR; i++)
+		vmxnet3_disable_intr(sc, i);
+}
+
+int
+vmxnet3_intr(void *arg)
+{
+	struct vmxnet3_softc *sc = arg;
+
+	if (READ_BAR1(sc, VMXNET3_BAR1_INTR) == 0)
+		return 0;
+	if (sc->sc_ds->event)
+		vmxnet3_evintr(sc);
+	vmxnet3_rxintr(sc, &sc->sc_rxq[0]);
+	vmxnet3_txintr(sc, &sc->sc_txq[0]);
+#ifdef VMXNET3_STAT
+	vmxstat.intr++;
+#endif
+	vmxnet3_enable_intr(sc, 0);
+	return 1;
+}
+
+void
+vmxnet3_evintr(struct vmxnet3_softc *sc)
+{
+	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+	u_int event = sc->sc_ds->event;
+	struct vmxnet3_txq_shared *ts;
+	struct vmxnet3_rxq_shared *rs;
+
+	/* Clear events. */
+	WRITE_BAR1(sc, VMXNET3_BAR1_EVENT, event);
+
+	/* Link state change? */
+	if (event & VMXNET3_EVENT_LINK)
+		vmxnet3_link_state(sc);
+
+	/* Queue error? */
+	if (event & (VMXNET3_EVENT_TQERROR | VMXNET3_EVENT_RQERROR)) {
+		WRITE_CMD(sc, VMXNET3_CMD_GET_STATUS);
+
+		ts = sc->sc_txq[0].ts;
+		if (ts->stopped)
+			printf("%s: TX error 0x%x\n", ifp->if_xname, ts->error);
+		rs = sc->sc_rxq[0].rs;
+		if (rs->stopped)
+			printf("%s: RX error 0x%x\n", ifp->if_xname, rs->error);
+		vmxnet3_reset(ifp);
+	}
+
+	if (event & VMXNET3_EVENT_DIC)
+		printf("%s: device implementation change event\n",
+		    ifp->if_xname);
+	if (event & VMXNET3_EVENT_DEBUG)
+		printf("%s: debug event\n", ifp->if_xname);
+}
+
+void
+vmxnet3_txintr(struct vmxnet3_softc *sc, struct vmxnet3_txqueue *tq)
+{
+	struct vmxnet3_txring *ring = &tq->cmd_ring;
+	struct vmxnet3_comp_ring *comp_ring = &tq->comp_ring;
+	struct vmxnet3_txcompdesc *txcd;
+	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+	u_int sop;
+
+	for (;;) {
+		txcd = &comp_ring->txcd[comp_ring->next];
+
+		if (le32toh((txcd->txc_word3 >> VMXNET3_TXC_GEN_S) &
+		    VMXNET3_TXC_GEN_M) != comp_ring->gen)
+			break;
+
+		comp_ring->next++;
+		if (comp_ring->next == NTXCOMPDESC) {
+			comp_ring->next = 0;
+			comp_ring->gen ^= 1;
+		}
+
+		sop = ring->next;
+		if (ring->m[sop] == NULL)
+			panic("vmxnet3_txintr");
+		m_freem(ring->m[sop]);
+		ring->m[sop] = NULL;
+		bus_dmamap_unload(sc->sc_dmat, ring->dmap[sop]);
+		ring->next = (le32toh((txcd->txc_word0 >>
+		    VMXNET3_TXC_EOPIDX_S) & VMXNET3_TXC_EOPIDX_M) + 1)
+		    % NTXDESC;
+
+		ifp->if_flags &= ~IFF_OACTIVE;
+	}
+	if (ring->head == ring->next)
+		ifp->if_timer = 0;
+	vmxnet3_start(ifp);
+}
+
+void
+vmxnet3_rxintr(struct vmxnet3_softc *sc, struct vmxnet3_rxqueue *rq)
+{
+	struct vmxnet3_comp_ring *comp_ring = &rq->comp_ring;
+	struct vmxnet3_rxring *ring;
+	struct vmxnet3_rxdesc *rxd;
+	struct vmxnet3_rxcompdesc *rxcd;
+	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+	struct mbuf *m;
+	int idx, len;
+
+	for (;;) {
+		rxcd = &comp_ring->rxcd[comp_ring->next];
+		if (le32toh((rxcd->rxc_word3 >> VMXNET3_RXC_GEN_S) &
+		    VMXNET3_RXC_GEN_M) != comp_ring->gen)
+			break;
+
+		comp_ring->next++;
+		if (comp_ring->next == NRXCOMPDESC) {
+			comp_ring->next = 0;
+			comp_ring->gen ^= 1;
+		}
+
+		idx = le32toh((rxcd->rxc_word0 >> VMXNET3_RXC_IDX_S) &
+		    VMXNET3_RXC_IDX_M);
+		if (le32toh((rxcd->rxc_word0 >> VMXNET3_RXC_QID_S) &
+		    VMXNET3_RXC_QID_M) < NRXQUEUE)
+			ring = &rq->cmd_ring[0];
+		else
+			ring = &rq->cmd_ring[1];
+		rxd = &ring->rxd[idx];
+		len = le32toh((rxcd->rxc_word2 >> VMXNET3_RXC_LEN_S) &
+		    VMXNET3_RXC_LEN_M);
+		m = ring->m[idx];
+		ring->m[idx] = NULL;
+		bus_dmamap_unload(sc->sc_dmat, ring->dmap[idx]);
+
+		if (m == NULL)
+			panic("NULL mbuf");
+
+		if (le32toh((rxd->rx_word2 >> VMXNET3_RX_BTYPE_S) &
+		    VMXNET3_RX_BTYPE_M) != VMXNET3_BTYPE_HEAD) {
+			m_freem(m);
+			goto skip_buffer;
+		}
+		if (le32toh(rxcd->rxc_word2 & VMXNET3_RXC_ERROR)) {
+			ifp->if_ierrors++;
+			m_freem(m);
+			goto skip_buffer;
+		}
+		if (len < VMXNET3_MIN_MTU) {
+			printf("%s: short packet (%d)\n", ifp->if_xname, len);
+			m_freem(m);
+			goto skip_buffer;
+		}
+
+		ifp->if_ipackets++;
+		ifp->if_ibytes += len;
+
+		vmxnet3_rx_csum(rxcd, m);
+		m->m_pkthdr.rcvif = ifp;
+		m->m_pkthdr.len = m->m_len = len;
+		if (le32toh(rxcd->rxc_word2 & VMXNET3_RXC_VLAN)) {
+			VLAN_INPUT_TAG(ifp, m,
+			    le32toh((rxcd->rxc_word2 >>
+			    VMXNET3_RXC_VLANTAG_S) & VMXNET3_RXC_VLANTAG_M),
+			    m_freem(m); goto skip_buffer);
+		}
+
+		bpf_mtap(ifp, m);
+
+		(*ifp->if_input)(ifp, m);
+
+skip_buffer:
+#ifdef VMXNET3_STAT
+		vmxstat.rxdone = idx;
+#endif
+		if (rq->rs->update_rxhead) {
+			u_int qid = le32toh((rxcd->rxc_word0 >>
+			    VMXNET3_RXC_QID_S) & VMXNET3_RXC_QID_M);
+
+			idx = (idx + 1) % NRXDESC;
+			if (qid < NRXQUEUE) {
+				WRITE_BAR0(sc, VMXNET3_BAR0_RXH1(qid), idx);
+			} else {
+				qid -= NRXQUEUE;
+				WRITE_BAR0(sc, VMXNET3_BAR0_RXH2(qid), idx);
+			}
+		}
+	}
+
+	/* XXX Should we (try to) allocate buffers for ring 2 too? */
+	ring = &rq->cmd_ring[0];
+	for (;;) {
+		idx = ring->fill;
+		if (ring->m[idx])
+			return;
+		if (vmxnet3_getbuf(sc, ring))
+			return;
+	}
+}
+
+void
+vmxnet3_iff(struct vmxnet3_softc *sc)
+{
+	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+	struct ethercom *ec = &sc->sc_ethercom;
+	struct vmxnet3_driver_shared *ds = sc->sc_ds;
+	struct ether_multi *enm;
+	struct ether_multistep step;
+	u_int mode;
+	uint8_t *p;
+
+	ds->mcast_tablelen = 0;
+	CLR(ifp->if_flags, IFF_ALLMULTI);
+
+	/*
+	 * Always accept broadcast frames.
+	 * Always accept frames destined to our station address.
+	 */
+	mode = VMXNET3_RXMODE_BCAST | VMXNET3_RXMODE_UCAST;
+
+	if (ISSET(ifp->if_flags, IFF_PROMISC) || ec->ec_multicnt > 682)
+		goto allmulti;
+
+	p = sc->sc_mcast;
+	ETHER_FIRST_MULTI(step, ec, enm);
+	while (enm != NULL) {
+		if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
+			/*
+			 * We must listen to a range of multicast addresses.
+			 * For now, just accept all multicasts, rather than
+			 * trying to set only those filter bits needed to match
+			 * the range.  (At this time, the only use of address
+			 * ranges is for IP multicast routing, for which the
+			 * range is big enough to require all bits set.)
+			 */
+			goto allmulti;
+		}
+		memcpy(p, enm->enm_addrlo, ETHER_ADDR_LEN);
+
+		p += ETHER_ADDR_LEN;
+
+		ETHER_NEXT_MULTI(step, enm);
+	}
+
+	if (ec->ec_multicnt > 0) {
+		SET(mode, VMXNET3_RXMODE_MCAST);
+		ds->mcast_tablelen = p - sc->sc_mcast;
+	}
+
+	goto setit;
+
+allmulti:
+	SET(ifp->if_flags, IFF_ALLMULTI);
+	SET(mode, (VMXNET3_RXMODE_ALLMULTI | VMXNET3_RXMODE_MCAST));
+	if (ifp->if_flags & IFF_PROMISC)
+		SET(mode, VMXNET3_RXMODE_PROMISC);
+
+setit:
+	WRITE_CMD(sc, VMXNET3_CMD_SET_FILTER);
+	ds->rxmode = mode;
+	WRITE_CMD(sc, VMXNET3_CMD_SET_RXMODE);
+}
+
+
+void
+vmxnet3_rx_csum(struct vmxnet3_rxcompdesc *rxcd, struct mbuf *m)
+{
+	if (le32toh(rxcd->rxc_word0 & VMXNET3_RXC_NOCSUM))
+		return;
+
+	if (rxcd->rxc_word3 & VMXNET3_RXC_IPV4) {
+		m->m_pkthdr.csum_flags |= M_CSUM_IPv4;
+		if ((rxcd->rxc_word3 & VMXNET3_RXC_IPSUM_OK) == 0)
+			m->m_pkthdr.csum_flags |= M_CSUM_IPv4_BAD;
+	}
+
+	if (rxcd->rxc_word3 & VMXNET3_RXC_FRAGMENT)
+		return;
+
+	if (rxcd->rxc_word3 & VMXNET3_RXC_TCP) {
+		m->m_pkthdr.csum_flags |= M_CSUM_TCPv4;
+		if ((rxcd->rxc_word3 & VMXNET3_RXC_CSUM_OK) == 0)
+			m->m_pkthdr.csum_flags |= M_CSUM_TCP_UDP_BAD;
+	}
+
+	if (rxcd->rxc_word3 & VMXNET3_RXC_UDP) {
+		m->m_pkthdr.csum_flags |= M_CSUM_UDPv4;
+		if ((rxcd->rxc_word3 & VMXNET3_RXC_CSUM_OK) == 0)
+			m->m_pkthdr.csum_flags |= M_CSUM_TCP_UDP_BAD;
+	}
+}
+
+int
+vmxnet3_getbuf(struct vmxnet3_softc *sc, struct vmxnet3_rxring *ring)
+{
+	int idx = ring->fill;
+	struct vmxnet3_rxdesc *rxd = &ring->rxd[idx];
+	struct mbuf *m;
+	int btype;
+
+	if (ring->m[idx])
+		panic("vmxnet3_getbuf: buffer has mbuf");
+
+#if 1
+	/* XXX Don't allocate buffers for ring 2 for now. */
+	if (ring->rid != 0)
+		return -1;
+	btype = VMXNET3_BTYPE_HEAD;
+#else
+	if (ring->rid == 0)
+		btype = VMXNET3_BTYPE_HEAD;
+	else
+		btype = VMXNET3_BTYPE_BODY;
+#endif
+
+	MGETHDR(m, M_DONTWAIT, MT_DATA);
+	if (m == NULL)
+		return -1;
+
+	MCLGET(m, M_DONTWAIT);
+	if ((m->m_flags & M_EXT) == 0) {
+		m_freem(m);
+		return -1;
+	}
+
+	m->m_pkthdr.len = m->m_len = JUMBO_LEN;
+	m_adj(m, ETHER_ALIGN);
+	ring->m[idx] = m;
+
+	if (bus_dmamap_load_mbuf(sc->sc_dmat, ring->dmap[idx], m,
+	    BUS_DMA_NOWAIT))
+		panic("load mbuf");
+	rxd->rx_addr = htole64(DMAADDR(ring->dmap[idx]));
+	rxd->rx_word2 = htole32(((m->m_pkthdr.len & VMXNET3_RX_LEN_M) <<
+	    VMXNET3_RX_LEN_S) | ((btype & VMXNET3_RX_BTYPE_M) <<
+	    VMXNET3_RX_BTYPE_S) | ((ring->gen & VMXNET3_RX_GEN_M) <<
+	    VMXNET3_RX_GEN_S));
+	idx++;
+	if (idx == NRXDESC) {
+		idx = 0;
+		ring->gen ^= 1;
+	}
+	ring->fill = idx;
+#ifdef VMXNET3_STAT
+	vmxstat.rxfill = ring->fill;
+#endif
+	return 0;
+}
+
+void
+vmxnet3_stop(struct ifnet *ifp)
+{
+	struct vmxnet3_softc *sc = ifp->if_softc;
+	int queue;
+
+	if ((ifp->if_flags & IFF_RUNNING) == 0)
+		return;
+
+	vmxnet3_disable_all_intrs(sc);
+	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+	ifp->if_timer = 0;
+
+	WRITE_CMD(sc, VMXNET3_CMD_DISABLE);
+
+	for (queue = 0; queue < NTXQUEUE; queue++)
+		vmxnet3_txstop(sc, &sc->sc_txq[queue]);
+	for (queue = 0; queue < NRXQUEUE; queue++)
+		vmxnet3_rxstop(sc, &sc->sc_rxq[queue]);
+}
+
+void
+vmxnet3_reset(struct ifnet *ifp)
+{
+	struct vmxnet3_softc *sc = ifp->if_softc;
+
+	vmxnet3_stop(ifp);
+	WRITE_CMD(sc, VMXNET3_CMD_RESET);
+	vmxnet3_init(ifp);
+}
+
+int
+vmxnet3_init(struct ifnet *ifp)
+{
+	struct vmxnet3_softc *sc = ifp->if_softc;
+	int queue;
+
+	if (ifp->if_flags & IFF_RUNNING)
+		return 0;
+
+	ifp->if_flags |= IFF_RUNNING;
+	ifp->if_flags &= ~IFF_OACTIVE;
+
+	for (queue = 0; queue < NTXQUEUE; queue++)
+		vmxnet3_txinit(sc, &sc->sc_txq[queue]);
+	for (queue = 0; queue < NRXQUEUE; queue++)
+		vmxnet3_rxinit(sc, &sc->sc_rxq[queue]);
+
+	WRITE_CMD(sc, VMXNET3_CMD_ENABLE);
+	if (READ_BAR1(sc, VMXNET3_BAR1_CMD)) {
+		printf("%s: failed to initialize\n", ifp->if_xname);
+		vmxnet3_stop(ifp);
+		return EIO;
+	}
+
+	for (queue = 0; queue < NRXQUEUE; queue++) {
+		WRITE_BAR0(sc, VMXNET3_BAR0_RXH1(queue), 0);
+		WRITE_BAR0(sc, VMXNET3_BAR0_RXH2(queue), 0);
+	}
+
+	vmxnet3_iff(sc);
+	vmxnet3_enable_all_intrs(sc);
+	vmxnet3_link_state(sc);
+	return 0;
+}
+
+int
+vmxnet3_change_mtu(struct vmxnet3_softc *sc, int mtu)
+{
+	struct vmxnet3_driver_shared *ds = sc->sc_ds;
+	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+	int error;
+
+	if (mtu < VMXNET3_MIN_MTU || mtu > VMXNET3_MAX_MTU)
+		return EINVAL;
+	vmxnet3_stop(ifp);
+	ifp->if_mtu = ds->mtu = mtu;
+	error = vmxnet3_init(ifp);
+	return error;
+}
+
+int
+vmxnet3_ioctl(struct ifnet *ifp, u_long cmd, void *data)
+{
+	struct vmxnet3_softc *sc = ifp->if_softc;
+	struct ifreq *ifr = (struct ifreq *)data;
+	int error = 0, s;
+
+	s = splnet();
+
+	switch (cmd) {
+	case SIOCSIFMTU:
+		error = vmxnet3_change_mtu(sc, ifr->ifr_mtu);
+		break;
+	case SIOCSIFMEDIA:
+	case SIOCGIFMEDIA:
+		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
+		break;
+	default:
+		error = ether_ioctl(ifp, cmd, data);
+	}
+
+	if (error == ENETRESET) {
+		if (ifp->if_flags & IFF_RUNNING)
+			vmxnet3_iff(sc);
+		error = 0;
+	}
+
+	splx(s);
+	return error;
+}
+
+void
+vmxnet3_start(struct ifnet *ifp)
+{
+	struct vmxnet3_softc *sc = ifp->if_softc;
+	struct vmxnet3_txqueue *tq = &sc->sc_txq[0];
+	struct vmxnet3_txring *ring = &tq->cmd_ring;
+	struct mbuf *m;
+	int n = 0;
+
+	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
+		return;
+
+	for (;;) {
+		IFQ_POLL(&ifp->if_snd, m);
+		if (m == NULL)
+			break;
+		if ((ring->next - ring->head - 1) % NTXDESC < NTXSEGS) {
+			ifp->if_flags |= IFF_OACTIVE;
+			break;
+		}
+
+		IFQ_DEQUEUE(&ifp->if_snd, m);
+		if (vmxnet3_load_mbuf(sc, m) != 0) {
+			ifp->if_oerrors++;
+			continue;
+		}
+		bpf_mtap(ifp, m);
+
+		ifp->if_timer = 5;
+		ifp->if_opackets++;
+		n++;
+	}
+
+	if (n > 0)
+		WRITE_BAR0(sc, VMXNET3_BAR0_TXH(0), ring->head);
+#ifdef VMXNET3_STAT
+	vmxstat.txhead = ring->head;
+	vmxstat.txdone = ring->next;
+	vmxstat.maxtxlen =
+	    max(vmxstat.maxtxlen, (ring->head - ring->next) % NTXDESC);
+#endif
+}
+
+int
+vmxnet3_load_mbuf(struct vmxnet3_softc *sc, struct mbuf *m)
+{
+	struct vmxnet3_txqueue *tq = &sc->sc_txq[0];
+	struct vmxnet3_txring *ring = &tq->cmd_ring;
+	struct vmxnet3_txdesc *txd = NULL, *sop;
+	struct mbuf *mp;
+	struct m_tag *mtag;
+	struct ip *ip;
+	bus_dmamap_t map = ring->dmap[ring->head];
+	u_int hlen = ETHER_HDR_LEN, csum_off = 0;
+	int offp, gen, i;
+
+#if 0
+	if (m->m_pkthdr.csum_flags & M_CSUM_IPv4) {
+		printf("%s: IP checksum offloading is not supported\n",
+		    sc->sc_dev.dv_xname);
+		return -1;
+	}
+#endif
+	if (m->m_pkthdr.csum_flags & (M_CSUM_UDPv4|M_CSUM_TCPv4)) {
+		if (m->m_pkthdr.csum_flags & M_CSUM_TCPv4)
+			csum_off = offsetof(struct tcphdr, th_sum);
+		else
+			csum_off = offsetof(struct udphdr, uh_sum);
+
+		mp = m_pulldown(m, hlen, sizeof(*ip), &offp);
+		if (mp == NULL)
+			return (-1);
+
+		ip = (struct ip *)(mp->m_data + offp);
+		hlen += ip->ip_hl << 2;
+
+		mp = m_pulldown(m, 0, hlen + csum_off + 2, &offp);
+		if (mp == NULL)
+			return (-1);
+	}
+
+	switch (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT)) {
+	case 0:
+		break;
+	case EFBIG:
+		if (m_defrag(m, M_DONTWAIT) == 0 &&
+		    bus_dmamap_load_mbuf(sc->sc_dmat, map, m,
+		     BUS_DMA_NOWAIT) == 0)
+			break;
+
+		/* FALLTHROUGH */
+	default:
+		m_freem(m);
+		return -1;
+	}
+
+	ring->m[ring->head] = m;
+	sop = &ring->txd[ring->head];
+	gen = ring->gen ^ 1;		/* owned by cpu (yet) */
+	for (i = 0; i < map->dm_nsegs; i++) {
+		txd = &ring->txd[ring->head];
+		txd->tx_addr = htole64(map->dm_segs[i].ds_addr);
+		txd->tx_word2 = htole32(((map->dm_segs[i].ds_len &
+		    VMXNET3_TX_LEN_M) << VMXNET3_TX_LEN_S) |
+		    ((gen & VMXNET3_TX_GEN_M) << VMXNET3_TX_GEN_S));
+		txd->tx_word3 = 0;
+		ring->head++;
+		if (ring->head == NTXDESC) {
+			ring->head = 0;
+			ring->gen ^= 1;
+		}
+		gen = ring->gen;
+	}
+	if (txd != NULL)
+		txd->tx_word3 |= htole32(VMXNET3_TX_EOP | VMXNET3_TX_COMPREQ);
+
+	if ((mtag = VLAN_OUTPUT_TAG(&sc->sc_ethercom, m)) != NULL) {
+		sop->tx_word3 |= htole32(VMXNET3_TX_VTAG_MODE);
+		sop->tx_word3 |= htole32((VLAN_TAG_VALUE(mtag) &
+		    VMXNET3_TX_VLANTAG_M) << VMXNET3_TX_VLANTAG_S);
+	}
+	if (m->m_pkthdr.csum_flags & (M_CSUM_UDPv4|M_CSUM_TCPv4)) {
+		sop->tx_word2 |= htole32(((hlen + csum_off) &
+		    VMXNET3_TX_OP_M) << VMXNET3_TX_OP_S);
+		sop->tx_word3 |= htole32(((hlen & VMXNET3_TX_HLEN_M) <<
+		    VMXNET3_TX_HLEN_S) | (VMXNET3_OM_CSUM << VMXNET3_TX_OM_S));
+	}
+
+	/* Change the ownership by flipping the "generation" bit */
+	sop->tx_word2 ^= htole32(VMXNET3_TX_GEN_M << VMXNET3_TX_GEN_S);
+
+	return (0);
+}
+
+void
+vmxnet3_watchdog(struct ifnet *ifp)
+{
+	int s;
+
+	printf("%s: device timeout\n", ifp->if_xname);
+	s = splnet();
+	vmxnet3_stop(ifp);
+	vmxnet3_init(ifp);
+	splx(s);
+}
+
+void
+vmxnet3_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+	struct vmxnet3_softc *sc = ifp->if_softc;
+
+	vmxnet3_link_state(sc);
+
+	ifmr->ifm_status = IFM_AVALID;
+	ifmr->ifm_active = IFM_ETHER;
+
+	if (ifp->if_link_state != LINK_STATE_UP)
+		return;
+
+	ifmr->ifm_status |= IFM_ACTIVE;
+
+	if (ifp->if_baudrate >= IF_Gbps(10ULL))
+		ifmr->ifm_active |= IFM_10G_T;
+}
+
+int
+vmxnet3_media_change(struct ifnet *ifp)
+{
+	return 0;
+}
+
+void *
+vmxnet3_dma_allocmem(struct vmxnet3_softc *sc, u_int size, u_int align, bus_addr_t *pa)
+{
+	bus_dma_tag_t t = sc->sc_dmat;
+	bus_dma_segment_t segs[1];
+	bus_dmamap_t map;
+	void *va;
+	int n;
+
+	if (bus_dmamem_alloc(t, size, align, 0, segs, 1, &n, BUS_DMA_NOWAIT))
+		return NULL;
+	if (bus_dmamem_map(t, segs, 1, size, &va, BUS_DMA_NOWAIT))
+		return NULL;
+	if (bus_dmamap_create(t, size, 1, size, 0, BUS_DMA_NOWAIT, &map))
+		return NULL;
+	if (bus_dmamap_load(t, map, va, size, NULL, BUS_DMA_NOWAIT))
+		return NULL;
+	memset(va, 0, size);
+	*pa = DMAADDR(map);
+	bus_dmamap_unload(t, map);
+	bus_dmamap_destroy(t, map);
+	return va;
+}
Index: src/sys/arch/x86/pci/if_vmxreg.h
diff -u /dev/null src/sys/arch/x86/pci/if_vmxreg.h:1.1
--- /dev/null	Tue Jun 10 01:42:39 2014
+++ src/sys/arch/x86/pci/if_vmxreg.h	Tue Jun 10 01:42:39 2014
@@ -0,0 +1,328 @@
+/*	$NetBSD: if_vmxreg.h,v 1.1 2014/06/10 01:42:39 hikaru Exp $	*/
+/*	$OpenBSD: if_vmxreg.h,v 1.3 2013/08/28 10:19:19 reyk Exp $	*/
+
+/*
+ * Copyright (c) 2013 Tsubai Masanari
+ *
+ * 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.
+ */
+
+struct UPT1_TxStats {
+	uint64_t TSO_packets;
+	uint64_t TSO_bytes;
+	uint64_t ucast_packets;
+	uint64_t ucast_bytes;
+	uint64_t mcast_packets;
+	uint64_t mcast_bytes;
+	uint64_t bcast_packets;
+	uint64_t bcast_bytes;
+	uint64_t error;
+	uint64_t discard;
+} __packed;
+
+struct UPT1_RxStats {
+	uint64_t LRO_packets;
+	uint64_t LRO_bytes;
+	uint64_t ucast_packets;
+	uint64_t ucast_bytes;
+	uint64_t mcast_packets;
+	uint64_t mcast_bytes;
+	uint64_t bcast_packets;
+	uint64_t bcast_bytes;
+	uint64_t nobuffer;
+	uint64_t error;
+} __packed;
+
+#define ETHER_ALIGN 2
+
+/* interrupt moderation levels */
+#define UPT1_IMOD_NONE     0		/* no moderation */
+#define UPT1_IMOD_HIGHEST  7		/* least interrupts */
+#define UPT1_IMOD_ADAPTIVE 8		/* adaptive interrupt moderation */
+
+/* hardware features */
+#define UPT1_F_CSUM 0x0001		/* Rx checksum verification */
+#define UPT1_F_RSS  0x0002		/* receive side scaling */
+#define UPT1_F_VLAN 0x0004		/* VLAN tag stripping */
+#define UPT1_F_LRO  0x0008		/* large receive offloading */
+
+#define VMXNET3_BAR0_IMASK(irq)	(0x000 + (irq) * 8)	/* interrupt mask */
+#define VMXNET3_BAR0_TXH(q)	(0x600 + (q) * 8)	/* Tx head */
+#define VMXNET3_BAR0_RXH1(q)	(0x800 + (q) * 8)	/* ring1 Rx head */
+#define VMXNET3_BAR0_RXH2(q)	(0xa00 + (q) * 8)	/* ring2 Rx head */
+#define VMXNET3_BAR1_VRRS	0x000	/* VMXNET3 revision report selection */
+#define VMXNET3_BAR1_UVRS	0x008	/* UPT version report selection */
+#define VMXNET3_BAR1_DSL	0x010	/* driver shared address low */
+#define VMXNET3_BAR1_DSH	0x018	/* driver shared address high */
+#define VMXNET3_BAR1_CMD	0x020	/* command */
+#define VMXNET3_BAR1_MACL	0x028	/* MAC address low */
+#define VMXNET3_BAR1_MACH	0x030	/* MAC address high */
+#define VMXNET3_BAR1_INTR	0x038	/* interrupt status */
+#define VMXNET3_BAR1_EVENT	0x040	/* event status */
+
+#define VMXNET3_CMD_ENABLE	0xcafe0000	/* enable VMXNET3 */
+#define VMXNET3_CMD_DISABLE	0xcafe0001	/* disable VMXNET3 */
+#define VMXNET3_CMD_RESET	0xcafe0002	/* reset device */
+#define VMXNET3_CMD_SET_RXMODE	0xcafe0003	/* set interface flags */
+#define VMXNET3_CMD_SET_FILTER	0xcafe0004	/* set address filter */
+#define VMXNET3_CMD_GET_STATUS	0xf00d0000	/* get queue errors */
+#define VMXNET3_CMD_GET_LINK	0xf00d0002	/* get link status */
+#define VMXNET3_CMD_GET_MACL	0xf00d0003
+#define VMXNET3_CMD_GET_MACH	0xf00d0004
+
+#define VMXNET3_DMADESC_ALIGN	128
+
+/* All descriptors are in little-endian format. */
+struct vmxnet3_txdesc {
+	uint64_t		tx_addr;
+
+	uint32_t		tx_word2;
+#define	VMXNET3_TX_LEN_M	0x00003fff
+#define	VMXNET3_TX_LEN_S	0
+#define VMXNET3_TX_GEN_M	0x00000001	/* generation */
+#define VMXNET3_TX_GEN_S	14
+#define VMXNET3_TX_RES0		0x00008000
+#define	VMXNET3_TX_DTYPE_M	0x00000001	/* descriptor type */
+#define	VMXNET3_TX_DTYPE_S	16		/* descriptor type */
+#define	VMXNET3_TX_RES1		0x00000002
+#define VMXNET3_TX_OP_M		0x00003fff	/* offloading position */
+#define	VMXNET3_TX_OP_S		18
+
+	uint32_t		tx_word3;
+#define VMXNET3_TX_HLEN_M	0x000003ff	/* header len */
+#define VMXNET3_TX_HLEN_S	0
+#define VMXNET3_TX_OM_M		0x00000003	/* offloading mode */
+#define VMXNET3_TX_OM_S		10
+#define VMXNET3_TX_EOP		0x00001000	/* end of packet */
+#define VMXNET3_TX_COMPREQ	0x00002000	/* completion request */
+#define VMXNET3_TX_RES2		0x00004000
+#define VMXNET3_TX_VTAG_MODE	0x00008000	/* VLAN tag insertion mode */
+#define VMXNET3_TX_VLANTAG_M	0x0000ffff
+#define VMXNET3_TX_VLANTAG_S	16
+} __packed;
+
+/* offloading modes */
+#define VMXNET3_OM_NONE 0
+#define VMXNET3_OM_CSUM 2
+#define VMXNET3_OM_TSO  3
+
+struct vmxnet3_txcompdesc {
+	uint32_t		txc_word0;	
+#define VMXNET3_TXC_EOPIDX_M	0x00000fff	/* eop index in Tx ring */
+#define VMXNET3_TXC_EOPIDX_S	0
+#define VMXNET3_TXC_RES0_M	0x000fffff
+#define VMXNET3_TXC_RES0_S	12
+
+	uint32_t		txc_word1;
+	uint32_t		txc_word2;
+
+	uint32_t		txc_word3;
+#define VMXNET3_TXC_RES2_M	0x00ffffff
+#define VMXNET3_TXC_TYPE_M	0x0000007f
+#define VMXNET3_TXC_TYPE_S	24
+#define VMXNET3_TXC_GEN_M	0x00000001
+#define VMXNET3_TXC_GEN_S	31
+} __packed;
+
+struct vmxnet3_rxdesc {
+	uint64_t		rx_addr;
+
+	uint32_t		rx_word2;
+#define VMXNET3_RX_LEN_M	0x00003fff
+#define VMXNET3_RX_LEN_S	0
+#define VMXNET3_RX_BTYPE_M	0x00000001	/* buffer type */
+#define VMXNET3_RX_BTYPE_S	14
+#define VMXNET3_RX_DTYPE_M	0x00000001	/* descriptor type */
+#define VMXNET3_RX_DTYPE_S	15
+#define VMXNET3_RX_RES0_M	0x00007fff
+#define VMXNET3_RX_RES0_S	16
+#define VMXNET3_RX_GEN_M	0x00000001
+#define VMXNET3_RX_GEN_S	31
+
+	uint32_t		rx_word3;
+} __packed;
+
+/* buffer types */
+#define VMXNET3_BTYPE_HEAD 0	/* head only */
+#define VMXNET3_BTYPE_BODY 1	/* body only */
+
+struct vmxnet3_rxcompdesc {
+	uint32_t		rxc_word0;
+#define VMXNET3_RXC_IDX_M	0x00000fff	/* Rx descriptor index */
+#define VMXNET3_RXC_IDX_S	0
+#define VMXNET3_RXC_RES0_M	0x00000003
+#define VMXNET3_RXC_RES0_S	12
+#define VMXNET3_RXC_EOP		0x00004000	/* end of packet */
+#define VMXNET3_RXC_SOP		0x00008000	/* start of packet */
+#define VMXNET3_RXC_QID_M	0x000003ff
+#define VMXNET3_RXC_QID_S	16
+#define VMXNET3_RXC_RSSTYPE_M	0x0000000f
+#define VMXNET3_RXC_RSSTYPE_S	26
+#define VMXNET3_RXC_NOCSUM	0x40000000	/* no checksum calculated */
+#define VMXNET3_RXC_RES1	0x80000000
+
+	uint32_t		rxc_word1;
+#define VMXNET3_RXC_RSSHASH_M	0xffffffff	/* RSS hash value */
+#define VMXNET3_RXC_RSSHASH_S	0
+
+	uint32_t		rxc_word2;
+#define VMXNET3_RXC_LEN_M	0x00003fff
+#define VMXNET3_RXC_LEN_S	0
+#define VMXNET3_RXC_ERROR	0x00004000
+#define VMXNET3_RXC_VLAN	0x00008000	/* 802.1Q VLAN frame */
+#define VMXNET3_RXC_VLANTAG_M	0x0000ffff	/* VLAN tag */
+#define VMXNET3_RXC_VLANTAG_S	16
+
+	uint32_t		rxc_word3;
+#define VMXNET3_RXC_CSUM_M	0x0000ffff	/* TCP/UDP checksum */
+#define VMXNET3_RXC_CSUM_S	16
+#define VMXNET3_RXC_CSUM_OK	0x00010000	/* TCP/UDP checksum ok */
+#define VMXNET3_RXC_UDP		0x00020000
+#define VMXNET3_RXC_TCP		0x00040000
+#define VMXNET3_RXC_IPSUM_OK	0x00080000	/* IP checksum ok */
+#define VMXNET3_RXC_IPV6	0x00100000
+#define VMXNET3_RXC_IPV4	0x00200000
+#define VMXNET3_RXC_FRAGMENT	0x00400000	/* IP fragment */
+#define VMXNET3_RXC_FCS		0x00800000	/* frame CRC correct */
+#define VMXNET3_RXC_TYPE_M	0x7f000000
+#define VMXNET3_RXC_GEN_M	0x00000001
+#define VMXNET3_RXC_GEN_S	31
+} __packed;
+
+#define VMXNET3_REV1_MAGIC 0xbabefee1
+
+#define VMXNET3_GOS_UNKNOWN 0x00
+#define VMXNET3_GOS_LINUX   0x04
+#define VMXNET3_GOS_WINDOWS 0x08
+#define VMXNET3_GOS_SOLARIS 0x0c
+#define VMXNET3_GOS_FREEBSD 0x10
+#define VMXNET3_GOS_PXE     0x14
+
+#define VMXNET3_GOS_32BIT   0x01
+#define VMXNET3_GOS_64BIT   0x02
+
+#define VMXNET3_MAX_TX_QUEUES 8
+#define VMXNET3_MAX_RX_QUEUES 16
+#define VMXNET3_MAX_INTRS (VMXNET3_MAX_TX_QUEUES + VMXNET3_MAX_RX_QUEUES + 1)
+#define VMXNET3_NINTR 1
+
+#define VMXNET3_ICTRL_DISABLE_ALL 0x01
+
+#define VMXNET3_RXMODE_UCAST    0x01
+#define VMXNET3_RXMODE_MCAST    0x02
+#define VMXNET3_RXMODE_BCAST    0x04
+#define VMXNET3_RXMODE_ALLMULTI 0x08
+#define VMXNET3_RXMODE_PROMISC  0x10
+
+#define VMXNET3_EVENT_RQERROR 0x01
+#define VMXNET3_EVENT_TQERROR 0x02
+#define VMXNET3_EVENT_LINK    0x04
+#define VMXNET3_EVENT_DIC     0x08
+#define VMXNET3_EVENT_DEBUG   0x10
+
+#define VMXNET3_MAX_MTU 9000
+#define VMXNET3_MIN_MTU 60
+
+struct vmxnet3_driver_shared {
+	uint32_t magic;
+	uint32_t pad1;
+
+	uint32_t version;		/* driver version */
+	uint32_t guest;		/* guest OS */
+	uint32_t vmxnet3_revision;	/* supported VMXNET3 revision */
+	uint32_t upt_version;		/* supported UPT version */
+	uint64_t upt_features;
+	uint64_t driver_data;
+	uint64_t queue_shared;
+	uint32_t driver_data_len;
+	uint32_t queue_shared_len;
+	uint32_t mtu;
+	uint16_t nrxsg_max;
+	uint8_t ntxqueue;
+	uint8_t nrxqueue;
+	uint32_t reserved1[4];
+
+	/* interrupt control */
+	uint8_t automask;
+	uint8_t nintr;
+	uint8_t evintr;
+	uint8_t modlevel[VMXNET3_MAX_INTRS];
+	uint32_t ictrl;
+	uint32_t reserved2[2];
+
+	/* receive filter parameters */
+	uint32_t rxmode;
+	uint16_t mcast_tablelen;
+	uint16_t pad2;
+	uint64_t mcast_table;
+	uint32_t vlan_filter[4096 / 32];
+
+	struct {
+		uint32_t version;
+		uint32_t len;
+		uint64_t paddr;
+	} rss, pm, plugin;
+
+	uint32_t event;
+	uint32_t reserved3[5];
+} __packed;
+
+struct vmxnet3_txq_shared {
+	uint32_t npending;
+	uint32_t intr_threshold;
+	uint64_t reserved1;
+
+	uint64_t cmd_ring;
+	uint64_t data_ring;
+	uint64_t comp_ring;
+	uint64_t driver_data;
+	uint64_t reserved2;
+	uint32_t cmd_ring_len;
+	uint32_t data_ring_len;
+	uint32_t comp_ring_len;
+	uint32_t driver_data_len;
+	uint8_t intr_idx;
+	uint8_t pad1[7];
+
+	uint8_t stopped;
+	uint8_t pad2[3];
+	uint32_t error;
+
+	struct UPT1_TxStats stats;
+
+	uint8_t pad3[88];
+} __packed;
+
+struct vmxnet3_rxq_shared {
+	uint8_t update_rxhead;
+	uint8_t pad1[7];
+	uint64_t reserved1;
+
+	uint64_t cmd_ring[2];
+	uint64_t comp_ring;
+	uint64_t driver_data;
+	uint64_t reserved2;
+	uint32_t cmd_ring_len[2];
+	uint32_t comp_ring_len;
+	uint32_t driver_data_len;
+	uint8_t intr_idx;
+	uint8_t pad2[7];
+
+	uint8_t stopped;
+	uint8_t pad3[3];
+	uint32_t error;
+
+	struct UPT1_RxStats stats;
+
+	uint8_t pad4[88];
+} __packed;

Reply via email to