Date: Fri, 23 Aug 2013 20:47:17 +0000 (UTC) From: Bryan Venteicher <bryanv@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r254738 - in head: share/man/man4 sys/conf sys/dev/vmware sys/dev/vmware/vmxnet3 sys/modules sys/modules/vmware sys/modules/vmware/vmxnet3 Message-ID: <201308232047.r7NKlHHD079485@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: bryanv Date: Fri Aug 23 20:47:16 2013 New Revision: 254738 URL: http://svnweb.freebsd.org/changeset/base/254738 Log: Add vmx(4), a VMware VMXNET3 ethernet driver ported from OpenBSD Added: head/share/man/man4/vmx.4 (contents, props changed) head/sys/dev/vmware/ head/sys/dev/vmware/vmxnet3/ head/sys/dev/vmware/vmxnet3/if_vmx.c (contents, props changed) head/sys/dev/vmware/vmxnet3/if_vmxreg.h (contents, props changed) head/sys/dev/vmware/vmxnet3/if_vmxvar.h (contents, props changed) head/sys/modules/vmware/ head/sys/modules/vmware/Makefile (contents, props changed) head/sys/modules/vmware/vmxnet3/ head/sys/modules/vmware/vmxnet3/Makefile (contents, props changed) Modified: head/share/man/man4/Makefile head/sys/conf/files.amd64 head/sys/conf/files.i386 head/sys/modules/Makefile Modified: head/share/man/man4/Makefile ============================================================================== --- head/share/man/man4/Makefile Fri Aug 23 20:39:41 2013 (r254737) +++ head/share/man/man4/Makefile Fri Aug 23 20:47:16 2013 (r254738) @@ -539,6 +539,7 @@ MAN= aac.4 \ ${_virtio_scsi.4} \ vkbd.4 \ vlan.4 \ + ${_vmx.4} \ vpo.4 \ vr.4 \ vte.4 \ @@ -706,6 +707,7 @@ MLINKS+=ural.4 if_ural.4 MLINKS+=${_urtw.4} ${_if_urtw.4} MLINKS+=vge.4 if_vge.4 MLINKS+=vlan.4 if_vlan.4 +MLINKS+=${_vmx.4} ${_if_vmx.4} MLINKS+=vpo.4 imm.4 MLINKS+=vr.4 if_vr.4 MLINKS+=vte.4 if_vte.4 @@ -758,6 +760,7 @@ _if_nfe.4= if_nfe.4 _if_nve.4= if_nve.4 _if_nxge.4= if_nxge.4 _if_urtw.4= if_urtw.4 +_if_vmx.4= if_vmx.4 _if_vtnet.4= if_vtnet.4 _if_vxge.4= if_vxge.4 _if_wpi.4= if_wpi.4 @@ -777,6 +780,7 @@ _virtio.4= virtio.4 _virtio_balloon.4=virtio_balloon.4 _virtio_blk.4= virtio_blk.4 _virtio_scsi.4= virtio_scsi.4 +_vmx.4= vmx.4 _vtnet.4= vtnet.4 _vxge.4= vxge.4 _padlock.4= padlock.4 Added: head/share/man/man4/vmx.4 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/share/man/man4/vmx.4 Fri Aug 23 20:47:16 2013 (r254738) @@ -0,0 +1,224 @@ +.\" +.\" Copyright (c) 2006,2013 Reyk Floeter <reyk@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.\" $OpenBSD: src/share/man/man4/vmx.4,v 1.1 2013/05/31 20:18:44 reyk Exp $ +.\" +.\" $FreeBSD$ +.\" +.Dd August 4, 2013 +.Dt VMX 4 +.Os +.Sh NAME +.Nm vmx +.Nd VMware VMXNET3 Virtual Interface Controller device +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following line in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device vmx" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +if_vmx_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides support for the VMXNET3 virtual NIC available in virtual +machines by VMware. +It appears as a simple Ethernet device but is actually a virtual network +interface to the underlying host operating system. +.Pp +This driver supports the +.Ic VMXNET3 +driver protocol, as an alternative to the emulated +.Xr pcn 4 , +.Xr em 4 +interfaces also available in the VMware environment. +The +.Nm +driver is optimized for the virtual machine, it can provide advanced +capabilities depending on the underlying host operating system and +the physical network interface controller of the host. +The +.Nm +driver supports features like multiqueue support, IPv6 +checksum offloading, MSI/MSI-X support and hardware VLAN tagging in +VMware's VLAN Guest Tagging (VGT) mode. +.Pp +The +.Nm +driver supports VMXNET3 VMware virtual NICs provided by the virtual +machine hardware version 7 or newer, as provided by the following +products: +.Pp +.Bl -bullet -compact -offset indent +.It +VMware ESX/ESXi 4.0 and newer +.It +VMware Server 2.0 and newer +.It +VMware Workstation 6.5 and newer +.It +VMware Fusion 2.0 and newer +.El +.Pp +For more information on configuring this device, see +.Xr ifconfig 8 . +.Sh EXAMPLES +The following entry must be added to the VMware configuration file +to provide the +.Nm +device: +.Bd -literal -offset indent +ethernet0.virtualDev = "vmxnet3" +.Ed +.Sh SEE ALSO +.Xr altq 4 , +.Xr arp 4 , +.Xr em 4 , +.Xr netintro 4 , +.Xr ng_ether 4 , +.Xr pcn 4 , +.Xr vlan 4 , +.Xr ifconfig 8 +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was ported from +.Ox +by +.An Bryan Venteicher Aq bryanv@freebsd.org . +The +.Ox +driver was written by +.An Tsubai Masanari . +.\" +.\" Copyright (c) 2006,2013 Reyk Floeter <reyk@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.\" $OpenBSD: src/share/man/man4/vmx.4,v 1.1 2013/05/31 20:18:44 reyk Exp $ +.\" +.\" $FreeBSD$ +.\" +.Dd August 4, 2013 +.Dt VMX 4 +.Os +.Sh NAME +.Nm vmx +.Nd VMware VMXNET3 Virtual Interface Controller device +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following line in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device vmx" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +if_vmx_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides support for the VMXNET3 virtual NIC available in virtual +machines by VMware. +It appears as a simple Ethernet device but is actually a virtual network +interface to the underlying host operating system. +.Pp +This driver supports the +.Ic VMXNET3 +driver protocol, as an alternative to the emulated +.Xr pcn 4 , +.Xr em 4 +interfaces also available in the VMware environment. +The +.Nm +driver is optimized for the virtual machine, it can provide advanced +capabilities depending on the underlying host operating system and +the physical network interface controller of the host. +The +.Nm +driver supports features like multiqueue support, IPv6 +checksum offloading, MSI/MSI-X support and hardware VLAN tagging in +VMware's VLAN Guest Tagging (VGT) mode. +.Pp +The +.Nm +driver supports VMXNET3 VMware virtual NICs provided by the virtual +machine hardware version 7 or newer, as provided by the following +products: +.Pp +.Bl -bullet -compact -offset indent +.It +VMware ESX/ESXi 4.0 and newer +.It +VMware Server 2.0 and newer +.It +VMware Workstation 6.5 and newer +.It +VMware Fusion 2.0 and newer +.El +.Pp +For more information on configuring this device, see +.Xr ifconfig 8 . +.Sh EXAMPLES +The following entry must be added to the VMware configuration file +to provide the +.Nm +device: +.Bd -literal -offset indent +ethernet0.virtualDev = "vmxnet3" +.Ed +.Sh SEE ALSO +.Xr altq 4 , +.Xr arp 4 , +.Xr em 4 , +.Xr netintro 4 , +.Xr ng_ether 4 , +.Xr pcn 4 , +.Xr vlan 4 , +.Xr ifconfig 8 +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was ported from +.Ox +by +.An Bryan Venteicher Aq bryanv@freebsd.org . +The +.Ox +driver was written by +.An Tsubai Masanari . Modified: head/sys/conf/files.amd64 ============================================================================== --- head/sys/conf/files.amd64 Fri Aug 23 20:39:41 2013 (r254737) +++ head/sys/conf/files.amd64 Fri Aug 23 20:47:16 2013 (r254738) @@ -304,6 +304,7 @@ dev/tpm/tpm_acpi.c optional tpm acpi dev/tpm/tpm_isa.c optional tpm isa dev/uart/uart_cpu_x86.c optional uart dev/viawd/viawd.c optional viawd +dev/vmware/vmxnet3/if_vmx.c optional vmx dev/wbwd/wbwd.c optional wbwd dev/wpi/if_wpi.c optional wpi dev/isci/isci.c optional isci Modified: head/sys/conf/files.i386 ============================================================================== --- head/sys/conf/files.i386 Fri Aug 23 20:39:41 2013 (r254737) +++ head/sys/conf/files.i386 Fri Aug 23 20:47:16 2013 (r254738) @@ -267,6 +267,7 @@ dev/tpm/tpm_acpi.c optional tpm acpi dev/tpm/tpm_isa.c optional tpm isa dev/uart/uart_cpu_x86.c optional uart dev/viawd/viawd.c optional viawd +dev/vmware/vmxnet3/if_vmx.c optional vmx dev/acpica/acpi_if.m standard dev/acpi_support/acpi_wmi_if.m standard dev/wbwd/wbwd.c optional wbwd Added: head/sys/dev/vmware/vmxnet3/if_vmx.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/vmware/vmxnet3/if_vmx.c Fri Aug 23 20:47:16 2013 (r254738) @@ -0,0 +1,3305 @@ +/*- + * Copyright (c) 2013 Tsubai Masanari + * Copyright (c) 2013 Bryan Venteicher <bryanv@FreeBSD.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: src/sys/dev/pci/if_vmx.c,v 1.11 2013/06/22 00:28:10 uebayasi Exp $ + */ + +/* Driver for VMware vmxnet3 virtual ethernet devices. */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/endian.h> +#include <sys/sockio.h> +#include <sys/mbuf.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <vm/vm.h> +#include <vm/pmap.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_dl.h> +#include <net/if_types.h> +#include <net/if_media.h> +#include <net/if_vlan_var.h> + +#include <net/bpf.h> + +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip6.h> +#include <netinet6/ip6_var.h> +#include <netinet/udp.h> +#include <netinet/tcp.h> + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/bus.h> +#include <sys/rman.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> + +#include "if_vmxreg.h" +#include "if_vmxvar.h" + +#include "opt_inet.h" +#include "opt_inet6.h" + +/* Always enable for now - useful for queue hangs. */ +#define VMXNET3_DEBUG_SYSCTL + +#ifdef VMXNET3_FAILPOINTS +#include <sys/fail.h> +static SYSCTL_NODE(DEBUG_FP, OID_AUTO, vmxnet3, CTLFLAG_RW, 0, + "vmxnet3 fail points"); +#define VMXNET3_FP _debug_fail_point_vmxnet3 +#endif + +static int vmxnet3_probe(device_t); +static int vmxnet3_attach(device_t); +static int vmxnet3_detach(device_t); +static int vmxnet3_shutdown(device_t); + +static int vmxnet3_alloc_resources(struct vmxnet3_softc *); +static void vmxnet3_free_resources(struct vmxnet3_softc *); +static int vmxnet3_check_version(struct vmxnet3_softc *); +static void vmxnet3_initial_config(struct vmxnet3_softc *); + +static int vmxnet3_alloc_msix_interrupts(struct vmxnet3_softc *); +static int vmxnet3_alloc_msi_interrupts(struct vmxnet3_softc *); +static int vmxnet3_alloc_legacy_interrupts(struct vmxnet3_softc *); +static int vmxnet3_alloc_interrupt(struct vmxnet3_softc *, int, int, + struct vmxnet3_interrupt *); +static int vmxnet3_alloc_intr_resources(struct vmxnet3_softc *); +static int vmxnet3_setup_msix_interrupts(struct vmxnet3_softc *); +static int vmxnet3_setup_legacy_interrupt(struct vmxnet3_softc *); +static int vmxnet3_setup_interrupts(struct vmxnet3_softc *); +static int vmxnet3_alloc_interrupts(struct vmxnet3_softc *); + +static void vmxnet3_free_interrupt(struct vmxnet3_softc *, + struct vmxnet3_interrupt *); +static void vmxnet3_free_interrupts(struct vmxnet3_softc *); + +static int vmxnet3_init_rxq(struct vmxnet3_softc *, int); +static int vmxnet3_init_txq(struct vmxnet3_softc *, int); +static int vmxnet3_alloc_rxtx_queues(struct vmxnet3_softc *); +static void vmxnet3_destroy_rxq(struct vmxnet3_rxqueue *); +static void vmxnet3_destroy_txq(struct vmxnet3_txqueue *); +static void vmxnet3_free_rxtx_queues(struct vmxnet3_softc *); + +static int vmxnet3_alloc_shared_data(struct vmxnet3_softc *); +static void vmxnet3_free_shared_data(struct vmxnet3_softc *); +static int vmxnet3_alloc_txq_data(struct vmxnet3_softc *); +static void vmxnet3_free_txq_data(struct vmxnet3_softc *); +static int vmxnet3_alloc_rxq_data(struct vmxnet3_softc *); +static void vmxnet3_free_rxq_data(struct vmxnet3_softc *); +static int vmxnet3_alloc_queue_data(struct vmxnet3_softc *); +static void vmxnet3_free_queue_data(struct vmxnet3_softc *); +static int vmxnet3_alloc_mcast_table(struct vmxnet3_softc *); +static void vmxnet3_init_shared_data(struct vmxnet3_softc *); +static void vmxnet3_reinit_interface(struct vmxnet3_softc *); +static void vmxnet3_reinit_shared_data(struct vmxnet3_softc *); +static int vmxnet3_alloc_data(struct vmxnet3_softc *); +static void vmxnet3_free_data(struct vmxnet3_softc *); +static int vmxnet3_setup_interface(struct vmxnet3_softc *); + +static void vmxnet3_evintr(struct vmxnet3_softc *); +static void vmxnet3_txq_eof(struct vmxnet3_txqueue *); +static void vmxnet3_rx_csum(struct vmxnet3_rxcompdesc *, struct mbuf *); +static int vmxnet3_newbuf(struct vmxnet3_softc *, struct vmxnet3_rxring *); +static void vmxnet3_rxq_eof_discard(struct vmxnet3_rxqueue *, + struct vmxnet3_rxring *, int); +static void vmxnet3_rxq_eof(struct vmxnet3_rxqueue *); +static void vmxnet3_legacy_intr(void *); +static void vmxnet3_txq_intr(void *); +static void vmxnet3_rxq_intr(void *); +static void vmxnet3_event_intr(void *); + +static void vmxnet3_txstop(struct vmxnet3_softc *, struct vmxnet3_txqueue *); +static void vmxnet3_rxstop(struct vmxnet3_softc *, struct vmxnet3_rxqueue *); +static void vmxnet3_stop(struct vmxnet3_softc *); + +static void vmxnet3_txinit(struct vmxnet3_softc *, struct vmxnet3_txqueue *); +static int vmxnet3_rxinit(struct vmxnet3_softc *, struct vmxnet3_rxqueue *); +static int vmxnet3_reinit_queues(struct vmxnet3_softc *); +static int vmxnet3_enable_device(struct vmxnet3_softc *); +static void vmxnet3_reinit_rxfilters(struct vmxnet3_softc *); +static int vmxnet3_reinit(struct vmxnet3_softc *); +static void vmxnet3_init_locked(struct vmxnet3_softc *); +static void vmxnet3_init(void *); + +static int vmxnet3_txq_offload_ctx(struct mbuf *, int *, int *, int *); +static int vmxnet3_txq_load_mbuf(struct vmxnet3_txqueue *, struct mbuf **, + bus_dmamap_t, bus_dma_segment_t [], int *); +static void vmxnet3_txq_unload_mbuf(struct vmxnet3_txqueue *, bus_dmamap_t); +static int vmxnet3_txq_encap(struct vmxnet3_txqueue *, struct mbuf **); +static void vmxnet3_start_locked(struct ifnet *); +static void vmxnet3_start(struct ifnet *); + +static void vmxnet3_update_vlan_filter(struct vmxnet3_softc *, int, + uint16_t); +static void vmxnet3_register_vlan(void *, struct ifnet *, uint16_t); +static void vmxnet3_unregister_vlan(void *, struct ifnet *, uint16_t); +static void vmxnet3_set_rxfilter(struct vmxnet3_softc *); +static int vmxnet3_change_mtu(struct vmxnet3_softc *, int); +static int vmxnet3_ioctl(struct ifnet *, u_long, caddr_t); + +static int vmxnet3_watchdog(struct vmxnet3_txqueue *); +static void vmxnet3_tick(void *); +static void vmxnet3_link_status(struct vmxnet3_softc *); +static void vmxnet3_media_status(struct ifnet *, struct ifmediareq *); +static int vmxnet3_media_change(struct ifnet *); +static void vmxnet3_set_lladdr(struct vmxnet3_softc *); +static void vmxnet3_get_lladdr(struct vmxnet3_softc *); + +static void vmxnet3_setup_txq_sysctl(struct vmxnet3_txqueue *, + struct sysctl_ctx_list *, struct sysctl_oid_list *); +static void vmxnet3_setup_rxq_sysctl(struct vmxnet3_rxqueue *, + struct sysctl_ctx_list *, struct sysctl_oid_list *); +static void vmxnet3_setup_queue_sysctl(struct vmxnet3_softc *, + struct sysctl_ctx_list *, struct sysctl_oid_list *); +static void vmxnet3_setup_sysctl(struct vmxnet3_softc *); + +static void vmxnet3_write_bar0(struct vmxnet3_softc *, bus_size_t, + uint32_t); +static uint32_t vmxnet3_read_bar1(struct vmxnet3_softc *, bus_size_t); +static void vmxnet3_write_bar1(struct vmxnet3_softc *, bus_size_t, + uint32_t); +static void vmxnet3_write_cmd(struct vmxnet3_softc *, uint32_t); +static uint32_t vmxnet3_read_cmd(struct vmxnet3_softc *, uint32_t); + +static void vmxnet3_enable_intr(struct vmxnet3_softc *, int); +static void vmxnet3_disable_intr(struct vmxnet3_softc *, int); +static void vmxnet3_enable_all_intrs(struct vmxnet3_softc *); +static void vmxnet3_disable_all_intrs(struct vmxnet3_softc *); + +static int vmxnet3_dma_malloc(struct vmxnet3_softc *, bus_size_t, + bus_size_t, struct vmxnet3_dma_alloc *); +static void vmxnet3_dma_free(struct vmxnet3_softc *, + struct vmxnet3_dma_alloc *); + +typedef enum { + VMXNET3_BARRIER_RD, + VMXNET3_BARRIER_WR, + VMXNET3_BARRIER_RDWR, +} vmxnet3_barrier_t; + +static void vmxnet3_barrier(struct vmxnet3_softc *, vmxnet3_barrier_t); + +static device_method_t vmxnet3_methods[] = { + /* Device interface. */ + DEVMETHOD(device_probe, vmxnet3_probe), + DEVMETHOD(device_attach, vmxnet3_attach), + DEVMETHOD(device_detach, vmxnet3_detach), + DEVMETHOD(device_shutdown, vmxnet3_shutdown), + + DEVMETHOD_END +}; + +static driver_t vmxnet3_driver = { + "vmx", vmxnet3_methods, sizeof(struct vmxnet3_softc) +}; + +static devclass_t vmxnet3_devclass; +DRIVER_MODULE(vmx, pci, vmxnet3_driver, vmxnet3_devclass, 0, 0); + +MODULE_DEPEND(vmx, pci, 1, 1, 1); +MODULE_DEPEND(vmx, ether, 1, 1, 1); + +#define VMXNET3_VMWARE_VENDOR_ID 0x15AD +#define VMXNET3_VMWARE_DEVICE_ID 0x07B0 + +static int +vmxnet3_probe(device_t dev) +{ + + if (pci_get_vendor(dev) == VMXNET3_VMWARE_VENDOR_ID && + pci_get_device(dev) == VMXNET3_VMWARE_DEVICE_ID) { + device_set_desc(dev, "VMware VMXNET3 Ethernet Adapter"); + return (BUS_PROBE_DEFAULT); + } + + return (ENXIO); +} + +static int +vmxnet3_attach(device_t dev) +{ + struct vmxnet3_softc *sc; + int error; + + sc = device_get_softc(dev); + sc->vmx_dev = dev; + + pci_enable_busmaster(dev); + + VMXNET3_CORE_LOCK_INIT(sc, device_get_nameunit(dev)); + callout_init_mtx(&sc->vmx_tick, &sc->vmx_mtx, 0); + + vmxnet3_initial_config(sc); + + error = vmxnet3_alloc_resources(sc); + if (error) + goto fail; + + error = vmxnet3_check_version(sc); + if (error) + goto fail; + + error = vmxnet3_alloc_rxtx_queues(sc); + if (error) + goto fail; + + error = vmxnet3_alloc_interrupts(sc); + if (error) + goto fail; + + error = vmxnet3_alloc_data(sc); + if (error) + goto fail; + + error = vmxnet3_setup_interface(sc); + if (error) + goto fail; + + error = vmxnet3_setup_interrupts(sc); + if (error) { + ether_ifdetach(sc->vmx_ifp); + device_printf(dev, "could not set up interrupt\n"); + goto fail; + } + + vmxnet3_setup_sysctl(sc); + vmxnet3_link_status(sc); + +fail: + if (error) + vmxnet3_detach(dev); + + return (error); +} + +static int +vmxnet3_detach(device_t dev) +{ + struct vmxnet3_softc *sc; + struct ifnet *ifp; + + sc = device_get_softc(dev); + ifp = sc->vmx_ifp; + + if (device_is_attached(dev)) { + ether_ifdetach(ifp); + VMXNET3_CORE_LOCK(sc); + vmxnet3_stop(sc); + VMXNET3_CORE_UNLOCK(sc); + callout_drain(&sc->vmx_tick); + } + + if (sc->vmx_vlan_attach != NULL) { + EVENTHANDLER_DEREGISTER(vlan_config, sc->vmx_vlan_attach); + sc->vmx_vlan_attach = NULL; + } + if (sc->vmx_vlan_detach != NULL) { + EVENTHANDLER_DEREGISTER(vlan_config, sc->vmx_vlan_detach); + sc->vmx_vlan_detach = NULL; + } + + vmxnet3_free_interrupts(sc); + + if (ifp != NULL) { + if_free(ifp); + sc->vmx_ifp = NULL; + } + + ifmedia_removeall(&sc->vmx_media); + + vmxnet3_free_data(sc); + vmxnet3_free_resources(sc); + vmxnet3_free_rxtx_queues(sc); + + VMXNET3_CORE_LOCK_DESTROY(sc); + + return (0); +} + +static int +vmxnet3_shutdown(device_t dev) +{ + + return (0); +} + +static int +vmxnet3_alloc_resources(struct vmxnet3_softc *sc) +{ + device_t dev; + int rid; + + dev = sc->vmx_dev; + + rid = PCIR_BAR(0); + sc->vmx_res0 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE); + if (sc->vmx_res0 == NULL) { + device_printf(dev, + "could not map BAR0 memory\n"); + return (ENXIO); + } + + sc->vmx_iot0 = rman_get_bustag(sc->vmx_res0); + sc->vmx_ioh0 = rman_get_bushandle(sc->vmx_res0); + + rid = PCIR_BAR(1); + sc->vmx_res1 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE); + if (sc->vmx_res1 == NULL) { + device_printf(dev, + "could not map BAR1 memory\n"); + return (ENXIO); + } + + sc->vmx_iot1 = rman_get_bustag(sc->vmx_res1); + sc->vmx_ioh1 = rman_get_bushandle(sc->vmx_res1); + + if (pci_find_cap(dev, PCIY_MSIX, NULL) == 0) { + rid = PCIR_BAR(2); + sc->vmx_msix_res = bus_alloc_resource_any(dev, + SYS_RES_MEMORY, &rid, RF_ACTIVE); + } + + if (sc->vmx_msix_res == NULL) + sc->vmx_flags |= VMXNET3_FLAG_NO_MSIX; + + return (0); +} + +static void +vmxnet3_free_resources(struct vmxnet3_softc *sc) +{ + device_t dev; + int rid; + + dev = sc->vmx_dev; + + if (sc->vmx_res0 != NULL) { + rid = PCIR_BAR(0); + bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->vmx_res0); + sc->vmx_res0 = NULL; + } + + if (sc->vmx_res1 != NULL) { + rid = PCIR_BAR(1); + bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->vmx_res1); + sc->vmx_res1 = NULL; + } + + if (sc->vmx_msix_res != NULL) { + rid = PCIR_BAR(2); + bus_release_resource(dev, SYS_RES_MEMORY, rid, + sc->vmx_msix_res); + sc->vmx_msix_res = NULL; + } +} + +static int +vmxnet3_check_version(struct vmxnet3_softc *sc) +{ + device_t dev; + uint32_t version; + + dev = sc->vmx_dev; + + version = vmxnet3_read_bar1(sc, VMXNET3_BAR1_VRRS); + if ((version & 0x01) == 0) { + device_printf(dev, "unsupported hardware version %#x\n", + version); + return (ENOTSUP); + } else + vmxnet3_write_bar1(sc, VMXNET3_BAR1_VRRS, 1); + + version = vmxnet3_read_bar1(sc, VMXNET3_BAR1_UVRS); + if ((version & 0x01) == 0) { + device_printf(dev, "unsupported UPT version %#x\n", version); + return (ENOTSUP); + } else + vmxnet3_write_bar1(sc, VMXNET3_BAR1_UVRS, 1); + + return (0); +} + +static void +vmxnet3_initial_config(struct vmxnet3_softc *sc) +{ + + sc->vmx_ntxqueues = 1; + sc->vmx_nrxqueues = 1; + sc->vmx_ntxdescs = VMXNET3_MAX_TX_NDESC; + sc->vmx_nrxdescs = VMXNET3_MAX_RX_NDESC; + sc->vmx_max_rxsegs = VMXNET3_MAX_RX_SEGS; +} + +static int +vmxnet3_alloc_msix_interrupts(struct vmxnet3_softc *sc) +{ + device_t dev; + int nmsix, cnt, required; + + dev = sc->vmx_dev; + + if (sc->vmx_flags & VMXNET3_FLAG_NO_MSIX) + return (1); + + /* Allocate an additional vector for the events interrupt. */ + required = sc->vmx_nrxqueues + sc->vmx_ntxqueues + 1; + + nmsix = pci_msix_count(dev); + if (nmsix < required) + return (1); + + cnt = required; + if (pci_alloc_msix(dev, &cnt) == 0 && cnt >= required) { + sc->vmx_nintrs = required; + return (0); + } else + pci_release_msi(dev); + + return (1); +} + +static int +vmxnet3_alloc_msi_interrupts(struct vmxnet3_softc *sc) +{ + device_t dev; + int nmsi, cnt, required; + + dev = sc->vmx_dev; + required = 1; + + nmsi = pci_msi_count(dev); + if (nmsi < required) + return (1); + + cnt = required; + if (pci_alloc_msi(dev, &cnt) == 0 && cnt >= required) { + sc->vmx_nintrs = 1; + return (0); + } else + pci_release_msi(dev); + + return (1); +} + +static int +vmxnet3_alloc_legacy_interrupts(struct vmxnet3_softc *sc) +{ + + sc->vmx_nintrs = 1; + return (0); +} + +static int +vmxnet3_alloc_interrupt(struct vmxnet3_softc *sc, int rid, int flags, + struct vmxnet3_interrupt *intr) +{ + struct resource *irq; + + irq = bus_alloc_resource_any(sc->vmx_dev, SYS_RES_IRQ, &rid, flags); + if (irq == NULL) + return (ENXIO); + + intr->vmxi_irq = irq; + intr->vmxi_rid = rid; + + return (0); +} + +static int +vmxnet3_alloc_intr_resources(struct vmxnet3_softc *sc) +{ + int i, rid, flags, error; + + rid = 0; + flags = RF_ACTIVE; + + if (sc->vmx_intr_type == VMXNET3_IT_LEGACY) + flags |= RF_SHAREABLE; + else + rid = 1; + + for (i = 0; i < sc->vmx_nintrs; i++, rid++) { + error = vmxnet3_alloc_interrupt(sc, rid, flags, + &sc->vmx_intrs[i]); + if (error) + return (error); + } + + return (0); +} + +/* + * NOTE: We only support the simple case of each Rx and Tx queue on its + * own MSIX vector. This is good enough until we support mulitqueue. + */ +static int +vmxnet3_setup_msix_interrupts(struct vmxnet3_softc *sc) +{ + device_t dev; + struct vmxnet3_txqueue *txq; + struct vmxnet3_rxqueue *rxq; + struct vmxnet3_interrupt *intr; + enum intr_type type; + int i, error; + + dev = sc->vmx_dev; + intr = &sc->vmx_intrs[0]; + type = INTR_TYPE_NET | INTR_MPSAFE; + + for (i = 0; i < sc->vmx_ntxqueues; i++, intr++) { + txq = &sc->vmx_txq[i]; + error = bus_setup_intr(dev, intr->vmxi_irq, type, NULL, + vmxnet3_txq_intr, txq, &intr->vmxi_handler); + if (error) + return (error); + txq->vxtxq_intr_idx = intr->vmxi_rid - 1; + } + + for (i = 0; i < sc->vmx_nrxqueues; i++, intr++) { + rxq = &sc->vmx_rxq[i]; + error = bus_setup_intr(dev, intr->vmxi_irq, type, NULL, + vmxnet3_rxq_intr, rxq, &intr->vmxi_handler); + if (error) + return (error); + rxq->vxrxq_intr_idx = intr->vmxi_rid - 1; + } + + error = bus_setup_intr(dev, intr->vmxi_irq, type, NULL, + vmxnet3_event_intr, sc, &intr->vmxi_handler); + if (error) + return (error); + sc->vmx_event_intr_idx = intr->vmxi_rid - 1; + + return (0); +} + +static int +vmxnet3_setup_legacy_interrupt(struct vmxnet3_softc *sc) +{ + struct vmxnet3_interrupt *intr; + int i, error; + + intr = &sc->vmx_intrs[0]; + error = bus_setup_intr(sc->vmx_dev, intr->vmxi_irq, + INTR_TYPE_NET | INTR_MPSAFE, NULL, vmxnet3_legacy_intr, sc, + &intr->vmxi_handler); + + for (i = 0; i < sc->vmx_ntxqueues; i++) + sc->vmx_txq[i].vxtxq_intr_idx = 0; + for (i = 0; i < sc->vmx_nrxqueues; i++) + sc->vmx_rxq[i].vxrxq_intr_idx = 0; + sc->vmx_event_intr_idx = 0; + + return (error); +} + +/* + * XXX BMV Should probably reorganize the attach and just do + * this in vmxnet3_init_shared_data(). + */ +static void +vmxnet3_set_interrupt_idx(struct vmxnet3_softc *sc) +{ + struct vmxnet3_txqueue *txq; + struct vmxnet3_txq_shared *txs; + struct vmxnet3_rxqueue *rxq; + struct vmxnet3_rxq_shared *rxs; + int i; + + sc->vmx_ds->evintr = sc->vmx_event_intr_idx; + + for (i = 0; i < sc->vmx_ntxqueues; i++) { + txq = &sc->vmx_txq[i]; + txs = txq->vxtxq_ts; + txs->intr_idx = txq->vxtxq_intr_idx; + } + + for (i = 0; i < sc->vmx_nrxqueues; i++) { + rxq = &sc->vmx_rxq[i]; + rxs = rxq->vxrxq_rs; + rxs->intr_idx = rxq->vxrxq_intr_idx; + } +} + +static int +vmxnet3_setup_interrupts(struct vmxnet3_softc *sc) +{ + int error; + + error = vmxnet3_alloc_intr_resources(sc); + if (error) + return (error); + + switch (sc->vmx_intr_type) { + case VMXNET3_IT_MSIX: + error = vmxnet3_setup_msix_interrupts(sc); + break; + case VMXNET3_IT_MSI: + case VMXNET3_IT_LEGACY: + error = vmxnet3_setup_legacy_interrupt(sc); + break; + default: + panic("%s: invalid interrupt type %d", __func__, + sc->vmx_intr_type); + } + + if (error == 0) + vmxnet3_set_interrupt_idx(sc); + + return (error); +} + +static int +vmxnet3_alloc_interrupts(struct vmxnet3_softc *sc) +{ + device_t dev; + uint32_t config; + int error; + + dev = sc->vmx_dev; + config = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_INTRCFG); + + sc->vmx_intr_type = config & 0x03; + sc->vmx_intr_mask_mode = (config >> 2) & 0x03; + + switch (sc->vmx_intr_type) { + case VMXNET3_IT_AUTO: + sc->vmx_intr_type = VMXNET3_IT_MSIX; + /* FALLTHROUGH */ + case VMXNET3_IT_MSIX: + error = vmxnet3_alloc_msix_interrupts(sc); + if (error == 0) + break; + sc->vmx_intr_type = VMXNET3_IT_MSI; + /* FALLTHROUGH */ + case VMXNET3_IT_MSI: + error = vmxnet3_alloc_msi_interrupts(sc); + if (error == 0) + break; + sc->vmx_intr_type = VMXNET3_IT_LEGACY; + /* FALLTHROUGH */ + case VMXNET3_IT_LEGACY: + error = vmxnet3_alloc_legacy_interrupts(sc); + if (error == 0) + break; + /* FALLTHROUGH */ *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201308232047.r7NKlHHD079485>