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>
24281cab4dSAndriy Gapon #include "opt_rss.h"
25281cab4dSAndriy Gapon
26e3c97c2cSBryan Venteicher #include <sys/param.h>
27e3c97c2cSBryan Venteicher #include <sys/systm.h>
28e3c97c2cSBryan Venteicher #include <sys/kernel.h>
29e3c97c2cSBryan Venteicher #include <sys/endian.h>
30e3c97c2cSBryan Venteicher #include <sys/sockio.h>
31e3c97c2cSBryan Venteicher #include <sys/mbuf.h>
32e3c97c2cSBryan Venteicher #include <sys/malloc.h>
33e3c97c2cSBryan Venteicher #include <sys/module.h>
34e3c97c2cSBryan Venteicher #include <sys/socket.h>
35e3c97c2cSBryan Venteicher #include <sys/sysctl.h>
36e557c1ddSBryan Venteicher #include <sys/smp.h>
37e3c97c2cSBryan Venteicher #include <vm/vm.h>
38e3c97c2cSBryan Venteicher #include <vm/pmap.h>
39e3c97c2cSBryan Venteicher
40e3c97c2cSBryan Venteicher #include <net/ethernet.h>
41e3c97c2cSBryan Venteicher #include <net/if.h>
4276039bc8SGleb Smirnoff #include <net/if_var.h>
43e3c97c2cSBryan Venteicher #include <net/if_arp.h>
44e3c97c2cSBryan Venteicher #include <net/if_dl.h>
45e3c97c2cSBryan Venteicher #include <net/if_types.h>
46e3c97c2cSBryan Venteicher #include <net/if_media.h>
47e3c97c2cSBryan Venteicher #include <net/if_vlan_var.h>
488f82136aSPatrick Kelsey #include <net/iflib.h>
49281cab4dSAndriy Gapon #ifdef RSS
50281cab4dSAndriy Gapon #include <net/rss_config.h>
51281cab4dSAndriy Gapon #endif
52e3c97c2cSBryan Venteicher
53e3c97c2cSBryan Venteicher #include <netinet/in_systm.h>
54e3c97c2cSBryan Venteicher #include <netinet/in.h>
55e3c97c2cSBryan Venteicher #include <netinet/ip.h>
56e3c97c2cSBryan Venteicher #include <netinet/ip6.h>
57e3c97c2cSBryan Venteicher #include <netinet6/ip6_var.h>
58e3c97c2cSBryan Venteicher #include <netinet/udp.h>
59e3c97c2cSBryan Venteicher #include <netinet/tcp.h>
60e3c97c2cSBryan Venteicher
61e3c97c2cSBryan Venteicher #include <machine/bus.h>
62e3c97c2cSBryan Venteicher #include <machine/resource.h>
63e3c97c2cSBryan Venteicher #include <sys/bus.h>
64e3c97c2cSBryan Venteicher #include <sys/rman.h>
65e3c97c2cSBryan Venteicher
66e3c97c2cSBryan Venteicher #include <dev/pci/pcireg.h>
67e3c97c2cSBryan Venteicher #include <dev/pci/pcivar.h>
68e3c97c2cSBryan Venteicher
698f82136aSPatrick Kelsey #include "ifdi_if.h"
708f82136aSPatrick Kelsey
71e3c97c2cSBryan Venteicher #include "if_vmxreg.h"
72e3c97c2cSBryan Venteicher #include "if_vmxvar.h"
73e3c97c2cSBryan Venteicher
74e3c97c2cSBryan Venteicher #include "opt_inet.h"
75e3c97c2cSBryan Venteicher #include "opt_inet6.h"
76e3c97c2cSBryan Venteicher
778f82136aSPatrick Kelsey #define VMXNET3_VMWARE_VENDOR_ID 0x15AD
788f82136aSPatrick Kelsey #define VMXNET3_VMWARE_DEVICE_ID 0x07B0
798f82136aSPatrick Kelsey
8051e23514SMarius Strobl static const pci_vendor_info_t vmxnet3_vendor_info_array[] =
818f82136aSPatrick Kelsey {
828f82136aSPatrick Kelsey PVID(VMXNET3_VMWARE_VENDOR_ID, VMXNET3_VMWARE_DEVICE_ID, "VMware VMXNET3 Ethernet Adapter"),
838f82136aSPatrick Kelsey /* required last entry */
848f82136aSPatrick Kelsey PVID_END
858f82136aSPatrick Kelsey };
868f82136aSPatrick Kelsey
878f82136aSPatrick Kelsey static void *vmxnet3_register(device_t);
888f82136aSPatrick Kelsey static int vmxnet3_attach_pre(if_ctx_t);
898f82136aSPatrick Kelsey static int vmxnet3_msix_intr_assign(if_ctx_t, int);
908f82136aSPatrick Kelsey static void vmxnet3_free_irqs(struct vmxnet3_softc *);
918f82136aSPatrick Kelsey static int vmxnet3_attach_post(if_ctx_t);
928f82136aSPatrick Kelsey static int vmxnet3_detach(if_ctx_t);
938f82136aSPatrick Kelsey static int vmxnet3_shutdown(if_ctx_t);
948f82136aSPatrick Kelsey static int vmxnet3_suspend(if_ctx_t);
958f82136aSPatrick Kelsey static int vmxnet3_resume(if_ctx_t);
96e3c97c2cSBryan Venteicher
97e3c97c2cSBryan Venteicher static int vmxnet3_alloc_resources(struct vmxnet3_softc *);
98e3c97c2cSBryan Venteicher static void vmxnet3_free_resources(struct vmxnet3_softc *);
99e3c97c2cSBryan Venteicher static int vmxnet3_check_version(struct vmxnet3_softc *);
1008f82136aSPatrick Kelsey static void vmxnet3_set_interrupt_idx(struct vmxnet3_softc *);
101e3c97c2cSBryan Venteicher
1028f82136aSPatrick Kelsey static int vmxnet3_queues_shared_alloc(struct vmxnet3_softc *);
1038f82136aSPatrick Kelsey static void vmxnet3_init_txq(struct vmxnet3_softc *, int);
1048f82136aSPatrick Kelsey static int vmxnet3_tx_queues_alloc(if_ctx_t, caddr_t *, uint64_t *, int, int);
1058f82136aSPatrick Kelsey static void vmxnet3_init_rxq(struct vmxnet3_softc *, int, int);
1068f82136aSPatrick Kelsey static int vmxnet3_rx_queues_alloc(if_ctx_t, caddr_t *, uint64_t *, int, int);
1078f82136aSPatrick Kelsey static void vmxnet3_queues_free(if_ctx_t);
108e3c97c2cSBryan Venteicher
109e3c97c2cSBryan Venteicher static int vmxnet3_alloc_shared_data(struct vmxnet3_softc *);
110e3c97c2cSBryan Venteicher static void vmxnet3_free_shared_data(struct vmxnet3_softc *);
111e3c97c2cSBryan Venteicher static int vmxnet3_alloc_mcast_table(struct vmxnet3_softc *);
1128f82136aSPatrick Kelsey static void vmxnet3_free_mcast_table(struct vmxnet3_softc *);
113e3c97c2cSBryan Venteicher static void vmxnet3_init_shared_data(struct vmxnet3_softc *);
114e557c1ddSBryan Venteicher static void vmxnet3_reinit_rss_shared_data(struct vmxnet3_softc *);
115e3c97c2cSBryan Venteicher static void vmxnet3_reinit_shared_data(struct vmxnet3_softc *);
116e3c97c2cSBryan Venteicher static int vmxnet3_alloc_data(struct vmxnet3_softc *);
117e3c97c2cSBryan Venteicher static void vmxnet3_free_data(struct vmxnet3_softc *);
118e3c97c2cSBryan Venteicher
119e3c97c2cSBryan Venteicher static void vmxnet3_evintr(struct vmxnet3_softc *);
1208f82136aSPatrick Kelsey static int vmxnet3_isc_txd_encap(void *, if_pkt_info_t);
1218f82136aSPatrick Kelsey static void vmxnet3_isc_txd_flush(void *, uint16_t, qidx_t);
1228f82136aSPatrick Kelsey static int vmxnet3_isc_txd_credits_update(void *, uint16_t, bool);
1238f82136aSPatrick Kelsey static int vmxnet3_isc_rxd_available(void *, uint16_t, qidx_t, qidx_t);
1248f82136aSPatrick Kelsey static int vmxnet3_isc_rxd_pkt_get(void *, if_rxd_info_t);
1258f82136aSPatrick Kelsey static void vmxnet3_isc_rxd_refill(void *, if_rxd_update_t);
1268f82136aSPatrick Kelsey static void vmxnet3_isc_rxd_flush(void *, uint16_t, uint8_t, qidx_t);
1278f82136aSPatrick Kelsey static int vmxnet3_legacy_intr(void *);
1288f82136aSPatrick Kelsey static int vmxnet3_rxq_intr(void *);
1298f82136aSPatrick Kelsey static int vmxnet3_event_intr(void *);
130e3c97c2cSBryan Venteicher
1318f82136aSPatrick Kelsey static void vmxnet3_stop(if_ctx_t);
132e3c97c2cSBryan Venteicher
133e3c97c2cSBryan Venteicher static void vmxnet3_txinit(struct vmxnet3_softc *, struct vmxnet3_txqueue *);
1348f82136aSPatrick Kelsey static void vmxnet3_rxinit(struct vmxnet3_softc *, struct vmxnet3_rxqueue *);
1358f82136aSPatrick Kelsey static void vmxnet3_reinit_queues(struct vmxnet3_softc *);
136e3c97c2cSBryan Venteicher static int vmxnet3_enable_device(struct vmxnet3_softc *);
137e3c97c2cSBryan Venteicher static void vmxnet3_reinit_rxfilters(struct vmxnet3_softc *);
1388f82136aSPatrick Kelsey static void vmxnet3_init(if_ctx_t);
1398f82136aSPatrick Kelsey static void vmxnet3_multi_set(if_ctx_t);
1408f82136aSPatrick Kelsey static int vmxnet3_mtu_set(if_ctx_t, uint32_t);
1418f82136aSPatrick Kelsey static void vmxnet3_media_status(if_ctx_t, struct ifmediareq *);
1428f82136aSPatrick Kelsey static int vmxnet3_media_change(if_ctx_t);
1438f82136aSPatrick Kelsey static int vmxnet3_promisc_set(if_ctx_t, int);
1448f82136aSPatrick Kelsey static uint64_t vmxnet3_get_counter(if_ctx_t, ift_counter);
1458f82136aSPatrick Kelsey static void vmxnet3_update_admin_status(if_ctx_t);
1468f82136aSPatrick Kelsey static void vmxnet3_txq_timer(if_ctx_t, uint16_t);
147e3c97c2cSBryan Venteicher
148e3c97c2cSBryan Venteicher static void vmxnet3_update_vlan_filter(struct vmxnet3_softc *, int,
149e3c97c2cSBryan Venteicher uint16_t);
1508f82136aSPatrick Kelsey static void vmxnet3_vlan_register(if_ctx_t, uint16_t);
1518f82136aSPatrick Kelsey static void vmxnet3_vlan_unregister(if_ctx_t, uint16_t);
1528f82136aSPatrick Kelsey static void vmxnet3_set_rxfilter(struct vmxnet3_softc *, int);
153e3c97c2cSBryan Venteicher
154e557c1ddSBryan Venteicher static void vmxnet3_refresh_host_stats(struct vmxnet3_softc *);
1558f82136aSPatrick Kelsey static int vmxnet3_link_is_up(struct vmxnet3_softc *);
156e3c97c2cSBryan Venteicher static void vmxnet3_link_status(struct vmxnet3_softc *);
157e3c97c2cSBryan Venteicher static void vmxnet3_set_lladdr(struct vmxnet3_softc *);
158e3c97c2cSBryan Venteicher static void vmxnet3_get_lladdr(struct vmxnet3_softc *);
159e3c97c2cSBryan Venteicher
160e3c97c2cSBryan Venteicher static void vmxnet3_setup_txq_sysctl(struct vmxnet3_txqueue *,
161e3c97c2cSBryan Venteicher struct sysctl_ctx_list *, struct sysctl_oid_list *);
162e3c97c2cSBryan Venteicher static void vmxnet3_setup_rxq_sysctl(struct vmxnet3_rxqueue *,
163e3c97c2cSBryan Venteicher struct sysctl_ctx_list *, struct sysctl_oid_list *);
164e3c97c2cSBryan Venteicher static void vmxnet3_setup_queue_sysctl(struct vmxnet3_softc *,
165e3c97c2cSBryan Venteicher struct sysctl_ctx_list *, struct sysctl_oid_list *);
166e3c97c2cSBryan Venteicher static void vmxnet3_setup_sysctl(struct vmxnet3_softc *);
167e3c97c2cSBryan Venteicher
168e3c97c2cSBryan Venteicher static void vmxnet3_write_bar0(struct vmxnet3_softc *, bus_size_t,
169e3c97c2cSBryan Venteicher uint32_t);
170e3c97c2cSBryan Venteicher static uint32_t vmxnet3_read_bar1(struct vmxnet3_softc *, bus_size_t);
171e3c97c2cSBryan Venteicher static void vmxnet3_write_bar1(struct vmxnet3_softc *, bus_size_t,
172e3c97c2cSBryan Venteicher uint32_t);
173e3c97c2cSBryan Venteicher static void vmxnet3_write_cmd(struct vmxnet3_softc *, uint32_t);
174e3c97c2cSBryan Venteicher static uint32_t vmxnet3_read_cmd(struct vmxnet3_softc *, uint32_t);
175e3c97c2cSBryan Venteicher
1768f82136aSPatrick Kelsey static int vmxnet3_tx_queue_intr_enable(if_ctx_t, uint16_t);
1778f82136aSPatrick Kelsey static int vmxnet3_rx_queue_intr_enable(if_ctx_t, uint16_t);
1788f82136aSPatrick Kelsey static void vmxnet3_link_intr_enable(if_ctx_t);
179e3c97c2cSBryan Venteicher static void vmxnet3_enable_intr(struct vmxnet3_softc *, int);
180e3c97c2cSBryan Venteicher static void vmxnet3_disable_intr(struct vmxnet3_softc *, int);
1818f82136aSPatrick Kelsey static void vmxnet3_intr_enable_all(if_ctx_t);
1828f82136aSPatrick Kelsey static void vmxnet3_intr_disable_all(if_ctx_t);
183b6b75424SKevin Bowling static bool vmxnet3_if_needs_restart(if_ctx_t, enum iflib_restart_event);
184e3c97c2cSBryan Venteicher
185e3c97c2cSBryan Venteicher typedef enum {
186e3c97c2cSBryan Venteicher VMXNET3_BARRIER_RD,
187e3c97c2cSBryan Venteicher VMXNET3_BARRIER_WR,
188e3c97c2cSBryan Venteicher VMXNET3_BARRIER_RDWR,
189e3c97c2cSBryan Venteicher } vmxnet3_barrier_t;
190e3c97c2cSBryan Venteicher
191e3c97c2cSBryan Venteicher static void vmxnet3_barrier(struct vmxnet3_softc *, vmxnet3_barrier_t);
192e3c97c2cSBryan Venteicher
193e3c97c2cSBryan Venteicher static device_method_t vmxnet3_methods[] = {
1948f82136aSPatrick Kelsey /* Device interface */
1958f82136aSPatrick Kelsey DEVMETHOD(device_register, vmxnet3_register),
1968f82136aSPatrick Kelsey DEVMETHOD(device_probe, iflib_device_probe),
1978f82136aSPatrick Kelsey DEVMETHOD(device_attach, iflib_device_attach),
1988f82136aSPatrick Kelsey DEVMETHOD(device_detach, iflib_device_detach),
1998f82136aSPatrick Kelsey DEVMETHOD(device_shutdown, iflib_device_shutdown),
2008f82136aSPatrick Kelsey DEVMETHOD(device_suspend, iflib_device_suspend),
2018f82136aSPatrick Kelsey DEVMETHOD(device_resume, iflib_device_resume),
202e3c97c2cSBryan Venteicher DEVMETHOD_END
203e3c97c2cSBryan Venteicher };
204e3c97c2cSBryan Venteicher
205e3c97c2cSBryan Venteicher static driver_t vmxnet3_driver = {
206e3c97c2cSBryan Venteicher "vmx", vmxnet3_methods, sizeof(struct vmxnet3_softc)
207e3c97c2cSBryan Venteicher };
208e3c97c2cSBryan Venteicher
20943df074dSJohn Baldwin DRIVER_MODULE(vmx, pci, vmxnet3_driver, 0, 0);
2108f82136aSPatrick Kelsey IFLIB_PNP_INFO(pci, vmx, vmxnet3_vendor_info_array);
2118f82136aSPatrick Kelsey MODULE_VERSION(vmx, 2);
212e3c97c2cSBryan Venteicher
213e3c97c2cSBryan Venteicher MODULE_DEPEND(vmx, pci, 1, 1, 1);
214e3c97c2cSBryan Venteicher MODULE_DEPEND(vmx, ether, 1, 1, 1);
2158f82136aSPatrick Kelsey MODULE_DEPEND(vmx, iflib, 1, 1, 1);
216e3c97c2cSBryan Venteicher
2178f82136aSPatrick Kelsey static device_method_t vmxnet3_iflib_methods[] = {
2188f82136aSPatrick Kelsey DEVMETHOD(ifdi_tx_queues_alloc, vmxnet3_tx_queues_alloc),
2198f82136aSPatrick Kelsey DEVMETHOD(ifdi_rx_queues_alloc, vmxnet3_rx_queues_alloc),
2208f82136aSPatrick Kelsey DEVMETHOD(ifdi_queues_free, vmxnet3_queues_free),
221e3c97c2cSBryan Venteicher
2228f82136aSPatrick Kelsey DEVMETHOD(ifdi_attach_pre, vmxnet3_attach_pre),
2238f82136aSPatrick Kelsey DEVMETHOD(ifdi_attach_post, vmxnet3_attach_post),
2248f82136aSPatrick Kelsey DEVMETHOD(ifdi_detach, vmxnet3_detach),
2258f82136aSPatrick Kelsey
2268f82136aSPatrick Kelsey DEVMETHOD(ifdi_init, vmxnet3_init),
2278f82136aSPatrick Kelsey DEVMETHOD(ifdi_stop, vmxnet3_stop),
2288f82136aSPatrick Kelsey DEVMETHOD(ifdi_multi_set, vmxnet3_multi_set),
2298f82136aSPatrick Kelsey DEVMETHOD(ifdi_mtu_set, vmxnet3_mtu_set),
2308f82136aSPatrick Kelsey DEVMETHOD(ifdi_media_status, vmxnet3_media_status),
2318f82136aSPatrick Kelsey DEVMETHOD(ifdi_media_change, vmxnet3_media_change),
2328f82136aSPatrick Kelsey DEVMETHOD(ifdi_promisc_set, vmxnet3_promisc_set),
2338f82136aSPatrick Kelsey DEVMETHOD(ifdi_get_counter, vmxnet3_get_counter),
2348f82136aSPatrick Kelsey DEVMETHOD(ifdi_update_admin_status, vmxnet3_update_admin_status),
2358f82136aSPatrick Kelsey DEVMETHOD(ifdi_timer, vmxnet3_txq_timer),
2368f82136aSPatrick Kelsey
2378f82136aSPatrick Kelsey DEVMETHOD(ifdi_tx_queue_intr_enable, vmxnet3_tx_queue_intr_enable),
2388f82136aSPatrick Kelsey DEVMETHOD(ifdi_rx_queue_intr_enable, vmxnet3_rx_queue_intr_enable),
2398f82136aSPatrick Kelsey DEVMETHOD(ifdi_link_intr_enable, vmxnet3_link_intr_enable),
2408f82136aSPatrick Kelsey DEVMETHOD(ifdi_intr_enable, vmxnet3_intr_enable_all),
2418f82136aSPatrick Kelsey DEVMETHOD(ifdi_intr_disable, vmxnet3_intr_disable_all),
2428f82136aSPatrick Kelsey DEVMETHOD(ifdi_msix_intr_assign, vmxnet3_msix_intr_assign),
2438f82136aSPatrick Kelsey
2448f82136aSPatrick Kelsey DEVMETHOD(ifdi_vlan_register, vmxnet3_vlan_register),
2458f82136aSPatrick Kelsey DEVMETHOD(ifdi_vlan_unregister, vmxnet3_vlan_unregister),
2468f82136aSPatrick Kelsey
2478f82136aSPatrick Kelsey DEVMETHOD(ifdi_shutdown, vmxnet3_shutdown),
2488f82136aSPatrick Kelsey DEVMETHOD(ifdi_suspend, vmxnet3_suspend),
2498f82136aSPatrick Kelsey DEVMETHOD(ifdi_resume, vmxnet3_resume),
2508f82136aSPatrick Kelsey
251b6b75424SKevin Bowling DEVMETHOD(ifdi_needs_restart, vmxnet3_if_needs_restart),
252b6b75424SKevin Bowling
2538f82136aSPatrick Kelsey DEVMETHOD_END
2548f82136aSPatrick Kelsey };
2558f82136aSPatrick Kelsey
2568f82136aSPatrick Kelsey static driver_t vmxnet3_iflib_driver = {
2578f82136aSPatrick Kelsey "vmx", vmxnet3_iflib_methods, sizeof(struct vmxnet3_softc)
2588f82136aSPatrick Kelsey };
2598f82136aSPatrick Kelsey
2608f82136aSPatrick Kelsey struct if_txrx vmxnet3_txrx = {
2618f82136aSPatrick Kelsey .ift_txd_encap = vmxnet3_isc_txd_encap,
2628f82136aSPatrick Kelsey .ift_txd_flush = vmxnet3_isc_txd_flush,
2638f82136aSPatrick Kelsey .ift_txd_credits_update = vmxnet3_isc_txd_credits_update,
2648f82136aSPatrick Kelsey .ift_rxd_available = vmxnet3_isc_rxd_available,
2658f82136aSPatrick Kelsey .ift_rxd_pkt_get = vmxnet3_isc_rxd_pkt_get,
2668f82136aSPatrick Kelsey .ift_rxd_refill = vmxnet3_isc_rxd_refill,
2678f82136aSPatrick Kelsey .ift_rxd_flush = vmxnet3_isc_rxd_flush,
2688f82136aSPatrick Kelsey .ift_legacy_intr = vmxnet3_legacy_intr
2698f82136aSPatrick Kelsey };
2708f82136aSPatrick Kelsey
2718f82136aSPatrick Kelsey static struct if_shared_ctx vmxnet3_sctx_init = {
2728f82136aSPatrick Kelsey .isc_magic = IFLIB_MAGIC,
2738f82136aSPatrick Kelsey .isc_q_align = 512,
2748f82136aSPatrick Kelsey
2758f82136aSPatrick Kelsey .isc_tx_maxsize = VMXNET3_TX_MAXSIZE,
2768f82136aSPatrick Kelsey .isc_tx_maxsegsize = VMXNET3_TX_MAXSEGSIZE,
2778f82136aSPatrick Kelsey .isc_tso_maxsize = VMXNET3_TSO_MAXSIZE + sizeof(struct ether_vlan_header),
2788f82136aSPatrick Kelsey .isc_tso_maxsegsize = VMXNET3_TX_MAXSEGSIZE,
2798f82136aSPatrick Kelsey
2808f82136aSPatrick Kelsey /*
2818f82136aSPatrick Kelsey * These values are used to configure the busdma tag used for
2828f82136aSPatrick Kelsey * receive descriptors. Each receive descriptor only points to one
2838f82136aSPatrick Kelsey * buffer.
2848f82136aSPatrick Kelsey */
2858f82136aSPatrick Kelsey .isc_rx_maxsize = VMXNET3_RX_MAXSEGSIZE, /* One buf per descriptor */
2868f82136aSPatrick Kelsey .isc_rx_nsegments = 1, /* One mapping per descriptor */
2878f82136aSPatrick Kelsey .isc_rx_maxsegsize = VMXNET3_RX_MAXSEGSIZE,
2888f82136aSPatrick Kelsey
2898f82136aSPatrick Kelsey .isc_admin_intrcnt = 1,
2908f82136aSPatrick Kelsey .isc_vendor_info = vmxnet3_vendor_info_array,
2918f82136aSPatrick Kelsey .isc_driver_version = "2",
2928f82136aSPatrick Kelsey .isc_driver = &vmxnet3_iflib_driver,
29341669133SMark Johnston .isc_flags = IFLIB_HAS_RXCQ | IFLIB_HAS_TXCQ | IFLIB_SINGLE_IRQ_RX_ONLY,
2948f82136aSPatrick Kelsey
2958f82136aSPatrick Kelsey /*
2968f82136aSPatrick Kelsey * Number of receive queues per receive queue set, with associated
2978f82136aSPatrick Kelsey * descriptor settings for each.
2988f82136aSPatrick Kelsey */
2998f82136aSPatrick Kelsey .isc_nrxqs = 3,
3008f82136aSPatrick Kelsey .isc_nfl = 2, /* one free list for each receive command queue */
3018f82136aSPatrick Kelsey .isc_nrxd_min = {VMXNET3_MIN_RX_NDESC, VMXNET3_MIN_RX_NDESC, VMXNET3_MIN_RX_NDESC},
3028f82136aSPatrick Kelsey .isc_nrxd_max = {VMXNET3_MAX_RX_NDESC, VMXNET3_MAX_RX_NDESC, VMXNET3_MAX_RX_NDESC},
3038f82136aSPatrick Kelsey .isc_nrxd_default = {VMXNET3_DEF_RX_NDESC, VMXNET3_DEF_RX_NDESC, VMXNET3_DEF_RX_NDESC},
3048f82136aSPatrick Kelsey
3058f82136aSPatrick Kelsey /*
3068f82136aSPatrick Kelsey * Number of transmit queues per transmit queue set, with associated
3078f82136aSPatrick Kelsey * descriptor settings for each.
3088f82136aSPatrick Kelsey */
3098f82136aSPatrick Kelsey .isc_ntxqs = 2,
3108f82136aSPatrick Kelsey .isc_ntxd_min = {VMXNET3_MIN_TX_NDESC, VMXNET3_MIN_TX_NDESC},
3118f82136aSPatrick Kelsey .isc_ntxd_max = {VMXNET3_MAX_TX_NDESC, VMXNET3_MAX_TX_NDESC},
3128f82136aSPatrick Kelsey .isc_ntxd_default = {VMXNET3_DEF_TX_NDESC, VMXNET3_DEF_TX_NDESC},
3138f82136aSPatrick Kelsey };
3148f82136aSPatrick Kelsey
3158f82136aSPatrick Kelsey static void *
vmxnet3_register(device_t dev)3168f82136aSPatrick Kelsey vmxnet3_register(device_t dev)
317e3c97c2cSBryan Venteicher {
3188f82136aSPatrick Kelsey return (&vmxnet3_sctx_init);
319e3c97c2cSBryan Venteicher }
320e3c97c2cSBryan Venteicher
321e3c97c2cSBryan Venteicher static int
trunc_powerof2(int val)3225d1899eeSPatrick Kelsey trunc_powerof2(int val)
3235d1899eeSPatrick Kelsey {
3245d1899eeSPatrick Kelsey
3255d1899eeSPatrick Kelsey return (1U << (fls(val) - 1));
3265d1899eeSPatrick Kelsey }
3275d1899eeSPatrick Kelsey
3285d1899eeSPatrick Kelsey static int
vmxnet3_attach_pre(if_ctx_t ctx)3298f82136aSPatrick Kelsey vmxnet3_attach_pre(if_ctx_t ctx)
330e3c97c2cSBryan Venteicher {
3318f82136aSPatrick Kelsey device_t dev;
3328f82136aSPatrick Kelsey if_softc_ctx_t scctx;
333e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc;
3348f82136aSPatrick Kelsey uint32_t intr_config;
335e3c97c2cSBryan Venteicher int error;
336e3c97c2cSBryan Venteicher
3378f82136aSPatrick Kelsey dev = iflib_get_dev(ctx);
3388f82136aSPatrick Kelsey sc = iflib_get_softc(ctx);
339e3c97c2cSBryan Venteicher sc->vmx_dev = dev;
3408f82136aSPatrick Kelsey sc->vmx_ctx = ctx;
3418f82136aSPatrick Kelsey sc->vmx_sctx = iflib_get_sctx(ctx);
3428f82136aSPatrick Kelsey sc->vmx_scctx = iflib_get_softc_ctx(ctx);
3438f82136aSPatrick Kelsey sc->vmx_ifp = iflib_get_ifp(ctx);
3448f82136aSPatrick Kelsey sc->vmx_media = iflib_get_media(ctx);
3458f82136aSPatrick Kelsey scctx = sc->vmx_scctx;
346e3c97c2cSBryan Venteicher
3478f82136aSPatrick Kelsey scctx->isc_tx_nsegments = VMXNET3_TX_MAXSEGS;
3488f82136aSPatrick Kelsey scctx->isc_tx_tso_segments_max = VMXNET3_TX_MAXSEGS;
3498f82136aSPatrick Kelsey /* isc_tx_tso_size_max doesn't include possible vlan header */
3508f82136aSPatrick Kelsey scctx->isc_tx_tso_size_max = VMXNET3_TSO_MAXSIZE;
3518f82136aSPatrick Kelsey scctx->isc_tx_tso_segsize_max = VMXNET3_TX_MAXSEGSIZE;
3528f82136aSPatrick Kelsey scctx->isc_txrx = &vmxnet3_txrx;
353e3c97c2cSBryan Venteicher
3548f82136aSPatrick Kelsey /* If 0, the iflib tunable was not set, so set to the default */
3558f82136aSPatrick Kelsey if (scctx->isc_nrxqsets == 0)
3568f82136aSPatrick Kelsey scctx->isc_nrxqsets = VMXNET3_DEF_RX_QUEUES;
3575d1899eeSPatrick Kelsey scctx->isc_nrxqsets = trunc_powerof2(scctx->isc_nrxqsets);
3588f82136aSPatrick Kelsey scctx->isc_nrxqsets_max = min(VMXNET3_MAX_RX_QUEUES, mp_ncpus);
3595d1899eeSPatrick Kelsey scctx->isc_nrxqsets_max = trunc_powerof2(scctx->isc_nrxqsets_max);
360e3c97c2cSBryan Venteicher
3618f82136aSPatrick Kelsey /* If 0, the iflib tunable was not set, so set to the default */
3628f82136aSPatrick Kelsey if (scctx->isc_ntxqsets == 0)
3638f82136aSPatrick Kelsey scctx->isc_ntxqsets = VMXNET3_DEF_TX_QUEUES;
3645d1899eeSPatrick Kelsey scctx->isc_ntxqsets = trunc_powerof2(scctx->isc_ntxqsets);
3658f82136aSPatrick Kelsey scctx->isc_ntxqsets_max = min(VMXNET3_MAX_TX_QUEUES, mp_ncpus);
3665d1899eeSPatrick Kelsey scctx->isc_ntxqsets_max = trunc_powerof2(scctx->isc_ntxqsets_max);
367e3c97c2cSBryan Venteicher
3688f82136aSPatrick Kelsey /*
3698f82136aSPatrick Kelsey * Enforce that the transmit completion queue descriptor count is
3708f82136aSPatrick Kelsey * the same as the transmit command queue descriptor count.
3718f82136aSPatrick Kelsey */
3728f82136aSPatrick Kelsey scctx->isc_ntxd[0] = scctx->isc_ntxd[1];
3738f82136aSPatrick Kelsey scctx->isc_txqsizes[0] =
3748f82136aSPatrick Kelsey sizeof(struct vmxnet3_txcompdesc) * scctx->isc_ntxd[0];
3758f82136aSPatrick Kelsey scctx->isc_txqsizes[1] =
3768f82136aSPatrick Kelsey sizeof(struct vmxnet3_txdesc) * scctx->isc_ntxd[1];
3778f82136aSPatrick Kelsey
3788f82136aSPatrick Kelsey /*
3798f82136aSPatrick Kelsey * Enforce that the receive completion queue descriptor count is the
3808f82136aSPatrick Kelsey * sum of the receive command queue descriptor counts, and that the
3818f82136aSPatrick Kelsey * second receive command queue descriptor count is the same as the
3828f82136aSPatrick Kelsey * first one.
3838f82136aSPatrick Kelsey */
3848f82136aSPatrick Kelsey scctx->isc_nrxd[2] = scctx->isc_nrxd[1];
3858f82136aSPatrick Kelsey scctx->isc_nrxd[0] = scctx->isc_nrxd[1] + scctx->isc_nrxd[2];
3868f82136aSPatrick Kelsey scctx->isc_rxqsizes[0] =
3878f82136aSPatrick Kelsey sizeof(struct vmxnet3_rxcompdesc) * scctx->isc_nrxd[0];
3888f82136aSPatrick Kelsey scctx->isc_rxqsizes[1] =
3898f82136aSPatrick Kelsey sizeof(struct vmxnet3_rxdesc) * scctx->isc_nrxd[1];
3908f82136aSPatrick Kelsey scctx->isc_rxqsizes[2] =
3918f82136aSPatrick Kelsey sizeof(struct vmxnet3_rxdesc) * scctx->isc_nrxd[2];
3928f82136aSPatrick Kelsey
3931342c8c6SPatrick Kelsey /*
3941342c8c6SPatrick Kelsey * Initialize the max frame size and descriptor queue buffer
3951342c8c6SPatrick Kelsey * sizes.
3961342c8c6SPatrick Kelsey */
3971342c8c6SPatrick Kelsey vmxnet3_mtu_set(ctx, if_getmtu(sc->vmx_ifp));
3981342c8c6SPatrick Kelsey
3998f82136aSPatrick Kelsey scctx->isc_rss_table_size = UPT1_RSS_MAX_IND_TABLE_SIZE;
4008f82136aSPatrick Kelsey
4018f82136aSPatrick Kelsey /* Map PCI BARs */
402e3c97c2cSBryan Venteicher error = vmxnet3_alloc_resources(sc);
403e3c97c2cSBryan Venteicher if (error)
404e3c97c2cSBryan Venteicher goto fail;
405e3c97c2cSBryan Venteicher
4068f82136aSPatrick Kelsey /* Check device versions */
407e3c97c2cSBryan Venteicher error = vmxnet3_check_version(sc);
408e3c97c2cSBryan Venteicher if (error)
409e3c97c2cSBryan Venteicher goto fail;
410e3c97c2cSBryan Venteicher
4118f82136aSPatrick Kelsey /*
4128f82136aSPatrick Kelsey * The interrupt mode can be set in the hypervisor configuration via
4138f82136aSPatrick Kelsey * the parameter ethernet<N>.intrMode.
4148f82136aSPatrick Kelsey */
4158f82136aSPatrick Kelsey intr_config = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_INTRCFG);
4168f82136aSPatrick Kelsey sc->vmx_intr_mask_mode = (intr_config >> 2) & 0x03;
417e3c97c2cSBryan Venteicher
4188f82136aSPatrick Kelsey /*
4198f82136aSPatrick Kelsey * Configure the softc context to attempt to configure the interrupt
4208f82136aSPatrick Kelsey * mode now indicated by intr_config. iflib will follow the usual
421b97de13aSMarius Strobl * fallback path MSI-X -> MSI -> LEGACY, starting at the configured
4228f82136aSPatrick Kelsey * starting mode.
4238f82136aSPatrick Kelsey */
4248f82136aSPatrick Kelsey switch (intr_config & 0x03) {
4258f82136aSPatrick Kelsey case VMXNET3_IT_AUTO:
4268f82136aSPatrick Kelsey case VMXNET3_IT_MSIX:
4278f82136aSPatrick Kelsey scctx->isc_msix_bar = pci_msix_table_bar(dev);
4288f82136aSPatrick Kelsey break;
4298f82136aSPatrick Kelsey case VMXNET3_IT_MSI:
4308f82136aSPatrick Kelsey scctx->isc_msix_bar = -1;
4318f82136aSPatrick Kelsey scctx->isc_disable_msix = 1;
4328f82136aSPatrick Kelsey break;
4338f82136aSPatrick Kelsey case VMXNET3_IT_LEGACY:
4348f82136aSPatrick Kelsey scctx->isc_msix_bar = 0;
4358f82136aSPatrick Kelsey break;
436e3c97c2cSBryan Venteicher }
437e3c97c2cSBryan Venteicher
4388f82136aSPatrick Kelsey scctx->isc_tx_csum_flags = VMXNET3_CSUM_ALL_OFFLOAD;
4398f82136aSPatrick Kelsey scctx->isc_capabilities = scctx->isc_capenable =
4408f82136aSPatrick Kelsey IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6 |
4418f82136aSPatrick Kelsey IFCAP_TSO4 | IFCAP_TSO6 |
4428f82136aSPatrick Kelsey IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6 |
4438f82136aSPatrick Kelsey IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING |
4448f82136aSPatrick Kelsey IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO |
4458f82136aSPatrick Kelsey IFCAP_JUMBO_MTU;
446e3c97c2cSBryan Venteicher
4478f82136aSPatrick Kelsey /* These capabilities are not enabled by default. */
4488f82136aSPatrick Kelsey scctx->isc_capabilities |= IFCAP_LRO | IFCAP_VLAN_HWFILTER;
4498f82136aSPatrick Kelsey
4508f82136aSPatrick Kelsey vmxnet3_get_lladdr(sc);
4518f82136aSPatrick Kelsey iflib_set_mac(ctx, sc->vmx_lladdr);
4528f82136aSPatrick Kelsey
4538f82136aSPatrick Kelsey return (0);
454e3c97c2cSBryan Venteicher fail:
4558f82136aSPatrick Kelsey /*
4568f82136aSPatrick Kelsey * We must completely clean up anything allocated above as iflib
4578f82136aSPatrick Kelsey * will not invoke any other driver entry points as a result of this
4588f82136aSPatrick Kelsey * failure.
4598f82136aSPatrick Kelsey */
4608f82136aSPatrick Kelsey vmxnet3_free_resources(sc);
461e3c97c2cSBryan Venteicher
462e3c97c2cSBryan Venteicher return (error);
463e3c97c2cSBryan Venteicher }
464e3c97c2cSBryan Venteicher
465e3c97c2cSBryan Venteicher static int
vmxnet3_msix_intr_assign(if_ctx_t ctx,int msix)4668f82136aSPatrick Kelsey vmxnet3_msix_intr_assign(if_ctx_t ctx, int msix)
467e3c97c2cSBryan Venteicher {
468e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc;
4698f82136aSPatrick Kelsey if_softc_ctx_t scctx;
4708f82136aSPatrick Kelsey struct vmxnet3_rxqueue *rxq;
4718f82136aSPatrick Kelsey int error;
4728f82136aSPatrick Kelsey int i;
4738f82136aSPatrick Kelsey char irq_name[16];
474e3c97c2cSBryan Venteicher
4758f82136aSPatrick Kelsey sc = iflib_get_softc(ctx);
4768f82136aSPatrick Kelsey scctx = sc->vmx_scctx;
477e3c97c2cSBryan Venteicher
4788f82136aSPatrick Kelsey for (i = 0; i < scctx->isc_nrxqsets; i++) {
4798f82136aSPatrick Kelsey snprintf(irq_name, sizeof(irq_name), "rxq%d", i);
480e557c1ddSBryan Venteicher
4818f82136aSPatrick Kelsey rxq = &sc->vmx_rxq[i];
4828f82136aSPatrick Kelsey error = iflib_irq_alloc_generic(ctx, &rxq->vxrxq_irq, i + 1,
48381be6552SMatt Macy IFLIB_INTR_RXTX, vmxnet3_rxq_intr, rxq, i, irq_name);
4848f82136aSPatrick Kelsey if (error) {
4858f82136aSPatrick Kelsey device_printf(iflib_get_dev(ctx),
4868f82136aSPatrick Kelsey "Failed to register rxq %d interrupt handler\n", i);
4878f82136aSPatrick Kelsey return (error);
4888f82136aSPatrick Kelsey }
489e3c97c2cSBryan Venteicher }
490e3c97c2cSBryan Venteicher
4918f82136aSPatrick Kelsey for (i = 0; i < scctx->isc_ntxqsets; i++) {
4928f82136aSPatrick Kelsey snprintf(irq_name, sizeof(irq_name), "txq%d", i);
4938f82136aSPatrick Kelsey
4948f82136aSPatrick Kelsey /*
4958f82136aSPatrick Kelsey * Don't provide the corresponding rxq irq for reference -
4968f82136aSPatrick Kelsey * we want the transmit task to be attached to a task queue
4978f82136aSPatrick Kelsey * that is different from the one used by the corresponding
4988f82136aSPatrick Kelsey * rxq irq. That is because the TX doorbell writes are very
4998f82136aSPatrick Kelsey * expensive as virtualized MMIO operations, so we want to
5008f82136aSPatrick Kelsey * be able to defer them to another core when possible so
5018f82136aSPatrick Kelsey * that they don't steal receive processing cycles during
5028f82136aSPatrick Kelsey * stack turnarounds like TCP ACK generation. The other
5038f82136aSPatrick Kelsey * piece to this approach is enabling the iflib abdicate
5048f82136aSPatrick Kelsey * option (currently via an interface-specific
5058f82136aSPatrick Kelsey * tunable/sysctl).
5068f82136aSPatrick Kelsey */
5078f82136aSPatrick Kelsey iflib_softirq_alloc_generic(ctx, NULL, IFLIB_INTR_TX, NULL, i,
5088f82136aSPatrick Kelsey irq_name);
509e3c97c2cSBryan Venteicher }
510e3c97c2cSBryan Venteicher
5118f82136aSPatrick Kelsey error = iflib_irq_alloc_generic(ctx, &sc->vmx_event_intr_irq,
5128f82136aSPatrick Kelsey scctx->isc_nrxqsets + 1, IFLIB_INTR_ADMIN, vmxnet3_event_intr, sc, 0,
5138f82136aSPatrick Kelsey "event");
5148f82136aSPatrick Kelsey if (error) {
5158f82136aSPatrick Kelsey device_printf(iflib_get_dev(ctx),
5168f82136aSPatrick Kelsey "Failed to register event interrupt handler\n");
5178f82136aSPatrick Kelsey return (error);
518e3c97c2cSBryan Venteicher }
519e3c97c2cSBryan Venteicher
5208f82136aSPatrick Kelsey return (0);
5218f82136aSPatrick Kelsey }
522e3c97c2cSBryan Venteicher
5238f82136aSPatrick Kelsey static void
vmxnet3_free_irqs(struct vmxnet3_softc * sc)5248f82136aSPatrick Kelsey vmxnet3_free_irqs(struct vmxnet3_softc *sc)
5258f82136aSPatrick Kelsey {
5268f82136aSPatrick Kelsey if_softc_ctx_t scctx;
5278f82136aSPatrick Kelsey struct vmxnet3_rxqueue *rxq;
5288f82136aSPatrick Kelsey int i;
5298f82136aSPatrick Kelsey
5308f82136aSPatrick Kelsey scctx = sc->vmx_scctx;
5318f82136aSPatrick Kelsey
5328f82136aSPatrick Kelsey for (i = 0; i < scctx->isc_nrxqsets; i++) {
5338f82136aSPatrick Kelsey rxq = &sc->vmx_rxq[i];
5348f82136aSPatrick Kelsey iflib_irq_free(sc->vmx_ctx, &rxq->vxrxq_irq);
5358f82136aSPatrick Kelsey }
5368f82136aSPatrick Kelsey
5378f82136aSPatrick Kelsey iflib_irq_free(sc->vmx_ctx, &sc->vmx_event_intr_irq);
5388f82136aSPatrick Kelsey }
5398f82136aSPatrick Kelsey
5408f82136aSPatrick Kelsey static int
vmxnet3_attach_post(if_ctx_t ctx)5418f82136aSPatrick Kelsey vmxnet3_attach_post(if_ctx_t ctx)
5428f82136aSPatrick Kelsey {
5438f82136aSPatrick Kelsey if_softc_ctx_t scctx;
5448f82136aSPatrick Kelsey struct vmxnet3_softc *sc;
5458f82136aSPatrick Kelsey int error;
5468f82136aSPatrick Kelsey
5478f82136aSPatrick Kelsey scctx = iflib_get_softc_ctx(ctx);
5488f82136aSPatrick Kelsey sc = iflib_get_softc(ctx);
5498f82136aSPatrick Kelsey
5508f82136aSPatrick Kelsey if (scctx->isc_nrxqsets > 1)
5518f82136aSPatrick Kelsey sc->vmx_flags |= VMXNET3_FLAG_RSS;
5528f82136aSPatrick Kelsey
5538f82136aSPatrick Kelsey error = vmxnet3_alloc_data(sc);
5548f82136aSPatrick Kelsey if (error)
5558f82136aSPatrick Kelsey goto fail;
5568f82136aSPatrick Kelsey
5578f82136aSPatrick Kelsey vmxnet3_set_interrupt_idx(sc);
5588f82136aSPatrick Kelsey vmxnet3_setup_sysctl(sc);
5598f82136aSPatrick Kelsey
5608f82136aSPatrick Kelsey ifmedia_add(sc->vmx_media, IFM_ETHER | IFM_AUTO, 0, NULL);
5618f82136aSPatrick Kelsey ifmedia_set(sc->vmx_media, IFM_ETHER | IFM_AUTO);
5628f82136aSPatrick Kelsey
5638f82136aSPatrick Kelsey fail:
5648f82136aSPatrick Kelsey return (error);
5658f82136aSPatrick Kelsey }
5668f82136aSPatrick Kelsey
5678f82136aSPatrick Kelsey static int
vmxnet3_detach(if_ctx_t ctx)5688f82136aSPatrick Kelsey vmxnet3_detach(if_ctx_t ctx)
5698f82136aSPatrick Kelsey {
5708f82136aSPatrick Kelsey struct vmxnet3_softc *sc;
5718f82136aSPatrick Kelsey
5728f82136aSPatrick Kelsey sc = iflib_get_softc(ctx);
5738f82136aSPatrick Kelsey
5748f82136aSPatrick Kelsey vmxnet3_free_irqs(sc);
575e3c97c2cSBryan Venteicher vmxnet3_free_data(sc);
576e3c97c2cSBryan Venteicher vmxnet3_free_resources(sc);
577e3c97c2cSBryan Venteicher
578e3c97c2cSBryan Venteicher return (0);
579e3c97c2cSBryan Venteicher }
580e3c97c2cSBryan Venteicher
581e3c97c2cSBryan Venteicher static int
vmxnet3_shutdown(if_ctx_t ctx)5828f82136aSPatrick Kelsey vmxnet3_shutdown(if_ctx_t ctx)
5838f82136aSPatrick Kelsey {
5848f82136aSPatrick Kelsey
5858f82136aSPatrick Kelsey return (0);
5868f82136aSPatrick Kelsey }
5878f82136aSPatrick Kelsey
5888f82136aSPatrick Kelsey static int
vmxnet3_suspend(if_ctx_t ctx)5898f82136aSPatrick Kelsey vmxnet3_suspend(if_ctx_t ctx)
5908f82136aSPatrick Kelsey {
5918f82136aSPatrick Kelsey
5928f82136aSPatrick Kelsey return (0);
5938f82136aSPatrick Kelsey }
5948f82136aSPatrick Kelsey
5958f82136aSPatrick Kelsey static int
vmxnet3_resume(if_ctx_t ctx)5968f82136aSPatrick Kelsey vmxnet3_resume(if_ctx_t ctx)
597e3c97c2cSBryan Venteicher {
598e3c97c2cSBryan Venteicher
599e3c97c2cSBryan Venteicher return (0);
600e3c97c2cSBryan Venteicher }
601e3c97c2cSBryan Venteicher
602e3c97c2cSBryan Venteicher static int
vmxnet3_alloc_resources(struct vmxnet3_softc * sc)603e3c97c2cSBryan Venteicher vmxnet3_alloc_resources(struct vmxnet3_softc *sc)
604e3c97c2cSBryan Venteicher {
605e3c97c2cSBryan Venteicher device_t dev;
606e3c97c2cSBryan Venteicher int rid;
607e3c97c2cSBryan Venteicher
608e3c97c2cSBryan Venteicher dev = sc->vmx_dev;
609e3c97c2cSBryan Venteicher
610e3c97c2cSBryan Venteicher rid = PCIR_BAR(0);
611e3c97c2cSBryan Venteicher sc->vmx_res0 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
612e3c97c2cSBryan Venteicher RF_ACTIVE);
613e3c97c2cSBryan Venteicher if (sc->vmx_res0 == NULL) {
614e3c97c2cSBryan Venteicher device_printf(dev,
615e3c97c2cSBryan Venteicher "could not map BAR0 memory\n");
616e3c97c2cSBryan Venteicher return (ENXIO);
617e3c97c2cSBryan Venteicher }
618e3c97c2cSBryan Venteicher
619e3c97c2cSBryan Venteicher sc->vmx_iot0 = rman_get_bustag(sc->vmx_res0);
620e3c97c2cSBryan Venteicher sc->vmx_ioh0 = rman_get_bushandle(sc->vmx_res0);
621e3c97c2cSBryan Venteicher
622e3c97c2cSBryan Venteicher rid = PCIR_BAR(1);
623e3c97c2cSBryan Venteicher sc->vmx_res1 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
624e3c97c2cSBryan Venteicher RF_ACTIVE);
625e3c97c2cSBryan Venteicher if (sc->vmx_res1 == NULL) {
626e3c97c2cSBryan Venteicher device_printf(dev,
627e3c97c2cSBryan Venteicher "could not map BAR1 memory\n");
628e3c97c2cSBryan Venteicher return (ENXIO);
629e3c97c2cSBryan Venteicher }
630e3c97c2cSBryan Venteicher
631e3c97c2cSBryan Venteicher sc->vmx_iot1 = rman_get_bustag(sc->vmx_res1);
632e3c97c2cSBryan Venteicher sc->vmx_ioh1 = rman_get_bushandle(sc->vmx_res1);
633e3c97c2cSBryan Venteicher
634e3c97c2cSBryan Venteicher return (0);
635e3c97c2cSBryan Venteicher }
636e3c97c2cSBryan Venteicher
637e3c97c2cSBryan Venteicher static void
vmxnet3_free_resources(struct vmxnet3_softc * sc)638e3c97c2cSBryan Venteicher vmxnet3_free_resources(struct vmxnet3_softc *sc)
639e3c97c2cSBryan Venteicher {
640e3c97c2cSBryan Venteicher device_t dev;
641e3c97c2cSBryan Venteicher
642e3c97c2cSBryan Venteicher dev = sc->vmx_dev;
643e3c97c2cSBryan Venteicher
644e3c97c2cSBryan Venteicher if (sc->vmx_res0 != NULL) {
645b97de13aSMarius Strobl bus_release_resource(dev, SYS_RES_MEMORY,
646b97de13aSMarius Strobl rman_get_rid(sc->vmx_res0), sc->vmx_res0);
647e3c97c2cSBryan Venteicher sc->vmx_res0 = NULL;
648e3c97c2cSBryan Venteicher }
649e3c97c2cSBryan Venteicher
650e3c97c2cSBryan Venteicher if (sc->vmx_res1 != NULL) {
651b97de13aSMarius Strobl bus_release_resource(dev, SYS_RES_MEMORY,
652b97de13aSMarius Strobl rman_get_rid(sc->vmx_res1), sc->vmx_res1);
653e3c97c2cSBryan Venteicher sc->vmx_res1 = NULL;
654e3c97c2cSBryan Venteicher }
655e3c97c2cSBryan Venteicher }
656e3c97c2cSBryan Venteicher
657e3c97c2cSBryan Venteicher static int
vmxnet3_check_version(struct vmxnet3_softc * sc)658e3c97c2cSBryan Venteicher vmxnet3_check_version(struct vmxnet3_softc *sc)
659e3c97c2cSBryan Venteicher {
660e3c97c2cSBryan Venteicher device_t dev;
661e3c97c2cSBryan Venteicher uint32_t version;
662e3c97c2cSBryan Venteicher
663e3c97c2cSBryan Venteicher dev = sc->vmx_dev;
664e3c97c2cSBryan Venteicher
665e3c97c2cSBryan Venteicher version = vmxnet3_read_bar1(sc, VMXNET3_BAR1_VRRS);
666e3c97c2cSBryan Venteicher if ((version & 0x01) == 0) {
667e3c97c2cSBryan Venteicher device_printf(dev, "unsupported hardware version %#x\n",
668e3c97c2cSBryan Venteicher version);
669e3c97c2cSBryan Venteicher return (ENOTSUP);
6703c965775SBryan Venteicher }
671e3c97c2cSBryan Venteicher vmxnet3_write_bar1(sc, VMXNET3_BAR1_VRRS, 1);
672e3c97c2cSBryan Venteicher
673e3c97c2cSBryan Venteicher version = vmxnet3_read_bar1(sc, VMXNET3_BAR1_UVRS);
674e3c97c2cSBryan Venteicher if ((version & 0x01) == 0) {
675e3c97c2cSBryan Venteicher device_printf(dev, "unsupported UPT version %#x\n", version);
676e3c97c2cSBryan Venteicher return (ENOTSUP);
6773c965775SBryan Venteicher }
678e3c97c2cSBryan Venteicher vmxnet3_write_bar1(sc, VMXNET3_BAR1_UVRS, 1);
679e3c97c2cSBryan Venteicher
680e3c97c2cSBryan Venteicher return (0);
681e3c97c2cSBryan Venteicher }
682e3c97c2cSBryan Venteicher
683e3c97c2cSBryan Venteicher static void
vmxnet3_set_interrupt_idx(struct vmxnet3_softc * sc)684e3c97c2cSBryan Venteicher vmxnet3_set_interrupt_idx(struct vmxnet3_softc *sc)
685e3c97c2cSBryan Venteicher {
6868f82136aSPatrick Kelsey if_softc_ctx_t scctx;
687e3c97c2cSBryan Venteicher struct vmxnet3_txqueue *txq;
688e3c97c2cSBryan Venteicher struct vmxnet3_txq_shared *txs;
689e3c97c2cSBryan Venteicher struct vmxnet3_rxqueue *rxq;
690e3c97c2cSBryan Venteicher struct vmxnet3_rxq_shared *rxs;
6918f82136aSPatrick Kelsey int intr_idx;
692e3c97c2cSBryan Venteicher int i;
693e3c97c2cSBryan Venteicher
6948f82136aSPatrick Kelsey scctx = sc->vmx_scctx;
695e3c97c2cSBryan Venteicher
6968f82136aSPatrick Kelsey /*
697769d56ecSPatrick Kelsey * There is always one interrupt per receive queue, assigned
698769d56ecSPatrick Kelsey * starting with the first interrupt. When there is only one
699769d56ecSPatrick Kelsey * interrupt available, the event interrupt shares the receive queue
700769d56ecSPatrick Kelsey * interrupt, otherwise it uses the interrupt following the last
701769d56ecSPatrick Kelsey * receive queue interrupt. Transmit queues are not assigned
702769d56ecSPatrick Kelsey * interrupts, so they are given indexes beyond the indexes that
703769d56ecSPatrick Kelsey * correspond to the real interrupts.
7048f82136aSPatrick Kelsey */
705769d56ecSPatrick Kelsey
706769d56ecSPatrick Kelsey /* The event interrupt is always the last vector. */
7078f82136aSPatrick Kelsey sc->vmx_event_intr_idx = scctx->isc_vectors - 1;
708e3c97c2cSBryan Venteicher
7098f82136aSPatrick Kelsey intr_idx = 0;
7108f82136aSPatrick Kelsey for (i = 0; i < scctx->isc_nrxqsets; i++, intr_idx++) {
711e3c97c2cSBryan Venteicher rxq = &sc->vmx_rxq[i];
712e3c97c2cSBryan Venteicher rxs = rxq->vxrxq_rs;
7138f82136aSPatrick Kelsey rxq->vxrxq_intr_idx = intr_idx;
714e3c97c2cSBryan Venteicher rxs->intr_idx = rxq->vxrxq_intr_idx;
715e3c97c2cSBryan Venteicher }
7168f82136aSPatrick Kelsey
7178f82136aSPatrick Kelsey /*
7188f82136aSPatrick Kelsey * Assign the tx queues interrupt indexes above what we are actually
7198f82136aSPatrick Kelsey * using. These interrupts will never be enabled.
7208f82136aSPatrick Kelsey */
7218f82136aSPatrick Kelsey intr_idx = scctx->isc_vectors;
7228f82136aSPatrick Kelsey for (i = 0; i < scctx->isc_ntxqsets; i++, intr_idx++) {
7238f82136aSPatrick Kelsey txq = &sc->vmx_txq[i];
7248f82136aSPatrick Kelsey txs = txq->vxtxq_ts;
7258f82136aSPatrick Kelsey txq->vxtxq_intr_idx = intr_idx;
7268f82136aSPatrick Kelsey txs->intr_idx = txq->vxtxq_intr_idx;
7278f82136aSPatrick Kelsey }
728e3c97c2cSBryan Venteicher }
729e3c97c2cSBryan Venteicher
730e3c97c2cSBryan Venteicher static int
vmxnet3_queues_shared_alloc(struct vmxnet3_softc * sc)7318f82136aSPatrick Kelsey vmxnet3_queues_shared_alloc(struct vmxnet3_softc *sc)
732e3c97c2cSBryan Venteicher {
7338f82136aSPatrick Kelsey if_softc_ctx_t scctx;
7348f82136aSPatrick Kelsey int size;
735e3c97c2cSBryan Venteicher int error;
736e3c97c2cSBryan Venteicher
7378f82136aSPatrick Kelsey scctx = sc->vmx_scctx;
738e3c97c2cSBryan Venteicher
7398f82136aSPatrick Kelsey /*
7408f82136aSPatrick Kelsey * The txq and rxq shared data areas must be allocated contiguously
7418f82136aSPatrick Kelsey * as vmxnet3_driver_shared contains only a single address member
7428f82136aSPatrick Kelsey * for the shared queue data area.
7438f82136aSPatrick Kelsey */
7448f82136aSPatrick Kelsey size = scctx->isc_ntxqsets * sizeof(struct vmxnet3_txq_shared) +
7458f82136aSPatrick Kelsey scctx->isc_nrxqsets * sizeof(struct vmxnet3_rxq_shared);
7468f82136aSPatrick Kelsey error = iflib_dma_alloc_align(sc->vmx_ctx, size, 128, &sc->vmx_qs_dma, 0);
7478f82136aSPatrick Kelsey if (error) {
7488f82136aSPatrick Kelsey device_printf(sc->vmx_dev, "cannot alloc queue shared memory\n");
749e3c97c2cSBryan Venteicher return (error);
750e3c97c2cSBryan Venteicher }
751e3c97c2cSBryan Venteicher
752e557c1ddSBryan Venteicher return (0);
753e557c1ddSBryan Venteicher }
754e557c1ddSBryan Venteicher
755e557c1ddSBryan Venteicher static void
vmxnet3_init_txq(struct vmxnet3_softc * sc,int q)7568f82136aSPatrick Kelsey vmxnet3_init_txq(struct vmxnet3_softc *sc, int q)
757e557c1ddSBryan Venteicher {
758e557c1ddSBryan Venteicher struct vmxnet3_txqueue *txq;
7598f82136aSPatrick Kelsey struct vmxnet3_comp_ring *txc;
7608f82136aSPatrick Kelsey struct vmxnet3_txring *txr;
7618f82136aSPatrick Kelsey if_softc_ctx_t scctx;
762e557c1ddSBryan Venteicher
7638f82136aSPatrick Kelsey txq = &sc->vmx_txq[q];
7648f82136aSPatrick Kelsey txc = &txq->vxtxq_comp_ring;
7658f82136aSPatrick Kelsey txr = &txq->vxtxq_cmd_ring;
7668f82136aSPatrick Kelsey scctx = sc->vmx_scctx;
7678f82136aSPatrick Kelsey
7688f82136aSPatrick Kelsey snprintf(txq->vxtxq_name, sizeof(txq->vxtxq_name), "%s-tx%d",
7698f82136aSPatrick Kelsey device_get_nameunit(sc->vmx_dev), q);
7708f82136aSPatrick Kelsey
7718f82136aSPatrick Kelsey txq->vxtxq_sc = sc;
7728f82136aSPatrick Kelsey txq->vxtxq_id = q;
7738f82136aSPatrick Kelsey txc->vxcr_ndesc = scctx->isc_ntxd[0];
7748f82136aSPatrick Kelsey txr->vxtxr_ndesc = scctx->isc_ntxd[1];
775e557c1ddSBryan Venteicher }
7768f82136aSPatrick Kelsey
7778f82136aSPatrick Kelsey static int
vmxnet3_tx_queues_alloc(if_ctx_t ctx,caddr_t * vaddrs,uint64_t * paddrs,int ntxqs,int ntxqsets)7788f82136aSPatrick Kelsey vmxnet3_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
7798f82136aSPatrick Kelsey int ntxqs, int ntxqsets)
7808f82136aSPatrick Kelsey {
7818f82136aSPatrick Kelsey struct vmxnet3_softc *sc;
7828f82136aSPatrick Kelsey int q;
7838f82136aSPatrick Kelsey int error;
7848f82136aSPatrick Kelsey caddr_t kva;
7858f82136aSPatrick Kelsey
7868f82136aSPatrick Kelsey sc = iflib_get_softc(ctx);
7878f82136aSPatrick Kelsey
7888f82136aSPatrick Kelsey /* Allocate the array of transmit queues */
7898f82136aSPatrick Kelsey sc->vmx_txq = malloc(sizeof(struct vmxnet3_txqueue) *
7908f82136aSPatrick Kelsey ntxqsets, M_DEVBUF, M_NOWAIT | M_ZERO);
7918f82136aSPatrick Kelsey if (sc->vmx_txq == NULL)
7928f82136aSPatrick Kelsey return (ENOMEM);
7938f82136aSPatrick Kelsey
7948f82136aSPatrick Kelsey /* Initialize driver state for each transmit queue */
7958f82136aSPatrick Kelsey for (q = 0; q < ntxqsets; q++)
7968f82136aSPatrick Kelsey vmxnet3_init_txq(sc, q);
7978f82136aSPatrick Kelsey
7988f82136aSPatrick Kelsey /*
7998f82136aSPatrick Kelsey * Allocate queue state that is shared with the device. This check
8008f82136aSPatrick Kelsey * and call is performed in both vmxnet3_tx_queues_alloc() and
8018f82136aSPatrick Kelsey * vmxnet3_rx_queues_alloc() so that we don't have to care which
8028f82136aSPatrick Kelsey * order iflib invokes those routines in.
8038f82136aSPatrick Kelsey */
8048f82136aSPatrick Kelsey if (sc->vmx_qs_dma.idi_size == 0) {
8058f82136aSPatrick Kelsey error = vmxnet3_queues_shared_alloc(sc);
8068f82136aSPatrick Kelsey if (error)
8078f82136aSPatrick Kelsey return (error);
808e557c1ddSBryan Venteicher }
8098f82136aSPatrick Kelsey
8108f82136aSPatrick Kelsey kva = sc->vmx_qs_dma.idi_vaddr;
8118f82136aSPatrick Kelsey for (q = 0; q < ntxqsets; q++) {
8128f82136aSPatrick Kelsey sc->vmx_txq[q].vxtxq_ts = (struct vmxnet3_txq_shared *) kva;
8138f82136aSPatrick Kelsey kva += sizeof(struct vmxnet3_txq_shared);
8148f82136aSPatrick Kelsey }
8158f82136aSPatrick Kelsey
8168f82136aSPatrick Kelsey /* Record descriptor ring vaddrs and paddrs */
8178f82136aSPatrick Kelsey for (q = 0; q < ntxqsets; q++) {
8188f82136aSPatrick Kelsey struct vmxnet3_txqueue *txq;
8198f82136aSPatrick Kelsey struct vmxnet3_txring *txr;
8208f82136aSPatrick Kelsey struct vmxnet3_comp_ring *txc;
8218f82136aSPatrick Kelsey
8228f82136aSPatrick Kelsey txq = &sc->vmx_txq[q];
8238f82136aSPatrick Kelsey txc = &txq->vxtxq_comp_ring;
8248f82136aSPatrick Kelsey txr = &txq->vxtxq_cmd_ring;
8258f82136aSPatrick Kelsey
8268f82136aSPatrick Kelsey /* Completion ring */
8278f82136aSPatrick Kelsey txc->vxcr_u.txcd =
8288f82136aSPatrick Kelsey (struct vmxnet3_txcompdesc *) vaddrs[q * ntxqs + 0];
8298f82136aSPatrick Kelsey txc->vxcr_paddr = paddrs[q * ntxqs + 0];
8308f82136aSPatrick Kelsey
8318f82136aSPatrick Kelsey /* Command ring */
8328f82136aSPatrick Kelsey txr->vxtxr_txd =
8338f82136aSPatrick Kelsey (struct vmxnet3_txdesc *) vaddrs[q * ntxqs + 1];
8348f82136aSPatrick Kelsey txr->vxtxr_paddr = paddrs[q * ntxqs + 1];
8358f82136aSPatrick Kelsey }
8368f82136aSPatrick Kelsey
8378f82136aSPatrick Kelsey return (0);
838e557c1ddSBryan Venteicher }
839e557c1ddSBryan Venteicher
840e557c1ddSBryan Venteicher static void
vmxnet3_init_rxq(struct vmxnet3_softc * sc,int q,int nrxqs)8418f82136aSPatrick Kelsey vmxnet3_init_rxq(struct vmxnet3_softc *sc, int q, int nrxqs)
842e3c97c2cSBryan Venteicher {
843e3c97c2cSBryan Venteicher struct vmxnet3_rxqueue *rxq;
8448f82136aSPatrick Kelsey struct vmxnet3_comp_ring *rxc;
845e3c97c2cSBryan Venteicher struct vmxnet3_rxring *rxr;
8468f82136aSPatrick Kelsey if_softc_ctx_t scctx;
847e3c97c2cSBryan Venteicher int i;
848e3c97c2cSBryan Venteicher
849e3c97c2cSBryan Venteicher rxq = &sc->vmx_rxq[q];
8508f82136aSPatrick Kelsey rxc = &rxq->vxrxq_comp_ring;
8518f82136aSPatrick Kelsey scctx = sc->vmx_scctx;
852e3c97c2cSBryan Venteicher
853e3c97c2cSBryan Venteicher snprintf(rxq->vxrxq_name, sizeof(rxq->vxrxq_name), "%s-rx%d",
854e3c97c2cSBryan Venteicher device_get_nameunit(sc->vmx_dev), q);
855e3c97c2cSBryan Venteicher
856e3c97c2cSBryan Venteicher rxq->vxrxq_sc = sc;
857e3c97c2cSBryan Venteicher rxq->vxrxq_id = q;
858e3c97c2cSBryan Venteicher
8598f82136aSPatrick Kelsey /*
8608f82136aSPatrick Kelsey * First rxq is the completion queue, so there are nrxqs - 1 command
8618f82136aSPatrick Kelsey * rings starting at iflib queue id 1.
8628f82136aSPatrick Kelsey */
8638f82136aSPatrick Kelsey rxc->vxcr_ndesc = scctx->isc_nrxd[0];
8648f82136aSPatrick Kelsey for (i = 0; i < nrxqs - 1; i++) {
865e3c97c2cSBryan Venteicher rxr = &rxq->vxrxq_cmd_ring[i];
8668f82136aSPatrick Kelsey rxr->vxrxr_ndesc = scctx->isc_nrxd[i + 1];
8673c965775SBryan Venteicher }
868e3c97c2cSBryan Venteicher }
869e3c97c2cSBryan Venteicher
870e3c97c2cSBryan Venteicher static int
vmxnet3_rx_queues_alloc(if_ctx_t ctx,caddr_t * vaddrs,uint64_t * paddrs,int nrxqs,int nrxqsets)8718f82136aSPatrick Kelsey vmxnet3_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
8728f82136aSPatrick Kelsey int nrxqs, int nrxqsets)
873e3c97c2cSBryan Venteicher {
8748f82136aSPatrick Kelsey struct vmxnet3_softc *sc;
8758f82136aSPatrick Kelsey if_softc_ctx_t scctx;
8768f82136aSPatrick Kelsey int q;
8778f82136aSPatrick Kelsey int i;
8788f82136aSPatrick Kelsey int error;
8798f82136aSPatrick Kelsey caddr_t kva;
880e3c97c2cSBryan Venteicher
8818f82136aSPatrick Kelsey sc = iflib_get_softc(ctx);
8828f82136aSPatrick Kelsey scctx = sc->vmx_scctx;
883e3c97c2cSBryan Venteicher
8848f82136aSPatrick Kelsey /* Allocate the array of receive queues */
8858f82136aSPatrick Kelsey sc->vmx_rxq = malloc(sizeof(struct vmxnet3_rxqueue) *
8868f82136aSPatrick Kelsey nrxqsets, M_DEVBUF, M_NOWAIT | M_ZERO);
8878f82136aSPatrick Kelsey if (sc->vmx_rxq == NULL)
888e3c97c2cSBryan Venteicher return (ENOMEM);
889e3c97c2cSBryan Venteicher
8908f82136aSPatrick Kelsey /* Initialize driver state for each receive queue */
8918f82136aSPatrick Kelsey for (q = 0; q < nrxqsets; q++)
8928f82136aSPatrick Kelsey vmxnet3_init_rxq(sc, q, nrxqs);
893e3c97c2cSBryan Venteicher
894e557c1ddSBryan Venteicher /*
8958f82136aSPatrick Kelsey * Allocate queue state that is shared with the device. This check
8968f82136aSPatrick Kelsey * and call is performed in both vmxnet3_tx_queues_alloc() and
8978f82136aSPatrick Kelsey * vmxnet3_rx_queues_alloc() so that we don't have to care which
8988f82136aSPatrick Kelsey * order iflib invokes those routines in.
899e557c1ddSBryan Venteicher */
9008f82136aSPatrick Kelsey if (sc->vmx_qs_dma.idi_size == 0) {
9018f82136aSPatrick Kelsey error = vmxnet3_queues_shared_alloc(sc);
902e3c97c2cSBryan Venteicher if (error)
903e3c97c2cSBryan Venteicher return (error);
904e3c97c2cSBryan Venteicher }
905e3c97c2cSBryan Venteicher
9068f82136aSPatrick Kelsey kva = sc->vmx_qs_dma.idi_vaddr +
9078f82136aSPatrick Kelsey scctx->isc_ntxqsets * sizeof(struct vmxnet3_txq_shared);
9088f82136aSPatrick Kelsey for (q = 0; q < nrxqsets; q++) {
9098f82136aSPatrick Kelsey sc->vmx_rxq[q].vxrxq_rs = (struct vmxnet3_rxq_shared *) kva;
9108f82136aSPatrick Kelsey kva += sizeof(struct vmxnet3_rxq_shared);
9118f82136aSPatrick Kelsey }
9128f82136aSPatrick Kelsey
9138f82136aSPatrick Kelsey /* Record descriptor ring vaddrs and paddrs */
9148f82136aSPatrick Kelsey for (q = 0; q < nrxqsets; q++) {
9158f82136aSPatrick Kelsey struct vmxnet3_rxqueue *rxq;
9168f82136aSPatrick Kelsey struct vmxnet3_rxring *rxr;
9178f82136aSPatrick Kelsey struct vmxnet3_comp_ring *rxc;
9188f82136aSPatrick Kelsey
9198f82136aSPatrick Kelsey rxq = &sc->vmx_rxq[q];
9208f82136aSPatrick Kelsey rxc = &rxq->vxrxq_comp_ring;
9218f82136aSPatrick Kelsey
9228f82136aSPatrick Kelsey /* Completion ring */
9238f82136aSPatrick Kelsey rxc->vxcr_u.rxcd =
9248f82136aSPatrick Kelsey (struct vmxnet3_rxcompdesc *) vaddrs[q * nrxqs + 0];
9258f82136aSPatrick Kelsey rxc->vxcr_paddr = paddrs[q * nrxqs + 0];
9268f82136aSPatrick Kelsey
9278f82136aSPatrick Kelsey /* Command ring(s) */
9288f82136aSPatrick Kelsey for (i = 0; i < nrxqs - 1; i++) {
9298f82136aSPatrick Kelsey rxr = &rxq->vxrxq_cmd_ring[i];
9308f82136aSPatrick Kelsey
9318f82136aSPatrick Kelsey rxr->vxrxr_rxd =
9328f82136aSPatrick Kelsey (struct vmxnet3_rxdesc *) vaddrs[q * nrxqs + 1 + i];
9338f82136aSPatrick Kelsey rxr->vxrxr_paddr = paddrs[q * nrxqs + 1 + i];
9348f82136aSPatrick Kelsey }
935e3c97c2cSBryan Venteicher }
936e3c97c2cSBryan Venteicher
937e3c97c2cSBryan Venteicher return (0);
938e3c97c2cSBryan Venteicher }
939e3c97c2cSBryan Venteicher
940e3c97c2cSBryan Venteicher static void
vmxnet3_queues_free(if_ctx_t ctx)9418f82136aSPatrick Kelsey vmxnet3_queues_free(if_ctx_t ctx)
942e3c97c2cSBryan Venteicher {
9438f82136aSPatrick Kelsey struct vmxnet3_softc *sc;
944e3c97c2cSBryan Venteicher
9458f82136aSPatrick Kelsey sc = iflib_get_softc(ctx);
946e3c97c2cSBryan Venteicher
9478f82136aSPatrick Kelsey /* Free queue state area that is shared with the device */
9488f82136aSPatrick Kelsey if (sc->vmx_qs_dma.idi_size != 0) {
9498f82136aSPatrick Kelsey iflib_dma_free(&sc->vmx_qs_dma);
9508f82136aSPatrick Kelsey sc->vmx_qs_dma.idi_size = 0;
951e3c97c2cSBryan Venteicher }
952e3c97c2cSBryan Venteicher
9538f82136aSPatrick Kelsey /* Free array of receive queues */
954e3c97c2cSBryan Venteicher if (sc->vmx_rxq != NULL) {
955e3c97c2cSBryan Venteicher free(sc->vmx_rxq, M_DEVBUF);
956e3c97c2cSBryan Venteicher sc->vmx_rxq = NULL;
957e3c97c2cSBryan Venteicher }
958e3c97c2cSBryan Venteicher
9598f82136aSPatrick Kelsey /* Free array of transmit queues */
960e3c97c2cSBryan Venteicher if (sc->vmx_txq != NULL) {
961e3c97c2cSBryan Venteicher free(sc->vmx_txq, M_DEVBUF);
962e3c97c2cSBryan Venteicher sc->vmx_txq = NULL;
963e3c97c2cSBryan Venteicher }
964e3c97c2cSBryan Venteicher }
965e3c97c2cSBryan Venteicher
966e3c97c2cSBryan Venteicher static int
vmxnet3_alloc_shared_data(struct vmxnet3_softc * sc)967e3c97c2cSBryan Venteicher vmxnet3_alloc_shared_data(struct vmxnet3_softc *sc)
968e3c97c2cSBryan Venteicher {
969e3c97c2cSBryan Venteicher device_t dev;
970e3c97c2cSBryan Venteicher size_t size;
9718f82136aSPatrick Kelsey int error;
972e3c97c2cSBryan Venteicher
973e3c97c2cSBryan Venteicher dev = sc->vmx_dev;
974e3c97c2cSBryan Venteicher
9758f82136aSPatrick Kelsey /* Top level state structure shared with the device */
976e3c97c2cSBryan Venteicher size = sizeof(struct vmxnet3_driver_shared);
9778f82136aSPatrick Kelsey error = iflib_dma_alloc_align(sc->vmx_ctx, size, 1, &sc->vmx_ds_dma, 0);
978e3c97c2cSBryan Venteicher if (error) {
979e3c97c2cSBryan Venteicher device_printf(dev, "cannot alloc shared memory\n");
980e3c97c2cSBryan Venteicher return (error);
981e3c97c2cSBryan Venteicher }
9828f82136aSPatrick Kelsey sc->vmx_ds = (struct vmxnet3_driver_shared *) sc->vmx_ds_dma.idi_vaddr;
983e3c97c2cSBryan Venteicher
9848f82136aSPatrick Kelsey /* RSS table state shared with the device */
985e557c1ddSBryan Venteicher if (sc->vmx_flags & VMXNET3_FLAG_RSS) {
986e557c1ddSBryan Venteicher size = sizeof(struct vmxnet3_rss_shared);
9878f82136aSPatrick Kelsey error = iflib_dma_alloc_align(sc->vmx_ctx, size, 128,
9888f82136aSPatrick Kelsey &sc->vmx_rss_dma, 0);
989e557c1ddSBryan Venteicher if (error) {
990e557c1ddSBryan Venteicher device_printf(dev, "cannot alloc rss shared memory\n");
991e557c1ddSBryan Venteicher return (error);
992e557c1ddSBryan Venteicher }
993e557c1ddSBryan Venteicher sc->vmx_rss =
9948f82136aSPatrick Kelsey (struct vmxnet3_rss_shared *) sc->vmx_rss_dma.idi_vaddr;
995e557c1ddSBryan Venteicher }
996e557c1ddSBryan Venteicher
997e3c97c2cSBryan Venteicher return (0);
998e3c97c2cSBryan Venteicher }
999e3c97c2cSBryan Venteicher
1000e3c97c2cSBryan Venteicher static void
vmxnet3_free_shared_data(struct vmxnet3_softc * sc)1001e3c97c2cSBryan Venteicher vmxnet3_free_shared_data(struct vmxnet3_softc *sc)
1002e3c97c2cSBryan Venteicher {
1003e3c97c2cSBryan Venteicher
10048f82136aSPatrick Kelsey /* Free RSS table state shared with the device */
1005e557c1ddSBryan Venteicher if (sc->vmx_rss != NULL) {
10068f82136aSPatrick Kelsey iflib_dma_free(&sc->vmx_rss_dma);
1007e557c1ddSBryan Venteicher sc->vmx_rss = NULL;
1008e557c1ddSBryan Venteicher }
1009e557c1ddSBryan Venteicher
10108f82136aSPatrick Kelsey /* Free top level state structure shared with the device */
1011e3c97c2cSBryan Venteicher if (sc->vmx_ds != NULL) {
10128f82136aSPatrick Kelsey iflib_dma_free(&sc->vmx_ds_dma);
1013e3c97c2cSBryan Venteicher sc->vmx_ds = NULL;
1014e3c97c2cSBryan Venteicher }
1015e3c97c2cSBryan Venteicher }
1016e3c97c2cSBryan Venteicher
1017e3c97c2cSBryan Venteicher static int
vmxnet3_alloc_mcast_table(struct vmxnet3_softc * sc)1018e3c97c2cSBryan Venteicher vmxnet3_alloc_mcast_table(struct vmxnet3_softc *sc)
1019e3c97c2cSBryan Venteicher {
1020e3c97c2cSBryan Venteicher int error;
1021e3c97c2cSBryan Venteicher
10228f82136aSPatrick Kelsey /* Multicast table state shared with the device */
10238f82136aSPatrick Kelsey error = iflib_dma_alloc_align(sc->vmx_ctx,
10248f82136aSPatrick Kelsey VMXNET3_MULTICAST_MAX * ETHER_ADDR_LEN, 32, &sc->vmx_mcast_dma, 0);
1025e3c97c2cSBryan Venteicher if (error)
1026e3c97c2cSBryan Venteicher device_printf(sc->vmx_dev, "unable to alloc multicast table\n");
1027e3c97c2cSBryan Venteicher else
10288f82136aSPatrick Kelsey sc->vmx_mcast = sc->vmx_mcast_dma.idi_vaddr;
1029e3c97c2cSBryan Venteicher
1030e3c97c2cSBryan Venteicher return (error);
1031e3c97c2cSBryan Venteicher }
1032e3c97c2cSBryan Venteicher
1033e3c97c2cSBryan Venteicher static void
vmxnet3_free_mcast_table(struct vmxnet3_softc * sc)1034e3c97c2cSBryan Venteicher vmxnet3_free_mcast_table(struct vmxnet3_softc *sc)
1035e3c97c2cSBryan Venteicher {
1036e3c97c2cSBryan Venteicher
10378f82136aSPatrick Kelsey /* Free multicast table state shared with the device */
1038e3c97c2cSBryan Venteicher if (sc->vmx_mcast != NULL) {
10398f82136aSPatrick Kelsey iflib_dma_free(&sc->vmx_mcast_dma);
1040e3c97c2cSBryan Venteicher sc->vmx_mcast = NULL;
1041e3c97c2cSBryan Venteicher }
1042e3c97c2cSBryan Venteicher }
1043e3c97c2cSBryan Venteicher
1044e3c97c2cSBryan Venteicher static void
vmxnet3_init_shared_data(struct vmxnet3_softc * sc)1045e3c97c2cSBryan Venteicher vmxnet3_init_shared_data(struct vmxnet3_softc *sc)
1046e3c97c2cSBryan Venteicher {
1047e3c97c2cSBryan Venteicher struct vmxnet3_driver_shared *ds;
10488f82136aSPatrick Kelsey if_softc_ctx_t scctx;
1049e3c97c2cSBryan Venteicher struct vmxnet3_txqueue *txq;
1050e3c97c2cSBryan Venteicher struct vmxnet3_txq_shared *txs;
1051e3c97c2cSBryan Venteicher struct vmxnet3_rxqueue *rxq;
1052e3c97c2cSBryan Venteicher struct vmxnet3_rxq_shared *rxs;
1053e3c97c2cSBryan Venteicher int i;
1054e3c97c2cSBryan Venteicher
1055e3c97c2cSBryan Venteicher ds = sc->vmx_ds;
10568f82136aSPatrick Kelsey scctx = sc->vmx_scctx;
1057e3c97c2cSBryan Venteicher
1058e3c97c2cSBryan Venteicher /*
1059e3c97c2cSBryan Venteicher * Initialize fields of the shared data that remains the same across
1060e3c97c2cSBryan Venteicher * reinits. Note the shared data is zero'd when allocated.
1061e3c97c2cSBryan Venteicher */
1062e3c97c2cSBryan Venteicher
1063e3c97c2cSBryan Venteicher ds->magic = VMXNET3_REV1_MAGIC;
1064e3c97c2cSBryan Venteicher
1065e3c97c2cSBryan Venteicher /* DriverInfo */
1066e3c97c2cSBryan Venteicher ds->version = VMXNET3_DRIVER_VERSION;
1067ce3be286SBryan Venteicher ds->guest = VMXNET3_GOS_FREEBSD |
1068e3c97c2cSBryan Venteicher #ifdef __LP64__
1069e3c97c2cSBryan Venteicher VMXNET3_GOS_64BIT;
1070e3c97c2cSBryan Venteicher #else
1071e3c97c2cSBryan Venteicher VMXNET3_GOS_32BIT;
1072e3c97c2cSBryan Venteicher #endif
1073e3c97c2cSBryan Venteicher ds->vmxnet3_revision = 1;
1074e3c97c2cSBryan Venteicher ds->upt_version = 1;
1075e3c97c2cSBryan Venteicher
1076e3c97c2cSBryan Venteicher /* Misc. conf */
1077e3c97c2cSBryan Venteicher ds->driver_data = vtophys(sc);
1078e3c97c2cSBryan Venteicher ds->driver_data_len = sizeof(struct vmxnet3_softc);
10798f82136aSPatrick Kelsey ds->queue_shared = sc->vmx_qs_dma.idi_paddr;
10808f82136aSPatrick Kelsey ds->queue_shared_len = sc->vmx_qs_dma.idi_size;
10818f82136aSPatrick Kelsey ds->nrxsg_max = IFLIB_MAX_RX_SEGS;
1082e3c97c2cSBryan Venteicher
1083e557c1ddSBryan Venteicher /* RSS conf */
1084e557c1ddSBryan Venteicher if (sc->vmx_flags & VMXNET3_FLAG_RSS) {
1085e557c1ddSBryan Venteicher ds->rss.version = 1;
10868f82136aSPatrick Kelsey ds->rss.paddr = sc->vmx_rss_dma.idi_paddr;
10878f82136aSPatrick Kelsey ds->rss.len = sc->vmx_rss_dma.idi_size;
1088e557c1ddSBryan Venteicher }
1089e557c1ddSBryan Venteicher
1090e3c97c2cSBryan Venteicher /* Interrupt control. */
1091e3c97c2cSBryan Venteicher ds->automask = sc->vmx_intr_mask_mode == VMXNET3_IMM_AUTO;
10928f82136aSPatrick Kelsey /*
10938f82136aSPatrick Kelsey * Total number of interrupt indexes we are using in the shared
1094769d56ecSPatrick Kelsey * config data, even though we don't actually allocate interrupt
10958f82136aSPatrick Kelsey * resources for the tx queues. Some versions of the device will
10968f82136aSPatrick Kelsey * fail to initialize successfully if interrupt indexes are used in
10978f82136aSPatrick Kelsey * the shared config that exceed the number of interrupts configured
10988f82136aSPatrick Kelsey * here.
10998f82136aSPatrick Kelsey */
11008f82136aSPatrick Kelsey ds->nintr = (scctx->isc_vectors == 1) ?
1101769d56ecSPatrick Kelsey 2 : (scctx->isc_nrxqsets + scctx->isc_ntxqsets + 1);
1102e3c97c2cSBryan Venteicher ds->evintr = sc->vmx_event_intr_idx;
1103e3c97c2cSBryan Venteicher ds->ictrl = VMXNET3_ICTRL_DISABLE_ALL;
1104e3c97c2cSBryan Venteicher
11058f82136aSPatrick Kelsey for (i = 0; i < ds->nintr; i++)
1106e3c97c2cSBryan Venteicher ds->modlevel[i] = UPT1_IMOD_ADAPTIVE;
1107e3c97c2cSBryan Venteicher
1108e3c97c2cSBryan Venteicher /* Receive filter. */
11098f82136aSPatrick Kelsey ds->mcast_table = sc->vmx_mcast_dma.idi_paddr;
11108f82136aSPatrick Kelsey ds->mcast_tablelen = sc->vmx_mcast_dma.idi_size;
1111e3c97c2cSBryan Venteicher
1112e3c97c2cSBryan Venteicher /* Tx queues */
11138f82136aSPatrick Kelsey for (i = 0; i < scctx->isc_ntxqsets; i++) {
1114e3c97c2cSBryan Venteicher txq = &sc->vmx_txq[i];
1115e3c97c2cSBryan Venteicher txs = txq->vxtxq_ts;
1116e3c97c2cSBryan Venteicher
11178f82136aSPatrick Kelsey txs->cmd_ring = txq->vxtxq_cmd_ring.vxtxr_paddr;
11183c965775SBryan Venteicher txs->cmd_ring_len = txq->vxtxq_cmd_ring.vxtxr_ndesc;
11198f82136aSPatrick Kelsey txs->comp_ring = txq->vxtxq_comp_ring.vxcr_paddr;
11203c965775SBryan Venteicher txs->comp_ring_len = txq->vxtxq_comp_ring.vxcr_ndesc;
1121e3c97c2cSBryan Venteicher txs->driver_data = vtophys(txq);
1122e3c97c2cSBryan Venteicher txs->driver_data_len = sizeof(struct vmxnet3_txqueue);
1123e3c97c2cSBryan Venteicher }
1124e3c97c2cSBryan Venteicher
1125e3c97c2cSBryan Venteicher /* Rx queues */
11268f82136aSPatrick Kelsey for (i = 0; i < scctx->isc_nrxqsets; i++) {
1127e3c97c2cSBryan Venteicher rxq = &sc->vmx_rxq[i];
1128e3c97c2cSBryan Venteicher rxs = rxq->vxrxq_rs;
1129e3c97c2cSBryan Venteicher
11308f82136aSPatrick Kelsey rxs->cmd_ring[0] = rxq->vxrxq_cmd_ring[0].vxrxr_paddr;
1131e3c97c2cSBryan Venteicher rxs->cmd_ring_len[0] = rxq->vxrxq_cmd_ring[0].vxrxr_ndesc;
11328f82136aSPatrick Kelsey rxs->cmd_ring[1] = rxq->vxrxq_cmd_ring[1].vxrxr_paddr;
1133e3c97c2cSBryan Venteicher rxs->cmd_ring_len[1] = rxq->vxrxq_cmd_ring[1].vxrxr_ndesc;
11348f82136aSPatrick Kelsey rxs->comp_ring = rxq->vxrxq_comp_ring.vxcr_paddr;
11353c965775SBryan Venteicher rxs->comp_ring_len = rxq->vxrxq_comp_ring.vxcr_ndesc;
1136e3c97c2cSBryan Venteicher rxs->driver_data = vtophys(rxq);
1137e3c97c2cSBryan Venteicher rxs->driver_data_len = sizeof(struct vmxnet3_rxqueue);
1138e3c97c2cSBryan Venteicher }
1139e3c97c2cSBryan Venteicher }
1140e3c97c2cSBryan Venteicher
1141e3c97c2cSBryan Venteicher static void
vmxnet3_reinit_rss_shared_data(struct vmxnet3_softc * sc)1142e557c1ddSBryan Venteicher vmxnet3_reinit_rss_shared_data(struct vmxnet3_softc *sc)
1143e557c1ddSBryan Venteicher {
1144e557c1ddSBryan Venteicher /*
1145e557c1ddSBryan Venteicher * Use the same key as the Linux driver until FreeBSD can do
1146e557c1ddSBryan Venteicher * RSS (presumably Toeplitz) in software.
1147e557c1ddSBryan Venteicher */
1148e557c1ddSBryan Venteicher static const uint8_t rss_key[UPT1_RSS_MAX_KEY_SIZE] = {
1149e557c1ddSBryan Venteicher 0x3b, 0x56, 0xd1, 0x56, 0x13, 0x4a, 0xe7, 0xac,
1150e557c1ddSBryan Venteicher 0xe8, 0x79, 0x09, 0x75, 0xe8, 0x65, 0x79, 0x28,
1151e557c1ddSBryan Venteicher 0x35, 0x12, 0xb9, 0x56, 0x7c, 0x76, 0x4b, 0x70,
1152e557c1ddSBryan Venteicher 0xd8, 0x56, 0xa3, 0x18, 0x9b, 0x0a, 0xee, 0xf3,
1153e557c1ddSBryan Venteicher 0x96, 0xa6, 0x9f, 0x8f, 0x9e, 0x8c, 0x90, 0xc9,
1154e557c1ddSBryan Venteicher };
1155e557c1ddSBryan Venteicher
11568f82136aSPatrick Kelsey if_softc_ctx_t scctx;
1157e557c1ddSBryan Venteicher struct vmxnet3_rss_shared *rss;
1158281cab4dSAndriy Gapon #ifdef RSS
1159281cab4dSAndriy Gapon uint8_t rss_algo;
1160281cab4dSAndriy Gapon #endif
1161e557c1ddSBryan Venteicher int i;
1162e557c1ddSBryan Venteicher
11638f82136aSPatrick Kelsey scctx = sc->vmx_scctx;
1164e557c1ddSBryan Venteicher rss = sc->vmx_rss;
1165e557c1ddSBryan Venteicher
1166e557c1ddSBryan Venteicher rss->hash_type =
1167e557c1ddSBryan Venteicher UPT1_RSS_HASH_TYPE_IPV4 | UPT1_RSS_HASH_TYPE_TCP_IPV4 |
1168e557c1ddSBryan Venteicher UPT1_RSS_HASH_TYPE_IPV6 | UPT1_RSS_HASH_TYPE_TCP_IPV6;
1169e557c1ddSBryan Venteicher rss->hash_func = UPT1_RSS_HASH_FUNC_TOEPLITZ;
1170e557c1ddSBryan Venteicher rss->hash_key_size = UPT1_RSS_MAX_KEY_SIZE;
1171e557c1ddSBryan Venteicher rss->ind_table_size = UPT1_RSS_MAX_IND_TABLE_SIZE;
1172281cab4dSAndriy Gapon #ifdef RSS
1173281cab4dSAndriy Gapon /*
1174281cab4dSAndriy Gapon * If the software RSS is configured to anything else other than
1175281cab4dSAndriy Gapon * Toeplitz, then just do Toeplitz in "hardware" for the sake of
1176281cab4dSAndriy Gapon * the packet distribution, but report the hash as opaque to
1177281cab4dSAndriy Gapon * disengage from the software RSS.
1178281cab4dSAndriy Gapon */
1179281cab4dSAndriy Gapon rss_algo = rss_gethashalgo();
1180281cab4dSAndriy Gapon if (rss_algo == RSS_HASH_TOEPLITZ) {
1181281cab4dSAndriy Gapon rss_getkey(rss->hash_key);
1182281cab4dSAndriy Gapon for (i = 0; i < UPT1_RSS_MAX_IND_TABLE_SIZE; i++) {
1183281cab4dSAndriy Gapon rss->ind_table[i] = rss_get_indirection_to_bucket(i) %
1184281cab4dSAndriy Gapon scctx->isc_nrxqsets;
1185281cab4dSAndriy Gapon }
1186281cab4dSAndriy Gapon sc->vmx_flags |= VMXNET3_FLAG_SOFT_RSS;
1187281cab4dSAndriy Gapon } else
1188281cab4dSAndriy Gapon #endif
1189281cab4dSAndriy Gapon {
1190e557c1ddSBryan Venteicher memcpy(rss->hash_key, rss_key, UPT1_RSS_MAX_KEY_SIZE);
1191e557c1ddSBryan Venteicher for (i = 0; i < UPT1_RSS_MAX_IND_TABLE_SIZE; i++)
11928f82136aSPatrick Kelsey rss->ind_table[i] = i % scctx->isc_nrxqsets;
1193281cab4dSAndriy Gapon sc->vmx_flags &= ~VMXNET3_FLAG_SOFT_RSS;
1194281cab4dSAndriy Gapon }
1195e3c97c2cSBryan Venteicher }
1196e3c97c2cSBryan Venteicher
1197e3c97c2cSBryan Venteicher static void
vmxnet3_reinit_shared_data(struct vmxnet3_softc * sc)1198e3c97c2cSBryan Venteicher vmxnet3_reinit_shared_data(struct vmxnet3_softc *sc)
1199e3c97c2cSBryan Venteicher {
1200402810d3SJustin Hibbits if_t ifp;
1201e3c97c2cSBryan Venteicher struct vmxnet3_driver_shared *ds;
12028f82136aSPatrick Kelsey if_softc_ctx_t scctx;
1203e3c97c2cSBryan Venteicher
1204e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp;
1205e3c97c2cSBryan Venteicher ds = sc->vmx_ds;
12068f82136aSPatrick Kelsey scctx = sc->vmx_scctx;
1207e3c97c2cSBryan Venteicher
1208402810d3SJustin Hibbits ds->mtu = if_getmtu(ifp);
12098f82136aSPatrick Kelsey ds->ntxqueue = scctx->isc_ntxqsets;
12108f82136aSPatrick Kelsey ds->nrxqueue = scctx->isc_nrxqsets;
1211e557c1ddSBryan Venteicher
1212e3c97c2cSBryan Venteicher ds->upt_features = 0;
1213402810d3SJustin Hibbits if (if_getcapenable(ifp) & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6))
1214e3c97c2cSBryan Venteicher ds->upt_features |= UPT1_F_CSUM;
1215402810d3SJustin Hibbits if (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING)
12163c5dfe89SBryan Venteicher ds->upt_features |= UPT1_F_VLAN;
1217402810d3SJustin Hibbits if (if_getcapenable(ifp) & IFCAP_LRO)
1218e3c97c2cSBryan Venteicher ds->upt_features |= UPT1_F_LRO;
1219e3c97c2cSBryan Venteicher
1220e557c1ddSBryan Venteicher if (sc->vmx_flags & VMXNET3_FLAG_RSS) {
1221e557c1ddSBryan Venteicher ds->upt_features |= UPT1_F_RSS;
1222e557c1ddSBryan Venteicher vmxnet3_reinit_rss_shared_data(sc);
1223e557c1ddSBryan Venteicher }
1224e3c97c2cSBryan Venteicher
12258f82136aSPatrick Kelsey vmxnet3_write_bar1(sc, VMXNET3_BAR1_DSL, sc->vmx_ds_dma.idi_paddr);
1226e3c97c2cSBryan Venteicher vmxnet3_write_bar1(sc, VMXNET3_BAR1_DSH,
12278f82136aSPatrick Kelsey (uint64_t) sc->vmx_ds_dma.idi_paddr >> 32);
1228e3c97c2cSBryan Venteicher }
1229e3c97c2cSBryan Venteicher
1230e3c97c2cSBryan Venteicher static int
vmxnet3_alloc_data(struct vmxnet3_softc * sc)1231e3c97c2cSBryan Venteicher vmxnet3_alloc_data(struct vmxnet3_softc *sc)
1232e3c97c2cSBryan Venteicher {
1233e3c97c2cSBryan Venteicher int error;
1234e3c97c2cSBryan Venteicher
1235e3c97c2cSBryan Venteicher error = vmxnet3_alloc_shared_data(sc);
1236e3c97c2cSBryan Venteicher if (error)
1237e3c97c2cSBryan Venteicher return (error);
1238e3c97c2cSBryan Venteicher
1239e3c97c2cSBryan Venteicher error = vmxnet3_alloc_mcast_table(sc);
1240e3c97c2cSBryan Venteicher if (error)
1241e3c97c2cSBryan Venteicher return (error);
1242e3c97c2cSBryan Venteicher
1243e3c97c2cSBryan Venteicher vmxnet3_init_shared_data(sc);
1244e3c97c2cSBryan Venteicher
1245e3c97c2cSBryan Venteicher return (0);
1246e3c97c2cSBryan Venteicher }
1247e3c97c2cSBryan Venteicher
1248e3c97c2cSBryan Venteicher static void
vmxnet3_free_data(struct vmxnet3_softc * sc)1249e3c97c2cSBryan Venteicher vmxnet3_free_data(struct vmxnet3_softc *sc)
1250e3c97c2cSBryan Venteicher {
1251e3c97c2cSBryan Venteicher
1252e3c97c2cSBryan Venteicher vmxnet3_free_mcast_table(sc);
1253e3c97c2cSBryan Venteicher vmxnet3_free_shared_data(sc);
1254e3c97c2cSBryan Venteicher }
1255e3c97c2cSBryan Venteicher
1256e3c97c2cSBryan Venteicher static void
vmxnet3_evintr(struct vmxnet3_softc * sc)1257e3c97c2cSBryan Venteicher vmxnet3_evintr(struct vmxnet3_softc *sc)
1258e3c97c2cSBryan Venteicher {
1259e3c97c2cSBryan Venteicher device_t dev;
1260e3c97c2cSBryan Venteicher struct vmxnet3_txq_shared *ts;
1261e3c97c2cSBryan Venteicher struct vmxnet3_rxq_shared *rs;
1262e3c97c2cSBryan Venteicher uint32_t event;
1263e3c97c2cSBryan Venteicher
1264e3c97c2cSBryan Venteicher dev = sc->vmx_dev;
1265e3c97c2cSBryan Venteicher
1266e3c97c2cSBryan Venteicher /* Clear events. */
1267e3c97c2cSBryan Venteicher event = sc->vmx_ds->event;
1268e3c97c2cSBryan Venteicher vmxnet3_write_bar1(sc, VMXNET3_BAR1_EVENT, event);
1269e3c97c2cSBryan Venteicher
12708f82136aSPatrick Kelsey if (event & VMXNET3_EVENT_LINK)
1271e3c97c2cSBryan Venteicher vmxnet3_link_status(sc);
1272e3c97c2cSBryan Venteicher
1273e3c97c2cSBryan Venteicher if (event & (VMXNET3_EVENT_TQERROR | VMXNET3_EVENT_RQERROR)) {
1274e3c97c2cSBryan Venteicher vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_STATUS);
1275e3c97c2cSBryan Venteicher ts = sc->vmx_txq[0].vxtxq_ts;
1276e3c97c2cSBryan Venteicher if (ts->stopped != 0)
1277e3c97c2cSBryan Venteicher device_printf(dev, "Tx queue error %#x\n", ts->error);
1278e3c97c2cSBryan Venteicher rs = sc->vmx_rxq[0].vxrxq_rs;
1279e3c97c2cSBryan Venteicher if (rs->stopped != 0)
1280e3c97c2cSBryan Venteicher device_printf(dev, "Rx queue error %#x\n", rs->error);
12818f82136aSPatrick Kelsey
12828f82136aSPatrick Kelsey /* XXX - rely on liflib watchdog to reset us? */
12838f82136aSPatrick Kelsey device_printf(dev, "Rx/Tx queue error event ... "
12848f82136aSPatrick Kelsey "waiting for iflib watchdog reset\n");
1285e3c97c2cSBryan Venteicher }
1286e3c97c2cSBryan Venteicher
1287e3c97c2cSBryan Venteicher if (event & VMXNET3_EVENT_DIC)
1288e3c97c2cSBryan Venteicher device_printf(dev, "device implementation change event\n");
1289e3c97c2cSBryan Venteicher if (event & VMXNET3_EVENT_DEBUG)
1290e3c97c2cSBryan Venteicher device_printf(dev, "debug event\n");
1291e3c97c2cSBryan Venteicher }
1292e3c97c2cSBryan Venteicher
12938f82136aSPatrick Kelsey static int
vmxnet3_isc_txd_encap(void * vsc,if_pkt_info_t pi)12948f82136aSPatrick Kelsey vmxnet3_isc_txd_encap(void *vsc, if_pkt_info_t pi)
12958f82136aSPatrick Kelsey {
12968f82136aSPatrick Kelsey struct vmxnet3_softc *sc;
12978f82136aSPatrick Kelsey struct vmxnet3_txqueue *txq;
12988f82136aSPatrick Kelsey struct vmxnet3_txring *txr;
12998f82136aSPatrick Kelsey struct vmxnet3_txdesc *txd, *sop;
13008f82136aSPatrick Kelsey bus_dma_segment_t *segs;
13018f82136aSPatrick Kelsey int nsegs;
13028f82136aSPatrick Kelsey int pidx;
13038f82136aSPatrick Kelsey int hdrlen;
13048f82136aSPatrick Kelsey int i;
13058f82136aSPatrick Kelsey int gen;
13068f82136aSPatrick Kelsey
13078f82136aSPatrick Kelsey sc = vsc;
13088f82136aSPatrick Kelsey txq = &sc->vmx_txq[pi->ipi_qsidx];
13098f82136aSPatrick Kelsey txr = &txq->vxtxq_cmd_ring;
13108f82136aSPatrick Kelsey segs = pi->ipi_segs;
13118f82136aSPatrick Kelsey nsegs = pi->ipi_nsegs;
13128f82136aSPatrick Kelsey pidx = pi->ipi_pidx;
13138f82136aSPatrick Kelsey
13148f82136aSPatrick Kelsey KASSERT(nsegs <= VMXNET3_TX_MAXSEGS,
13158f82136aSPatrick Kelsey ("%s: packet with too many segments %d", __func__, nsegs));
13168f82136aSPatrick Kelsey
13178f82136aSPatrick Kelsey sop = &txr->vxtxr_txd[pidx];
13188f82136aSPatrick Kelsey gen = txr->vxtxr_gen ^ 1; /* Owned by cpu (yet) */
13198f82136aSPatrick Kelsey
13208f82136aSPatrick Kelsey for (i = 0; i < nsegs; i++) {
13218f82136aSPatrick Kelsey txd = &txr->vxtxr_txd[pidx];
13228f82136aSPatrick Kelsey
13238f82136aSPatrick Kelsey txd->addr = segs[i].ds_addr;
13248f82136aSPatrick Kelsey txd->len = segs[i].ds_len;
13258f82136aSPatrick Kelsey txd->gen = gen;
13268f82136aSPatrick Kelsey txd->dtype = 0;
13278f82136aSPatrick Kelsey txd->offload_mode = VMXNET3_OM_NONE;
13288f82136aSPatrick Kelsey txd->offload_pos = 0;
13298f82136aSPatrick Kelsey txd->hlen = 0;
13308f82136aSPatrick Kelsey txd->eop = 0;
13318f82136aSPatrick Kelsey txd->compreq = 0;
13328f82136aSPatrick Kelsey txd->vtag_mode = 0;
13338f82136aSPatrick Kelsey txd->vtag = 0;
13348f82136aSPatrick Kelsey
13358f82136aSPatrick Kelsey if (++pidx == txr->vxtxr_ndesc) {
13368f82136aSPatrick Kelsey pidx = 0;
13378f82136aSPatrick Kelsey txr->vxtxr_gen ^= 1;
13388f82136aSPatrick Kelsey }
13398f82136aSPatrick Kelsey gen = txr->vxtxr_gen;
13408f82136aSPatrick Kelsey }
13418f82136aSPatrick Kelsey txd->eop = 1;
13428f82136aSPatrick Kelsey txd->compreq = !!(pi->ipi_flags & IPI_TX_INTR);
13438f82136aSPatrick Kelsey pi->ipi_new_pidx = pidx;
13448f82136aSPatrick Kelsey
13458f82136aSPatrick Kelsey /*
13468f82136aSPatrick Kelsey * VLAN
13478f82136aSPatrick Kelsey */
13488f82136aSPatrick Kelsey if (pi->ipi_mflags & M_VLANTAG) {
13498f82136aSPatrick Kelsey sop->vtag_mode = 1;
13508f82136aSPatrick Kelsey sop->vtag = pi->ipi_vtag;
13518f82136aSPatrick Kelsey }
13528f82136aSPatrick Kelsey
13538f82136aSPatrick Kelsey /*
13548f82136aSPatrick Kelsey * TSO and checksum offloads
13558f82136aSPatrick Kelsey */
13568f82136aSPatrick Kelsey hdrlen = pi->ipi_ehdrlen + pi->ipi_ip_hlen;
13578f82136aSPatrick Kelsey if (pi->ipi_csum_flags & CSUM_TSO) {
13588f82136aSPatrick Kelsey sop->offload_mode = VMXNET3_OM_TSO;
1359f55f37d9SVincenzo Maffione sop->hlen = hdrlen + pi->ipi_tcp_hlen;
13608f82136aSPatrick Kelsey sop->offload_pos = pi->ipi_tso_segsz;
13618f82136aSPatrick Kelsey } else if (pi->ipi_csum_flags & (VMXNET3_CSUM_OFFLOAD |
13628f82136aSPatrick Kelsey VMXNET3_CSUM_OFFLOAD_IPV6)) {
13638f82136aSPatrick Kelsey sop->offload_mode = VMXNET3_OM_CSUM;
13648f82136aSPatrick Kelsey sop->hlen = hdrlen;
13658f82136aSPatrick Kelsey sop->offload_pos = hdrlen +
13668f82136aSPatrick Kelsey ((pi->ipi_ipproto == IPPROTO_TCP) ?
13678f82136aSPatrick Kelsey offsetof(struct tcphdr, th_sum) :
13688f82136aSPatrick Kelsey offsetof(struct udphdr, uh_sum));
13698f82136aSPatrick Kelsey }
13708f82136aSPatrick Kelsey
13718f82136aSPatrick Kelsey /* Finally, change the ownership. */
13728f82136aSPatrick Kelsey vmxnet3_barrier(sc, VMXNET3_BARRIER_WR);
13738f82136aSPatrick Kelsey sop->gen ^= 1;
13748f82136aSPatrick Kelsey
13758f82136aSPatrick Kelsey return (0);
1376e3c97c2cSBryan Venteicher }
1377e3c97c2cSBryan Venteicher
1378e3c97c2cSBryan Venteicher static void
vmxnet3_isc_txd_flush(void * vsc,uint16_t txqid,qidx_t pidx)13798f82136aSPatrick Kelsey vmxnet3_isc_txd_flush(void *vsc, uint16_t txqid, qidx_t pidx)
1380e3c97c2cSBryan Venteicher {
1381e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc;
13828f82136aSPatrick Kelsey struct vmxnet3_txqueue *txq;
13838f82136aSPatrick Kelsey
13848f82136aSPatrick Kelsey sc = vsc;
13858f82136aSPatrick Kelsey txq = &sc->vmx_txq[txqid];
13868f82136aSPatrick Kelsey
13878f82136aSPatrick Kelsey /*
13888f82136aSPatrick Kelsey * pidx is what we last set ipi_new_pidx to in
13898f82136aSPatrick Kelsey * vmxnet3_isc_txd_encap()
13908f82136aSPatrick Kelsey */
13918f82136aSPatrick Kelsey
13928f82136aSPatrick Kelsey /*
13938f82136aSPatrick Kelsey * Avoid expensive register updates if the flush request is
13948f82136aSPatrick Kelsey * redundant.
13958f82136aSPatrick Kelsey */
13968f82136aSPatrick Kelsey if (txq->vxtxq_last_flush == pidx)
13978f82136aSPatrick Kelsey return;
13988f82136aSPatrick Kelsey txq->vxtxq_last_flush = pidx;
13998f82136aSPatrick Kelsey vmxnet3_write_bar0(sc, VMXNET3_BAR0_TXH(txq->vxtxq_id), pidx);
14008f82136aSPatrick Kelsey }
14018f82136aSPatrick Kelsey
14028f82136aSPatrick Kelsey static int
vmxnet3_isc_txd_credits_update(void * vsc,uint16_t txqid,bool clear)14038f82136aSPatrick Kelsey vmxnet3_isc_txd_credits_update(void *vsc, uint16_t txqid, bool clear)
14048f82136aSPatrick Kelsey {
14058f82136aSPatrick Kelsey struct vmxnet3_softc *sc;
14068f82136aSPatrick Kelsey struct vmxnet3_txqueue *txq;
1407e3c97c2cSBryan Venteicher struct vmxnet3_comp_ring *txc;
1408e3c97c2cSBryan Venteicher struct vmxnet3_txcompdesc *txcd;
14098f82136aSPatrick Kelsey struct vmxnet3_txring *txr;
14108f82136aSPatrick Kelsey int processed;
1411e3c97c2cSBryan Venteicher
14128f82136aSPatrick Kelsey sc = vsc;
14138f82136aSPatrick Kelsey txq = &sc->vmx_txq[txqid];
1414e3c97c2cSBryan Venteicher txc = &txq->vxtxq_comp_ring;
14158f82136aSPatrick Kelsey txr = &txq->vxtxq_cmd_ring;
1416e3c97c2cSBryan Venteicher
14178f82136aSPatrick Kelsey /*
14188f82136aSPatrick Kelsey * If clear is true, we need to report the number of TX command ring
14198f82136aSPatrick Kelsey * descriptors that have been processed by the device. If clear is
14208f82136aSPatrick Kelsey * false, we just need to report whether or not at least one TX
14218f82136aSPatrick Kelsey * command ring descriptor has been processed by the device.
14228f82136aSPatrick Kelsey */
14238f82136aSPatrick Kelsey processed = 0;
1424e3c97c2cSBryan Venteicher for (;;) {
1425e3c97c2cSBryan Venteicher txcd = &txc->vxcr_u.txcd[txc->vxcr_next];
1426e3c97c2cSBryan Venteicher if (txcd->gen != txc->vxcr_gen)
1427e3c97c2cSBryan Venteicher break;
14288f82136aSPatrick Kelsey else if (!clear)
14298f82136aSPatrick Kelsey return (1);
14303c965775SBryan Venteicher vmxnet3_barrier(sc, VMXNET3_BARRIER_RD);
1431e3c97c2cSBryan Venteicher
1432*3ff0dc1aSKristof Provost MPASS(txc->vxcr_next < txc->vxcr_ndesc);
1433*3ff0dc1aSKristof Provost if (++txc->vxcr_next >= txc->vxcr_ndesc) {
1434e3c97c2cSBryan Venteicher txc->vxcr_next = 0;
1435e3c97c2cSBryan Venteicher txc->vxcr_gen ^= 1;
1436e3c97c2cSBryan Venteicher }
1437e3c97c2cSBryan Venteicher
14388f82136aSPatrick Kelsey if (txcd->eop_idx < txr->vxtxr_next)
14398f82136aSPatrick Kelsey processed += txr->vxtxr_ndesc -
14408f82136aSPatrick Kelsey (txr->vxtxr_next - txcd->eop_idx) + 1;
14418f82136aSPatrick Kelsey else
14428f82136aSPatrick Kelsey processed += txcd->eop_idx - txr->vxtxr_next + 1;
1443e3c97c2cSBryan Venteicher txr->vxtxr_next = (txcd->eop_idx + 1) % txr->vxtxr_ndesc;
1444e3c97c2cSBryan Venteicher }
1445e3c97c2cSBryan Venteicher
14468f82136aSPatrick Kelsey return (processed);
1447e3c97c2cSBryan Venteicher }
1448e3c97c2cSBryan Venteicher
1449e3c97c2cSBryan Venteicher static int
vmxnet3_isc_rxd_available(void * vsc,uint16_t rxqid,qidx_t idx,qidx_t budget)14508f82136aSPatrick Kelsey vmxnet3_isc_rxd_available(void *vsc, uint16_t rxqid, qidx_t idx, qidx_t budget)
1451e3c97c2cSBryan Venteicher {
14528f82136aSPatrick Kelsey struct vmxnet3_softc *sc;
14538f82136aSPatrick Kelsey struct vmxnet3_rxqueue *rxq;
14548f82136aSPatrick Kelsey struct vmxnet3_comp_ring *rxc;
14558f82136aSPatrick Kelsey struct vmxnet3_rxcompdesc *rxcd;
14568f82136aSPatrick Kelsey int avail;
14578f82136aSPatrick Kelsey int completed_gen;
14588f82136aSPatrick Kelsey #ifdef INVARIANTS
14598f82136aSPatrick Kelsey int expect_sop = 1;
14608f82136aSPatrick Kelsey #endif
14618f82136aSPatrick Kelsey sc = vsc;
14628f82136aSPatrick Kelsey rxq = &sc->vmx_rxq[rxqid];
14638f82136aSPatrick Kelsey rxc = &rxq->vxrxq_comp_ring;
14648f82136aSPatrick Kelsey
14658f82136aSPatrick Kelsey avail = 0;
14668f82136aSPatrick Kelsey completed_gen = rxc->vxcr_gen;
14678f82136aSPatrick Kelsey for (;;) {
14688f82136aSPatrick Kelsey rxcd = &rxc->vxcr_u.rxcd[idx];
14698f82136aSPatrick Kelsey if (rxcd->gen != completed_gen)
14708f82136aSPatrick Kelsey break;
14718f82136aSPatrick Kelsey vmxnet3_barrier(sc, VMXNET3_BARRIER_RD);
14728f82136aSPatrick Kelsey
14738f82136aSPatrick Kelsey #ifdef INVARIANTS
14748f82136aSPatrick Kelsey if (expect_sop)
14758f82136aSPatrick Kelsey KASSERT(rxcd->sop, ("%s: expected sop", __func__));
14768f82136aSPatrick Kelsey else
14778f82136aSPatrick Kelsey KASSERT(!rxcd->sop, ("%s: unexpected sop", __func__));
14788f82136aSPatrick Kelsey expect_sop = rxcd->eop;
14798f82136aSPatrick Kelsey #endif
14808f82136aSPatrick Kelsey if (rxcd->eop && (rxcd->len != 0))
14818f82136aSPatrick Kelsey avail++;
14828f82136aSPatrick Kelsey if (avail > budget)
14838f82136aSPatrick Kelsey break;
14848f82136aSPatrick Kelsey if (++idx == rxc->vxcr_ndesc) {
14858f82136aSPatrick Kelsey idx = 0;
14868f82136aSPatrick Kelsey completed_gen ^= 1;
14878f82136aSPatrick Kelsey }
14888f82136aSPatrick Kelsey }
14898f82136aSPatrick Kelsey
14908f82136aSPatrick Kelsey return (avail);
14918f82136aSPatrick Kelsey }
14928f82136aSPatrick Kelsey
14938f82136aSPatrick Kelsey static int
vmxnet3_isc_rxd_pkt_get(void * vsc,if_rxd_info_t ri)14948f82136aSPatrick Kelsey vmxnet3_isc_rxd_pkt_get(void *vsc, if_rxd_info_t ri)
14958f82136aSPatrick Kelsey {
14968f82136aSPatrick Kelsey struct vmxnet3_softc *sc;
14978f82136aSPatrick Kelsey if_softc_ctx_t scctx;
14988f82136aSPatrick Kelsey struct vmxnet3_rxqueue *rxq;
14998f82136aSPatrick Kelsey struct vmxnet3_comp_ring *rxc;
15008f82136aSPatrick Kelsey struct vmxnet3_rxcompdesc *rxcd;
15018f82136aSPatrick Kelsey if_rxd_frag_t frag;
15028f82136aSPatrick Kelsey int cqidx;
15038f82136aSPatrick Kelsey uint16_t total_len;
15048f82136aSPatrick Kelsey uint8_t nfrags;
1505f50375eeSPatrick Kelsey uint8_t i;
15068f82136aSPatrick Kelsey uint8_t flid;
1507e3c97c2cSBryan Venteicher
15088f82136aSPatrick Kelsey sc = vsc;
15098f82136aSPatrick Kelsey scctx = sc->vmx_scctx;
15108f82136aSPatrick Kelsey rxq = &sc->vmx_rxq[ri->iri_qsidx];
15118f82136aSPatrick Kelsey rxc = &rxq->vxrxq_comp_ring;
1512e3c97c2cSBryan Venteicher
1513e3c97c2cSBryan Venteicher /*
15148f82136aSPatrick Kelsey * Get a single packet starting at the given index in the completion
15158f82136aSPatrick Kelsey * queue. That we have been called indicates that
15168f82136aSPatrick Kelsey * vmxnet3_isc_rxd_available() has already verified that either
15178f82136aSPatrick Kelsey * there is a complete packet available starting at the given index,
15188f82136aSPatrick Kelsey * or there are one or more zero length packets starting at the
15198f82136aSPatrick Kelsey * given index followed by a complete packet, so no verification of
15208f82136aSPatrick Kelsey * ownership of the descriptors (and no associated read barrier) is
15218f82136aSPatrick Kelsey * required here.
1522e3c97c2cSBryan Venteicher */
15238f82136aSPatrick Kelsey cqidx = ri->iri_cidx;
15248f82136aSPatrick Kelsey rxcd = &rxc->vxcr_u.rxcd[cqidx];
15258f82136aSPatrick Kelsey while (rxcd->len == 0) {
15268f82136aSPatrick Kelsey KASSERT(rxcd->sop && rxcd->eop,
15278f82136aSPatrick Kelsey ("%s: zero-length packet without both sop and eop set",
15288f82136aSPatrick Kelsey __func__));
1529f50375eeSPatrick Kelsey rxc->vxcr_zero_length++;
15308f82136aSPatrick Kelsey if (++cqidx == rxc->vxcr_ndesc) {
15318f82136aSPatrick Kelsey cqidx = 0;
15328f82136aSPatrick Kelsey rxc->vxcr_gen ^= 1;
15338f82136aSPatrick Kelsey }
15348f82136aSPatrick Kelsey rxcd = &rxc->vxcr_u.rxcd[cqidx];
15358f82136aSPatrick Kelsey }
15368f82136aSPatrick Kelsey KASSERT(rxcd->sop, ("%s: expected sop", __func__));
15378f82136aSPatrick Kelsey
15388f82136aSPatrick Kelsey /*
1539281cab4dSAndriy Gapon * RSS and flow ID.
1540281cab4dSAndriy Gapon * Types other than M_HASHTYPE_NONE and M_HASHTYPE_OPAQUE_HASH should
1541281cab4dSAndriy Gapon * be used only if the software RSS is enabled and it uses the same
1542281cab4dSAndriy Gapon * algorithm and the hash key as the "hardware". If the software RSS
1543281cab4dSAndriy Gapon * is not enabled, then it's simply pointless to use those types.
1544281cab4dSAndriy Gapon * If it's enabled but with different parameters, then hash values will
1545281cab4dSAndriy Gapon * not match.
15468f82136aSPatrick Kelsey */
15478f82136aSPatrick Kelsey ri->iri_flowid = rxcd->rss_hash;
1548281cab4dSAndriy Gapon #ifdef RSS
1549281cab4dSAndriy Gapon if ((sc->vmx_flags & VMXNET3_FLAG_SOFT_RSS) != 0) {
15508f82136aSPatrick Kelsey switch (rxcd->rss_type) {
15518f82136aSPatrick Kelsey case VMXNET3_RCD_RSS_TYPE_NONE:
15528f82136aSPatrick Kelsey ri->iri_flowid = ri->iri_qsidx;
15538f82136aSPatrick Kelsey ri->iri_rsstype = M_HASHTYPE_NONE;
15548f82136aSPatrick Kelsey break;
15558f82136aSPatrick Kelsey case VMXNET3_RCD_RSS_TYPE_IPV4:
15568f82136aSPatrick Kelsey ri->iri_rsstype = M_HASHTYPE_RSS_IPV4;
15578f82136aSPatrick Kelsey break;
15588f82136aSPatrick Kelsey case VMXNET3_RCD_RSS_TYPE_TCPIPV4:
15598f82136aSPatrick Kelsey ri->iri_rsstype = M_HASHTYPE_RSS_TCP_IPV4;
15608f82136aSPatrick Kelsey break;
15618f82136aSPatrick Kelsey case VMXNET3_RCD_RSS_TYPE_IPV6:
15628f82136aSPatrick Kelsey ri->iri_rsstype = M_HASHTYPE_RSS_IPV6;
15638f82136aSPatrick Kelsey break;
15648f82136aSPatrick Kelsey case VMXNET3_RCD_RSS_TYPE_TCPIPV6:
15658f82136aSPatrick Kelsey ri->iri_rsstype = M_HASHTYPE_RSS_TCP_IPV6;
15668f82136aSPatrick Kelsey break;
15678f82136aSPatrick Kelsey default:
15688f82136aSPatrick Kelsey ri->iri_rsstype = M_HASHTYPE_OPAQUE_HASH;
15698f82136aSPatrick Kelsey break;
1570e3c97c2cSBryan Venteicher }
1571281cab4dSAndriy Gapon } else
1572281cab4dSAndriy Gapon #endif
1573281cab4dSAndriy Gapon {
1574281cab4dSAndriy Gapon switch (rxcd->rss_type) {
1575281cab4dSAndriy Gapon case VMXNET3_RCD_RSS_TYPE_NONE:
1576281cab4dSAndriy Gapon ri->iri_flowid = ri->iri_qsidx;
1577281cab4dSAndriy Gapon ri->iri_rsstype = M_HASHTYPE_NONE;
1578281cab4dSAndriy Gapon break;
1579281cab4dSAndriy Gapon default:
1580281cab4dSAndriy Gapon ri->iri_rsstype = M_HASHTYPE_OPAQUE_HASH;
1581281cab4dSAndriy Gapon break;
1582281cab4dSAndriy Gapon }
1583281cab4dSAndriy Gapon }
1584e3c97c2cSBryan Venteicher
15858f82136aSPatrick Kelsey /*
15868f82136aSPatrick Kelsey * The queue numbering scheme used for rxcd->qid is as follows:
15878f82136aSPatrick Kelsey * - All of the command ring 0s are numbered [0, nrxqsets - 1]
15888f82136aSPatrick Kelsey * - All of the command ring 1s are numbered [nrxqsets, 2*nrxqsets - 1]
15898f82136aSPatrick Kelsey *
15908f82136aSPatrick Kelsey * Thus, rxcd->qid less than nrxqsets indicates command ring (and
15918f82136aSPatrick Kelsey * flid) 0, and rxcd->qid greater than or equal to nrxqsets
15928f82136aSPatrick Kelsey * indicates command ring (and flid) 1.
15938f82136aSPatrick Kelsey */
15948f82136aSPatrick Kelsey nfrags = 0;
15958f82136aSPatrick Kelsey total_len = 0;
15968f82136aSPatrick Kelsey do {
15978f82136aSPatrick Kelsey rxcd = &rxc->vxcr_u.rxcd[cqidx];
15988f82136aSPatrick Kelsey KASSERT(rxcd->gen == rxc->vxcr_gen,
15998f82136aSPatrick Kelsey ("%s: generation mismatch", __func__));
16009c612a5dSAndriy Gapon KASSERT(nfrags < IFLIB_MAX_RX_SEGS,
16019c612a5dSAndriy Gapon ("%s: too many fragments", __func__));
16029c612a5dSAndriy Gapon if (__predict_true(rxcd->len != 0)) {
16038f82136aSPatrick Kelsey frag = &ri->iri_frags[nfrags];
16049c612a5dSAndriy Gapon flid = (rxcd->qid >= scctx->isc_nrxqsets) ? 1 : 0;
16058f82136aSPatrick Kelsey frag->irf_flid = flid;
16068f82136aSPatrick Kelsey frag->irf_idx = rxcd->rxd_idx;
16078f82136aSPatrick Kelsey frag->irf_len = rxcd->len;
16088f82136aSPatrick Kelsey total_len += rxcd->len;
16098f82136aSPatrick Kelsey nfrags++;
16109c612a5dSAndriy Gapon } else {
16119c612a5dSAndriy Gapon rxc->vcxr_zero_length_frag++;
16129c612a5dSAndriy Gapon }
16138f82136aSPatrick Kelsey if (++cqidx == rxc->vxcr_ndesc) {
16148f82136aSPatrick Kelsey cqidx = 0;
16158f82136aSPatrick Kelsey rxc->vxcr_gen ^= 1;
16168f82136aSPatrick Kelsey }
16178f82136aSPatrick Kelsey } while (!rxcd->eop);
1618e3c97c2cSBryan Venteicher
16198f82136aSPatrick Kelsey ri->iri_cidx = cqidx;
16208f82136aSPatrick Kelsey ri->iri_nfrags = nfrags;
16218f82136aSPatrick Kelsey ri->iri_len = total_len;
16228f82136aSPatrick Kelsey
1623f50375eeSPatrick Kelsey /*
1624f50375eeSPatrick Kelsey * If there's an error, the last descriptor in the packet will
1625f50375eeSPatrick Kelsey * have the error indicator set. In this case, set all
1626f50375eeSPatrick Kelsey * fragment lengths to zero. This will cause iflib to discard
1627f50375eeSPatrick Kelsey * the packet, but process all associated descriptors through
1628f50375eeSPatrick Kelsey * the refill mechanism.
1629f50375eeSPatrick Kelsey */
1630f50375eeSPatrick Kelsey if (__predict_false(rxcd->error)) {
1631f50375eeSPatrick Kelsey rxc->vxcr_pkt_errors++;
1632f50375eeSPatrick Kelsey for (i = 0; i < nfrags; i++) {
1633f50375eeSPatrick Kelsey frag = &ri->iri_frags[i];
1634f50375eeSPatrick Kelsey frag->irf_len = 0;
1635f50375eeSPatrick Kelsey }
1636f50375eeSPatrick Kelsey } else {
1637f50375eeSPatrick Kelsey /* Checksum offload information is in the last descriptor. */
1638f50375eeSPatrick Kelsey if (!rxcd->no_csum) {
1639f50375eeSPatrick Kelsey uint32_t csum_flags = 0;
1640f50375eeSPatrick Kelsey
1641f50375eeSPatrick Kelsey if (rxcd->ipv4) {
1642f50375eeSPatrick Kelsey csum_flags |= CSUM_IP_CHECKED;
1643f50375eeSPatrick Kelsey if (rxcd->ipcsum_ok)
1644f50375eeSPatrick Kelsey csum_flags |= CSUM_IP_VALID;
1645f50375eeSPatrick Kelsey }
1646f50375eeSPatrick Kelsey if (!rxcd->fragment && (rxcd->tcp || rxcd->udp)) {
1647f50375eeSPatrick Kelsey csum_flags |= CSUM_L4_CALC;
1648f50375eeSPatrick Kelsey if (rxcd->csum_ok) {
1649f50375eeSPatrick Kelsey csum_flags |= CSUM_L4_VALID;
1650f50375eeSPatrick Kelsey ri->iri_csum_data = 0xffff;
1651f50375eeSPatrick Kelsey }
1652f50375eeSPatrick Kelsey }
1653f50375eeSPatrick Kelsey ri->iri_csum_flags = csum_flags;
1654f50375eeSPatrick Kelsey }
1655f50375eeSPatrick Kelsey
1656f50375eeSPatrick Kelsey /* VLAN information is in the last descriptor. */
1657f50375eeSPatrick Kelsey if (rxcd->vlan) {
1658f50375eeSPatrick Kelsey ri->iri_flags |= M_VLANTAG;
1659f50375eeSPatrick Kelsey ri->iri_vtag = rxcd->vtag;
1660f50375eeSPatrick Kelsey }
1661f50375eeSPatrick Kelsey }
1662f50375eeSPatrick Kelsey
1663e3c97c2cSBryan Venteicher return (0);
1664e3c97c2cSBryan Venteicher }
1665e3c97c2cSBryan Venteicher
1666e3c97c2cSBryan Venteicher static void
vmxnet3_isc_rxd_refill(void * vsc,if_rxd_update_t iru)16678f82136aSPatrick Kelsey vmxnet3_isc_rxd_refill(void *vsc, if_rxd_update_t iru)
1668e3c97c2cSBryan Venteicher {
1669e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc;
16708f82136aSPatrick Kelsey struct vmxnet3_rxqueue *rxq;
1671e3c97c2cSBryan Venteicher struct vmxnet3_rxring *rxr;
1672e3c97c2cSBryan Venteicher struct vmxnet3_rxdesc *rxd;
16738f82136aSPatrick Kelsey uint64_t *paddrs;
16748f82136aSPatrick Kelsey int count;
16758f82136aSPatrick Kelsey int len;
1676f50375eeSPatrick Kelsey int idx;
16778f82136aSPatrick Kelsey int i;
16788f82136aSPatrick Kelsey uint8_t flid;
16798f82136aSPatrick Kelsey uint8_t btype;
1680e3c97c2cSBryan Venteicher
16818f82136aSPatrick Kelsey count = iru->iru_count;
16828f82136aSPatrick Kelsey len = iru->iru_buf_size;
16838f82136aSPatrick Kelsey flid = iru->iru_flidx;
16848f82136aSPatrick Kelsey paddrs = iru->iru_paddrs;
1685e3c97c2cSBryan Venteicher
16868f82136aSPatrick Kelsey sc = vsc;
16878f82136aSPatrick Kelsey rxq = &sc->vmx_rxq[iru->iru_qsidx];
16888f82136aSPatrick Kelsey rxr = &rxq->vxrxq_cmd_ring[flid];
16898f82136aSPatrick Kelsey rxd = rxr->vxrxr_rxd;
1690e3c97c2cSBryan Venteicher
1691e3c97c2cSBryan Venteicher /*
16928f82136aSPatrick Kelsey * Command ring 0 is filled with BTYPE_HEAD descriptors, and
16938f82136aSPatrick Kelsey * command ring 1 is filled with BTYPE_BODY descriptors.
1694e3c97c2cSBryan Venteicher */
16958f82136aSPatrick Kelsey btype = (flid == 0) ? VMXNET3_BTYPE_HEAD : VMXNET3_BTYPE_BODY;
1696f50375eeSPatrick Kelsey /*
1697f50375eeSPatrick Kelsey * The refill entries from iflib will advance monotonically,
1698f50375eeSPatrick Kelsey * but the refilled descriptors may not be contiguous due to
1699f50375eeSPatrick Kelsey * earlier skipping of descriptors by the device. The refill
1700f50375eeSPatrick Kelsey * entries from iflib need an entire state update, while the
1701f50375eeSPatrick Kelsey * descriptors previously skipped by the device only need to
1702f50375eeSPatrick Kelsey * have their generation numbers updated.
1703f50375eeSPatrick Kelsey */
1704f50375eeSPatrick Kelsey idx = rxr->vxrxr_refill_start;
1705f50375eeSPatrick Kelsey i = 0;
1706f50375eeSPatrick Kelsey do {
1707f50375eeSPatrick Kelsey if (idx == iru->iru_idxs[i]) {
1708f50375eeSPatrick Kelsey rxd[idx].addr = paddrs[i];
1709f50375eeSPatrick Kelsey rxd[idx].len = len;
1710f50375eeSPatrick Kelsey rxd[idx].btype = btype;
1711f50375eeSPatrick Kelsey i++;
1712f50375eeSPatrick Kelsey } else
1713f50375eeSPatrick Kelsey rxr->vxrxr_desc_skips++;
1714f50375eeSPatrick Kelsey rxd[idx].gen = rxr->vxrxr_gen;
17158f82136aSPatrick Kelsey
1716f50375eeSPatrick Kelsey if (++idx == rxr->vxrxr_ndesc) {
1717f50375eeSPatrick Kelsey idx = 0;
17188f82136aSPatrick Kelsey rxr->vxrxr_gen ^= 1;
17198f82136aSPatrick Kelsey }
1720f50375eeSPatrick Kelsey } while (i != count);
1721f50375eeSPatrick Kelsey rxr->vxrxr_refill_start = idx;
1722e3c97c2cSBryan Venteicher }
1723e3c97c2cSBryan Venteicher
17248f82136aSPatrick Kelsey static void
vmxnet3_isc_rxd_flush(void * vsc,uint16_t rxqid,uint8_t flid,qidx_t pidx)17258f82136aSPatrick Kelsey vmxnet3_isc_rxd_flush(void *vsc, uint16_t rxqid, uint8_t flid, qidx_t pidx)
17268f82136aSPatrick Kelsey {
17278f82136aSPatrick Kelsey struct vmxnet3_softc *sc;
1728e3c97c2cSBryan Venteicher bus_size_t r;
1729e3c97c2cSBryan Venteicher
17308f82136aSPatrick Kelsey sc = vsc;
17318f82136aSPatrick Kelsey
17328f82136aSPatrick Kelsey if (flid == 0)
17338f82136aSPatrick Kelsey r = VMXNET3_BAR0_RXH1(rxqid);
17348f82136aSPatrick Kelsey else
17358f82136aSPatrick Kelsey r = VMXNET3_BAR0_RXH2(rxqid);
17368f82136aSPatrick Kelsey
17378f82136aSPatrick Kelsey vmxnet3_write_bar0(sc, r, pidx);
1738e3c97c2cSBryan Venteicher }
1739e3c97c2cSBryan Venteicher
17408f82136aSPatrick Kelsey static int
vmxnet3_legacy_intr(void * xsc)1741e3c97c2cSBryan Venteicher vmxnet3_legacy_intr(void *xsc)
1742e3c97c2cSBryan Venteicher {
1743e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc;
17448f82136aSPatrick Kelsey if_softc_ctx_t scctx;
17458f82136aSPatrick Kelsey if_ctx_t ctx;
1746e3c97c2cSBryan Venteicher
1747e3c97c2cSBryan Venteicher sc = xsc;
17488f82136aSPatrick Kelsey scctx = sc->vmx_scctx;
17498f82136aSPatrick Kelsey ctx = sc->vmx_ctx;
1750e3c97c2cSBryan Venteicher
17518f82136aSPatrick Kelsey /*
17528f82136aSPatrick Kelsey * When there is only a single interrupt configured, this routine
17538f82136aSPatrick Kelsey * runs in fast interrupt context, following which the rxq 0 task
17548f82136aSPatrick Kelsey * will be enqueued.
17558f82136aSPatrick Kelsey */
17568f82136aSPatrick Kelsey if (scctx->isc_intr == IFLIB_INTR_LEGACY) {
1757e3c97c2cSBryan Venteicher if (vmxnet3_read_bar1(sc, VMXNET3_BAR1_INTR) == 0)
17588f82136aSPatrick Kelsey return (FILTER_HANDLED);
1759e3c97c2cSBryan Venteicher }
1760e3c97c2cSBryan Venteicher if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE)
17618f82136aSPatrick Kelsey vmxnet3_intr_disable_all(ctx);
1762e3c97c2cSBryan Venteicher
1763e3c97c2cSBryan Venteicher if (sc->vmx_ds->event != 0)
17648f82136aSPatrick Kelsey iflib_admin_intr_deferred(ctx);
1765e3c97c2cSBryan Venteicher
17668f82136aSPatrick Kelsey /*
17678f82136aSPatrick Kelsey * XXX - When there is both rxq and event activity, do we care
17688f82136aSPatrick Kelsey * whether the rxq 0 task or the admin task re-enables the interrupt
17698f82136aSPatrick Kelsey * first?
17708f82136aSPatrick Kelsey */
17718f82136aSPatrick Kelsey return (FILTER_SCHEDULE_THREAD);
1772e3c97c2cSBryan Venteicher }
1773e3c97c2cSBryan Venteicher
17748f82136aSPatrick Kelsey static int
vmxnet3_rxq_intr(void * vrxq)17758f82136aSPatrick Kelsey vmxnet3_rxq_intr(void *vrxq)
1776e3c97c2cSBryan Venteicher {
1777e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc;
1778e3c97c2cSBryan Venteicher struct vmxnet3_rxqueue *rxq;
1779e3c97c2cSBryan Venteicher
17808f82136aSPatrick Kelsey rxq = vrxq;
1781e3c97c2cSBryan Venteicher sc = rxq->vxrxq_sc;
1782e3c97c2cSBryan Venteicher
1783e3c97c2cSBryan Venteicher if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE)
1784e3c97c2cSBryan Venteicher vmxnet3_disable_intr(sc, rxq->vxrxq_intr_idx);
1785e3c97c2cSBryan Venteicher
17868f82136aSPatrick Kelsey return (FILTER_SCHEDULE_THREAD);
1787e3c97c2cSBryan Venteicher }
1788e3c97c2cSBryan Venteicher
17898f82136aSPatrick Kelsey static int
vmxnet3_event_intr(void * vsc)17908f82136aSPatrick Kelsey vmxnet3_event_intr(void *vsc)
1791e3c97c2cSBryan Venteicher {
1792e3c97c2cSBryan Venteicher struct vmxnet3_softc *sc;
1793e3c97c2cSBryan Venteicher
17948f82136aSPatrick Kelsey sc = vsc;
1795e3c97c2cSBryan Venteicher
1796e3c97c2cSBryan Venteicher if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE)
1797e3c97c2cSBryan Venteicher vmxnet3_disable_intr(sc, sc->vmx_event_intr_idx);
1798e3c97c2cSBryan Venteicher
17998f82136aSPatrick Kelsey /*
18008f82136aSPatrick Kelsey * The work will be done via vmxnet3_update_admin_status(), and the
18018f82136aSPatrick Kelsey * interrupt will be re-enabled in vmxnet3_link_intr_enable().
18028f82136aSPatrick Kelsey *
18038f82136aSPatrick Kelsey * The interrupt will be re-enabled by vmxnet3_link_intr_enable().
18048f82136aSPatrick Kelsey */
18058f82136aSPatrick Kelsey return (FILTER_SCHEDULE_THREAD);
1806e3c97c2cSBryan Venteicher }
1807e3c97c2cSBryan Venteicher
1808e3c97c2cSBryan Venteicher static void
vmxnet3_stop(if_ctx_t ctx)18098f82136aSPatrick Kelsey vmxnet3_stop(if_ctx_t ctx)
1810e3c97c2cSBryan Venteicher {
18118f82136aSPatrick Kelsey struct vmxnet3_softc *sc;
1812e3c97c2cSBryan Venteicher
18138f82136aSPatrick Kelsey sc = iflib_get_softc(ctx);
1814e3c97c2cSBryan Venteicher
1815e3c97c2cSBryan Venteicher sc->vmx_link_active = 0;
1816e3c97c2cSBryan Venteicher vmxnet3_write_cmd(sc, VMXNET3_CMD_DISABLE);
1817e3c97c2cSBryan Venteicher vmxnet3_write_cmd(sc, VMXNET3_CMD_RESET);
1818e3c97c2cSBryan Venteicher }
1819e3c97c2cSBryan Venteicher
1820e3c97c2cSBryan Venteicher static void
vmxnet3_txinit(struct vmxnet3_softc * sc,struct vmxnet3_txqueue * txq)1821e3c97c2cSBryan Venteicher vmxnet3_txinit(struct vmxnet3_softc *sc, struct vmxnet3_txqueue *txq)
1822e3c97c2cSBryan Venteicher {
1823e3c97c2cSBryan Venteicher struct vmxnet3_txring *txr;
1824e3c97c2cSBryan Venteicher struct vmxnet3_comp_ring *txc;
1825e3c97c2cSBryan Venteicher
18268f82136aSPatrick Kelsey txq->vxtxq_last_flush = -1;
18278f82136aSPatrick Kelsey
1828e3c97c2cSBryan Venteicher txr = &txq->vxtxq_cmd_ring;
1829e3c97c2cSBryan Venteicher txr->vxtxr_next = 0;
1830e3c97c2cSBryan Venteicher txr->vxtxr_gen = VMXNET3_INIT_GEN;
18318f82136aSPatrick Kelsey /*
18328f82136aSPatrick Kelsey * iflib has zeroed out the descriptor array during the prior attach
18338f82136aSPatrick Kelsey * or stop
18348f82136aSPatrick Kelsey */
1835e3c97c2cSBryan Venteicher
1836e3c97c2cSBryan Venteicher txc = &txq->vxtxq_comp_ring;
1837e3c97c2cSBryan Venteicher txc->vxcr_next = 0;
1838e3c97c2cSBryan Venteicher txc->vxcr_gen = VMXNET3_INIT_GEN;
18398f82136aSPatrick Kelsey /*
18408f82136aSPatrick Kelsey * iflib has zeroed out the descriptor array during the prior attach
18418f82136aSPatrick Kelsey * or stop
18428f82136aSPatrick Kelsey */
1843e3c97c2cSBryan Venteicher }
1844e3c97c2cSBryan Venteicher
18458f82136aSPatrick Kelsey static void
vmxnet3_rxinit(struct vmxnet3_softc * sc,struct vmxnet3_rxqueue * rxq)1846e3c97c2cSBryan Venteicher vmxnet3_rxinit(struct vmxnet3_softc *sc, struct vmxnet3_rxqueue *rxq)
1847e3c97c2cSBryan Venteicher {
1848e3c97c2cSBryan Venteicher struct vmxnet3_rxring *rxr;
1849e3c97c2cSBryan Venteicher struct vmxnet3_comp_ring *rxc;
18508f82136aSPatrick Kelsey int i;
1851e3c97c2cSBryan Venteicher
1852e3c97c2cSBryan Venteicher /*
18538f82136aSPatrick Kelsey * The descriptors will be populated with buffers during a
18548f82136aSPatrick Kelsey * subsequent invocation of vmxnet3_isc_rxd_refill()
1855e3c97c2cSBryan Venteicher */
18568f82136aSPatrick Kelsey for (i = 0; i < sc->vmx_sctx->isc_nrxqs - 1; i++) {
1857e3c97c2cSBryan Venteicher rxr = &rxq->vxrxq_cmd_ring[i];
1858e3c97c2cSBryan Venteicher rxr->vxrxr_gen = VMXNET3_INIT_GEN;
1859f50375eeSPatrick Kelsey rxr->vxrxr_desc_skips = 0;
1860f50375eeSPatrick Kelsey rxr->vxrxr_refill_start = 0;
18618f82136aSPatrick Kelsey /*
18628f82136aSPatrick Kelsey * iflib has zeroed out the descriptor array during the
18638f82136aSPatrick Kelsey * prior attach or stop
18648f82136aSPatrick Kelsey */
1865e3c97c2cSBryan Venteicher }
1866e3c97c2cSBryan Venteicher
1867e3c97c2cSBryan Venteicher for (/**/; i < VMXNET3_RXRINGS_PERQ; i++) {
1868e3c97c2cSBryan Venteicher rxr = &rxq->vxrxq_cmd_ring[i];
1869e3c97c2cSBryan Venteicher rxr->vxrxr_gen = 0;
1870f50375eeSPatrick Kelsey rxr->vxrxr_desc_skips = 0;
1871f50375eeSPatrick Kelsey rxr->vxrxr_refill_start = 0;
1872e3c97c2cSBryan Venteicher bzero(rxr->vxrxr_rxd,
1873e3c97c2cSBryan Venteicher rxr->vxrxr_ndesc * sizeof(struct vmxnet3_rxdesc));
1874e3c97c2cSBryan Venteicher }
1875e3c97c2cSBryan Venteicher
1876e3c97c2cSBryan Venteicher rxc = &rxq->vxrxq_comp_ring;
1877e3c97c2cSBryan Venteicher rxc->vxcr_next = 0;
1878e3c97c2cSBryan Venteicher rxc->vxcr_gen = VMXNET3_INIT_GEN;
1879f50375eeSPatrick Kelsey rxc->vxcr_zero_length = 0;
18809c612a5dSAndriy Gapon rxc->vcxr_zero_length_frag = 0;
1881f50375eeSPatrick Kelsey rxc->vxcr_pkt_errors = 0;
18828f82136aSPatrick Kelsey /*
18838f82136aSPatrick Kelsey * iflib has zeroed out the descriptor array during the prior attach
18848f82136aSPatrick Kelsey * or stop
18858f82136aSPatrick Kelsey */
1886e3c97c2cSBryan Venteicher }
1887e3c97c2cSBryan Venteicher
18888f82136aSPatrick Kelsey static void
vmxnet3_reinit_queues(struct vmxnet3_softc * sc)1889e3c97c2cSBryan Venteicher vmxnet3_reinit_queues(struct vmxnet3_softc *sc)
1890e3c97c2cSBryan Venteicher {
18918f82136aSPatrick Kelsey if_softc_ctx_t scctx;
18928f82136aSPatrick Kelsey int q;
1893e3c97c2cSBryan Venteicher
18948f82136aSPatrick Kelsey scctx = sc->vmx_scctx;
1895e3c97c2cSBryan Venteicher
18968f82136aSPatrick Kelsey for (q = 0; q < scctx->isc_ntxqsets; q++)
1897e3c97c2cSBryan Venteicher vmxnet3_txinit(sc, &sc->vmx_txq[q]);
1898e3c97c2cSBryan Venteicher
18998f82136aSPatrick Kelsey for (q = 0; q < scctx->isc_nrxqsets; q++)
19008f82136aSPatrick Kelsey vmxnet3_rxinit(sc, &sc->vmx_rxq[q]);
1901e3c97c2cSBryan Venteicher }
1902e3c97c2cSBryan Venteicher
1903e3c97c2cSBryan Venteicher static int
vmxnet3_enable_device(struct vmxnet3_softc * sc)1904e3c97c2cSBryan Venteicher vmxnet3_enable_device(struct vmxnet3_softc *sc)
1905e3c97c2cSBryan Venteicher {
19068f82136aSPatrick Kelsey if_softc_ctx_t scctx;
1907e3c97c2cSBryan Venteicher int q;
1908e3c97c2cSBryan Venteicher
19098f82136aSPatrick Kelsey scctx = sc->vmx_scctx;
19108f82136aSPatrick Kelsey
1911e3c97c2cSBryan Venteicher if (vmxnet3_read_cmd(sc, VMXNET3_CMD_ENABLE) != 0) {
1912e3c97c2cSBryan Venteicher device_printf(sc->vmx_dev, "device enable command failed!\n");
1913e3c97c2cSBryan Venteicher return (1);
1914e3c97c2cSBryan Venteicher }
1915e3c97c2cSBryan Venteicher
1916e3c97c2cSBryan Venteicher /* Reset the Rx queue heads. */
19178f82136aSPatrick Kelsey for (q = 0; q < scctx->isc_nrxqsets; q++) {
1918e3c97c2cSBryan Venteicher vmxnet3_write_bar0(sc, VMXNET3_BAR0_RXH1(q), 0);
1919e3c97c2cSBryan Venteicher vmxnet3_write_bar0(sc, VMXNET3_BAR0_RXH2(q), 0);
1920e3c97c2cSBryan Venteicher }
1921e3c97c2cSBryan Venteicher
1922e3c97c2cSBryan Venteicher return (0);
1923e3c97c2cSBryan Venteicher }
1924e3c97c2cSBryan Venteicher
1925e3c97c2cSBryan Venteicher static void
vmxnet3_reinit_rxfilters(struct vmxnet3_softc * sc)1926e3c97c2cSBryan Venteicher vmxnet3_reinit_rxfilters(struct vmxnet3_softc *sc)
1927e3c97c2cSBryan Venteicher {
1928402810d3SJustin Hibbits if_t ifp;
1929e3c97c2cSBryan Venteicher
1930e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp;
1931e3c97c2cSBryan Venteicher
19328f82136aSPatrick Kelsey vmxnet3_set_rxfilter(sc, if_getflags(ifp));
1933e3c97c2cSBryan Venteicher
1934402810d3SJustin Hibbits if (if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER)
1935e3c97c2cSBryan Venteicher bcopy(sc->vmx_vlan_filter, sc->vmx_ds->vlan_filter,
1936e3c97c2cSBryan Venteicher sizeof(sc->vmx_ds->vlan_filter));
1937e3c97c2cSBryan Venteicher else
1938e3c97c2cSBryan Venteicher bzero(sc->vmx_ds->vlan_filter,
1939e3c97c2cSBryan Venteicher sizeof(sc->vmx_ds->vlan_filter));
1940e3c97c2cSBryan Venteicher vmxnet3_write_cmd(sc, VMXNET3_CMD_VLAN_FILTER);
1941e3c97c2cSBryan Venteicher }
1942e3c97c2cSBryan Venteicher
19438f82136aSPatrick Kelsey static void
vmxnet3_init(if_ctx_t ctx)19448f82136aSPatrick Kelsey vmxnet3_init(if_ctx_t ctx)
1945e3c97c2cSBryan Venteicher {
19468f82136aSPatrick Kelsey struct vmxnet3_softc *sc;
1947e3c97c2cSBryan Venteicher
19488f82136aSPatrick Kelsey sc = iflib_get_softc(ctx);
19498f82136aSPatrick Kelsey
19508f82136aSPatrick Kelsey /* Use the current MAC address. */
1951402810d3SJustin Hibbits bcopy(if_getlladdr(sc->vmx_ifp), sc->vmx_lladdr, ETHER_ADDR_LEN);
19528f82136aSPatrick Kelsey vmxnet3_set_lladdr(sc);
19538f82136aSPatrick Kelsey
1954e3c97c2cSBryan Venteicher vmxnet3_reinit_shared_data(sc);
19558f82136aSPatrick Kelsey vmxnet3_reinit_queues(sc);
1956e3c97c2cSBryan Venteicher
19578f82136aSPatrick Kelsey vmxnet3_enable_device(sc);
1958e3c97c2cSBryan Venteicher
1959e3c97c2cSBryan Venteicher vmxnet3_reinit_rxfilters(sc);
1960e3c97c2cSBryan Venteicher vmxnet3_link_status(sc);
1961e3c97c2cSBryan Venteicher }
1962e3c97c2cSBryan Venteicher
1963e3c97c2cSBryan Venteicher static void
vmxnet3_multi_set(if_ctx_t ctx)19648f82136aSPatrick Kelsey vmxnet3_multi_set(if_ctx_t ctx)
1965e3c97c2cSBryan Venteicher {
1966e3c97c2cSBryan Venteicher
19678f82136aSPatrick Kelsey vmxnet3_set_rxfilter(iflib_get_softc(ctx),
19688f82136aSPatrick Kelsey if_getflags(iflib_get_ifp(ctx)));
1969e3c97c2cSBryan Venteicher }
1970e3c97c2cSBryan Venteicher
1971e3c97c2cSBryan Venteicher static int
vmxnet3_mtu_set(if_ctx_t ctx,uint32_t mtu)19728f82136aSPatrick Kelsey vmxnet3_mtu_set(if_ctx_t ctx, uint32_t mtu)
1973e3c97c2cSBryan Venteicher {
19741342c8c6SPatrick Kelsey struct vmxnet3_softc *sc;
19751342c8c6SPatrick Kelsey if_softc_ctx_t scctx;
19761342c8c6SPatrick Kelsey
19771342c8c6SPatrick Kelsey sc = iflib_get_softc(ctx);
19781342c8c6SPatrick Kelsey scctx = sc->vmx_scctx;
1979e3c97c2cSBryan Venteicher
19808f82136aSPatrick Kelsey if (mtu > VMXNET3_TX_MAXSIZE - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN +
19818f82136aSPatrick Kelsey ETHER_CRC_LEN))
1982e3c97c2cSBryan Venteicher return (EINVAL);
1983e3c97c2cSBryan Venteicher
19841342c8c6SPatrick Kelsey /*
19851342c8c6SPatrick Kelsey * Update the max frame size so that the rx mbuf size is
19861342c8c6SPatrick Kelsey * chosen based on the new mtu during the interface init that
19871342c8c6SPatrick Kelsey * will occur after this routine returns.
19881342c8c6SPatrick Kelsey */
19891342c8c6SPatrick Kelsey scctx->isc_max_frame_size = mtu +
19901342c8c6SPatrick Kelsey ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + ETHER_CRC_LEN;
19911342c8c6SPatrick Kelsey /* RX completion queue - n/a */
19921342c8c6SPatrick Kelsey scctx->isc_rxd_buf_size[0] = 0;
19931342c8c6SPatrick Kelsey /*
19941342c8c6SPatrick Kelsey * For header-type descriptors (used for first segment of
19951342c8c6SPatrick Kelsey * packet), let iflib determine the buffer size based on the
19961342c8c6SPatrick Kelsey * max frame size.
19971342c8c6SPatrick Kelsey */
19981342c8c6SPatrick Kelsey scctx->isc_rxd_buf_size[1] = 0;
19991342c8c6SPatrick Kelsey /*
20001342c8c6SPatrick Kelsey * For body-type descriptors (used for jumbo frames and LRO),
20011342c8c6SPatrick Kelsey * always use page-sized buffers.
20021342c8c6SPatrick Kelsey */
20031342c8c6SPatrick Kelsey scctx->isc_rxd_buf_size[2] = MJUMPAGESIZE;
20041342c8c6SPatrick Kelsey
2005e3c97c2cSBryan Venteicher return (0);
2006e3c97c2cSBryan Venteicher }
2007e3c97c2cSBryan Venteicher
20088f82136aSPatrick Kelsey static void
vmxnet3_media_status(if_ctx_t ctx,struct ifmediareq * ifmr)20098f82136aSPatrick Kelsey vmxnet3_media_status(if_ctx_t ctx, struct ifmediareq * ifmr)
2010e3c97c2cSBryan Venteicher {
20118f82136aSPatrick Kelsey struct vmxnet3_softc *sc;
2012e3c97c2cSBryan Venteicher
20138f82136aSPatrick Kelsey sc = iflib_get_softc(ctx);
2014e3c97c2cSBryan Venteicher
20158f82136aSPatrick Kelsey ifmr->ifm_status = IFM_AVALID;
20168f82136aSPatrick Kelsey ifmr->ifm_active = IFM_ETHER;
2017e3c97c2cSBryan Venteicher
20188f82136aSPatrick Kelsey if (vmxnet3_link_is_up(sc) != 0) {
20198f82136aSPatrick Kelsey ifmr->ifm_status |= IFM_ACTIVE;
20208f82136aSPatrick Kelsey ifmr->ifm_active |= IFM_AUTO;
2021e3c97c2cSBryan Venteicher } else
20228f82136aSPatrick Kelsey ifmr->ifm_active |= IFM_NONE;
2023e3c97c2cSBryan Venteicher }
2024e3c97c2cSBryan Venteicher
2025e3c97c2cSBryan Venteicher static int
vmxnet3_media_change(if_ctx_t ctx)20268f82136aSPatrick Kelsey vmxnet3_media_change(if_ctx_t ctx)
2027e3c97c2cSBryan Venteicher {
2028e3c97c2cSBryan Venteicher
20298f82136aSPatrick Kelsey /* Ignore. */
2030c7156fe9SLuigi Rizzo return (0);
2031e557c1ddSBryan Venteicher }
2032e557c1ddSBryan Venteicher
2033e557c1ddSBryan Venteicher static int
vmxnet3_promisc_set(if_ctx_t ctx,int flags)20348f82136aSPatrick Kelsey vmxnet3_promisc_set(if_ctx_t ctx, int flags)
2035e557c1ddSBryan Venteicher {
2036e557c1ddSBryan Venteicher
20378f82136aSPatrick Kelsey vmxnet3_set_rxfilter(iflib_get_softc(ctx), flags);
2038e557c1ddSBryan Venteicher
20398f82136aSPatrick Kelsey return (0);
2040e557c1ddSBryan Venteicher }
2041e557c1ddSBryan Venteicher
20428f82136aSPatrick Kelsey static uint64_t
vmxnet3_get_counter(if_ctx_t ctx,ift_counter cnt)20438f82136aSPatrick Kelsey vmxnet3_get_counter(if_ctx_t ctx, ift_counter cnt)
20448f82136aSPatrick Kelsey {
20458f82136aSPatrick Kelsey if_t ifp = iflib_get_ifp(ctx);
20468f82136aSPatrick Kelsey
20478f82136aSPatrick Kelsey if (cnt < IFCOUNTERS)
20488f82136aSPatrick Kelsey return if_get_counter_default(ifp, cnt);
20498f82136aSPatrick Kelsey
20508f82136aSPatrick Kelsey return (0);
2051e557c1ddSBryan Venteicher }
2052e557c1ddSBryan Venteicher
2053e557c1ddSBryan Venteicher static void
vmxnet3_update_admin_status(if_ctx_t ctx)20548f82136aSPatrick Kelsey vmxnet3_update_admin_status(if_ctx_t ctx)
2055e557c1ddSBryan Venteicher {
2056e557c1ddSBryan Venteicher struct vmxnet3_softc *sc;
2057e557c1ddSBryan Venteicher
20588f82136aSPatrick Kelsey sc = iflib_get_softc(ctx);
20598f82136aSPatrick Kelsey if (sc->vmx_ds->event != 0)
20608f82136aSPatrick Kelsey vmxnet3_evintr(sc);
2061e557c1ddSBryan Venteicher
20628f82136aSPatrick Kelsey vmxnet3_refresh_host_stats(sc);
2063e557c1ddSBryan Venteicher }
2064e557c1ddSBryan Venteicher
2065e557c1ddSBryan Venteicher static void
vmxnet3_txq_timer(if_ctx_t ctx,uint16_t qid)20668f82136aSPatrick Kelsey vmxnet3_txq_timer(if_ctx_t ctx, uint16_t qid)
2067e557c1ddSBryan Venteicher {
20688f82136aSPatrick Kelsey /* Host stats refresh is global, so just trigger it on txq 0 */
20698f82136aSPatrick Kelsey if (qid == 0)
20708f82136aSPatrick Kelsey vmxnet3_refresh_host_stats(iflib_get_softc(ctx));
2071e557c1ddSBryan Venteicher }
2072e557c1ddSBryan Venteicher
2073e3c97c2cSBryan Venteicher static void
vmxnet3_update_vlan_filter(struct vmxnet3_softc * sc,int add,uint16_t tag)2074e3c97c2cSBryan Venteicher vmxnet3_update_vlan_filter(struct vmxnet3_softc *sc, int add, uint16_t tag)
2075e3c97c2cSBryan Venteicher {
2076e3c97c2cSBryan Venteicher int idx, bit;
2077e3c97c2cSBryan Venteicher
2078e3c97c2cSBryan Venteicher if (tag == 0 || tag > 4095)
2079e3c97c2cSBryan Venteicher return;
2080e3c97c2cSBryan Venteicher
20818f82136aSPatrick Kelsey idx = (tag >> 5) & 0x7F;
20828f82136aSPatrick Kelsey bit = tag & 0x1F;
2083e3c97c2cSBryan Venteicher
2084e3c97c2cSBryan Venteicher /* Update our private VLAN bitvector. */
2085e3c97c2cSBryan Venteicher if (add)
2086e3c97c2cSBryan Venteicher sc->vmx_vlan_filter[idx] |= (1 << bit);
2087e3c97c2cSBryan Venteicher else
2088e3c97c2cSBryan Venteicher sc->vmx_vlan_filter[idx] &= ~(1 << bit);
2089e3c97c2cSBryan Venteicher }
2090e3c97c2cSBryan Venteicher
2091e3c97c2cSBryan Venteicher static void
vmxnet3_vlan_register(if_ctx_t ctx,uint16_t tag)20928f82136aSPatrick Kelsey vmxnet3_vlan_register(if_ctx_t ctx, uint16_t tag)
2093e3c97c2cSBryan Venteicher {
2094e3c97c2cSBryan Venteicher
20958f82136aSPatrick Kelsey vmxnet3_update_vlan_filter(iflib_get_softc(ctx), 1, tag);
2096e3c97c2cSBryan Venteicher }
2097e3c97c2cSBryan Venteicher
2098e3c97c2cSBryan Venteicher static void
vmxnet3_vlan_unregister(if_ctx_t ctx,uint16_t tag)20998f82136aSPatrick Kelsey vmxnet3_vlan_unregister(if_ctx_t ctx, uint16_t tag)
2100e3c97c2cSBryan Venteicher {
2101e3c97c2cSBryan Venteicher
21028f82136aSPatrick Kelsey vmxnet3_update_vlan_filter(iflib_get_softc(ctx), 0, tag);
2103e3c97c2cSBryan Venteicher }
2104e3c97c2cSBryan Venteicher
2105d6b5965bSGleb Smirnoff static u_int
vmxnet3_hash_maddr(void * arg,struct sockaddr_dl * sdl,u_int count)2106d6b5965bSGleb Smirnoff vmxnet3_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int count)
2107d6b5965bSGleb Smirnoff {
2108d6b5965bSGleb Smirnoff struct vmxnet3_softc *sc = arg;
2109d6b5965bSGleb Smirnoff
2110d6b5965bSGleb Smirnoff if (count < VMXNET3_MULTICAST_MAX)
2111d6b5965bSGleb Smirnoff bcopy(LLADDR(sdl), &sc->vmx_mcast[count * ETHER_ADDR_LEN],
2112d6b5965bSGleb Smirnoff ETHER_ADDR_LEN);
2113d6b5965bSGleb Smirnoff
2114d6b5965bSGleb Smirnoff return (1);
2115d6b5965bSGleb Smirnoff }
2116d6b5965bSGleb Smirnoff
2117e3c97c2cSBryan Venteicher static void
vmxnet3_set_rxfilter(struct vmxnet3_softc * sc,int flags)21188f82136aSPatrick Kelsey vmxnet3_set_rxfilter(struct vmxnet3_softc *sc, int flags)
2119e3c97c2cSBryan Venteicher {
2120402810d3SJustin Hibbits if_t ifp;
2121e3c97c2cSBryan Venteicher struct vmxnet3_driver_shared *ds;
2122e3c97c2cSBryan Venteicher u_int mode;
2123e3c97c2cSBryan Venteicher
2124e3c97c2cSBryan Venteicher ifp = sc->vmx_ifp;
2125e3c97c2cSBryan Venteicher ds = sc->vmx_ds;
2126e3c97c2cSBryan Venteicher
2127e557c1ddSBryan Venteicher mode = VMXNET3_RXMODE_UCAST | VMXNET3_RXMODE_BCAST;
21288f82136aSPatrick Kelsey if (flags & IFF_PROMISC)
2129e3c97c2cSBryan Venteicher mode |= VMXNET3_RXMODE_PROMISC;
21308f82136aSPatrick Kelsey if (flags & IFF_ALLMULTI)
2131e3c97c2cSBryan Venteicher mode |= VMXNET3_RXMODE_ALLMULTI;
2132e3c97c2cSBryan Venteicher else {
2133d6b5965bSGleb Smirnoff int cnt;
2134e3c97c2cSBryan Venteicher
2135d6b5965bSGleb Smirnoff cnt = if_foreach_llmaddr(ifp, vmxnet3_hash_maddr, sc);
2136d6b5965bSGleb Smirnoff if (cnt >= VMXNET3_MULTICAST_MAX) {
2137e3c97c2cSBryan Venteicher cnt = 0;
2138e3c97c2cSBryan Venteicher mode |= VMXNET3_RXMODE_ALLMULTI;
2139e3c97c2cSBryan Venteicher } else if (cnt > 0)
2140e3c97c2cSBryan Venteicher mode |= VMXNET3_RXMODE_MCAST;
2141e3c97c2cSBryan Venteicher ds->mcast_tablelen = cnt * ETHER_ADDR_LEN;
2142e3c97c2cSBryan Venteicher }
2143e3c97c2cSBryan Venteicher
2144e3c97c2cSBryan Venteicher ds->rxmode = mode;
2145e3c97c2cSBryan Venteicher
2146e3c97c2cSBryan Venteicher vmxnet3_write_cmd(sc, VMXNET3_CMD_SET_FILTER);
2147e3c97c2cSBryan Venteicher vmxnet3_write_cmd(sc, VMXNET3_CMD_SET_RXMODE);
2148e3c97c2cSBryan Venteicher }
2149e3c97c2cSBryan Venteicher
2150e3c97c2cSBryan Venteicher static void
vmxnet3_refresh_host_stats(struct vmxnet3_softc * sc)2151e557c1ddSBryan Venteicher vmxnet3_refresh_host_stats(struct vmxnet3_softc *sc)
2152e3c97c2cSBryan Venteicher {
2153e3c97c2cSBryan Venteicher
2154e3c97c2cSBryan Venteicher vmxnet3_write_cmd(sc, VMXNET3_CMD_GET_STATS);
2155e3c97c2cSBryan Venteicher }
2156e3c97c2cSBryan Venteicher
2157e3c97c2cSBryan Venteicher static int
vmxnet3_link_is_up(struct vmxnet3_softc * sc)2158e3c97c2cSBryan Venteicher vmxnet3_link_is_up(struct vmxnet3_softc *sc)
2159e3c97c2cSBryan Venteicher {
2160e3c97c2cSBryan Venteicher uint32_t status;
2161e3c97c2cSBryan Venteicher
2162e3c97c2cSBryan Venteicher status = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_LINK);
2163e3c97c2cSBryan Venteicher return !!(status & 0x1);
2164e3c97c2cSBryan Venteicher }
2165e3c97c2cSBryan Venteicher
2166e3c97c2cSBryan Venteicher static void
vmxnet3_link_status(struct vmxnet3_softc * sc)2167e3c97c2cSBryan Venteicher vmxnet3_link_status(struct vmxnet3_softc *sc)
2168e3c97c2cSBryan Venteicher {
21698f82136aSPatrick Kelsey if_ctx_t ctx;
21708f82136aSPatrick Kelsey uint64_t speed;
2171e3c97c2cSBryan Venteicher int link;
2172e3c97c2cSBryan Venteicher
21738f82136aSPatrick Kelsey ctx = sc->vmx_ctx;
2174e3c97c2cSBryan Venteicher link = vmxnet3_link_is_up(sc);
21758f82136aSPatrick Kelsey speed = IF_Gbps(10);
2176e3c97c2cSBryan Venteicher
2177e3c97c2cSBryan Venteicher if (link != 0 && sc->vmx_link_active == 0) {
2178e3c97c2cSBryan Venteicher sc->vmx_link_active = 1;
21798f82136aSPatrick Kelsey iflib_link_state_change(ctx, LINK_STATE_UP, speed);
2180e3c97c2cSBryan Venteicher } else if (link == 0 && sc->vmx_link_active != 0) {
2181e3c97c2cSBryan Venteicher sc->vmx_link_active = 0;
21828f82136aSPatrick Kelsey iflib_link_state_change(ctx, LINK_STATE_DOWN, speed);
2183e3c97c2cSBryan Venteicher }
2184e3c97c2cSBryan Venteicher }
2185e3c97c2cSBryan Venteicher
2186e3c97c2cSBryan Venteicher static void
vmxnet3_set_lladdr(struct vmxnet3_softc * sc)2187e3c97c2cSBryan Venteicher vmxnet3_set_lladdr(struct vmxnet3_softc *sc)
2188e3c97c2cSBryan Venteicher {
2189e3c97c2cSBryan Venteicher uint32_t ml, mh;
2190e3c97c2cSBryan Venteicher
2191e3c97c2cSBryan Venteicher ml = sc->vmx_lladdr[0];
2192e3c97c2cSBryan Venteicher ml |= sc->vmx_lladdr[1] << 8;
2193e3c97c2cSBryan Venteicher ml |= sc->vmx_lladdr[2] << 16;
2194e3c97c2cSBryan Venteicher ml |= sc->vmx_lladdr[3] << 24;
2195e3c97c2cSBryan Venteicher vmxnet3_write_bar1(sc, VMXNET3_BAR1_MACL, ml);
2196e3c97c2cSBryan Venteicher
2197e3c97c2cSBryan Venteicher mh = sc->vmx_lladdr[4];
2198e3c97c2cSBryan Venteicher mh |= sc->vmx_lladdr[5] << 8;
2199e3c97c2cSBryan Venteicher vmxnet3_write_bar1(sc, VMXNET3_BAR1_MACH, mh);
2200e3c97c2cSBryan Venteicher }
2201e3c97c2cSBryan Venteicher
2202e3c97c2cSBryan Venteicher static void
vmxnet3_get_lladdr(struct vmxnet3_softc * sc)2203e3c97c2cSBryan Venteicher vmxnet3_get_lladdr(struct vmxnet3_softc *sc)
2204e3c97c2cSBryan Venteicher {
2205e3c97c2cSBryan Venteicher uint32_t ml, mh;
2206e3c97c2cSBryan Venteicher
2207e3c97c2cSBryan Venteicher ml = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_MACL);
2208e3c97c2cSBryan Venteicher mh = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_MACH);
2209e3c97c2cSBryan Venteicher
2210e3c97c2cSBryan Venteicher sc->vmx_lladdr[0] = ml;
2211e3c97c2cSBryan Venteicher sc->vmx_lladdr[1] = ml >> 8;
2212e3c97c2cSBryan Venteicher sc->vmx_lladdr[2] = ml >> 16;
2213e3c97c2cSBryan Venteicher sc->vmx_lladdr[3] = ml >> 24;
2214e3c97c2cSBryan Venteicher sc->vmx_lladdr[4] = mh;
2215e3c97c2cSBryan Venteicher sc->vmx_lladdr[5] = mh >> 8;
2216e3c97c2cSBryan Venteicher }
2217e3c97c2cSBryan Venteicher
2218e3c97c2cSBryan Venteicher static void
vmxnet3_setup_txq_sysctl(struct vmxnet3_txqueue * txq,struct sysctl_ctx_list * ctx,struct sysctl_oid_list * child)2219e3c97c2cSBryan Venteicher vmxnet3_setup_txq_sysctl(struct vmxnet3_txqueue *txq,
2220e3c97c2cSBryan Venteicher struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2221e3c97c2cSBryan Venteicher {
2222e3c97c2cSBryan Venteicher struct sysctl_oid *node, *txsnode;
2223e3c97c2cSBryan Venteicher struct sysctl_oid_list *list, *txslist;
2224e3c97c2cSBryan Venteicher struct UPT1_TxStats *txstats;
2225e3c97c2cSBryan Venteicher char namebuf[16];
2226e3c97c2cSBryan Venteicher
2227e3c97c2cSBryan Venteicher txstats = &txq->vxtxq_ts->stats;
2228e3c97c2cSBryan Venteicher
2229e3c97c2cSBryan Venteicher snprintf(namebuf, sizeof(namebuf), "txq%d", txq->vxtxq_id);
22307029da5cSPawel Biernacki node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf,
22317029da5cSPawel Biernacki CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Transmit Queue");
2232e3c97c2cSBryan Venteicher txq->vxtxq_sysctl = list = SYSCTL_CHILDREN(node);
2233e3c97c2cSBryan Venteicher
2234e3c97c2cSBryan Venteicher /*
22358f82136aSPatrick Kelsey * Add statistics reported by the host. These are updated by the
22368f82136aSPatrick Kelsey * iflib txq timer on txq 0.
2237e3c97c2cSBryan Venteicher */
22387029da5cSPawel Biernacki txsnode = SYSCTL_ADD_NODE(ctx, list, OID_AUTO, "hstats",
22397029da5cSPawel Biernacki CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Host Statistics");
2240e3c97c2cSBryan Venteicher txslist = SYSCTL_CHILDREN(txsnode);
2241e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "tso_packets", CTLFLAG_RD,
2242e3c97c2cSBryan Venteicher &txstats->TSO_packets, "TSO packets");
2243e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "tso_bytes", CTLFLAG_RD,
2244e3c97c2cSBryan Venteicher &txstats->TSO_bytes, "TSO bytes");
2245e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "ucast_packets", CTLFLAG_RD,
2246e3c97c2cSBryan Venteicher &txstats->ucast_packets, "Unicast packets");
2247e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "unicast_bytes", CTLFLAG_RD,
2248e3c97c2cSBryan Venteicher &txstats->ucast_bytes, "Unicast bytes");
2249e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "mcast_packets", CTLFLAG_RD,
2250e3c97c2cSBryan Venteicher &txstats->mcast_packets, "Multicast packets");
2251e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "mcast_bytes", CTLFLAG_RD,
2252e3c97c2cSBryan Venteicher &txstats->mcast_bytes, "Multicast bytes");
2253e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "error", CTLFLAG_RD,
2254e3c97c2cSBryan Venteicher &txstats->error, "Errors");
2255e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "discard", CTLFLAG_RD,
2256e3c97c2cSBryan Venteicher &txstats->discard, "Discards");
2257e3c97c2cSBryan Venteicher }
2258e3c97c2cSBryan Venteicher
2259e3c97c2cSBryan Venteicher static void
vmxnet3_setup_rxq_sysctl(struct vmxnet3_rxqueue * rxq,struct sysctl_ctx_list * ctx,struct sysctl_oid_list * child)2260e3c97c2cSBryan Venteicher vmxnet3_setup_rxq_sysctl(struct vmxnet3_rxqueue *rxq,
2261e3c97c2cSBryan Venteicher struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2262e3c97c2cSBryan Venteicher {
2263e3c97c2cSBryan Venteicher struct sysctl_oid *node, *rxsnode;
2264e3c97c2cSBryan Venteicher struct sysctl_oid_list *list, *rxslist;
2265e3c97c2cSBryan Venteicher struct UPT1_RxStats *rxstats;
2266e3c97c2cSBryan Venteicher char namebuf[16];
2267e3c97c2cSBryan Venteicher
2268e3c97c2cSBryan Venteicher rxstats = &rxq->vxrxq_rs->stats;
2269e3c97c2cSBryan Venteicher
2270e3c97c2cSBryan Venteicher snprintf(namebuf, sizeof(namebuf), "rxq%d", rxq->vxrxq_id);
22717029da5cSPawel Biernacki node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf,
22727029da5cSPawel Biernacki CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Receive Queue");
2273e3c97c2cSBryan Venteicher rxq->vxrxq_sysctl = list = SYSCTL_CHILDREN(node);
2274e3c97c2cSBryan Venteicher
2275e3c97c2cSBryan Venteicher /*
22768f82136aSPatrick Kelsey * Add statistics reported by the host. These are updated by the
22778f82136aSPatrick Kelsey * iflib txq timer on txq 0.
2278e3c97c2cSBryan Venteicher */
22797029da5cSPawel Biernacki rxsnode = SYSCTL_ADD_NODE(ctx, list, OID_AUTO, "hstats",
22807029da5cSPawel Biernacki CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Host Statistics");
2281e3c97c2cSBryan Venteicher rxslist = SYSCTL_CHILDREN(rxsnode);
2282e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "lro_packets", CTLFLAG_RD,
2283e3c97c2cSBryan Venteicher &rxstats->LRO_packets, "LRO packets");
2284e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "lro_bytes", CTLFLAG_RD,
2285e3c97c2cSBryan Venteicher &rxstats->LRO_bytes, "LRO bytes");
2286e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "ucast_packets", CTLFLAG_RD,
2287e3c97c2cSBryan Venteicher &rxstats->ucast_packets, "Unicast packets");
2288e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "unicast_bytes", CTLFLAG_RD,
2289e3c97c2cSBryan Venteicher &rxstats->ucast_bytes, "Unicast bytes");
2290e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "mcast_packets", CTLFLAG_RD,
2291e3c97c2cSBryan Venteicher &rxstats->mcast_packets, "Multicast packets");
2292e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "mcast_bytes", CTLFLAG_RD,
2293e3c97c2cSBryan Venteicher &rxstats->mcast_bytes, "Multicast bytes");
2294e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "bcast_packets", CTLFLAG_RD,
2295e3c97c2cSBryan Venteicher &rxstats->bcast_packets, "Broadcast packets");
2296e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "bcast_bytes", CTLFLAG_RD,
2297e3c97c2cSBryan Venteicher &rxstats->bcast_bytes, "Broadcast bytes");
2298e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "nobuffer", CTLFLAG_RD,
2299e3c97c2cSBryan Venteicher &rxstats->nobuffer, "No buffer");
2300e3c97c2cSBryan Venteicher SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "error", CTLFLAG_RD,
2301e3c97c2cSBryan Venteicher &rxstats->error, "Errors");
2302e3c97c2cSBryan Venteicher }
2303e3c97c2cSBryan Venteicher
2304e3c97c2cSBryan Venteicher static void
vmxnet3_setup_debug_sysctl(struct vmxnet3_softc * sc,struct sysctl_ctx_list * ctx,struct sysctl_oid_list * child)2305e3c97c2cSBryan Venteicher vmxnet3_setup_debug_sysctl(struct vmxnet3_softc *sc,
2306e3c97c2cSBryan Venteicher struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2307e3c97c2cSBryan Venteicher {
23088f82136aSPatrick Kelsey if_softc_ctx_t scctx;
2309e3c97c2cSBryan Venteicher struct sysctl_oid *node;
2310e3c97c2cSBryan Venteicher struct sysctl_oid_list *list;
2311e3c97c2cSBryan Venteicher int i;
2312e3c97c2cSBryan Venteicher
23138f82136aSPatrick Kelsey scctx = sc->vmx_scctx;
23148f82136aSPatrick Kelsey
23158f82136aSPatrick Kelsey for (i = 0; i < scctx->isc_ntxqsets; i++) {
2316e3c97c2cSBryan Venteicher struct vmxnet3_txqueue *txq = &sc->vmx_txq[i];
2317e3c97c2cSBryan Venteicher
2318e3c97c2cSBryan Venteicher node = SYSCTL_ADD_NODE(ctx, txq->vxtxq_sysctl, OID_AUTO,
23197029da5cSPawel Biernacki "debug", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "");
2320e3c97c2cSBryan Venteicher list = SYSCTL_CHILDREN(node);
2321e3c97c2cSBryan Venteicher
2322e3c97c2cSBryan Venteicher SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd_next", CTLFLAG_RD,
2323e3c97c2cSBryan Venteicher &txq->vxtxq_cmd_ring.vxtxr_next, 0, "");
2324e3c97c2cSBryan Venteicher SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd_ndesc", CTLFLAG_RD,
2325e3c97c2cSBryan Venteicher &txq->vxtxq_cmd_ring.vxtxr_ndesc, 0, "");
2326e3c97c2cSBryan Venteicher SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd_gen", CTLFLAG_RD,
2327e3c97c2cSBryan Venteicher &txq->vxtxq_cmd_ring.vxtxr_gen, 0, "");
2328e3c97c2cSBryan Venteicher SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_next", CTLFLAG_RD,
2329e3c97c2cSBryan Venteicher &txq->vxtxq_comp_ring.vxcr_next, 0, "");
2330e3c97c2cSBryan Venteicher SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_ndesc", CTLFLAG_RD,
2331e3c97c2cSBryan Venteicher &txq->vxtxq_comp_ring.vxcr_ndesc, 0,"");
2332e3c97c2cSBryan Venteicher SYSCTL_ADD_INT(ctx, list, OID_AUTO, "comp_gen", CTLFLAG_RD,
2333e3c97c2cSBryan Venteicher &txq->vxtxq_comp_ring.vxcr_gen, 0, "");
2334e3c97c2cSBryan Venteicher }
2335e3c97c2cSBryan Venteicher
23368f82136aSPatrick Kelsey for (i = 0; i < scctx->isc_nrxqsets; i++) {
2337e3c97c2cSBryan Venteicher struct vmxnet3_rxqueue *rxq = &sc->vmx_rxq[i];
2338e3c97c2cSBryan Venteicher
2339e3c97c2cSBryan Venteicher node = SYSCTL_ADD_NODE(ctx, rxq->vxrxq_sysctl, OID_AUTO,
23407029da5cSPawel Biernacki "debug", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "");
2341e3c97c2cSBryan Venteicher list = SYSCTL_CHILDREN(node);
2342e3c97c2cSBryan Venteicher
2343e3c97c2cSBryan Venteicher SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd0_ndesc", CTLFLAG_RD,
2344e3c97c2cSBryan Venteicher &rxq->vxrxq_cmd_ring[0].vxrxr_ndesc, 0, "");
2345e3c97c2cSBryan Venteicher SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd0_gen", CTLFLAG_RD,
2346e3c97c2cSBryan Venteicher &rxq->vxrxq_cmd_ring[0].vxrxr_gen, 0, "");
2347f50375eeSPatrick Kelsey SYSCTL_ADD_U64(ctx, list, OID_AUTO, "cmd0_desc_skips", CTLFLAG_RD,
2348f50375eeSPatrick Kelsey &rxq->vxrxq_cmd_ring[0].vxrxr_desc_skips, 0, "");
2349e3c97c2cSBryan Venteicher SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd1_ndesc", CTLFLAG_RD,
2350e3c97c2cSBryan Venteicher &rxq->vxrxq_cmd_ring[1].vxrxr_ndesc, 0, "");
2351e3c97c2cSBryan Venteicher SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd1_gen", CTLFLAG_RD,
2352e3c97c2cSBryan Venteicher &rxq->vxrxq_cmd_ring[1].vxrxr_gen, 0, "");
2353f50375eeSPatrick Kelsey SYSCTL_ADD_U64(ctx, list, OID_AUTO, "cmd1_desc_skips", CTLFLAG_RD,
2354f50375eeSPatrick Kelsey &rxq->vxrxq_cmd_ring[1].vxrxr_desc_skips, 0, "");
2355e3c97c2cSBryan Venteicher SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_ndesc", CTLFLAG_RD,
2356e3c97c2cSBryan Venteicher &rxq->vxrxq_comp_ring.vxcr_ndesc, 0,"");
2357e3c97c2cSBryan Venteicher SYSCTL_ADD_INT(ctx, list, OID_AUTO, "comp_gen", CTLFLAG_RD,
2358e3c97c2cSBryan Venteicher &rxq->vxrxq_comp_ring.vxcr_gen, 0, "");
2359f50375eeSPatrick Kelsey SYSCTL_ADD_U64(ctx, list, OID_AUTO, "comp_zero_length", CTLFLAG_RD,
2360f50375eeSPatrick Kelsey &rxq->vxrxq_comp_ring.vxcr_zero_length, 0, "");
23619c612a5dSAndriy Gapon SYSCTL_ADD_U64(ctx, list, OID_AUTO, "comp_zero_length_frag",
23629c612a5dSAndriy Gapon CTLFLAG_RD, &rxq->vxrxq_comp_ring.vcxr_zero_length_frag,
23639c612a5dSAndriy Gapon 0, "");
2364f50375eeSPatrick Kelsey SYSCTL_ADD_U64(ctx, list, OID_AUTO, "comp_pkt_errors", CTLFLAG_RD,
2365f50375eeSPatrick Kelsey &rxq->vxrxq_comp_ring.vxcr_pkt_errors, 0, "");
2366e3c97c2cSBryan Venteicher }
2367e3c97c2cSBryan Venteicher }
2368e3c97c2cSBryan Venteicher
2369e3c97c2cSBryan Venteicher static void
vmxnet3_setup_queue_sysctl(struct vmxnet3_softc * sc,struct sysctl_ctx_list * ctx,struct sysctl_oid_list * child)2370e3c97c2cSBryan Venteicher vmxnet3_setup_queue_sysctl(struct vmxnet3_softc *sc,
2371e3c97c2cSBryan Venteicher struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
2372e3c97c2cSBryan Venteicher {
23738f82136aSPatrick Kelsey if_softc_ctx_t scctx;
2374e3c97c2cSBryan Venteicher int i;
2375e3c97c2cSBryan Venteicher
23768f82136aSPatrick Kelsey scctx = sc->vmx_scctx;
23778f82136aSPatrick Kelsey
23788f82136aSPatrick Kelsey for (i = 0; i < scctx->isc_ntxqsets; i++)
2379e3c97c2cSBryan Venteicher vmxnet3_setup_txq_sysctl(&sc->vmx_txq[i], ctx, child);
23808f82136aSPatrick Kelsey for (i = 0; i < scctx->isc_nrxqsets; i++)
2381e3c97c2cSBryan Venteicher vmxnet3_setup_rxq_sysctl(&sc->vmx_rxq[i], ctx, child);
2382e3c97c2cSBryan Venteicher
2383e3c97c2cSBryan Venteicher vmxnet3_setup_debug_sysctl(sc, ctx, child);
2384e3c97c2cSBryan Venteicher }
2385e3c97c2cSBryan Venteicher
2386e3c97c2cSBryan Venteicher static void
vmxnet3_setup_sysctl(struct vmxnet3_softc * sc)2387e3c97c2cSBryan Venteicher vmxnet3_setup_sysctl(struct vmxnet3_softc *sc)
2388e3c97c2cSBryan Venteicher {
2389e3c97c2cSBryan Venteicher device_t dev;
2390e3c97c2cSBryan Venteicher struct sysctl_ctx_list *ctx;
2391e3c97c2cSBryan Venteicher struct sysctl_oid *tree;
2392e3c97c2cSBryan Venteicher struct sysctl_oid_list *child;
2393e3c97c2cSBryan Venteicher
2394e3c97c2cSBryan Venteicher dev = sc->vmx_dev;
2395e3c97c2cSBryan Venteicher ctx = device_get_sysctl_ctx(dev);
2396e3c97c2cSBryan Venteicher tree = device_get_sysctl_tree(dev);
2397e3c97c2cSBryan Venteicher child = SYSCTL_CHILDREN(tree);
2398e3c97c2cSBryan Venteicher
2399e3c97c2cSBryan Venteicher vmxnet3_setup_queue_sysctl(sc, ctx, child);
2400e3c97c2cSBryan Venteicher }
2401e3c97c2cSBryan Venteicher
2402e3c97c2cSBryan Venteicher static void
vmxnet3_write_bar0(struct vmxnet3_softc * sc,bus_size_t r,uint32_t v)2403e3c97c2cSBryan Venteicher vmxnet3_write_bar0(struct vmxnet3_softc *sc, bus_size_t r, uint32_t v)
2404e3c97c2cSBryan Venteicher {
2405e3c97c2cSBryan Venteicher
2406e3c97c2cSBryan Venteicher bus_space_write_4(sc->vmx_iot0, sc->vmx_ioh0, r, v);
2407e3c97c2cSBryan Venteicher }
2408e3c97c2cSBryan Venteicher
2409e3c97c2cSBryan Venteicher static uint32_t
vmxnet3_read_bar1(struct vmxnet3_softc * sc,bus_size_t r)2410e3c97c2cSBryan Venteicher vmxnet3_read_bar1(struct vmxnet3_softc *sc, bus_size_t r)
2411e3c97c2cSBryan Venteicher {
2412e3c97c2cSBryan Venteicher
2413e3c97c2cSBryan Venteicher return (bus_space_read_4(sc->vmx_iot1, sc->vmx_ioh1, r));
2414e3c97c2cSBryan Venteicher }
2415e3c97c2cSBryan Venteicher
2416e3c97c2cSBryan Venteicher static void
vmxnet3_write_bar1(struct vmxnet3_softc * sc,bus_size_t r,uint32_t v)2417e3c97c2cSBryan Venteicher vmxnet3_write_bar1(struct vmxnet3_softc *sc, bus_size_t r, uint32_t v)
2418e3c97c2cSBryan Venteicher {
2419e3c97c2cSBryan Venteicher
2420e3c97c2cSBryan Venteicher bus_space_write_4(sc->vmx_iot1, sc->vmx_ioh1, r, v);
2421e3c97c2cSBryan Venteicher }
2422e3c97c2cSBryan Venteicher
2423e3c97c2cSBryan Venteicher static void
vmxnet3_write_cmd(struct vmxnet3_softc * sc,uint32_t cmd)2424e3c97c2cSBryan Venteicher vmxnet3_write_cmd(struct vmxnet3_softc *sc, uint32_t cmd)
2425e3c97c2cSBryan Venteicher {
2426e3c97c2cSBryan Venteicher
2427e3c97c2cSBryan Venteicher vmxnet3_write_bar1(sc, VMXNET3_BAR1_CMD, cmd);
2428e3c97c2cSBryan Venteicher }
2429e3c97c2cSBryan Venteicher
2430e3c97c2cSBryan Venteicher static uint32_t
vmxnet3_read_cmd(struct vmxnet3_softc * sc,uint32_t cmd)2431e3c97c2cSBryan Venteicher vmxnet3_read_cmd(struct vmxnet3_softc *sc, uint32_t cmd)
2432e3c97c2cSBryan Venteicher {
2433e3c97c2cSBryan Venteicher
2434e3c97c2cSBryan Venteicher vmxnet3_write_cmd(sc, cmd);
2435e3c97c2cSBryan Venteicher bus_space_barrier(sc->vmx_iot1, sc->vmx_ioh1, 0, 0,
2436e3c97c2cSBryan Venteicher BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
2437e3c97c2cSBryan Venteicher return (vmxnet3_read_bar1(sc, VMXNET3_BAR1_CMD));
2438e3c97c2cSBryan Venteicher }
2439e3c97c2cSBryan Venteicher
2440e3c97c2cSBryan Venteicher static void
vmxnet3_enable_intr(struct vmxnet3_softc * sc,int irq)2441e3c97c2cSBryan Venteicher vmxnet3_enable_intr(struct vmxnet3_softc *sc, int irq)
2442e3c97c2cSBryan Venteicher {
2443e3c97c2cSBryan Venteicher
2444e3c97c2cSBryan Venteicher vmxnet3_write_bar0(sc, VMXNET3_BAR0_IMASK(irq), 0);
2445e3c97c2cSBryan Venteicher }
2446e3c97c2cSBryan Venteicher
2447e3c97c2cSBryan Venteicher static void
vmxnet3_disable_intr(struct vmxnet3_softc * sc,int irq)2448e3c97c2cSBryan Venteicher vmxnet3_disable_intr(struct vmxnet3_softc *sc, int irq)
2449e3c97c2cSBryan Venteicher {
2450e3c97c2cSBryan Venteicher
2451e3c97c2cSBryan Venteicher vmxnet3_write_bar0(sc, VMXNET3_BAR0_IMASK(irq), 1);
2452e3c97c2cSBryan Venteicher }
2453e3c97c2cSBryan Venteicher
24548f82136aSPatrick Kelsey static int
vmxnet3_tx_queue_intr_enable(if_ctx_t ctx,uint16_t qid)24558f82136aSPatrick Kelsey vmxnet3_tx_queue_intr_enable(if_ctx_t ctx, uint16_t qid)
2456e3c97c2cSBryan Venteicher {
24578f82136aSPatrick Kelsey /* Not using interrupts for TX */
24588f82136aSPatrick Kelsey return (0);
24598f82136aSPatrick Kelsey }
24608f82136aSPatrick Kelsey
24618f82136aSPatrick Kelsey static int
vmxnet3_rx_queue_intr_enable(if_ctx_t ctx,uint16_t qid)24628f82136aSPatrick Kelsey vmxnet3_rx_queue_intr_enable(if_ctx_t ctx, uint16_t qid)
24638f82136aSPatrick Kelsey {
24648f82136aSPatrick Kelsey struct vmxnet3_softc *sc;
24658f82136aSPatrick Kelsey
24668f82136aSPatrick Kelsey sc = iflib_get_softc(ctx);
24678f82136aSPatrick Kelsey vmxnet3_enable_intr(sc, sc->vmx_rxq[qid].vxrxq_intr_idx);
24688f82136aSPatrick Kelsey return (0);
24698f82136aSPatrick Kelsey }
24708f82136aSPatrick Kelsey
24718f82136aSPatrick Kelsey static void
vmxnet3_link_intr_enable(if_ctx_t ctx)24728f82136aSPatrick Kelsey vmxnet3_link_intr_enable(if_ctx_t ctx)
24738f82136aSPatrick Kelsey {
24748f82136aSPatrick Kelsey struct vmxnet3_softc *sc;
24758f82136aSPatrick Kelsey
24768f82136aSPatrick Kelsey sc = iflib_get_softc(ctx);
24778f82136aSPatrick Kelsey vmxnet3_enable_intr(sc, sc->vmx_event_intr_idx);
24788f82136aSPatrick Kelsey }
24798f82136aSPatrick Kelsey
24808f82136aSPatrick Kelsey static void
vmxnet3_intr_enable_all(if_ctx_t ctx)24818f82136aSPatrick Kelsey vmxnet3_intr_enable_all(if_ctx_t ctx)
24828f82136aSPatrick Kelsey {
24838f82136aSPatrick Kelsey struct vmxnet3_softc *sc;
24848f82136aSPatrick Kelsey if_softc_ctx_t scctx;
2485e3c97c2cSBryan Venteicher int i;
2486e3c97c2cSBryan Venteicher
24878f82136aSPatrick Kelsey sc = iflib_get_softc(ctx);
24888f82136aSPatrick Kelsey scctx = sc->vmx_scctx;
2489e3c97c2cSBryan Venteicher sc->vmx_ds->ictrl &= ~VMXNET3_ICTRL_DISABLE_ALL;
24908f82136aSPatrick Kelsey for (i = 0; i < scctx->isc_vectors; i++)
2491e3c97c2cSBryan Venteicher vmxnet3_enable_intr(sc, i);
2492e3c97c2cSBryan Venteicher }
2493e3c97c2cSBryan Venteicher
2494e3c97c2cSBryan Venteicher static void
vmxnet3_intr_disable_all(if_ctx_t ctx)24958f82136aSPatrick Kelsey vmxnet3_intr_disable_all(if_ctx_t ctx)
2496e3c97c2cSBryan Venteicher {
24978f82136aSPatrick Kelsey struct vmxnet3_softc *sc;
2498e3c97c2cSBryan Venteicher int i;
2499e3c97c2cSBryan Venteicher
25008f82136aSPatrick Kelsey sc = iflib_get_softc(ctx);
25018f82136aSPatrick Kelsey /*
25028f82136aSPatrick Kelsey * iflib may invoke this routine before vmxnet3_attach_post() has
25038f82136aSPatrick Kelsey * run, which is before the top level shared data area is
25048f82136aSPatrick Kelsey * initialized and the device made aware of it.
25058f82136aSPatrick Kelsey */
25068f82136aSPatrick Kelsey if (sc->vmx_ds != NULL)
2507e3c97c2cSBryan Venteicher sc->vmx_ds->ictrl |= VMXNET3_ICTRL_DISABLE_ALL;
25088f82136aSPatrick Kelsey for (i = 0; i < VMXNET3_MAX_INTRS; i++)
2509e3c97c2cSBryan Venteicher vmxnet3_disable_intr(sc, i);
2510e3c97c2cSBryan Venteicher }
2511e3c97c2cSBryan Venteicher
2512b6b75424SKevin Bowling static bool
vmxnet3_if_needs_restart(if_ctx_t ctx __unused,enum iflib_restart_event event)2513b6b75424SKevin Bowling vmxnet3_if_needs_restart(if_ctx_t ctx __unused, enum iflib_restart_event event)
2514b6b75424SKevin Bowling {
2515b6b75424SKevin Bowling switch (event) {
2516b6b75424SKevin Bowling case IFLIB_RESTART_VLAN_CONFIG:
25178c127413SKristof Provost return (true);
2518b6b75424SKevin Bowling default:
2519b6b75424SKevin Bowling return (false);
2520b6b75424SKevin Bowling }
2521b6b75424SKevin Bowling }
2522b6b75424SKevin Bowling
2523e3c97c2cSBryan Venteicher /*
2524e3c97c2cSBryan Venteicher * Since this is a purely paravirtualized device, we do not have
2525e3c97c2cSBryan Venteicher * to worry about DMA coherency. But at times, we must make sure
2526e3c97c2cSBryan Venteicher * both the compiler and CPU do not reorder memory operations.
2527e3c97c2cSBryan Venteicher */
2528e3c97c2cSBryan Venteicher static inline void
vmxnet3_barrier(struct vmxnet3_softc * sc,vmxnet3_barrier_t type)2529e3c97c2cSBryan Venteicher vmxnet3_barrier(struct vmxnet3_softc *sc, vmxnet3_barrier_t type)
2530e3c97c2cSBryan Venteicher {
2531e3c97c2cSBryan Venteicher
2532e3c97c2cSBryan Venteicher switch (type) {
2533e3c97c2cSBryan Venteicher case VMXNET3_BARRIER_RD:
2534e3c97c2cSBryan Venteicher rmb();
2535e3c97c2cSBryan Venteicher break;
2536e3c97c2cSBryan Venteicher case VMXNET3_BARRIER_WR:
2537e3c97c2cSBryan Venteicher wmb();
2538e3c97c2cSBryan Venteicher break;
2539e3c97c2cSBryan Venteicher case VMXNET3_BARRIER_RDWR:
2540e3c97c2cSBryan Venteicher mb();
2541e3c97c2cSBryan Venteicher break;
2542e3c97c2cSBryan Venteicher default:
2543e3c97c2cSBryan Venteicher panic("%s: bad barrier type %d", __func__, type);
2544e3c97c2cSBryan Venteicher }
2545e3c97c2cSBryan Venteicher }
2546