xref: /freebsd/sys/dev/vmware/vmxnet3/if_vmx.c (revision 81be655266fac2b333e25f386f32c9bcd17f523d)
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 
798f82136aSPatrick Kelsey #define VMXNET3_VMWARE_VENDOR_ID	0x15AD
808f82136aSPatrick Kelsey #define VMXNET3_VMWARE_DEVICE_ID	0x07B0
818f82136aSPatrick Kelsey 
828f82136aSPatrick Kelsey static pci_vendor_info_t vmxnet3_vendor_info_array[] =
838f82136aSPatrick Kelsey {
848f82136aSPatrick Kelsey 	PVID(VMXNET3_VMWARE_VENDOR_ID, VMXNET3_VMWARE_DEVICE_ID, "VMware VMXNET3 Ethernet Adapter"),
858f82136aSPatrick Kelsey 	/* required last entry */
868f82136aSPatrick Kelsey 	PVID_END
878f82136aSPatrick Kelsey };
888f82136aSPatrick Kelsey 
898f82136aSPatrick Kelsey static void	*vmxnet3_register(device_t);
908f82136aSPatrick Kelsey static int	vmxnet3_attach_pre(if_ctx_t);
918f82136aSPatrick Kelsey static int	vmxnet3_msix_intr_assign(if_ctx_t, int);
928f82136aSPatrick Kelsey static void	vmxnet3_free_irqs(struct vmxnet3_softc *);
938f82136aSPatrick Kelsey static int	vmxnet3_attach_post(if_ctx_t);
948f82136aSPatrick Kelsey static int	vmxnet3_detach(if_ctx_t);
958f82136aSPatrick Kelsey static int	vmxnet3_shutdown(if_ctx_t);
968f82136aSPatrick Kelsey static int	vmxnet3_suspend(if_ctx_t);
978f82136aSPatrick Kelsey static int	vmxnet3_resume(if_ctx_t);
98e3c97c2cSBryan Venteicher 
99e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_resources(struct vmxnet3_softc *);
100e3c97c2cSBryan Venteicher static void	vmxnet3_free_resources(struct vmxnet3_softc *);
101e3c97c2cSBryan Venteicher static int	vmxnet3_check_version(struct vmxnet3_softc *);
1028f82136aSPatrick Kelsey static void	vmxnet3_set_interrupt_idx(struct vmxnet3_softc *);
103e3c97c2cSBryan Venteicher 
1048f82136aSPatrick Kelsey static int	vmxnet3_queues_shared_alloc(struct vmxnet3_softc *);
1058f82136aSPatrick Kelsey static void	vmxnet3_init_txq(struct vmxnet3_softc *, int);
1068f82136aSPatrick Kelsey static int	vmxnet3_tx_queues_alloc(if_ctx_t, caddr_t *, uint64_t *, int, int);
1078f82136aSPatrick Kelsey static void	vmxnet3_init_rxq(struct vmxnet3_softc *, int, int);
1088f82136aSPatrick Kelsey static int	vmxnet3_rx_queues_alloc(if_ctx_t, caddr_t *, uint64_t *, int, int);
1098f82136aSPatrick Kelsey static void	vmxnet3_queues_free(if_ctx_t);
110e3c97c2cSBryan Venteicher 
111e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_shared_data(struct vmxnet3_softc *);
112e3c97c2cSBryan Venteicher static void	vmxnet3_free_shared_data(struct vmxnet3_softc *);
113e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_mcast_table(struct vmxnet3_softc *);
1148f82136aSPatrick Kelsey static void	vmxnet3_free_mcast_table(struct vmxnet3_softc *);
115e3c97c2cSBryan Venteicher static void	vmxnet3_init_shared_data(struct vmxnet3_softc *);
116e557c1ddSBryan Venteicher static void	vmxnet3_reinit_rss_shared_data(struct vmxnet3_softc *);
117e3c97c2cSBryan Venteicher static void	vmxnet3_reinit_shared_data(struct vmxnet3_softc *);
118e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_data(struct vmxnet3_softc *);
119e3c97c2cSBryan Venteicher static void	vmxnet3_free_data(struct vmxnet3_softc *);
120e3c97c2cSBryan Venteicher 
121e3c97c2cSBryan Venteicher static void	vmxnet3_evintr(struct vmxnet3_softc *);
1228f82136aSPatrick Kelsey static int	vmxnet3_isc_txd_encap(void *, if_pkt_info_t);
1238f82136aSPatrick Kelsey static void	vmxnet3_isc_txd_flush(void *, uint16_t, qidx_t);
1248f82136aSPatrick Kelsey static int	vmxnet3_isc_txd_credits_update(void *, uint16_t, bool);
1258f82136aSPatrick Kelsey static int	vmxnet3_isc_rxd_available(void *, uint16_t, qidx_t, qidx_t);
1268f82136aSPatrick Kelsey static int	vmxnet3_isc_rxd_pkt_get(void *, if_rxd_info_t);
1278f82136aSPatrick Kelsey static void	vmxnet3_isc_rxd_refill(void *, if_rxd_update_t);
1288f82136aSPatrick Kelsey static void	vmxnet3_isc_rxd_flush(void *, uint16_t, uint8_t, qidx_t);
1298f82136aSPatrick Kelsey static int	vmxnet3_legacy_intr(void *);
1308f82136aSPatrick Kelsey static int	vmxnet3_rxq_intr(void *);
1318f82136aSPatrick Kelsey static int	vmxnet3_event_intr(void *);
132e3c97c2cSBryan Venteicher 
1338f82136aSPatrick Kelsey static void	vmxnet3_stop(if_ctx_t);
134e3c97c2cSBryan Venteicher 
135e3c97c2cSBryan Venteicher static void	vmxnet3_txinit(struct vmxnet3_softc *, struct vmxnet3_txqueue *);
1368f82136aSPatrick Kelsey static void	vmxnet3_rxinit(struct vmxnet3_softc *, struct vmxnet3_rxqueue *);
1378f82136aSPatrick Kelsey static void	vmxnet3_reinit_queues(struct vmxnet3_softc *);
138e3c97c2cSBryan Venteicher static int	vmxnet3_enable_device(struct vmxnet3_softc *);
139e3c97c2cSBryan Venteicher static void	vmxnet3_reinit_rxfilters(struct vmxnet3_softc *);
1408f82136aSPatrick Kelsey static void	vmxnet3_init(if_ctx_t);
1418f82136aSPatrick Kelsey static void	vmxnet3_multi_set(if_ctx_t);
1428f82136aSPatrick Kelsey static int	vmxnet3_mtu_set(if_ctx_t, uint32_t);
1438f82136aSPatrick Kelsey static void	vmxnet3_media_status(if_ctx_t, struct ifmediareq *);
1448f82136aSPatrick Kelsey static int	vmxnet3_media_change(if_ctx_t);
1458f82136aSPatrick Kelsey static int	vmxnet3_promisc_set(if_ctx_t, int);
1468f82136aSPatrick Kelsey static uint64_t	vmxnet3_get_counter(if_ctx_t, ift_counter);
1478f82136aSPatrick Kelsey static void	vmxnet3_update_admin_status(if_ctx_t);
1488f82136aSPatrick Kelsey static void	vmxnet3_txq_timer(if_ctx_t, uint16_t);
149e3c97c2cSBryan Venteicher 
150e3c97c2cSBryan Venteicher static void	vmxnet3_update_vlan_filter(struct vmxnet3_softc *, int,
151e3c97c2cSBryan Venteicher 		    uint16_t);
1528f82136aSPatrick Kelsey static void	vmxnet3_vlan_register(if_ctx_t, uint16_t);
1538f82136aSPatrick Kelsey static void	vmxnet3_vlan_unregister(if_ctx_t, uint16_t);
1548f82136aSPatrick Kelsey static void	vmxnet3_set_rxfilter(struct vmxnet3_softc *, int);
155e3c97c2cSBryan Venteicher 
156e557c1ddSBryan Venteicher static void	vmxnet3_refresh_host_stats(struct vmxnet3_softc *);
1578f82136aSPatrick Kelsey static int	vmxnet3_link_is_up(struct vmxnet3_softc *);
158e3c97c2cSBryan Venteicher static void	vmxnet3_link_status(struct vmxnet3_softc *);
159e3c97c2cSBryan Venteicher static void	vmxnet3_set_lladdr(struct vmxnet3_softc *);
160e3c97c2cSBryan Venteicher static void	vmxnet3_get_lladdr(struct vmxnet3_softc *);
161e3c97c2cSBryan Venteicher 
162e3c97c2cSBryan Venteicher static void	vmxnet3_setup_txq_sysctl(struct vmxnet3_txqueue *,
163e3c97c2cSBryan Venteicher 		    struct sysctl_ctx_list *, struct sysctl_oid_list *);
164e3c97c2cSBryan Venteicher static void	vmxnet3_setup_rxq_sysctl(struct vmxnet3_rxqueue *,
165e3c97c2cSBryan Venteicher 		    struct sysctl_ctx_list *, struct sysctl_oid_list *);
166e3c97c2cSBryan Venteicher static void	vmxnet3_setup_queue_sysctl(struct vmxnet3_softc *,
167e3c97c2cSBryan Venteicher 		    struct sysctl_ctx_list *, struct sysctl_oid_list *);
168e3c97c2cSBryan Venteicher static void	vmxnet3_setup_sysctl(struct vmxnet3_softc *);
169e3c97c2cSBryan Venteicher 
170e3c97c2cSBryan Venteicher static void	vmxnet3_write_bar0(struct vmxnet3_softc *, bus_size_t,
171e3c97c2cSBryan Venteicher 		    uint32_t);
172e3c97c2cSBryan Venteicher static uint32_t	vmxnet3_read_bar1(struct vmxnet3_softc *, bus_size_t);
173e3c97c2cSBryan Venteicher static void	vmxnet3_write_bar1(struct vmxnet3_softc *, bus_size_t,
174e3c97c2cSBryan Venteicher 		    uint32_t);
175e3c97c2cSBryan Venteicher static void	vmxnet3_write_cmd(struct vmxnet3_softc *, uint32_t);
176e3c97c2cSBryan Venteicher static uint32_t	vmxnet3_read_cmd(struct vmxnet3_softc *, uint32_t);
177e3c97c2cSBryan Venteicher 
1788f82136aSPatrick Kelsey static int	vmxnet3_tx_queue_intr_enable(if_ctx_t, uint16_t);
1798f82136aSPatrick Kelsey static int	vmxnet3_rx_queue_intr_enable(if_ctx_t, uint16_t);
1808f82136aSPatrick Kelsey static void	vmxnet3_link_intr_enable(if_ctx_t);
181e3c97c2cSBryan Venteicher static void	vmxnet3_enable_intr(struct vmxnet3_softc *, int);
182e3c97c2cSBryan Venteicher static void	vmxnet3_disable_intr(struct vmxnet3_softc *, int);
1838f82136aSPatrick Kelsey static void	vmxnet3_intr_enable_all(if_ctx_t);
1848f82136aSPatrick Kelsey static void	vmxnet3_intr_disable_all(if_ctx_t);
185e3c97c2cSBryan Venteicher 
186e3c97c2cSBryan Venteicher typedef enum {
187e3c97c2cSBryan Venteicher 	VMXNET3_BARRIER_RD,
188e3c97c2cSBryan Venteicher 	VMXNET3_BARRIER_WR,
189e3c97c2cSBryan Venteicher 	VMXNET3_BARRIER_RDWR,
190e3c97c2cSBryan Venteicher } vmxnet3_barrier_t;
191e3c97c2cSBryan Venteicher 
192e3c97c2cSBryan Venteicher static void	vmxnet3_barrier(struct vmxnet3_softc *, vmxnet3_barrier_t);
193e3c97c2cSBryan Venteicher 
194e3c97c2cSBryan Venteicher static device_method_t vmxnet3_methods[] = {
1958f82136aSPatrick Kelsey 	/* Device interface */
1968f82136aSPatrick Kelsey 	DEVMETHOD(device_register, vmxnet3_register),
1978f82136aSPatrick Kelsey 	DEVMETHOD(device_probe, iflib_device_probe),
1988f82136aSPatrick Kelsey 	DEVMETHOD(device_attach, iflib_device_attach),
1998f82136aSPatrick Kelsey 	DEVMETHOD(device_detach, iflib_device_detach),
2008f82136aSPatrick Kelsey 	DEVMETHOD(device_shutdown, iflib_device_shutdown),
2018f82136aSPatrick Kelsey 	DEVMETHOD(device_suspend, iflib_device_suspend),
2028f82136aSPatrick Kelsey 	DEVMETHOD(device_resume, iflib_device_resume),
203e3c97c2cSBryan Venteicher 	DEVMETHOD_END
204e3c97c2cSBryan Venteicher };
205e3c97c2cSBryan Venteicher 
206e3c97c2cSBryan Venteicher static driver_t vmxnet3_driver = {
207e3c97c2cSBryan Venteicher 	"vmx", vmxnet3_methods, sizeof(struct vmxnet3_softc)
208e3c97c2cSBryan Venteicher };
209e3c97c2cSBryan Venteicher 
210e3c97c2cSBryan Venteicher static devclass_t vmxnet3_devclass;
211e3c97c2cSBryan Venteicher DRIVER_MODULE(vmx, pci, vmxnet3_driver, vmxnet3_devclass, 0, 0);
2128f82136aSPatrick Kelsey IFLIB_PNP_INFO(pci, vmx, vmxnet3_vendor_info_array);
2138f82136aSPatrick Kelsey MODULE_VERSION(vmx, 2);
214e3c97c2cSBryan Venteicher 
215e3c97c2cSBryan Venteicher MODULE_DEPEND(vmx, pci, 1, 1, 1);
216e3c97c2cSBryan Venteicher MODULE_DEPEND(vmx, ether, 1, 1, 1);
2178f82136aSPatrick Kelsey MODULE_DEPEND(vmx, iflib, 1, 1, 1);
218e3c97c2cSBryan Venteicher 
2198f82136aSPatrick Kelsey static device_method_t vmxnet3_iflib_methods[] = {
2208f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_tx_queues_alloc, vmxnet3_tx_queues_alloc),
2218f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_rx_queues_alloc, vmxnet3_rx_queues_alloc),
2228f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_queues_free, vmxnet3_queues_free),
223e3c97c2cSBryan Venteicher 
2248f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_attach_pre, vmxnet3_attach_pre),
2258f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_attach_post, vmxnet3_attach_post),
2268f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_detach, vmxnet3_detach),
2278f82136aSPatrick Kelsey 
2288f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_init, vmxnet3_init),
2298f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_stop, vmxnet3_stop),
2308f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_multi_set, vmxnet3_multi_set),
2318f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_mtu_set, vmxnet3_mtu_set),
2328f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_media_status, vmxnet3_media_status),
2338f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_media_change, vmxnet3_media_change),
2348f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_promisc_set, vmxnet3_promisc_set),
2358f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_get_counter, vmxnet3_get_counter),
2368f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_update_admin_status, vmxnet3_update_admin_status),
2378f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_timer, vmxnet3_txq_timer),
2388f82136aSPatrick Kelsey 
2398f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_tx_queue_intr_enable, vmxnet3_tx_queue_intr_enable),
2408f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_rx_queue_intr_enable, vmxnet3_rx_queue_intr_enable),
2418f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_link_intr_enable, vmxnet3_link_intr_enable),
2428f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_intr_enable, vmxnet3_intr_enable_all),
2438f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_intr_disable, vmxnet3_intr_disable_all),
2448f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_msix_intr_assign, vmxnet3_msix_intr_assign),
2458f82136aSPatrick Kelsey 
2468f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_vlan_register, vmxnet3_vlan_register),
2478f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_vlan_unregister, vmxnet3_vlan_unregister),
2488f82136aSPatrick Kelsey 
2498f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_shutdown, vmxnet3_shutdown),
2508f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_suspend, vmxnet3_suspend),
2518f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_resume, vmxnet3_resume),
2528f82136aSPatrick Kelsey 
2538f82136aSPatrick Kelsey 	DEVMETHOD_END
2548f82136aSPatrick Kelsey };
2558f82136aSPatrick Kelsey 
2568f82136aSPatrick Kelsey static driver_t vmxnet3_iflib_driver = {
2578f82136aSPatrick Kelsey 	"vmx", vmxnet3_iflib_methods, sizeof(struct vmxnet3_softc)
2588f82136aSPatrick Kelsey };
2598f82136aSPatrick Kelsey 
2608f82136aSPatrick Kelsey struct if_txrx vmxnet3_txrx = {
2618f82136aSPatrick Kelsey 	.ift_txd_encap = vmxnet3_isc_txd_encap,
2628f82136aSPatrick Kelsey 	.ift_txd_flush = vmxnet3_isc_txd_flush,
2638f82136aSPatrick Kelsey 	.ift_txd_credits_update = vmxnet3_isc_txd_credits_update,
2648f82136aSPatrick Kelsey 	.ift_rxd_available = vmxnet3_isc_rxd_available,
2658f82136aSPatrick Kelsey 	.ift_rxd_pkt_get = vmxnet3_isc_rxd_pkt_get,
2668f82136aSPatrick Kelsey 	.ift_rxd_refill = vmxnet3_isc_rxd_refill,
2678f82136aSPatrick Kelsey 	.ift_rxd_flush = vmxnet3_isc_rxd_flush,
2688f82136aSPatrick Kelsey 	.ift_legacy_intr = vmxnet3_legacy_intr
2698f82136aSPatrick Kelsey };
2708f82136aSPatrick Kelsey 
2718f82136aSPatrick Kelsey static struct if_shared_ctx vmxnet3_sctx_init = {
2728f82136aSPatrick Kelsey 	.isc_magic = IFLIB_MAGIC,
2738f82136aSPatrick Kelsey 	.isc_q_align = 512,
2748f82136aSPatrick Kelsey 
2758f82136aSPatrick Kelsey 	.isc_tx_maxsize = VMXNET3_TX_MAXSIZE,
2768f82136aSPatrick Kelsey 	.isc_tx_maxsegsize = VMXNET3_TX_MAXSEGSIZE,
2778f82136aSPatrick Kelsey 	.isc_tso_maxsize = VMXNET3_TSO_MAXSIZE + sizeof(struct ether_vlan_header),
2788f82136aSPatrick Kelsey 	.isc_tso_maxsegsize = VMXNET3_TX_MAXSEGSIZE,
2798f82136aSPatrick Kelsey 
2808f82136aSPatrick Kelsey 	/*
2818f82136aSPatrick Kelsey 	 * These values are used to configure the busdma tag used for
2828f82136aSPatrick Kelsey 	 * receive descriptors.  Each receive descriptor only points to one
2838f82136aSPatrick Kelsey 	 * buffer.
2848f82136aSPatrick Kelsey 	 */
2858f82136aSPatrick Kelsey 	.isc_rx_maxsize = VMXNET3_RX_MAXSEGSIZE, /* One buf per descriptor */
2868f82136aSPatrick Kelsey 	.isc_rx_nsegments = 1,  /* One mapping per descriptor */
2878f82136aSPatrick Kelsey 	.isc_rx_maxsegsize = VMXNET3_RX_MAXSEGSIZE,
2888f82136aSPatrick Kelsey 
2898f82136aSPatrick Kelsey 	.isc_admin_intrcnt = 1,
2908f82136aSPatrick Kelsey 	.isc_vendor_info = vmxnet3_vendor_info_array,
2918f82136aSPatrick Kelsey 	.isc_driver_version = "2",
2928f82136aSPatrick Kelsey 	.isc_driver = &vmxnet3_iflib_driver,
29341669133SMark Johnston 	.isc_flags = IFLIB_HAS_RXCQ | IFLIB_HAS_TXCQ | IFLIB_SINGLE_IRQ_RX_ONLY,
2948f82136aSPatrick Kelsey 
2958f82136aSPatrick Kelsey 	/*
2968f82136aSPatrick Kelsey 	 * Number of receive queues per receive queue set, with associated
2978f82136aSPatrick Kelsey 	 * descriptor settings for each.
2988f82136aSPatrick Kelsey 	 */
2998f82136aSPatrick Kelsey 	.isc_nrxqs = 3,
3008f82136aSPatrick Kelsey 	.isc_nfl = 2, /* one free list for each receive command queue */
3018f82136aSPatrick Kelsey 	.isc_nrxd_min = {VMXNET3_MIN_RX_NDESC, VMXNET3_MIN_RX_NDESC, VMXNET3_MIN_RX_NDESC},
3028f82136aSPatrick Kelsey 	.isc_nrxd_max = {VMXNET3_MAX_RX_NDESC, VMXNET3_MAX_RX_NDESC, VMXNET3_MAX_RX_NDESC},
3038f82136aSPatrick Kelsey 	.isc_nrxd_default = {VMXNET3_DEF_RX_NDESC, VMXNET3_DEF_RX_NDESC, VMXNET3_DEF_RX_NDESC},
3048f82136aSPatrick Kelsey 
3058f82136aSPatrick Kelsey 	/*
3068f82136aSPatrick Kelsey 	 * Number of transmit queues per transmit queue set, with associated
3078f82136aSPatrick Kelsey 	 * descriptor settings for each.
3088f82136aSPatrick Kelsey 	 */
3098f82136aSPatrick Kelsey 	.isc_ntxqs = 2,
3108f82136aSPatrick Kelsey 	.isc_ntxd_min = {VMXNET3_MIN_TX_NDESC, VMXNET3_MIN_TX_NDESC},
3118f82136aSPatrick Kelsey 	.isc_ntxd_max = {VMXNET3_MAX_TX_NDESC, VMXNET3_MAX_TX_NDESC},
3128f82136aSPatrick Kelsey 	.isc_ntxd_default = {VMXNET3_DEF_TX_NDESC, VMXNET3_DEF_TX_NDESC},
3138f82136aSPatrick Kelsey };
3148f82136aSPatrick Kelsey 
3158f82136aSPatrick Kelsey static void *
3168f82136aSPatrick Kelsey vmxnet3_register(device_t dev)
317e3c97c2cSBryan Venteicher {
3188f82136aSPatrick Kelsey 	return (&vmxnet3_sctx_init);
319e3c97c2cSBryan Venteicher }
320e3c97c2cSBryan Venteicher 
321e3c97c2cSBryan Venteicher static int
3225d1899eeSPatrick Kelsey trunc_powerof2(int val)
3235d1899eeSPatrick Kelsey {
3245d1899eeSPatrick Kelsey 
3255d1899eeSPatrick Kelsey 	return (1U << (fls(val) - 1));
3265d1899eeSPatrick Kelsey }
3275d1899eeSPatrick Kelsey 
3285d1899eeSPatrick Kelsey static int
3298f82136aSPatrick Kelsey vmxnet3_attach_pre(if_ctx_t ctx)
330e3c97c2cSBryan Venteicher {
3318f82136aSPatrick Kelsey 	device_t dev;
3328f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
333e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
3348f82136aSPatrick Kelsey 	uint32_t intr_config;
335e3c97c2cSBryan Venteicher 	int error;
336e3c97c2cSBryan Venteicher 
3378f82136aSPatrick Kelsey 	dev = iflib_get_dev(ctx);
3388f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
339e3c97c2cSBryan Venteicher 	sc->vmx_dev = dev;
3408f82136aSPatrick Kelsey 	sc->vmx_ctx = ctx;
3418f82136aSPatrick Kelsey 	sc->vmx_sctx = iflib_get_sctx(ctx);
3428f82136aSPatrick Kelsey 	sc->vmx_scctx = iflib_get_softc_ctx(ctx);
3438f82136aSPatrick Kelsey 	sc->vmx_ifp = iflib_get_ifp(ctx);
3448f82136aSPatrick Kelsey 	sc->vmx_media = iflib_get_media(ctx);
3458f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
346e3c97c2cSBryan Venteicher 
3478f82136aSPatrick Kelsey 	scctx->isc_tx_nsegments = VMXNET3_TX_MAXSEGS;
3488f82136aSPatrick Kelsey 	scctx->isc_tx_tso_segments_max = VMXNET3_TX_MAXSEGS;
3498f82136aSPatrick Kelsey 	/* isc_tx_tso_size_max doesn't include possible vlan header */
3508f82136aSPatrick Kelsey 	scctx->isc_tx_tso_size_max = VMXNET3_TSO_MAXSIZE;
3518f82136aSPatrick Kelsey 	scctx->isc_tx_tso_segsize_max = VMXNET3_TX_MAXSEGSIZE;
3528f82136aSPatrick Kelsey 	scctx->isc_txrx = &vmxnet3_txrx;
353e3c97c2cSBryan Venteicher 
3548f82136aSPatrick Kelsey 	/* If 0, the iflib tunable was not set, so set to the default */
3558f82136aSPatrick Kelsey 	if (scctx->isc_nrxqsets == 0)
3568f82136aSPatrick Kelsey 		scctx->isc_nrxqsets = VMXNET3_DEF_RX_QUEUES;
3575d1899eeSPatrick Kelsey 	scctx->isc_nrxqsets = trunc_powerof2(scctx->isc_nrxqsets);
3588f82136aSPatrick Kelsey 	scctx->isc_nrxqsets_max = min(VMXNET3_MAX_RX_QUEUES, mp_ncpus);
3595d1899eeSPatrick Kelsey 	scctx->isc_nrxqsets_max = trunc_powerof2(scctx->isc_nrxqsets_max);
360e3c97c2cSBryan Venteicher 
3618f82136aSPatrick Kelsey 	/* If 0, the iflib tunable was not set, so set to the default */
3628f82136aSPatrick Kelsey 	if (scctx->isc_ntxqsets == 0)
3638f82136aSPatrick Kelsey 		scctx->isc_ntxqsets = VMXNET3_DEF_TX_QUEUES;
3645d1899eeSPatrick Kelsey 	scctx->isc_ntxqsets = trunc_powerof2(scctx->isc_ntxqsets);
3658f82136aSPatrick Kelsey 	scctx->isc_ntxqsets_max = min(VMXNET3_MAX_TX_QUEUES, mp_ncpus);
3665d1899eeSPatrick Kelsey 	scctx->isc_ntxqsets_max = trunc_powerof2(scctx->isc_ntxqsets_max);
367e3c97c2cSBryan Venteicher 
3688f82136aSPatrick Kelsey 	/*
3698f82136aSPatrick Kelsey 	 * Enforce that the transmit completion queue descriptor count is
3708f82136aSPatrick Kelsey 	 * the same as the transmit command queue descriptor count.
3718f82136aSPatrick Kelsey 	 */
3728f82136aSPatrick Kelsey 	scctx->isc_ntxd[0] = scctx->isc_ntxd[1];
3738f82136aSPatrick Kelsey 	scctx->isc_txqsizes[0] =
3748f82136aSPatrick Kelsey 	    sizeof(struct vmxnet3_txcompdesc) * scctx->isc_ntxd[0];
3758f82136aSPatrick Kelsey 	scctx->isc_txqsizes[1] =
3768f82136aSPatrick Kelsey 	    sizeof(struct vmxnet3_txdesc) * scctx->isc_ntxd[1];
3778f82136aSPatrick Kelsey 
3788f82136aSPatrick Kelsey 	/*
3798f82136aSPatrick Kelsey 	 * Enforce that the receive completion queue descriptor count is the
3808f82136aSPatrick Kelsey 	 * sum of the receive command queue descriptor counts, and that the
3818f82136aSPatrick Kelsey 	 * second receive command queue descriptor count is the same as the
3828f82136aSPatrick Kelsey 	 * first one.
3838f82136aSPatrick Kelsey 	 */
3848f82136aSPatrick Kelsey 	scctx->isc_nrxd[2] = scctx->isc_nrxd[1];
3858f82136aSPatrick Kelsey 	scctx->isc_nrxd[0] = scctx->isc_nrxd[1] + scctx->isc_nrxd[2];
3868f82136aSPatrick Kelsey 	scctx->isc_rxqsizes[0] =
3878f82136aSPatrick Kelsey 	    sizeof(struct vmxnet3_rxcompdesc) * scctx->isc_nrxd[0];
3888f82136aSPatrick Kelsey 	scctx->isc_rxqsizes[1] =
3898f82136aSPatrick Kelsey 	    sizeof(struct vmxnet3_rxdesc) * scctx->isc_nrxd[1];
3908f82136aSPatrick Kelsey 	scctx->isc_rxqsizes[2] =
3918f82136aSPatrick Kelsey 	    sizeof(struct vmxnet3_rxdesc) * scctx->isc_nrxd[2];
3928f82136aSPatrick Kelsey 
3931342c8c6SPatrick Kelsey 	/*
3941342c8c6SPatrick Kelsey 	 * Initialize the max frame size and descriptor queue buffer
3951342c8c6SPatrick Kelsey 	 * sizes.
3961342c8c6SPatrick Kelsey 	 */
3971342c8c6SPatrick Kelsey 	vmxnet3_mtu_set(ctx, if_getmtu(sc->vmx_ifp));
3981342c8c6SPatrick Kelsey 
3998f82136aSPatrick Kelsey 	scctx->isc_rss_table_size = UPT1_RSS_MAX_IND_TABLE_SIZE;
4008f82136aSPatrick Kelsey 
4018f82136aSPatrick Kelsey 	/* Map PCI BARs */
402e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_resources(sc);
403e3c97c2cSBryan Venteicher 	if (error)
404e3c97c2cSBryan Venteicher 		goto fail;
405e3c97c2cSBryan Venteicher 
4068f82136aSPatrick Kelsey 	/* Check device versions */
407e3c97c2cSBryan Venteicher 	error = vmxnet3_check_version(sc);
408e3c97c2cSBryan Venteicher 	if (error)
409e3c97c2cSBryan Venteicher 		goto fail;
410e3c97c2cSBryan Venteicher 
4118f82136aSPatrick Kelsey 	/*
4128f82136aSPatrick Kelsey 	 * The interrupt mode can be set in the hypervisor configuration via
4138f82136aSPatrick Kelsey 	 * the parameter ethernet<N>.intrMode.
4148f82136aSPatrick Kelsey 	 */
4158f82136aSPatrick Kelsey 	intr_config = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_INTRCFG);
4168f82136aSPatrick Kelsey 	sc->vmx_intr_mask_mode = (intr_config >> 2) & 0x03;
417e3c97c2cSBryan Venteicher 
4188f82136aSPatrick Kelsey 	/*
4198f82136aSPatrick Kelsey 	 * Configure the softc context to attempt to configure the interrupt
4208f82136aSPatrick Kelsey 	 * mode now indicated by intr_config.  iflib will follow the usual
421b97de13aSMarius Strobl 	 * fallback path MSI-X -> MSI -> LEGACY, starting at the configured
4228f82136aSPatrick Kelsey 	 * starting mode.
4238f82136aSPatrick Kelsey 	 */
4248f82136aSPatrick Kelsey 	switch (intr_config & 0x03) {
4258f82136aSPatrick Kelsey 	case VMXNET3_IT_AUTO:
4268f82136aSPatrick Kelsey 	case VMXNET3_IT_MSIX:
4278f82136aSPatrick Kelsey 		scctx->isc_msix_bar = pci_msix_table_bar(dev);
4288f82136aSPatrick Kelsey 		break;
4298f82136aSPatrick Kelsey 	case VMXNET3_IT_MSI:
4308f82136aSPatrick Kelsey 		scctx->isc_msix_bar = -1;
4318f82136aSPatrick Kelsey 		scctx->isc_disable_msix = 1;
4328f82136aSPatrick Kelsey 		break;
4338f82136aSPatrick Kelsey 	case VMXNET3_IT_LEGACY:
4348f82136aSPatrick Kelsey 		scctx->isc_msix_bar = 0;
4358f82136aSPatrick Kelsey 		break;
436e3c97c2cSBryan Venteicher 	}
437e3c97c2cSBryan Venteicher 
4388f82136aSPatrick Kelsey 	scctx->isc_tx_csum_flags = VMXNET3_CSUM_ALL_OFFLOAD;
4398f82136aSPatrick Kelsey 	scctx->isc_capabilities = scctx->isc_capenable =
4408f82136aSPatrick Kelsey 	    IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6 |
4418f82136aSPatrick Kelsey 	    IFCAP_TSO4 | IFCAP_TSO6 |
4428f82136aSPatrick Kelsey 	    IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6 |
4438f82136aSPatrick Kelsey 	    IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING |
4448f82136aSPatrick Kelsey 	    IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO |
4458f82136aSPatrick Kelsey 	    IFCAP_JUMBO_MTU;
446e3c97c2cSBryan Venteicher 
4478f82136aSPatrick Kelsey 	/* These capabilities are not enabled by default. */
4488f82136aSPatrick Kelsey 	scctx->isc_capabilities |= IFCAP_LRO | IFCAP_VLAN_HWFILTER;
4498f82136aSPatrick Kelsey 
4508f82136aSPatrick Kelsey 	vmxnet3_get_lladdr(sc);
4518f82136aSPatrick Kelsey 	iflib_set_mac(ctx, sc->vmx_lladdr);
4528f82136aSPatrick Kelsey 
4538f82136aSPatrick Kelsey 	return (0);
454e3c97c2cSBryan Venteicher fail:
4558f82136aSPatrick Kelsey 	/*
4568f82136aSPatrick Kelsey 	 * We must completely clean up anything allocated above as iflib
4578f82136aSPatrick Kelsey 	 * will not invoke any other driver entry points as a result of this
4588f82136aSPatrick Kelsey 	 * failure.
4598f82136aSPatrick Kelsey 	 */
4608f82136aSPatrick Kelsey 	vmxnet3_free_resources(sc);
461e3c97c2cSBryan Venteicher 
462e3c97c2cSBryan Venteicher 	return (error);
463e3c97c2cSBryan Venteicher }
464e3c97c2cSBryan Venteicher 
465e3c97c2cSBryan Venteicher static int
4668f82136aSPatrick Kelsey vmxnet3_msix_intr_assign(if_ctx_t ctx, int msix)
467e3c97c2cSBryan Venteicher {
468e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
4698f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
4708f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
4718f82136aSPatrick Kelsey 	int error;
4728f82136aSPatrick Kelsey 	int i;
4738f82136aSPatrick Kelsey 	char irq_name[16];
474e3c97c2cSBryan Venteicher 
4758f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
4768f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
477e3c97c2cSBryan Venteicher 
4788f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
4798f82136aSPatrick Kelsey 		snprintf(irq_name, sizeof(irq_name), "rxq%d", i);
480e557c1ddSBryan Venteicher 
4818f82136aSPatrick Kelsey 		rxq = &sc->vmx_rxq[i];
4828f82136aSPatrick Kelsey 		error = iflib_irq_alloc_generic(ctx, &rxq->vxrxq_irq, i + 1,
483*81be6552SMatt Macy 		    IFLIB_INTR_RXTX, vmxnet3_rxq_intr, rxq, i, irq_name);
4848f82136aSPatrick Kelsey 		if (error) {
4858f82136aSPatrick Kelsey 			device_printf(iflib_get_dev(ctx),
4868f82136aSPatrick Kelsey 			    "Failed to register rxq %d interrupt handler\n", i);
4878f82136aSPatrick Kelsey 			return (error);
4888f82136aSPatrick Kelsey 		}
489e3c97c2cSBryan Venteicher 	}
490e3c97c2cSBryan Venteicher 
4918f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++) {
4928f82136aSPatrick Kelsey 		snprintf(irq_name, sizeof(irq_name), "txq%d", i);
4938f82136aSPatrick Kelsey 
4948f82136aSPatrick Kelsey 		/*
4958f82136aSPatrick Kelsey 		 * Don't provide the corresponding rxq irq for reference -
4968f82136aSPatrick Kelsey 		 * we want the transmit task to be attached to a task queue
4978f82136aSPatrick Kelsey 		 * that is different from the one used by the corresponding
4988f82136aSPatrick Kelsey 		 * rxq irq.  That is because the TX doorbell writes are very
4998f82136aSPatrick Kelsey 		 * expensive as virtualized MMIO operations, so we want to
5008f82136aSPatrick Kelsey 		 * be able to defer them to another core when possible so
5018f82136aSPatrick Kelsey 		 * that they don't steal receive processing cycles during
5028f82136aSPatrick Kelsey 		 * stack turnarounds like TCP ACK generation.  The other
5038f82136aSPatrick Kelsey 		 * piece to this approach is enabling the iflib abdicate
5048f82136aSPatrick Kelsey 		 * option (currently via an interface-specific
5058f82136aSPatrick Kelsey 		 * tunable/sysctl).
5068f82136aSPatrick Kelsey 		 */
5078f82136aSPatrick Kelsey 		iflib_softirq_alloc_generic(ctx, NULL, IFLIB_INTR_TX, NULL, i,
5088f82136aSPatrick Kelsey 		    irq_name);
509e3c97c2cSBryan Venteicher 	}
510e3c97c2cSBryan Venteicher 
5118f82136aSPatrick Kelsey 	error = iflib_irq_alloc_generic(ctx, &sc->vmx_event_intr_irq,
5128f82136aSPatrick Kelsey 	    scctx->isc_nrxqsets + 1, IFLIB_INTR_ADMIN, vmxnet3_event_intr, sc, 0,
5138f82136aSPatrick Kelsey 	    "event");
5148f82136aSPatrick Kelsey 	if (error) {
5158f82136aSPatrick Kelsey 		device_printf(iflib_get_dev(ctx),
5168f82136aSPatrick Kelsey 		    "Failed to register event interrupt handler\n");
5178f82136aSPatrick Kelsey 		return (error);
518e3c97c2cSBryan Venteicher 	}
519e3c97c2cSBryan Venteicher 
5208f82136aSPatrick Kelsey 	return (0);
5218f82136aSPatrick Kelsey }
522e3c97c2cSBryan Venteicher 
5238f82136aSPatrick Kelsey static void
5248f82136aSPatrick Kelsey vmxnet3_free_irqs(struct vmxnet3_softc *sc)
5258f82136aSPatrick Kelsey {
5268f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
5278f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
5288f82136aSPatrick Kelsey 	int i;
5298f82136aSPatrick Kelsey 
5308f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
5318f82136aSPatrick Kelsey 
5328f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
5338f82136aSPatrick Kelsey 		rxq = &sc->vmx_rxq[i];
5348f82136aSPatrick Kelsey 		iflib_irq_free(sc->vmx_ctx, &rxq->vxrxq_irq);
5358f82136aSPatrick Kelsey 	}
5368f82136aSPatrick Kelsey 
5378f82136aSPatrick Kelsey 	iflib_irq_free(sc->vmx_ctx, &sc->vmx_event_intr_irq);
5388f82136aSPatrick Kelsey }
5398f82136aSPatrick Kelsey 
5408f82136aSPatrick Kelsey static int
5418f82136aSPatrick Kelsey vmxnet3_attach_post(if_ctx_t ctx)
5428f82136aSPatrick Kelsey {
5438f82136aSPatrick Kelsey 	device_t dev;
5448f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
5458f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
5468f82136aSPatrick Kelsey 	int error;
5478f82136aSPatrick Kelsey 
5488f82136aSPatrick Kelsey 	dev = iflib_get_dev(ctx);
5498f82136aSPatrick Kelsey 	scctx = iflib_get_softc_ctx(ctx);
5508f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
5518f82136aSPatrick Kelsey 
5528f82136aSPatrick Kelsey 	if (scctx->isc_nrxqsets > 1)
5538f82136aSPatrick Kelsey 		sc->vmx_flags |= VMXNET3_FLAG_RSS;
5548f82136aSPatrick Kelsey 
5558f82136aSPatrick Kelsey 	error = vmxnet3_alloc_data(sc);
5568f82136aSPatrick Kelsey 	if (error)
5578f82136aSPatrick Kelsey 		goto fail;
5588f82136aSPatrick Kelsey 
5598f82136aSPatrick Kelsey 	vmxnet3_set_interrupt_idx(sc);
5608f82136aSPatrick Kelsey 	vmxnet3_setup_sysctl(sc);
5618f82136aSPatrick Kelsey 
5628f82136aSPatrick Kelsey 	ifmedia_add(sc->vmx_media, IFM_ETHER | IFM_AUTO, 0, NULL);
5638f82136aSPatrick Kelsey 	ifmedia_set(sc->vmx_media, IFM_ETHER | IFM_AUTO);
5648f82136aSPatrick Kelsey 
5658f82136aSPatrick Kelsey fail:
5668f82136aSPatrick Kelsey 	return (error);
5678f82136aSPatrick Kelsey }
5688f82136aSPatrick Kelsey 
5698f82136aSPatrick Kelsey static int
5708f82136aSPatrick Kelsey vmxnet3_detach(if_ctx_t ctx)
5718f82136aSPatrick Kelsey {
5728f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
5738f82136aSPatrick Kelsey 
5748f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
5758f82136aSPatrick Kelsey 
5768f82136aSPatrick Kelsey 	vmxnet3_free_irqs(sc);
577e3c97c2cSBryan Venteicher 	vmxnet3_free_data(sc);
578e3c97c2cSBryan Venteicher 	vmxnet3_free_resources(sc);
579e3c97c2cSBryan Venteicher 
580e3c97c2cSBryan Venteicher 	return (0);
581e3c97c2cSBryan Venteicher }
582e3c97c2cSBryan Venteicher 
583e3c97c2cSBryan Venteicher static int
5848f82136aSPatrick Kelsey vmxnet3_shutdown(if_ctx_t ctx)
5858f82136aSPatrick Kelsey {
5868f82136aSPatrick Kelsey 
5878f82136aSPatrick Kelsey 	return (0);
5888f82136aSPatrick Kelsey }
5898f82136aSPatrick Kelsey 
5908f82136aSPatrick Kelsey static int
5918f82136aSPatrick Kelsey vmxnet3_suspend(if_ctx_t ctx)
5928f82136aSPatrick Kelsey {
5938f82136aSPatrick Kelsey 
5948f82136aSPatrick Kelsey 	return (0);
5958f82136aSPatrick Kelsey }
5968f82136aSPatrick Kelsey 
5978f82136aSPatrick Kelsey static int
5988f82136aSPatrick Kelsey vmxnet3_resume(if_ctx_t ctx)
599e3c97c2cSBryan Venteicher {
600e3c97c2cSBryan Venteicher 
601e3c97c2cSBryan Venteicher 	return (0);
602e3c97c2cSBryan Venteicher }
603e3c97c2cSBryan Venteicher 
604e3c97c2cSBryan Venteicher static int
605e3c97c2cSBryan Venteicher vmxnet3_alloc_resources(struct vmxnet3_softc *sc)
606e3c97c2cSBryan Venteicher {
607e3c97c2cSBryan Venteicher 	device_t dev;
608e3c97c2cSBryan Venteicher 	int rid;
609e3c97c2cSBryan Venteicher 
610e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
611e3c97c2cSBryan Venteicher 
612e3c97c2cSBryan Venteicher 	rid = PCIR_BAR(0);
613e3c97c2cSBryan Venteicher 	sc->vmx_res0 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
614e3c97c2cSBryan Venteicher 	    RF_ACTIVE);
615e3c97c2cSBryan Venteicher 	if (sc->vmx_res0 == NULL) {
616e3c97c2cSBryan Venteicher 		device_printf(dev,
617e3c97c2cSBryan Venteicher 		    "could not map BAR0 memory\n");
618e3c97c2cSBryan Venteicher 		return (ENXIO);
619e3c97c2cSBryan Venteicher 	}
620e3c97c2cSBryan Venteicher 
621e3c97c2cSBryan Venteicher 	sc->vmx_iot0 = rman_get_bustag(sc->vmx_res0);
622e3c97c2cSBryan Venteicher 	sc->vmx_ioh0 = rman_get_bushandle(sc->vmx_res0);
623e3c97c2cSBryan Venteicher 
624e3c97c2cSBryan Venteicher 	rid = PCIR_BAR(1);
625e3c97c2cSBryan Venteicher 	sc->vmx_res1 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
626e3c97c2cSBryan Venteicher 	    RF_ACTIVE);
627e3c97c2cSBryan Venteicher 	if (sc->vmx_res1 == NULL) {
628e3c97c2cSBryan Venteicher 		device_printf(dev,
629e3c97c2cSBryan Venteicher 		    "could not map BAR1 memory\n");
630e3c97c2cSBryan Venteicher 		return (ENXIO);
631e3c97c2cSBryan Venteicher 	}
632e3c97c2cSBryan Venteicher 
633e3c97c2cSBryan Venteicher 	sc->vmx_iot1 = rman_get_bustag(sc->vmx_res1);
634e3c97c2cSBryan Venteicher 	sc->vmx_ioh1 = rman_get_bushandle(sc->vmx_res1);
635e3c97c2cSBryan Venteicher 
636e3c97c2cSBryan Venteicher 	return (0);
637e3c97c2cSBryan Venteicher }
638e3c97c2cSBryan Venteicher 
639e3c97c2cSBryan Venteicher static void
640e3c97c2cSBryan Venteicher vmxnet3_free_resources(struct vmxnet3_softc *sc)
641e3c97c2cSBryan Venteicher {
642e3c97c2cSBryan Venteicher 	device_t dev;
643e3c97c2cSBryan Venteicher 
644e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
645e3c97c2cSBryan Venteicher 
646e3c97c2cSBryan Venteicher 	if (sc->vmx_res0 != NULL) {
647b97de13aSMarius Strobl 		bus_release_resource(dev, SYS_RES_MEMORY,
648b97de13aSMarius Strobl 		    rman_get_rid(sc->vmx_res0), sc->vmx_res0);
649e3c97c2cSBryan Venteicher 		sc->vmx_res0 = NULL;
650e3c97c2cSBryan Venteicher 	}
651e3c97c2cSBryan Venteicher 
652e3c97c2cSBryan Venteicher 	if (sc->vmx_res1 != NULL) {
653b97de13aSMarius Strobl 		bus_release_resource(dev, SYS_RES_MEMORY,
654b97de13aSMarius Strobl 		    rman_get_rid(sc->vmx_res1), sc->vmx_res1);
655e3c97c2cSBryan Venteicher 		sc->vmx_res1 = NULL;
656e3c97c2cSBryan Venteicher 	}
657e3c97c2cSBryan Venteicher }
658e3c97c2cSBryan Venteicher 
659e3c97c2cSBryan Venteicher static int
660e3c97c2cSBryan Venteicher vmxnet3_check_version(struct vmxnet3_softc *sc)
661e3c97c2cSBryan Venteicher {
662e3c97c2cSBryan Venteicher 	device_t dev;
663e3c97c2cSBryan Venteicher 	uint32_t version;
664e3c97c2cSBryan Venteicher 
665e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
666e3c97c2cSBryan Venteicher 
667e3c97c2cSBryan Venteicher 	version = vmxnet3_read_bar1(sc, VMXNET3_BAR1_VRRS);
668e3c97c2cSBryan Venteicher 	if ((version & 0x01) == 0) {
669e3c97c2cSBryan Venteicher 		device_printf(dev, "unsupported hardware version %#x\n",
670e3c97c2cSBryan Venteicher 		    version);
671e3c97c2cSBryan Venteicher 		return (ENOTSUP);
6723c965775SBryan Venteicher 	}
673e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_VRRS, 1);
674e3c97c2cSBryan Venteicher 
675e3c97c2cSBryan Venteicher 	version = vmxnet3_read_bar1(sc, VMXNET3_BAR1_UVRS);
676e3c97c2cSBryan Venteicher 	if ((version & 0x01) == 0) {
677e3c97c2cSBryan Venteicher 		device_printf(dev, "unsupported UPT version %#x\n", version);
678e3c97c2cSBryan Venteicher 		return (ENOTSUP);
6793c965775SBryan Venteicher 	}
680e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_UVRS, 1);
681e3c97c2cSBryan Venteicher 
682e3c97c2cSBryan Venteicher 	return (0);
683e3c97c2cSBryan Venteicher }
684e3c97c2cSBryan Venteicher 
685e3c97c2cSBryan Venteicher static void
686e3c97c2cSBryan Venteicher vmxnet3_set_interrupt_idx(struct vmxnet3_softc *sc)
687e3c97c2cSBryan Venteicher {
6888f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
689e3c97c2cSBryan Venteicher 	struct vmxnet3_txqueue *txq;
690e3c97c2cSBryan Venteicher 	struct vmxnet3_txq_shared *txs;
691e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
692e3c97c2cSBryan Venteicher 	struct vmxnet3_rxq_shared *rxs;
6938f82136aSPatrick Kelsey 	int intr_idx;
694e3c97c2cSBryan Venteicher 	int i;
695e3c97c2cSBryan Venteicher 
6968f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
697e3c97c2cSBryan Venteicher 
6988f82136aSPatrick Kelsey 	/*
699769d56ecSPatrick Kelsey 	 * There is always one interrupt per receive queue, assigned
700769d56ecSPatrick Kelsey 	 * starting with the first interrupt.  When there is only one
701769d56ecSPatrick Kelsey 	 * interrupt available, the event interrupt shares the receive queue
702769d56ecSPatrick Kelsey 	 * interrupt, otherwise it uses the interrupt following the last
703769d56ecSPatrick Kelsey 	 * receive queue interrupt.  Transmit queues are not assigned
704769d56ecSPatrick Kelsey 	 * interrupts, so they are given indexes beyond the indexes that
705769d56ecSPatrick Kelsey 	 * correspond to the real interrupts.
7068f82136aSPatrick Kelsey 	 */
707769d56ecSPatrick Kelsey 
708769d56ecSPatrick Kelsey 	/* The event interrupt is always the last vector. */
7098f82136aSPatrick Kelsey 	sc->vmx_event_intr_idx = scctx->isc_vectors - 1;
710e3c97c2cSBryan Venteicher 
7118f82136aSPatrick Kelsey 	intr_idx = 0;
7128f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++, intr_idx++) {
713e3c97c2cSBryan Venteicher 		rxq = &sc->vmx_rxq[i];
714e3c97c2cSBryan Venteicher 		rxs = rxq->vxrxq_rs;
7158f82136aSPatrick Kelsey 		rxq->vxrxq_intr_idx = intr_idx;
716e3c97c2cSBryan Venteicher 		rxs->intr_idx = rxq->vxrxq_intr_idx;
717e3c97c2cSBryan Venteicher 	}
7188f82136aSPatrick Kelsey 
7198f82136aSPatrick Kelsey 	/*
7208f82136aSPatrick Kelsey 	 * Assign the tx queues interrupt indexes above what we are actually
7218f82136aSPatrick Kelsey 	 * using.  These interrupts will never be enabled.
7228f82136aSPatrick Kelsey 	 */
7238f82136aSPatrick Kelsey 	intr_idx = scctx->isc_vectors;
7248f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++, intr_idx++) {
7258f82136aSPatrick Kelsey 		txq = &sc->vmx_txq[i];
7268f82136aSPatrick Kelsey 		txs = txq->vxtxq_ts;
7278f82136aSPatrick Kelsey 		txq->vxtxq_intr_idx = intr_idx;
7288f82136aSPatrick Kelsey 		txs->intr_idx = txq->vxtxq_intr_idx;
7298f82136aSPatrick Kelsey 	}
730e3c97c2cSBryan Venteicher }
731e3c97c2cSBryan Venteicher 
732e3c97c2cSBryan Venteicher static int
7338f82136aSPatrick Kelsey vmxnet3_queues_shared_alloc(struct vmxnet3_softc *sc)
734e3c97c2cSBryan Venteicher {
7358f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
7368f82136aSPatrick Kelsey 	int size;
737e3c97c2cSBryan Venteicher 	int error;
738e3c97c2cSBryan Venteicher 
7398f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
740e3c97c2cSBryan Venteicher 
7418f82136aSPatrick Kelsey 	/*
7428f82136aSPatrick Kelsey 	 * The txq and rxq shared data areas must be allocated contiguously
7438f82136aSPatrick Kelsey 	 * as vmxnet3_driver_shared contains only a single address member
7448f82136aSPatrick Kelsey 	 * for the shared queue data area.
7458f82136aSPatrick Kelsey 	 */
7468f82136aSPatrick Kelsey 	size = scctx->isc_ntxqsets * sizeof(struct vmxnet3_txq_shared) +
7478f82136aSPatrick Kelsey 	    scctx->isc_nrxqsets * sizeof(struct vmxnet3_rxq_shared);
7488f82136aSPatrick Kelsey 	error = iflib_dma_alloc_align(sc->vmx_ctx, size, 128, &sc->vmx_qs_dma, 0);
7498f82136aSPatrick Kelsey 	if (error) {
7508f82136aSPatrick Kelsey 		device_printf(sc->vmx_dev, "cannot alloc queue shared memory\n");
751e3c97c2cSBryan Venteicher 		return (error);
752e3c97c2cSBryan Venteicher 	}
753e3c97c2cSBryan Venteicher 
754e557c1ddSBryan Venteicher 	return (0);
755e557c1ddSBryan Venteicher }
756e557c1ddSBryan Venteicher 
757e557c1ddSBryan Venteicher static void
7588f82136aSPatrick Kelsey vmxnet3_init_txq(struct vmxnet3_softc *sc, int q)
759e557c1ddSBryan Venteicher {
760e557c1ddSBryan Venteicher 	struct vmxnet3_txqueue *txq;
7618f82136aSPatrick Kelsey 	struct vmxnet3_comp_ring *txc;
7628f82136aSPatrick Kelsey 	struct vmxnet3_txring *txr;
7638f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
764e557c1ddSBryan Venteicher 
7658f82136aSPatrick Kelsey 	txq = &sc->vmx_txq[q];
7668f82136aSPatrick Kelsey 	txc = &txq->vxtxq_comp_ring;
7678f82136aSPatrick Kelsey 	txr = &txq->vxtxq_cmd_ring;
7688f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
7698f82136aSPatrick Kelsey 
7708f82136aSPatrick Kelsey 	snprintf(txq->vxtxq_name, sizeof(txq->vxtxq_name), "%s-tx%d",
7718f82136aSPatrick Kelsey 	    device_get_nameunit(sc->vmx_dev), q);
7728f82136aSPatrick Kelsey 
7738f82136aSPatrick Kelsey 	txq->vxtxq_sc = sc;
7748f82136aSPatrick Kelsey 	txq->vxtxq_id = q;
7758f82136aSPatrick Kelsey 	txc->vxcr_ndesc = scctx->isc_ntxd[0];
7768f82136aSPatrick Kelsey 	txr->vxtxr_ndesc = scctx->isc_ntxd[1];
777e557c1ddSBryan Venteicher }
7788f82136aSPatrick Kelsey 
7798f82136aSPatrick Kelsey static int
7808f82136aSPatrick Kelsey vmxnet3_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
7818f82136aSPatrick Kelsey     int ntxqs, int ntxqsets)
7828f82136aSPatrick Kelsey {
7838f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
7848f82136aSPatrick Kelsey 	int q;
7858f82136aSPatrick Kelsey 	int error;
7868f82136aSPatrick Kelsey 	caddr_t kva;
7878f82136aSPatrick Kelsey 
7888f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
7898f82136aSPatrick Kelsey 
7908f82136aSPatrick Kelsey 	/* Allocate the array of transmit queues */
7918f82136aSPatrick Kelsey 	sc->vmx_txq = malloc(sizeof(struct vmxnet3_txqueue) *
7928f82136aSPatrick Kelsey 	    ntxqsets, M_DEVBUF, M_NOWAIT | M_ZERO);
7938f82136aSPatrick Kelsey 	if (sc->vmx_txq == NULL)
7948f82136aSPatrick Kelsey 		return (ENOMEM);
7958f82136aSPatrick Kelsey 
7968f82136aSPatrick Kelsey 	/* Initialize driver state for each transmit queue */
7978f82136aSPatrick Kelsey 	for (q = 0; q < ntxqsets; q++)
7988f82136aSPatrick Kelsey 		vmxnet3_init_txq(sc, q);
7998f82136aSPatrick Kelsey 
8008f82136aSPatrick Kelsey 	/*
8018f82136aSPatrick Kelsey 	 * Allocate queue state that is shared with the device.  This check
8028f82136aSPatrick Kelsey 	 * and call is performed in both vmxnet3_tx_queues_alloc() and
8038f82136aSPatrick Kelsey 	 * vmxnet3_rx_queues_alloc() so that we don't have to care which
8048f82136aSPatrick Kelsey 	 * order iflib invokes those routines in.
8058f82136aSPatrick Kelsey 	 */
8068f82136aSPatrick Kelsey 	if (sc->vmx_qs_dma.idi_size == 0) {
8078f82136aSPatrick Kelsey 		error = vmxnet3_queues_shared_alloc(sc);
8088f82136aSPatrick Kelsey 		if (error)
8098f82136aSPatrick Kelsey 			return (error);
810e557c1ddSBryan Venteicher 	}
8118f82136aSPatrick Kelsey 
8128f82136aSPatrick Kelsey 	kva = sc->vmx_qs_dma.idi_vaddr;
8138f82136aSPatrick Kelsey 	for (q = 0; q < ntxqsets; q++) {
8148f82136aSPatrick Kelsey 		sc->vmx_txq[q].vxtxq_ts = (struct vmxnet3_txq_shared *) kva;
8158f82136aSPatrick Kelsey 		kva += sizeof(struct vmxnet3_txq_shared);
8168f82136aSPatrick Kelsey 	}
8178f82136aSPatrick Kelsey 
8188f82136aSPatrick Kelsey 	/* Record descriptor ring vaddrs and paddrs */
8198f82136aSPatrick Kelsey 	for (q = 0; q < ntxqsets; q++) {
8208f82136aSPatrick Kelsey 		struct vmxnet3_txqueue *txq;
8218f82136aSPatrick Kelsey 		struct vmxnet3_txring *txr;
8228f82136aSPatrick Kelsey 		struct vmxnet3_comp_ring *txc;
8238f82136aSPatrick Kelsey 
8248f82136aSPatrick Kelsey 		txq = &sc->vmx_txq[q];
8258f82136aSPatrick Kelsey 		txc = &txq->vxtxq_comp_ring;
8268f82136aSPatrick Kelsey 		txr = &txq->vxtxq_cmd_ring;
8278f82136aSPatrick Kelsey 
8288f82136aSPatrick Kelsey 		/* Completion ring */
8298f82136aSPatrick Kelsey 		txc->vxcr_u.txcd =
8308f82136aSPatrick Kelsey 		    (struct vmxnet3_txcompdesc *) vaddrs[q * ntxqs + 0];
8318f82136aSPatrick Kelsey 		txc->vxcr_paddr = paddrs[q * ntxqs + 0];
8328f82136aSPatrick Kelsey 
8338f82136aSPatrick Kelsey 		/* Command ring */
8348f82136aSPatrick Kelsey 		txr->vxtxr_txd =
8358f82136aSPatrick Kelsey 		    (struct vmxnet3_txdesc *) vaddrs[q * ntxqs + 1];
8368f82136aSPatrick Kelsey 		txr->vxtxr_paddr = paddrs[q * ntxqs + 1];
8378f82136aSPatrick Kelsey 	}
8388f82136aSPatrick Kelsey 
8398f82136aSPatrick Kelsey 	return (0);
840e557c1ddSBryan Venteicher }
841e557c1ddSBryan Venteicher 
842e557c1ddSBryan Venteicher static void
8438f82136aSPatrick Kelsey vmxnet3_init_rxq(struct vmxnet3_softc *sc, int q, int nrxqs)
844e3c97c2cSBryan Venteicher {
845e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
8468f82136aSPatrick Kelsey 	struct vmxnet3_comp_ring *rxc;
847e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
8488f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
849e3c97c2cSBryan Venteicher 	int i;
850e3c97c2cSBryan Venteicher 
851e3c97c2cSBryan Venteicher 	rxq = &sc->vmx_rxq[q];
8528f82136aSPatrick Kelsey 	rxc = &rxq->vxrxq_comp_ring;
8538f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
854e3c97c2cSBryan Venteicher 
855e3c97c2cSBryan Venteicher 	snprintf(rxq->vxrxq_name, sizeof(rxq->vxrxq_name), "%s-rx%d",
856e3c97c2cSBryan Venteicher 	    device_get_nameunit(sc->vmx_dev), q);
857e3c97c2cSBryan Venteicher 
858e3c97c2cSBryan Venteicher 	rxq->vxrxq_sc = sc;
859e3c97c2cSBryan Venteicher 	rxq->vxrxq_id = q;
860e3c97c2cSBryan Venteicher 
8618f82136aSPatrick Kelsey 	/*
8628f82136aSPatrick Kelsey 	 * First rxq is the completion queue, so there are nrxqs - 1 command
8638f82136aSPatrick Kelsey 	 * rings starting at iflib queue id 1.
8648f82136aSPatrick Kelsey 	 */
8658f82136aSPatrick Kelsey 	rxc->vxcr_ndesc = scctx->isc_nrxd[0];
8668f82136aSPatrick Kelsey 	for (i = 0; i < nrxqs - 1; i++) {
867e3c97c2cSBryan Venteicher 		rxr = &rxq->vxrxq_cmd_ring[i];
8688f82136aSPatrick Kelsey 		rxr->vxrxr_ndesc = scctx->isc_nrxd[i + 1];
8693c965775SBryan Venteicher 	}
870e3c97c2cSBryan Venteicher }
871e3c97c2cSBryan Venteicher 
872e3c97c2cSBryan Venteicher static int
8738f82136aSPatrick Kelsey vmxnet3_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
8748f82136aSPatrick Kelsey     int nrxqs, int nrxqsets)
875e3c97c2cSBryan Venteicher {
8768f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
8778f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
8788f82136aSPatrick Kelsey 	int q;
8798f82136aSPatrick Kelsey 	int i;
8808f82136aSPatrick Kelsey 	int error;
8818f82136aSPatrick Kelsey 	caddr_t kva;
882e3c97c2cSBryan Venteicher 
8838f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
8848f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
885e3c97c2cSBryan Venteicher 
8868f82136aSPatrick Kelsey 	/* Allocate the array of receive queues */
8878f82136aSPatrick Kelsey 	sc->vmx_rxq = malloc(sizeof(struct vmxnet3_rxqueue) *
8888f82136aSPatrick Kelsey 	    nrxqsets, M_DEVBUF, M_NOWAIT | M_ZERO);
8898f82136aSPatrick Kelsey 	if (sc->vmx_rxq == NULL)
890e3c97c2cSBryan Venteicher 		return (ENOMEM);
891e3c97c2cSBryan Venteicher 
8928f82136aSPatrick Kelsey 	/* Initialize driver state for each receive queue */
8938f82136aSPatrick Kelsey 	for (q = 0; q < nrxqsets; q++)
8948f82136aSPatrick Kelsey 		vmxnet3_init_rxq(sc, q, nrxqs);
895e3c97c2cSBryan Venteicher 
896e557c1ddSBryan Venteicher 	/*
8978f82136aSPatrick Kelsey 	 * Allocate queue state that is shared with the device.  This check
8988f82136aSPatrick Kelsey 	 * and call is performed in both vmxnet3_tx_queues_alloc() and
8998f82136aSPatrick Kelsey 	 * vmxnet3_rx_queues_alloc() so that we don't have to care which
9008f82136aSPatrick Kelsey 	 * order iflib invokes those routines in.
901e557c1ddSBryan Venteicher 	 */
9028f82136aSPatrick Kelsey 	if (sc->vmx_qs_dma.idi_size == 0) {
9038f82136aSPatrick Kelsey 		error = vmxnet3_queues_shared_alloc(sc);
904e3c97c2cSBryan Venteicher 		if (error)
905e3c97c2cSBryan Venteicher 			return (error);
906e3c97c2cSBryan Venteicher 	}
907e3c97c2cSBryan Venteicher 
9088f82136aSPatrick Kelsey 	kva = sc->vmx_qs_dma.idi_vaddr +
9098f82136aSPatrick Kelsey 	    scctx->isc_ntxqsets * sizeof(struct vmxnet3_txq_shared);
9108f82136aSPatrick Kelsey 	for (q = 0; q < nrxqsets; q++) {
9118f82136aSPatrick Kelsey 		sc->vmx_rxq[q].vxrxq_rs = (struct vmxnet3_rxq_shared *) kva;
9128f82136aSPatrick Kelsey 		kva += sizeof(struct vmxnet3_rxq_shared);
9138f82136aSPatrick Kelsey 	}
9148f82136aSPatrick Kelsey 
9158f82136aSPatrick Kelsey 	/* Record descriptor ring vaddrs and paddrs */
9168f82136aSPatrick Kelsey 	for (q = 0; q < nrxqsets; q++) {
9178f82136aSPatrick Kelsey 		struct vmxnet3_rxqueue *rxq;
9188f82136aSPatrick Kelsey 		struct vmxnet3_rxring *rxr;
9198f82136aSPatrick Kelsey 		struct vmxnet3_comp_ring *rxc;
9208f82136aSPatrick Kelsey 
9218f82136aSPatrick Kelsey 		rxq = &sc->vmx_rxq[q];
9228f82136aSPatrick Kelsey 		rxc = &rxq->vxrxq_comp_ring;
9238f82136aSPatrick Kelsey 
9248f82136aSPatrick Kelsey 		/* Completion ring */
9258f82136aSPatrick Kelsey 		rxc->vxcr_u.rxcd =
9268f82136aSPatrick Kelsey 		    (struct vmxnet3_rxcompdesc *) vaddrs[q * nrxqs + 0];
9278f82136aSPatrick Kelsey 		rxc->vxcr_paddr = paddrs[q * nrxqs + 0];
9288f82136aSPatrick Kelsey 
9298f82136aSPatrick Kelsey 		/* Command ring(s) */
9308f82136aSPatrick Kelsey 		for (i = 0; i < nrxqs - 1; i++) {
9318f82136aSPatrick Kelsey 			rxr = &rxq->vxrxq_cmd_ring[i];
9328f82136aSPatrick Kelsey 
9338f82136aSPatrick Kelsey 			rxr->vxrxr_rxd =
9348f82136aSPatrick Kelsey 			    (struct vmxnet3_rxdesc *) vaddrs[q * nrxqs + 1 + i];
9358f82136aSPatrick Kelsey 			rxr->vxrxr_paddr = paddrs[q * nrxqs + 1 + i];
9368f82136aSPatrick Kelsey 		}
937e3c97c2cSBryan Venteicher 	}
938e3c97c2cSBryan Venteicher 
939e3c97c2cSBryan Venteicher 	return (0);
940e3c97c2cSBryan Venteicher }
941e3c97c2cSBryan Venteicher 
942e3c97c2cSBryan Venteicher static void
9438f82136aSPatrick Kelsey vmxnet3_queues_free(if_ctx_t ctx)
944e3c97c2cSBryan Venteicher {
9458f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
946e3c97c2cSBryan Venteicher 
9478f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
948e3c97c2cSBryan Venteicher 
9498f82136aSPatrick Kelsey 	/* Free queue state area that is shared with the device */
9508f82136aSPatrick Kelsey 	if (sc->vmx_qs_dma.idi_size != 0) {
9518f82136aSPatrick Kelsey 		iflib_dma_free(&sc->vmx_qs_dma);
9528f82136aSPatrick Kelsey 		sc->vmx_qs_dma.idi_size = 0;
953e3c97c2cSBryan Venteicher 	}
954e3c97c2cSBryan Venteicher 
9558f82136aSPatrick Kelsey 	/* Free array of receive queues */
956e3c97c2cSBryan Venteicher 	if (sc->vmx_rxq != NULL) {
957e3c97c2cSBryan Venteicher 		free(sc->vmx_rxq, M_DEVBUF);
958e3c97c2cSBryan Venteicher 		sc->vmx_rxq = NULL;
959e3c97c2cSBryan Venteicher 	}
960e3c97c2cSBryan Venteicher 
9618f82136aSPatrick Kelsey 	/* Free array of transmit queues */
962e3c97c2cSBryan Venteicher 	if (sc->vmx_txq != NULL) {
963e3c97c2cSBryan Venteicher 		free(sc->vmx_txq, M_DEVBUF);
964e3c97c2cSBryan Venteicher 		sc->vmx_txq = NULL;
965e3c97c2cSBryan Venteicher 	}
966e3c97c2cSBryan Venteicher }
967e3c97c2cSBryan Venteicher 
968e3c97c2cSBryan Venteicher static int
969e3c97c2cSBryan Venteicher vmxnet3_alloc_shared_data(struct vmxnet3_softc *sc)
970e3c97c2cSBryan Venteicher {
971e3c97c2cSBryan Venteicher 	device_t dev;
972e3c97c2cSBryan Venteicher 	size_t size;
9738f82136aSPatrick Kelsey 	int error;
974e3c97c2cSBryan Venteicher 
975e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
976e3c97c2cSBryan Venteicher 
9778f82136aSPatrick Kelsey 	/* Top level state structure shared with the device */
978e3c97c2cSBryan Venteicher 	size = sizeof(struct vmxnet3_driver_shared);
9798f82136aSPatrick Kelsey 	error = iflib_dma_alloc_align(sc->vmx_ctx, size, 1, &sc->vmx_ds_dma, 0);
980e3c97c2cSBryan Venteicher 	if (error) {
981e3c97c2cSBryan Venteicher 		device_printf(dev, "cannot alloc shared memory\n");
982e3c97c2cSBryan Venteicher 		return (error);
983e3c97c2cSBryan Venteicher 	}
9848f82136aSPatrick Kelsey 	sc->vmx_ds = (struct vmxnet3_driver_shared *) sc->vmx_ds_dma.idi_vaddr;
985e3c97c2cSBryan Venteicher 
9868f82136aSPatrick Kelsey 	/* RSS table state shared with the device */
987e557c1ddSBryan Venteicher 	if (sc->vmx_flags & VMXNET3_FLAG_RSS) {
988e557c1ddSBryan Venteicher 		size = sizeof(struct vmxnet3_rss_shared);
9898f82136aSPatrick Kelsey 		error = iflib_dma_alloc_align(sc->vmx_ctx, size, 128,
9908f82136aSPatrick Kelsey 		    &sc->vmx_rss_dma, 0);
991e557c1ddSBryan Venteicher 		if (error) {
992e557c1ddSBryan Venteicher 			device_printf(dev, "cannot alloc rss shared memory\n");
993e557c1ddSBryan Venteicher 			return (error);
994e557c1ddSBryan Venteicher 		}
995e557c1ddSBryan Venteicher 		sc->vmx_rss =
9968f82136aSPatrick Kelsey 		    (struct vmxnet3_rss_shared *) sc->vmx_rss_dma.idi_vaddr;
997e557c1ddSBryan Venteicher 	}
998e557c1ddSBryan Venteicher 
999e3c97c2cSBryan Venteicher 	return (0);
1000e3c97c2cSBryan Venteicher }
1001e3c97c2cSBryan Venteicher 
1002e3c97c2cSBryan Venteicher static void
1003e3c97c2cSBryan Venteicher vmxnet3_free_shared_data(struct vmxnet3_softc *sc)
1004e3c97c2cSBryan Venteicher {
1005e3c97c2cSBryan Venteicher 
10068f82136aSPatrick Kelsey 	/* Free RSS table state shared with the device */
1007e557c1ddSBryan Venteicher 	if (sc->vmx_rss != NULL) {
10088f82136aSPatrick Kelsey 		iflib_dma_free(&sc->vmx_rss_dma);
1009e557c1ddSBryan Venteicher 		sc->vmx_rss = NULL;
1010e557c1ddSBryan Venteicher 	}
1011e557c1ddSBryan Venteicher 
10128f82136aSPatrick Kelsey 	/* Free top level state structure shared with the device */
1013e3c97c2cSBryan Venteicher 	if (sc->vmx_ds != NULL) {
10148f82136aSPatrick Kelsey 		iflib_dma_free(&sc->vmx_ds_dma);
1015e3c97c2cSBryan Venteicher 		sc->vmx_ds = NULL;
1016e3c97c2cSBryan Venteicher 	}
1017e3c97c2cSBryan Venteicher }
1018e3c97c2cSBryan Venteicher 
1019e3c97c2cSBryan Venteicher static int
1020e3c97c2cSBryan Venteicher vmxnet3_alloc_mcast_table(struct vmxnet3_softc *sc)
1021e3c97c2cSBryan Venteicher {
1022e3c97c2cSBryan Venteicher 	int error;
1023e3c97c2cSBryan Venteicher 
10248f82136aSPatrick Kelsey 	/* Multicast table state shared with the device */
10258f82136aSPatrick Kelsey 	error = iflib_dma_alloc_align(sc->vmx_ctx,
10268f82136aSPatrick Kelsey 	    VMXNET3_MULTICAST_MAX * ETHER_ADDR_LEN, 32, &sc->vmx_mcast_dma, 0);
1027e3c97c2cSBryan Venteicher 	if (error)
1028e3c97c2cSBryan Venteicher 		device_printf(sc->vmx_dev, "unable to alloc multicast table\n");
1029e3c97c2cSBryan Venteicher 	else
10308f82136aSPatrick Kelsey 		sc->vmx_mcast = sc->vmx_mcast_dma.idi_vaddr;
1031e3c97c2cSBryan Venteicher 
1032e3c97c2cSBryan Venteicher 	return (error);
1033e3c97c2cSBryan Venteicher }
1034e3c97c2cSBryan Venteicher 
1035e3c97c2cSBryan Venteicher static void
1036e3c97c2cSBryan Venteicher vmxnet3_free_mcast_table(struct vmxnet3_softc *sc)
1037e3c97c2cSBryan Venteicher {
1038e3c97c2cSBryan Venteicher 
10398f82136aSPatrick Kelsey 	/* Free multicast table state shared with the device */
1040e3c97c2cSBryan Venteicher 	if (sc->vmx_mcast != NULL) {
10418f82136aSPatrick Kelsey 		iflib_dma_free(&sc->vmx_mcast_dma);
1042e3c97c2cSBryan Venteicher 		sc->vmx_mcast = NULL;
1043e3c97c2cSBryan Venteicher 	}
1044e3c97c2cSBryan Venteicher }
1045e3c97c2cSBryan Venteicher 
1046e3c97c2cSBryan Venteicher static void
1047e3c97c2cSBryan Venteicher vmxnet3_init_shared_data(struct vmxnet3_softc *sc)
1048e3c97c2cSBryan Venteicher {
1049e3c97c2cSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
10508f82136aSPatrick Kelsey 	if_shared_ctx_t sctx;
10518f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
1052e3c97c2cSBryan Venteicher 	struct vmxnet3_txqueue *txq;
1053e3c97c2cSBryan Venteicher 	struct vmxnet3_txq_shared *txs;
1054e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
1055e3c97c2cSBryan Venteicher 	struct vmxnet3_rxq_shared *rxs;
1056e3c97c2cSBryan Venteicher 	int i;
1057e3c97c2cSBryan Venteicher 
1058e3c97c2cSBryan Venteicher 	ds = sc->vmx_ds;
10598f82136aSPatrick Kelsey 	sctx = sc->vmx_sctx;
10608f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
1061e3c97c2cSBryan Venteicher 
1062e3c97c2cSBryan Venteicher 	/*
1063e3c97c2cSBryan Venteicher 	 * Initialize fields of the shared data that remains the same across
1064e3c97c2cSBryan Venteicher 	 * reinits. Note the shared data is zero'd when allocated.
1065e3c97c2cSBryan Venteicher 	 */
1066e3c97c2cSBryan Venteicher 
1067e3c97c2cSBryan Venteicher 	ds->magic = VMXNET3_REV1_MAGIC;
1068e3c97c2cSBryan Venteicher 
1069e3c97c2cSBryan Venteicher 	/* DriverInfo */
1070e3c97c2cSBryan Venteicher 	ds->version = VMXNET3_DRIVER_VERSION;
1071ce3be286SBryan Venteicher 	ds->guest = VMXNET3_GOS_FREEBSD |
1072e3c97c2cSBryan Venteicher #ifdef __LP64__
1073e3c97c2cSBryan Venteicher 	    VMXNET3_GOS_64BIT;
1074e3c97c2cSBryan Venteicher #else
1075e3c97c2cSBryan Venteicher 	    VMXNET3_GOS_32BIT;
1076e3c97c2cSBryan Venteicher #endif
1077e3c97c2cSBryan Venteicher 	ds->vmxnet3_revision = 1;
1078e3c97c2cSBryan Venteicher 	ds->upt_version = 1;
1079e3c97c2cSBryan Venteicher 
1080e3c97c2cSBryan Venteicher 	/* Misc. conf */
1081e3c97c2cSBryan Venteicher 	ds->driver_data = vtophys(sc);
1082e3c97c2cSBryan Venteicher 	ds->driver_data_len = sizeof(struct vmxnet3_softc);
10838f82136aSPatrick Kelsey 	ds->queue_shared = sc->vmx_qs_dma.idi_paddr;
10848f82136aSPatrick Kelsey 	ds->queue_shared_len = sc->vmx_qs_dma.idi_size;
10858f82136aSPatrick Kelsey 	ds->nrxsg_max = IFLIB_MAX_RX_SEGS;
1086e3c97c2cSBryan Venteicher 
1087e557c1ddSBryan Venteicher 	/* RSS conf */
1088e557c1ddSBryan Venteicher 	if (sc->vmx_flags & VMXNET3_FLAG_RSS) {
1089e557c1ddSBryan Venteicher 		ds->rss.version = 1;
10908f82136aSPatrick Kelsey 		ds->rss.paddr = sc->vmx_rss_dma.idi_paddr;
10918f82136aSPatrick Kelsey 		ds->rss.len = sc->vmx_rss_dma.idi_size;
1092e557c1ddSBryan Venteicher 	}
1093e557c1ddSBryan Venteicher 
1094e3c97c2cSBryan Venteicher 	/* Interrupt control. */
1095e3c97c2cSBryan Venteicher 	ds->automask = sc->vmx_intr_mask_mode == VMXNET3_IMM_AUTO;
10968f82136aSPatrick Kelsey 	/*
10978f82136aSPatrick Kelsey 	 * Total number of interrupt indexes we are using in the shared
1098769d56ecSPatrick Kelsey 	 * config data, even though we don't actually allocate interrupt
10998f82136aSPatrick Kelsey 	 * resources for the tx queues.  Some versions of the device will
11008f82136aSPatrick Kelsey 	 * fail to initialize successfully if interrupt indexes are used in
11018f82136aSPatrick Kelsey 	 * the shared config that exceed the number of interrupts configured
11028f82136aSPatrick Kelsey 	 * here.
11038f82136aSPatrick Kelsey 	 */
11048f82136aSPatrick Kelsey 	ds->nintr = (scctx->isc_vectors == 1) ?
1105769d56ecSPatrick Kelsey 	    2 : (scctx->isc_nrxqsets + scctx->isc_ntxqsets + 1);
1106e3c97c2cSBryan Venteicher 	ds->evintr = sc->vmx_event_intr_idx;
1107e3c97c2cSBryan Venteicher 	ds->ictrl = VMXNET3_ICTRL_DISABLE_ALL;
1108e3c97c2cSBryan Venteicher 
11098f82136aSPatrick Kelsey 	for (i = 0; i < ds->nintr; i++)
1110e3c97c2cSBryan Venteicher 		ds->modlevel[i] = UPT1_IMOD_ADAPTIVE;
1111e3c97c2cSBryan Venteicher 
1112e3c97c2cSBryan Venteicher 	/* Receive filter. */
11138f82136aSPatrick Kelsey 	ds->mcast_table = sc->vmx_mcast_dma.idi_paddr;
11148f82136aSPatrick Kelsey 	ds->mcast_tablelen = sc->vmx_mcast_dma.idi_size;
1115e3c97c2cSBryan Venteicher 
1116e3c97c2cSBryan Venteicher 	/* Tx queues */
11178f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++) {
1118e3c97c2cSBryan Venteicher 		txq = &sc->vmx_txq[i];
1119e3c97c2cSBryan Venteicher 		txs = txq->vxtxq_ts;
1120e3c97c2cSBryan Venteicher 
11218f82136aSPatrick Kelsey 		txs->cmd_ring = txq->vxtxq_cmd_ring.vxtxr_paddr;
11223c965775SBryan Venteicher 		txs->cmd_ring_len = txq->vxtxq_cmd_ring.vxtxr_ndesc;
11238f82136aSPatrick Kelsey 		txs->comp_ring = txq->vxtxq_comp_ring.vxcr_paddr;
11243c965775SBryan Venteicher 		txs->comp_ring_len = txq->vxtxq_comp_ring.vxcr_ndesc;
1125e3c97c2cSBryan Venteicher 		txs->driver_data = vtophys(txq);
1126e3c97c2cSBryan Venteicher 		txs->driver_data_len = sizeof(struct vmxnet3_txqueue);
1127e3c97c2cSBryan Venteicher 	}
1128e3c97c2cSBryan Venteicher 
1129e3c97c2cSBryan Venteicher 	/* Rx queues */
11308f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
1131e3c97c2cSBryan Venteicher 		rxq = &sc->vmx_rxq[i];
1132e3c97c2cSBryan Venteicher 		rxs = rxq->vxrxq_rs;
1133e3c97c2cSBryan Venteicher 
11348f82136aSPatrick Kelsey 		rxs->cmd_ring[0] = rxq->vxrxq_cmd_ring[0].vxrxr_paddr;
1135e3c97c2cSBryan Venteicher 		rxs->cmd_ring_len[0] = rxq->vxrxq_cmd_ring[0].vxrxr_ndesc;
11368f82136aSPatrick Kelsey 		rxs->cmd_ring[1] = rxq->vxrxq_cmd_ring[1].vxrxr_paddr;
1137e3c97c2cSBryan Venteicher 		rxs->cmd_ring_len[1] = rxq->vxrxq_cmd_ring[1].vxrxr_ndesc;
11388f82136aSPatrick Kelsey 		rxs->comp_ring = rxq->vxrxq_comp_ring.vxcr_paddr;
11393c965775SBryan Venteicher 		rxs->comp_ring_len = rxq->vxrxq_comp_ring.vxcr_ndesc;
1140e3c97c2cSBryan Venteicher 		rxs->driver_data = vtophys(rxq);
1141e3c97c2cSBryan Venteicher 		rxs->driver_data_len = sizeof(struct vmxnet3_rxqueue);
1142e3c97c2cSBryan Venteicher 	}
1143e3c97c2cSBryan Venteicher }
1144e3c97c2cSBryan Venteicher 
1145e3c97c2cSBryan Venteicher static void
1146e557c1ddSBryan Venteicher vmxnet3_reinit_rss_shared_data(struct vmxnet3_softc *sc)
1147e557c1ddSBryan Venteicher {
1148e557c1ddSBryan Venteicher 	/*
1149e557c1ddSBryan Venteicher 	 * Use the same key as the Linux driver until FreeBSD can do
1150e557c1ddSBryan Venteicher 	 * RSS (presumably Toeplitz) in software.
1151e557c1ddSBryan Venteicher 	 */
1152e557c1ddSBryan Venteicher 	static const uint8_t rss_key[UPT1_RSS_MAX_KEY_SIZE] = {
1153e557c1ddSBryan Venteicher 	    0x3b, 0x56, 0xd1, 0x56, 0x13, 0x4a, 0xe7, 0xac,
1154e557c1ddSBryan Venteicher 	    0xe8, 0x79, 0x09, 0x75, 0xe8, 0x65, 0x79, 0x28,
1155e557c1ddSBryan Venteicher 	    0x35, 0x12, 0xb9, 0x56, 0x7c, 0x76, 0x4b, 0x70,
1156e557c1ddSBryan Venteicher 	    0xd8, 0x56, 0xa3, 0x18, 0x9b, 0x0a, 0xee, 0xf3,
1157e557c1ddSBryan Venteicher 	    0x96, 0xa6, 0x9f, 0x8f, 0x9e, 0x8c, 0x90, 0xc9,
1158e557c1ddSBryan Venteicher 	};
1159e557c1ddSBryan Venteicher 
1160e557c1ddSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
11618f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
1162e557c1ddSBryan Venteicher 	struct vmxnet3_rss_shared *rss;
1163281cab4dSAndriy Gapon #ifdef RSS
1164281cab4dSAndriy Gapon 	uint8_t rss_algo;
1165281cab4dSAndriy Gapon #endif
1166e557c1ddSBryan Venteicher 	int i;
1167e557c1ddSBryan Venteicher 
1168e557c1ddSBryan Venteicher 	ds = sc->vmx_ds;
11698f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
1170e557c1ddSBryan Venteicher 	rss = sc->vmx_rss;
1171e557c1ddSBryan Venteicher 
1172e557c1ddSBryan Venteicher 	rss->hash_type =
1173e557c1ddSBryan Venteicher 	    UPT1_RSS_HASH_TYPE_IPV4 | UPT1_RSS_HASH_TYPE_TCP_IPV4 |
1174e557c1ddSBryan Venteicher 	    UPT1_RSS_HASH_TYPE_IPV6 | UPT1_RSS_HASH_TYPE_TCP_IPV6;
1175e557c1ddSBryan Venteicher 	rss->hash_func = UPT1_RSS_HASH_FUNC_TOEPLITZ;
1176e557c1ddSBryan Venteicher 	rss->hash_key_size = UPT1_RSS_MAX_KEY_SIZE;
1177e557c1ddSBryan Venteicher 	rss->ind_table_size = UPT1_RSS_MAX_IND_TABLE_SIZE;
1178281cab4dSAndriy Gapon #ifdef RSS
1179281cab4dSAndriy Gapon 	/*
1180281cab4dSAndriy Gapon 	 * If the software RSS is configured to anything else other than
1181281cab4dSAndriy Gapon 	 * Toeplitz, then just do Toeplitz in "hardware" for the sake of
1182281cab4dSAndriy Gapon 	 * the packet distribution, but report the hash as opaque to
1183281cab4dSAndriy Gapon 	 * disengage from the software RSS.
1184281cab4dSAndriy Gapon 	 */
1185281cab4dSAndriy Gapon 	rss_algo = rss_gethashalgo();
1186281cab4dSAndriy Gapon 	if (rss_algo == RSS_HASH_TOEPLITZ) {
1187281cab4dSAndriy Gapon 		rss_getkey(rss->hash_key);
1188281cab4dSAndriy Gapon 		for (i = 0; i < UPT1_RSS_MAX_IND_TABLE_SIZE; i++) {
1189281cab4dSAndriy Gapon 			rss->ind_table[i] = rss_get_indirection_to_bucket(i) %
1190281cab4dSAndriy Gapon 			    scctx->isc_nrxqsets;
1191281cab4dSAndriy Gapon 		}
1192281cab4dSAndriy Gapon 		sc->vmx_flags |= VMXNET3_FLAG_SOFT_RSS;
1193281cab4dSAndriy Gapon 	} else
1194281cab4dSAndriy Gapon #endif
1195281cab4dSAndriy Gapon 	{
1196e557c1ddSBryan Venteicher 		memcpy(rss->hash_key, rss_key, UPT1_RSS_MAX_KEY_SIZE);
1197e557c1ddSBryan Venteicher 		for (i = 0; i < UPT1_RSS_MAX_IND_TABLE_SIZE; i++)
11988f82136aSPatrick Kelsey 			rss->ind_table[i] = i % scctx->isc_nrxqsets;
1199281cab4dSAndriy Gapon 		sc->vmx_flags &= ~VMXNET3_FLAG_SOFT_RSS;
1200281cab4dSAndriy Gapon 	}
1201e3c97c2cSBryan Venteicher }
1202e3c97c2cSBryan Venteicher 
1203e3c97c2cSBryan Venteicher static void
1204e3c97c2cSBryan Venteicher vmxnet3_reinit_shared_data(struct vmxnet3_softc *sc)
1205e3c97c2cSBryan Venteicher {
1206e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
1207e3c97c2cSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
12088f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
1209e3c97c2cSBryan Venteicher 
1210e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
1211e3c97c2cSBryan Venteicher 	ds = sc->vmx_ds;
12128f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
1213e3c97c2cSBryan Venteicher 
1214e557c1ddSBryan Venteicher 	ds->mtu = ifp->if_mtu;
12158f82136aSPatrick Kelsey 	ds->ntxqueue = scctx->isc_ntxqsets;
12168f82136aSPatrick Kelsey 	ds->nrxqueue = scctx->isc_nrxqsets;
1217e557c1ddSBryan Venteicher 
1218e3c97c2cSBryan Venteicher 	ds->upt_features = 0;
1219e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6))
1220e3c97c2cSBryan Venteicher 		ds->upt_features |= UPT1_F_CSUM;
12213c5dfe89SBryan Venteicher 	if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
12223c5dfe89SBryan Venteicher 		ds->upt_features |= UPT1_F_VLAN;
1223e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & IFCAP_LRO)
1224e3c97c2cSBryan Venteicher 		ds->upt_features |= UPT1_F_LRO;
1225e3c97c2cSBryan Venteicher 
1226e557c1ddSBryan Venteicher 	if (sc->vmx_flags & VMXNET3_FLAG_RSS) {
1227e557c1ddSBryan Venteicher 		ds->upt_features |= UPT1_F_RSS;
1228e557c1ddSBryan Venteicher 		vmxnet3_reinit_rss_shared_data(sc);
1229e557c1ddSBryan Venteicher 	}
1230e3c97c2cSBryan Venteicher 
12318f82136aSPatrick Kelsey 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_DSL, sc->vmx_ds_dma.idi_paddr);
1232e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_DSH,
12338f82136aSPatrick Kelsey 	    (uint64_t) sc->vmx_ds_dma.idi_paddr >> 32);
1234e3c97c2cSBryan Venteicher }
1235e3c97c2cSBryan Venteicher 
1236e3c97c2cSBryan Venteicher static int
1237e3c97c2cSBryan Venteicher vmxnet3_alloc_data(struct vmxnet3_softc *sc)
1238e3c97c2cSBryan Venteicher {
1239e3c97c2cSBryan Venteicher 	int error;
1240e3c97c2cSBryan Venteicher 
1241e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_shared_data(sc);
1242e3c97c2cSBryan Venteicher 	if (error)
1243e3c97c2cSBryan Venteicher 		return (error);
1244e3c97c2cSBryan Venteicher 
1245e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_mcast_table(sc);
1246e3c97c2cSBryan Venteicher 	if (error)
1247e3c97c2cSBryan Venteicher 		return (error);
1248e3c97c2cSBryan Venteicher 
1249e3c97c2cSBryan Venteicher 	vmxnet3_init_shared_data(sc);
1250e3c97c2cSBryan Venteicher 
1251e3c97c2cSBryan Venteicher 	return (0);
1252e3c97c2cSBryan Venteicher }
1253e3c97c2cSBryan Venteicher 
1254e3c97c2cSBryan Venteicher static void
1255e3c97c2cSBryan Venteicher vmxnet3_free_data(struct vmxnet3_softc *sc)
1256e3c97c2cSBryan Venteicher {
1257e3c97c2cSBryan Venteicher 
1258e3c97c2cSBryan Venteicher 	vmxnet3_free_mcast_table(sc);
1259e3c97c2cSBryan Venteicher 	vmxnet3_free_shared_data(sc);
1260e3c97c2cSBryan Venteicher }
1261e3c97c2cSBryan Venteicher 
1262e3c97c2cSBryan Venteicher static void
1263e3c97c2cSBryan Venteicher vmxnet3_evintr(struct vmxnet3_softc *sc)
1264e3c97c2cSBryan Venteicher {
1265e3c97c2cSBryan Venteicher 	device_t dev;
1266e3c97c2cSBryan Venteicher 	struct vmxnet3_txq_shared *ts;
1267e3c97c2cSBryan Venteicher 	struct vmxnet3_rxq_shared *rs;
1268e3c97c2cSBryan Venteicher 	uint32_t event;
1269e3c97c2cSBryan Venteicher 
1270e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
1271e3c97c2cSBryan Venteicher 
1272e3c97c2cSBryan Venteicher 	/* Clear events. */
1273e3c97c2cSBryan Venteicher 	event = sc->vmx_ds->event;
1274e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_EVENT, event);
1275e3c97c2cSBryan Venteicher 
12768f82136aSPatrick Kelsey 	if (event & VMXNET3_EVENT_LINK)
1277e3c97c2cSBryan Venteicher 		vmxnet3_link_status(sc);
1278e3c97c2cSBryan Venteicher 
1279e3c97c2cSBryan Venteicher 	if (event & (VMXNET3_EVENT_TQERROR | VMXNET3_EVENT_RQERROR)) {
1280e3c97c2cSBryan Venteicher 		vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_STATUS);
1281e3c97c2cSBryan Venteicher 		ts = sc->vmx_txq[0].vxtxq_ts;
1282e3c97c2cSBryan Venteicher 		if (ts->stopped != 0)
1283e3c97c2cSBryan Venteicher 			device_printf(dev, "Tx queue error %#x\n", ts->error);
1284e3c97c2cSBryan Venteicher 		rs = sc->vmx_rxq[0].vxrxq_rs;
1285e3c97c2cSBryan Venteicher 		if (rs->stopped != 0)
1286e3c97c2cSBryan Venteicher 			device_printf(dev, "Rx queue error %#x\n", rs->error);
12878f82136aSPatrick Kelsey 
12888f82136aSPatrick Kelsey 		/* XXX - rely on liflib watchdog to reset us? */
12898f82136aSPatrick Kelsey 		device_printf(dev, "Rx/Tx queue error event ... "
12908f82136aSPatrick Kelsey 		    "waiting for iflib watchdog reset\n");
1291e3c97c2cSBryan Venteicher 	}
1292e3c97c2cSBryan Venteicher 
1293e3c97c2cSBryan Venteicher 	if (event & VMXNET3_EVENT_DIC)
1294e3c97c2cSBryan Venteicher 		device_printf(dev, "device implementation change event\n");
1295e3c97c2cSBryan Venteicher 	if (event & VMXNET3_EVENT_DEBUG)
1296e3c97c2cSBryan Venteicher 		device_printf(dev, "debug event\n");
1297e3c97c2cSBryan Venteicher }
1298e3c97c2cSBryan Venteicher 
12998f82136aSPatrick Kelsey static int
13008f82136aSPatrick Kelsey vmxnet3_isc_txd_encap(void *vsc, if_pkt_info_t pi)
13018f82136aSPatrick Kelsey {
13028f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
13038f82136aSPatrick Kelsey 	struct vmxnet3_txqueue *txq;
13048f82136aSPatrick Kelsey 	struct vmxnet3_txring *txr;
13058f82136aSPatrick Kelsey 	struct vmxnet3_txdesc *txd, *sop;
13068f82136aSPatrick Kelsey 	bus_dma_segment_t *segs;
13078f82136aSPatrick Kelsey 	int nsegs;
13088f82136aSPatrick Kelsey 	int pidx;
13098f82136aSPatrick Kelsey 	int hdrlen;
13108f82136aSPatrick Kelsey 	int i;
13118f82136aSPatrick Kelsey 	int gen;
13128f82136aSPatrick Kelsey 
13138f82136aSPatrick Kelsey 	sc = vsc;
13148f82136aSPatrick Kelsey 	txq = &sc->vmx_txq[pi->ipi_qsidx];
13158f82136aSPatrick Kelsey 	txr = &txq->vxtxq_cmd_ring;
13168f82136aSPatrick Kelsey 	segs = pi->ipi_segs;
13178f82136aSPatrick Kelsey 	nsegs = pi->ipi_nsegs;
13188f82136aSPatrick Kelsey 	pidx = pi->ipi_pidx;
13198f82136aSPatrick Kelsey 
13208f82136aSPatrick Kelsey 	KASSERT(nsegs <= VMXNET3_TX_MAXSEGS,
13218f82136aSPatrick Kelsey 	    ("%s: packet with too many segments %d", __func__, nsegs));
13228f82136aSPatrick Kelsey 
13238f82136aSPatrick Kelsey 	sop = &txr->vxtxr_txd[pidx];
13248f82136aSPatrick Kelsey 	gen = txr->vxtxr_gen ^ 1;	/* Owned by cpu (yet) */
13258f82136aSPatrick Kelsey 
13268f82136aSPatrick Kelsey 	for (i = 0; i < nsegs; i++) {
13278f82136aSPatrick Kelsey 		txd = &txr->vxtxr_txd[pidx];
13288f82136aSPatrick Kelsey 
13298f82136aSPatrick Kelsey 		txd->addr = segs[i].ds_addr;
13308f82136aSPatrick Kelsey 		txd->len = segs[i].ds_len;
13318f82136aSPatrick Kelsey 		txd->gen = gen;
13328f82136aSPatrick Kelsey 		txd->dtype = 0;
13338f82136aSPatrick Kelsey 		txd->offload_mode = VMXNET3_OM_NONE;
13348f82136aSPatrick Kelsey 		txd->offload_pos = 0;
13358f82136aSPatrick Kelsey 		txd->hlen = 0;
13368f82136aSPatrick Kelsey 		txd->eop = 0;
13378f82136aSPatrick Kelsey 		txd->compreq = 0;
13388f82136aSPatrick Kelsey 		txd->vtag_mode = 0;
13398f82136aSPatrick Kelsey 		txd->vtag = 0;
13408f82136aSPatrick Kelsey 
13418f82136aSPatrick Kelsey 		if (++pidx == txr->vxtxr_ndesc) {
13428f82136aSPatrick Kelsey 			pidx = 0;
13438f82136aSPatrick Kelsey 			txr->vxtxr_gen ^= 1;
13448f82136aSPatrick Kelsey 		}
13458f82136aSPatrick Kelsey 		gen = txr->vxtxr_gen;
13468f82136aSPatrick Kelsey 	}
13478f82136aSPatrick Kelsey 	txd->eop = 1;
13488f82136aSPatrick Kelsey 	txd->compreq = !!(pi->ipi_flags & IPI_TX_INTR);
13498f82136aSPatrick Kelsey 	pi->ipi_new_pidx = pidx;
13508f82136aSPatrick Kelsey 
13518f82136aSPatrick Kelsey 	/*
13528f82136aSPatrick Kelsey 	 * VLAN
13538f82136aSPatrick Kelsey 	 */
13548f82136aSPatrick Kelsey 	if (pi->ipi_mflags & M_VLANTAG) {
13558f82136aSPatrick Kelsey 		sop->vtag_mode = 1;
13568f82136aSPatrick Kelsey 		sop->vtag = pi->ipi_vtag;
13578f82136aSPatrick Kelsey 	}
13588f82136aSPatrick Kelsey 
13598f82136aSPatrick Kelsey 	/*
13608f82136aSPatrick Kelsey 	 * TSO and checksum offloads
13618f82136aSPatrick Kelsey 	 */
13628f82136aSPatrick Kelsey 	hdrlen = pi->ipi_ehdrlen + pi->ipi_ip_hlen;
13638f82136aSPatrick Kelsey 	if (pi->ipi_csum_flags & CSUM_TSO) {
13648f82136aSPatrick Kelsey 		sop->offload_mode = VMXNET3_OM_TSO;
1365f55f37d9SVincenzo Maffione 		sop->hlen = hdrlen + pi->ipi_tcp_hlen;
13668f82136aSPatrick Kelsey 		sop->offload_pos = pi->ipi_tso_segsz;
13678f82136aSPatrick Kelsey 	} else if (pi->ipi_csum_flags & (VMXNET3_CSUM_OFFLOAD |
13688f82136aSPatrick Kelsey 	    VMXNET3_CSUM_OFFLOAD_IPV6)) {
13698f82136aSPatrick Kelsey 		sop->offload_mode = VMXNET3_OM_CSUM;
13708f82136aSPatrick Kelsey 		sop->hlen = hdrlen;
13718f82136aSPatrick Kelsey 		sop->offload_pos = hdrlen +
13728f82136aSPatrick Kelsey 		    ((pi->ipi_ipproto == IPPROTO_TCP) ?
13738f82136aSPatrick Kelsey 			offsetof(struct tcphdr, th_sum) :
13748f82136aSPatrick Kelsey 			offsetof(struct udphdr, uh_sum));
13758f82136aSPatrick Kelsey 	}
13768f82136aSPatrick Kelsey 
13778f82136aSPatrick Kelsey 	/* Finally, change the ownership. */
13788f82136aSPatrick Kelsey 	vmxnet3_barrier(sc, VMXNET3_BARRIER_WR);
13798f82136aSPatrick Kelsey 	sop->gen ^= 1;
13808f82136aSPatrick Kelsey 
13818f82136aSPatrick Kelsey 	return (0);
1382e3c97c2cSBryan Venteicher }
1383e3c97c2cSBryan Venteicher 
1384e3c97c2cSBryan Venteicher static void
13858f82136aSPatrick Kelsey vmxnet3_isc_txd_flush(void *vsc, uint16_t txqid, qidx_t pidx)
1386e3c97c2cSBryan Venteicher {
1387e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
13888f82136aSPatrick Kelsey 	struct vmxnet3_txqueue *txq;
13898f82136aSPatrick Kelsey 
13908f82136aSPatrick Kelsey 	sc = vsc;
13918f82136aSPatrick Kelsey 	txq = &sc->vmx_txq[txqid];
13928f82136aSPatrick Kelsey 
13938f82136aSPatrick Kelsey 	/*
13948f82136aSPatrick Kelsey 	 * pidx is what we last set ipi_new_pidx to in
13958f82136aSPatrick Kelsey 	 * vmxnet3_isc_txd_encap()
13968f82136aSPatrick Kelsey 	 */
13978f82136aSPatrick Kelsey 
13988f82136aSPatrick Kelsey 	/*
13998f82136aSPatrick Kelsey 	 * Avoid expensive register updates if the flush request is
14008f82136aSPatrick Kelsey 	 * redundant.
14018f82136aSPatrick Kelsey 	 */
14028f82136aSPatrick Kelsey 	if (txq->vxtxq_last_flush == pidx)
14038f82136aSPatrick Kelsey 		return;
14048f82136aSPatrick Kelsey 	txq->vxtxq_last_flush = pidx;
14058f82136aSPatrick Kelsey 	vmxnet3_write_bar0(sc, VMXNET3_BAR0_TXH(txq->vxtxq_id), pidx);
14068f82136aSPatrick Kelsey }
14078f82136aSPatrick Kelsey 
14088f82136aSPatrick Kelsey static int
14098f82136aSPatrick Kelsey vmxnet3_isc_txd_credits_update(void *vsc, uint16_t txqid, bool clear)
14108f82136aSPatrick Kelsey {
14118f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
14128f82136aSPatrick Kelsey 	struct vmxnet3_txqueue *txq;
1413e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *txc;
1414e3c97c2cSBryan Venteicher 	struct vmxnet3_txcompdesc *txcd;
14158f82136aSPatrick Kelsey 	struct vmxnet3_txring *txr;
14168f82136aSPatrick Kelsey 	int processed;
1417e3c97c2cSBryan Venteicher 
14188f82136aSPatrick Kelsey 	sc = vsc;
14198f82136aSPatrick Kelsey 	txq = &sc->vmx_txq[txqid];
1420e3c97c2cSBryan Venteicher 	txc = &txq->vxtxq_comp_ring;
14218f82136aSPatrick Kelsey 	txr = &txq->vxtxq_cmd_ring;
1422e3c97c2cSBryan Venteicher 
14238f82136aSPatrick Kelsey 	/*
14248f82136aSPatrick Kelsey 	 * If clear is true, we need to report the number of TX command ring
14258f82136aSPatrick Kelsey 	 * descriptors that have been processed by the device.  If clear is
14268f82136aSPatrick Kelsey 	 * false, we just need to report whether or not at least one TX
14278f82136aSPatrick Kelsey 	 * command ring descriptor has been processed by the device.
14288f82136aSPatrick Kelsey 	 */
14298f82136aSPatrick Kelsey 	processed = 0;
1430e3c97c2cSBryan Venteicher 	for (;;) {
1431e3c97c2cSBryan Venteicher 		txcd = &txc->vxcr_u.txcd[txc->vxcr_next];
1432e3c97c2cSBryan Venteicher 		if (txcd->gen != txc->vxcr_gen)
1433e3c97c2cSBryan Venteicher 			break;
14348f82136aSPatrick Kelsey 		else if (!clear)
14358f82136aSPatrick Kelsey 			return (1);
14363c965775SBryan Venteicher 		vmxnet3_barrier(sc, VMXNET3_BARRIER_RD);
1437e3c97c2cSBryan Venteicher 
1438e3c97c2cSBryan Venteicher 		if (++txc->vxcr_next == txc->vxcr_ndesc) {
1439e3c97c2cSBryan Venteicher 			txc->vxcr_next = 0;
1440e3c97c2cSBryan Venteicher 			txc->vxcr_gen ^= 1;
1441e3c97c2cSBryan Venteicher 		}
1442e3c97c2cSBryan Venteicher 
14438f82136aSPatrick Kelsey 		if (txcd->eop_idx < txr->vxtxr_next)
14448f82136aSPatrick Kelsey 			processed += txr->vxtxr_ndesc -
14458f82136aSPatrick Kelsey 			    (txr->vxtxr_next - txcd->eop_idx) + 1;
14468f82136aSPatrick Kelsey 		else
14478f82136aSPatrick Kelsey 			processed += txcd->eop_idx - txr->vxtxr_next + 1;
1448e3c97c2cSBryan Venteicher 		txr->vxtxr_next = (txcd->eop_idx + 1) % txr->vxtxr_ndesc;
1449e3c97c2cSBryan Venteicher 	}
1450e3c97c2cSBryan Venteicher 
14518f82136aSPatrick Kelsey 	return (processed);
1452e3c97c2cSBryan Venteicher }
1453e3c97c2cSBryan Venteicher 
1454e3c97c2cSBryan Venteicher static int
14558f82136aSPatrick Kelsey vmxnet3_isc_rxd_available(void *vsc, uint16_t rxqid, qidx_t idx, qidx_t budget)
1456e3c97c2cSBryan Venteicher {
14578f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
14588f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
14598f82136aSPatrick Kelsey 	struct vmxnet3_comp_ring *rxc;
14608f82136aSPatrick Kelsey 	struct vmxnet3_rxcompdesc *rxcd;
14618f82136aSPatrick Kelsey 	int avail;
14628f82136aSPatrick Kelsey 	int completed_gen;
14638f82136aSPatrick Kelsey #ifdef INVARIANTS
14648f82136aSPatrick Kelsey 	int expect_sop = 1;
14658f82136aSPatrick Kelsey #endif
14668f82136aSPatrick Kelsey 	sc = vsc;
14678f82136aSPatrick Kelsey 	rxq = &sc->vmx_rxq[rxqid];
14688f82136aSPatrick Kelsey 	rxc = &rxq->vxrxq_comp_ring;
14698f82136aSPatrick Kelsey 
14708f82136aSPatrick Kelsey 	avail = 0;
14718f82136aSPatrick Kelsey 	completed_gen = rxc->vxcr_gen;
14728f82136aSPatrick Kelsey 	for (;;) {
14738f82136aSPatrick Kelsey 		rxcd = &rxc->vxcr_u.rxcd[idx];
14748f82136aSPatrick Kelsey 		if (rxcd->gen != completed_gen)
14758f82136aSPatrick Kelsey 			break;
14768f82136aSPatrick Kelsey 		vmxnet3_barrier(sc, VMXNET3_BARRIER_RD);
14778f82136aSPatrick Kelsey 
14788f82136aSPatrick Kelsey #ifdef INVARIANTS
14798f82136aSPatrick Kelsey 		if (expect_sop)
14808f82136aSPatrick Kelsey 			KASSERT(rxcd->sop, ("%s: expected sop", __func__));
14818f82136aSPatrick Kelsey 		else
14828f82136aSPatrick Kelsey 			KASSERT(!rxcd->sop, ("%s: unexpected sop", __func__));
14838f82136aSPatrick Kelsey 		expect_sop = rxcd->eop;
14848f82136aSPatrick Kelsey #endif
14858f82136aSPatrick Kelsey 		if (rxcd->eop && (rxcd->len != 0))
14868f82136aSPatrick Kelsey 			avail++;
14878f82136aSPatrick Kelsey 		if (avail > budget)
14888f82136aSPatrick Kelsey 			break;
14898f82136aSPatrick Kelsey 		if (++idx == rxc->vxcr_ndesc) {
14908f82136aSPatrick Kelsey 			idx = 0;
14918f82136aSPatrick Kelsey 			completed_gen ^= 1;
14928f82136aSPatrick Kelsey 		}
14938f82136aSPatrick Kelsey 	}
14948f82136aSPatrick Kelsey 
14958f82136aSPatrick Kelsey 	return (avail);
14968f82136aSPatrick Kelsey }
14978f82136aSPatrick Kelsey 
14988f82136aSPatrick Kelsey static int
14998f82136aSPatrick Kelsey vmxnet3_isc_rxd_pkt_get(void *vsc, if_rxd_info_t ri)
15008f82136aSPatrick Kelsey {
15018f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
15028f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
15038f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
15048f82136aSPatrick Kelsey 	struct vmxnet3_comp_ring *rxc;
15058f82136aSPatrick Kelsey 	struct vmxnet3_rxcompdesc *rxcd;
15068f82136aSPatrick Kelsey 	struct vmxnet3_rxring *rxr;
1507e3c97c2cSBryan Venteicher 	struct vmxnet3_rxdesc *rxd;
15088f82136aSPatrick Kelsey 	if_rxd_frag_t frag;
15098f82136aSPatrick Kelsey 	int cqidx;
15108f82136aSPatrick Kelsey 	uint16_t total_len;
15118f82136aSPatrick Kelsey 	uint8_t nfrags;
1512f50375eeSPatrick Kelsey 	uint8_t i;
15138f82136aSPatrick Kelsey 	uint8_t flid;
1514e3c97c2cSBryan Venteicher 
15158f82136aSPatrick Kelsey 	sc = vsc;
15168f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
15178f82136aSPatrick Kelsey 	rxq = &sc->vmx_rxq[ri->iri_qsidx];
15188f82136aSPatrick Kelsey 	rxc = &rxq->vxrxq_comp_ring;
1519e3c97c2cSBryan Venteicher 
1520e3c97c2cSBryan Venteicher 	/*
15218f82136aSPatrick Kelsey 	 * Get a single packet starting at the given index in the completion
15228f82136aSPatrick Kelsey 	 * queue.  That we have been called indicates that
15238f82136aSPatrick Kelsey 	 * vmxnet3_isc_rxd_available() has already verified that either
15248f82136aSPatrick Kelsey 	 * there is a complete packet available starting at the given index,
15258f82136aSPatrick Kelsey 	 * or there are one or more zero length packets starting at the
15268f82136aSPatrick Kelsey 	 * given index followed by a complete packet, so no verification of
15278f82136aSPatrick Kelsey 	 * ownership of the descriptors (and no associated read barrier) is
15288f82136aSPatrick Kelsey 	 * required here.
1529e3c97c2cSBryan Venteicher 	 */
15308f82136aSPatrick Kelsey 	cqidx = ri->iri_cidx;
15318f82136aSPatrick Kelsey 	rxcd = &rxc->vxcr_u.rxcd[cqidx];
15328f82136aSPatrick Kelsey 	while (rxcd->len == 0) {
15338f82136aSPatrick Kelsey 		KASSERT(rxcd->sop && rxcd->eop,
15348f82136aSPatrick Kelsey 		    ("%s: zero-length packet without both sop and eop set",
15358f82136aSPatrick Kelsey 			__func__));
1536f50375eeSPatrick Kelsey 		rxc->vxcr_zero_length++;
15378f82136aSPatrick Kelsey 		if (++cqidx == rxc->vxcr_ndesc) {
15388f82136aSPatrick Kelsey 			cqidx = 0;
15398f82136aSPatrick Kelsey 			rxc->vxcr_gen ^= 1;
15408f82136aSPatrick Kelsey 		}
15418f82136aSPatrick Kelsey 		rxcd = &rxc->vxcr_u.rxcd[cqidx];
15428f82136aSPatrick Kelsey 	}
15438f82136aSPatrick Kelsey 	KASSERT(rxcd->sop, ("%s: expected sop", __func__));
15448f82136aSPatrick Kelsey 
15458f82136aSPatrick Kelsey 	/*
1546281cab4dSAndriy Gapon 	 * RSS and flow ID.
1547281cab4dSAndriy Gapon 	 * Types other than M_HASHTYPE_NONE and M_HASHTYPE_OPAQUE_HASH should
1548281cab4dSAndriy Gapon 	 * be used only if the software RSS is enabled and it uses the same
1549281cab4dSAndriy Gapon 	 * algorithm and the hash key as the "hardware".  If the software RSS
1550281cab4dSAndriy Gapon 	 * is not enabled, then it's simply pointless to use those types.
1551281cab4dSAndriy Gapon 	 * If it's enabled but with different parameters, then hash values will
1552281cab4dSAndriy Gapon 	 * not match.
15538f82136aSPatrick Kelsey 	 */
15548f82136aSPatrick Kelsey 	ri->iri_flowid = rxcd->rss_hash;
1555281cab4dSAndriy Gapon #ifdef RSS
1556281cab4dSAndriy Gapon 	if ((sc->vmx_flags & VMXNET3_FLAG_SOFT_RSS) != 0) {
15578f82136aSPatrick Kelsey 		switch (rxcd->rss_type) {
15588f82136aSPatrick Kelsey 		case VMXNET3_RCD_RSS_TYPE_NONE:
15598f82136aSPatrick Kelsey 			ri->iri_flowid = ri->iri_qsidx;
15608f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_NONE;
15618f82136aSPatrick Kelsey 			break;
15628f82136aSPatrick Kelsey 		case VMXNET3_RCD_RSS_TYPE_IPV4:
15638f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_RSS_IPV4;
15648f82136aSPatrick Kelsey 			break;
15658f82136aSPatrick Kelsey 		case VMXNET3_RCD_RSS_TYPE_TCPIPV4:
15668f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_RSS_TCP_IPV4;
15678f82136aSPatrick Kelsey 			break;
15688f82136aSPatrick Kelsey 		case VMXNET3_RCD_RSS_TYPE_IPV6:
15698f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_RSS_IPV6;
15708f82136aSPatrick Kelsey 			break;
15718f82136aSPatrick Kelsey 		case VMXNET3_RCD_RSS_TYPE_TCPIPV6:
15728f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_RSS_TCP_IPV6;
15738f82136aSPatrick Kelsey 			break;
15748f82136aSPatrick Kelsey 		default:
15758f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_OPAQUE_HASH;
15768f82136aSPatrick Kelsey 			break;
1577e3c97c2cSBryan Venteicher 		}
1578281cab4dSAndriy Gapon 	} else
1579281cab4dSAndriy Gapon #endif
1580281cab4dSAndriy Gapon 	{
1581281cab4dSAndriy Gapon 		switch (rxcd->rss_type) {
1582281cab4dSAndriy Gapon 		case VMXNET3_RCD_RSS_TYPE_NONE:
1583281cab4dSAndriy Gapon 			ri->iri_flowid = ri->iri_qsidx;
1584281cab4dSAndriy Gapon 			ri->iri_rsstype = M_HASHTYPE_NONE;
1585281cab4dSAndriy Gapon 			break;
1586281cab4dSAndriy Gapon 		default:
1587281cab4dSAndriy Gapon 			ri->iri_rsstype = M_HASHTYPE_OPAQUE_HASH;
1588281cab4dSAndriy Gapon 			break;
1589281cab4dSAndriy Gapon 		}
1590281cab4dSAndriy Gapon 	}
1591e3c97c2cSBryan Venteicher 
15928f82136aSPatrick Kelsey 	/*
15938f82136aSPatrick Kelsey 	 * The queue numbering scheme used for rxcd->qid is as follows:
15948f82136aSPatrick Kelsey 	 *  - All of the command ring 0s are numbered [0, nrxqsets - 1]
15958f82136aSPatrick Kelsey 	 *  - All of the command ring 1s are numbered [nrxqsets, 2*nrxqsets - 1]
15968f82136aSPatrick Kelsey 	 *
15978f82136aSPatrick Kelsey 	 * Thus, rxcd->qid less than nrxqsets indicates command ring (and
15988f82136aSPatrick Kelsey 	 * flid) 0, and rxcd->qid greater than or equal to nrxqsets
15998f82136aSPatrick Kelsey 	 * indicates command ring (and flid) 1.
16008f82136aSPatrick Kelsey 	 */
16018f82136aSPatrick Kelsey 	nfrags = 0;
16028f82136aSPatrick Kelsey 	total_len = 0;
16038f82136aSPatrick Kelsey 	do {
16048f82136aSPatrick Kelsey 		rxcd = &rxc->vxcr_u.rxcd[cqidx];
16058f82136aSPatrick Kelsey 		KASSERT(rxcd->gen == rxc->vxcr_gen,
16068f82136aSPatrick Kelsey 		    ("%s: generation mismatch", __func__));
16078f82136aSPatrick Kelsey 		flid = (rxcd->qid >= scctx->isc_nrxqsets) ? 1 : 0;
16088f82136aSPatrick Kelsey 		rxr = &rxq->vxrxq_cmd_ring[flid];
16098f82136aSPatrick Kelsey 		rxd = &rxr->vxrxr_rxd[rxcd->rxd_idx];
1610e3c97c2cSBryan Venteicher 
16118f82136aSPatrick Kelsey 		frag = &ri->iri_frags[nfrags];
16128f82136aSPatrick Kelsey 		frag->irf_flid = flid;
16138f82136aSPatrick Kelsey 		frag->irf_idx = rxcd->rxd_idx;
16148f82136aSPatrick Kelsey 		frag->irf_len = rxcd->len;
16158f82136aSPatrick Kelsey 		total_len += rxcd->len;
16168f82136aSPatrick Kelsey 		nfrags++;
16178f82136aSPatrick Kelsey 		if (++cqidx == rxc->vxcr_ndesc) {
16188f82136aSPatrick Kelsey 			cqidx = 0;
16198f82136aSPatrick Kelsey 			rxc->vxcr_gen ^= 1;
16208f82136aSPatrick Kelsey 		}
16218f82136aSPatrick Kelsey 	} while (!rxcd->eop);
1622e3c97c2cSBryan Venteicher 
16238f82136aSPatrick Kelsey 	ri->iri_cidx = cqidx;
16248f82136aSPatrick Kelsey 	ri->iri_nfrags = nfrags;
16258f82136aSPatrick Kelsey 	ri->iri_len = total_len;
16268f82136aSPatrick Kelsey 
1627f50375eeSPatrick Kelsey 	/*
1628f50375eeSPatrick Kelsey 	 * If there's an error, the last descriptor in the packet will
1629f50375eeSPatrick Kelsey 	 * have the error indicator set.  In this case, set all
1630f50375eeSPatrick Kelsey 	 * fragment lengths to zero.  This will cause iflib to discard
1631f50375eeSPatrick Kelsey 	 * the packet, but process all associated descriptors through
1632f50375eeSPatrick Kelsey 	 * the refill mechanism.
1633f50375eeSPatrick Kelsey 	 */
1634f50375eeSPatrick Kelsey 	if (__predict_false(rxcd->error)) {
1635f50375eeSPatrick Kelsey 		rxc->vxcr_pkt_errors++;
1636f50375eeSPatrick Kelsey 		for (i = 0; i < nfrags; i++) {
1637f50375eeSPatrick Kelsey 			frag = &ri->iri_frags[i];
1638f50375eeSPatrick Kelsey 			frag->irf_len = 0;
1639f50375eeSPatrick Kelsey 		}
1640f50375eeSPatrick Kelsey 	} else {
1641f50375eeSPatrick Kelsey 		/* Checksum offload information is in the last descriptor. */
1642f50375eeSPatrick Kelsey 		if (!rxcd->no_csum) {
1643f50375eeSPatrick Kelsey 			uint32_t csum_flags = 0;
1644f50375eeSPatrick Kelsey 
1645f50375eeSPatrick Kelsey 			if (rxcd->ipv4) {
1646f50375eeSPatrick Kelsey 				csum_flags |= CSUM_IP_CHECKED;
1647f50375eeSPatrick Kelsey 				if (rxcd->ipcsum_ok)
1648f50375eeSPatrick Kelsey 					csum_flags |= CSUM_IP_VALID;
1649f50375eeSPatrick Kelsey 			}
1650f50375eeSPatrick Kelsey 			if (!rxcd->fragment && (rxcd->tcp || rxcd->udp)) {
1651f50375eeSPatrick Kelsey 				csum_flags |= CSUM_L4_CALC;
1652f50375eeSPatrick Kelsey 				if (rxcd->csum_ok) {
1653f50375eeSPatrick Kelsey 					csum_flags |= CSUM_L4_VALID;
1654f50375eeSPatrick Kelsey 					ri->iri_csum_data = 0xffff;
1655f50375eeSPatrick Kelsey 				}
1656f50375eeSPatrick Kelsey 			}
1657f50375eeSPatrick Kelsey 			ri->iri_csum_flags = csum_flags;
1658f50375eeSPatrick Kelsey 		}
1659f50375eeSPatrick Kelsey 
1660f50375eeSPatrick Kelsey 		/* VLAN information is in the last descriptor. */
1661f50375eeSPatrick Kelsey 		if (rxcd->vlan) {
1662f50375eeSPatrick Kelsey 			ri->iri_flags |= M_VLANTAG;
1663f50375eeSPatrick Kelsey 			ri->iri_vtag = rxcd->vtag;
1664f50375eeSPatrick Kelsey 		}
1665f50375eeSPatrick Kelsey 	}
1666f50375eeSPatrick Kelsey 
1667e3c97c2cSBryan Venteicher 	return (0);
1668e3c97c2cSBryan Venteicher }
1669e3c97c2cSBryan Venteicher 
1670e3c97c2cSBryan Venteicher static void
16718f82136aSPatrick Kelsey vmxnet3_isc_rxd_refill(void *vsc, if_rxd_update_t iru)
1672e3c97c2cSBryan Venteicher {
1673e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
16748f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
1675e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
1676e3c97c2cSBryan Venteicher 	struct vmxnet3_rxdesc *rxd;
16778f82136aSPatrick Kelsey 	uint64_t *paddrs;
16788f82136aSPatrick Kelsey 	int count;
16798f82136aSPatrick Kelsey 	int len;
1680f50375eeSPatrick Kelsey 	int idx;
16818f82136aSPatrick Kelsey 	int i;
16828f82136aSPatrick Kelsey 	uint8_t flid;
16838f82136aSPatrick Kelsey 	uint8_t btype;
1684e3c97c2cSBryan Venteicher 
16858f82136aSPatrick Kelsey 	count = iru->iru_count;
16868f82136aSPatrick Kelsey 	len = iru->iru_buf_size;
16878f82136aSPatrick Kelsey 	flid = iru->iru_flidx;
16888f82136aSPatrick Kelsey 	paddrs = iru->iru_paddrs;
1689e3c97c2cSBryan Venteicher 
16908f82136aSPatrick Kelsey 	sc = vsc;
16918f82136aSPatrick Kelsey 	rxq = &sc->vmx_rxq[iru->iru_qsidx];
16928f82136aSPatrick Kelsey 	rxr = &rxq->vxrxq_cmd_ring[flid];
16938f82136aSPatrick Kelsey 	rxd = rxr->vxrxr_rxd;
1694e3c97c2cSBryan Venteicher 
1695e3c97c2cSBryan Venteicher 	/*
16968f82136aSPatrick Kelsey 	 * Command ring 0 is filled with BTYPE_HEAD descriptors, and
16978f82136aSPatrick Kelsey 	 * command ring 1 is filled with BTYPE_BODY descriptors.
1698e3c97c2cSBryan Venteicher 	 */
16998f82136aSPatrick Kelsey 	btype = (flid == 0) ? VMXNET3_BTYPE_HEAD : VMXNET3_BTYPE_BODY;
1700f50375eeSPatrick Kelsey 	/*
1701f50375eeSPatrick Kelsey 	 * The refill entries from iflib will advance monotonically,
1702f50375eeSPatrick Kelsey 	 * but the refilled descriptors may not be contiguous due to
1703f50375eeSPatrick Kelsey 	 * earlier skipping of descriptors by the device.  The refill
1704f50375eeSPatrick Kelsey 	 * entries from iflib need an entire state update, while the
1705f50375eeSPatrick Kelsey 	 * descriptors previously skipped by the device only need to
1706f50375eeSPatrick Kelsey 	 * have their generation numbers updated.
1707f50375eeSPatrick Kelsey 	 */
1708f50375eeSPatrick Kelsey 	idx = rxr->vxrxr_refill_start;
1709f50375eeSPatrick Kelsey 	i = 0;
1710f50375eeSPatrick Kelsey 	do {
1711f50375eeSPatrick Kelsey 		if (idx == iru->iru_idxs[i]) {
1712f50375eeSPatrick Kelsey 			rxd[idx].addr = paddrs[i];
1713f50375eeSPatrick Kelsey 			rxd[idx].len = len;
1714f50375eeSPatrick Kelsey 			rxd[idx].btype = btype;
1715f50375eeSPatrick Kelsey 			i++;
1716f50375eeSPatrick Kelsey 		} else
1717f50375eeSPatrick Kelsey 			rxr->vxrxr_desc_skips++;
1718f50375eeSPatrick Kelsey 		rxd[idx].gen = rxr->vxrxr_gen;
17198f82136aSPatrick Kelsey 
1720f50375eeSPatrick Kelsey 		if (++idx == rxr->vxrxr_ndesc) {
1721f50375eeSPatrick Kelsey 			idx = 0;
17228f82136aSPatrick Kelsey 			rxr->vxrxr_gen ^= 1;
17238f82136aSPatrick Kelsey 		}
1724f50375eeSPatrick Kelsey 	} while (i != count);
1725f50375eeSPatrick Kelsey 	rxr->vxrxr_refill_start = idx;
1726e3c97c2cSBryan Venteicher }
1727e3c97c2cSBryan Venteicher 
17288f82136aSPatrick Kelsey static void
17298f82136aSPatrick Kelsey vmxnet3_isc_rxd_flush(void *vsc, uint16_t rxqid, uint8_t flid, qidx_t pidx)
17308f82136aSPatrick Kelsey {
17318f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
17328f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
17338f82136aSPatrick Kelsey 	struct vmxnet3_rxring *rxr;
1734e3c97c2cSBryan Venteicher 	bus_size_t r;
1735e3c97c2cSBryan Venteicher 
17368f82136aSPatrick Kelsey 	sc = vsc;
17378f82136aSPatrick Kelsey 	rxq = &sc->vmx_rxq[rxqid];
17388f82136aSPatrick Kelsey 	rxr = &rxq->vxrxq_cmd_ring[flid];
17398f82136aSPatrick Kelsey 
17408f82136aSPatrick Kelsey 	if (flid == 0)
17418f82136aSPatrick Kelsey 		r = VMXNET3_BAR0_RXH1(rxqid);
17428f82136aSPatrick Kelsey 	else
17438f82136aSPatrick Kelsey 		r = VMXNET3_BAR0_RXH2(rxqid);
17448f82136aSPatrick Kelsey 
17458f82136aSPatrick Kelsey 	vmxnet3_write_bar0(sc, r, pidx);
1746e3c97c2cSBryan Venteicher }
1747e3c97c2cSBryan Venteicher 
17488f82136aSPatrick Kelsey static int
1749e3c97c2cSBryan Venteicher vmxnet3_legacy_intr(void *xsc)
1750e3c97c2cSBryan Venteicher {
1751e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
17528f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
17538f82136aSPatrick Kelsey 	if_ctx_t ctx;
1754e3c97c2cSBryan Venteicher 
1755e3c97c2cSBryan Venteicher 	sc = xsc;
17568f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
17578f82136aSPatrick Kelsey 	ctx = sc->vmx_ctx;
1758e3c97c2cSBryan Venteicher 
17598f82136aSPatrick Kelsey 	/*
17608f82136aSPatrick Kelsey 	 * When there is only a single interrupt configured, this routine
17618f82136aSPatrick Kelsey 	 * runs in fast interrupt context, following which the rxq 0 task
17628f82136aSPatrick Kelsey 	 * will be enqueued.
17638f82136aSPatrick Kelsey 	 */
17648f82136aSPatrick Kelsey 	if (scctx->isc_intr == IFLIB_INTR_LEGACY) {
1765e3c97c2cSBryan Venteicher 		if (vmxnet3_read_bar1(sc, VMXNET3_BAR1_INTR) == 0)
17668f82136aSPatrick Kelsey 			return (FILTER_HANDLED);
1767e3c97c2cSBryan Venteicher 	}
1768e3c97c2cSBryan Venteicher 	if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE)
17698f82136aSPatrick Kelsey 		vmxnet3_intr_disable_all(ctx);
1770e3c97c2cSBryan Venteicher 
1771e3c97c2cSBryan Venteicher 	if (sc->vmx_ds->event != 0)
17728f82136aSPatrick Kelsey 		iflib_admin_intr_deferred(ctx);
1773e3c97c2cSBryan Venteicher 
17748f82136aSPatrick Kelsey 	/*
17758f82136aSPatrick Kelsey 	 * XXX - When there is both rxq and event activity, do we care
17768f82136aSPatrick Kelsey 	 * whether the rxq 0 task or the admin task re-enables the interrupt
17778f82136aSPatrick Kelsey 	 * first?
17788f82136aSPatrick Kelsey 	 */
17798f82136aSPatrick Kelsey 	return (FILTER_SCHEDULE_THREAD);
1780e3c97c2cSBryan Venteicher }
1781e3c97c2cSBryan Venteicher 
17828f82136aSPatrick Kelsey static int
17838f82136aSPatrick Kelsey vmxnet3_rxq_intr(void *vrxq)
1784e3c97c2cSBryan Venteicher {
1785e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
1786e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
1787e3c97c2cSBryan Venteicher 
17888f82136aSPatrick Kelsey 	rxq = vrxq;
1789e3c97c2cSBryan Venteicher 	sc = rxq->vxrxq_sc;
1790e3c97c2cSBryan Venteicher 
1791e3c97c2cSBryan Venteicher 	if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE)
1792e3c97c2cSBryan Venteicher 		vmxnet3_disable_intr(sc, rxq->vxrxq_intr_idx);
1793e3c97c2cSBryan Venteicher 
17948f82136aSPatrick Kelsey 	return (FILTER_SCHEDULE_THREAD);
1795e3c97c2cSBryan Venteicher }
1796e3c97c2cSBryan Venteicher 
17978f82136aSPatrick Kelsey static int
17988f82136aSPatrick Kelsey vmxnet3_event_intr(void *vsc)
1799e3c97c2cSBryan Venteicher {
1800e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
1801e3c97c2cSBryan Venteicher 
18028f82136aSPatrick Kelsey 	sc = vsc;
1803e3c97c2cSBryan Venteicher 
1804e3c97c2cSBryan Venteicher 	if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE)
1805e3c97c2cSBryan Venteicher 		vmxnet3_disable_intr(sc, sc->vmx_event_intr_idx);
1806e3c97c2cSBryan Venteicher 
18078f82136aSPatrick Kelsey 	/*
18088f82136aSPatrick Kelsey 	 * The work will be done via vmxnet3_update_admin_status(), and the
18098f82136aSPatrick Kelsey 	 * interrupt will be re-enabled in vmxnet3_link_intr_enable().
18108f82136aSPatrick Kelsey 	 *
18118f82136aSPatrick Kelsey 	 * The interrupt will be re-enabled by vmxnet3_link_intr_enable().
18128f82136aSPatrick Kelsey 	 */
18138f82136aSPatrick Kelsey 	return (FILTER_SCHEDULE_THREAD);
1814e3c97c2cSBryan Venteicher }
1815e3c97c2cSBryan Venteicher 
1816e3c97c2cSBryan Venteicher static void
18178f82136aSPatrick Kelsey vmxnet3_stop(if_ctx_t ctx)
1818e3c97c2cSBryan Venteicher {
18198f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
1820e3c97c2cSBryan Venteicher 
18218f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
1822e3c97c2cSBryan Venteicher 
1823e3c97c2cSBryan Venteicher 	sc->vmx_link_active = 0;
1824e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_DISABLE);
1825e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_RESET);
1826e3c97c2cSBryan Venteicher }
1827e3c97c2cSBryan Venteicher 
1828e3c97c2cSBryan Venteicher static void
1829e3c97c2cSBryan Venteicher vmxnet3_txinit(struct vmxnet3_softc *sc, struct vmxnet3_txqueue *txq)
1830e3c97c2cSBryan Venteicher {
1831e3c97c2cSBryan Venteicher 	struct vmxnet3_txring *txr;
1832e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *txc;
1833e3c97c2cSBryan Venteicher 
18348f82136aSPatrick Kelsey 	txq->vxtxq_last_flush = -1;
18358f82136aSPatrick Kelsey 
1836e3c97c2cSBryan Venteicher 	txr = &txq->vxtxq_cmd_ring;
1837e3c97c2cSBryan Venteicher 	txr->vxtxr_next = 0;
1838e3c97c2cSBryan Venteicher 	txr->vxtxr_gen = VMXNET3_INIT_GEN;
18398f82136aSPatrick Kelsey 	/*
18408f82136aSPatrick Kelsey 	 * iflib has zeroed out the descriptor array during the prior attach
18418f82136aSPatrick Kelsey 	 * or stop
18428f82136aSPatrick Kelsey 	 */
1843e3c97c2cSBryan Venteicher 
1844e3c97c2cSBryan Venteicher 	txc = &txq->vxtxq_comp_ring;
1845e3c97c2cSBryan Venteicher 	txc->vxcr_next = 0;
1846e3c97c2cSBryan Venteicher 	txc->vxcr_gen = VMXNET3_INIT_GEN;
18478f82136aSPatrick Kelsey 	/*
18488f82136aSPatrick Kelsey 	 * iflib has zeroed out the descriptor array during the prior attach
18498f82136aSPatrick Kelsey 	 * or stop
18508f82136aSPatrick Kelsey 	 */
1851e3c97c2cSBryan Venteicher }
1852e3c97c2cSBryan Venteicher 
18538f82136aSPatrick Kelsey static void
1854e3c97c2cSBryan Venteicher vmxnet3_rxinit(struct vmxnet3_softc *sc, struct vmxnet3_rxqueue *rxq)
1855e3c97c2cSBryan Venteicher {
1856e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
1857e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *rxc;
18588f82136aSPatrick Kelsey 	int i;
1859e3c97c2cSBryan Venteicher 
1860e3c97c2cSBryan Venteicher 	/*
18618f82136aSPatrick Kelsey 	 * The descriptors will be populated with buffers during a
18628f82136aSPatrick Kelsey 	 * subsequent invocation of vmxnet3_isc_rxd_refill()
1863e3c97c2cSBryan Venteicher 	 */
18648f82136aSPatrick Kelsey 	for (i = 0; i < sc->vmx_sctx->isc_nrxqs - 1; i++) {
1865e3c97c2cSBryan Venteicher 		rxr = &rxq->vxrxq_cmd_ring[i];
1866e3c97c2cSBryan Venteicher 		rxr->vxrxr_gen = VMXNET3_INIT_GEN;
1867f50375eeSPatrick Kelsey 		rxr->vxrxr_desc_skips = 0;
1868f50375eeSPatrick Kelsey 		rxr->vxrxr_refill_start = 0;
18698f82136aSPatrick Kelsey 		/*
18708f82136aSPatrick Kelsey 		 * iflib has zeroed out the descriptor array during the
18718f82136aSPatrick Kelsey 		 * prior attach or stop
18728f82136aSPatrick Kelsey 		 */
1873e3c97c2cSBryan Venteicher 	}
1874e3c97c2cSBryan Venteicher 
1875e3c97c2cSBryan Venteicher 	for (/**/; i < VMXNET3_RXRINGS_PERQ; i++) {
1876e3c97c2cSBryan Venteicher 		rxr = &rxq->vxrxq_cmd_ring[i];
1877e3c97c2cSBryan Venteicher 		rxr->vxrxr_gen = 0;
1878f50375eeSPatrick Kelsey 		rxr->vxrxr_desc_skips = 0;
1879f50375eeSPatrick Kelsey 		rxr->vxrxr_refill_start = 0;
1880e3c97c2cSBryan Venteicher 		bzero(rxr->vxrxr_rxd,
1881e3c97c2cSBryan Venteicher 		    rxr->vxrxr_ndesc * sizeof(struct vmxnet3_rxdesc));
1882e3c97c2cSBryan Venteicher 	}
1883e3c97c2cSBryan Venteicher 
1884e3c97c2cSBryan Venteicher 	rxc = &rxq->vxrxq_comp_ring;
1885e3c97c2cSBryan Venteicher 	rxc->vxcr_next = 0;
1886e3c97c2cSBryan Venteicher 	rxc->vxcr_gen = VMXNET3_INIT_GEN;
1887f50375eeSPatrick Kelsey 	rxc->vxcr_zero_length = 0;
1888f50375eeSPatrick Kelsey 	rxc->vxcr_pkt_errors = 0;
18898f82136aSPatrick Kelsey 	/*
18908f82136aSPatrick Kelsey 	 * iflib has zeroed out the descriptor array during the prior attach
18918f82136aSPatrick Kelsey 	 * or stop
18928f82136aSPatrick Kelsey 	 */
1893e3c97c2cSBryan Venteicher }
1894e3c97c2cSBryan Venteicher 
18958f82136aSPatrick Kelsey static void
1896e3c97c2cSBryan Venteicher vmxnet3_reinit_queues(struct vmxnet3_softc *sc)
1897e3c97c2cSBryan Venteicher {
18988f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
18998f82136aSPatrick Kelsey 	int q;
1900e3c97c2cSBryan Venteicher 
19018f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
1902e3c97c2cSBryan Venteicher 
19038f82136aSPatrick Kelsey 	for (q = 0; q < scctx->isc_ntxqsets; q++)
1904e3c97c2cSBryan Venteicher 		vmxnet3_txinit(sc, &sc->vmx_txq[q]);
1905e3c97c2cSBryan Venteicher 
19068f82136aSPatrick Kelsey 	for (q = 0; q < scctx->isc_nrxqsets; q++)
19078f82136aSPatrick Kelsey 		vmxnet3_rxinit(sc, &sc->vmx_rxq[q]);
1908e3c97c2cSBryan Venteicher }
1909e3c97c2cSBryan Venteicher 
1910e3c97c2cSBryan Venteicher static int
1911e3c97c2cSBryan Venteicher vmxnet3_enable_device(struct vmxnet3_softc *sc)
1912e3c97c2cSBryan Venteicher {
19138f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
1914e3c97c2cSBryan Venteicher 	int q;
1915e3c97c2cSBryan Venteicher 
19168f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
19178f82136aSPatrick Kelsey 
1918e3c97c2cSBryan Venteicher 	if (vmxnet3_read_cmd(sc, VMXNET3_CMD_ENABLE) != 0) {
1919e3c97c2cSBryan Venteicher 		device_printf(sc->vmx_dev, "device enable command failed!\n");
1920e3c97c2cSBryan Venteicher 		return (1);
1921e3c97c2cSBryan Venteicher 	}
1922e3c97c2cSBryan Venteicher 
1923e3c97c2cSBryan Venteicher 	/* Reset the Rx queue heads. */
19248f82136aSPatrick Kelsey 	for (q = 0; q < scctx->isc_nrxqsets; q++) {
1925e3c97c2cSBryan Venteicher 		vmxnet3_write_bar0(sc, VMXNET3_BAR0_RXH1(q), 0);
1926e3c97c2cSBryan Venteicher 		vmxnet3_write_bar0(sc, VMXNET3_BAR0_RXH2(q), 0);
1927e3c97c2cSBryan Venteicher 	}
1928e3c97c2cSBryan Venteicher 
1929e3c97c2cSBryan Venteicher 	return (0);
1930e3c97c2cSBryan Venteicher }
1931e3c97c2cSBryan Venteicher 
1932e3c97c2cSBryan Venteicher static void
1933e3c97c2cSBryan Venteicher vmxnet3_reinit_rxfilters(struct vmxnet3_softc *sc)
1934e3c97c2cSBryan Venteicher {
1935e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
1936e3c97c2cSBryan Venteicher 
1937e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
1938e3c97c2cSBryan Venteicher 
19398f82136aSPatrick Kelsey 	vmxnet3_set_rxfilter(sc, if_getflags(ifp));
1940e3c97c2cSBryan Venteicher 
1941e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & IFCAP_VLAN_HWFILTER)
1942e3c97c2cSBryan Venteicher 		bcopy(sc->vmx_vlan_filter, sc->vmx_ds->vlan_filter,
1943e3c97c2cSBryan Venteicher 		    sizeof(sc->vmx_ds->vlan_filter));
1944e3c97c2cSBryan Venteicher 	else
1945e3c97c2cSBryan Venteicher 		bzero(sc->vmx_ds->vlan_filter,
1946e3c97c2cSBryan Venteicher 		    sizeof(sc->vmx_ds->vlan_filter));
1947e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_VLAN_FILTER);
1948e3c97c2cSBryan Venteicher }
1949e3c97c2cSBryan Venteicher 
19508f82136aSPatrick Kelsey static void
19518f82136aSPatrick Kelsey vmxnet3_init(if_ctx_t ctx)
1952e3c97c2cSBryan Venteicher {
19538f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
1954e3c97c2cSBryan Venteicher 
19558f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
19568f82136aSPatrick Kelsey 
19578f82136aSPatrick Kelsey 	/* Use the current MAC address. */
19588f82136aSPatrick Kelsey 	bcopy(IF_LLADDR(sc->vmx_ifp), sc->vmx_lladdr, ETHER_ADDR_LEN);
19598f82136aSPatrick Kelsey 	vmxnet3_set_lladdr(sc);
19608f82136aSPatrick Kelsey 
1961e3c97c2cSBryan Venteicher 	vmxnet3_reinit_shared_data(sc);
19628f82136aSPatrick Kelsey 	vmxnet3_reinit_queues(sc);
1963e3c97c2cSBryan Venteicher 
19648f82136aSPatrick Kelsey 	vmxnet3_enable_device(sc);
1965e3c97c2cSBryan Venteicher 
1966e3c97c2cSBryan Venteicher 	vmxnet3_reinit_rxfilters(sc);
1967e3c97c2cSBryan Venteicher 	vmxnet3_link_status(sc);
1968e3c97c2cSBryan Venteicher }
1969e3c97c2cSBryan Venteicher 
1970e3c97c2cSBryan Venteicher static void
19718f82136aSPatrick Kelsey vmxnet3_multi_set(if_ctx_t ctx)
1972e3c97c2cSBryan Venteicher {
1973e3c97c2cSBryan Venteicher 
19748f82136aSPatrick Kelsey 	vmxnet3_set_rxfilter(iflib_get_softc(ctx),
19758f82136aSPatrick Kelsey 	    if_getflags(iflib_get_ifp(ctx)));
1976e3c97c2cSBryan Venteicher }
1977e3c97c2cSBryan Venteicher 
1978e3c97c2cSBryan Venteicher static int
19798f82136aSPatrick Kelsey vmxnet3_mtu_set(if_ctx_t ctx, uint32_t mtu)
1980e3c97c2cSBryan Venteicher {
19811342c8c6SPatrick Kelsey 	struct vmxnet3_softc *sc;
19821342c8c6SPatrick Kelsey 	if_softc_ctx_t scctx;
19831342c8c6SPatrick Kelsey 
19841342c8c6SPatrick Kelsey 	sc = iflib_get_softc(ctx);
19851342c8c6SPatrick Kelsey 	scctx = sc->vmx_scctx;
1986e3c97c2cSBryan Venteicher 
19878f82136aSPatrick Kelsey 	if (mtu > VMXNET3_TX_MAXSIZE - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN +
19888f82136aSPatrick Kelsey 		ETHER_CRC_LEN))
1989e3c97c2cSBryan Venteicher 		return (EINVAL);
1990e3c97c2cSBryan Venteicher 
19911342c8c6SPatrick Kelsey 	/*
19921342c8c6SPatrick Kelsey 	 * Update the max frame size so that the rx mbuf size is
19931342c8c6SPatrick Kelsey 	 * chosen based on the new mtu during the interface init that
19941342c8c6SPatrick Kelsey 	 * will occur after this routine returns.
19951342c8c6SPatrick Kelsey 	 */
19961342c8c6SPatrick Kelsey 	scctx->isc_max_frame_size = mtu +
19971342c8c6SPatrick Kelsey 		ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + ETHER_CRC_LEN;
19981342c8c6SPatrick Kelsey 	/* RX completion queue - n/a */
19991342c8c6SPatrick Kelsey 	scctx->isc_rxd_buf_size[0] = 0;
20001342c8c6SPatrick Kelsey 	/*
20011342c8c6SPatrick Kelsey 	 * For header-type descriptors (used for first segment of
20021342c8c6SPatrick Kelsey 	 * packet), let iflib determine the buffer size based on the
20031342c8c6SPatrick Kelsey 	 * max frame size.
20041342c8c6SPatrick Kelsey 	 */
20051342c8c6SPatrick Kelsey 	scctx->isc_rxd_buf_size[1] = 0;
20061342c8c6SPatrick Kelsey 	/*
20071342c8c6SPatrick Kelsey 	 * For body-type descriptors (used for jumbo frames and LRO),
20081342c8c6SPatrick Kelsey 	 * always use page-sized buffers.
20091342c8c6SPatrick Kelsey 	 */
20101342c8c6SPatrick Kelsey 	scctx->isc_rxd_buf_size[2] = MJUMPAGESIZE;
20111342c8c6SPatrick Kelsey 
2012e3c97c2cSBryan Venteicher 	return (0);
2013e3c97c2cSBryan Venteicher }
2014e3c97c2cSBryan Venteicher 
20158f82136aSPatrick Kelsey static void
20168f82136aSPatrick Kelsey vmxnet3_media_status(if_ctx_t ctx, struct ifmediareq * ifmr)
2017e3c97c2cSBryan Venteicher {
20188f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
2019e3c97c2cSBryan Venteicher 
20208f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
2021e3c97c2cSBryan Venteicher 
20228f82136aSPatrick Kelsey 	ifmr->ifm_status = IFM_AVALID;
20238f82136aSPatrick Kelsey 	ifmr->ifm_active = IFM_ETHER;
2024e3c97c2cSBryan Venteicher 
20258f82136aSPatrick Kelsey 	if (vmxnet3_link_is_up(sc) != 0) {
20268f82136aSPatrick Kelsey 		ifmr->ifm_status |= IFM_ACTIVE;
20278f82136aSPatrick Kelsey 		ifmr->ifm_active |= IFM_AUTO;
2028e3c97c2cSBryan Venteicher 	} else
20298f82136aSPatrick Kelsey 		ifmr->ifm_active |= IFM_NONE;
2030e3c97c2cSBryan Venteicher }
2031e3c97c2cSBryan Venteicher 
2032e3c97c2cSBryan Venteicher static int
20338f82136aSPatrick Kelsey vmxnet3_media_change(if_ctx_t ctx)
2034e3c97c2cSBryan Venteicher {
2035e3c97c2cSBryan Venteicher 
20368f82136aSPatrick Kelsey 	/* Ignore. */
2037c7156fe9SLuigi Rizzo 	return (0);
2038e557c1ddSBryan Venteicher }
2039e557c1ddSBryan Venteicher 
2040e557c1ddSBryan Venteicher static int
20418f82136aSPatrick Kelsey vmxnet3_promisc_set(if_ctx_t ctx, int flags)
2042e557c1ddSBryan Venteicher {
2043e557c1ddSBryan Venteicher 
20448f82136aSPatrick Kelsey 	vmxnet3_set_rxfilter(iflib_get_softc(ctx), flags);
2045e557c1ddSBryan Venteicher 
20468f82136aSPatrick Kelsey 	return (0);
2047e557c1ddSBryan Venteicher }
2048e557c1ddSBryan Venteicher 
20498f82136aSPatrick Kelsey static uint64_t
20508f82136aSPatrick Kelsey vmxnet3_get_counter(if_ctx_t ctx, ift_counter cnt)
20518f82136aSPatrick Kelsey {
20528f82136aSPatrick Kelsey 	if_t ifp = iflib_get_ifp(ctx);
20538f82136aSPatrick Kelsey 
20548f82136aSPatrick Kelsey 	if (cnt < IFCOUNTERS)
20558f82136aSPatrick Kelsey 		return if_get_counter_default(ifp, cnt);
20568f82136aSPatrick Kelsey 
20578f82136aSPatrick Kelsey 	return (0);
2058e557c1ddSBryan Venteicher }
2059e557c1ddSBryan Venteicher 
2060e557c1ddSBryan Venteicher static void
20618f82136aSPatrick Kelsey vmxnet3_update_admin_status(if_ctx_t ctx)
2062e557c1ddSBryan Venteicher {
2063e557c1ddSBryan Venteicher 	struct vmxnet3_softc *sc;
2064e557c1ddSBryan Venteicher 
20658f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
20668f82136aSPatrick Kelsey 	if (sc->vmx_ds->event != 0)
20678f82136aSPatrick Kelsey 		vmxnet3_evintr(sc);
2068e557c1ddSBryan Venteicher 
20698f82136aSPatrick Kelsey 	vmxnet3_refresh_host_stats(sc);
2070e557c1ddSBryan Venteicher }
2071e557c1ddSBryan Venteicher 
2072e557c1ddSBryan Venteicher static void
20738f82136aSPatrick Kelsey vmxnet3_txq_timer(if_ctx_t ctx, uint16_t qid)
2074e557c1ddSBryan Venteicher {
20758f82136aSPatrick Kelsey 	/* Host stats refresh is global, so just trigger it on txq 0 */
20768f82136aSPatrick Kelsey 	if (qid == 0)
20778f82136aSPatrick Kelsey 		vmxnet3_refresh_host_stats(iflib_get_softc(ctx));
2078e557c1ddSBryan Venteicher }
2079e557c1ddSBryan Venteicher 
2080e3c97c2cSBryan Venteicher static void
2081e3c97c2cSBryan Venteicher vmxnet3_update_vlan_filter(struct vmxnet3_softc *sc, int add, uint16_t tag)
2082e3c97c2cSBryan Venteicher {
2083e3c97c2cSBryan Venteicher 	int idx, bit;
2084e3c97c2cSBryan Venteicher 
2085e3c97c2cSBryan Venteicher 	if (tag == 0 || tag > 4095)
2086e3c97c2cSBryan Venteicher 		return;
2087e3c97c2cSBryan Venteicher 
20888f82136aSPatrick Kelsey 	idx = (tag >> 5) & 0x7F;
20898f82136aSPatrick Kelsey 	bit = tag & 0x1F;
2090e3c97c2cSBryan Venteicher 
2091e3c97c2cSBryan Venteicher 	/* Update our private VLAN bitvector. */
2092e3c97c2cSBryan Venteicher 	if (add)
2093e3c97c2cSBryan Venteicher 		sc->vmx_vlan_filter[idx] |= (1 << bit);
2094e3c97c2cSBryan Venteicher 	else
2095e3c97c2cSBryan Venteicher 		sc->vmx_vlan_filter[idx] &= ~(1 << bit);
2096e3c97c2cSBryan Venteicher }
2097e3c97c2cSBryan Venteicher 
2098e3c97c2cSBryan Venteicher static void
20998f82136aSPatrick Kelsey vmxnet3_vlan_register(if_ctx_t ctx, uint16_t tag)
2100e3c97c2cSBryan Venteicher {
2101e3c97c2cSBryan Venteicher 
21028f82136aSPatrick Kelsey 	vmxnet3_update_vlan_filter(iflib_get_softc(ctx), 1, tag);
2103e3c97c2cSBryan Venteicher }
2104e3c97c2cSBryan Venteicher 
2105e3c97c2cSBryan Venteicher static void
21068f82136aSPatrick Kelsey vmxnet3_vlan_unregister(if_ctx_t ctx, uint16_t tag)
2107e3c97c2cSBryan Venteicher {
2108e3c97c2cSBryan Venteicher 
21098f82136aSPatrick Kelsey 	vmxnet3_update_vlan_filter(iflib_get_softc(ctx), 0, tag);
2110e3c97c2cSBryan Venteicher }
2111e3c97c2cSBryan Venteicher 
2112d6b5965bSGleb Smirnoff static u_int
2113d6b5965bSGleb Smirnoff vmxnet3_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int count)
2114d6b5965bSGleb Smirnoff {
2115d6b5965bSGleb Smirnoff 	struct vmxnet3_softc *sc = arg;
2116d6b5965bSGleb Smirnoff 
2117d6b5965bSGleb Smirnoff 	if (count < VMXNET3_MULTICAST_MAX)
2118d6b5965bSGleb Smirnoff 		bcopy(LLADDR(sdl), &sc->vmx_mcast[count * ETHER_ADDR_LEN],
2119d6b5965bSGleb Smirnoff 		    ETHER_ADDR_LEN);
2120d6b5965bSGleb Smirnoff 
2121d6b5965bSGleb Smirnoff 	return (1);
2122d6b5965bSGleb Smirnoff }
2123d6b5965bSGleb Smirnoff 
2124e3c97c2cSBryan Venteicher static void
21258f82136aSPatrick Kelsey vmxnet3_set_rxfilter(struct vmxnet3_softc *sc, int flags)
2126e3c97c2cSBryan Venteicher {
2127e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
2128e3c97c2cSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
2129e3c97c2cSBryan Venteicher 	u_int mode;
2130e3c97c2cSBryan Venteicher 
2131e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
2132e3c97c2cSBryan Venteicher 	ds = sc->vmx_ds;
2133e3c97c2cSBryan Venteicher 
2134e557c1ddSBryan Venteicher 	mode = VMXNET3_RXMODE_UCAST | VMXNET3_RXMODE_BCAST;
21358f82136aSPatrick Kelsey 	if (flags & IFF_PROMISC)
2136e3c97c2cSBryan Venteicher 		mode |= VMXNET3_RXMODE_PROMISC;
21378f82136aSPatrick Kelsey 	if (flags & IFF_ALLMULTI)
2138e3c97c2cSBryan Venteicher 		mode |= VMXNET3_RXMODE_ALLMULTI;
2139e3c97c2cSBryan Venteicher 	else {
2140d6b5965bSGleb Smirnoff 		int cnt;
2141e3c97c2cSBryan Venteicher 
2142d6b5965bSGleb Smirnoff 		cnt = if_foreach_llmaddr(ifp, vmxnet3_hash_maddr, sc);
2143d6b5965bSGleb Smirnoff 		if (cnt >= VMXNET3_MULTICAST_MAX) {
2144e3c97c2cSBryan Venteicher 			cnt = 0;
2145e3c97c2cSBryan Venteicher 			mode |= VMXNET3_RXMODE_ALLMULTI;
2146e3c97c2cSBryan Venteicher 		} else if (cnt > 0)
2147e3c97c2cSBryan Venteicher 			mode |= VMXNET3_RXMODE_MCAST;
2148e3c97c2cSBryan Venteicher 		ds->mcast_tablelen = cnt * ETHER_ADDR_LEN;
2149e3c97c2cSBryan Venteicher 	}
2150e3c97c2cSBryan Venteicher 
2151e3c97c2cSBryan Venteicher 	ds->rxmode = mode;
2152e3c97c2cSBryan Venteicher 
2153e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_SET_FILTER);
2154e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_SET_RXMODE);
2155e3c97c2cSBryan Venteicher }
2156e3c97c2cSBryan Venteicher 
2157e3c97c2cSBryan Venteicher static void
2158e557c1ddSBryan Venteicher vmxnet3_refresh_host_stats(struct vmxnet3_softc *sc)
2159e3c97c2cSBryan Venteicher {
2160e3c97c2cSBryan Venteicher 
2161e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_GET_STATS);
2162e3c97c2cSBryan Venteicher }
2163e3c97c2cSBryan Venteicher 
2164e3c97c2cSBryan Venteicher static int
2165e3c97c2cSBryan Venteicher vmxnet3_link_is_up(struct vmxnet3_softc *sc)
2166e3c97c2cSBryan Venteicher {
2167e3c97c2cSBryan Venteicher 	uint32_t status;
2168e3c97c2cSBryan Venteicher 
2169e3c97c2cSBryan Venteicher 	status = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_LINK);
2170e3c97c2cSBryan Venteicher 	return !!(status & 0x1);
2171e3c97c2cSBryan Venteicher }
2172e3c97c2cSBryan Venteicher 
2173e3c97c2cSBryan Venteicher static void
2174e3c97c2cSBryan Venteicher vmxnet3_link_status(struct vmxnet3_softc *sc)
2175e3c97c2cSBryan Venteicher {
21768f82136aSPatrick Kelsey 	if_ctx_t ctx;
21778f82136aSPatrick Kelsey 	uint64_t speed;
2178e3c97c2cSBryan Venteicher 	int link;
2179e3c97c2cSBryan Venteicher 
21808f82136aSPatrick Kelsey 	ctx = sc->vmx_ctx;
2181e3c97c2cSBryan Venteicher 	link = vmxnet3_link_is_up(sc);
21828f82136aSPatrick Kelsey 	speed = IF_Gbps(10);
2183e3c97c2cSBryan Venteicher 
2184e3c97c2cSBryan Venteicher 	if (link != 0 && sc->vmx_link_active == 0) {
2185e3c97c2cSBryan Venteicher 		sc->vmx_link_active = 1;
21868f82136aSPatrick Kelsey 		iflib_link_state_change(ctx, LINK_STATE_UP, speed);
2187e3c97c2cSBryan Venteicher 	} else if (link == 0 && sc->vmx_link_active != 0) {
2188e3c97c2cSBryan Venteicher 		sc->vmx_link_active = 0;
21898f82136aSPatrick Kelsey 		iflib_link_state_change(ctx, LINK_STATE_DOWN, speed);
2190e3c97c2cSBryan Venteicher 	}
2191e3c97c2cSBryan Venteicher }
2192e3c97c2cSBryan Venteicher 
2193e3c97c2cSBryan Venteicher static void
2194e3c97c2cSBryan Venteicher vmxnet3_set_lladdr(struct vmxnet3_softc *sc)
2195e3c97c2cSBryan Venteicher {
2196e3c97c2cSBryan Venteicher 	uint32_t ml, mh;
2197e3c97c2cSBryan Venteicher 
2198e3c97c2cSBryan Venteicher 	ml  = sc->vmx_lladdr[0];
2199e3c97c2cSBryan Venteicher 	ml |= sc->vmx_lladdr[1] << 8;
2200e3c97c2cSBryan Venteicher 	ml |= sc->vmx_lladdr[2] << 16;
2201e3c97c2cSBryan Venteicher 	ml |= sc->vmx_lladdr[3] << 24;
2202e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_MACL, ml);
2203e3c97c2cSBryan Venteicher 
2204e3c97c2cSBryan Venteicher 	mh  = sc->vmx_lladdr[4];
2205e3c97c2cSBryan Venteicher 	mh |= sc->vmx_lladdr[5] << 8;
2206e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_MACH, mh);
2207e3c97c2cSBryan Venteicher }
2208e3c97c2cSBryan Venteicher 
2209e3c97c2cSBryan Venteicher static void
2210e3c97c2cSBryan Venteicher vmxnet3_get_lladdr(struct vmxnet3_softc *sc)
2211e3c97c2cSBryan Venteicher {
2212e3c97c2cSBryan Venteicher 	uint32_t ml, mh;
2213e3c97c2cSBryan Venteicher 
2214e3c97c2cSBryan Venteicher 	ml = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_MACL);
2215e3c97c2cSBryan Venteicher 	mh = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_MACH);
2216e3c97c2cSBryan Venteicher 
2217e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[0] = ml;
2218e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[1] = ml >> 8;
2219e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[2] = ml >> 16;
2220e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[3] = ml >> 24;
2221e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[4] = mh;
2222e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[5] = mh >> 8;
2223e3c97c2cSBryan Venteicher }
2224e3c97c2cSBryan Venteicher 
2225e3c97c2cSBryan Venteicher static void
2226e3c97c2cSBryan Venteicher vmxnet3_setup_txq_sysctl(struct vmxnet3_txqueue *txq,
2227e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2228e3c97c2cSBryan Venteicher {
2229e3c97c2cSBryan Venteicher 	struct sysctl_oid *node, *txsnode;
2230e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *list, *txslist;
2231e3c97c2cSBryan Venteicher 	struct UPT1_TxStats *txstats;
2232e3c97c2cSBryan Venteicher 	char namebuf[16];
2233e3c97c2cSBryan Venteicher 
2234e3c97c2cSBryan Venteicher 	txstats = &txq->vxtxq_ts->stats;
2235e3c97c2cSBryan Venteicher 
2236e3c97c2cSBryan Venteicher 	snprintf(namebuf, sizeof(namebuf), "txq%d", txq->vxtxq_id);
22377029da5cSPawel Biernacki 	node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf,
22387029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Transmit Queue");
2239e3c97c2cSBryan Venteicher 	txq->vxtxq_sysctl = list = SYSCTL_CHILDREN(node);
2240e3c97c2cSBryan Venteicher 
2241e3c97c2cSBryan Venteicher 	/*
22428f82136aSPatrick Kelsey 	 * Add statistics reported by the host. These are updated by the
22438f82136aSPatrick Kelsey 	 * iflib txq timer on txq 0.
2244e3c97c2cSBryan Venteicher 	 */
22457029da5cSPawel Biernacki 	txsnode = SYSCTL_ADD_NODE(ctx, list, OID_AUTO, "hstats",
22467029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Host Statistics");
2247e3c97c2cSBryan Venteicher 	txslist = SYSCTL_CHILDREN(txsnode);
2248e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "tso_packets", CTLFLAG_RD,
2249e3c97c2cSBryan Venteicher 	    &txstats->TSO_packets, "TSO packets");
2250e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "tso_bytes", CTLFLAG_RD,
2251e3c97c2cSBryan Venteicher 	    &txstats->TSO_bytes, "TSO bytes");
2252e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "ucast_packets", CTLFLAG_RD,
2253e3c97c2cSBryan Venteicher 	    &txstats->ucast_packets, "Unicast packets");
2254e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "unicast_bytes", CTLFLAG_RD,
2255e3c97c2cSBryan Venteicher 	    &txstats->ucast_bytes, "Unicast bytes");
2256e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "mcast_packets", CTLFLAG_RD,
2257e3c97c2cSBryan Venteicher 	    &txstats->mcast_packets, "Multicast packets");
2258e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "mcast_bytes", CTLFLAG_RD,
2259e3c97c2cSBryan Venteicher 	    &txstats->mcast_bytes, "Multicast bytes");
2260e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "error", CTLFLAG_RD,
2261e3c97c2cSBryan Venteicher 	    &txstats->error, "Errors");
2262e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "discard", CTLFLAG_RD,
2263e3c97c2cSBryan Venteicher 	    &txstats->discard, "Discards");
2264e3c97c2cSBryan Venteicher }
2265e3c97c2cSBryan Venteicher 
2266e3c97c2cSBryan Venteicher static void
2267e3c97c2cSBryan Venteicher vmxnet3_setup_rxq_sysctl(struct vmxnet3_rxqueue *rxq,
2268e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2269e3c97c2cSBryan Venteicher {
2270e3c97c2cSBryan Venteicher 	struct sysctl_oid *node, *rxsnode;
2271e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *list, *rxslist;
2272e3c97c2cSBryan Venteicher 	struct UPT1_RxStats *rxstats;
2273e3c97c2cSBryan Venteicher 	char namebuf[16];
2274e3c97c2cSBryan Venteicher 
2275e3c97c2cSBryan Venteicher 	rxstats = &rxq->vxrxq_rs->stats;
2276e3c97c2cSBryan Venteicher 
2277e3c97c2cSBryan Venteicher 	snprintf(namebuf, sizeof(namebuf), "rxq%d", rxq->vxrxq_id);
22787029da5cSPawel Biernacki 	node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf,
22797029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Receive Queue");
2280e3c97c2cSBryan Venteicher 	rxq->vxrxq_sysctl = list = SYSCTL_CHILDREN(node);
2281e3c97c2cSBryan Venteicher 
2282e3c97c2cSBryan Venteicher 	/*
22838f82136aSPatrick Kelsey 	 * Add statistics reported by the host. These are updated by the
22848f82136aSPatrick Kelsey 	 * iflib txq timer on txq 0.
2285e3c97c2cSBryan Venteicher 	 */
22867029da5cSPawel Biernacki 	rxsnode = SYSCTL_ADD_NODE(ctx, list, OID_AUTO, "hstats",
22877029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Host Statistics");
2288e3c97c2cSBryan Venteicher 	rxslist = SYSCTL_CHILDREN(rxsnode);
2289e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "lro_packets", CTLFLAG_RD,
2290e3c97c2cSBryan Venteicher 	    &rxstats->LRO_packets, "LRO packets");
2291e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "lro_bytes", CTLFLAG_RD,
2292e3c97c2cSBryan Venteicher 	    &rxstats->LRO_bytes, "LRO bytes");
2293e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "ucast_packets", CTLFLAG_RD,
2294e3c97c2cSBryan Venteicher 	    &rxstats->ucast_packets, "Unicast packets");
2295e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "unicast_bytes", CTLFLAG_RD,
2296e3c97c2cSBryan Venteicher 	    &rxstats->ucast_bytes, "Unicast bytes");
2297e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "mcast_packets", CTLFLAG_RD,
2298e3c97c2cSBryan Venteicher 	    &rxstats->mcast_packets, "Multicast packets");
2299e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "mcast_bytes", CTLFLAG_RD,
2300e3c97c2cSBryan Venteicher 	    &rxstats->mcast_bytes, "Multicast bytes");
2301e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "bcast_packets", CTLFLAG_RD,
2302e3c97c2cSBryan Venteicher 	    &rxstats->bcast_packets, "Broadcast packets");
2303e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "bcast_bytes", CTLFLAG_RD,
2304e3c97c2cSBryan Venteicher 	    &rxstats->bcast_bytes, "Broadcast bytes");
2305e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "nobuffer", CTLFLAG_RD,
2306e3c97c2cSBryan Venteicher 	    &rxstats->nobuffer, "No buffer");
2307e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "error", CTLFLAG_RD,
2308e3c97c2cSBryan Venteicher 	    &rxstats->error, "Errors");
2309e3c97c2cSBryan Venteicher }
2310e3c97c2cSBryan Venteicher 
2311e3c97c2cSBryan Venteicher static void
2312e3c97c2cSBryan Venteicher vmxnet3_setup_debug_sysctl(struct vmxnet3_softc *sc,
2313e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2314e3c97c2cSBryan Venteicher {
23158f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
2316e3c97c2cSBryan Venteicher 	struct sysctl_oid *node;
2317e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *list;
2318e3c97c2cSBryan Venteicher 	int i;
2319e3c97c2cSBryan Venteicher 
23208f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
23218f82136aSPatrick Kelsey 
23228f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++) {
2323e3c97c2cSBryan Venteicher 		struct vmxnet3_txqueue *txq = &sc->vmx_txq[i];
2324e3c97c2cSBryan Venteicher 
2325e3c97c2cSBryan Venteicher 		node = SYSCTL_ADD_NODE(ctx, txq->vxtxq_sysctl, OID_AUTO,
23267029da5cSPawel Biernacki 		    "debug", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "");
2327e3c97c2cSBryan Venteicher 		list = SYSCTL_CHILDREN(node);
2328e3c97c2cSBryan Venteicher 
2329e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd_next", CTLFLAG_RD,
2330e3c97c2cSBryan Venteicher 		    &txq->vxtxq_cmd_ring.vxtxr_next, 0, "");
2331e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd_ndesc", CTLFLAG_RD,
2332e3c97c2cSBryan Venteicher 		    &txq->vxtxq_cmd_ring.vxtxr_ndesc, 0, "");
2333e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd_gen", CTLFLAG_RD,
2334e3c97c2cSBryan Venteicher 		    &txq->vxtxq_cmd_ring.vxtxr_gen, 0, "");
2335e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_next", CTLFLAG_RD,
2336e3c97c2cSBryan Venteicher 		    &txq->vxtxq_comp_ring.vxcr_next, 0, "");
2337e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_ndesc", CTLFLAG_RD,
2338e3c97c2cSBryan Venteicher 		    &txq->vxtxq_comp_ring.vxcr_ndesc, 0,"");
2339e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "comp_gen", CTLFLAG_RD,
2340e3c97c2cSBryan Venteicher 		    &txq->vxtxq_comp_ring.vxcr_gen, 0, "");
2341e3c97c2cSBryan Venteicher 	}
2342e3c97c2cSBryan Venteicher 
23438f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
2344e3c97c2cSBryan Venteicher 		struct vmxnet3_rxqueue *rxq = &sc->vmx_rxq[i];
2345e3c97c2cSBryan Venteicher 
2346e3c97c2cSBryan Venteicher 		node = SYSCTL_ADD_NODE(ctx, rxq->vxrxq_sysctl, OID_AUTO,
23477029da5cSPawel Biernacki 		    "debug", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "");
2348e3c97c2cSBryan Venteicher 		list = SYSCTL_CHILDREN(node);
2349e3c97c2cSBryan Venteicher 
2350e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd0_ndesc", CTLFLAG_RD,
2351e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[0].vxrxr_ndesc, 0, "");
2352e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd0_gen", CTLFLAG_RD,
2353e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[0].vxrxr_gen, 0, "");
2354f50375eeSPatrick Kelsey 		SYSCTL_ADD_U64(ctx, list, OID_AUTO, "cmd0_desc_skips", CTLFLAG_RD,
2355f50375eeSPatrick Kelsey 		    &rxq->vxrxq_cmd_ring[0].vxrxr_desc_skips, 0, "");
2356e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd1_ndesc", CTLFLAG_RD,
2357e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[1].vxrxr_ndesc, 0, "");
2358e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd1_gen", CTLFLAG_RD,
2359e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[1].vxrxr_gen, 0, "");
2360f50375eeSPatrick Kelsey 		SYSCTL_ADD_U64(ctx, list, OID_AUTO, "cmd1_desc_skips", CTLFLAG_RD,
2361f50375eeSPatrick Kelsey 		    &rxq->vxrxq_cmd_ring[1].vxrxr_desc_skips, 0, "");
2362e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_ndesc", CTLFLAG_RD,
2363e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_comp_ring.vxcr_ndesc, 0,"");
2364e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "comp_gen", CTLFLAG_RD,
2365e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_comp_ring.vxcr_gen, 0, "");
2366f50375eeSPatrick Kelsey 		SYSCTL_ADD_U64(ctx, list, OID_AUTO, "comp_zero_length", CTLFLAG_RD,
2367f50375eeSPatrick Kelsey 		    &rxq->vxrxq_comp_ring.vxcr_zero_length, 0, "");
2368f50375eeSPatrick Kelsey 		SYSCTL_ADD_U64(ctx, list, OID_AUTO, "comp_pkt_errors", CTLFLAG_RD,
2369f50375eeSPatrick Kelsey 		    &rxq->vxrxq_comp_ring.vxcr_pkt_errors, 0, "");
2370e3c97c2cSBryan Venteicher 	}
2371e3c97c2cSBryan Venteicher }
2372e3c97c2cSBryan Venteicher 
2373e3c97c2cSBryan Venteicher static void
2374e3c97c2cSBryan Venteicher vmxnet3_setup_queue_sysctl(struct vmxnet3_softc *sc,
2375e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2376e3c97c2cSBryan Venteicher {
23778f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
2378e3c97c2cSBryan Venteicher 	int i;
2379e3c97c2cSBryan Venteicher 
23808f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
23818f82136aSPatrick Kelsey 
23828f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++)
2383e3c97c2cSBryan Venteicher 		vmxnet3_setup_txq_sysctl(&sc->vmx_txq[i], ctx, child);
23848f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++)
2385e3c97c2cSBryan Venteicher 		vmxnet3_setup_rxq_sysctl(&sc->vmx_rxq[i], ctx, child);
2386e3c97c2cSBryan Venteicher 
2387e3c97c2cSBryan Venteicher 	vmxnet3_setup_debug_sysctl(sc, ctx, child);
2388e3c97c2cSBryan Venteicher }
2389e3c97c2cSBryan Venteicher 
2390e3c97c2cSBryan Venteicher static void
2391e3c97c2cSBryan Venteicher vmxnet3_setup_sysctl(struct vmxnet3_softc *sc)
2392e3c97c2cSBryan Venteicher {
2393e3c97c2cSBryan Venteicher 	device_t dev;
2394e3c97c2cSBryan Venteicher 	struct sysctl_ctx_list *ctx;
2395e3c97c2cSBryan Venteicher 	struct sysctl_oid *tree;
2396e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *child;
2397e3c97c2cSBryan Venteicher 
2398e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
2399e3c97c2cSBryan Venteicher 	ctx = device_get_sysctl_ctx(dev);
2400e3c97c2cSBryan Venteicher 	tree = device_get_sysctl_tree(dev);
2401e3c97c2cSBryan Venteicher 	child = SYSCTL_CHILDREN(tree);
2402e3c97c2cSBryan Venteicher 
2403e3c97c2cSBryan Venteicher 	vmxnet3_setup_queue_sysctl(sc, ctx, child);
2404e3c97c2cSBryan Venteicher }
2405e3c97c2cSBryan Venteicher 
2406e3c97c2cSBryan Venteicher static void
2407e3c97c2cSBryan Venteicher vmxnet3_write_bar0(struct vmxnet3_softc *sc, bus_size_t r, uint32_t v)
2408e3c97c2cSBryan Venteicher {
2409e3c97c2cSBryan Venteicher 
2410e3c97c2cSBryan Venteicher 	bus_space_write_4(sc->vmx_iot0, sc->vmx_ioh0, r, v);
2411e3c97c2cSBryan Venteicher }
2412e3c97c2cSBryan Venteicher 
2413e3c97c2cSBryan Venteicher static uint32_t
2414e3c97c2cSBryan Venteicher vmxnet3_read_bar1(struct vmxnet3_softc *sc, bus_size_t r)
2415e3c97c2cSBryan Venteicher {
2416e3c97c2cSBryan Venteicher 
2417e3c97c2cSBryan Venteicher 	return (bus_space_read_4(sc->vmx_iot1, sc->vmx_ioh1, r));
2418e3c97c2cSBryan Venteicher }
2419e3c97c2cSBryan Venteicher 
2420e3c97c2cSBryan Venteicher static void
2421e3c97c2cSBryan Venteicher vmxnet3_write_bar1(struct vmxnet3_softc *sc, bus_size_t r, uint32_t v)
2422e3c97c2cSBryan Venteicher {
2423e3c97c2cSBryan Venteicher 
2424e3c97c2cSBryan Venteicher 	bus_space_write_4(sc->vmx_iot1, sc->vmx_ioh1, r, v);
2425e3c97c2cSBryan Venteicher }
2426e3c97c2cSBryan Venteicher 
2427e3c97c2cSBryan Venteicher static void
2428e3c97c2cSBryan Venteicher vmxnet3_write_cmd(struct vmxnet3_softc *sc, uint32_t cmd)
2429e3c97c2cSBryan Venteicher {
2430e3c97c2cSBryan Venteicher 
2431e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_CMD, cmd);
2432e3c97c2cSBryan Venteicher }
2433e3c97c2cSBryan Venteicher 
2434e3c97c2cSBryan Venteicher static uint32_t
2435e3c97c2cSBryan Venteicher vmxnet3_read_cmd(struct vmxnet3_softc *sc, uint32_t cmd)
2436e3c97c2cSBryan Venteicher {
2437e3c97c2cSBryan Venteicher 
2438e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, cmd);
2439e3c97c2cSBryan Venteicher 	bus_space_barrier(sc->vmx_iot1, sc->vmx_ioh1, 0, 0,
2440e3c97c2cSBryan Venteicher 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
2441e3c97c2cSBryan Venteicher 	return (vmxnet3_read_bar1(sc, VMXNET3_BAR1_CMD));
2442e3c97c2cSBryan Venteicher }
2443e3c97c2cSBryan Venteicher 
2444e3c97c2cSBryan Venteicher static void
2445e3c97c2cSBryan Venteicher vmxnet3_enable_intr(struct vmxnet3_softc *sc, int irq)
2446e3c97c2cSBryan Venteicher {
2447e3c97c2cSBryan Venteicher 
2448e3c97c2cSBryan Venteicher 	vmxnet3_write_bar0(sc, VMXNET3_BAR0_IMASK(irq), 0);
2449e3c97c2cSBryan Venteicher }
2450e3c97c2cSBryan Venteicher 
2451e3c97c2cSBryan Venteicher static void
2452e3c97c2cSBryan Venteicher vmxnet3_disable_intr(struct vmxnet3_softc *sc, int irq)
2453e3c97c2cSBryan Venteicher {
2454e3c97c2cSBryan Venteicher 
2455e3c97c2cSBryan Venteicher 	vmxnet3_write_bar0(sc, VMXNET3_BAR0_IMASK(irq), 1);
2456e3c97c2cSBryan Venteicher }
2457e3c97c2cSBryan Venteicher 
24588f82136aSPatrick Kelsey static int
24598f82136aSPatrick Kelsey vmxnet3_tx_queue_intr_enable(if_ctx_t ctx, uint16_t qid)
2460e3c97c2cSBryan Venteicher {
24618f82136aSPatrick Kelsey 	/* Not using interrupts for TX */
24628f82136aSPatrick Kelsey 	return (0);
24638f82136aSPatrick Kelsey }
24648f82136aSPatrick Kelsey 
24658f82136aSPatrick Kelsey static int
24668f82136aSPatrick Kelsey vmxnet3_rx_queue_intr_enable(if_ctx_t ctx, uint16_t qid)
24678f82136aSPatrick Kelsey {
24688f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
24698f82136aSPatrick Kelsey 
24708f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
24718f82136aSPatrick Kelsey 	vmxnet3_enable_intr(sc, sc->vmx_rxq[qid].vxrxq_intr_idx);
24728f82136aSPatrick Kelsey 	return (0);
24738f82136aSPatrick Kelsey }
24748f82136aSPatrick Kelsey 
24758f82136aSPatrick Kelsey static void
24768f82136aSPatrick Kelsey vmxnet3_link_intr_enable(if_ctx_t ctx)
24778f82136aSPatrick Kelsey {
24788f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
24798f82136aSPatrick Kelsey 
24808f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
24818f82136aSPatrick Kelsey 	vmxnet3_enable_intr(sc, sc->vmx_event_intr_idx);
24828f82136aSPatrick Kelsey }
24838f82136aSPatrick Kelsey 
24848f82136aSPatrick Kelsey static void
24858f82136aSPatrick Kelsey vmxnet3_intr_enable_all(if_ctx_t ctx)
24868f82136aSPatrick Kelsey {
24878f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
24888f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
2489e3c97c2cSBryan Venteicher 	int i;
2490e3c97c2cSBryan Venteicher 
24918f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
24928f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
2493e3c97c2cSBryan Venteicher 	sc->vmx_ds->ictrl &= ~VMXNET3_ICTRL_DISABLE_ALL;
24948f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_vectors; i++)
2495e3c97c2cSBryan Venteicher 		vmxnet3_enable_intr(sc, i);
2496e3c97c2cSBryan Venteicher }
2497e3c97c2cSBryan Venteicher 
2498e3c97c2cSBryan Venteicher static void
24998f82136aSPatrick Kelsey vmxnet3_intr_disable_all(if_ctx_t ctx)
2500e3c97c2cSBryan Venteicher {
25018f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
2502e3c97c2cSBryan Venteicher 	int i;
2503e3c97c2cSBryan Venteicher 
25048f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
25058f82136aSPatrick Kelsey 	/*
25068f82136aSPatrick Kelsey 	 * iflib may invoke this routine before vmxnet3_attach_post() has
25078f82136aSPatrick Kelsey 	 * run, which is before the top level shared data area is
25088f82136aSPatrick Kelsey 	 * initialized and the device made aware of it.
25098f82136aSPatrick Kelsey 	 */
25108f82136aSPatrick Kelsey 	if (sc->vmx_ds != NULL)
2511e3c97c2cSBryan Venteicher 		sc->vmx_ds->ictrl |= VMXNET3_ICTRL_DISABLE_ALL;
25128f82136aSPatrick Kelsey 	for (i = 0; i < VMXNET3_MAX_INTRS; i++)
2513e3c97c2cSBryan Venteicher 		vmxnet3_disable_intr(sc, i);
2514e3c97c2cSBryan Venteicher }
2515e3c97c2cSBryan Venteicher 
2516e3c97c2cSBryan Venteicher /*
2517e3c97c2cSBryan Venteicher  * Since this is a purely paravirtualized device, we do not have
2518e3c97c2cSBryan Venteicher  * to worry about DMA coherency. But at times, we must make sure
2519e3c97c2cSBryan Venteicher  * both the compiler and CPU do not reorder memory operations.
2520e3c97c2cSBryan Venteicher  */
2521e3c97c2cSBryan Venteicher static inline void
2522e3c97c2cSBryan Venteicher vmxnet3_barrier(struct vmxnet3_softc *sc, vmxnet3_barrier_t type)
2523e3c97c2cSBryan Venteicher {
2524e3c97c2cSBryan Venteicher 
2525e3c97c2cSBryan Venteicher 	switch (type) {
2526e3c97c2cSBryan Venteicher 	case VMXNET3_BARRIER_RD:
2527e3c97c2cSBryan Venteicher 		rmb();
2528e3c97c2cSBryan Venteicher 		break;
2529e3c97c2cSBryan Venteicher 	case VMXNET3_BARRIER_WR:
2530e3c97c2cSBryan Venteicher 		wmb();
2531e3c97c2cSBryan Venteicher 		break;
2532e3c97c2cSBryan Venteicher 	case VMXNET3_BARRIER_RDWR:
2533e3c97c2cSBryan Venteicher 		mb();
2534e3c97c2cSBryan Venteicher 		break;
2535e3c97c2cSBryan Venteicher 	default:
2536e3c97c2cSBryan Venteicher 		panic("%s: bad barrier type %d", __func__, type);
2537e3c97c2cSBryan Venteicher 	}
2538e3c97c2cSBryan Venteicher }
2539