xref: /freebsd/sys/dev/vmware/vmxnet3/if_vmx.c (revision f55f37d9c5b8e02e1568cdecf8e1bbb58a6d19ec)
1e3c97c2cSBryan Venteicher /*-
2e3c97c2cSBryan Venteicher  * Copyright (c) 2013 Tsubai Masanari
3e3c97c2cSBryan Venteicher  * Copyright (c) 2013 Bryan Venteicher <bryanv@FreeBSD.org>
48f82136aSPatrick Kelsey  * Copyright (c) 2018 Patrick Kelsey
5e3c97c2cSBryan Venteicher  *
6e3c97c2cSBryan Venteicher  * Permission to use, copy, modify, and distribute this software for any
7e3c97c2cSBryan Venteicher  * purpose with or without fee is hereby granted, provided that the above
8e3c97c2cSBryan Venteicher  * copyright notice and this permission notice appear in all copies.
9e3c97c2cSBryan Venteicher  *
10e3c97c2cSBryan Venteicher  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11e3c97c2cSBryan Venteicher  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12e3c97c2cSBryan Venteicher  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13e3c97c2cSBryan Venteicher  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14e3c97c2cSBryan Venteicher  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15e3c97c2cSBryan Venteicher  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16e3c97c2cSBryan Venteicher  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17e3c97c2cSBryan Venteicher  *
18e3c97c2cSBryan Venteicher  * $OpenBSD: src/sys/dev/pci/if_vmx.c,v 1.11 2013/06/22 00:28:10 uebayasi Exp $
19e3c97c2cSBryan Venteicher  */
20e3c97c2cSBryan Venteicher 
21e3c97c2cSBryan Venteicher /* Driver for VMware vmxnet3 virtual ethernet devices. */
22e3c97c2cSBryan Venteicher 
23e3c97c2cSBryan Venteicher #include <sys/cdefs.h>
24e3c97c2cSBryan Venteicher __FBSDID("$FreeBSD$");
25e3c97c2cSBryan Venteicher 
26e3c97c2cSBryan Venteicher #include <sys/param.h>
27e3c97c2cSBryan Venteicher #include <sys/systm.h>
28e3c97c2cSBryan Venteicher #include <sys/kernel.h>
29e3c97c2cSBryan Venteicher #include <sys/endian.h>
30e3c97c2cSBryan Venteicher #include <sys/sockio.h>
31e3c97c2cSBryan Venteicher #include <sys/mbuf.h>
32e3c97c2cSBryan Venteicher #include <sys/malloc.h>
33e3c97c2cSBryan Venteicher #include <sys/module.h>
34e3c97c2cSBryan Venteicher #include <sys/socket.h>
35e3c97c2cSBryan Venteicher #include <sys/sysctl.h>
36e557c1ddSBryan Venteicher #include <sys/smp.h>
37e3c97c2cSBryan Venteicher #include <vm/vm.h>
38e3c97c2cSBryan Venteicher #include <vm/pmap.h>
39e3c97c2cSBryan Venteicher 
40e3c97c2cSBryan Venteicher #include <net/ethernet.h>
41e3c97c2cSBryan Venteicher #include <net/if.h>
4276039bc8SGleb Smirnoff #include <net/if_var.h>
43e3c97c2cSBryan Venteicher #include <net/if_arp.h>
44e3c97c2cSBryan Venteicher #include <net/if_dl.h>
45e3c97c2cSBryan Venteicher #include <net/if_types.h>
46e3c97c2cSBryan Venteicher #include <net/if_media.h>
47e3c97c2cSBryan Venteicher #include <net/if_vlan_var.h>
488f82136aSPatrick Kelsey #include <net/iflib.h>
49e3c97c2cSBryan Venteicher 
50e3c97c2cSBryan Venteicher #include <netinet/in_systm.h>
51e3c97c2cSBryan Venteicher #include <netinet/in.h>
52e3c97c2cSBryan Venteicher #include <netinet/ip.h>
53e3c97c2cSBryan Venteicher #include <netinet/ip6.h>
54e3c97c2cSBryan Venteicher #include <netinet6/ip6_var.h>
55e3c97c2cSBryan Venteicher #include <netinet/udp.h>
56e3c97c2cSBryan Venteicher #include <netinet/tcp.h>
57e3c97c2cSBryan Venteicher 
58e3c97c2cSBryan Venteicher #include <machine/bus.h>
59e3c97c2cSBryan Venteicher #include <machine/resource.h>
60e3c97c2cSBryan Venteicher #include <sys/bus.h>
61e3c97c2cSBryan Venteicher #include <sys/rman.h>
62e3c97c2cSBryan Venteicher 
63e3c97c2cSBryan Venteicher #include <dev/pci/pcireg.h>
64e3c97c2cSBryan Venteicher #include <dev/pci/pcivar.h>
65e3c97c2cSBryan Venteicher 
668f82136aSPatrick Kelsey #include "ifdi_if.h"
678f82136aSPatrick Kelsey 
68e3c97c2cSBryan Venteicher #include "if_vmxreg.h"
69e3c97c2cSBryan Venteicher #include "if_vmxvar.h"
70e3c97c2cSBryan Venteicher 
71e3c97c2cSBryan Venteicher #include "opt_inet.h"
72e3c97c2cSBryan Venteicher #include "opt_inet6.h"
73e3c97c2cSBryan Venteicher 
74e3c97c2cSBryan Venteicher 
758f82136aSPatrick Kelsey #define VMXNET3_VMWARE_VENDOR_ID	0x15AD
768f82136aSPatrick Kelsey #define VMXNET3_VMWARE_DEVICE_ID	0x07B0
778f82136aSPatrick Kelsey 
788f82136aSPatrick Kelsey static pci_vendor_info_t vmxnet3_vendor_info_array[] =
798f82136aSPatrick Kelsey {
808f82136aSPatrick Kelsey 	PVID(VMXNET3_VMWARE_VENDOR_ID, VMXNET3_VMWARE_DEVICE_ID, "VMware VMXNET3 Ethernet Adapter"),
818f82136aSPatrick Kelsey 	/* required last entry */
828f82136aSPatrick Kelsey 	PVID_END
838f82136aSPatrick Kelsey };
848f82136aSPatrick Kelsey 
858f82136aSPatrick Kelsey static void	*vmxnet3_register(device_t);
868f82136aSPatrick Kelsey static int	vmxnet3_attach_pre(if_ctx_t);
878f82136aSPatrick Kelsey static int	vmxnet3_msix_intr_assign(if_ctx_t, int);
888f82136aSPatrick Kelsey static void	vmxnet3_free_irqs(struct vmxnet3_softc *);
898f82136aSPatrick Kelsey static int	vmxnet3_attach_post(if_ctx_t);
908f82136aSPatrick Kelsey static int	vmxnet3_detach(if_ctx_t);
918f82136aSPatrick Kelsey static int	vmxnet3_shutdown(if_ctx_t);
928f82136aSPatrick Kelsey static int	vmxnet3_suspend(if_ctx_t);
938f82136aSPatrick Kelsey static int	vmxnet3_resume(if_ctx_t);
94e3c97c2cSBryan Venteicher 
95e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_resources(struct vmxnet3_softc *);
96e3c97c2cSBryan Venteicher static void	vmxnet3_free_resources(struct vmxnet3_softc *);
97e3c97c2cSBryan Venteicher static int	vmxnet3_check_version(struct vmxnet3_softc *);
988f82136aSPatrick Kelsey static void	vmxnet3_set_interrupt_idx(struct vmxnet3_softc *);
99e3c97c2cSBryan Venteicher 
1008f82136aSPatrick Kelsey static int	vmxnet3_queues_shared_alloc(struct vmxnet3_softc *);
1018f82136aSPatrick Kelsey static void	vmxnet3_init_txq(struct vmxnet3_softc *, int);
1028f82136aSPatrick Kelsey static int	vmxnet3_tx_queues_alloc(if_ctx_t, caddr_t *, uint64_t *, int, int);
1038f82136aSPatrick Kelsey static void	vmxnet3_init_rxq(struct vmxnet3_softc *, int, int);
1048f82136aSPatrick Kelsey static int	vmxnet3_rx_queues_alloc(if_ctx_t, caddr_t *, uint64_t *, int, int);
1058f82136aSPatrick Kelsey static void	vmxnet3_queues_free(if_ctx_t);
106e3c97c2cSBryan Venteicher 
107e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_shared_data(struct vmxnet3_softc *);
108e3c97c2cSBryan Venteicher static void	vmxnet3_free_shared_data(struct vmxnet3_softc *);
109e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_mcast_table(struct vmxnet3_softc *);
1108f82136aSPatrick Kelsey static void	vmxnet3_free_mcast_table(struct vmxnet3_softc *);
111e3c97c2cSBryan Venteicher static void	vmxnet3_init_shared_data(struct vmxnet3_softc *);
112e557c1ddSBryan Venteicher static void	vmxnet3_reinit_rss_shared_data(struct vmxnet3_softc *);
113e3c97c2cSBryan Venteicher static void	vmxnet3_reinit_shared_data(struct vmxnet3_softc *);
114e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_data(struct vmxnet3_softc *);
115e3c97c2cSBryan Venteicher static void	vmxnet3_free_data(struct vmxnet3_softc *);
116e3c97c2cSBryan Venteicher 
117e3c97c2cSBryan Venteicher static void	vmxnet3_evintr(struct vmxnet3_softc *);
1188f82136aSPatrick Kelsey static int	vmxnet3_isc_txd_encap(void *, if_pkt_info_t);
1198f82136aSPatrick Kelsey static void	vmxnet3_isc_txd_flush(void *, uint16_t, qidx_t);
1208f82136aSPatrick Kelsey static int	vmxnet3_isc_txd_credits_update(void *, uint16_t, bool);
1218f82136aSPatrick Kelsey static int	vmxnet3_isc_rxd_available(void *, uint16_t, qidx_t, qidx_t);
1228f82136aSPatrick Kelsey static int	vmxnet3_isc_rxd_pkt_get(void *, if_rxd_info_t);
1238f82136aSPatrick Kelsey static void	vmxnet3_isc_rxd_refill(void *, if_rxd_update_t);
1248f82136aSPatrick Kelsey static void	vmxnet3_isc_rxd_flush(void *, uint16_t, uint8_t, qidx_t);
1258f82136aSPatrick Kelsey static int	vmxnet3_legacy_intr(void *);
1268f82136aSPatrick Kelsey static int	vmxnet3_rxq_intr(void *);
1278f82136aSPatrick Kelsey static int	vmxnet3_event_intr(void *);
128e3c97c2cSBryan Venteicher 
1298f82136aSPatrick Kelsey static void	vmxnet3_stop(if_ctx_t);
130e3c97c2cSBryan Venteicher 
131e3c97c2cSBryan Venteicher static void	vmxnet3_txinit(struct vmxnet3_softc *, struct vmxnet3_txqueue *);
1328f82136aSPatrick Kelsey static void	vmxnet3_rxinit(struct vmxnet3_softc *, struct vmxnet3_rxqueue *);
1338f82136aSPatrick Kelsey static void	vmxnet3_reinit_queues(struct vmxnet3_softc *);
134e3c97c2cSBryan Venteicher static int	vmxnet3_enable_device(struct vmxnet3_softc *);
135e3c97c2cSBryan Venteicher static void	vmxnet3_reinit_rxfilters(struct vmxnet3_softc *);
1368f82136aSPatrick Kelsey static void	vmxnet3_init(if_ctx_t);
1378f82136aSPatrick Kelsey static void	vmxnet3_multi_set(if_ctx_t);
1388f82136aSPatrick Kelsey static int	vmxnet3_mtu_set(if_ctx_t, uint32_t);
1398f82136aSPatrick Kelsey static void	vmxnet3_media_status(if_ctx_t, struct ifmediareq *);
1408f82136aSPatrick Kelsey static int	vmxnet3_media_change(if_ctx_t);
1418f82136aSPatrick Kelsey static int	vmxnet3_promisc_set(if_ctx_t, int);
1428f82136aSPatrick Kelsey static uint64_t	vmxnet3_get_counter(if_ctx_t, ift_counter);
1438f82136aSPatrick Kelsey static void	vmxnet3_update_admin_status(if_ctx_t);
1448f82136aSPatrick Kelsey static void	vmxnet3_txq_timer(if_ctx_t, uint16_t);
145e3c97c2cSBryan Venteicher 
146e3c97c2cSBryan Venteicher static void	vmxnet3_update_vlan_filter(struct vmxnet3_softc *, int,
147e3c97c2cSBryan Venteicher 		    uint16_t);
1488f82136aSPatrick Kelsey static void	vmxnet3_vlan_register(if_ctx_t, uint16_t);
1498f82136aSPatrick Kelsey static void	vmxnet3_vlan_unregister(if_ctx_t, uint16_t);
1508f82136aSPatrick Kelsey static void	vmxnet3_set_rxfilter(struct vmxnet3_softc *, int);
151e3c97c2cSBryan Venteicher 
152e557c1ddSBryan Venteicher static void	vmxnet3_refresh_host_stats(struct vmxnet3_softc *);
1538f82136aSPatrick Kelsey static int	vmxnet3_link_is_up(struct vmxnet3_softc *);
154e3c97c2cSBryan Venteicher static void	vmxnet3_link_status(struct vmxnet3_softc *);
155e3c97c2cSBryan Venteicher static void	vmxnet3_set_lladdr(struct vmxnet3_softc *);
156e3c97c2cSBryan Venteicher static void	vmxnet3_get_lladdr(struct vmxnet3_softc *);
157e3c97c2cSBryan Venteicher 
158e3c97c2cSBryan Venteicher static void	vmxnet3_setup_txq_sysctl(struct vmxnet3_txqueue *,
159e3c97c2cSBryan Venteicher 		    struct sysctl_ctx_list *, struct sysctl_oid_list *);
160e3c97c2cSBryan Venteicher static void	vmxnet3_setup_rxq_sysctl(struct vmxnet3_rxqueue *,
161e3c97c2cSBryan Venteicher 		    struct sysctl_ctx_list *, struct sysctl_oid_list *);
162e3c97c2cSBryan Venteicher static void	vmxnet3_setup_queue_sysctl(struct vmxnet3_softc *,
163e3c97c2cSBryan Venteicher 		    struct sysctl_ctx_list *, struct sysctl_oid_list *);
164e3c97c2cSBryan Venteicher static void	vmxnet3_setup_sysctl(struct vmxnet3_softc *);
165e3c97c2cSBryan Venteicher 
166e3c97c2cSBryan Venteicher static void	vmxnet3_write_bar0(struct vmxnet3_softc *, bus_size_t,
167e3c97c2cSBryan Venteicher 		    uint32_t);
168e3c97c2cSBryan Venteicher static uint32_t	vmxnet3_read_bar1(struct vmxnet3_softc *, bus_size_t);
169e3c97c2cSBryan Venteicher static void	vmxnet3_write_bar1(struct vmxnet3_softc *, bus_size_t,
170e3c97c2cSBryan Venteicher 		    uint32_t);
171e3c97c2cSBryan Venteicher static void	vmxnet3_write_cmd(struct vmxnet3_softc *, uint32_t);
172e3c97c2cSBryan Venteicher static uint32_t	vmxnet3_read_cmd(struct vmxnet3_softc *, uint32_t);
173e3c97c2cSBryan Venteicher 
1748f82136aSPatrick Kelsey static int	vmxnet3_tx_queue_intr_enable(if_ctx_t, uint16_t);
1758f82136aSPatrick Kelsey static int	vmxnet3_rx_queue_intr_enable(if_ctx_t, uint16_t);
1768f82136aSPatrick Kelsey static void	vmxnet3_link_intr_enable(if_ctx_t);
177e3c97c2cSBryan Venteicher static void	vmxnet3_enable_intr(struct vmxnet3_softc *, int);
178e3c97c2cSBryan Venteicher static void	vmxnet3_disable_intr(struct vmxnet3_softc *, int);
1798f82136aSPatrick Kelsey static void	vmxnet3_intr_enable_all(if_ctx_t);
1808f82136aSPatrick Kelsey static void	vmxnet3_intr_disable_all(if_ctx_t);
181e3c97c2cSBryan Venteicher 
182e3c97c2cSBryan Venteicher typedef enum {
183e3c97c2cSBryan Venteicher 	VMXNET3_BARRIER_RD,
184e3c97c2cSBryan Venteicher 	VMXNET3_BARRIER_WR,
185e3c97c2cSBryan Venteicher 	VMXNET3_BARRIER_RDWR,
186e3c97c2cSBryan Venteicher } vmxnet3_barrier_t;
187e3c97c2cSBryan Venteicher 
188e3c97c2cSBryan Venteicher static void	vmxnet3_barrier(struct vmxnet3_softc *, vmxnet3_barrier_t);
189e3c97c2cSBryan Venteicher 
1903c5dfe89SBryan Venteicher 
191e3c97c2cSBryan Venteicher static device_method_t vmxnet3_methods[] = {
1928f82136aSPatrick Kelsey 	/* Device interface */
1938f82136aSPatrick Kelsey 	DEVMETHOD(device_register, vmxnet3_register),
1948f82136aSPatrick Kelsey 	DEVMETHOD(device_probe, iflib_device_probe),
1958f82136aSPatrick Kelsey 	DEVMETHOD(device_attach, iflib_device_attach),
1968f82136aSPatrick Kelsey 	DEVMETHOD(device_detach, iflib_device_detach),
1978f82136aSPatrick Kelsey 	DEVMETHOD(device_shutdown, iflib_device_shutdown),
1988f82136aSPatrick Kelsey 	DEVMETHOD(device_suspend, iflib_device_suspend),
1998f82136aSPatrick Kelsey 	DEVMETHOD(device_resume, iflib_device_resume),
200e3c97c2cSBryan Venteicher 	DEVMETHOD_END
201e3c97c2cSBryan Venteicher };
202e3c97c2cSBryan Venteicher 
203e3c97c2cSBryan Venteicher static driver_t vmxnet3_driver = {
204e3c97c2cSBryan Venteicher 	"vmx", vmxnet3_methods, sizeof(struct vmxnet3_softc)
205e3c97c2cSBryan Venteicher };
206e3c97c2cSBryan Venteicher 
207e3c97c2cSBryan Venteicher static devclass_t vmxnet3_devclass;
208e3c97c2cSBryan Venteicher DRIVER_MODULE(vmx, pci, vmxnet3_driver, vmxnet3_devclass, 0, 0);
2098f82136aSPatrick Kelsey IFLIB_PNP_INFO(pci, vmx, vmxnet3_vendor_info_array);
2108f82136aSPatrick Kelsey MODULE_VERSION(vmx, 2);
211e3c97c2cSBryan Venteicher 
212e3c97c2cSBryan Venteicher MODULE_DEPEND(vmx, pci, 1, 1, 1);
213e3c97c2cSBryan Venteicher MODULE_DEPEND(vmx, ether, 1, 1, 1);
2148f82136aSPatrick Kelsey MODULE_DEPEND(vmx, iflib, 1, 1, 1);
215e3c97c2cSBryan Venteicher 
2168f82136aSPatrick Kelsey static device_method_t vmxnet3_iflib_methods[] = {
2178f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_tx_queues_alloc, vmxnet3_tx_queues_alloc),
2188f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_rx_queues_alloc, vmxnet3_rx_queues_alloc),
2198f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_queues_free, vmxnet3_queues_free),
220e3c97c2cSBryan Venteicher 
2218f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_attach_pre, vmxnet3_attach_pre),
2228f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_attach_post, vmxnet3_attach_post),
2238f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_detach, vmxnet3_detach),
2248f82136aSPatrick Kelsey 
2258f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_init, vmxnet3_init),
2268f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_stop, vmxnet3_stop),
2278f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_multi_set, vmxnet3_multi_set),
2288f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_mtu_set, vmxnet3_mtu_set),
2298f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_media_status, vmxnet3_media_status),
2308f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_media_change, vmxnet3_media_change),
2318f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_promisc_set, vmxnet3_promisc_set),
2328f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_get_counter, vmxnet3_get_counter),
2338f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_update_admin_status, vmxnet3_update_admin_status),
2348f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_timer, vmxnet3_txq_timer),
2358f82136aSPatrick Kelsey 
2368f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_tx_queue_intr_enable, vmxnet3_tx_queue_intr_enable),
2378f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_rx_queue_intr_enable, vmxnet3_rx_queue_intr_enable),
2388f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_link_intr_enable, vmxnet3_link_intr_enable),
2398f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_intr_enable, vmxnet3_intr_enable_all),
2408f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_intr_disable, vmxnet3_intr_disable_all),
2418f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_msix_intr_assign, vmxnet3_msix_intr_assign),
2428f82136aSPatrick Kelsey 
2438f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_vlan_register, vmxnet3_vlan_register),
2448f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_vlan_unregister, vmxnet3_vlan_unregister),
2458f82136aSPatrick Kelsey 
2468f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_shutdown, vmxnet3_shutdown),
2478f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_suspend, vmxnet3_suspend),
2488f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_resume, vmxnet3_resume),
2498f82136aSPatrick Kelsey 
2508f82136aSPatrick Kelsey 	DEVMETHOD_END
2518f82136aSPatrick Kelsey };
2528f82136aSPatrick Kelsey 
2538f82136aSPatrick Kelsey static driver_t vmxnet3_iflib_driver = {
2548f82136aSPatrick Kelsey 	"vmx", vmxnet3_iflib_methods, sizeof(struct vmxnet3_softc)
2558f82136aSPatrick Kelsey };
2568f82136aSPatrick Kelsey 
2578f82136aSPatrick Kelsey struct if_txrx vmxnet3_txrx = {
2588f82136aSPatrick Kelsey 	.ift_txd_encap = vmxnet3_isc_txd_encap,
2598f82136aSPatrick Kelsey 	.ift_txd_flush = vmxnet3_isc_txd_flush,
2608f82136aSPatrick Kelsey 	.ift_txd_credits_update = vmxnet3_isc_txd_credits_update,
2618f82136aSPatrick Kelsey 	.ift_rxd_available = vmxnet3_isc_rxd_available,
2628f82136aSPatrick Kelsey 	.ift_rxd_pkt_get = vmxnet3_isc_rxd_pkt_get,
2638f82136aSPatrick Kelsey 	.ift_rxd_refill = vmxnet3_isc_rxd_refill,
2648f82136aSPatrick Kelsey 	.ift_rxd_flush = vmxnet3_isc_rxd_flush,
2658f82136aSPatrick Kelsey 	.ift_legacy_intr = vmxnet3_legacy_intr
2668f82136aSPatrick Kelsey };
2678f82136aSPatrick Kelsey 
2688f82136aSPatrick Kelsey static struct if_shared_ctx vmxnet3_sctx_init = {
2698f82136aSPatrick Kelsey 	.isc_magic = IFLIB_MAGIC,
2708f82136aSPatrick Kelsey 	.isc_q_align = 512,
2718f82136aSPatrick Kelsey 
2728f82136aSPatrick Kelsey 	.isc_tx_maxsize = VMXNET3_TX_MAXSIZE,
2738f82136aSPatrick Kelsey 	.isc_tx_maxsegsize = VMXNET3_TX_MAXSEGSIZE,
2748f82136aSPatrick Kelsey 	.isc_tso_maxsize = VMXNET3_TSO_MAXSIZE + sizeof(struct ether_vlan_header),
2758f82136aSPatrick Kelsey 	.isc_tso_maxsegsize = VMXNET3_TX_MAXSEGSIZE,
2768f82136aSPatrick Kelsey 
2778f82136aSPatrick Kelsey 	/*
2788f82136aSPatrick Kelsey 	 * These values are used to configure the busdma tag used for
2798f82136aSPatrick Kelsey 	 * receive descriptors.  Each receive descriptor only points to one
2808f82136aSPatrick Kelsey 	 * buffer.
2818f82136aSPatrick Kelsey 	 */
2828f82136aSPatrick Kelsey 	.isc_rx_maxsize = VMXNET3_RX_MAXSEGSIZE, /* One buf per descriptor */
2838f82136aSPatrick Kelsey 	.isc_rx_nsegments = 1,  /* One mapping per descriptor */
2848f82136aSPatrick Kelsey 	.isc_rx_maxsegsize = VMXNET3_RX_MAXSEGSIZE,
2858f82136aSPatrick Kelsey 
2868f82136aSPatrick Kelsey 	.isc_admin_intrcnt = 1,
2878f82136aSPatrick Kelsey 	.isc_vendor_info = vmxnet3_vendor_info_array,
2888f82136aSPatrick Kelsey 	.isc_driver_version = "2",
2898f82136aSPatrick Kelsey 	.isc_driver = &vmxnet3_iflib_driver,
29041669133SMark Johnston 	.isc_flags = IFLIB_HAS_RXCQ | IFLIB_HAS_TXCQ | IFLIB_SINGLE_IRQ_RX_ONLY,
2918f82136aSPatrick Kelsey 
2928f82136aSPatrick Kelsey 	/*
2938f82136aSPatrick Kelsey 	 * Number of receive queues per receive queue set, with associated
2948f82136aSPatrick Kelsey 	 * descriptor settings for each.
2958f82136aSPatrick Kelsey 	 */
2968f82136aSPatrick Kelsey 	.isc_nrxqs = 3,
2978f82136aSPatrick Kelsey 	.isc_nfl = 2, /* one free list for each receive command queue */
2988f82136aSPatrick Kelsey 	.isc_nrxd_min = {VMXNET3_MIN_RX_NDESC, VMXNET3_MIN_RX_NDESC, VMXNET3_MIN_RX_NDESC},
2998f82136aSPatrick Kelsey 	.isc_nrxd_max = {VMXNET3_MAX_RX_NDESC, VMXNET3_MAX_RX_NDESC, VMXNET3_MAX_RX_NDESC},
3008f82136aSPatrick Kelsey 	.isc_nrxd_default = {VMXNET3_DEF_RX_NDESC, VMXNET3_DEF_RX_NDESC, VMXNET3_DEF_RX_NDESC},
3018f82136aSPatrick Kelsey 
3028f82136aSPatrick Kelsey 	/*
3038f82136aSPatrick Kelsey 	 * Number of transmit queues per transmit queue set, with associated
3048f82136aSPatrick Kelsey 	 * descriptor settings for each.
3058f82136aSPatrick Kelsey 	 */
3068f82136aSPatrick Kelsey 	.isc_ntxqs = 2,
3078f82136aSPatrick Kelsey 	.isc_ntxd_min = {VMXNET3_MIN_TX_NDESC, VMXNET3_MIN_TX_NDESC},
3088f82136aSPatrick Kelsey 	.isc_ntxd_max = {VMXNET3_MAX_TX_NDESC, VMXNET3_MAX_TX_NDESC},
3098f82136aSPatrick Kelsey 	.isc_ntxd_default = {VMXNET3_DEF_TX_NDESC, VMXNET3_DEF_TX_NDESC},
3108f82136aSPatrick Kelsey };
3118f82136aSPatrick Kelsey 
3128f82136aSPatrick Kelsey static void *
3138f82136aSPatrick Kelsey vmxnet3_register(device_t dev)
314e3c97c2cSBryan Venteicher {
3158f82136aSPatrick Kelsey 	return (&vmxnet3_sctx_init);
316e3c97c2cSBryan Venteicher }
317e3c97c2cSBryan Venteicher 
318e3c97c2cSBryan Venteicher static int
3198f82136aSPatrick Kelsey vmxnet3_attach_pre(if_ctx_t ctx)
320e3c97c2cSBryan Venteicher {
3218f82136aSPatrick Kelsey 	device_t dev;
3228f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
323e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
3248f82136aSPatrick Kelsey 	uint32_t intr_config;
325e3c97c2cSBryan Venteicher 	int error;
326e3c97c2cSBryan Venteicher 
3278f82136aSPatrick Kelsey 	dev = iflib_get_dev(ctx);
3288f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
329e3c97c2cSBryan Venteicher 	sc->vmx_dev = dev;
3308f82136aSPatrick Kelsey 	sc->vmx_ctx = ctx;
3318f82136aSPatrick Kelsey 	sc->vmx_sctx = iflib_get_sctx(ctx);
3328f82136aSPatrick Kelsey 	sc->vmx_scctx = iflib_get_softc_ctx(ctx);
3338f82136aSPatrick Kelsey 	sc->vmx_ifp = iflib_get_ifp(ctx);
3348f82136aSPatrick Kelsey 	sc->vmx_media = iflib_get_media(ctx);
3358f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
336e3c97c2cSBryan Venteicher 
3378f82136aSPatrick Kelsey 	scctx->isc_tx_nsegments = VMXNET3_TX_MAXSEGS;
3388f82136aSPatrick Kelsey 	scctx->isc_tx_tso_segments_max = VMXNET3_TX_MAXSEGS;
3398f82136aSPatrick Kelsey 	/* isc_tx_tso_size_max doesn't include possible vlan header */
3408f82136aSPatrick Kelsey 	scctx->isc_tx_tso_size_max = VMXNET3_TSO_MAXSIZE;
3418f82136aSPatrick Kelsey 	scctx->isc_tx_tso_segsize_max = VMXNET3_TX_MAXSEGSIZE;
3428f82136aSPatrick Kelsey 	scctx->isc_txrx = &vmxnet3_txrx;
343e3c97c2cSBryan Venteicher 
3448f82136aSPatrick Kelsey 	/* If 0, the iflib tunable was not set, so set to the default */
3458f82136aSPatrick Kelsey 	if (scctx->isc_nrxqsets == 0)
3468f82136aSPatrick Kelsey 		scctx->isc_nrxqsets = VMXNET3_DEF_RX_QUEUES;
3478f82136aSPatrick Kelsey 	scctx->isc_nrxqsets_max = min(VMXNET3_MAX_RX_QUEUES, mp_ncpus);
348e3c97c2cSBryan Venteicher 
3498f82136aSPatrick Kelsey 	/* If 0, the iflib tunable was not set, so set to the default */
3508f82136aSPatrick Kelsey 	if (scctx->isc_ntxqsets == 0)
3518f82136aSPatrick Kelsey 		scctx->isc_ntxqsets = VMXNET3_DEF_TX_QUEUES;
3528f82136aSPatrick Kelsey 	scctx->isc_ntxqsets_max = min(VMXNET3_MAX_TX_QUEUES, mp_ncpus);
353e3c97c2cSBryan Venteicher 
3548f82136aSPatrick Kelsey 	/*
3558f82136aSPatrick Kelsey 	 * Enforce that the transmit completion queue descriptor count is
3568f82136aSPatrick Kelsey 	 * the same as the transmit command queue descriptor count.
3578f82136aSPatrick Kelsey 	 */
3588f82136aSPatrick Kelsey 	scctx->isc_ntxd[0] = scctx->isc_ntxd[1];
3598f82136aSPatrick Kelsey 	scctx->isc_txqsizes[0] =
3608f82136aSPatrick Kelsey 	    sizeof(struct vmxnet3_txcompdesc) * scctx->isc_ntxd[0];
3618f82136aSPatrick Kelsey 	scctx->isc_txqsizes[1] =
3628f82136aSPatrick Kelsey 	    sizeof(struct vmxnet3_txdesc) * scctx->isc_ntxd[1];
3638f82136aSPatrick Kelsey 
3648f82136aSPatrick Kelsey 	/*
3658f82136aSPatrick Kelsey 	 * Enforce that the receive completion queue descriptor count is the
3668f82136aSPatrick Kelsey 	 * sum of the receive command queue descriptor counts, and that the
3678f82136aSPatrick Kelsey 	 * second receive command queue descriptor count is the same as the
3688f82136aSPatrick Kelsey 	 * first one.
3698f82136aSPatrick Kelsey 	 */
3708f82136aSPatrick Kelsey 	scctx->isc_nrxd[2] = scctx->isc_nrxd[1];
3718f82136aSPatrick Kelsey 	scctx->isc_nrxd[0] = scctx->isc_nrxd[1] + scctx->isc_nrxd[2];
3728f82136aSPatrick Kelsey 	scctx->isc_rxqsizes[0] =
3738f82136aSPatrick Kelsey 	    sizeof(struct vmxnet3_rxcompdesc) * scctx->isc_nrxd[0];
3748f82136aSPatrick Kelsey 	scctx->isc_rxqsizes[1] =
3758f82136aSPatrick Kelsey 	    sizeof(struct vmxnet3_rxdesc) * scctx->isc_nrxd[1];
3768f82136aSPatrick Kelsey 	scctx->isc_rxqsizes[2] =
3778f82136aSPatrick Kelsey 	    sizeof(struct vmxnet3_rxdesc) * scctx->isc_nrxd[2];
3788f82136aSPatrick Kelsey 
3798f82136aSPatrick Kelsey 	scctx->isc_rss_table_size = UPT1_RSS_MAX_IND_TABLE_SIZE;
3808f82136aSPatrick Kelsey 
3818f82136aSPatrick Kelsey 	/* Map PCI BARs */
382e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_resources(sc);
383e3c97c2cSBryan Venteicher 	if (error)
384e3c97c2cSBryan Venteicher 		goto fail;
385e3c97c2cSBryan Venteicher 
3868f82136aSPatrick Kelsey 	/* Check device versions */
387e3c97c2cSBryan Venteicher 	error = vmxnet3_check_version(sc);
388e3c97c2cSBryan Venteicher 	if (error)
389e3c97c2cSBryan Venteicher 		goto fail;
390e3c97c2cSBryan Venteicher 
3918f82136aSPatrick Kelsey 	/*
3928f82136aSPatrick Kelsey 	 * The interrupt mode can be set in the hypervisor configuration via
3938f82136aSPatrick Kelsey 	 * the parameter ethernet<N>.intrMode.
3948f82136aSPatrick Kelsey 	 */
3958f82136aSPatrick Kelsey 	intr_config = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_INTRCFG);
3968f82136aSPatrick Kelsey 	sc->vmx_intr_mask_mode = (intr_config >> 2) & 0x03;
397e3c97c2cSBryan Venteicher 
3988f82136aSPatrick Kelsey 	/*
3998f82136aSPatrick Kelsey 	 * Configure the softc context to attempt to configure the interrupt
4008f82136aSPatrick Kelsey 	 * mode now indicated by intr_config.  iflib will follow the usual
401b97de13aSMarius Strobl 	 * fallback path MSI-X -> MSI -> LEGACY, starting at the configured
4028f82136aSPatrick Kelsey 	 * starting mode.
4038f82136aSPatrick Kelsey 	 */
4048f82136aSPatrick Kelsey 	switch (intr_config & 0x03) {
4058f82136aSPatrick Kelsey 	case VMXNET3_IT_AUTO:
4068f82136aSPatrick Kelsey 	case VMXNET3_IT_MSIX:
4078f82136aSPatrick Kelsey 		scctx->isc_msix_bar = pci_msix_table_bar(dev);
4088f82136aSPatrick Kelsey 		break;
4098f82136aSPatrick Kelsey 	case VMXNET3_IT_MSI:
4108f82136aSPatrick Kelsey 		scctx->isc_msix_bar = -1;
4118f82136aSPatrick Kelsey 		scctx->isc_disable_msix = 1;
4128f82136aSPatrick Kelsey 		break;
4138f82136aSPatrick Kelsey 	case VMXNET3_IT_LEGACY:
4148f82136aSPatrick Kelsey 		scctx->isc_msix_bar = 0;
4158f82136aSPatrick Kelsey 		break;
416e3c97c2cSBryan Venteicher 	}
417e3c97c2cSBryan Venteicher 
4188f82136aSPatrick Kelsey 	scctx->isc_tx_csum_flags = VMXNET3_CSUM_ALL_OFFLOAD;
4198f82136aSPatrick Kelsey 	scctx->isc_capabilities = scctx->isc_capenable =
4208f82136aSPatrick Kelsey 	    IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6 |
4218f82136aSPatrick Kelsey 	    IFCAP_TSO4 | IFCAP_TSO6 |
4228f82136aSPatrick Kelsey 	    IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6 |
4238f82136aSPatrick Kelsey 	    IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING |
4248f82136aSPatrick Kelsey 	    IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO |
4258f82136aSPatrick Kelsey 	    IFCAP_JUMBO_MTU;
426e3c97c2cSBryan Venteicher 
4278f82136aSPatrick Kelsey 	/* These capabilities are not enabled by default. */
4288f82136aSPatrick Kelsey 	scctx->isc_capabilities |= IFCAP_LRO | IFCAP_VLAN_HWFILTER;
4298f82136aSPatrick Kelsey 
4308f82136aSPatrick Kelsey 	vmxnet3_get_lladdr(sc);
4318f82136aSPatrick Kelsey 	iflib_set_mac(ctx, sc->vmx_lladdr);
4328f82136aSPatrick Kelsey 
4338f82136aSPatrick Kelsey 	return (0);
434e3c97c2cSBryan Venteicher fail:
4358f82136aSPatrick Kelsey 	/*
4368f82136aSPatrick Kelsey 	 * We must completely clean up anything allocated above as iflib
4378f82136aSPatrick Kelsey 	 * will not invoke any other driver entry points as a result of this
4388f82136aSPatrick Kelsey 	 * failure.
4398f82136aSPatrick Kelsey 	 */
4408f82136aSPatrick Kelsey 	vmxnet3_free_resources(sc);
441e3c97c2cSBryan Venteicher 
442e3c97c2cSBryan Venteicher 	return (error);
443e3c97c2cSBryan Venteicher }
444e3c97c2cSBryan Venteicher 
445e3c97c2cSBryan Venteicher static int
4468f82136aSPatrick Kelsey vmxnet3_msix_intr_assign(if_ctx_t ctx, int msix)
447e3c97c2cSBryan Venteicher {
448e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
4498f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
4508f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
4518f82136aSPatrick Kelsey 	int error;
4528f82136aSPatrick Kelsey 	int i;
4538f82136aSPatrick Kelsey 	char irq_name[16];
454e3c97c2cSBryan Venteicher 
4558f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
4568f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
457e3c97c2cSBryan Venteicher 
4588f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
4598f82136aSPatrick Kelsey 		snprintf(irq_name, sizeof(irq_name), "rxq%d", i);
460e557c1ddSBryan Venteicher 
4618f82136aSPatrick Kelsey 		rxq = &sc->vmx_rxq[i];
4628f82136aSPatrick Kelsey 		error = iflib_irq_alloc_generic(ctx, &rxq->vxrxq_irq, i + 1,
4638f82136aSPatrick Kelsey 		    IFLIB_INTR_RX, vmxnet3_rxq_intr, rxq, i, irq_name);
4648f82136aSPatrick Kelsey 		if (error) {
4658f82136aSPatrick Kelsey 			device_printf(iflib_get_dev(ctx),
4668f82136aSPatrick Kelsey 			    "Failed to register rxq %d interrupt handler\n", i);
4678f82136aSPatrick Kelsey 			return (error);
4688f82136aSPatrick Kelsey 		}
469e3c97c2cSBryan Venteicher 	}
470e3c97c2cSBryan Venteicher 
4718f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++) {
4728f82136aSPatrick Kelsey 		snprintf(irq_name, sizeof(irq_name), "txq%d", i);
4738f82136aSPatrick Kelsey 
4748f82136aSPatrick Kelsey 		/*
4758f82136aSPatrick Kelsey 		 * Don't provide the corresponding rxq irq for reference -
4768f82136aSPatrick Kelsey 		 * we want the transmit task to be attached to a task queue
4778f82136aSPatrick Kelsey 		 * that is different from the one used by the corresponding
4788f82136aSPatrick Kelsey 		 * rxq irq.  That is because the TX doorbell writes are very
4798f82136aSPatrick Kelsey 		 * expensive as virtualized MMIO operations, so we want to
4808f82136aSPatrick Kelsey 		 * be able to defer them to another core when possible so
4818f82136aSPatrick Kelsey 		 * that they don't steal receive processing cycles during
4828f82136aSPatrick Kelsey 		 * stack turnarounds like TCP ACK generation.  The other
4838f82136aSPatrick Kelsey 		 * piece to this approach is enabling the iflib abdicate
4848f82136aSPatrick Kelsey 		 * option (currently via an interface-specific
4858f82136aSPatrick Kelsey 		 * tunable/sysctl).
4868f82136aSPatrick Kelsey 		 */
4878f82136aSPatrick Kelsey 		iflib_softirq_alloc_generic(ctx, NULL, IFLIB_INTR_TX, NULL, i,
4888f82136aSPatrick Kelsey 		    irq_name);
489e3c97c2cSBryan Venteicher 	}
490e3c97c2cSBryan Venteicher 
4918f82136aSPatrick Kelsey 	error = iflib_irq_alloc_generic(ctx, &sc->vmx_event_intr_irq,
4928f82136aSPatrick Kelsey 	    scctx->isc_nrxqsets + 1, IFLIB_INTR_ADMIN, vmxnet3_event_intr, sc, 0,
4938f82136aSPatrick Kelsey 	    "event");
4948f82136aSPatrick Kelsey 	if (error) {
4958f82136aSPatrick Kelsey 		device_printf(iflib_get_dev(ctx),
4968f82136aSPatrick Kelsey 		    "Failed to register event interrupt handler\n");
4978f82136aSPatrick Kelsey 		return (error);
498e3c97c2cSBryan Venteicher 	}
499e3c97c2cSBryan Venteicher 
5008f82136aSPatrick Kelsey 	return (0);
5018f82136aSPatrick Kelsey }
502e3c97c2cSBryan Venteicher 
5038f82136aSPatrick Kelsey static void
5048f82136aSPatrick Kelsey vmxnet3_free_irqs(struct vmxnet3_softc *sc)
5058f82136aSPatrick Kelsey {
5068f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
5078f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
5088f82136aSPatrick Kelsey 	int i;
5098f82136aSPatrick Kelsey 
5108f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
5118f82136aSPatrick Kelsey 
5128f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
5138f82136aSPatrick Kelsey 		rxq = &sc->vmx_rxq[i];
5148f82136aSPatrick Kelsey 		iflib_irq_free(sc->vmx_ctx, &rxq->vxrxq_irq);
5158f82136aSPatrick Kelsey 	}
5168f82136aSPatrick Kelsey 
5178f82136aSPatrick Kelsey 	iflib_irq_free(sc->vmx_ctx, &sc->vmx_event_intr_irq);
5188f82136aSPatrick Kelsey }
5198f82136aSPatrick Kelsey 
5208f82136aSPatrick Kelsey static int
5218f82136aSPatrick Kelsey vmxnet3_attach_post(if_ctx_t ctx)
5228f82136aSPatrick Kelsey {
5238f82136aSPatrick Kelsey 	device_t dev;
5248f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
5258f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
5268f82136aSPatrick Kelsey 	int error;
5278f82136aSPatrick Kelsey 
5288f82136aSPatrick Kelsey 	dev = iflib_get_dev(ctx);
5298f82136aSPatrick Kelsey 	scctx = iflib_get_softc_ctx(ctx);
5308f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
5318f82136aSPatrick Kelsey 
5328f82136aSPatrick Kelsey 	if (scctx->isc_nrxqsets > 1)
5338f82136aSPatrick Kelsey 		sc->vmx_flags |= VMXNET3_FLAG_RSS;
5348f82136aSPatrick Kelsey 
5358f82136aSPatrick Kelsey 	error = vmxnet3_alloc_data(sc);
5368f82136aSPatrick Kelsey 	if (error)
5378f82136aSPatrick Kelsey 		goto fail;
5388f82136aSPatrick Kelsey 
5398f82136aSPatrick Kelsey 	vmxnet3_set_interrupt_idx(sc);
5408f82136aSPatrick Kelsey 	vmxnet3_setup_sysctl(sc);
5418f82136aSPatrick Kelsey 
5428f82136aSPatrick Kelsey 	ifmedia_add(sc->vmx_media, IFM_ETHER | IFM_AUTO, 0, NULL);
5438f82136aSPatrick Kelsey 	ifmedia_set(sc->vmx_media, IFM_ETHER | IFM_AUTO);
5448f82136aSPatrick Kelsey 
5458f82136aSPatrick Kelsey fail:
5468f82136aSPatrick Kelsey 	return (error);
5478f82136aSPatrick Kelsey }
5488f82136aSPatrick Kelsey 
5498f82136aSPatrick Kelsey static int
5508f82136aSPatrick Kelsey vmxnet3_detach(if_ctx_t ctx)
5518f82136aSPatrick Kelsey {
5528f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
5538f82136aSPatrick Kelsey 
5548f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
5558f82136aSPatrick Kelsey 
5568f82136aSPatrick Kelsey 	vmxnet3_free_irqs(sc);
557e3c97c2cSBryan Venteicher 	vmxnet3_free_data(sc);
558e3c97c2cSBryan Venteicher 	vmxnet3_free_resources(sc);
559e3c97c2cSBryan Venteicher 
560e3c97c2cSBryan Venteicher 	return (0);
561e3c97c2cSBryan Venteicher }
562e3c97c2cSBryan Venteicher 
563e3c97c2cSBryan Venteicher static int
5648f82136aSPatrick Kelsey vmxnet3_shutdown(if_ctx_t ctx)
5658f82136aSPatrick Kelsey {
5668f82136aSPatrick Kelsey 
5678f82136aSPatrick Kelsey 	return (0);
5688f82136aSPatrick Kelsey }
5698f82136aSPatrick Kelsey 
5708f82136aSPatrick Kelsey static int
5718f82136aSPatrick Kelsey vmxnet3_suspend(if_ctx_t ctx)
5728f82136aSPatrick Kelsey {
5738f82136aSPatrick Kelsey 
5748f82136aSPatrick Kelsey 	return (0);
5758f82136aSPatrick Kelsey }
5768f82136aSPatrick Kelsey 
5778f82136aSPatrick Kelsey static int
5788f82136aSPatrick Kelsey vmxnet3_resume(if_ctx_t ctx)
579e3c97c2cSBryan Venteicher {
580e3c97c2cSBryan Venteicher 
581e3c97c2cSBryan Venteicher 	return (0);
582e3c97c2cSBryan Venteicher }
583e3c97c2cSBryan Venteicher 
584e3c97c2cSBryan Venteicher static int
585e3c97c2cSBryan Venteicher vmxnet3_alloc_resources(struct vmxnet3_softc *sc)
586e3c97c2cSBryan Venteicher {
587e3c97c2cSBryan Venteicher 	device_t dev;
588e3c97c2cSBryan Venteicher 	int rid;
589e3c97c2cSBryan Venteicher 
590e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
591e3c97c2cSBryan Venteicher 
592e3c97c2cSBryan Venteicher 	rid = PCIR_BAR(0);
593e3c97c2cSBryan Venteicher 	sc->vmx_res0 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
594e3c97c2cSBryan Venteicher 	    RF_ACTIVE);
595e3c97c2cSBryan Venteicher 	if (sc->vmx_res0 == NULL) {
596e3c97c2cSBryan Venteicher 		device_printf(dev,
597e3c97c2cSBryan Venteicher 		    "could not map BAR0 memory\n");
598e3c97c2cSBryan Venteicher 		return (ENXIO);
599e3c97c2cSBryan Venteicher 	}
600e3c97c2cSBryan Venteicher 
601e3c97c2cSBryan Venteicher 	sc->vmx_iot0 = rman_get_bustag(sc->vmx_res0);
602e3c97c2cSBryan Venteicher 	sc->vmx_ioh0 = rman_get_bushandle(sc->vmx_res0);
603e3c97c2cSBryan Venteicher 
604e3c97c2cSBryan Venteicher 	rid = PCIR_BAR(1);
605e3c97c2cSBryan Venteicher 	sc->vmx_res1 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
606e3c97c2cSBryan Venteicher 	    RF_ACTIVE);
607e3c97c2cSBryan Venteicher 	if (sc->vmx_res1 == NULL) {
608e3c97c2cSBryan Venteicher 		device_printf(dev,
609e3c97c2cSBryan Venteicher 		    "could not map BAR1 memory\n");
610e3c97c2cSBryan Venteicher 		return (ENXIO);
611e3c97c2cSBryan Venteicher 	}
612e3c97c2cSBryan Venteicher 
613e3c97c2cSBryan Venteicher 	sc->vmx_iot1 = rman_get_bustag(sc->vmx_res1);
614e3c97c2cSBryan Venteicher 	sc->vmx_ioh1 = rman_get_bushandle(sc->vmx_res1);
615e3c97c2cSBryan Venteicher 
616e3c97c2cSBryan Venteicher 	return (0);
617e3c97c2cSBryan Venteicher }
618e3c97c2cSBryan Venteicher 
619e3c97c2cSBryan Venteicher static void
620e3c97c2cSBryan Venteicher vmxnet3_free_resources(struct vmxnet3_softc *sc)
621e3c97c2cSBryan Venteicher {
622e3c97c2cSBryan Venteicher 	device_t dev;
623e3c97c2cSBryan Venteicher 
624e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
625e3c97c2cSBryan Venteicher 
626e3c97c2cSBryan Venteicher 	if (sc->vmx_res0 != NULL) {
627b97de13aSMarius Strobl 		bus_release_resource(dev, SYS_RES_MEMORY,
628b97de13aSMarius Strobl 		    rman_get_rid(sc->vmx_res0), sc->vmx_res0);
629e3c97c2cSBryan Venteicher 		sc->vmx_res0 = NULL;
630e3c97c2cSBryan Venteicher 	}
631e3c97c2cSBryan Venteicher 
632e3c97c2cSBryan Venteicher 	if (sc->vmx_res1 != NULL) {
633b97de13aSMarius Strobl 		bus_release_resource(dev, SYS_RES_MEMORY,
634b97de13aSMarius Strobl 		    rman_get_rid(sc->vmx_res1), sc->vmx_res1);
635e3c97c2cSBryan Venteicher 		sc->vmx_res1 = NULL;
636e3c97c2cSBryan Venteicher 	}
637e3c97c2cSBryan Venteicher }
638e3c97c2cSBryan Venteicher 
639e3c97c2cSBryan Venteicher static int
640e3c97c2cSBryan Venteicher vmxnet3_check_version(struct vmxnet3_softc *sc)
641e3c97c2cSBryan Venteicher {
642e3c97c2cSBryan Venteicher 	device_t dev;
643e3c97c2cSBryan Venteicher 	uint32_t version;
644e3c97c2cSBryan Venteicher 
645e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
646e3c97c2cSBryan Venteicher 
647e3c97c2cSBryan Venteicher 	version = vmxnet3_read_bar1(sc, VMXNET3_BAR1_VRRS);
648e3c97c2cSBryan Venteicher 	if ((version & 0x01) == 0) {
649e3c97c2cSBryan Venteicher 		device_printf(dev, "unsupported hardware version %#x\n",
650e3c97c2cSBryan Venteicher 		    version);
651e3c97c2cSBryan Venteicher 		return (ENOTSUP);
6523c965775SBryan Venteicher 	}
653e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_VRRS, 1);
654e3c97c2cSBryan Venteicher 
655e3c97c2cSBryan Venteicher 	version = vmxnet3_read_bar1(sc, VMXNET3_BAR1_UVRS);
656e3c97c2cSBryan Venteicher 	if ((version & 0x01) == 0) {
657e3c97c2cSBryan Venteicher 		device_printf(dev, "unsupported UPT version %#x\n", version);
658e3c97c2cSBryan Venteicher 		return (ENOTSUP);
6593c965775SBryan Venteicher 	}
660e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_UVRS, 1);
661e3c97c2cSBryan Venteicher 
662e3c97c2cSBryan Venteicher 	return (0);
663e3c97c2cSBryan Venteicher }
664e3c97c2cSBryan Venteicher 
665e3c97c2cSBryan Venteicher static void
666e3c97c2cSBryan Venteicher vmxnet3_set_interrupt_idx(struct vmxnet3_softc *sc)
667e3c97c2cSBryan Venteicher {
6688f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
669e3c97c2cSBryan Venteicher 	struct vmxnet3_txqueue *txq;
670e3c97c2cSBryan Venteicher 	struct vmxnet3_txq_shared *txs;
671e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
672e3c97c2cSBryan Venteicher 	struct vmxnet3_rxq_shared *rxs;
6738f82136aSPatrick Kelsey 	int intr_idx;
674e3c97c2cSBryan Venteicher 	int i;
675e3c97c2cSBryan Venteicher 
6768f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
677e3c97c2cSBryan Venteicher 
6788f82136aSPatrick Kelsey 	/*
679769d56ecSPatrick Kelsey 	 * There is always one interrupt per receive queue, assigned
680769d56ecSPatrick Kelsey 	 * starting with the first interrupt.  When there is only one
681769d56ecSPatrick Kelsey 	 * interrupt available, the event interrupt shares the receive queue
682769d56ecSPatrick Kelsey 	 * interrupt, otherwise it uses the interrupt following the last
683769d56ecSPatrick Kelsey 	 * receive queue interrupt.  Transmit queues are not assigned
684769d56ecSPatrick Kelsey 	 * interrupts, so they are given indexes beyond the indexes that
685769d56ecSPatrick Kelsey 	 * correspond to the real interrupts.
6868f82136aSPatrick Kelsey 	 */
687769d56ecSPatrick Kelsey 
688769d56ecSPatrick Kelsey 	/* The event interrupt is always the last vector. */
6898f82136aSPatrick Kelsey 	sc->vmx_event_intr_idx = scctx->isc_vectors - 1;
690e3c97c2cSBryan Venteicher 
6918f82136aSPatrick Kelsey 	intr_idx = 0;
6928f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++, intr_idx++) {
693e3c97c2cSBryan Venteicher 		rxq = &sc->vmx_rxq[i];
694e3c97c2cSBryan Venteicher 		rxs = rxq->vxrxq_rs;
6958f82136aSPatrick Kelsey 		rxq->vxrxq_intr_idx = intr_idx;
696e3c97c2cSBryan Venteicher 		rxs->intr_idx = rxq->vxrxq_intr_idx;
697e3c97c2cSBryan Venteicher 	}
6988f82136aSPatrick Kelsey 
6998f82136aSPatrick Kelsey 	/*
7008f82136aSPatrick Kelsey 	 * Assign the tx queues interrupt indexes above what we are actually
7018f82136aSPatrick Kelsey 	 * using.  These interrupts will never be enabled.
7028f82136aSPatrick Kelsey 	 */
7038f82136aSPatrick Kelsey 	intr_idx = scctx->isc_vectors;
7048f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++, intr_idx++) {
7058f82136aSPatrick Kelsey 		txq = &sc->vmx_txq[i];
7068f82136aSPatrick Kelsey 		txs = txq->vxtxq_ts;
7078f82136aSPatrick Kelsey 		txq->vxtxq_intr_idx = intr_idx;
7088f82136aSPatrick Kelsey 		txs->intr_idx = txq->vxtxq_intr_idx;
7098f82136aSPatrick Kelsey 	}
710e3c97c2cSBryan Venteicher }
711e3c97c2cSBryan Venteicher 
712e3c97c2cSBryan Venteicher static int
7138f82136aSPatrick Kelsey vmxnet3_queues_shared_alloc(struct vmxnet3_softc *sc)
714e3c97c2cSBryan Venteicher {
7158f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
7168f82136aSPatrick Kelsey 	int size;
717e3c97c2cSBryan Venteicher 	int error;
718e3c97c2cSBryan Venteicher 
7198f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
720e3c97c2cSBryan Venteicher 
7218f82136aSPatrick Kelsey 	/*
7228f82136aSPatrick Kelsey 	 * The txq and rxq shared data areas must be allocated contiguously
7238f82136aSPatrick Kelsey 	 * as vmxnet3_driver_shared contains only a single address member
7248f82136aSPatrick Kelsey 	 * for the shared queue data area.
7258f82136aSPatrick Kelsey 	 */
7268f82136aSPatrick Kelsey 	size = scctx->isc_ntxqsets * sizeof(struct vmxnet3_txq_shared) +
7278f82136aSPatrick Kelsey 	    scctx->isc_nrxqsets * sizeof(struct vmxnet3_rxq_shared);
7288f82136aSPatrick Kelsey 	error = iflib_dma_alloc_align(sc->vmx_ctx, size, 128, &sc->vmx_qs_dma, 0);
7298f82136aSPatrick Kelsey 	if (error) {
7308f82136aSPatrick Kelsey 		device_printf(sc->vmx_dev, "cannot alloc queue shared memory\n");
731e3c97c2cSBryan Venteicher 		return (error);
732e3c97c2cSBryan Venteicher 	}
733e3c97c2cSBryan Venteicher 
734e557c1ddSBryan Venteicher 	return (0);
735e557c1ddSBryan Venteicher }
736e557c1ddSBryan Venteicher 
737e557c1ddSBryan Venteicher static void
7388f82136aSPatrick Kelsey vmxnet3_init_txq(struct vmxnet3_softc *sc, int q)
739e557c1ddSBryan Venteicher {
740e557c1ddSBryan Venteicher 	struct vmxnet3_txqueue *txq;
7418f82136aSPatrick Kelsey 	struct vmxnet3_comp_ring *txc;
7428f82136aSPatrick Kelsey 	struct vmxnet3_txring *txr;
7438f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
744e557c1ddSBryan Venteicher 
7458f82136aSPatrick Kelsey 	txq = &sc->vmx_txq[q];
7468f82136aSPatrick Kelsey 	txc = &txq->vxtxq_comp_ring;
7478f82136aSPatrick Kelsey 	txr = &txq->vxtxq_cmd_ring;
7488f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
7498f82136aSPatrick Kelsey 
7508f82136aSPatrick Kelsey 	snprintf(txq->vxtxq_name, sizeof(txq->vxtxq_name), "%s-tx%d",
7518f82136aSPatrick Kelsey 	    device_get_nameunit(sc->vmx_dev), q);
7528f82136aSPatrick Kelsey 
7538f82136aSPatrick Kelsey 	txq->vxtxq_sc = sc;
7548f82136aSPatrick Kelsey 	txq->vxtxq_id = q;
7558f82136aSPatrick Kelsey 	txc->vxcr_ndesc = scctx->isc_ntxd[0];
7568f82136aSPatrick Kelsey 	txr->vxtxr_ndesc = scctx->isc_ntxd[1];
757e557c1ddSBryan Venteicher }
7588f82136aSPatrick Kelsey 
7598f82136aSPatrick Kelsey static int
7608f82136aSPatrick Kelsey vmxnet3_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
7618f82136aSPatrick Kelsey     int ntxqs, int ntxqsets)
7628f82136aSPatrick Kelsey {
7638f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
7648f82136aSPatrick Kelsey 	int q;
7658f82136aSPatrick Kelsey 	int error;
7668f82136aSPatrick Kelsey 	caddr_t kva;
7678f82136aSPatrick Kelsey 
7688f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
7698f82136aSPatrick Kelsey 
7708f82136aSPatrick Kelsey 	/* Allocate the array of transmit queues */
7718f82136aSPatrick Kelsey 	sc->vmx_txq = malloc(sizeof(struct vmxnet3_txqueue) *
7728f82136aSPatrick Kelsey 	    ntxqsets, M_DEVBUF, M_NOWAIT | M_ZERO);
7738f82136aSPatrick Kelsey 	if (sc->vmx_txq == NULL)
7748f82136aSPatrick Kelsey 		return (ENOMEM);
7758f82136aSPatrick Kelsey 
7768f82136aSPatrick Kelsey 	/* Initialize driver state for each transmit queue */
7778f82136aSPatrick Kelsey 	for (q = 0; q < ntxqsets; q++)
7788f82136aSPatrick Kelsey 		vmxnet3_init_txq(sc, q);
7798f82136aSPatrick Kelsey 
7808f82136aSPatrick Kelsey 	/*
7818f82136aSPatrick Kelsey 	 * Allocate queue state that is shared with the device.  This check
7828f82136aSPatrick Kelsey 	 * and call is performed in both vmxnet3_tx_queues_alloc() and
7838f82136aSPatrick Kelsey 	 * vmxnet3_rx_queues_alloc() so that we don't have to care which
7848f82136aSPatrick Kelsey 	 * order iflib invokes those routines in.
7858f82136aSPatrick Kelsey 	 */
7868f82136aSPatrick Kelsey 	if (sc->vmx_qs_dma.idi_size == 0) {
7878f82136aSPatrick Kelsey 		error = vmxnet3_queues_shared_alloc(sc);
7888f82136aSPatrick Kelsey 		if (error)
7898f82136aSPatrick Kelsey 			return (error);
790e557c1ddSBryan Venteicher 	}
7918f82136aSPatrick Kelsey 
7928f82136aSPatrick Kelsey 	kva = sc->vmx_qs_dma.idi_vaddr;
7938f82136aSPatrick Kelsey 	for (q = 0; q < ntxqsets; q++) {
7948f82136aSPatrick Kelsey 		sc->vmx_txq[q].vxtxq_ts = (struct vmxnet3_txq_shared *) kva;
7958f82136aSPatrick Kelsey 		kva += sizeof(struct vmxnet3_txq_shared);
7968f82136aSPatrick Kelsey 	}
7978f82136aSPatrick Kelsey 
7988f82136aSPatrick Kelsey 	/* Record descriptor ring vaddrs and paddrs */
7998f82136aSPatrick Kelsey 	for (q = 0; q < ntxqsets; q++) {
8008f82136aSPatrick Kelsey 		struct vmxnet3_txqueue *txq;
8018f82136aSPatrick Kelsey 		struct vmxnet3_txring *txr;
8028f82136aSPatrick Kelsey 		struct vmxnet3_comp_ring *txc;
8038f82136aSPatrick Kelsey 
8048f82136aSPatrick Kelsey 		txq = &sc->vmx_txq[q];
8058f82136aSPatrick Kelsey 		txc = &txq->vxtxq_comp_ring;
8068f82136aSPatrick Kelsey 		txr = &txq->vxtxq_cmd_ring;
8078f82136aSPatrick Kelsey 
8088f82136aSPatrick Kelsey 		/* Completion ring */
8098f82136aSPatrick Kelsey 		txc->vxcr_u.txcd =
8108f82136aSPatrick Kelsey 		    (struct vmxnet3_txcompdesc *) vaddrs[q * ntxqs + 0];
8118f82136aSPatrick Kelsey 		txc->vxcr_paddr = paddrs[q * ntxqs + 0];
8128f82136aSPatrick Kelsey 
8138f82136aSPatrick Kelsey 		/* Command ring */
8148f82136aSPatrick Kelsey 		txr->vxtxr_txd =
8158f82136aSPatrick Kelsey 		    (struct vmxnet3_txdesc *) vaddrs[q * ntxqs + 1];
8168f82136aSPatrick Kelsey 		txr->vxtxr_paddr = paddrs[q * ntxqs + 1];
8178f82136aSPatrick Kelsey 	}
8188f82136aSPatrick Kelsey 
8198f82136aSPatrick Kelsey 	return (0);
820e557c1ddSBryan Venteicher }
821e557c1ddSBryan Venteicher 
822e557c1ddSBryan Venteicher static void
8238f82136aSPatrick Kelsey vmxnet3_init_rxq(struct vmxnet3_softc *sc, int q, int nrxqs)
824e3c97c2cSBryan Venteicher {
825e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
8268f82136aSPatrick Kelsey 	struct vmxnet3_comp_ring *rxc;
827e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
8288f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
829e3c97c2cSBryan Venteicher 	int i;
830e3c97c2cSBryan Venteicher 
831e3c97c2cSBryan Venteicher 	rxq = &sc->vmx_rxq[q];
8328f82136aSPatrick Kelsey 	rxc = &rxq->vxrxq_comp_ring;
8338f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
834e3c97c2cSBryan Venteicher 
835e3c97c2cSBryan Venteicher 	snprintf(rxq->vxrxq_name, sizeof(rxq->vxrxq_name), "%s-rx%d",
836e3c97c2cSBryan Venteicher 	    device_get_nameunit(sc->vmx_dev), q);
837e3c97c2cSBryan Venteicher 
838e3c97c2cSBryan Venteicher 	rxq->vxrxq_sc = sc;
839e3c97c2cSBryan Venteicher 	rxq->vxrxq_id = q;
840e3c97c2cSBryan Venteicher 
8418f82136aSPatrick Kelsey 	/*
8428f82136aSPatrick Kelsey 	 * First rxq is the completion queue, so there are nrxqs - 1 command
8438f82136aSPatrick Kelsey 	 * rings starting at iflib queue id 1.
8448f82136aSPatrick Kelsey 	 */
8458f82136aSPatrick Kelsey 	rxc->vxcr_ndesc = scctx->isc_nrxd[0];
8468f82136aSPatrick Kelsey 	for (i = 0; i < nrxqs - 1; i++) {
847e3c97c2cSBryan Venteicher 		rxr = &rxq->vxrxq_cmd_ring[i];
8488f82136aSPatrick Kelsey 		rxr->vxrxr_ndesc = scctx->isc_nrxd[i + 1];
8493c965775SBryan Venteicher 	}
850e3c97c2cSBryan Venteicher }
851e3c97c2cSBryan Venteicher 
852e3c97c2cSBryan Venteicher static int
8538f82136aSPatrick Kelsey vmxnet3_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
8548f82136aSPatrick Kelsey     int nrxqs, int nrxqsets)
855e3c97c2cSBryan Venteicher {
8568f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
8578f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
8588f82136aSPatrick Kelsey 	int q;
8598f82136aSPatrick Kelsey 	int i;
8608f82136aSPatrick Kelsey 	int error;
8618f82136aSPatrick Kelsey 	caddr_t kva;
862e3c97c2cSBryan Venteicher 
8638f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
8648f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
865e3c97c2cSBryan Venteicher 
8668f82136aSPatrick Kelsey 	/* Allocate the array of receive queues */
8678f82136aSPatrick Kelsey 	sc->vmx_rxq = malloc(sizeof(struct vmxnet3_rxqueue) *
8688f82136aSPatrick Kelsey 	    nrxqsets, M_DEVBUF, M_NOWAIT | M_ZERO);
8698f82136aSPatrick Kelsey 	if (sc->vmx_rxq == NULL)
870e3c97c2cSBryan Venteicher 		return (ENOMEM);
871e3c97c2cSBryan Venteicher 
8728f82136aSPatrick Kelsey 	/* Initialize driver state for each receive queue */
8738f82136aSPatrick Kelsey 	for (q = 0; q < nrxqsets; q++)
8748f82136aSPatrick Kelsey 		vmxnet3_init_rxq(sc, q, nrxqs);
875e3c97c2cSBryan Venteicher 
876e557c1ddSBryan Venteicher 	/*
8778f82136aSPatrick Kelsey 	 * Allocate queue state that is shared with the device.  This check
8788f82136aSPatrick Kelsey 	 * and call is performed in both vmxnet3_tx_queues_alloc() and
8798f82136aSPatrick Kelsey 	 * vmxnet3_rx_queues_alloc() so that we don't have to care which
8808f82136aSPatrick Kelsey 	 * order iflib invokes those routines in.
881e557c1ddSBryan Venteicher 	 */
8828f82136aSPatrick Kelsey 	if (sc->vmx_qs_dma.idi_size == 0) {
8838f82136aSPatrick Kelsey 		error = vmxnet3_queues_shared_alloc(sc);
884e3c97c2cSBryan Venteicher 		if (error)
885e3c97c2cSBryan Venteicher 			return (error);
886e3c97c2cSBryan Venteicher 	}
887e3c97c2cSBryan Venteicher 
8888f82136aSPatrick Kelsey 	kva = sc->vmx_qs_dma.idi_vaddr +
8898f82136aSPatrick Kelsey 	    scctx->isc_ntxqsets * sizeof(struct vmxnet3_txq_shared);
8908f82136aSPatrick Kelsey 	for (q = 0; q < nrxqsets; q++) {
8918f82136aSPatrick Kelsey 		sc->vmx_rxq[q].vxrxq_rs = (struct vmxnet3_rxq_shared *) kva;
8928f82136aSPatrick Kelsey 		kva += sizeof(struct vmxnet3_rxq_shared);
8938f82136aSPatrick Kelsey 	}
8948f82136aSPatrick Kelsey 
8958f82136aSPatrick Kelsey 	/* Record descriptor ring vaddrs and paddrs */
8968f82136aSPatrick Kelsey 	for (q = 0; q < nrxqsets; q++) {
8978f82136aSPatrick Kelsey 		struct vmxnet3_rxqueue *rxq;
8988f82136aSPatrick Kelsey 		struct vmxnet3_rxring *rxr;
8998f82136aSPatrick Kelsey 		struct vmxnet3_comp_ring *rxc;
9008f82136aSPatrick Kelsey 
9018f82136aSPatrick Kelsey 		rxq = &sc->vmx_rxq[q];
9028f82136aSPatrick Kelsey 		rxc = &rxq->vxrxq_comp_ring;
9038f82136aSPatrick Kelsey 
9048f82136aSPatrick Kelsey 		/* Completion ring */
9058f82136aSPatrick Kelsey 		rxc->vxcr_u.rxcd =
9068f82136aSPatrick Kelsey 		    (struct vmxnet3_rxcompdesc *) vaddrs[q * nrxqs + 0];
9078f82136aSPatrick Kelsey 		rxc->vxcr_paddr = paddrs[q * nrxqs + 0];
9088f82136aSPatrick Kelsey 
9098f82136aSPatrick Kelsey 		/* Command ring(s) */
9108f82136aSPatrick Kelsey 		for (i = 0; i < nrxqs - 1; i++) {
9118f82136aSPatrick Kelsey 			rxr = &rxq->vxrxq_cmd_ring[i];
9128f82136aSPatrick Kelsey 
9138f82136aSPatrick Kelsey 			rxr->vxrxr_rxd =
9148f82136aSPatrick Kelsey 			    (struct vmxnet3_rxdesc *) vaddrs[q * nrxqs + 1 + i];
9158f82136aSPatrick Kelsey 			rxr->vxrxr_paddr = paddrs[q * nrxqs + 1 + i];
9168f82136aSPatrick Kelsey 		}
917e3c97c2cSBryan Venteicher 	}
918e3c97c2cSBryan Venteicher 
919e3c97c2cSBryan Venteicher 	return (0);
920e3c97c2cSBryan Venteicher }
921e3c97c2cSBryan Venteicher 
922e3c97c2cSBryan Venteicher static void
9238f82136aSPatrick Kelsey vmxnet3_queues_free(if_ctx_t ctx)
924e3c97c2cSBryan Venteicher {
9258f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
926e3c97c2cSBryan Venteicher 
9278f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
928e3c97c2cSBryan Venteicher 
9298f82136aSPatrick Kelsey 	/* Free queue state area that is shared with the device */
9308f82136aSPatrick Kelsey 	if (sc->vmx_qs_dma.idi_size != 0) {
9318f82136aSPatrick Kelsey 		iflib_dma_free(&sc->vmx_qs_dma);
9328f82136aSPatrick Kelsey 		sc->vmx_qs_dma.idi_size = 0;
933e3c97c2cSBryan Venteicher 	}
934e3c97c2cSBryan Venteicher 
9358f82136aSPatrick Kelsey 	/* Free array of receive queues */
936e3c97c2cSBryan Venteicher 	if (sc->vmx_rxq != NULL) {
937e3c97c2cSBryan Venteicher 		free(sc->vmx_rxq, M_DEVBUF);
938e3c97c2cSBryan Venteicher 		sc->vmx_rxq = NULL;
939e3c97c2cSBryan Venteicher 	}
940e3c97c2cSBryan Venteicher 
9418f82136aSPatrick Kelsey 	/* Free array of transmit queues */
942e3c97c2cSBryan Venteicher 	if (sc->vmx_txq != NULL) {
943e3c97c2cSBryan Venteicher 		free(sc->vmx_txq, M_DEVBUF);
944e3c97c2cSBryan Venteicher 		sc->vmx_txq = NULL;
945e3c97c2cSBryan Venteicher 	}
946e3c97c2cSBryan Venteicher }
947e3c97c2cSBryan Venteicher 
948e3c97c2cSBryan Venteicher static int
949e3c97c2cSBryan Venteicher vmxnet3_alloc_shared_data(struct vmxnet3_softc *sc)
950e3c97c2cSBryan Venteicher {
951e3c97c2cSBryan Venteicher 	device_t dev;
952e3c97c2cSBryan Venteicher 	size_t size;
9538f82136aSPatrick Kelsey 	int error;
954e3c97c2cSBryan Venteicher 
955e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
956e3c97c2cSBryan Venteicher 
9578f82136aSPatrick Kelsey 	/* Top level state structure shared with the device */
958e3c97c2cSBryan Venteicher 	size = sizeof(struct vmxnet3_driver_shared);
9598f82136aSPatrick Kelsey 	error = iflib_dma_alloc_align(sc->vmx_ctx, size, 1, &sc->vmx_ds_dma, 0);
960e3c97c2cSBryan Venteicher 	if (error) {
961e3c97c2cSBryan Venteicher 		device_printf(dev, "cannot alloc shared memory\n");
962e3c97c2cSBryan Venteicher 		return (error);
963e3c97c2cSBryan Venteicher 	}
9648f82136aSPatrick Kelsey 	sc->vmx_ds = (struct vmxnet3_driver_shared *) sc->vmx_ds_dma.idi_vaddr;
965e3c97c2cSBryan Venteicher 
9668f82136aSPatrick Kelsey 	/* RSS table state shared with the device */
967e557c1ddSBryan Venteicher 	if (sc->vmx_flags & VMXNET3_FLAG_RSS) {
968e557c1ddSBryan Venteicher 		size = sizeof(struct vmxnet3_rss_shared);
9698f82136aSPatrick Kelsey 		error = iflib_dma_alloc_align(sc->vmx_ctx, size, 128,
9708f82136aSPatrick Kelsey 		    &sc->vmx_rss_dma, 0);
971e557c1ddSBryan Venteicher 		if (error) {
972e557c1ddSBryan Venteicher 			device_printf(dev, "cannot alloc rss shared memory\n");
973e557c1ddSBryan Venteicher 			return (error);
974e557c1ddSBryan Venteicher 		}
975e557c1ddSBryan Venteicher 		sc->vmx_rss =
9768f82136aSPatrick Kelsey 		    (struct vmxnet3_rss_shared *) sc->vmx_rss_dma.idi_vaddr;
977e557c1ddSBryan Venteicher 	}
978e557c1ddSBryan Venteicher 
979e3c97c2cSBryan Venteicher 	return (0);
980e3c97c2cSBryan Venteicher }
981e3c97c2cSBryan Venteicher 
982e3c97c2cSBryan Venteicher static void
983e3c97c2cSBryan Venteicher vmxnet3_free_shared_data(struct vmxnet3_softc *sc)
984e3c97c2cSBryan Venteicher {
985e3c97c2cSBryan Venteicher 
9868f82136aSPatrick Kelsey 	/* Free RSS table state shared with the device */
987e557c1ddSBryan Venteicher 	if (sc->vmx_rss != NULL) {
9888f82136aSPatrick Kelsey 		iflib_dma_free(&sc->vmx_rss_dma);
989e557c1ddSBryan Venteicher 		sc->vmx_rss = NULL;
990e557c1ddSBryan Venteicher 	}
991e557c1ddSBryan Venteicher 
9928f82136aSPatrick Kelsey 	/* Free top level state structure shared with the device */
993e3c97c2cSBryan Venteicher 	if (sc->vmx_ds != NULL) {
9948f82136aSPatrick Kelsey 		iflib_dma_free(&sc->vmx_ds_dma);
995e3c97c2cSBryan Venteicher 		sc->vmx_ds = NULL;
996e3c97c2cSBryan Venteicher 	}
997e3c97c2cSBryan Venteicher }
998e3c97c2cSBryan Venteicher 
999e3c97c2cSBryan Venteicher static int
1000e3c97c2cSBryan Venteicher vmxnet3_alloc_mcast_table(struct vmxnet3_softc *sc)
1001e3c97c2cSBryan Venteicher {
1002e3c97c2cSBryan Venteicher 	int error;
1003e3c97c2cSBryan Venteicher 
10048f82136aSPatrick Kelsey 	/* Multicast table state shared with the device */
10058f82136aSPatrick Kelsey 	error = iflib_dma_alloc_align(sc->vmx_ctx,
10068f82136aSPatrick Kelsey 	    VMXNET3_MULTICAST_MAX * ETHER_ADDR_LEN, 32, &sc->vmx_mcast_dma, 0);
1007e3c97c2cSBryan Venteicher 	if (error)
1008e3c97c2cSBryan Venteicher 		device_printf(sc->vmx_dev, "unable to alloc multicast table\n");
1009e3c97c2cSBryan Venteicher 	else
10108f82136aSPatrick Kelsey 		sc->vmx_mcast = sc->vmx_mcast_dma.idi_vaddr;
1011e3c97c2cSBryan Venteicher 
1012e3c97c2cSBryan Venteicher 	return (error);
1013e3c97c2cSBryan Venteicher }
1014e3c97c2cSBryan Venteicher 
1015e3c97c2cSBryan Venteicher static void
1016e3c97c2cSBryan Venteicher vmxnet3_free_mcast_table(struct vmxnet3_softc *sc)
1017e3c97c2cSBryan Venteicher {
1018e3c97c2cSBryan Venteicher 
10198f82136aSPatrick Kelsey 	/* Free multicast table state shared with the device */
1020e3c97c2cSBryan Venteicher 	if (sc->vmx_mcast != NULL) {
10218f82136aSPatrick Kelsey 		iflib_dma_free(&sc->vmx_mcast_dma);
1022e3c97c2cSBryan Venteicher 		sc->vmx_mcast = NULL;
1023e3c97c2cSBryan Venteicher 	}
1024e3c97c2cSBryan Venteicher }
1025e3c97c2cSBryan Venteicher 
1026e3c97c2cSBryan Venteicher static void
1027e3c97c2cSBryan Venteicher vmxnet3_init_shared_data(struct vmxnet3_softc *sc)
1028e3c97c2cSBryan Venteicher {
1029e3c97c2cSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
10308f82136aSPatrick Kelsey 	if_shared_ctx_t sctx;
10318f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
1032e3c97c2cSBryan Venteicher 	struct vmxnet3_txqueue *txq;
1033e3c97c2cSBryan Venteicher 	struct vmxnet3_txq_shared *txs;
1034e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
1035e3c97c2cSBryan Venteicher 	struct vmxnet3_rxq_shared *rxs;
1036e3c97c2cSBryan Venteicher 	int i;
1037e3c97c2cSBryan Venteicher 
1038e3c97c2cSBryan Venteicher 	ds = sc->vmx_ds;
10398f82136aSPatrick Kelsey 	sctx = sc->vmx_sctx;
10408f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
1041e3c97c2cSBryan Venteicher 
1042e3c97c2cSBryan Venteicher 	/*
1043e3c97c2cSBryan Venteicher 	 * Initialize fields of the shared data that remains the same across
1044e3c97c2cSBryan Venteicher 	 * reinits. Note the shared data is zero'd when allocated.
1045e3c97c2cSBryan Venteicher 	 */
1046e3c97c2cSBryan Venteicher 
1047e3c97c2cSBryan Venteicher 	ds->magic = VMXNET3_REV1_MAGIC;
1048e3c97c2cSBryan Venteicher 
1049e3c97c2cSBryan Venteicher 	/* DriverInfo */
1050e3c97c2cSBryan Venteicher 	ds->version = VMXNET3_DRIVER_VERSION;
1051ce3be286SBryan Venteicher 	ds->guest = VMXNET3_GOS_FREEBSD |
1052e3c97c2cSBryan Venteicher #ifdef __LP64__
1053e3c97c2cSBryan Venteicher 	    VMXNET3_GOS_64BIT;
1054e3c97c2cSBryan Venteicher #else
1055e3c97c2cSBryan Venteicher 	    VMXNET3_GOS_32BIT;
1056e3c97c2cSBryan Venteicher #endif
1057e3c97c2cSBryan Venteicher 	ds->vmxnet3_revision = 1;
1058e3c97c2cSBryan Venteicher 	ds->upt_version = 1;
1059e3c97c2cSBryan Venteicher 
1060e3c97c2cSBryan Venteicher 	/* Misc. conf */
1061e3c97c2cSBryan Venteicher 	ds->driver_data = vtophys(sc);
1062e3c97c2cSBryan Venteicher 	ds->driver_data_len = sizeof(struct vmxnet3_softc);
10638f82136aSPatrick Kelsey 	ds->queue_shared = sc->vmx_qs_dma.idi_paddr;
10648f82136aSPatrick Kelsey 	ds->queue_shared_len = sc->vmx_qs_dma.idi_size;
10658f82136aSPatrick Kelsey 	ds->nrxsg_max = IFLIB_MAX_RX_SEGS;
1066e3c97c2cSBryan Venteicher 
1067e557c1ddSBryan Venteicher 	/* RSS conf */
1068e557c1ddSBryan Venteicher 	if (sc->vmx_flags & VMXNET3_FLAG_RSS) {
1069e557c1ddSBryan Venteicher 		ds->rss.version = 1;
10708f82136aSPatrick Kelsey 		ds->rss.paddr = sc->vmx_rss_dma.idi_paddr;
10718f82136aSPatrick Kelsey 		ds->rss.len = sc->vmx_rss_dma.idi_size;
1072e557c1ddSBryan Venteicher 	}
1073e557c1ddSBryan Venteicher 
1074e3c97c2cSBryan Venteicher 	/* Interrupt control. */
1075e3c97c2cSBryan Venteicher 	ds->automask = sc->vmx_intr_mask_mode == VMXNET3_IMM_AUTO;
10768f82136aSPatrick Kelsey 	/*
10778f82136aSPatrick Kelsey 	 * Total number of interrupt indexes we are using in the shared
1078769d56ecSPatrick Kelsey 	 * config data, even though we don't actually allocate interrupt
10798f82136aSPatrick Kelsey 	 * resources for the tx queues.  Some versions of the device will
10808f82136aSPatrick Kelsey 	 * fail to initialize successfully if interrupt indexes are used in
10818f82136aSPatrick Kelsey 	 * the shared config that exceed the number of interrupts configured
10828f82136aSPatrick Kelsey 	 * here.
10838f82136aSPatrick Kelsey 	 */
10848f82136aSPatrick Kelsey 	ds->nintr = (scctx->isc_vectors == 1) ?
1085769d56ecSPatrick Kelsey 	    2 : (scctx->isc_nrxqsets + scctx->isc_ntxqsets + 1);
1086e3c97c2cSBryan Venteicher 	ds->evintr = sc->vmx_event_intr_idx;
1087e3c97c2cSBryan Venteicher 	ds->ictrl = VMXNET3_ICTRL_DISABLE_ALL;
1088e3c97c2cSBryan Venteicher 
10898f82136aSPatrick Kelsey 	for (i = 0; i < ds->nintr; i++)
1090e3c97c2cSBryan Venteicher 		ds->modlevel[i] = UPT1_IMOD_ADAPTIVE;
1091e3c97c2cSBryan Venteicher 
1092e3c97c2cSBryan Venteicher 	/* Receive filter. */
10938f82136aSPatrick Kelsey 	ds->mcast_table = sc->vmx_mcast_dma.idi_paddr;
10948f82136aSPatrick Kelsey 	ds->mcast_tablelen = sc->vmx_mcast_dma.idi_size;
1095e3c97c2cSBryan Venteicher 
1096e3c97c2cSBryan Venteicher 	/* Tx queues */
10978f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++) {
1098e3c97c2cSBryan Venteicher 		txq = &sc->vmx_txq[i];
1099e3c97c2cSBryan Venteicher 		txs = txq->vxtxq_ts;
1100e3c97c2cSBryan Venteicher 
11018f82136aSPatrick Kelsey 		txs->cmd_ring = txq->vxtxq_cmd_ring.vxtxr_paddr;
11023c965775SBryan Venteicher 		txs->cmd_ring_len = txq->vxtxq_cmd_ring.vxtxr_ndesc;
11038f82136aSPatrick Kelsey 		txs->comp_ring = txq->vxtxq_comp_ring.vxcr_paddr;
11043c965775SBryan Venteicher 		txs->comp_ring_len = txq->vxtxq_comp_ring.vxcr_ndesc;
1105e3c97c2cSBryan Venteicher 		txs->driver_data = vtophys(txq);
1106e3c97c2cSBryan Venteicher 		txs->driver_data_len = sizeof(struct vmxnet3_txqueue);
1107e3c97c2cSBryan Venteicher 	}
1108e3c97c2cSBryan Venteicher 
1109e3c97c2cSBryan Venteicher 	/* Rx queues */
11108f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
1111e3c97c2cSBryan Venteicher 		rxq = &sc->vmx_rxq[i];
1112e3c97c2cSBryan Venteicher 		rxs = rxq->vxrxq_rs;
1113e3c97c2cSBryan Venteicher 
11148f82136aSPatrick Kelsey 		rxs->cmd_ring[0] = rxq->vxrxq_cmd_ring[0].vxrxr_paddr;
1115e3c97c2cSBryan Venteicher 		rxs->cmd_ring_len[0] = rxq->vxrxq_cmd_ring[0].vxrxr_ndesc;
11168f82136aSPatrick Kelsey 		rxs->cmd_ring[1] = rxq->vxrxq_cmd_ring[1].vxrxr_paddr;
1117e3c97c2cSBryan Venteicher 		rxs->cmd_ring_len[1] = rxq->vxrxq_cmd_ring[1].vxrxr_ndesc;
11188f82136aSPatrick Kelsey 		rxs->comp_ring = rxq->vxrxq_comp_ring.vxcr_paddr;
11193c965775SBryan Venteicher 		rxs->comp_ring_len = rxq->vxrxq_comp_ring.vxcr_ndesc;
1120e3c97c2cSBryan Venteicher 		rxs->driver_data = vtophys(rxq);
1121e3c97c2cSBryan Venteicher 		rxs->driver_data_len = sizeof(struct vmxnet3_rxqueue);
1122e3c97c2cSBryan Venteicher 	}
1123e3c97c2cSBryan Venteicher }
1124e3c97c2cSBryan Venteicher 
1125e3c97c2cSBryan Venteicher static void
1126e557c1ddSBryan Venteicher vmxnet3_reinit_rss_shared_data(struct vmxnet3_softc *sc)
1127e557c1ddSBryan Venteicher {
1128e557c1ddSBryan Venteicher 	/*
1129e557c1ddSBryan Venteicher 	 * Use the same key as the Linux driver until FreeBSD can do
1130e557c1ddSBryan Venteicher 	 * RSS (presumably Toeplitz) in software.
1131e557c1ddSBryan Venteicher 	 */
1132e557c1ddSBryan Venteicher 	static const uint8_t rss_key[UPT1_RSS_MAX_KEY_SIZE] = {
1133e557c1ddSBryan Venteicher 	    0x3b, 0x56, 0xd1, 0x56, 0x13, 0x4a, 0xe7, 0xac,
1134e557c1ddSBryan Venteicher 	    0xe8, 0x79, 0x09, 0x75, 0xe8, 0x65, 0x79, 0x28,
1135e557c1ddSBryan Venteicher 	    0x35, 0x12, 0xb9, 0x56, 0x7c, 0x76, 0x4b, 0x70,
1136e557c1ddSBryan Venteicher 	    0xd8, 0x56, 0xa3, 0x18, 0x9b, 0x0a, 0xee, 0xf3,
1137e557c1ddSBryan Venteicher 	    0x96, 0xa6, 0x9f, 0x8f, 0x9e, 0x8c, 0x90, 0xc9,
1138e557c1ddSBryan Venteicher 	};
1139e557c1ddSBryan Venteicher 
1140e557c1ddSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
11418f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
1142e557c1ddSBryan Venteicher 	struct vmxnet3_rss_shared *rss;
1143e557c1ddSBryan Venteicher 	int i;
1144e557c1ddSBryan Venteicher 
1145e557c1ddSBryan Venteicher 	ds = sc->vmx_ds;
11468f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
1147e557c1ddSBryan Venteicher 	rss = sc->vmx_rss;
1148e557c1ddSBryan Venteicher 
1149e557c1ddSBryan Venteicher 	rss->hash_type =
1150e557c1ddSBryan Venteicher 	    UPT1_RSS_HASH_TYPE_IPV4 | UPT1_RSS_HASH_TYPE_TCP_IPV4 |
1151e557c1ddSBryan Venteicher 	    UPT1_RSS_HASH_TYPE_IPV6 | UPT1_RSS_HASH_TYPE_TCP_IPV6;
1152e557c1ddSBryan Venteicher 	rss->hash_func = UPT1_RSS_HASH_FUNC_TOEPLITZ;
1153e557c1ddSBryan Venteicher 	rss->hash_key_size = UPT1_RSS_MAX_KEY_SIZE;
1154e557c1ddSBryan Venteicher 	rss->ind_table_size = UPT1_RSS_MAX_IND_TABLE_SIZE;
1155e557c1ddSBryan Venteicher 	memcpy(rss->hash_key, rss_key, UPT1_RSS_MAX_KEY_SIZE);
1156e557c1ddSBryan Venteicher 
1157e557c1ddSBryan Venteicher 	for (i = 0; i < UPT1_RSS_MAX_IND_TABLE_SIZE; i++)
11588f82136aSPatrick Kelsey 		rss->ind_table[i] = i % scctx->isc_nrxqsets;
1159e3c97c2cSBryan Venteicher }
1160e3c97c2cSBryan Venteicher 
1161e3c97c2cSBryan Venteicher static void
1162e3c97c2cSBryan Venteicher vmxnet3_reinit_shared_data(struct vmxnet3_softc *sc)
1163e3c97c2cSBryan Venteicher {
1164e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
1165e3c97c2cSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
11668f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
1167e3c97c2cSBryan Venteicher 
1168e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
1169e3c97c2cSBryan Venteicher 	ds = sc->vmx_ds;
11708f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
1171e3c97c2cSBryan Venteicher 
1172e557c1ddSBryan Venteicher 	ds->mtu = ifp->if_mtu;
11738f82136aSPatrick Kelsey 	ds->ntxqueue = scctx->isc_ntxqsets;
11748f82136aSPatrick Kelsey 	ds->nrxqueue = scctx->isc_nrxqsets;
1175e557c1ddSBryan Venteicher 
1176e3c97c2cSBryan Venteicher 	ds->upt_features = 0;
1177e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6))
1178e3c97c2cSBryan Venteicher 		ds->upt_features |= UPT1_F_CSUM;
11793c5dfe89SBryan Venteicher 	if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
11803c5dfe89SBryan Venteicher 		ds->upt_features |= UPT1_F_VLAN;
1181e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & IFCAP_LRO)
1182e3c97c2cSBryan Venteicher 		ds->upt_features |= UPT1_F_LRO;
1183e3c97c2cSBryan Venteicher 
1184e557c1ddSBryan Venteicher 	if (sc->vmx_flags & VMXNET3_FLAG_RSS) {
1185e557c1ddSBryan Venteicher 		ds->upt_features |= UPT1_F_RSS;
1186e557c1ddSBryan Venteicher 		vmxnet3_reinit_rss_shared_data(sc);
1187e557c1ddSBryan Venteicher 	}
1188e3c97c2cSBryan Venteicher 
11898f82136aSPatrick Kelsey 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_DSL, sc->vmx_ds_dma.idi_paddr);
1190e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_DSH,
11918f82136aSPatrick Kelsey 	    (uint64_t) sc->vmx_ds_dma.idi_paddr >> 32);
1192e3c97c2cSBryan Venteicher }
1193e3c97c2cSBryan Venteicher 
1194e3c97c2cSBryan Venteicher static int
1195e3c97c2cSBryan Venteicher vmxnet3_alloc_data(struct vmxnet3_softc *sc)
1196e3c97c2cSBryan Venteicher {
1197e3c97c2cSBryan Venteicher 	int error;
1198e3c97c2cSBryan Venteicher 
1199e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_shared_data(sc);
1200e3c97c2cSBryan Venteicher 	if (error)
1201e3c97c2cSBryan Venteicher 		return (error);
1202e3c97c2cSBryan Venteicher 
1203e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_mcast_table(sc);
1204e3c97c2cSBryan Venteicher 	if (error)
1205e3c97c2cSBryan Venteicher 		return (error);
1206e3c97c2cSBryan Venteicher 
1207e3c97c2cSBryan Venteicher 	vmxnet3_init_shared_data(sc);
1208e3c97c2cSBryan Venteicher 
1209e3c97c2cSBryan Venteicher 	return (0);
1210e3c97c2cSBryan Venteicher }
1211e3c97c2cSBryan Venteicher 
1212e3c97c2cSBryan Venteicher static void
1213e3c97c2cSBryan Venteicher vmxnet3_free_data(struct vmxnet3_softc *sc)
1214e3c97c2cSBryan Venteicher {
1215e3c97c2cSBryan Venteicher 
1216e3c97c2cSBryan Venteicher 	vmxnet3_free_mcast_table(sc);
1217e3c97c2cSBryan Venteicher 	vmxnet3_free_shared_data(sc);
1218e3c97c2cSBryan Venteicher }
1219e3c97c2cSBryan Venteicher 
1220e3c97c2cSBryan Venteicher static void
1221e3c97c2cSBryan Venteicher vmxnet3_evintr(struct vmxnet3_softc *sc)
1222e3c97c2cSBryan Venteicher {
1223e3c97c2cSBryan Venteicher 	device_t dev;
1224e3c97c2cSBryan Venteicher 	struct vmxnet3_txq_shared *ts;
1225e3c97c2cSBryan Venteicher 	struct vmxnet3_rxq_shared *rs;
1226e3c97c2cSBryan Venteicher 	uint32_t event;
1227e3c97c2cSBryan Venteicher 
1228e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
1229e3c97c2cSBryan Venteicher 
1230e3c97c2cSBryan Venteicher 	/* Clear events. */
1231e3c97c2cSBryan Venteicher 	event = sc->vmx_ds->event;
1232e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_EVENT, event);
1233e3c97c2cSBryan Venteicher 
12348f82136aSPatrick Kelsey 	if (event & VMXNET3_EVENT_LINK)
1235e3c97c2cSBryan Venteicher 		vmxnet3_link_status(sc);
1236e3c97c2cSBryan Venteicher 
1237e3c97c2cSBryan Venteicher 	if (event & (VMXNET3_EVENT_TQERROR | VMXNET3_EVENT_RQERROR)) {
1238e3c97c2cSBryan Venteicher 		vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_STATUS);
1239e3c97c2cSBryan Venteicher 		ts = sc->vmx_txq[0].vxtxq_ts;
1240e3c97c2cSBryan Venteicher 		if (ts->stopped != 0)
1241e3c97c2cSBryan Venteicher 			device_printf(dev, "Tx queue error %#x\n", ts->error);
1242e3c97c2cSBryan Venteicher 		rs = sc->vmx_rxq[0].vxrxq_rs;
1243e3c97c2cSBryan Venteicher 		if (rs->stopped != 0)
1244e3c97c2cSBryan Venteicher 			device_printf(dev, "Rx queue error %#x\n", rs->error);
12458f82136aSPatrick Kelsey 
12468f82136aSPatrick Kelsey 		/* XXX - rely on liflib watchdog to reset us? */
12478f82136aSPatrick Kelsey 		device_printf(dev, "Rx/Tx queue error event ... "
12488f82136aSPatrick Kelsey 		    "waiting for iflib watchdog reset\n");
1249e3c97c2cSBryan Venteicher 	}
1250e3c97c2cSBryan Venteicher 
1251e3c97c2cSBryan Venteicher 	if (event & VMXNET3_EVENT_DIC)
1252e3c97c2cSBryan Venteicher 		device_printf(dev, "device implementation change event\n");
1253e3c97c2cSBryan Venteicher 	if (event & VMXNET3_EVENT_DEBUG)
1254e3c97c2cSBryan Venteicher 		device_printf(dev, "debug event\n");
1255e3c97c2cSBryan Venteicher }
1256e3c97c2cSBryan Venteicher 
12578f82136aSPatrick Kelsey static int
12588f82136aSPatrick Kelsey vmxnet3_isc_txd_encap(void *vsc, if_pkt_info_t pi)
12598f82136aSPatrick Kelsey {
12608f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
12618f82136aSPatrick Kelsey 	struct vmxnet3_txqueue *txq;
12628f82136aSPatrick Kelsey 	struct vmxnet3_txring *txr;
12638f82136aSPatrick Kelsey 	struct vmxnet3_txdesc *txd, *sop;
12648f82136aSPatrick Kelsey 	bus_dma_segment_t *segs;
12658f82136aSPatrick Kelsey 	int nsegs;
12668f82136aSPatrick Kelsey 	int pidx;
12678f82136aSPatrick Kelsey 	int hdrlen;
12688f82136aSPatrick Kelsey 	int i;
12698f82136aSPatrick Kelsey 	int gen;
12708f82136aSPatrick Kelsey 
12718f82136aSPatrick Kelsey 	sc = vsc;
12728f82136aSPatrick Kelsey 	txq = &sc->vmx_txq[pi->ipi_qsidx];
12738f82136aSPatrick Kelsey 	txr = &txq->vxtxq_cmd_ring;
12748f82136aSPatrick Kelsey 	segs = pi->ipi_segs;
12758f82136aSPatrick Kelsey 	nsegs = pi->ipi_nsegs;
12768f82136aSPatrick Kelsey 	pidx = pi->ipi_pidx;
12778f82136aSPatrick Kelsey 
12788f82136aSPatrick Kelsey 	KASSERT(nsegs <= VMXNET3_TX_MAXSEGS,
12798f82136aSPatrick Kelsey 	    ("%s: packet with too many segments %d", __func__, nsegs));
12808f82136aSPatrick Kelsey 
12818f82136aSPatrick Kelsey 	sop = &txr->vxtxr_txd[pidx];
12828f82136aSPatrick Kelsey 	gen = txr->vxtxr_gen ^ 1;	/* Owned by cpu (yet) */
12838f82136aSPatrick Kelsey 
12848f82136aSPatrick Kelsey 	for (i = 0; i < nsegs; i++) {
12858f82136aSPatrick Kelsey 		txd = &txr->vxtxr_txd[pidx];
12868f82136aSPatrick Kelsey 
12878f82136aSPatrick Kelsey 		txd->addr = segs[i].ds_addr;
12888f82136aSPatrick Kelsey 		txd->len = segs[i].ds_len;
12898f82136aSPatrick Kelsey 		txd->gen = gen;
12908f82136aSPatrick Kelsey 		txd->dtype = 0;
12918f82136aSPatrick Kelsey 		txd->offload_mode = VMXNET3_OM_NONE;
12928f82136aSPatrick Kelsey 		txd->offload_pos = 0;
12938f82136aSPatrick Kelsey 		txd->hlen = 0;
12948f82136aSPatrick Kelsey 		txd->eop = 0;
12958f82136aSPatrick Kelsey 		txd->compreq = 0;
12968f82136aSPatrick Kelsey 		txd->vtag_mode = 0;
12978f82136aSPatrick Kelsey 		txd->vtag = 0;
12988f82136aSPatrick Kelsey 
12998f82136aSPatrick Kelsey 		if (++pidx == txr->vxtxr_ndesc) {
13008f82136aSPatrick Kelsey 			pidx = 0;
13018f82136aSPatrick Kelsey 			txr->vxtxr_gen ^= 1;
13028f82136aSPatrick Kelsey 		}
13038f82136aSPatrick Kelsey 		gen = txr->vxtxr_gen;
13048f82136aSPatrick Kelsey 	}
13058f82136aSPatrick Kelsey 	txd->eop = 1;
13068f82136aSPatrick Kelsey 	txd->compreq = !!(pi->ipi_flags & IPI_TX_INTR);
13078f82136aSPatrick Kelsey 	pi->ipi_new_pidx = pidx;
13088f82136aSPatrick Kelsey 
13098f82136aSPatrick Kelsey 	/*
13108f82136aSPatrick Kelsey 	 * VLAN
13118f82136aSPatrick Kelsey 	 */
13128f82136aSPatrick Kelsey 	if (pi->ipi_mflags & M_VLANTAG) {
13138f82136aSPatrick Kelsey 		sop->vtag_mode = 1;
13148f82136aSPatrick Kelsey 		sop->vtag = pi->ipi_vtag;
13158f82136aSPatrick Kelsey 	}
13168f82136aSPatrick Kelsey 
13178f82136aSPatrick Kelsey 	/*
13188f82136aSPatrick Kelsey 	 * TSO and checksum offloads
13198f82136aSPatrick Kelsey 	 */
13208f82136aSPatrick Kelsey 	hdrlen = pi->ipi_ehdrlen + pi->ipi_ip_hlen;
13218f82136aSPatrick Kelsey 	if (pi->ipi_csum_flags & CSUM_TSO) {
13228f82136aSPatrick Kelsey 		sop->offload_mode = VMXNET3_OM_TSO;
1323*f55f37d9SVincenzo Maffione 		sop->hlen = hdrlen + pi->ipi_tcp_hlen;
13248f82136aSPatrick Kelsey 		sop->offload_pos = pi->ipi_tso_segsz;
13258f82136aSPatrick Kelsey 	} else if (pi->ipi_csum_flags & (VMXNET3_CSUM_OFFLOAD |
13268f82136aSPatrick Kelsey 	    VMXNET3_CSUM_OFFLOAD_IPV6)) {
13278f82136aSPatrick Kelsey 		sop->offload_mode = VMXNET3_OM_CSUM;
13288f82136aSPatrick Kelsey 		sop->hlen = hdrlen;
13298f82136aSPatrick Kelsey 		sop->offload_pos = hdrlen +
13308f82136aSPatrick Kelsey 		    ((pi->ipi_ipproto == IPPROTO_TCP) ?
13318f82136aSPatrick Kelsey 			offsetof(struct tcphdr, th_sum) :
13328f82136aSPatrick Kelsey 			offsetof(struct udphdr, uh_sum));
13338f82136aSPatrick Kelsey 	}
13348f82136aSPatrick Kelsey 
13358f82136aSPatrick Kelsey 	/* Finally, change the ownership. */
13368f82136aSPatrick Kelsey 	vmxnet3_barrier(sc, VMXNET3_BARRIER_WR);
13378f82136aSPatrick Kelsey 	sop->gen ^= 1;
13388f82136aSPatrick Kelsey 
13398f82136aSPatrick Kelsey 	return (0);
1340e3c97c2cSBryan Venteicher }
1341e3c97c2cSBryan Venteicher 
1342e3c97c2cSBryan Venteicher static void
13438f82136aSPatrick Kelsey vmxnet3_isc_txd_flush(void *vsc, uint16_t txqid, qidx_t pidx)
1344e3c97c2cSBryan Venteicher {
1345e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
13468f82136aSPatrick Kelsey 	struct vmxnet3_txqueue *txq;
13478f82136aSPatrick Kelsey 
13488f82136aSPatrick Kelsey 	sc = vsc;
13498f82136aSPatrick Kelsey 	txq = &sc->vmx_txq[txqid];
13508f82136aSPatrick Kelsey 
13518f82136aSPatrick Kelsey 	/*
13528f82136aSPatrick Kelsey 	 * pidx is what we last set ipi_new_pidx to in
13538f82136aSPatrick Kelsey 	 * vmxnet3_isc_txd_encap()
13548f82136aSPatrick Kelsey 	 */
13558f82136aSPatrick Kelsey 
13568f82136aSPatrick Kelsey 	/*
13578f82136aSPatrick Kelsey 	 * Avoid expensive register updates if the flush request is
13588f82136aSPatrick Kelsey 	 * redundant.
13598f82136aSPatrick Kelsey 	 */
13608f82136aSPatrick Kelsey 	if (txq->vxtxq_last_flush == pidx)
13618f82136aSPatrick Kelsey 		return;
13628f82136aSPatrick Kelsey 	txq->vxtxq_last_flush = pidx;
13638f82136aSPatrick Kelsey 	vmxnet3_write_bar0(sc, VMXNET3_BAR0_TXH(txq->vxtxq_id), pidx);
13648f82136aSPatrick Kelsey }
13658f82136aSPatrick Kelsey 
13668f82136aSPatrick Kelsey static int
13678f82136aSPatrick Kelsey vmxnet3_isc_txd_credits_update(void *vsc, uint16_t txqid, bool clear)
13688f82136aSPatrick Kelsey {
13698f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
13708f82136aSPatrick Kelsey 	struct vmxnet3_txqueue *txq;
1371e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *txc;
1372e3c97c2cSBryan Venteicher 	struct vmxnet3_txcompdesc *txcd;
13738f82136aSPatrick Kelsey 	struct vmxnet3_txring *txr;
13748f82136aSPatrick Kelsey 	int processed;
1375e3c97c2cSBryan Venteicher 
13768f82136aSPatrick Kelsey 	sc = vsc;
13778f82136aSPatrick Kelsey 	txq = &sc->vmx_txq[txqid];
1378e3c97c2cSBryan Venteicher 	txc = &txq->vxtxq_comp_ring;
13798f82136aSPatrick Kelsey 	txr = &txq->vxtxq_cmd_ring;
1380e3c97c2cSBryan Venteicher 
13818f82136aSPatrick Kelsey 	/*
13828f82136aSPatrick Kelsey 	 * If clear is true, we need to report the number of TX command ring
13838f82136aSPatrick Kelsey 	 * descriptors that have been processed by the device.  If clear is
13848f82136aSPatrick Kelsey 	 * false, we just need to report whether or not at least one TX
13858f82136aSPatrick Kelsey 	 * command ring descriptor has been processed by the device.
13868f82136aSPatrick Kelsey 	 */
13878f82136aSPatrick Kelsey 	processed = 0;
1388e3c97c2cSBryan Venteicher 	for (;;) {
1389e3c97c2cSBryan Venteicher 		txcd = &txc->vxcr_u.txcd[txc->vxcr_next];
1390e3c97c2cSBryan Venteicher 		if (txcd->gen != txc->vxcr_gen)
1391e3c97c2cSBryan Venteicher 			break;
13928f82136aSPatrick Kelsey 		else if (!clear)
13938f82136aSPatrick Kelsey 			return (1);
13943c965775SBryan Venteicher 		vmxnet3_barrier(sc, VMXNET3_BARRIER_RD);
1395e3c97c2cSBryan Venteicher 
1396e3c97c2cSBryan Venteicher 		if (++txc->vxcr_next == txc->vxcr_ndesc) {
1397e3c97c2cSBryan Venteicher 			txc->vxcr_next = 0;
1398e3c97c2cSBryan Venteicher 			txc->vxcr_gen ^= 1;
1399e3c97c2cSBryan Venteicher 		}
1400e3c97c2cSBryan Venteicher 
14018f82136aSPatrick Kelsey 		if (txcd->eop_idx < txr->vxtxr_next)
14028f82136aSPatrick Kelsey 			processed += txr->vxtxr_ndesc -
14038f82136aSPatrick Kelsey 			    (txr->vxtxr_next - txcd->eop_idx) + 1;
14048f82136aSPatrick Kelsey 		else
14058f82136aSPatrick Kelsey 			processed += txcd->eop_idx - txr->vxtxr_next + 1;
1406e3c97c2cSBryan Venteicher 		txr->vxtxr_next = (txcd->eop_idx + 1) % txr->vxtxr_ndesc;
1407e3c97c2cSBryan Venteicher 	}
1408e3c97c2cSBryan Venteicher 
14098f82136aSPatrick Kelsey 	return (processed);
1410e3c97c2cSBryan Venteicher }
1411e3c97c2cSBryan Venteicher 
1412e3c97c2cSBryan Venteicher static int
14138f82136aSPatrick Kelsey vmxnet3_isc_rxd_available(void *vsc, uint16_t rxqid, qidx_t idx, qidx_t budget)
1414e3c97c2cSBryan Venteicher {
14158f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
14168f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
14178f82136aSPatrick Kelsey 	struct vmxnet3_comp_ring *rxc;
14188f82136aSPatrick Kelsey 	struct vmxnet3_rxcompdesc *rxcd;
14198f82136aSPatrick Kelsey 	int avail;
14208f82136aSPatrick Kelsey 	int completed_gen;
14218f82136aSPatrick Kelsey #ifdef INVARIANTS
14228f82136aSPatrick Kelsey 	int expect_sop = 1;
14238f82136aSPatrick Kelsey #endif
14248f82136aSPatrick Kelsey 	sc = vsc;
14258f82136aSPatrick Kelsey 	rxq = &sc->vmx_rxq[rxqid];
14268f82136aSPatrick Kelsey 	rxc = &rxq->vxrxq_comp_ring;
14278f82136aSPatrick Kelsey 
14288f82136aSPatrick Kelsey 	avail = 0;
14298f82136aSPatrick Kelsey 	completed_gen = rxc->vxcr_gen;
14308f82136aSPatrick Kelsey 	for (;;) {
14318f82136aSPatrick Kelsey 		rxcd = &rxc->vxcr_u.rxcd[idx];
14328f82136aSPatrick Kelsey 		if (rxcd->gen != completed_gen)
14338f82136aSPatrick Kelsey 			break;
14348f82136aSPatrick Kelsey 		vmxnet3_barrier(sc, VMXNET3_BARRIER_RD);
14358f82136aSPatrick Kelsey 
14368f82136aSPatrick Kelsey #ifdef INVARIANTS
14378f82136aSPatrick Kelsey 		if (expect_sop)
14388f82136aSPatrick Kelsey 			KASSERT(rxcd->sop, ("%s: expected sop", __func__));
14398f82136aSPatrick Kelsey 		else
14408f82136aSPatrick Kelsey 			KASSERT(!rxcd->sop, ("%s: unexpected sop", __func__));
14418f82136aSPatrick Kelsey 		expect_sop = rxcd->eop;
14428f82136aSPatrick Kelsey #endif
14438f82136aSPatrick Kelsey 		if (rxcd->eop && (rxcd->len != 0))
14448f82136aSPatrick Kelsey 			avail++;
14458f82136aSPatrick Kelsey 		if (avail > budget)
14468f82136aSPatrick Kelsey 			break;
14478f82136aSPatrick Kelsey 		if (++idx == rxc->vxcr_ndesc) {
14488f82136aSPatrick Kelsey 			idx = 0;
14498f82136aSPatrick Kelsey 			completed_gen ^= 1;
14508f82136aSPatrick Kelsey 		}
14518f82136aSPatrick Kelsey 	}
14528f82136aSPatrick Kelsey 
14538f82136aSPatrick Kelsey 	return (avail);
14548f82136aSPatrick Kelsey }
14558f82136aSPatrick Kelsey 
14568f82136aSPatrick Kelsey static int
14578f82136aSPatrick Kelsey vmxnet3_isc_rxd_pkt_get(void *vsc, if_rxd_info_t ri)
14588f82136aSPatrick Kelsey {
14598f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
14608f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
14618f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
14628f82136aSPatrick Kelsey 	struct vmxnet3_comp_ring *rxc;
14638f82136aSPatrick Kelsey 	struct vmxnet3_rxcompdesc *rxcd;
14648f82136aSPatrick Kelsey 	struct vmxnet3_rxring *rxr;
1465e3c97c2cSBryan Venteicher 	struct vmxnet3_rxdesc *rxd;
14668f82136aSPatrick Kelsey 	if_rxd_frag_t frag;
14678f82136aSPatrick Kelsey 	int cqidx;
14688f82136aSPatrick Kelsey 	uint16_t total_len;
14698f82136aSPatrick Kelsey 	uint8_t nfrags;
14708f82136aSPatrick Kelsey 	uint8_t flid;
1471e3c97c2cSBryan Venteicher 
14728f82136aSPatrick Kelsey 	sc = vsc;
14738f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
14748f82136aSPatrick Kelsey 	rxq = &sc->vmx_rxq[ri->iri_qsidx];
14758f82136aSPatrick Kelsey 	rxc = &rxq->vxrxq_comp_ring;
1476e3c97c2cSBryan Venteicher 
1477e3c97c2cSBryan Venteicher 	/*
14788f82136aSPatrick Kelsey 	 * Get a single packet starting at the given index in the completion
14798f82136aSPatrick Kelsey 	 * queue.  That we have been called indicates that
14808f82136aSPatrick Kelsey 	 * vmxnet3_isc_rxd_available() has already verified that either
14818f82136aSPatrick Kelsey 	 * there is a complete packet available starting at the given index,
14828f82136aSPatrick Kelsey 	 * or there are one or more zero length packets starting at the
14838f82136aSPatrick Kelsey 	 * given index followed by a complete packet, so no verification of
14848f82136aSPatrick Kelsey 	 * ownership of the descriptors (and no associated read barrier) is
14858f82136aSPatrick Kelsey 	 * required here.
1486e3c97c2cSBryan Venteicher 	 */
14878f82136aSPatrick Kelsey 	cqidx = ri->iri_cidx;
14888f82136aSPatrick Kelsey 	rxcd = &rxc->vxcr_u.rxcd[cqidx];
14898f82136aSPatrick Kelsey 	while (rxcd->len == 0) {
14908f82136aSPatrick Kelsey 		KASSERT(rxcd->sop && rxcd->eop,
14918f82136aSPatrick Kelsey 		    ("%s: zero-length packet without both sop and eop set",
14928f82136aSPatrick Kelsey 			__func__));
14938f82136aSPatrick Kelsey 		if (++cqidx == rxc->vxcr_ndesc) {
14948f82136aSPatrick Kelsey 			cqidx = 0;
14958f82136aSPatrick Kelsey 			rxc->vxcr_gen ^= 1;
14968f82136aSPatrick Kelsey 		}
14978f82136aSPatrick Kelsey 		rxcd = &rxc->vxcr_u.rxcd[cqidx];
14988f82136aSPatrick Kelsey 	}
14998f82136aSPatrick Kelsey 	KASSERT(rxcd->sop, ("%s: expected sop", __func__));
15008f82136aSPatrick Kelsey 
15018f82136aSPatrick Kelsey 	/*
15028f82136aSPatrick Kelsey 	 * RSS and flow ID
15038f82136aSPatrick Kelsey 	 */
15048f82136aSPatrick Kelsey 	ri->iri_flowid = rxcd->rss_hash;
15058f82136aSPatrick Kelsey 	switch (rxcd->rss_type) {
15068f82136aSPatrick Kelsey 	case VMXNET3_RCD_RSS_TYPE_NONE:
15078f82136aSPatrick Kelsey 		ri->iri_flowid = ri->iri_qsidx;
15088f82136aSPatrick Kelsey 		ri->iri_rsstype = M_HASHTYPE_NONE;
15098f82136aSPatrick Kelsey 		break;
15108f82136aSPatrick Kelsey 	case VMXNET3_RCD_RSS_TYPE_IPV4:
15118f82136aSPatrick Kelsey 		ri->iri_rsstype = M_HASHTYPE_RSS_IPV4;
15128f82136aSPatrick Kelsey 		break;
15138f82136aSPatrick Kelsey 	case VMXNET3_RCD_RSS_TYPE_TCPIPV4:
15148f82136aSPatrick Kelsey 		ri->iri_rsstype = M_HASHTYPE_RSS_TCP_IPV4;
15158f82136aSPatrick Kelsey 		break;
15168f82136aSPatrick Kelsey 	case VMXNET3_RCD_RSS_TYPE_IPV6:
15178f82136aSPatrick Kelsey 		ri->iri_rsstype = M_HASHTYPE_RSS_IPV6;
15188f82136aSPatrick Kelsey 		break;
15198f82136aSPatrick Kelsey 	case VMXNET3_RCD_RSS_TYPE_TCPIPV6:
15208f82136aSPatrick Kelsey 		ri->iri_rsstype = M_HASHTYPE_RSS_TCP_IPV6;
15218f82136aSPatrick Kelsey 		break;
15228f82136aSPatrick Kelsey 	default:
15238f82136aSPatrick Kelsey 		ri->iri_rsstype = M_HASHTYPE_OPAQUE_HASH;
15248f82136aSPatrick Kelsey 		break;
1525e3c97c2cSBryan Venteicher 	}
1526e3c97c2cSBryan Venteicher 
15278f82136aSPatrick Kelsey 	/* VLAN */
15288f82136aSPatrick Kelsey 	if (rxcd->vlan) {
15298f82136aSPatrick Kelsey 		ri->iri_flags |= M_VLANTAG;
15308f82136aSPatrick Kelsey 		ri->iri_vtag = rxcd->vtag;
1531e3c97c2cSBryan Venteicher 	}
1532e3c97c2cSBryan Venteicher 
15338f82136aSPatrick Kelsey 	/* Checksum offload */
15348f82136aSPatrick Kelsey 	if (!rxcd->no_csum) {
15358f82136aSPatrick Kelsey 		uint32_t csum_flags = 0;
1536e3c97c2cSBryan Venteicher 
15378f82136aSPatrick Kelsey 		if (rxcd->ipv4) {
15388f82136aSPatrick Kelsey 			csum_flags |= CSUM_IP_CHECKED;
15398f82136aSPatrick Kelsey 			if (rxcd->ipcsum_ok)
15408f82136aSPatrick Kelsey 				csum_flags |= CSUM_IP_VALID;
1541e3c97c2cSBryan Venteicher 		}
15428f82136aSPatrick Kelsey 		if (!rxcd->fragment && (rxcd->tcp || rxcd->udp)) {
15438f82136aSPatrick Kelsey 			csum_flags |= CSUM_L4_CALC;
15448f82136aSPatrick Kelsey 			if (rxcd->csum_ok) {
15458f82136aSPatrick Kelsey 				csum_flags |= CSUM_L4_VALID;
15468f82136aSPatrick Kelsey 				ri->iri_csum_data = 0xffff;
15478f82136aSPatrick Kelsey 			}
15488f82136aSPatrick Kelsey 		}
15498f82136aSPatrick Kelsey 		ri->iri_csum_flags = csum_flags;
1550e3c97c2cSBryan Venteicher 	}
1551e3c97c2cSBryan Venteicher 
15528f82136aSPatrick Kelsey 	/*
15538f82136aSPatrick Kelsey 	 * The queue numbering scheme used for rxcd->qid is as follows:
15548f82136aSPatrick Kelsey 	 *  - All of the command ring 0s are numbered [0, nrxqsets - 1]
15558f82136aSPatrick Kelsey 	 *  - All of the command ring 1s are numbered [nrxqsets, 2*nrxqsets - 1]
15568f82136aSPatrick Kelsey 	 *
15578f82136aSPatrick Kelsey 	 * Thus, rxcd->qid less than nrxqsets indicates command ring (and
15588f82136aSPatrick Kelsey 	 * flid) 0, and rxcd->qid greater than or equal to nrxqsets
15598f82136aSPatrick Kelsey 	 * indicates command ring (and flid) 1.
15608f82136aSPatrick Kelsey 	 */
15618f82136aSPatrick Kelsey 	nfrags = 0;
15628f82136aSPatrick Kelsey 	total_len = 0;
15638f82136aSPatrick Kelsey 	do {
15648f82136aSPatrick Kelsey 		rxcd = &rxc->vxcr_u.rxcd[cqidx];
15658f82136aSPatrick Kelsey 		KASSERT(rxcd->gen == rxc->vxcr_gen,
15668f82136aSPatrick Kelsey 		    ("%s: generation mismatch", __func__));
15678f82136aSPatrick Kelsey 		flid = (rxcd->qid >= scctx->isc_nrxqsets) ? 1 : 0;
15688f82136aSPatrick Kelsey 		rxr = &rxq->vxrxq_cmd_ring[flid];
15698f82136aSPatrick Kelsey 		rxd = &rxr->vxrxr_rxd[rxcd->rxd_idx];
1570e3c97c2cSBryan Venteicher 
15718f82136aSPatrick Kelsey 		frag = &ri->iri_frags[nfrags];
15728f82136aSPatrick Kelsey 		frag->irf_flid = flid;
15738f82136aSPatrick Kelsey 		frag->irf_idx = rxcd->rxd_idx;
15748f82136aSPatrick Kelsey 		frag->irf_len = rxcd->len;
15758f82136aSPatrick Kelsey 		total_len += rxcd->len;
15768f82136aSPatrick Kelsey 		nfrags++;
15778f82136aSPatrick Kelsey 		if (++cqidx == rxc->vxcr_ndesc) {
15788f82136aSPatrick Kelsey 			cqidx = 0;
15798f82136aSPatrick Kelsey 			rxc->vxcr_gen ^= 1;
15808f82136aSPatrick Kelsey 		}
15818f82136aSPatrick Kelsey 	} while (!rxcd->eop);
1582e3c97c2cSBryan Venteicher 
15838f82136aSPatrick Kelsey 	ri->iri_cidx = cqidx;
15848f82136aSPatrick Kelsey 	ri->iri_nfrags = nfrags;
15858f82136aSPatrick Kelsey 	ri->iri_len = total_len;
15868f82136aSPatrick Kelsey 
1587e3c97c2cSBryan Venteicher 	return (0);
1588e3c97c2cSBryan Venteicher }
1589e3c97c2cSBryan Venteicher 
1590e3c97c2cSBryan Venteicher static void
15918f82136aSPatrick Kelsey vmxnet3_isc_rxd_refill(void *vsc, if_rxd_update_t iru)
1592e3c97c2cSBryan Venteicher {
1593e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
15948f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
1595e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
1596e3c97c2cSBryan Venteicher 	struct vmxnet3_rxdesc *rxd;
15978f82136aSPatrick Kelsey 	uint64_t *paddrs;
15988f82136aSPatrick Kelsey 	int count;
15998f82136aSPatrick Kelsey 	int len;
16008f82136aSPatrick Kelsey 	int pidx;
16018f82136aSPatrick Kelsey 	int i;
16028f82136aSPatrick Kelsey 	uint8_t flid;
16038f82136aSPatrick Kelsey 	uint8_t btype;
1604e3c97c2cSBryan Venteicher 
16058f82136aSPatrick Kelsey 	count = iru->iru_count;
16068f82136aSPatrick Kelsey 	len = iru->iru_buf_size;
16078f82136aSPatrick Kelsey 	pidx = iru->iru_pidx;
16088f82136aSPatrick Kelsey 	flid = iru->iru_flidx;
16098f82136aSPatrick Kelsey 	paddrs = iru->iru_paddrs;
1610e3c97c2cSBryan Venteicher 
16118f82136aSPatrick Kelsey 	sc = vsc;
16128f82136aSPatrick Kelsey 	rxq = &sc->vmx_rxq[iru->iru_qsidx];
16138f82136aSPatrick Kelsey 	rxr = &rxq->vxrxq_cmd_ring[flid];
16148f82136aSPatrick Kelsey 	rxd = rxr->vxrxr_rxd;
1615e3c97c2cSBryan Venteicher 
1616e3c97c2cSBryan Venteicher 	/*
16178f82136aSPatrick Kelsey 	 * Command ring 0 is filled with BTYPE_HEAD descriptors, and
16188f82136aSPatrick Kelsey 	 * command ring 1 is filled with BTYPE_BODY descriptors.
1619e3c97c2cSBryan Venteicher 	 */
16208f82136aSPatrick Kelsey 	btype = (flid == 0) ? VMXNET3_BTYPE_HEAD : VMXNET3_BTYPE_BODY;
16218f82136aSPatrick Kelsey 	for (i = 0; i < count; i++) {
16228f82136aSPatrick Kelsey 		rxd[pidx].addr = paddrs[i];
16238f82136aSPatrick Kelsey 		rxd[pidx].len = len;
16248f82136aSPatrick Kelsey 		rxd[pidx].btype = btype;
16258f82136aSPatrick Kelsey 		rxd[pidx].gen = rxr->vxrxr_gen;
16268f82136aSPatrick Kelsey 
16278f82136aSPatrick Kelsey 		if (++pidx == rxr->vxrxr_ndesc) {
16288f82136aSPatrick Kelsey 			pidx = 0;
16298f82136aSPatrick Kelsey 			rxr->vxrxr_gen ^= 1;
16308f82136aSPatrick Kelsey 		}
1631e3c97c2cSBryan Venteicher 	}
1632e3c97c2cSBryan Venteicher }
1633e3c97c2cSBryan Venteicher 
16348f82136aSPatrick Kelsey static void
16358f82136aSPatrick Kelsey vmxnet3_isc_rxd_flush(void *vsc, uint16_t rxqid, uint8_t flid, qidx_t pidx)
16368f82136aSPatrick Kelsey {
16378f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
16388f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
16398f82136aSPatrick Kelsey 	struct vmxnet3_rxring *rxr;
1640e3c97c2cSBryan Venteicher 	bus_size_t r;
1641e3c97c2cSBryan Venteicher 
16428f82136aSPatrick Kelsey 	sc = vsc;
16438f82136aSPatrick Kelsey 	rxq = &sc->vmx_rxq[rxqid];
16448f82136aSPatrick Kelsey 	rxr = &rxq->vxrxq_cmd_ring[flid];
16458f82136aSPatrick Kelsey 
16468f82136aSPatrick Kelsey 	if (flid == 0)
16478f82136aSPatrick Kelsey 		r = VMXNET3_BAR0_RXH1(rxqid);
16488f82136aSPatrick Kelsey 	else
16498f82136aSPatrick Kelsey 		r = VMXNET3_BAR0_RXH2(rxqid);
16508f82136aSPatrick Kelsey 
16518f82136aSPatrick Kelsey 	/*
16528f82136aSPatrick Kelsey 	 * pidx is the index of the last descriptor with a buffer the device
16538f82136aSPatrick Kelsey 	 * can use, and the device needs to be told which index is one past
16548f82136aSPatrick Kelsey 	 * that.
16558f82136aSPatrick Kelsey 	 */
16568f82136aSPatrick Kelsey 	if (++pidx == rxr->vxrxr_ndesc)
16578f82136aSPatrick Kelsey 		pidx = 0;
16588f82136aSPatrick Kelsey 	vmxnet3_write_bar0(sc, r, pidx);
1659e3c97c2cSBryan Venteicher }
1660e3c97c2cSBryan Venteicher 
16618f82136aSPatrick Kelsey static int
1662e3c97c2cSBryan Venteicher vmxnet3_legacy_intr(void *xsc)
1663e3c97c2cSBryan Venteicher {
1664e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
16658f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
16668f82136aSPatrick Kelsey 	if_ctx_t ctx;
1667e3c97c2cSBryan Venteicher 
1668e3c97c2cSBryan Venteicher 	sc = xsc;
16698f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
16708f82136aSPatrick Kelsey 	ctx = sc->vmx_ctx;
1671e3c97c2cSBryan Venteicher 
16728f82136aSPatrick Kelsey 	/*
16738f82136aSPatrick Kelsey 	 * When there is only a single interrupt configured, this routine
16748f82136aSPatrick Kelsey 	 * runs in fast interrupt context, following which the rxq 0 task
16758f82136aSPatrick Kelsey 	 * will be enqueued.
16768f82136aSPatrick Kelsey 	 */
16778f82136aSPatrick Kelsey 	if (scctx->isc_intr == IFLIB_INTR_LEGACY) {
1678e3c97c2cSBryan Venteicher 		if (vmxnet3_read_bar1(sc, VMXNET3_BAR1_INTR) == 0)
16798f82136aSPatrick Kelsey 			return (FILTER_HANDLED);
1680e3c97c2cSBryan Venteicher 	}
1681e3c97c2cSBryan Venteicher 	if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE)
16828f82136aSPatrick Kelsey 		vmxnet3_intr_disable_all(ctx);
1683e3c97c2cSBryan Venteicher 
1684e3c97c2cSBryan Venteicher 	if (sc->vmx_ds->event != 0)
16858f82136aSPatrick Kelsey 		iflib_admin_intr_deferred(ctx);
1686e3c97c2cSBryan Venteicher 
16878f82136aSPatrick Kelsey 	/*
16888f82136aSPatrick Kelsey 	 * XXX - When there is both rxq and event activity, do we care
16898f82136aSPatrick Kelsey 	 * whether the rxq 0 task or the admin task re-enables the interrupt
16908f82136aSPatrick Kelsey 	 * first?
16918f82136aSPatrick Kelsey 	 */
16928f82136aSPatrick Kelsey 	return (FILTER_SCHEDULE_THREAD);
1693e3c97c2cSBryan Venteicher }
1694e3c97c2cSBryan Venteicher 
16958f82136aSPatrick Kelsey static int
16968f82136aSPatrick Kelsey vmxnet3_rxq_intr(void *vrxq)
1697e3c97c2cSBryan Venteicher {
1698e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
1699e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
1700e3c97c2cSBryan Venteicher 
17018f82136aSPatrick Kelsey 	rxq = vrxq;
1702e3c97c2cSBryan Venteicher 	sc = rxq->vxrxq_sc;
1703e3c97c2cSBryan Venteicher 
1704e3c97c2cSBryan Venteicher 	if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE)
1705e3c97c2cSBryan Venteicher 		vmxnet3_disable_intr(sc, rxq->vxrxq_intr_idx);
1706e3c97c2cSBryan Venteicher 
17078f82136aSPatrick Kelsey 	return (FILTER_SCHEDULE_THREAD);
1708e3c97c2cSBryan Venteicher }
1709e3c97c2cSBryan Venteicher 
17108f82136aSPatrick Kelsey static int
17118f82136aSPatrick Kelsey vmxnet3_event_intr(void *vsc)
1712e3c97c2cSBryan Venteicher {
1713e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
1714e3c97c2cSBryan Venteicher 
17158f82136aSPatrick Kelsey 	sc = vsc;
1716e3c97c2cSBryan Venteicher 
1717e3c97c2cSBryan Venteicher 	if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE)
1718e3c97c2cSBryan Venteicher 		vmxnet3_disable_intr(sc, sc->vmx_event_intr_idx);
1719e3c97c2cSBryan Venteicher 
17208f82136aSPatrick Kelsey 	/*
17218f82136aSPatrick Kelsey 	 * The work will be done via vmxnet3_update_admin_status(), and the
17228f82136aSPatrick Kelsey 	 * interrupt will be re-enabled in vmxnet3_link_intr_enable().
17238f82136aSPatrick Kelsey 	 *
17248f82136aSPatrick Kelsey 	 * The interrupt will be re-enabled by vmxnet3_link_intr_enable().
17258f82136aSPatrick Kelsey 	 */
17268f82136aSPatrick Kelsey 	return (FILTER_SCHEDULE_THREAD);
1727e3c97c2cSBryan Venteicher }
1728e3c97c2cSBryan Venteicher 
1729e3c97c2cSBryan Venteicher static void
17308f82136aSPatrick Kelsey vmxnet3_stop(if_ctx_t ctx)
1731e3c97c2cSBryan Venteicher {
17328f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
1733e3c97c2cSBryan Venteicher 
17348f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
1735e3c97c2cSBryan Venteicher 
1736e3c97c2cSBryan Venteicher 	sc->vmx_link_active = 0;
1737e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_DISABLE);
1738e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_RESET);
1739e3c97c2cSBryan Venteicher }
1740e3c97c2cSBryan Venteicher 
1741e3c97c2cSBryan Venteicher static void
1742e3c97c2cSBryan Venteicher vmxnet3_txinit(struct vmxnet3_softc *sc, struct vmxnet3_txqueue *txq)
1743e3c97c2cSBryan Venteicher {
1744e3c97c2cSBryan Venteicher 	struct vmxnet3_txring *txr;
1745e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *txc;
1746e3c97c2cSBryan Venteicher 
17478f82136aSPatrick Kelsey 	txq->vxtxq_last_flush = -1;
17488f82136aSPatrick Kelsey 
1749e3c97c2cSBryan Venteicher 	txr = &txq->vxtxq_cmd_ring;
1750e3c97c2cSBryan Venteicher 	txr->vxtxr_next = 0;
1751e3c97c2cSBryan Venteicher 	txr->vxtxr_gen = VMXNET3_INIT_GEN;
17528f82136aSPatrick Kelsey 	/*
17538f82136aSPatrick Kelsey 	 * iflib has zeroed out the descriptor array during the prior attach
17548f82136aSPatrick Kelsey 	 * or stop
17558f82136aSPatrick Kelsey 	 */
1756e3c97c2cSBryan Venteicher 
1757e3c97c2cSBryan Venteicher 	txc = &txq->vxtxq_comp_ring;
1758e3c97c2cSBryan Venteicher 	txc->vxcr_next = 0;
1759e3c97c2cSBryan Venteicher 	txc->vxcr_gen = VMXNET3_INIT_GEN;
17608f82136aSPatrick Kelsey 	/*
17618f82136aSPatrick Kelsey 	 * iflib has zeroed out the descriptor array during the prior attach
17628f82136aSPatrick Kelsey 	 * or stop
17638f82136aSPatrick Kelsey 	 */
1764e3c97c2cSBryan Venteicher }
1765e3c97c2cSBryan Venteicher 
17668f82136aSPatrick Kelsey static void
1767e3c97c2cSBryan Venteicher vmxnet3_rxinit(struct vmxnet3_softc *sc, struct vmxnet3_rxqueue *rxq)
1768e3c97c2cSBryan Venteicher {
1769e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
1770e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *rxc;
17718f82136aSPatrick Kelsey 	int i;
1772e3c97c2cSBryan Venteicher 
1773e3c97c2cSBryan Venteicher 	/*
17748f82136aSPatrick Kelsey 	 * The descriptors will be populated with buffers during a
17758f82136aSPatrick Kelsey 	 * subsequent invocation of vmxnet3_isc_rxd_refill()
1776e3c97c2cSBryan Venteicher 	 */
17778f82136aSPatrick Kelsey 	for (i = 0; i < sc->vmx_sctx->isc_nrxqs - 1; i++) {
1778e3c97c2cSBryan Venteicher 		rxr = &rxq->vxrxq_cmd_ring[i];
1779e3c97c2cSBryan Venteicher 		rxr->vxrxr_gen = VMXNET3_INIT_GEN;
17808f82136aSPatrick Kelsey 		/*
17818f82136aSPatrick Kelsey 		 * iflib has zeroed out the descriptor array during the
17828f82136aSPatrick Kelsey 		 * prior attach or stop
17838f82136aSPatrick Kelsey 		 */
1784e3c97c2cSBryan Venteicher 	}
1785e3c97c2cSBryan Venteicher 
1786e3c97c2cSBryan Venteicher 	for (/**/; i < VMXNET3_RXRINGS_PERQ; i++) {
1787e3c97c2cSBryan Venteicher 		rxr = &rxq->vxrxq_cmd_ring[i];
1788e3c97c2cSBryan Venteicher 		rxr->vxrxr_gen = 0;
1789e3c97c2cSBryan Venteicher 		bzero(rxr->vxrxr_rxd,
1790e3c97c2cSBryan Venteicher 		    rxr->vxrxr_ndesc * sizeof(struct vmxnet3_rxdesc));
1791e3c97c2cSBryan Venteicher 	}
1792e3c97c2cSBryan Venteicher 
1793e3c97c2cSBryan Venteicher 	rxc = &rxq->vxrxq_comp_ring;
1794e3c97c2cSBryan Venteicher 	rxc->vxcr_next = 0;
1795e3c97c2cSBryan Venteicher 	rxc->vxcr_gen = VMXNET3_INIT_GEN;
17968f82136aSPatrick Kelsey 	/*
17978f82136aSPatrick Kelsey 	 * iflib has zeroed out the descriptor array during the prior attach
17988f82136aSPatrick Kelsey 	 * or stop
17998f82136aSPatrick Kelsey 	 */
1800e3c97c2cSBryan Venteicher }
1801e3c97c2cSBryan Venteicher 
18028f82136aSPatrick Kelsey static void
1803e3c97c2cSBryan Venteicher vmxnet3_reinit_queues(struct vmxnet3_softc *sc)
1804e3c97c2cSBryan Venteicher {
18058f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
18068f82136aSPatrick Kelsey 	int q;
1807e3c97c2cSBryan Venteicher 
18088f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
1809e3c97c2cSBryan Venteicher 
18108f82136aSPatrick Kelsey 	for (q = 0; q < scctx->isc_ntxqsets; q++)
1811e3c97c2cSBryan Venteicher 		vmxnet3_txinit(sc, &sc->vmx_txq[q]);
1812e3c97c2cSBryan Venteicher 
18138f82136aSPatrick Kelsey 	for (q = 0; q < scctx->isc_nrxqsets; q++)
18148f82136aSPatrick Kelsey 		vmxnet3_rxinit(sc, &sc->vmx_rxq[q]);
1815e3c97c2cSBryan Venteicher }
1816e3c97c2cSBryan Venteicher 
1817e3c97c2cSBryan Venteicher static int
1818e3c97c2cSBryan Venteicher vmxnet3_enable_device(struct vmxnet3_softc *sc)
1819e3c97c2cSBryan Venteicher {
18208f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
1821e3c97c2cSBryan Venteicher 	int q;
1822e3c97c2cSBryan Venteicher 
18238f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
18248f82136aSPatrick Kelsey 
1825e3c97c2cSBryan Venteicher 	if (vmxnet3_read_cmd(sc, VMXNET3_CMD_ENABLE) != 0) {
1826e3c97c2cSBryan Venteicher 		device_printf(sc->vmx_dev, "device enable command failed!\n");
1827e3c97c2cSBryan Venteicher 		return (1);
1828e3c97c2cSBryan Venteicher 	}
1829e3c97c2cSBryan Venteicher 
1830e3c97c2cSBryan Venteicher 	/* Reset the Rx queue heads. */
18318f82136aSPatrick Kelsey 	for (q = 0; q < scctx->isc_nrxqsets; q++) {
1832e3c97c2cSBryan Venteicher 		vmxnet3_write_bar0(sc, VMXNET3_BAR0_RXH1(q), 0);
1833e3c97c2cSBryan Venteicher 		vmxnet3_write_bar0(sc, VMXNET3_BAR0_RXH2(q), 0);
1834e3c97c2cSBryan Venteicher 	}
1835e3c97c2cSBryan Venteicher 
1836e3c97c2cSBryan Venteicher 	return (0);
1837e3c97c2cSBryan Venteicher }
1838e3c97c2cSBryan Venteicher 
1839e3c97c2cSBryan Venteicher static void
1840e3c97c2cSBryan Venteicher vmxnet3_reinit_rxfilters(struct vmxnet3_softc *sc)
1841e3c97c2cSBryan Venteicher {
1842e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
1843e3c97c2cSBryan Venteicher 
1844e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
1845e3c97c2cSBryan Venteicher 
18468f82136aSPatrick Kelsey 	vmxnet3_set_rxfilter(sc, if_getflags(ifp));
1847e3c97c2cSBryan Venteicher 
1848e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & IFCAP_VLAN_HWFILTER)
1849e3c97c2cSBryan Venteicher 		bcopy(sc->vmx_vlan_filter, sc->vmx_ds->vlan_filter,
1850e3c97c2cSBryan Venteicher 		    sizeof(sc->vmx_ds->vlan_filter));
1851e3c97c2cSBryan Venteicher 	else
1852e3c97c2cSBryan Venteicher 		bzero(sc->vmx_ds->vlan_filter,
1853e3c97c2cSBryan Venteicher 		    sizeof(sc->vmx_ds->vlan_filter));
1854e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_VLAN_FILTER);
1855e3c97c2cSBryan Venteicher }
1856e3c97c2cSBryan Venteicher 
18578f82136aSPatrick Kelsey static void
18588f82136aSPatrick Kelsey vmxnet3_init(if_ctx_t ctx)
1859e3c97c2cSBryan Venteicher {
18608f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
18618f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
1862e3c97c2cSBryan Venteicher 
18638f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
18648f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
18658f82136aSPatrick Kelsey 
18668f82136aSPatrick Kelsey 	scctx->isc_max_frame_size = if_getmtu(iflib_get_ifp(ctx)) +
18678f82136aSPatrick Kelsey 	    ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + ETHER_CRC_LEN;
18688f82136aSPatrick Kelsey 
18698f82136aSPatrick Kelsey 	/* Use the current MAC address. */
18708f82136aSPatrick Kelsey 	bcopy(IF_LLADDR(sc->vmx_ifp), sc->vmx_lladdr, ETHER_ADDR_LEN);
18718f82136aSPatrick Kelsey 	vmxnet3_set_lladdr(sc);
18728f82136aSPatrick Kelsey 
1873e3c97c2cSBryan Venteicher 	vmxnet3_reinit_shared_data(sc);
18748f82136aSPatrick Kelsey 	vmxnet3_reinit_queues(sc);
1875e3c97c2cSBryan Venteicher 
18768f82136aSPatrick Kelsey 	vmxnet3_enable_device(sc);
1877e3c97c2cSBryan Venteicher 
1878e3c97c2cSBryan Venteicher 	vmxnet3_reinit_rxfilters(sc);
1879e3c97c2cSBryan Venteicher 	vmxnet3_link_status(sc);
1880e3c97c2cSBryan Venteicher }
1881e3c97c2cSBryan Venteicher 
1882e3c97c2cSBryan Venteicher static void
18838f82136aSPatrick Kelsey vmxnet3_multi_set(if_ctx_t ctx)
1884e3c97c2cSBryan Venteicher {
1885e3c97c2cSBryan Venteicher 
18868f82136aSPatrick Kelsey 	vmxnet3_set_rxfilter(iflib_get_softc(ctx),
18878f82136aSPatrick Kelsey 	    if_getflags(iflib_get_ifp(ctx)));
1888e3c97c2cSBryan Venteicher }
1889e3c97c2cSBryan Venteicher 
1890e3c97c2cSBryan Venteicher static int
18918f82136aSPatrick Kelsey vmxnet3_mtu_set(if_ctx_t ctx, uint32_t mtu)
1892e3c97c2cSBryan Venteicher {
1893e3c97c2cSBryan Venteicher 
18948f82136aSPatrick Kelsey 	if (mtu > VMXNET3_TX_MAXSIZE - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN +
18958f82136aSPatrick Kelsey 		ETHER_CRC_LEN))
1896e3c97c2cSBryan Venteicher 		return (EINVAL);
1897e3c97c2cSBryan Venteicher 
1898e3c97c2cSBryan Venteicher 	return (0);
1899e3c97c2cSBryan Venteicher }
1900e3c97c2cSBryan Venteicher 
19018f82136aSPatrick Kelsey static void
19028f82136aSPatrick Kelsey vmxnet3_media_status(if_ctx_t ctx, struct ifmediareq * ifmr)
1903e3c97c2cSBryan Venteicher {
19048f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
1905e3c97c2cSBryan Venteicher 
19068f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
1907e3c97c2cSBryan Venteicher 
19088f82136aSPatrick Kelsey 	ifmr->ifm_status = IFM_AVALID;
19098f82136aSPatrick Kelsey 	ifmr->ifm_active = IFM_ETHER;
1910e3c97c2cSBryan Venteicher 
19118f82136aSPatrick Kelsey 	if (vmxnet3_link_is_up(sc) != 0) {
19128f82136aSPatrick Kelsey 		ifmr->ifm_status |= IFM_ACTIVE;
19138f82136aSPatrick Kelsey 		ifmr->ifm_active |= IFM_AUTO;
1914e3c97c2cSBryan Venteicher 	} else
19158f82136aSPatrick Kelsey 		ifmr->ifm_active |= IFM_NONE;
1916e3c97c2cSBryan Venteicher }
1917e3c97c2cSBryan Venteicher 
1918e3c97c2cSBryan Venteicher static int
19198f82136aSPatrick Kelsey vmxnet3_media_change(if_ctx_t ctx)
1920e3c97c2cSBryan Venteicher {
1921e3c97c2cSBryan Venteicher 
19228f82136aSPatrick Kelsey 	/* Ignore. */
1923c7156fe9SLuigi Rizzo 	return (0);
1924e557c1ddSBryan Venteicher }
1925e557c1ddSBryan Venteicher 
1926e557c1ddSBryan Venteicher static int
19278f82136aSPatrick Kelsey vmxnet3_promisc_set(if_ctx_t ctx, int flags)
1928e557c1ddSBryan Venteicher {
1929e557c1ddSBryan Venteicher 
19308f82136aSPatrick Kelsey 	vmxnet3_set_rxfilter(iflib_get_softc(ctx), flags);
1931e557c1ddSBryan Venteicher 
19328f82136aSPatrick Kelsey 	return (0);
1933e557c1ddSBryan Venteicher }
1934e557c1ddSBryan Venteicher 
19358f82136aSPatrick Kelsey static uint64_t
19368f82136aSPatrick Kelsey vmxnet3_get_counter(if_ctx_t ctx, ift_counter cnt)
19378f82136aSPatrick Kelsey {
19388f82136aSPatrick Kelsey 	if_t ifp = iflib_get_ifp(ctx);
19398f82136aSPatrick Kelsey 
19408f82136aSPatrick Kelsey 	if (cnt < IFCOUNTERS)
19418f82136aSPatrick Kelsey 		return if_get_counter_default(ifp, cnt);
19428f82136aSPatrick Kelsey 
19438f82136aSPatrick Kelsey 	return (0);
1944e557c1ddSBryan Venteicher }
1945e557c1ddSBryan Venteicher 
1946e557c1ddSBryan Venteicher static void
19478f82136aSPatrick Kelsey vmxnet3_update_admin_status(if_ctx_t ctx)
1948e557c1ddSBryan Venteicher {
1949e557c1ddSBryan Venteicher 	struct vmxnet3_softc *sc;
1950e557c1ddSBryan Venteicher 
19518f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
19528f82136aSPatrick Kelsey 	if (sc->vmx_ds->event != 0)
19538f82136aSPatrick Kelsey 		vmxnet3_evintr(sc);
1954e557c1ddSBryan Venteicher 
19558f82136aSPatrick Kelsey 	vmxnet3_refresh_host_stats(sc);
1956e557c1ddSBryan Venteicher }
1957e557c1ddSBryan Venteicher 
1958e557c1ddSBryan Venteicher static void
19598f82136aSPatrick Kelsey vmxnet3_txq_timer(if_ctx_t ctx, uint16_t qid)
1960e557c1ddSBryan Venteicher {
19618f82136aSPatrick Kelsey 	/* Host stats refresh is global, so just trigger it on txq 0 */
19628f82136aSPatrick Kelsey 	if (qid == 0)
19638f82136aSPatrick Kelsey 		vmxnet3_refresh_host_stats(iflib_get_softc(ctx));
1964e557c1ddSBryan Venteicher }
1965e557c1ddSBryan Venteicher 
1966e3c97c2cSBryan Venteicher static void
1967e3c97c2cSBryan Venteicher vmxnet3_update_vlan_filter(struct vmxnet3_softc *sc, int add, uint16_t tag)
1968e3c97c2cSBryan Venteicher {
1969e3c97c2cSBryan Venteicher 	int idx, bit;
1970e3c97c2cSBryan Venteicher 
1971e3c97c2cSBryan Venteicher 	if (tag == 0 || tag > 4095)
1972e3c97c2cSBryan Venteicher 		return;
1973e3c97c2cSBryan Venteicher 
19748f82136aSPatrick Kelsey 	idx = (tag >> 5) & 0x7F;
19758f82136aSPatrick Kelsey 	bit = tag & 0x1F;
1976e3c97c2cSBryan Venteicher 
1977e3c97c2cSBryan Venteicher 	/* Update our private VLAN bitvector. */
1978e3c97c2cSBryan Venteicher 	if (add)
1979e3c97c2cSBryan Venteicher 		sc->vmx_vlan_filter[idx] |= (1 << bit);
1980e3c97c2cSBryan Venteicher 	else
1981e3c97c2cSBryan Venteicher 		sc->vmx_vlan_filter[idx] &= ~(1 << bit);
1982e3c97c2cSBryan Venteicher }
1983e3c97c2cSBryan Venteicher 
1984e3c97c2cSBryan Venteicher static void
19858f82136aSPatrick Kelsey vmxnet3_vlan_register(if_ctx_t ctx, uint16_t tag)
1986e3c97c2cSBryan Venteicher {
1987e3c97c2cSBryan Venteicher 
19888f82136aSPatrick Kelsey 	vmxnet3_update_vlan_filter(iflib_get_softc(ctx), 1, tag);
1989e3c97c2cSBryan Venteicher }
1990e3c97c2cSBryan Venteicher 
1991e3c97c2cSBryan Venteicher static void
19928f82136aSPatrick Kelsey vmxnet3_vlan_unregister(if_ctx_t ctx, uint16_t tag)
1993e3c97c2cSBryan Venteicher {
1994e3c97c2cSBryan Venteicher 
19958f82136aSPatrick Kelsey 	vmxnet3_update_vlan_filter(iflib_get_softc(ctx), 0, tag);
1996e3c97c2cSBryan Venteicher }
1997e3c97c2cSBryan Venteicher 
1998d6b5965bSGleb Smirnoff static u_int
1999d6b5965bSGleb Smirnoff vmxnet3_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int count)
2000d6b5965bSGleb Smirnoff {
2001d6b5965bSGleb Smirnoff 	struct vmxnet3_softc *sc = arg;
2002d6b5965bSGleb Smirnoff 
2003d6b5965bSGleb Smirnoff 	if (count < VMXNET3_MULTICAST_MAX)
2004d6b5965bSGleb Smirnoff 		bcopy(LLADDR(sdl), &sc->vmx_mcast[count * ETHER_ADDR_LEN],
2005d6b5965bSGleb Smirnoff 		    ETHER_ADDR_LEN);
2006d6b5965bSGleb Smirnoff 
2007d6b5965bSGleb Smirnoff 	return (1);
2008d6b5965bSGleb Smirnoff }
2009d6b5965bSGleb Smirnoff 
2010e3c97c2cSBryan Venteicher static void
20118f82136aSPatrick Kelsey vmxnet3_set_rxfilter(struct vmxnet3_softc *sc, int flags)
2012e3c97c2cSBryan Venteicher {
2013e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
2014e3c97c2cSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
2015e3c97c2cSBryan Venteicher 	u_int mode;
2016e3c97c2cSBryan Venteicher 
2017e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
2018e3c97c2cSBryan Venteicher 	ds = sc->vmx_ds;
2019e3c97c2cSBryan Venteicher 
2020e557c1ddSBryan Venteicher 	mode = VMXNET3_RXMODE_UCAST | VMXNET3_RXMODE_BCAST;
20218f82136aSPatrick Kelsey 	if (flags & IFF_PROMISC)
2022e3c97c2cSBryan Venteicher 		mode |= VMXNET3_RXMODE_PROMISC;
20238f82136aSPatrick Kelsey 	if (flags & IFF_ALLMULTI)
2024e3c97c2cSBryan Venteicher 		mode |= VMXNET3_RXMODE_ALLMULTI;
2025e3c97c2cSBryan Venteicher 	else {
2026d6b5965bSGleb Smirnoff 		int cnt;
2027e3c97c2cSBryan Venteicher 
2028d6b5965bSGleb Smirnoff 		cnt = if_foreach_llmaddr(ifp, vmxnet3_hash_maddr, sc);
2029d6b5965bSGleb Smirnoff 		if (cnt >= VMXNET3_MULTICAST_MAX) {
2030e3c97c2cSBryan Venteicher 			cnt = 0;
2031e3c97c2cSBryan Venteicher 			mode |= VMXNET3_RXMODE_ALLMULTI;
2032e3c97c2cSBryan Venteicher 		} else if (cnt > 0)
2033e3c97c2cSBryan Venteicher 			mode |= VMXNET3_RXMODE_MCAST;
2034e3c97c2cSBryan Venteicher 		ds->mcast_tablelen = cnt * ETHER_ADDR_LEN;
2035e3c97c2cSBryan Venteicher 	}
2036e3c97c2cSBryan Venteicher 
2037e3c97c2cSBryan Venteicher 	ds->rxmode = mode;
2038e3c97c2cSBryan Venteicher 
2039e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_SET_FILTER);
2040e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_SET_RXMODE);
2041e3c97c2cSBryan Venteicher }
2042e3c97c2cSBryan Venteicher 
2043e3c97c2cSBryan Venteicher static void
2044e557c1ddSBryan Venteicher vmxnet3_refresh_host_stats(struct vmxnet3_softc *sc)
2045e3c97c2cSBryan Venteicher {
2046e3c97c2cSBryan Venteicher 
2047e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_GET_STATS);
2048e3c97c2cSBryan Venteicher }
2049e3c97c2cSBryan Venteicher 
2050e3c97c2cSBryan Venteicher static int
2051e3c97c2cSBryan Venteicher vmxnet3_link_is_up(struct vmxnet3_softc *sc)
2052e3c97c2cSBryan Venteicher {
2053e3c97c2cSBryan Venteicher 	uint32_t status;
2054e3c97c2cSBryan Venteicher 
2055e3c97c2cSBryan Venteicher 	status = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_LINK);
2056e3c97c2cSBryan Venteicher 	return !!(status & 0x1);
2057e3c97c2cSBryan Venteicher }
2058e3c97c2cSBryan Venteicher 
2059e3c97c2cSBryan Venteicher static void
2060e3c97c2cSBryan Venteicher vmxnet3_link_status(struct vmxnet3_softc *sc)
2061e3c97c2cSBryan Venteicher {
20628f82136aSPatrick Kelsey 	if_ctx_t ctx;
20638f82136aSPatrick Kelsey 	uint64_t speed;
2064e3c97c2cSBryan Venteicher 	int link;
2065e3c97c2cSBryan Venteicher 
20668f82136aSPatrick Kelsey 	ctx = sc->vmx_ctx;
2067e3c97c2cSBryan Venteicher 	link = vmxnet3_link_is_up(sc);
20688f82136aSPatrick Kelsey 	speed = IF_Gbps(10);
2069e3c97c2cSBryan Venteicher 
2070e3c97c2cSBryan Venteicher 	if (link != 0 && sc->vmx_link_active == 0) {
2071e3c97c2cSBryan Venteicher 		sc->vmx_link_active = 1;
20728f82136aSPatrick Kelsey 		iflib_link_state_change(ctx, LINK_STATE_UP, speed);
2073e3c97c2cSBryan Venteicher 	} else if (link == 0 && sc->vmx_link_active != 0) {
2074e3c97c2cSBryan Venteicher 		sc->vmx_link_active = 0;
20758f82136aSPatrick Kelsey 		iflib_link_state_change(ctx, LINK_STATE_DOWN, speed);
2076e3c97c2cSBryan Venteicher 	}
2077e3c97c2cSBryan Venteicher }
2078e3c97c2cSBryan Venteicher 
2079e3c97c2cSBryan Venteicher static void
2080e3c97c2cSBryan Venteicher vmxnet3_set_lladdr(struct vmxnet3_softc *sc)
2081e3c97c2cSBryan Venteicher {
2082e3c97c2cSBryan Venteicher 	uint32_t ml, mh;
2083e3c97c2cSBryan Venteicher 
2084e3c97c2cSBryan Venteicher 	ml  = sc->vmx_lladdr[0];
2085e3c97c2cSBryan Venteicher 	ml |= sc->vmx_lladdr[1] << 8;
2086e3c97c2cSBryan Venteicher 	ml |= sc->vmx_lladdr[2] << 16;
2087e3c97c2cSBryan Venteicher 	ml |= sc->vmx_lladdr[3] << 24;
2088e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_MACL, ml);
2089e3c97c2cSBryan Venteicher 
2090e3c97c2cSBryan Venteicher 	mh  = sc->vmx_lladdr[4];
2091e3c97c2cSBryan Venteicher 	mh |= sc->vmx_lladdr[5] << 8;
2092e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_MACH, mh);
2093e3c97c2cSBryan Venteicher }
2094e3c97c2cSBryan Venteicher 
2095e3c97c2cSBryan Venteicher static void
2096e3c97c2cSBryan Venteicher vmxnet3_get_lladdr(struct vmxnet3_softc *sc)
2097e3c97c2cSBryan Venteicher {
2098e3c97c2cSBryan Venteicher 	uint32_t ml, mh;
2099e3c97c2cSBryan Venteicher 
2100e3c97c2cSBryan Venteicher 	ml = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_MACL);
2101e3c97c2cSBryan Venteicher 	mh = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_MACH);
2102e3c97c2cSBryan Venteicher 
2103e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[0] = ml;
2104e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[1] = ml >> 8;
2105e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[2] = ml >> 16;
2106e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[3] = ml >> 24;
2107e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[4] = mh;
2108e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[5] = mh >> 8;
2109e3c97c2cSBryan Venteicher }
2110e3c97c2cSBryan Venteicher 
2111e3c97c2cSBryan Venteicher static void
2112e3c97c2cSBryan Venteicher vmxnet3_setup_txq_sysctl(struct vmxnet3_txqueue *txq,
2113e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2114e3c97c2cSBryan Venteicher {
2115e3c97c2cSBryan Venteicher 	struct sysctl_oid *node, *txsnode;
2116e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *list, *txslist;
2117e3c97c2cSBryan Venteicher 	struct UPT1_TxStats *txstats;
2118e3c97c2cSBryan Venteicher 	char namebuf[16];
2119e3c97c2cSBryan Venteicher 
2120e3c97c2cSBryan Venteicher 	txstats = &txq->vxtxq_ts->stats;
2121e3c97c2cSBryan Venteicher 
2122e3c97c2cSBryan Venteicher 	snprintf(namebuf, sizeof(namebuf), "txq%d", txq->vxtxq_id);
2123e3c97c2cSBryan Venteicher 	node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, CTLFLAG_RD,
2124e3c97c2cSBryan Venteicher 	    NULL, "Transmit Queue");
2125e3c97c2cSBryan Venteicher 	txq->vxtxq_sysctl = list = SYSCTL_CHILDREN(node);
2126e3c97c2cSBryan Venteicher 
2127e3c97c2cSBryan Venteicher 	/*
21288f82136aSPatrick Kelsey 	 * Add statistics reported by the host. These are updated by the
21298f82136aSPatrick Kelsey 	 * iflib txq timer on txq 0.
2130e3c97c2cSBryan Venteicher 	 */
2131e3c97c2cSBryan Venteicher 	txsnode = SYSCTL_ADD_NODE(ctx, list, OID_AUTO, "hstats", CTLFLAG_RD,
2132e3c97c2cSBryan Venteicher 	    NULL, "Host Statistics");
2133e3c97c2cSBryan Venteicher 	txslist = SYSCTL_CHILDREN(txsnode);
2134e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "tso_packets", CTLFLAG_RD,
2135e3c97c2cSBryan Venteicher 	    &txstats->TSO_packets, "TSO packets");
2136e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "tso_bytes", CTLFLAG_RD,
2137e3c97c2cSBryan Venteicher 	    &txstats->TSO_bytes, "TSO bytes");
2138e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "ucast_packets", CTLFLAG_RD,
2139e3c97c2cSBryan Venteicher 	    &txstats->ucast_packets, "Unicast packets");
2140e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "unicast_bytes", CTLFLAG_RD,
2141e3c97c2cSBryan Venteicher 	    &txstats->ucast_bytes, "Unicast bytes");
2142e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "mcast_packets", CTLFLAG_RD,
2143e3c97c2cSBryan Venteicher 	    &txstats->mcast_packets, "Multicast packets");
2144e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "mcast_bytes", CTLFLAG_RD,
2145e3c97c2cSBryan Venteicher 	    &txstats->mcast_bytes, "Multicast bytes");
2146e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "error", CTLFLAG_RD,
2147e3c97c2cSBryan Venteicher 	    &txstats->error, "Errors");
2148e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "discard", CTLFLAG_RD,
2149e3c97c2cSBryan Venteicher 	    &txstats->discard, "Discards");
2150e3c97c2cSBryan Venteicher }
2151e3c97c2cSBryan Venteicher 
2152e3c97c2cSBryan Venteicher static void
2153e3c97c2cSBryan Venteicher vmxnet3_setup_rxq_sysctl(struct vmxnet3_rxqueue *rxq,
2154e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2155e3c97c2cSBryan Venteicher {
2156e3c97c2cSBryan Venteicher 	struct sysctl_oid *node, *rxsnode;
2157e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *list, *rxslist;
2158e3c97c2cSBryan Venteicher 	struct UPT1_RxStats *rxstats;
2159e3c97c2cSBryan Venteicher 	char namebuf[16];
2160e3c97c2cSBryan Venteicher 
2161e3c97c2cSBryan Venteicher 	rxstats = &rxq->vxrxq_rs->stats;
2162e3c97c2cSBryan Venteicher 
2163e3c97c2cSBryan Venteicher 	snprintf(namebuf, sizeof(namebuf), "rxq%d", rxq->vxrxq_id);
2164e3c97c2cSBryan Venteicher 	node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, CTLFLAG_RD,
2165e3c97c2cSBryan Venteicher 	    NULL, "Receive Queue");
2166e3c97c2cSBryan Venteicher 	rxq->vxrxq_sysctl = list = SYSCTL_CHILDREN(node);
2167e3c97c2cSBryan Venteicher 
2168e3c97c2cSBryan Venteicher 	/*
21698f82136aSPatrick Kelsey 	 * Add statistics reported by the host. These are updated by the
21708f82136aSPatrick Kelsey 	 * iflib txq timer on txq 0.
2171e3c97c2cSBryan Venteicher 	 */
2172e3c97c2cSBryan Venteicher 	rxsnode = SYSCTL_ADD_NODE(ctx, list, OID_AUTO, "hstats", CTLFLAG_RD,
2173e3c97c2cSBryan Venteicher 	    NULL, "Host Statistics");
2174e3c97c2cSBryan Venteicher 	rxslist = SYSCTL_CHILDREN(rxsnode);
2175e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "lro_packets", CTLFLAG_RD,
2176e3c97c2cSBryan Venteicher 	    &rxstats->LRO_packets, "LRO packets");
2177e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "lro_bytes", CTLFLAG_RD,
2178e3c97c2cSBryan Venteicher 	    &rxstats->LRO_bytes, "LRO bytes");
2179e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "ucast_packets", CTLFLAG_RD,
2180e3c97c2cSBryan Venteicher 	    &rxstats->ucast_packets, "Unicast packets");
2181e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "unicast_bytes", CTLFLAG_RD,
2182e3c97c2cSBryan Venteicher 	    &rxstats->ucast_bytes, "Unicast bytes");
2183e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "mcast_packets", CTLFLAG_RD,
2184e3c97c2cSBryan Venteicher 	    &rxstats->mcast_packets, "Multicast packets");
2185e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "mcast_bytes", CTLFLAG_RD,
2186e3c97c2cSBryan Venteicher 	    &rxstats->mcast_bytes, "Multicast bytes");
2187e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "bcast_packets", CTLFLAG_RD,
2188e3c97c2cSBryan Venteicher 	    &rxstats->bcast_packets, "Broadcast packets");
2189e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "bcast_bytes", CTLFLAG_RD,
2190e3c97c2cSBryan Venteicher 	    &rxstats->bcast_bytes, "Broadcast bytes");
2191e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "nobuffer", CTLFLAG_RD,
2192e3c97c2cSBryan Venteicher 	    &rxstats->nobuffer, "No buffer");
2193e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "error", CTLFLAG_RD,
2194e3c97c2cSBryan Venteicher 	    &rxstats->error, "Errors");
2195e3c97c2cSBryan Venteicher }
2196e3c97c2cSBryan Venteicher 
2197e3c97c2cSBryan Venteicher static void
2198e3c97c2cSBryan Venteicher vmxnet3_setup_debug_sysctl(struct vmxnet3_softc *sc,
2199e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2200e3c97c2cSBryan Venteicher {
22018f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
2202e3c97c2cSBryan Venteicher 	struct sysctl_oid *node;
2203e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *list;
2204e3c97c2cSBryan Venteicher 	int i;
2205e3c97c2cSBryan Venteicher 
22068f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
22078f82136aSPatrick Kelsey 
22088f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++) {
2209e3c97c2cSBryan Venteicher 		struct vmxnet3_txqueue *txq = &sc->vmx_txq[i];
2210e3c97c2cSBryan Venteicher 
2211e3c97c2cSBryan Venteicher 		node = SYSCTL_ADD_NODE(ctx, txq->vxtxq_sysctl, OID_AUTO,
2212e3c97c2cSBryan Venteicher 		    "debug", CTLFLAG_RD, NULL, "");
2213e3c97c2cSBryan Venteicher 		list = SYSCTL_CHILDREN(node);
2214e3c97c2cSBryan Venteicher 
2215e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd_next", CTLFLAG_RD,
2216e3c97c2cSBryan Venteicher 		    &txq->vxtxq_cmd_ring.vxtxr_next, 0, "");
2217e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd_ndesc", CTLFLAG_RD,
2218e3c97c2cSBryan Venteicher 		    &txq->vxtxq_cmd_ring.vxtxr_ndesc, 0, "");
2219e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd_gen", CTLFLAG_RD,
2220e3c97c2cSBryan Venteicher 		    &txq->vxtxq_cmd_ring.vxtxr_gen, 0, "");
2221e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_next", CTLFLAG_RD,
2222e3c97c2cSBryan Venteicher 		    &txq->vxtxq_comp_ring.vxcr_next, 0, "");
2223e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_ndesc", CTLFLAG_RD,
2224e3c97c2cSBryan Venteicher 		    &txq->vxtxq_comp_ring.vxcr_ndesc, 0,"");
2225e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "comp_gen", CTLFLAG_RD,
2226e3c97c2cSBryan Venteicher 		    &txq->vxtxq_comp_ring.vxcr_gen, 0, "");
2227e3c97c2cSBryan Venteicher 	}
2228e3c97c2cSBryan Venteicher 
22298f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
2230e3c97c2cSBryan Venteicher 		struct vmxnet3_rxqueue *rxq = &sc->vmx_rxq[i];
2231e3c97c2cSBryan Venteicher 
2232e3c97c2cSBryan Venteicher 		node = SYSCTL_ADD_NODE(ctx, rxq->vxrxq_sysctl, OID_AUTO,
2233e3c97c2cSBryan Venteicher 		    "debug", CTLFLAG_RD, NULL, "");
2234e3c97c2cSBryan Venteicher 		list = SYSCTL_CHILDREN(node);
2235e3c97c2cSBryan Venteicher 
2236e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd0_ndesc", CTLFLAG_RD,
2237e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[0].vxrxr_ndesc, 0, "");
2238e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd0_gen", CTLFLAG_RD,
2239e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[0].vxrxr_gen, 0, "");
2240e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd1_ndesc", CTLFLAG_RD,
2241e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[1].vxrxr_ndesc, 0, "");
2242e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd1_gen", CTLFLAG_RD,
2243e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[1].vxrxr_gen, 0, "");
2244e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_ndesc", CTLFLAG_RD,
2245e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_comp_ring.vxcr_ndesc, 0,"");
2246e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "comp_gen", CTLFLAG_RD,
2247e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_comp_ring.vxcr_gen, 0, "");
2248e3c97c2cSBryan Venteicher 	}
2249e3c97c2cSBryan Venteicher }
2250e3c97c2cSBryan Venteicher 
2251e3c97c2cSBryan Venteicher static void
2252e3c97c2cSBryan Venteicher vmxnet3_setup_queue_sysctl(struct vmxnet3_softc *sc,
2253e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2254e3c97c2cSBryan Venteicher {
22558f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
2256e3c97c2cSBryan Venteicher 	int i;
2257e3c97c2cSBryan Venteicher 
22588f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
22598f82136aSPatrick Kelsey 
22608f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++)
2261e3c97c2cSBryan Venteicher 		vmxnet3_setup_txq_sysctl(&sc->vmx_txq[i], ctx, child);
22628f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++)
2263e3c97c2cSBryan Venteicher 		vmxnet3_setup_rxq_sysctl(&sc->vmx_rxq[i], ctx, child);
2264e3c97c2cSBryan Venteicher 
2265e3c97c2cSBryan Venteicher 	vmxnet3_setup_debug_sysctl(sc, ctx, child);
2266e3c97c2cSBryan Venteicher }
2267e3c97c2cSBryan Venteicher 
2268e3c97c2cSBryan Venteicher static void
2269e3c97c2cSBryan Venteicher vmxnet3_setup_sysctl(struct vmxnet3_softc *sc)
2270e3c97c2cSBryan Venteicher {
2271e3c97c2cSBryan Venteicher 	device_t dev;
2272e3c97c2cSBryan Venteicher 	struct sysctl_ctx_list *ctx;
2273e3c97c2cSBryan Venteicher 	struct sysctl_oid *tree;
2274e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *child;
2275e3c97c2cSBryan Venteicher 
2276e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
2277e3c97c2cSBryan Venteicher 	ctx = device_get_sysctl_ctx(dev);
2278e3c97c2cSBryan Venteicher 	tree = device_get_sysctl_tree(dev);
2279e3c97c2cSBryan Venteicher 	child = SYSCTL_CHILDREN(tree);
2280e3c97c2cSBryan Venteicher 
2281e3c97c2cSBryan Venteicher 	vmxnet3_setup_queue_sysctl(sc, ctx, child);
2282e3c97c2cSBryan Venteicher }
2283e3c97c2cSBryan Venteicher 
2284e3c97c2cSBryan Venteicher static void
2285e3c97c2cSBryan Venteicher vmxnet3_write_bar0(struct vmxnet3_softc *sc, bus_size_t r, uint32_t v)
2286e3c97c2cSBryan Venteicher {
2287e3c97c2cSBryan Venteicher 
2288e3c97c2cSBryan Venteicher 	bus_space_write_4(sc->vmx_iot0, sc->vmx_ioh0, r, v);
2289e3c97c2cSBryan Venteicher }
2290e3c97c2cSBryan Venteicher 
2291e3c97c2cSBryan Venteicher static uint32_t
2292e3c97c2cSBryan Venteicher vmxnet3_read_bar1(struct vmxnet3_softc *sc, bus_size_t r)
2293e3c97c2cSBryan Venteicher {
2294e3c97c2cSBryan Venteicher 
2295e3c97c2cSBryan Venteicher 	return (bus_space_read_4(sc->vmx_iot1, sc->vmx_ioh1, r));
2296e3c97c2cSBryan Venteicher }
2297e3c97c2cSBryan Venteicher 
2298e3c97c2cSBryan Venteicher static void
2299e3c97c2cSBryan Venteicher vmxnet3_write_bar1(struct vmxnet3_softc *sc, bus_size_t r, uint32_t v)
2300e3c97c2cSBryan Venteicher {
2301e3c97c2cSBryan Venteicher 
2302e3c97c2cSBryan Venteicher 	bus_space_write_4(sc->vmx_iot1, sc->vmx_ioh1, r, v);
2303e3c97c2cSBryan Venteicher }
2304e3c97c2cSBryan Venteicher 
2305e3c97c2cSBryan Venteicher static void
2306e3c97c2cSBryan Venteicher vmxnet3_write_cmd(struct vmxnet3_softc *sc, uint32_t cmd)
2307e3c97c2cSBryan Venteicher {
2308e3c97c2cSBryan Venteicher 
2309e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_CMD, cmd);
2310e3c97c2cSBryan Venteicher }
2311e3c97c2cSBryan Venteicher 
2312e3c97c2cSBryan Venteicher static uint32_t
2313e3c97c2cSBryan Venteicher vmxnet3_read_cmd(struct vmxnet3_softc *sc, uint32_t cmd)
2314e3c97c2cSBryan Venteicher {
2315e3c97c2cSBryan Venteicher 
2316e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, cmd);
2317e3c97c2cSBryan Venteicher 	bus_space_barrier(sc->vmx_iot1, sc->vmx_ioh1, 0, 0,
2318e3c97c2cSBryan Venteicher 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
2319e3c97c2cSBryan Venteicher 	return (vmxnet3_read_bar1(sc, VMXNET3_BAR1_CMD));
2320e3c97c2cSBryan Venteicher }
2321e3c97c2cSBryan Venteicher 
2322e3c97c2cSBryan Venteicher static void
2323e3c97c2cSBryan Venteicher vmxnet3_enable_intr(struct vmxnet3_softc *sc, int irq)
2324e3c97c2cSBryan Venteicher {
2325e3c97c2cSBryan Venteicher 
2326e3c97c2cSBryan Venteicher 	vmxnet3_write_bar0(sc, VMXNET3_BAR0_IMASK(irq), 0);
2327e3c97c2cSBryan Venteicher }
2328e3c97c2cSBryan Venteicher 
2329e3c97c2cSBryan Venteicher static void
2330e3c97c2cSBryan Venteicher vmxnet3_disable_intr(struct vmxnet3_softc *sc, int irq)
2331e3c97c2cSBryan Venteicher {
2332e3c97c2cSBryan Venteicher 
2333e3c97c2cSBryan Venteicher 	vmxnet3_write_bar0(sc, VMXNET3_BAR0_IMASK(irq), 1);
2334e3c97c2cSBryan Venteicher }
2335e3c97c2cSBryan Venteicher 
23368f82136aSPatrick Kelsey static int
23378f82136aSPatrick Kelsey vmxnet3_tx_queue_intr_enable(if_ctx_t ctx, uint16_t qid)
2338e3c97c2cSBryan Venteicher {
23398f82136aSPatrick Kelsey 	/* Not using interrupts for TX */
23408f82136aSPatrick Kelsey 	return (0);
23418f82136aSPatrick Kelsey }
23428f82136aSPatrick Kelsey 
23438f82136aSPatrick Kelsey static int
23448f82136aSPatrick Kelsey vmxnet3_rx_queue_intr_enable(if_ctx_t ctx, uint16_t qid)
23458f82136aSPatrick Kelsey {
23468f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
23478f82136aSPatrick Kelsey 
23488f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
23498f82136aSPatrick Kelsey 	vmxnet3_enable_intr(sc, sc->vmx_rxq[qid].vxrxq_intr_idx);
23508f82136aSPatrick Kelsey 	return (0);
23518f82136aSPatrick Kelsey }
23528f82136aSPatrick Kelsey 
23538f82136aSPatrick Kelsey static void
23548f82136aSPatrick Kelsey vmxnet3_link_intr_enable(if_ctx_t ctx)
23558f82136aSPatrick Kelsey {
23568f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
23578f82136aSPatrick Kelsey 
23588f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
23598f82136aSPatrick Kelsey 	vmxnet3_enable_intr(sc, sc->vmx_event_intr_idx);
23608f82136aSPatrick Kelsey }
23618f82136aSPatrick Kelsey 
23628f82136aSPatrick Kelsey static void
23638f82136aSPatrick Kelsey vmxnet3_intr_enable_all(if_ctx_t ctx)
23648f82136aSPatrick Kelsey {
23658f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
23668f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
2367e3c97c2cSBryan Venteicher 	int i;
2368e3c97c2cSBryan Venteicher 
23698f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
23708f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
2371e3c97c2cSBryan Venteicher 	sc->vmx_ds->ictrl &= ~VMXNET3_ICTRL_DISABLE_ALL;
23728f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_vectors; i++)
2373e3c97c2cSBryan Venteicher 		vmxnet3_enable_intr(sc, i);
2374e3c97c2cSBryan Venteicher }
2375e3c97c2cSBryan Venteicher 
2376e3c97c2cSBryan Venteicher static void
23778f82136aSPatrick Kelsey vmxnet3_intr_disable_all(if_ctx_t ctx)
2378e3c97c2cSBryan Venteicher {
23798f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
2380e3c97c2cSBryan Venteicher 	int i;
2381e3c97c2cSBryan Venteicher 
23828f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
23838f82136aSPatrick Kelsey 	/*
23848f82136aSPatrick Kelsey 	 * iflib may invoke this routine before vmxnet3_attach_post() has
23858f82136aSPatrick Kelsey 	 * run, which is before the top level shared data area is
23868f82136aSPatrick Kelsey 	 * initialized and the device made aware of it.
23878f82136aSPatrick Kelsey 	 */
23888f82136aSPatrick Kelsey 	if (sc->vmx_ds != NULL)
2389e3c97c2cSBryan Venteicher 		sc->vmx_ds->ictrl |= VMXNET3_ICTRL_DISABLE_ALL;
23908f82136aSPatrick Kelsey 	for (i = 0; i < VMXNET3_MAX_INTRS; i++)
2391e3c97c2cSBryan Venteicher 		vmxnet3_disable_intr(sc, i);
2392e3c97c2cSBryan Venteicher }
2393e3c97c2cSBryan Venteicher 
2394e3c97c2cSBryan Venteicher /*
2395e3c97c2cSBryan Venteicher  * Since this is a purely paravirtualized device, we do not have
2396e3c97c2cSBryan Venteicher  * to worry about DMA coherency. But at times, we must make sure
2397e3c97c2cSBryan Venteicher  * both the compiler and CPU do not reorder memory operations.
2398e3c97c2cSBryan Venteicher  */
2399e3c97c2cSBryan Venteicher static inline void
2400e3c97c2cSBryan Venteicher vmxnet3_barrier(struct vmxnet3_softc *sc, vmxnet3_barrier_t type)
2401e3c97c2cSBryan Venteicher {
2402e3c97c2cSBryan Venteicher 
2403e3c97c2cSBryan Venteicher 	switch (type) {
2404e3c97c2cSBryan Venteicher 	case VMXNET3_BARRIER_RD:
2405e3c97c2cSBryan Venteicher 		rmb();
2406e3c97c2cSBryan Venteicher 		break;
2407e3c97c2cSBryan Venteicher 	case VMXNET3_BARRIER_WR:
2408e3c97c2cSBryan Venteicher 		wmb();
2409e3c97c2cSBryan Venteicher 		break;
2410e3c97c2cSBryan Venteicher 	case VMXNET3_BARRIER_RDWR:
2411e3c97c2cSBryan Venteicher 		mb();
2412e3c97c2cSBryan Venteicher 		break;
2413e3c97c2cSBryan Venteicher 	default:
2414e3c97c2cSBryan Venteicher 		panic("%s: bad barrier type %d", __func__, type);
2415e3c97c2cSBryan Venteicher 	}
2416e3c97c2cSBryan Venteicher }
2417