xref: /freebsd/sys/dev/vmware/vmxnet3/if_vmx.c (revision 7029da5c36f2d3cf6bb6c81bf551229f416399e8)
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 
26281cab4dSAndriy Gapon #include "opt_rss.h"
27281cab4dSAndriy Gapon 
28e3c97c2cSBryan Venteicher #include <sys/param.h>
29e3c97c2cSBryan Venteicher #include <sys/systm.h>
30e3c97c2cSBryan Venteicher #include <sys/kernel.h>
31e3c97c2cSBryan Venteicher #include <sys/endian.h>
32e3c97c2cSBryan Venteicher #include <sys/sockio.h>
33e3c97c2cSBryan Venteicher #include <sys/mbuf.h>
34e3c97c2cSBryan Venteicher #include <sys/malloc.h>
35e3c97c2cSBryan Venteicher #include <sys/module.h>
36e3c97c2cSBryan Venteicher #include <sys/socket.h>
37e3c97c2cSBryan Venteicher #include <sys/sysctl.h>
38e557c1ddSBryan Venteicher #include <sys/smp.h>
39e3c97c2cSBryan Venteicher #include <vm/vm.h>
40e3c97c2cSBryan Venteicher #include <vm/pmap.h>
41e3c97c2cSBryan Venteicher 
42e3c97c2cSBryan Venteicher #include <net/ethernet.h>
43e3c97c2cSBryan Venteicher #include <net/if.h>
4476039bc8SGleb Smirnoff #include <net/if_var.h>
45e3c97c2cSBryan Venteicher #include <net/if_arp.h>
46e3c97c2cSBryan Venteicher #include <net/if_dl.h>
47e3c97c2cSBryan Venteicher #include <net/if_types.h>
48e3c97c2cSBryan Venteicher #include <net/if_media.h>
49e3c97c2cSBryan Venteicher #include <net/if_vlan_var.h>
508f82136aSPatrick Kelsey #include <net/iflib.h>
51281cab4dSAndriy Gapon #ifdef RSS
52281cab4dSAndriy Gapon #include <net/rss_config.h>
53281cab4dSAndriy Gapon #endif
54e3c97c2cSBryan Venteicher 
55e3c97c2cSBryan Venteicher #include <netinet/in_systm.h>
56e3c97c2cSBryan Venteicher #include <netinet/in.h>
57e3c97c2cSBryan Venteicher #include <netinet/ip.h>
58e3c97c2cSBryan Venteicher #include <netinet/ip6.h>
59e3c97c2cSBryan Venteicher #include <netinet6/ip6_var.h>
60e3c97c2cSBryan Venteicher #include <netinet/udp.h>
61e3c97c2cSBryan Venteicher #include <netinet/tcp.h>
62e3c97c2cSBryan Venteicher 
63e3c97c2cSBryan Venteicher #include <machine/bus.h>
64e3c97c2cSBryan Venteicher #include <machine/resource.h>
65e3c97c2cSBryan Venteicher #include <sys/bus.h>
66e3c97c2cSBryan Venteicher #include <sys/rman.h>
67e3c97c2cSBryan Venteicher 
68e3c97c2cSBryan Venteicher #include <dev/pci/pcireg.h>
69e3c97c2cSBryan Venteicher #include <dev/pci/pcivar.h>
70e3c97c2cSBryan Venteicher 
718f82136aSPatrick Kelsey #include "ifdi_if.h"
728f82136aSPatrick Kelsey 
73e3c97c2cSBryan Venteicher #include "if_vmxreg.h"
74e3c97c2cSBryan Venteicher #include "if_vmxvar.h"
75e3c97c2cSBryan Venteicher 
76e3c97c2cSBryan Venteicher #include "opt_inet.h"
77e3c97c2cSBryan Venteicher #include "opt_inet6.h"
78e3c97c2cSBryan Venteicher 
79e3c97c2cSBryan Venteicher 
808f82136aSPatrick Kelsey #define VMXNET3_VMWARE_VENDOR_ID	0x15AD
818f82136aSPatrick Kelsey #define VMXNET3_VMWARE_DEVICE_ID	0x07B0
828f82136aSPatrick Kelsey 
838f82136aSPatrick Kelsey static pci_vendor_info_t vmxnet3_vendor_info_array[] =
848f82136aSPatrick Kelsey {
858f82136aSPatrick Kelsey 	PVID(VMXNET3_VMWARE_VENDOR_ID, VMXNET3_VMWARE_DEVICE_ID, "VMware VMXNET3 Ethernet Adapter"),
868f82136aSPatrick Kelsey 	/* required last entry */
878f82136aSPatrick Kelsey 	PVID_END
888f82136aSPatrick Kelsey };
898f82136aSPatrick Kelsey 
908f82136aSPatrick Kelsey static void	*vmxnet3_register(device_t);
918f82136aSPatrick Kelsey static int	vmxnet3_attach_pre(if_ctx_t);
928f82136aSPatrick Kelsey static int	vmxnet3_msix_intr_assign(if_ctx_t, int);
938f82136aSPatrick Kelsey static void	vmxnet3_free_irqs(struct vmxnet3_softc *);
948f82136aSPatrick Kelsey static int	vmxnet3_attach_post(if_ctx_t);
958f82136aSPatrick Kelsey static int	vmxnet3_detach(if_ctx_t);
968f82136aSPatrick Kelsey static int	vmxnet3_shutdown(if_ctx_t);
978f82136aSPatrick Kelsey static int	vmxnet3_suspend(if_ctx_t);
988f82136aSPatrick Kelsey static int	vmxnet3_resume(if_ctx_t);
99e3c97c2cSBryan Venteicher 
100e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_resources(struct vmxnet3_softc *);
101e3c97c2cSBryan Venteicher static void	vmxnet3_free_resources(struct vmxnet3_softc *);
102e3c97c2cSBryan Venteicher static int	vmxnet3_check_version(struct vmxnet3_softc *);
1038f82136aSPatrick Kelsey static void	vmxnet3_set_interrupt_idx(struct vmxnet3_softc *);
104e3c97c2cSBryan Venteicher 
1058f82136aSPatrick Kelsey static int	vmxnet3_queues_shared_alloc(struct vmxnet3_softc *);
1068f82136aSPatrick Kelsey static void	vmxnet3_init_txq(struct vmxnet3_softc *, int);
1078f82136aSPatrick Kelsey static int	vmxnet3_tx_queues_alloc(if_ctx_t, caddr_t *, uint64_t *, int, int);
1088f82136aSPatrick Kelsey static void	vmxnet3_init_rxq(struct vmxnet3_softc *, int, int);
1098f82136aSPatrick Kelsey static int	vmxnet3_rx_queues_alloc(if_ctx_t, caddr_t *, uint64_t *, int, int);
1108f82136aSPatrick Kelsey static void	vmxnet3_queues_free(if_ctx_t);
111e3c97c2cSBryan Venteicher 
112e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_shared_data(struct vmxnet3_softc *);
113e3c97c2cSBryan Venteicher static void	vmxnet3_free_shared_data(struct vmxnet3_softc *);
114e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_mcast_table(struct vmxnet3_softc *);
1158f82136aSPatrick Kelsey static void	vmxnet3_free_mcast_table(struct vmxnet3_softc *);
116e3c97c2cSBryan Venteicher static void	vmxnet3_init_shared_data(struct vmxnet3_softc *);
117e557c1ddSBryan Venteicher static void	vmxnet3_reinit_rss_shared_data(struct vmxnet3_softc *);
118e3c97c2cSBryan Venteicher static void	vmxnet3_reinit_shared_data(struct vmxnet3_softc *);
119e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_data(struct vmxnet3_softc *);
120e3c97c2cSBryan Venteicher static void	vmxnet3_free_data(struct vmxnet3_softc *);
121e3c97c2cSBryan Venteicher 
122e3c97c2cSBryan Venteicher static void	vmxnet3_evintr(struct vmxnet3_softc *);
1238f82136aSPatrick Kelsey static int	vmxnet3_isc_txd_encap(void *, if_pkt_info_t);
1248f82136aSPatrick Kelsey static void	vmxnet3_isc_txd_flush(void *, uint16_t, qidx_t);
1258f82136aSPatrick Kelsey static int	vmxnet3_isc_txd_credits_update(void *, uint16_t, bool);
1268f82136aSPatrick Kelsey static int	vmxnet3_isc_rxd_available(void *, uint16_t, qidx_t, qidx_t);
1278f82136aSPatrick Kelsey static int	vmxnet3_isc_rxd_pkt_get(void *, if_rxd_info_t);
1288f82136aSPatrick Kelsey static void	vmxnet3_isc_rxd_refill(void *, if_rxd_update_t);
1298f82136aSPatrick Kelsey static void	vmxnet3_isc_rxd_flush(void *, uint16_t, uint8_t, qidx_t);
1308f82136aSPatrick Kelsey static int	vmxnet3_legacy_intr(void *);
1318f82136aSPatrick Kelsey static int	vmxnet3_rxq_intr(void *);
1328f82136aSPatrick Kelsey static int	vmxnet3_event_intr(void *);
133e3c97c2cSBryan Venteicher 
1348f82136aSPatrick Kelsey static void	vmxnet3_stop(if_ctx_t);
135e3c97c2cSBryan Venteicher 
136e3c97c2cSBryan Venteicher static void	vmxnet3_txinit(struct vmxnet3_softc *, struct vmxnet3_txqueue *);
1378f82136aSPatrick Kelsey static void	vmxnet3_rxinit(struct vmxnet3_softc *, struct vmxnet3_rxqueue *);
1388f82136aSPatrick Kelsey static void	vmxnet3_reinit_queues(struct vmxnet3_softc *);
139e3c97c2cSBryan Venteicher static int	vmxnet3_enable_device(struct vmxnet3_softc *);
140e3c97c2cSBryan Venteicher static void	vmxnet3_reinit_rxfilters(struct vmxnet3_softc *);
1418f82136aSPatrick Kelsey static void	vmxnet3_init(if_ctx_t);
1428f82136aSPatrick Kelsey static void	vmxnet3_multi_set(if_ctx_t);
1438f82136aSPatrick Kelsey static int	vmxnet3_mtu_set(if_ctx_t, uint32_t);
1448f82136aSPatrick Kelsey static void	vmxnet3_media_status(if_ctx_t, struct ifmediareq *);
1458f82136aSPatrick Kelsey static int	vmxnet3_media_change(if_ctx_t);
1468f82136aSPatrick Kelsey static int	vmxnet3_promisc_set(if_ctx_t, int);
1478f82136aSPatrick Kelsey static uint64_t	vmxnet3_get_counter(if_ctx_t, ift_counter);
1488f82136aSPatrick Kelsey static void	vmxnet3_update_admin_status(if_ctx_t);
1498f82136aSPatrick Kelsey static void	vmxnet3_txq_timer(if_ctx_t, uint16_t);
150e3c97c2cSBryan Venteicher 
151e3c97c2cSBryan Venteicher static void	vmxnet3_update_vlan_filter(struct vmxnet3_softc *, int,
152e3c97c2cSBryan Venteicher 		    uint16_t);
1538f82136aSPatrick Kelsey static void	vmxnet3_vlan_register(if_ctx_t, uint16_t);
1548f82136aSPatrick Kelsey static void	vmxnet3_vlan_unregister(if_ctx_t, uint16_t);
1558f82136aSPatrick Kelsey static void	vmxnet3_set_rxfilter(struct vmxnet3_softc *, int);
156e3c97c2cSBryan Venteicher 
157e557c1ddSBryan Venteicher static void	vmxnet3_refresh_host_stats(struct vmxnet3_softc *);
1588f82136aSPatrick Kelsey static int	vmxnet3_link_is_up(struct vmxnet3_softc *);
159e3c97c2cSBryan Venteicher static void	vmxnet3_link_status(struct vmxnet3_softc *);
160e3c97c2cSBryan Venteicher static void	vmxnet3_set_lladdr(struct vmxnet3_softc *);
161e3c97c2cSBryan Venteicher static void	vmxnet3_get_lladdr(struct vmxnet3_softc *);
162e3c97c2cSBryan Venteicher 
163e3c97c2cSBryan Venteicher static void	vmxnet3_setup_txq_sysctl(struct vmxnet3_txqueue *,
164e3c97c2cSBryan Venteicher 		    struct sysctl_ctx_list *, struct sysctl_oid_list *);
165e3c97c2cSBryan Venteicher static void	vmxnet3_setup_rxq_sysctl(struct vmxnet3_rxqueue *,
166e3c97c2cSBryan Venteicher 		    struct sysctl_ctx_list *, struct sysctl_oid_list *);
167e3c97c2cSBryan Venteicher static void	vmxnet3_setup_queue_sysctl(struct vmxnet3_softc *,
168e3c97c2cSBryan Venteicher 		    struct sysctl_ctx_list *, struct sysctl_oid_list *);
169e3c97c2cSBryan Venteicher static void	vmxnet3_setup_sysctl(struct vmxnet3_softc *);
170e3c97c2cSBryan Venteicher 
171e3c97c2cSBryan Venteicher static void	vmxnet3_write_bar0(struct vmxnet3_softc *, bus_size_t,
172e3c97c2cSBryan Venteicher 		    uint32_t);
173e3c97c2cSBryan Venteicher static uint32_t	vmxnet3_read_bar1(struct vmxnet3_softc *, bus_size_t);
174e3c97c2cSBryan Venteicher static void	vmxnet3_write_bar1(struct vmxnet3_softc *, bus_size_t,
175e3c97c2cSBryan Venteicher 		    uint32_t);
176e3c97c2cSBryan Venteicher static void	vmxnet3_write_cmd(struct vmxnet3_softc *, uint32_t);
177e3c97c2cSBryan Venteicher static uint32_t	vmxnet3_read_cmd(struct vmxnet3_softc *, uint32_t);
178e3c97c2cSBryan Venteicher 
1798f82136aSPatrick Kelsey static int	vmxnet3_tx_queue_intr_enable(if_ctx_t, uint16_t);
1808f82136aSPatrick Kelsey static int	vmxnet3_rx_queue_intr_enable(if_ctx_t, uint16_t);
1818f82136aSPatrick Kelsey static void	vmxnet3_link_intr_enable(if_ctx_t);
182e3c97c2cSBryan Venteicher static void	vmxnet3_enable_intr(struct vmxnet3_softc *, int);
183e3c97c2cSBryan Venteicher static void	vmxnet3_disable_intr(struct vmxnet3_softc *, int);
1848f82136aSPatrick Kelsey static void	vmxnet3_intr_enable_all(if_ctx_t);
1858f82136aSPatrick Kelsey static void	vmxnet3_intr_disable_all(if_ctx_t);
186e3c97c2cSBryan Venteicher 
187e3c97c2cSBryan Venteicher typedef enum {
188e3c97c2cSBryan Venteicher 	VMXNET3_BARRIER_RD,
189e3c97c2cSBryan Venteicher 	VMXNET3_BARRIER_WR,
190e3c97c2cSBryan Venteicher 	VMXNET3_BARRIER_RDWR,
191e3c97c2cSBryan Venteicher } vmxnet3_barrier_t;
192e3c97c2cSBryan Venteicher 
193e3c97c2cSBryan Venteicher static void	vmxnet3_barrier(struct vmxnet3_softc *, vmxnet3_barrier_t);
194e3c97c2cSBryan Venteicher 
1953c5dfe89SBryan Venteicher 
196e3c97c2cSBryan Venteicher static device_method_t vmxnet3_methods[] = {
1978f82136aSPatrick Kelsey 	/* Device interface */
1988f82136aSPatrick Kelsey 	DEVMETHOD(device_register, vmxnet3_register),
1998f82136aSPatrick Kelsey 	DEVMETHOD(device_probe, iflib_device_probe),
2008f82136aSPatrick Kelsey 	DEVMETHOD(device_attach, iflib_device_attach),
2018f82136aSPatrick Kelsey 	DEVMETHOD(device_detach, iflib_device_detach),
2028f82136aSPatrick Kelsey 	DEVMETHOD(device_shutdown, iflib_device_shutdown),
2038f82136aSPatrick Kelsey 	DEVMETHOD(device_suspend, iflib_device_suspend),
2048f82136aSPatrick Kelsey 	DEVMETHOD(device_resume, iflib_device_resume),
205e3c97c2cSBryan Venteicher 	DEVMETHOD_END
206e3c97c2cSBryan Venteicher };
207e3c97c2cSBryan Venteicher 
208e3c97c2cSBryan Venteicher static driver_t vmxnet3_driver = {
209e3c97c2cSBryan Venteicher 	"vmx", vmxnet3_methods, sizeof(struct vmxnet3_softc)
210e3c97c2cSBryan Venteicher };
211e3c97c2cSBryan Venteicher 
212e3c97c2cSBryan Venteicher static devclass_t vmxnet3_devclass;
213e3c97c2cSBryan Venteicher DRIVER_MODULE(vmx, pci, vmxnet3_driver, vmxnet3_devclass, 0, 0);
2148f82136aSPatrick Kelsey IFLIB_PNP_INFO(pci, vmx, vmxnet3_vendor_info_array);
2158f82136aSPatrick Kelsey MODULE_VERSION(vmx, 2);
216e3c97c2cSBryan Venteicher 
217e3c97c2cSBryan Venteicher MODULE_DEPEND(vmx, pci, 1, 1, 1);
218e3c97c2cSBryan Venteicher MODULE_DEPEND(vmx, ether, 1, 1, 1);
2198f82136aSPatrick Kelsey MODULE_DEPEND(vmx, iflib, 1, 1, 1);
220e3c97c2cSBryan Venteicher 
2218f82136aSPatrick Kelsey static device_method_t vmxnet3_iflib_methods[] = {
2228f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_tx_queues_alloc, vmxnet3_tx_queues_alloc),
2238f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_rx_queues_alloc, vmxnet3_rx_queues_alloc),
2248f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_queues_free, vmxnet3_queues_free),
225e3c97c2cSBryan Venteicher 
2268f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_attach_pre, vmxnet3_attach_pre),
2278f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_attach_post, vmxnet3_attach_post),
2288f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_detach, vmxnet3_detach),
2298f82136aSPatrick Kelsey 
2308f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_init, vmxnet3_init),
2318f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_stop, vmxnet3_stop),
2328f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_multi_set, vmxnet3_multi_set),
2338f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_mtu_set, vmxnet3_mtu_set),
2348f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_media_status, vmxnet3_media_status),
2358f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_media_change, vmxnet3_media_change),
2368f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_promisc_set, vmxnet3_promisc_set),
2378f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_get_counter, vmxnet3_get_counter),
2388f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_update_admin_status, vmxnet3_update_admin_status),
2398f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_timer, vmxnet3_txq_timer),
2408f82136aSPatrick Kelsey 
2418f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_tx_queue_intr_enable, vmxnet3_tx_queue_intr_enable),
2428f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_rx_queue_intr_enable, vmxnet3_rx_queue_intr_enable),
2438f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_link_intr_enable, vmxnet3_link_intr_enable),
2448f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_intr_enable, vmxnet3_intr_enable_all),
2458f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_intr_disable, vmxnet3_intr_disable_all),
2468f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_msix_intr_assign, vmxnet3_msix_intr_assign),
2478f82136aSPatrick Kelsey 
2488f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_vlan_register, vmxnet3_vlan_register),
2498f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_vlan_unregister, vmxnet3_vlan_unregister),
2508f82136aSPatrick Kelsey 
2518f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_shutdown, vmxnet3_shutdown),
2528f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_suspend, vmxnet3_suspend),
2538f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_resume, vmxnet3_resume),
2548f82136aSPatrick Kelsey 
2558f82136aSPatrick Kelsey 	DEVMETHOD_END
2568f82136aSPatrick Kelsey };
2578f82136aSPatrick Kelsey 
2588f82136aSPatrick Kelsey static driver_t vmxnet3_iflib_driver = {
2598f82136aSPatrick Kelsey 	"vmx", vmxnet3_iflib_methods, sizeof(struct vmxnet3_softc)
2608f82136aSPatrick Kelsey };
2618f82136aSPatrick Kelsey 
2628f82136aSPatrick Kelsey struct if_txrx vmxnet3_txrx = {
2638f82136aSPatrick Kelsey 	.ift_txd_encap = vmxnet3_isc_txd_encap,
2648f82136aSPatrick Kelsey 	.ift_txd_flush = vmxnet3_isc_txd_flush,
2658f82136aSPatrick Kelsey 	.ift_txd_credits_update = vmxnet3_isc_txd_credits_update,
2668f82136aSPatrick Kelsey 	.ift_rxd_available = vmxnet3_isc_rxd_available,
2678f82136aSPatrick Kelsey 	.ift_rxd_pkt_get = vmxnet3_isc_rxd_pkt_get,
2688f82136aSPatrick Kelsey 	.ift_rxd_refill = vmxnet3_isc_rxd_refill,
2698f82136aSPatrick Kelsey 	.ift_rxd_flush = vmxnet3_isc_rxd_flush,
2708f82136aSPatrick Kelsey 	.ift_legacy_intr = vmxnet3_legacy_intr
2718f82136aSPatrick Kelsey };
2728f82136aSPatrick Kelsey 
2738f82136aSPatrick Kelsey static struct if_shared_ctx vmxnet3_sctx_init = {
2748f82136aSPatrick Kelsey 	.isc_magic = IFLIB_MAGIC,
2758f82136aSPatrick Kelsey 	.isc_q_align = 512,
2768f82136aSPatrick Kelsey 
2778f82136aSPatrick Kelsey 	.isc_tx_maxsize = VMXNET3_TX_MAXSIZE,
2788f82136aSPatrick Kelsey 	.isc_tx_maxsegsize = VMXNET3_TX_MAXSEGSIZE,
2798f82136aSPatrick Kelsey 	.isc_tso_maxsize = VMXNET3_TSO_MAXSIZE + sizeof(struct ether_vlan_header),
2808f82136aSPatrick Kelsey 	.isc_tso_maxsegsize = VMXNET3_TX_MAXSEGSIZE,
2818f82136aSPatrick Kelsey 
2828f82136aSPatrick Kelsey 	/*
2838f82136aSPatrick Kelsey 	 * These values are used to configure the busdma tag used for
2848f82136aSPatrick Kelsey 	 * receive descriptors.  Each receive descriptor only points to one
2858f82136aSPatrick Kelsey 	 * buffer.
2868f82136aSPatrick Kelsey 	 */
2878f82136aSPatrick Kelsey 	.isc_rx_maxsize = VMXNET3_RX_MAXSEGSIZE, /* One buf per descriptor */
2888f82136aSPatrick Kelsey 	.isc_rx_nsegments = 1,  /* One mapping per descriptor */
2898f82136aSPatrick Kelsey 	.isc_rx_maxsegsize = VMXNET3_RX_MAXSEGSIZE,
2908f82136aSPatrick Kelsey 
2918f82136aSPatrick Kelsey 	.isc_admin_intrcnt = 1,
2928f82136aSPatrick Kelsey 	.isc_vendor_info = vmxnet3_vendor_info_array,
2938f82136aSPatrick Kelsey 	.isc_driver_version = "2",
2948f82136aSPatrick Kelsey 	.isc_driver = &vmxnet3_iflib_driver,
29541669133SMark Johnston 	.isc_flags = IFLIB_HAS_RXCQ | IFLIB_HAS_TXCQ | IFLIB_SINGLE_IRQ_RX_ONLY,
2968f82136aSPatrick Kelsey 
2978f82136aSPatrick Kelsey 	/*
2988f82136aSPatrick Kelsey 	 * Number of receive queues per receive queue set, with associated
2998f82136aSPatrick Kelsey 	 * descriptor settings for each.
3008f82136aSPatrick Kelsey 	 */
3018f82136aSPatrick Kelsey 	.isc_nrxqs = 3,
3028f82136aSPatrick Kelsey 	.isc_nfl = 2, /* one free list for each receive command queue */
3038f82136aSPatrick Kelsey 	.isc_nrxd_min = {VMXNET3_MIN_RX_NDESC, VMXNET3_MIN_RX_NDESC, VMXNET3_MIN_RX_NDESC},
3048f82136aSPatrick Kelsey 	.isc_nrxd_max = {VMXNET3_MAX_RX_NDESC, VMXNET3_MAX_RX_NDESC, VMXNET3_MAX_RX_NDESC},
3058f82136aSPatrick Kelsey 	.isc_nrxd_default = {VMXNET3_DEF_RX_NDESC, VMXNET3_DEF_RX_NDESC, VMXNET3_DEF_RX_NDESC},
3068f82136aSPatrick Kelsey 
3078f82136aSPatrick Kelsey 	/*
3088f82136aSPatrick Kelsey 	 * Number of transmit queues per transmit queue set, with associated
3098f82136aSPatrick Kelsey 	 * descriptor settings for each.
3108f82136aSPatrick Kelsey 	 */
3118f82136aSPatrick Kelsey 	.isc_ntxqs = 2,
3128f82136aSPatrick Kelsey 	.isc_ntxd_min = {VMXNET3_MIN_TX_NDESC, VMXNET3_MIN_TX_NDESC},
3138f82136aSPatrick Kelsey 	.isc_ntxd_max = {VMXNET3_MAX_TX_NDESC, VMXNET3_MAX_TX_NDESC},
3148f82136aSPatrick Kelsey 	.isc_ntxd_default = {VMXNET3_DEF_TX_NDESC, VMXNET3_DEF_TX_NDESC},
3158f82136aSPatrick Kelsey };
3168f82136aSPatrick Kelsey 
3178f82136aSPatrick Kelsey static void *
3188f82136aSPatrick Kelsey vmxnet3_register(device_t dev)
319e3c97c2cSBryan Venteicher {
3208f82136aSPatrick Kelsey 	return (&vmxnet3_sctx_init);
321e3c97c2cSBryan Venteicher }
322e3c97c2cSBryan Venteicher 
323e3c97c2cSBryan Venteicher static int
3248f82136aSPatrick Kelsey vmxnet3_attach_pre(if_ctx_t ctx)
325e3c97c2cSBryan Venteicher {
3268f82136aSPatrick Kelsey 	device_t dev;
3278f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
328e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
3298f82136aSPatrick Kelsey 	uint32_t intr_config;
330e3c97c2cSBryan Venteicher 	int error;
331e3c97c2cSBryan Venteicher 
3328f82136aSPatrick Kelsey 	dev = iflib_get_dev(ctx);
3338f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
334e3c97c2cSBryan Venteicher 	sc->vmx_dev = dev;
3358f82136aSPatrick Kelsey 	sc->vmx_ctx = ctx;
3368f82136aSPatrick Kelsey 	sc->vmx_sctx = iflib_get_sctx(ctx);
3378f82136aSPatrick Kelsey 	sc->vmx_scctx = iflib_get_softc_ctx(ctx);
3388f82136aSPatrick Kelsey 	sc->vmx_ifp = iflib_get_ifp(ctx);
3398f82136aSPatrick Kelsey 	sc->vmx_media = iflib_get_media(ctx);
3408f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
341e3c97c2cSBryan Venteicher 
3428f82136aSPatrick Kelsey 	scctx->isc_tx_nsegments = VMXNET3_TX_MAXSEGS;
3438f82136aSPatrick Kelsey 	scctx->isc_tx_tso_segments_max = VMXNET3_TX_MAXSEGS;
3448f82136aSPatrick Kelsey 	/* isc_tx_tso_size_max doesn't include possible vlan header */
3458f82136aSPatrick Kelsey 	scctx->isc_tx_tso_size_max = VMXNET3_TSO_MAXSIZE;
3468f82136aSPatrick Kelsey 	scctx->isc_tx_tso_segsize_max = VMXNET3_TX_MAXSEGSIZE;
3478f82136aSPatrick Kelsey 	scctx->isc_txrx = &vmxnet3_txrx;
348e3c97c2cSBryan Venteicher 
3498f82136aSPatrick Kelsey 	/* If 0, the iflib tunable was not set, so set to the default */
3508f82136aSPatrick Kelsey 	if (scctx->isc_nrxqsets == 0)
3518f82136aSPatrick Kelsey 		scctx->isc_nrxqsets = VMXNET3_DEF_RX_QUEUES;
3528f82136aSPatrick Kelsey 	scctx->isc_nrxqsets_max = min(VMXNET3_MAX_RX_QUEUES, mp_ncpus);
353e3c97c2cSBryan Venteicher 
3548f82136aSPatrick Kelsey 	/* If 0, the iflib tunable was not set, so set to the default */
3558f82136aSPatrick Kelsey 	if (scctx->isc_ntxqsets == 0)
3568f82136aSPatrick Kelsey 		scctx->isc_ntxqsets = VMXNET3_DEF_TX_QUEUES;
3578f82136aSPatrick Kelsey 	scctx->isc_ntxqsets_max = min(VMXNET3_MAX_TX_QUEUES, mp_ncpus);
358e3c97c2cSBryan Venteicher 
3598f82136aSPatrick Kelsey 	/*
3608f82136aSPatrick Kelsey 	 * Enforce that the transmit completion queue descriptor count is
3618f82136aSPatrick Kelsey 	 * the same as the transmit command queue descriptor count.
3628f82136aSPatrick Kelsey 	 */
3638f82136aSPatrick Kelsey 	scctx->isc_ntxd[0] = scctx->isc_ntxd[1];
3648f82136aSPatrick Kelsey 	scctx->isc_txqsizes[0] =
3658f82136aSPatrick Kelsey 	    sizeof(struct vmxnet3_txcompdesc) * scctx->isc_ntxd[0];
3668f82136aSPatrick Kelsey 	scctx->isc_txqsizes[1] =
3678f82136aSPatrick Kelsey 	    sizeof(struct vmxnet3_txdesc) * scctx->isc_ntxd[1];
3688f82136aSPatrick Kelsey 
3698f82136aSPatrick Kelsey 	/*
3708f82136aSPatrick Kelsey 	 * Enforce that the receive completion queue descriptor count is the
3718f82136aSPatrick Kelsey 	 * sum of the receive command queue descriptor counts, and that the
3728f82136aSPatrick Kelsey 	 * second receive command queue descriptor count is the same as the
3738f82136aSPatrick Kelsey 	 * first one.
3748f82136aSPatrick Kelsey 	 */
3758f82136aSPatrick Kelsey 	scctx->isc_nrxd[2] = scctx->isc_nrxd[1];
3768f82136aSPatrick Kelsey 	scctx->isc_nrxd[0] = scctx->isc_nrxd[1] + scctx->isc_nrxd[2];
3778f82136aSPatrick Kelsey 	scctx->isc_rxqsizes[0] =
3788f82136aSPatrick Kelsey 	    sizeof(struct vmxnet3_rxcompdesc) * scctx->isc_nrxd[0];
3798f82136aSPatrick Kelsey 	scctx->isc_rxqsizes[1] =
3808f82136aSPatrick Kelsey 	    sizeof(struct vmxnet3_rxdesc) * scctx->isc_nrxd[1];
3818f82136aSPatrick Kelsey 	scctx->isc_rxqsizes[2] =
3828f82136aSPatrick Kelsey 	    sizeof(struct vmxnet3_rxdesc) * scctx->isc_nrxd[2];
3838f82136aSPatrick Kelsey 
3848f82136aSPatrick Kelsey 	scctx->isc_rss_table_size = UPT1_RSS_MAX_IND_TABLE_SIZE;
3858f82136aSPatrick Kelsey 
3868f82136aSPatrick Kelsey 	/* Map PCI BARs */
387e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_resources(sc);
388e3c97c2cSBryan Venteicher 	if (error)
389e3c97c2cSBryan Venteicher 		goto fail;
390e3c97c2cSBryan Venteicher 
3918f82136aSPatrick Kelsey 	/* Check device versions */
392e3c97c2cSBryan Venteicher 	error = vmxnet3_check_version(sc);
393e3c97c2cSBryan Venteicher 	if (error)
394e3c97c2cSBryan Venteicher 		goto fail;
395e3c97c2cSBryan Venteicher 
3968f82136aSPatrick Kelsey 	/*
3978f82136aSPatrick Kelsey 	 * The interrupt mode can be set in the hypervisor configuration via
3988f82136aSPatrick Kelsey 	 * the parameter ethernet<N>.intrMode.
3998f82136aSPatrick Kelsey 	 */
4008f82136aSPatrick Kelsey 	intr_config = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_INTRCFG);
4018f82136aSPatrick Kelsey 	sc->vmx_intr_mask_mode = (intr_config >> 2) & 0x03;
402e3c97c2cSBryan Venteicher 
4038f82136aSPatrick Kelsey 	/*
4048f82136aSPatrick Kelsey 	 * Configure the softc context to attempt to configure the interrupt
4058f82136aSPatrick Kelsey 	 * mode now indicated by intr_config.  iflib will follow the usual
406b97de13aSMarius Strobl 	 * fallback path MSI-X -> MSI -> LEGACY, starting at the configured
4078f82136aSPatrick Kelsey 	 * starting mode.
4088f82136aSPatrick Kelsey 	 */
4098f82136aSPatrick Kelsey 	switch (intr_config & 0x03) {
4108f82136aSPatrick Kelsey 	case VMXNET3_IT_AUTO:
4118f82136aSPatrick Kelsey 	case VMXNET3_IT_MSIX:
4128f82136aSPatrick Kelsey 		scctx->isc_msix_bar = pci_msix_table_bar(dev);
4138f82136aSPatrick Kelsey 		break;
4148f82136aSPatrick Kelsey 	case VMXNET3_IT_MSI:
4158f82136aSPatrick Kelsey 		scctx->isc_msix_bar = -1;
4168f82136aSPatrick Kelsey 		scctx->isc_disable_msix = 1;
4178f82136aSPatrick Kelsey 		break;
4188f82136aSPatrick Kelsey 	case VMXNET3_IT_LEGACY:
4198f82136aSPatrick Kelsey 		scctx->isc_msix_bar = 0;
4208f82136aSPatrick Kelsey 		break;
421e3c97c2cSBryan Venteicher 	}
422e3c97c2cSBryan Venteicher 
4238f82136aSPatrick Kelsey 	scctx->isc_tx_csum_flags = VMXNET3_CSUM_ALL_OFFLOAD;
4248f82136aSPatrick Kelsey 	scctx->isc_capabilities = scctx->isc_capenable =
4258f82136aSPatrick Kelsey 	    IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6 |
4268f82136aSPatrick Kelsey 	    IFCAP_TSO4 | IFCAP_TSO6 |
4278f82136aSPatrick Kelsey 	    IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6 |
4288f82136aSPatrick Kelsey 	    IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING |
4298f82136aSPatrick Kelsey 	    IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO |
4308f82136aSPatrick Kelsey 	    IFCAP_JUMBO_MTU;
431e3c97c2cSBryan Venteicher 
4328f82136aSPatrick Kelsey 	/* These capabilities are not enabled by default. */
4338f82136aSPatrick Kelsey 	scctx->isc_capabilities |= IFCAP_LRO | IFCAP_VLAN_HWFILTER;
4348f82136aSPatrick Kelsey 
4358f82136aSPatrick Kelsey 	vmxnet3_get_lladdr(sc);
4368f82136aSPatrick Kelsey 	iflib_set_mac(ctx, sc->vmx_lladdr);
4378f82136aSPatrick Kelsey 
4388f82136aSPatrick Kelsey 	return (0);
439e3c97c2cSBryan Venteicher fail:
4408f82136aSPatrick Kelsey 	/*
4418f82136aSPatrick Kelsey 	 * We must completely clean up anything allocated above as iflib
4428f82136aSPatrick Kelsey 	 * will not invoke any other driver entry points as a result of this
4438f82136aSPatrick Kelsey 	 * failure.
4448f82136aSPatrick Kelsey 	 */
4458f82136aSPatrick Kelsey 	vmxnet3_free_resources(sc);
446e3c97c2cSBryan Venteicher 
447e3c97c2cSBryan Venteicher 	return (error);
448e3c97c2cSBryan Venteicher }
449e3c97c2cSBryan Venteicher 
450e3c97c2cSBryan Venteicher static int
4518f82136aSPatrick Kelsey vmxnet3_msix_intr_assign(if_ctx_t ctx, int msix)
452e3c97c2cSBryan Venteicher {
453e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
4548f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
4558f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
4568f82136aSPatrick Kelsey 	int error;
4578f82136aSPatrick Kelsey 	int i;
4588f82136aSPatrick Kelsey 	char irq_name[16];
459e3c97c2cSBryan Venteicher 
4608f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
4618f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
462e3c97c2cSBryan Venteicher 
4638f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
4648f82136aSPatrick Kelsey 		snprintf(irq_name, sizeof(irq_name), "rxq%d", i);
465e557c1ddSBryan Venteicher 
4668f82136aSPatrick Kelsey 		rxq = &sc->vmx_rxq[i];
4678f82136aSPatrick Kelsey 		error = iflib_irq_alloc_generic(ctx, &rxq->vxrxq_irq, i + 1,
4688f82136aSPatrick Kelsey 		    IFLIB_INTR_RX, vmxnet3_rxq_intr, rxq, i, irq_name);
4698f82136aSPatrick Kelsey 		if (error) {
4708f82136aSPatrick Kelsey 			device_printf(iflib_get_dev(ctx),
4718f82136aSPatrick Kelsey 			    "Failed to register rxq %d interrupt handler\n", i);
4728f82136aSPatrick Kelsey 			return (error);
4738f82136aSPatrick Kelsey 		}
474e3c97c2cSBryan Venteicher 	}
475e3c97c2cSBryan Venteicher 
4768f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++) {
4778f82136aSPatrick Kelsey 		snprintf(irq_name, sizeof(irq_name), "txq%d", i);
4788f82136aSPatrick Kelsey 
4798f82136aSPatrick Kelsey 		/*
4808f82136aSPatrick Kelsey 		 * Don't provide the corresponding rxq irq for reference -
4818f82136aSPatrick Kelsey 		 * we want the transmit task to be attached to a task queue
4828f82136aSPatrick Kelsey 		 * that is different from the one used by the corresponding
4838f82136aSPatrick Kelsey 		 * rxq irq.  That is because the TX doorbell writes are very
4848f82136aSPatrick Kelsey 		 * expensive as virtualized MMIO operations, so we want to
4858f82136aSPatrick Kelsey 		 * be able to defer them to another core when possible so
4868f82136aSPatrick Kelsey 		 * that they don't steal receive processing cycles during
4878f82136aSPatrick Kelsey 		 * stack turnarounds like TCP ACK generation.  The other
4888f82136aSPatrick Kelsey 		 * piece to this approach is enabling the iflib abdicate
4898f82136aSPatrick Kelsey 		 * option (currently via an interface-specific
4908f82136aSPatrick Kelsey 		 * tunable/sysctl).
4918f82136aSPatrick Kelsey 		 */
4928f82136aSPatrick Kelsey 		iflib_softirq_alloc_generic(ctx, NULL, IFLIB_INTR_TX, NULL, i,
4938f82136aSPatrick Kelsey 		    irq_name);
494e3c97c2cSBryan Venteicher 	}
495e3c97c2cSBryan Venteicher 
4968f82136aSPatrick Kelsey 	error = iflib_irq_alloc_generic(ctx, &sc->vmx_event_intr_irq,
4978f82136aSPatrick Kelsey 	    scctx->isc_nrxqsets + 1, IFLIB_INTR_ADMIN, vmxnet3_event_intr, sc, 0,
4988f82136aSPatrick Kelsey 	    "event");
4998f82136aSPatrick Kelsey 	if (error) {
5008f82136aSPatrick Kelsey 		device_printf(iflib_get_dev(ctx),
5018f82136aSPatrick Kelsey 		    "Failed to register event interrupt handler\n");
5028f82136aSPatrick Kelsey 		return (error);
503e3c97c2cSBryan Venteicher 	}
504e3c97c2cSBryan Venteicher 
5058f82136aSPatrick Kelsey 	return (0);
5068f82136aSPatrick Kelsey }
507e3c97c2cSBryan Venteicher 
5088f82136aSPatrick Kelsey static void
5098f82136aSPatrick Kelsey vmxnet3_free_irqs(struct vmxnet3_softc *sc)
5108f82136aSPatrick Kelsey {
5118f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
5128f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
5138f82136aSPatrick Kelsey 	int i;
5148f82136aSPatrick Kelsey 
5158f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
5168f82136aSPatrick Kelsey 
5178f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
5188f82136aSPatrick Kelsey 		rxq = &sc->vmx_rxq[i];
5198f82136aSPatrick Kelsey 		iflib_irq_free(sc->vmx_ctx, &rxq->vxrxq_irq);
5208f82136aSPatrick Kelsey 	}
5218f82136aSPatrick Kelsey 
5228f82136aSPatrick Kelsey 	iflib_irq_free(sc->vmx_ctx, &sc->vmx_event_intr_irq);
5238f82136aSPatrick Kelsey }
5248f82136aSPatrick Kelsey 
5258f82136aSPatrick Kelsey static int
5268f82136aSPatrick Kelsey vmxnet3_attach_post(if_ctx_t ctx)
5278f82136aSPatrick Kelsey {
5288f82136aSPatrick Kelsey 	device_t dev;
5298f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
5308f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
5318f82136aSPatrick Kelsey 	int error;
5328f82136aSPatrick Kelsey 
5338f82136aSPatrick Kelsey 	dev = iflib_get_dev(ctx);
5348f82136aSPatrick Kelsey 	scctx = iflib_get_softc_ctx(ctx);
5358f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
5368f82136aSPatrick Kelsey 
5378f82136aSPatrick Kelsey 	if (scctx->isc_nrxqsets > 1)
5388f82136aSPatrick Kelsey 		sc->vmx_flags |= VMXNET3_FLAG_RSS;
5398f82136aSPatrick Kelsey 
5408f82136aSPatrick Kelsey 	error = vmxnet3_alloc_data(sc);
5418f82136aSPatrick Kelsey 	if (error)
5428f82136aSPatrick Kelsey 		goto fail;
5438f82136aSPatrick Kelsey 
5448f82136aSPatrick Kelsey 	vmxnet3_set_interrupt_idx(sc);
5458f82136aSPatrick Kelsey 	vmxnet3_setup_sysctl(sc);
5468f82136aSPatrick Kelsey 
5478f82136aSPatrick Kelsey 	ifmedia_add(sc->vmx_media, IFM_ETHER | IFM_AUTO, 0, NULL);
5488f82136aSPatrick Kelsey 	ifmedia_set(sc->vmx_media, IFM_ETHER | IFM_AUTO);
5498f82136aSPatrick Kelsey 
5508f82136aSPatrick Kelsey fail:
5518f82136aSPatrick Kelsey 	return (error);
5528f82136aSPatrick Kelsey }
5538f82136aSPatrick Kelsey 
5548f82136aSPatrick Kelsey static int
5558f82136aSPatrick Kelsey vmxnet3_detach(if_ctx_t ctx)
5568f82136aSPatrick Kelsey {
5578f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
5588f82136aSPatrick Kelsey 
5598f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
5608f82136aSPatrick Kelsey 
5618f82136aSPatrick Kelsey 	vmxnet3_free_irqs(sc);
562e3c97c2cSBryan Venteicher 	vmxnet3_free_data(sc);
563e3c97c2cSBryan Venteicher 	vmxnet3_free_resources(sc);
564e3c97c2cSBryan Venteicher 
565e3c97c2cSBryan Venteicher 	return (0);
566e3c97c2cSBryan Venteicher }
567e3c97c2cSBryan Venteicher 
568e3c97c2cSBryan Venteicher static int
5698f82136aSPatrick Kelsey vmxnet3_shutdown(if_ctx_t ctx)
5708f82136aSPatrick Kelsey {
5718f82136aSPatrick Kelsey 
5728f82136aSPatrick Kelsey 	return (0);
5738f82136aSPatrick Kelsey }
5748f82136aSPatrick Kelsey 
5758f82136aSPatrick Kelsey static int
5768f82136aSPatrick Kelsey vmxnet3_suspend(if_ctx_t ctx)
5778f82136aSPatrick Kelsey {
5788f82136aSPatrick Kelsey 
5798f82136aSPatrick Kelsey 	return (0);
5808f82136aSPatrick Kelsey }
5818f82136aSPatrick Kelsey 
5828f82136aSPatrick Kelsey static int
5838f82136aSPatrick Kelsey vmxnet3_resume(if_ctx_t ctx)
584e3c97c2cSBryan Venteicher {
585e3c97c2cSBryan Venteicher 
586e3c97c2cSBryan Venteicher 	return (0);
587e3c97c2cSBryan Venteicher }
588e3c97c2cSBryan Venteicher 
589e3c97c2cSBryan Venteicher static int
590e3c97c2cSBryan Venteicher vmxnet3_alloc_resources(struct vmxnet3_softc *sc)
591e3c97c2cSBryan Venteicher {
592e3c97c2cSBryan Venteicher 	device_t dev;
593e3c97c2cSBryan Venteicher 	int rid;
594e3c97c2cSBryan Venteicher 
595e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
596e3c97c2cSBryan Venteicher 
597e3c97c2cSBryan Venteicher 	rid = PCIR_BAR(0);
598e3c97c2cSBryan Venteicher 	sc->vmx_res0 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
599e3c97c2cSBryan Venteicher 	    RF_ACTIVE);
600e3c97c2cSBryan Venteicher 	if (sc->vmx_res0 == NULL) {
601e3c97c2cSBryan Venteicher 		device_printf(dev,
602e3c97c2cSBryan Venteicher 		    "could not map BAR0 memory\n");
603e3c97c2cSBryan Venteicher 		return (ENXIO);
604e3c97c2cSBryan Venteicher 	}
605e3c97c2cSBryan Venteicher 
606e3c97c2cSBryan Venteicher 	sc->vmx_iot0 = rman_get_bustag(sc->vmx_res0);
607e3c97c2cSBryan Venteicher 	sc->vmx_ioh0 = rman_get_bushandle(sc->vmx_res0);
608e3c97c2cSBryan Venteicher 
609e3c97c2cSBryan Venteicher 	rid = PCIR_BAR(1);
610e3c97c2cSBryan Venteicher 	sc->vmx_res1 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
611e3c97c2cSBryan Venteicher 	    RF_ACTIVE);
612e3c97c2cSBryan Venteicher 	if (sc->vmx_res1 == NULL) {
613e3c97c2cSBryan Venteicher 		device_printf(dev,
614e3c97c2cSBryan Venteicher 		    "could not map BAR1 memory\n");
615e3c97c2cSBryan Venteicher 		return (ENXIO);
616e3c97c2cSBryan Venteicher 	}
617e3c97c2cSBryan Venteicher 
618e3c97c2cSBryan Venteicher 	sc->vmx_iot1 = rman_get_bustag(sc->vmx_res1);
619e3c97c2cSBryan Venteicher 	sc->vmx_ioh1 = rman_get_bushandle(sc->vmx_res1);
620e3c97c2cSBryan Venteicher 
621e3c97c2cSBryan Venteicher 	return (0);
622e3c97c2cSBryan Venteicher }
623e3c97c2cSBryan Venteicher 
624e3c97c2cSBryan Venteicher static void
625e3c97c2cSBryan Venteicher vmxnet3_free_resources(struct vmxnet3_softc *sc)
626e3c97c2cSBryan Venteicher {
627e3c97c2cSBryan Venteicher 	device_t dev;
628e3c97c2cSBryan Venteicher 
629e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
630e3c97c2cSBryan Venteicher 
631e3c97c2cSBryan Venteicher 	if (sc->vmx_res0 != NULL) {
632b97de13aSMarius Strobl 		bus_release_resource(dev, SYS_RES_MEMORY,
633b97de13aSMarius Strobl 		    rman_get_rid(sc->vmx_res0), sc->vmx_res0);
634e3c97c2cSBryan Venteicher 		sc->vmx_res0 = NULL;
635e3c97c2cSBryan Venteicher 	}
636e3c97c2cSBryan Venteicher 
637e3c97c2cSBryan Venteicher 	if (sc->vmx_res1 != NULL) {
638b97de13aSMarius Strobl 		bus_release_resource(dev, SYS_RES_MEMORY,
639b97de13aSMarius Strobl 		    rman_get_rid(sc->vmx_res1), sc->vmx_res1);
640e3c97c2cSBryan Venteicher 		sc->vmx_res1 = NULL;
641e3c97c2cSBryan Venteicher 	}
642e3c97c2cSBryan Venteicher }
643e3c97c2cSBryan Venteicher 
644e3c97c2cSBryan Venteicher static int
645e3c97c2cSBryan Venteicher vmxnet3_check_version(struct vmxnet3_softc *sc)
646e3c97c2cSBryan Venteicher {
647e3c97c2cSBryan Venteicher 	device_t dev;
648e3c97c2cSBryan Venteicher 	uint32_t version;
649e3c97c2cSBryan Venteicher 
650e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
651e3c97c2cSBryan Venteicher 
652e3c97c2cSBryan Venteicher 	version = vmxnet3_read_bar1(sc, VMXNET3_BAR1_VRRS);
653e3c97c2cSBryan Venteicher 	if ((version & 0x01) == 0) {
654e3c97c2cSBryan Venteicher 		device_printf(dev, "unsupported hardware version %#x\n",
655e3c97c2cSBryan Venteicher 		    version);
656e3c97c2cSBryan Venteicher 		return (ENOTSUP);
6573c965775SBryan Venteicher 	}
658e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_VRRS, 1);
659e3c97c2cSBryan Venteicher 
660e3c97c2cSBryan Venteicher 	version = vmxnet3_read_bar1(sc, VMXNET3_BAR1_UVRS);
661e3c97c2cSBryan Venteicher 	if ((version & 0x01) == 0) {
662e3c97c2cSBryan Venteicher 		device_printf(dev, "unsupported UPT version %#x\n", version);
663e3c97c2cSBryan Venteicher 		return (ENOTSUP);
6643c965775SBryan Venteicher 	}
665e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_UVRS, 1);
666e3c97c2cSBryan Venteicher 
667e3c97c2cSBryan Venteicher 	return (0);
668e3c97c2cSBryan Venteicher }
669e3c97c2cSBryan Venteicher 
670e3c97c2cSBryan Venteicher static void
671e3c97c2cSBryan Venteicher vmxnet3_set_interrupt_idx(struct vmxnet3_softc *sc)
672e3c97c2cSBryan Venteicher {
6738f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
674e3c97c2cSBryan Venteicher 	struct vmxnet3_txqueue *txq;
675e3c97c2cSBryan Venteicher 	struct vmxnet3_txq_shared *txs;
676e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
677e3c97c2cSBryan Venteicher 	struct vmxnet3_rxq_shared *rxs;
6788f82136aSPatrick Kelsey 	int intr_idx;
679e3c97c2cSBryan Venteicher 	int i;
680e3c97c2cSBryan Venteicher 
6818f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
682e3c97c2cSBryan Venteicher 
6838f82136aSPatrick Kelsey 	/*
684769d56ecSPatrick Kelsey 	 * There is always one interrupt per receive queue, assigned
685769d56ecSPatrick Kelsey 	 * starting with the first interrupt.  When there is only one
686769d56ecSPatrick Kelsey 	 * interrupt available, the event interrupt shares the receive queue
687769d56ecSPatrick Kelsey 	 * interrupt, otherwise it uses the interrupt following the last
688769d56ecSPatrick Kelsey 	 * receive queue interrupt.  Transmit queues are not assigned
689769d56ecSPatrick Kelsey 	 * interrupts, so they are given indexes beyond the indexes that
690769d56ecSPatrick Kelsey 	 * correspond to the real interrupts.
6918f82136aSPatrick Kelsey 	 */
692769d56ecSPatrick Kelsey 
693769d56ecSPatrick Kelsey 	/* The event interrupt is always the last vector. */
6948f82136aSPatrick Kelsey 	sc->vmx_event_intr_idx = scctx->isc_vectors - 1;
695e3c97c2cSBryan Venteicher 
6968f82136aSPatrick Kelsey 	intr_idx = 0;
6978f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++, intr_idx++) {
698e3c97c2cSBryan Venteicher 		rxq = &sc->vmx_rxq[i];
699e3c97c2cSBryan Venteicher 		rxs = rxq->vxrxq_rs;
7008f82136aSPatrick Kelsey 		rxq->vxrxq_intr_idx = intr_idx;
701e3c97c2cSBryan Venteicher 		rxs->intr_idx = rxq->vxrxq_intr_idx;
702e3c97c2cSBryan Venteicher 	}
7038f82136aSPatrick Kelsey 
7048f82136aSPatrick Kelsey 	/*
7058f82136aSPatrick Kelsey 	 * Assign the tx queues interrupt indexes above what we are actually
7068f82136aSPatrick Kelsey 	 * using.  These interrupts will never be enabled.
7078f82136aSPatrick Kelsey 	 */
7088f82136aSPatrick Kelsey 	intr_idx = scctx->isc_vectors;
7098f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++, intr_idx++) {
7108f82136aSPatrick Kelsey 		txq = &sc->vmx_txq[i];
7118f82136aSPatrick Kelsey 		txs = txq->vxtxq_ts;
7128f82136aSPatrick Kelsey 		txq->vxtxq_intr_idx = intr_idx;
7138f82136aSPatrick Kelsey 		txs->intr_idx = txq->vxtxq_intr_idx;
7148f82136aSPatrick Kelsey 	}
715e3c97c2cSBryan Venteicher }
716e3c97c2cSBryan Venteicher 
717e3c97c2cSBryan Venteicher static int
7188f82136aSPatrick Kelsey vmxnet3_queues_shared_alloc(struct vmxnet3_softc *sc)
719e3c97c2cSBryan Venteicher {
7208f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
7218f82136aSPatrick Kelsey 	int size;
722e3c97c2cSBryan Venteicher 	int error;
723e3c97c2cSBryan Venteicher 
7248f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
725e3c97c2cSBryan Venteicher 
7268f82136aSPatrick Kelsey 	/*
7278f82136aSPatrick Kelsey 	 * The txq and rxq shared data areas must be allocated contiguously
7288f82136aSPatrick Kelsey 	 * as vmxnet3_driver_shared contains only a single address member
7298f82136aSPatrick Kelsey 	 * for the shared queue data area.
7308f82136aSPatrick Kelsey 	 */
7318f82136aSPatrick Kelsey 	size = scctx->isc_ntxqsets * sizeof(struct vmxnet3_txq_shared) +
7328f82136aSPatrick Kelsey 	    scctx->isc_nrxqsets * sizeof(struct vmxnet3_rxq_shared);
7338f82136aSPatrick Kelsey 	error = iflib_dma_alloc_align(sc->vmx_ctx, size, 128, &sc->vmx_qs_dma, 0);
7348f82136aSPatrick Kelsey 	if (error) {
7358f82136aSPatrick Kelsey 		device_printf(sc->vmx_dev, "cannot alloc queue shared memory\n");
736e3c97c2cSBryan Venteicher 		return (error);
737e3c97c2cSBryan Venteicher 	}
738e3c97c2cSBryan Venteicher 
739e557c1ddSBryan Venteicher 	return (0);
740e557c1ddSBryan Venteicher }
741e557c1ddSBryan Venteicher 
742e557c1ddSBryan Venteicher static void
7438f82136aSPatrick Kelsey vmxnet3_init_txq(struct vmxnet3_softc *sc, int q)
744e557c1ddSBryan Venteicher {
745e557c1ddSBryan Venteicher 	struct vmxnet3_txqueue *txq;
7468f82136aSPatrick Kelsey 	struct vmxnet3_comp_ring *txc;
7478f82136aSPatrick Kelsey 	struct vmxnet3_txring *txr;
7488f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
749e557c1ddSBryan Venteicher 
7508f82136aSPatrick Kelsey 	txq = &sc->vmx_txq[q];
7518f82136aSPatrick Kelsey 	txc = &txq->vxtxq_comp_ring;
7528f82136aSPatrick Kelsey 	txr = &txq->vxtxq_cmd_ring;
7538f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
7548f82136aSPatrick Kelsey 
7558f82136aSPatrick Kelsey 	snprintf(txq->vxtxq_name, sizeof(txq->vxtxq_name), "%s-tx%d",
7568f82136aSPatrick Kelsey 	    device_get_nameunit(sc->vmx_dev), q);
7578f82136aSPatrick Kelsey 
7588f82136aSPatrick Kelsey 	txq->vxtxq_sc = sc;
7598f82136aSPatrick Kelsey 	txq->vxtxq_id = q;
7608f82136aSPatrick Kelsey 	txc->vxcr_ndesc = scctx->isc_ntxd[0];
7618f82136aSPatrick Kelsey 	txr->vxtxr_ndesc = scctx->isc_ntxd[1];
762e557c1ddSBryan Venteicher }
7638f82136aSPatrick Kelsey 
7648f82136aSPatrick Kelsey static int
7658f82136aSPatrick Kelsey vmxnet3_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
7668f82136aSPatrick Kelsey     int ntxqs, int ntxqsets)
7678f82136aSPatrick Kelsey {
7688f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
7698f82136aSPatrick Kelsey 	int q;
7708f82136aSPatrick Kelsey 	int error;
7718f82136aSPatrick Kelsey 	caddr_t kva;
7728f82136aSPatrick Kelsey 
7738f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
7748f82136aSPatrick Kelsey 
7758f82136aSPatrick Kelsey 	/* Allocate the array of transmit queues */
7768f82136aSPatrick Kelsey 	sc->vmx_txq = malloc(sizeof(struct vmxnet3_txqueue) *
7778f82136aSPatrick Kelsey 	    ntxqsets, M_DEVBUF, M_NOWAIT | M_ZERO);
7788f82136aSPatrick Kelsey 	if (sc->vmx_txq == NULL)
7798f82136aSPatrick Kelsey 		return (ENOMEM);
7808f82136aSPatrick Kelsey 
7818f82136aSPatrick Kelsey 	/* Initialize driver state for each transmit queue */
7828f82136aSPatrick Kelsey 	for (q = 0; q < ntxqsets; q++)
7838f82136aSPatrick Kelsey 		vmxnet3_init_txq(sc, q);
7848f82136aSPatrick Kelsey 
7858f82136aSPatrick Kelsey 	/*
7868f82136aSPatrick Kelsey 	 * Allocate queue state that is shared with the device.  This check
7878f82136aSPatrick Kelsey 	 * and call is performed in both vmxnet3_tx_queues_alloc() and
7888f82136aSPatrick Kelsey 	 * vmxnet3_rx_queues_alloc() so that we don't have to care which
7898f82136aSPatrick Kelsey 	 * order iflib invokes those routines in.
7908f82136aSPatrick Kelsey 	 */
7918f82136aSPatrick Kelsey 	if (sc->vmx_qs_dma.idi_size == 0) {
7928f82136aSPatrick Kelsey 		error = vmxnet3_queues_shared_alloc(sc);
7938f82136aSPatrick Kelsey 		if (error)
7948f82136aSPatrick Kelsey 			return (error);
795e557c1ddSBryan Venteicher 	}
7968f82136aSPatrick Kelsey 
7978f82136aSPatrick Kelsey 	kva = sc->vmx_qs_dma.idi_vaddr;
7988f82136aSPatrick Kelsey 	for (q = 0; q < ntxqsets; q++) {
7998f82136aSPatrick Kelsey 		sc->vmx_txq[q].vxtxq_ts = (struct vmxnet3_txq_shared *) kva;
8008f82136aSPatrick Kelsey 		kva += sizeof(struct vmxnet3_txq_shared);
8018f82136aSPatrick Kelsey 	}
8028f82136aSPatrick Kelsey 
8038f82136aSPatrick Kelsey 	/* Record descriptor ring vaddrs and paddrs */
8048f82136aSPatrick Kelsey 	for (q = 0; q < ntxqsets; q++) {
8058f82136aSPatrick Kelsey 		struct vmxnet3_txqueue *txq;
8068f82136aSPatrick Kelsey 		struct vmxnet3_txring *txr;
8078f82136aSPatrick Kelsey 		struct vmxnet3_comp_ring *txc;
8088f82136aSPatrick Kelsey 
8098f82136aSPatrick Kelsey 		txq = &sc->vmx_txq[q];
8108f82136aSPatrick Kelsey 		txc = &txq->vxtxq_comp_ring;
8118f82136aSPatrick Kelsey 		txr = &txq->vxtxq_cmd_ring;
8128f82136aSPatrick Kelsey 
8138f82136aSPatrick Kelsey 		/* Completion ring */
8148f82136aSPatrick Kelsey 		txc->vxcr_u.txcd =
8158f82136aSPatrick Kelsey 		    (struct vmxnet3_txcompdesc *) vaddrs[q * ntxqs + 0];
8168f82136aSPatrick Kelsey 		txc->vxcr_paddr = paddrs[q * ntxqs + 0];
8178f82136aSPatrick Kelsey 
8188f82136aSPatrick Kelsey 		/* Command ring */
8198f82136aSPatrick Kelsey 		txr->vxtxr_txd =
8208f82136aSPatrick Kelsey 		    (struct vmxnet3_txdesc *) vaddrs[q * ntxqs + 1];
8218f82136aSPatrick Kelsey 		txr->vxtxr_paddr = paddrs[q * ntxqs + 1];
8228f82136aSPatrick Kelsey 	}
8238f82136aSPatrick Kelsey 
8248f82136aSPatrick Kelsey 	return (0);
825e557c1ddSBryan Venteicher }
826e557c1ddSBryan Venteicher 
827e557c1ddSBryan Venteicher static void
8288f82136aSPatrick Kelsey vmxnet3_init_rxq(struct vmxnet3_softc *sc, int q, int nrxqs)
829e3c97c2cSBryan Venteicher {
830e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
8318f82136aSPatrick Kelsey 	struct vmxnet3_comp_ring *rxc;
832e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
8338f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
834e3c97c2cSBryan Venteicher 	int i;
835e3c97c2cSBryan Venteicher 
836e3c97c2cSBryan Venteicher 	rxq = &sc->vmx_rxq[q];
8378f82136aSPatrick Kelsey 	rxc = &rxq->vxrxq_comp_ring;
8388f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
839e3c97c2cSBryan Venteicher 
840e3c97c2cSBryan Venteicher 	snprintf(rxq->vxrxq_name, sizeof(rxq->vxrxq_name), "%s-rx%d",
841e3c97c2cSBryan Venteicher 	    device_get_nameunit(sc->vmx_dev), q);
842e3c97c2cSBryan Venteicher 
843e3c97c2cSBryan Venteicher 	rxq->vxrxq_sc = sc;
844e3c97c2cSBryan Venteicher 	rxq->vxrxq_id = q;
845e3c97c2cSBryan Venteicher 
8468f82136aSPatrick Kelsey 	/*
8478f82136aSPatrick Kelsey 	 * First rxq is the completion queue, so there are nrxqs - 1 command
8488f82136aSPatrick Kelsey 	 * rings starting at iflib queue id 1.
8498f82136aSPatrick Kelsey 	 */
8508f82136aSPatrick Kelsey 	rxc->vxcr_ndesc = scctx->isc_nrxd[0];
8518f82136aSPatrick Kelsey 	for (i = 0; i < nrxqs - 1; i++) {
852e3c97c2cSBryan Venteicher 		rxr = &rxq->vxrxq_cmd_ring[i];
8538f82136aSPatrick Kelsey 		rxr->vxrxr_ndesc = scctx->isc_nrxd[i + 1];
8543c965775SBryan Venteicher 	}
855e3c97c2cSBryan Venteicher }
856e3c97c2cSBryan Venteicher 
857e3c97c2cSBryan Venteicher static int
8588f82136aSPatrick Kelsey vmxnet3_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
8598f82136aSPatrick Kelsey     int nrxqs, int nrxqsets)
860e3c97c2cSBryan Venteicher {
8618f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
8628f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
8638f82136aSPatrick Kelsey 	int q;
8648f82136aSPatrick Kelsey 	int i;
8658f82136aSPatrick Kelsey 	int error;
8668f82136aSPatrick Kelsey 	caddr_t kva;
867e3c97c2cSBryan Venteicher 
8688f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
8698f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
870e3c97c2cSBryan Venteicher 
8718f82136aSPatrick Kelsey 	/* Allocate the array of receive queues */
8728f82136aSPatrick Kelsey 	sc->vmx_rxq = malloc(sizeof(struct vmxnet3_rxqueue) *
8738f82136aSPatrick Kelsey 	    nrxqsets, M_DEVBUF, M_NOWAIT | M_ZERO);
8748f82136aSPatrick Kelsey 	if (sc->vmx_rxq == NULL)
875e3c97c2cSBryan Venteicher 		return (ENOMEM);
876e3c97c2cSBryan Venteicher 
8778f82136aSPatrick Kelsey 	/* Initialize driver state for each receive queue */
8788f82136aSPatrick Kelsey 	for (q = 0; q < nrxqsets; q++)
8798f82136aSPatrick Kelsey 		vmxnet3_init_rxq(sc, q, nrxqs);
880e3c97c2cSBryan Venteicher 
881e557c1ddSBryan Venteicher 	/*
8828f82136aSPatrick Kelsey 	 * Allocate queue state that is shared with the device.  This check
8838f82136aSPatrick Kelsey 	 * and call is performed in both vmxnet3_tx_queues_alloc() and
8848f82136aSPatrick Kelsey 	 * vmxnet3_rx_queues_alloc() so that we don't have to care which
8858f82136aSPatrick Kelsey 	 * order iflib invokes those routines in.
886e557c1ddSBryan Venteicher 	 */
8878f82136aSPatrick Kelsey 	if (sc->vmx_qs_dma.idi_size == 0) {
8888f82136aSPatrick Kelsey 		error = vmxnet3_queues_shared_alloc(sc);
889e3c97c2cSBryan Venteicher 		if (error)
890e3c97c2cSBryan Venteicher 			return (error);
891e3c97c2cSBryan Venteicher 	}
892e3c97c2cSBryan Venteicher 
8938f82136aSPatrick Kelsey 	kva = sc->vmx_qs_dma.idi_vaddr +
8948f82136aSPatrick Kelsey 	    scctx->isc_ntxqsets * sizeof(struct vmxnet3_txq_shared);
8958f82136aSPatrick Kelsey 	for (q = 0; q < nrxqsets; q++) {
8968f82136aSPatrick Kelsey 		sc->vmx_rxq[q].vxrxq_rs = (struct vmxnet3_rxq_shared *) kva;
8978f82136aSPatrick Kelsey 		kva += sizeof(struct vmxnet3_rxq_shared);
8988f82136aSPatrick Kelsey 	}
8998f82136aSPatrick Kelsey 
9008f82136aSPatrick Kelsey 	/* Record descriptor ring vaddrs and paddrs */
9018f82136aSPatrick Kelsey 	for (q = 0; q < nrxqsets; q++) {
9028f82136aSPatrick Kelsey 		struct vmxnet3_rxqueue *rxq;
9038f82136aSPatrick Kelsey 		struct vmxnet3_rxring *rxr;
9048f82136aSPatrick Kelsey 		struct vmxnet3_comp_ring *rxc;
9058f82136aSPatrick Kelsey 
9068f82136aSPatrick Kelsey 		rxq = &sc->vmx_rxq[q];
9078f82136aSPatrick Kelsey 		rxc = &rxq->vxrxq_comp_ring;
9088f82136aSPatrick Kelsey 
9098f82136aSPatrick Kelsey 		/* Completion ring */
9108f82136aSPatrick Kelsey 		rxc->vxcr_u.rxcd =
9118f82136aSPatrick Kelsey 		    (struct vmxnet3_rxcompdesc *) vaddrs[q * nrxqs + 0];
9128f82136aSPatrick Kelsey 		rxc->vxcr_paddr = paddrs[q * nrxqs + 0];
9138f82136aSPatrick Kelsey 
9148f82136aSPatrick Kelsey 		/* Command ring(s) */
9158f82136aSPatrick Kelsey 		for (i = 0; i < nrxqs - 1; i++) {
9168f82136aSPatrick Kelsey 			rxr = &rxq->vxrxq_cmd_ring[i];
9178f82136aSPatrick Kelsey 
9188f82136aSPatrick Kelsey 			rxr->vxrxr_rxd =
9198f82136aSPatrick Kelsey 			    (struct vmxnet3_rxdesc *) vaddrs[q * nrxqs + 1 + i];
9208f82136aSPatrick Kelsey 			rxr->vxrxr_paddr = paddrs[q * nrxqs + 1 + i];
9218f82136aSPatrick Kelsey 		}
922e3c97c2cSBryan Venteicher 	}
923e3c97c2cSBryan Venteicher 
924e3c97c2cSBryan Venteicher 	return (0);
925e3c97c2cSBryan Venteicher }
926e3c97c2cSBryan Venteicher 
927e3c97c2cSBryan Venteicher static void
9288f82136aSPatrick Kelsey vmxnet3_queues_free(if_ctx_t ctx)
929e3c97c2cSBryan Venteicher {
9308f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
931e3c97c2cSBryan Venteicher 
9328f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
933e3c97c2cSBryan Venteicher 
9348f82136aSPatrick Kelsey 	/* Free queue state area that is shared with the device */
9358f82136aSPatrick Kelsey 	if (sc->vmx_qs_dma.idi_size != 0) {
9368f82136aSPatrick Kelsey 		iflib_dma_free(&sc->vmx_qs_dma);
9378f82136aSPatrick Kelsey 		sc->vmx_qs_dma.idi_size = 0;
938e3c97c2cSBryan Venteicher 	}
939e3c97c2cSBryan Venteicher 
9408f82136aSPatrick Kelsey 	/* Free array of receive queues */
941e3c97c2cSBryan Venteicher 	if (sc->vmx_rxq != NULL) {
942e3c97c2cSBryan Venteicher 		free(sc->vmx_rxq, M_DEVBUF);
943e3c97c2cSBryan Venteicher 		sc->vmx_rxq = NULL;
944e3c97c2cSBryan Venteicher 	}
945e3c97c2cSBryan Venteicher 
9468f82136aSPatrick Kelsey 	/* Free array of transmit queues */
947e3c97c2cSBryan Venteicher 	if (sc->vmx_txq != NULL) {
948e3c97c2cSBryan Venteicher 		free(sc->vmx_txq, M_DEVBUF);
949e3c97c2cSBryan Venteicher 		sc->vmx_txq = NULL;
950e3c97c2cSBryan Venteicher 	}
951e3c97c2cSBryan Venteicher }
952e3c97c2cSBryan Venteicher 
953e3c97c2cSBryan Venteicher static int
954e3c97c2cSBryan Venteicher vmxnet3_alloc_shared_data(struct vmxnet3_softc *sc)
955e3c97c2cSBryan Venteicher {
956e3c97c2cSBryan Venteicher 	device_t dev;
957e3c97c2cSBryan Venteicher 	size_t size;
9588f82136aSPatrick Kelsey 	int error;
959e3c97c2cSBryan Venteicher 
960e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
961e3c97c2cSBryan Venteicher 
9628f82136aSPatrick Kelsey 	/* Top level state structure shared with the device */
963e3c97c2cSBryan Venteicher 	size = sizeof(struct vmxnet3_driver_shared);
9648f82136aSPatrick Kelsey 	error = iflib_dma_alloc_align(sc->vmx_ctx, size, 1, &sc->vmx_ds_dma, 0);
965e3c97c2cSBryan Venteicher 	if (error) {
966e3c97c2cSBryan Venteicher 		device_printf(dev, "cannot alloc shared memory\n");
967e3c97c2cSBryan Venteicher 		return (error);
968e3c97c2cSBryan Venteicher 	}
9698f82136aSPatrick Kelsey 	sc->vmx_ds = (struct vmxnet3_driver_shared *) sc->vmx_ds_dma.idi_vaddr;
970e3c97c2cSBryan Venteicher 
9718f82136aSPatrick Kelsey 	/* RSS table state shared with the device */
972e557c1ddSBryan Venteicher 	if (sc->vmx_flags & VMXNET3_FLAG_RSS) {
973e557c1ddSBryan Venteicher 		size = sizeof(struct vmxnet3_rss_shared);
9748f82136aSPatrick Kelsey 		error = iflib_dma_alloc_align(sc->vmx_ctx, size, 128,
9758f82136aSPatrick Kelsey 		    &sc->vmx_rss_dma, 0);
976e557c1ddSBryan Venteicher 		if (error) {
977e557c1ddSBryan Venteicher 			device_printf(dev, "cannot alloc rss shared memory\n");
978e557c1ddSBryan Venteicher 			return (error);
979e557c1ddSBryan Venteicher 		}
980e557c1ddSBryan Venteicher 		sc->vmx_rss =
9818f82136aSPatrick Kelsey 		    (struct vmxnet3_rss_shared *) sc->vmx_rss_dma.idi_vaddr;
982e557c1ddSBryan Venteicher 	}
983e557c1ddSBryan Venteicher 
984e3c97c2cSBryan Venteicher 	return (0);
985e3c97c2cSBryan Venteicher }
986e3c97c2cSBryan Venteicher 
987e3c97c2cSBryan Venteicher static void
988e3c97c2cSBryan Venteicher vmxnet3_free_shared_data(struct vmxnet3_softc *sc)
989e3c97c2cSBryan Venteicher {
990e3c97c2cSBryan Venteicher 
9918f82136aSPatrick Kelsey 	/* Free RSS table state shared with the device */
992e557c1ddSBryan Venteicher 	if (sc->vmx_rss != NULL) {
9938f82136aSPatrick Kelsey 		iflib_dma_free(&sc->vmx_rss_dma);
994e557c1ddSBryan Venteicher 		sc->vmx_rss = NULL;
995e557c1ddSBryan Venteicher 	}
996e557c1ddSBryan Venteicher 
9978f82136aSPatrick Kelsey 	/* Free top level state structure shared with the device */
998e3c97c2cSBryan Venteicher 	if (sc->vmx_ds != NULL) {
9998f82136aSPatrick Kelsey 		iflib_dma_free(&sc->vmx_ds_dma);
1000e3c97c2cSBryan Venteicher 		sc->vmx_ds = NULL;
1001e3c97c2cSBryan Venteicher 	}
1002e3c97c2cSBryan Venteicher }
1003e3c97c2cSBryan Venteicher 
1004e3c97c2cSBryan Venteicher static int
1005e3c97c2cSBryan Venteicher vmxnet3_alloc_mcast_table(struct vmxnet3_softc *sc)
1006e3c97c2cSBryan Venteicher {
1007e3c97c2cSBryan Venteicher 	int error;
1008e3c97c2cSBryan Venteicher 
10098f82136aSPatrick Kelsey 	/* Multicast table state shared with the device */
10108f82136aSPatrick Kelsey 	error = iflib_dma_alloc_align(sc->vmx_ctx,
10118f82136aSPatrick Kelsey 	    VMXNET3_MULTICAST_MAX * ETHER_ADDR_LEN, 32, &sc->vmx_mcast_dma, 0);
1012e3c97c2cSBryan Venteicher 	if (error)
1013e3c97c2cSBryan Venteicher 		device_printf(sc->vmx_dev, "unable to alloc multicast table\n");
1014e3c97c2cSBryan Venteicher 	else
10158f82136aSPatrick Kelsey 		sc->vmx_mcast = sc->vmx_mcast_dma.idi_vaddr;
1016e3c97c2cSBryan Venteicher 
1017e3c97c2cSBryan Venteicher 	return (error);
1018e3c97c2cSBryan Venteicher }
1019e3c97c2cSBryan Venteicher 
1020e3c97c2cSBryan Venteicher static void
1021e3c97c2cSBryan Venteicher vmxnet3_free_mcast_table(struct vmxnet3_softc *sc)
1022e3c97c2cSBryan Venteicher {
1023e3c97c2cSBryan Venteicher 
10248f82136aSPatrick Kelsey 	/* Free multicast table state shared with the device */
1025e3c97c2cSBryan Venteicher 	if (sc->vmx_mcast != NULL) {
10268f82136aSPatrick Kelsey 		iflib_dma_free(&sc->vmx_mcast_dma);
1027e3c97c2cSBryan Venteicher 		sc->vmx_mcast = NULL;
1028e3c97c2cSBryan Venteicher 	}
1029e3c97c2cSBryan Venteicher }
1030e3c97c2cSBryan Venteicher 
1031e3c97c2cSBryan Venteicher static void
1032e3c97c2cSBryan Venteicher vmxnet3_init_shared_data(struct vmxnet3_softc *sc)
1033e3c97c2cSBryan Venteicher {
1034e3c97c2cSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
10358f82136aSPatrick Kelsey 	if_shared_ctx_t sctx;
10368f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
1037e3c97c2cSBryan Venteicher 	struct vmxnet3_txqueue *txq;
1038e3c97c2cSBryan Venteicher 	struct vmxnet3_txq_shared *txs;
1039e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
1040e3c97c2cSBryan Venteicher 	struct vmxnet3_rxq_shared *rxs;
1041e3c97c2cSBryan Venteicher 	int i;
1042e3c97c2cSBryan Venteicher 
1043e3c97c2cSBryan Venteicher 	ds = sc->vmx_ds;
10448f82136aSPatrick Kelsey 	sctx = sc->vmx_sctx;
10458f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
1046e3c97c2cSBryan Venteicher 
1047e3c97c2cSBryan Venteicher 	/*
1048e3c97c2cSBryan Venteicher 	 * Initialize fields of the shared data that remains the same across
1049e3c97c2cSBryan Venteicher 	 * reinits. Note the shared data is zero'd when allocated.
1050e3c97c2cSBryan Venteicher 	 */
1051e3c97c2cSBryan Venteicher 
1052e3c97c2cSBryan Venteicher 	ds->magic = VMXNET3_REV1_MAGIC;
1053e3c97c2cSBryan Venteicher 
1054e3c97c2cSBryan Venteicher 	/* DriverInfo */
1055e3c97c2cSBryan Venteicher 	ds->version = VMXNET3_DRIVER_VERSION;
1056ce3be286SBryan Venteicher 	ds->guest = VMXNET3_GOS_FREEBSD |
1057e3c97c2cSBryan Venteicher #ifdef __LP64__
1058e3c97c2cSBryan Venteicher 	    VMXNET3_GOS_64BIT;
1059e3c97c2cSBryan Venteicher #else
1060e3c97c2cSBryan Venteicher 	    VMXNET3_GOS_32BIT;
1061e3c97c2cSBryan Venteicher #endif
1062e3c97c2cSBryan Venteicher 	ds->vmxnet3_revision = 1;
1063e3c97c2cSBryan Venteicher 	ds->upt_version = 1;
1064e3c97c2cSBryan Venteicher 
1065e3c97c2cSBryan Venteicher 	/* Misc. conf */
1066e3c97c2cSBryan Venteicher 	ds->driver_data = vtophys(sc);
1067e3c97c2cSBryan Venteicher 	ds->driver_data_len = sizeof(struct vmxnet3_softc);
10688f82136aSPatrick Kelsey 	ds->queue_shared = sc->vmx_qs_dma.idi_paddr;
10698f82136aSPatrick Kelsey 	ds->queue_shared_len = sc->vmx_qs_dma.idi_size;
10708f82136aSPatrick Kelsey 	ds->nrxsg_max = IFLIB_MAX_RX_SEGS;
1071e3c97c2cSBryan Venteicher 
1072e557c1ddSBryan Venteicher 	/* RSS conf */
1073e557c1ddSBryan Venteicher 	if (sc->vmx_flags & VMXNET3_FLAG_RSS) {
1074e557c1ddSBryan Venteicher 		ds->rss.version = 1;
10758f82136aSPatrick Kelsey 		ds->rss.paddr = sc->vmx_rss_dma.idi_paddr;
10768f82136aSPatrick Kelsey 		ds->rss.len = sc->vmx_rss_dma.idi_size;
1077e557c1ddSBryan Venteicher 	}
1078e557c1ddSBryan Venteicher 
1079e3c97c2cSBryan Venteicher 	/* Interrupt control. */
1080e3c97c2cSBryan Venteicher 	ds->automask = sc->vmx_intr_mask_mode == VMXNET3_IMM_AUTO;
10818f82136aSPatrick Kelsey 	/*
10828f82136aSPatrick Kelsey 	 * Total number of interrupt indexes we are using in the shared
1083769d56ecSPatrick Kelsey 	 * config data, even though we don't actually allocate interrupt
10848f82136aSPatrick Kelsey 	 * resources for the tx queues.  Some versions of the device will
10858f82136aSPatrick Kelsey 	 * fail to initialize successfully if interrupt indexes are used in
10868f82136aSPatrick Kelsey 	 * the shared config that exceed the number of interrupts configured
10878f82136aSPatrick Kelsey 	 * here.
10888f82136aSPatrick Kelsey 	 */
10898f82136aSPatrick Kelsey 	ds->nintr = (scctx->isc_vectors == 1) ?
1090769d56ecSPatrick Kelsey 	    2 : (scctx->isc_nrxqsets + scctx->isc_ntxqsets + 1);
1091e3c97c2cSBryan Venteicher 	ds->evintr = sc->vmx_event_intr_idx;
1092e3c97c2cSBryan Venteicher 	ds->ictrl = VMXNET3_ICTRL_DISABLE_ALL;
1093e3c97c2cSBryan Venteicher 
10948f82136aSPatrick Kelsey 	for (i = 0; i < ds->nintr; i++)
1095e3c97c2cSBryan Venteicher 		ds->modlevel[i] = UPT1_IMOD_ADAPTIVE;
1096e3c97c2cSBryan Venteicher 
1097e3c97c2cSBryan Venteicher 	/* Receive filter. */
10988f82136aSPatrick Kelsey 	ds->mcast_table = sc->vmx_mcast_dma.idi_paddr;
10998f82136aSPatrick Kelsey 	ds->mcast_tablelen = sc->vmx_mcast_dma.idi_size;
1100e3c97c2cSBryan Venteicher 
1101e3c97c2cSBryan Venteicher 	/* Tx queues */
11028f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++) {
1103e3c97c2cSBryan Venteicher 		txq = &sc->vmx_txq[i];
1104e3c97c2cSBryan Venteicher 		txs = txq->vxtxq_ts;
1105e3c97c2cSBryan Venteicher 
11068f82136aSPatrick Kelsey 		txs->cmd_ring = txq->vxtxq_cmd_ring.vxtxr_paddr;
11073c965775SBryan Venteicher 		txs->cmd_ring_len = txq->vxtxq_cmd_ring.vxtxr_ndesc;
11088f82136aSPatrick Kelsey 		txs->comp_ring = txq->vxtxq_comp_ring.vxcr_paddr;
11093c965775SBryan Venteicher 		txs->comp_ring_len = txq->vxtxq_comp_ring.vxcr_ndesc;
1110e3c97c2cSBryan Venteicher 		txs->driver_data = vtophys(txq);
1111e3c97c2cSBryan Venteicher 		txs->driver_data_len = sizeof(struct vmxnet3_txqueue);
1112e3c97c2cSBryan Venteicher 	}
1113e3c97c2cSBryan Venteicher 
1114e3c97c2cSBryan Venteicher 	/* Rx queues */
11158f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
1116e3c97c2cSBryan Venteicher 		rxq = &sc->vmx_rxq[i];
1117e3c97c2cSBryan Venteicher 		rxs = rxq->vxrxq_rs;
1118e3c97c2cSBryan Venteicher 
11198f82136aSPatrick Kelsey 		rxs->cmd_ring[0] = rxq->vxrxq_cmd_ring[0].vxrxr_paddr;
1120e3c97c2cSBryan Venteicher 		rxs->cmd_ring_len[0] = rxq->vxrxq_cmd_ring[0].vxrxr_ndesc;
11218f82136aSPatrick Kelsey 		rxs->cmd_ring[1] = rxq->vxrxq_cmd_ring[1].vxrxr_paddr;
1122e3c97c2cSBryan Venteicher 		rxs->cmd_ring_len[1] = rxq->vxrxq_cmd_ring[1].vxrxr_ndesc;
11238f82136aSPatrick Kelsey 		rxs->comp_ring = rxq->vxrxq_comp_ring.vxcr_paddr;
11243c965775SBryan Venteicher 		rxs->comp_ring_len = rxq->vxrxq_comp_ring.vxcr_ndesc;
1125e3c97c2cSBryan Venteicher 		rxs->driver_data = vtophys(rxq);
1126e3c97c2cSBryan Venteicher 		rxs->driver_data_len = sizeof(struct vmxnet3_rxqueue);
1127e3c97c2cSBryan Venteicher 	}
1128e3c97c2cSBryan Venteicher }
1129e3c97c2cSBryan Venteicher 
1130e3c97c2cSBryan Venteicher static void
1131e557c1ddSBryan Venteicher vmxnet3_reinit_rss_shared_data(struct vmxnet3_softc *sc)
1132e557c1ddSBryan Venteicher {
1133e557c1ddSBryan Venteicher 	/*
1134e557c1ddSBryan Venteicher 	 * Use the same key as the Linux driver until FreeBSD can do
1135e557c1ddSBryan Venteicher 	 * RSS (presumably Toeplitz) in software.
1136e557c1ddSBryan Venteicher 	 */
1137e557c1ddSBryan Venteicher 	static const uint8_t rss_key[UPT1_RSS_MAX_KEY_SIZE] = {
1138e557c1ddSBryan Venteicher 	    0x3b, 0x56, 0xd1, 0x56, 0x13, 0x4a, 0xe7, 0xac,
1139e557c1ddSBryan Venteicher 	    0xe8, 0x79, 0x09, 0x75, 0xe8, 0x65, 0x79, 0x28,
1140e557c1ddSBryan Venteicher 	    0x35, 0x12, 0xb9, 0x56, 0x7c, 0x76, 0x4b, 0x70,
1141e557c1ddSBryan Venteicher 	    0xd8, 0x56, 0xa3, 0x18, 0x9b, 0x0a, 0xee, 0xf3,
1142e557c1ddSBryan Venteicher 	    0x96, 0xa6, 0x9f, 0x8f, 0x9e, 0x8c, 0x90, 0xc9,
1143e557c1ddSBryan Venteicher 	};
1144e557c1ddSBryan Venteicher 
1145e557c1ddSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
11468f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
1147e557c1ddSBryan Venteicher 	struct vmxnet3_rss_shared *rss;
1148281cab4dSAndriy Gapon #ifdef RSS
1149281cab4dSAndriy Gapon 	uint8_t rss_algo;
1150281cab4dSAndriy Gapon #endif
1151e557c1ddSBryan Venteicher 	int i;
1152e557c1ddSBryan Venteicher 
1153e557c1ddSBryan Venteicher 	ds = sc->vmx_ds;
11548f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
1155e557c1ddSBryan Venteicher 	rss = sc->vmx_rss;
1156e557c1ddSBryan Venteicher 
1157e557c1ddSBryan Venteicher 	rss->hash_type =
1158e557c1ddSBryan Venteicher 	    UPT1_RSS_HASH_TYPE_IPV4 | UPT1_RSS_HASH_TYPE_TCP_IPV4 |
1159e557c1ddSBryan Venteicher 	    UPT1_RSS_HASH_TYPE_IPV6 | UPT1_RSS_HASH_TYPE_TCP_IPV6;
1160e557c1ddSBryan Venteicher 	rss->hash_func = UPT1_RSS_HASH_FUNC_TOEPLITZ;
1161e557c1ddSBryan Venteicher 	rss->hash_key_size = UPT1_RSS_MAX_KEY_SIZE;
1162e557c1ddSBryan Venteicher 	rss->ind_table_size = UPT1_RSS_MAX_IND_TABLE_SIZE;
1163281cab4dSAndriy Gapon #ifdef RSS
1164281cab4dSAndriy Gapon 	/*
1165281cab4dSAndriy Gapon 	 * If the software RSS is configured to anything else other than
1166281cab4dSAndriy Gapon 	 * Toeplitz, then just do Toeplitz in "hardware" for the sake of
1167281cab4dSAndriy Gapon 	 * the packet distribution, but report the hash as opaque to
1168281cab4dSAndriy Gapon 	 * disengage from the software RSS.
1169281cab4dSAndriy Gapon 	 */
1170281cab4dSAndriy Gapon 	rss_algo = rss_gethashalgo();
1171281cab4dSAndriy Gapon 	if (rss_algo == RSS_HASH_TOEPLITZ) {
1172281cab4dSAndriy Gapon 		rss_getkey(rss->hash_key);
1173281cab4dSAndriy Gapon 		for (i = 0; i < UPT1_RSS_MAX_IND_TABLE_SIZE; i++) {
1174281cab4dSAndriy Gapon 			rss->ind_table[i] = rss_get_indirection_to_bucket(i) %
1175281cab4dSAndriy Gapon 			    scctx->isc_nrxqsets;
1176281cab4dSAndriy Gapon 		}
1177281cab4dSAndriy Gapon 		sc->vmx_flags |= VMXNET3_FLAG_SOFT_RSS;
1178281cab4dSAndriy Gapon 	} else
1179281cab4dSAndriy Gapon #endif
1180281cab4dSAndriy Gapon 	{
1181e557c1ddSBryan Venteicher 		memcpy(rss->hash_key, rss_key, UPT1_RSS_MAX_KEY_SIZE);
1182e557c1ddSBryan Venteicher 		for (i = 0; i < UPT1_RSS_MAX_IND_TABLE_SIZE; i++)
11838f82136aSPatrick Kelsey 			rss->ind_table[i] = i % scctx->isc_nrxqsets;
1184281cab4dSAndriy Gapon 		sc->vmx_flags &= ~VMXNET3_FLAG_SOFT_RSS;
1185281cab4dSAndriy Gapon 	}
1186e3c97c2cSBryan Venteicher }
1187e3c97c2cSBryan Venteicher 
1188e3c97c2cSBryan Venteicher static void
1189e3c97c2cSBryan Venteicher vmxnet3_reinit_shared_data(struct vmxnet3_softc *sc)
1190e3c97c2cSBryan Venteicher {
1191e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
1192e3c97c2cSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
11938f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
1194e3c97c2cSBryan Venteicher 
1195e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
1196e3c97c2cSBryan Venteicher 	ds = sc->vmx_ds;
11978f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
1198e3c97c2cSBryan Venteicher 
1199e557c1ddSBryan Venteicher 	ds->mtu = ifp->if_mtu;
12008f82136aSPatrick Kelsey 	ds->ntxqueue = scctx->isc_ntxqsets;
12018f82136aSPatrick Kelsey 	ds->nrxqueue = scctx->isc_nrxqsets;
1202e557c1ddSBryan Venteicher 
1203e3c97c2cSBryan Venteicher 	ds->upt_features = 0;
1204e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6))
1205e3c97c2cSBryan Venteicher 		ds->upt_features |= UPT1_F_CSUM;
12063c5dfe89SBryan Venteicher 	if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
12073c5dfe89SBryan Venteicher 		ds->upt_features |= UPT1_F_VLAN;
1208e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & IFCAP_LRO)
1209e3c97c2cSBryan Venteicher 		ds->upt_features |= UPT1_F_LRO;
1210e3c97c2cSBryan Venteicher 
1211e557c1ddSBryan Venteicher 	if (sc->vmx_flags & VMXNET3_FLAG_RSS) {
1212e557c1ddSBryan Venteicher 		ds->upt_features |= UPT1_F_RSS;
1213e557c1ddSBryan Venteicher 		vmxnet3_reinit_rss_shared_data(sc);
1214e557c1ddSBryan Venteicher 	}
1215e3c97c2cSBryan Venteicher 
12168f82136aSPatrick Kelsey 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_DSL, sc->vmx_ds_dma.idi_paddr);
1217e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_DSH,
12188f82136aSPatrick Kelsey 	    (uint64_t) sc->vmx_ds_dma.idi_paddr >> 32);
1219e3c97c2cSBryan Venteicher }
1220e3c97c2cSBryan Venteicher 
1221e3c97c2cSBryan Venteicher static int
1222e3c97c2cSBryan Venteicher vmxnet3_alloc_data(struct vmxnet3_softc *sc)
1223e3c97c2cSBryan Venteicher {
1224e3c97c2cSBryan Venteicher 	int error;
1225e3c97c2cSBryan Venteicher 
1226e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_shared_data(sc);
1227e3c97c2cSBryan Venteicher 	if (error)
1228e3c97c2cSBryan Venteicher 		return (error);
1229e3c97c2cSBryan Venteicher 
1230e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_mcast_table(sc);
1231e3c97c2cSBryan Venteicher 	if (error)
1232e3c97c2cSBryan Venteicher 		return (error);
1233e3c97c2cSBryan Venteicher 
1234e3c97c2cSBryan Venteicher 	vmxnet3_init_shared_data(sc);
1235e3c97c2cSBryan Venteicher 
1236e3c97c2cSBryan Venteicher 	return (0);
1237e3c97c2cSBryan Venteicher }
1238e3c97c2cSBryan Venteicher 
1239e3c97c2cSBryan Venteicher static void
1240e3c97c2cSBryan Venteicher vmxnet3_free_data(struct vmxnet3_softc *sc)
1241e3c97c2cSBryan Venteicher {
1242e3c97c2cSBryan Venteicher 
1243e3c97c2cSBryan Venteicher 	vmxnet3_free_mcast_table(sc);
1244e3c97c2cSBryan Venteicher 	vmxnet3_free_shared_data(sc);
1245e3c97c2cSBryan Venteicher }
1246e3c97c2cSBryan Venteicher 
1247e3c97c2cSBryan Venteicher static void
1248e3c97c2cSBryan Venteicher vmxnet3_evintr(struct vmxnet3_softc *sc)
1249e3c97c2cSBryan Venteicher {
1250e3c97c2cSBryan Venteicher 	device_t dev;
1251e3c97c2cSBryan Venteicher 	struct vmxnet3_txq_shared *ts;
1252e3c97c2cSBryan Venteicher 	struct vmxnet3_rxq_shared *rs;
1253e3c97c2cSBryan Venteicher 	uint32_t event;
1254e3c97c2cSBryan Venteicher 
1255e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
1256e3c97c2cSBryan Venteicher 
1257e3c97c2cSBryan Venteicher 	/* Clear events. */
1258e3c97c2cSBryan Venteicher 	event = sc->vmx_ds->event;
1259e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_EVENT, event);
1260e3c97c2cSBryan Venteicher 
12618f82136aSPatrick Kelsey 	if (event & VMXNET3_EVENT_LINK)
1262e3c97c2cSBryan Venteicher 		vmxnet3_link_status(sc);
1263e3c97c2cSBryan Venteicher 
1264e3c97c2cSBryan Venteicher 	if (event & (VMXNET3_EVENT_TQERROR | VMXNET3_EVENT_RQERROR)) {
1265e3c97c2cSBryan Venteicher 		vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_STATUS);
1266e3c97c2cSBryan Venteicher 		ts = sc->vmx_txq[0].vxtxq_ts;
1267e3c97c2cSBryan Venteicher 		if (ts->stopped != 0)
1268e3c97c2cSBryan Venteicher 			device_printf(dev, "Tx queue error %#x\n", ts->error);
1269e3c97c2cSBryan Venteicher 		rs = sc->vmx_rxq[0].vxrxq_rs;
1270e3c97c2cSBryan Venteicher 		if (rs->stopped != 0)
1271e3c97c2cSBryan Venteicher 			device_printf(dev, "Rx queue error %#x\n", rs->error);
12728f82136aSPatrick Kelsey 
12738f82136aSPatrick Kelsey 		/* XXX - rely on liflib watchdog to reset us? */
12748f82136aSPatrick Kelsey 		device_printf(dev, "Rx/Tx queue error event ... "
12758f82136aSPatrick Kelsey 		    "waiting for iflib watchdog reset\n");
1276e3c97c2cSBryan Venteicher 	}
1277e3c97c2cSBryan Venteicher 
1278e3c97c2cSBryan Venteicher 	if (event & VMXNET3_EVENT_DIC)
1279e3c97c2cSBryan Venteicher 		device_printf(dev, "device implementation change event\n");
1280e3c97c2cSBryan Venteicher 	if (event & VMXNET3_EVENT_DEBUG)
1281e3c97c2cSBryan Venteicher 		device_printf(dev, "debug event\n");
1282e3c97c2cSBryan Venteicher }
1283e3c97c2cSBryan Venteicher 
12848f82136aSPatrick Kelsey static int
12858f82136aSPatrick Kelsey vmxnet3_isc_txd_encap(void *vsc, if_pkt_info_t pi)
12868f82136aSPatrick Kelsey {
12878f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
12888f82136aSPatrick Kelsey 	struct vmxnet3_txqueue *txq;
12898f82136aSPatrick Kelsey 	struct vmxnet3_txring *txr;
12908f82136aSPatrick Kelsey 	struct vmxnet3_txdesc *txd, *sop;
12918f82136aSPatrick Kelsey 	bus_dma_segment_t *segs;
12928f82136aSPatrick Kelsey 	int nsegs;
12938f82136aSPatrick Kelsey 	int pidx;
12948f82136aSPatrick Kelsey 	int hdrlen;
12958f82136aSPatrick Kelsey 	int i;
12968f82136aSPatrick Kelsey 	int gen;
12978f82136aSPatrick Kelsey 
12988f82136aSPatrick Kelsey 	sc = vsc;
12998f82136aSPatrick Kelsey 	txq = &sc->vmx_txq[pi->ipi_qsidx];
13008f82136aSPatrick Kelsey 	txr = &txq->vxtxq_cmd_ring;
13018f82136aSPatrick Kelsey 	segs = pi->ipi_segs;
13028f82136aSPatrick Kelsey 	nsegs = pi->ipi_nsegs;
13038f82136aSPatrick Kelsey 	pidx = pi->ipi_pidx;
13048f82136aSPatrick Kelsey 
13058f82136aSPatrick Kelsey 	KASSERT(nsegs <= VMXNET3_TX_MAXSEGS,
13068f82136aSPatrick Kelsey 	    ("%s: packet with too many segments %d", __func__, nsegs));
13078f82136aSPatrick Kelsey 
13088f82136aSPatrick Kelsey 	sop = &txr->vxtxr_txd[pidx];
13098f82136aSPatrick Kelsey 	gen = txr->vxtxr_gen ^ 1;	/* Owned by cpu (yet) */
13108f82136aSPatrick Kelsey 
13118f82136aSPatrick Kelsey 	for (i = 0; i < nsegs; i++) {
13128f82136aSPatrick Kelsey 		txd = &txr->vxtxr_txd[pidx];
13138f82136aSPatrick Kelsey 
13148f82136aSPatrick Kelsey 		txd->addr = segs[i].ds_addr;
13158f82136aSPatrick Kelsey 		txd->len = segs[i].ds_len;
13168f82136aSPatrick Kelsey 		txd->gen = gen;
13178f82136aSPatrick Kelsey 		txd->dtype = 0;
13188f82136aSPatrick Kelsey 		txd->offload_mode = VMXNET3_OM_NONE;
13198f82136aSPatrick Kelsey 		txd->offload_pos = 0;
13208f82136aSPatrick Kelsey 		txd->hlen = 0;
13218f82136aSPatrick Kelsey 		txd->eop = 0;
13228f82136aSPatrick Kelsey 		txd->compreq = 0;
13238f82136aSPatrick Kelsey 		txd->vtag_mode = 0;
13248f82136aSPatrick Kelsey 		txd->vtag = 0;
13258f82136aSPatrick Kelsey 
13268f82136aSPatrick Kelsey 		if (++pidx == txr->vxtxr_ndesc) {
13278f82136aSPatrick Kelsey 			pidx = 0;
13288f82136aSPatrick Kelsey 			txr->vxtxr_gen ^= 1;
13298f82136aSPatrick Kelsey 		}
13308f82136aSPatrick Kelsey 		gen = txr->vxtxr_gen;
13318f82136aSPatrick Kelsey 	}
13328f82136aSPatrick Kelsey 	txd->eop = 1;
13338f82136aSPatrick Kelsey 	txd->compreq = !!(pi->ipi_flags & IPI_TX_INTR);
13348f82136aSPatrick Kelsey 	pi->ipi_new_pidx = pidx;
13358f82136aSPatrick Kelsey 
13368f82136aSPatrick Kelsey 	/*
13378f82136aSPatrick Kelsey 	 * VLAN
13388f82136aSPatrick Kelsey 	 */
13398f82136aSPatrick Kelsey 	if (pi->ipi_mflags & M_VLANTAG) {
13408f82136aSPatrick Kelsey 		sop->vtag_mode = 1;
13418f82136aSPatrick Kelsey 		sop->vtag = pi->ipi_vtag;
13428f82136aSPatrick Kelsey 	}
13438f82136aSPatrick Kelsey 
13448f82136aSPatrick Kelsey 	/*
13458f82136aSPatrick Kelsey 	 * TSO and checksum offloads
13468f82136aSPatrick Kelsey 	 */
13478f82136aSPatrick Kelsey 	hdrlen = pi->ipi_ehdrlen + pi->ipi_ip_hlen;
13488f82136aSPatrick Kelsey 	if (pi->ipi_csum_flags & CSUM_TSO) {
13498f82136aSPatrick Kelsey 		sop->offload_mode = VMXNET3_OM_TSO;
1350f55f37d9SVincenzo Maffione 		sop->hlen = hdrlen + pi->ipi_tcp_hlen;
13518f82136aSPatrick Kelsey 		sop->offload_pos = pi->ipi_tso_segsz;
13528f82136aSPatrick Kelsey 	} else if (pi->ipi_csum_flags & (VMXNET3_CSUM_OFFLOAD |
13538f82136aSPatrick Kelsey 	    VMXNET3_CSUM_OFFLOAD_IPV6)) {
13548f82136aSPatrick Kelsey 		sop->offload_mode = VMXNET3_OM_CSUM;
13558f82136aSPatrick Kelsey 		sop->hlen = hdrlen;
13568f82136aSPatrick Kelsey 		sop->offload_pos = hdrlen +
13578f82136aSPatrick Kelsey 		    ((pi->ipi_ipproto == IPPROTO_TCP) ?
13588f82136aSPatrick Kelsey 			offsetof(struct tcphdr, th_sum) :
13598f82136aSPatrick Kelsey 			offsetof(struct udphdr, uh_sum));
13608f82136aSPatrick Kelsey 	}
13618f82136aSPatrick Kelsey 
13628f82136aSPatrick Kelsey 	/* Finally, change the ownership. */
13638f82136aSPatrick Kelsey 	vmxnet3_barrier(sc, VMXNET3_BARRIER_WR);
13648f82136aSPatrick Kelsey 	sop->gen ^= 1;
13658f82136aSPatrick Kelsey 
13668f82136aSPatrick Kelsey 	return (0);
1367e3c97c2cSBryan Venteicher }
1368e3c97c2cSBryan Venteicher 
1369e3c97c2cSBryan Venteicher static void
13708f82136aSPatrick Kelsey vmxnet3_isc_txd_flush(void *vsc, uint16_t txqid, qidx_t pidx)
1371e3c97c2cSBryan Venteicher {
1372e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
13738f82136aSPatrick Kelsey 	struct vmxnet3_txqueue *txq;
13748f82136aSPatrick Kelsey 
13758f82136aSPatrick Kelsey 	sc = vsc;
13768f82136aSPatrick Kelsey 	txq = &sc->vmx_txq[txqid];
13778f82136aSPatrick Kelsey 
13788f82136aSPatrick Kelsey 	/*
13798f82136aSPatrick Kelsey 	 * pidx is what we last set ipi_new_pidx to in
13808f82136aSPatrick Kelsey 	 * vmxnet3_isc_txd_encap()
13818f82136aSPatrick Kelsey 	 */
13828f82136aSPatrick Kelsey 
13838f82136aSPatrick Kelsey 	/*
13848f82136aSPatrick Kelsey 	 * Avoid expensive register updates if the flush request is
13858f82136aSPatrick Kelsey 	 * redundant.
13868f82136aSPatrick Kelsey 	 */
13878f82136aSPatrick Kelsey 	if (txq->vxtxq_last_flush == pidx)
13888f82136aSPatrick Kelsey 		return;
13898f82136aSPatrick Kelsey 	txq->vxtxq_last_flush = pidx;
13908f82136aSPatrick Kelsey 	vmxnet3_write_bar0(sc, VMXNET3_BAR0_TXH(txq->vxtxq_id), pidx);
13918f82136aSPatrick Kelsey }
13928f82136aSPatrick Kelsey 
13938f82136aSPatrick Kelsey static int
13948f82136aSPatrick Kelsey vmxnet3_isc_txd_credits_update(void *vsc, uint16_t txqid, bool clear)
13958f82136aSPatrick Kelsey {
13968f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
13978f82136aSPatrick Kelsey 	struct vmxnet3_txqueue *txq;
1398e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *txc;
1399e3c97c2cSBryan Venteicher 	struct vmxnet3_txcompdesc *txcd;
14008f82136aSPatrick Kelsey 	struct vmxnet3_txring *txr;
14018f82136aSPatrick Kelsey 	int processed;
1402e3c97c2cSBryan Venteicher 
14038f82136aSPatrick Kelsey 	sc = vsc;
14048f82136aSPatrick Kelsey 	txq = &sc->vmx_txq[txqid];
1405e3c97c2cSBryan Venteicher 	txc = &txq->vxtxq_comp_ring;
14068f82136aSPatrick Kelsey 	txr = &txq->vxtxq_cmd_ring;
1407e3c97c2cSBryan Venteicher 
14088f82136aSPatrick Kelsey 	/*
14098f82136aSPatrick Kelsey 	 * If clear is true, we need to report the number of TX command ring
14108f82136aSPatrick Kelsey 	 * descriptors that have been processed by the device.  If clear is
14118f82136aSPatrick Kelsey 	 * false, we just need to report whether or not at least one TX
14128f82136aSPatrick Kelsey 	 * command ring descriptor has been processed by the device.
14138f82136aSPatrick Kelsey 	 */
14148f82136aSPatrick Kelsey 	processed = 0;
1415e3c97c2cSBryan Venteicher 	for (;;) {
1416e3c97c2cSBryan Venteicher 		txcd = &txc->vxcr_u.txcd[txc->vxcr_next];
1417e3c97c2cSBryan Venteicher 		if (txcd->gen != txc->vxcr_gen)
1418e3c97c2cSBryan Venteicher 			break;
14198f82136aSPatrick Kelsey 		else if (!clear)
14208f82136aSPatrick Kelsey 			return (1);
14213c965775SBryan Venteicher 		vmxnet3_barrier(sc, VMXNET3_BARRIER_RD);
1422e3c97c2cSBryan Venteicher 
1423e3c97c2cSBryan Venteicher 		if (++txc->vxcr_next == txc->vxcr_ndesc) {
1424e3c97c2cSBryan Venteicher 			txc->vxcr_next = 0;
1425e3c97c2cSBryan Venteicher 			txc->vxcr_gen ^= 1;
1426e3c97c2cSBryan Venteicher 		}
1427e3c97c2cSBryan Venteicher 
14288f82136aSPatrick Kelsey 		if (txcd->eop_idx < txr->vxtxr_next)
14298f82136aSPatrick Kelsey 			processed += txr->vxtxr_ndesc -
14308f82136aSPatrick Kelsey 			    (txr->vxtxr_next - txcd->eop_idx) + 1;
14318f82136aSPatrick Kelsey 		else
14328f82136aSPatrick Kelsey 			processed += txcd->eop_idx - txr->vxtxr_next + 1;
1433e3c97c2cSBryan Venteicher 		txr->vxtxr_next = (txcd->eop_idx + 1) % txr->vxtxr_ndesc;
1434e3c97c2cSBryan Venteicher 	}
1435e3c97c2cSBryan Venteicher 
14368f82136aSPatrick Kelsey 	return (processed);
1437e3c97c2cSBryan Venteicher }
1438e3c97c2cSBryan Venteicher 
1439e3c97c2cSBryan Venteicher static int
14408f82136aSPatrick Kelsey vmxnet3_isc_rxd_available(void *vsc, uint16_t rxqid, qidx_t idx, qidx_t budget)
1441e3c97c2cSBryan Venteicher {
14428f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
14438f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
14448f82136aSPatrick Kelsey 	struct vmxnet3_comp_ring *rxc;
14458f82136aSPatrick Kelsey 	struct vmxnet3_rxcompdesc *rxcd;
14468f82136aSPatrick Kelsey 	int avail;
14478f82136aSPatrick Kelsey 	int completed_gen;
14488f82136aSPatrick Kelsey #ifdef INVARIANTS
14498f82136aSPatrick Kelsey 	int expect_sop = 1;
14508f82136aSPatrick Kelsey #endif
14518f82136aSPatrick Kelsey 	sc = vsc;
14528f82136aSPatrick Kelsey 	rxq = &sc->vmx_rxq[rxqid];
14538f82136aSPatrick Kelsey 	rxc = &rxq->vxrxq_comp_ring;
14548f82136aSPatrick Kelsey 
14558f82136aSPatrick Kelsey 	avail = 0;
14568f82136aSPatrick Kelsey 	completed_gen = rxc->vxcr_gen;
14578f82136aSPatrick Kelsey 	for (;;) {
14588f82136aSPatrick Kelsey 		rxcd = &rxc->vxcr_u.rxcd[idx];
14598f82136aSPatrick Kelsey 		if (rxcd->gen != completed_gen)
14608f82136aSPatrick Kelsey 			break;
14618f82136aSPatrick Kelsey 		vmxnet3_barrier(sc, VMXNET3_BARRIER_RD);
14628f82136aSPatrick Kelsey 
14638f82136aSPatrick Kelsey #ifdef INVARIANTS
14648f82136aSPatrick Kelsey 		if (expect_sop)
14658f82136aSPatrick Kelsey 			KASSERT(rxcd->sop, ("%s: expected sop", __func__));
14668f82136aSPatrick Kelsey 		else
14678f82136aSPatrick Kelsey 			KASSERT(!rxcd->sop, ("%s: unexpected sop", __func__));
14688f82136aSPatrick Kelsey 		expect_sop = rxcd->eop;
14698f82136aSPatrick Kelsey #endif
14708f82136aSPatrick Kelsey 		if (rxcd->eop && (rxcd->len != 0))
14718f82136aSPatrick Kelsey 			avail++;
14728f82136aSPatrick Kelsey 		if (avail > budget)
14738f82136aSPatrick Kelsey 			break;
14748f82136aSPatrick Kelsey 		if (++idx == rxc->vxcr_ndesc) {
14758f82136aSPatrick Kelsey 			idx = 0;
14768f82136aSPatrick Kelsey 			completed_gen ^= 1;
14778f82136aSPatrick Kelsey 		}
14788f82136aSPatrick Kelsey 	}
14798f82136aSPatrick Kelsey 
14808f82136aSPatrick Kelsey 	return (avail);
14818f82136aSPatrick Kelsey }
14828f82136aSPatrick Kelsey 
14838f82136aSPatrick Kelsey static int
14848f82136aSPatrick Kelsey vmxnet3_isc_rxd_pkt_get(void *vsc, if_rxd_info_t ri)
14858f82136aSPatrick Kelsey {
14868f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
14878f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
14888f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
14898f82136aSPatrick Kelsey 	struct vmxnet3_comp_ring *rxc;
14908f82136aSPatrick Kelsey 	struct vmxnet3_rxcompdesc *rxcd;
14918f82136aSPatrick Kelsey 	struct vmxnet3_rxring *rxr;
1492e3c97c2cSBryan Venteicher 	struct vmxnet3_rxdesc *rxd;
14938f82136aSPatrick Kelsey 	if_rxd_frag_t frag;
14948f82136aSPatrick Kelsey 	int cqidx;
14958f82136aSPatrick Kelsey 	uint16_t total_len;
14968f82136aSPatrick Kelsey 	uint8_t nfrags;
14978f82136aSPatrick Kelsey 	uint8_t flid;
1498e3c97c2cSBryan Venteicher 
14998f82136aSPatrick Kelsey 	sc = vsc;
15008f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
15018f82136aSPatrick Kelsey 	rxq = &sc->vmx_rxq[ri->iri_qsidx];
15028f82136aSPatrick Kelsey 	rxc = &rxq->vxrxq_comp_ring;
1503e3c97c2cSBryan Venteicher 
1504e3c97c2cSBryan Venteicher 	/*
15058f82136aSPatrick Kelsey 	 * Get a single packet starting at the given index in the completion
15068f82136aSPatrick Kelsey 	 * queue.  That we have been called indicates that
15078f82136aSPatrick Kelsey 	 * vmxnet3_isc_rxd_available() has already verified that either
15088f82136aSPatrick Kelsey 	 * there is a complete packet available starting at the given index,
15098f82136aSPatrick Kelsey 	 * or there are one or more zero length packets starting at the
15108f82136aSPatrick Kelsey 	 * given index followed by a complete packet, so no verification of
15118f82136aSPatrick Kelsey 	 * ownership of the descriptors (and no associated read barrier) is
15128f82136aSPatrick Kelsey 	 * required here.
1513e3c97c2cSBryan Venteicher 	 */
15148f82136aSPatrick Kelsey 	cqidx = ri->iri_cidx;
15158f82136aSPatrick Kelsey 	rxcd = &rxc->vxcr_u.rxcd[cqidx];
15168f82136aSPatrick Kelsey 	while (rxcd->len == 0) {
15178f82136aSPatrick Kelsey 		KASSERT(rxcd->sop && rxcd->eop,
15188f82136aSPatrick Kelsey 		    ("%s: zero-length packet without both sop and eop set",
15198f82136aSPatrick Kelsey 			__func__));
15208f82136aSPatrick Kelsey 		if (++cqidx == rxc->vxcr_ndesc) {
15218f82136aSPatrick Kelsey 			cqidx = 0;
15228f82136aSPatrick Kelsey 			rxc->vxcr_gen ^= 1;
15238f82136aSPatrick Kelsey 		}
15248f82136aSPatrick Kelsey 		rxcd = &rxc->vxcr_u.rxcd[cqidx];
15258f82136aSPatrick Kelsey 	}
15268f82136aSPatrick Kelsey 	KASSERT(rxcd->sop, ("%s: expected sop", __func__));
15278f82136aSPatrick Kelsey 
15288f82136aSPatrick Kelsey 	/*
1529281cab4dSAndriy Gapon 	 * RSS and flow ID.
1530281cab4dSAndriy Gapon 	 * Types other than M_HASHTYPE_NONE and M_HASHTYPE_OPAQUE_HASH should
1531281cab4dSAndriy Gapon 	 * be used only if the software RSS is enabled and it uses the same
1532281cab4dSAndriy Gapon 	 * algorithm and the hash key as the "hardware".  If the software RSS
1533281cab4dSAndriy Gapon 	 * is not enabled, then it's simply pointless to use those types.
1534281cab4dSAndriy Gapon 	 * If it's enabled but with different parameters, then hash values will
1535281cab4dSAndriy Gapon 	 * not match.
15368f82136aSPatrick Kelsey 	 */
15378f82136aSPatrick Kelsey 	ri->iri_flowid = rxcd->rss_hash;
1538281cab4dSAndriy Gapon #ifdef RSS
1539281cab4dSAndriy Gapon 	if ((sc->vmx_flags & VMXNET3_FLAG_SOFT_RSS) != 0) {
15408f82136aSPatrick Kelsey 		switch (rxcd->rss_type) {
15418f82136aSPatrick Kelsey 		case VMXNET3_RCD_RSS_TYPE_NONE:
15428f82136aSPatrick Kelsey 			ri->iri_flowid = ri->iri_qsidx;
15438f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_NONE;
15448f82136aSPatrick Kelsey 			break;
15458f82136aSPatrick Kelsey 		case VMXNET3_RCD_RSS_TYPE_IPV4:
15468f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_RSS_IPV4;
15478f82136aSPatrick Kelsey 			break;
15488f82136aSPatrick Kelsey 		case VMXNET3_RCD_RSS_TYPE_TCPIPV4:
15498f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_RSS_TCP_IPV4;
15508f82136aSPatrick Kelsey 			break;
15518f82136aSPatrick Kelsey 		case VMXNET3_RCD_RSS_TYPE_IPV6:
15528f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_RSS_IPV6;
15538f82136aSPatrick Kelsey 			break;
15548f82136aSPatrick Kelsey 		case VMXNET3_RCD_RSS_TYPE_TCPIPV6:
15558f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_RSS_TCP_IPV6;
15568f82136aSPatrick Kelsey 			break;
15578f82136aSPatrick Kelsey 		default:
15588f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_OPAQUE_HASH;
15598f82136aSPatrick Kelsey 			break;
1560e3c97c2cSBryan Venteicher 		}
1561281cab4dSAndriy Gapon 	} else
1562281cab4dSAndriy Gapon #endif
1563281cab4dSAndriy Gapon 	{
1564281cab4dSAndriy Gapon 		switch (rxcd->rss_type) {
1565281cab4dSAndriy Gapon 		case VMXNET3_RCD_RSS_TYPE_NONE:
1566281cab4dSAndriy Gapon 			ri->iri_flowid = ri->iri_qsidx;
1567281cab4dSAndriy Gapon 			ri->iri_rsstype = M_HASHTYPE_NONE;
1568281cab4dSAndriy Gapon 			break;
1569281cab4dSAndriy Gapon 		default:
1570281cab4dSAndriy Gapon 			ri->iri_rsstype = M_HASHTYPE_OPAQUE_HASH;
1571281cab4dSAndriy Gapon 			break;
1572281cab4dSAndriy Gapon 		}
1573281cab4dSAndriy Gapon 	}
1574e3c97c2cSBryan Venteicher 
15758f82136aSPatrick Kelsey 	/* VLAN */
15768f82136aSPatrick Kelsey 	if (rxcd->vlan) {
15778f82136aSPatrick Kelsey 		ri->iri_flags |= M_VLANTAG;
15788f82136aSPatrick Kelsey 		ri->iri_vtag = rxcd->vtag;
1579e3c97c2cSBryan Venteicher 	}
1580e3c97c2cSBryan Venteicher 
15818f82136aSPatrick Kelsey 	/* Checksum offload */
15828f82136aSPatrick Kelsey 	if (!rxcd->no_csum) {
15838f82136aSPatrick Kelsey 		uint32_t csum_flags = 0;
1584e3c97c2cSBryan Venteicher 
15858f82136aSPatrick Kelsey 		if (rxcd->ipv4) {
15868f82136aSPatrick Kelsey 			csum_flags |= CSUM_IP_CHECKED;
15878f82136aSPatrick Kelsey 			if (rxcd->ipcsum_ok)
15888f82136aSPatrick Kelsey 				csum_flags |= CSUM_IP_VALID;
1589e3c97c2cSBryan Venteicher 		}
15908f82136aSPatrick Kelsey 		if (!rxcd->fragment && (rxcd->tcp || rxcd->udp)) {
15918f82136aSPatrick Kelsey 			csum_flags |= CSUM_L4_CALC;
15928f82136aSPatrick Kelsey 			if (rxcd->csum_ok) {
15938f82136aSPatrick Kelsey 				csum_flags |= CSUM_L4_VALID;
15948f82136aSPatrick Kelsey 				ri->iri_csum_data = 0xffff;
15958f82136aSPatrick Kelsey 			}
15968f82136aSPatrick Kelsey 		}
15978f82136aSPatrick Kelsey 		ri->iri_csum_flags = csum_flags;
1598e3c97c2cSBryan Venteicher 	}
1599e3c97c2cSBryan Venteicher 
16008f82136aSPatrick Kelsey 	/*
16018f82136aSPatrick Kelsey 	 * The queue numbering scheme used for rxcd->qid is as follows:
16028f82136aSPatrick Kelsey 	 *  - All of the command ring 0s are numbered [0, nrxqsets - 1]
16038f82136aSPatrick Kelsey 	 *  - All of the command ring 1s are numbered [nrxqsets, 2*nrxqsets - 1]
16048f82136aSPatrick Kelsey 	 *
16058f82136aSPatrick Kelsey 	 * Thus, rxcd->qid less than nrxqsets indicates command ring (and
16068f82136aSPatrick Kelsey 	 * flid) 0, and rxcd->qid greater than or equal to nrxqsets
16078f82136aSPatrick Kelsey 	 * indicates command ring (and flid) 1.
16088f82136aSPatrick Kelsey 	 */
16098f82136aSPatrick Kelsey 	nfrags = 0;
16108f82136aSPatrick Kelsey 	total_len = 0;
16118f82136aSPatrick Kelsey 	do {
16128f82136aSPatrick Kelsey 		rxcd = &rxc->vxcr_u.rxcd[cqidx];
16138f82136aSPatrick Kelsey 		KASSERT(rxcd->gen == rxc->vxcr_gen,
16148f82136aSPatrick Kelsey 		    ("%s: generation mismatch", __func__));
16158f82136aSPatrick Kelsey 		flid = (rxcd->qid >= scctx->isc_nrxqsets) ? 1 : 0;
16168f82136aSPatrick Kelsey 		rxr = &rxq->vxrxq_cmd_ring[flid];
16178f82136aSPatrick Kelsey 		rxd = &rxr->vxrxr_rxd[rxcd->rxd_idx];
1618e3c97c2cSBryan Venteicher 
16198f82136aSPatrick Kelsey 		frag = &ri->iri_frags[nfrags];
16208f82136aSPatrick Kelsey 		frag->irf_flid = flid;
16218f82136aSPatrick Kelsey 		frag->irf_idx = rxcd->rxd_idx;
16228f82136aSPatrick Kelsey 		frag->irf_len = rxcd->len;
16238f82136aSPatrick Kelsey 		total_len += rxcd->len;
16248f82136aSPatrick Kelsey 		nfrags++;
16258f82136aSPatrick Kelsey 		if (++cqidx == rxc->vxcr_ndesc) {
16268f82136aSPatrick Kelsey 			cqidx = 0;
16278f82136aSPatrick Kelsey 			rxc->vxcr_gen ^= 1;
16288f82136aSPatrick Kelsey 		}
16298f82136aSPatrick Kelsey 	} while (!rxcd->eop);
1630e3c97c2cSBryan Venteicher 
16318f82136aSPatrick Kelsey 	ri->iri_cidx = cqidx;
16328f82136aSPatrick Kelsey 	ri->iri_nfrags = nfrags;
16338f82136aSPatrick Kelsey 	ri->iri_len = total_len;
16348f82136aSPatrick Kelsey 
1635e3c97c2cSBryan Venteicher 	return (0);
1636e3c97c2cSBryan Venteicher }
1637e3c97c2cSBryan Venteicher 
1638e3c97c2cSBryan Venteicher static void
16398f82136aSPatrick Kelsey vmxnet3_isc_rxd_refill(void *vsc, if_rxd_update_t iru)
1640e3c97c2cSBryan Venteicher {
1641e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
16428f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
1643e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
1644e3c97c2cSBryan Venteicher 	struct vmxnet3_rxdesc *rxd;
16458f82136aSPatrick Kelsey 	uint64_t *paddrs;
16468f82136aSPatrick Kelsey 	int count;
16478f82136aSPatrick Kelsey 	int len;
16488f82136aSPatrick Kelsey 	int pidx;
16498f82136aSPatrick Kelsey 	int i;
16508f82136aSPatrick Kelsey 	uint8_t flid;
16518f82136aSPatrick Kelsey 	uint8_t btype;
1652e3c97c2cSBryan Venteicher 
16538f82136aSPatrick Kelsey 	count = iru->iru_count;
16548f82136aSPatrick Kelsey 	len = iru->iru_buf_size;
16558f82136aSPatrick Kelsey 	pidx = iru->iru_pidx;
16568f82136aSPatrick Kelsey 	flid = iru->iru_flidx;
16578f82136aSPatrick Kelsey 	paddrs = iru->iru_paddrs;
1658e3c97c2cSBryan Venteicher 
16598f82136aSPatrick Kelsey 	sc = vsc;
16608f82136aSPatrick Kelsey 	rxq = &sc->vmx_rxq[iru->iru_qsidx];
16618f82136aSPatrick Kelsey 	rxr = &rxq->vxrxq_cmd_ring[flid];
16628f82136aSPatrick Kelsey 	rxd = rxr->vxrxr_rxd;
1663e3c97c2cSBryan Venteicher 
1664e3c97c2cSBryan Venteicher 	/*
16658f82136aSPatrick Kelsey 	 * Command ring 0 is filled with BTYPE_HEAD descriptors, and
16668f82136aSPatrick Kelsey 	 * command ring 1 is filled with BTYPE_BODY descriptors.
1667e3c97c2cSBryan Venteicher 	 */
16688f82136aSPatrick Kelsey 	btype = (flid == 0) ? VMXNET3_BTYPE_HEAD : VMXNET3_BTYPE_BODY;
16698f82136aSPatrick Kelsey 	for (i = 0; i < count; i++) {
16708f82136aSPatrick Kelsey 		rxd[pidx].addr = paddrs[i];
16718f82136aSPatrick Kelsey 		rxd[pidx].len = len;
16728f82136aSPatrick Kelsey 		rxd[pidx].btype = btype;
16738f82136aSPatrick Kelsey 		rxd[pidx].gen = rxr->vxrxr_gen;
16748f82136aSPatrick Kelsey 
16758f82136aSPatrick Kelsey 		if (++pidx == rxr->vxrxr_ndesc) {
16768f82136aSPatrick Kelsey 			pidx = 0;
16778f82136aSPatrick Kelsey 			rxr->vxrxr_gen ^= 1;
16788f82136aSPatrick Kelsey 		}
1679e3c97c2cSBryan Venteicher 	}
1680e3c97c2cSBryan Venteicher }
1681e3c97c2cSBryan Venteicher 
16828f82136aSPatrick Kelsey static void
16838f82136aSPatrick Kelsey vmxnet3_isc_rxd_flush(void *vsc, uint16_t rxqid, uint8_t flid, qidx_t pidx)
16848f82136aSPatrick Kelsey {
16858f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
16868f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
16878f82136aSPatrick Kelsey 	struct vmxnet3_rxring *rxr;
1688e3c97c2cSBryan Venteicher 	bus_size_t r;
1689e3c97c2cSBryan Venteicher 
16908f82136aSPatrick Kelsey 	sc = vsc;
16918f82136aSPatrick Kelsey 	rxq = &sc->vmx_rxq[rxqid];
16928f82136aSPatrick Kelsey 	rxr = &rxq->vxrxq_cmd_ring[flid];
16938f82136aSPatrick Kelsey 
16948f82136aSPatrick Kelsey 	if (flid == 0)
16958f82136aSPatrick Kelsey 		r = VMXNET3_BAR0_RXH1(rxqid);
16968f82136aSPatrick Kelsey 	else
16978f82136aSPatrick Kelsey 		r = VMXNET3_BAR0_RXH2(rxqid);
16988f82136aSPatrick Kelsey 
16998f82136aSPatrick Kelsey 	/*
17008f82136aSPatrick Kelsey 	 * pidx is the index of the last descriptor with a buffer the device
17018f82136aSPatrick Kelsey 	 * can use, and the device needs to be told which index is one past
17028f82136aSPatrick Kelsey 	 * that.
17038f82136aSPatrick Kelsey 	 */
17048f82136aSPatrick Kelsey 	if (++pidx == rxr->vxrxr_ndesc)
17058f82136aSPatrick Kelsey 		pidx = 0;
17068f82136aSPatrick Kelsey 	vmxnet3_write_bar0(sc, r, pidx);
1707e3c97c2cSBryan Venteicher }
1708e3c97c2cSBryan Venteicher 
17098f82136aSPatrick Kelsey static int
1710e3c97c2cSBryan Venteicher vmxnet3_legacy_intr(void *xsc)
1711e3c97c2cSBryan Venteicher {
1712e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
17138f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
17148f82136aSPatrick Kelsey 	if_ctx_t ctx;
1715e3c97c2cSBryan Venteicher 
1716e3c97c2cSBryan Venteicher 	sc = xsc;
17178f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
17188f82136aSPatrick Kelsey 	ctx = sc->vmx_ctx;
1719e3c97c2cSBryan Venteicher 
17208f82136aSPatrick Kelsey 	/*
17218f82136aSPatrick Kelsey 	 * When there is only a single interrupt configured, this routine
17228f82136aSPatrick Kelsey 	 * runs in fast interrupt context, following which the rxq 0 task
17238f82136aSPatrick Kelsey 	 * will be enqueued.
17248f82136aSPatrick Kelsey 	 */
17258f82136aSPatrick Kelsey 	if (scctx->isc_intr == IFLIB_INTR_LEGACY) {
1726e3c97c2cSBryan Venteicher 		if (vmxnet3_read_bar1(sc, VMXNET3_BAR1_INTR) == 0)
17278f82136aSPatrick Kelsey 			return (FILTER_HANDLED);
1728e3c97c2cSBryan Venteicher 	}
1729e3c97c2cSBryan Venteicher 	if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE)
17308f82136aSPatrick Kelsey 		vmxnet3_intr_disable_all(ctx);
1731e3c97c2cSBryan Venteicher 
1732e3c97c2cSBryan Venteicher 	if (sc->vmx_ds->event != 0)
17338f82136aSPatrick Kelsey 		iflib_admin_intr_deferred(ctx);
1734e3c97c2cSBryan Venteicher 
17358f82136aSPatrick Kelsey 	/*
17368f82136aSPatrick Kelsey 	 * XXX - When there is both rxq and event activity, do we care
17378f82136aSPatrick Kelsey 	 * whether the rxq 0 task or the admin task re-enables the interrupt
17388f82136aSPatrick Kelsey 	 * first?
17398f82136aSPatrick Kelsey 	 */
17408f82136aSPatrick Kelsey 	return (FILTER_SCHEDULE_THREAD);
1741e3c97c2cSBryan Venteicher }
1742e3c97c2cSBryan Venteicher 
17438f82136aSPatrick Kelsey static int
17448f82136aSPatrick Kelsey vmxnet3_rxq_intr(void *vrxq)
1745e3c97c2cSBryan Venteicher {
1746e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
1747e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
1748e3c97c2cSBryan Venteicher 
17498f82136aSPatrick Kelsey 	rxq = vrxq;
1750e3c97c2cSBryan Venteicher 	sc = rxq->vxrxq_sc;
1751e3c97c2cSBryan Venteicher 
1752e3c97c2cSBryan Venteicher 	if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE)
1753e3c97c2cSBryan Venteicher 		vmxnet3_disable_intr(sc, rxq->vxrxq_intr_idx);
1754e3c97c2cSBryan Venteicher 
17558f82136aSPatrick Kelsey 	return (FILTER_SCHEDULE_THREAD);
1756e3c97c2cSBryan Venteicher }
1757e3c97c2cSBryan Venteicher 
17588f82136aSPatrick Kelsey static int
17598f82136aSPatrick Kelsey vmxnet3_event_intr(void *vsc)
1760e3c97c2cSBryan Venteicher {
1761e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
1762e3c97c2cSBryan Venteicher 
17638f82136aSPatrick Kelsey 	sc = vsc;
1764e3c97c2cSBryan Venteicher 
1765e3c97c2cSBryan Venteicher 	if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE)
1766e3c97c2cSBryan Venteicher 		vmxnet3_disable_intr(sc, sc->vmx_event_intr_idx);
1767e3c97c2cSBryan Venteicher 
17688f82136aSPatrick Kelsey 	/*
17698f82136aSPatrick Kelsey 	 * The work will be done via vmxnet3_update_admin_status(), and the
17708f82136aSPatrick Kelsey 	 * interrupt will be re-enabled in vmxnet3_link_intr_enable().
17718f82136aSPatrick Kelsey 	 *
17728f82136aSPatrick Kelsey 	 * The interrupt will be re-enabled by vmxnet3_link_intr_enable().
17738f82136aSPatrick Kelsey 	 */
17748f82136aSPatrick Kelsey 	return (FILTER_SCHEDULE_THREAD);
1775e3c97c2cSBryan Venteicher }
1776e3c97c2cSBryan Venteicher 
1777e3c97c2cSBryan Venteicher static void
17788f82136aSPatrick Kelsey vmxnet3_stop(if_ctx_t ctx)
1779e3c97c2cSBryan Venteicher {
17808f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
1781e3c97c2cSBryan Venteicher 
17828f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
1783e3c97c2cSBryan Venteicher 
1784e3c97c2cSBryan Venteicher 	sc->vmx_link_active = 0;
1785e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_DISABLE);
1786e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_RESET);
1787e3c97c2cSBryan Venteicher }
1788e3c97c2cSBryan Venteicher 
1789e3c97c2cSBryan Venteicher static void
1790e3c97c2cSBryan Venteicher vmxnet3_txinit(struct vmxnet3_softc *sc, struct vmxnet3_txqueue *txq)
1791e3c97c2cSBryan Venteicher {
1792e3c97c2cSBryan Venteicher 	struct vmxnet3_txring *txr;
1793e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *txc;
1794e3c97c2cSBryan Venteicher 
17958f82136aSPatrick Kelsey 	txq->vxtxq_last_flush = -1;
17968f82136aSPatrick Kelsey 
1797e3c97c2cSBryan Venteicher 	txr = &txq->vxtxq_cmd_ring;
1798e3c97c2cSBryan Venteicher 	txr->vxtxr_next = 0;
1799e3c97c2cSBryan Venteicher 	txr->vxtxr_gen = VMXNET3_INIT_GEN;
18008f82136aSPatrick Kelsey 	/*
18018f82136aSPatrick Kelsey 	 * iflib has zeroed out the descriptor array during the prior attach
18028f82136aSPatrick Kelsey 	 * or stop
18038f82136aSPatrick Kelsey 	 */
1804e3c97c2cSBryan Venteicher 
1805e3c97c2cSBryan Venteicher 	txc = &txq->vxtxq_comp_ring;
1806e3c97c2cSBryan Venteicher 	txc->vxcr_next = 0;
1807e3c97c2cSBryan Venteicher 	txc->vxcr_gen = VMXNET3_INIT_GEN;
18088f82136aSPatrick Kelsey 	/*
18098f82136aSPatrick Kelsey 	 * iflib has zeroed out the descriptor array during the prior attach
18108f82136aSPatrick Kelsey 	 * or stop
18118f82136aSPatrick Kelsey 	 */
1812e3c97c2cSBryan Venteicher }
1813e3c97c2cSBryan Venteicher 
18148f82136aSPatrick Kelsey static void
1815e3c97c2cSBryan Venteicher vmxnet3_rxinit(struct vmxnet3_softc *sc, struct vmxnet3_rxqueue *rxq)
1816e3c97c2cSBryan Venteicher {
1817e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
1818e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *rxc;
18198f82136aSPatrick Kelsey 	int i;
1820e3c97c2cSBryan Venteicher 
1821e3c97c2cSBryan Venteicher 	/*
18228f82136aSPatrick Kelsey 	 * The descriptors will be populated with buffers during a
18238f82136aSPatrick Kelsey 	 * subsequent invocation of vmxnet3_isc_rxd_refill()
1824e3c97c2cSBryan Venteicher 	 */
18258f82136aSPatrick Kelsey 	for (i = 0; i < sc->vmx_sctx->isc_nrxqs - 1; i++) {
1826e3c97c2cSBryan Venteicher 		rxr = &rxq->vxrxq_cmd_ring[i];
1827e3c97c2cSBryan Venteicher 		rxr->vxrxr_gen = VMXNET3_INIT_GEN;
18288f82136aSPatrick Kelsey 		/*
18298f82136aSPatrick Kelsey 		 * iflib has zeroed out the descriptor array during the
18308f82136aSPatrick Kelsey 		 * prior attach or stop
18318f82136aSPatrick Kelsey 		 */
1832e3c97c2cSBryan Venteicher 	}
1833e3c97c2cSBryan Venteicher 
1834e3c97c2cSBryan Venteicher 	for (/**/; i < VMXNET3_RXRINGS_PERQ; i++) {
1835e3c97c2cSBryan Venteicher 		rxr = &rxq->vxrxq_cmd_ring[i];
1836e3c97c2cSBryan Venteicher 		rxr->vxrxr_gen = 0;
1837e3c97c2cSBryan Venteicher 		bzero(rxr->vxrxr_rxd,
1838e3c97c2cSBryan Venteicher 		    rxr->vxrxr_ndesc * sizeof(struct vmxnet3_rxdesc));
1839e3c97c2cSBryan Venteicher 	}
1840e3c97c2cSBryan Venteicher 
1841e3c97c2cSBryan Venteicher 	rxc = &rxq->vxrxq_comp_ring;
1842e3c97c2cSBryan Venteicher 	rxc->vxcr_next = 0;
1843e3c97c2cSBryan Venteicher 	rxc->vxcr_gen = VMXNET3_INIT_GEN;
18448f82136aSPatrick Kelsey 	/*
18458f82136aSPatrick Kelsey 	 * iflib has zeroed out the descriptor array during the prior attach
18468f82136aSPatrick Kelsey 	 * or stop
18478f82136aSPatrick Kelsey 	 */
1848e3c97c2cSBryan Venteicher }
1849e3c97c2cSBryan Venteicher 
18508f82136aSPatrick Kelsey static void
1851e3c97c2cSBryan Venteicher vmxnet3_reinit_queues(struct vmxnet3_softc *sc)
1852e3c97c2cSBryan Venteicher {
18538f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
18548f82136aSPatrick Kelsey 	int q;
1855e3c97c2cSBryan Venteicher 
18568f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
1857e3c97c2cSBryan Venteicher 
18588f82136aSPatrick Kelsey 	for (q = 0; q < scctx->isc_ntxqsets; q++)
1859e3c97c2cSBryan Venteicher 		vmxnet3_txinit(sc, &sc->vmx_txq[q]);
1860e3c97c2cSBryan Venteicher 
18618f82136aSPatrick Kelsey 	for (q = 0; q < scctx->isc_nrxqsets; q++)
18628f82136aSPatrick Kelsey 		vmxnet3_rxinit(sc, &sc->vmx_rxq[q]);
1863e3c97c2cSBryan Venteicher }
1864e3c97c2cSBryan Venteicher 
1865e3c97c2cSBryan Venteicher static int
1866e3c97c2cSBryan Venteicher vmxnet3_enable_device(struct vmxnet3_softc *sc)
1867e3c97c2cSBryan Venteicher {
18688f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
1869e3c97c2cSBryan Venteicher 	int q;
1870e3c97c2cSBryan Venteicher 
18718f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
18728f82136aSPatrick Kelsey 
1873e3c97c2cSBryan Venteicher 	if (vmxnet3_read_cmd(sc, VMXNET3_CMD_ENABLE) != 0) {
1874e3c97c2cSBryan Venteicher 		device_printf(sc->vmx_dev, "device enable command failed!\n");
1875e3c97c2cSBryan Venteicher 		return (1);
1876e3c97c2cSBryan Venteicher 	}
1877e3c97c2cSBryan Venteicher 
1878e3c97c2cSBryan Venteicher 	/* Reset the Rx queue heads. */
18798f82136aSPatrick Kelsey 	for (q = 0; q < scctx->isc_nrxqsets; q++) {
1880e3c97c2cSBryan Venteicher 		vmxnet3_write_bar0(sc, VMXNET3_BAR0_RXH1(q), 0);
1881e3c97c2cSBryan Venteicher 		vmxnet3_write_bar0(sc, VMXNET3_BAR0_RXH2(q), 0);
1882e3c97c2cSBryan Venteicher 	}
1883e3c97c2cSBryan Venteicher 
1884e3c97c2cSBryan Venteicher 	return (0);
1885e3c97c2cSBryan Venteicher }
1886e3c97c2cSBryan Venteicher 
1887e3c97c2cSBryan Venteicher static void
1888e3c97c2cSBryan Venteicher vmxnet3_reinit_rxfilters(struct vmxnet3_softc *sc)
1889e3c97c2cSBryan Venteicher {
1890e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
1891e3c97c2cSBryan Venteicher 
1892e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
1893e3c97c2cSBryan Venteicher 
18948f82136aSPatrick Kelsey 	vmxnet3_set_rxfilter(sc, if_getflags(ifp));
1895e3c97c2cSBryan Venteicher 
1896e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & IFCAP_VLAN_HWFILTER)
1897e3c97c2cSBryan Venteicher 		bcopy(sc->vmx_vlan_filter, sc->vmx_ds->vlan_filter,
1898e3c97c2cSBryan Venteicher 		    sizeof(sc->vmx_ds->vlan_filter));
1899e3c97c2cSBryan Venteicher 	else
1900e3c97c2cSBryan Venteicher 		bzero(sc->vmx_ds->vlan_filter,
1901e3c97c2cSBryan Venteicher 		    sizeof(sc->vmx_ds->vlan_filter));
1902e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_VLAN_FILTER);
1903e3c97c2cSBryan Venteicher }
1904e3c97c2cSBryan Venteicher 
19058f82136aSPatrick Kelsey static void
19068f82136aSPatrick Kelsey vmxnet3_init(if_ctx_t ctx)
1907e3c97c2cSBryan Venteicher {
19088f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
19098f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
1910e3c97c2cSBryan Venteicher 
19118f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
19128f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
19138f82136aSPatrick Kelsey 
19148f82136aSPatrick Kelsey 	scctx->isc_max_frame_size = if_getmtu(iflib_get_ifp(ctx)) +
19158f82136aSPatrick Kelsey 	    ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + ETHER_CRC_LEN;
19168f82136aSPatrick Kelsey 
19178f82136aSPatrick Kelsey 	/* Use the current MAC address. */
19188f82136aSPatrick Kelsey 	bcopy(IF_LLADDR(sc->vmx_ifp), sc->vmx_lladdr, ETHER_ADDR_LEN);
19198f82136aSPatrick Kelsey 	vmxnet3_set_lladdr(sc);
19208f82136aSPatrick Kelsey 
1921e3c97c2cSBryan Venteicher 	vmxnet3_reinit_shared_data(sc);
19228f82136aSPatrick Kelsey 	vmxnet3_reinit_queues(sc);
1923e3c97c2cSBryan Venteicher 
19248f82136aSPatrick Kelsey 	vmxnet3_enable_device(sc);
1925e3c97c2cSBryan Venteicher 
1926e3c97c2cSBryan Venteicher 	vmxnet3_reinit_rxfilters(sc);
1927e3c97c2cSBryan Venteicher 	vmxnet3_link_status(sc);
1928e3c97c2cSBryan Venteicher }
1929e3c97c2cSBryan Venteicher 
1930e3c97c2cSBryan Venteicher static void
19318f82136aSPatrick Kelsey vmxnet3_multi_set(if_ctx_t ctx)
1932e3c97c2cSBryan Venteicher {
1933e3c97c2cSBryan Venteicher 
19348f82136aSPatrick Kelsey 	vmxnet3_set_rxfilter(iflib_get_softc(ctx),
19358f82136aSPatrick Kelsey 	    if_getflags(iflib_get_ifp(ctx)));
1936e3c97c2cSBryan Venteicher }
1937e3c97c2cSBryan Venteicher 
1938e3c97c2cSBryan Venteicher static int
19398f82136aSPatrick Kelsey vmxnet3_mtu_set(if_ctx_t ctx, uint32_t mtu)
1940e3c97c2cSBryan Venteicher {
1941e3c97c2cSBryan Venteicher 
19428f82136aSPatrick Kelsey 	if (mtu > VMXNET3_TX_MAXSIZE - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN +
19438f82136aSPatrick Kelsey 		ETHER_CRC_LEN))
1944e3c97c2cSBryan Venteicher 		return (EINVAL);
1945e3c97c2cSBryan Venteicher 
1946e3c97c2cSBryan Venteicher 	return (0);
1947e3c97c2cSBryan Venteicher }
1948e3c97c2cSBryan Venteicher 
19498f82136aSPatrick Kelsey static void
19508f82136aSPatrick Kelsey vmxnet3_media_status(if_ctx_t ctx, struct ifmediareq * ifmr)
1951e3c97c2cSBryan Venteicher {
19528f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
1953e3c97c2cSBryan Venteicher 
19548f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
1955e3c97c2cSBryan Venteicher 
19568f82136aSPatrick Kelsey 	ifmr->ifm_status = IFM_AVALID;
19578f82136aSPatrick Kelsey 	ifmr->ifm_active = IFM_ETHER;
1958e3c97c2cSBryan Venteicher 
19598f82136aSPatrick Kelsey 	if (vmxnet3_link_is_up(sc) != 0) {
19608f82136aSPatrick Kelsey 		ifmr->ifm_status |= IFM_ACTIVE;
19618f82136aSPatrick Kelsey 		ifmr->ifm_active |= IFM_AUTO;
1962e3c97c2cSBryan Venteicher 	} else
19638f82136aSPatrick Kelsey 		ifmr->ifm_active |= IFM_NONE;
1964e3c97c2cSBryan Venteicher }
1965e3c97c2cSBryan Venteicher 
1966e3c97c2cSBryan Venteicher static int
19678f82136aSPatrick Kelsey vmxnet3_media_change(if_ctx_t ctx)
1968e3c97c2cSBryan Venteicher {
1969e3c97c2cSBryan Venteicher 
19708f82136aSPatrick Kelsey 	/* Ignore. */
1971c7156fe9SLuigi Rizzo 	return (0);
1972e557c1ddSBryan Venteicher }
1973e557c1ddSBryan Venteicher 
1974e557c1ddSBryan Venteicher static int
19758f82136aSPatrick Kelsey vmxnet3_promisc_set(if_ctx_t ctx, int flags)
1976e557c1ddSBryan Venteicher {
1977e557c1ddSBryan Venteicher 
19788f82136aSPatrick Kelsey 	vmxnet3_set_rxfilter(iflib_get_softc(ctx), flags);
1979e557c1ddSBryan Venteicher 
19808f82136aSPatrick Kelsey 	return (0);
1981e557c1ddSBryan Venteicher }
1982e557c1ddSBryan Venteicher 
19838f82136aSPatrick Kelsey static uint64_t
19848f82136aSPatrick Kelsey vmxnet3_get_counter(if_ctx_t ctx, ift_counter cnt)
19858f82136aSPatrick Kelsey {
19868f82136aSPatrick Kelsey 	if_t ifp = iflib_get_ifp(ctx);
19878f82136aSPatrick Kelsey 
19888f82136aSPatrick Kelsey 	if (cnt < IFCOUNTERS)
19898f82136aSPatrick Kelsey 		return if_get_counter_default(ifp, cnt);
19908f82136aSPatrick Kelsey 
19918f82136aSPatrick Kelsey 	return (0);
1992e557c1ddSBryan Venteicher }
1993e557c1ddSBryan Venteicher 
1994e557c1ddSBryan Venteicher static void
19958f82136aSPatrick Kelsey vmxnet3_update_admin_status(if_ctx_t ctx)
1996e557c1ddSBryan Venteicher {
1997e557c1ddSBryan Venteicher 	struct vmxnet3_softc *sc;
1998e557c1ddSBryan Venteicher 
19998f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
20008f82136aSPatrick Kelsey 	if (sc->vmx_ds->event != 0)
20018f82136aSPatrick Kelsey 		vmxnet3_evintr(sc);
2002e557c1ddSBryan Venteicher 
20038f82136aSPatrick Kelsey 	vmxnet3_refresh_host_stats(sc);
2004e557c1ddSBryan Venteicher }
2005e557c1ddSBryan Venteicher 
2006e557c1ddSBryan Venteicher static void
20078f82136aSPatrick Kelsey vmxnet3_txq_timer(if_ctx_t ctx, uint16_t qid)
2008e557c1ddSBryan Venteicher {
20098f82136aSPatrick Kelsey 	/* Host stats refresh is global, so just trigger it on txq 0 */
20108f82136aSPatrick Kelsey 	if (qid == 0)
20118f82136aSPatrick Kelsey 		vmxnet3_refresh_host_stats(iflib_get_softc(ctx));
2012e557c1ddSBryan Venteicher }
2013e557c1ddSBryan Venteicher 
2014e3c97c2cSBryan Venteicher static void
2015e3c97c2cSBryan Venteicher vmxnet3_update_vlan_filter(struct vmxnet3_softc *sc, int add, uint16_t tag)
2016e3c97c2cSBryan Venteicher {
2017e3c97c2cSBryan Venteicher 	int idx, bit;
2018e3c97c2cSBryan Venteicher 
2019e3c97c2cSBryan Venteicher 	if (tag == 0 || tag > 4095)
2020e3c97c2cSBryan Venteicher 		return;
2021e3c97c2cSBryan Venteicher 
20228f82136aSPatrick Kelsey 	idx = (tag >> 5) & 0x7F;
20238f82136aSPatrick Kelsey 	bit = tag & 0x1F;
2024e3c97c2cSBryan Venteicher 
2025e3c97c2cSBryan Venteicher 	/* Update our private VLAN bitvector. */
2026e3c97c2cSBryan Venteicher 	if (add)
2027e3c97c2cSBryan Venteicher 		sc->vmx_vlan_filter[idx] |= (1 << bit);
2028e3c97c2cSBryan Venteicher 	else
2029e3c97c2cSBryan Venteicher 		sc->vmx_vlan_filter[idx] &= ~(1 << bit);
2030e3c97c2cSBryan Venteicher }
2031e3c97c2cSBryan Venteicher 
2032e3c97c2cSBryan Venteicher static void
20338f82136aSPatrick Kelsey vmxnet3_vlan_register(if_ctx_t ctx, uint16_t tag)
2034e3c97c2cSBryan Venteicher {
2035e3c97c2cSBryan Venteicher 
20368f82136aSPatrick Kelsey 	vmxnet3_update_vlan_filter(iflib_get_softc(ctx), 1, tag);
2037e3c97c2cSBryan Venteicher }
2038e3c97c2cSBryan Venteicher 
2039e3c97c2cSBryan Venteicher static void
20408f82136aSPatrick Kelsey vmxnet3_vlan_unregister(if_ctx_t ctx, uint16_t tag)
2041e3c97c2cSBryan Venteicher {
2042e3c97c2cSBryan Venteicher 
20438f82136aSPatrick Kelsey 	vmxnet3_update_vlan_filter(iflib_get_softc(ctx), 0, tag);
2044e3c97c2cSBryan Venteicher }
2045e3c97c2cSBryan Venteicher 
2046d6b5965bSGleb Smirnoff static u_int
2047d6b5965bSGleb Smirnoff vmxnet3_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int count)
2048d6b5965bSGleb Smirnoff {
2049d6b5965bSGleb Smirnoff 	struct vmxnet3_softc *sc = arg;
2050d6b5965bSGleb Smirnoff 
2051d6b5965bSGleb Smirnoff 	if (count < VMXNET3_MULTICAST_MAX)
2052d6b5965bSGleb Smirnoff 		bcopy(LLADDR(sdl), &sc->vmx_mcast[count * ETHER_ADDR_LEN],
2053d6b5965bSGleb Smirnoff 		    ETHER_ADDR_LEN);
2054d6b5965bSGleb Smirnoff 
2055d6b5965bSGleb Smirnoff 	return (1);
2056d6b5965bSGleb Smirnoff }
2057d6b5965bSGleb Smirnoff 
2058e3c97c2cSBryan Venteicher static void
20598f82136aSPatrick Kelsey vmxnet3_set_rxfilter(struct vmxnet3_softc *sc, int flags)
2060e3c97c2cSBryan Venteicher {
2061e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
2062e3c97c2cSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
2063e3c97c2cSBryan Venteicher 	u_int mode;
2064e3c97c2cSBryan Venteicher 
2065e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
2066e3c97c2cSBryan Venteicher 	ds = sc->vmx_ds;
2067e3c97c2cSBryan Venteicher 
2068e557c1ddSBryan Venteicher 	mode = VMXNET3_RXMODE_UCAST | VMXNET3_RXMODE_BCAST;
20698f82136aSPatrick Kelsey 	if (flags & IFF_PROMISC)
2070e3c97c2cSBryan Venteicher 		mode |= VMXNET3_RXMODE_PROMISC;
20718f82136aSPatrick Kelsey 	if (flags & IFF_ALLMULTI)
2072e3c97c2cSBryan Venteicher 		mode |= VMXNET3_RXMODE_ALLMULTI;
2073e3c97c2cSBryan Venteicher 	else {
2074d6b5965bSGleb Smirnoff 		int cnt;
2075e3c97c2cSBryan Venteicher 
2076d6b5965bSGleb Smirnoff 		cnt = if_foreach_llmaddr(ifp, vmxnet3_hash_maddr, sc);
2077d6b5965bSGleb Smirnoff 		if (cnt >= VMXNET3_MULTICAST_MAX) {
2078e3c97c2cSBryan Venteicher 			cnt = 0;
2079e3c97c2cSBryan Venteicher 			mode |= VMXNET3_RXMODE_ALLMULTI;
2080e3c97c2cSBryan Venteicher 		} else if (cnt > 0)
2081e3c97c2cSBryan Venteicher 			mode |= VMXNET3_RXMODE_MCAST;
2082e3c97c2cSBryan Venteicher 		ds->mcast_tablelen = cnt * ETHER_ADDR_LEN;
2083e3c97c2cSBryan Venteicher 	}
2084e3c97c2cSBryan Venteicher 
2085e3c97c2cSBryan Venteicher 	ds->rxmode = mode;
2086e3c97c2cSBryan Venteicher 
2087e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_SET_FILTER);
2088e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_SET_RXMODE);
2089e3c97c2cSBryan Venteicher }
2090e3c97c2cSBryan Venteicher 
2091e3c97c2cSBryan Venteicher static void
2092e557c1ddSBryan Venteicher vmxnet3_refresh_host_stats(struct vmxnet3_softc *sc)
2093e3c97c2cSBryan Venteicher {
2094e3c97c2cSBryan Venteicher 
2095e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_GET_STATS);
2096e3c97c2cSBryan Venteicher }
2097e3c97c2cSBryan Venteicher 
2098e3c97c2cSBryan Venteicher static int
2099e3c97c2cSBryan Venteicher vmxnet3_link_is_up(struct vmxnet3_softc *sc)
2100e3c97c2cSBryan Venteicher {
2101e3c97c2cSBryan Venteicher 	uint32_t status;
2102e3c97c2cSBryan Venteicher 
2103e3c97c2cSBryan Venteicher 	status = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_LINK);
2104e3c97c2cSBryan Venteicher 	return !!(status & 0x1);
2105e3c97c2cSBryan Venteicher }
2106e3c97c2cSBryan Venteicher 
2107e3c97c2cSBryan Venteicher static void
2108e3c97c2cSBryan Venteicher vmxnet3_link_status(struct vmxnet3_softc *sc)
2109e3c97c2cSBryan Venteicher {
21108f82136aSPatrick Kelsey 	if_ctx_t ctx;
21118f82136aSPatrick Kelsey 	uint64_t speed;
2112e3c97c2cSBryan Venteicher 	int link;
2113e3c97c2cSBryan Venteicher 
21148f82136aSPatrick Kelsey 	ctx = sc->vmx_ctx;
2115e3c97c2cSBryan Venteicher 	link = vmxnet3_link_is_up(sc);
21168f82136aSPatrick Kelsey 	speed = IF_Gbps(10);
2117e3c97c2cSBryan Venteicher 
2118e3c97c2cSBryan Venteicher 	if (link != 0 && sc->vmx_link_active == 0) {
2119e3c97c2cSBryan Venteicher 		sc->vmx_link_active = 1;
21208f82136aSPatrick Kelsey 		iflib_link_state_change(ctx, LINK_STATE_UP, speed);
2121e3c97c2cSBryan Venteicher 	} else if (link == 0 && sc->vmx_link_active != 0) {
2122e3c97c2cSBryan Venteicher 		sc->vmx_link_active = 0;
21238f82136aSPatrick Kelsey 		iflib_link_state_change(ctx, LINK_STATE_DOWN, speed);
2124e3c97c2cSBryan Venteicher 	}
2125e3c97c2cSBryan Venteicher }
2126e3c97c2cSBryan Venteicher 
2127e3c97c2cSBryan Venteicher static void
2128e3c97c2cSBryan Venteicher vmxnet3_set_lladdr(struct vmxnet3_softc *sc)
2129e3c97c2cSBryan Venteicher {
2130e3c97c2cSBryan Venteicher 	uint32_t ml, mh;
2131e3c97c2cSBryan Venteicher 
2132e3c97c2cSBryan Venteicher 	ml  = sc->vmx_lladdr[0];
2133e3c97c2cSBryan Venteicher 	ml |= sc->vmx_lladdr[1] << 8;
2134e3c97c2cSBryan Venteicher 	ml |= sc->vmx_lladdr[2] << 16;
2135e3c97c2cSBryan Venteicher 	ml |= sc->vmx_lladdr[3] << 24;
2136e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_MACL, ml);
2137e3c97c2cSBryan Venteicher 
2138e3c97c2cSBryan Venteicher 	mh  = sc->vmx_lladdr[4];
2139e3c97c2cSBryan Venteicher 	mh |= sc->vmx_lladdr[5] << 8;
2140e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_MACH, mh);
2141e3c97c2cSBryan Venteicher }
2142e3c97c2cSBryan Venteicher 
2143e3c97c2cSBryan Venteicher static void
2144e3c97c2cSBryan Venteicher vmxnet3_get_lladdr(struct vmxnet3_softc *sc)
2145e3c97c2cSBryan Venteicher {
2146e3c97c2cSBryan Venteicher 	uint32_t ml, mh;
2147e3c97c2cSBryan Venteicher 
2148e3c97c2cSBryan Venteicher 	ml = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_MACL);
2149e3c97c2cSBryan Venteicher 	mh = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_MACH);
2150e3c97c2cSBryan Venteicher 
2151e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[0] = ml;
2152e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[1] = ml >> 8;
2153e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[2] = ml >> 16;
2154e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[3] = ml >> 24;
2155e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[4] = mh;
2156e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[5] = mh >> 8;
2157e3c97c2cSBryan Venteicher }
2158e3c97c2cSBryan Venteicher 
2159e3c97c2cSBryan Venteicher static void
2160e3c97c2cSBryan Venteicher vmxnet3_setup_txq_sysctl(struct vmxnet3_txqueue *txq,
2161e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2162e3c97c2cSBryan Venteicher {
2163e3c97c2cSBryan Venteicher 	struct sysctl_oid *node, *txsnode;
2164e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *list, *txslist;
2165e3c97c2cSBryan Venteicher 	struct UPT1_TxStats *txstats;
2166e3c97c2cSBryan Venteicher 	char namebuf[16];
2167e3c97c2cSBryan Venteicher 
2168e3c97c2cSBryan Venteicher 	txstats = &txq->vxtxq_ts->stats;
2169e3c97c2cSBryan Venteicher 
2170e3c97c2cSBryan Venteicher 	snprintf(namebuf, sizeof(namebuf), "txq%d", txq->vxtxq_id);
2171*7029da5cSPawel Biernacki 	node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf,
2172*7029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Transmit Queue");
2173e3c97c2cSBryan Venteicher 	txq->vxtxq_sysctl = list = SYSCTL_CHILDREN(node);
2174e3c97c2cSBryan Venteicher 
2175e3c97c2cSBryan Venteicher 	/*
21768f82136aSPatrick Kelsey 	 * Add statistics reported by the host. These are updated by the
21778f82136aSPatrick Kelsey 	 * iflib txq timer on txq 0.
2178e3c97c2cSBryan Venteicher 	 */
2179*7029da5cSPawel Biernacki 	txsnode = SYSCTL_ADD_NODE(ctx, list, OID_AUTO, "hstats",
2180*7029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Host Statistics");
2181e3c97c2cSBryan Venteicher 	txslist = SYSCTL_CHILDREN(txsnode);
2182e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "tso_packets", CTLFLAG_RD,
2183e3c97c2cSBryan Venteicher 	    &txstats->TSO_packets, "TSO packets");
2184e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "tso_bytes", CTLFLAG_RD,
2185e3c97c2cSBryan Venteicher 	    &txstats->TSO_bytes, "TSO bytes");
2186e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "ucast_packets", CTLFLAG_RD,
2187e3c97c2cSBryan Venteicher 	    &txstats->ucast_packets, "Unicast packets");
2188e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "unicast_bytes", CTLFLAG_RD,
2189e3c97c2cSBryan Venteicher 	    &txstats->ucast_bytes, "Unicast bytes");
2190e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "mcast_packets", CTLFLAG_RD,
2191e3c97c2cSBryan Venteicher 	    &txstats->mcast_packets, "Multicast packets");
2192e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "mcast_bytes", CTLFLAG_RD,
2193e3c97c2cSBryan Venteicher 	    &txstats->mcast_bytes, "Multicast bytes");
2194e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "error", CTLFLAG_RD,
2195e3c97c2cSBryan Venteicher 	    &txstats->error, "Errors");
2196e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "discard", CTLFLAG_RD,
2197e3c97c2cSBryan Venteicher 	    &txstats->discard, "Discards");
2198e3c97c2cSBryan Venteicher }
2199e3c97c2cSBryan Venteicher 
2200e3c97c2cSBryan Venteicher static void
2201e3c97c2cSBryan Venteicher vmxnet3_setup_rxq_sysctl(struct vmxnet3_rxqueue *rxq,
2202e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2203e3c97c2cSBryan Venteicher {
2204e3c97c2cSBryan Venteicher 	struct sysctl_oid *node, *rxsnode;
2205e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *list, *rxslist;
2206e3c97c2cSBryan Venteicher 	struct UPT1_RxStats *rxstats;
2207e3c97c2cSBryan Venteicher 	char namebuf[16];
2208e3c97c2cSBryan Venteicher 
2209e3c97c2cSBryan Venteicher 	rxstats = &rxq->vxrxq_rs->stats;
2210e3c97c2cSBryan Venteicher 
2211e3c97c2cSBryan Venteicher 	snprintf(namebuf, sizeof(namebuf), "rxq%d", rxq->vxrxq_id);
2212*7029da5cSPawel Biernacki 	node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf,
2213*7029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Receive Queue");
2214e3c97c2cSBryan Venteicher 	rxq->vxrxq_sysctl = list = SYSCTL_CHILDREN(node);
2215e3c97c2cSBryan Venteicher 
2216e3c97c2cSBryan Venteicher 	/*
22178f82136aSPatrick Kelsey 	 * Add statistics reported by the host. These are updated by the
22188f82136aSPatrick Kelsey 	 * iflib txq timer on txq 0.
2219e3c97c2cSBryan Venteicher 	 */
2220*7029da5cSPawel Biernacki 	rxsnode = SYSCTL_ADD_NODE(ctx, list, OID_AUTO, "hstats",
2221*7029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Host Statistics");
2222e3c97c2cSBryan Venteicher 	rxslist = SYSCTL_CHILDREN(rxsnode);
2223e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "lro_packets", CTLFLAG_RD,
2224e3c97c2cSBryan Venteicher 	    &rxstats->LRO_packets, "LRO packets");
2225e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "lro_bytes", CTLFLAG_RD,
2226e3c97c2cSBryan Venteicher 	    &rxstats->LRO_bytes, "LRO bytes");
2227e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "ucast_packets", CTLFLAG_RD,
2228e3c97c2cSBryan Venteicher 	    &rxstats->ucast_packets, "Unicast packets");
2229e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "unicast_bytes", CTLFLAG_RD,
2230e3c97c2cSBryan Venteicher 	    &rxstats->ucast_bytes, "Unicast bytes");
2231e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "mcast_packets", CTLFLAG_RD,
2232e3c97c2cSBryan Venteicher 	    &rxstats->mcast_packets, "Multicast packets");
2233e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "mcast_bytes", CTLFLAG_RD,
2234e3c97c2cSBryan Venteicher 	    &rxstats->mcast_bytes, "Multicast bytes");
2235e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "bcast_packets", CTLFLAG_RD,
2236e3c97c2cSBryan Venteicher 	    &rxstats->bcast_packets, "Broadcast packets");
2237e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "bcast_bytes", CTLFLAG_RD,
2238e3c97c2cSBryan Venteicher 	    &rxstats->bcast_bytes, "Broadcast bytes");
2239e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "nobuffer", CTLFLAG_RD,
2240e3c97c2cSBryan Venteicher 	    &rxstats->nobuffer, "No buffer");
2241e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "error", CTLFLAG_RD,
2242e3c97c2cSBryan Venteicher 	    &rxstats->error, "Errors");
2243e3c97c2cSBryan Venteicher }
2244e3c97c2cSBryan Venteicher 
2245e3c97c2cSBryan Venteicher static void
2246e3c97c2cSBryan Venteicher vmxnet3_setup_debug_sysctl(struct vmxnet3_softc *sc,
2247e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2248e3c97c2cSBryan Venteicher {
22498f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
2250e3c97c2cSBryan Venteicher 	struct sysctl_oid *node;
2251e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *list;
2252e3c97c2cSBryan Venteicher 	int i;
2253e3c97c2cSBryan Venteicher 
22548f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
22558f82136aSPatrick Kelsey 
22568f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++) {
2257e3c97c2cSBryan Venteicher 		struct vmxnet3_txqueue *txq = &sc->vmx_txq[i];
2258e3c97c2cSBryan Venteicher 
2259e3c97c2cSBryan Venteicher 		node = SYSCTL_ADD_NODE(ctx, txq->vxtxq_sysctl, OID_AUTO,
2260*7029da5cSPawel Biernacki 		    "debug", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "");
2261e3c97c2cSBryan Venteicher 		list = SYSCTL_CHILDREN(node);
2262e3c97c2cSBryan Venteicher 
2263e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd_next", CTLFLAG_RD,
2264e3c97c2cSBryan Venteicher 		    &txq->vxtxq_cmd_ring.vxtxr_next, 0, "");
2265e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd_ndesc", CTLFLAG_RD,
2266e3c97c2cSBryan Venteicher 		    &txq->vxtxq_cmd_ring.vxtxr_ndesc, 0, "");
2267e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd_gen", CTLFLAG_RD,
2268e3c97c2cSBryan Venteicher 		    &txq->vxtxq_cmd_ring.vxtxr_gen, 0, "");
2269e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_next", CTLFLAG_RD,
2270e3c97c2cSBryan Venteicher 		    &txq->vxtxq_comp_ring.vxcr_next, 0, "");
2271e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_ndesc", CTLFLAG_RD,
2272e3c97c2cSBryan Venteicher 		    &txq->vxtxq_comp_ring.vxcr_ndesc, 0,"");
2273e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "comp_gen", CTLFLAG_RD,
2274e3c97c2cSBryan Venteicher 		    &txq->vxtxq_comp_ring.vxcr_gen, 0, "");
2275e3c97c2cSBryan Venteicher 	}
2276e3c97c2cSBryan Venteicher 
22778f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
2278e3c97c2cSBryan Venteicher 		struct vmxnet3_rxqueue *rxq = &sc->vmx_rxq[i];
2279e3c97c2cSBryan Venteicher 
2280e3c97c2cSBryan Venteicher 		node = SYSCTL_ADD_NODE(ctx, rxq->vxrxq_sysctl, OID_AUTO,
2281*7029da5cSPawel Biernacki 		    "debug", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "");
2282e3c97c2cSBryan Venteicher 		list = SYSCTL_CHILDREN(node);
2283e3c97c2cSBryan Venteicher 
2284e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd0_ndesc", CTLFLAG_RD,
2285e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[0].vxrxr_ndesc, 0, "");
2286e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd0_gen", CTLFLAG_RD,
2287e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[0].vxrxr_gen, 0, "");
2288e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd1_ndesc", CTLFLAG_RD,
2289e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[1].vxrxr_ndesc, 0, "");
2290e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd1_gen", CTLFLAG_RD,
2291e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[1].vxrxr_gen, 0, "");
2292e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_ndesc", CTLFLAG_RD,
2293e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_comp_ring.vxcr_ndesc, 0,"");
2294e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "comp_gen", CTLFLAG_RD,
2295e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_comp_ring.vxcr_gen, 0, "");
2296e3c97c2cSBryan Venteicher 	}
2297e3c97c2cSBryan Venteicher }
2298e3c97c2cSBryan Venteicher 
2299e3c97c2cSBryan Venteicher static void
2300e3c97c2cSBryan Venteicher vmxnet3_setup_queue_sysctl(struct vmxnet3_softc *sc,
2301e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2302e3c97c2cSBryan Venteicher {
23038f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
2304e3c97c2cSBryan Venteicher 	int i;
2305e3c97c2cSBryan Venteicher 
23068f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
23078f82136aSPatrick Kelsey 
23088f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++)
2309e3c97c2cSBryan Venteicher 		vmxnet3_setup_txq_sysctl(&sc->vmx_txq[i], ctx, child);
23108f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++)
2311e3c97c2cSBryan Venteicher 		vmxnet3_setup_rxq_sysctl(&sc->vmx_rxq[i], ctx, child);
2312e3c97c2cSBryan Venteicher 
2313e3c97c2cSBryan Venteicher 	vmxnet3_setup_debug_sysctl(sc, ctx, child);
2314e3c97c2cSBryan Venteicher }
2315e3c97c2cSBryan Venteicher 
2316e3c97c2cSBryan Venteicher static void
2317e3c97c2cSBryan Venteicher vmxnet3_setup_sysctl(struct vmxnet3_softc *sc)
2318e3c97c2cSBryan Venteicher {
2319e3c97c2cSBryan Venteicher 	device_t dev;
2320e3c97c2cSBryan Venteicher 	struct sysctl_ctx_list *ctx;
2321e3c97c2cSBryan Venteicher 	struct sysctl_oid *tree;
2322e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *child;
2323e3c97c2cSBryan Venteicher 
2324e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
2325e3c97c2cSBryan Venteicher 	ctx = device_get_sysctl_ctx(dev);
2326e3c97c2cSBryan Venteicher 	tree = device_get_sysctl_tree(dev);
2327e3c97c2cSBryan Venteicher 	child = SYSCTL_CHILDREN(tree);
2328e3c97c2cSBryan Venteicher 
2329e3c97c2cSBryan Venteicher 	vmxnet3_setup_queue_sysctl(sc, ctx, child);
2330e3c97c2cSBryan Venteicher }
2331e3c97c2cSBryan Venteicher 
2332e3c97c2cSBryan Venteicher static void
2333e3c97c2cSBryan Venteicher vmxnet3_write_bar0(struct vmxnet3_softc *sc, bus_size_t r, uint32_t v)
2334e3c97c2cSBryan Venteicher {
2335e3c97c2cSBryan Venteicher 
2336e3c97c2cSBryan Venteicher 	bus_space_write_4(sc->vmx_iot0, sc->vmx_ioh0, r, v);
2337e3c97c2cSBryan Venteicher }
2338e3c97c2cSBryan Venteicher 
2339e3c97c2cSBryan Venteicher static uint32_t
2340e3c97c2cSBryan Venteicher vmxnet3_read_bar1(struct vmxnet3_softc *sc, bus_size_t r)
2341e3c97c2cSBryan Venteicher {
2342e3c97c2cSBryan Venteicher 
2343e3c97c2cSBryan Venteicher 	return (bus_space_read_4(sc->vmx_iot1, sc->vmx_ioh1, r));
2344e3c97c2cSBryan Venteicher }
2345e3c97c2cSBryan Venteicher 
2346e3c97c2cSBryan Venteicher static void
2347e3c97c2cSBryan Venteicher vmxnet3_write_bar1(struct vmxnet3_softc *sc, bus_size_t r, uint32_t v)
2348e3c97c2cSBryan Venteicher {
2349e3c97c2cSBryan Venteicher 
2350e3c97c2cSBryan Venteicher 	bus_space_write_4(sc->vmx_iot1, sc->vmx_ioh1, r, v);
2351e3c97c2cSBryan Venteicher }
2352e3c97c2cSBryan Venteicher 
2353e3c97c2cSBryan Venteicher static void
2354e3c97c2cSBryan Venteicher vmxnet3_write_cmd(struct vmxnet3_softc *sc, uint32_t cmd)
2355e3c97c2cSBryan Venteicher {
2356e3c97c2cSBryan Venteicher 
2357e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_CMD, cmd);
2358e3c97c2cSBryan Venteicher }
2359e3c97c2cSBryan Venteicher 
2360e3c97c2cSBryan Venteicher static uint32_t
2361e3c97c2cSBryan Venteicher vmxnet3_read_cmd(struct vmxnet3_softc *sc, uint32_t cmd)
2362e3c97c2cSBryan Venteicher {
2363e3c97c2cSBryan Venteicher 
2364e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, cmd);
2365e3c97c2cSBryan Venteicher 	bus_space_barrier(sc->vmx_iot1, sc->vmx_ioh1, 0, 0,
2366e3c97c2cSBryan Venteicher 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
2367e3c97c2cSBryan Venteicher 	return (vmxnet3_read_bar1(sc, VMXNET3_BAR1_CMD));
2368e3c97c2cSBryan Venteicher }
2369e3c97c2cSBryan Venteicher 
2370e3c97c2cSBryan Venteicher static void
2371e3c97c2cSBryan Venteicher vmxnet3_enable_intr(struct vmxnet3_softc *sc, int irq)
2372e3c97c2cSBryan Venteicher {
2373e3c97c2cSBryan Venteicher 
2374e3c97c2cSBryan Venteicher 	vmxnet3_write_bar0(sc, VMXNET3_BAR0_IMASK(irq), 0);
2375e3c97c2cSBryan Venteicher }
2376e3c97c2cSBryan Venteicher 
2377e3c97c2cSBryan Venteicher static void
2378e3c97c2cSBryan Venteicher vmxnet3_disable_intr(struct vmxnet3_softc *sc, int irq)
2379e3c97c2cSBryan Venteicher {
2380e3c97c2cSBryan Venteicher 
2381e3c97c2cSBryan Venteicher 	vmxnet3_write_bar0(sc, VMXNET3_BAR0_IMASK(irq), 1);
2382e3c97c2cSBryan Venteicher }
2383e3c97c2cSBryan Venteicher 
23848f82136aSPatrick Kelsey static int
23858f82136aSPatrick Kelsey vmxnet3_tx_queue_intr_enable(if_ctx_t ctx, uint16_t qid)
2386e3c97c2cSBryan Venteicher {
23878f82136aSPatrick Kelsey 	/* Not using interrupts for TX */
23888f82136aSPatrick Kelsey 	return (0);
23898f82136aSPatrick Kelsey }
23908f82136aSPatrick Kelsey 
23918f82136aSPatrick Kelsey static int
23928f82136aSPatrick Kelsey vmxnet3_rx_queue_intr_enable(if_ctx_t ctx, uint16_t qid)
23938f82136aSPatrick Kelsey {
23948f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
23958f82136aSPatrick Kelsey 
23968f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
23978f82136aSPatrick Kelsey 	vmxnet3_enable_intr(sc, sc->vmx_rxq[qid].vxrxq_intr_idx);
23988f82136aSPatrick Kelsey 	return (0);
23998f82136aSPatrick Kelsey }
24008f82136aSPatrick Kelsey 
24018f82136aSPatrick Kelsey static void
24028f82136aSPatrick Kelsey vmxnet3_link_intr_enable(if_ctx_t ctx)
24038f82136aSPatrick Kelsey {
24048f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
24058f82136aSPatrick Kelsey 
24068f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
24078f82136aSPatrick Kelsey 	vmxnet3_enable_intr(sc, sc->vmx_event_intr_idx);
24088f82136aSPatrick Kelsey }
24098f82136aSPatrick Kelsey 
24108f82136aSPatrick Kelsey static void
24118f82136aSPatrick Kelsey vmxnet3_intr_enable_all(if_ctx_t ctx)
24128f82136aSPatrick Kelsey {
24138f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
24148f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
2415e3c97c2cSBryan Venteicher 	int i;
2416e3c97c2cSBryan Venteicher 
24178f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
24188f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
2419e3c97c2cSBryan Venteicher 	sc->vmx_ds->ictrl &= ~VMXNET3_ICTRL_DISABLE_ALL;
24208f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_vectors; i++)
2421e3c97c2cSBryan Venteicher 		vmxnet3_enable_intr(sc, i);
2422e3c97c2cSBryan Venteicher }
2423e3c97c2cSBryan Venteicher 
2424e3c97c2cSBryan Venteicher static void
24258f82136aSPatrick Kelsey vmxnet3_intr_disable_all(if_ctx_t ctx)
2426e3c97c2cSBryan Venteicher {
24278f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
2428e3c97c2cSBryan Venteicher 	int i;
2429e3c97c2cSBryan Venteicher 
24308f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
24318f82136aSPatrick Kelsey 	/*
24328f82136aSPatrick Kelsey 	 * iflib may invoke this routine before vmxnet3_attach_post() has
24338f82136aSPatrick Kelsey 	 * run, which is before the top level shared data area is
24348f82136aSPatrick Kelsey 	 * initialized and the device made aware of it.
24358f82136aSPatrick Kelsey 	 */
24368f82136aSPatrick Kelsey 	if (sc->vmx_ds != NULL)
2437e3c97c2cSBryan Venteicher 		sc->vmx_ds->ictrl |= VMXNET3_ICTRL_DISABLE_ALL;
24388f82136aSPatrick Kelsey 	for (i = 0; i < VMXNET3_MAX_INTRS; i++)
2439e3c97c2cSBryan Venteicher 		vmxnet3_disable_intr(sc, i);
2440e3c97c2cSBryan Venteicher }
2441e3c97c2cSBryan Venteicher 
2442e3c97c2cSBryan Venteicher /*
2443e3c97c2cSBryan Venteicher  * Since this is a purely paravirtualized device, we do not have
2444e3c97c2cSBryan Venteicher  * to worry about DMA coherency. But at times, we must make sure
2445e3c97c2cSBryan Venteicher  * both the compiler and CPU do not reorder memory operations.
2446e3c97c2cSBryan Venteicher  */
2447e3c97c2cSBryan Venteicher static inline void
2448e3c97c2cSBryan Venteicher vmxnet3_barrier(struct vmxnet3_softc *sc, vmxnet3_barrier_t type)
2449e3c97c2cSBryan Venteicher {
2450e3c97c2cSBryan Venteicher 
2451e3c97c2cSBryan Venteicher 	switch (type) {
2452e3c97c2cSBryan Venteicher 	case VMXNET3_BARRIER_RD:
2453e3c97c2cSBryan Venteicher 		rmb();
2454e3c97c2cSBryan Venteicher 		break;
2455e3c97c2cSBryan Venteicher 	case VMXNET3_BARRIER_WR:
2456e3c97c2cSBryan Venteicher 		wmb();
2457e3c97c2cSBryan Venteicher 		break;
2458e3c97c2cSBryan Venteicher 	case VMXNET3_BARRIER_RDWR:
2459e3c97c2cSBryan Venteicher 		mb();
2460e3c97c2cSBryan Venteicher 		break;
2461e3c97c2cSBryan Venteicher 	default:
2462e3c97c2cSBryan Venteicher 		panic("%s: bad barrier type %d", __func__, type);
2463e3c97c2cSBryan Venteicher 	}
2464e3c97c2cSBryan Venteicher }
2465