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 <[email protected]>
+.\"
+.\" 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 [email protected] .
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;