xref: /freebsd/sys/dev/vmware/vmxnet3/if_vmx.c (revision 43df074d9c8b48e165946d37a22d39e7e00d16e3)
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 
210*43df074dSJohn Baldwin DRIVER_MODULE(vmx, pci, vmxnet3_driver, 0, 0);
2118f82136aSPatrick Kelsey IFLIB_PNP_INFO(pci, vmx, vmxnet3_vendor_info_array);
2128f82136aSPatrick Kelsey MODULE_VERSION(vmx, 2);
213e3c97c2cSBryan Venteicher 
214e3c97c2cSBryan Venteicher MODULE_DEPEND(vmx, pci, 1, 1, 1);
215e3c97c2cSBryan Venteicher MODULE_DEPEND(vmx, ether, 1, 1, 1);
2168f82136aSPatrick Kelsey MODULE_DEPEND(vmx, iflib, 1, 1, 1);
217e3c97c2cSBryan Venteicher 
2188f82136aSPatrick Kelsey static device_method_t vmxnet3_iflib_methods[] = {
2198f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_tx_queues_alloc, vmxnet3_tx_queues_alloc),
2208f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_rx_queues_alloc, vmxnet3_rx_queues_alloc),
2218f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_queues_free, vmxnet3_queues_free),
222e3c97c2cSBryan Venteicher 
2238f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_attach_pre, vmxnet3_attach_pre),
2248f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_attach_post, vmxnet3_attach_post),
2258f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_detach, vmxnet3_detach),
2268f82136aSPatrick Kelsey 
2278f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_init, vmxnet3_init),
2288f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_stop, vmxnet3_stop),
2298f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_multi_set, vmxnet3_multi_set),
2308f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_mtu_set, vmxnet3_mtu_set),
2318f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_media_status, vmxnet3_media_status),
2328f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_media_change, vmxnet3_media_change),
2338f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_promisc_set, vmxnet3_promisc_set),
2348f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_get_counter, vmxnet3_get_counter),
2358f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_update_admin_status, vmxnet3_update_admin_status),
2368f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_timer, vmxnet3_txq_timer),
2378f82136aSPatrick Kelsey 
2388f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_tx_queue_intr_enable, vmxnet3_tx_queue_intr_enable),
2398f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_rx_queue_intr_enable, vmxnet3_rx_queue_intr_enable),
2408f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_link_intr_enable, vmxnet3_link_intr_enable),
2418f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_intr_enable, vmxnet3_intr_enable_all),
2428f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_intr_disable, vmxnet3_intr_disable_all),
2438f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_msix_intr_assign, vmxnet3_msix_intr_assign),
2448f82136aSPatrick Kelsey 
2458f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_vlan_register, vmxnet3_vlan_register),
2468f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_vlan_unregister, vmxnet3_vlan_unregister),
2478f82136aSPatrick Kelsey 
2488f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_shutdown, vmxnet3_shutdown),
2498f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_suspend, vmxnet3_suspend),
2508f82136aSPatrick Kelsey 	DEVMETHOD(ifdi_resume, vmxnet3_resume),
2518f82136aSPatrick Kelsey 
2528f82136aSPatrick Kelsey 	DEVMETHOD_END
2538f82136aSPatrick Kelsey };
2548f82136aSPatrick Kelsey 
2558f82136aSPatrick Kelsey static driver_t vmxnet3_iflib_driver = {
2568f82136aSPatrick Kelsey 	"vmx", vmxnet3_iflib_methods, sizeof(struct vmxnet3_softc)
2578f82136aSPatrick Kelsey };
2588f82136aSPatrick Kelsey 
2598f82136aSPatrick Kelsey struct if_txrx vmxnet3_txrx = {
2608f82136aSPatrick Kelsey 	.ift_txd_encap = vmxnet3_isc_txd_encap,
2618f82136aSPatrick Kelsey 	.ift_txd_flush = vmxnet3_isc_txd_flush,
2628f82136aSPatrick Kelsey 	.ift_txd_credits_update = vmxnet3_isc_txd_credits_update,
2638f82136aSPatrick Kelsey 	.ift_rxd_available = vmxnet3_isc_rxd_available,
2648f82136aSPatrick Kelsey 	.ift_rxd_pkt_get = vmxnet3_isc_rxd_pkt_get,
2658f82136aSPatrick Kelsey 	.ift_rxd_refill = vmxnet3_isc_rxd_refill,
2668f82136aSPatrick Kelsey 	.ift_rxd_flush = vmxnet3_isc_rxd_flush,
2678f82136aSPatrick Kelsey 	.ift_legacy_intr = vmxnet3_legacy_intr
2688f82136aSPatrick Kelsey };
2698f82136aSPatrick Kelsey 
2708f82136aSPatrick Kelsey static struct if_shared_ctx vmxnet3_sctx_init = {
2718f82136aSPatrick Kelsey 	.isc_magic = IFLIB_MAGIC,
2728f82136aSPatrick Kelsey 	.isc_q_align = 512,
2738f82136aSPatrick Kelsey 
2748f82136aSPatrick Kelsey 	.isc_tx_maxsize = VMXNET3_TX_MAXSIZE,
2758f82136aSPatrick Kelsey 	.isc_tx_maxsegsize = VMXNET3_TX_MAXSEGSIZE,
2768f82136aSPatrick Kelsey 	.isc_tso_maxsize = VMXNET3_TSO_MAXSIZE + sizeof(struct ether_vlan_header),
2778f82136aSPatrick Kelsey 	.isc_tso_maxsegsize = VMXNET3_TX_MAXSEGSIZE,
2788f82136aSPatrick Kelsey 
2798f82136aSPatrick Kelsey 	/*
2808f82136aSPatrick Kelsey 	 * These values are used to configure the busdma tag used for
2818f82136aSPatrick Kelsey 	 * receive descriptors.  Each receive descriptor only points to one
2828f82136aSPatrick Kelsey 	 * buffer.
2838f82136aSPatrick Kelsey 	 */
2848f82136aSPatrick Kelsey 	.isc_rx_maxsize = VMXNET3_RX_MAXSEGSIZE, /* One buf per descriptor */
2858f82136aSPatrick Kelsey 	.isc_rx_nsegments = 1,  /* One mapping per descriptor */
2868f82136aSPatrick Kelsey 	.isc_rx_maxsegsize = VMXNET3_RX_MAXSEGSIZE,
2878f82136aSPatrick Kelsey 
2888f82136aSPatrick Kelsey 	.isc_admin_intrcnt = 1,
2898f82136aSPatrick Kelsey 	.isc_vendor_info = vmxnet3_vendor_info_array,
2908f82136aSPatrick Kelsey 	.isc_driver_version = "2",
2918f82136aSPatrick Kelsey 	.isc_driver = &vmxnet3_iflib_driver,
29241669133SMark Johnston 	.isc_flags = IFLIB_HAS_RXCQ | IFLIB_HAS_TXCQ | IFLIB_SINGLE_IRQ_RX_ONLY,
2938f82136aSPatrick Kelsey 
2948f82136aSPatrick Kelsey 	/*
2958f82136aSPatrick Kelsey 	 * Number of receive queues per receive queue set, with associated
2968f82136aSPatrick Kelsey 	 * descriptor settings for each.
2978f82136aSPatrick Kelsey 	 */
2988f82136aSPatrick Kelsey 	.isc_nrxqs = 3,
2998f82136aSPatrick Kelsey 	.isc_nfl = 2, /* one free list for each receive command queue */
3008f82136aSPatrick Kelsey 	.isc_nrxd_min = {VMXNET3_MIN_RX_NDESC, VMXNET3_MIN_RX_NDESC, VMXNET3_MIN_RX_NDESC},
3018f82136aSPatrick Kelsey 	.isc_nrxd_max = {VMXNET3_MAX_RX_NDESC, VMXNET3_MAX_RX_NDESC, VMXNET3_MAX_RX_NDESC},
3028f82136aSPatrick Kelsey 	.isc_nrxd_default = {VMXNET3_DEF_RX_NDESC, VMXNET3_DEF_RX_NDESC, VMXNET3_DEF_RX_NDESC},
3038f82136aSPatrick Kelsey 
3048f82136aSPatrick Kelsey 	/*
3058f82136aSPatrick Kelsey 	 * Number of transmit queues per transmit queue set, with associated
3068f82136aSPatrick Kelsey 	 * descriptor settings for each.
3078f82136aSPatrick Kelsey 	 */
3088f82136aSPatrick Kelsey 	.isc_ntxqs = 2,
3098f82136aSPatrick Kelsey 	.isc_ntxd_min = {VMXNET3_MIN_TX_NDESC, VMXNET3_MIN_TX_NDESC},
3108f82136aSPatrick Kelsey 	.isc_ntxd_max = {VMXNET3_MAX_TX_NDESC, VMXNET3_MAX_TX_NDESC},
3118f82136aSPatrick Kelsey 	.isc_ntxd_default = {VMXNET3_DEF_TX_NDESC, VMXNET3_DEF_TX_NDESC},
3128f82136aSPatrick Kelsey };
3138f82136aSPatrick Kelsey 
3148f82136aSPatrick Kelsey static void *
3158f82136aSPatrick Kelsey vmxnet3_register(device_t dev)
316e3c97c2cSBryan Venteicher {
3178f82136aSPatrick Kelsey 	return (&vmxnet3_sctx_init);
318e3c97c2cSBryan Venteicher }
319e3c97c2cSBryan Venteicher 
320e3c97c2cSBryan Venteicher static int
3215d1899eeSPatrick Kelsey trunc_powerof2(int val)
3225d1899eeSPatrick Kelsey {
3235d1899eeSPatrick Kelsey 
3245d1899eeSPatrick Kelsey 	return (1U << (fls(val) - 1));
3255d1899eeSPatrick Kelsey }
3265d1899eeSPatrick Kelsey 
3275d1899eeSPatrick Kelsey static int
3288f82136aSPatrick Kelsey vmxnet3_attach_pre(if_ctx_t ctx)
329e3c97c2cSBryan Venteicher {
3308f82136aSPatrick Kelsey 	device_t dev;
3318f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
332e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
3338f82136aSPatrick Kelsey 	uint32_t intr_config;
334e3c97c2cSBryan Venteicher 	int error;
335e3c97c2cSBryan Venteicher 
3368f82136aSPatrick Kelsey 	dev = iflib_get_dev(ctx);
3378f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
338e3c97c2cSBryan Venteicher 	sc->vmx_dev = dev;
3398f82136aSPatrick Kelsey 	sc->vmx_ctx = ctx;
3408f82136aSPatrick Kelsey 	sc->vmx_sctx = iflib_get_sctx(ctx);
3418f82136aSPatrick Kelsey 	sc->vmx_scctx = iflib_get_softc_ctx(ctx);
3428f82136aSPatrick Kelsey 	sc->vmx_ifp = iflib_get_ifp(ctx);
3438f82136aSPatrick Kelsey 	sc->vmx_media = iflib_get_media(ctx);
3448f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
345e3c97c2cSBryan Venteicher 
3468f82136aSPatrick Kelsey 	scctx->isc_tx_nsegments = VMXNET3_TX_MAXSEGS;
3478f82136aSPatrick Kelsey 	scctx->isc_tx_tso_segments_max = VMXNET3_TX_MAXSEGS;
3488f82136aSPatrick Kelsey 	/* isc_tx_tso_size_max doesn't include possible vlan header */
3498f82136aSPatrick Kelsey 	scctx->isc_tx_tso_size_max = VMXNET3_TSO_MAXSIZE;
3508f82136aSPatrick Kelsey 	scctx->isc_tx_tso_segsize_max = VMXNET3_TX_MAXSEGSIZE;
3518f82136aSPatrick Kelsey 	scctx->isc_txrx = &vmxnet3_txrx;
352e3c97c2cSBryan Venteicher 
3538f82136aSPatrick Kelsey 	/* If 0, the iflib tunable was not set, so set to the default */
3548f82136aSPatrick Kelsey 	if (scctx->isc_nrxqsets == 0)
3558f82136aSPatrick Kelsey 		scctx->isc_nrxqsets = VMXNET3_DEF_RX_QUEUES;
3565d1899eeSPatrick Kelsey 	scctx->isc_nrxqsets = trunc_powerof2(scctx->isc_nrxqsets);
3578f82136aSPatrick Kelsey 	scctx->isc_nrxqsets_max = min(VMXNET3_MAX_RX_QUEUES, mp_ncpus);
3585d1899eeSPatrick Kelsey 	scctx->isc_nrxqsets_max = trunc_powerof2(scctx->isc_nrxqsets_max);
359e3c97c2cSBryan Venteicher 
3608f82136aSPatrick Kelsey 	/* If 0, the iflib tunable was not set, so set to the default */
3618f82136aSPatrick Kelsey 	if (scctx->isc_ntxqsets == 0)
3628f82136aSPatrick Kelsey 		scctx->isc_ntxqsets = VMXNET3_DEF_TX_QUEUES;
3635d1899eeSPatrick Kelsey 	scctx->isc_ntxqsets = trunc_powerof2(scctx->isc_ntxqsets);
3648f82136aSPatrick Kelsey 	scctx->isc_ntxqsets_max = min(VMXNET3_MAX_TX_QUEUES, mp_ncpus);
3655d1899eeSPatrick Kelsey 	scctx->isc_ntxqsets_max = trunc_powerof2(scctx->isc_ntxqsets_max);
366e3c97c2cSBryan Venteicher 
3678f82136aSPatrick Kelsey 	/*
3688f82136aSPatrick Kelsey 	 * Enforce that the transmit completion queue descriptor count is
3698f82136aSPatrick Kelsey 	 * the same as the transmit command queue descriptor count.
3708f82136aSPatrick Kelsey 	 */
3718f82136aSPatrick Kelsey 	scctx->isc_ntxd[0] = scctx->isc_ntxd[1];
3728f82136aSPatrick Kelsey 	scctx->isc_txqsizes[0] =
3738f82136aSPatrick Kelsey 	    sizeof(struct vmxnet3_txcompdesc) * scctx->isc_ntxd[0];
3748f82136aSPatrick Kelsey 	scctx->isc_txqsizes[1] =
3758f82136aSPatrick Kelsey 	    sizeof(struct vmxnet3_txdesc) * scctx->isc_ntxd[1];
3768f82136aSPatrick Kelsey 
3778f82136aSPatrick Kelsey 	/*
3788f82136aSPatrick Kelsey 	 * Enforce that the receive completion queue descriptor count is the
3798f82136aSPatrick Kelsey 	 * sum of the receive command queue descriptor counts, and that the
3808f82136aSPatrick Kelsey 	 * second receive command queue descriptor count is the same as the
3818f82136aSPatrick Kelsey 	 * first one.
3828f82136aSPatrick Kelsey 	 */
3838f82136aSPatrick Kelsey 	scctx->isc_nrxd[2] = scctx->isc_nrxd[1];
3848f82136aSPatrick Kelsey 	scctx->isc_nrxd[0] = scctx->isc_nrxd[1] + scctx->isc_nrxd[2];
3858f82136aSPatrick Kelsey 	scctx->isc_rxqsizes[0] =
3868f82136aSPatrick Kelsey 	    sizeof(struct vmxnet3_rxcompdesc) * scctx->isc_nrxd[0];
3878f82136aSPatrick Kelsey 	scctx->isc_rxqsizes[1] =
3888f82136aSPatrick Kelsey 	    sizeof(struct vmxnet3_rxdesc) * scctx->isc_nrxd[1];
3898f82136aSPatrick Kelsey 	scctx->isc_rxqsizes[2] =
3908f82136aSPatrick Kelsey 	    sizeof(struct vmxnet3_rxdesc) * scctx->isc_nrxd[2];
3918f82136aSPatrick Kelsey 
3921342c8c6SPatrick Kelsey 	/*
3931342c8c6SPatrick Kelsey 	 * Initialize the max frame size and descriptor queue buffer
3941342c8c6SPatrick Kelsey 	 * sizes.
3951342c8c6SPatrick Kelsey 	 */
3961342c8c6SPatrick Kelsey 	vmxnet3_mtu_set(ctx, if_getmtu(sc->vmx_ifp));
3971342c8c6SPatrick Kelsey 
3988f82136aSPatrick Kelsey 	scctx->isc_rss_table_size = UPT1_RSS_MAX_IND_TABLE_SIZE;
3998f82136aSPatrick Kelsey 
4008f82136aSPatrick Kelsey 	/* Map PCI BARs */
401e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_resources(sc);
402e3c97c2cSBryan Venteicher 	if (error)
403e3c97c2cSBryan Venteicher 		goto fail;
404e3c97c2cSBryan Venteicher 
4058f82136aSPatrick Kelsey 	/* Check device versions */
406e3c97c2cSBryan Venteicher 	error = vmxnet3_check_version(sc);
407e3c97c2cSBryan Venteicher 	if (error)
408e3c97c2cSBryan Venteicher 		goto fail;
409e3c97c2cSBryan Venteicher 
4108f82136aSPatrick Kelsey 	/*
4118f82136aSPatrick Kelsey 	 * The interrupt mode can be set in the hypervisor configuration via
4128f82136aSPatrick Kelsey 	 * the parameter ethernet<N>.intrMode.
4138f82136aSPatrick Kelsey 	 */
4148f82136aSPatrick Kelsey 	intr_config = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_INTRCFG);
4158f82136aSPatrick Kelsey 	sc->vmx_intr_mask_mode = (intr_config >> 2) & 0x03;
416e3c97c2cSBryan Venteicher 
4178f82136aSPatrick Kelsey 	/*
4188f82136aSPatrick Kelsey 	 * Configure the softc context to attempt to configure the interrupt
4198f82136aSPatrick Kelsey 	 * mode now indicated by intr_config.  iflib will follow the usual
420b97de13aSMarius Strobl 	 * fallback path MSI-X -> MSI -> LEGACY, starting at the configured
4218f82136aSPatrick Kelsey 	 * starting mode.
4228f82136aSPatrick Kelsey 	 */
4238f82136aSPatrick Kelsey 	switch (intr_config & 0x03) {
4248f82136aSPatrick Kelsey 	case VMXNET3_IT_AUTO:
4258f82136aSPatrick Kelsey 	case VMXNET3_IT_MSIX:
4268f82136aSPatrick Kelsey 		scctx->isc_msix_bar = pci_msix_table_bar(dev);
4278f82136aSPatrick Kelsey 		break;
4288f82136aSPatrick Kelsey 	case VMXNET3_IT_MSI:
4298f82136aSPatrick Kelsey 		scctx->isc_msix_bar = -1;
4308f82136aSPatrick Kelsey 		scctx->isc_disable_msix = 1;
4318f82136aSPatrick Kelsey 		break;
4328f82136aSPatrick Kelsey 	case VMXNET3_IT_LEGACY:
4338f82136aSPatrick Kelsey 		scctx->isc_msix_bar = 0;
4348f82136aSPatrick Kelsey 		break;
435e3c97c2cSBryan Venteicher 	}
436e3c97c2cSBryan Venteicher 
4378f82136aSPatrick Kelsey 	scctx->isc_tx_csum_flags = VMXNET3_CSUM_ALL_OFFLOAD;
4388f82136aSPatrick Kelsey 	scctx->isc_capabilities = scctx->isc_capenable =
4398f82136aSPatrick Kelsey 	    IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6 |
4408f82136aSPatrick Kelsey 	    IFCAP_TSO4 | IFCAP_TSO6 |
4418f82136aSPatrick Kelsey 	    IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6 |
4428f82136aSPatrick Kelsey 	    IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING |
4438f82136aSPatrick Kelsey 	    IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO |
4448f82136aSPatrick Kelsey 	    IFCAP_JUMBO_MTU;
445e3c97c2cSBryan Venteicher 
4468f82136aSPatrick Kelsey 	/* These capabilities are not enabled by default. */
4478f82136aSPatrick Kelsey 	scctx->isc_capabilities |= IFCAP_LRO | IFCAP_VLAN_HWFILTER;
4488f82136aSPatrick Kelsey 
4498f82136aSPatrick Kelsey 	vmxnet3_get_lladdr(sc);
4508f82136aSPatrick Kelsey 	iflib_set_mac(ctx, sc->vmx_lladdr);
4518f82136aSPatrick Kelsey 
4528f82136aSPatrick Kelsey 	return (0);
453e3c97c2cSBryan Venteicher fail:
4548f82136aSPatrick Kelsey 	/*
4558f82136aSPatrick Kelsey 	 * We must completely clean up anything allocated above as iflib
4568f82136aSPatrick Kelsey 	 * will not invoke any other driver entry points as a result of this
4578f82136aSPatrick Kelsey 	 * failure.
4588f82136aSPatrick Kelsey 	 */
4598f82136aSPatrick Kelsey 	vmxnet3_free_resources(sc);
460e3c97c2cSBryan Venteicher 
461e3c97c2cSBryan Venteicher 	return (error);
462e3c97c2cSBryan Venteicher }
463e3c97c2cSBryan Venteicher 
464e3c97c2cSBryan Venteicher static int
4658f82136aSPatrick Kelsey vmxnet3_msix_intr_assign(if_ctx_t ctx, int msix)
466e3c97c2cSBryan Venteicher {
467e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
4688f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
4698f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
4708f82136aSPatrick Kelsey 	int error;
4718f82136aSPatrick Kelsey 	int i;
4728f82136aSPatrick Kelsey 	char irq_name[16];
473e3c97c2cSBryan Venteicher 
4748f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
4758f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
476e3c97c2cSBryan Venteicher 
4778f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
4788f82136aSPatrick Kelsey 		snprintf(irq_name, sizeof(irq_name), "rxq%d", i);
479e557c1ddSBryan Venteicher 
4808f82136aSPatrick Kelsey 		rxq = &sc->vmx_rxq[i];
4818f82136aSPatrick Kelsey 		error = iflib_irq_alloc_generic(ctx, &rxq->vxrxq_irq, i + 1,
48281be6552SMatt Macy 		    IFLIB_INTR_RXTX, vmxnet3_rxq_intr, rxq, i, irq_name);
4838f82136aSPatrick Kelsey 		if (error) {
4848f82136aSPatrick Kelsey 			device_printf(iflib_get_dev(ctx),
4858f82136aSPatrick Kelsey 			    "Failed to register rxq %d interrupt handler\n", i);
4868f82136aSPatrick Kelsey 			return (error);
4878f82136aSPatrick Kelsey 		}
488e3c97c2cSBryan Venteicher 	}
489e3c97c2cSBryan Venteicher 
4908f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++) {
4918f82136aSPatrick Kelsey 		snprintf(irq_name, sizeof(irq_name), "txq%d", i);
4928f82136aSPatrick Kelsey 
4938f82136aSPatrick Kelsey 		/*
4948f82136aSPatrick Kelsey 		 * Don't provide the corresponding rxq irq for reference -
4958f82136aSPatrick Kelsey 		 * we want the transmit task to be attached to a task queue
4968f82136aSPatrick Kelsey 		 * that is different from the one used by the corresponding
4978f82136aSPatrick Kelsey 		 * rxq irq.  That is because the TX doorbell writes are very
4988f82136aSPatrick Kelsey 		 * expensive as virtualized MMIO operations, so we want to
4998f82136aSPatrick Kelsey 		 * be able to defer them to another core when possible so
5008f82136aSPatrick Kelsey 		 * that they don't steal receive processing cycles during
5018f82136aSPatrick Kelsey 		 * stack turnarounds like TCP ACK generation.  The other
5028f82136aSPatrick Kelsey 		 * piece to this approach is enabling the iflib abdicate
5038f82136aSPatrick Kelsey 		 * option (currently via an interface-specific
5048f82136aSPatrick Kelsey 		 * tunable/sysctl).
5058f82136aSPatrick Kelsey 		 */
5068f82136aSPatrick Kelsey 		iflib_softirq_alloc_generic(ctx, NULL, IFLIB_INTR_TX, NULL, i,
5078f82136aSPatrick Kelsey 		    irq_name);
508e3c97c2cSBryan Venteicher 	}
509e3c97c2cSBryan Venteicher 
5108f82136aSPatrick Kelsey 	error = iflib_irq_alloc_generic(ctx, &sc->vmx_event_intr_irq,
5118f82136aSPatrick Kelsey 	    scctx->isc_nrxqsets + 1, IFLIB_INTR_ADMIN, vmxnet3_event_intr, sc, 0,
5128f82136aSPatrick Kelsey 	    "event");
5138f82136aSPatrick Kelsey 	if (error) {
5148f82136aSPatrick Kelsey 		device_printf(iflib_get_dev(ctx),
5158f82136aSPatrick Kelsey 		    "Failed to register event interrupt handler\n");
5168f82136aSPatrick Kelsey 		return (error);
517e3c97c2cSBryan Venteicher 	}
518e3c97c2cSBryan Venteicher 
5198f82136aSPatrick Kelsey 	return (0);
5208f82136aSPatrick Kelsey }
521e3c97c2cSBryan Venteicher 
5228f82136aSPatrick Kelsey static void
5238f82136aSPatrick Kelsey vmxnet3_free_irqs(struct vmxnet3_softc *sc)
5248f82136aSPatrick Kelsey {
5258f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
5268f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
5278f82136aSPatrick Kelsey 	int i;
5288f82136aSPatrick Kelsey 
5298f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
5308f82136aSPatrick Kelsey 
5318f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
5328f82136aSPatrick Kelsey 		rxq = &sc->vmx_rxq[i];
5338f82136aSPatrick Kelsey 		iflib_irq_free(sc->vmx_ctx, &rxq->vxrxq_irq);
5348f82136aSPatrick Kelsey 	}
5358f82136aSPatrick Kelsey 
5368f82136aSPatrick Kelsey 	iflib_irq_free(sc->vmx_ctx, &sc->vmx_event_intr_irq);
5378f82136aSPatrick Kelsey }
5388f82136aSPatrick Kelsey 
5398f82136aSPatrick Kelsey static int
5408f82136aSPatrick Kelsey vmxnet3_attach_post(if_ctx_t ctx)
5418f82136aSPatrick Kelsey {
5428f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
5438f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
5448f82136aSPatrick Kelsey 	int error;
5458f82136aSPatrick Kelsey 
5468f82136aSPatrick Kelsey 	scctx = iflib_get_softc_ctx(ctx);
5478f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
5488f82136aSPatrick Kelsey 
5498f82136aSPatrick Kelsey 	if (scctx->isc_nrxqsets > 1)
5508f82136aSPatrick Kelsey 		sc->vmx_flags |= VMXNET3_FLAG_RSS;
5518f82136aSPatrick Kelsey 
5528f82136aSPatrick Kelsey 	error = vmxnet3_alloc_data(sc);
5538f82136aSPatrick Kelsey 	if (error)
5548f82136aSPatrick Kelsey 		goto fail;
5558f82136aSPatrick Kelsey 
5568f82136aSPatrick Kelsey 	vmxnet3_set_interrupt_idx(sc);
5578f82136aSPatrick Kelsey 	vmxnet3_setup_sysctl(sc);
5588f82136aSPatrick Kelsey 
5598f82136aSPatrick Kelsey 	ifmedia_add(sc->vmx_media, IFM_ETHER | IFM_AUTO, 0, NULL);
5608f82136aSPatrick Kelsey 	ifmedia_set(sc->vmx_media, IFM_ETHER | IFM_AUTO);
5618f82136aSPatrick Kelsey 
5628f82136aSPatrick Kelsey fail:
5638f82136aSPatrick Kelsey 	return (error);
5648f82136aSPatrick Kelsey }
5658f82136aSPatrick Kelsey 
5668f82136aSPatrick Kelsey static int
5678f82136aSPatrick Kelsey vmxnet3_detach(if_ctx_t ctx)
5688f82136aSPatrick Kelsey {
5698f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
5708f82136aSPatrick Kelsey 
5718f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
5728f82136aSPatrick Kelsey 
5738f82136aSPatrick Kelsey 	vmxnet3_free_irqs(sc);
574e3c97c2cSBryan Venteicher 	vmxnet3_free_data(sc);
575e3c97c2cSBryan Venteicher 	vmxnet3_free_resources(sc);
576e3c97c2cSBryan Venteicher 
577e3c97c2cSBryan Venteicher 	return (0);
578e3c97c2cSBryan Venteicher }
579e3c97c2cSBryan Venteicher 
580e3c97c2cSBryan Venteicher static int
5818f82136aSPatrick Kelsey vmxnet3_shutdown(if_ctx_t ctx)
5828f82136aSPatrick Kelsey {
5838f82136aSPatrick Kelsey 
5848f82136aSPatrick Kelsey 	return (0);
5858f82136aSPatrick Kelsey }
5868f82136aSPatrick Kelsey 
5878f82136aSPatrick Kelsey static int
5888f82136aSPatrick Kelsey vmxnet3_suspend(if_ctx_t ctx)
5898f82136aSPatrick Kelsey {
5908f82136aSPatrick Kelsey 
5918f82136aSPatrick Kelsey 	return (0);
5928f82136aSPatrick Kelsey }
5938f82136aSPatrick Kelsey 
5948f82136aSPatrick Kelsey static int
5958f82136aSPatrick Kelsey vmxnet3_resume(if_ctx_t ctx)
596e3c97c2cSBryan Venteicher {
597e3c97c2cSBryan Venteicher 
598e3c97c2cSBryan Venteicher 	return (0);
599e3c97c2cSBryan Venteicher }
600e3c97c2cSBryan Venteicher 
601e3c97c2cSBryan Venteicher static int
602e3c97c2cSBryan Venteicher vmxnet3_alloc_resources(struct vmxnet3_softc *sc)
603e3c97c2cSBryan Venteicher {
604e3c97c2cSBryan Venteicher 	device_t dev;
605e3c97c2cSBryan Venteicher 	int rid;
606e3c97c2cSBryan Venteicher 
607e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
608e3c97c2cSBryan Venteicher 
609e3c97c2cSBryan Venteicher 	rid = PCIR_BAR(0);
610e3c97c2cSBryan Venteicher 	sc->vmx_res0 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
611e3c97c2cSBryan Venteicher 	    RF_ACTIVE);
612e3c97c2cSBryan Venteicher 	if (sc->vmx_res0 == NULL) {
613e3c97c2cSBryan Venteicher 		device_printf(dev,
614e3c97c2cSBryan Venteicher 		    "could not map BAR0 memory\n");
615e3c97c2cSBryan Venteicher 		return (ENXIO);
616e3c97c2cSBryan Venteicher 	}
617e3c97c2cSBryan Venteicher 
618e3c97c2cSBryan Venteicher 	sc->vmx_iot0 = rman_get_bustag(sc->vmx_res0);
619e3c97c2cSBryan Venteicher 	sc->vmx_ioh0 = rman_get_bushandle(sc->vmx_res0);
620e3c97c2cSBryan Venteicher 
621e3c97c2cSBryan Venteicher 	rid = PCIR_BAR(1);
622e3c97c2cSBryan Venteicher 	sc->vmx_res1 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
623e3c97c2cSBryan Venteicher 	    RF_ACTIVE);
624e3c97c2cSBryan Venteicher 	if (sc->vmx_res1 == NULL) {
625e3c97c2cSBryan Venteicher 		device_printf(dev,
626e3c97c2cSBryan Venteicher 		    "could not map BAR1 memory\n");
627e3c97c2cSBryan Venteicher 		return (ENXIO);
628e3c97c2cSBryan Venteicher 	}
629e3c97c2cSBryan Venteicher 
630e3c97c2cSBryan Venteicher 	sc->vmx_iot1 = rman_get_bustag(sc->vmx_res1);
631e3c97c2cSBryan Venteicher 	sc->vmx_ioh1 = rman_get_bushandle(sc->vmx_res1);
632e3c97c2cSBryan Venteicher 
633e3c97c2cSBryan Venteicher 	return (0);
634e3c97c2cSBryan Venteicher }
635e3c97c2cSBryan Venteicher 
636e3c97c2cSBryan Venteicher static void
637e3c97c2cSBryan Venteicher vmxnet3_free_resources(struct vmxnet3_softc *sc)
638e3c97c2cSBryan Venteicher {
639e3c97c2cSBryan Venteicher 	device_t dev;
640e3c97c2cSBryan Venteicher 
641e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
642e3c97c2cSBryan Venteicher 
643e3c97c2cSBryan Venteicher 	if (sc->vmx_res0 != NULL) {
644b97de13aSMarius Strobl 		bus_release_resource(dev, SYS_RES_MEMORY,
645b97de13aSMarius Strobl 		    rman_get_rid(sc->vmx_res0), sc->vmx_res0);
646e3c97c2cSBryan Venteicher 		sc->vmx_res0 = NULL;
647e3c97c2cSBryan Venteicher 	}
648e3c97c2cSBryan Venteicher 
649e3c97c2cSBryan Venteicher 	if (sc->vmx_res1 != NULL) {
650b97de13aSMarius Strobl 		bus_release_resource(dev, SYS_RES_MEMORY,
651b97de13aSMarius Strobl 		    rman_get_rid(sc->vmx_res1), sc->vmx_res1);
652e3c97c2cSBryan Venteicher 		sc->vmx_res1 = NULL;
653e3c97c2cSBryan Venteicher 	}
654e3c97c2cSBryan Venteicher }
655e3c97c2cSBryan Venteicher 
656e3c97c2cSBryan Venteicher static int
657e3c97c2cSBryan Venteicher vmxnet3_check_version(struct vmxnet3_softc *sc)
658e3c97c2cSBryan Venteicher {
659e3c97c2cSBryan Venteicher 	device_t dev;
660e3c97c2cSBryan Venteicher 	uint32_t version;
661e3c97c2cSBryan Venteicher 
662e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
663e3c97c2cSBryan Venteicher 
664e3c97c2cSBryan Venteicher 	version = vmxnet3_read_bar1(sc, VMXNET3_BAR1_VRRS);
665e3c97c2cSBryan Venteicher 	if ((version & 0x01) == 0) {
666e3c97c2cSBryan Venteicher 		device_printf(dev, "unsupported hardware version %#x\n",
667e3c97c2cSBryan Venteicher 		    version);
668e3c97c2cSBryan Venteicher 		return (ENOTSUP);
6693c965775SBryan Venteicher 	}
670e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_VRRS, 1);
671e3c97c2cSBryan Venteicher 
672e3c97c2cSBryan Venteicher 	version = vmxnet3_read_bar1(sc, VMXNET3_BAR1_UVRS);
673e3c97c2cSBryan Venteicher 	if ((version & 0x01) == 0) {
674e3c97c2cSBryan Venteicher 		device_printf(dev, "unsupported UPT version %#x\n", version);
675e3c97c2cSBryan Venteicher 		return (ENOTSUP);
6763c965775SBryan Venteicher 	}
677e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_UVRS, 1);
678e3c97c2cSBryan Venteicher 
679e3c97c2cSBryan Venteicher 	return (0);
680e3c97c2cSBryan Venteicher }
681e3c97c2cSBryan Venteicher 
682e3c97c2cSBryan Venteicher static void
683e3c97c2cSBryan Venteicher vmxnet3_set_interrupt_idx(struct vmxnet3_softc *sc)
684e3c97c2cSBryan Venteicher {
6858f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
686e3c97c2cSBryan Venteicher 	struct vmxnet3_txqueue *txq;
687e3c97c2cSBryan Venteicher 	struct vmxnet3_txq_shared *txs;
688e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
689e3c97c2cSBryan Venteicher 	struct vmxnet3_rxq_shared *rxs;
6908f82136aSPatrick Kelsey 	int intr_idx;
691e3c97c2cSBryan Venteicher 	int i;
692e3c97c2cSBryan Venteicher 
6938f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
694e3c97c2cSBryan Venteicher 
6958f82136aSPatrick Kelsey 	/*
696769d56ecSPatrick Kelsey 	 * There is always one interrupt per receive queue, assigned
697769d56ecSPatrick Kelsey 	 * starting with the first interrupt.  When there is only one
698769d56ecSPatrick Kelsey 	 * interrupt available, the event interrupt shares the receive queue
699769d56ecSPatrick Kelsey 	 * interrupt, otherwise it uses the interrupt following the last
700769d56ecSPatrick Kelsey 	 * receive queue interrupt.  Transmit queues are not assigned
701769d56ecSPatrick Kelsey 	 * interrupts, so they are given indexes beyond the indexes that
702769d56ecSPatrick Kelsey 	 * correspond to the real interrupts.
7038f82136aSPatrick Kelsey 	 */
704769d56ecSPatrick Kelsey 
705769d56ecSPatrick Kelsey 	/* The event interrupt is always the last vector. */
7068f82136aSPatrick Kelsey 	sc->vmx_event_intr_idx = scctx->isc_vectors - 1;
707e3c97c2cSBryan Venteicher 
7088f82136aSPatrick Kelsey 	intr_idx = 0;
7098f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++, intr_idx++) {
710e3c97c2cSBryan Venteicher 		rxq = &sc->vmx_rxq[i];
711e3c97c2cSBryan Venteicher 		rxs = rxq->vxrxq_rs;
7128f82136aSPatrick Kelsey 		rxq->vxrxq_intr_idx = intr_idx;
713e3c97c2cSBryan Venteicher 		rxs->intr_idx = rxq->vxrxq_intr_idx;
714e3c97c2cSBryan Venteicher 	}
7158f82136aSPatrick Kelsey 
7168f82136aSPatrick Kelsey 	/*
7178f82136aSPatrick Kelsey 	 * Assign the tx queues interrupt indexes above what we are actually
7188f82136aSPatrick Kelsey 	 * using.  These interrupts will never be enabled.
7198f82136aSPatrick Kelsey 	 */
7208f82136aSPatrick Kelsey 	intr_idx = scctx->isc_vectors;
7218f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++, intr_idx++) {
7228f82136aSPatrick Kelsey 		txq = &sc->vmx_txq[i];
7238f82136aSPatrick Kelsey 		txs = txq->vxtxq_ts;
7248f82136aSPatrick Kelsey 		txq->vxtxq_intr_idx = intr_idx;
7258f82136aSPatrick Kelsey 		txs->intr_idx = txq->vxtxq_intr_idx;
7268f82136aSPatrick Kelsey 	}
727e3c97c2cSBryan Venteicher }
728e3c97c2cSBryan Venteicher 
729e3c97c2cSBryan Venteicher static int
7308f82136aSPatrick Kelsey vmxnet3_queues_shared_alloc(struct vmxnet3_softc *sc)
731e3c97c2cSBryan Venteicher {
7328f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
7338f82136aSPatrick Kelsey 	int size;
734e3c97c2cSBryan Venteicher 	int error;
735e3c97c2cSBryan Venteicher 
7368f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
737e3c97c2cSBryan Venteicher 
7388f82136aSPatrick Kelsey 	/*
7398f82136aSPatrick Kelsey 	 * The txq and rxq shared data areas must be allocated contiguously
7408f82136aSPatrick Kelsey 	 * as vmxnet3_driver_shared contains only a single address member
7418f82136aSPatrick Kelsey 	 * for the shared queue data area.
7428f82136aSPatrick Kelsey 	 */
7438f82136aSPatrick Kelsey 	size = scctx->isc_ntxqsets * sizeof(struct vmxnet3_txq_shared) +
7448f82136aSPatrick Kelsey 	    scctx->isc_nrxqsets * sizeof(struct vmxnet3_rxq_shared);
7458f82136aSPatrick Kelsey 	error = iflib_dma_alloc_align(sc->vmx_ctx, size, 128, &sc->vmx_qs_dma, 0);
7468f82136aSPatrick Kelsey 	if (error) {
7478f82136aSPatrick Kelsey 		device_printf(sc->vmx_dev, "cannot alloc queue shared memory\n");
748e3c97c2cSBryan Venteicher 		return (error);
749e3c97c2cSBryan Venteicher 	}
750e3c97c2cSBryan Venteicher 
751e557c1ddSBryan Venteicher 	return (0);
752e557c1ddSBryan Venteicher }
753e557c1ddSBryan Venteicher 
754e557c1ddSBryan Venteicher static void
7558f82136aSPatrick Kelsey vmxnet3_init_txq(struct vmxnet3_softc *sc, int q)
756e557c1ddSBryan Venteicher {
757e557c1ddSBryan Venteicher 	struct vmxnet3_txqueue *txq;
7588f82136aSPatrick Kelsey 	struct vmxnet3_comp_ring *txc;
7598f82136aSPatrick Kelsey 	struct vmxnet3_txring *txr;
7608f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
761e557c1ddSBryan Venteicher 
7628f82136aSPatrick Kelsey 	txq = &sc->vmx_txq[q];
7638f82136aSPatrick Kelsey 	txc = &txq->vxtxq_comp_ring;
7648f82136aSPatrick Kelsey 	txr = &txq->vxtxq_cmd_ring;
7658f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
7668f82136aSPatrick Kelsey 
7678f82136aSPatrick Kelsey 	snprintf(txq->vxtxq_name, sizeof(txq->vxtxq_name), "%s-tx%d",
7688f82136aSPatrick Kelsey 	    device_get_nameunit(sc->vmx_dev), q);
7698f82136aSPatrick Kelsey 
7708f82136aSPatrick Kelsey 	txq->vxtxq_sc = sc;
7718f82136aSPatrick Kelsey 	txq->vxtxq_id = q;
7728f82136aSPatrick Kelsey 	txc->vxcr_ndesc = scctx->isc_ntxd[0];
7738f82136aSPatrick Kelsey 	txr->vxtxr_ndesc = scctx->isc_ntxd[1];
774e557c1ddSBryan Venteicher }
7758f82136aSPatrick Kelsey 
7768f82136aSPatrick Kelsey static int
7778f82136aSPatrick Kelsey vmxnet3_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
7788f82136aSPatrick Kelsey     int ntxqs, int ntxqsets)
7798f82136aSPatrick Kelsey {
7808f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
7818f82136aSPatrick Kelsey 	int q;
7828f82136aSPatrick Kelsey 	int error;
7838f82136aSPatrick Kelsey 	caddr_t kva;
7848f82136aSPatrick Kelsey 
7858f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
7868f82136aSPatrick Kelsey 
7878f82136aSPatrick Kelsey 	/* Allocate the array of transmit queues */
7888f82136aSPatrick Kelsey 	sc->vmx_txq = malloc(sizeof(struct vmxnet3_txqueue) *
7898f82136aSPatrick Kelsey 	    ntxqsets, M_DEVBUF, M_NOWAIT | M_ZERO);
7908f82136aSPatrick Kelsey 	if (sc->vmx_txq == NULL)
7918f82136aSPatrick Kelsey 		return (ENOMEM);
7928f82136aSPatrick Kelsey 
7938f82136aSPatrick Kelsey 	/* Initialize driver state for each transmit queue */
7948f82136aSPatrick Kelsey 	for (q = 0; q < ntxqsets; q++)
7958f82136aSPatrick Kelsey 		vmxnet3_init_txq(sc, q);
7968f82136aSPatrick Kelsey 
7978f82136aSPatrick Kelsey 	/*
7988f82136aSPatrick Kelsey 	 * Allocate queue state that is shared with the device.  This check
7998f82136aSPatrick Kelsey 	 * and call is performed in both vmxnet3_tx_queues_alloc() and
8008f82136aSPatrick Kelsey 	 * vmxnet3_rx_queues_alloc() so that we don't have to care which
8018f82136aSPatrick Kelsey 	 * order iflib invokes those routines in.
8028f82136aSPatrick Kelsey 	 */
8038f82136aSPatrick Kelsey 	if (sc->vmx_qs_dma.idi_size == 0) {
8048f82136aSPatrick Kelsey 		error = vmxnet3_queues_shared_alloc(sc);
8058f82136aSPatrick Kelsey 		if (error)
8068f82136aSPatrick Kelsey 			return (error);
807e557c1ddSBryan Venteicher 	}
8088f82136aSPatrick Kelsey 
8098f82136aSPatrick Kelsey 	kva = sc->vmx_qs_dma.idi_vaddr;
8108f82136aSPatrick Kelsey 	for (q = 0; q < ntxqsets; q++) {
8118f82136aSPatrick Kelsey 		sc->vmx_txq[q].vxtxq_ts = (struct vmxnet3_txq_shared *) kva;
8128f82136aSPatrick Kelsey 		kva += sizeof(struct vmxnet3_txq_shared);
8138f82136aSPatrick Kelsey 	}
8148f82136aSPatrick Kelsey 
8158f82136aSPatrick Kelsey 	/* Record descriptor ring vaddrs and paddrs */
8168f82136aSPatrick Kelsey 	for (q = 0; q < ntxqsets; q++) {
8178f82136aSPatrick Kelsey 		struct vmxnet3_txqueue *txq;
8188f82136aSPatrick Kelsey 		struct vmxnet3_txring *txr;
8198f82136aSPatrick Kelsey 		struct vmxnet3_comp_ring *txc;
8208f82136aSPatrick Kelsey 
8218f82136aSPatrick Kelsey 		txq = &sc->vmx_txq[q];
8228f82136aSPatrick Kelsey 		txc = &txq->vxtxq_comp_ring;
8238f82136aSPatrick Kelsey 		txr = &txq->vxtxq_cmd_ring;
8248f82136aSPatrick Kelsey 
8258f82136aSPatrick Kelsey 		/* Completion ring */
8268f82136aSPatrick Kelsey 		txc->vxcr_u.txcd =
8278f82136aSPatrick Kelsey 		    (struct vmxnet3_txcompdesc *) vaddrs[q * ntxqs + 0];
8288f82136aSPatrick Kelsey 		txc->vxcr_paddr = paddrs[q * ntxqs + 0];
8298f82136aSPatrick Kelsey 
8308f82136aSPatrick Kelsey 		/* Command ring */
8318f82136aSPatrick Kelsey 		txr->vxtxr_txd =
8328f82136aSPatrick Kelsey 		    (struct vmxnet3_txdesc *) vaddrs[q * ntxqs + 1];
8338f82136aSPatrick Kelsey 		txr->vxtxr_paddr = paddrs[q * ntxqs + 1];
8348f82136aSPatrick Kelsey 	}
8358f82136aSPatrick Kelsey 
8368f82136aSPatrick Kelsey 	return (0);
837e557c1ddSBryan Venteicher }
838e557c1ddSBryan Venteicher 
839e557c1ddSBryan Venteicher static void
8408f82136aSPatrick Kelsey vmxnet3_init_rxq(struct vmxnet3_softc *sc, int q, int nrxqs)
841e3c97c2cSBryan Venteicher {
842e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
8438f82136aSPatrick Kelsey 	struct vmxnet3_comp_ring *rxc;
844e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
8458f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
846e3c97c2cSBryan Venteicher 	int i;
847e3c97c2cSBryan Venteicher 
848e3c97c2cSBryan Venteicher 	rxq = &sc->vmx_rxq[q];
8498f82136aSPatrick Kelsey 	rxc = &rxq->vxrxq_comp_ring;
8508f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
851e3c97c2cSBryan Venteicher 
852e3c97c2cSBryan Venteicher 	snprintf(rxq->vxrxq_name, sizeof(rxq->vxrxq_name), "%s-rx%d",
853e3c97c2cSBryan Venteicher 	    device_get_nameunit(sc->vmx_dev), q);
854e3c97c2cSBryan Venteicher 
855e3c97c2cSBryan Venteicher 	rxq->vxrxq_sc = sc;
856e3c97c2cSBryan Venteicher 	rxq->vxrxq_id = q;
857e3c97c2cSBryan Venteicher 
8588f82136aSPatrick Kelsey 	/*
8598f82136aSPatrick Kelsey 	 * First rxq is the completion queue, so there are nrxqs - 1 command
8608f82136aSPatrick Kelsey 	 * rings starting at iflib queue id 1.
8618f82136aSPatrick Kelsey 	 */
8628f82136aSPatrick Kelsey 	rxc->vxcr_ndesc = scctx->isc_nrxd[0];
8638f82136aSPatrick Kelsey 	for (i = 0; i < nrxqs - 1; i++) {
864e3c97c2cSBryan Venteicher 		rxr = &rxq->vxrxq_cmd_ring[i];
8658f82136aSPatrick Kelsey 		rxr->vxrxr_ndesc = scctx->isc_nrxd[i + 1];
8663c965775SBryan Venteicher 	}
867e3c97c2cSBryan Venteicher }
868e3c97c2cSBryan Venteicher 
869e3c97c2cSBryan Venteicher static int
8708f82136aSPatrick Kelsey vmxnet3_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
8718f82136aSPatrick Kelsey     int nrxqs, int nrxqsets)
872e3c97c2cSBryan Venteicher {
8738f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
8748f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
8758f82136aSPatrick Kelsey 	int q;
8768f82136aSPatrick Kelsey 	int i;
8778f82136aSPatrick Kelsey 	int error;
8788f82136aSPatrick Kelsey 	caddr_t kva;
879e3c97c2cSBryan Venteicher 
8808f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
8818f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
882e3c97c2cSBryan Venteicher 
8838f82136aSPatrick Kelsey 	/* Allocate the array of receive queues */
8848f82136aSPatrick Kelsey 	sc->vmx_rxq = malloc(sizeof(struct vmxnet3_rxqueue) *
8858f82136aSPatrick Kelsey 	    nrxqsets, M_DEVBUF, M_NOWAIT | M_ZERO);
8868f82136aSPatrick Kelsey 	if (sc->vmx_rxq == NULL)
887e3c97c2cSBryan Venteicher 		return (ENOMEM);
888e3c97c2cSBryan Venteicher 
8898f82136aSPatrick Kelsey 	/* Initialize driver state for each receive queue */
8908f82136aSPatrick Kelsey 	for (q = 0; q < nrxqsets; q++)
8918f82136aSPatrick Kelsey 		vmxnet3_init_rxq(sc, q, nrxqs);
892e3c97c2cSBryan Venteicher 
893e557c1ddSBryan Venteicher 	/*
8948f82136aSPatrick Kelsey 	 * Allocate queue state that is shared with the device.  This check
8958f82136aSPatrick Kelsey 	 * and call is performed in both vmxnet3_tx_queues_alloc() and
8968f82136aSPatrick Kelsey 	 * vmxnet3_rx_queues_alloc() so that we don't have to care which
8978f82136aSPatrick Kelsey 	 * order iflib invokes those routines in.
898e557c1ddSBryan Venteicher 	 */
8998f82136aSPatrick Kelsey 	if (sc->vmx_qs_dma.idi_size == 0) {
9008f82136aSPatrick Kelsey 		error = vmxnet3_queues_shared_alloc(sc);
901e3c97c2cSBryan Venteicher 		if (error)
902e3c97c2cSBryan Venteicher 			return (error);
903e3c97c2cSBryan Venteicher 	}
904e3c97c2cSBryan Venteicher 
9058f82136aSPatrick Kelsey 	kva = sc->vmx_qs_dma.idi_vaddr +
9068f82136aSPatrick Kelsey 	    scctx->isc_ntxqsets * sizeof(struct vmxnet3_txq_shared);
9078f82136aSPatrick Kelsey 	for (q = 0; q < nrxqsets; q++) {
9088f82136aSPatrick Kelsey 		sc->vmx_rxq[q].vxrxq_rs = (struct vmxnet3_rxq_shared *) kva;
9098f82136aSPatrick Kelsey 		kva += sizeof(struct vmxnet3_rxq_shared);
9108f82136aSPatrick Kelsey 	}
9118f82136aSPatrick Kelsey 
9128f82136aSPatrick Kelsey 	/* Record descriptor ring vaddrs and paddrs */
9138f82136aSPatrick Kelsey 	for (q = 0; q < nrxqsets; q++) {
9148f82136aSPatrick Kelsey 		struct vmxnet3_rxqueue *rxq;
9158f82136aSPatrick Kelsey 		struct vmxnet3_rxring *rxr;
9168f82136aSPatrick Kelsey 		struct vmxnet3_comp_ring *rxc;
9178f82136aSPatrick Kelsey 
9188f82136aSPatrick Kelsey 		rxq = &sc->vmx_rxq[q];
9198f82136aSPatrick Kelsey 		rxc = &rxq->vxrxq_comp_ring;
9208f82136aSPatrick Kelsey 
9218f82136aSPatrick Kelsey 		/* Completion ring */
9228f82136aSPatrick Kelsey 		rxc->vxcr_u.rxcd =
9238f82136aSPatrick Kelsey 		    (struct vmxnet3_rxcompdesc *) vaddrs[q * nrxqs + 0];
9248f82136aSPatrick Kelsey 		rxc->vxcr_paddr = paddrs[q * nrxqs + 0];
9258f82136aSPatrick Kelsey 
9268f82136aSPatrick Kelsey 		/* Command ring(s) */
9278f82136aSPatrick Kelsey 		for (i = 0; i < nrxqs - 1; i++) {
9288f82136aSPatrick Kelsey 			rxr = &rxq->vxrxq_cmd_ring[i];
9298f82136aSPatrick Kelsey 
9308f82136aSPatrick Kelsey 			rxr->vxrxr_rxd =
9318f82136aSPatrick Kelsey 			    (struct vmxnet3_rxdesc *) vaddrs[q * nrxqs + 1 + i];
9328f82136aSPatrick Kelsey 			rxr->vxrxr_paddr = paddrs[q * nrxqs + 1 + i];
9338f82136aSPatrick Kelsey 		}
934e3c97c2cSBryan Venteicher 	}
935e3c97c2cSBryan Venteicher 
936e3c97c2cSBryan Venteicher 	return (0);
937e3c97c2cSBryan Venteicher }
938e3c97c2cSBryan Venteicher 
939e3c97c2cSBryan Venteicher static void
9408f82136aSPatrick Kelsey vmxnet3_queues_free(if_ctx_t ctx)
941e3c97c2cSBryan Venteicher {
9428f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
943e3c97c2cSBryan Venteicher 
9448f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
945e3c97c2cSBryan Venteicher 
9468f82136aSPatrick Kelsey 	/* Free queue state area that is shared with the device */
9478f82136aSPatrick Kelsey 	if (sc->vmx_qs_dma.idi_size != 0) {
9488f82136aSPatrick Kelsey 		iflib_dma_free(&sc->vmx_qs_dma);
9498f82136aSPatrick Kelsey 		sc->vmx_qs_dma.idi_size = 0;
950e3c97c2cSBryan Venteicher 	}
951e3c97c2cSBryan Venteicher 
9528f82136aSPatrick Kelsey 	/* Free array of receive queues */
953e3c97c2cSBryan Venteicher 	if (sc->vmx_rxq != NULL) {
954e3c97c2cSBryan Venteicher 		free(sc->vmx_rxq, M_DEVBUF);
955e3c97c2cSBryan Venteicher 		sc->vmx_rxq = NULL;
956e3c97c2cSBryan Venteicher 	}
957e3c97c2cSBryan Venteicher 
9588f82136aSPatrick Kelsey 	/* Free array of transmit queues */
959e3c97c2cSBryan Venteicher 	if (sc->vmx_txq != NULL) {
960e3c97c2cSBryan Venteicher 		free(sc->vmx_txq, M_DEVBUF);
961e3c97c2cSBryan Venteicher 		sc->vmx_txq = NULL;
962e3c97c2cSBryan Venteicher 	}
963e3c97c2cSBryan Venteicher }
964e3c97c2cSBryan Venteicher 
965e3c97c2cSBryan Venteicher static int
966e3c97c2cSBryan Venteicher vmxnet3_alloc_shared_data(struct vmxnet3_softc *sc)
967e3c97c2cSBryan Venteicher {
968e3c97c2cSBryan Venteicher 	device_t dev;
969e3c97c2cSBryan Venteicher 	size_t size;
9708f82136aSPatrick Kelsey 	int error;
971e3c97c2cSBryan Venteicher 
972e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
973e3c97c2cSBryan Venteicher 
9748f82136aSPatrick Kelsey 	/* Top level state structure shared with the device */
975e3c97c2cSBryan Venteicher 	size = sizeof(struct vmxnet3_driver_shared);
9768f82136aSPatrick Kelsey 	error = iflib_dma_alloc_align(sc->vmx_ctx, size, 1, &sc->vmx_ds_dma, 0);
977e3c97c2cSBryan Venteicher 	if (error) {
978e3c97c2cSBryan Venteicher 		device_printf(dev, "cannot alloc shared memory\n");
979e3c97c2cSBryan Venteicher 		return (error);
980e3c97c2cSBryan Venteicher 	}
9818f82136aSPatrick Kelsey 	sc->vmx_ds = (struct vmxnet3_driver_shared *) sc->vmx_ds_dma.idi_vaddr;
982e3c97c2cSBryan Venteicher 
9838f82136aSPatrick Kelsey 	/* RSS table state shared with the device */
984e557c1ddSBryan Venteicher 	if (sc->vmx_flags & VMXNET3_FLAG_RSS) {
985e557c1ddSBryan Venteicher 		size = sizeof(struct vmxnet3_rss_shared);
9868f82136aSPatrick Kelsey 		error = iflib_dma_alloc_align(sc->vmx_ctx, size, 128,
9878f82136aSPatrick Kelsey 		    &sc->vmx_rss_dma, 0);
988e557c1ddSBryan Venteicher 		if (error) {
989e557c1ddSBryan Venteicher 			device_printf(dev, "cannot alloc rss shared memory\n");
990e557c1ddSBryan Venteicher 			return (error);
991e557c1ddSBryan Venteicher 		}
992e557c1ddSBryan Venteicher 		sc->vmx_rss =
9938f82136aSPatrick Kelsey 		    (struct vmxnet3_rss_shared *) sc->vmx_rss_dma.idi_vaddr;
994e557c1ddSBryan Venteicher 	}
995e557c1ddSBryan Venteicher 
996e3c97c2cSBryan Venteicher 	return (0);
997e3c97c2cSBryan Venteicher }
998e3c97c2cSBryan Venteicher 
999e3c97c2cSBryan Venteicher static void
1000e3c97c2cSBryan Venteicher vmxnet3_free_shared_data(struct vmxnet3_softc *sc)
1001e3c97c2cSBryan Venteicher {
1002e3c97c2cSBryan Venteicher 
10038f82136aSPatrick Kelsey 	/* Free RSS table state shared with the device */
1004e557c1ddSBryan Venteicher 	if (sc->vmx_rss != NULL) {
10058f82136aSPatrick Kelsey 		iflib_dma_free(&sc->vmx_rss_dma);
1006e557c1ddSBryan Venteicher 		sc->vmx_rss = NULL;
1007e557c1ddSBryan Venteicher 	}
1008e557c1ddSBryan Venteicher 
10098f82136aSPatrick Kelsey 	/* Free top level state structure shared with the device */
1010e3c97c2cSBryan Venteicher 	if (sc->vmx_ds != NULL) {
10118f82136aSPatrick Kelsey 		iflib_dma_free(&sc->vmx_ds_dma);
1012e3c97c2cSBryan Venteicher 		sc->vmx_ds = NULL;
1013e3c97c2cSBryan Venteicher 	}
1014e3c97c2cSBryan Venteicher }
1015e3c97c2cSBryan Venteicher 
1016e3c97c2cSBryan Venteicher static int
1017e3c97c2cSBryan Venteicher vmxnet3_alloc_mcast_table(struct vmxnet3_softc *sc)
1018e3c97c2cSBryan Venteicher {
1019e3c97c2cSBryan Venteicher 	int error;
1020e3c97c2cSBryan Venteicher 
10218f82136aSPatrick Kelsey 	/* Multicast table state shared with the device */
10228f82136aSPatrick Kelsey 	error = iflib_dma_alloc_align(sc->vmx_ctx,
10238f82136aSPatrick Kelsey 	    VMXNET3_MULTICAST_MAX * ETHER_ADDR_LEN, 32, &sc->vmx_mcast_dma, 0);
1024e3c97c2cSBryan Venteicher 	if (error)
1025e3c97c2cSBryan Venteicher 		device_printf(sc->vmx_dev, "unable to alloc multicast table\n");
1026e3c97c2cSBryan Venteicher 	else
10278f82136aSPatrick Kelsey 		sc->vmx_mcast = sc->vmx_mcast_dma.idi_vaddr;
1028e3c97c2cSBryan Venteicher 
1029e3c97c2cSBryan Venteicher 	return (error);
1030e3c97c2cSBryan Venteicher }
1031e3c97c2cSBryan Venteicher 
1032e3c97c2cSBryan Venteicher static void
1033e3c97c2cSBryan Venteicher vmxnet3_free_mcast_table(struct vmxnet3_softc *sc)
1034e3c97c2cSBryan Venteicher {
1035e3c97c2cSBryan Venteicher 
10368f82136aSPatrick Kelsey 	/* Free multicast table state shared with the device */
1037e3c97c2cSBryan Venteicher 	if (sc->vmx_mcast != NULL) {
10388f82136aSPatrick Kelsey 		iflib_dma_free(&sc->vmx_mcast_dma);
1039e3c97c2cSBryan Venteicher 		sc->vmx_mcast = NULL;
1040e3c97c2cSBryan Venteicher 	}
1041e3c97c2cSBryan Venteicher }
1042e3c97c2cSBryan Venteicher 
1043e3c97c2cSBryan Venteicher static void
1044e3c97c2cSBryan Venteicher vmxnet3_init_shared_data(struct vmxnet3_softc *sc)
1045e3c97c2cSBryan Venteicher {
1046e3c97c2cSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
10478f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
1048e3c97c2cSBryan Venteicher 	struct vmxnet3_txqueue *txq;
1049e3c97c2cSBryan Venteicher 	struct vmxnet3_txq_shared *txs;
1050e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
1051e3c97c2cSBryan Venteicher 	struct vmxnet3_rxq_shared *rxs;
1052e3c97c2cSBryan Venteicher 	int i;
1053e3c97c2cSBryan Venteicher 
1054e3c97c2cSBryan Venteicher 	ds = sc->vmx_ds;
10558f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
1056e3c97c2cSBryan Venteicher 
1057e3c97c2cSBryan Venteicher 	/*
1058e3c97c2cSBryan Venteicher 	 * Initialize fields of the shared data that remains the same across
1059e3c97c2cSBryan Venteicher 	 * reinits. Note the shared data is zero'd when allocated.
1060e3c97c2cSBryan Venteicher 	 */
1061e3c97c2cSBryan Venteicher 
1062e3c97c2cSBryan Venteicher 	ds->magic = VMXNET3_REV1_MAGIC;
1063e3c97c2cSBryan Venteicher 
1064e3c97c2cSBryan Venteicher 	/* DriverInfo */
1065e3c97c2cSBryan Venteicher 	ds->version = VMXNET3_DRIVER_VERSION;
1066ce3be286SBryan Venteicher 	ds->guest = VMXNET3_GOS_FREEBSD |
1067e3c97c2cSBryan Venteicher #ifdef __LP64__
1068e3c97c2cSBryan Venteicher 	    VMXNET3_GOS_64BIT;
1069e3c97c2cSBryan Venteicher #else
1070e3c97c2cSBryan Venteicher 	    VMXNET3_GOS_32BIT;
1071e3c97c2cSBryan Venteicher #endif
1072e3c97c2cSBryan Venteicher 	ds->vmxnet3_revision = 1;
1073e3c97c2cSBryan Venteicher 	ds->upt_version = 1;
1074e3c97c2cSBryan Venteicher 
1075e3c97c2cSBryan Venteicher 	/* Misc. conf */
1076e3c97c2cSBryan Venteicher 	ds->driver_data = vtophys(sc);
1077e3c97c2cSBryan Venteicher 	ds->driver_data_len = sizeof(struct vmxnet3_softc);
10788f82136aSPatrick Kelsey 	ds->queue_shared = sc->vmx_qs_dma.idi_paddr;
10798f82136aSPatrick Kelsey 	ds->queue_shared_len = sc->vmx_qs_dma.idi_size;
10808f82136aSPatrick Kelsey 	ds->nrxsg_max = IFLIB_MAX_RX_SEGS;
1081e3c97c2cSBryan Venteicher 
1082e557c1ddSBryan Venteicher 	/* RSS conf */
1083e557c1ddSBryan Venteicher 	if (sc->vmx_flags & VMXNET3_FLAG_RSS) {
1084e557c1ddSBryan Venteicher 		ds->rss.version = 1;
10858f82136aSPatrick Kelsey 		ds->rss.paddr = sc->vmx_rss_dma.idi_paddr;
10868f82136aSPatrick Kelsey 		ds->rss.len = sc->vmx_rss_dma.idi_size;
1087e557c1ddSBryan Venteicher 	}
1088e557c1ddSBryan Venteicher 
1089e3c97c2cSBryan Venteicher 	/* Interrupt control. */
1090e3c97c2cSBryan Venteicher 	ds->automask = sc->vmx_intr_mask_mode == VMXNET3_IMM_AUTO;
10918f82136aSPatrick Kelsey 	/*
10928f82136aSPatrick Kelsey 	 * Total number of interrupt indexes we are using in the shared
1093769d56ecSPatrick Kelsey 	 * config data, even though we don't actually allocate interrupt
10948f82136aSPatrick Kelsey 	 * resources for the tx queues.  Some versions of the device will
10958f82136aSPatrick Kelsey 	 * fail to initialize successfully if interrupt indexes are used in
10968f82136aSPatrick Kelsey 	 * the shared config that exceed the number of interrupts configured
10978f82136aSPatrick Kelsey 	 * here.
10988f82136aSPatrick Kelsey 	 */
10998f82136aSPatrick Kelsey 	ds->nintr = (scctx->isc_vectors == 1) ?
1100769d56ecSPatrick Kelsey 	    2 : (scctx->isc_nrxqsets + scctx->isc_ntxqsets + 1);
1101e3c97c2cSBryan Venteicher 	ds->evintr = sc->vmx_event_intr_idx;
1102e3c97c2cSBryan Venteicher 	ds->ictrl = VMXNET3_ICTRL_DISABLE_ALL;
1103e3c97c2cSBryan Venteicher 
11048f82136aSPatrick Kelsey 	for (i = 0; i < ds->nintr; i++)
1105e3c97c2cSBryan Venteicher 		ds->modlevel[i] = UPT1_IMOD_ADAPTIVE;
1106e3c97c2cSBryan Venteicher 
1107e3c97c2cSBryan Venteicher 	/* Receive filter. */
11088f82136aSPatrick Kelsey 	ds->mcast_table = sc->vmx_mcast_dma.idi_paddr;
11098f82136aSPatrick Kelsey 	ds->mcast_tablelen = sc->vmx_mcast_dma.idi_size;
1110e3c97c2cSBryan Venteicher 
1111e3c97c2cSBryan Venteicher 	/* Tx queues */
11128f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++) {
1113e3c97c2cSBryan Venteicher 		txq = &sc->vmx_txq[i];
1114e3c97c2cSBryan Venteicher 		txs = txq->vxtxq_ts;
1115e3c97c2cSBryan Venteicher 
11168f82136aSPatrick Kelsey 		txs->cmd_ring = txq->vxtxq_cmd_ring.vxtxr_paddr;
11173c965775SBryan Venteicher 		txs->cmd_ring_len = txq->vxtxq_cmd_ring.vxtxr_ndesc;
11188f82136aSPatrick Kelsey 		txs->comp_ring = txq->vxtxq_comp_ring.vxcr_paddr;
11193c965775SBryan Venteicher 		txs->comp_ring_len = txq->vxtxq_comp_ring.vxcr_ndesc;
1120e3c97c2cSBryan Venteicher 		txs->driver_data = vtophys(txq);
1121e3c97c2cSBryan Venteicher 		txs->driver_data_len = sizeof(struct vmxnet3_txqueue);
1122e3c97c2cSBryan Venteicher 	}
1123e3c97c2cSBryan Venteicher 
1124e3c97c2cSBryan Venteicher 	/* Rx queues */
11258f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
1126e3c97c2cSBryan Venteicher 		rxq = &sc->vmx_rxq[i];
1127e3c97c2cSBryan Venteicher 		rxs = rxq->vxrxq_rs;
1128e3c97c2cSBryan Venteicher 
11298f82136aSPatrick Kelsey 		rxs->cmd_ring[0] = rxq->vxrxq_cmd_ring[0].vxrxr_paddr;
1130e3c97c2cSBryan Venteicher 		rxs->cmd_ring_len[0] = rxq->vxrxq_cmd_ring[0].vxrxr_ndesc;
11318f82136aSPatrick Kelsey 		rxs->cmd_ring[1] = rxq->vxrxq_cmd_ring[1].vxrxr_paddr;
1132e3c97c2cSBryan Venteicher 		rxs->cmd_ring_len[1] = rxq->vxrxq_cmd_ring[1].vxrxr_ndesc;
11338f82136aSPatrick Kelsey 		rxs->comp_ring = rxq->vxrxq_comp_ring.vxcr_paddr;
11343c965775SBryan Venteicher 		rxs->comp_ring_len = rxq->vxrxq_comp_ring.vxcr_ndesc;
1135e3c97c2cSBryan Venteicher 		rxs->driver_data = vtophys(rxq);
1136e3c97c2cSBryan Venteicher 		rxs->driver_data_len = sizeof(struct vmxnet3_rxqueue);
1137e3c97c2cSBryan Venteicher 	}
1138e3c97c2cSBryan Venteicher }
1139e3c97c2cSBryan Venteicher 
1140e3c97c2cSBryan Venteicher static void
1141e557c1ddSBryan Venteicher vmxnet3_reinit_rss_shared_data(struct vmxnet3_softc *sc)
1142e557c1ddSBryan Venteicher {
1143e557c1ddSBryan Venteicher 	/*
1144e557c1ddSBryan Venteicher 	 * Use the same key as the Linux driver until FreeBSD can do
1145e557c1ddSBryan Venteicher 	 * RSS (presumably Toeplitz) in software.
1146e557c1ddSBryan Venteicher 	 */
1147e557c1ddSBryan Venteicher 	static const uint8_t rss_key[UPT1_RSS_MAX_KEY_SIZE] = {
1148e557c1ddSBryan Venteicher 	    0x3b, 0x56, 0xd1, 0x56, 0x13, 0x4a, 0xe7, 0xac,
1149e557c1ddSBryan Venteicher 	    0xe8, 0x79, 0x09, 0x75, 0xe8, 0x65, 0x79, 0x28,
1150e557c1ddSBryan Venteicher 	    0x35, 0x12, 0xb9, 0x56, 0x7c, 0x76, 0x4b, 0x70,
1151e557c1ddSBryan Venteicher 	    0xd8, 0x56, 0xa3, 0x18, 0x9b, 0x0a, 0xee, 0xf3,
1152e557c1ddSBryan Venteicher 	    0x96, 0xa6, 0x9f, 0x8f, 0x9e, 0x8c, 0x90, 0xc9,
1153e557c1ddSBryan Venteicher 	};
1154e557c1ddSBryan Venteicher 
11558f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
1156e557c1ddSBryan Venteicher 	struct vmxnet3_rss_shared *rss;
1157281cab4dSAndriy Gapon #ifdef RSS
1158281cab4dSAndriy Gapon 	uint8_t rss_algo;
1159281cab4dSAndriy Gapon #endif
1160e557c1ddSBryan Venteicher 	int i;
1161e557c1ddSBryan Venteicher 
11628f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
1163e557c1ddSBryan Venteicher 	rss = sc->vmx_rss;
1164e557c1ddSBryan Venteicher 
1165e557c1ddSBryan Venteicher 	rss->hash_type =
1166e557c1ddSBryan Venteicher 	    UPT1_RSS_HASH_TYPE_IPV4 | UPT1_RSS_HASH_TYPE_TCP_IPV4 |
1167e557c1ddSBryan Venteicher 	    UPT1_RSS_HASH_TYPE_IPV6 | UPT1_RSS_HASH_TYPE_TCP_IPV6;
1168e557c1ddSBryan Venteicher 	rss->hash_func = UPT1_RSS_HASH_FUNC_TOEPLITZ;
1169e557c1ddSBryan Venteicher 	rss->hash_key_size = UPT1_RSS_MAX_KEY_SIZE;
1170e557c1ddSBryan Venteicher 	rss->ind_table_size = UPT1_RSS_MAX_IND_TABLE_SIZE;
1171281cab4dSAndriy Gapon #ifdef RSS
1172281cab4dSAndriy Gapon 	/*
1173281cab4dSAndriy Gapon 	 * If the software RSS is configured to anything else other than
1174281cab4dSAndriy Gapon 	 * Toeplitz, then just do Toeplitz in "hardware" for the sake of
1175281cab4dSAndriy Gapon 	 * the packet distribution, but report the hash as opaque to
1176281cab4dSAndriy Gapon 	 * disengage from the software RSS.
1177281cab4dSAndriy Gapon 	 */
1178281cab4dSAndriy Gapon 	rss_algo = rss_gethashalgo();
1179281cab4dSAndriy Gapon 	if (rss_algo == RSS_HASH_TOEPLITZ) {
1180281cab4dSAndriy Gapon 		rss_getkey(rss->hash_key);
1181281cab4dSAndriy Gapon 		for (i = 0; i < UPT1_RSS_MAX_IND_TABLE_SIZE; i++) {
1182281cab4dSAndriy Gapon 			rss->ind_table[i] = rss_get_indirection_to_bucket(i) %
1183281cab4dSAndriy Gapon 			    scctx->isc_nrxqsets;
1184281cab4dSAndriy Gapon 		}
1185281cab4dSAndriy Gapon 		sc->vmx_flags |= VMXNET3_FLAG_SOFT_RSS;
1186281cab4dSAndriy Gapon 	} else
1187281cab4dSAndriy Gapon #endif
1188281cab4dSAndriy Gapon 	{
1189e557c1ddSBryan Venteicher 		memcpy(rss->hash_key, rss_key, UPT1_RSS_MAX_KEY_SIZE);
1190e557c1ddSBryan Venteicher 		for (i = 0; i < UPT1_RSS_MAX_IND_TABLE_SIZE; i++)
11918f82136aSPatrick Kelsey 			rss->ind_table[i] = i % scctx->isc_nrxqsets;
1192281cab4dSAndriy Gapon 		sc->vmx_flags &= ~VMXNET3_FLAG_SOFT_RSS;
1193281cab4dSAndriy Gapon 	}
1194e3c97c2cSBryan Venteicher }
1195e3c97c2cSBryan Venteicher 
1196e3c97c2cSBryan Venteicher static void
1197e3c97c2cSBryan Venteicher vmxnet3_reinit_shared_data(struct vmxnet3_softc *sc)
1198e3c97c2cSBryan Venteicher {
1199e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
1200e3c97c2cSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
12018f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
1202e3c97c2cSBryan Venteicher 
1203e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
1204e3c97c2cSBryan Venteicher 	ds = sc->vmx_ds;
12058f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
1206e3c97c2cSBryan Venteicher 
1207e557c1ddSBryan Venteicher 	ds->mtu = ifp->if_mtu;
12088f82136aSPatrick Kelsey 	ds->ntxqueue = scctx->isc_ntxqsets;
12098f82136aSPatrick Kelsey 	ds->nrxqueue = scctx->isc_nrxqsets;
1210e557c1ddSBryan Venteicher 
1211e3c97c2cSBryan Venteicher 	ds->upt_features = 0;
1212e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6))
1213e3c97c2cSBryan Venteicher 		ds->upt_features |= UPT1_F_CSUM;
12143c5dfe89SBryan Venteicher 	if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
12153c5dfe89SBryan Venteicher 		ds->upt_features |= UPT1_F_VLAN;
1216e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & IFCAP_LRO)
1217e3c97c2cSBryan Venteicher 		ds->upt_features |= UPT1_F_LRO;
1218e3c97c2cSBryan Venteicher 
1219e557c1ddSBryan Venteicher 	if (sc->vmx_flags & VMXNET3_FLAG_RSS) {
1220e557c1ddSBryan Venteicher 		ds->upt_features |= UPT1_F_RSS;
1221e557c1ddSBryan Venteicher 		vmxnet3_reinit_rss_shared_data(sc);
1222e557c1ddSBryan Venteicher 	}
1223e3c97c2cSBryan Venteicher 
12248f82136aSPatrick Kelsey 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_DSL, sc->vmx_ds_dma.idi_paddr);
1225e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_DSH,
12268f82136aSPatrick Kelsey 	    (uint64_t) sc->vmx_ds_dma.idi_paddr >> 32);
1227e3c97c2cSBryan Venteicher }
1228e3c97c2cSBryan Venteicher 
1229e3c97c2cSBryan Venteicher static int
1230e3c97c2cSBryan Venteicher vmxnet3_alloc_data(struct vmxnet3_softc *sc)
1231e3c97c2cSBryan Venteicher {
1232e3c97c2cSBryan Venteicher 	int error;
1233e3c97c2cSBryan Venteicher 
1234e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_shared_data(sc);
1235e3c97c2cSBryan Venteicher 	if (error)
1236e3c97c2cSBryan Venteicher 		return (error);
1237e3c97c2cSBryan Venteicher 
1238e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_mcast_table(sc);
1239e3c97c2cSBryan Venteicher 	if (error)
1240e3c97c2cSBryan Venteicher 		return (error);
1241e3c97c2cSBryan Venteicher 
1242e3c97c2cSBryan Venteicher 	vmxnet3_init_shared_data(sc);
1243e3c97c2cSBryan Venteicher 
1244e3c97c2cSBryan Venteicher 	return (0);
1245e3c97c2cSBryan Venteicher }
1246e3c97c2cSBryan Venteicher 
1247e3c97c2cSBryan Venteicher static void
1248e3c97c2cSBryan Venteicher vmxnet3_free_data(struct vmxnet3_softc *sc)
1249e3c97c2cSBryan Venteicher {
1250e3c97c2cSBryan Venteicher 
1251e3c97c2cSBryan Venteicher 	vmxnet3_free_mcast_table(sc);
1252e3c97c2cSBryan Venteicher 	vmxnet3_free_shared_data(sc);
1253e3c97c2cSBryan Venteicher }
1254e3c97c2cSBryan Venteicher 
1255e3c97c2cSBryan Venteicher static void
1256e3c97c2cSBryan Venteicher vmxnet3_evintr(struct vmxnet3_softc *sc)
1257e3c97c2cSBryan Venteicher {
1258e3c97c2cSBryan Venteicher 	device_t dev;
1259e3c97c2cSBryan Venteicher 	struct vmxnet3_txq_shared *ts;
1260e3c97c2cSBryan Venteicher 	struct vmxnet3_rxq_shared *rs;
1261e3c97c2cSBryan Venteicher 	uint32_t event;
1262e3c97c2cSBryan Venteicher 
1263e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
1264e3c97c2cSBryan Venteicher 
1265e3c97c2cSBryan Venteicher 	/* Clear events. */
1266e3c97c2cSBryan Venteicher 	event = sc->vmx_ds->event;
1267e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_EVENT, event);
1268e3c97c2cSBryan Venteicher 
12698f82136aSPatrick Kelsey 	if (event & VMXNET3_EVENT_LINK)
1270e3c97c2cSBryan Venteicher 		vmxnet3_link_status(sc);
1271e3c97c2cSBryan Venteicher 
1272e3c97c2cSBryan Venteicher 	if (event & (VMXNET3_EVENT_TQERROR | VMXNET3_EVENT_RQERROR)) {
1273e3c97c2cSBryan Venteicher 		vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_STATUS);
1274e3c97c2cSBryan Venteicher 		ts = sc->vmx_txq[0].vxtxq_ts;
1275e3c97c2cSBryan Venteicher 		if (ts->stopped != 0)
1276e3c97c2cSBryan Venteicher 			device_printf(dev, "Tx queue error %#x\n", ts->error);
1277e3c97c2cSBryan Venteicher 		rs = sc->vmx_rxq[0].vxrxq_rs;
1278e3c97c2cSBryan Venteicher 		if (rs->stopped != 0)
1279e3c97c2cSBryan Venteicher 			device_printf(dev, "Rx queue error %#x\n", rs->error);
12808f82136aSPatrick Kelsey 
12818f82136aSPatrick Kelsey 		/* XXX - rely on liflib watchdog to reset us? */
12828f82136aSPatrick Kelsey 		device_printf(dev, "Rx/Tx queue error event ... "
12838f82136aSPatrick Kelsey 		    "waiting for iflib watchdog reset\n");
1284e3c97c2cSBryan Venteicher 	}
1285e3c97c2cSBryan Venteicher 
1286e3c97c2cSBryan Venteicher 	if (event & VMXNET3_EVENT_DIC)
1287e3c97c2cSBryan Venteicher 		device_printf(dev, "device implementation change event\n");
1288e3c97c2cSBryan Venteicher 	if (event & VMXNET3_EVENT_DEBUG)
1289e3c97c2cSBryan Venteicher 		device_printf(dev, "debug event\n");
1290e3c97c2cSBryan Venteicher }
1291e3c97c2cSBryan Venteicher 
12928f82136aSPatrick Kelsey static int
12938f82136aSPatrick Kelsey vmxnet3_isc_txd_encap(void *vsc, if_pkt_info_t pi)
12948f82136aSPatrick Kelsey {
12958f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
12968f82136aSPatrick Kelsey 	struct vmxnet3_txqueue *txq;
12978f82136aSPatrick Kelsey 	struct vmxnet3_txring *txr;
12988f82136aSPatrick Kelsey 	struct vmxnet3_txdesc *txd, *sop;
12998f82136aSPatrick Kelsey 	bus_dma_segment_t *segs;
13008f82136aSPatrick Kelsey 	int nsegs;
13018f82136aSPatrick Kelsey 	int pidx;
13028f82136aSPatrick Kelsey 	int hdrlen;
13038f82136aSPatrick Kelsey 	int i;
13048f82136aSPatrick Kelsey 	int gen;
13058f82136aSPatrick Kelsey 
13068f82136aSPatrick Kelsey 	sc = vsc;
13078f82136aSPatrick Kelsey 	txq = &sc->vmx_txq[pi->ipi_qsidx];
13088f82136aSPatrick Kelsey 	txr = &txq->vxtxq_cmd_ring;
13098f82136aSPatrick Kelsey 	segs = pi->ipi_segs;
13108f82136aSPatrick Kelsey 	nsegs = pi->ipi_nsegs;
13118f82136aSPatrick Kelsey 	pidx = pi->ipi_pidx;
13128f82136aSPatrick Kelsey 
13138f82136aSPatrick Kelsey 	KASSERT(nsegs <= VMXNET3_TX_MAXSEGS,
13148f82136aSPatrick Kelsey 	    ("%s: packet with too many segments %d", __func__, nsegs));
13158f82136aSPatrick Kelsey 
13168f82136aSPatrick Kelsey 	sop = &txr->vxtxr_txd[pidx];
13178f82136aSPatrick Kelsey 	gen = txr->vxtxr_gen ^ 1;	/* Owned by cpu (yet) */
13188f82136aSPatrick Kelsey 
13198f82136aSPatrick Kelsey 	for (i = 0; i < nsegs; i++) {
13208f82136aSPatrick Kelsey 		txd = &txr->vxtxr_txd[pidx];
13218f82136aSPatrick Kelsey 
13228f82136aSPatrick Kelsey 		txd->addr = segs[i].ds_addr;
13238f82136aSPatrick Kelsey 		txd->len = segs[i].ds_len;
13248f82136aSPatrick Kelsey 		txd->gen = gen;
13258f82136aSPatrick Kelsey 		txd->dtype = 0;
13268f82136aSPatrick Kelsey 		txd->offload_mode = VMXNET3_OM_NONE;
13278f82136aSPatrick Kelsey 		txd->offload_pos = 0;
13288f82136aSPatrick Kelsey 		txd->hlen = 0;
13298f82136aSPatrick Kelsey 		txd->eop = 0;
13308f82136aSPatrick Kelsey 		txd->compreq = 0;
13318f82136aSPatrick Kelsey 		txd->vtag_mode = 0;
13328f82136aSPatrick Kelsey 		txd->vtag = 0;
13338f82136aSPatrick Kelsey 
13348f82136aSPatrick Kelsey 		if (++pidx == txr->vxtxr_ndesc) {
13358f82136aSPatrick Kelsey 			pidx = 0;
13368f82136aSPatrick Kelsey 			txr->vxtxr_gen ^= 1;
13378f82136aSPatrick Kelsey 		}
13388f82136aSPatrick Kelsey 		gen = txr->vxtxr_gen;
13398f82136aSPatrick Kelsey 	}
13408f82136aSPatrick Kelsey 	txd->eop = 1;
13418f82136aSPatrick Kelsey 	txd->compreq = !!(pi->ipi_flags & IPI_TX_INTR);
13428f82136aSPatrick Kelsey 	pi->ipi_new_pidx = pidx;
13438f82136aSPatrick Kelsey 
13448f82136aSPatrick Kelsey 	/*
13458f82136aSPatrick Kelsey 	 * VLAN
13468f82136aSPatrick Kelsey 	 */
13478f82136aSPatrick Kelsey 	if (pi->ipi_mflags & M_VLANTAG) {
13488f82136aSPatrick Kelsey 		sop->vtag_mode = 1;
13498f82136aSPatrick Kelsey 		sop->vtag = pi->ipi_vtag;
13508f82136aSPatrick Kelsey 	}
13518f82136aSPatrick Kelsey 
13528f82136aSPatrick Kelsey 	/*
13538f82136aSPatrick Kelsey 	 * TSO and checksum offloads
13548f82136aSPatrick Kelsey 	 */
13558f82136aSPatrick Kelsey 	hdrlen = pi->ipi_ehdrlen + pi->ipi_ip_hlen;
13568f82136aSPatrick Kelsey 	if (pi->ipi_csum_flags & CSUM_TSO) {
13578f82136aSPatrick Kelsey 		sop->offload_mode = VMXNET3_OM_TSO;
1358f55f37d9SVincenzo Maffione 		sop->hlen = hdrlen + pi->ipi_tcp_hlen;
13598f82136aSPatrick Kelsey 		sop->offload_pos = pi->ipi_tso_segsz;
13608f82136aSPatrick Kelsey 	} else if (pi->ipi_csum_flags & (VMXNET3_CSUM_OFFLOAD |
13618f82136aSPatrick Kelsey 	    VMXNET3_CSUM_OFFLOAD_IPV6)) {
13628f82136aSPatrick Kelsey 		sop->offload_mode = VMXNET3_OM_CSUM;
13638f82136aSPatrick Kelsey 		sop->hlen = hdrlen;
13648f82136aSPatrick Kelsey 		sop->offload_pos = hdrlen +
13658f82136aSPatrick Kelsey 		    ((pi->ipi_ipproto == IPPROTO_TCP) ?
13668f82136aSPatrick Kelsey 			offsetof(struct tcphdr, th_sum) :
13678f82136aSPatrick Kelsey 			offsetof(struct udphdr, uh_sum));
13688f82136aSPatrick Kelsey 	}
13698f82136aSPatrick Kelsey 
13708f82136aSPatrick Kelsey 	/* Finally, change the ownership. */
13718f82136aSPatrick Kelsey 	vmxnet3_barrier(sc, VMXNET3_BARRIER_WR);
13728f82136aSPatrick Kelsey 	sop->gen ^= 1;
13738f82136aSPatrick Kelsey 
13748f82136aSPatrick Kelsey 	return (0);
1375e3c97c2cSBryan Venteicher }
1376e3c97c2cSBryan Venteicher 
1377e3c97c2cSBryan Venteicher static void
13788f82136aSPatrick Kelsey vmxnet3_isc_txd_flush(void *vsc, uint16_t txqid, qidx_t pidx)
1379e3c97c2cSBryan Venteicher {
1380e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
13818f82136aSPatrick Kelsey 	struct vmxnet3_txqueue *txq;
13828f82136aSPatrick Kelsey 
13838f82136aSPatrick Kelsey 	sc = vsc;
13848f82136aSPatrick Kelsey 	txq = &sc->vmx_txq[txqid];
13858f82136aSPatrick Kelsey 
13868f82136aSPatrick Kelsey 	/*
13878f82136aSPatrick Kelsey 	 * pidx is what we last set ipi_new_pidx to in
13888f82136aSPatrick Kelsey 	 * vmxnet3_isc_txd_encap()
13898f82136aSPatrick Kelsey 	 */
13908f82136aSPatrick Kelsey 
13918f82136aSPatrick Kelsey 	/*
13928f82136aSPatrick Kelsey 	 * Avoid expensive register updates if the flush request is
13938f82136aSPatrick Kelsey 	 * redundant.
13948f82136aSPatrick Kelsey 	 */
13958f82136aSPatrick Kelsey 	if (txq->vxtxq_last_flush == pidx)
13968f82136aSPatrick Kelsey 		return;
13978f82136aSPatrick Kelsey 	txq->vxtxq_last_flush = pidx;
13988f82136aSPatrick Kelsey 	vmxnet3_write_bar0(sc, VMXNET3_BAR0_TXH(txq->vxtxq_id), pidx);
13998f82136aSPatrick Kelsey }
14008f82136aSPatrick Kelsey 
14018f82136aSPatrick Kelsey static int
14028f82136aSPatrick Kelsey vmxnet3_isc_txd_credits_update(void *vsc, uint16_t txqid, bool clear)
14038f82136aSPatrick Kelsey {
14048f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
14058f82136aSPatrick Kelsey 	struct vmxnet3_txqueue *txq;
1406e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *txc;
1407e3c97c2cSBryan Venteicher 	struct vmxnet3_txcompdesc *txcd;
14088f82136aSPatrick Kelsey 	struct vmxnet3_txring *txr;
14098f82136aSPatrick Kelsey 	int processed;
1410e3c97c2cSBryan Venteicher 
14118f82136aSPatrick Kelsey 	sc = vsc;
14128f82136aSPatrick Kelsey 	txq = &sc->vmx_txq[txqid];
1413e3c97c2cSBryan Venteicher 	txc = &txq->vxtxq_comp_ring;
14148f82136aSPatrick Kelsey 	txr = &txq->vxtxq_cmd_ring;
1415e3c97c2cSBryan Venteicher 
14168f82136aSPatrick Kelsey 	/*
14178f82136aSPatrick Kelsey 	 * If clear is true, we need to report the number of TX command ring
14188f82136aSPatrick Kelsey 	 * descriptors that have been processed by the device.  If clear is
14198f82136aSPatrick Kelsey 	 * false, we just need to report whether or not at least one TX
14208f82136aSPatrick Kelsey 	 * command ring descriptor has been processed by the device.
14218f82136aSPatrick Kelsey 	 */
14228f82136aSPatrick Kelsey 	processed = 0;
1423e3c97c2cSBryan Venteicher 	for (;;) {
1424e3c97c2cSBryan Venteicher 		txcd = &txc->vxcr_u.txcd[txc->vxcr_next];
1425e3c97c2cSBryan Venteicher 		if (txcd->gen != txc->vxcr_gen)
1426e3c97c2cSBryan Venteicher 			break;
14278f82136aSPatrick Kelsey 		else if (!clear)
14288f82136aSPatrick Kelsey 			return (1);
14293c965775SBryan Venteicher 		vmxnet3_barrier(sc, VMXNET3_BARRIER_RD);
1430e3c97c2cSBryan Venteicher 
1431e3c97c2cSBryan Venteicher 		if (++txc->vxcr_next == txc->vxcr_ndesc) {
1432e3c97c2cSBryan Venteicher 			txc->vxcr_next = 0;
1433e3c97c2cSBryan Venteicher 			txc->vxcr_gen ^= 1;
1434e3c97c2cSBryan Venteicher 		}
1435e3c97c2cSBryan Venteicher 
14368f82136aSPatrick Kelsey 		if (txcd->eop_idx < txr->vxtxr_next)
14378f82136aSPatrick Kelsey 			processed += txr->vxtxr_ndesc -
14388f82136aSPatrick Kelsey 			    (txr->vxtxr_next - txcd->eop_idx) + 1;
14398f82136aSPatrick Kelsey 		else
14408f82136aSPatrick Kelsey 			processed += txcd->eop_idx - txr->vxtxr_next + 1;
1441e3c97c2cSBryan Venteicher 		txr->vxtxr_next = (txcd->eop_idx + 1) % txr->vxtxr_ndesc;
1442e3c97c2cSBryan Venteicher 	}
1443e3c97c2cSBryan Venteicher 
14448f82136aSPatrick Kelsey 	return (processed);
1445e3c97c2cSBryan Venteicher }
1446e3c97c2cSBryan Venteicher 
1447e3c97c2cSBryan Venteicher static int
14488f82136aSPatrick Kelsey vmxnet3_isc_rxd_available(void *vsc, uint16_t rxqid, qidx_t idx, qidx_t budget)
1449e3c97c2cSBryan Venteicher {
14508f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
14518f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
14528f82136aSPatrick Kelsey 	struct vmxnet3_comp_ring *rxc;
14538f82136aSPatrick Kelsey 	struct vmxnet3_rxcompdesc *rxcd;
14548f82136aSPatrick Kelsey 	int avail;
14558f82136aSPatrick Kelsey 	int completed_gen;
14568f82136aSPatrick Kelsey #ifdef INVARIANTS
14578f82136aSPatrick Kelsey 	int expect_sop = 1;
14588f82136aSPatrick Kelsey #endif
14598f82136aSPatrick Kelsey 	sc = vsc;
14608f82136aSPatrick Kelsey 	rxq = &sc->vmx_rxq[rxqid];
14618f82136aSPatrick Kelsey 	rxc = &rxq->vxrxq_comp_ring;
14628f82136aSPatrick Kelsey 
14638f82136aSPatrick Kelsey 	avail = 0;
14648f82136aSPatrick Kelsey 	completed_gen = rxc->vxcr_gen;
14658f82136aSPatrick Kelsey 	for (;;) {
14668f82136aSPatrick Kelsey 		rxcd = &rxc->vxcr_u.rxcd[idx];
14678f82136aSPatrick Kelsey 		if (rxcd->gen != completed_gen)
14688f82136aSPatrick Kelsey 			break;
14698f82136aSPatrick Kelsey 		vmxnet3_barrier(sc, VMXNET3_BARRIER_RD);
14708f82136aSPatrick Kelsey 
14718f82136aSPatrick Kelsey #ifdef INVARIANTS
14728f82136aSPatrick Kelsey 		if (expect_sop)
14738f82136aSPatrick Kelsey 			KASSERT(rxcd->sop, ("%s: expected sop", __func__));
14748f82136aSPatrick Kelsey 		else
14758f82136aSPatrick Kelsey 			KASSERT(!rxcd->sop, ("%s: unexpected sop", __func__));
14768f82136aSPatrick Kelsey 		expect_sop = rxcd->eop;
14778f82136aSPatrick Kelsey #endif
14788f82136aSPatrick Kelsey 		if (rxcd->eop && (rxcd->len != 0))
14798f82136aSPatrick Kelsey 			avail++;
14808f82136aSPatrick Kelsey 		if (avail > budget)
14818f82136aSPatrick Kelsey 			break;
14828f82136aSPatrick Kelsey 		if (++idx == rxc->vxcr_ndesc) {
14838f82136aSPatrick Kelsey 			idx = 0;
14848f82136aSPatrick Kelsey 			completed_gen ^= 1;
14858f82136aSPatrick Kelsey 		}
14868f82136aSPatrick Kelsey 	}
14878f82136aSPatrick Kelsey 
14888f82136aSPatrick Kelsey 	return (avail);
14898f82136aSPatrick Kelsey }
14908f82136aSPatrick Kelsey 
14918f82136aSPatrick Kelsey static int
14928f82136aSPatrick Kelsey vmxnet3_isc_rxd_pkt_get(void *vsc, if_rxd_info_t ri)
14938f82136aSPatrick Kelsey {
14948f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
14958f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
14968f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
14978f82136aSPatrick Kelsey 	struct vmxnet3_comp_ring *rxc;
14988f82136aSPatrick Kelsey 	struct vmxnet3_rxcompdesc *rxcd;
14998f82136aSPatrick Kelsey 	if_rxd_frag_t frag;
15008f82136aSPatrick Kelsey 	int cqidx;
15018f82136aSPatrick Kelsey 	uint16_t total_len;
15028f82136aSPatrick Kelsey 	uint8_t nfrags;
1503f50375eeSPatrick Kelsey 	uint8_t i;
15048f82136aSPatrick Kelsey 	uint8_t flid;
1505e3c97c2cSBryan Venteicher 
15068f82136aSPatrick Kelsey 	sc = vsc;
15078f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
15088f82136aSPatrick Kelsey 	rxq = &sc->vmx_rxq[ri->iri_qsidx];
15098f82136aSPatrick Kelsey 	rxc = &rxq->vxrxq_comp_ring;
1510e3c97c2cSBryan Venteicher 
1511e3c97c2cSBryan Venteicher 	/*
15128f82136aSPatrick Kelsey 	 * Get a single packet starting at the given index in the completion
15138f82136aSPatrick Kelsey 	 * queue.  That we have been called indicates that
15148f82136aSPatrick Kelsey 	 * vmxnet3_isc_rxd_available() has already verified that either
15158f82136aSPatrick Kelsey 	 * there is a complete packet available starting at the given index,
15168f82136aSPatrick Kelsey 	 * or there are one or more zero length packets starting at the
15178f82136aSPatrick Kelsey 	 * given index followed by a complete packet, so no verification of
15188f82136aSPatrick Kelsey 	 * ownership of the descriptors (and no associated read barrier) is
15198f82136aSPatrick Kelsey 	 * required here.
1520e3c97c2cSBryan Venteicher 	 */
15218f82136aSPatrick Kelsey 	cqidx = ri->iri_cidx;
15228f82136aSPatrick Kelsey 	rxcd = &rxc->vxcr_u.rxcd[cqidx];
15238f82136aSPatrick Kelsey 	while (rxcd->len == 0) {
15248f82136aSPatrick Kelsey 		KASSERT(rxcd->sop && rxcd->eop,
15258f82136aSPatrick Kelsey 		    ("%s: zero-length packet without both sop and eop set",
15268f82136aSPatrick Kelsey 			__func__));
1527f50375eeSPatrick Kelsey 		rxc->vxcr_zero_length++;
15288f82136aSPatrick Kelsey 		if (++cqidx == rxc->vxcr_ndesc) {
15298f82136aSPatrick Kelsey 			cqidx = 0;
15308f82136aSPatrick Kelsey 			rxc->vxcr_gen ^= 1;
15318f82136aSPatrick Kelsey 		}
15328f82136aSPatrick Kelsey 		rxcd = &rxc->vxcr_u.rxcd[cqidx];
15338f82136aSPatrick Kelsey 	}
15348f82136aSPatrick Kelsey 	KASSERT(rxcd->sop, ("%s: expected sop", __func__));
15358f82136aSPatrick Kelsey 
15368f82136aSPatrick Kelsey 	/*
1537281cab4dSAndriy Gapon 	 * RSS and flow ID.
1538281cab4dSAndriy Gapon 	 * Types other than M_HASHTYPE_NONE and M_HASHTYPE_OPAQUE_HASH should
1539281cab4dSAndriy Gapon 	 * be used only if the software RSS is enabled and it uses the same
1540281cab4dSAndriy Gapon 	 * algorithm and the hash key as the "hardware".  If the software RSS
1541281cab4dSAndriy Gapon 	 * is not enabled, then it's simply pointless to use those types.
1542281cab4dSAndriy Gapon 	 * If it's enabled but with different parameters, then hash values will
1543281cab4dSAndriy Gapon 	 * not match.
15448f82136aSPatrick Kelsey 	 */
15458f82136aSPatrick Kelsey 	ri->iri_flowid = rxcd->rss_hash;
1546281cab4dSAndriy Gapon #ifdef RSS
1547281cab4dSAndriy Gapon 	if ((sc->vmx_flags & VMXNET3_FLAG_SOFT_RSS) != 0) {
15488f82136aSPatrick Kelsey 		switch (rxcd->rss_type) {
15498f82136aSPatrick Kelsey 		case VMXNET3_RCD_RSS_TYPE_NONE:
15508f82136aSPatrick Kelsey 			ri->iri_flowid = ri->iri_qsidx;
15518f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_NONE;
15528f82136aSPatrick Kelsey 			break;
15538f82136aSPatrick Kelsey 		case VMXNET3_RCD_RSS_TYPE_IPV4:
15548f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_RSS_IPV4;
15558f82136aSPatrick Kelsey 			break;
15568f82136aSPatrick Kelsey 		case VMXNET3_RCD_RSS_TYPE_TCPIPV4:
15578f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_RSS_TCP_IPV4;
15588f82136aSPatrick Kelsey 			break;
15598f82136aSPatrick Kelsey 		case VMXNET3_RCD_RSS_TYPE_IPV6:
15608f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_RSS_IPV6;
15618f82136aSPatrick Kelsey 			break;
15628f82136aSPatrick Kelsey 		case VMXNET3_RCD_RSS_TYPE_TCPIPV6:
15638f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_RSS_TCP_IPV6;
15648f82136aSPatrick Kelsey 			break;
15658f82136aSPatrick Kelsey 		default:
15668f82136aSPatrick Kelsey 			ri->iri_rsstype = M_HASHTYPE_OPAQUE_HASH;
15678f82136aSPatrick Kelsey 			break;
1568e3c97c2cSBryan Venteicher 		}
1569281cab4dSAndriy Gapon 	} else
1570281cab4dSAndriy Gapon #endif
1571281cab4dSAndriy Gapon 	{
1572281cab4dSAndriy Gapon 		switch (rxcd->rss_type) {
1573281cab4dSAndriy Gapon 		case VMXNET3_RCD_RSS_TYPE_NONE:
1574281cab4dSAndriy Gapon 			ri->iri_flowid = ri->iri_qsidx;
1575281cab4dSAndriy Gapon 			ri->iri_rsstype = M_HASHTYPE_NONE;
1576281cab4dSAndriy Gapon 			break;
1577281cab4dSAndriy Gapon 		default:
1578281cab4dSAndriy Gapon 			ri->iri_rsstype = M_HASHTYPE_OPAQUE_HASH;
1579281cab4dSAndriy Gapon 			break;
1580281cab4dSAndriy Gapon 		}
1581281cab4dSAndriy Gapon 	}
1582e3c97c2cSBryan Venteicher 
15838f82136aSPatrick Kelsey 	/*
15848f82136aSPatrick Kelsey 	 * The queue numbering scheme used for rxcd->qid is as follows:
15858f82136aSPatrick Kelsey 	 *  - All of the command ring 0s are numbered [0, nrxqsets - 1]
15868f82136aSPatrick Kelsey 	 *  - All of the command ring 1s are numbered [nrxqsets, 2*nrxqsets - 1]
15878f82136aSPatrick Kelsey 	 *
15888f82136aSPatrick Kelsey 	 * Thus, rxcd->qid less than nrxqsets indicates command ring (and
15898f82136aSPatrick Kelsey 	 * flid) 0, and rxcd->qid greater than or equal to nrxqsets
15908f82136aSPatrick Kelsey 	 * indicates command ring (and flid) 1.
15918f82136aSPatrick Kelsey 	 */
15928f82136aSPatrick Kelsey 	nfrags = 0;
15938f82136aSPatrick Kelsey 	total_len = 0;
15948f82136aSPatrick Kelsey 	do {
15958f82136aSPatrick Kelsey 		rxcd = &rxc->vxcr_u.rxcd[cqidx];
15968f82136aSPatrick Kelsey 		KASSERT(rxcd->gen == rxc->vxcr_gen,
15978f82136aSPatrick Kelsey 		    ("%s: generation mismatch", __func__));
15989c612a5dSAndriy Gapon 		KASSERT(nfrags < IFLIB_MAX_RX_SEGS,
15999c612a5dSAndriy Gapon 		    ("%s: too many fragments", __func__));
16009c612a5dSAndriy Gapon 		if (__predict_true(rxcd->len != 0)) {
16018f82136aSPatrick Kelsey 			frag = &ri->iri_frags[nfrags];
16029c612a5dSAndriy Gapon 			flid = (rxcd->qid >= scctx->isc_nrxqsets) ? 1 : 0;
16038f82136aSPatrick Kelsey 			frag->irf_flid = flid;
16048f82136aSPatrick Kelsey 			frag->irf_idx = rxcd->rxd_idx;
16058f82136aSPatrick Kelsey 			frag->irf_len = rxcd->len;
16068f82136aSPatrick Kelsey 			total_len += rxcd->len;
16078f82136aSPatrick Kelsey 			nfrags++;
16089c612a5dSAndriy Gapon 		} else {
16099c612a5dSAndriy Gapon 			rxc->vcxr_zero_length_frag++;
16109c612a5dSAndriy Gapon 		}
16118f82136aSPatrick Kelsey 		if (++cqidx == rxc->vxcr_ndesc) {
16128f82136aSPatrick Kelsey 			cqidx = 0;
16138f82136aSPatrick Kelsey 			rxc->vxcr_gen ^= 1;
16148f82136aSPatrick Kelsey 		}
16158f82136aSPatrick Kelsey 	} while (!rxcd->eop);
1616e3c97c2cSBryan Venteicher 
16178f82136aSPatrick Kelsey 	ri->iri_cidx = cqidx;
16188f82136aSPatrick Kelsey 	ri->iri_nfrags = nfrags;
16198f82136aSPatrick Kelsey 	ri->iri_len = total_len;
16208f82136aSPatrick Kelsey 
1621f50375eeSPatrick Kelsey 	/*
1622f50375eeSPatrick Kelsey 	 * If there's an error, the last descriptor in the packet will
1623f50375eeSPatrick Kelsey 	 * have the error indicator set.  In this case, set all
1624f50375eeSPatrick Kelsey 	 * fragment lengths to zero.  This will cause iflib to discard
1625f50375eeSPatrick Kelsey 	 * the packet, but process all associated descriptors through
1626f50375eeSPatrick Kelsey 	 * the refill mechanism.
1627f50375eeSPatrick Kelsey 	 */
1628f50375eeSPatrick Kelsey 	if (__predict_false(rxcd->error)) {
1629f50375eeSPatrick Kelsey 		rxc->vxcr_pkt_errors++;
1630f50375eeSPatrick Kelsey 		for (i = 0; i < nfrags; i++) {
1631f50375eeSPatrick Kelsey 			frag = &ri->iri_frags[i];
1632f50375eeSPatrick Kelsey 			frag->irf_len = 0;
1633f50375eeSPatrick Kelsey 		}
1634f50375eeSPatrick Kelsey 	} else {
1635f50375eeSPatrick Kelsey 		/* Checksum offload information is in the last descriptor. */
1636f50375eeSPatrick Kelsey 		if (!rxcd->no_csum) {
1637f50375eeSPatrick Kelsey 			uint32_t csum_flags = 0;
1638f50375eeSPatrick Kelsey 
1639f50375eeSPatrick Kelsey 			if (rxcd->ipv4) {
1640f50375eeSPatrick Kelsey 				csum_flags |= CSUM_IP_CHECKED;
1641f50375eeSPatrick Kelsey 				if (rxcd->ipcsum_ok)
1642f50375eeSPatrick Kelsey 					csum_flags |= CSUM_IP_VALID;
1643f50375eeSPatrick Kelsey 			}
1644f50375eeSPatrick Kelsey 			if (!rxcd->fragment && (rxcd->tcp || rxcd->udp)) {
1645f50375eeSPatrick Kelsey 				csum_flags |= CSUM_L4_CALC;
1646f50375eeSPatrick Kelsey 				if (rxcd->csum_ok) {
1647f50375eeSPatrick Kelsey 					csum_flags |= CSUM_L4_VALID;
1648f50375eeSPatrick Kelsey 					ri->iri_csum_data = 0xffff;
1649f50375eeSPatrick Kelsey 				}
1650f50375eeSPatrick Kelsey 			}
1651f50375eeSPatrick Kelsey 			ri->iri_csum_flags = csum_flags;
1652f50375eeSPatrick Kelsey 		}
1653f50375eeSPatrick Kelsey 
1654f50375eeSPatrick Kelsey 		/* VLAN information is in the last descriptor. */
1655f50375eeSPatrick Kelsey 		if (rxcd->vlan) {
1656f50375eeSPatrick Kelsey 			ri->iri_flags |= M_VLANTAG;
1657f50375eeSPatrick Kelsey 			ri->iri_vtag = rxcd->vtag;
1658f50375eeSPatrick Kelsey 		}
1659f50375eeSPatrick Kelsey 	}
1660f50375eeSPatrick Kelsey 
1661e3c97c2cSBryan Venteicher 	return (0);
1662e3c97c2cSBryan Venteicher }
1663e3c97c2cSBryan Venteicher 
1664e3c97c2cSBryan Venteicher static void
16658f82136aSPatrick Kelsey vmxnet3_isc_rxd_refill(void *vsc, if_rxd_update_t iru)
1666e3c97c2cSBryan Venteicher {
1667e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
16688f82136aSPatrick Kelsey 	struct vmxnet3_rxqueue *rxq;
1669e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
1670e3c97c2cSBryan Venteicher 	struct vmxnet3_rxdesc *rxd;
16718f82136aSPatrick Kelsey 	uint64_t *paddrs;
16728f82136aSPatrick Kelsey 	int count;
16738f82136aSPatrick Kelsey 	int len;
1674f50375eeSPatrick Kelsey 	int idx;
16758f82136aSPatrick Kelsey 	int i;
16768f82136aSPatrick Kelsey 	uint8_t flid;
16778f82136aSPatrick Kelsey 	uint8_t btype;
1678e3c97c2cSBryan Venteicher 
16798f82136aSPatrick Kelsey 	count = iru->iru_count;
16808f82136aSPatrick Kelsey 	len = iru->iru_buf_size;
16818f82136aSPatrick Kelsey 	flid = iru->iru_flidx;
16828f82136aSPatrick Kelsey 	paddrs = iru->iru_paddrs;
1683e3c97c2cSBryan Venteicher 
16848f82136aSPatrick Kelsey 	sc = vsc;
16858f82136aSPatrick Kelsey 	rxq = &sc->vmx_rxq[iru->iru_qsidx];
16868f82136aSPatrick Kelsey 	rxr = &rxq->vxrxq_cmd_ring[flid];
16878f82136aSPatrick Kelsey 	rxd = rxr->vxrxr_rxd;
1688e3c97c2cSBryan Venteicher 
1689e3c97c2cSBryan Venteicher 	/*
16908f82136aSPatrick Kelsey 	 * Command ring 0 is filled with BTYPE_HEAD descriptors, and
16918f82136aSPatrick Kelsey 	 * command ring 1 is filled with BTYPE_BODY descriptors.
1692e3c97c2cSBryan Venteicher 	 */
16938f82136aSPatrick Kelsey 	btype = (flid == 0) ? VMXNET3_BTYPE_HEAD : VMXNET3_BTYPE_BODY;
1694f50375eeSPatrick Kelsey 	/*
1695f50375eeSPatrick Kelsey 	 * The refill entries from iflib will advance monotonically,
1696f50375eeSPatrick Kelsey 	 * but the refilled descriptors may not be contiguous due to
1697f50375eeSPatrick Kelsey 	 * earlier skipping of descriptors by the device.  The refill
1698f50375eeSPatrick Kelsey 	 * entries from iflib need an entire state update, while the
1699f50375eeSPatrick Kelsey 	 * descriptors previously skipped by the device only need to
1700f50375eeSPatrick Kelsey 	 * have their generation numbers updated.
1701f50375eeSPatrick Kelsey 	 */
1702f50375eeSPatrick Kelsey 	idx = rxr->vxrxr_refill_start;
1703f50375eeSPatrick Kelsey 	i = 0;
1704f50375eeSPatrick Kelsey 	do {
1705f50375eeSPatrick Kelsey 		if (idx == iru->iru_idxs[i]) {
1706f50375eeSPatrick Kelsey 			rxd[idx].addr = paddrs[i];
1707f50375eeSPatrick Kelsey 			rxd[idx].len = len;
1708f50375eeSPatrick Kelsey 			rxd[idx].btype = btype;
1709f50375eeSPatrick Kelsey 			i++;
1710f50375eeSPatrick Kelsey 		} else
1711f50375eeSPatrick Kelsey 			rxr->vxrxr_desc_skips++;
1712f50375eeSPatrick Kelsey 		rxd[idx].gen = rxr->vxrxr_gen;
17138f82136aSPatrick Kelsey 
1714f50375eeSPatrick Kelsey 		if (++idx == rxr->vxrxr_ndesc) {
1715f50375eeSPatrick Kelsey 			idx = 0;
17168f82136aSPatrick Kelsey 			rxr->vxrxr_gen ^= 1;
17178f82136aSPatrick Kelsey 		}
1718f50375eeSPatrick Kelsey 	} while (i != count);
1719f50375eeSPatrick Kelsey 	rxr->vxrxr_refill_start = idx;
1720e3c97c2cSBryan Venteicher }
1721e3c97c2cSBryan Venteicher 
17228f82136aSPatrick Kelsey static void
17238f82136aSPatrick Kelsey vmxnet3_isc_rxd_flush(void *vsc, uint16_t rxqid, uint8_t flid, qidx_t pidx)
17248f82136aSPatrick Kelsey {
17258f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
1726e3c97c2cSBryan Venteicher 	bus_size_t r;
1727e3c97c2cSBryan Venteicher 
17288f82136aSPatrick Kelsey 	sc = vsc;
17298f82136aSPatrick Kelsey 
17308f82136aSPatrick Kelsey 	if (flid == 0)
17318f82136aSPatrick Kelsey 		r = VMXNET3_BAR0_RXH1(rxqid);
17328f82136aSPatrick Kelsey 	else
17338f82136aSPatrick Kelsey 		r = VMXNET3_BAR0_RXH2(rxqid);
17348f82136aSPatrick Kelsey 
17358f82136aSPatrick Kelsey 	vmxnet3_write_bar0(sc, r, pidx);
1736e3c97c2cSBryan Venteicher }
1737e3c97c2cSBryan Venteicher 
17388f82136aSPatrick Kelsey static int
1739e3c97c2cSBryan Venteicher vmxnet3_legacy_intr(void *xsc)
1740e3c97c2cSBryan Venteicher {
1741e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
17428f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
17438f82136aSPatrick Kelsey 	if_ctx_t ctx;
1744e3c97c2cSBryan Venteicher 
1745e3c97c2cSBryan Venteicher 	sc = xsc;
17468f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
17478f82136aSPatrick Kelsey 	ctx = sc->vmx_ctx;
1748e3c97c2cSBryan Venteicher 
17498f82136aSPatrick Kelsey 	/*
17508f82136aSPatrick Kelsey 	 * When there is only a single interrupt configured, this routine
17518f82136aSPatrick Kelsey 	 * runs in fast interrupt context, following which the rxq 0 task
17528f82136aSPatrick Kelsey 	 * will be enqueued.
17538f82136aSPatrick Kelsey 	 */
17548f82136aSPatrick Kelsey 	if (scctx->isc_intr == IFLIB_INTR_LEGACY) {
1755e3c97c2cSBryan Venteicher 		if (vmxnet3_read_bar1(sc, VMXNET3_BAR1_INTR) == 0)
17568f82136aSPatrick Kelsey 			return (FILTER_HANDLED);
1757e3c97c2cSBryan Venteicher 	}
1758e3c97c2cSBryan Venteicher 	if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE)
17598f82136aSPatrick Kelsey 		vmxnet3_intr_disable_all(ctx);
1760e3c97c2cSBryan Venteicher 
1761e3c97c2cSBryan Venteicher 	if (sc->vmx_ds->event != 0)
17628f82136aSPatrick Kelsey 		iflib_admin_intr_deferred(ctx);
1763e3c97c2cSBryan Venteicher 
17648f82136aSPatrick Kelsey 	/*
17658f82136aSPatrick Kelsey 	 * XXX - When there is both rxq and event activity, do we care
17668f82136aSPatrick Kelsey 	 * whether the rxq 0 task or the admin task re-enables the interrupt
17678f82136aSPatrick Kelsey 	 * first?
17688f82136aSPatrick Kelsey 	 */
17698f82136aSPatrick Kelsey 	return (FILTER_SCHEDULE_THREAD);
1770e3c97c2cSBryan Venteicher }
1771e3c97c2cSBryan Venteicher 
17728f82136aSPatrick Kelsey static int
17738f82136aSPatrick Kelsey vmxnet3_rxq_intr(void *vrxq)
1774e3c97c2cSBryan Venteicher {
1775e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
1776e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
1777e3c97c2cSBryan Venteicher 
17788f82136aSPatrick Kelsey 	rxq = vrxq;
1779e3c97c2cSBryan Venteicher 	sc = rxq->vxrxq_sc;
1780e3c97c2cSBryan Venteicher 
1781e3c97c2cSBryan Venteicher 	if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE)
1782e3c97c2cSBryan Venteicher 		vmxnet3_disable_intr(sc, rxq->vxrxq_intr_idx);
1783e3c97c2cSBryan Venteicher 
17848f82136aSPatrick Kelsey 	return (FILTER_SCHEDULE_THREAD);
1785e3c97c2cSBryan Venteicher }
1786e3c97c2cSBryan Venteicher 
17878f82136aSPatrick Kelsey static int
17888f82136aSPatrick Kelsey vmxnet3_event_intr(void *vsc)
1789e3c97c2cSBryan Venteicher {
1790e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
1791e3c97c2cSBryan Venteicher 
17928f82136aSPatrick Kelsey 	sc = vsc;
1793e3c97c2cSBryan Venteicher 
1794e3c97c2cSBryan Venteicher 	if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE)
1795e3c97c2cSBryan Venteicher 		vmxnet3_disable_intr(sc, sc->vmx_event_intr_idx);
1796e3c97c2cSBryan Venteicher 
17978f82136aSPatrick Kelsey 	/*
17988f82136aSPatrick Kelsey 	 * The work will be done via vmxnet3_update_admin_status(), and the
17998f82136aSPatrick Kelsey 	 * interrupt will be re-enabled in vmxnet3_link_intr_enable().
18008f82136aSPatrick Kelsey 	 *
18018f82136aSPatrick Kelsey 	 * The interrupt will be re-enabled by vmxnet3_link_intr_enable().
18028f82136aSPatrick Kelsey 	 */
18038f82136aSPatrick Kelsey 	return (FILTER_SCHEDULE_THREAD);
1804e3c97c2cSBryan Venteicher }
1805e3c97c2cSBryan Venteicher 
1806e3c97c2cSBryan Venteicher static void
18078f82136aSPatrick Kelsey vmxnet3_stop(if_ctx_t ctx)
1808e3c97c2cSBryan Venteicher {
18098f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
1810e3c97c2cSBryan Venteicher 
18118f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
1812e3c97c2cSBryan Venteicher 
1813e3c97c2cSBryan Venteicher 	sc->vmx_link_active = 0;
1814e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_DISABLE);
1815e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_RESET);
1816e3c97c2cSBryan Venteicher }
1817e3c97c2cSBryan Venteicher 
1818e3c97c2cSBryan Venteicher static void
1819e3c97c2cSBryan Venteicher vmxnet3_txinit(struct vmxnet3_softc *sc, struct vmxnet3_txqueue *txq)
1820e3c97c2cSBryan Venteicher {
1821e3c97c2cSBryan Venteicher 	struct vmxnet3_txring *txr;
1822e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *txc;
1823e3c97c2cSBryan Venteicher 
18248f82136aSPatrick Kelsey 	txq->vxtxq_last_flush = -1;
18258f82136aSPatrick Kelsey 
1826e3c97c2cSBryan Venteicher 	txr = &txq->vxtxq_cmd_ring;
1827e3c97c2cSBryan Venteicher 	txr->vxtxr_next = 0;
1828e3c97c2cSBryan Venteicher 	txr->vxtxr_gen = VMXNET3_INIT_GEN;
18298f82136aSPatrick Kelsey 	/*
18308f82136aSPatrick Kelsey 	 * iflib has zeroed out the descriptor array during the prior attach
18318f82136aSPatrick Kelsey 	 * or stop
18328f82136aSPatrick Kelsey 	 */
1833e3c97c2cSBryan Venteicher 
1834e3c97c2cSBryan Venteicher 	txc = &txq->vxtxq_comp_ring;
1835e3c97c2cSBryan Venteicher 	txc->vxcr_next = 0;
1836e3c97c2cSBryan Venteicher 	txc->vxcr_gen = VMXNET3_INIT_GEN;
18378f82136aSPatrick Kelsey 	/*
18388f82136aSPatrick Kelsey 	 * iflib has zeroed out the descriptor array during the prior attach
18398f82136aSPatrick Kelsey 	 * or stop
18408f82136aSPatrick Kelsey 	 */
1841e3c97c2cSBryan Venteicher }
1842e3c97c2cSBryan Venteicher 
18438f82136aSPatrick Kelsey static void
1844e3c97c2cSBryan Venteicher vmxnet3_rxinit(struct vmxnet3_softc *sc, struct vmxnet3_rxqueue *rxq)
1845e3c97c2cSBryan Venteicher {
1846e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
1847e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *rxc;
18488f82136aSPatrick Kelsey 	int i;
1849e3c97c2cSBryan Venteicher 
1850e3c97c2cSBryan Venteicher 	/*
18518f82136aSPatrick Kelsey 	 * The descriptors will be populated with buffers during a
18528f82136aSPatrick Kelsey 	 * subsequent invocation of vmxnet3_isc_rxd_refill()
1853e3c97c2cSBryan Venteicher 	 */
18548f82136aSPatrick Kelsey 	for (i = 0; i < sc->vmx_sctx->isc_nrxqs - 1; i++) {
1855e3c97c2cSBryan Venteicher 		rxr = &rxq->vxrxq_cmd_ring[i];
1856e3c97c2cSBryan Venteicher 		rxr->vxrxr_gen = VMXNET3_INIT_GEN;
1857f50375eeSPatrick Kelsey 		rxr->vxrxr_desc_skips = 0;
1858f50375eeSPatrick Kelsey 		rxr->vxrxr_refill_start = 0;
18598f82136aSPatrick Kelsey 		/*
18608f82136aSPatrick Kelsey 		 * iflib has zeroed out the descriptor array during the
18618f82136aSPatrick Kelsey 		 * prior attach or stop
18628f82136aSPatrick Kelsey 		 */
1863e3c97c2cSBryan Venteicher 	}
1864e3c97c2cSBryan Venteicher 
1865e3c97c2cSBryan Venteicher 	for (/**/; i < VMXNET3_RXRINGS_PERQ; i++) {
1866e3c97c2cSBryan Venteicher 		rxr = &rxq->vxrxq_cmd_ring[i];
1867e3c97c2cSBryan Venteicher 		rxr->vxrxr_gen = 0;
1868f50375eeSPatrick Kelsey 		rxr->vxrxr_desc_skips = 0;
1869f50375eeSPatrick Kelsey 		rxr->vxrxr_refill_start = 0;
1870e3c97c2cSBryan Venteicher 		bzero(rxr->vxrxr_rxd,
1871e3c97c2cSBryan Venteicher 		    rxr->vxrxr_ndesc * sizeof(struct vmxnet3_rxdesc));
1872e3c97c2cSBryan Venteicher 	}
1873e3c97c2cSBryan Venteicher 
1874e3c97c2cSBryan Venteicher 	rxc = &rxq->vxrxq_comp_ring;
1875e3c97c2cSBryan Venteicher 	rxc->vxcr_next = 0;
1876e3c97c2cSBryan Venteicher 	rxc->vxcr_gen = VMXNET3_INIT_GEN;
1877f50375eeSPatrick Kelsey 	rxc->vxcr_zero_length = 0;
18789c612a5dSAndriy Gapon 	rxc->vcxr_zero_length_frag = 0;
1879f50375eeSPatrick Kelsey 	rxc->vxcr_pkt_errors = 0;
18808f82136aSPatrick Kelsey 	/*
18818f82136aSPatrick Kelsey 	 * iflib has zeroed out the descriptor array during the prior attach
18828f82136aSPatrick Kelsey 	 * or stop
18838f82136aSPatrick Kelsey 	 */
1884e3c97c2cSBryan Venteicher }
1885e3c97c2cSBryan Venteicher 
18868f82136aSPatrick Kelsey static void
1887e3c97c2cSBryan Venteicher vmxnet3_reinit_queues(struct vmxnet3_softc *sc)
1888e3c97c2cSBryan Venteicher {
18898f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
18908f82136aSPatrick Kelsey 	int q;
1891e3c97c2cSBryan Venteicher 
18928f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
1893e3c97c2cSBryan Venteicher 
18948f82136aSPatrick Kelsey 	for (q = 0; q < scctx->isc_ntxqsets; q++)
1895e3c97c2cSBryan Venteicher 		vmxnet3_txinit(sc, &sc->vmx_txq[q]);
1896e3c97c2cSBryan Venteicher 
18978f82136aSPatrick Kelsey 	for (q = 0; q < scctx->isc_nrxqsets; q++)
18988f82136aSPatrick Kelsey 		vmxnet3_rxinit(sc, &sc->vmx_rxq[q]);
1899e3c97c2cSBryan Venteicher }
1900e3c97c2cSBryan Venteicher 
1901e3c97c2cSBryan Venteicher static int
1902e3c97c2cSBryan Venteicher vmxnet3_enable_device(struct vmxnet3_softc *sc)
1903e3c97c2cSBryan Venteicher {
19048f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
1905e3c97c2cSBryan Venteicher 	int q;
1906e3c97c2cSBryan Venteicher 
19078f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
19088f82136aSPatrick Kelsey 
1909e3c97c2cSBryan Venteicher 	if (vmxnet3_read_cmd(sc, VMXNET3_CMD_ENABLE) != 0) {
1910e3c97c2cSBryan Venteicher 		device_printf(sc->vmx_dev, "device enable command failed!\n");
1911e3c97c2cSBryan Venteicher 		return (1);
1912e3c97c2cSBryan Venteicher 	}
1913e3c97c2cSBryan Venteicher 
1914e3c97c2cSBryan Venteicher 	/* Reset the Rx queue heads. */
19158f82136aSPatrick Kelsey 	for (q = 0; q < scctx->isc_nrxqsets; q++) {
1916e3c97c2cSBryan Venteicher 		vmxnet3_write_bar0(sc, VMXNET3_BAR0_RXH1(q), 0);
1917e3c97c2cSBryan Venteicher 		vmxnet3_write_bar0(sc, VMXNET3_BAR0_RXH2(q), 0);
1918e3c97c2cSBryan Venteicher 	}
1919e3c97c2cSBryan Venteicher 
1920e3c97c2cSBryan Venteicher 	return (0);
1921e3c97c2cSBryan Venteicher }
1922e3c97c2cSBryan Venteicher 
1923e3c97c2cSBryan Venteicher static void
1924e3c97c2cSBryan Venteicher vmxnet3_reinit_rxfilters(struct vmxnet3_softc *sc)
1925e3c97c2cSBryan Venteicher {
1926e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
1927e3c97c2cSBryan Venteicher 
1928e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
1929e3c97c2cSBryan Venteicher 
19308f82136aSPatrick Kelsey 	vmxnet3_set_rxfilter(sc, if_getflags(ifp));
1931e3c97c2cSBryan Venteicher 
1932e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & IFCAP_VLAN_HWFILTER)
1933e3c97c2cSBryan Venteicher 		bcopy(sc->vmx_vlan_filter, sc->vmx_ds->vlan_filter,
1934e3c97c2cSBryan Venteicher 		    sizeof(sc->vmx_ds->vlan_filter));
1935e3c97c2cSBryan Venteicher 	else
1936e3c97c2cSBryan Venteicher 		bzero(sc->vmx_ds->vlan_filter,
1937e3c97c2cSBryan Venteicher 		    sizeof(sc->vmx_ds->vlan_filter));
1938e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_VLAN_FILTER);
1939e3c97c2cSBryan Venteicher }
1940e3c97c2cSBryan Venteicher 
19418f82136aSPatrick Kelsey static void
19428f82136aSPatrick Kelsey vmxnet3_init(if_ctx_t ctx)
1943e3c97c2cSBryan Venteicher {
19448f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
1945e3c97c2cSBryan Venteicher 
19468f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
19478f82136aSPatrick Kelsey 
19488f82136aSPatrick Kelsey 	/* Use the current MAC address. */
19498f82136aSPatrick Kelsey 	bcopy(IF_LLADDR(sc->vmx_ifp), sc->vmx_lladdr, ETHER_ADDR_LEN);
19508f82136aSPatrick Kelsey 	vmxnet3_set_lladdr(sc);
19518f82136aSPatrick Kelsey 
1952e3c97c2cSBryan Venteicher 	vmxnet3_reinit_shared_data(sc);
19538f82136aSPatrick Kelsey 	vmxnet3_reinit_queues(sc);
1954e3c97c2cSBryan Venteicher 
19558f82136aSPatrick Kelsey 	vmxnet3_enable_device(sc);
1956e3c97c2cSBryan Venteicher 
1957e3c97c2cSBryan Venteicher 	vmxnet3_reinit_rxfilters(sc);
1958e3c97c2cSBryan Venteicher 	vmxnet3_link_status(sc);
1959e3c97c2cSBryan Venteicher }
1960e3c97c2cSBryan Venteicher 
1961e3c97c2cSBryan Venteicher static void
19628f82136aSPatrick Kelsey vmxnet3_multi_set(if_ctx_t ctx)
1963e3c97c2cSBryan Venteicher {
1964e3c97c2cSBryan Venteicher 
19658f82136aSPatrick Kelsey 	vmxnet3_set_rxfilter(iflib_get_softc(ctx),
19668f82136aSPatrick Kelsey 	    if_getflags(iflib_get_ifp(ctx)));
1967e3c97c2cSBryan Venteicher }
1968e3c97c2cSBryan Venteicher 
1969e3c97c2cSBryan Venteicher static int
19708f82136aSPatrick Kelsey vmxnet3_mtu_set(if_ctx_t ctx, uint32_t mtu)
1971e3c97c2cSBryan Venteicher {
19721342c8c6SPatrick Kelsey 	struct vmxnet3_softc *sc;
19731342c8c6SPatrick Kelsey 	if_softc_ctx_t scctx;
19741342c8c6SPatrick Kelsey 
19751342c8c6SPatrick Kelsey 	sc = iflib_get_softc(ctx);
19761342c8c6SPatrick Kelsey 	scctx = sc->vmx_scctx;
1977e3c97c2cSBryan Venteicher 
19788f82136aSPatrick Kelsey 	if (mtu > VMXNET3_TX_MAXSIZE - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN +
19798f82136aSPatrick Kelsey 		ETHER_CRC_LEN))
1980e3c97c2cSBryan Venteicher 		return (EINVAL);
1981e3c97c2cSBryan Venteicher 
19821342c8c6SPatrick Kelsey 	/*
19831342c8c6SPatrick Kelsey 	 * Update the max frame size so that the rx mbuf size is
19841342c8c6SPatrick Kelsey 	 * chosen based on the new mtu during the interface init that
19851342c8c6SPatrick Kelsey 	 * will occur after this routine returns.
19861342c8c6SPatrick Kelsey 	 */
19871342c8c6SPatrick Kelsey 	scctx->isc_max_frame_size = mtu +
19881342c8c6SPatrick Kelsey 		ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + ETHER_CRC_LEN;
19891342c8c6SPatrick Kelsey 	/* RX completion queue - n/a */
19901342c8c6SPatrick Kelsey 	scctx->isc_rxd_buf_size[0] = 0;
19911342c8c6SPatrick Kelsey 	/*
19921342c8c6SPatrick Kelsey 	 * For header-type descriptors (used for first segment of
19931342c8c6SPatrick Kelsey 	 * packet), let iflib determine the buffer size based on the
19941342c8c6SPatrick Kelsey 	 * max frame size.
19951342c8c6SPatrick Kelsey 	 */
19961342c8c6SPatrick Kelsey 	scctx->isc_rxd_buf_size[1] = 0;
19971342c8c6SPatrick Kelsey 	/*
19981342c8c6SPatrick Kelsey 	 * For body-type descriptors (used for jumbo frames and LRO),
19991342c8c6SPatrick Kelsey 	 * always use page-sized buffers.
20001342c8c6SPatrick Kelsey 	 */
20011342c8c6SPatrick Kelsey 	scctx->isc_rxd_buf_size[2] = MJUMPAGESIZE;
20021342c8c6SPatrick Kelsey 
2003e3c97c2cSBryan Venteicher 	return (0);
2004e3c97c2cSBryan Venteicher }
2005e3c97c2cSBryan Venteicher 
20068f82136aSPatrick Kelsey static void
20078f82136aSPatrick Kelsey vmxnet3_media_status(if_ctx_t ctx, struct ifmediareq * ifmr)
2008e3c97c2cSBryan Venteicher {
20098f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
2010e3c97c2cSBryan Venteicher 
20118f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
2012e3c97c2cSBryan Venteicher 
20138f82136aSPatrick Kelsey 	ifmr->ifm_status = IFM_AVALID;
20148f82136aSPatrick Kelsey 	ifmr->ifm_active = IFM_ETHER;
2015e3c97c2cSBryan Venteicher 
20168f82136aSPatrick Kelsey 	if (vmxnet3_link_is_up(sc) != 0) {
20178f82136aSPatrick Kelsey 		ifmr->ifm_status |= IFM_ACTIVE;
20188f82136aSPatrick Kelsey 		ifmr->ifm_active |= IFM_AUTO;
2019e3c97c2cSBryan Venteicher 	} else
20208f82136aSPatrick Kelsey 		ifmr->ifm_active |= IFM_NONE;
2021e3c97c2cSBryan Venteicher }
2022e3c97c2cSBryan Venteicher 
2023e3c97c2cSBryan Venteicher static int
20248f82136aSPatrick Kelsey vmxnet3_media_change(if_ctx_t ctx)
2025e3c97c2cSBryan Venteicher {
2026e3c97c2cSBryan Venteicher 
20278f82136aSPatrick Kelsey 	/* Ignore. */
2028c7156fe9SLuigi Rizzo 	return (0);
2029e557c1ddSBryan Venteicher }
2030e557c1ddSBryan Venteicher 
2031e557c1ddSBryan Venteicher static int
20328f82136aSPatrick Kelsey vmxnet3_promisc_set(if_ctx_t ctx, int flags)
2033e557c1ddSBryan Venteicher {
2034e557c1ddSBryan Venteicher 
20358f82136aSPatrick Kelsey 	vmxnet3_set_rxfilter(iflib_get_softc(ctx), flags);
2036e557c1ddSBryan Venteicher 
20378f82136aSPatrick Kelsey 	return (0);
2038e557c1ddSBryan Venteicher }
2039e557c1ddSBryan Venteicher 
20408f82136aSPatrick Kelsey static uint64_t
20418f82136aSPatrick Kelsey vmxnet3_get_counter(if_ctx_t ctx, ift_counter cnt)
20428f82136aSPatrick Kelsey {
20438f82136aSPatrick Kelsey 	if_t ifp = iflib_get_ifp(ctx);
20448f82136aSPatrick Kelsey 
20458f82136aSPatrick Kelsey 	if (cnt < IFCOUNTERS)
20468f82136aSPatrick Kelsey 		return if_get_counter_default(ifp, cnt);
20478f82136aSPatrick Kelsey 
20488f82136aSPatrick Kelsey 	return (0);
2049e557c1ddSBryan Venteicher }
2050e557c1ddSBryan Venteicher 
2051e557c1ddSBryan Venteicher static void
20528f82136aSPatrick Kelsey vmxnet3_update_admin_status(if_ctx_t ctx)
2053e557c1ddSBryan Venteicher {
2054e557c1ddSBryan Venteicher 	struct vmxnet3_softc *sc;
2055e557c1ddSBryan Venteicher 
20568f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
20578f82136aSPatrick Kelsey 	if (sc->vmx_ds->event != 0)
20588f82136aSPatrick Kelsey 		vmxnet3_evintr(sc);
2059e557c1ddSBryan Venteicher 
20608f82136aSPatrick Kelsey 	vmxnet3_refresh_host_stats(sc);
2061e557c1ddSBryan Venteicher }
2062e557c1ddSBryan Venteicher 
2063e557c1ddSBryan Venteicher static void
20648f82136aSPatrick Kelsey vmxnet3_txq_timer(if_ctx_t ctx, uint16_t qid)
2065e557c1ddSBryan Venteicher {
20668f82136aSPatrick Kelsey 	/* Host stats refresh is global, so just trigger it on txq 0 */
20678f82136aSPatrick Kelsey 	if (qid == 0)
20688f82136aSPatrick Kelsey 		vmxnet3_refresh_host_stats(iflib_get_softc(ctx));
2069e557c1ddSBryan Venteicher }
2070e557c1ddSBryan Venteicher 
2071e3c97c2cSBryan Venteicher static void
2072e3c97c2cSBryan Venteicher vmxnet3_update_vlan_filter(struct vmxnet3_softc *sc, int add, uint16_t tag)
2073e3c97c2cSBryan Venteicher {
2074e3c97c2cSBryan Venteicher 	int idx, bit;
2075e3c97c2cSBryan Venteicher 
2076e3c97c2cSBryan Venteicher 	if (tag == 0 || tag > 4095)
2077e3c97c2cSBryan Venteicher 		return;
2078e3c97c2cSBryan Venteicher 
20798f82136aSPatrick Kelsey 	idx = (tag >> 5) & 0x7F;
20808f82136aSPatrick Kelsey 	bit = tag & 0x1F;
2081e3c97c2cSBryan Venteicher 
2082e3c97c2cSBryan Venteicher 	/* Update our private VLAN bitvector. */
2083e3c97c2cSBryan Venteicher 	if (add)
2084e3c97c2cSBryan Venteicher 		sc->vmx_vlan_filter[idx] |= (1 << bit);
2085e3c97c2cSBryan Venteicher 	else
2086e3c97c2cSBryan Venteicher 		sc->vmx_vlan_filter[idx] &= ~(1 << bit);
2087e3c97c2cSBryan Venteicher }
2088e3c97c2cSBryan Venteicher 
2089e3c97c2cSBryan Venteicher static void
20908f82136aSPatrick Kelsey vmxnet3_vlan_register(if_ctx_t ctx, uint16_t tag)
2091e3c97c2cSBryan Venteicher {
2092e3c97c2cSBryan Venteicher 
20938f82136aSPatrick Kelsey 	vmxnet3_update_vlan_filter(iflib_get_softc(ctx), 1, tag);
2094e3c97c2cSBryan Venteicher }
2095e3c97c2cSBryan Venteicher 
2096e3c97c2cSBryan Venteicher static void
20978f82136aSPatrick Kelsey vmxnet3_vlan_unregister(if_ctx_t ctx, uint16_t tag)
2098e3c97c2cSBryan Venteicher {
2099e3c97c2cSBryan Venteicher 
21008f82136aSPatrick Kelsey 	vmxnet3_update_vlan_filter(iflib_get_softc(ctx), 0, tag);
2101e3c97c2cSBryan Venteicher }
2102e3c97c2cSBryan Venteicher 
2103d6b5965bSGleb Smirnoff static u_int
2104d6b5965bSGleb Smirnoff vmxnet3_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int count)
2105d6b5965bSGleb Smirnoff {
2106d6b5965bSGleb Smirnoff 	struct vmxnet3_softc *sc = arg;
2107d6b5965bSGleb Smirnoff 
2108d6b5965bSGleb Smirnoff 	if (count < VMXNET3_MULTICAST_MAX)
2109d6b5965bSGleb Smirnoff 		bcopy(LLADDR(sdl), &sc->vmx_mcast[count * ETHER_ADDR_LEN],
2110d6b5965bSGleb Smirnoff 		    ETHER_ADDR_LEN);
2111d6b5965bSGleb Smirnoff 
2112d6b5965bSGleb Smirnoff 	return (1);
2113d6b5965bSGleb Smirnoff }
2114d6b5965bSGleb Smirnoff 
2115e3c97c2cSBryan Venteicher static void
21168f82136aSPatrick Kelsey vmxnet3_set_rxfilter(struct vmxnet3_softc *sc, int flags)
2117e3c97c2cSBryan Venteicher {
2118e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
2119e3c97c2cSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
2120e3c97c2cSBryan Venteicher 	u_int mode;
2121e3c97c2cSBryan Venteicher 
2122e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
2123e3c97c2cSBryan Venteicher 	ds = sc->vmx_ds;
2124e3c97c2cSBryan Venteicher 
2125e557c1ddSBryan Venteicher 	mode = VMXNET3_RXMODE_UCAST | VMXNET3_RXMODE_BCAST;
21268f82136aSPatrick Kelsey 	if (flags & IFF_PROMISC)
2127e3c97c2cSBryan Venteicher 		mode |= VMXNET3_RXMODE_PROMISC;
21288f82136aSPatrick Kelsey 	if (flags & IFF_ALLMULTI)
2129e3c97c2cSBryan Venteicher 		mode |= VMXNET3_RXMODE_ALLMULTI;
2130e3c97c2cSBryan Venteicher 	else {
2131d6b5965bSGleb Smirnoff 		int cnt;
2132e3c97c2cSBryan Venteicher 
2133d6b5965bSGleb Smirnoff 		cnt = if_foreach_llmaddr(ifp, vmxnet3_hash_maddr, sc);
2134d6b5965bSGleb Smirnoff 		if (cnt >= VMXNET3_MULTICAST_MAX) {
2135e3c97c2cSBryan Venteicher 			cnt = 0;
2136e3c97c2cSBryan Venteicher 			mode |= VMXNET3_RXMODE_ALLMULTI;
2137e3c97c2cSBryan Venteicher 		} else if (cnt > 0)
2138e3c97c2cSBryan Venteicher 			mode |= VMXNET3_RXMODE_MCAST;
2139e3c97c2cSBryan Venteicher 		ds->mcast_tablelen = cnt * ETHER_ADDR_LEN;
2140e3c97c2cSBryan Venteicher 	}
2141e3c97c2cSBryan Venteicher 
2142e3c97c2cSBryan Venteicher 	ds->rxmode = mode;
2143e3c97c2cSBryan Venteicher 
2144e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_SET_FILTER);
2145e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_SET_RXMODE);
2146e3c97c2cSBryan Venteicher }
2147e3c97c2cSBryan Venteicher 
2148e3c97c2cSBryan Venteicher static void
2149e557c1ddSBryan Venteicher vmxnet3_refresh_host_stats(struct vmxnet3_softc *sc)
2150e3c97c2cSBryan Venteicher {
2151e3c97c2cSBryan Venteicher 
2152e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_GET_STATS);
2153e3c97c2cSBryan Venteicher }
2154e3c97c2cSBryan Venteicher 
2155e3c97c2cSBryan Venteicher static int
2156e3c97c2cSBryan Venteicher vmxnet3_link_is_up(struct vmxnet3_softc *sc)
2157e3c97c2cSBryan Venteicher {
2158e3c97c2cSBryan Venteicher 	uint32_t status;
2159e3c97c2cSBryan Venteicher 
2160e3c97c2cSBryan Venteicher 	status = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_LINK);
2161e3c97c2cSBryan Venteicher 	return !!(status & 0x1);
2162e3c97c2cSBryan Venteicher }
2163e3c97c2cSBryan Venteicher 
2164e3c97c2cSBryan Venteicher static void
2165e3c97c2cSBryan Venteicher vmxnet3_link_status(struct vmxnet3_softc *sc)
2166e3c97c2cSBryan Venteicher {
21678f82136aSPatrick Kelsey 	if_ctx_t ctx;
21688f82136aSPatrick Kelsey 	uint64_t speed;
2169e3c97c2cSBryan Venteicher 	int link;
2170e3c97c2cSBryan Venteicher 
21718f82136aSPatrick Kelsey 	ctx = sc->vmx_ctx;
2172e3c97c2cSBryan Venteicher 	link = vmxnet3_link_is_up(sc);
21738f82136aSPatrick Kelsey 	speed = IF_Gbps(10);
2174e3c97c2cSBryan Venteicher 
2175e3c97c2cSBryan Venteicher 	if (link != 0 && sc->vmx_link_active == 0) {
2176e3c97c2cSBryan Venteicher 		sc->vmx_link_active = 1;
21778f82136aSPatrick Kelsey 		iflib_link_state_change(ctx, LINK_STATE_UP, speed);
2178e3c97c2cSBryan Venteicher 	} else if (link == 0 && sc->vmx_link_active != 0) {
2179e3c97c2cSBryan Venteicher 		sc->vmx_link_active = 0;
21808f82136aSPatrick Kelsey 		iflib_link_state_change(ctx, LINK_STATE_DOWN, speed);
2181e3c97c2cSBryan Venteicher 	}
2182e3c97c2cSBryan Venteicher }
2183e3c97c2cSBryan Venteicher 
2184e3c97c2cSBryan Venteicher static void
2185e3c97c2cSBryan Venteicher vmxnet3_set_lladdr(struct vmxnet3_softc *sc)
2186e3c97c2cSBryan Venteicher {
2187e3c97c2cSBryan Venteicher 	uint32_t ml, mh;
2188e3c97c2cSBryan Venteicher 
2189e3c97c2cSBryan Venteicher 	ml  = sc->vmx_lladdr[0];
2190e3c97c2cSBryan Venteicher 	ml |= sc->vmx_lladdr[1] << 8;
2191e3c97c2cSBryan Venteicher 	ml |= sc->vmx_lladdr[2] << 16;
2192e3c97c2cSBryan Venteicher 	ml |= sc->vmx_lladdr[3] << 24;
2193e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_MACL, ml);
2194e3c97c2cSBryan Venteicher 
2195e3c97c2cSBryan Venteicher 	mh  = sc->vmx_lladdr[4];
2196e3c97c2cSBryan Venteicher 	mh |= sc->vmx_lladdr[5] << 8;
2197e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_MACH, mh);
2198e3c97c2cSBryan Venteicher }
2199e3c97c2cSBryan Venteicher 
2200e3c97c2cSBryan Venteicher static void
2201e3c97c2cSBryan Venteicher vmxnet3_get_lladdr(struct vmxnet3_softc *sc)
2202e3c97c2cSBryan Venteicher {
2203e3c97c2cSBryan Venteicher 	uint32_t ml, mh;
2204e3c97c2cSBryan Venteicher 
2205e3c97c2cSBryan Venteicher 	ml = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_MACL);
2206e3c97c2cSBryan Venteicher 	mh = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_MACH);
2207e3c97c2cSBryan Venteicher 
2208e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[0] = ml;
2209e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[1] = ml >> 8;
2210e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[2] = ml >> 16;
2211e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[3] = ml >> 24;
2212e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[4] = mh;
2213e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[5] = mh >> 8;
2214e3c97c2cSBryan Venteicher }
2215e3c97c2cSBryan Venteicher 
2216e3c97c2cSBryan Venteicher static void
2217e3c97c2cSBryan Venteicher vmxnet3_setup_txq_sysctl(struct vmxnet3_txqueue *txq,
2218e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2219e3c97c2cSBryan Venteicher {
2220e3c97c2cSBryan Venteicher 	struct sysctl_oid *node, *txsnode;
2221e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *list, *txslist;
2222e3c97c2cSBryan Venteicher 	struct UPT1_TxStats *txstats;
2223e3c97c2cSBryan Venteicher 	char namebuf[16];
2224e3c97c2cSBryan Venteicher 
2225e3c97c2cSBryan Venteicher 	txstats = &txq->vxtxq_ts->stats;
2226e3c97c2cSBryan Venteicher 
2227e3c97c2cSBryan Venteicher 	snprintf(namebuf, sizeof(namebuf), "txq%d", txq->vxtxq_id);
22287029da5cSPawel Biernacki 	node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf,
22297029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Transmit Queue");
2230e3c97c2cSBryan Venteicher 	txq->vxtxq_sysctl = list = SYSCTL_CHILDREN(node);
2231e3c97c2cSBryan Venteicher 
2232e3c97c2cSBryan Venteicher 	/*
22338f82136aSPatrick Kelsey 	 * Add statistics reported by the host. These are updated by the
22348f82136aSPatrick Kelsey 	 * iflib txq timer on txq 0.
2235e3c97c2cSBryan Venteicher 	 */
22367029da5cSPawel Biernacki 	txsnode = SYSCTL_ADD_NODE(ctx, list, OID_AUTO, "hstats",
22377029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Host Statistics");
2238e3c97c2cSBryan Venteicher 	txslist = SYSCTL_CHILDREN(txsnode);
2239e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "tso_packets", CTLFLAG_RD,
2240e3c97c2cSBryan Venteicher 	    &txstats->TSO_packets, "TSO packets");
2241e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "tso_bytes", CTLFLAG_RD,
2242e3c97c2cSBryan Venteicher 	    &txstats->TSO_bytes, "TSO bytes");
2243e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "ucast_packets", CTLFLAG_RD,
2244e3c97c2cSBryan Venteicher 	    &txstats->ucast_packets, "Unicast packets");
2245e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "unicast_bytes", CTLFLAG_RD,
2246e3c97c2cSBryan Venteicher 	    &txstats->ucast_bytes, "Unicast bytes");
2247e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "mcast_packets", CTLFLAG_RD,
2248e3c97c2cSBryan Venteicher 	    &txstats->mcast_packets, "Multicast packets");
2249e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "mcast_bytes", CTLFLAG_RD,
2250e3c97c2cSBryan Venteicher 	    &txstats->mcast_bytes, "Multicast bytes");
2251e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "error", CTLFLAG_RD,
2252e3c97c2cSBryan Venteicher 	    &txstats->error, "Errors");
2253e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "discard", CTLFLAG_RD,
2254e3c97c2cSBryan Venteicher 	    &txstats->discard, "Discards");
2255e3c97c2cSBryan Venteicher }
2256e3c97c2cSBryan Venteicher 
2257e3c97c2cSBryan Venteicher static void
2258e3c97c2cSBryan Venteicher vmxnet3_setup_rxq_sysctl(struct vmxnet3_rxqueue *rxq,
2259e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2260e3c97c2cSBryan Venteicher {
2261e3c97c2cSBryan Venteicher 	struct sysctl_oid *node, *rxsnode;
2262e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *list, *rxslist;
2263e3c97c2cSBryan Venteicher 	struct UPT1_RxStats *rxstats;
2264e3c97c2cSBryan Venteicher 	char namebuf[16];
2265e3c97c2cSBryan Venteicher 
2266e3c97c2cSBryan Venteicher 	rxstats = &rxq->vxrxq_rs->stats;
2267e3c97c2cSBryan Venteicher 
2268e3c97c2cSBryan Venteicher 	snprintf(namebuf, sizeof(namebuf), "rxq%d", rxq->vxrxq_id);
22697029da5cSPawel Biernacki 	node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf,
22707029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Receive Queue");
2271e3c97c2cSBryan Venteicher 	rxq->vxrxq_sysctl = list = SYSCTL_CHILDREN(node);
2272e3c97c2cSBryan Venteicher 
2273e3c97c2cSBryan Venteicher 	/*
22748f82136aSPatrick Kelsey 	 * Add statistics reported by the host. These are updated by the
22758f82136aSPatrick Kelsey 	 * iflib txq timer on txq 0.
2276e3c97c2cSBryan Venteicher 	 */
22777029da5cSPawel Biernacki 	rxsnode = SYSCTL_ADD_NODE(ctx, list, OID_AUTO, "hstats",
22787029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Host Statistics");
2279e3c97c2cSBryan Venteicher 	rxslist = SYSCTL_CHILDREN(rxsnode);
2280e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "lro_packets", CTLFLAG_RD,
2281e3c97c2cSBryan Venteicher 	    &rxstats->LRO_packets, "LRO packets");
2282e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "lro_bytes", CTLFLAG_RD,
2283e3c97c2cSBryan Venteicher 	    &rxstats->LRO_bytes, "LRO bytes");
2284e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "ucast_packets", CTLFLAG_RD,
2285e3c97c2cSBryan Venteicher 	    &rxstats->ucast_packets, "Unicast packets");
2286e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "unicast_bytes", CTLFLAG_RD,
2287e3c97c2cSBryan Venteicher 	    &rxstats->ucast_bytes, "Unicast bytes");
2288e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "mcast_packets", CTLFLAG_RD,
2289e3c97c2cSBryan Venteicher 	    &rxstats->mcast_packets, "Multicast packets");
2290e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "mcast_bytes", CTLFLAG_RD,
2291e3c97c2cSBryan Venteicher 	    &rxstats->mcast_bytes, "Multicast bytes");
2292e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "bcast_packets", CTLFLAG_RD,
2293e3c97c2cSBryan Venteicher 	    &rxstats->bcast_packets, "Broadcast packets");
2294e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "bcast_bytes", CTLFLAG_RD,
2295e3c97c2cSBryan Venteicher 	    &rxstats->bcast_bytes, "Broadcast bytes");
2296e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "nobuffer", CTLFLAG_RD,
2297e3c97c2cSBryan Venteicher 	    &rxstats->nobuffer, "No buffer");
2298e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "error", CTLFLAG_RD,
2299e3c97c2cSBryan Venteicher 	    &rxstats->error, "Errors");
2300e3c97c2cSBryan Venteicher }
2301e3c97c2cSBryan Venteicher 
2302e3c97c2cSBryan Venteicher static void
2303e3c97c2cSBryan Venteicher vmxnet3_setup_debug_sysctl(struct vmxnet3_softc *sc,
2304e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2305e3c97c2cSBryan Venteicher {
23068f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
2307e3c97c2cSBryan Venteicher 	struct sysctl_oid *node;
2308e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *list;
2309e3c97c2cSBryan Venteicher 	int i;
2310e3c97c2cSBryan Venteicher 
23118f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
23128f82136aSPatrick Kelsey 
23138f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++) {
2314e3c97c2cSBryan Venteicher 		struct vmxnet3_txqueue *txq = &sc->vmx_txq[i];
2315e3c97c2cSBryan Venteicher 
2316e3c97c2cSBryan Venteicher 		node = SYSCTL_ADD_NODE(ctx, txq->vxtxq_sysctl, OID_AUTO,
23177029da5cSPawel Biernacki 		    "debug", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "");
2318e3c97c2cSBryan Venteicher 		list = SYSCTL_CHILDREN(node);
2319e3c97c2cSBryan Venteicher 
2320e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd_next", CTLFLAG_RD,
2321e3c97c2cSBryan Venteicher 		    &txq->vxtxq_cmd_ring.vxtxr_next, 0, "");
2322e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd_ndesc", CTLFLAG_RD,
2323e3c97c2cSBryan Venteicher 		    &txq->vxtxq_cmd_ring.vxtxr_ndesc, 0, "");
2324e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd_gen", CTLFLAG_RD,
2325e3c97c2cSBryan Venteicher 		    &txq->vxtxq_cmd_ring.vxtxr_gen, 0, "");
2326e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_next", CTLFLAG_RD,
2327e3c97c2cSBryan Venteicher 		    &txq->vxtxq_comp_ring.vxcr_next, 0, "");
2328e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_ndesc", CTLFLAG_RD,
2329e3c97c2cSBryan Venteicher 		    &txq->vxtxq_comp_ring.vxcr_ndesc, 0,"");
2330e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "comp_gen", CTLFLAG_RD,
2331e3c97c2cSBryan Venteicher 		    &txq->vxtxq_comp_ring.vxcr_gen, 0, "");
2332e3c97c2cSBryan Venteicher 	}
2333e3c97c2cSBryan Venteicher 
23348f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++) {
2335e3c97c2cSBryan Venteicher 		struct vmxnet3_rxqueue *rxq = &sc->vmx_rxq[i];
2336e3c97c2cSBryan Venteicher 
2337e3c97c2cSBryan Venteicher 		node = SYSCTL_ADD_NODE(ctx, rxq->vxrxq_sysctl, OID_AUTO,
23387029da5cSPawel Biernacki 		    "debug", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "");
2339e3c97c2cSBryan Venteicher 		list = SYSCTL_CHILDREN(node);
2340e3c97c2cSBryan Venteicher 
2341e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd0_ndesc", CTLFLAG_RD,
2342e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[0].vxrxr_ndesc, 0, "");
2343e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd0_gen", CTLFLAG_RD,
2344e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[0].vxrxr_gen, 0, "");
2345f50375eeSPatrick Kelsey 		SYSCTL_ADD_U64(ctx, list, OID_AUTO, "cmd0_desc_skips", CTLFLAG_RD,
2346f50375eeSPatrick Kelsey 		    &rxq->vxrxq_cmd_ring[0].vxrxr_desc_skips, 0, "");
2347e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd1_ndesc", CTLFLAG_RD,
2348e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[1].vxrxr_ndesc, 0, "");
2349e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd1_gen", CTLFLAG_RD,
2350e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[1].vxrxr_gen, 0, "");
2351f50375eeSPatrick Kelsey 		SYSCTL_ADD_U64(ctx, list, OID_AUTO, "cmd1_desc_skips", CTLFLAG_RD,
2352f50375eeSPatrick Kelsey 		    &rxq->vxrxq_cmd_ring[1].vxrxr_desc_skips, 0, "");
2353e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_ndesc", CTLFLAG_RD,
2354e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_comp_ring.vxcr_ndesc, 0,"");
2355e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "comp_gen", CTLFLAG_RD,
2356e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_comp_ring.vxcr_gen, 0, "");
2357f50375eeSPatrick Kelsey 		SYSCTL_ADD_U64(ctx, list, OID_AUTO, "comp_zero_length", CTLFLAG_RD,
2358f50375eeSPatrick Kelsey 		    &rxq->vxrxq_comp_ring.vxcr_zero_length, 0, "");
23599c612a5dSAndriy Gapon 		SYSCTL_ADD_U64(ctx, list, OID_AUTO, "comp_zero_length_frag",
23609c612a5dSAndriy Gapon 		    CTLFLAG_RD, &rxq->vxrxq_comp_ring.vcxr_zero_length_frag,
23619c612a5dSAndriy Gapon 		    0, "");
2362f50375eeSPatrick Kelsey 		SYSCTL_ADD_U64(ctx, list, OID_AUTO, "comp_pkt_errors", CTLFLAG_RD,
2363f50375eeSPatrick Kelsey 		    &rxq->vxrxq_comp_ring.vxcr_pkt_errors, 0, "");
2364e3c97c2cSBryan Venteicher 	}
2365e3c97c2cSBryan Venteicher }
2366e3c97c2cSBryan Venteicher 
2367e3c97c2cSBryan Venteicher static void
2368e3c97c2cSBryan Venteicher vmxnet3_setup_queue_sysctl(struct vmxnet3_softc *sc,
2369e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2370e3c97c2cSBryan Venteicher {
23718f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
2372e3c97c2cSBryan Venteicher 	int i;
2373e3c97c2cSBryan Venteicher 
23748f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
23758f82136aSPatrick Kelsey 
23768f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_ntxqsets; i++)
2377e3c97c2cSBryan Venteicher 		vmxnet3_setup_txq_sysctl(&sc->vmx_txq[i], ctx, child);
23788f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_nrxqsets; i++)
2379e3c97c2cSBryan Venteicher 		vmxnet3_setup_rxq_sysctl(&sc->vmx_rxq[i], ctx, child);
2380e3c97c2cSBryan Venteicher 
2381e3c97c2cSBryan Venteicher 	vmxnet3_setup_debug_sysctl(sc, ctx, child);
2382e3c97c2cSBryan Venteicher }
2383e3c97c2cSBryan Venteicher 
2384e3c97c2cSBryan Venteicher static void
2385e3c97c2cSBryan Venteicher vmxnet3_setup_sysctl(struct vmxnet3_softc *sc)
2386e3c97c2cSBryan Venteicher {
2387e3c97c2cSBryan Venteicher 	device_t dev;
2388e3c97c2cSBryan Venteicher 	struct sysctl_ctx_list *ctx;
2389e3c97c2cSBryan Venteicher 	struct sysctl_oid *tree;
2390e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *child;
2391e3c97c2cSBryan Venteicher 
2392e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
2393e3c97c2cSBryan Venteicher 	ctx = device_get_sysctl_ctx(dev);
2394e3c97c2cSBryan Venteicher 	tree = device_get_sysctl_tree(dev);
2395e3c97c2cSBryan Venteicher 	child = SYSCTL_CHILDREN(tree);
2396e3c97c2cSBryan Venteicher 
2397e3c97c2cSBryan Venteicher 	vmxnet3_setup_queue_sysctl(sc, ctx, child);
2398e3c97c2cSBryan Venteicher }
2399e3c97c2cSBryan Venteicher 
2400e3c97c2cSBryan Venteicher static void
2401e3c97c2cSBryan Venteicher vmxnet3_write_bar0(struct vmxnet3_softc *sc, bus_size_t r, uint32_t v)
2402e3c97c2cSBryan Venteicher {
2403e3c97c2cSBryan Venteicher 
2404e3c97c2cSBryan Venteicher 	bus_space_write_4(sc->vmx_iot0, sc->vmx_ioh0, r, v);
2405e3c97c2cSBryan Venteicher }
2406e3c97c2cSBryan Venteicher 
2407e3c97c2cSBryan Venteicher static uint32_t
2408e3c97c2cSBryan Venteicher vmxnet3_read_bar1(struct vmxnet3_softc *sc, bus_size_t r)
2409e3c97c2cSBryan Venteicher {
2410e3c97c2cSBryan Venteicher 
2411e3c97c2cSBryan Venteicher 	return (bus_space_read_4(sc->vmx_iot1, sc->vmx_ioh1, r));
2412e3c97c2cSBryan Venteicher }
2413e3c97c2cSBryan Venteicher 
2414e3c97c2cSBryan Venteicher static void
2415e3c97c2cSBryan Venteicher vmxnet3_write_bar1(struct vmxnet3_softc *sc, bus_size_t r, uint32_t v)
2416e3c97c2cSBryan Venteicher {
2417e3c97c2cSBryan Venteicher 
2418e3c97c2cSBryan Venteicher 	bus_space_write_4(sc->vmx_iot1, sc->vmx_ioh1, r, v);
2419e3c97c2cSBryan Venteicher }
2420e3c97c2cSBryan Venteicher 
2421e3c97c2cSBryan Venteicher static void
2422e3c97c2cSBryan Venteicher vmxnet3_write_cmd(struct vmxnet3_softc *sc, uint32_t cmd)
2423e3c97c2cSBryan Venteicher {
2424e3c97c2cSBryan Venteicher 
2425e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_CMD, cmd);
2426e3c97c2cSBryan Venteicher }
2427e3c97c2cSBryan Venteicher 
2428e3c97c2cSBryan Venteicher static uint32_t
2429e3c97c2cSBryan Venteicher vmxnet3_read_cmd(struct vmxnet3_softc *sc, uint32_t cmd)
2430e3c97c2cSBryan Venteicher {
2431e3c97c2cSBryan Venteicher 
2432e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, cmd);
2433e3c97c2cSBryan Venteicher 	bus_space_barrier(sc->vmx_iot1, sc->vmx_ioh1, 0, 0,
2434e3c97c2cSBryan Venteicher 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
2435e3c97c2cSBryan Venteicher 	return (vmxnet3_read_bar1(sc, VMXNET3_BAR1_CMD));
2436e3c97c2cSBryan Venteicher }
2437e3c97c2cSBryan Venteicher 
2438e3c97c2cSBryan Venteicher static void
2439e3c97c2cSBryan Venteicher vmxnet3_enable_intr(struct vmxnet3_softc *sc, int irq)
2440e3c97c2cSBryan Venteicher {
2441e3c97c2cSBryan Venteicher 
2442e3c97c2cSBryan Venteicher 	vmxnet3_write_bar0(sc, VMXNET3_BAR0_IMASK(irq), 0);
2443e3c97c2cSBryan Venteicher }
2444e3c97c2cSBryan Venteicher 
2445e3c97c2cSBryan Venteicher static void
2446e3c97c2cSBryan Venteicher vmxnet3_disable_intr(struct vmxnet3_softc *sc, int irq)
2447e3c97c2cSBryan Venteicher {
2448e3c97c2cSBryan Venteicher 
2449e3c97c2cSBryan Venteicher 	vmxnet3_write_bar0(sc, VMXNET3_BAR0_IMASK(irq), 1);
2450e3c97c2cSBryan Venteicher }
2451e3c97c2cSBryan Venteicher 
24528f82136aSPatrick Kelsey static int
24538f82136aSPatrick Kelsey vmxnet3_tx_queue_intr_enable(if_ctx_t ctx, uint16_t qid)
2454e3c97c2cSBryan Venteicher {
24558f82136aSPatrick Kelsey 	/* Not using interrupts for TX */
24568f82136aSPatrick Kelsey 	return (0);
24578f82136aSPatrick Kelsey }
24588f82136aSPatrick Kelsey 
24598f82136aSPatrick Kelsey static int
24608f82136aSPatrick Kelsey vmxnet3_rx_queue_intr_enable(if_ctx_t ctx, uint16_t qid)
24618f82136aSPatrick Kelsey {
24628f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
24638f82136aSPatrick Kelsey 
24648f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
24658f82136aSPatrick Kelsey 	vmxnet3_enable_intr(sc, sc->vmx_rxq[qid].vxrxq_intr_idx);
24668f82136aSPatrick Kelsey 	return (0);
24678f82136aSPatrick Kelsey }
24688f82136aSPatrick Kelsey 
24698f82136aSPatrick Kelsey static void
24708f82136aSPatrick Kelsey vmxnet3_link_intr_enable(if_ctx_t ctx)
24718f82136aSPatrick Kelsey {
24728f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
24738f82136aSPatrick Kelsey 
24748f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
24758f82136aSPatrick Kelsey 	vmxnet3_enable_intr(sc, sc->vmx_event_intr_idx);
24768f82136aSPatrick Kelsey }
24778f82136aSPatrick Kelsey 
24788f82136aSPatrick Kelsey static void
24798f82136aSPatrick Kelsey vmxnet3_intr_enable_all(if_ctx_t ctx)
24808f82136aSPatrick Kelsey {
24818f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
24828f82136aSPatrick Kelsey 	if_softc_ctx_t scctx;
2483e3c97c2cSBryan Venteicher 	int i;
2484e3c97c2cSBryan Venteicher 
24858f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
24868f82136aSPatrick Kelsey 	scctx = sc->vmx_scctx;
2487e3c97c2cSBryan Venteicher 	sc->vmx_ds->ictrl &= ~VMXNET3_ICTRL_DISABLE_ALL;
24888f82136aSPatrick Kelsey 	for (i = 0; i < scctx->isc_vectors; i++)
2489e3c97c2cSBryan Venteicher 		vmxnet3_enable_intr(sc, i);
2490e3c97c2cSBryan Venteicher }
2491e3c97c2cSBryan Venteicher 
2492e3c97c2cSBryan Venteicher static void
24938f82136aSPatrick Kelsey vmxnet3_intr_disable_all(if_ctx_t ctx)
2494e3c97c2cSBryan Venteicher {
24958f82136aSPatrick Kelsey 	struct vmxnet3_softc *sc;
2496e3c97c2cSBryan Venteicher 	int i;
2497e3c97c2cSBryan Venteicher 
24988f82136aSPatrick Kelsey 	sc = iflib_get_softc(ctx);
24998f82136aSPatrick Kelsey 	/*
25008f82136aSPatrick Kelsey 	 * iflib may invoke this routine before vmxnet3_attach_post() has
25018f82136aSPatrick Kelsey 	 * run, which is before the top level shared data area is
25028f82136aSPatrick Kelsey 	 * initialized and the device made aware of it.
25038f82136aSPatrick Kelsey 	 */
25048f82136aSPatrick Kelsey 	if (sc->vmx_ds != NULL)
2505e3c97c2cSBryan Venteicher 		sc->vmx_ds->ictrl |= VMXNET3_ICTRL_DISABLE_ALL;
25068f82136aSPatrick Kelsey 	for (i = 0; i < VMXNET3_MAX_INTRS; i++)
2507e3c97c2cSBryan Venteicher 		vmxnet3_disable_intr(sc, i);
2508e3c97c2cSBryan Venteicher }
2509e3c97c2cSBryan Venteicher 
2510e3c97c2cSBryan Venteicher /*
2511e3c97c2cSBryan Venteicher  * Since this is a purely paravirtualized device, we do not have
2512e3c97c2cSBryan Venteicher  * to worry about DMA coherency. But at times, we must make sure
2513e3c97c2cSBryan Venteicher  * both the compiler and CPU do not reorder memory operations.
2514e3c97c2cSBryan Venteicher  */
2515e3c97c2cSBryan Venteicher static inline void
2516e3c97c2cSBryan Venteicher vmxnet3_barrier(struct vmxnet3_softc *sc, vmxnet3_barrier_t type)
2517e3c97c2cSBryan Venteicher {
2518e3c97c2cSBryan Venteicher 
2519e3c97c2cSBryan Venteicher 	switch (type) {
2520e3c97c2cSBryan Venteicher 	case VMXNET3_BARRIER_RD:
2521e3c97c2cSBryan Venteicher 		rmb();
2522e3c97c2cSBryan Venteicher 		break;
2523e3c97c2cSBryan Venteicher 	case VMXNET3_BARRIER_WR:
2524e3c97c2cSBryan Venteicher 		wmb();
2525e3c97c2cSBryan Venteicher 		break;
2526e3c97c2cSBryan Venteicher 	case VMXNET3_BARRIER_RDWR:
2527e3c97c2cSBryan Venteicher 		mb();
2528e3c97c2cSBryan Venteicher 		break;
2529e3c97c2cSBryan Venteicher 	default:
2530e3c97c2cSBryan Venteicher 		panic("%s: bad barrier type %d", __func__, type);
2531e3c97c2cSBryan Venteicher 	}
2532e3c97c2cSBryan Venteicher }
2533