xref: /freebsd/sys/dev/vmware/vmxnet3/if_vmx.c (revision 1342c8c622ea00e26fbdb475e3ee19e141972cc8)
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 
384*1342c8c6SPatrick Kelsey 	/*
385*1342c8c6SPatrick Kelsey 	 * Initialize the max frame size and descriptor queue buffer
386*1342c8c6SPatrick Kelsey 	 * sizes.
387*1342c8c6SPatrick Kelsey 	 */
388*1342c8c6SPatrick Kelsey 	vmxnet3_mtu_set(ctx, if_getmtu(sc->vmx_ifp));
389*1342c8c6SPatrick Kelsey 
3908f82136aSPatrick Kelsey 	scctx->isc_rss_table_size = UPT1_RSS_MAX_IND_TABLE_SIZE;
3918f82136aSPatrick Kelsey 
3928f82136aSPatrick Kelsey 	/* Map PCI BARs */
393e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_resources(sc);
394e3c97c2cSBryan Venteicher 	if (error)
395e3c97c2cSBryan Venteicher 		goto fail;
396e3c97c2cSBryan Venteicher 
3978f82136aSPatrick Kelsey 	/* Check device versions */
398e3c97c2cSBryan Venteicher 	error = vmxnet3_check_version(sc);
399e3c97c2cSBryan Venteicher 	if (error)
400e3c97c2cSBryan Venteicher 		goto fail;
401e3c97c2cSBryan Venteicher 
4028f82136aSPatrick Kelsey 	/*
4038f82136aSPatrick Kelsey 	 * The interrupt mode can be set in the hypervisor configuration via
4048f82136aSPatrick Kelsey 	 * the parameter ethernet<N>.intrMode.
4058f82136aSPatrick Kelsey 	 */
4068f82136aSPatrick Kelsey 	intr_config = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_INTRCFG);
4078f82136aSPatrick Kelsey 	sc->vmx_intr_mask_mode = (intr_config >> 2) & 0x03;
408e3c97c2cSBryan Venteicher 
4098f82136aSPatrick Kelsey 	/*
4108f82136aSPatrick Kelsey 	 * Configure the softc context to attempt to configure the interrupt
4118f82136aSPatrick Kelsey 	 * mode now indicated by intr_config.  iflib will follow the usual
412b97de13aSMarius Strobl 	 * fallback path MSI-X -> MSI -> LEGACY, starting at the configured
4138f82136aSPatrick Kelsey 	 * starting mode.
4148f82136aSPatrick Kelsey 	 */
4158f82136aSPatrick Kelsey 	switch (intr_config & 0x03) {
4168f82136aSPatrick Kelsey 	case VMXNET3_IT_AUTO:
4178f82136aSPatrick Kelsey 	case VMXNET3_IT_MSIX:
4188f82136aSPatrick Kelsey 		scctx->isc_msix_bar = pci_msix_table_bar(dev);
4198f82136aSPatrick Kelsey 		break;
4208f82136aSPatrick Kelsey 	case VMXNET3_IT_MSI:
4218f82136aSPatrick Kelsey 		scctx->isc_msix_bar = -1;
4228f82136aSPatrick Kelsey 		scctx->isc_disable_msix = 1;
4238f82136aSPatrick Kelsey 		break;
4248f82136aSPatrick Kelsey 	case VMXNET3_IT_LEGACY:
4258f82136aSPatrick Kelsey 		scctx->isc_msix_bar = 0;
4268f82136aSPatrick Kelsey 		break;
427e3c97c2cSBryan Venteicher 	}
428e3c97c2cSBryan Venteicher 
4298f82136aSPatrick Kelsey 	scctx->isc_tx_csum_flags = VMXNET3_CSUM_ALL_OFFLOAD;
4308f82136aSPatrick Kelsey 	scctx->isc_capabilities = scctx->isc_capenable =
4318f82136aSPatrick Kelsey 	    IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6 |
4328f82136aSPatrick Kelsey 	    IFCAP_TSO4 | IFCAP_TSO6 |
4338f82136aSPatrick Kelsey 	    IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6 |
4348f82136aSPatrick Kelsey 	    IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING |
4358f82136aSPatrick Kelsey 	    IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO |
4368f82136aSPatrick Kelsey 	    IFCAP_JUMBO_MTU;
437e3c97c2cSBryan Venteicher 
4388f82136aSPatrick Kelsey 	/* These capabilities are not enabled by default. */
4398f82136aSPatrick Kelsey 	scctx->isc_capabilities |= IFCAP_LRO | IFCAP_VLAN_HWFILTER;
4408f82136aSPatrick Kelsey 
4418f82136aSPatrick Kelsey 	vmxnet3_get_lladdr(sc);
4428f82136aSPatrick Kelsey 	iflib_set_mac(ctx, sc->vmx_lladdr);
4438f82136aSPatrick Kelsey 
4448f82136aSPatrick Kelsey 	return (0);
445e3c97c2cSBryan Venteicher fail:
4468f82136aSPatrick Kelsey 	/*
4478f82136aSPatrick Kelsey 	 * We must completely clean up anything allocated above as iflib
4488f82136aSPatrick Kelsey 	 * will not invoke any other driver entry points as a result of this
4498f82136aSPatrick Kelsey 	 * failure.
4508f82136aSPatrick Kelsey 	 */
4518f82136aSPatrick Kelsey 	vmxnet3_free_resources(sc);
452e3c97c2cSBryan Venteicher 
453e3c97c2cSBryan Venteicher 	return (error);
454e3c97c2cSBryan Venteicher }
455e3c97c2cSBryan Venteicher 
456e3c97c2cSBryan Venteicher static int
4578f82136aSPatrick Kelsey vmxnet3_msix_intr_assign(if_ctx_t ctx, int msix)
458e3c97c2cSBryan Venteicher {
459e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
4608f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
4618f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
4628f82136aSPatrick Kelsey 	int error;
4638f82136aSPatrick Kelsey 	int i;
4648f82136aSPatrick Kelsey 	char irq_name[16];
465e3c97c2cSBryan Venteicher 
4668f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
4678f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
468e3c97c2cSBryan Venteicher 
4698f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
4708f82136aSPatrick Kelsey 		snprintf(irq_name, sizeof(irq_name), "rxq%d", i);
471e557c1ddSBryan Venteicher 
4728f82136aSPatrick Kelsey 		rxq = &sc->vmx_rxq[i];
4738f82136aSPatrick Kelsey 		error = iflib_irq_alloc_generic(ctx, &rxq->vxrxq_irq, i + 1,
4748f82136aSPatrick Kelsey 		    IFLIB_INTR_RX, vmxnet3_rxq_intr, rxq, i, irq_name);
4758f82136aSPatrick Kelsey 		if (error) {
4768f82136aSPatrick Kelsey 			device_printf(iflib_get_dev(ctx),
4778f82136aSPatrick Kelsey 			    "Failed to register rxq %d interrupt handler\n", i);
4788f82136aSPatrick Kelsey 			return (error);
4798f82136aSPatrick Kelsey 		}
480e3c97c2cSBryan Venteicher 	}
481e3c97c2cSBryan Venteicher 
4828f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++) {
4838f82136aSPatrick Kelsey 		snprintf(irq_name, sizeof(irq_name), "txq%d", i);
4848f82136aSPatrick Kelsey 
4858f82136aSPatrick Kelsey 		/*
4868f82136aSPatrick Kelsey 		 * Don't provide the corresponding rxq irq for reference -
4878f82136aSPatrick Kelsey 		 * we want the transmit task to be attached to a task queue
4888f82136aSPatrick Kelsey 		 * that is different from the one used by the corresponding
4898f82136aSPatrick Kelsey 		 * rxq irq.  That is because the TX doorbell writes are very
4908f82136aSPatrick Kelsey 		 * expensive as virtualized MMIO operations, so we want to
4918f82136aSPatrick Kelsey 		 * be able to defer them to another core when possible so
4928f82136aSPatrick Kelsey 		 * that they don't steal receive processing cycles during
4938f82136aSPatrick Kelsey 		 * stack turnarounds like TCP ACK generation.  The other
4948f82136aSPatrick Kelsey 		 * piece to this approach is enabling the iflib abdicate
4958f82136aSPatrick Kelsey 		 * option (currently via an interface-specific
4968f82136aSPatrick Kelsey 		 * tunable/sysctl).
4978f82136aSPatrick Kelsey 		 */
4988f82136aSPatrick Kelsey 		iflib_softirq_alloc_generic(ctx, NULL, IFLIB_INTR_TX, NULL, i,
4998f82136aSPatrick Kelsey 		    irq_name);
500e3c97c2cSBryan Venteicher 	}
501e3c97c2cSBryan Venteicher 
5028f82136aSPatrick Kelsey 	error = iflib_irq_alloc_generic(ctx, &sc->vmx_event_intr_irq,
5038f82136aSPatrick Kelsey 	    scctx->isc_nrxqsets + 1, IFLIB_INTR_ADMIN, vmxnet3_event_intr, sc, 0,
5048f82136aSPatrick Kelsey 	    "event");
5058f82136aSPatrick Kelsey 	if (error) {
5068f82136aSPatrick Kelsey 		device_printf(iflib_get_dev(ctx),
5078f82136aSPatrick Kelsey 		    "Failed to register event interrupt handler\n");
5088f82136aSPatrick Kelsey 		return (error);
509e3c97c2cSBryan Venteicher 	}
510e3c97c2cSBryan Venteicher 
5118f82136aSPatrick Kelsey 	return (0);
5128f82136aSPatrick Kelsey }
513e3c97c2cSBryan Venteicher 
5148f82136aSPatrick Kelsey static void
5158f82136aSPatrick Kelsey vmxnet3_free_irqs(struct vmxnet3_softc *sc)
5168f82136aSPatrick Kelsey {
5178f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
5188f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
5198f82136aSPatrick Kelsey 	int i;
5208f82136aSPatrick Kelsey 
5218f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
5228f82136aSPatrick Kelsey 
5238f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
5248f82136aSPatrick Kelsey 		rxq = &sc->vmx_rxq[i];
5258f82136aSPatrick Kelsey 		iflib_irq_free(sc->vmx_ctx, &rxq->vxrxq_irq);
5268f82136aSPatrick Kelsey 	}
5278f82136aSPatrick Kelsey 
5288f82136aSPatrick Kelsey 	iflib_irq_free(sc->vmx_ctx, &sc->vmx_event_intr_irq);
5298f82136aSPatrick Kelsey }
5308f82136aSPatrick Kelsey 
5318f82136aSPatrick Kelsey static int
5328f82136aSPatrick Kelsey vmxnet3_attach_post(if_ctx_t ctx)
5338f82136aSPatrick Kelsey {
5348f82136aSPatrick Kelsey 	device_t dev;
5358f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
5368f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
5378f82136aSPatrick Kelsey 	int error;
5388f82136aSPatrick Kelsey 
5398f82136aSPatrick Kelsey 	dev = iflib_get_dev(ctx);
5408f82136aSPatrick Kelsey 	scctx = iflib_get_softc_ctx(ctx);
5418f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
5428f82136aSPatrick Kelsey 
5438f82136aSPatrick Kelsey 	if (scctx->isc_nrxqsets > 1)
5448f82136aSPatrick Kelsey 		sc->vmx_flags |= VMXNET3_FLAG_RSS;
5458f82136aSPatrick Kelsey 
5468f82136aSPatrick Kelsey 	error = vmxnet3_alloc_data(sc);
5478f82136aSPatrick Kelsey 	if (error)
5488f82136aSPatrick Kelsey 		goto fail;
5498f82136aSPatrick Kelsey 
5508f82136aSPatrick Kelsey 	vmxnet3_set_interrupt_idx(sc);
5518f82136aSPatrick Kelsey 	vmxnet3_setup_sysctl(sc);
5528f82136aSPatrick Kelsey 
5538f82136aSPatrick Kelsey 	ifmedia_add(sc->vmx_media, IFM_ETHER | IFM_AUTO, 0, NULL);
5548f82136aSPatrick Kelsey 	ifmedia_set(sc->vmx_media, IFM_ETHER | IFM_AUTO);
5558f82136aSPatrick Kelsey 
5568f82136aSPatrick Kelsey fail:
5578f82136aSPatrick Kelsey 	return (error);
5588f82136aSPatrick Kelsey }
5598f82136aSPatrick Kelsey 
5608f82136aSPatrick Kelsey static int
5618f82136aSPatrick Kelsey vmxnet3_detach(if_ctx_t ctx)
5628f82136aSPatrick Kelsey {
5638f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
5648f82136aSPatrick Kelsey 
5658f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
5668f82136aSPatrick Kelsey 
5678f82136aSPatrick Kelsey 	vmxnet3_free_irqs(sc);
568e3c97c2cSBryan Venteicher 	vmxnet3_free_data(sc);
569e3c97c2cSBryan Venteicher 	vmxnet3_free_resources(sc);
570e3c97c2cSBryan Venteicher 
571e3c97c2cSBryan Venteicher 	return (0);
572e3c97c2cSBryan Venteicher }
573e3c97c2cSBryan Venteicher 
574e3c97c2cSBryan Venteicher static int
5758f82136aSPatrick Kelsey vmxnet3_shutdown(if_ctx_t ctx)
5768f82136aSPatrick Kelsey {
5778f82136aSPatrick Kelsey 
5788f82136aSPatrick Kelsey 	return (0);
5798f82136aSPatrick Kelsey }
5808f82136aSPatrick Kelsey 
5818f82136aSPatrick Kelsey static int
5828f82136aSPatrick Kelsey vmxnet3_suspend(if_ctx_t ctx)
5838f82136aSPatrick Kelsey {
5848f82136aSPatrick Kelsey 
5858f82136aSPatrick Kelsey 	return (0);
5868f82136aSPatrick Kelsey }
5878f82136aSPatrick Kelsey 
5888f82136aSPatrick Kelsey static int
5898f82136aSPatrick Kelsey vmxnet3_resume(if_ctx_t ctx)
590e3c97c2cSBryan Venteicher {
591e3c97c2cSBryan Venteicher 
592e3c97c2cSBryan Venteicher 	return (0);
593e3c97c2cSBryan Venteicher }
594e3c97c2cSBryan Venteicher 
595e3c97c2cSBryan Venteicher static int
596e3c97c2cSBryan Venteicher vmxnet3_alloc_resources(struct vmxnet3_softc *sc)
597e3c97c2cSBryan Venteicher {
598e3c97c2cSBryan Venteicher 	device_t dev;
599e3c97c2cSBryan Venteicher 	int rid;
600e3c97c2cSBryan Venteicher 
601e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
602e3c97c2cSBryan Venteicher 
603e3c97c2cSBryan Venteicher 	rid = PCIR_BAR(0);
604e3c97c2cSBryan Venteicher 	sc->vmx_res0 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
605e3c97c2cSBryan Venteicher 	    RF_ACTIVE);
606e3c97c2cSBryan Venteicher 	if (sc->vmx_res0 == NULL) {
607e3c97c2cSBryan Venteicher 		device_printf(dev,
608e3c97c2cSBryan Venteicher 		    "could not map BAR0 memory\n");
609e3c97c2cSBryan Venteicher 		return (ENXIO);
610e3c97c2cSBryan Venteicher 	}
611e3c97c2cSBryan Venteicher 
612e3c97c2cSBryan Venteicher 	sc->vmx_iot0 = rman_get_bustag(sc->vmx_res0);
613e3c97c2cSBryan Venteicher 	sc->vmx_ioh0 = rman_get_bushandle(sc->vmx_res0);
614e3c97c2cSBryan Venteicher 
615e3c97c2cSBryan Venteicher 	rid = PCIR_BAR(1);
616e3c97c2cSBryan Venteicher 	sc->vmx_res1 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
617e3c97c2cSBryan Venteicher 	    RF_ACTIVE);
618e3c97c2cSBryan Venteicher 	if (sc->vmx_res1 == NULL) {
619e3c97c2cSBryan Venteicher 		device_printf(dev,
620e3c97c2cSBryan Venteicher 		    "could not map BAR1 memory\n");
621e3c97c2cSBryan Venteicher 		return (ENXIO);
622e3c97c2cSBryan Venteicher 	}
623e3c97c2cSBryan Venteicher 
624e3c97c2cSBryan Venteicher 	sc->vmx_iot1 = rman_get_bustag(sc->vmx_res1);
625e3c97c2cSBryan Venteicher 	sc->vmx_ioh1 = rman_get_bushandle(sc->vmx_res1);
626e3c97c2cSBryan Venteicher 
627e3c97c2cSBryan Venteicher 	return (0);
628e3c97c2cSBryan Venteicher }
629e3c97c2cSBryan Venteicher 
630e3c97c2cSBryan Venteicher static void
631e3c97c2cSBryan Venteicher vmxnet3_free_resources(struct vmxnet3_softc *sc)
632e3c97c2cSBryan Venteicher {
633e3c97c2cSBryan Venteicher 	device_t dev;
634e3c97c2cSBryan Venteicher 
635e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
636e3c97c2cSBryan Venteicher 
637e3c97c2cSBryan Venteicher 	if (sc->vmx_res0 != NULL) {
638b97de13aSMarius Strobl 		bus_release_resource(dev, SYS_RES_MEMORY,
639b97de13aSMarius Strobl 		    rman_get_rid(sc->vmx_res0), sc->vmx_res0);
640e3c97c2cSBryan Venteicher 		sc->vmx_res0 = NULL;
641e3c97c2cSBryan Venteicher 	}
642e3c97c2cSBryan Venteicher 
643e3c97c2cSBryan Venteicher 	if (sc->vmx_res1 != NULL) {
644b97de13aSMarius Strobl 		bus_release_resource(dev, SYS_RES_MEMORY,
645b97de13aSMarius Strobl 		    rman_get_rid(sc->vmx_res1), sc->vmx_res1);
646e3c97c2cSBryan Venteicher 		sc->vmx_res1 = NULL;
647e3c97c2cSBryan Venteicher 	}
648e3c97c2cSBryan Venteicher }
649e3c97c2cSBryan Venteicher 
650e3c97c2cSBryan Venteicher static int
651e3c97c2cSBryan Venteicher vmxnet3_check_version(struct vmxnet3_softc *sc)
652e3c97c2cSBryan Venteicher {
653e3c97c2cSBryan Venteicher 	device_t dev;
654e3c97c2cSBryan Venteicher 	uint32_t version;
655e3c97c2cSBryan Venteicher 
656e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
657e3c97c2cSBryan Venteicher 
658e3c97c2cSBryan Venteicher 	version = vmxnet3_read_bar1(sc, VMXNET3_BAR1_VRRS);
659e3c97c2cSBryan Venteicher 	if ((version & 0x01) == 0) {
660e3c97c2cSBryan Venteicher 		device_printf(dev, "unsupported hardware version %#x\n",
661e3c97c2cSBryan Venteicher 		    version);
662e3c97c2cSBryan Venteicher 		return (ENOTSUP);
6633c965775SBryan Venteicher 	}
664e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_VRRS, 1);
665e3c97c2cSBryan Venteicher 
666e3c97c2cSBryan Venteicher 	version = vmxnet3_read_bar1(sc, VMXNET3_BAR1_UVRS);
667e3c97c2cSBryan Venteicher 	if ((version & 0x01) == 0) {
668e3c97c2cSBryan Venteicher 		device_printf(dev, "unsupported UPT version %#x\n", version);
669e3c97c2cSBryan Venteicher 		return (ENOTSUP);
6703c965775SBryan Venteicher 	}
671e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_UVRS, 1);
672e3c97c2cSBryan Venteicher 
673e3c97c2cSBryan Venteicher 	return (0);
674e3c97c2cSBryan Venteicher }
675e3c97c2cSBryan Venteicher 
676e3c97c2cSBryan Venteicher static void
677e3c97c2cSBryan Venteicher vmxnet3_set_interrupt_idx(struct vmxnet3_softc *sc)
678e3c97c2cSBryan Venteicher {
6798f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
680e3c97c2cSBryan Venteicher 	struct vmxnet3_txqueue *txq;
681e3c97c2cSBryan Venteicher 	struct vmxnet3_txq_shared *txs;
682e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
683e3c97c2cSBryan Venteicher 	struct vmxnet3_rxq_shared *rxs;
6848f82136aSPatrick Kelsey 	int intr_idx;
685e3c97c2cSBryan Venteicher 	int i;
686e3c97c2cSBryan Venteicher 
6878f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
688e3c97c2cSBryan Venteicher 
6898f82136aSPatrick Kelsey 	/*
690769d56ecSPatrick Kelsey 	 * There is always one interrupt per receive queue, assigned
691769d56ecSPatrick Kelsey 	 * starting with the first interrupt.  When there is only one
692769d56ecSPatrick Kelsey 	 * interrupt available, the event interrupt shares the receive queue
693769d56ecSPatrick Kelsey 	 * interrupt, otherwise it uses the interrupt following the last
694769d56ecSPatrick Kelsey 	 * receive queue interrupt.  Transmit queues are not assigned
695769d56ecSPatrick Kelsey 	 * interrupts, so they are given indexes beyond the indexes that
696769d56ecSPatrick Kelsey 	 * correspond to the real interrupts.
6978f82136aSPatrick Kelsey 	 */
698769d56ecSPatrick Kelsey 
699769d56ecSPatrick Kelsey 	/* The event interrupt is always the last vector. */
7008f82136aSPatrick Kelsey 	sc->vmx_event_intr_idx = scctx->isc_vectors - 1;
701e3c97c2cSBryan Venteicher 
7028f82136aSPatrick Kelsey 	intr_idx = 0;
7038f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++, intr_idx++) {
704e3c97c2cSBryan Venteicher 		rxq = &sc->vmx_rxq[i];
705e3c97c2cSBryan Venteicher 		rxs = rxq->vxrxq_rs;
7068f82136aSPatrick Kelsey 		rxq->vxrxq_intr_idx = intr_idx;
707e3c97c2cSBryan Venteicher 		rxs->intr_idx = rxq->vxrxq_intr_idx;
708e3c97c2cSBryan Venteicher 	}
7098f82136aSPatrick Kelsey 
7108f82136aSPatrick Kelsey 	/*
7118f82136aSPatrick Kelsey 	 * Assign the tx queues interrupt indexes above what we are actually
7128f82136aSPatrick Kelsey 	 * using.  These interrupts will never be enabled.
7138f82136aSPatrick Kelsey 	 */
7148f82136aSPatrick Kelsey 	intr_idx = scctx->isc_vectors;
7158f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++, intr_idx++) {
7168f82136aSPatrick Kelsey 		txq = &sc->vmx_txq[i];
7178f82136aSPatrick Kelsey 		txs = txq->vxtxq_ts;
7188f82136aSPatrick Kelsey 		txq->vxtxq_intr_idx = intr_idx;
7198f82136aSPatrick Kelsey 		txs->intr_idx = txq->vxtxq_intr_idx;
7208f82136aSPatrick Kelsey 	}
721e3c97c2cSBryan Venteicher }
722e3c97c2cSBryan Venteicher 
723e3c97c2cSBryan Venteicher static int
7248f82136aSPatrick Kelsey vmxnet3_queues_shared_alloc(struct vmxnet3_softc *sc)
725e3c97c2cSBryan Venteicher {
7268f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
7278f82136aSPatrick Kelsey 	int size;
728e3c97c2cSBryan Venteicher 	int error;
729e3c97c2cSBryan Venteicher 
7308f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
731e3c97c2cSBryan Venteicher 
7328f82136aSPatrick Kelsey 	/*
7338f82136aSPatrick Kelsey 	 * The txq and rxq shared data areas must be allocated contiguously
7348f82136aSPatrick Kelsey 	 * as vmxnet3_driver_shared contains only a single address member
7358f82136aSPatrick Kelsey 	 * for the shared queue data area.
7368f82136aSPatrick Kelsey 	 */
7378f82136aSPatrick Kelsey 	size = scctx->isc_ntxqsets * sizeof(struct vmxnet3_txq_shared) +
7388f82136aSPatrick Kelsey 	    scctx->isc_nrxqsets * sizeof(struct vmxnet3_rxq_shared);
7398f82136aSPatrick Kelsey 	error = iflib_dma_alloc_align(sc->vmx_ctx, size, 128, &sc->vmx_qs_dma, 0);
7408f82136aSPatrick Kelsey 	if (error) {
7418f82136aSPatrick Kelsey 		device_printf(sc->vmx_dev, "cannot alloc queue shared memory\n");
742e3c97c2cSBryan Venteicher 		return (error);
743e3c97c2cSBryan Venteicher 	}
744e3c97c2cSBryan Venteicher 
745e557c1ddSBryan Venteicher 	return (0);
746e557c1ddSBryan Venteicher }
747e557c1ddSBryan Venteicher 
748e557c1ddSBryan Venteicher static void
7498f82136aSPatrick Kelsey vmxnet3_init_txq(struct vmxnet3_softc *sc, int q)
750e557c1ddSBryan Venteicher {
751e557c1ddSBryan Venteicher 	struct vmxnet3_txqueue *txq;
7528f82136aSPatrick Kelsey 	struct vmxnet3_comp_ring *txc;
7538f82136aSPatrick Kelsey 	struct vmxnet3_txring *txr;
7548f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
755e557c1ddSBryan Venteicher 
7568f82136aSPatrick Kelsey 	txq = &sc->vmx_txq[q];
7578f82136aSPatrick Kelsey 	txc = &txq->vxtxq_comp_ring;
7588f82136aSPatrick Kelsey 	txr = &txq->vxtxq_cmd_ring;
7598f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
7608f82136aSPatrick Kelsey 
7618f82136aSPatrick Kelsey 	snprintf(txq->vxtxq_name, sizeof(txq->vxtxq_name), "%s-tx%d",
7628f82136aSPatrick Kelsey 	    device_get_nameunit(sc->vmx_dev), q);
7638f82136aSPatrick Kelsey 
7648f82136aSPatrick Kelsey 	txq->vxtxq_sc = sc;
7658f82136aSPatrick Kelsey 	txq->vxtxq_id = q;
7668f82136aSPatrick Kelsey 	txc->vxcr_ndesc = scctx->isc_ntxd[0];
7678f82136aSPatrick Kelsey 	txr->vxtxr_ndesc = scctx->isc_ntxd[1];
768e557c1ddSBryan Venteicher }
7698f82136aSPatrick Kelsey 
7708f82136aSPatrick Kelsey static int
7718f82136aSPatrick Kelsey vmxnet3_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
7728f82136aSPatrick Kelsey     int ntxqs, int ntxqsets)
7738f82136aSPatrick Kelsey {
7748f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
7758f82136aSPatrick Kelsey 	int q;
7768f82136aSPatrick Kelsey 	int error;
7778f82136aSPatrick Kelsey 	caddr_t kva;
7788f82136aSPatrick Kelsey 
7798f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
7808f82136aSPatrick Kelsey 
7818f82136aSPatrick Kelsey 	/* Allocate the array of transmit queues */
7828f82136aSPatrick Kelsey 	sc->vmx_txq = malloc(sizeof(struct vmxnet3_txqueue) *
7838f82136aSPatrick Kelsey 	    ntxqsets, M_DEVBUF, M_NOWAIT | M_ZERO);
7848f82136aSPatrick Kelsey 	if (sc->vmx_txq == NULL)
7858f82136aSPatrick Kelsey 		return (ENOMEM);
7868f82136aSPatrick Kelsey 
7878f82136aSPatrick Kelsey 	/* Initialize driver state for each transmit queue */
7888f82136aSPatrick Kelsey 	for (q = 0; q < ntxqsets; q++)
7898f82136aSPatrick Kelsey 		vmxnet3_init_txq(sc, q);
7908f82136aSPatrick Kelsey 
7918f82136aSPatrick Kelsey 	/*
7928f82136aSPatrick Kelsey 	 * Allocate queue state that is shared with the device.  This check
7938f82136aSPatrick Kelsey 	 * and call is performed in both vmxnet3_tx_queues_alloc() and
7948f82136aSPatrick Kelsey 	 * vmxnet3_rx_queues_alloc() so that we don't have to care which
7958f82136aSPatrick Kelsey 	 * order iflib invokes those routines in.
7968f82136aSPatrick Kelsey 	 */
7978f82136aSPatrick Kelsey 	if (sc->vmx_qs_dma.idi_size == 0) {
7988f82136aSPatrick Kelsey 		error = vmxnet3_queues_shared_alloc(sc);
7998f82136aSPatrick Kelsey 		if (error)
8008f82136aSPatrick Kelsey 			return (error);
801e557c1ddSBryan Venteicher 	}
8028f82136aSPatrick Kelsey 
8038f82136aSPatrick Kelsey 	kva = sc->vmx_qs_dma.idi_vaddr;
8048f82136aSPatrick Kelsey 	for (q = 0; q < ntxqsets; q++) {
8058f82136aSPatrick Kelsey 		sc->vmx_txq[q].vxtxq_ts = (struct vmxnet3_txq_shared *) kva;
8068f82136aSPatrick Kelsey 		kva += sizeof(struct vmxnet3_txq_shared);
8078f82136aSPatrick Kelsey 	}
8088f82136aSPatrick Kelsey 
8098f82136aSPatrick Kelsey 	/* Record descriptor ring vaddrs and paddrs */
8108f82136aSPatrick Kelsey 	for (q = 0; q < ntxqsets; q++) {
8118f82136aSPatrick Kelsey 		struct vmxnet3_txqueue *txq;
8128f82136aSPatrick Kelsey 		struct vmxnet3_txring *txr;
8138f82136aSPatrick Kelsey 		struct vmxnet3_comp_ring *txc;
8148f82136aSPatrick Kelsey 
8158f82136aSPatrick Kelsey 		txq = &sc->vmx_txq[q];
8168f82136aSPatrick Kelsey 		txc = &txq->vxtxq_comp_ring;
8178f82136aSPatrick Kelsey 		txr = &txq->vxtxq_cmd_ring;
8188f82136aSPatrick Kelsey 
8198f82136aSPatrick Kelsey 		/* Completion ring */
8208f82136aSPatrick Kelsey 		txc->vxcr_u.txcd =
8218f82136aSPatrick Kelsey 		    (struct vmxnet3_txcompdesc *) vaddrs[q * ntxqs + 0];
8228f82136aSPatrick Kelsey 		txc->vxcr_paddr = paddrs[q * ntxqs + 0];
8238f82136aSPatrick Kelsey 
8248f82136aSPatrick Kelsey 		/* Command ring */
8258f82136aSPatrick Kelsey 		txr->vxtxr_txd =
8268f82136aSPatrick Kelsey 		    (struct vmxnet3_txdesc *) vaddrs[q * ntxqs + 1];
8278f82136aSPatrick Kelsey 		txr->vxtxr_paddr = paddrs[q * ntxqs + 1];
8288f82136aSPatrick Kelsey 	}
8298f82136aSPatrick Kelsey 
8308f82136aSPatrick Kelsey 	return (0);
831e557c1ddSBryan Venteicher }
832e557c1ddSBryan Venteicher 
833e557c1ddSBryan Venteicher static void
8348f82136aSPatrick Kelsey vmxnet3_init_rxq(struct vmxnet3_softc *sc, int q, int nrxqs)
835e3c97c2cSBryan Venteicher {
836e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
8378f82136aSPatrick Kelsey 	struct vmxnet3_comp_ring *rxc;
838e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
8398f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
840e3c97c2cSBryan Venteicher 	int i;
841e3c97c2cSBryan Venteicher 
842e3c97c2cSBryan Venteicher 	rxq = &sc->vmx_rxq[q];
8438f82136aSPatrick Kelsey 	rxc = &rxq->vxrxq_comp_ring;
8448f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
845e3c97c2cSBryan Venteicher 
846e3c97c2cSBryan Venteicher 	snprintf(rxq->vxrxq_name, sizeof(rxq->vxrxq_name), "%s-rx%d",
847e3c97c2cSBryan Venteicher 	    device_get_nameunit(sc->vmx_dev), q);
848e3c97c2cSBryan Venteicher 
849e3c97c2cSBryan Venteicher 	rxq->vxrxq_sc = sc;
850e3c97c2cSBryan Venteicher 	rxq->vxrxq_id = q;
851e3c97c2cSBryan Venteicher 
8528f82136aSPatrick Kelsey 	/*
8538f82136aSPatrick Kelsey 	 * First rxq is the completion queue, so there are nrxqs - 1 command
8548f82136aSPatrick Kelsey 	 * rings starting at iflib queue id 1.
8558f82136aSPatrick Kelsey 	 */
8568f82136aSPatrick Kelsey 	rxc->vxcr_ndesc = scctx->isc_nrxd[0];
8578f82136aSPatrick Kelsey 	for (i = 0; i < nrxqs - 1; i++) {
858e3c97c2cSBryan Venteicher 		rxr = &rxq->vxrxq_cmd_ring[i];
8598f82136aSPatrick Kelsey 		rxr->vxrxr_ndesc = scctx->isc_nrxd[i + 1];
8603c965775SBryan Venteicher 	}
861e3c97c2cSBryan Venteicher }
862e3c97c2cSBryan Venteicher 
863e3c97c2cSBryan Venteicher static int
8648f82136aSPatrick Kelsey vmxnet3_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
8658f82136aSPatrick Kelsey     int nrxqs, int nrxqsets)
866e3c97c2cSBryan Venteicher {
8678f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
8688f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
8698f82136aSPatrick Kelsey 	int q;
8708f82136aSPatrick Kelsey 	int i;
8718f82136aSPatrick Kelsey 	int error;
8728f82136aSPatrick Kelsey 	caddr_t kva;
873e3c97c2cSBryan Venteicher 
8748f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
8758f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
876e3c97c2cSBryan Venteicher 
8778f82136aSPatrick Kelsey 	/* Allocate the array of receive queues */
8788f82136aSPatrick Kelsey 	sc->vmx_rxq = malloc(sizeof(struct vmxnet3_rxqueue) *
8798f82136aSPatrick Kelsey 	    nrxqsets, M_DEVBUF, M_NOWAIT | M_ZERO);
8808f82136aSPatrick Kelsey 	if (sc->vmx_rxq == NULL)
881e3c97c2cSBryan Venteicher 		return (ENOMEM);
882e3c97c2cSBryan Venteicher 
8838f82136aSPatrick Kelsey 	/* Initialize driver state for each receive queue */
8848f82136aSPatrick Kelsey 	for (q = 0; q < nrxqsets; q++)
8858f82136aSPatrick Kelsey 		vmxnet3_init_rxq(sc, q, nrxqs);
886e3c97c2cSBryan Venteicher 
887e557c1ddSBryan Venteicher 	/*
8888f82136aSPatrick Kelsey 	 * Allocate queue state that is shared with the device.  This check
8898f82136aSPatrick Kelsey 	 * and call is performed in both vmxnet3_tx_queues_alloc() and
8908f82136aSPatrick Kelsey 	 * vmxnet3_rx_queues_alloc() so that we don't have to care which
8918f82136aSPatrick Kelsey 	 * order iflib invokes those routines in.
892e557c1ddSBryan Venteicher 	 */
8938f82136aSPatrick Kelsey 	if (sc->vmx_qs_dma.idi_size == 0) {
8948f82136aSPatrick Kelsey 		error = vmxnet3_queues_shared_alloc(sc);
895e3c97c2cSBryan Venteicher 		if (error)
896e3c97c2cSBryan Venteicher 			return (error);
897e3c97c2cSBryan Venteicher 	}
898e3c97c2cSBryan Venteicher 
8998f82136aSPatrick Kelsey 	kva = sc->vmx_qs_dma.idi_vaddr +
9008f82136aSPatrick Kelsey 	    scctx->isc_ntxqsets * sizeof(struct vmxnet3_txq_shared);
9018f82136aSPatrick Kelsey 	for (q = 0; q < nrxqsets; q++) {
9028f82136aSPatrick Kelsey 		sc->vmx_rxq[q].vxrxq_rs = (struct vmxnet3_rxq_shared *) kva;
9038f82136aSPatrick Kelsey 		kva += sizeof(struct vmxnet3_rxq_shared);
9048f82136aSPatrick Kelsey 	}
9058f82136aSPatrick Kelsey 
9068f82136aSPatrick Kelsey 	/* Record descriptor ring vaddrs and paddrs */
9078f82136aSPatrick Kelsey 	for (q = 0; q < nrxqsets; q++) {
9088f82136aSPatrick Kelsey 		struct vmxnet3_rxqueue *rxq;
9098f82136aSPatrick Kelsey 		struct vmxnet3_rxring *rxr;
9108f82136aSPatrick Kelsey 		struct vmxnet3_comp_ring *rxc;
9118f82136aSPatrick Kelsey 
9128f82136aSPatrick Kelsey 		rxq = &sc->vmx_rxq[q];
9138f82136aSPatrick Kelsey 		rxc = &rxq->vxrxq_comp_ring;
9148f82136aSPatrick Kelsey 
9158f82136aSPatrick Kelsey 		/* Completion ring */
9168f82136aSPatrick Kelsey 		rxc->vxcr_u.rxcd =
9178f82136aSPatrick Kelsey 		    (struct vmxnet3_rxcompdesc *) vaddrs[q * nrxqs + 0];
9188f82136aSPatrick Kelsey 		rxc->vxcr_paddr = paddrs[q * nrxqs + 0];
9198f82136aSPatrick Kelsey 
9208f82136aSPatrick Kelsey 		/* Command ring(s) */
9218f82136aSPatrick Kelsey 		for (i = 0; i < nrxqs - 1; i++) {
9228f82136aSPatrick Kelsey 			rxr = &rxq->vxrxq_cmd_ring[i];
9238f82136aSPatrick Kelsey 
9248f82136aSPatrick Kelsey 			rxr->vxrxr_rxd =
9258f82136aSPatrick Kelsey 			    (struct vmxnet3_rxdesc *) vaddrs[q * nrxqs + 1 + i];
9268f82136aSPatrick Kelsey 			rxr->vxrxr_paddr = paddrs[q * nrxqs + 1 + i];
9278f82136aSPatrick Kelsey 		}
928e3c97c2cSBryan Venteicher 	}
929e3c97c2cSBryan Venteicher 
930e3c97c2cSBryan Venteicher 	return (0);
931e3c97c2cSBryan Venteicher }
932e3c97c2cSBryan Venteicher 
933e3c97c2cSBryan Venteicher static void
9348f82136aSPatrick Kelsey vmxnet3_queues_free(if_ctx_t ctx)
935e3c97c2cSBryan Venteicher {
9368f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
937e3c97c2cSBryan Venteicher 
9388f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
939e3c97c2cSBryan Venteicher 
9408f82136aSPatrick Kelsey 	/* Free queue state area that is shared with the device */
9418f82136aSPatrick Kelsey 	if (sc->vmx_qs_dma.idi_size != 0) {
9428f82136aSPatrick Kelsey 		iflib_dma_free(&sc->vmx_qs_dma);
9438f82136aSPatrick Kelsey 		sc->vmx_qs_dma.idi_size = 0;
944e3c97c2cSBryan Venteicher 	}
945e3c97c2cSBryan Venteicher 
9468f82136aSPatrick Kelsey 	/* Free array of receive queues */
947e3c97c2cSBryan Venteicher 	if (sc->vmx_rxq != NULL) {
948e3c97c2cSBryan Venteicher 		free(sc->vmx_rxq, M_DEVBUF);
949e3c97c2cSBryan Venteicher 		sc->vmx_rxq = NULL;
950e3c97c2cSBryan Venteicher 	}
951e3c97c2cSBryan Venteicher 
9528f82136aSPatrick Kelsey 	/* Free array of transmit queues */
953e3c97c2cSBryan Venteicher 	if (sc->vmx_txq != NULL) {
954e3c97c2cSBryan Venteicher 		free(sc->vmx_txq, M_DEVBUF);
955e3c97c2cSBryan Venteicher 		sc->vmx_txq = NULL;
956e3c97c2cSBryan Venteicher 	}
957e3c97c2cSBryan Venteicher }
958e3c97c2cSBryan Venteicher 
959e3c97c2cSBryan Venteicher static int
960e3c97c2cSBryan Venteicher vmxnet3_alloc_shared_data(struct vmxnet3_softc *sc)
961e3c97c2cSBryan Venteicher {
962e3c97c2cSBryan Venteicher 	device_t dev;
963e3c97c2cSBryan Venteicher 	size_t size;
9648f82136aSPatrick Kelsey 	int error;
965e3c97c2cSBryan Venteicher 
966e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
967e3c97c2cSBryan Venteicher 
9688f82136aSPatrick Kelsey 	/* Top level state structure shared with the device */
969e3c97c2cSBryan Venteicher 	size = sizeof(struct vmxnet3_driver_shared);
9708f82136aSPatrick Kelsey 	error = iflib_dma_alloc_align(sc->vmx_ctx, size, 1, &sc->vmx_ds_dma, 0);
971e3c97c2cSBryan Venteicher 	if (error) {
972e3c97c2cSBryan Venteicher 		device_printf(dev, "cannot alloc shared memory\n");
973e3c97c2cSBryan Venteicher 		return (error);
974e3c97c2cSBryan Venteicher 	}
9758f82136aSPatrick Kelsey 	sc->vmx_ds = (struct vmxnet3_driver_shared *) sc->vmx_ds_dma.idi_vaddr;
976e3c97c2cSBryan Venteicher 
9778f82136aSPatrick Kelsey 	/* RSS table state shared with the device */
978e557c1ddSBryan Venteicher 	if (sc->vmx_flags & VMXNET3_FLAG_RSS) {
979e557c1ddSBryan Venteicher 		size = sizeof(struct vmxnet3_rss_shared);
9808f82136aSPatrick Kelsey 		error = iflib_dma_alloc_align(sc->vmx_ctx, size, 128,
9818f82136aSPatrick Kelsey 		    &sc->vmx_rss_dma, 0);
982e557c1ddSBryan Venteicher 		if (error) {
983e557c1ddSBryan Venteicher 			device_printf(dev, "cannot alloc rss shared memory\n");
984e557c1ddSBryan Venteicher 			return (error);
985e557c1ddSBryan Venteicher 		}
986e557c1ddSBryan Venteicher 		sc->vmx_rss =
9878f82136aSPatrick Kelsey 		    (struct vmxnet3_rss_shared *) sc->vmx_rss_dma.idi_vaddr;
988e557c1ddSBryan Venteicher 	}
989e557c1ddSBryan Venteicher 
990e3c97c2cSBryan Venteicher 	return (0);
991e3c97c2cSBryan Venteicher }
992e3c97c2cSBryan Venteicher 
993e3c97c2cSBryan Venteicher static void
994e3c97c2cSBryan Venteicher vmxnet3_free_shared_data(struct vmxnet3_softc *sc)
995e3c97c2cSBryan Venteicher {
996e3c97c2cSBryan Venteicher 
9978f82136aSPatrick Kelsey 	/* Free RSS table state shared with the device */
998e557c1ddSBryan Venteicher 	if (sc->vmx_rss != NULL) {
9998f82136aSPatrick Kelsey 		iflib_dma_free(&sc->vmx_rss_dma);
1000e557c1ddSBryan Venteicher 		sc->vmx_rss = NULL;
1001e557c1ddSBryan Venteicher 	}
1002e557c1ddSBryan Venteicher 
10038f82136aSPatrick Kelsey 	/* Free top level state structure shared with the device */
1004e3c97c2cSBryan Venteicher 	if (sc->vmx_ds != NULL) {
10058f82136aSPatrick Kelsey 		iflib_dma_free(&sc->vmx_ds_dma);
1006e3c97c2cSBryan Venteicher 		sc->vmx_ds = NULL;
1007e3c97c2cSBryan Venteicher 	}
1008e3c97c2cSBryan Venteicher }
1009e3c97c2cSBryan Venteicher 
1010e3c97c2cSBryan Venteicher static int
1011e3c97c2cSBryan Venteicher vmxnet3_alloc_mcast_table(struct vmxnet3_softc *sc)
1012e3c97c2cSBryan Venteicher {
1013e3c97c2cSBryan Venteicher 	int error;
1014e3c97c2cSBryan Venteicher 
10158f82136aSPatrick Kelsey 	/* Multicast table state shared with the device */
10168f82136aSPatrick Kelsey 	error = iflib_dma_alloc_align(sc->vmx_ctx,
10178f82136aSPatrick Kelsey 	    VMXNET3_MULTICAST_MAX * ETHER_ADDR_LEN, 32, &sc->vmx_mcast_dma, 0);
1018e3c97c2cSBryan Venteicher 	if (error)
1019e3c97c2cSBryan Venteicher 		device_printf(sc->vmx_dev, "unable to alloc multicast table\n");
1020e3c97c2cSBryan Venteicher 	else
10218f82136aSPatrick Kelsey 		sc->vmx_mcast = sc->vmx_mcast_dma.idi_vaddr;
1022e3c97c2cSBryan Venteicher 
1023e3c97c2cSBryan Venteicher 	return (error);
1024e3c97c2cSBryan Venteicher }
1025e3c97c2cSBryan Venteicher 
1026e3c97c2cSBryan Venteicher static void
1027e3c97c2cSBryan Venteicher vmxnet3_free_mcast_table(struct vmxnet3_softc *sc)
1028e3c97c2cSBryan Venteicher {
1029e3c97c2cSBryan Venteicher 
10308f82136aSPatrick Kelsey 	/* Free multicast table state shared with the device */
1031e3c97c2cSBryan Venteicher 	if (sc->vmx_mcast != NULL) {
10328f82136aSPatrick Kelsey 		iflib_dma_free(&sc->vmx_mcast_dma);
1033e3c97c2cSBryan Venteicher 		sc->vmx_mcast = NULL;
1034e3c97c2cSBryan Venteicher 	}
1035e3c97c2cSBryan Venteicher }
1036e3c97c2cSBryan Venteicher 
1037e3c97c2cSBryan Venteicher static void
1038e3c97c2cSBryan Venteicher vmxnet3_init_shared_data(struct vmxnet3_softc *sc)
1039e3c97c2cSBryan Venteicher {
1040e3c97c2cSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
10418f82136aSPatrick Kelsey 	if_shared_ctx_t sctx;
10428f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
1043e3c97c2cSBryan Venteicher 	struct vmxnet3_txqueue *txq;
1044e3c97c2cSBryan Venteicher 	struct vmxnet3_txq_shared *txs;
1045e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
1046e3c97c2cSBryan Venteicher 	struct vmxnet3_rxq_shared *rxs;
1047e3c97c2cSBryan Venteicher 	int i;
1048e3c97c2cSBryan Venteicher 
1049e3c97c2cSBryan Venteicher 	ds = sc->vmx_ds;
10508f82136aSPatrick Kelsey 	sctx = sc->vmx_sctx;
10518f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
1052e3c97c2cSBryan Venteicher 
1053e3c97c2cSBryan Venteicher 	/*
1054e3c97c2cSBryan Venteicher 	 * Initialize fields of the shared data that remains the same across
1055e3c97c2cSBryan Venteicher 	 * reinits. Note the shared data is zero'd when allocated.
1056e3c97c2cSBryan Venteicher 	 */
1057e3c97c2cSBryan Venteicher 
1058e3c97c2cSBryan Venteicher 	ds->magic = VMXNET3_REV1_MAGIC;
1059e3c97c2cSBryan Venteicher 
1060e3c97c2cSBryan Venteicher 	/* DriverInfo */
1061e3c97c2cSBryan Venteicher 	ds->version = VMXNET3_DRIVER_VERSION;
1062ce3be286SBryan Venteicher 	ds->guest = VMXNET3_GOS_FREEBSD |
1063e3c97c2cSBryan Venteicher #ifdef __LP64__
1064e3c97c2cSBryan Venteicher 	    VMXNET3_GOS_64BIT;
1065e3c97c2cSBryan Venteicher #else
1066e3c97c2cSBryan Venteicher 	    VMXNET3_GOS_32BIT;
1067e3c97c2cSBryan Venteicher #endif
1068e3c97c2cSBryan Venteicher 	ds->vmxnet3_revision = 1;
1069e3c97c2cSBryan Venteicher 	ds->upt_version = 1;
1070e3c97c2cSBryan Venteicher 
1071e3c97c2cSBryan Venteicher 	/* Misc. conf */
1072e3c97c2cSBryan Venteicher 	ds->driver_data = vtophys(sc);
1073e3c97c2cSBryan Venteicher 	ds->driver_data_len = sizeof(struct vmxnet3_softc);
10748f82136aSPatrick Kelsey 	ds->queue_shared = sc->vmx_qs_dma.idi_paddr;
10758f82136aSPatrick Kelsey 	ds->queue_shared_len = sc->vmx_qs_dma.idi_size;
10768f82136aSPatrick Kelsey 	ds->nrxsg_max = IFLIB_MAX_RX_SEGS;
1077e3c97c2cSBryan Venteicher 
1078e557c1ddSBryan Venteicher 	/* RSS conf */
1079e557c1ddSBryan Venteicher 	if (sc->vmx_flags & VMXNET3_FLAG_RSS) {
1080e557c1ddSBryan Venteicher 		ds->rss.version = 1;
10818f82136aSPatrick Kelsey 		ds->rss.paddr = sc->vmx_rss_dma.idi_paddr;
10828f82136aSPatrick Kelsey 		ds->rss.len = sc->vmx_rss_dma.idi_size;
1083e557c1ddSBryan Venteicher 	}
1084e557c1ddSBryan Venteicher 
1085e3c97c2cSBryan Venteicher 	/* Interrupt control. */
1086e3c97c2cSBryan Venteicher 	ds->automask = sc->vmx_intr_mask_mode == VMXNET3_IMM_AUTO;
10878f82136aSPatrick Kelsey 	/*
10888f82136aSPatrick Kelsey 	 * Total number of interrupt indexes we are using in the shared
1089769d56ecSPatrick Kelsey 	 * config data, even though we don't actually allocate interrupt
10908f82136aSPatrick Kelsey 	 * resources for the tx queues.  Some versions of the device will
10918f82136aSPatrick Kelsey 	 * fail to initialize successfully if interrupt indexes are used in
10928f82136aSPatrick Kelsey 	 * the shared config that exceed the number of interrupts configured
10938f82136aSPatrick Kelsey 	 * here.
10948f82136aSPatrick Kelsey 	 */
10958f82136aSPatrick Kelsey 	ds->nintr = (scctx->isc_vectors == 1) ?
1096769d56ecSPatrick Kelsey 	    2 : (scctx->isc_nrxqsets + scctx->isc_ntxqsets + 1);
1097e3c97c2cSBryan Venteicher 	ds->evintr = sc->vmx_event_intr_idx;
1098e3c97c2cSBryan Venteicher 	ds->ictrl = VMXNET3_ICTRL_DISABLE_ALL;
1099e3c97c2cSBryan Venteicher 
11008f82136aSPatrick Kelsey 	for (i = 0; i < ds->nintr; i++)
1101e3c97c2cSBryan Venteicher 		ds->modlevel[i] = UPT1_IMOD_ADAPTIVE;
1102e3c97c2cSBryan Venteicher 
1103e3c97c2cSBryan Venteicher 	/* Receive filter. */
11048f82136aSPatrick Kelsey 	ds->mcast_table = sc->vmx_mcast_dma.idi_paddr;
11058f82136aSPatrick Kelsey 	ds->mcast_tablelen = sc->vmx_mcast_dma.idi_size;
1106e3c97c2cSBryan Venteicher 
1107e3c97c2cSBryan Venteicher 	/* Tx queues */
11088f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++) {
1109e3c97c2cSBryan Venteicher 		txq = &sc->vmx_txq[i];
1110e3c97c2cSBryan Venteicher 		txs = txq->vxtxq_ts;
1111e3c97c2cSBryan Venteicher 
11128f82136aSPatrick Kelsey 		txs->cmd_ring = txq->vxtxq_cmd_ring.vxtxr_paddr;
11133c965775SBryan Venteicher 		txs->cmd_ring_len = txq->vxtxq_cmd_ring.vxtxr_ndesc;
11148f82136aSPatrick Kelsey 		txs->comp_ring = txq->vxtxq_comp_ring.vxcr_paddr;
11153c965775SBryan Venteicher 		txs->comp_ring_len = txq->vxtxq_comp_ring.vxcr_ndesc;
1116e3c97c2cSBryan Venteicher 		txs->driver_data = vtophys(txq);
1117e3c97c2cSBryan Venteicher 		txs->driver_data_len = sizeof(struct vmxnet3_txqueue);
1118e3c97c2cSBryan Venteicher 	}
1119e3c97c2cSBryan Venteicher 
1120e3c97c2cSBryan Venteicher 	/* Rx queues */
11218f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
1122e3c97c2cSBryan Venteicher 		rxq = &sc->vmx_rxq[i];
1123e3c97c2cSBryan Venteicher 		rxs = rxq->vxrxq_rs;
1124e3c97c2cSBryan Venteicher 
11258f82136aSPatrick Kelsey 		rxs->cmd_ring[0] = rxq->vxrxq_cmd_ring[0].vxrxr_paddr;
1126e3c97c2cSBryan Venteicher 		rxs->cmd_ring_len[0] = rxq->vxrxq_cmd_ring[0].vxrxr_ndesc;
11278f82136aSPatrick Kelsey 		rxs->cmd_ring[1] = rxq->vxrxq_cmd_ring[1].vxrxr_paddr;
1128e3c97c2cSBryan Venteicher 		rxs->cmd_ring_len[1] = rxq->vxrxq_cmd_ring[1].vxrxr_ndesc;
11298f82136aSPatrick Kelsey 		rxs->comp_ring = rxq->vxrxq_comp_ring.vxcr_paddr;
11303c965775SBryan Venteicher 		rxs->comp_ring_len = rxq->vxrxq_comp_ring.vxcr_ndesc;
1131e3c97c2cSBryan Venteicher 		rxs->driver_data = vtophys(rxq);
1132e3c97c2cSBryan Venteicher 		rxs->driver_data_len = sizeof(struct vmxnet3_rxqueue);
1133e3c97c2cSBryan Venteicher 	}
1134e3c97c2cSBryan Venteicher }
1135e3c97c2cSBryan Venteicher 
1136e3c97c2cSBryan Venteicher static void
1137e557c1ddSBryan Venteicher vmxnet3_reinit_rss_shared_data(struct vmxnet3_softc *sc)
1138e557c1ddSBryan Venteicher {
1139e557c1ddSBryan Venteicher 	/*
1140e557c1ddSBryan Venteicher 	 * Use the same key as the Linux driver until FreeBSD can do
1141e557c1ddSBryan Venteicher 	 * RSS (presumably Toeplitz) in software.
1142e557c1ddSBryan Venteicher 	 */
1143e557c1ddSBryan Venteicher 	static const uint8_t rss_key[UPT1_RSS_MAX_KEY_SIZE] = {
1144e557c1ddSBryan Venteicher 	    0x3b, 0x56, 0xd1, 0x56, 0x13, 0x4a, 0xe7, 0xac,
1145e557c1ddSBryan Venteicher 	    0xe8, 0x79, 0x09, 0x75, 0xe8, 0x65, 0x79, 0x28,
1146e557c1ddSBryan Venteicher 	    0x35, 0x12, 0xb9, 0x56, 0x7c, 0x76, 0x4b, 0x70,
1147e557c1ddSBryan Venteicher 	    0xd8, 0x56, 0xa3, 0x18, 0x9b, 0x0a, 0xee, 0xf3,
1148e557c1ddSBryan Venteicher 	    0x96, 0xa6, 0x9f, 0x8f, 0x9e, 0x8c, 0x90, 0xc9,
1149e557c1ddSBryan Venteicher 	};
1150e557c1ddSBryan Venteicher 
1151e557c1ddSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
11528f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
1153e557c1ddSBryan Venteicher 	struct vmxnet3_rss_shared *rss;
1154281cab4dSAndriy Gapon #ifdef RSS
1155281cab4dSAndriy Gapon 	uint8_t rss_algo;
1156281cab4dSAndriy Gapon #endif
1157e557c1ddSBryan Venteicher 	int i;
1158e557c1ddSBryan Venteicher 
1159e557c1ddSBryan Venteicher 	ds = sc->vmx_ds;
11608f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
1161e557c1ddSBryan Venteicher 	rss = sc->vmx_rss;
1162e557c1ddSBryan Venteicher 
1163e557c1ddSBryan Venteicher 	rss->hash_type =
1164e557c1ddSBryan Venteicher 	    UPT1_RSS_HASH_TYPE_IPV4 | UPT1_RSS_HASH_TYPE_TCP_IPV4 |
1165e557c1ddSBryan Venteicher 	    UPT1_RSS_HASH_TYPE_IPV6 | UPT1_RSS_HASH_TYPE_TCP_IPV6;
1166e557c1ddSBryan Venteicher 	rss->hash_func = UPT1_RSS_HASH_FUNC_TOEPLITZ;
1167e557c1ddSBryan Venteicher 	rss->hash_key_size = UPT1_RSS_MAX_KEY_SIZE;
1168e557c1ddSBryan Venteicher 	rss->ind_table_size = UPT1_RSS_MAX_IND_TABLE_SIZE;
1169281cab4dSAndriy Gapon #ifdef RSS
1170281cab4dSAndriy Gapon 	/*
1171281cab4dSAndriy Gapon 	 * If the software RSS is configured to anything else other than
1172281cab4dSAndriy Gapon 	 * Toeplitz, then just do Toeplitz in "hardware" for the sake of
1173281cab4dSAndriy Gapon 	 * the packet distribution, but report the hash as opaque to
1174281cab4dSAndriy Gapon 	 * disengage from the software RSS.
1175281cab4dSAndriy Gapon 	 */
1176281cab4dSAndriy Gapon 	rss_algo = rss_gethashalgo();
1177281cab4dSAndriy Gapon 	if (rss_algo == RSS_HASH_TOEPLITZ) {
1178281cab4dSAndriy Gapon 		rss_getkey(rss->hash_key);
1179281cab4dSAndriy Gapon 		for (i = 0; i < UPT1_RSS_MAX_IND_TABLE_SIZE; i++) {
1180281cab4dSAndriy Gapon 			rss->ind_table[i] = rss_get_indirection_to_bucket(i) %
1181281cab4dSAndriy Gapon 			    scctx->isc_nrxqsets;
1182281cab4dSAndriy Gapon 		}
1183281cab4dSAndriy Gapon 		sc->vmx_flags |= VMXNET3_FLAG_SOFT_RSS;
1184281cab4dSAndriy Gapon 	} else
1185281cab4dSAndriy Gapon #endif
1186281cab4dSAndriy Gapon 	{
1187e557c1ddSBryan Venteicher 		memcpy(rss->hash_key, rss_key, UPT1_RSS_MAX_KEY_SIZE);
1188e557c1ddSBryan Venteicher 		for (i = 0; i < UPT1_RSS_MAX_IND_TABLE_SIZE; i++)
11898f82136aSPatrick Kelsey 			rss->ind_table[i] = i % scctx->isc_nrxqsets;
1190281cab4dSAndriy Gapon 		sc->vmx_flags &= ~VMXNET3_FLAG_SOFT_RSS;
1191281cab4dSAndriy Gapon 	}
1192e3c97c2cSBryan Venteicher }
1193e3c97c2cSBryan Venteicher 
1194e3c97c2cSBryan Venteicher static void
1195e3c97c2cSBryan Venteicher vmxnet3_reinit_shared_data(struct vmxnet3_softc *sc)
1196e3c97c2cSBryan Venteicher {
1197e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
1198e3c97c2cSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
11998f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
1200e3c97c2cSBryan Venteicher 
1201e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
1202e3c97c2cSBryan Venteicher 	ds = sc->vmx_ds;
12038f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
1204e3c97c2cSBryan Venteicher 
1205e557c1ddSBryan Venteicher 	ds->mtu = ifp->if_mtu;
12068f82136aSPatrick Kelsey 	ds->ntxqueue = scctx->isc_ntxqsets;
12078f82136aSPatrick Kelsey 	ds->nrxqueue = scctx->isc_nrxqsets;
1208e557c1ddSBryan Venteicher 
1209e3c97c2cSBryan Venteicher 	ds->upt_features = 0;
1210e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6))
1211e3c97c2cSBryan Venteicher 		ds->upt_features |= UPT1_F_CSUM;
12123c5dfe89SBryan Venteicher 	if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
12133c5dfe89SBryan Venteicher 		ds->upt_features |= UPT1_F_VLAN;
1214e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & IFCAP_LRO)
1215e3c97c2cSBryan Venteicher 		ds->upt_features |= UPT1_F_LRO;
1216e3c97c2cSBryan Venteicher 
1217e557c1ddSBryan Venteicher 	if (sc->vmx_flags & VMXNET3_FLAG_RSS) {
1218e557c1ddSBryan Venteicher 		ds->upt_features |= UPT1_F_RSS;
1219e557c1ddSBryan Venteicher 		vmxnet3_reinit_rss_shared_data(sc);
1220e557c1ddSBryan Venteicher 	}
1221e3c97c2cSBryan Venteicher 
12228f82136aSPatrick Kelsey 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_DSL, sc->vmx_ds_dma.idi_paddr);
1223e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_DSH,
12248f82136aSPatrick Kelsey 	    (uint64_t) sc->vmx_ds_dma.idi_paddr >> 32);
1225e3c97c2cSBryan Venteicher }
1226e3c97c2cSBryan Venteicher 
1227e3c97c2cSBryan Venteicher static int
1228e3c97c2cSBryan Venteicher vmxnet3_alloc_data(struct vmxnet3_softc *sc)
1229e3c97c2cSBryan Venteicher {
1230e3c97c2cSBryan Venteicher 	int error;
1231e3c97c2cSBryan Venteicher 
1232e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_shared_data(sc);
1233e3c97c2cSBryan Venteicher 	if (error)
1234e3c97c2cSBryan Venteicher 		return (error);
1235e3c97c2cSBryan Venteicher 
1236e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_mcast_table(sc);
1237e3c97c2cSBryan Venteicher 	if (error)
1238e3c97c2cSBryan Venteicher 		return (error);
1239e3c97c2cSBryan Venteicher 
1240e3c97c2cSBryan Venteicher 	vmxnet3_init_shared_data(sc);
1241e3c97c2cSBryan Venteicher 
1242e3c97c2cSBryan Venteicher 	return (0);
1243e3c97c2cSBryan Venteicher }
1244e3c97c2cSBryan Venteicher 
1245e3c97c2cSBryan Venteicher static void
1246e3c97c2cSBryan Venteicher vmxnet3_free_data(struct vmxnet3_softc *sc)
1247e3c97c2cSBryan Venteicher {
1248e3c97c2cSBryan Venteicher 
1249e3c97c2cSBryan Venteicher 	vmxnet3_free_mcast_table(sc);
1250e3c97c2cSBryan Venteicher 	vmxnet3_free_shared_data(sc);
1251e3c97c2cSBryan Venteicher }
1252e3c97c2cSBryan Venteicher 
1253e3c97c2cSBryan Venteicher static void
1254e3c97c2cSBryan Venteicher vmxnet3_evintr(struct vmxnet3_softc *sc)
1255e3c97c2cSBryan Venteicher {
1256e3c97c2cSBryan Venteicher 	device_t dev;
1257e3c97c2cSBryan Venteicher 	struct vmxnet3_txq_shared *ts;
1258e3c97c2cSBryan Venteicher 	struct vmxnet3_rxq_shared *rs;
1259e3c97c2cSBryan Venteicher 	uint32_t event;
1260e3c97c2cSBryan Venteicher 
1261e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
1262e3c97c2cSBryan Venteicher 
1263e3c97c2cSBryan Venteicher 	/* Clear events. */
1264e3c97c2cSBryan Venteicher 	event = sc->vmx_ds->event;
1265e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_EVENT, event);
1266e3c97c2cSBryan Venteicher 
12678f82136aSPatrick Kelsey 	if (event & VMXNET3_EVENT_LINK)
1268e3c97c2cSBryan Venteicher 		vmxnet3_link_status(sc);
1269e3c97c2cSBryan Venteicher 
1270e3c97c2cSBryan Venteicher 	if (event & (VMXNET3_EVENT_TQERROR | VMXNET3_EVENT_RQERROR)) {
1271e3c97c2cSBryan Venteicher 		vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_STATUS);
1272e3c97c2cSBryan Venteicher 		ts = sc->vmx_txq[0].vxtxq_ts;
1273e3c97c2cSBryan Venteicher 		if (ts->stopped != 0)
1274e3c97c2cSBryan Venteicher 			device_printf(dev, "Tx queue error %#x\n", ts->error);
1275e3c97c2cSBryan Venteicher 		rs = sc->vmx_rxq[0].vxrxq_rs;
1276e3c97c2cSBryan Venteicher 		if (rs->stopped != 0)
1277e3c97c2cSBryan Venteicher 			device_printf(dev, "Rx queue error %#x\n", rs->error);
12788f82136aSPatrick Kelsey 
12798f82136aSPatrick Kelsey 		/* XXX - rely on liflib watchdog to reset us? */
12808f82136aSPatrick Kelsey 		device_printf(dev, "Rx/Tx queue error event ... "
12818f82136aSPatrick Kelsey 		    "waiting for iflib watchdog reset\n");
1282e3c97c2cSBryan Venteicher 	}
1283e3c97c2cSBryan Venteicher 
1284e3c97c2cSBryan Venteicher 	if (event & VMXNET3_EVENT_DIC)
1285e3c97c2cSBryan Venteicher 		device_printf(dev, "device implementation change event\n");
1286e3c97c2cSBryan Venteicher 	if (event & VMXNET3_EVENT_DEBUG)
1287e3c97c2cSBryan Venteicher 		device_printf(dev, "debug event\n");
1288e3c97c2cSBryan Venteicher }
1289e3c97c2cSBryan Venteicher 
12908f82136aSPatrick Kelsey static int
12918f82136aSPatrick Kelsey vmxnet3_isc_txd_encap(void *vsc, if_pkt_info_t pi)
12928f82136aSPatrick Kelsey {
12938f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
12948f82136aSPatrick Kelsey 	struct vmxnet3_txqueue *txq;
12958f82136aSPatrick Kelsey 	struct vmxnet3_txring *txr;
12968f82136aSPatrick Kelsey 	struct vmxnet3_txdesc *txd, *sop;
12978f82136aSPatrick Kelsey 	bus_dma_segment_t *segs;
12988f82136aSPatrick Kelsey 	int nsegs;
12998f82136aSPatrick Kelsey 	int pidx;
13008f82136aSPatrick Kelsey 	int hdrlen;
13018f82136aSPatrick Kelsey 	int i;
13028f82136aSPatrick Kelsey 	int gen;
13038f82136aSPatrick Kelsey 
13048f82136aSPatrick Kelsey 	sc = vsc;
13058f82136aSPatrick Kelsey 	txq = &sc->vmx_txq[pi->ipi_qsidx];
13068f82136aSPatrick Kelsey 	txr = &txq->vxtxq_cmd_ring;
13078f82136aSPatrick Kelsey 	segs = pi->ipi_segs;
13088f82136aSPatrick Kelsey 	nsegs = pi->ipi_nsegs;
13098f82136aSPatrick Kelsey 	pidx = pi->ipi_pidx;
13108f82136aSPatrick Kelsey 
13118f82136aSPatrick Kelsey 	KASSERT(nsegs <= VMXNET3_TX_MAXSEGS,
13128f82136aSPatrick Kelsey 	    ("%s: packet with too many segments %d", __func__, nsegs));
13138f82136aSPatrick Kelsey 
13148f82136aSPatrick Kelsey 	sop = &txr->vxtxr_txd[pidx];
13158f82136aSPatrick Kelsey 	gen = txr->vxtxr_gen ^ 1;	/* Owned by cpu (yet) */
13168f82136aSPatrick Kelsey 
13178f82136aSPatrick Kelsey 	for (i = 0; i < nsegs; i++) {
13188f82136aSPatrick Kelsey 		txd = &txr->vxtxr_txd[pidx];
13198f82136aSPatrick Kelsey 
13208f82136aSPatrick Kelsey 		txd->addr = segs[i].ds_addr;
13218f82136aSPatrick Kelsey 		txd->len = segs[i].ds_len;
13228f82136aSPatrick Kelsey 		txd->gen = gen;
13238f82136aSPatrick Kelsey 		txd->dtype = 0;
13248f82136aSPatrick Kelsey 		txd->offload_mode = VMXNET3_OM_NONE;
13258f82136aSPatrick Kelsey 		txd->offload_pos = 0;
13268f82136aSPatrick Kelsey 		txd->hlen = 0;
13278f82136aSPatrick Kelsey 		txd->eop = 0;
13288f82136aSPatrick Kelsey 		txd->compreq = 0;
13298f82136aSPatrick Kelsey 		txd->vtag_mode = 0;
13308f82136aSPatrick Kelsey 		txd->vtag = 0;
13318f82136aSPatrick Kelsey 
13328f82136aSPatrick Kelsey 		if (++pidx == txr->vxtxr_ndesc) {
13338f82136aSPatrick Kelsey 			pidx = 0;
13348f82136aSPatrick Kelsey 			txr->vxtxr_gen ^= 1;
13358f82136aSPatrick Kelsey 		}
13368f82136aSPatrick Kelsey 		gen = txr->vxtxr_gen;
13378f82136aSPatrick Kelsey 	}
13388f82136aSPatrick Kelsey 	txd->eop = 1;
13398f82136aSPatrick Kelsey 	txd->compreq = !!(pi->ipi_flags & IPI_TX_INTR);
13408f82136aSPatrick Kelsey 	pi->ipi_new_pidx = pidx;
13418f82136aSPatrick Kelsey 
13428f82136aSPatrick Kelsey 	/*
13438f82136aSPatrick Kelsey 	 * VLAN
13448f82136aSPatrick Kelsey 	 */
13458f82136aSPatrick Kelsey 	if (pi->ipi_mflags & M_VLANTAG) {
13468f82136aSPatrick Kelsey 		sop->vtag_mode = 1;
13478f82136aSPatrick Kelsey 		sop->vtag = pi->ipi_vtag;
13488f82136aSPatrick Kelsey 	}
13498f82136aSPatrick Kelsey 
13508f82136aSPatrick Kelsey 	/*
13518f82136aSPatrick Kelsey 	 * TSO and checksum offloads
13528f82136aSPatrick Kelsey 	 */
13538f82136aSPatrick Kelsey 	hdrlen = pi->ipi_ehdrlen + pi->ipi_ip_hlen;
13548f82136aSPatrick Kelsey 	if (pi->ipi_csum_flags & CSUM_TSO) {
13558f82136aSPatrick Kelsey 		sop->offload_mode = VMXNET3_OM_TSO;
1356f55f37d9SVincenzo Maffione 		sop->hlen = hdrlen + pi->ipi_tcp_hlen;
13578f82136aSPatrick Kelsey 		sop->offload_pos = pi->ipi_tso_segsz;
13588f82136aSPatrick Kelsey 	} else if (pi->ipi_csum_flags & (VMXNET3_CSUM_OFFLOAD |
13598f82136aSPatrick Kelsey 	    VMXNET3_CSUM_OFFLOAD_IPV6)) {
13608f82136aSPatrick Kelsey 		sop->offload_mode = VMXNET3_OM_CSUM;
13618f82136aSPatrick Kelsey 		sop->hlen = hdrlen;
13628f82136aSPatrick Kelsey 		sop->offload_pos = hdrlen +
13638f82136aSPatrick Kelsey 		    ((pi->ipi_ipproto == IPPROTO_TCP) ?
13648f82136aSPatrick Kelsey 			offsetof(struct tcphdr, th_sum) :
13658f82136aSPatrick Kelsey 			offsetof(struct udphdr, uh_sum));
13668f82136aSPatrick Kelsey 	}
13678f82136aSPatrick Kelsey 
13688f82136aSPatrick Kelsey 	/* Finally, change the ownership. */
13698f82136aSPatrick Kelsey 	vmxnet3_barrier(sc, VMXNET3_BARRIER_WR);
13708f82136aSPatrick Kelsey 	sop->gen ^= 1;
13718f82136aSPatrick Kelsey 
13728f82136aSPatrick Kelsey 	return (0);
1373e3c97c2cSBryan Venteicher }
1374e3c97c2cSBryan Venteicher 
1375e3c97c2cSBryan Venteicher static void
13768f82136aSPatrick Kelsey vmxnet3_isc_txd_flush(void *vsc, uint16_t txqid, qidx_t pidx)
1377e3c97c2cSBryan Venteicher {
1378e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
13798f82136aSPatrick Kelsey 	struct vmxnet3_txqueue *txq;
13808f82136aSPatrick Kelsey 
13818f82136aSPatrick Kelsey 	sc = vsc;
13828f82136aSPatrick Kelsey 	txq = &sc->vmx_txq[txqid];
13838f82136aSPatrick Kelsey 
13848f82136aSPatrick Kelsey 	/*
13858f82136aSPatrick Kelsey 	 * pidx is what we last set ipi_new_pidx to in
13868f82136aSPatrick Kelsey 	 * vmxnet3_isc_txd_encap()
13878f82136aSPatrick Kelsey 	 */
13888f82136aSPatrick Kelsey 
13898f82136aSPatrick Kelsey 	/*
13908f82136aSPatrick Kelsey 	 * Avoid expensive register updates if the flush request is
13918f82136aSPatrick Kelsey 	 * redundant.
13928f82136aSPatrick Kelsey 	 */
13938f82136aSPatrick Kelsey 	if (txq->vxtxq_last_flush == pidx)
13948f82136aSPatrick Kelsey 		return;
13958f82136aSPatrick Kelsey 	txq->vxtxq_last_flush = pidx;
13968f82136aSPatrick Kelsey 	vmxnet3_write_bar0(sc, VMXNET3_BAR0_TXH(txq->vxtxq_id), pidx);
13978f82136aSPatrick Kelsey }
13988f82136aSPatrick Kelsey 
13998f82136aSPatrick Kelsey static int
14008f82136aSPatrick Kelsey vmxnet3_isc_txd_credits_update(void *vsc, uint16_t txqid, bool clear)
14018f82136aSPatrick Kelsey {
14028f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
14038f82136aSPatrick Kelsey 	struct vmxnet3_txqueue *txq;
1404e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *txc;
1405e3c97c2cSBryan Venteicher 	struct vmxnet3_txcompdesc *txcd;
14068f82136aSPatrick Kelsey 	struct vmxnet3_txring *txr;
14078f82136aSPatrick Kelsey 	int processed;
1408e3c97c2cSBryan Venteicher 
14098f82136aSPatrick Kelsey 	sc = vsc;
14108f82136aSPatrick Kelsey 	txq = &sc->vmx_txq[txqid];
1411e3c97c2cSBryan Venteicher 	txc = &txq->vxtxq_comp_ring;
14128f82136aSPatrick Kelsey 	txr = &txq->vxtxq_cmd_ring;
1413e3c97c2cSBryan Venteicher 
14148f82136aSPatrick Kelsey 	/*
14158f82136aSPatrick Kelsey 	 * If clear is true, we need to report the number of TX command ring
14168f82136aSPatrick Kelsey 	 * descriptors that have been processed by the device.  If clear is
14178f82136aSPatrick Kelsey 	 * false, we just need to report whether or not at least one TX
14188f82136aSPatrick Kelsey 	 * command ring descriptor has been processed by the device.
14198f82136aSPatrick Kelsey 	 */
14208f82136aSPatrick Kelsey 	processed = 0;
1421e3c97c2cSBryan Venteicher 	for (;;) {
1422e3c97c2cSBryan Venteicher 		txcd = &txc->vxcr_u.txcd[txc->vxcr_next];
1423e3c97c2cSBryan Venteicher 		if (txcd->gen != txc->vxcr_gen)
1424e3c97c2cSBryan Venteicher 			break;
14258f82136aSPatrick Kelsey 		else if (!clear)
14268f82136aSPatrick Kelsey 			return (1);
14273c965775SBryan Venteicher 		vmxnet3_barrier(sc, VMXNET3_BARRIER_RD);
1428e3c97c2cSBryan Venteicher 
1429e3c97c2cSBryan Venteicher 		if (++txc->vxcr_next == txc->vxcr_ndesc) {
1430e3c97c2cSBryan Venteicher 			txc->vxcr_next = 0;
1431e3c97c2cSBryan Venteicher 			txc->vxcr_gen ^= 1;
1432e3c97c2cSBryan Venteicher 		}
1433e3c97c2cSBryan Venteicher 
14348f82136aSPatrick Kelsey 		if (txcd->eop_idx < txr->vxtxr_next)
14358f82136aSPatrick Kelsey 			processed += txr->vxtxr_ndesc -
14368f82136aSPatrick Kelsey 			    (txr->vxtxr_next - txcd->eop_idx) + 1;
14378f82136aSPatrick Kelsey 		else
14388f82136aSPatrick Kelsey 			processed += txcd->eop_idx - txr->vxtxr_next + 1;
1439e3c97c2cSBryan Venteicher 		txr->vxtxr_next = (txcd->eop_idx + 1) % txr->vxtxr_ndesc;
1440e3c97c2cSBryan Venteicher 	}
1441e3c97c2cSBryan Venteicher 
14428f82136aSPatrick Kelsey 	return (processed);
1443e3c97c2cSBryan Venteicher }
1444e3c97c2cSBryan Venteicher 
1445e3c97c2cSBryan Venteicher static int
14468f82136aSPatrick Kelsey vmxnet3_isc_rxd_available(void *vsc, uint16_t rxqid, qidx_t idx, qidx_t budget)
1447e3c97c2cSBryan Venteicher {
14488f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
14498f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
14508f82136aSPatrick Kelsey 	struct vmxnet3_comp_ring *rxc;
14518f82136aSPatrick Kelsey 	struct vmxnet3_rxcompdesc *rxcd;
14528f82136aSPatrick Kelsey 	int avail;
14538f82136aSPatrick Kelsey 	int completed_gen;
14548f82136aSPatrick Kelsey #ifdef INVARIANTS
14558f82136aSPatrick Kelsey 	int expect_sop = 1;
14568f82136aSPatrick Kelsey #endif
14578f82136aSPatrick Kelsey 	sc = vsc;
14588f82136aSPatrick Kelsey 	rxq = &sc->vmx_rxq[rxqid];
14598f82136aSPatrick Kelsey 	rxc = &rxq->vxrxq_comp_ring;
14608f82136aSPatrick Kelsey 
14618f82136aSPatrick Kelsey 	avail = 0;
14628f82136aSPatrick Kelsey 	completed_gen = rxc->vxcr_gen;
14638f82136aSPatrick Kelsey 	for (;;) {
14648f82136aSPatrick Kelsey 		rxcd = &rxc->vxcr_u.rxcd[idx];
14658f82136aSPatrick Kelsey 		if (rxcd->gen != completed_gen)
14668f82136aSPatrick Kelsey 			break;
14678f82136aSPatrick Kelsey 		vmxnet3_barrier(sc, VMXNET3_BARRIER_RD);
14688f82136aSPatrick Kelsey 
14698f82136aSPatrick Kelsey #ifdef INVARIANTS
14708f82136aSPatrick Kelsey 		if (expect_sop)
14718f82136aSPatrick Kelsey 			KASSERT(rxcd->sop, ("%s: expected sop", __func__));
14728f82136aSPatrick Kelsey 		else
14738f82136aSPatrick Kelsey 			KASSERT(!rxcd->sop, ("%s: unexpected sop", __func__));
14748f82136aSPatrick Kelsey 		expect_sop = rxcd->eop;
14758f82136aSPatrick Kelsey #endif
14768f82136aSPatrick Kelsey 		if (rxcd->eop && (rxcd->len != 0))
14778f82136aSPatrick Kelsey 			avail++;
14788f82136aSPatrick Kelsey 		if (avail > budget)
14798f82136aSPatrick Kelsey 			break;
14808f82136aSPatrick Kelsey 		if (++idx == rxc->vxcr_ndesc) {
14818f82136aSPatrick Kelsey 			idx = 0;
14828f82136aSPatrick Kelsey 			completed_gen ^= 1;
14838f82136aSPatrick Kelsey 		}
14848f82136aSPatrick Kelsey 	}
14858f82136aSPatrick Kelsey 
14868f82136aSPatrick Kelsey 	return (avail);
14878f82136aSPatrick Kelsey }
14888f82136aSPatrick Kelsey 
14898f82136aSPatrick Kelsey static int
14908f82136aSPatrick Kelsey vmxnet3_isc_rxd_pkt_get(void *vsc, if_rxd_info_t ri)
14918f82136aSPatrick Kelsey {
14928f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
14938f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
14948f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
14958f82136aSPatrick Kelsey 	struct vmxnet3_comp_ring *rxc;
14968f82136aSPatrick Kelsey 	struct vmxnet3_rxcompdesc *rxcd;
14978f82136aSPatrick Kelsey 	struct vmxnet3_rxring *rxr;
1498e3c97c2cSBryan Venteicher 	struct vmxnet3_rxdesc *rxd;
14998f82136aSPatrick Kelsey 	if_rxd_frag_t frag;
15008f82136aSPatrick Kelsey 	int cqidx;
15018f82136aSPatrick Kelsey 	uint16_t total_len;
15028f82136aSPatrick Kelsey 	uint8_t nfrags;
1503f50375eeSPatrick Kelsey 	uint8_t i;
15048f82136aSPatrick Kelsey 	uint8_t flid;
1505e3c97c2cSBryan Venteicher 
15068f82136aSPatrick Kelsey 	sc = vsc;
15078f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
15088f82136aSPatrick Kelsey 	rxq = &sc->vmx_rxq[ri->iri_qsidx];
15098f82136aSPatrick Kelsey 	rxc = &rxq->vxrxq_comp_ring;
1510e3c97c2cSBryan Venteicher 
1511e3c97c2cSBryan Venteicher 	/*
15128f82136aSPatrick Kelsey 	 * Get a single packet starting at the given index in the completion
15138f82136aSPatrick Kelsey 	 * queue.  That we have been called indicates that
15148f82136aSPatrick Kelsey 	 * vmxnet3_isc_rxd_available() has already verified that either
15158f82136aSPatrick Kelsey 	 * there is a complete packet available starting at the given index,
15168f82136aSPatrick Kelsey 	 * or there are one or more zero length packets starting at the
15178f82136aSPatrick Kelsey 	 * given index followed by a complete packet, so no verification of
15188f82136aSPatrick Kelsey 	 * ownership of the descriptors (and no associated read barrier) is
15198f82136aSPatrick Kelsey 	 * required here.
1520e3c97c2cSBryan Venteicher 	 */
15218f82136aSPatrick Kelsey 	cqidx = ri->iri_cidx;
15228f82136aSPatrick Kelsey 	rxcd = &rxc->vxcr_u.rxcd[cqidx];
15238f82136aSPatrick Kelsey 	while (rxcd->len == 0) {
15248f82136aSPatrick Kelsey 		KASSERT(rxcd->sop && rxcd->eop,
15258f82136aSPatrick Kelsey 		    ("%s: zero-length packet without both sop and eop set",
15268f82136aSPatrick Kelsey 			__func__));
1527f50375eeSPatrick Kelsey 		rxc->vxcr_zero_length++;
15288f82136aSPatrick Kelsey 		if (++cqidx == rxc->vxcr_ndesc) {
15298f82136aSPatrick Kelsey 			cqidx = 0;
15308f82136aSPatrick Kelsey 			rxc->vxcr_gen ^= 1;
15318f82136aSPatrick Kelsey 		}
15328f82136aSPatrick Kelsey 		rxcd = &rxc->vxcr_u.rxcd[cqidx];
15338f82136aSPatrick Kelsey 	}
15348f82136aSPatrick Kelsey 	KASSERT(rxcd->sop, ("%s: expected sop", __func__));
15358f82136aSPatrick Kelsey 
15368f82136aSPatrick Kelsey 	/*
1537281cab4dSAndriy Gapon 	 * RSS and flow ID.
1538281cab4dSAndriy Gapon 	 * Types other than M_HASHTYPE_NONE and M_HASHTYPE_OPAQUE_HASH should
1539281cab4dSAndriy Gapon 	 * be used only if the software RSS is enabled and it uses the same
1540281cab4dSAndriy Gapon 	 * algorithm and the hash key as the "hardware".  If the software RSS
1541281cab4dSAndriy Gapon 	 * is not enabled, then it's simply pointless to use those types.
1542281cab4dSAndriy Gapon 	 * If it's enabled but with different parameters, then hash values will
1543281cab4dSAndriy Gapon 	 * not match.
15448f82136aSPatrick Kelsey 	 */
15458f82136aSPatrick Kelsey 	ri->iri_flowid = rxcd->rss_hash;
1546281cab4dSAndriy Gapon #ifdef RSS
1547281cab4dSAndriy Gapon 	if ((sc->vmx_flags & VMXNET3_FLAG_SOFT_RSS) != 0) {
15488f82136aSPatrick Kelsey 		switch (rxcd->rss_type) {
15498f82136aSPatrick Kelsey 		case VMXNET3_RCD_RSS_TYPE_NONE:
15508f82136aSPatrick Kelsey 			ri->iri_flowid = ri->iri_qsidx;
15518f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_NONE;
15528f82136aSPatrick Kelsey 			break;
15538f82136aSPatrick Kelsey 		case VMXNET3_RCD_RSS_TYPE_IPV4:
15548f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_RSS_IPV4;
15558f82136aSPatrick Kelsey 			break;
15568f82136aSPatrick Kelsey 		case VMXNET3_RCD_RSS_TYPE_TCPIPV4:
15578f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_RSS_TCP_IPV4;
15588f82136aSPatrick Kelsey 			break;
15598f82136aSPatrick Kelsey 		case VMXNET3_RCD_RSS_TYPE_IPV6:
15608f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_RSS_IPV6;
15618f82136aSPatrick Kelsey 			break;
15628f82136aSPatrick Kelsey 		case VMXNET3_RCD_RSS_TYPE_TCPIPV6:
15638f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_RSS_TCP_IPV6;
15648f82136aSPatrick Kelsey 			break;
15658f82136aSPatrick Kelsey 		default:
15668f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_OPAQUE_HASH;
15678f82136aSPatrick Kelsey 			break;
1568e3c97c2cSBryan Venteicher 		}
1569281cab4dSAndriy Gapon 	} else
1570281cab4dSAndriy Gapon #endif
1571281cab4dSAndriy Gapon 	{
1572281cab4dSAndriy Gapon 		switch (rxcd->rss_type) {
1573281cab4dSAndriy Gapon 		case VMXNET3_RCD_RSS_TYPE_NONE:
1574281cab4dSAndriy Gapon 			ri->iri_flowid = ri->iri_qsidx;
1575281cab4dSAndriy Gapon 			ri->iri_rsstype = M_HASHTYPE_NONE;
1576281cab4dSAndriy Gapon 			break;
1577281cab4dSAndriy Gapon 		default:
1578281cab4dSAndriy Gapon 			ri->iri_rsstype = M_HASHTYPE_OPAQUE_HASH;
1579281cab4dSAndriy Gapon 			break;
1580281cab4dSAndriy Gapon 		}
1581281cab4dSAndriy Gapon 	}
1582e3c97c2cSBryan Venteicher 
15838f82136aSPatrick Kelsey 	/*
15848f82136aSPatrick Kelsey 	 * The queue numbering scheme used for rxcd->qid is as follows:
15858f82136aSPatrick Kelsey 	 *  - All of the command ring 0s are numbered [0, nrxqsets - 1]
15868f82136aSPatrick Kelsey 	 *  - All of the command ring 1s are numbered [nrxqsets, 2*nrxqsets - 1]
15878f82136aSPatrick Kelsey 	 *
15888f82136aSPatrick Kelsey 	 * Thus, rxcd->qid less than nrxqsets indicates command ring (and
15898f82136aSPatrick Kelsey 	 * flid) 0, and rxcd->qid greater than or equal to nrxqsets
15908f82136aSPatrick Kelsey 	 * indicates command ring (and flid) 1.
15918f82136aSPatrick Kelsey 	 */
15928f82136aSPatrick Kelsey 	nfrags = 0;
15938f82136aSPatrick Kelsey 	total_len = 0;
15948f82136aSPatrick Kelsey 	do {
15958f82136aSPatrick Kelsey 		rxcd = &rxc->vxcr_u.rxcd[cqidx];
15968f82136aSPatrick Kelsey 		KASSERT(rxcd->gen == rxc->vxcr_gen,
15978f82136aSPatrick Kelsey 		    ("%s: generation mismatch", __func__));
15988f82136aSPatrick Kelsey 		flid = (rxcd->qid >= scctx->isc_nrxqsets) ? 1 : 0;
15998f82136aSPatrick Kelsey 		rxr = &rxq->vxrxq_cmd_ring[flid];
16008f82136aSPatrick Kelsey 		rxd = &rxr->vxrxr_rxd[rxcd->rxd_idx];
1601e3c97c2cSBryan Venteicher 
16028f82136aSPatrick Kelsey 		frag = &ri->iri_frags[nfrags];
16038f82136aSPatrick Kelsey 		frag->irf_flid = flid;
16048f82136aSPatrick Kelsey 		frag->irf_idx = rxcd->rxd_idx;
16058f82136aSPatrick Kelsey 		frag->irf_len = rxcd->len;
16068f82136aSPatrick Kelsey 		total_len += rxcd->len;
16078f82136aSPatrick Kelsey 		nfrags++;
16088f82136aSPatrick Kelsey 		if (++cqidx == rxc->vxcr_ndesc) {
16098f82136aSPatrick Kelsey 			cqidx = 0;
16108f82136aSPatrick Kelsey 			rxc->vxcr_gen ^= 1;
16118f82136aSPatrick Kelsey 		}
16128f82136aSPatrick Kelsey 	} while (!rxcd->eop);
1613e3c97c2cSBryan Venteicher 
16148f82136aSPatrick Kelsey 	ri->iri_cidx = cqidx;
16158f82136aSPatrick Kelsey 	ri->iri_nfrags = nfrags;
16168f82136aSPatrick Kelsey 	ri->iri_len = total_len;
16178f82136aSPatrick Kelsey 
1618f50375eeSPatrick Kelsey 	/*
1619f50375eeSPatrick Kelsey 	 * If there's an error, the last descriptor in the packet will
1620f50375eeSPatrick Kelsey 	 * have the error indicator set.  In this case, set all
1621f50375eeSPatrick Kelsey 	 * fragment lengths to zero.  This will cause iflib to discard
1622f50375eeSPatrick Kelsey 	 * the packet, but process all associated descriptors through
1623f50375eeSPatrick Kelsey 	 * the refill mechanism.
1624f50375eeSPatrick Kelsey 	 */
1625f50375eeSPatrick Kelsey 	if (__predict_false(rxcd->error)) {
1626f50375eeSPatrick Kelsey 		rxc->vxcr_pkt_errors++;
1627f50375eeSPatrick Kelsey 		for (i = 0; i < nfrags; i++) {
1628f50375eeSPatrick Kelsey 			frag = &ri->iri_frags[i];
1629f50375eeSPatrick Kelsey 			frag->irf_len = 0;
1630f50375eeSPatrick Kelsey 		}
1631f50375eeSPatrick Kelsey 	} else {
1632f50375eeSPatrick Kelsey 		/* Checksum offload information is in the last descriptor. */
1633f50375eeSPatrick Kelsey 		if (!rxcd->no_csum) {
1634f50375eeSPatrick Kelsey 			uint32_t csum_flags = 0;
1635f50375eeSPatrick Kelsey 
1636f50375eeSPatrick Kelsey 			if (rxcd->ipv4) {
1637f50375eeSPatrick Kelsey 				csum_flags |= CSUM_IP_CHECKED;
1638f50375eeSPatrick Kelsey 				if (rxcd->ipcsum_ok)
1639f50375eeSPatrick Kelsey 					csum_flags |= CSUM_IP_VALID;
1640f50375eeSPatrick Kelsey 			}
1641f50375eeSPatrick Kelsey 			if (!rxcd->fragment && (rxcd->tcp || rxcd->udp)) {
1642f50375eeSPatrick Kelsey 				csum_flags |= CSUM_L4_CALC;
1643f50375eeSPatrick Kelsey 				if (rxcd->csum_ok) {
1644f50375eeSPatrick Kelsey 					csum_flags |= CSUM_L4_VALID;
1645f50375eeSPatrick Kelsey 					ri->iri_csum_data = 0xffff;
1646f50375eeSPatrick Kelsey 				}
1647f50375eeSPatrick Kelsey 			}
1648f50375eeSPatrick Kelsey 			ri->iri_csum_flags = csum_flags;
1649f50375eeSPatrick Kelsey 		}
1650f50375eeSPatrick Kelsey 
1651f50375eeSPatrick Kelsey 		/* VLAN information is in the last descriptor. */
1652f50375eeSPatrick Kelsey 		if (rxcd->vlan) {
1653f50375eeSPatrick Kelsey 			ri->iri_flags |= M_VLANTAG;
1654f50375eeSPatrick Kelsey 			ri->iri_vtag = rxcd->vtag;
1655f50375eeSPatrick Kelsey 		}
1656f50375eeSPatrick Kelsey 	}
1657f50375eeSPatrick Kelsey 
1658e3c97c2cSBryan Venteicher 	return (0);
1659e3c97c2cSBryan Venteicher }
1660e3c97c2cSBryan Venteicher 
1661e3c97c2cSBryan Venteicher static void
16628f82136aSPatrick Kelsey vmxnet3_isc_rxd_refill(void *vsc, if_rxd_update_t iru)
1663e3c97c2cSBryan Venteicher {
1664e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
16658f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
1666e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
1667e3c97c2cSBryan Venteicher 	struct vmxnet3_rxdesc *rxd;
16688f82136aSPatrick Kelsey 	uint64_t *paddrs;
16698f82136aSPatrick Kelsey 	int count;
16708f82136aSPatrick Kelsey 	int len;
1671f50375eeSPatrick Kelsey 	int idx;
16728f82136aSPatrick Kelsey 	int i;
16738f82136aSPatrick Kelsey 	uint8_t flid;
16748f82136aSPatrick Kelsey 	uint8_t btype;
1675e3c97c2cSBryan Venteicher 
16768f82136aSPatrick Kelsey 	count = iru->iru_count;
16778f82136aSPatrick Kelsey 	len = iru->iru_buf_size;
16788f82136aSPatrick Kelsey 	flid = iru->iru_flidx;
16798f82136aSPatrick Kelsey 	paddrs = iru->iru_paddrs;
1680e3c97c2cSBryan Venteicher 
16818f82136aSPatrick Kelsey 	sc = vsc;
16828f82136aSPatrick Kelsey 	rxq = &sc->vmx_rxq[iru->iru_qsidx];
16838f82136aSPatrick Kelsey 	rxr = &rxq->vxrxq_cmd_ring[flid];
16848f82136aSPatrick Kelsey 	rxd = rxr->vxrxr_rxd;
1685e3c97c2cSBryan Venteicher 
1686e3c97c2cSBryan Venteicher 	/*
16878f82136aSPatrick Kelsey 	 * Command ring 0 is filled with BTYPE_HEAD descriptors, and
16888f82136aSPatrick Kelsey 	 * command ring 1 is filled with BTYPE_BODY descriptors.
1689e3c97c2cSBryan Venteicher 	 */
16908f82136aSPatrick Kelsey 	btype = (flid == 0) ? VMXNET3_BTYPE_HEAD : VMXNET3_BTYPE_BODY;
1691f50375eeSPatrick Kelsey 	/*
1692f50375eeSPatrick Kelsey 	 * The refill entries from iflib will advance monotonically,
1693f50375eeSPatrick Kelsey 	 * but the refilled descriptors may not be contiguous due to
1694f50375eeSPatrick Kelsey 	 * earlier skipping of descriptors by the device.  The refill
1695f50375eeSPatrick Kelsey 	 * entries from iflib need an entire state update, while the
1696f50375eeSPatrick Kelsey 	 * descriptors previously skipped by the device only need to
1697f50375eeSPatrick Kelsey 	 * have their generation numbers updated.
1698f50375eeSPatrick Kelsey 	 */
1699f50375eeSPatrick Kelsey 	idx = rxr->vxrxr_refill_start;
1700f50375eeSPatrick Kelsey 	i = 0;
1701f50375eeSPatrick Kelsey 	do {
1702f50375eeSPatrick Kelsey 		if (idx == iru->iru_idxs[i]) {
1703f50375eeSPatrick Kelsey 			rxd[idx].addr = paddrs[i];
1704f50375eeSPatrick Kelsey 			rxd[idx].len = len;
1705f50375eeSPatrick Kelsey 			rxd[idx].btype = btype;
1706f50375eeSPatrick Kelsey 			i++;
1707f50375eeSPatrick Kelsey 		} else
1708f50375eeSPatrick Kelsey 			rxr->vxrxr_desc_skips++;
1709f50375eeSPatrick Kelsey 		rxd[idx].gen = rxr->vxrxr_gen;
17108f82136aSPatrick Kelsey 
1711f50375eeSPatrick Kelsey 		if (++idx == rxr->vxrxr_ndesc) {
1712f50375eeSPatrick Kelsey 			idx = 0;
17138f82136aSPatrick Kelsey 			rxr->vxrxr_gen ^= 1;
17148f82136aSPatrick Kelsey 		}
1715f50375eeSPatrick Kelsey 	} while (i != count);
1716f50375eeSPatrick Kelsey 	rxr->vxrxr_refill_start = idx;
1717e3c97c2cSBryan Venteicher }
1718e3c97c2cSBryan Venteicher 
17198f82136aSPatrick Kelsey static void
17208f82136aSPatrick Kelsey vmxnet3_isc_rxd_flush(void *vsc, uint16_t rxqid, uint8_t flid, qidx_t pidx)
17218f82136aSPatrick Kelsey {
17228f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
17238f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
17248f82136aSPatrick Kelsey 	struct vmxnet3_rxring *rxr;
1725e3c97c2cSBryan Venteicher 	bus_size_t r;
1726e3c97c2cSBryan Venteicher 
17278f82136aSPatrick Kelsey 	sc = vsc;
17288f82136aSPatrick Kelsey 	rxq = &sc->vmx_rxq[rxqid];
17298f82136aSPatrick Kelsey 	rxr = &rxq->vxrxq_cmd_ring[flid];
17308f82136aSPatrick Kelsey 
17318f82136aSPatrick Kelsey 	if (flid == 0)
17328f82136aSPatrick Kelsey 		r = VMXNET3_BAR0_RXH1(rxqid);
17338f82136aSPatrick Kelsey 	else
17348f82136aSPatrick Kelsey 		r = VMXNET3_BAR0_RXH2(rxqid);
17358f82136aSPatrick Kelsey 
17368f82136aSPatrick Kelsey 	/*
17378f82136aSPatrick Kelsey 	 * pidx is the index of the last descriptor with a buffer the device
17388f82136aSPatrick Kelsey 	 * can use, and the device needs to be told which index is one past
17398f82136aSPatrick Kelsey 	 * that.
17408f82136aSPatrick Kelsey 	 */
17418f82136aSPatrick Kelsey 	if (++pidx == rxr->vxrxr_ndesc)
17428f82136aSPatrick Kelsey 		pidx = 0;
17438f82136aSPatrick Kelsey 	vmxnet3_write_bar0(sc, r, pidx);
1744e3c97c2cSBryan Venteicher }
1745e3c97c2cSBryan Venteicher 
17468f82136aSPatrick Kelsey static int
1747e3c97c2cSBryan Venteicher vmxnet3_legacy_intr(void *xsc)
1748e3c97c2cSBryan Venteicher {
1749e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
17508f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
17518f82136aSPatrick Kelsey 	if_ctx_t ctx;
1752e3c97c2cSBryan Venteicher 
1753e3c97c2cSBryan Venteicher 	sc = xsc;
17548f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
17558f82136aSPatrick Kelsey 	ctx = sc->vmx_ctx;
1756e3c97c2cSBryan Venteicher 
17578f82136aSPatrick Kelsey 	/*
17588f82136aSPatrick Kelsey 	 * When there is only a single interrupt configured, this routine
17598f82136aSPatrick Kelsey 	 * runs in fast interrupt context, following which the rxq 0 task
17608f82136aSPatrick Kelsey 	 * will be enqueued.
17618f82136aSPatrick Kelsey 	 */
17628f82136aSPatrick Kelsey 	if (scctx->isc_intr == IFLIB_INTR_LEGACY) {
1763e3c97c2cSBryan Venteicher 		if (vmxnet3_read_bar1(sc, VMXNET3_BAR1_INTR) == 0)
17648f82136aSPatrick Kelsey 			return (FILTER_HANDLED);
1765e3c97c2cSBryan Venteicher 	}
1766e3c97c2cSBryan Venteicher 	if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE)
17678f82136aSPatrick Kelsey 		vmxnet3_intr_disable_all(ctx);
1768e3c97c2cSBryan Venteicher 
1769e3c97c2cSBryan Venteicher 	if (sc->vmx_ds->event != 0)
17708f82136aSPatrick Kelsey 		iflib_admin_intr_deferred(ctx);
1771e3c97c2cSBryan Venteicher 
17728f82136aSPatrick Kelsey 	/*
17738f82136aSPatrick Kelsey 	 * XXX - When there is both rxq and event activity, do we care
17748f82136aSPatrick Kelsey 	 * whether the rxq 0 task or the admin task re-enables the interrupt
17758f82136aSPatrick Kelsey 	 * first?
17768f82136aSPatrick Kelsey 	 */
17778f82136aSPatrick Kelsey 	return (FILTER_SCHEDULE_THREAD);
1778e3c97c2cSBryan Venteicher }
1779e3c97c2cSBryan Venteicher 
17808f82136aSPatrick Kelsey static int
17818f82136aSPatrick Kelsey vmxnet3_rxq_intr(void *vrxq)
1782e3c97c2cSBryan Venteicher {
1783e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
1784e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
1785e3c97c2cSBryan Venteicher 
17868f82136aSPatrick Kelsey 	rxq = vrxq;
1787e3c97c2cSBryan Venteicher 	sc = rxq->vxrxq_sc;
1788e3c97c2cSBryan Venteicher 
1789e3c97c2cSBryan Venteicher 	if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE)
1790e3c97c2cSBryan Venteicher 		vmxnet3_disable_intr(sc, rxq->vxrxq_intr_idx);
1791e3c97c2cSBryan Venteicher 
17928f82136aSPatrick Kelsey 	return (FILTER_SCHEDULE_THREAD);
1793e3c97c2cSBryan Venteicher }
1794e3c97c2cSBryan Venteicher 
17958f82136aSPatrick Kelsey static int
17968f82136aSPatrick Kelsey vmxnet3_event_intr(void *vsc)
1797e3c97c2cSBryan Venteicher {
1798e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
1799e3c97c2cSBryan Venteicher 
18008f82136aSPatrick Kelsey 	sc = vsc;
1801e3c97c2cSBryan Venteicher 
1802e3c97c2cSBryan Venteicher 	if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE)
1803e3c97c2cSBryan Venteicher 		vmxnet3_disable_intr(sc, sc->vmx_event_intr_idx);
1804e3c97c2cSBryan Venteicher 
18058f82136aSPatrick Kelsey 	/*
18068f82136aSPatrick Kelsey 	 * The work will be done via vmxnet3_update_admin_status(), and the
18078f82136aSPatrick Kelsey 	 * interrupt will be re-enabled in vmxnet3_link_intr_enable().
18088f82136aSPatrick Kelsey 	 *
18098f82136aSPatrick Kelsey 	 * The interrupt will be re-enabled by vmxnet3_link_intr_enable().
18108f82136aSPatrick Kelsey 	 */
18118f82136aSPatrick Kelsey 	return (FILTER_SCHEDULE_THREAD);
1812e3c97c2cSBryan Venteicher }
1813e3c97c2cSBryan Venteicher 
1814e3c97c2cSBryan Venteicher static void
18158f82136aSPatrick Kelsey vmxnet3_stop(if_ctx_t ctx)
1816e3c97c2cSBryan Venteicher {
18178f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
1818e3c97c2cSBryan Venteicher 
18198f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
1820e3c97c2cSBryan Venteicher 
1821e3c97c2cSBryan Venteicher 	sc->vmx_link_active = 0;
1822e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_DISABLE);
1823e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_RESET);
1824e3c97c2cSBryan Venteicher }
1825e3c97c2cSBryan Venteicher 
1826e3c97c2cSBryan Venteicher static void
1827e3c97c2cSBryan Venteicher vmxnet3_txinit(struct vmxnet3_softc *sc, struct vmxnet3_txqueue *txq)
1828e3c97c2cSBryan Venteicher {
1829e3c97c2cSBryan Venteicher 	struct vmxnet3_txring *txr;
1830e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *txc;
1831e3c97c2cSBryan Venteicher 
18328f82136aSPatrick Kelsey 	txq->vxtxq_last_flush = -1;
18338f82136aSPatrick Kelsey 
1834e3c97c2cSBryan Venteicher 	txr = &txq->vxtxq_cmd_ring;
1835e3c97c2cSBryan Venteicher 	txr->vxtxr_next = 0;
1836e3c97c2cSBryan Venteicher 	txr->vxtxr_gen = VMXNET3_INIT_GEN;
18378f82136aSPatrick Kelsey 	/*
18388f82136aSPatrick Kelsey 	 * iflib has zeroed out the descriptor array during the prior attach
18398f82136aSPatrick Kelsey 	 * or stop
18408f82136aSPatrick Kelsey 	 */
1841e3c97c2cSBryan Venteicher 
1842e3c97c2cSBryan Venteicher 	txc = &txq->vxtxq_comp_ring;
1843e3c97c2cSBryan Venteicher 	txc->vxcr_next = 0;
1844e3c97c2cSBryan Venteicher 	txc->vxcr_gen = VMXNET3_INIT_GEN;
18458f82136aSPatrick Kelsey 	/*
18468f82136aSPatrick Kelsey 	 * iflib has zeroed out the descriptor array during the prior attach
18478f82136aSPatrick Kelsey 	 * or stop
18488f82136aSPatrick Kelsey 	 */
1849e3c97c2cSBryan Venteicher }
1850e3c97c2cSBryan Venteicher 
18518f82136aSPatrick Kelsey static void
1852e3c97c2cSBryan Venteicher vmxnet3_rxinit(struct vmxnet3_softc *sc, struct vmxnet3_rxqueue *rxq)
1853e3c97c2cSBryan Venteicher {
1854e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
1855e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *rxc;
18568f82136aSPatrick Kelsey 	int i;
1857e3c97c2cSBryan Venteicher 
1858e3c97c2cSBryan Venteicher 	/*
18598f82136aSPatrick Kelsey 	 * The descriptors will be populated with buffers during a
18608f82136aSPatrick Kelsey 	 * subsequent invocation of vmxnet3_isc_rxd_refill()
1861e3c97c2cSBryan Venteicher 	 */
18628f82136aSPatrick Kelsey 	for (i = 0; i < sc->vmx_sctx->isc_nrxqs - 1; i++) {
1863e3c97c2cSBryan Venteicher 		rxr = &rxq->vxrxq_cmd_ring[i];
1864e3c97c2cSBryan Venteicher 		rxr->vxrxr_gen = VMXNET3_INIT_GEN;
1865f50375eeSPatrick Kelsey 		rxr->vxrxr_desc_skips = 0;
1866f50375eeSPatrick Kelsey 		rxr->vxrxr_refill_start = 0;
18678f82136aSPatrick Kelsey 		/*
18688f82136aSPatrick Kelsey 		 * iflib has zeroed out the descriptor array during the
18698f82136aSPatrick Kelsey 		 * prior attach or stop
18708f82136aSPatrick Kelsey 		 */
1871e3c97c2cSBryan Venteicher 	}
1872e3c97c2cSBryan Venteicher 
1873e3c97c2cSBryan Venteicher 	for (/**/; i < VMXNET3_RXRINGS_PERQ; i++) {
1874e3c97c2cSBryan Venteicher 		rxr = &rxq->vxrxq_cmd_ring[i];
1875e3c97c2cSBryan Venteicher 		rxr->vxrxr_gen = 0;
1876f50375eeSPatrick Kelsey 		rxr->vxrxr_desc_skips = 0;
1877f50375eeSPatrick Kelsey 		rxr->vxrxr_refill_start = 0;
1878e3c97c2cSBryan Venteicher 		bzero(rxr->vxrxr_rxd,
1879e3c97c2cSBryan Venteicher 		    rxr->vxrxr_ndesc * sizeof(struct vmxnet3_rxdesc));
1880e3c97c2cSBryan Venteicher 	}
1881e3c97c2cSBryan Venteicher 
1882e3c97c2cSBryan Venteicher 	rxc = &rxq->vxrxq_comp_ring;
1883e3c97c2cSBryan Venteicher 	rxc->vxcr_next = 0;
1884e3c97c2cSBryan Venteicher 	rxc->vxcr_gen = VMXNET3_INIT_GEN;
1885f50375eeSPatrick Kelsey 	rxc->vxcr_zero_length = 0;
1886f50375eeSPatrick Kelsey 	rxc->vxcr_pkt_errors = 0;
18878f82136aSPatrick Kelsey 	/*
18888f82136aSPatrick Kelsey 	 * iflib has zeroed out the descriptor array during the prior attach
18898f82136aSPatrick Kelsey 	 * or stop
18908f82136aSPatrick Kelsey 	 */
1891e3c97c2cSBryan Venteicher }
1892e3c97c2cSBryan Venteicher 
18938f82136aSPatrick Kelsey static void
1894e3c97c2cSBryan Venteicher vmxnet3_reinit_queues(struct vmxnet3_softc *sc)
1895e3c97c2cSBryan Venteicher {
18968f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
18978f82136aSPatrick Kelsey 	int q;
1898e3c97c2cSBryan Venteicher 
18998f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
1900e3c97c2cSBryan Venteicher 
19018f82136aSPatrick Kelsey 	for (q = 0; q < scctx->isc_ntxqsets; q++)
1902e3c97c2cSBryan Venteicher 		vmxnet3_txinit(sc, &sc->vmx_txq[q]);
1903e3c97c2cSBryan Venteicher 
19048f82136aSPatrick Kelsey 	for (q = 0; q < scctx->isc_nrxqsets; q++)
19058f82136aSPatrick Kelsey 		vmxnet3_rxinit(sc, &sc->vmx_rxq[q]);
1906e3c97c2cSBryan Venteicher }
1907e3c97c2cSBryan Venteicher 
1908e3c97c2cSBryan Venteicher static int
1909e3c97c2cSBryan Venteicher vmxnet3_enable_device(struct vmxnet3_softc *sc)
1910e3c97c2cSBryan Venteicher {
19118f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
1912e3c97c2cSBryan Venteicher 	int q;
1913e3c97c2cSBryan Venteicher 
19148f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
19158f82136aSPatrick Kelsey 
1916e3c97c2cSBryan Venteicher 	if (vmxnet3_read_cmd(sc, VMXNET3_CMD_ENABLE) != 0) {
1917e3c97c2cSBryan Venteicher 		device_printf(sc->vmx_dev, "device enable command failed!\n");
1918e3c97c2cSBryan Venteicher 		return (1);
1919e3c97c2cSBryan Venteicher 	}
1920e3c97c2cSBryan Venteicher 
1921e3c97c2cSBryan Venteicher 	/* Reset the Rx queue heads. */
19228f82136aSPatrick Kelsey 	for (q = 0; q < scctx->isc_nrxqsets; q++) {
1923e3c97c2cSBryan Venteicher 		vmxnet3_write_bar0(sc, VMXNET3_BAR0_RXH1(q), 0);
1924e3c97c2cSBryan Venteicher 		vmxnet3_write_bar0(sc, VMXNET3_BAR0_RXH2(q), 0);
1925e3c97c2cSBryan Venteicher 	}
1926e3c97c2cSBryan Venteicher 
1927e3c97c2cSBryan Venteicher 	return (0);
1928e3c97c2cSBryan Venteicher }
1929e3c97c2cSBryan Venteicher 
1930e3c97c2cSBryan Venteicher static void
1931e3c97c2cSBryan Venteicher vmxnet3_reinit_rxfilters(struct vmxnet3_softc *sc)
1932e3c97c2cSBryan Venteicher {
1933e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
1934e3c97c2cSBryan Venteicher 
1935e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
1936e3c97c2cSBryan Venteicher 
19378f82136aSPatrick Kelsey 	vmxnet3_set_rxfilter(sc, if_getflags(ifp));
1938e3c97c2cSBryan Venteicher 
1939e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & IFCAP_VLAN_HWFILTER)
1940e3c97c2cSBryan Venteicher 		bcopy(sc->vmx_vlan_filter, sc->vmx_ds->vlan_filter,
1941e3c97c2cSBryan Venteicher 		    sizeof(sc->vmx_ds->vlan_filter));
1942e3c97c2cSBryan Venteicher 	else
1943e3c97c2cSBryan Venteicher 		bzero(sc->vmx_ds->vlan_filter,
1944e3c97c2cSBryan Venteicher 		    sizeof(sc->vmx_ds->vlan_filter));
1945e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_VLAN_FILTER);
1946e3c97c2cSBryan Venteicher }
1947e3c97c2cSBryan Venteicher 
19488f82136aSPatrick Kelsey static void
19498f82136aSPatrick Kelsey vmxnet3_init(if_ctx_t ctx)
1950e3c97c2cSBryan Venteicher {
19518f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
1952e3c97c2cSBryan Venteicher 
19538f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
19548f82136aSPatrick Kelsey 
19558f82136aSPatrick Kelsey 	/* Use the current MAC address. */
19568f82136aSPatrick Kelsey 	bcopy(IF_LLADDR(sc->vmx_ifp), sc->vmx_lladdr, ETHER_ADDR_LEN);
19578f82136aSPatrick Kelsey 	vmxnet3_set_lladdr(sc);
19588f82136aSPatrick Kelsey 
1959e3c97c2cSBryan Venteicher 	vmxnet3_reinit_shared_data(sc);
19608f82136aSPatrick Kelsey 	vmxnet3_reinit_queues(sc);
1961e3c97c2cSBryan Venteicher 
19628f82136aSPatrick Kelsey 	vmxnet3_enable_device(sc);
1963e3c97c2cSBryan Venteicher 
1964e3c97c2cSBryan Venteicher 	vmxnet3_reinit_rxfilters(sc);
1965e3c97c2cSBryan Venteicher 	vmxnet3_link_status(sc);
1966e3c97c2cSBryan Venteicher }
1967e3c97c2cSBryan Venteicher 
1968e3c97c2cSBryan Venteicher static void
19698f82136aSPatrick Kelsey vmxnet3_multi_set(if_ctx_t ctx)
1970e3c97c2cSBryan Venteicher {
1971e3c97c2cSBryan Venteicher 
19728f82136aSPatrick Kelsey 	vmxnet3_set_rxfilter(iflib_get_softc(ctx),
19738f82136aSPatrick Kelsey 	    if_getflags(iflib_get_ifp(ctx)));
1974e3c97c2cSBryan Venteicher }
1975e3c97c2cSBryan Venteicher 
1976e3c97c2cSBryan Venteicher static int
19778f82136aSPatrick Kelsey vmxnet3_mtu_set(if_ctx_t ctx, uint32_t mtu)
1978e3c97c2cSBryan Venteicher {
1979*1342c8c6SPatrick Kelsey 	struct vmxnet3_softc *sc;
1980*1342c8c6SPatrick Kelsey 	if_softc_ctx_t scctx;
1981*1342c8c6SPatrick Kelsey 
1982*1342c8c6SPatrick Kelsey 	sc = iflib_get_softc(ctx);
1983*1342c8c6SPatrick Kelsey 	scctx = sc->vmx_scctx;
1984e3c97c2cSBryan Venteicher 
19858f82136aSPatrick Kelsey 	if (mtu > VMXNET3_TX_MAXSIZE - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN +
19868f82136aSPatrick Kelsey 		ETHER_CRC_LEN))
1987e3c97c2cSBryan Venteicher 		return (EINVAL);
1988e3c97c2cSBryan Venteicher 
1989*1342c8c6SPatrick Kelsey 	/*
1990*1342c8c6SPatrick Kelsey 	 * Update the max frame size so that the rx mbuf size is
1991*1342c8c6SPatrick Kelsey 	 * chosen based on the new mtu during the interface init that
1992*1342c8c6SPatrick Kelsey 	 * will occur after this routine returns.
1993*1342c8c6SPatrick Kelsey 	 */
1994*1342c8c6SPatrick Kelsey 	scctx->isc_max_frame_size = mtu +
1995*1342c8c6SPatrick Kelsey 		ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + ETHER_CRC_LEN;
1996*1342c8c6SPatrick Kelsey 	/* RX completion queue - n/a */
1997*1342c8c6SPatrick Kelsey 	scctx->isc_rxd_buf_size[0] = 0;
1998*1342c8c6SPatrick Kelsey 	/*
1999*1342c8c6SPatrick Kelsey 	 * For header-type descriptors (used for first segment of
2000*1342c8c6SPatrick Kelsey 	 * packet), let iflib determine the buffer size based on the
2001*1342c8c6SPatrick Kelsey 	 * max frame size.
2002*1342c8c6SPatrick Kelsey 	 */
2003*1342c8c6SPatrick Kelsey 	scctx->isc_rxd_buf_size[1] = 0;
2004*1342c8c6SPatrick Kelsey 	/*
2005*1342c8c6SPatrick Kelsey 	 * For body-type descriptors (used for jumbo frames and LRO),
2006*1342c8c6SPatrick Kelsey 	 * always use page-sized buffers.
2007*1342c8c6SPatrick Kelsey 	 */
2008*1342c8c6SPatrick Kelsey 	scctx->isc_rxd_buf_size[2] = MJUMPAGESIZE;
2009*1342c8c6SPatrick Kelsey 
2010e3c97c2cSBryan Venteicher 	return (0);
2011e3c97c2cSBryan Venteicher }
2012e3c97c2cSBryan Venteicher 
20138f82136aSPatrick Kelsey static void
20148f82136aSPatrick Kelsey vmxnet3_media_status(if_ctx_t ctx, struct ifmediareq * ifmr)
2015e3c97c2cSBryan Venteicher {
20168f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
2017e3c97c2cSBryan Venteicher 
20188f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
2019e3c97c2cSBryan Venteicher 
20208f82136aSPatrick Kelsey 	ifmr->ifm_status = IFM_AVALID;
20218f82136aSPatrick Kelsey 	ifmr->ifm_active = IFM_ETHER;
2022e3c97c2cSBryan Venteicher 
20238f82136aSPatrick Kelsey 	if (vmxnet3_link_is_up(sc) != 0) {
20248f82136aSPatrick Kelsey 		ifmr->ifm_status |= IFM_ACTIVE;
20258f82136aSPatrick Kelsey 		ifmr->ifm_active |= IFM_AUTO;
2026e3c97c2cSBryan Venteicher 	} else
20278f82136aSPatrick Kelsey 		ifmr->ifm_active |= IFM_NONE;
2028e3c97c2cSBryan Venteicher }
2029e3c97c2cSBryan Venteicher 
2030e3c97c2cSBryan Venteicher static int
20318f82136aSPatrick Kelsey vmxnet3_media_change(if_ctx_t ctx)
2032e3c97c2cSBryan Venteicher {
2033e3c97c2cSBryan Venteicher 
20348f82136aSPatrick Kelsey 	/* Ignore. */
2035c7156fe9SLuigi Rizzo 	return (0);
2036e557c1ddSBryan Venteicher }
2037e557c1ddSBryan Venteicher 
2038e557c1ddSBryan Venteicher static int
20398f82136aSPatrick Kelsey vmxnet3_promisc_set(if_ctx_t ctx, int flags)
2040e557c1ddSBryan Venteicher {
2041e557c1ddSBryan Venteicher 
20428f82136aSPatrick Kelsey 	vmxnet3_set_rxfilter(iflib_get_softc(ctx), flags);
2043e557c1ddSBryan Venteicher 
20448f82136aSPatrick Kelsey 	return (0);
2045e557c1ddSBryan Venteicher }
2046e557c1ddSBryan Venteicher 
20478f82136aSPatrick Kelsey static uint64_t
20488f82136aSPatrick Kelsey vmxnet3_get_counter(if_ctx_t ctx, ift_counter cnt)
20498f82136aSPatrick Kelsey {
20508f82136aSPatrick Kelsey 	if_t ifp = iflib_get_ifp(ctx);
20518f82136aSPatrick Kelsey 
20528f82136aSPatrick Kelsey 	if (cnt < IFCOUNTERS)
20538f82136aSPatrick Kelsey 		return if_get_counter_default(ifp, cnt);
20548f82136aSPatrick Kelsey 
20558f82136aSPatrick Kelsey 	return (0);
2056e557c1ddSBryan Venteicher }
2057e557c1ddSBryan Venteicher 
2058e557c1ddSBryan Venteicher static void
20598f82136aSPatrick Kelsey vmxnet3_update_admin_status(if_ctx_t ctx)
2060e557c1ddSBryan Venteicher {
2061e557c1ddSBryan Venteicher 	struct vmxnet3_softc *sc;
2062e557c1ddSBryan Venteicher 
20638f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
20648f82136aSPatrick Kelsey 	if (sc->vmx_ds->event != 0)
20658f82136aSPatrick Kelsey 		vmxnet3_evintr(sc);
2066e557c1ddSBryan Venteicher 
20678f82136aSPatrick Kelsey 	vmxnet3_refresh_host_stats(sc);
2068e557c1ddSBryan Venteicher }
2069e557c1ddSBryan Venteicher 
2070e557c1ddSBryan Venteicher static void
20718f82136aSPatrick Kelsey vmxnet3_txq_timer(if_ctx_t ctx, uint16_t qid)
2072e557c1ddSBryan Venteicher {
20738f82136aSPatrick Kelsey 	/* Host stats refresh is global, so just trigger it on txq 0 */
20748f82136aSPatrick Kelsey 	if (qid == 0)
20758f82136aSPatrick Kelsey 		vmxnet3_refresh_host_stats(iflib_get_softc(ctx));
2076e557c1ddSBryan Venteicher }
2077e557c1ddSBryan Venteicher 
2078e3c97c2cSBryan Venteicher static void
2079e3c97c2cSBryan Venteicher vmxnet3_update_vlan_filter(struct vmxnet3_softc *sc, int add, uint16_t tag)
2080e3c97c2cSBryan Venteicher {
2081e3c97c2cSBryan Venteicher 	int idx, bit;
2082e3c97c2cSBryan Venteicher 
2083e3c97c2cSBryan Venteicher 	if (tag == 0 || tag > 4095)
2084e3c97c2cSBryan Venteicher 		return;
2085e3c97c2cSBryan Venteicher 
20868f82136aSPatrick Kelsey 	idx = (tag >> 5) & 0x7F;
20878f82136aSPatrick Kelsey 	bit = tag & 0x1F;
2088e3c97c2cSBryan Venteicher 
2089e3c97c2cSBryan Venteicher 	/* Update our private VLAN bitvector. */
2090e3c97c2cSBryan Venteicher 	if (add)
2091e3c97c2cSBryan Venteicher 		sc->vmx_vlan_filter[idx] |= (1 << bit);
2092e3c97c2cSBryan Venteicher 	else
2093e3c97c2cSBryan Venteicher 		sc->vmx_vlan_filter[idx] &= ~(1 << bit);
2094e3c97c2cSBryan Venteicher }
2095e3c97c2cSBryan Venteicher 
2096e3c97c2cSBryan Venteicher static void
20978f82136aSPatrick Kelsey vmxnet3_vlan_register(if_ctx_t ctx, uint16_t tag)
2098e3c97c2cSBryan Venteicher {
2099e3c97c2cSBryan Venteicher 
21008f82136aSPatrick Kelsey 	vmxnet3_update_vlan_filter(iflib_get_softc(ctx), 1, tag);
2101e3c97c2cSBryan Venteicher }
2102e3c97c2cSBryan Venteicher 
2103e3c97c2cSBryan Venteicher static void
21048f82136aSPatrick Kelsey vmxnet3_vlan_unregister(if_ctx_t ctx, uint16_t tag)
2105e3c97c2cSBryan Venteicher {
2106e3c97c2cSBryan Venteicher 
21078f82136aSPatrick Kelsey 	vmxnet3_update_vlan_filter(iflib_get_softc(ctx), 0, tag);
2108e3c97c2cSBryan Venteicher }
2109e3c97c2cSBryan Venteicher 
2110d6b5965bSGleb Smirnoff static u_int
2111d6b5965bSGleb Smirnoff vmxnet3_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int count)
2112d6b5965bSGleb Smirnoff {
2113d6b5965bSGleb Smirnoff 	struct vmxnet3_softc *sc = arg;
2114d6b5965bSGleb Smirnoff 
2115d6b5965bSGleb Smirnoff 	if (count < VMXNET3_MULTICAST_MAX)
2116d6b5965bSGleb Smirnoff 		bcopy(LLADDR(sdl), &sc->vmx_mcast[count * ETHER_ADDR_LEN],
2117d6b5965bSGleb Smirnoff 		    ETHER_ADDR_LEN);
2118d6b5965bSGleb Smirnoff 
2119d6b5965bSGleb Smirnoff 	return (1);
2120d6b5965bSGleb Smirnoff }
2121d6b5965bSGleb Smirnoff 
2122e3c97c2cSBryan Venteicher static void
21238f82136aSPatrick Kelsey vmxnet3_set_rxfilter(struct vmxnet3_softc *sc, int flags)
2124e3c97c2cSBryan Venteicher {
2125e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
2126e3c97c2cSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
2127e3c97c2cSBryan Venteicher 	u_int mode;
2128e3c97c2cSBryan Venteicher 
2129e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
2130e3c97c2cSBryan Venteicher 	ds = sc->vmx_ds;
2131e3c97c2cSBryan Venteicher 
2132e557c1ddSBryan Venteicher 	mode = VMXNET3_RXMODE_UCAST | VMXNET3_RXMODE_BCAST;
21338f82136aSPatrick Kelsey 	if (flags & IFF_PROMISC)
2134e3c97c2cSBryan Venteicher 		mode |= VMXNET3_RXMODE_PROMISC;
21358f82136aSPatrick Kelsey 	if (flags & IFF_ALLMULTI)
2136e3c97c2cSBryan Venteicher 		mode |= VMXNET3_RXMODE_ALLMULTI;
2137e3c97c2cSBryan Venteicher 	else {
2138d6b5965bSGleb Smirnoff 		int cnt;
2139e3c97c2cSBryan Venteicher 
2140d6b5965bSGleb Smirnoff 		cnt = if_foreach_llmaddr(ifp, vmxnet3_hash_maddr, sc);
2141d6b5965bSGleb Smirnoff 		if (cnt >= VMXNET3_MULTICAST_MAX) {
2142e3c97c2cSBryan Venteicher 			cnt = 0;
2143e3c97c2cSBryan Venteicher 			mode |= VMXNET3_RXMODE_ALLMULTI;
2144e3c97c2cSBryan Venteicher 		} else if (cnt > 0)
2145e3c97c2cSBryan Venteicher 			mode |= VMXNET3_RXMODE_MCAST;
2146e3c97c2cSBryan Venteicher 		ds->mcast_tablelen = cnt * ETHER_ADDR_LEN;
2147e3c97c2cSBryan Venteicher 	}
2148e3c97c2cSBryan Venteicher 
2149e3c97c2cSBryan Venteicher 	ds->rxmode = mode;
2150e3c97c2cSBryan Venteicher 
2151e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_SET_FILTER);
2152e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_SET_RXMODE);
2153e3c97c2cSBryan Venteicher }
2154e3c97c2cSBryan Venteicher 
2155e3c97c2cSBryan Venteicher static void
2156e557c1ddSBryan Venteicher vmxnet3_refresh_host_stats(struct vmxnet3_softc *sc)
2157e3c97c2cSBryan Venteicher {
2158e3c97c2cSBryan Venteicher 
2159e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_GET_STATS);
2160e3c97c2cSBryan Venteicher }
2161e3c97c2cSBryan Venteicher 
2162e3c97c2cSBryan Venteicher static int
2163e3c97c2cSBryan Venteicher vmxnet3_link_is_up(struct vmxnet3_softc *sc)
2164e3c97c2cSBryan Venteicher {
2165e3c97c2cSBryan Venteicher 	uint32_t status;
2166e3c97c2cSBryan Venteicher 
2167e3c97c2cSBryan Venteicher 	status = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_LINK);
2168e3c97c2cSBryan Venteicher 	return !!(status & 0x1);
2169e3c97c2cSBryan Venteicher }
2170e3c97c2cSBryan Venteicher 
2171e3c97c2cSBryan Venteicher static void
2172e3c97c2cSBryan Venteicher vmxnet3_link_status(struct vmxnet3_softc *sc)
2173e3c97c2cSBryan Venteicher {
21748f82136aSPatrick Kelsey 	if_ctx_t ctx;
21758f82136aSPatrick Kelsey 	uint64_t speed;
2176e3c97c2cSBryan Venteicher 	int link;
2177e3c97c2cSBryan Venteicher 
21788f82136aSPatrick Kelsey 	ctx = sc->vmx_ctx;
2179e3c97c2cSBryan Venteicher 	link = vmxnet3_link_is_up(sc);
21808f82136aSPatrick Kelsey 	speed = IF_Gbps(10);
2181e3c97c2cSBryan Venteicher 
2182e3c97c2cSBryan Venteicher 	if (link != 0 && sc->vmx_link_active == 0) {
2183e3c97c2cSBryan Venteicher 		sc->vmx_link_active = 1;
21848f82136aSPatrick Kelsey 		iflib_link_state_change(ctx, LINK_STATE_UP, speed);
2185e3c97c2cSBryan Venteicher 	} else if (link == 0 && sc->vmx_link_active != 0) {
2186e3c97c2cSBryan Venteicher 		sc->vmx_link_active = 0;
21878f82136aSPatrick Kelsey 		iflib_link_state_change(ctx, LINK_STATE_DOWN, speed);
2188e3c97c2cSBryan Venteicher 	}
2189e3c97c2cSBryan Venteicher }
2190e3c97c2cSBryan Venteicher 
2191e3c97c2cSBryan Venteicher static void
2192e3c97c2cSBryan Venteicher vmxnet3_set_lladdr(struct vmxnet3_softc *sc)
2193e3c97c2cSBryan Venteicher {
2194e3c97c2cSBryan Venteicher 	uint32_t ml, mh;
2195e3c97c2cSBryan Venteicher 
2196e3c97c2cSBryan Venteicher 	ml  = sc->vmx_lladdr[0];
2197e3c97c2cSBryan Venteicher 	ml |= sc->vmx_lladdr[1] << 8;
2198e3c97c2cSBryan Venteicher 	ml |= sc->vmx_lladdr[2] << 16;
2199e3c97c2cSBryan Venteicher 	ml |= sc->vmx_lladdr[3] << 24;
2200e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_MACL, ml);
2201e3c97c2cSBryan Venteicher 
2202e3c97c2cSBryan Venteicher 	mh  = sc->vmx_lladdr[4];
2203e3c97c2cSBryan Venteicher 	mh |= sc->vmx_lladdr[5] << 8;
2204e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_MACH, mh);
2205e3c97c2cSBryan Venteicher }
2206e3c97c2cSBryan Venteicher 
2207e3c97c2cSBryan Venteicher static void
2208e3c97c2cSBryan Venteicher vmxnet3_get_lladdr(struct vmxnet3_softc *sc)
2209e3c97c2cSBryan Venteicher {
2210e3c97c2cSBryan Venteicher 	uint32_t ml, mh;
2211e3c97c2cSBryan Venteicher 
2212e3c97c2cSBryan Venteicher 	ml = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_MACL);
2213e3c97c2cSBryan Venteicher 	mh = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_MACH);
2214e3c97c2cSBryan Venteicher 
2215e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[0] = ml;
2216e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[1] = ml >> 8;
2217e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[2] = ml >> 16;
2218e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[3] = ml >> 24;
2219e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[4] = mh;
2220e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[5] = mh >> 8;
2221e3c97c2cSBryan Venteicher }
2222e3c97c2cSBryan Venteicher 
2223e3c97c2cSBryan Venteicher static void
2224e3c97c2cSBryan Venteicher vmxnet3_setup_txq_sysctl(struct vmxnet3_txqueue *txq,
2225e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2226e3c97c2cSBryan Venteicher {
2227e3c97c2cSBryan Venteicher 	struct sysctl_oid *node, *txsnode;
2228e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *list, *txslist;
2229e3c97c2cSBryan Venteicher 	struct UPT1_TxStats *txstats;
2230e3c97c2cSBryan Venteicher 	char namebuf[16];
2231e3c97c2cSBryan Venteicher 
2232e3c97c2cSBryan Venteicher 	txstats = &txq->vxtxq_ts->stats;
2233e3c97c2cSBryan Venteicher 
2234e3c97c2cSBryan Venteicher 	snprintf(namebuf, sizeof(namebuf), "txq%d", txq->vxtxq_id);
22357029da5cSPawel Biernacki 	node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf,
22367029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Transmit Queue");
2237e3c97c2cSBryan Venteicher 	txq->vxtxq_sysctl = list = SYSCTL_CHILDREN(node);
2238e3c97c2cSBryan Venteicher 
2239e3c97c2cSBryan Venteicher 	/*
22408f82136aSPatrick Kelsey 	 * Add statistics reported by the host. These are updated by the
22418f82136aSPatrick Kelsey 	 * iflib txq timer on txq 0.
2242e3c97c2cSBryan Venteicher 	 */
22437029da5cSPawel Biernacki 	txsnode = SYSCTL_ADD_NODE(ctx, list, OID_AUTO, "hstats",
22447029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Host Statistics");
2245e3c97c2cSBryan Venteicher 	txslist = SYSCTL_CHILDREN(txsnode);
2246e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "tso_packets", CTLFLAG_RD,
2247e3c97c2cSBryan Venteicher 	    &txstats->TSO_packets, "TSO packets");
2248e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "tso_bytes", CTLFLAG_RD,
2249e3c97c2cSBryan Venteicher 	    &txstats->TSO_bytes, "TSO bytes");
2250e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "ucast_packets", CTLFLAG_RD,
2251e3c97c2cSBryan Venteicher 	    &txstats->ucast_packets, "Unicast packets");
2252e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "unicast_bytes", CTLFLAG_RD,
2253e3c97c2cSBryan Venteicher 	    &txstats->ucast_bytes, "Unicast bytes");
2254e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "mcast_packets", CTLFLAG_RD,
2255e3c97c2cSBryan Venteicher 	    &txstats->mcast_packets, "Multicast packets");
2256e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "mcast_bytes", CTLFLAG_RD,
2257e3c97c2cSBryan Venteicher 	    &txstats->mcast_bytes, "Multicast bytes");
2258e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "error", CTLFLAG_RD,
2259e3c97c2cSBryan Venteicher 	    &txstats->error, "Errors");
2260e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "discard", CTLFLAG_RD,
2261e3c97c2cSBryan Venteicher 	    &txstats->discard, "Discards");
2262e3c97c2cSBryan Venteicher }
2263e3c97c2cSBryan Venteicher 
2264e3c97c2cSBryan Venteicher static void
2265e3c97c2cSBryan Venteicher vmxnet3_setup_rxq_sysctl(struct vmxnet3_rxqueue *rxq,
2266e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2267e3c97c2cSBryan Venteicher {
2268e3c97c2cSBryan Venteicher 	struct sysctl_oid *node, *rxsnode;
2269e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *list, *rxslist;
2270e3c97c2cSBryan Venteicher 	struct UPT1_RxStats *rxstats;
2271e3c97c2cSBryan Venteicher 	char namebuf[16];
2272e3c97c2cSBryan Venteicher 
2273e3c97c2cSBryan Venteicher 	rxstats = &rxq->vxrxq_rs->stats;
2274e3c97c2cSBryan Venteicher 
2275e3c97c2cSBryan Venteicher 	snprintf(namebuf, sizeof(namebuf), "rxq%d", rxq->vxrxq_id);
22767029da5cSPawel Biernacki 	node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf,
22777029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Receive Queue");
2278e3c97c2cSBryan Venteicher 	rxq->vxrxq_sysctl = list = SYSCTL_CHILDREN(node);
2279e3c97c2cSBryan Venteicher 
2280e3c97c2cSBryan Venteicher 	/*
22818f82136aSPatrick Kelsey 	 * Add statistics reported by the host. These are updated by the
22828f82136aSPatrick Kelsey 	 * iflib txq timer on txq 0.
2283e3c97c2cSBryan Venteicher 	 */
22847029da5cSPawel Biernacki 	rxsnode = SYSCTL_ADD_NODE(ctx, list, OID_AUTO, "hstats",
22857029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Host Statistics");
2286e3c97c2cSBryan Venteicher 	rxslist = SYSCTL_CHILDREN(rxsnode);
2287e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "lro_packets", CTLFLAG_RD,
2288e3c97c2cSBryan Venteicher 	    &rxstats->LRO_packets, "LRO packets");
2289e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "lro_bytes", CTLFLAG_RD,
2290e3c97c2cSBryan Venteicher 	    &rxstats->LRO_bytes, "LRO bytes");
2291e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "ucast_packets", CTLFLAG_RD,
2292e3c97c2cSBryan Venteicher 	    &rxstats->ucast_packets, "Unicast packets");
2293e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "unicast_bytes", CTLFLAG_RD,
2294e3c97c2cSBryan Venteicher 	    &rxstats->ucast_bytes, "Unicast bytes");
2295e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "mcast_packets", CTLFLAG_RD,
2296e3c97c2cSBryan Venteicher 	    &rxstats->mcast_packets, "Multicast packets");
2297e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "mcast_bytes", CTLFLAG_RD,
2298e3c97c2cSBryan Venteicher 	    &rxstats->mcast_bytes, "Multicast bytes");
2299e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "bcast_packets", CTLFLAG_RD,
2300e3c97c2cSBryan Venteicher 	    &rxstats->bcast_packets, "Broadcast packets");
2301e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "bcast_bytes", CTLFLAG_RD,
2302e3c97c2cSBryan Venteicher 	    &rxstats->bcast_bytes, "Broadcast bytes");
2303e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "nobuffer", CTLFLAG_RD,
2304e3c97c2cSBryan Venteicher 	    &rxstats->nobuffer, "No buffer");
2305e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "error", CTLFLAG_RD,
2306e3c97c2cSBryan Venteicher 	    &rxstats->error, "Errors");
2307e3c97c2cSBryan Venteicher }
2308e3c97c2cSBryan Venteicher 
2309e3c97c2cSBryan Venteicher static void
2310e3c97c2cSBryan Venteicher vmxnet3_setup_debug_sysctl(struct vmxnet3_softc *sc,
2311e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2312e3c97c2cSBryan Venteicher {
23138f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
2314e3c97c2cSBryan Venteicher 	struct sysctl_oid *node;
2315e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *list;
2316e3c97c2cSBryan Venteicher 	int i;
2317e3c97c2cSBryan Venteicher 
23188f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
23198f82136aSPatrick Kelsey 
23208f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++) {
2321e3c97c2cSBryan Venteicher 		struct vmxnet3_txqueue *txq = &sc->vmx_txq[i];
2322e3c97c2cSBryan Venteicher 
2323e3c97c2cSBryan Venteicher 		node = SYSCTL_ADD_NODE(ctx, txq->vxtxq_sysctl, OID_AUTO,
23247029da5cSPawel Biernacki 		    "debug", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "");
2325e3c97c2cSBryan Venteicher 		list = SYSCTL_CHILDREN(node);
2326e3c97c2cSBryan Venteicher 
2327e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd_next", CTLFLAG_RD,
2328e3c97c2cSBryan Venteicher 		    &txq->vxtxq_cmd_ring.vxtxr_next, 0, "");
2329e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd_ndesc", CTLFLAG_RD,
2330e3c97c2cSBryan Venteicher 		    &txq->vxtxq_cmd_ring.vxtxr_ndesc, 0, "");
2331e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd_gen", CTLFLAG_RD,
2332e3c97c2cSBryan Venteicher 		    &txq->vxtxq_cmd_ring.vxtxr_gen, 0, "");
2333e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_next", CTLFLAG_RD,
2334e3c97c2cSBryan Venteicher 		    &txq->vxtxq_comp_ring.vxcr_next, 0, "");
2335e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_ndesc", CTLFLAG_RD,
2336e3c97c2cSBryan Venteicher 		    &txq->vxtxq_comp_ring.vxcr_ndesc, 0,"");
2337e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "comp_gen", CTLFLAG_RD,
2338e3c97c2cSBryan Venteicher 		    &txq->vxtxq_comp_ring.vxcr_gen, 0, "");
2339e3c97c2cSBryan Venteicher 	}
2340e3c97c2cSBryan Venteicher 
23418f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
2342e3c97c2cSBryan Venteicher 		struct vmxnet3_rxqueue *rxq = &sc->vmx_rxq[i];
2343e3c97c2cSBryan Venteicher 
2344e3c97c2cSBryan Venteicher 		node = SYSCTL_ADD_NODE(ctx, rxq->vxrxq_sysctl, OID_AUTO,
23457029da5cSPawel Biernacki 		    "debug", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "");
2346e3c97c2cSBryan Venteicher 		list = SYSCTL_CHILDREN(node);
2347e3c97c2cSBryan Venteicher 
2348e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd0_ndesc", CTLFLAG_RD,
2349e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[0].vxrxr_ndesc, 0, "");
2350e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd0_gen", CTLFLAG_RD,
2351e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[0].vxrxr_gen, 0, "");
2352f50375eeSPatrick Kelsey 		SYSCTL_ADD_U64(ctx, list, OID_AUTO, "cmd0_desc_skips", CTLFLAG_RD,
2353f50375eeSPatrick Kelsey 		    &rxq->vxrxq_cmd_ring[0].vxrxr_desc_skips, 0, "");
2354e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd1_ndesc", CTLFLAG_RD,
2355e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[1].vxrxr_ndesc, 0, "");
2356e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd1_gen", CTLFLAG_RD,
2357e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[1].vxrxr_gen, 0, "");
2358f50375eeSPatrick Kelsey 		SYSCTL_ADD_U64(ctx, list, OID_AUTO, "cmd1_desc_skips", CTLFLAG_RD,
2359f50375eeSPatrick Kelsey 		    &rxq->vxrxq_cmd_ring[1].vxrxr_desc_skips, 0, "");
2360e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_ndesc", CTLFLAG_RD,
2361e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_comp_ring.vxcr_ndesc, 0,"");
2362e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "comp_gen", CTLFLAG_RD,
2363e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_comp_ring.vxcr_gen, 0, "");
2364f50375eeSPatrick Kelsey 		SYSCTL_ADD_U64(ctx, list, OID_AUTO, "comp_zero_length", CTLFLAG_RD,
2365f50375eeSPatrick Kelsey 		    &rxq->vxrxq_comp_ring.vxcr_zero_length, 0, "");
2366f50375eeSPatrick Kelsey 		SYSCTL_ADD_U64(ctx, list, OID_AUTO, "comp_pkt_errors", CTLFLAG_RD,
2367f50375eeSPatrick Kelsey 		    &rxq->vxrxq_comp_ring.vxcr_pkt_errors, 0, "");
2368e3c97c2cSBryan Venteicher 	}
2369e3c97c2cSBryan Venteicher }
2370e3c97c2cSBryan Venteicher 
2371e3c97c2cSBryan Venteicher static void
2372e3c97c2cSBryan Venteicher vmxnet3_setup_queue_sysctl(struct vmxnet3_softc *sc,
2373e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2374e3c97c2cSBryan Venteicher {
23758f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
2376e3c97c2cSBryan Venteicher 	int i;
2377e3c97c2cSBryan Venteicher 
23788f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
23798f82136aSPatrick Kelsey 
23808f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++)
2381e3c97c2cSBryan Venteicher 		vmxnet3_setup_txq_sysctl(&sc->vmx_txq[i], ctx, child);
23828f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++)
2383e3c97c2cSBryan Venteicher 		vmxnet3_setup_rxq_sysctl(&sc->vmx_rxq[i], ctx, child);
2384e3c97c2cSBryan Venteicher 
2385e3c97c2cSBryan Venteicher 	vmxnet3_setup_debug_sysctl(sc, ctx, child);
2386e3c97c2cSBryan Venteicher }
2387e3c97c2cSBryan Venteicher 
2388e3c97c2cSBryan Venteicher static void
2389e3c97c2cSBryan Venteicher vmxnet3_setup_sysctl(struct vmxnet3_softc *sc)
2390e3c97c2cSBryan Venteicher {
2391e3c97c2cSBryan Venteicher 	device_t dev;
2392e3c97c2cSBryan Venteicher 	struct sysctl_ctx_list *ctx;
2393e3c97c2cSBryan Venteicher 	struct sysctl_oid *tree;
2394e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *child;
2395e3c97c2cSBryan Venteicher 
2396e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
2397e3c97c2cSBryan Venteicher 	ctx = device_get_sysctl_ctx(dev);
2398e3c97c2cSBryan Venteicher 	tree = device_get_sysctl_tree(dev);
2399e3c97c2cSBryan Venteicher 	child = SYSCTL_CHILDREN(tree);
2400e3c97c2cSBryan Venteicher 
2401e3c97c2cSBryan Venteicher 	vmxnet3_setup_queue_sysctl(sc, ctx, child);
2402e3c97c2cSBryan Venteicher }
2403e3c97c2cSBryan Venteicher 
2404e3c97c2cSBryan Venteicher static void
2405e3c97c2cSBryan Venteicher vmxnet3_write_bar0(struct vmxnet3_softc *sc, bus_size_t r, uint32_t v)
2406e3c97c2cSBryan Venteicher {
2407e3c97c2cSBryan Venteicher 
2408e3c97c2cSBryan Venteicher 	bus_space_write_4(sc->vmx_iot0, sc->vmx_ioh0, r, v);
2409e3c97c2cSBryan Venteicher }
2410e3c97c2cSBryan Venteicher 
2411e3c97c2cSBryan Venteicher static uint32_t
2412e3c97c2cSBryan Venteicher vmxnet3_read_bar1(struct vmxnet3_softc *sc, bus_size_t r)
2413e3c97c2cSBryan Venteicher {
2414e3c97c2cSBryan Venteicher 
2415e3c97c2cSBryan Venteicher 	return (bus_space_read_4(sc->vmx_iot1, sc->vmx_ioh1, r));
2416e3c97c2cSBryan Venteicher }
2417e3c97c2cSBryan Venteicher 
2418e3c97c2cSBryan Venteicher static void
2419e3c97c2cSBryan Venteicher vmxnet3_write_bar1(struct vmxnet3_softc *sc, bus_size_t r, uint32_t v)
2420e3c97c2cSBryan Venteicher {
2421e3c97c2cSBryan Venteicher 
2422e3c97c2cSBryan Venteicher 	bus_space_write_4(sc->vmx_iot1, sc->vmx_ioh1, r, v);
2423e3c97c2cSBryan Venteicher }
2424e3c97c2cSBryan Venteicher 
2425e3c97c2cSBryan Venteicher static void
2426e3c97c2cSBryan Venteicher vmxnet3_write_cmd(struct vmxnet3_softc *sc, uint32_t cmd)
2427e3c97c2cSBryan Venteicher {
2428e3c97c2cSBryan Venteicher 
2429e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_CMD, cmd);
2430e3c97c2cSBryan Venteicher }
2431e3c97c2cSBryan Venteicher 
2432e3c97c2cSBryan Venteicher static uint32_t
2433e3c97c2cSBryan Venteicher vmxnet3_read_cmd(struct vmxnet3_softc *sc, uint32_t cmd)
2434e3c97c2cSBryan Venteicher {
2435e3c97c2cSBryan Venteicher 
2436e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, cmd);
2437e3c97c2cSBryan Venteicher 	bus_space_barrier(sc->vmx_iot1, sc->vmx_ioh1, 0, 0,
2438e3c97c2cSBryan Venteicher 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
2439e3c97c2cSBryan Venteicher 	return (vmxnet3_read_bar1(sc, VMXNET3_BAR1_CMD));
2440e3c97c2cSBryan Venteicher }
2441e3c97c2cSBryan Venteicher 
2442e3c97c2cSBryan Venteicher static void
2443e3c97c2cSBryan Venteicher vmxnet3_enable_intr(struct vmxnet3_softc *sc, int irq)
2444e3c97c2cSBryan Venteicher {
2445e3c97c2cSBryan Venteicher 
2446e3c97c2cSBryan Venteicher 	vmxnet3_write_bar0(sc, VMXNET3_BAR0_IMASK(irq), 0);
2447e3c97c2cSBryan Venteicher }
2448e3c97c2cSBryan Venteicher 
2449e3c97c2cSBryan Venteicher static void
2450e3c97c2cSBryan Venteicher vmxnet3_disable_intr(struct vmxnet3_softc *sc, int irq)
2451e3c97c2cSBryan Venteicher {
2452e3c97c2cSBryan Venteicher 
2453e3c97c2cSBryan Venteicher 	vmxnet3_write_bar0(sc, VMXNET3_BAR0_IMASK(irq), 1);
2454e3c97c2cSBryan Venteicher }
2455e3c97c2cSBryan Venteicher 
24568f82136aSPatrick Kelsey static int
24578f82136aSPatrick Kelsey vmxnet3_tx_queue_intr_enable(if_ctx_t ctx, uint16_t qid)
2458e3c97c2cSBryan Venteicher {
24598f82136aSPatrick Kelsey 	/* Not using interrupts for TX */
24608f82136aSPatrick Kelsey 	return (0);
24618f82136aSPatrick Kelsey }
24628f82136aSPatrick Kelsey 
24638f82136aSPatrick Kelsey static int
24648f82136aSPatrick Kelsey vmxnet3_rx_queue_intr_enable(if_ctx_t ctx, uint16_t qid)
24658f82136aSPatrick Kelsey {
24668f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
24678f82136aSPatrick Kelsey 
24688f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
24698f82136aSPatrick Kelsey 	vmxnet3_enable_intr(sc, sc->vmx_rxq[qid].vxrxq_intr_idx);
24708f82136aSPatrick Kelsey 	return (0);
24718f82136aSPatrick Kelsey }
24728f82136aSPatrick Kelsey 
24738f82136aSPatrick Kelsey static void
24748f82136aSPatrick Kelsey vmxnet3_link_intr_enable(if_ctx_t ctx)
24758f82136aSPatrick Kelsey {
24768f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
24778f82136aSPatrick Kelsey 
24788f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
24798f82136aSPatrick Kelsey 	vmxnet3_enable_intr(sc, sc->vmx_event_intr_idx);
24808f82136aSPatrick Kelsey }
24818f82136aSPatrick Kelsey 
24828f82136aSPatrick Kelsey static void
24838f82136aSPatrick Kelsey vmxnet3_intr_enable_all(if_ctx_t ctx)
24848f82136aSPatrick Kelsey {
24858f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
24868f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
2487e3c97c2cSBryan Venteicher 	int i;
2488e3c97c2cSBryan Venteicher 
24898f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
24908f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
2491e3c97c2cSBryan Venteicher 	sc->vmx_ds->ictrl &= ~VMXNET3_ICTRL_DISABLE_ALL;
24928f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_vectors; i++)
2493e3c97c2cSBryan Venteicher 		vmxnet3_enable_intr(sc, i);
2494e3c97c2cSBryan Venteicher }
2495e3c97c2cSBryan Venteicher 
2496e3c97c2cSBryan Venteicher static void
24978f82136aSPatrick Kelsey vmxnet3_intr_disable_all(if_ctx_t ctx)
2498e3c97c2cSBryan Venteicher {
24998f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
2500e3c97c2cSBryan Venteicher 	int i;
2501e3c97c2cSBryan Venteicher 
25028f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
25038f82136aSPatrick Kelsey 	/*
25048f82136aSPatrick Kelsey 	 * iflib may invoke this routine before vmxnet3_attach_post() has
25058f82136aSPatrick Kelsey 	 * run, which is before the top level shared data area is
25068f82136aSPatrick Kelsey 	 * initialized and the device made aware of it.
25078f82136aSPatrick Kelsey 	 */
25088f82136aSPatrick Kelsey 	if (sc->vmx_ds != NULL)
2509e3c97c2cSBryan Venteicher 		sc->vmx_ds->ictrl |= VMXNET3_ICTRL_DISABLE_ALL;
25108f82136aSPatrick Kelsey 	for (i = 0; i < VMXNET3_MAX_INTRS; i++)
2511e3c97c2cSBryan Venteicher 		vmxnet3_disable_intr(sc, i);
2512e3c97c2cSBryan Venteicher }
2513e3c97c2cSBryan Venteicher 
2514e3c97c2cSBryan Venteicher /*
2515e3c97c2cSBryan Venteicher  * Since this is a purely paravirtualized device, we do not have
2516e3c97c2cSBryan Venteicher  * to worry about DMA coherency. But at times, we must make sure
2517e3c97c2cSBryan Venteicher  * both the compiler and CPU do not reorder memory operations.
2518e3c97c2cSBryan Venteicher  */
2519e3c97c2cSBryan Venteicher static inline void
2520e3c97c2cSBryan Venteicher vmxnet3_barrier(struct vmxnet3_softc *sc, vmxnet3_barrier_t type)
2521e3c97c2cSBryan Venteicher {
2522e3c97c2cSBryan Venteicher 
2523e3c97c2cSBryan Venteicher 	switch (type) {
2524e3c97c2cSBryan Venteicher 	case VMXNET3_BARRIER_RD:
2525e3c97c2cSBryan Venteicher 		rmb();
2526e3c97c2cSBryan Venteicher 		break;
2527e3c97c2cSBryan Venteicher 	case VMXNET3_BARRIER_WR:
2528e3c97c2cSBryan Venteicher 		wmb();
2529e3c97c2cSBryan Venteicher 		break;
2530e3c97c2cSBryan Venteicher 	case VMXNET3_BARRIER_RDWR:
2531e3c97c2cSBryan Venteicher 		mb();
2532e3c97c2cSBryan Venteicher 		break;
2533e3c97c2cSBryan Venteicher 	default:
2534e3c97c2cSBryan Venteicher 		panic("%s: bad barrier type %d", __func__, type);
2535e3c97c2cSBryan Venteicher 	}
2536e3c97c2cSBryan Venteicher }
2537