xref: /freebsd/sys/dev/vmware/vmxnet3/if_vmx.c (revision e557c1dd901bf51ed1c17c0c48d9d5dcd7f64d30)
1e3c97c2cSBryan Venteicher /*-
2e3c97c2cSBryan Venteicher  * Copyright (c) 2013 Tsubai Masanari
3e3c97c2cSBryan Venteicher  * Copyright (c) 2013 Bryan Venteicher <bryanv@FreeBSD.org>
4e3c97c2cSBryan Venteicher  *
5e3c97c2cSBryan Venteicher  * Permission to use, copy, modify, and distribute this software for any
6e3c97c2cSBryan Venteicher  * purpose with or without fee is hereby granted, provided that the above
7e3c97c2cSBryan Venteicher  * copyright notice and this permission notice appear in all copies.
8e3c97c2cSBryan Venteicher  *
9e3c97c2cSBryan Venteicher  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10e3c97c2cSBryan Venteicher  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11e3c97c2cSBryan Venteicher  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12e3c97c2cSBryan Venteicher  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13e3c97c2cSBryan Venteicher  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14e3c97c2cSBryan Venteicher  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15e3c97c2cSBryan Venteicher  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16e3c97c2cSBryan Venteicher  *
17e3c97c2cSBryan Venteicher  * $OpenBSD: src/sys/dev/pci/if_vmx.c,v 1.11 2013/06/22 00:28:10 uebayasi Exp $
18e3c97c2cSBryan Venteicher  */
19e3c97c2cSBryan Venteicher 
20e3c97c2cSBryan Venteicher /* Driver for VMware vmxnet3 virtual ethernet devices. */
21e3c97c2cSBryan Venteicher 
22e3c97c2cSBryan Venteicher #include <sys/cdefs.h>
23e3c97c2cSBryan Venteicher __FBSDID("$FreeBSD$");
24e3c97c2cSBryan Venteicher 
25e3c97c2cSBryan Venteicher #include <sys/param.h>
26e3c97c2cSBryan Venteicher #include <sys/systm.h>
27c3322cb9SGleb Smirnoff #include <sys/eventhandler.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>
36*e557c1ddSBryan Venteicher #include <sys/smp.h>
37*e557c1ddSBryan Venteicher #include <sys/taskqueue.h>
38e3c97c2cSBryan Venteicher #include <vm/vm.h>
39e3c97c2cSBryan Venteicher #include <vm/pmap.h>
40e3c97c2cSBryan Venteicher 
41e3c97c2cSBryan Venteicher #include <net/ethernet.h>
42e3c97c2cSBryan Venteicher #include <net/if.h>
4376039bc8SGleb Smirnoff #include <net/if_var.h>
44e3c97c2cSBryan Venteicher #include <net/if_arp.h>
45e3c97c2cSBryan Venteicher #include <net/if_dl.h>
46e3c97c2cSBryan Venteicher #include <net/if_types.h>
47e3c97c2cSBryan Venteicher #include <net/if_media.h>
48e3c97c2cSBryan Venteicher #include <net/if_vlan_var.h>
49e3c97c2cSBryan Venteicher 
50e3c97c2cSBryan Venteicher #include <net/bpf.h>
51e3c97c2cSBryan Venteicher 
52e3c97c2cSBryan Venteicher #include <netinet/in_systm.h>
53e3c97c2cSBryan Venteicher #include <netinet/in.h>
54e3c97c2cSBryan Venteicher #include <netinet/ip.h>
55e3c97c2cSBryan Venteicher #include <netinet/ip6.h>
56e3c97c2cSBryan Venteicher #include <netinet6/ip6_var.h>
57e3c97c2cSBryan Venteicher #include <netinet/udp.h>
58e3c97c2cSBryan Venteicher #include <netinet/tcp.h>
59e3c97c2cSBryan Venteicher 
60e3c97c2cSBryan Venteicher #include <machine/bus.h>
61e3c97c2cSBryan Venteicher #include <machine/resource.h>
62e3c97c2cSBryan Venteicher #include <sys/bus.h>
63e3c97c2cSBryan Venteicher #include <sys/rman.h>
64e3c97c2cSBryan Venteicher 
65e3c97c2cSBryan Venteicher #include <dev/pci/pcireg.h>
66e3c97c2cSBryan Venteicher #include <dev/pci/pcivar.h>
67e3c97c2cSBryan Venteicher 
68e3c97c2cSBryan Venteicher #include "if_vmxreg.h"
69e3c97c2cSBryan Venteicher #include "if_vmxvar.h"
70e3c97c2cSBryan Venteicher 
71e3c97c2cSBryan Venteicher #include "opt_inet.h"
72e3c97c2cSBryan Venteicher #include "opt_inet6.h"
73e3c97c2cSBryan Venteicher 
74e3c97c2cSBryan Venteicher #ifdef VMXNET3_FAILPOINTS
75e3c97c2cSBryan Venteicher #include <sys/fail.h>
76e3c97c2cSBryan Venteicher static SYSCTL_NODE(DEBUG_FP, OID_AUTO, vmxnet3, CTLFLAG_RW, 0,
77e3c97c2cSBryan Venteicher     "vmxnet3 fail points");
78e3c97c2cSBryan Venteicher #define VMXNET3_FP	_debug_fail_point_vmxnet3
79e3c97c2cSBryan Venteicher #endif
80e3c97c2cSBryan Venteicher 
81e3c97c2cSBryan Venteicher static int	vmxnet3_probe(device_t);
82e3c97c2cSBryan Venteicher static int	vmxnet3_attach(device_t);
83e3c97c2cSBryan Venteicher static int	vmxnet3_detach(device_t);
84e3c97c2cSBryan Venteicher static int	vmxnet3_shutdown(device_t);
85e3c97c2cSBryan Venteicher 
86e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_resources(struct vmxnet3_softc *);
87e3c97c2cSBryan Venteicher static void	vmxnet3_free_resources(struct vmxnet3_softc *);
88e3c97c2cSBryan Venteicher static int	vmxnet3_check_version(struct vmxnet3_softc *);
89e3c97c2cSBryan Venteicher static void	vmxnet3_initial_config(struct vmxnet3_softc *);
90*e557c1ddSBryan Venteicher static void	vmxnet3_check_multiqueue(struct vmxnet3_softc *);
91e3c97c2cSBryan Venteicher 
92e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_msix_interrupts(struct vmxnet3_softc *);
93e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_msi_interrupts(struct vmxnet3_softc *);
94e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_legacy_interrupts(struct vmxnet3_softc *);
95e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_interrupt(struct vmxnet3_softc *, int, int,
96e3c97c2cSBryan Venteicher 		    struct vmxnet3_interrupt *);
97e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_intr_resources(struct vmxnet3_softc *);
98e3c97c2cSBryan Venteicher static int	vmxnet3_setup_msix_interrupts(struct vmxnet3_softc *);
99e3c97c2cSBryan Venteicher static int	vmxnet3_setup_legacy_interrupt(struct vmxnet3_softc *);
100e3c97c2cSBryan Venteicher static int	vmxnet3_setup_interrupts(struct vmxnet3_softc *);
101e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_interrupts(struct vmxnet3_softc *);
102e3c97c2cSBryan Venteicher 
103e3c97c2cSBryan Venteicher static void	vmxnet3_free_interrupt(struct vmxnet3_softc *,
104e3c97c2cSBryan Venteicher 		    struct vmxnet3_interrupt *);
105e3c97c2cSBryan Venteicher static void	vmxnet3_free_interrupts(struct vmxnet3_softc *);
106e3c97c2cSBryan Venteicher 
107*e557c1ddSBryan Venteicher #ifndef VMXNET3_LEGACY_TX
108*e557c1ddSBryan Venteicher static int	vmxnet3_alloc_taskqueue(struct vmxnet3_softc *);
109*e557c1ddSBryan Venteicher static void	vmxnet3_start_taskqueue(struct vmxnet3_softc *);
110*e557c1ddSBryan Venteicher static void	vmxnet3_drain_taskqueue(struct vmxnet3_softc *);
111*e557c1ddSBryan Venteicher static void	vmxnet3_free_taskqueue(struct vmxnet3_softc *);
112*e557c1ddSBryan Venteicher #endif
113*e557c1ddSBryan Venteicher 
114e3c97c2cSBryan Venteicher static int	vmxnet3_init_rxq(struct vmxnet3_softc *, int);
115e3c97c2cSBryan Venteicher static int	vmxnet3_init_txq(struct vmxnet3_softc *, int);
116e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_rxtx_queues(struct vmxnet3_softc *);
117e3c97c2cSBryan Venteicher static void	vmxnet3_destroy_rxq(struct vmxnet3_rxqueue *);
118e3c97c2cSBryan Venteicher static void	vmxnet3_destroy_txq(struct vmxnet3_txqueue *);
119e3c97c2cSBryan Venteicher static void	vmxnet3_free_rxtx_queues(struct vmxnet3_softc *);
120e3c97c2cSBryan Venteicher 
121e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_shared_data(struct vmxnet3_softc *);
122e3c97c2cSBryan Venteicher static void	vmxnet3_free_shared_data(struct vmxnet3_softc *);
123e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_txq_data(struct vmxnet3_softc *);
124e3c97c2cSBryan Venteicher static void	vmxnet3_free_txq_data(struct vmxnet3_softc *);
125e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_rxq_data(struct vmxnet3_softc *);
126e3c97c2cSBryan Venteicher static void	vmxnet3_free_rxq_data(struct vmxnet3_softc *);
127e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_queue_data(struct vmxnet3_softc *);
128e3c97c2cSBryan Venteicher static void	vmxnet3_free_queue_data(struct vmxnet3_softc *);
129e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_mcast_table(struct vmxnet3_softc *);
130e3c97c2cSBryan Venteicher static void	vmxnet3_init_shared_data(struct vmxnet3_softc *);
131e3c97c2cSBryan Venteicher static void	vmxnet3_reinit_interface(struct vmxnet3_softc *);
132*e557c1ddSBryan Venteicher static void	vmxnet3_reinit_rss_shared_data(struct vmxnet3_softc *);
133e3c97c2cSBryan Venteicher static void	vmxnet3_reinit_shared_data(struct vmxnet3_softc *);
134e3c97c2cSBryan Venteicher static int	vmxnet3_alloc_data(struct vmxnet3_softc *);
135e3c97c2cSBryan Venteicher static void	vmxnet3_free_data(struct vmxnet3_softc *);
136e3c97c2cSBryan Venteicher static int	vmxnet3_setup_interface(struct vmxnet3_softc *);
137e3c97c2cSBryan Venteicher 
138e3c97c2cSBryan Venteicher static void	vmxnet3_evintr(struct vmxnet3_softc *);
139e3c97c2cSBryan Venteicher static void	vmxnet3_txq_eof(struct vmxnet3_txqueue *);
140e3c97c2cSBryan Venteicher static void	vmxnet3_rx_csum(struct vmxnet3_rxcompdesc *, struct mbuf *);
141e3c97c2cSBryan Venteicher static int	vmxnet3_newbuf(struct vmxnet3_softc *, struct vmxnet3_rxring *);
142e3c97c2cSBryan Venteicher static void	vmxnet3_rxq_eof_discard(struct vmxnet3_rxqueue *,
143e3c97c2cSBryan Venteicher 		    struct vmxnet3_rxring *, int);
144e3c97c2cSBryan Venteicher static void	vmxnet3_rxq_eof(struct vmxnet3_rxqueue *);
145e3c97c2cSBryan Venteicher static void	vmxnet3_legacy_intr(void *);
146e3c97c2cSBryan Venteicher static void	vmxnet3_txq_intr(void *);
147e3c97c2cSBryan Venteicher static void	vmxnet3_rxq_intr(void *);
148e3c97c2cSBryan Venteicher static void	vmxnet3_event_intr(void *);
149e3c97c2cSBryan Venteicher 
150e3c97c2cSBryan Venteicher static void	vmxnet3_txstop(struct vmxnet3_softc *, struct vmxnet3_txqueue *);
151e3c97c2cSBryan Venteicher static void	vmxnet3_rxstop(struct vmxnet3_softc *, struct vmxnet3_rxqueue *);
152e3c97c2cSBryan Venteicher static void	vmxnet3_stop(struct vmxnet3_softc *);
153e3c97c2cSBryan Venteicher 
154e3c97c2cSBryan Venteicher static void	vmxnet3_txinit(struct vmxnet3_softc *, struct vmxnet3_txqueue *);
155e3c97c2cSBryan Venteicher static int	vmxnet3_rxinit(struct vmxnet3_softc *, struct vmxnet3_rxqueue *);
156e3c97c2cSBryan Venteicher static int	vmxnet3_reinit_queues(struct vmxnet3_softc *);
157e3c97c2cSBryan Venteicher static int	vmxnet3_enable_device(struct vmxnet3_softc *);
158e3c97c2cSBryan Venteicher static void	vmxnet3_reinit_rxfilters(struct vmxnet3_softc *);
159e3c97c2cSBryan Venteicher static int	vmxnet3_reinit(struct vmxnet3_softc *);
160e3c97c2cSBryan Venteicher static void	vmxnet3_init_locked(struct vmxnet3_softc *);
161e3c97c2cSBryan Venteicher static void	vmxnet3_init(void *);
162e3c97c2cSBryan Venteicher 
163*e557c1ddSBryan Venteicher static int	vmxnet3_txq_offload_ctx(struct vmxnet3_txqueue *,struct mbuf *,
164*e557c1ddSBryan Venteicher 		    int *, int *, int *);
165e3c97c2cSBryan Venteicher static int	vmxnet3_txq_load_mbuf(struct vmxnet3_txqueue *, struct mbuf **,
166e3c97c2cSBryan Venteicher 		    bus_dmamap_t, bus_dma_segment_t [], int *);
167e3c97c2cSBryan Venteicher static void	vmxnet3_txq_unload_mbuf(struct vmxnet3_txqueue *, bus_dmamap_t);
168e3c97c2cSBryan Venteicher static int	vmxnet3_txq_encap(struct vmxnet3_txqueue *, struct mbuf **);
169*e557c1ddSBryan Venteicher static void	vmxnet3_txq_update_pending(struct vmxnet3_txqueue *);
170*e557c1ddSBryan Venteicher #ifdef VMXNET3_LEGACY_TX
171e3c97c2cSBryan Venteicher static void	vmxnet3_start_locked(struct ifnet *);
172e3c97c2cSBryan Venteicher static void	vmxnet3_start(struct ifnet *);
173*e557c1ddSBryan Venteicher #else
174*e557c1ddSBryan Venteicher static int	vmxnet3_txq_mq_start_locked(struct vmxnet3_txqueue *,
175*e557c1ddSBryan Venteicher 		    struct mbuf *);
176*e557c1ddSBryan Venteicher static int	vmxnet3_txq_mq_start(struct ifnet *, struct mbuf *);
177*e557c1ddSBryan Venteicher static void	vmxnet3_txq_tq_deferred(void *, int);
178*e557c1ddSBryan Venteicher #endif
179*e557c1ddSBryan Venteicher static void	vmxnet3_txq_start(struct vmxnet3_txqueue *);
180*e557c1ddSBryan Venteicher static void	vmxnet3_tx_start_all(struct vmxnet3_softc *);
181e3c97c2cSBryan Venteicher 
182e3c97c2cSBryan Venteicher static void	vmxnet3_update_vlan_filter(struct vmxnet3_softc *, int,
183e3c97c2cSBryan Venteicher 		    uint16_t);
184e3c97c2cSBryan Venteicher static void	vmxnet3_register_vlan(void *, struct ifnet *, uint16_t);
185e3c97c2cSBryan Venteicher static void	vmxnet3_unregister_vlan(void *, struct ifnet *, uint16_t);
186e3c97c2cSBryan Venteicher static void	vmxnet3_set_rxfilter(struct vmxnet3_softc *);
187e3c97c2cSBryan Venteicher static int	vmxnet3_change_mtu(struct vmxnet3_softc *, int);
188e3c97c2cSBryan Venteicher static int	vmxnet3_ioctl(struct ifnet *, u_long, caddr_t);
189e3c97c2cSBryan Venteicher 
190*e557c1ddSBryan Venteicher #ifndef VMXNET3_LEGACY_TX
191*e557c1ddSBryan Venteicher static void	vmxnet3_qflush(struct ifnet *);
192*e557c1ddSBryan Venteicher #endif
193*e557c1ddSBryan Venteicher 
194e3c97c2cSBryan Venteicher static int	vmxnet3_watchdog(struct vmxnet3_txqueue *);
195*e557c1ddSBryan Venteicher static void	vmxnet3_refresh_host_stats(struct vmxnet3_softc *);
196*e557c1ddSBryan Venteicher static void	vmxnet3_txq_accum_stats(struct vmxnet3_txqueue *,
197*e557c1ddSBryan Venteicher 		    struct vmxnet3_txq_stats *);
198*e557c1ddSBryan Venteicher static void	vmxnet3_rxq_accum_stats(struct vmxnet3_rxqueue *,
199*e557c1ddSBryan Venteicher 		    struct vmxnet3_rxq_stats *);
200e3c97c2cSBryan Venteicher static void	vmxnet3_tick(void *);
201e3c97c2cSBryan Venteicher static void	vmxnet3_link_status(struct vmxnet3_softc *);
202e3c97c2cSBryan Venteicher static void	vmxnet3_media_status(struct ifnet *, struct ifmediareq *);
203e3c97c2cSBryan Venteicher static int	vmxnet3_media_change(struct ifnet *);
204e3c97c2cSBryan Venteicher static void	vmxnet3_set_lladdr(struct vmxnet3_softc *);
205e3c97c2cSBryan Venteicher static void	vmxnet3_get_lladdr(struct vmxnet3_softc *);
206e3c97c2cSBryan Venteicher 
207e3c97c2cSBryan Venteicher static void	vmxnet3_setup_txq_sysctl(struct vmxnet3_txqueue *,
208e3c97c2cSBryan Venteicher 		    struct sysctl_ctx_list *, struct sysctl_oid_list *);
209e3c97c2cSBryan Venteicher static void	vmxnet3_setup_rxq_sysctl(struct vmxnet3_rxqueue *,
210e3c97c2cSBryan Venteicher 		    struct sysctl_ctx_list *, struct sysctl_oid_list *);
211e3c97c2cSBryan Venteicher static void	vmxnet3_setup_queue_sysctl(struct vmxnet3_softc *,
212e3c97c2cSBryan Venteicher 		    struct sysctl_ctx_list *, struct sysctl_oid_list *);
213e3c97c2cSBryan Venteicher static void	vmxnet3_setup_sysctl(struct vmxnet3_softc *);
214e3c97c2cSBryan Venteicher 
215e3c97c2cSBryan Venteicher static void	vmxnet3_write_bar0(struct vmxnet3_softc *, bus_size_t,
216e3c97c2cSBryan Venteicher 		    uint32_t);
217e3c97c2cSBryan Venteicher static uint32_t	vmxnet3_read_bar1(struct vmxnet3_softc *, bus_size_t);
218e3c97c2cSBryan Venteicher static void	vmxnet3_write_bar1(struct vmxnet3_softc *, bus_size_t,
219e3c97c2cSBryan Venteicher 		    uint32_t);
220e3c97c2cSBryan Venteicher static void	vmxnet3_write_cmd(struct vmxnet3_softc *, uint32_t);
221e3c97c2cSBryan Venteicher static uint32_t	vmxnet3_read_cmd(struct vmxnet3_softc *, uint32_t);
222e3c97c2cSBryan Venteicher 
223e3c97c2cSBryan Venteicher static void	vmxnet3_enable_intr(struct vmxnet3_softc *, int);
224e3c97c2cSBryan Venteicher static void	vmxnet3_disable_intr(struct vmxnet3_softc *, int);
225e3c97c2cSBryan Venteicher static void	vmxnet3_enable_all_intrs(struct vmxnet3_softc *);
226e3c97c2cSBryan Venteicher static void	vmxnet3_disable_all_intrs(struct vmxnet3_softc *);
227e3c97c2cSBryan Venteicher 
228e3c97c2cSBryan Venteicher static int	vmxnet3_dma_malloc(struct vmxnet3_softc *, bus_size_t,
229e3c97c2cSBryan Venteicher 		    bus_size_t, struct vmxnet3_dma_alloc *);
230e3c97c2cSBryan Venteicher static void	vmxnet3_dma_free(struct vmxnet3_softc *,
231e3c97c2cSBryan Venteicher 		    struct vmxnet3_dma_alloc *);
2323c5dfe89SBryan Venteicher static int	vmxnet3_tunable_int(struct vmxnet3_softc *,
2333c5dfe89SBryan Venteicher 		    const char *, int);
234e3c97c2cSBryan Venteicher 
235e3c97c2cSBryan Venteicher typedef enum {
236e3c97c2cSBryan Venteicher 	VMXNET3_BARRIER_RD,
237e3c97c2cSBryan Venteicher 	VMXNET3_BARRIER_WR,
238e3c97c2cSBryan Venteicher 	VMXNET3_BARRIER_RDWR,
239e3c97c2cSBryan Venteicher } vmxnet3_barrier_t;
240e3c97c2cSBryan Venteicher 
241e3c97c2cSBryan Venteicher static void	vmxnet3_barrier(struct vmxnet3_softc *, vmxnet3_barrier_t);
242e3c97c2cSBryan Venteicher 
2433c5dfe89SBryan Venteicher /* Tunables. */
244*e557c1ddSBryan Venteicher static int vmxnet3_mq_disable = 0;
245*e557c1ddSBryan Venteicher TUNABLE_INT("hw.vmx.mq_disable", &vmxnet3_mq_disable);
246*e557c1ddSBryan Venteicher static int vmxnet3_default_txnqueue = VMXNET3_DEF_TX_QUEUES;
247*e557c1ddSBryan Venteicher TUNABLE_INT("hw.vmx.txnqueue", &vmxnet3_default_txnqueue);
248*e557c1ddSBryan Venteicher static int vmxnet3_default_rxnqueue = VMXNET3_DEF_RX_QUEUES;
249*e557c1ddSBryan Venteicher TUNABLE_INT("hw.vmx.rxnqueue", &vmxnet3_default_rxnqueue);
2503c5dfe89SBryan Venteicher static int vmxnet3_default_txndesc = VMXNET3_DEF_TX_NDESC;
2513c5dfe89SBryan Venteicher TUNABLE_INT("hw.vmx.txndesc", &vmxnet3_default_txndesc);
2523c5dfe89SBryan Venteicher static int vmxnet3_default_rxndesc = VMXNET3_DEF_RX_NDESC;
2533c5dfe89SBryan Venteicher TUNABLE_INT("hw.vmx.rxndesc", &vmxnet3_default_rxndesc);
2543c5dfe89SBryan Venteicher 
255e3c97c2cSBryan Venteicher static device_method_t vmxnet3_methods[] = {
256e3c97c2cSBryan Venteicher 	/* Device interface. */
257e3c97c2cSBryan Venteicher 	DEVMETHOD(device_probe,		vmxnet3_probe),
258e3c97c2cSBryan Venteicher 	DEVMETHOD(device_attach,	vmxnet3_attach),
259e3c97c2cSBryan Venteicher 	DEVMETHOD(device_detach,	vmxnet3_detach),
260e3c97c2cSBryan Venteicher 	DEVMETHOD(device_shutdown,	vmxnet3_shutdown),
261e3c97c2cSBryan Venteicher 
262e3c97c2cSBryan Venteicher 	DEVMETHOD_END
263e3c97c2cSBryan Venteicher };
264e3c97c2cSBryan Venteicher 
265e3c97c2cSBryan Venteicher static driver_t vmxnet3_driver = {
266e3c97c2cSBryan Venteicher 	"vmx", vmxnet3_methods, sizeof(struct vmxnet3_softc)
267e3c97c2cSBryan Venteicher };
268e3c97c2cSBryan Venteicher 
269e3c97c2cSBryan Venteicher static devclass_t vmxnet3_devclass;
270e3c97c2cSBryan Venteicher DRIVER_MODULE(vmx, pci, vmxnet3_driver, vmxnet3_devclass, 0, 0);
271e3c97c2cSBryan Venteicher 
272e3c97c2cSBryan Venteicher MODULE_DEPEND(vmx, pci, 1, 1, 1);
273e3c97c2cSBryan Venteicher MODULE_DEPEND(vmx, ether, 1, 1, 1);
274e3c97c2cSBryan Venteicher 
275e3c97c2cSBryan Venteicher #define VMXNET3_VMWARE_VENDOR_ID	0x15AD
276e3c97c2cSBryan Venteicher #define VMXNET3_VMWARE_DEVICE_ID	0x07B0
277e3c97c2cSBryan Venteicher 
278e3c97c2cSBryan Venteicher static int
279e3c97c2cSBryan Venteicher vmxnet3_probe(device_t dev)
280e3c97c2cSBryan Venteicher {
281e3c97c2cSBryan Venteicher 
282e3c97c2cSBryan Venteicher 	if (pci_get_vendor(dev) == VMXNET3_VMWARE_VENDOR_ID &&
283e3c97c2cSBryan Venteicher 	    pci_get_device(dev) == VMXNET3_VMWARE_DEVICE_ID) {
284e3c97c2cSBryan Venteicher 		device_set_desc(dev, "VMware VMXNET3 Ethernet Adapter");
285e3c97c2cSBryan Venteicher 		return (BUS_PROBE_DEFAULT);
286e3c97c2cSBryan Venteicher 	}
287e3c97c2cSBryan Venteicher 
288e3c97c2cSBryan Venteicher 	return (ENXIO);
289e3c97c2cSBryan Venteicher }
290e3c97c2cSBryan Venteicher 
291e3c97c2cSBryan Venteicher static int
292e3c97c2cSBryan Venteicher vmxnet3_attach(device_t dev)
293e3c97c2cSBryan Venteicher {
294e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
295e3c97c2cSBryan Venteicher 	int error;
296e3c97c2cSBryan Venteicher 
297e3c97c2cSBryan Venteicher 	sc = device_get_softc(dev);
298e3c97c2cSBryan Venteicher 	sc->vmx_dev = dev;
299e3c97c2cSBryan Venteicher 
300e3c97c2cSBryan Venteicher 	pci_enable_busmaster(dev);
301e3c97c2cSBryan Venteicher 
302e3c97c2cSBryan Venteicher 	VMXNET3_CORE_LOCK_INIT(sc, device_get_nameunit(dev));
303e3c97c2cSBryan Venteicher 	callout_init_mtx(&sc->vmx_tick, &sc->vmx_mtx, 0);
304e3c97c2cSBryan Venteicher 
305e3c97c2cSBryan Venteicher 	vmxnet3_initial_config(sc);
306e3c97c2cSBryan Venteicher 
307e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_resources(sc);
308e3c97c2cSBryan Venteicher 	if (error)
309e3c97c2cSBryan Venteicher 		goto fail;
310e3c97c2cSBryan Venteicher 
311e3c97c2cSBryan Venteicher 	error = vmxnet3_check_version(sc);
312e3c97c2cSBryan Venteicher 	if (error)
313e3c97c2cSBryan Venteicher 		goto fail;
314e3c97c2cSBryan Venteicher 
315e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_rxtx_queues(sc);
316e3c97c2cSBryan Venteicher 	if (error)
317e3c97c2cSBryan Venteicher 		goto fail;
318e3c97c2cSBryan Venteicher 
319*e557c1ddSBryan Venteicher #ifndef VMXNET3_LEGACY_TX
320*e557c1ddSBryan Venteicher 	error = vmxnet3_alloc_taskqueue(sc);
321*e557c1ddSBryan Venteicher 	if (error)
322*e557c1ddSBryan Venteicher 		goto fail;
323*e557c1ddSBryan Venteicher #endif
324*e557c1ddSBryan Venteicher 
325e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_interrupts(sc);
326e3c97c2cSBryan Venteicher 	if (error)
327e3c97c2cSBryan Venteicher 		goto fail;
328e3c97c2cSBryan Venteicher 
329*e557c1ddSBryan Venteicher 	vmxnet3_check_multiqueue(sc);
330*e557c1ddSBryan Venteicher 
331e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_data(sc);
332e3c97c2cSBryan Venteicher 	if (error)
333e3c97c2cSBryan Venteicher 		goto fail;
334e3c97c2cSBryan Venteicher 
335e3c97c2cSBryan Venteicher 	error = vmxnet3_setup_interface(sc);
336e3c97c2cSBryan Venteicher 	if (error)
337e3c97c2cSBryan Venteicher 		goto fail;
338e3c97c2cSBryan Venteicher 
339e3c97c2cSBryan Venteicher 	error = vmxnet3_setup_interrupts(sc);
340e3c97c2cSBryan Venteicher 	if (error) {
341e3c97c2cSBryan Venteicher 		ether_ifdetach(sc->vmx_ifp);
342e3c97c2cSBryan Venteicher 		device_printf(dev, "could not set up interrupt\n");
343e3c97c2cSBryan Venteicher 		goto fail;
344e3c97c2cSBryan Venteicher 	}
345e3c97c2cSBryan Venteicher 
346e3c97c2cSBryan Venteicher 	vmxnet3_setup_sysctl(sc);
347*e557c1ddSBryan Venteicher #ifndef VMXNET3_LEGACY_TX
348*e557c1ddSBryan Venteicher 	vmxnet3_start_taskqueue(sc);
349*e557c1ddSBryan Venteicher #endif
350e3c97c2cSBryan Venteicher 
351e3c97c2cSBryan Venteicher fail:
352e3c97c2cSBryan Venteicher 	if (error)
353e3c97c2cSBryan Venteicher 		vmxnet3_detach(dev);
354e3c97c2cSBryan Venteicher 
355e3c97c2cSBryan Venteicher 	return (error);
356e3c97c2cSBryan Venteicher }
357e3c97c2cSBryan Venteicher 
358e3c97c2cSBryan Venteicher static int
359e3c97c2cSBryan Venteicher vmxnet3_detach(device_t dev)
360e3c97c2cSBryan Venteicher {
361e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
362e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
363e3c97c2cSBryan Venteicher 
364e3c97c2cSBryan Venteicher 	sc = device_get_softc(dev);
365e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
366e3c97c2cSBryan Venteicher 
367e3c97c2cSBryan Venteicher 	if (device_is_attached(dev)) {
368e3c97c2cSBryan Venteicher 		VMXNET3_CORE_LOCK(sc);
369e3c97c2cSBryan Venteicher 		vmxnet3_stop(sc);
370e3c97c2cSBryan Venteicher 		VMXNET3_CORE_UNLOCK(sc);
371*e557c1ddSBryan Venteicher 
372e3c97c2cSBryan Venteicher 		callout_drain(&sc->vmx_tick);
373*e557c1ddSBryan Venteicher #ifndef VMXNET3_LEGACY_TX
374*e557c1ddSBryan Venteicher 		vmxnet3_drain_taskqueue(sc);
375*e557c1ddSBryan Venteicher #endif
376*e557c1ddSBryan Venteicher 
377*e557c1ddSBryan Venteicher 		ether_ifdetach(ifp);
378e3c97c2cSBryan Venteicher 	}
379e3c97c2cSBryan Venteicher 
380e3c97c2cSBryan Venteicher 	if (sc->vmx_vlan_attach != NULL) {
381e3c97c2cSBryan Venteicher 		EVENTHANDLER_DEREGISTER(vlan_config, sc->vmx_vlan_attach);
382e3c97c2cSBryan Venteicher 		sc->vmx_vlan_attach = NULL;
383e3c97c2cSBryan Venteicher 	}
384e3c97c2cSBryan Venteicher 	if (sc->vmx_vlan_detach != NULL) {
385e3c97c2cSBryan Venteicher 		EVENTHANDLER_DEREGISTER(vlan_config, sc->vmx_vlan_detach);
386e3c97c2cSBryan Venteicher 		sc->vmx_vlan_detach = NULL;
387e3c97c2cSBryan Venteicher 	}
388e3c97c2cSBryan Venteicher 
389*e557c1ddSBryan Venteicher #ifndef VMXNET3_LEGACY_TX
390*e557c1ddSBryan Venteicher 	vmxnet3_free_taskqueue(sc);
391*e557c1ddSBryan Venteicher #endif
392e3c97c2cSBryan Venteicher 	vmxnet3_free_interrupts(sc);
393e3c97c2cSBryan Venteicher 
394e3c97c2cSBryan Venteicher 	if (ifp != NULL) {
395e3c97c2cSBryan Venteicher 		if_free(ifp);
396e3c97c2cSBryan Venteicher 		sc->vmx_ifp = NULL;
397e3c97c2cSBryan Venteicher 	}
398e3c97c2cSBryan Venteicher 
399e3c97c2cSBryan Venteicher 	ifmedia_removeall(&sc->vmx_media);
400e3c97c2cSBryan Venteicher 
401e3c97c2cSBryan Venteicher 	vmxnet3_free_data(sc);
402e3c97c2cSBryan Venteicher 	vmxnet3_free_resources(sc);
403e3c97c2cSBryan Venteicher 	vmxnet3_free_rxtx_queues(sc);
404e3c97c2cSBryan Venteicher 
405e3c97c2cSBryan Venteicher 	VMXNET3_CORE_LOCK_DESTROY(sc);
406e3c97c2cSBryan Venteicher 
407e3c97c2cSBryan Venteicher 	return (0);
408e3c97c2cSBryan Venteicher }
409e3c97c2cSBryan Venteicher 
410e3c97c2cSBryan Venteicher static int
411e3c97c2cSBryan Venteicher vmxnet3_shutdown(device_t dev)
412e3c97c2cSBryan Venteicher {
413e3c97c2cSBryan Venteicher 
414e3c97c2cSBryan Venteicher 	return (0);
415e3c97c2cSBryan Venteicher }
416e3c97c2cSBryan Venteicher 
417e3c97c2cSBryan Venteicher static int
418e3c97c2cSBryan Venteicher vmxnet3_alloc_resources(struct vmxnet3_softc *sc)
419e3c97c2cSBryan Venteicher {
420e3c97c2cSBryan Venteicher 	device_t dev;
421e3c97c2cSBryan Venteicher 	int rid;
422e3c97c2cSBryan Venteicher 
423e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
424e3c97c2cSBryan Venteicher 
425e3c97c2cSBryan Venteicher 	rid = PCIR_BAR(0);
426e3c97c2cSBryan Venteicher 	sc->vmx_res0 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
427e3c97c2cSBryan Venteicher 	    RF_ACTIVE);
428e3c97c2cSBryan Venteicher 	if (sc->vmx_res0 == NULL) {
429e3c97c2cSBryan Venteicher 		device_printf(dev,
430e3c97c2cSBryan Venteicher 		    "could not map BAR0 memory\n");
431e3c97c2cSBryan Venteicher 		return (ENXIO);
432e3c97c2cSBryan Venteicher 	}
433e3c97c2cSBryan Venteicher 
434e3c97c2cSBryan Venteicher 	sc->vmx_iot0 = rman_get_bustag(sc->vmx_res0);
435e3c97c2cSBryan Venteicher 	sc->vmx_ioh0 = rman_get_bushandle(sc->vmx_res0);
436e3c97c2cSBryan Venteicher 
437e3c97c2cSBryan Venteicher 	rid = PCIR_BAR(1);
438e3c97c2cSBryan Venteicher 	sc->vmx_res1 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
439e3c97c2cSBryan Venteicher 	    RF_ACTIVE);
440e3c97c2cSBryan Venteicher 	if (sc->vmx_res1 == NULL) {
441e3c97c2cSBryan Venteicher 		device_printf(dev,
442e3c97c2cSBryan Venteicher 		    "could not map BAR1 memory\n");
443e3c97c2cSBryan Venteicher 		return (ENXIO);
444e3c97c2cSBryan Venteicher 	}
445e3c97c2cSBryan Venteicher 
446e3c97c2cSBryan Venteicher 	sc->vmx_iot1 = rman_get_bustag(sc->vmx_res1);
447e3c97c2cSBryan Venteicher 	sc->vmx_ioh1 = rman_get_bushandle(sc->vmx_res1);
448e3c97c2cSBryan Venteicher 
449e3c97c2cSBryan Venteicher 	if (pci_find_cap(dev, PCIY_MSIX, NULL) == 0) {
450e3c97c2cSBryan Venteicher 		rid = PCIR_BAR(2);
451e3c97c2cSBryan Venteicher 		sc->vmx_msix_res = bus_alloc_resource_any(dev,
452e3c97c2cSBryan Venteicher 		    SYS_RES_MEMORY, &rid, RF_ACTIVE);
453e3c97c2cSBryan Venteicher 	}
454e3c97c2cSBryan Venteicher 
455e3c97c2cSBryan Venteicher 	if (sc->vmx_msix_res == NULL)
456e3c97c2cSBryan Venteicher 		sc->vmx_flags |= VMXNET3_FLAG_NO_MSIX;
457e3c97c2cSBryan Venteicher 
458e3c97c2cSBryan Venteicher 	return (0);
459e3c97c2cSBryan Venteicher }
460e3c97c2cSBryan Venteicher 
461e3c97c2cSBryan Venteicher static void
462e3c97c2cSBryan Venteicher vmxnet3_free_resources(struct vmxnet3_softc *sc)
463e3c97c2cSBryan Venteicher {
464e3c97c2cSBryan Venteicher 	device_t dev;
465e3c97c2cSBryan Venteicher 	int rid;
466e3c97c2cSBryan Venteicher 
467e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
468e3c97c2cSBryan Venteicher 
469e3c97c2cSBryan Venteicher 	if (sc->vmx_res0 != NULL) {
470e3c97c2cSBryan Venteicher 		rid = PCIR_BAR(0);
471e3c97c2cSBryan Venteicher 		bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->vmx_res0);
472e3c97c2cSBryan Venteicher 		sc->vmx_res0 = NULL;
473e3c97c2cSBryan Venteicher 	}
474e3c97c2cSBryan Venteicher 
475e3c97c2cSBryan Venteicher 	if (sc->vmx_res1 != NULL) {
476e3c97c2cSBryan Venteicher 		rid = PCIR_BAR(1);
477e3c97c2cSBryan Venteicher 		bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->vmx_res1);
478e3c97c2cSBryan Venteicher 		sc->vmx_res1 = NULL;
479e3c97c2cSBryan Venteicher 	}
480e3c97c2cSBryan Venteicher 
481e3c97c2cSBryan Venteicher 	if (sc->vmx_msix_res != NULL) {
482e3c97c2cSBryan Venteicher 		rid = PCIR_BAR(2);
483e3c97c2cSBryan Venteicher 		bus_release_resource(dev, SYS_RES_MEMORY, rid,
484e3c97c2cSBryan Venteicher 		    sc->vmx_msix_res);
485e3c97c2cSBryan Venteicher 		sc->vmx_msix_res = NULL;
486e3c97c2cSBryan Venteicher 	}
487e3c97c2cSBryan Venteicher }
488e3c97c2cSBryan Venteicher 
489e3c97c2cSBryan Venteicher static int
490e3c97c2cSBryan Venteicher vmxnet3_check_version(struct vmxnet3_softc *sc)
491e3c97c2cSBryan Venteicher {
492e3c97c2cSBryan Venteicher 	device_t dev;
493e3c97c2cSBryan Venteicher 	uint32_t version;
494e3c97c2cSBryan Venteicher 
495e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
496e3c97c2cSBryan Venteicher 
497e3c97c2cSBryan Venteicher 	version = vmxnet3_read_bar1(sc, VMXNET3_BAR1_VRRS);
498e3c97c2cSBryan Venteicher 	if ((version & 0x01) == 0) {
499e3c97c2cSBryan Venteicher 		device_printf(dev, "unsupported hardware version %#x\n",
500e3c97c2cSBryan Venteicher 		    version);
501e3c97c2cSBryan Venteicher 		return (ENOTSUP);
5023c965775SBryan Venteicher 	}
503e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_VRRS, 1);
504e3c97c2cSBryan Venteicher 
505e3c97c2cSBryan Venteicher 	version = vmxnet3_read_bar1(sc, VMXNET3_BAR1_UVRS);
506e3c97c2cSBryan Venteicher 	if ((version & 0x01) == 0) {
507e3c97c2cSBryan Venteicher 		device_printf(dev, "unsupported UPT version %#x\n", version);
508e3c97c2cSBryan Venteicher 		return (ENOTSUP);
5093c965775SBryan Venteicher 	}
510e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_UVRS, 1);
511e3c97c2cSBryan Venteicher 
512e3c97c2cSBryan Venteicher 	return (0);
513e3c97c2cSBryan Venteicher }
514e3c97c2cSBryan Venteicher 
515e3c97c2cSBryan Venteicher static void
516e3c97c2cSBryan Venteicher vmxnet3_initial_config(struct vmxnet3_softc *sc)
517e3c97c2cSBryan Venteicher {
518*e557c1ddSBryan Venteicher 	int nqueue, ndesc;
519e3c97c2cSBryan Venteicher 
520*e557c1ddSBryan Venteicher 	nqueue = vmxnet3_tunable_int(sc, "txnqueue", vmxnet3_default_txnqueue);
521*e557c1ddSBryan Venteicher 	if (nqueue > VMXNET3_MAX_TX_QUEUES || nqueue < 1)
522*e557c1ddSBryan Venteicher 		nqueue = VMXNET3_DEF_TX_QUEUES;
523*e557c1ddSBryan Venteicher 	if (nqueue > mp_ncpus)
524*e557c1ddSBryan Venteicher 		nqueue = mp_ncpus;
525*e557c1ddSBryan Venteicher 	sc->vmx_max_ntxqueues = nqueue;
526*e557c1ddSBryan Venteicher 
527*e557c1ddSBryan Venteicher 	nqueue = vmxnet3_tunable_int(sc, "rxnqueue", vmxnet3_default_rxnqueue);
528*e557c1ddSBryan Venteicher 	if (nqueue > VMXNET3_MAX_RX_QUEUES || nqueue < 1)
529*e557c1ddSBryan Venteicher 		nqueue = VMXNET3_DEF_RX_QUEUES;
530*e557c1ddSBryan Venteicher 	if (nqueue > mp_ncpus)
531*e557c1ddSBryan Venteicher 		nqueue = mp_ncpus;
532*e557c1ddSBryan Venteicher 	sc->vmx_max_nrxqueues = nqueue;
533*e557c1ddSBryan Venteicher 
534*e557c1ddSBryan Venteicher 	if (vmxnet3_tunable_int(sc, "mq_disable", vmxnet3_mq_disable)) {
535*e557c1ddSBryan Venteicher 		sc->vmx_max_nrxqueues = 1;
536*e557c1ddSBryan Venteicher 		sc->vmx_max_ntxqueues = 1;
537*e557c1ddSBryan Venteicher 	}
5383c5dfe89SBryan Venteicher 
5393c5dfe89SBryan Venteicher 	ndesc = vmxnet3_tunable_int(sc, "txd", vmxnet3_default_txndesc);
5403c5dfe89SBryan Venteicher 	if (ndesc > VMXNET3_MAX_TX_NDESC || ndesc < VMXNET3_MIN_TX_NDESC)
5413c5dfe89SBryan Venteicher 		ndesc = VMXNET3_DEF_TX_NDESC;
5423c5dfe89SBryan Venteicher 	if (ndesc & VMXNET3_MASK_TX_NDESC)
5433c5dfe89SBryan Venteicher 		ndesc &= ~VMXNET3_MASK_TX_NDESC;
5443c5dfe89SBryan Venteicher 	sc->vmx_ntxdescs = ndesc;
5453c5dfe89SBryan Venteicher 
5463c5dfe89SBryan Venteicher 	ndesc = vmxnet3_tunable_int(sc, "rxd", vmxnet3_default_rxndesc);
5473c5dfe89SBryan Venteicher 	if (ndesc > VMXNET3_MAX_RX_NDESC || ndesc < VMXNET3_MIN_RX_NDESC)
5483c5dfe89SBryan Venteicher 		ndesc = VMXNET3_DEF_RX_NDESC;
5493c5dfe89SBryan Venteicher 	if (ndesc & VMXNET3_MASK_RX_NDESC)
5503c5dfe89SBryan Venteicher 		ndesc &= ~VMXNET3_MASK_RX_NDESC;
5513c5dfe89SBryan Venteicher 	sc->vmx_nrxdescs = ndesc;
552e3c97c2cSBryan Venteicher 	sc->vmx_max_rxsegs = VMXNET3_MAX_RX_SEGS;
553e3c97c2cSBryan Venteicher }
554e3c97c2cSBryan Venteicher 
555*e557c1ddSBryan Venteicher static void
556*e557c1ddSBryan Venteicher vmxnet3_check_multiqueue(struct vmxnet3_softc *sc)
557*e557c1ddSBryan Venteicher {
558*e557c1ddSBryan Venteicher 
559*e557c1ddSBryan Venteicher 	if (sc->vmx_intr_type != VMXNET3_IT_MSIX)
560*e557c1ddSBryan Venteicher 		goto out;
561*e557c1ddSBryan Venteicher 
562*e557c1ddSBryan Venteicher 	/* BMV: Just use the maximum configured for now. */
563*e557c1ddSBryan Venteicher 	sc->vmx_nrxqueues = sc->vmx_max_nrxqueues;
564*e557c1ddSBryan Venteicher 	sc->vmx_ntxqueues = sc->vmx_max_ntxqueues;
565*e557c1ddSBryan Venteicher 
566*e557c1ddSBryan Venteicher 	if (sc->vmx_nrxqueues > 1)
567*e557c1ddSBryan Venteicher 		sc->vmx_flags |= VMXNET3_FLAG_RSS;
568*e557c1ddSBryan Venteicher 
569*e557c1ddSBryan Venteicher 	return;
570*e557c1ddSBryan Venteicher 
571*e557c1ddSBryan Venteicher out:
572*e557c1ddSBryan Venteicher 	sc->vmx_ntxqueues = 1;
573*e557c1ddSBryan Venteicher 	sc->vmx_nrxqueues = 1;
574*e557c1ddSBryan Venteicher }
575*e557c1ddSBryan Venteicher 
576e3c97c2cSBryan Venteicher static int
577e3c97c2cSBryan Venteicher vmxnet3_alloc_msix_interrupts(struct vmxnet3_softc *sc)
578e3c97c2cSBryan Venteicher {
579e3c97c2cSBryan Venteicher 	device_t dev;
580e3c97c2cSBryan Venteicher 	int nmsix, cnt, required;
581e3c97c2cSBryan Venteicher 
582e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
583e3c97c2cSBryan Venteicher 
584e3c97c2cSBryan Venteicher 	if (sc->vmx_flags & VMXNET3_FLAG_NO_MSIX)
585e3c97c2cSBryan Venteicher 		return (1);
586e3c97c2cSBryan Venteicher 
587e3c97c2cSBryan Venteicher 	/* Allocate an additional vector for the events interrupt. */
588*e557c1ddSBryan Venteicher 	required = sc->vmx_max_nrxqueues + sc->vmx_max_ntxqueues + 1;
589e3c97c2cSBryan Venteicher 
590e3c97c2cSBryan Venteicher 	nmsix = pci_msix_count(dev);
591e3c97c2cSBryan Venteicher 	if (nmsix < required)
592e3c97c2cSBryan Venteicher 		return (1);
593e3c97c2cSBryan Venteicher 
594e3c97c2cSBryan Venteicher 	cnt = required;
595e3c97c2cSBryan Venteicher 	if (pci_alloc_msix(dev, &cnt) == 0 && cnt >= required) {
596e3c97c2cSBryan Venteicher 		sc->vmx_nintrs = required;
597e3c97c2cSBryan Venteicher 		return (0);
598e3c97c2cSBryan Venteicher 	} else
599e3c97c2cSBryan Venteicher 		pci_release_msi(dev);
600e3c97c2cSBryan Venteicher 
601*e557c1ddSBryan Venteicher 	/* BMV TODO Fallback to sharing MSIX vectors if possible. */
602*e557c1ddSBryan Venteicher 
603e3c97c2cSBryan Venteicher 	return (1);
604e3c97c2cSBryan Venteicher }
605e3c97c2cSBryan Venteicher 
606e3c97c2cSBryan Venteicher static int
607e3c97c2cSBryan Venteicher vmxnet3_alloc_msi_interrupts(struct vmxnet3_softc *sc)
608e3c97c2cSBryan Venteicher {
609e3c97c2cSBryan Venteicher 	device_t dev;
610e3c97c2cSBryan Venteicher 	int nmsi, cnt, required;
611e3c97c2cSBryan Venteicher 
612e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
613e3c97c2cSBryan Venteicher 	required = 1;
614e3c97c2cSBryan Venteicher 
615e3c97c2cSBryan Venteicher 	nmsi = pci_msi_count(dev);
616e3c97c2cSBryan Venteicher 	if (nmsi < required)
617e3c97c2cSBryan Venteicher 		return (1);
618e3c97c2cSBryan Venteicher 
619e3c97c2cSBryan Venteicher 	cnt = required;
620e3c97c2cSBryan Venteicher 	if (pci_alloc_msi(dev, &cnt) == 0 && cnt >= required) {
621e3c97c2cSBryan Venteicher 		sc->vmx_nintrs = 1;
622e3c97c2cSBryan Venteicher 		return (0);
623e3c97c2cSBryan Venteicher 	} else
624e3c97c2cSBryan Venteicher 		pci_release_msi(dev);
625e3c97c2cSBryan Venteicher 
626e3c97c2cSBryan Venteicher 	return (1);
627e3c97c2cSBryan Venteicher }
628e3c97c2cSBryan Venteicher 
629e3c97c2cSBryan Venteicher static int
630e3c97c2cSBryan Venteicher vmxnet3_alloc_legacy_interrupts(struct vmxnet3_softc *sc)
631e3c97c2cSBryan Venteicher {
632e3c97c2cSBryan Venteicher 
633e3c97c2cSBryan Venteicher 	sc->vmx_nintrs = 1;
634e3c97c2cSBryan Venteicher 	return (0);
635e3c97c2cSBryan Venteicher }
636e3c97c2cSBryan Venteicher 
637e3c97c2cSBryan Venteicher static int
638e3c97c2cSBryan Venteicher vmxnet3_alloc_interrupt(struct vmxnet3_softc *sc, int rid, int flags,
639e3c97c2cSBryan Venteicher     struct vmxnet3_interrupt *intr)
640e3c97c2cSBryan Venteicher {
641e3c97c2cSBryan Venteicher 	struct resource *irq;
642e3c97c2cSBryan Venteicher 
643e3c97c2cSBryan Venteicher 	irq = bus_alloc_resource_any(sc->vmx_dev, SYS_RES_IRQ, &rid, flags);
644e3c97c2cSBryan Venteicher 	if (irq == NULL)
645e3c97c2cSBryan Venteicher 		return (ENXIO);
646e3c97c2cSBryan Venteicher 
647e3c97c2cSBryan Venteicher 	intr->vmxi_irq = irq;
648e3c97c2cSBryan Venteicher 	intr->vmxi_rid = rid;
649e3c97c2cSBryan Venteicher 
650e3c97c2cSBryan Venteicher 	return (0);
651e3c97c2cSBryan Venteicher }
652e3c97c2cSBryan Venteicher 
653e3c97c2cSBryan Venteicher static int
654e3c97c2cSBryan Venteicher vmxnet3_alloc_intr_resources(struct vmxnet3_softc *sc)
655e3c97c2cSBryan Venteicher {
656e3c97c2cSBryan Venteicher 	int i, rid, flags, error;
657e3c97c2cSBryan Venteicher 
658e3c97c2cSBryan Venteicher 	rid = 0;
659e3c97c2cSBryan Venteicher 	flags = RF_ACTIVE;
660e3c97c2cSBryan Venteicher 
661e3c97c2cSBryan Venteicher 	if (sc->vmx_intr_type == VMXNET3_IT_LEGACY)
662e3c97c2cSBryan Venteicher 		flags |= RF_SHAREABLE;
663e3c97c2cSBryan Venteicher 	else
664e3c97c2cSBryan Venteicher 		rid = 1;
665e3c97c2cSBryan Venteicher 
666e3c97c2cSBryan Venteicher 	for (i = 0; i < sc->vmx_nintrs; i++, rid++) {
667e3c97c2cSBryan Venteicher 		error = vmxnet3_alloc_interrupt(sc, rid, flags,
668e3c97c2cSBryan Venteicher 		    &sc->vmx_intrs[i]);
669e3c97c2cSBryan Venteicher 		if (error)
670e3c97c2cSBryan Venteicher 			return (error);
671e3c97c2cSBryan Venteicher 	}
672e3c97c2cSBryan Venteicher 
673e3c97c2cSBryan Venteicher 	return (0);
674e3c97c2cSBryan Venteicher }
675e3c97c2cSBryan Venteicher 
676e3c97c2cSBryan Venteicher static int
677e3c97c2cSBryan Venteicher vmxnet3_setup_msix_interrupts(struct vmxnet3_softc *sc)
678e3c97c2cSBryan Venteicher {
679e3c97c2cSBryan Venteicher 	device_t dev;
680e3c97c2cSBryan Venteicher 	struct vmxnet3_txqueue *txq;
681e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
682e3c97c2cSBryan Venteicher 	struct vmxnet3_interrupt *intr;
683e3c97c2cSBryan Venteicher 	enum intr_type type;
684e3c97c2cSBryan Venteicher 	int i, error;
685e3c97c2cSBryan Venteicher 
686e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
687e3c97c2cSBryan Venteicher 	intr = &sc->vmx_intrs[0];
688e3c97c2cSBryan Venteicher 	type = INTR_TYPE_NET | INTR_MPSAFE;
689e3c97c2cSBryan Venteicher 
690e3c97c2cSBryan Venteicher 	for (i = 0; i < sc->vmx_ntxqueues; i++, intr++) {
691e3c97c2cSBryan Venteicher 		txq = &sc->vmx_txq[i];
692e3c97c2cSBryan Venteicher 		error = bus_setup_intr(dev, intr->vmxi_irq, type, NULL,
693e3c97c2cSBryan Venteicher 		     vmxnet3_txq_intr, txq, &intr->vmxi_handler);
694e3c97c2cSBryan Venteicher 		if (error)
695e3c97c2cSBryan Venteicher 			return (error);
696e3c97c2cSBryan Venteicher 		txq->vxtxq_intr_idx = intr->vmxi_rid - 1;
697e3c97c2cSBryan Venteicher 	}
698e3c97c2cSBryan Venteicher 
699e3c97c2cSBryan Venteicher 	for (i = 0; i < sc->vmx_nrxqueues; i++, intr++) {
700e3c97c2cSBryan Venteicher 		rxq = &sc->vmx_rxq[i];
701e3c97c2cSBryan Venteicher 		error = bus_setup_intr(dev, intr->vmxi_irq, type, NULL,
702e3c97c2cSBryan Venteicher 		    vmxnet3_rxq_intr, rxq, &intr->vmxi_handler);
703e3c97c2cSBryan Venteicher 		if (error)
704e3c97c2cSBryan Venteicher 			return (error);
705e3c97c2cSBryan Venteicher 		rxq->vxrxq_intr_idx = intr->vmxi_rid - 1;
706e3c97c2cSBryan Venteicher 	}
707e3c97c2cSBryan Venteicher 
708e3c97c2cSBryan Venteicher 	error = bus_setup_intr(dev, intr->vmxi_irq, type, NULL,
709e3c97c2cSBryan Venteicher 	    vmxnet3_event_intr, sc, &intr->vmxi_handler);
710e3c97c2cSBryan Venteicher 	if (error)
711e3c97c2cSBryan Venteicher 		return (error);
712e3c97c2cSBryan Venteicher 	sc->vmx_event_intr_idx = intr->vmxi_rid - 1;
713e3c97c2cSBryan Venteicher 
714e3c97c2cSBryan Venteicher 	return (0);
715e3c97c2cSBryan Venteicher }
716e3c97c2cSBryan Venteicher 
717e3c97c2cSBryan Venteicher static int
718e3c97c2cSBryan Venteicher vmxnet3_setup_legacy_interrupt(struct vmxnet3_softc *sc)
719e3c97c2cSBryan Venteicher {
720e3c97c2cSBryan Venteicher 	struct vmxnet3_interrupt *intr;
721e3c97c2cSBryan Venteicher 	int i, error;
722e3c97c2cSBryan Venteicher 
723e3c97c2cSBryan Venteicher 	intr = &sc->vmx_intrs[0];
724e3c97c2cSBryan Venteicher 	error = bus_setup_intr(sc->vmx_dev, intr->vmxi_irq,
725e3c97c2cSBryan Venteicher 	    INTR_TYPE_NET | INTR_MPSAFE, NULL, vmxnet3_legacy_intr, sc,
726e3c97c2cSBryan Venteicher 	    &intr->vmxi_handler);
727e3c97c2cSBryan Venteicher 
728e3c97c2cSBryan Venteicher 	for (i = 0; i < sc->vmx_ntxqueues; i++)
729e3c97c2cSBryan Venteicher 		sc->vmx_txq[i].vxtxq_intr_idx = 0;
730e3c97c2cSBryan Venteicher 	for (i = 0; i < sc->vmx_nrxqueues; i++)
731e3c97c2cSBryan Venteicher 		sc->vmx_rxq[i].vxrxq_intr_idx = 0;
732e3c97c2cSBryan Venteicher 	sc->vmx_event_intr_idx = 0;
733e3c97c2cSBryan Venteicher 
734e3c97c2cSBryan Venteicher 	return (error);
735e3c97c2cSBryan Venteicher }
736e3c97c2cSBryan Venteicher 
737e3c97c2cSBryan Venteicher static void
738e3c97c2cSBryan Venteicher vmxnet3_set_interrupt_idx(struct vmxnet3_softc *sc)
739e3c97c2cSBryan Venteicher {
740e3c97c2cSBryan Venteicher 	struct vmxnet3_txqueue *txq;
741e3c97c2cSBryan Venteicher 	struct vmxnet3_txq_shared *txs;
742e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
743e3c97c2cSBryan Venteicher 	struct vmxnet3_rxq_shared *rxs;
744e3c97c2cSBryan Venteicher 	int i;
745e3c97c2cSBryan Venteicher 
746e3c97c2cSBryan Venteicher 	sc->vmx_ds->evintr = sc->vmx_event_intr_idx;
747e3c97c2cSBryan Venteicher 
748e3c97c2cSBryan Venteicher 	for (i = 0; i < sc->vmx_ntxqueues; i++) {
749e3c97c2cSBryan Venteicher 		txq = &sc->vmx_txq[i];
750e3c97c2cSBryan Venteicher 		txs = txq->vxtxq_ts;
751e3c97c2cSBryan Venteicher 		txs->intr_idx = txq->vxtxq_intr_idx;
752e3c97c2cSBryan Venteicher 	}
753e3c97c2cSBryan Venteicher 
754e3c97c2cSBryan Venteicher 	for (i = 0; i < sc->vmx_nrxqueues; i++) {
755e3c97c2cSBryan Venteicher 		rxq = &sc->vmx_rxq[i];
756e3c97c2cSBryan Venteicher 		rxs = rxq->vxrxq_rs;
757e3c97c2cSBryan Venteicher 		rxs->intr_idx = rxq->vxrxq_intr_idx;
758e3c97c2cSBryan Venteicher 	}
759e3c97c2cSBryan Venteicher }
760e3c97c2cSBryan Venteicher 
761e3c97c2cSBryan Venteicher static int
762e3c97c2cSBryan Venteicher vmxnet3_setup_interrupts(struct vmxnet3_softc *sc)
763e3c97c2cSBryan Venteicher {
764e3c97c2cSBryan Venteicher 	int error;
765e3c97c2cSBryan Venteicher 
766e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_intr_resources(sc);
767e3c97c2cSBryan Venteicher 	if (error)
768e3c97c2cSBryan Venteicher 		return (error);
769e3c97c2cSBryan Venteicher 
770e3c97c2cSBryan Venteicher 	switch (sc->vmx_intr_type) {
771e3c97c2cSBryan Venteicher 	case VMXNET3_IT_MSIX:
772e3c97c2cSBryan Venteicher 		error = vmxnet3_setup_msix_interrupts(sc);
773e3c97c2cSBryan Venteicher 		break;
774e3c97c2cSBryan Venteicher 	case VMXNET3_IT_MSI:
775e3c97c2cSBryan Venteicher 	case VMXNET3_IT_LEGACY:
776e3c97c2cSBryan Venteicher 		error = vmxnet3_setup_legacy_interrupt(sc);
777e3c97c2cSBryan Venteicher 		break;
778e3c97c2cSBryan Venteicher 	default:
779e3c97c2cSBryan Venteicher 		panic("%s: invalid interrupt type %d", __func__,
780e3c97c2cSBryan Venteicher 		    sc->vmx_intr_type);
781e3c97c2cSBryan Venteicher 	}
782e3c97c2cSBryan Venteicher 
783e3c97c2cSBryan Venteicher 	if (error == 0)
784e3c97c2cSBryan Venteicher 		vmxnet3_set_interrupt_idx(sc);
785e3c97c2cSBryan Venteicher 
786e3c97c2cSBryan Venteicher 	return (error);
787e3c97c2cSBryan Venteicher }
788e3c97c2cSBryan Venteicher 
789e3c97c2cSBryan Venteicher static int
790e3c97c2cSBryan Venteicher vmxnet3_alloc_interrupts(struct vmxnet3_softc *sc)
791e3c97c2cSBryan Venteicher {
792e3c97c2cSBryan Venteicher 	device_t dev;
793e3c97c2cSBryan Venteicher 	uint32_t config;
794e3c97c2cSBryan Venteicher 	int error;
795e3c97c2cSBryan Venteicher 
796e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
797e3c97c2cSBryan Venteicher 	config = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_INTRCFG);
798e3c97c2cSBryan Venteicher 
799e3c97c2cSBryan Venteicher 	sc->vmx_intr_type = config & 0x03;
800e3c97c2cSBryan Venteicher 	sc->vmx_intr_mask_mode = (config >> 2) & 0x03;
801e3c97c2cSBryan Venteicher 
802e3c97c2cSBryan Venteicher 	switch (sc->vmx_intr_type) {
803e3c97c2cSBryan Venteicher 	case VMXNET3_IT_AUTO:
804e3c97c2cSBryan Venteicher 		sc->vmx_intr_type = VMXNET3_IT_MSIX;
805e3c97c2cSBryan Venteicher 		/* FALLTHROUGH */
806e3c97c2cSBryan Venteicher 	case VMXNET3_IT_MSIX:
807e3c97c2cSBryan Venteicher 		error = vmxnet3_alloc_msix_interrupts(sc);
808e3c97c2cSBryan Venteicher 		if (error == 0)
809e3c97c2cSBryan Venteicher 			break;
810e3c97c2cSBryan Venteicher 		sc->vmx_intr_type = VMXNET3_IT_MSI;
811e3c97c2cSBryan Venteicher 		/* FALLTHROUGH */
812e3c97c2cSBryan Venteicher 	case VMXNET3_IT_MSI:
813e3c97c2cSBryan Venteicher 		error = vmxnet3_alloc_msi_interrupts(sc);
814e3c97c2cSBryan Venteicher 		if (error == 0)
815e3c97c2cSBryan Venteicher 			break;
816e3c97c2cSBryan Venteicher 		sc->vmx_intr_type = VMXNET3_IT_LEGACY;
817e3c97c2cSBryan Venteicher 		/* FALLTHROUGH */
818e3c97c2cSBryan Venteicher 	case VMXNET3_IT_LEGACY:
819e3c97c2cSBryan Venteicher 		error = vmxnet3_alloc_legacy_interrupts(sc);
820e3c97c2cSBryan Venteicher 		if (error == 0)
821e3c97c2cSBryan Venteicher 			break;
822e3c97c2cSBryan Venteicher 		/* FALLTHROUGH */
823e3c97c2cSBryan Venteicher 	default:
824e3c97c2cSBryan Venteicher 		sc->vmx_intr_type = -1;
825e3c97c2cSBryan Venteicher 		device_printf(dev, "cannot allocate any interrupt resources\n");
826e3c97c2cSBryan Venteicher 		return (ENXIO);
827e3c97c2cSBryan Venteicher 	}
828e3c97c2cSBryan Venteicher 
829e3c97c2cSBryan Venteicher 	return (error);
830e3c97c2cSBryan Venteicher }
831e3c97c2cSBryan Venteicher 
832e3c97c2cSBryan Venteicher static void
833e3c97c2cSBryan Venteicher vmxnet3_free_interrupt(struct vmxnet3_softc *sc,
834e3c97c2cSBryan Venteicher     struct vmxnet3_interrupt *intr)
835e3c97c2cSBryan Venteicher {
836e3c97c2cSBryan Venteicher 	device_t dev;
837e3c97c2cSBryan Venteicher 
838e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
839e3c97c2cSBryan Venteicher 
840e3c97c2cSBryan Venteicher 	if (intr->vmxi_handler != NULL) {
841e3c97c2cSBryan Venteicher 		bus_teardown_intr(dev, intr->vmxi_irq, intr->vmxi_handler);
842e3c97c2cSBryan Venteicher 		intr->vmxi_handler = NULL;
843e3c97c2cSBryan Venteicher 	}
844e3c97c2cSBryan Venteicher 
845e3c97c2cSBryan Venteicher 	if (intr->vmxi_irq != NULL) {
846e3c97c2cSBryan Venteicher 		bus_release_resource(dev, SYS_RES_IRQ, intr->vmxi_rid,
847e3c97c2cSBryan Venteicher 		    intr->vmxi_irq);
848e3c97c2cSBryan Venteicher 		intr->vmxi_irq = NULL;
849e3c97c2cSBryan Venteicher 		intr->vmxi_rid = -1;
850e3c97c2cSBryan Venteicher 	}
851e3c97c2cSBryan Venteicher }
852e3c97c2cSBryan Venteicher 
853e3c97c2cSBryan Venteicher static void
854e3c97c2cSBryan Venteicher vmxnet3_free_interrupts(struct vmxnet3_softc *sc)
855e3c97c2cSBryan Venteicher {
856e3c97c2cSBryan Venteicher 	int i;
857e3c97c2cSBryan Venteicher 
858e3c97c2cSBryan Venteicher 	for (i = 0; i < sc->vmx_nintrs; i++)
859e3c97c2cSBryan Venteicher 		vmxnet3_free_interrupt(sc, &sc->vmx_intrs[i]);
860e3c97c2cSBryan Venteicher 
861e3c97c2cSBryan Venteicher 	if (sc->vmx_intr_type == VMXNET3_IT_MSI ||
862e3c97c2cSBryan Venteicher 	    sc->vmx_intr_type == VMXNET3_IT_MSIX)
863e3c97c2cSBryan Venteicher 		pci_release_msi(sc->vmx_dev);
864e3c97c2cSBryan Venteicher }
865e3c97c2cSBryan Venteicher 
866*e557c1ddSBryan Venteicher #ifndef VMXNET3_LEGACY_TX
867*e557c1ddSBryan Venteicher static int
868*e557c1ddSBryan Venteicher vmxnet3_alloc_taskqueue(struct vmxnet3_softc *sc)
869*e557c1ddSBryan Venteicher {
870*e557c1ddSBryan Venteicher 	device_t dev;
871*e557c1ddSBryan Venteicher 
872*e557c1ddSBryan Venteicher 	dev = sc->vmx_dev;
873*e557c1ddSBryan Venteicher 
874*e557c1ddSBryan Venteicher 	sc->vmx_tq = taskqueue_create(device_get_nameunit(dev), M_NOWAIT,
875*e557c1ddSBryan Venteicher 	    taskqueue_thread_enqueue, &sc->vmx_tq);
876*e557c1ddSBryan Venteicher 	if (sc->vmx_tq == NULL)
877*e557c1ddSBryan Venteicher 		return (ENOMEM);
878*e557c1ddSBryan Venteicher 
879*e557c1ddSBryan Venteicher 	return (0);
880*e557c1ddSBryan Venteicher }
881*e557c1ddSBryan Venteicher 
882*e557c1ddSBryan Venteicher static void
883*e557c1ddSBryan Venteicher vmxnet3_start_taskqueue(struct vmxnet3_softc *sc)
884*e557c1ddSBryan Venteicher {
885*e557c1ddSBryan Venteicher 	device_t dev;
886*e557c1ddSBryan Venteicher 	int nthreads, error;
887*e557c1ddSBryan Venteicher 
888*e557c1ddSBryan Venteicher 	dev = sc->vmx_dev;
889*e557c1ddSBryan Venteicher 
890*e557c1ddSBryan Venteicher 	/*
891*e557c1ddSBryan Venteicher 	 * The taskqueue is typically not frequently used, so a dedicated
892*e557c1ddSBryan Venteicher 	 * thread for each queue is unnecessary.
893*e557c1ddSBryan Venteicher 	 */
894*e557c1ddSBryan Venteicher 	nthreads = MAX(1, sc->vmx_ntxqueues / 2);
895*e557c1ddSBryan Venteicher 
896*e557c1ddSBryan Venteicher 	/*
897*e557c1ddSBryan Venteicher 	 * Most drivers just ignore the return value - it only fails
898*e557c1ddSBryan Venteicher 	 * with ENOMEM so an error is not likely. It is hard for us
899*e557c1ddSBryan Venteicher 	 * to recover from an error here.
900*e557c1ddSBryan Venteicher 	 */
901*e557c1ddSBryan Venteicher 	error = taskqueue_start_threads(&sc->vmx_tq, nthreads, PI_NET,
902*e557c1ddSBryan Venteicher 	    "%s taskq", device_get_nameunit(dev));
903*e557c1ddSBryan Venteicher 	if (error)
904*e557c1ddSBryan Venteicher 		device_printf(dev, "failed to start taskqueue: %d", error);
905*e557c1ddSBryan Venteicher }
906*e557c1ddSBryan Venteicher 
907*e557c1ddSBryan Venteicher static void
908*e557c1ddSBryan Venteicher vmxnet3_drain_taskqueue(struct vmxnet3_softc *sc)
909*e557c1ddSBryan Venteicher {
910*e557c1ddSBryan Venteicher 	struct vmxnet3_txqueue *txq;
911*e557c1ddSBryan Venteicher 	int i;
912*e557c1ddSBryan Venteicher 
913*e557c1ddSBryan Venteicher 	if (sc->vmx_tq != NULL) {
914*e557c1ddSBryan Venteicher 		for (i = 0; i < sc->vmx_max_ntxqueues; i++) {
915*e557c1ddSBryan Venteicher 			txq = &sc->vmx_txq[i];
916*e557c1ddSBryan Venteicher 			taskqueue_drain(sc->vmx_tq, &txq->vxtxq_defrtask);
917*e557c1ddSBryan Venteicher 		}
918*e557c1ddSBryan Venteicher 	}
919*e557c1ddSBryan Venteicher }
920*e557c1ddSBryan Venteicher 
921*e557c1ddSBryan Venteicher static void
922*e557c1ddSBryan Venteicher vmxnet3_free_taskqueue(struct vmxnet3_softc *sc)
923*e557c1ddSBryan Venteicher {
924*e557c1ddSBryan Venteicher 	if (sc->vmx_tq != NULL) {
925*e557c1ddSBryan Venteicher 		taskqueue_free(sc->vmx_tq);
926*e557c1ddSBryan Venteicher 		sc->vmx_tq = NULL;
927*e557c1ddSBryan Venteicher 	}
928*e557c1ddSBryan Venteicher }
929*e557c1ddSBryan Venteicher #endif
930*e557c1ddSBryan Venteicher 
931e3c97c2cSBryan Venteicher static int
932e3c97c2cSBryan Venteicher vmxnet3_init_rxq(struct vmxnet3_softc *sc, int q)
933e3c97c2cSBryan Venteicher {
934e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
935e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
936e3c97c2cSBryan Venteicher 	int i;
937e3c97c2cSBryan Venteicher 
938e3c97c2cSBryan Venteicher 	rxq = &sc->vmx_rxq[q];
939e3c97c2cSBryan Venteicher 
940e3c97c2cSBryan Venteicher 	snprintf(rxq->vxrxq_name, sizeof(rxq->vxrxq_name), "%s-rx%d",
941e3c97c2cSBryan Venteicher 	    device_get_nameunit(sc->vmx_dev), q);
942e3c97c2cSBryan Venteicher 	mtx_init(&rxq->vxrxq_mtx, rxq->vxrxq_name, NULL, MTX_DEF);
943e3c97c2cSBryan Venteicher 
944e3c97c2cSBryan Venteicher 	rxq->vxrxq_sc = sc;
945e3c97c2cSBryan Venteicher 	rxq->vxrxq_id = q;
946e3c97c2cSBryan Venteicher 
947e3c97c2cSBryan Venteicher 	for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) {
948e3c97c2cSBryan Venteicher 		rxr = &rxq->vxrxq_cmd_ring[i];
949e3c97c2cSBryan Venteicher 		rxr->vxrxr_rid = i;
950e3c97c2cSBryan Venteicher 		rxr->vxrxr_ndesc = sc->vmx_nrxdescs;
951e3c97c2cSBryan Venteicher 		rxr->vxrxr_rxbuf = malloc(rxr->vxrxr_ndesc *
952e3c97c2cSBryan Venteicher 		    sizeof(struct vmxnet3_rxbuf), M_DEVBUF, M_NOWAIT | M_ZERO);
953e3c97c2cSBryan Venteicher 		if (rxr->vxrxr_rxbuf == NULL)
954e3c97c2cSBryan Venteicher 			return (ENOMEM);
955e3c97c2cSBryan Venteicher 
9563c965775SBryan Venteicher 		rxq->vxrxq_comp_ring.vxcr_ndesc += sc->vmx_nrxdescs;
9573c965775SBryan Venteicher 	}
958e3c97c2cSBryan Venteicher 
959e3c97c2cSBryan Venteicher 	return (0);
960e3c97c2cSBryan Venteicher }
961e3c97c2cSBryan Venteicher 
962e3c97c2cSBryan Venteicher static int
963e3c97c2cSBryan Venteicher vmxnet3_init_txq(struct vmxnet3_softc *sc, int q)
964e3c97c2cSBryan Venteicher {
965e3c97c2cSBryan Venteicher 	struct vmxnet3_txqueue *txq;
966e3c97c2cSBryan Venteicher 	struct vmxnet3_txring *txr;
967e3c97c2cSBryan Venteicher 
968e3c97c2cSBryan Venteicher 	txq = &sc->vmx_txq[q];
969e3c97c2cSBryan Venteicher 	txr = &txq->vxtxq_cmd_ring;
970e3c97c2cSBryan Venteicher 
971e3c97c2cSBryan Venteicher 	snprintf(txq->vxtxq_name, sizeof(txq->vxtxq_name), "%s-tx%d",
972e3c97c2cSBryan Venteicher 	    device_get_nameunit(sc->vmx_dev), q);
973e3c97c2cSBryan Venteicher 	mtx_init(&txq->vxtxq_mtx, txq->vxtxq_name, NULL, MTX_DEF);
974e3c97c2cSBryan Venteicher 
975e3c97c2cSBryan Venteicher 	txq->vxtxq_sc = sc;
976e3c97c2cSBryan Venteicher 	txq->vxtxq_id = q;
977e3c97c2cSBryan Venteicher 
978e3c97c2cSBryan Venteicher 	txr->vxtxr_ndesc = sc->vmx_ntxdescs;
979e3c97c2cSBryan Venteicher 	txr->vxtxr_txbuf = malloc(txr->vxtxr_ndesc *
980e3c97c2cSBryan Venteicher 	    sizeof(struct vmxnet3_txbuf), M_DEVBUF, M_NOWAIT | M_ZERO);
981e3c97c2cSBryan Venteicher 	if (txr->vxtxr_txbuf == NULL)
982e3c97c2cSBryan Venteicher 		return (ENOMEM);
983e3c97c2cSBryan Venteicher 
984e3c97c2cSBryan Venteicher 	txq->vxtxq_comp_ring.vxcr_ndesc = sc->vmx_ntxdescs;
985e3c97c2cSBryan Venteicher 
986*e557c1ddSBryan Venteicher #ifndef VMXNET3_LEGACY_TX
987*e557c1ddSBryan Venteicher 	TASK_INIT(&txq->vxtxq_defrtask, 0, vmxnet3_txq_tq_deferred, txq);
988*e557c1ddSBryan Venteicher 
989*e557c1ddSBryan Venteicher 	txq->vxtxq_br = buf_ring_alloc(VMXNET3_DEF_BUFRING_SIZE, M_DEVBUF,
990*e557c1ddSBryan Venteicher 	    M_NOWAIT, &txq->vxtxq_mtx);
991*e557c1ddSBryan Venteicher 	if (txq->vxtxq_br == NULL)
992*e557c1ddSBryan Venteicher 		return (ENOMEM);
993*e557c1ddSBryan Venteicher #endif
994*e557c1ddSBryan Venteicher 
995e3c97c2cSBryan Venteicher 	return (0);
996e3c97c2cSBryan Venteicher }
997e3c97c2cSBryan Venteicher 
998e3c97c2cSBryan Venteicher static int
999e3c97c2cSBryan Venteicher vmxnet3_alloc_rxtx_queues(struct vmxnet3_softc *sc)
1000e3c97c2cSBryan Venteicher {
1001e3c97c2cSBryan Venteicher 	int i, error;
1002e3c97c2cSBryan Venteicher 
1003*e557c1ddSBryan Venteicher 	/*
1004*e557c1ddSBryan Venteicher 	 * Only attempt to create multiple queues if MSIX is available. MSIX is
1005*e557c1ddSBryan Venteicher 	 * disabled by default because its apparently broken for devices passed
1006*e557c1ddSBryan Venteicher 	 * through by at least ESXi 5.1. The hw.pci.honor_msi_blacklist tunable
1007*e557c1ddSBryan Venteicher 	 * must be set to zero for MSIX. This check prevents us from allocating
1008*e557c1ddSBryan Venteicher 	 * queue structures that we will not use.
1009*e557c1ddSBryan Venteicher 	 */
1010*e557c1ddSBryan Venteicher 	if (sc->vmx_flags & VMXNET3_FLAG_NO_MSIX) {
1011*e557c1ddSBryan Venteicher 		sc->vmx_max_nrxqueues = 1;
1012*e557c1ddSBryan Venteicher 		sc->vmx_max_ntxqueues = 1;
1013*e557c1ddSBryan Venteicher 	}
1014*e557c1ddSBryan Venteicher 
1015e3c97c2cSBryan Venteicher 	sc->vmx_rxq = malloc(sizeof(struct vmxnet3_rxqueue) *
1016*e557c1ddSBryan Venteicher 	    sc->vmx_max_nrxqueues, M_DEVBUF, M_NOWAIT | M_ZERO);
1017e3c97c2cSBryan Venteicher 	sc->vmx_txq = malloc(sizeof(struct vmxnet3_txqueue) *
1018*e557c1ddSBryan Venteicher 	    sc->vmx_max_ntxqueues, M_DEVBUF, M_NOWAIT | M_ZERO);
1019e3c97c2cSBryan Venteicher 	if (sc->vmx_rxq == NULL || sc->vmx_txq == NULL)
1020e3c97c2cSBryan Venteicher 		return (ENOMEM);
1021e3c97c2cSBryan Venteicher 
1022*e557c1ddSBryan Venteicher 	for (i = 0; i < sc->vmx_max_nrxqueues; i++) {
1023e3c97c2cSBryan Venteicher 		error = vmxnet3_init_rxq(sc, i);
1024e3c97c2cSBryan Venteicher 		if (error)
1025e3c97c2cSBryan Venteicher 			return (error);
1026e3c97c2cSBryan Venteicher 	}
1027e3c97c2cSBryan Venteicher 
1028*e557c1ddSBryan Venteicher 	for (i = 0; i < sc->vmx_max_ntxqueues; i++) {
1029e3c97c2cSBryan Venteicher 		error = vmxnet3_init_txq(sc, i);
1030e3c97c2cSBryan Venteicher 		if (error)
1031e3c97c2cSBryan Venteicher 			return (error);
1032e3c97c2cSBryan Venteicher 	}
1033e3c97c2cSBryan Venteicher 
1034e3c97c2cSBryan Venteicher 	return (0);
1035e3c97c2cSBryan Venteicher }
1036e3c97c2cSBryan Venteicher 
1037e3c97c2cSBryan Venteicher static void
1038e3c97c2cSBryan Venteicher vmxnet3_destroy_rxq(struct vmxnet3_rxqueue *rxq)
1039e3c97c2cSBryan Venteicher {
1040e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
1041e3c97c2cSBryan Venteicher 	int i;
1042e3c97c2cSBryan Venteicher 
1043e3c97c2cSBryan Venteicher 	rxq->vxrxq_sc = NULL;
1044e3c97c2cSBryan Venteicher 	rxq->vxrxq_id = -1;
1045e3c97c2cSBryan Venteicher 
1046e3c97c2cSBryan Venteicher 	for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) {
1047e3c97c2cSBryan Venteicher 		rxr = &rxq->vxrxq_cmd_ring[i];
1048e3c97c2cSBryan Venteicher 
1049e3c97c2cSBryan Venteicher 		if (rxr->vxrxr_rxbuf != NULL) {
1050e3c97c2cSBryan Venteicher 			free(rxr->vxrxr_rxbuf, M_DEVBUF);
1051e3c97c2cSBryan Venteicher 			rxr->vxrxr_rxbuf = NULL;
1052e3c97c2cSBryan Venteicher 		}
1053e3c97c2cSBryan Venteicher 	}
1054e3c97c2cSBryan Venteicher 
1055e3c97c2cSBryan Venteicher 	if (mtx_initialized(&rxq->vxrxq_mtx) != 0)
1056e3c97c2cSBryan Venteicher 		mtx_destroy(&rxq->vxrxq_mtx);
1057e3c97c2cSBryan Venteicher }
1058e3c97c2cSBryan Venteicher 
1059e3c97c2cSBryan Venteicher static void
1060e3c97c2cSBryan Venteicher vmxnet3_destroy_txq(struct vmxnet3_txqueue *txq)
1061e3c97c2cSBryan Venteicher {
1062e3c97c2cSBryan Venteicher 	struct vmxnet3_txring *txr;
1063e3c97c2cSBryan Venteicher 
1064e3c97c2cSBryan Venteicher 	txr = &txq->vxtxq_cmd_ring;
1065e3c97c2cSBryan Venteicher 
1066e3c97c2cSBryan Venteicher 	txq->vxtxq_sc = NULL;
1067e3c97c2cSBryan Venteicher 	txq->vxtxq_id = -1;
1068e3c97c2cSBryan Venteicher 
1069*e557c1ddSBryan Venteicher #ifndef VMXNET3_LEGACY_TX
1070*e557c1ddSBryan Venteicher 	if (txq->vxtxq_br != NULL) {
1071*e557c1ddSBryan Venteicher 		buf_ring_free(txq->vxtxq_br, M_DEVBUF);
1072*e557c1ddSBryan Venteicher 		txq->vxtxq_br = NULL;
1073*e557c1ddSBryan Venteicher 	}
1074*e557c1ddSBryan Venteicher #endif
1075*e557c1ddSBryan Venteicher 
1076e3c97c2cSBryan Venteicher 	if (txr->vxtxr_txbuf != NULL) {
1077e3c97c2cSBryan Venteicher 		free(txr->vxtxr_txbuf, M_DEVBUF);
1078e3c97c2cSBryan Venteicher 		txr->vxtxr_txbuf = NULL;
1079e3c97c2cSBryan Venteicher 	}
1080e3c97c2cSBryan Venteicher 
1081e3c97c2cSBryan Venteicher 	if (mtx_initialized(&txq->vxtxq_mtx) != 0)
1082e3c97c2cSBryan Venteicher 		mtx_destroy(&txq->vxtxq_mtx);
1083e3c97c2cSBryan Venteicher }
1084e3c97c2cSBryan Venteicher 
1085e3c97c2cSBryan Venteicher static void
1086e3c97c2cSBryan Venteicher vmxnet3_free_rxtx_queues(struct vmxnet3_softc *sc)
1087e3c97c2cSBryan Venteicher {
1088e3c97c2cSBryan Venteicher 	int i;
1089e3c97c2cSBryan Venteicher 
1090e3c97c2cSBryan Venteicher 	if (sc->vmx_rxq != NULL) {
1091*e557c1ddSBryan Venteicher 		for (i = 0; i < sc->vmx_max_nrxqueues; i++)
1092e3c97c2cSBryan Venteicher 			vmxnet3_destroy_rxq(&sc->vmx_rxq[i]);
1093e3c97c2cSBryan Venteicher 		free(sc->vmx_rxq, M_DEVBUF);
1094e3c97c2cSBryan Venteicher 		sc->vmx_rxq = NULL;
1095e3c97c2cSBryan Venteicher 	}
1096e3c97c2cSBryan Venteicher 
1097e3c97c2cSBryan Venteicher 	if (sc->vmx_txq != NULL) {
1098*e557c1ddSBryan Venteicher 		for (i = 0; i < sc->vmx_max_ntxqueues; i++)
1099e3c97c2cSBryan Venteicher 			vmxnet3_destroy_txq(&sc->vmx_txq[i]);
1100e3c97c2cSBryan Venteicher 		free(sc->vmx_txq, M_DEVBUF);
1101e3c97c2cSBryan Venteicher 		sc->vmx_txq = NULL;
1102e3c97c2cSBryan Venteicher 	}
1103e3c97c2cSBryan Venteicher }
1104e3c97c2cSBryan Venteicher 
1105e3c97c2cSBryan Venteicher static int
1106e3c97c2cSBryan Venteicher vmxnet3_alloc_shared_data(struct vmxnet3_softc *sc)
1107e3c97c2cSBryan Venteicher {
1108e3c97c2cSBryan Venteicher 	device_t dev;
1109e3c97c2cSBryan Venteicher 	uint8_t *kva;
1110e3c97c2cSBryan Venteicher 	size_t size;
1111e3c97c2cSBryan Venteicher 	int i, error;
1112e3c97c2cSBryan Venteicher 
1113e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
1114e3c97c2cSBryan Venteicher 
1115e3c97c2cSBryan Venteicher 	size = sizeof(struct vmxnet3_driver_shared);
1116e3c97c2cSBryan Venteicher 	error = vmxnet3_dma_malloc(sc, size, 1, &sc->vmx_ds_dma);
1117e3c97c2cSBryan Venteicher 	if (error) {
1118e3c97c2cSBryan Venteicher 		device_printf(dev, "cannot alloc shared memory\n");
1119e3c97c2cSBryan Venteicher 		return (error);
1120e3c97c2cSBryan Venteicher 	}
1121e3c97c2cSBryan Venteicher 	sc->vmx_ds = (struct vmxnet3_driver_shared *) sc->vmx_ds_dma.dma_vaddr;
1122e3c97c2cSBryan Venteicher 
1123e3c97c2cSBryan Venteicher 	size = sc->vmx_ntxqueues * sizeof(struct vmxnet3_txq_shared) +
1124e3c97c2cSBryan Venteicher 	    sc->vmx_nrxqueues * sizeof(struct vmxnet3_rxq_shared);
1125e3c97c2cSBryan Venteicher 	error = vmxnet3_dma_malloc(sc, size, 128, &sc->vmx_qs_dma);
1126e3c97c2cSBryan Venteicher 	if (error) {
1127e3c97c2cSBryan Venteicher 		device_printf(dev, "cannot alloc queue shared memory\n");
1128e3c97c2cSBryan Venteicher 		return (error);
1129e3c97c2cSBryan Venteicher 	}
1130e3c97c2cSBryan Venteicher 	sc->vmx_qs = (void *) sc->vmx_qs_dma.dma_vaddr;
1131e3c97c2cSBryan Venteicher 	kva = sc->vmx_qs;
1132e3c97c2cSBryan Venteicher 
1133e3c97c2cSBryan Venteicher 	for (i = 0; i < sc->vmx_ntxqueues; i++) {
1134e3c97c2cSBryan Venteicher 		sc->vmx_txq[i].vxtxq_ts = (struct vmxnet3_txq_shared *) kva;
1135e3c97c2cSBryan Venteicher 		kva += sizeof(struct vmxnet3_txq_shared);
1136e3c97c2cSBryan Venteicher 	}
1137e3c97c2cSBryan Venteicher 	for (i = 0; i < sc->vmx_nrxqueues; i++) {
1138e3c97c2cSBryan Venteicher 		sc->vmx_rxq[i].vxrxq_rs = (struct vmxnet3_rxq_shared *) kva;
1139e3c97c2cSBryan Venteicher 		kva += sizeof(struct vmxnet3_rxq_shared);
1140e3c97c2cSBryan Venteicher 	}
1141e3c97c2cSBryan Venteicher 
1142*e557c1ddSBryan Venteicher 	if (sc->vmx_flags & VMXNET3_FLAG_RSS) {
1143*e557c1ddSBryan Venteicher 		size = sizeof(struct vmxnet3_rss_shared);
1144*e557c1ddSBryan Venteicher 		error = vmxnet3_dma_malloc(sc, size, 128, &sc->vmx_rss_dma);
1145*e557c1ddSBryan Venteicher 		if (error) {
1146*e557c1ddSBryan Venteicher 			device_printf(dev, "cannot alloc rss shared memory\n");
1147*e557c1ddSBryan Venteicher 			return (error);
1148*e557c1ddSBryan Venteicher 		}
1149*e557c1ddSBryan Venteicher 		sc->vmx_rss =
1150*e557c1ddSBryan Venteicher 		    (struct vmxnet3_rss_shared *) sc->vmx_rss_dma.dma_vaddr;
1151*e557c1ddSBryan Venteicher 	}
1152*e557c1ddSBryan Venteicher 
1153e3c97c2cSBryan Venteicher 	return (0);
1154e3c97c2cSBryan Venteicher }
1155e3c97c2cSBryan Venteicher 
1156e3c97c2cSBryan Venteicher static void
1157e3c97c2cSBryan Venteicher vmxnet3_free_shared_data(struct vmxnet3_softc *sc)
1158e3c97c2cSBryan Venteicher {
1159e3c97c2cSBryan Venteicher 
1160*e557c1ddSBryan Venteicher 	if (sc->vmx_rss != NULL) {
1161*e557c1ddSBryan Venteicher 		vmxnet3_dma_free(sc, &sc->vmx_rss_dma);
1162*e557c1ddSBryan Venteicher 		sc->vmx_rss = NULL;
1163*e557c1ddSBryan Venteicher 	}
1164*e557c1ddSBryan Venteicher 
1165e3c97c2cSBryan Venteicher 	if (sc->vmx_qs != NULL) {
1166e3c97c2cSBryan Venteicher 		vmxnet3_dma_free(sc, &sc->vmx_qs_dma);
1167e3c97c2cSBryan Venteicher 		sc->vmx_qs = NULL;
1168e3c97c2cSBryan Venteicher 	}
1169e3c97c2cSBryan Venteicher 
1170e3c97c2cSBryan Venteicher 	if (sc->vmx_ds != NULL) {
1171e3c97c2cSBryan Venteicher 		vmxnet3_dma_free(sc, &sc->vmx_ds_dma);
1172e3c97c2cSBryan Venteicher 		sc->vmx_ds = NULL;
1173e3c97c2cSBryan Venteicher 	}
1174e3c97c2cSBryan Venteicher }
1175e3c97c2cSBryan Venteicher 
1176e3c97c2cSBryan Venteicher static int
1177e3c97c2cSBryan Venteicher vmxnet3_alloc_txq_data(struct vmxnet3_softc *sc)
1178e3c97c2cSBryan Venteicher {
1179e3c97c2cSBryan Venteicher 	device_t dev;
1180e3c97c2cSBryan Venteicher 	struct vmxnet3_txqueue *txq;
1181e3c97c2cSBryan Venteicher 	struct vmxnet3_txring *txr;
1182e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *txc;
1183e3c97c2cSBryan Venteicher 	size_t descsz, compsz;
1184e3c97c2cSBryan Venteicher 	int i, q, error;
1185e3c97c2cSBryan Venteicher 
1186e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
1187e3c97c2cSBryan Venteicher 
1188e3c97c2cSBryan Venteicher 	for (q = 0; q < sc->vmx_ntxqueues; q++) {
1189e3c97c2cSBryan Venteicher 		txq = &sc->vmx_txq[q];
1190e3c97c2cSBryan Venteicher 		txr = &txq->vxtxq_cmd_ring;
1191e3c97c2cSBryan Venteicher 		txc = &txq->vxtxq_comp_ring;
1192e3c97c2cSBryan Venteicher 
1193e3c97c2cSBryan Venteicher 		descsz = txr->vxtxr_ndesc * sizeof(struct vmxnet3_txdesc);
1194e3c97c2cSBryan Venteicher 		compsz = txr->vxtxr_ndesc * sizeof(struct vmxnet3_txcompdesc);
1195e3c97c2cSBryan Venteicher 
1196e3c97c2cSBryan Venteicher 		error = bus_dma_tag_create(bus_get_dma_tag(dev),
1197e3c97c2cSBryan Venteicher 		    1, 0,			/* alignment, boundary */
1198e3c97c2cSBryan Venteicher 		    BUS_SPACE_MAXADDR,		/* lowaddr */
1199e3c97c2cSBryan Venteicher 		    BUS_SPACE_MAXADDR,		/* highaddr */
1200e3c97c2cSBryan Venteicher 		    NULL, NULL,			/* filter, filterarg */
1201*e557c1ddSBryan Venteicher 		    VMXNET3_TX_MAXSIZE,		/* maxsize */
1202e3c97c2cSBryan Venteicher 		    VMXNET3_TX_MAXSEGS,		/* nsegments */
1203e3c97c2cSBryan Venteicher 		    VMXNET3_TX_MAXSEGSIZE,	/* maxsegsize */
1204e3c97c2cSBryan Venteicher 		    0,				/* flags */
1205e3c97c2cSBryan Venteicher 		    NULL, NULL,			/* lockfunc, lockarg */
1206e3c97c2cSBryan Venteicher 		    &txr->vxtxr_txtag);
1207e3c97c2cSBryan Venteicher 		if (error) {
1208e3c97c2cSBryan Venteicher 			device_printf(dev,
1209e3c97c2cSBryan Venteicher 			    "unable to create Tx buffer tag for queue %d\n", q);
1210e3c97c2cSBryan Venteicher 			return (error);
1211e3c97c2cSBryan Venteicher 		}
1212e3c97c2cSBryan Venteicher 
1213e3c97c2cSBryan Venteicher 		error = vmxnet3_dma_malloc(sc, descsz, 512, &txr->vxtxr_dma);
1214e3c97c2cSBryan Venteicher 		if (error) {
1215e3c97c2cSBryan Venteicher 			device_printf(dev, "cannot alloc Tx descriptors for "
1216e3c97c2cSBryan Venteicher 			    "queue %d error %d\n", q, error);
1217e3c97c2cSBryan Venteicher 			return (error);
1218e3c97c2cSBryan Venteicher 		}
1219e3c97c2cSBryan Venteicher 		txr->vxtxr_txd =
1220e3c97c2cSBryan Venteicher 		    (struct vmxnet3_txdesc *) txr->vxtxr_dma.dma_vaddr;
1221e3c97c2cSBryan Venteicher 
1222e3c97c2cSBryan Venteicher 		error = vmxnet3_dma_malloc(sc, compsz, 512, &txc->vxcr_dma);
1223e3c97c2cSBryan Venteicher 		if (error) {
1224e3c97c2cSBryan Venteicher 			device_printf(dev, "cannot alloc Tx comp descriptors "
1225e3c97c2cSBryan Venteicher 			   "for queue %d error %d\n", q, error);
1226e3c97c2cSBryan Venteicher 			return (error);
1227e3c97c2cSBryan Venteicher 		}
1228e3c97c2cSBryan Venteicher 		txc->vxcr_u.txcd =
1229e3c97c2cSBryan Venteicher 		    (struct vmxnet3_txcompdesc *) txc->vxcr_dma.dma_vaddr;
1230e3c97c2cSBryan Venteicher 
1231e3c97c2cSBryan Venteicher 		for (i = 0; i < txr->vxtxr_ndesc; i++) {
1232e3c97c2cSBryan Venteicher 			error = bus_dmamap_create(txr->vxtxr_txtag, 0,
1233e3c97c2cSBryan Venteicher 			    &txr->vxtxr_txbuf[i].vtxb_dmamap);
1234e3c97c2cSBryan Venteicher 			if (error) {
1235e3c97c2cSBryan Venteicher 				device_printf(dev, "unable to create Tx buf "
1236e3c97c2cSBryan Venteicher 				    "dmamap for queue %d idx %d\n", q, i);
1237e3c97c2cSBryan Venteicher 				return (error);
1238e3c97c2cSBryan Venteicher 			}
1239e3c97c2cSBryan Venteicher 		}
1240e3c97c2cSBryan Venteicher 	}
1241e3c97c2cSBryan Venteicher 
1242e3c97c2cSBryan Venteicher 	return (0);
1243e3c97c2cSBryan Venteicher }
1244e3c97c2cSBryan Venteicher 
1245e3c97c2cSBryan Venteicher static void
1246e3c97c2cSBryan Venteicher vmxnet3_free_txq_data(struct vmxnet3_softc *sc)
1247e3c97c2cSBryan Venteicher {
1248e3c97c2cSBryan Venteicher 	device_t dev;
1249e3c97c2cSBryan Venteicher 	struct vmxnet3_txqueue *txq;
1250e3c97c2cSBryan Venteicher 	struct vmxnet3_txring *txr;
1251e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *txc;
1252e3c97c2cSBryan Venteicher 	struct vmxnet3_txbuf *txb;
1253e3c97c2cSBryan Venteicher 	int i, q;
1254e3c97c2cSBryan Venteicher 
1255e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
1256e3c97c2cSBryan Venteicher 
1257e3c97c2cSBryan Venteicher 	for (q = 0; q < sc->vmx_ntxqueues; q++) {
1258e3c97c2cSBryan Venteicher 		txq = &sc->vmx_txq[q];
1259e3c97c2cSBryan Venteicher 		txr = &txq->vxtxq_cmd_ring;
1260e3c97c2cSBryan Venteicher 		txc = &txq->vxtxq_comp_ring;
1261e3c97c2cSBryan Venteicher 
1262e3c97c2cSBryan Venteicher 		for (i = 0; i < txr->vxtxr_ndesc; i++) {
1263e3c97c2cSBryan Venteicher 			txb = &txr->vxtxr_txbuf[i];
1264e3c97c2cSBryan Venteicher 			if (txb->vtxb_dmamap != NULL) {
1265e3c97c2cSBryan Venteicher 				bus_dmamap_destroy(txr->vxtxr_txtag,
1266e3c97c2cSBryan Venteicher 				    txb->vtxb_dmamap);
1267e3c97c2cSBryan Venteicher 				txb->vtxb_dmamap = NULL;
1268e3c97c2cSBryan Venteicher 			}
1269e3c97c2cSBryan Venteicher 		}
1270e3c97c2cSBryan Venteicher 
1271e3c97c2cSBryan Venteicher 		if (txc->vxcr_u.txcd != NULL) {
1272e3c97c2cSBryan Venteicher 			vmxnet3_dma_free(sc, &txc->vxcr_dma);
1273e3c97c2cSBryan Venteicher 			txc->vxcr_u.txcd = NULL;
1274e3c97c2cSBryan Venteicher 		}
1275e3c97c2cSBryan Venteicher 
1276e3c97c2cSBryan Venteicher 		if (txr->vxtxr_txd != NULL) {
1277e3c97c2cSBryan Venteicher 			vmxnet3_dma_free(sc, &txr->vxtxr_dma);
1278e3c97c2cSBryan Venteicher 			txr->vxtxr_txd = NULL;
1279e3c97c2cSBryan Venteicher 		}
1280e3c97c2cSBryan Venteicher 
1281e3c97c2cSBryan Venteicher 		if (txr->vxtxr_txtag != NULL) {
1282e3c97c2cSBryan Venteicher 			bus_dma_tag_destroy(txr->vxtxr_txtag);
1283e3c97c2cSBryan Venteicher 			txr->vxtxr_txtag = NULL;
1284e3c97c2cSBryan Venteicher 		}
1285e3c97c2cSBryan Venteicher 	}
1286e3c97c2cSBryan Venteicher }
1287e3c97c2cSBryan Venteicher 
1288e3c97c2cSBryan Venteicher static int
1289e3c97c2cSBryan Venteicher vmxnet3_alloc_rxq_data(struct vmxnet3_softc *sc)
1290e3c97c2cSBryan Venteicher {
1291e3c97c2cSBryan Venteicher 	device_t dev;
1292e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
1293e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
1294e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *rxc;
1295e3c97c2cSBryan Venteicher 	int descsz, compsz;
1296e3c97c2cSBryan Venteicher 	int i, j, q, error;
1297e3c97c2cSBryan Venteicher 
1298e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
1299e3c97c2cSBryan Venteicher 
1300e3c97c2cSBryan Venteicher 	for (q = 0; q < sc->vmx_nrxqueues; q++) {
1301e3c97c2cSBryan Venteicher 		rxq = &sc->vmx_rxq[q];
1302e3c97c2cSBryan Venteicher 		rxc = &rxq->vxrxq_comp_ring;
1303e3c97c2cSBryan Venteicher 		compsz = 0;
1304e3c97c2cSBryan Venteicher 
1305e3c97c2cSBryan Venteicher 		for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) {
1306e3c97c2cSBryan Venteicher 			rxr = &rxq->vxrxq_cmd_ring[i];
1307e3c97c2cSBryan Venteicher 
1308e3c97c2cSBryan Venteicher 			descsz = rxr->vxrxr_ndesc *
1309e3c97c2cSBryan Venteicher 			    sizeof(struct vmxnet3_rxdesc);
1310e3c97c2cSBryan Venteicher 			compsz += rxr->vxrxr_ndesc *
1311e3c97c2cSBryan Venteicher 			    sizeof(struct vmxnet3_rxcompdesc);
1312e3c97c2cSBryan Venteicher 
1313e3c97c2cSBryan Venteicher 			error = bus_dma_tag_create(bus_get_dma_tag(dev),
1314e3c97c2cSBryan Venteicher 			    1, 0,		/* alignment, boundary */
1315e3c97c2cSBryan Venteicher 			    BUS_SPACE_MAXADDR,	/* lowaddr */
1316e3c97c2cSBryan Venteicher 			    BUS_SPACE_MAXADDR,	/* highaddr */
1317e3c97c2cSBryan Venteicher 			    NULL, NULL,		/* filter, filterarg */
1318e3c97c2cSBryan Venteicher 			    MJUMPAGESIZE,	/* maxsize */
1319e3c97c2cSBryan Venteicher 			    1,			/* nsegments */
1320e3c97c2cSBryan Venteicher 			    MJUMPAGESIZE,	/* maxsegsize */
1321e3c97c2cSBryan Venteicher 			    0,			/* flags */
1322e3c97c2cSBryan Venteicher 			    NULL, NULL,		/* lockfunc, lockarg */
1323e3c97c2cSBryan Venteicher 			    &rxr->vxrxr_rxtag);
1324e3c97c2cSBryan Venteicher 			if (error) {
1325e3c97c2cSBryan Venteicher 				device_printf(dev,
1326e3c97c2cSBryan Venteicher 				    "unable to create Rx buffer tag for "
1327e3c97c2cSBryan Venteicher 				    "queue %d\n", q);
1328e3c97c2cSBryan Venteicher 				return (error);
1329e3c97c2cSBryan Venteicher 			}
1330e3c97c2cSBryan Venteicher 
1331e3c97c2cSBryan Venteicher 			error = vmxnet3_dma_malloc(sc, descsz, 512,
1332e3c97c2cSBryan Venteicher 			    &rxr->vxrxr_dma);
1333e3c97c2cSBryan Venteicher 			if (error) {
1334e3c97c2cSBryan Venteicher 				device_printf(dev, "cannot allocate Rx "
1335e3c97c2cSBryan Venteicher 				    "descriptors for queue %d/%d error %d\n",
1336e3c97c2cSBryan Venteicher 				    i, q, error);
1337e3c97c2cSBryan Venteicher 				return (error);
1338e3c97c2cSBryan Venteicher 			}
1339e3c97c2cSBryan Venteicher 			rxr->vxrxr_rxd =
1340e3c97c2cSBryan Venteicher 			    (struct vmxnet3_rxdesc *) rxr->vxrxr_dma.dma_vaddr;
1341e3c97c2cSBryan Venteicher 		}
1342e3c97c2cSBryan Venteicher 
1343e3c97c2cSBryan Venteicher 		error = vmxnet3_dma_malloc(sc, compsz, 512, &rxc->vxcr_dma);
1344e3c97c2cSBryan Venteicher 		if (error) {
1345e3c97c2cSBryan Venteicher 			device_printf(dev, "cannot alloc Rx comp descriptors "
1346e3c97c2cSBryan Venteicher 			    "for queue %d error %d\n", q, error);
1347e3c97c2cSBryan Venteicher 			return (error);
1348e3c97c2cSBryan Venteicher 		}
1349e3c97c2cSBryan Venteicher 		rxc->vxcr_u.rxcd =
1350e3c97c2cSBryan Venteicher 		    (struct vmxnet3_rxcompdesc *) rxc->vxcr_dma.dma_vaddr;
1351e3c97c2cSBryan Venteicher 
1352e3c97c2cSBryan Venteicher 		for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) {
1353e3c97c2cSBryan Venteicher 			rxr = &rxq->vxrxq_cmd_ring[i];
1354e3c97c2cSBryan Venteicher 
1355e3c97c2cSBryan Venteicher 			error = bus_dmamap_create(rxr->vxrxr_rxtag, 0,
1356e3c97c2cSBryan Venteicher 			    &rxr->vxrxr_spare_dmap);
1357e3c97c2cSBryan Venteicher 			if (error) {
1358e3c97c2cSBryan Venteicher 				device_printf(dev, "unable to create spare "
1359e3c97c2cSBryan Venteicher 				    "dmamap for queue %d/%d error %d\n",
1360e3c97c2cSBryan Venteicher 				    q, i, error);
1361e3c97c2cSBryan Venteicher 				return (error);
1362e3c97c2cSBryan Venteicher 			}
1363e3c97c2cSBryan Venteicher 
1364e3c97c2cSBryan Venteicher 			for (j = 0; j < rxr->vxrxr_ndesc; j++) {
1365e3c97c2cSBryan Venteicher 				error = bus_dmamap_create(rxr->vxrxr_rxtag, 0,
1366e3c97c2cSBryan Venteicher 				    &rxr->vxrxr_rxbuf[j].vrxb_dmamap);
1367e3c97c2cSBryan Venteicher 				if (error) {
1368e3c97c2cSBryan Venteicher 					device_printf(dev, "unable to create "
1369e3c97c2cSBryan Venteicher 					    "dmamap for queue %d/%d slot %d "
1370e3c97c2cSBryan Venteicher 					    "error %d\n",
1371e3c97c2cSBryan Venteicher 					    q, i, j, error);
1372e3c97c2cSBryan Venteicher 					return (error);
1373e3c97c2cSBryan Venteicher 				}
1374e3c97c2cSBryan Venteicher 			}
1375e3c97c2cSBryan Venteicher 		}
1376e3c97c2cSBryan Venteicher 	}
1377e3c97c2cSBryan Venteicher 
1378e3c97c2cSBryan Venteicher 	return (0);
1379e3c97c2cSBryan Venteicher }
1380e3c97c2cSBryan Venteicher 
1381e3c97c2cSBryan Venteicher static void
1382e3c97c2cSBryan Venteicher vmxnet3_free_rxq_data(struct vmxnet3_softc *sc)
1383e3c97c2cSBryan Venteicher {
1384e3c97c2cSBryan Venteicher 	device_t dev;
1385e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
1386e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
1387e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *rxc;
1388e3c97c2cSBryan Venteicher 	struct vmxnet3_rxbuf *rxb;
1389e3c97c2cSBryan Venteicher 	int i, j, q;
1390e3c97c2cSBryan Venteicher 
1391e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
1392e3c97c2cSBryan Venteicher 
1393e3c97c2cSBryan Venteicher 	for (q = 0; q < sc->vmx_nrxqueues; q++) {
1394e3c97c2cSBryan Venteicher 		rxq = &sc->vmx_rxq[q];
1395e3c97c2cSBryan Venteicher 		rxc = &rxq->vxrxq_comp_ring;
1396e3c97c2cSBryan Venteicher 
1397e3c97c2cSBryan Venteicher 		for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) {
1398e3c97c2cSBryan Venteicher 			rxr = &rxq->vxrxq_cmd_ring[i];
1399e3c97c2cSBryan Venteicher 
1400e3c97c2cSBryan Venteicher 			if (rxr->vxrxr_spare_dmap != NULL) {
1401e3c97c2cSBryan Venteicher 				bus_dmamap_destroy(rxr->vxrxr_rxtag,
1402e3c97c2cSBryan Venteicher 				    rxr->vxrxr_spare_dmap);
1403e3c97c2cSBryan Venteicher 				rxr->vxrxr_spare_dmap = NULL;
1404e3c97c2cSBryan Venteicher 			}
1405e3c97c2cSBryan Venteicher 
1406e3c97c2cSBryan Venteicher 			for (j = 0; j < rxr->vxrxr_ndesc; j++) {
1407e3c97c2cSBryan Venteicher 				rxb = &rxr->vxrxr_rxbuf[j];
1408e3c97c2cSBryan Venteicher 				if (rxb->vrxb_dmamap != NULL) {
1409e3c97c2cSBryan Venteicher 					bus_dmamap_destroy(rxr->vxrxr_rxtag,
1410e3c97c2cSBryan Venteicher 					    rxb->vrxb_dmamap);
1411e3c97c2cSBryan Venteicher 					rxb->vrxb_dmamap = NULL;
1412e3c97c2cSBryan Venteicher 				}
1413e3c97c2cSBryan Venteicher 			}
1414e3c97c2cSBryan Venteicher 		}
1415e3c97c2cSBryan Venteicher 
1416e3c97c2cSBryan Venteicher 		if (rxc->vxcr_u.rxcd != NULL) {
1417e3c97c2cSBryan Venteicher 			vmxnet3_dma_free(sc, &rxc->vxcr_dma);
1418e3c97c2cSBryan Venteicher 			rxc->vxcr_u.rxcd = NULL;
1419e3c97c2cSBryan Venteicher 		}
1420e3c97c2cSBryan Venteicher 
1421e3c97c2cSBryan Venteicher 		for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) {
1422e3c97c2cSBryan Venteicher 			rxr = &rxq->vxrxq_cmd_ring[i];
1423e3c97c2cSBryan Venteicher 
1424e3c97c2cSBryan Venteicher 			if (rxr->vxrxr_rxd != NULL) {
1425e3c97c2cSBryan Venteicher 				vmxnet3_dma_free(sc, &rxr->vxrxr_dma);
1426e3c97c2cSBryan Venteicher 				rxr->vxrxr_rxd = NULL;
1427e3c97c2cSBryan Venteicher 			}
1428e3c97c2cSBryan Venteicher 
1429e3c97c2cSBryan Venteicher 			if (rxr->vxrxr_rxtag != NULL) {
1430e3c97c2cSBryan Venteicher 				bus_dma_tag_destroy(rxr->vxrxr_rxtag);
1431e3c97c2cSBryan Venteicher 				rxr->vxrxr_rxtag = NULL;
1432e3c97c2cSBryan Venteicher 			}
1433e3c97c2cSBryan Venteicher 		}
1434e3c97c2cSBryan Venteicher 	}
1435e3c97c2cSBryan Venteicher }
1436e3c97c2cSBryan Venteicher 
1437e3c97c2cSBryan Venteicher static int
1438e3c97c2cSBryan Venteicher vmxnet3_alloc_queue_data(struct vmxnet3_softc *sc)
1439e3c97c2cSBryan Venteicher {
1440e3c97c2cSBryan Venteicher 	int error;
1441e3c97c2cSBryan Venteicher 
1442e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_txq_data(sc);
1443e3c97c2cSBryan Venteicher 	if (error)
1444e3c97c2cSBryan Venteicher 		return (error);
1445e3c97c2cSBryan Venteicher 
1446e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_rxq_data(sc);
1447e3c97c2cSBryan Venteicher 	if (error)
1448e3c97c2cSBryan Venteicher 		return (error);
1449e3c97c2cSBryan Venteicher 
1450e3c97c2cSBryan Venteicher 	return (0);
1451e3c97c2cSBryan Venteicher }
1452e3c97c2cSBryan Venteicher 
1453e3c97c2cSBryan Venteicher static void
1454e3c97c2cSBryan Venteicher vmxnet3_free_queue_data(struct vmxnet3_softc *sc)
1455e3c97c2cSBryan Venteicher {
1456e3c97c2cSBryan Venteicher 
14573c965775SBryan Venteicher 	if (sc->vmx_rxq != NULL)
1458e3c97c2cSBryan Venteicher 		vmxnet3_free_rxq_data(sc);
14593c965775SBryan Venteicher 
14603c965775SBryan Venteicher 	if (sc->vmx_txq != NULL)
1461e3c97c2cSBryan Venteicher 		vmxnet3_free_txq_data(sc);
1462e3c97c2cSBryan Venteicher }
1463e3c97c2cSBryan Venteicher 
1464e3c97c2cSBryan Venteicher static int
1465e3c97c2cSBryan Venteicher vmxnet3_alloc_mcast_table(struct vmxnet3_softc *sc)
1466e3c97c2cSBryan Venteicher {
1467e3c97c2cSBryan Venteicher 	int error;
1468e3c97c2cSBryan Venteicher 
1469e3c97c2cSBryan Venteicher 	error = vmxnet3_dma_malloc(sc, VMXNET3_MULTICAST_MAX * ETHER_ADDR_LEN,
1470e3c97c2cSBryan Venteicher 	    32, &sc->vmx_mcast_dma);
1471e3c97c2cSBryan Venteicher 	if (error)
1472e3c97c2cSBryan Venteicher 		device_printf(sc->vmx_dev, "unable to alloc multicast table\n");
1473e3c97c2cSBryan Venteicher 	else
1474e3c97c2cSBryan Venteicher 		sc->vmx_mcast = sc->vmx_mcast_dma.dma_vaddr;
1475e3c97c2cSBryan Venteicher 
1476e3c97c2cSBryan Venteicher 	return (error);
1477e3c97c2cSBryan Venteicher }
1478e3c97c2cSBryan Venteicher 
1479e3c97c2cSBryan Venteicher static void
1480e3c97c2cSBryan Venteicher vmxnet3_free_mcast_table(struct vmxnet3_softc *sc)
1481e3c97c2cSBryan Venteicher {
1482e3c97c2cSBryan Venteicher 
1483e3c97c2cSBryan Venteicher 	if (sc->vmx_mcast != NULL) {
1484e3c97c2cSBryan Venteicher 		vmxnet3_dma_free(sc, &sc->vmx_mcast_dma);
1485e3c97c2cSBryan Venteicher 		sc->vmx_mcast = NULL;
1486e3c97c2cSBryan Venteicher 	}
1487e3c97c2cSBryan Venteicher }
1488e3c97c2cSBryan Venteicher 
1489e3c97c2cSBryan Venteicher static void
1490e3c97c2cSBryan Venteicher vmxnet3_init_shared_data(struct vmxnet3_softc *sc)
1491e3c97c2cSBryan Venteicher {
1492e3c97c2cSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
1493e3c97c2cSBryan Venteicher 	struct vmxnet3_txqueue *txq;
1494e3c97c2cSBryan Venteicher 	struct vmxnet3_txq_shared *txs;
1495e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
1496e3c97c2cSBryan Venteicher 	struct vmxnet3_rxq_shared *rxs;
1497e3c97c2cSBryan Venteicher 	int i;
1498e3c97c2cSBryan Venteicher 
1499e3c97c2cSBryan Venteicher 	ds = sc->vmx_ds;
1500e3c97c2cSBryan Venteicher 
1501e3c97c2cSBryan Venteicher 	/*
1502e3c97c2cSBryan Venteicher 	 * Initialize fields of the shared data that remains the same across
1503e3c97c2cSBryan Venteicher 	 * reinits. Note the shared data is zero'd when allocated.
1504e3c97c2cSBryan Venteicher 	 */
1505e3c97c2cSBryan Venteicher 
1506e3c97c2cSBryan Venteicher 	ds->magic = VMXNET3_REV1_MAGIC;
1507e3c97c2cSBryan Venteicher 
1508e3c97c2cSBryan Venteicher 	/* DriverInfo */
1509e3c97c2cSBryan Venteicher 	ds->version = VMXNET3_DRIVER_VERSION;
1510ce3be286SBryan Venteicher 	ds->guest = VMXNET3_GOS_FREEBSD |
1511e3c97c2cSBryan Venteicher #ifdef __LP64__
1512e3c97c2cSBryan Venteicher 	    VMXNET3_GOS_64BIT;
1513e3c97c2cSBryan Venteicher #else
1514e3c97c2cSBryan Venteicher 	    VMXNET3_GOS_32BIT;
1515e3c97c2cSBryan Venteicher #endif
1516e3c97c2cSBryan Venteicher 	ds->vmxnet3_revision = 1;
1517e3c97c2cSBryan Venteicher 	ds->upt_version = 1;
1518e3c97c2cSBryan Venteicher 
1519e3c97c2cSBryan Venteicher 	/* Misc. conf */
1520e3c97c2cSBryan Venteicher 	ds->driver_data = vtophys(sc);
1521e3c97c2cSBryan Venteicher 	ds->driver_data_len = sizeof(struct vmxnet3_softc);
1522e3c97c2cSBryan Venteicher 	ds->queue_shared = sc->vmx_qs_dma.dma_paddr;
1523e3c97c2cSBryan Venteicher 	ds->queue_shared_len = sc->vmx_qs_dma.dma_size;
1524e3c97c2cSBryan Venteicher 	ds->nrxsg_max = sc->vmx_max_rxsegs;
1525e3c97c2cSBryan Venteicher 
1526*e557c1ddSBryan Venteicher 	/* RSS conf */
1527*e557c1ddSBryan Venteicher 	if (sc->vmx_flags & VMXNET3_FLAG_RSS) {
1528*e557c1ddSBryan Venteicher 		ds->rss.version = 1;
1529*e557c1ddSBryan Venteicher 		ds->rss.paddr = sc->vmx_rss_dma.dma_paddr;
1530*e557c1ddSBryan Venteicher 		ds->rss.len = sc->vmx_rss_dma.dma_size;
1531*e557c1ddSBryan Venteicher 	}
1532*e557c1ddSBryan Venteicher 
1533e3c97c2cSBryan Venteicher 	/* Interrupt control. */
1534e3c97c2cSBryan Venteicher 	ds->automask = sc->vmx_intr_mask_mode == VMXNET3_IMM_AUTO;
1535e3c97c2cSBryan Venteicher 	ds->nintr = sc->vmx_nintrs;
1536e3c97c2cSBryan Venteicher 	ds->evintr = sc->vmx_event_intr_idx;
1537e3c97c2cSBryan Venteicher 	ds->ictrl = VMXNET3_ICTRL_DISABLE_ALL;
1538e3c97c2cSBryan Venteicher 
1539e3c97c2cSBryan Venteicher 	for (i = 0; i < sc->vmx_nintrs; i++)
1540e3c97c2cSBryan Venteicher 		ds->modlevel[i] = UPT1_IMOD_ADAPTIVE;
1541e3c97c2cSBryan Venteicher 
1542e3c97c2cSBryan Venteicher 	/* Receive filter. */
1543e3c97c2cSBryan Venteicher 	ds->mcast_table = sc->vmx_mcast_dma.dma_paddr;
1544e3c97c2cSBryan Venteicher 	ds->mcast_tablelen = sc->vmx_mcast_dma.dma_size;
1545e3c97c2cSBryan Venteicher 
1546e3c97c2cSBryan Venteicher 	/* Tx queues */
1547e3c97c2cSBryan Venteicher 	for (i = 0; i < sc->vmx_ntxqueues; i++) {
1548e3c97c2cSBryan Venteicher 		txq = &sc->vmx_txq[i];
1549e3c97c2cSBryan Venteicher 		txs = txq->vxtxq_ts;
1550e3c97c2cSBryan Venteicher 
1551e3c97c2cSBryan Venteicher 		txs->cmd_ring = txq->vxtxq_cmd_ring.vxtxr_dma.dma_paddr;
15523c965775SBryan Venteicher 		txs->cmd_ring_len = txq->vxtxq_cmd_ring.vxtxr_ndesc;
1553e3c97c2cSBryan Venteicher 		txs->comp_ring = txq->vxtxq_comp_ring.vxcr_dma.dma_paddr;
15543c965775SBryan Venteicher 		txs->comp_ring_len = txq->vxtxq_comp_ring.vxcr_ndesc;
1555e3c97c2cSBryan Venteicher 		txs->driver_data = vtophys(txq);
1556e3c97c2cSBryan Venteicher 		txs->driver_data_len = sizeof(struct vmxnet3_txqueue);
1557e3c97c2cSBryan Venteicher 	}
1558e3c97c2cSBryan Venteicher 
1559e3c97c2cSBryan Venteicher 	/* Rx queues */
1560e3c97c2cSBryan Venteicher 	for (i = 0; i < sc->vmx_nrxqueues; i++) {
1561e3c97c2cSBryan Venteicher 		rxq = &sc->vmx_rxq[i];
1562e3c97c2cSBryan Venteicher 		rxs = rxq->vxrxq_rs;
1563e3c97c2cSBryan Venteicher 
1564e3c97c2cSBryan Venteicher 		rxs->cmd_ring[0] = rxq->vxrxq_cmd_ring[0].vxrxr_dma.dma_paddr;
1565e3c97c2cSBryan Venteicher 		rxs->cmd_ring_len[0] = rxq->vxrxq_cmd_ring[0].vxrxr_ndesc;
1566e3c97c2cSBryan Venteicher 		rxs->cmd_ring[1] = rxq->vxrxq_cmd_ring[1].vxrxr_dma.dma_paddr;
1567e3c97c2cSBryan Venteicher 		rxs->cmd_ring_len[1] = rxq->vxrxq_cmd_ring[1].vxrxr_ndesc;
1568e3c97c2cSBryan Venteicher 		rxs->comp_ring = rxq->vxrxq_comp_ring.vxcr_dma.dma_paddr;
15693c965775SBryan Venteicher 		rxs->comp_ring_len = rxq->vxrxq_comp_ring.vxcr_ndesc;
1570e3c97c2cSBryan Venteicher 		rxs->driver_data = vtophys(rxq);
1571e3c97c2cSBryan Venteicher 		rxs->driver_data_len = sizeof(struct vmxnet3_rxqueue);
1572e3c97c2cSBryan Venteicher 	}
1573e3c97c2cSBryan Venteicher }
1574e3c97c2cSBryan Venteicher 
1575e3c97c2cSBryan Venteicher static void
1576e3c97c2cSBryan Venteicher vmxnet3_reinit_interface(struct vmxnet3_softc *sc)
1577e3c97c2cSBryan Venteicher {
1578e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
1579e3c97c2cSBryan Venteicher 
1580e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
1581e3c97c2cSBryan Venteicher 
1582e3c97c2cSBryan Venteicher 	/* Use the current MAC address. */
1583e3c97c2cSBryan Venteicher 	bcopy(IF_LLADDR(sc->vmx_ifp), sc->vmx_lladdr, ETHER_ADDR_LEN);
1584e3c97c2cSBryan Venteicher 	vmxnet3_set_lladdr(sc);
1585e3c97c2cSBryan Venteicher 
1586e3c97c2cSBryan Venteicher 	ifp->if_hwassist = 0;
1587e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & IFCAP_TXCSUM)
1588e3c97c2cSBryan Venteicher 		ifp->if_hwassist |= VMXNET3_CSUM_OFFLOAD;
1589e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
1590e3c97c2cSBryan Venteicher 		ifp->if_hwassist |= VMXNET3_CSUM_OFFLOAD_IPV6;
1591e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & IFCAP_TSO4)
1592*e557c1ddSBryan Venteicher 		ifp->if_hwassist |= CSUM_IP_TSO;
1593e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & IFCAP_TSO6)
1594*e557c1ddSBryan Venteicher 		ifp->if_hwassist |= CSUM_IP6_TSO;
1595*e557c1ddSBryan Venteicher }
1596*e557c1ddSBryan Venteicher 
1597*e557c1ddSBryan Venteicher static void
1598*e557c1ddSBryan Venteicher vmxnet3_reinit_rss_shared_data(struct vmxnet3_softc *sc)
1599*e557c1ddSBryan Venteicher {
1600*e557c1ddSBryan Venteicher 	/*
1601*e557c1ddSBryan Venteicher 	 * Use the same key as the Linux driver until FreeBSD can do
1602*e557c1ddSBryan Venteicher 	 * RSS (presumably Toeplitz) in software.
1603*e557c1ddSBryan Venteicher 	 */
1604*e557c1ddSBryan Venteicher 	static const uint8_t rss_key[UPT1_RSS_MAX_KEY_SIZE] = {
1605*e557c1ddSBryan Venteicher 	    0x3b, 0x56, 0xd1, 0x56, 0x13, 0x4a, 0xe7, 0xac,
1606*e557c1ddSBryan Venteicher 	    0xe8, 0x79, 0x09, 0x75, 0xe8, 0x65, 0x79, 0x28,
1607*e557c1ddSBryan Venteicher 	    0x35, 0x12, 0xb9, 0x56, 0x7c, 0x76, 0x4b, 0x70,
1608*e557c1ddSBryan Venteicher 	    0xd8, 0x56, 0xa3, 0x18, 0x9b, 0x0a, 0xee, 0xf3,
1609*e557c1ddSBryan Venteicher 	    0x96, 0xa6, 0x9f, 0x8f, 0x9e, 0x8c, 0x90, 0xc9,
1610*e557c1ddSBryan Venteicher 	};
1611*e557c1ddSBryan Venteicher 
1612*e557c1ddSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
1613*e557c1ddSBryan Venteicher 	struct vmxnet3_rss_shared *rss;
1614*e557c1ddSBryan Venteicher 	int i;
1615*e557c1ddSBryan Venteicher 
1616*e557c1ddSBryan Venteicher 	ds = sc->vmx_ds;
1617*e557c1ddSBryan Venteicher 	rss = sc->vmx_rss;
1618*e557c1ddSBryan Venteicher 
1619*e557c1ddSBryan Venteicher 	rss->hash_type =
1620*e557c1ddSBryan Venteicher 	    UPT1_RSS_HASH_TYPE_IPV4 | UPT1_RSS_HASH_TYPE_TCP_IPV4 |
1621*e557c1ddSBryan Venteicher 	    UPT1_RSS_HASH_TYPE_IPV6 | UPT1_RSS_HASH_TYPE_TCP_IPV6;
1622*e557c1ddSBryan Venteicher 	rss->hash_func = UPT1_RSS_HASH_FUNC_TOEPLITZ;
1623*e557c1ddSBryan Venteicher 	rss->hash_key_size = UPT1_RSS_MAX_KEY_SIZE;
1624*e557c1ddSBryan Venteicher 	rss->ind_table_size = UPT1_RSS_MAX_IND_TABLE_SIZE;
1625*e557c1ddSBryan Venteicher 	memcpy(rss->hash_key, rss_key, UPT1_RSS_MAX_KEY_SIZE);
1626*e557c1ddSBryan Venteicher 
1627*e557c1ddSBryan Venteicher 	for (i = 0; i < UPT1_RSS_MAX_IND_TABLE_SIZE; i++)
1628*e557c1ddSBryan Venteicher 		rss->ind_table[i] = i % sc->vmx_nrxqueues;
1629e3c97c2cSBryan Venteicher }
1630e3c97c2cSBryan Venteicher 
1631e3c97c2cSBryan Venteicher static void
1632e3c97c2cSBryan Venteicher vmxnet3_reinit_shared_data(struct vmxnet3_softc *sc)
1633e3c97c2cSBryan Venteicher {
1634e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
1635e3c97c2cSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
1636e3c97c2cSBryan Venteicher 
1637e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
1638e3c97c2cSBryan Venteicher 	ds = sc->vmx_ds;
1639e3c97c2cSBryan Venteicher 
1640*e557c1ddSBryan Venteicher 	ds->mtu = ifp->if_mtu;
1641*e557c1ddSBryan Venteicher 	ds->ntxqueue = sc->vmx_ntxqueues;
1642*e557c1ddSBryan Venteicher 	ds->nrxqueue = sc->vmx_nrxqueues;
1643*e557c1ddSBryan Venteicher 
1644e3c97c2cSBryan Venteicher 	ds->upt_features = 0;
1645e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6))
1646e3c97c2cSBryan Venteicher 		ds->upt_features |= UPT1_F_CSUM;
16473c5dfe89SBryan Venteicher 	if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
16483c5dfe89SBryan Venteicher 		ds->upt_features |= UPT1_F_VLAN;
1649e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & IFCAP_LRO)
1650e3c97c2cSBryan Venteicher 		ds->upt_features |= UPT1_F_LRO;
1651e3c97c2cSBryan Venteicher 
1652*e557c1ddSBryan Venteicher 	if (sc->vmx_flags & VMXNET3_FLAG_RSS) {
1653*e557c1ddSBryan Venteicher 		ds->upt_features |= UPT1_F_RSS;
1654*e557c1ddSBryan Venteicher 		vmxnet3_reinit_rss_shared_data(sc);
1655*e557c1ddSBryan Venteicher 	}
1656e3c97c2cSBryan Venteicher 
1657e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_DSL, sc->vmx_ds_dma.dma_paddr);
1658e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_DSH,
1659e3c97c2cSBryan Venteicher 	    (uint64_t) sc->vmx_ds_dma.dma_paddr >> 32);
1660e3c97c2cSBryan Venteicher }
1661e3c97c2cSBryan Venteicher 
1662e3c97c2cSBryan Venteicher static int
1663e3c97c2cSBryan Venteicher vmxnet3_alloc_data(struct vmxnet3_softc *sc)
1664e3c97c2cSBryan Venteicher {
1665e3c97c2cSBryan Venteicher 	int error;
1666e3c97c2cSBryan Venteicher 
1667e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_shared_data(sc);
1668e3c97c2cSBryan Venteicher 	if (error)
1669e3c97c2cSBryan Venteicher 		return (error);
1670e3c97c2cSBryan Venteicher 
1671e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_queue_data(sc);
1672e3c97c2cSBryan Venteicher 	if (error)
1673e3c97c2cSBryan Venteicher 		return (error);
1674e3c97c2cSBryan Venteicher 
1675e3c97c2cSBryan Venteicher 	error = vmxnet3_alloc_mcast_table(sc);
1676e3c97c2cSBryan Venteicher 	if (error)
1677e3c97c2cSBryan Venteicher 		return (error);
1678e3c97c2cSBryan Venteicher 
1679e3c97c2cSBryan Venteicher 	vmxnet3_init_shared_data(sc);
1680e3c97c2cSBryan Venteicher 
1681e3c97c2cSBryan Venteicher 	return (0);
1682e3c97c2cSBryan Venteicher }
1683e3c97c2cSBryan Venteicher 
1684e3c97c2cSBryan Venteicher static void
1685e3c97c2cSBryan Venteicher vmxnet3_free_data(struct vmxnet3_softc *sc)
1686e3c97c2cSBryan Venteicher {
1687e3c97c2cSBryan Venteicher 
1688e3c97c2cSBryan Venteicher 	vmxnet3_free_mcast_table(sc);
1689e3c97c2cSBryan Venteicher 	vmxnet3_free_queue_data(sc);
1690e3c97c2cSBryan Venteicher 	vmxnet3_free_shared_data(sc);
1691e3c97c2cSBryan Venteicher }
1692e3c97c2cSBryan Venteicher 
1693e3c97c2cSBryan Venteicher static int
1694e3c97c2cSBryan Venteicher vmxnet3_setup_interface(struct vmxnet3_softc *sc)
1695e3c97c2cSBryan Venteicher {
1696e3c97c2cSBryan Venteicher 	device_t dev;
1697e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
1698e3c97c2cSBryan Venteicher 
1699e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
1700e3c97c2cSBryan Venteicher 
1701e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp = if_alloc(IFT_ETHER);
1702e3c97c2cSBryan Venteicher 	if (ifp == NULL) {
1703e3c97c2cSBryan Venteicher 		device_printf(dev, "cannot allocate ifnet structure\n");
1704e3c97c2cSBryan Venteicher 		return (ENOSPC);
1705e3c97c2cSBryan Venteicher 	}
1706e3c97c2cSBryan Venteicher 
1707e3c97c2cSBryan Venteicher 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
1708*e557c1ddSBryan Venteicher #if __FreeBSD_version < 1000025
1709*e557c1ddSBryan Venteicher 	ifp->if_baudrate = 1000000000;
1710*e557c1ddSBryan Venteicher #elif __FreeBSD_version < 1100011
1711*e557c1ddSBryan Venteicher 	if_initbaudrate(ifp, IF_Gbps(10));
1712*e557c1ddSBryan Venteicher #else
1713b245f96cSGleb Smirnoff 	ifp->if_baudrate = IF_Gbps(10);
1714*e557c1ddSBryan Venteicher #endif
1715e3c97c2cSBryan Venteicher 	ifp->if_softc = sc;
1716e3c97c2cSBryan Venteicher 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1717e3c97c2cSBryan Venteicher 	ifp->if_init = vmxnet3_init;
1718e3c97c2cSBryan Venteicher 	ifp->if_ioctl = vmxnet3_ioctl;
1719*e557c1ddSBryan Venteicher 	ifp->if_hw_tsomax = VMXNET3_TSO_MAXSIZE;
1720*e557c1ddSBryan Venteicher 
1721*e557c1ddSBryan Venteicher #ifdef VMXNET3_LEGACY_TX
1722e3c97c2cSBryan Venteicher 	ifp->if_start = vmxnet3_start;
1723e3c97c2cSBryan Venteicher 	ifp->if_snd.ifq_drv_maxlen = sc->vmx_ntxdescs - 1;
1724e3c97c2cSBryan Venteicher 	IFQ_SET_MAXLEN(&ifp->if_snd, sc->vmx_ntxdescs - 1);
1725e3c97c2cSBryan Venteicher 	IFQ_SET_READY(&ifp->if_snd);
1726*e557c1ddSBryan Venteicher #else
1727*e557c1ddSBryan Venteicher 	ifp->if_transmit = vmxnet3_txq_mq_start;
1728*e557c1ddSBryan Venteicher 	ifp->if_qflush = vmxnet3_qflush;
1729*e557c1ddSBryan Venteicher #endif
1730e3c97c2cSBryan Venteicher 
1731e3c97c2cSBryan Venteicher 	vmxnet3_get_lladdr(sc);
1732e3c97c2cSBryan Venteicher 	ether_ifattach(ifp, sc->vmx_lladdr);
1733e3c97c2cSBryan Venteicher 
1734e3c97c2cSBryan Venteicher 	ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_TXCSUM;
1735e3c97c2cSBryan Venteicher 	ifp->if_capabilities |= IFCAP_RXCSUM_IPV6 | IFCAP_TXCSUM_IPV6;
1736e3c97c2cSBryan Venteicher 	ifp->if_capabilities |= IFCAP_TSO4 | IFCAP_TSO6;
17373c5dfe89SBryan Venteicher 	ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING |
17383c5dfe89SBryan Venteicher 	    IFCAP_VLAN_HWCSUM;
1739e3c97c2cSBryan Venteicher 	ifp->if_capenable = ifp->if_capabilities;
1740e3c97c2cSBryan Venteicher 
17413c5dfe89SBryan Venteicher 	/* These capabilities are not enabled by default. */
17423c5dfe89SBryan Venteicher 	ifp->if_capabilities |= IFCAP_LRO | IFCAP_VLAN_HWFILTER;
1743e3c97c2cSBryan Venteicher 
1744e3c97c2cSBryan Venteicher 	sc->vmx_vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
1745e3c97c2cSBryan Venteicher 	    vmxnet3_register_vlan, sc, EVENTHANDLER_PRI_FIRST);
1746e3c97c2cSBryan Venteicher 	sc->vmx_vlan_detach = EVENTHANDLER_REGISTER(vlan_config,
1747e3c97c2cSBryan Venteicher 	    vmxnet3_unregister_vlan, sc, EVENTHANDLER_PRI_FIRST);
1748e3c97c2cSBryan Venteicher 
1749e3c97c2cSBryan Venteicher 	ifmedia_init(&sc->vmx_media, 0, vmxnet3_media_change,
1750e3c97c2cSBryan Venteicher 	    vmxnet3_media_status);
1751e3c97c2cSBryan Venteicher 	ifmedia_add(&sc->vmx_media, IFM_ETHER | IFM_AUTO, 0, NULL);
1752e3c97c2cSBryan Venteicher 	ifmedia_set(&sc->vmx_media, IFM_ETHER | IFM_AUTO);
1753e3c97c2cSBryan Venteicher 
1754e3c97c2cSBryan Venteicher 	return (0);
1755e3c97c2cSBryan Venteicher }
1756e3c97c2cSBryan Venteicher 
1757e3c97c2cSBryan Venteicher static void
1758e3c97c2cSBryan Venteicher vmxnet3_evintr(struct vmxnet3_softc *sc)
1759e3c97c2cSBryan Venteicher {
1760e3c97c2cSBryan Venteicher 	device_t dev;
1761e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
1762e3c97c2cSBryan Venteicher 	struct vmxnet3_txq_shared *ts;
1763e3c97c2cSBryan Venteicher 	struct vmxnet3_rxq_shared *rs;
1764e3c97c2cSBryan Venteicher 	uint32_t event;
1765e3c97c2cSBryan Venteicher 	int reset;
1766e3c97c2cSBryan Venteicher 
1767e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
1768e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
1769e3c97c2cSBryan Venteicher 	reset = 0;
1770e3c97c2cSBryan Venteicher 
1771e3c97c2cSBryan Venteicher 	VMXNET3_CORE_LOCK(sc);
1772e3c97c2cSBryan Venteicher 
1773e3c97c2cSBryan Venteicher 	/* Clear events. */
1774e3c97c2cSBryan Venteicher 	event = sc->vmx_ds->event;
1775e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_EVENT, event);
1776e3c97c2cSBryan Venteicher 
1777*e557c1ddSBryan Venteicher 	if (event & VMXNET3_EVENT_LINK) {
1778e3c97c2cSBryan Venteicher 		vmxnet3_link_status(sc);
1779*e557c1ddSBryan Venteicher 		if (sc->vmx_link_active != 0)
1780*e557c1ddSBryan Venteicher 			vmxnet3_tx_start_all(sc);
1781*e557c1ddSBryan Venteicher 	}
1782e3c97c2cSBryan Venteicher 
1783e3c97c2cSBryan Venteicher 	if (event & (VMXNET3_EVENT_TQERROR | VMXNET3_EVENT_RQERROR)) {
1784e3c97c2cSBryan Venteicher 		reset = 1;
1785e3c97c2cSBryan Venteicher 		vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_STATUS);
1786e3c97c2cSBryan Venteicher 		ts = sc->vmx_txq[0].vxtxq_ts;
1787e3c97c2cSBryan Venteicher 		if (ts->stopped != 0)
1788e3c97c2cSBryan Venteicher 			device_printf(dev, "Tx queue error %#x\n", ts->error);
1789e3c97c2cSBryan Venteicher 		rs = sc->vmx_rxq[0].vxrxq_rs;
1790e3c97c2cSBryan Venteicher 		if (rs->stopped != 0)
1791e3c97c2cSBryan Venteicher 			device_printf(dev, "Rx queue error %#x\n", rs->error);
1792e3c97c2cSBryan Venteicher 		device_printf(dev, "Rx/Tx queue error event ... resetting\n");
1793e3c97c2cSBryan Venteicher 	}
1794e3c97c2cSBryan Venteicher 
1795e3c97c2cSBryan Venteicher 	if (event & VMXNET3_EVENT_DIC)
1796e3c97c2cSBryan Venteicher 		device_printf(dev, "device implementation change event\n");
1797e3c97c2cSBryan Venteicher 	if (event & VMXNET3_EVENT_DEBUG)
1798e3c97c2cSBryan Venteicher 		device_printf(dev, "debug event\n");
1799e3c97c2cSBryan Venteicher 
1800e3c97c2cSBryan Venteicher 	if (reset != 0) {
1801e3c97c2cSBryan Venteicher 		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1802e3c97c2cSBryan Venteicher 		vmxnet3_init_locked(sc);
1803e3c97c2cSBryan Venteicher 	}
1804e3c97c2cSBryan Venteicher 
1805e3c97c2cSBryan Venteicher 	VMXNET3_CORE_UNLOCK(sc);
1806e3c97c2cSBryan Venteicher }
1807e3c97c2cSBryan Venteicher 
1808e3c97c2cSBryan Venteicher static void
1809e3c97c2cSBryan Venteicher vmxnet3_txq_eof(struct vmxnet3_txqueue *txq)
1810e3c97c2cSBryan Venteicher {
1811e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
1812e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
1813e3c97c2cSBryan Venteicher 	struct vmxnet3_txring *txr;
1814e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *txc;
1815e3c97c2cSBryan Venteicher 	struct vmxnet3_txcompdesc *txcd;
1816e3c97c2cSBryan Venteicher 	struct vmxnet3_txbuf *txb;
1817*e557c1ddSBryan Venteicher 	struct mbuf *m;
1818e3c97c2cSBryan Venteicher 	u_int sop;
1819e3c97c2cSBryan Venteicher 
1820e3c97c2cSBryan Venteicher 	sc = txq->vxtxq_sc;
1821e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
1822e3c97c2cSBryan Venteicher 	txr = &txq->vxtxq_cmd_ring;
1823e3c97c2cSBryan Venteicher 	txc = &txq->vxtxq_comp_ring;
1824e3c97c2cSBryan Venteicher 
1825e3c97c2cSBryan Venteicher 	VMXNET3_TXQ_LOCK_ASSERT(txq);
1826e3c97c2cSBryan Venteicher 
1827e3c97c2cSBryan Venteicher 	for (;;) {
1828e3c97c2cSBryan Venteicher 		txcd = &txc->vxcr_u.txcd[txc->vxcr_next];
1829e3c97c2cSBryan Venteicher 		if (txcd->gen != txc->vxcr_gen)
1830e3c97c2cSBryan Venteicher 			break;
18313c965775SBryan Venteicher 		vmxnet3_barrier(sc, VMXNET3_BARRIER_RD);
1832e3c97c2cSBryan Venteicher 
1833e3c97c2cSBryan Venteicher 		if (++txc->vxcr_next == txc->vxcr_ndesc) {
1834e3c97c2cSBryan Venteicher 			txc->vxcr_next = 0;
1835e3c97c2cSBryan Venteicher 			txc->vxcr_gen ^= 1;
1836e3c97c2cSBryan Venteicher 		}
1837e3c97c2cSBryan Venteicher 
1838e3c97c2cSBryan Venteicher 		sop = txr->vxtxr_next;
1839e3c97c2cSBryan Venteicher 		txb = &txr->vxtxr_txbuf[sop];
1840e3c97c2cSBryan Venteicher 
1841*e557c1ddSBryan Venteicher 		if ((m = txb->vtxb_m) != NULL) {
1842e3c97c2cSBryan Venteicher 			bus_dmamap_sync(txr->vxtxr_txtag, txb->vtxb_dmamap,
1843e3c97c2cSBryan Venteicher 			    BUS_DMASYNC_POSTWRITE);
1844e3c97c2cSBryan Venteicher 			bus_dmamap_unload(txr->vxtxr_txtag, txb->vtxb_dmamap);
1845e3c97c2cSBryan Venteicher 
1846*e557c1ddSBryan Venteicher 			txq->vxtxq_stats.vmtxs_opackets++;
1847*e557c1ddSBryan Venteicher 			txq->vxtxq_stats.vmtxs_obytes += m->m_pkthdr.len;
1848*e557c1ddSBryan Venteicher 			if (m->m_flags & M_MCAST)
1849*e557c1ddSBryan Venteicher 				txq->vxtxq_stats.vmtxs_omcasts++;
1850e3c97c2cSBryan Venteicher 
1851*e557c1ddSBryan Venteicher 			m_freem(m);
1852*e557c1ddSBryan Venteicher 			txb->vtxb_m = NULL;
1853e3c97c2cSBryan Venteicher 		}
1854e3c97c2cSBryan Venteicher 
1855e3c97c2cSBryan Venteicher 		txr->vxtxr_next = (txcd->eop_idx + 1) % txr->vxtxr_ndesc;
1856e3c97c2cSBryan Venteicher 	}
1857e3c97c2cSBryan Venteicher 
1858e3c97c2cSBryan Venteicher 	if (txr->vxtxr_head == txr->vxtxr_next)
1859e3c97c2cSBryan Venteicher 		txq->vxtxq_watchdog = 0;
1860e3c97c2cSBryan Venteicher }
1861e3c97c2cSBryan Venteicher 
1862e3c97c2cSBryan Venteicher static int
1863e3c97c2cSBryan Venteicher vmxnet3_newbuf(struct vmxnet3_softc *sc, struct vmxnet3_rxring *rxr)
1864e3c97c2cSBryan Venteicher {
1865e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
1866e3c97c2cSBryan Venteicher 	struct mbuf *m;
1867e3c97c2cSBryan Venteicher 	struct vmxnet3_rxdesc *rxd;
1868e3c97c2cSBryan Venteicher 	struct vmxnet3_rxbuf *rxb;
1869e3c97c2cSBryan Venteicher 	bus_dma_tag_t tag;
1870e3c97c2cSBryan Venteicher 	bus_dmamap_t dmap;
1871e3c97c2cSBryan Venteicher 	bus_dma_segment_t segs[1];
1872e3c97c2cSBryan Venteicher 	int idx, clsize, btype, flags, nsegs, error;
1873e3c97c2cSBryan Venteicher 
1874e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
1875e3c97c2cSBryan Venteicher 	tag = rxr->vxrxr_rxtag;
1876e3c97c2cSBryan Venteicher 	dmap = rxr->vxrxr_spare_dmap;
1877e3c97c2cSBryan Venteicher 	idx = rxr->vxrxr_fill;
1878e3c97c2cSBryan Venteicher 	rxd = &rxr->vxrxr_rxd[idx];
1879e3c97c2cSBryan Venteicher 	rxb = &rxr->vxrxr_rxbuf[idx];
1880e3c97c2cSBryan Venteicher 
1881e3c97c2cSBryan Venteicher #ifdef VMXNET3_FAILPOINTS
1882e3c97c2cSBryan Venteicher 	KFAIL_POINT_CODE(VMXNET3_FP, newbuf, return ENOBUFS);
1883e3c97c2cSBryan Venteicher 	if (rxr->vxrxr_rid != 0)
1884e3c97c2cSBryan Venteicher 		KFAIL_POINT_CODE(VMXNET3_FP, newbuf_body_only, return ENOBUFS);
1885e3c97c2cSBryan Venteicher #endif
1886e3c97c2cSBryan Venteicher 
1887e3c97c2cSBryan Venteicher 	if (rxr->vxrxr_rid == 0 && (idx % sc->vmx_rx_max_chain) == 0) {
1888e3c97c2cSBryan Venteicher 		flags = M_PKTHDR;
1889e3c97c2cSBryan Venteicher 		clsize = MCLBYTES;
1890e3c97c2cSBryan Venteicher 		btype = VMXNET3_BTYPE_HEAD;
1891e3c97c2cSBryan Venteicher 	} else {
1892e3c97c2cSBryan Venteicher #if __FreeBSD_version < 902001
1893e3c97c2cSBryan Venteicher 		/*
1894e3c97c2cSBryan Venteicher 		 * These mbufs will never be used for the start of a frame.
1895e3c97c2cSBryan Venteicher 		 * Roughly prior to branching releng/9.2, the load_mbuf_sg()
1896e3c97c2cSBryan Venteicher 		 * required the mbuf to always be a packet header. Avoid
1897e3c97c2cSBryan Venteicher 		 * unnecessary mbuf initialization in newer versions where
1898e3c97c2cSBryan Venteicher 		 * that is not the case.
1899e3c97c2cSBryan Venteicher 		 */
1900e3c97c2cSBryan Venteicher 		flags = M_PKTHDR;
1901e3c97c2cSBryan Venteicher #else
1902e3c97c2cSBryan Venteicher 		flags = 0;
1903e3c97c2cSBryan Venteicher #endif
1904e3c97c2cSBryan Venteicher 		clsize = MJUMPAGESIZE;
1905e3c97c2cSBryan Venteicher 		btype = VMXNET3_BTYPE_BODY;
1906e3c97c2cSBryan Venteicher 	}
1907e3c97c2cSBryan Venteicher 
1908e3c97c2cSBryan Venteicher 	m = m_getjcl(M_NOWAIT, MT_DATA, flags, clsize);
1909e3c97c2cSBryan Venteicher 	if (m == NULL) {
1910e3c97c2cSBryan Venteicher 		sc->vmx_stats.vmst_mgetcl_failed++;
1911e3c97c2cSBryan Venteicher 		return (ENOBUFS);
1912e3c97c2cSBryan Venteicher 	}
1913e3c97c2cSBryan Venteicher 
1914e3c97c2cSBryan Venteicher 	if (btype == VMXNET3_BTYPE_HEAD) {
1915e3c97c2cSBryan Venteicher 		m->m_len = m->m_pkthdr.len = clsize;
1916e3c97c2cSBryan Venteicher 		m_adj(m, ETHER_ALIGN);
1917e3c97c2cSBryan Venteicher 	} else
1918e3c97c2cSBryan Venteicher 		m->m_len = clsize;
1919e3c97c2cSBryan Venteicher 
1920e3c97c2cSBryan Venteicher 	error = bus_dmamap_load_mbuf_sg(tag, dmap, m, &segs[0], &nsegs,
1921e3c97c2cSBryan Venteicher 	    BUS_DMA_NOWAIT);
1922e3c97c2cSBryan Venteicher 	if (error) {
1923e3c97c2cSBryan Venteicher 		m_freem(m);
19243c965775SBryan Venteicher 		sc->vmx_stats.vmst_mbuf_load_failed++;
1925e3c97c2cSBryan Venteicher 		return (error);
1926e3c97c2cSBryan Venteicher 	}
1927e3c97c2cSBryan Venteicher 	KASSERT(nsegs == 1,
1928e3c97c2cSBryan Venteicher 	    ("%s: mbuf %p with too many segments %d", __func__, m, nsegs));
1929e3c97c2cSBryan Venteicher #if __FreeBSD_version < 902001
1930e3c97c2cSBryan Venteicher 	if (btype == VMXNET3_BTYPE_BODY)
1931e3c97c2cSBryan Venteicher 		m->m_flags &= ~M_PKTHDR;
1932e3c97c2cSBryan Venteicher #endif
1933e3c97c2cSBryan Venteicher 
1934e3c97c2cSBryan Venteicher 	if (rxb->vrxb_m != NULL) {
1935e3c97c2cSBryan Venteicher 		bus_dmamap_sync(tag, rxb->vrxb_dmamap, BUS_DMASYNC_POSTREAD);
1936e3c97c2cSBryan Venteicher 		bus_dmamap_unload(tag, rxb->vrxb_dmamap);
1937e3c97c2cSBryan Venteicher 	}
1938e3c97c2cSBryan Venteicher 
1939e3c97c2cSBryan Venteicher 	rxr->vxrxr_spare_dmap = rxb->vrxb_dmamap;
1940e3c97c2cSBryan Venteicher 	rxb->vrxb_dmamap = dmap;
1941e3c97c2cSBryan Venteicher 	rxb->vrxb_m = m;
1942e3c97c2cSBryan Venteicher 
1943e3c97c2cSBryan Venteicher 	rxd->addr = segs[0].ds_addr;
1944e3c97c2cSBryan Venteicher 	rxd->len = segs[0].ds_len;
1945e3c97c2cSBryan Venteicher 	rxd->btype = btype;
1946e3c97c2cSBryan Venteicher 	rxd->gen = rxr->vxrxr_gen;
1947e3c97c2cSBryan Venteicher 
1948e3c97c2cSBryan Venteicher 	vmxnet3_rxr_increment_fill(rxr);
1949e3c97c2cSBryan Venteicher 	return (0);
1950e3c97c2cSBryan Venteicher }
1951e3c97c2cSBryan Venteicher 
1952e3c97c2cSBryan Venteicher static void
1953e3c97c2cSBryan Venteicher vmxnet3_rxq_eof_discard(struct vmxnet3_rxqueue *rxq,
1954e3c97c2cSBryan Venteicher     struct vmxnet3_rxring *rxr, int idx)
1955e3c97c2cSBryan Venteicher {
1956e3c97c2cSBryan Venteicher 	struct vmxnet3_rxdesc *rxd;
1957e3c97c2cSBryan Venteicher 
1958e3c97c2cSBryan Venteicher 	rxd = &rxr->vxrxr_rxd[idx];
1959e3c97c2cSBryan Venteicher 	rxd->gen = rxr->vxrxr_gen;
1960e3c97c2cSBryan Venteicher 	vmxnet3_rxr_increment_fill(rxr);
1961e3c97c2cSBryan Venteicher }
1962e3c97c2cSBryan Venteicher 
1963e3c97c2cSBryan Venteicher static void
1964e3c97c2cSBryan Venteicher vmxnet3_rxq_discard_chain(struct vmxnet3_rxqueue *rxq)
1965e3c97c2cSBryan Venteicher {
1966e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
1967e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
1968e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *rxc;
1969e3c97c2cSBryan Venteicher 	struct vmxnet3_rxcompdesc *rxcd;
1970e3c97c2cSBryan Venteicher 	int idx, eof;
1971e3c97c2cSBryan Venteicher 
1972e3c97c2cSBryan Venteicher 	sc = rxq->vxrxq_sc;
1973e3c97c2cSBryan Venteicher 	rxc = &rxq->vxrxq_comp_ring;
1974e3c97c2cSBryan Venteicher 
1975e3c97c2cSBryan Venteicher 	do {
1976e3c97c2cSBryan Venteicher 		rxcd = &rxc->vxcr_u.rxcd[rxc->vxcr_next];
1977e3c97c2cSBryan Venteicher 		if (rxcd->gen != rxc->vxcr_gen)
1978e3c97c2cSBryan Venteicher 			break;		/* Not expected. */
1979e3c97c2cSBryan Venteicher 		vmxnet3_barrier(sc, VMXNET3_BARRIER_RD);
1980e3c97c2cSBryan Venteicher 
1981e3c97c2cSBryan Venteicher 		if (++rxc->vxcr_next == rxc->vxcr_ndesc) {
1982e3c97c2cSBryan Venteicher 			rxc->vxcr_next = 0;
1983e3c97c2cSBryan Venteicher 			rxc->vxcr_gen ^= 1;
1984e3c97c2cSBryan Venteicher 		}
1985e3c97c2cSBryan Venteicher 
1986e3c97c2cSBryan Venteicher 		idx = rxcd->rxd_idx;
1987e3c97c2cSBryan Venteicher 		eof = rxcd->eop;
1988e3c97c2cSBryan Venteicher 		if (rxcd->qid < sc->vmx_nrxqueues)
1989e3c97c2cSBryan Venteicher 			rxr = &rxq->vxrxq_cmd_ring[0];
1990e3c97c2cSBryan Venteicher 		else
1991e3c97c2cSBryan Venteicher 			rxr = &rxq->vxrxq_cmd_ring[1];
1992e3c97c2cSBryan Venteicher 		vmxnet3_rxq_eof_discard(rxq, rxr, idx);
1993e3c97c2cSBryan Venteicher 	} while (!eof);
1994e3c97c2cSBryan Venteicher }
1995e3c97c2cSBryan Venteicher 
1996e3c97c2cSBryan Venteicher static void
1997e3c97c2cSBryan Venteicher vmxnet3_rx_csum(struct vmxnet3_rxcompdesc *rxcd, struct mbuf *m)
1998e3c97c2cSBryan Venteicher {
1999e3c97c2cSBryan Venteicher 
2000e3c97c2cSBryan Venteicher 	if (rxcd->ipv4) {
2001e3c97c2cSBryan Venteicher 		m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
2002e3c97c2cSBryan Venteicher 		if (rxcd->ipcsum_ok)
2003e3c97c2cSBryan Venteicher 			m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
2004e3c97c2cSBryan Venteicher 	}
2005e3c97c2cSBryan Venteicher 
2006e3c97c2cSBryan Venteicher 	if (!rxcd->fragment) {
2007e3c97c2cSBryan Venteicher 		if (rxcd->csum_ok && (rxcd->tcp || rxcd->udp)) {
2008e3c97c2cSBryan Venteicher 			m->m_pkthdr.csum_flags |= CSUM_DATA_VALID |
2009e3c97c2cSBryan Venteicher 			    CSUM_PSEUDO_HDR;
2010e3c97c2cSBryan Venteicher 			m->m_pkthdr.csum_data = 0xFFFF;
2011e3c97c2cSBryan Venteicher 		}
2012e3c97c2cSBryan Venteicher 	}
2013e3c97c2cSBryan Venteicher }
2014e3c97c2cSBryan Venteicher 
2015e3c97c2cSBryan Venteicher static void
2016e3c97c2cSBryan Venteicher vmxnet3_rxq_input(struct vmxnet3_rxqueue *rxq,
2017e3c97c2cSBryan Venteicher     struct vmxnet3_rxcompdesc *rxcd, struct mbuf *m)
2018e3c97c2cSBryan Venteicher {
2019e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
2020e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
2021e3c97c2cSBryan Venteicher 
2022e3c97c2cSBryan Venteicher 	sc = rxq->vxrxq_sc;
2023e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
2024e3c97c2cSBryan Venteicher 
2025e3c97c2cSBryan Venteicher 	if (rxcd->error) {
2026*e557c1ddSBryan Venteicher 		rxq->vxrxq_stats.vmrxs_ierrors++;
2027e3c97c2cSBryan Venteicher 		m_freem(m);
2028e3c97c2cSBryan Venteicher 		return;
2029e3c97c2cSBryan Venteicher 	}
2030e3c97c2cSBryan Venteicher 
2031*e557c1ddSBryan Venteicher #ifdef notyet
2032*e557c1ddSBryan Venteicher 	switch (rxcd->rss_type) {
2033*e557c1ddSBryan Venteicher 	case VMXNET3_RCD_RSS_TYPE_IPV4:
2034*e557c1ddSBryan Venteicher 		m->m_pkthdr.flowid = rxcd->rss_hash;
2035*e557c1ddSBryan Venteicher 		M_HASHTYPE_SET(m, M_HASHTYPE_RSS_IPV4);
2036*e557c1ddSBryan Venteicher 		break;
2037*e557c1ddSBryan Venteicher 	case VMXNET3_RCD_RSS_TYPE_TCPIPV4:
2038*e557c1ddSBryan Venteicher 		m->m_pkthdr.flowid = rxcd->rss_hash;
2039*e557c1ddSBryan Venteicher 		M_HASHTYPE_SET(m, M_HASHTYPE_RSS_TCP_IPV4);
2040*e557c1ddSBryan Venteicher 		break;
2041*e557c1ddSBryan Venteicher 	case VMXNET3_RCD_RSS_TYPE_IPV6:
2042*e557c1ddSBryan Venteicher 		m->m_pkthdr.flowid = rxcd->rss_hash;
2043*e557c1ddSBryan Venteicher 		M_HASHTYPE_SET(m, M_HASHTYPE_RSS_IPV6);
2044*e557c1ddSBryan Venteicher 		break;
2045*e557c1ddSBryan Venteicher 	case VMXNET3_RCD_RSS_TYPE_TCPIPV6:
2046*e557c1ddSBryan Venteicher 		m->m_pkthdr.flowid = rxcd->rss_hash;
2047*e557c1ddSBryan Venteicher 		M_HASHTYPE_SET(m, M_HASHTYPE_RSS_TCP_IPV6);
2048*e557c1ddSBryan Venteicher 		break;
2049*e557c1ddSBryan Venteicher 	default: /* VMXNET3_RCD_RSS_TYPE_NONE */
2050*e557c1ddSBryan Venteicher 		m->m_pkthdr.flowid = rxq->vxrxq_id;
2051*e557c1ddSBryan Venteicher 		M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
2052*e557c1ddSBryan Venteicher 		break;
2053*e557c1ddSBryan Venteicher 	}
2054*e557c1ddSBryan Venteicher #else
2055*e557c1ddSBryan Venteicher 	m->m_pkthdr.flowid = rxq->vxrxq_id;
2056*e557c1ddSBryan Venteicher 	m->m_flags |= M_FLOWID;
2057*e557c1ddSBryan Venteicher #endif
2058*e557c1ddSBryan Venteicher 
2059e3c97c2cSBryan Venteicher 	if (!rxcd->no_csum)
2060e3c97c2cSBryan Venteicher 		vmxnet3_rx_csum(rxcd, m);
2061e3c97c2cSBryan Venteicher 	if (rxcd->vlan) {
2062e3c97c2cSBryan Venteicher 		m->m_flags |= M_VLANTAG;
2063e3c97c2cSBryan Venteicher 		m->m_pkthdr.ether_vtag = rxcd->vtag;
2064e3c97c2cSBryan Venteicher 	}
2065e3c97c2cSBryan Venteicher 
2066*e557c1ddSBryan Venteicher 	rxq->vxrxq_stats.vmrxs_ipackets++;
2067*e557c1ddSBryan Venteicher 	rxq->vxrxq_stats.vmrxs_ibytes += m->m_pkthdr.len;
2068*e557c1ddSBryan Venteicher 
2069e3c97c2cSBryan Venteicher 	VMXNET3_RXQ_UNLOCK(rxq);
2070e3c97c2cSBryan Venteicher 	(*ifp->if_input)(ifp, m);
2071e3c97c2cSBryan Venteicher 	VMXNET3_RXQ_LOCK(rxq);
2072e3c97c2cSBryan Venteicher }
2073e3c97c2cSBryan Venteicher 
2074e3c97c2cSBryan Venteicher static void
2075e3c97c2cSBryan Venteicher vmxnet3_rxq_eof(struct vmxnet3_rxqueue *rxq)
2076e3c97c2cSBryan Venteicher {
2077e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
2078e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
2079e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
2080e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *rxc;
2081e3c97c2cSBryan Venteicher 	struct vmxnet3_rxdesc *rxd;
2082e3c97c2cSBryan Venteicher 	struct vmxnet3_rxcompdesc *rxcd;
2083e3c97c2cSBryan Venteicher 	struct mbuf *m, *m_head, *m_tail;
2084e3c97c2cSBryan Venteicher 	int idx, length;
2085e3c97c2cSBryan Venteicher 
2086e3c97c2cSBryan Venteicher 	sc = rxq->vxrxq_sc;
2087e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
2088e3c97c2cSBryan Venteicher 	rxc = &rxq->vxrxq_comp_ring;
2089e3c97c2cSBryan Venteicher 	m_head = m_tail = NULL;
2090e3c97c2cSBryan Venteicher 
2091e3c97c2cSBryan Venteicher 	VMXNET3_RXQ_LOCK_ASSERT(rxq);
2092e3c97c2cSBryan Venteicher 
2093e3c97c2cSBryan Venteicher 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
2094e3c97c2cSBryan Venteicher 		return;
2095e3c97c2cSBryan Venteicher 
2096e3c97c2cSBryan Venteicher 	for (;;) {
2097e3c97c2cSBryan Venteicher 		rxcd = &rxc->vxcr_u.rxcd[rxc->vxcr_next];
2098e3c97c2cSBryan Venteicher 		if (rxcd->gen != rxc->vxcr_gen)
2099e3c97c2cSBryan Venteicher 			break;
2100e3c97c2cSBryan Venteicher 		vmxnet3_barrier(sc, VMXNET3_BARRIER_RD);
2101e3c97c2cSBryan Venteicher 
2102e3c97c2cSBryan Venteicher 		if (++rxc->vxcr_next == rxc->vxcr_ndesc) {
2103e3c97c2cSBryan Venteicher 			rxc->vxcr_next = 0;
2104e3c97c2cSBryan Venteicher 			rxc->vxcr_gen ^= 1;
2105e3c97c2cSBryan Venteicher 		}
2106e3c97c2cSBryan Venteicher 
2107e3c97c2cSBryan Venteicher 		idx = rxcd->rxd_idx;
2108e3c97c2cSBryan Venteicher 		length = rxcd->len;
2109e3c97c2cSBryan Venteicher 		if (rxcd->qid < sc->vmx_nrxqueues)
2110e3c97c2cSBryan Venteicher 			rxr = &rxq->vxrxq_cmd_ring[0];
2111e3c97c2cSBryan Venteicher 		else
2112e3c97c2cSBryan Venteicher 			rxr = &rxq->vxrxq_cmd_ring[1];
2113e3c97c2cSBryan Venteicher 		rxd = &rxr->vxrxr_rxd[idx];
2114e3c97c2cSBryan Venteicher 
2115e3c97c2cSBryan Venteicher 		m = rxr->vxrxr_rxbuf[idx].vrxb_m;
2116e3c97c2cSBryan Venteicher 		KASSERT(m != NULL, ("%s: queue %d idx %d without mbuf",
2117e3c97c2cSBryan Venteicher 		    __func__, rxcd->qid, idx));
2118e3c97c2cSBryan Venteicher 
2119e3c97c2cSBryan Venteicher 		/*
2120e3c97c2cSBryan Venteicher 		 * The host may skip descriptors. We detect this when this
2121e3c97c2cSBryan Venteicher 		 * descriptor does not match the previous fill index. Catch
2122e3c97c2cSBryan Venteicher 		 * up with the host now.
2123e3c97c2cSBryan Venteicher 		 */
2124e3c97c2cSBryan Venteicher 		if (__predict_false(rxr->vxrxr_fill != idx)) {
2125e3c97c2cSBryan Venteicher 			while (rxr->vxrxr_fill != idx) {
2126e3c97c2cSBryan Venteicher 				rxr->vxrxr_rxd[rxr->vxrxr_fill].gen =
2127e3c97c2cSBryan Venteicher 				    rxr->vxrxr_gen;
2128e3c97c2cSBryan Venteicher 				vmxnet3_rxr_increment_fill(rxr);
2129e3c97c2cSBryan Venteicher 			}
2130e3c97c2cSBryan Venteicher 		}
2131e3c97c2cSBryan Venteicher 
2132e3c97c2cSBryan Venteicher 		if (rxcd->sop) {
2133e3c97c2cSBryan Venteicher 			KASSERT(rxd->btype == VMXNET3_BTYPE_HEAD,
2134e3c97c2cSBryan Venteicher 			    ("%s: start of frame w/o head buffer", __func__));
2135e3c97c2cSBryan Venteicher 			KASSERT(rxr == &rxq->vxrxq_cmd_ring[0],
2136e3c97c2cSBryan Venteicher 			    ("%s: start of frame not in ring 0", __func__));
2137e3c97c2cSBryan Venteicher 			KASSERT((idx % sc->vmx_rx_max_chain) == 0,
2138e3c97c2cSBryan Venteicher 			    ("%s: start of frame at unexcepted index %d (%d)",
2139e3c97c2cSBryan Venteicher 			     __func__, idx, sc->vmx_rx_max_chain));
2140e3c97c2cSBryan Venteicher 			KASSERT(m_head == NULL,
2141e3c97c2cSBryan Venteicher 			    ("%s: duplicate start of frame?", __func__));
2142e3c97c2cSBryan Venteicher 
2143e3c97c2cSBryan Venteicher 			if (length == 0) {
2144e3c97c2cSBryan Venteicher 				/* Just ignore this descriptor. */
2145e3c97c2cSBryan Venteicher 				vmxnet3_rxq_eof_discard(rxq, rxr, idx);
2146e3c97c2cSBryan Venteicher 				goto nextp;
2147e3c97c2cSBryan Venteicher 			}
2148e3c97c2cSBryan Venteicher 
2149e3c97c2cSBryan Venteicher 			if (vmxnet3_newbuf(sc, rxr) != 0) {
2150*e557c1ddSBryan Venteicher 				rxq->vxrxq_stats.vmrxs_iqdrops++;
2151e3c97c2cSBryan Venteicher 				vmxnet3_rxq_eof_discard(rxq, rxr, idx);
2152e3c97c2cSBryan Venteicher 				if (!rxcd->eop)
2153e3c97c2cSBryan Venteicher 					vmxnet3_rxq_discard_chain(rxq);
2154e3c97c2cSBryan Venteicher 				goto nextp;
2155e3c97c2cSBryan Venteicher 			}
2156e3c97c2cSBryan Venteicher 
2157e3c97c2cSBryan Venteicher 			m->m_pkthdr.rcvif = ifp;
2158e3c97c2cSBryan Venteicher 			m->m_pkthdr.len = m->m_len = length;
2159e3c97c2cSBryan Venteicher 			m->m_pkthdr.csum_flags = 0;
2160e3c97c2cSBryan Venteicher 			m_head = m_tail = m;
2161e3c97c2cSBryan Venteicher 
2162e3c97c2cSBryan Venteicher 		} else {
2163e3c97c2cSBryan Venteicher 			KASSERT(rxd->btype == VMXNET3_BTYPE_BODY,
2164e3c97c2cSBryan Venteicher 			    ("%s: non start of frame w/o body buffer", __func__));
2165e3c97c2cSBryan Venteicher 			KASSERT(m_head != NULL,
2166e3c97c2cSBryan Venteicher 			    ("%s: frame not started?", __func__));
2167e3c97c2cSBryan Venteicher 
2168e3c97c2cSBryan Venteicher 			if (vmxnet3_newbuf(sc, rxr) != 0) {
2169*e557c1ddSBryan Venteicher 				rxq->vxrxq_stats.vmrxs_iqdrops++;
2170e3c97c2cSBryan Venteicher 				vmxnet3_rxq_eof_discard(rxq, rxr, idx);
2171e3c97c2cSBryan Venteicher 				if (!rxcd->eop)
2172e3c97c2cSBryan Venteicher 					vmxnet3_rxq_discard_chain(rxq);
2173e3c97c2cSBryan Venteicher 				m_freem(m_head);
2174e3c97c2cSBryan Venteicher 				m_head = m_tail = NULL;
2175e3c97c2cSBryan Venteicher 				goto nextp;
2176e3c97c2cSBryan Venteicher 			}
2177e3c97c2cSBryan Venteicher 
2178e3c97c2cSBryan Venteicher 			m->m_len = length;
2179e3c97c2cSBryan Venteicher 			m_head->m_pkthdr.len += length;
2180e3c97c2cSBryan Venteicher 			m_tail->m_next = m;
2181e3c97c2cSBryan Venteicher 			m_tail = m;
2182e3c97c2cSBryan Venteicher 		}
2183e3c97c2cSBryan Venteicher 
2184e3c97c2cSBryan Venteicher 		if (rxcd->eop) {
2185e3c97c2cSBryan Venteicher 			vmxnet3_rxq_input(rxq, rxcd, m_head);
2186e3c97c2cSBryan Venteicher 			m_head = m_tail = NULL;
2187e3c97c2cSBryan Venteicher 
2188e3c97c2cSBryan Venteicher 			/* Must recheck after dropping the Rx lock. */
2189e3c97c2cSBryan Venteicher 			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
2190e3c97c2cSBryan Venteicher 				break;
2191e3c97c2cSBryan Venteicher 		}
2192e3c97c2cSBryan Venteicher 
2193e3c97c2cSBryan Venteicher nextp:
2194e3c97c2cSBryan Venteicher 		if (__predict_false(rxq->vxrxq_rs->update_rxhead)) {
2195e3c97c2cSBryan Venteicher 			int qid = rxcd->qid;
2196e3c97c2cSBryan Venteicher 			bus_size_t r;
2197e3c97c2cSBryan Venteicher 
2198e3c97c2cSBryan Venteicher 			idx = (idx + 1) % rxr->vxrxr_ndesc;
2199e3c97c2cSBryan Venteicher 			if (qid >= sc->vmx_nrxqueues) {
2200e3c97c2cSBryan Venteicher 				qid -= sc->vmx_nrxqueues;
2201e3c97c2cSBryan Venteicher 				r = VMXNET3_BAR0_RXH2(qid);
2202e3c97c2cSBryan Venteicher 			} else
2203e3c97c2cSBryan Venteicher 				r = VMXNET3_BAR0_RXH1(qid);
2204e3c97c2cSBryan Venteicher 			vmxnet3_write_bar0(sc, r, idx);
2205e3c97c2cSBryan Venteicher 		}
2206e3c97c2cSBryan Venteicher 	}
2207e3c97c2cSBryan Venteicher }
2208e3c97c2cSBryan Venteicher 
2209e3c97c2cSBryan Venteicher static void
2210e3c97c2cSBryan Venteicher vmxnet3_legacy_intr(void *xsc)
2211e3c97c2cSBryan Venteicher {
2212e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
2213e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
2214e3c97c2cSBryan Venteicher 	struct vmxnet3_txqueue *txq;
2215e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
2216e3c97c2cSBryan Venteicher 
2217e3c97c2cSBryan Venteicher 	sc = xsc;
2218e3c97c2cSBryan Venteicher 	rxq = &sc->vmx_rxq[0];
2219e3c97c2cSBryan Venteicher 	txq = &sc->vmx_txq[0];
2220e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
2221e3c97c2cSBryan Venteicher 
2222e3c97c2cSBryan Venteicher 	if (sc->vmx_intr_type == VMXNET3_IT_LEGACY) {
2223e3c97c2cSBryan Venteicher 		if (vmxnet3_read_bar1(sc, VMXNET3_BAR1_INTR) == 0)
2224e3c97c2cSBryan Venteicher 			return;
2225e3c97c2cSBryan Venteicher 	}
2226e3c97c2cSBryan Venteicher 	if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE)
2227e3c97c2cSBryan Venteicher 		vmxnet3_disable_all_intrs(sc);
2228e3c97c2cSBryan Venteicher 
2229e3c97c2cSBryan Venteicher 	if (sc->vmx_ds->event != 0)
2230e3c97c2cSBryan Venteicher 		vmxnet3_evintr(sc);
2231e3c97c2cSBryan Venteicher 
2232e3c97c2cSBryan Venteicher 	VMXNET3_RXQ_LOCK(rxq);
2233e3c97c2cSBryan Venteicher 	vmxnet3_rxq_eof(rxq);
2234e3c97c2cSBryan Venteicher 	VMXNET3_RXQ_UNLOCK(rxq);
2235e3c97c2cSBryan Venteicher 
2236e3c97c2cSBryan Venteicher 	VMXNET3_TXQ_LOCK(txq);
2237e3c97c2cSBryan Venteicher 	vmxnet3_txq_eof(txq);
2238*e557c1ddSBryan Venteicher 	vmxnet3_txq_start(txq);
2239e3c97c2cSBryan Venteicher 	VMXNET3_TXQ_UNLOCK(txq);
2240e3c97c2cSBryan Venteicher 
2241e3c97c2cSBryan Venteicher 	vmxnet3_enable_all_intrs(sc);
2242e3c97c2cSBryan Venteicher }
2243e3c97c2cSBryan Venteicher 
2244e3c97c2cSBryan Venteicher static void
2245e3c97c2cSBryan Venteicher vmxnet3_txq_intr(void *xtxq)
2246e3c97c2cSBryan Venteicher {
2247e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
2248e3c97c2cSBryan Venteicher 	struct vmxnet3_txqueue *txq;
2249e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
2250e3c97c2cSBryan Venteicher 
2251e3c97c2cSBryan Venteicher 	txq = xtxq;
2252e3c97c2cSBryan Venteicher 	sc = txq->vxtxq_sc;
2253e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
2254e3c97c2cSBryan Venteicher 
2255e3c97c2cSBryan Venteicher 	if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE)
2256e3c97c2cSBryan Venteicher 		vmxnet3_disable_intr(sc, txq->vxtxq_intr_idx);
2257e3c97c2cSBryan Venteicher 
2258e3c97c2cSBryan Venteicher 	VMXNET3_TXQ_LOCK(txq);
2259e3c97c2cSBryan Venteicher 	vmxnet3_txq_eof(txq);
2260*e557c1ddSBryan Venteicher 	vmxnet3_txq_start(txq);
2261e3c97c2cSBryan Venteicher 	VMXNET3_TXQ_UNLOCK(txq);
2262e3c97c2cSBryan Venteicher 
2263e3c97c2cSBryan Venteicher 	vmxnet3_enable_intr(sc, txq->vxtxq_intr_idx);
2264e3c97c2cSBryan Venteicher }
2265e3c97c2cSBryan Venteicher 
2266e3c97c2cSBryan Venteicher static void
2267e3c97c2cSBryan Venteicher vmxnet3_rxq_intr(void *xrxq)
2268e3c97c2cSBryan Venteicher {
2269e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
2270e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
2271e3c97c2cSBryan Venteicher 
2272e3c97c2cSBryan Venteicher 	rxq = xrxq;
2273e3c97c2cSBryan Venteicher 	sc = rxq->vxrxq_sc;
2274e3c97c2cSBryan Venteicher 
2275e3c97c2cSBryan Venteicher 	if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE)
2276e3c97c2cSBryan Venteicher 		vmxnet3_disable_intr(sc, rxq->vxrxq_intr_idx);
2277e3c97c2cSBryan Venteicher 
2278e3c97c2cSBryan Venteicher 	VMXNET3_RXQ_LOCK(rxq);
2279e3c97c2cSBryan Venteicher 	vmxnet3_rxq_eof(rxq);
2280e3c97c2cSBryan Venteicher 	VMXNET3_RXQ_UNLOCK(rxq);
2281e3c97c2cSBryan Venteicher 
2282e3c97c2cSBryan Venteicher 	vmxnet3_enable_intr(sc, rxq->vxrxq_intr_idx);
2283e3c97c2cSBryan Venteicher }
2284e3c97c2cSBryan Venteicher 
2285e3c97c2cSBryan Venteicher static void
2286e3c97c2cSBryan Venteicher vmxnet3_event_intr(void *xsc)
2287e3c97c2cSBryan Venteicher {
2288e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
2289e3c97c2cSBryan Venteicher 
2290e3c97c2cSBryan Venteicher 	sc = xsc;
2291e3c97c2cSBryan Venteicher 
2292e3c97c2cSBryan Venteicher 	if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE)
2293e3c97c2cSBryan Venteicher 		vmxnet3_disable_intr(sc, sc->vmx_event_intr_idx);
2294e3c97c2cSBryan Venteicher 
2295e3c97c2cSBryan Venteicher 	if (sc->vmx_ds->event != 0)
2296e3c97c2cSBryan Venteicher 		vmxnet3_evintr(sc);
2297e3c97c2cSBryan Venteicher 
2298e3c97c2cSBryan Venteicher 	vmxnet3_enable_intr(sc, sc->vmx_event_intr_idx);
2299e3c97c2cSBryan Venteicher }
2300e3c97c2cSBryan Venteicher 
2301e3c97c2cSBryan Venteicher static void
2302e3c97c2cSBryan Venteicher vmxnet3_txstop(struct vmxnet3_softc *sc, struct vmxnet3_txqueue *txq)
2303e3c97c2cSBryan Venteicher {
2304e3c97c2cSBryan Venteicher 	struct vmxnet3_txring *txr;
2305e3c97c2cSBryan Venteicher 	struct vmxnet3_txbuf *txb;
2306e3c97c2cSBryan Venteicher 	int i;
2307e3c97c2cSBryan Venteicher 
2308e3c97c2cSBryan Venteicher 	txr = &txq->vxtxq_cmd_ring;
2309e3c97c2cSBryan Venteicher 
2310e3c97c2cSBryan Venteicher 	for (i = 0; i < txr->vxtxr_ndesc; i++) {
2311e3c97c2cSBryan Venteicher 		txb = &txr->vxtxr_txbuf[i];
2312e3c97c2cSBryan Venteicher 
2313e3c97c2cSBryan Venteicher 		if (txb->vtxb_m == NULL)
2314e3c97c2cSBryan Venteicher 			continue;
2315e3c97c2cSBryan Venteicher 
2316e3c97c2cSBryan Venteicher 		bus_dmamap_sync(txr->vxtxr_txtag, txb->vtxb_dmamap,
2317e3c97c2cSBryan Venteicher 		    BUS_DMASYNC_POSTWRITE);
2318e3c97c2cSBryan Venteicher 		bus_dmamap_unload(txr->vxtxr_txtag, txb->vtxb_dmamap);
2319e3c97c2cSBryan Venteicher 		m_freem(txb->vtxb_m);
2320e3c97c2cSBryan Venteicher 		txb->vtxb_m = NULL;
2321e3c97c2cSBryan Venteicher 	}
2322e3c97c2cSBryan Venteicher }
2323e3c97c2cSBryan Venteicher 
2324e3c97c2cSBryan Venteicher static void
2325e3c97c2cSBryan Venteicher vmxnet3_rxstop(struct vmxnet3_softc *sc, struct vmxnet3_rxqueue *rxq)
2326e3c97c2cSBryan Venteicher {
2327e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
2328e3c97c2cSBryan Venteicher 	struct vmxnet3_rxbuf *rxb;
2329e3c97c2cSBryan Venteicher 	int i, j;
2330e3c97c2cSBryan Venteicher 
2331e3c97c2cSBryan Venteicher 	for (i = 0; i < VMXNET3_RXRINGS_PERQ; i++) {
2332e3c97c2cSBryan Venteicher 		rxr = &rxq->vxrxq_cmd_ring[i];
2333e3c97c2cSBryan Venteicher 
2334e3c97c2cSBryan Venteicher 		for (j = 0; j < rxr->vxrxr_ndesc; j++) {
2335e3c97c2cSBryan Venteicher 			rxb = &rxr->vxrxr_rxbuf[j];
2336e3c97c2cSBryan Venteicher 
2337e3c97c2cSBryan Venteicher 			if (rxb->vrxb_m == NULL)
2338e3c97c2cSBryan Venteicher 				continue;
2339*e557c1ddSBryan Venteicher 
2340e3c97c2cSBryan Venteicher 			bus_dmamap_sync(rxr->vxrxr_rxtag, rxb->vrxb_dmamap,
2341e3c97c2cSBryan Venteicher 			    BUS_DMASYNC_POSTREAD);
2342e3c97c2cSBryan Venteicher 			bus_dmamap_unload(rxr->vxrxr_rxtag, rxb->vrxb_dmamap);
2343e3c97c2cSBryan Venteicher 			m_freem(rxb->vrxb_m);
2344e3c97c2cSBryan Venteicher 			rxb->vrxb_m = NULL;
2345e3c97c2cSBryan Venteicher 		}
2346e3c97c2cSBryan Venteicher 	}
2347e3c97c2cSBryan Venteicher }
2348e3c97c2cSBryan Venteicher 
2349e3c97c2cSBryan Venteicher static void
2350e3c97c2cSBryan Venteicher vmxnet3_stop_rendezvous(struct vmxnet3_softc *sc)
2351e3c97c2cSBryan Venteicher {
2352e3c97c2cSBryan Venteicher 	struct vmxnet3_rxqueue *rxq;
2353e3c97c2cSBryan Venteicher 	struct vmxnet3_txqueue *txq;
2354e3c97c2cSBryan Venteicher 	int i;
2355e3c97c2cSBryan Venteicher 
2356e3c97c2cSBryan Venteicher 	for (i = 0; i < sc->vmx_nrxqueues; i++) {
2357e3c97c2cSBryan Venteicher 		rxq = &sc->vmx_rxq[i];
2358e3c97c2cSBryan Venteicher 		VMXNET3_RXQ_LOCK(rxq);
2359e3c97c2cSBryan Venteicher 		VMXNET3_RXQ_UNLOCK(rxq);
2360e3c97c2cSBryan Venteicher 	}
2361e3c97c2cSBryan Venteicher 
2362e3c97c2cSBryan Venteicher 	for (i = 0; i < sc->vmx_ntxqueues; i++) {
2363e3c97c2cSBryan Venteicher 		txq = &sc->vmx_txq[i];
2364e3c97c2cSBryan Venteicher 		VMXNET3_TXQ_LOCK(txq);
2365e3c97c2cSBryan Venteicher 		VMXNET3_TXQ_UNLOCK(txq);
2366e3c97c2cSBryan Venteicher 	}
2367e3c97c2cSBryan Venteicher }
2368e3c97c2cSBryan Venteicher 
2369e3c97c2cSBryan Venteicher static void
2370e3c97c2cSBryan Venteicher vmxnet3_stop(struct vmxnet3_softc *sc)
2371e3c97c2cSBryan Venteicher {
2372e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
2373e3c97c2cSBryan Venteicher 	int q;
2374e3c97c2cSBryan Venteicher 
2375e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
2376e3c97c2cSBryan Venteicher 	VMXNET3_CORE_LOCK_ASSERT(sc);
2377e3c97c2cSBryan Venteicher 
2378e3c97c2cSBryan Venteicher 	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
2379e3c97c2cSBryan Venteicher 	sc->vmx_link_active = 0;
2380e3c97c2cSBryan Venteicher 	callout_stop(&sc->vmx_tick);
2381e3c97c2cSBryan Venteicher 
2382e3c97c2cSBryan Venteicher 	/* Disable interrupts. */
2383e3c97c2cSBryan Venteicher 	vmxnet3_disable_all_intrs(sc);
2384e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_DISABLE);
2385e3c97c2cSBryan Venteicher 
2386e3c97c2cSBryan Venteicher 	vmxnet3_stop_rendezvous(sc);
2387e3c97c2cSBryan Venteicher 
2388e3c97c2cSBryan Venteicher 	for (q = 0; q < sc->vmx_ntxqueues; q++)
2389e3c97c2cSBryan Venteicher 		vmxnet3_txstop(sc, &sc->vmx_txq[q]);
2390e3c97c2cSBryan Venteicher 	for (q = 0; q < sc->vmx_nrxqueues; q++)
2391e3c97c2cSBryan Venteicher 		vmxnet3_rxstop(sc, &sc->vmx_rxq[q]);
2392e3c97c2cSBryan Venteicher 
2393e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_RESET);
2394e3c97c2cSBryan Venteicher }
2395e3c97c2cSBryan Venteicher 
2396e3c97c2cSBryan Venteicher static void
2397e3c97c2cSBryan Venteicher vmxnet3_txinit(struct vmxnet3_softc *sc, struct vmxnet3_txqueue *txq)
2398e3c97c2cSBryan Venteicher {
2399e3c97c2cSBryan Venteicher 	struct vmxnet3_txring *txr;
2400e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *txc;
2401e3c97c2cSBryan Venteicher 
2402e3c97c2cSBryan Venteicher 	txr = &txq->vxtxq_cmd_ring;
2403e3c97c2cSBryan Venteicher 	txr->vxtxr_head = 0;
2404e3c97c2cSBryan Venteicher 	txr->vxtxr_next = 0;
2405e3c97c2cSBryan Venteicher 	txr->vxtxr_gen = VMXNET3_INIT_GEN;
2406e3c97c2cSBryan Venteicher 	bzero(txr->vxtxr_txd,
2407e3c97c2cSBryan Venteicher 	    txr->vxtxr_ndesc * sizeof(struct vmxnet3_txdesc));
2408e3c97c2cSBryan Venteicher 
2409e3c97c2cSBryan Venteicher 	txc = &txq->vxtxq_comp_ring;
2410e3c97c2cSBryan Venteicher 	txc->vxcr_next = 0;
2411e3c97c2cSBryan Venteicher 	txc->vxcr_gen = VMXNET3_INIT_GEN;
2412e3c97c2cSBryan Venteicher 	bzero(txc->vxcr_u.txcd,
2413e3c97c2cSBryan Venteicher 	    txc->vxcr_ndesc * sizeof(struct vmxnet3_txcompdesc));
2414e3c97c2cSBryan Venteicher }
2415e3c97c2cSBryan Venteicher 
2416e3c97c2cSBryan Venteicher static int
2417e3c97c2cSBryan Venteicher vmxnet3_rxinit(struct vmxnet3_softc *sc, struct vmxnet3_rxqueue *rxq)
2418e3c97c2cSBryan Venteicher {
2419e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
2420e3c97c2cSBryan Venteicher 	struct vmxnet3_rxring *rxr;
2421e3c97c2cSBryan Venteicher 	struct vmxnet3_comp_ring *rxc;
2422e3c97c2cSBryan Venteicher 	int i, populate, idx, frame_size, error;
2423e3c97c2cSBryan Venteicher 
2424e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
24253c965775SBryan Venteicher 	frame_size = ETHER_ALIGN + sizeof(struct ether_vlan_header) +
24263c965775SBryan Venteicher 	    ifp->if_mtu;
2427e3c97c2cSBryan Venteicher 
2428e3c97c2cSBryan Venteicher 	/*
24293c965775SBryan Venteicher 	 * If the MTU causes us to exceed what a regular sized cluster can
24303c965775SBryan Venteicher 	 * handle, we allocate a second MJUMPAGESIZE cluster after it in
24313c965775SBryan Venteicher 	 * ring 0. If in use, ring 1 always contains MJUMPAGESIZE clusters.
2432e3c97c2cSBryan Venteicher 	 *
24333c965775SBryan Venteicher 	 * Keep rx_max_chain a divisor of the maximum Rx ring size to make
24343c965775SBryan Venteicher 	 * our life easier. We do not support changing the ring size after
24353c965775SBryan Venteicher 	 * the attach.
2436e3c97c2cSBryan Venteicher 	 */
24373c965775SBryan Venteicher 	if (frame_size <= MCLBYTES)
2438e3c97c2cSBryan Venteicher 		sc->vmx_rx_max_chain = 1;
2439e3c97c2cSBryan Venteicher 	else
2440e3c97c2cSBryan Venteicher 		sc->vmx_rx_max_chain = 2;
2441e3c97c2cSBryan Venteicher 
2442e3c97c2cSBryan Venteicher 	/*
2443e3c97c2cSBryan Venteicher 	 * Only populate ring 1 if the configuration will take advantage
2444e3c97c2cSBryan Venteicher 	 * of it. That is either when LRO is enabled or the frame size
2445e3c97c2cSBryan Venteicher 	 * exceeds what ring 0 can contain.
2446e3c97c2cSBryan Venteicher 	 */
2447e3c97c2cSBryan Venteicher 	if ((ifp->if_capenable & IFCAP_LRO) == 0 &&
2448e3c97c2cSBryan Venteicher 	    frame_size <= MCLBYTES + MJUMPAGESIZE)
2449e3c97c2cSBryan Venteicher 		populate = 1;
2450e3c97c2cSBryan Venteicher 	else
2451e3c97c2cSBryan Venteicher 		populate = VMXNET3_RXRINGS_PERQ;
2452e3c97c2cSBryan Venteicher 
2453e3c97c2cSBryan Venteicher 	for (i = 0; i < populate; i++) {
2454e3c97c2cSBryan Venteicher 		rxr = &rxq->vxrxq_cmd_ring[i];
2455e3c97c2cSBryan Venteicher 		rxr->vxrxr_fill = 0;
2456e3c97c2cSBryan Venteicher 		rxr->vxrxr_gen = VMXNET3_INIT_GEN;
2457e3c97c2cSBryan Venteicher 		bzero(rxr->vxrxr_rxd,
2458e3c97c2cSBryan Venteicher 		    rxr->vxrxr_ndesc * sizeof(struct vmxnet3_rxdesc));
2459e3c97c2cSBryan Venteicher 
2460e3c97c2cSBryan Venteicher 		for (idx = 0; idx < rxr->vxrxr_ndesc; idx++) {
2461e3c97c2cSBryan Venteicher 			error = vmxnet3_newbuf(sc, rxr);
2462e3c97c2cSBryan Venteicher 			if (error)
2463e3c97c2cSBryan Venteicher 				return (error);
2464e3c97c2cSBryan Venteicher 		}
2465e3c97c2cSBryan Venteicher 	}
2466e3c97c2cSBryan Venteicher 
2467e3c97c2cSBryan Venteicher 	for (/**/; i < VMXNET3_RXRINGS_PERQ; i++) {
2468e3c97c2cSBryan Venteicher 		rxr = &rxq->vxrxq_cmd_ring[i];
2469e3c97c2cSBryan Venteicher 		rxr->vxrxr_fill = 0;
2470e3c97c2cSBryan Venteicher 		rxr->vxrxr_gen = 0;
2471e3c97c2cSBryan Venteicher 		bzero(rxr->vxrxr_rxd,
2472e3c97c2cSBryan Venteicher 		    rxr->vxrxr_ndesc * sizeof(struct vmxnet3_rxdesc));
2473e3c97c2cSBryan Venteicher 	}
2474e3c97c2cSBryan Venteicher 
2475e3c97c2cSBryan Venteicher 	rxc = &rxq->vxrxq_comp_ring;
2476e3c97c2cSBryan Venteicher 	rxc->vxcr_next = 0;
2477e3c97c2cSBryan Venteicher 	rxc->vxcr_gen = VMXNET3_INIT_GEN;
2478e3c97c2cSBryan Venteicher 	bzero(rxc->vxcr_u.rxcd,
2479e3c97c2cSBryan Venteicher 	    rxc->vxcr_ndesc * sizeof(struct vmxnet3_rxcompdesc));
2480e3c97c2cSBryan Venteicher 
2481e3c97c2cSBryan Venteicher 	return (0);
2482e3c97c2cSBryan Venteicher }
2483e3c97c2cSBryan Venteicher 
2484e3c97c2cSBryan Venteicher static int
2485e3c97c2cSBryan Venteicher vmxnet3_reinit_queues(struct vmxnet3_softc *sc)
2486e3c97c2cSBryan Venteicher {
2487e3c97c2cSBryan Venteicher 	device_t dev;
2488e3c97c2cSBryan Venteicher 	int q, error;
2489e3c97c2cSBryan Venteicher 
2490e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
2491e3c97c2cSBryan Venteicher 
2492e3c97c2cSBryan Venteicher 	for (q = 0; q < sc->vmx_ntxqueues; q++)
2493e3c97c2cSBryan Venteicher 		vmxnet3_txinit(sc, &sc->vmx_txq[q]);
2494e3c97c2cSBryan Venteicher 
2495e3c97c2cSBryan Venteicher 	for (q = 0; q < sc->vmx_nrxqueues; q++) {
2496e3c97c2cSBryan Venteicher 		error = vmxnet3_rxinit(sc, &sc->vmx_rxq[q]);
2497e3c97c2cSBryan Venteicher 		if (error) {
2498e3c97c2cSBryan Venteicher 			device_printf(dev, "cannot populate Rx queue %d\n", q);
2499e3c97c2cSBryan Venteicher 			return (error);
2500e3c97c2cSBryan Venteicher 		}
2501e3c97c2cSBryan Venteicher 	}
2502e3c97c2cSBryan Venteicher 
2503e3c97c2cSBryan Venteicher 	return (0);
2504e3c97c2cSBryan Venteicher }
2505e3c97c2cSBryan Venteicher 
2506e3c97c2cSBryan Venteicher static int
2507e3c97c2cSBryan Venteicher vmxnet3_enable_device(struct vmxnet3_softc *sc)
2508e3c97c2cSBryan Venteicher {
2509e3c97c2cSBryan Venteicher 	int q;
2510e3c97c2cSBryan Venteicher 
2511e3c97c2cSBryan Venteicher 	if (vmxnet3_read_cmd(sc, VMXNET3_CMD_ENABLE) != 0) {
2512e3c97c2cSBryan Venteicher 		device_printf(sc->vmx_dev, "device enable command failed!\n");
2513e3c97c2cSBryan Venteicher 		return (1);
2514e3c97c2cSBryan Venteicher 	}
2515e3c97c2cSBryan Venteicher 
2516e3c97c2cSBryan Venteicher 	/* Reset the Rx queue heads. */
2517e3c97c2cSBryan Venteicher 	for (q = 0; q < sc->vmx_nrxqueues; q++) {
2518e3c97c2cSBryan Venteicher 		vmxnet3_write_bar0(sc, VMXNET3_BAR0_RXH1(q), 0);
2519e3c97c2cSBryan Venteicher 		vmxnet3_write_bar0(sc, VMXNET3_BAR0_RXH2(q), 0);
2520e3c97c2cSBryan Venteicher 	}
2521e3c97c2cSBryan Venteicher 
2522e3c97c2cSBryan Venteicher 	return (0);
2523e3c97c2cSBryan Venteicher }
2524e3c97c2cSBryan Venteicher 
2525e3c97c2cSBryan Venteicher static void
2526e3c97c2cSBryan Venteicher vmxnet3_reinit_rxfilters(struct vmxnet3_softc *sc)
2527e3c97c2cSBryan Venteicher {
2528e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
2529e3c97c2cSBryan Venteicher 
2530e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
2531e3c97c2cSBryan Venteicher 
2532e3c97c2cSBryan Venteicher 	vmxnet3_set_rxfilter(sc);
2533e3c97c2cSBryan Venteicher 
2534e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & IFCAP_VLAN_HWFILTER)
2535e3c97c2cSBryan Venteicher 		bcopy(sc->vmx_vlan_filter, sc->vmx_ds->vlan_filter,
2536e3c97c2cSBryan Venteicher 		    sizeof(sc->vmx_ds->vlan_filter));
2537e3c97c2cSBryan Venteicher 	else
2538e3c97c2cSBryan Venteicher 		bzero(sc->vmx_ds->vlan_filter,
2539e3c97c2cSBryan Venteicher 		    sizeof(sc->vmx_ds->vlan_filter));
2540e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_VLAN_FILTER);
2541e3c97c2cSBryan Venteicher }
2542e3c97c2cSBryan Venteicher 
2543e3c97c2cSBryan Venteicher static int
2544e3c97c2cSBryan Venteicher vmxnet3_reinit(struct vmxnet3_softc *sc)
2545e3c97c2cSBryan Venteicher {
2546e3c97c2cSBryan Venteicher 
2547e3c97c2cSBryan Venteicher 	vmxnet3_reinit_interface(sc);
2548e3c97c2cSBryan Venteicher 	vmxnet3_reinit_shared_data(sc);
2549e3c97c2cSBryan Venteicher 
2550e3c97c2cSBryan Venteicher 	if (vmxnet3_reinit_queues(sc) != 0)
2551e3c97c2cSBryan Venteicher 		return (ENXIO);
2552e3c97c2cSBryan Venteicher 
2553e3c97c2cSBryan Venteicher 	if (vmxnet3_enable_device(sc) != 0)
2554e3c97c2cSBryan Venteicher 		return (ENXIO);
2555e3c97c2cSBryan Venteicher 
2556e3c97c2cSBryan Venteicher 	vmxnet3_reinit_rxfilters(sc);
2557e3c97c2cSBryan Venteicher 
2558e3c97c2cSBryan Venteicher 	return (0);
2559e3c97c2cSBryan Venteicher }
2560e3c97c2cSBryan Venteicher 
2561e3c97c2cSBryan Venteicher static void
2562e3c97c2cSBryan Venteicher vmxnet3_init_locked(struct vmxnet3_softc *sc)
2563e3c97c2cSBryan Venteicher {
2564e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
2565e3c97c2cSBryan Venteicher 
2566e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
2567e3c97c2cSBryan Venteicher 
2568e3c97c2cSBryan Venteicher 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
2569e3c97c2cSBryan Venteicher 		return;
2570e3c97c2cSBryan Venteicher 
2571e3c97c2cSBryan Venteicher 	vmxnet3_stop(sc);
2572e3c97c2cSBryan Venteicher 
2573e3c97c2cSBryan Venteicher 	if (vmxnet3_reinit(sc) != 0) {
2574e3c97c2cSBryan Venteicher 		vmxnet3_stop(sc);
2575e3c97c2cSBryan Venteicher 		return;
2576e3c97c2cSBryan Venteicher 	}
2577e3c97c2cSBryan Venteicher 
2578e3c97c2cSBryan Venteicher 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
2579e3c97c2cSBryan Venteicher 	vmxnet3_link_status(sc);
2580e3c97c2cSBryan Venteicher 
2581e3c97c2cSBryan Venteicher 	vmxnet3_enable_all_intrs(sc);
2582e3c97c2cSBryan Venteicher 	callout_reset(&sc->vmx_tick, hz, vmxnet3_tick, sc);
2583e3c97c2cSBryan Venteicher }
2584e3c97c2cSBryan Venteicher 
2585e3c97c2cSBryan Venteicher static void
2586e3c97c2cSBryan Venteicher vmxnet3_init(void *xsc)
2587e3c97c2cSBryan Venteicher {
2588e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
2589e3c97c2cSBryan Venteicher 
2590e3c97c2cSBryan Venteicher 	sc = xsc;
2591e3c97c2cSBryan Venteicher 
2592e3c97c2cSBryan Venteicher 	VMXNET3_CORE_LOCK(sc);
2593e3c97c2cSBryan Venteicher 	vmxnet3_init_locked(sc);
2594e3c97c2cSBryan Venteicher 	VMXNET3_CORE_UNLOCK(sc);
2595e3c97c2cSBryan Venteicher }
2596e3c97c2cSBryan Venteicher 
2597e3c97c2cSBryan Venteicher /*
2598e3c97c2cSBryan Venteicher  * BMV: Much of this can go away once we finally have offsets in
2599e3c97c2cSBryan Venteicher  * the mbuf packet header. Bug andre@.
2600e3c97c2cSBryan Venteicher  */
2601e3c97c2cSBryan Venteicher static int
2602*e557c1ddSBryan Venteicher vmxnet3_txq_offload_ctx(struct vmxnet3_txqueue *txq, struct mbuf *m,
2603*e557c1ddSBryan Venteicher     int *etype, int *proto, int *start)
2604e3c97c2cSBryan Venteicher {
2605e3c97c2cSBryan Venteicher 	struct ether_vlan_header *evh;
2606e3c97c2cSBryan Venteicher 	int offset;
2607e3c97c2cSBryan Venteicher 
2608e3c97c2cSBryan Venteicher 	evh = mtod(m, struct ether_vlan_header *);
2609e3c97c2cSBryan Venteicher 	if (evh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
2610e3c97c2cSBryan Venteicher 		/* BMV: We should handle nested VLAN tags too. */
2611e3c97c2cSBryan Venteicher 		*etype = ntohs(evh->evl_proto);
2612e3c97c2cSBryan Venteicher 		offset = sizeof(struct ether_vlan_header);
2613e3c97c2cSBryan Venteicher 	} else {
2614e3c97c2cSBryan Venteicher 		*etype = ntohs(evh->evl_encap_proto);
2615e3c97c2cSBryan Venteicher 		offset = sizeof(struct ether_header);
2616e3c97c2cSBryan Venteicher 	}
2617e3c97c2cSBryan Venteicher 
2618e3c97c2cSBryan Venteicher 	switch (*etype) {
2619e3c97c2cSBryan Venteicher #if defined(INET)
2620e3c97c2cSBryan Venteicher 	case ETHERTYPE_IP: {
2621e3c97c2cSBryan Venteicher 		struct ip *ip, iphdr;
2622e3c97c2cSBryan Venteicher 		if (__predict_false(m->m_len < offset + sizeof(struct ip))) {
2623e3c97c2cSBryan Venteicher 			m_copydata(m, offset, sizeof(struct ip),
2624e3c97c2cSBryan Venteicher 			    (caddr_t) &iphdr);
2625e3c97c2cSBryan Venteicher 			ip = &iphdr;
2626e3c97c2cSBryan Venteicher 		} else
2627*e557c1ddSBryan Venteicher 			ip = mtodo(m, offset);
2628e3c97c2cSBryan Venteicher 		*proto = ip->ip_p;
2629e3c97c2cSBryan Venteicher 		*start = offset + (ip->ip_hl << 2);
2630e3c97c2cSBryan Venteicher 		break;
2631e3c97c2cSBryan Venteicher 	}
2632e3c97c2cSBryan Venteicher #endif
2633e3c97c2cSBryan Venteicher #if defined(INET6)
2634e3c97c2cSBryan Venteicher 	case ETHERTYPE_IPV6:
2635e3c97c2cSBryan Venteicher 		*proto = -1;
2636e3c97c2cSBryan Venteicher 		*start = ip6_lasthdr(m, offset, IPPROTO_IPV6, proto);
2637e3c97c2cSBryan Venteicher 		/* Assert the network stack sent us a valid packet. */
2638e3c97c2cSBryan Venteicher 		KASSERT(*start > offset,
2639e3c97c2cSBryan Venteicher 		    ("%s: mbuf %p start %d offset %d proto %d", __func__, m,
2640e3c97c2cSBryan Venteicher 		    *start, offset, *proto));
2641e3c97c2cSBryan Venteicher 		break;
2642e3c97c2cSBryan Venteicher #endif
2643e3c97c2cSBryan Venteicher 	default:
2644e3c97c2cSBryan Venteicher 		return (EINVAL);
2645e3c97c2cSBryan Venteicher 	}
2646e3c97c2cSBryan Venteicher 
2647e3c97c2cSBryan Venteicher 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
2648e3c97c2cSBryan Venteicher 		struct tcphdr *tcp, tcphdr;
2649e3c97c2cSBryan Venteicher 
2650e3c97c2cSBryan Venteicher 		if (__predict_false(*proto != IPPROTO_TCP)) {
2651e3c97c2cSBryan Venteicher 			/* Likely failed to correctly parse the mbuf. */
2652e3c97c2cSBryan Venteicher 			return (EINVAL);
2653e3c97c2cSBryan Venteicher 		}
2654e3c97c2cSBryan Venteicher 
2655*e557c1ddSBryan Venteicher 		txq->vxtxq_stats.vmtxs_tso++;
2656e3c97c2cSBryan Venteicher 
2657e3c97c2cSBryan Venteicher 		/*
2658e3c97c2cSBryan Venteicher 		 * For TSO, the size of the protocol header is also
2659e3c97c2cSBryan Venteicher 		 * included in the descriptor header size.
2660e3c97c2cSBryan Venteicher 		 */
2661*e557c1ddSBryan Venteicher 		if (m->m_len < *start + sizeof(struct tcphdr)) {
2662*e557c1ddSBryan Venteicher 			m_copydata(m, offset, sizeof(struct tcphdr),
2663*e557c1ddSBryan Venteicher 			    (caddr_t) &tcphdr);
2664*e557c1ddSBryan Venteicher 			tcp = &tcphdr;
2665*e557c1ddSBryan Venteicher 		} else
2666*e557c1ddSBryan Venteicher 			tcp = mtodo(m, *start);
2667e3c97c2cSBryan Venteicher 		*start += (tcp->th_off << 2);
2668*e557c1ddSBryan Venteicher 	} else
2669*e557c1ddSBryan Venteicher 		txq->vxtxq_stats.vmtxs_csum++;
2670e3c97c2cSBryan Venteicher 
2671e3c97c2cSBryan Venteicher 	return (0);
2672e3c97c2cSBryan Venteicher }
2673e3c97c2cSBryan Venteicher 
2674e3c97c2cSBryan Venteicher static int
2675e3c97c2cSBryan Venteicher vmxnet3_txq_load_mbuf(struct vmxnet3_txqueue *txq, struct mbuf **m0,
2676e3c97c2cSBryan Venteicher     bus_dmamap_t dmap, bus_dma_segment_t segs[], int *nsegs)
2677e3c97c2cSBryan Venteicher {
2678e3c97c2cSBryan Venteicher 	struct vmxnet3_txring *txr;
2679e3c97c2cSBryan Venteicher 	struct mbuf *m;
2680e3c97c2cSBryan Venteicher 	bus_dma_tag_t tag;
2681*e557c1ddSBryan Venteicher 	int error;
2682e3c97c2cSBryan Venteicher 
2683e3c97c2cSBryan Venteicher 	txr = &txq->vxtxq_cmd_ring;
2684e3c97c2cSBryan Venteicher 	m = *m0;
2685e3c97c2cSBryan Venteicher 	tag = txr->vxtxr_txtag;
2686e3c97c2cSBryan Venteicher 
2687e3c97c2cSBryan Venteicher 	error = bus_dmamap_load_mbuf_sg(tag, dmap, m, segs, nsegs, 0);
2688e3c97c2cSBryan Venteicher 	if (error == 0 || error != EFBIG)
2689e3c97c2cSBryan Venteicher 		return (error);
2690e3c97c2cSBryan Venteicher 
2691*e557c1ddSBryan Venteicher 	m = m_defrag(m, M_NOWAIT);
2692e3c97c2cSBryan Venteicher 	if (m != NULL) {
2693e3c97c2cSBryan Venteicher 		*m0 = m;
2694e3c97c2cSBryan Venteicher 		error = bus_dmamap_load_mbuf_sg(tag, dmap, m, segs, nsegs, 0);
2695e3c97c2cSBryan Venteicher 	} else
2696e3c97c2cSBryan Venteicher 		error = ENOBUFS;
2697e3c97c2cSBryan Venteicher 
2698e3c97c2cSBryan Venteicher 	if (error) {
2699e3c97c2cSBryan Venteicher 		m_freem(*m0);
2700e3c97c2cSBryan Venteicher 		*m0 = NULL;
2701*e557c1ddSBryan Venteicher 		txq->vxtxq_sc->vmx_stats.vmst_defrag_failed++;
2702e3c97c2cSBryan Venteicher 	} else
2703*e557c1ddSBryan Venteicher 		txq->vxtxq_sc->vmx_stats.vmst_defragged++;
2704e3c97c2cSBryan Venteicher 
2705e3c97c2cSBryan Venteicher 	return (error);
2706e3c97c2cSBryan Venteicher }
2707e3c97c2cSBryan Venteicher 
2708e3c97c2cSBryan Venteicher static void
2709e3c97c2cSBryan Venteicher vmxnet3_txq_unload_mbuf(struct vmxnet3_txqueue *txq, bus_dmamap_t dmap)
2710e3c97c2cSBryan Venteicher {
2711e3c97c2cSBryan Venteicher 	struct vmxnet3_txring *txr;
2712e3c97c2cSBryan Venteicher 
2713e3c97c2cSBryan Venteicher 	txr = &txq->vxtxq_cmd_ring;
2714e3c97c2cSBryan Venteicher 	bus_dmamap_unload(txr->vxtxr_txtag, dmap);
2715e3c97c2cSBryan Venteicher }
2716e3c97c2cSBryan Venteicher 
2717e3c97c2cSBryan Venteicher static int
2718e3c97c2cSBryan Venteicher vmxnet3_txq_encap(struct vmxnet3_txqueue *txq, struct mbuf **m0)
2719e3c97c2cSBryan Venteicher {
2720e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
2721e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
2722e3c97c2cSBryan Venteicher 	struct vmxnet3_txring *txr;
2723e3c97c2cSBryan Venteicher 	struct vmxnet3_txdesc *txd, *sop;
2724e3c97c2cSBryan Venteicher 	struct mbuf *m;
2725e3c97c2cSBryan Venteicher 	bus_dmamap_t dmap;
2726e3c97c2cSBryan Venteicher 	bus_dma_segment_t segs[VMXNET3_TX_MAXSEGS];
2727e3c97c2cSBryan Venteicher 	int i, gen, nsegs, etype, proto, start, error;
2728e3c97c2cSBryan Venteicher 
2729e3c97c2cSBryan Venteicher 	sc = txq->vxtxq_sc;
2730e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
2731e3c97c2cSBryan Venteicher 	start = 0;
2732e3c97c2cSBryan Venteicher 	txd = NULL;
2733e3c97c2cSBryan Venteicher 	txr = &txq->vxtxq_cmd_ring;
2734e3c97c2cSBryan Venteicher 	dmap = txr->vxtxr_txbuf[txr->vxtxr_head].vtxb_dmamap;
2735e3c97c2cSBryan Venteicher 
2736e3c97c2cSBryan Venteicher 	error = vmxnet3_txq_load_mbuf(txq, m0, dmap, segs, &nsegs);
2737e3c97c2cSBryan Venteicher 	if (error)
2738e3c97c2cSBryan Venteicher 		return (error);
2739e3c97c2cSBryan Venteicher 
2740e3c97c2cSBryan Venteicher 	m = *m0;
2741e3c97c2cSBryan Venteicher 	M_ASSERTPKTHDR(m);
2742e3c97c2cSBryan Venteicher 	KASSERT(nsegs <= VMXNET3_TX_MAXSEGS,
2743e3c97c2cSBryan Venteicher 	    ("%s: mbuf %p with too many segments %d", __func__, m, nsegs));
2744e3c97c2cSBryan Venteicher 
2745e3c97c2cSBryan Venteicher 	if (VMXNET3_TXRING_AVAIL(txr) < nsegs) {
2746*e557c1ddSBryan Venteicher 		txq->vxtxq_stats.vmtxs_full++;
2747e3c97c2cSBryan Venteicher 		vmxnet3_txq_unload_mbuf(txq, dmap);
2748e3c97c2cSBryan Venteicher 		return (ENOSPC);
2749e3c97c2cSBryan Venteicher 	} else if (m->m_pkthdr.csum_flags & VMXNET3_CSUM_ALL_OFFLOAD) {
2750*e557c1ddSBryan Venteicher 		error = vmxnet3_txq_offload_ctx(txq, m, &etype, &proto, &start);
2751e3c97c2cSBryan Venteicher 		if (error) {
2752*e557c1ddSBryan Venteicher 			txq->vxtxq_stats.vmtxs_offload_failed++;
2753e3c97c2cSBryan Venteicher 			vmxnet3_txq_unload_mbuf(txq, dmap);
2754e3c97c2cSBryan Venteicher 			m_freem(m);
2755e3c97c2cSBryan Venteicher 			*m0 = NULL;
2756e3c97c2cSBryan Venteicher 			return (error);
2757e3c97c2cSBryan Venteicher 		}
2758e3c97c2cSBryan Venteicher 	}
2759e3c97c2cSBryan Venteicher 
2760e3c97c2cSBryan Venteicher 	txr->vxtxr_txbuf[txr->vxtxr_head].vtxb_m = m = *m0;
2761e3c97c2cSBryan Venteicher 	sop = &txr->vxtxr_txd[txr->vxtxr_head];
2762e3c97c2cSBryan Venteicher 	gen = txr->vxtxr_gen ^ 1;	/* Owned by cpu (yet) */
2763e3c97c2cSBryan Venteicher 
2764e3c97c2cSBryan Venteicher 	for (i = 0; i < nsegs; i++) {
2765e3c97c2cSBryan Venteicher 		txd = &txr->vxtxr_txd[txr->vxtxr_head];
2766e3c97c2cSBryan Venteicher 
2767e3c97c2cSBryan Venteicher 		txd->addr = segs[i].ds_addr;
2768e3c97c2cSBryan Venteicher 		txd->len = segs[i].ds_len;
2769e3c97c2cSBryan Venteicher 		txd->gen = gen;
2770e3c97c2cSBryan Venteicher 		txd->dtype = 0;
2771e3c97c2cSBryan Venteicher 		txd->offload_mode = VMXNET3_OM_NONE;
2772e3c97c2cSBryan Venteicher 		txd->offload_pos = 0;
2773e3c97c2cSBryan Venteicher 		txd->hlen = 0;
2774e3c97c2cSBryan Venteicher 		txd->eop = 0;
2775e3c97c2cSBryan Venteicher 		txd->compreq = 0;
2776e3c97c2cSBryan Venteicher 		txd->vtag_mode = 0;
2777e3c97c2cSBryan Venteicher 		txd->vtag = 0;
2778e3c97c2cSBryan Venteicher 
2779e3c97c2cSBryan Venteicher 		if (++txr->vxtxr_head == txr->vxtxr_ndesc) {
2780e3c97c2cSBryan Venteicher 			txr->vxtxr_head = 0;
2781e3c97c2cSBryan Venteicher 			txr->vxtxr_gen ^= 1;
2782e3c97c2cSBryan Venteicher 		}
2783e3c97c2cSBryan Venteicher 		gen = txr->vxtxr_gen;
2784e3c97c2cSBryan Venteicher 	}
2785e3c97c2cSBryan Venteicher 	txd->eop = 1;
2786e3c97c2cSBryan Venteicher 	txd->compreq = 1;
2787e3c97c2cSBryan Venteicher 
2788e3c97c2cSBryan Venteicher 	if (m->m_flags & M_VLANTAG) {
2789e3c97c2cSBryan Venteicher 		sop->vtag_mode = 1;
2790e3c97c2cSBryan Venteicher 		sop->vtag = m->m_pkthdr.ether_vtag;
2791e3c97c2cSBryan Venteicher 	}
2792e3c97c2cSBryan Venteicher 
2793e3c97c2cSBryan Venteicher 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
2794e3c97c2cSBryan Venteicher 		sop->offload_mode = VMXNET3_OM_TSO;
2795e3c97c2cSBryan Venteicher 		sop->hlen = start;
2796e3c97c2cSBryan Venteicher 		sop->offload_pos = m->m_pkthdr.tso_segsz;
2797e3c97c2cSBryan Venteicher 	} else if (m->m_pkthdr.csum_flags & (VMXNET3_CSUM_OFFLOAD |
2798e3c97c2cSBryan Venteicher 	    VMXNET3_CSUM_OFFLOAD_IPV6)) {
2799e3c97c2cSBryan Venteicher 		sop->offload_mode = VMXNET3_OM_CSUM;
2800e3c97c2cSBryan Venteicher 		sop->hlen = start;
2801e3c97c2cSBryan Venteicher 		sop->offload_pos = start + m->m_pkthdr.csum_data;
2802e3c97c2cSBryan Venteicher 	}
2803e3c97c2cSBryan Venteicher 
2804e3c97c2cSBryan Venteicher 	/* Finally, change the ownership. */
2805e3c97c2cSBryan Venteicher 	vmxnet3_barrier(sc, VMXNET3_BARRIER_WR);
2806e3c97c2cSBryan Venteicher 	sop->gen ^= 1;
2807e3c97c2cSBryan Venteicher 
2808e3c97c2cSBryan Venteicher 	if (++txq->vxtxq_ts->npending >= txq->vxtxq_ts->intr_threshold) {
2809e3c97c2cSBryan Venteicher 		txq->vxtxq_ts->npending = 0;
2810e3c97c2cSBryan Venteicher 		vmxnet3_write_bar0(sc, VMXNET3_BAR0_TXH(txq->vxtxq_id),
2811e3c97c2cSBryan Venteicher 		    txr->vxtxr_head);
2812e3c97c2cSBryan Venteicher 	}
2813e3c97c2cSBryan Venteicher 
2814e3c97c2cSBryan Venteicher 	return (0);
2815e3c97c2cSBryan Venteicher }
2816e3c97c2cSBryan Venteicher 
2817e3c97c2cSBryan Venteicher static void
2818*e557c1ddSBryan Venteicher vmxnet3_txq_update_pending(struct vmxnet3_txqueue *txq)
2819*e557c1ddSBryan Venteicher {
2820*e557c1ddSBryan Venteicher 	struct vmxnet3_txring *txr;
2821*e557c1ddSBryan Venteicher 
2822*e557c1ddSBryan Venteicher 	txr = &txq->vxtxq_cmd_ring;
2823*e557c1ddSBryan Venteicher 
2824*e557c1ddSBryan Venteicher 	if (txq->vxtxq_ts->npending > 0) {
2825*e557c1ddSBryan Venteicher 		txq->vxtxq_ts->npending = 0;
2826*e557c1ddSBryan Venteicher 		vmxnet3_write_bar0(txq->vxtxq_sc,
2827*e557c1ddSBryan Venteicher 		    VMXNET3_BAR0_TXH(txq->vxtxq_id), txr->vxtxr_head);
2828*e557c1ddSBryan Venteicher 	}
2829*e557c1ddSBryan Venteicher }
2830*e557c1ddSBryan Venteicher 
2831*e557c1ddSBryan Venteicher #ifdef VMXNET3_LEGACY_TX
2832*e557c1ddSBryan Venteicher 
2833*e557c1ddSBryan Venteicher static void
2834e3c97c2cSBryan Venteicher vmxnet3_start_locked(struct ifnet *ifp)
2835e3c97c2cSBryan Venteicher {
2836e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
2837e3c97c2cSBryan Venteicher 	struct vmxnet3_txqueue *txq;
2838e3c97c2cSBryan Venteicher 	struct vmxnet3_txring *txr;
2839e3c97c2cSBryan Venteicher 	struct mbuf *m_head;
28403c5dfe89SBryan Venteicher 	int tx, avail;
2841e3c97c2cSBryan Venteicher 
2842e3c97c2cSBryan Venteicher 	sc = ifp->if_softc;
2843e3c97c2cSBryan Venteicher 	txq = &sc->vmx_txq[0];
2844e3c97c2cSBryan Venteicher 	txr = &txq->vxtxq_cmd_ring;
2845e3c97c2cSBryan Venteicher 	tx = 0;
2846e3c97c2cSBryan Venteicher 
2847e3c97c2cSBryan Venteicher 	VMXNET3_TXQ_LOCK_ASSERT(txq);
2848e3c97c2cSBryan Venteicher 
2849e3c97c2cSBryan Venteicher 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
2850e3c97c2cSBryan Venteicher 	    sc->vmx_link_active == 0)
2851e3c97c2cSBryan Venteicher 		return;
2852e3c97c2cSBryan Venteicher 
28533c5dfe89SBryan Venteicher 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
28543c5dfe89SBryan Venteicher 		if ((avail = VMXNET3_TXRING_AVAIL(txr)) < 2)
28553c5dfe89SBryan Venteicher 			break;
28563c5dfe89SBryan Venteicher 
2857e3c97c2cSBryan Venteicher 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
2858e3c97c2cSBryan Venteicher 		if (m_head == NULL)
2859e3c97c2cSBryan Venteicher 			break;
2860e3c97c2cSBryan Venteicher 
28613c5dfe89SBryan Venteicher 		/* Assume worse case if this mbuf is the head of a chain. */
28623c5dfe89SBryan Venteicher 		if (m_head->m_next != NULL && avail < VMXNET3_TX_MAXSEGS) {
28633c5dfe89SBryan Venteicher 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
28643c5dfe89SBryan Venteicher 			break;
28653c5dfe89SBryan Venteicher 		}
28663c5dfe89SBryan Venteicher 
2867e3c97c2cSBryan Venteicher 		if (vmxnet3_txq_encap(txq, &m_head) != 0) {
2868e3c97c2cSBryan Venteicher 			if (m_head != NULL)
2869e3c97c2cSBryan Venteicher 				IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
2870e3c97c2cSBryan Venteicher 			break;
2871e3c97c2cSBryan Venteicher 		}
2872e3c97c2cSBryan Venteicher 
2873e3c97c2cSBryan Venteicher 		tx++;
2874e3c97c2cSBryan Venteicher 		ETHER_BPF_MTAP(ifp, m_head);
2875e3c97c2cSBryan Venteicher 	}
2876e3c97c2cSBryan Venteicher 
2877e3c97c2cSBryan Venteicher 	if (tx > 0) {
2878*e557c1ddSBryan Venteicher 		vmxnet3_txq_update_pending(txq);
2879e3c97c2cSBryan Venteicher 		txq->vxtxq_watchdog = VMXNET3_WATCHDOG_TIMEOUT;
2880e3c97c2cSBryan Venteicher 	}
2881e3c97c2cSBryan Venteicher }
2882e3c97c2cSBryan Venteicher 
2883e3c97c2cSBryan Venteicher static void
2884e3c97c2cSBryan Venteicher vmxnet3_start(struct ifnet *ifp)
2885e3c97c2cSBryan Venteicher {
2886e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
2887e3c97c2cSBryan Venteicher 	struct vmxnet3_txqueue *txq;
2888e3c97c2cSBryan Venteicher 
2889e3c97c2cSBryan Venteicher 	sc = ifp->if_softc;
2890e3c97c2cSBryan Venteicher 	txq = &sc->vmx_txq[0];
2891e3c97c2cSBryan Venteicher 
2892e3c97c2cSBryan Venteicher 	VMXNET3_TXQ_LOCK(txq);
2893e3c97c2cSBryan Venteicher 	vmxnet3_start_locked(ifp);
2894e3c97c2cSBryan Venteicher 	VMXNET3_TXQ_UNLOCK(txq);
2895e3c97c2cSBryan Venteicher }
2896e3c97c2cSBryan Venteicher 
2897*e557c1ddSBryan Venteicher #else /* !VMXNET3_LEGACY_TX */
2898*e557c1ddSBryan Venteicher 
2899*e557c1ddSBryan Venteicher static int
2900*e557c1ddSBryan Venteicher vmxnet3_txq_mq_start_locked(struct vmxnet3_txqueue *txq, struct mbuf *m)
2901*e557c1ddSBryan Venteicher {
2902*e557c1ddSBryan Venteicher 	struct vmxnet3_softc *sc;
2903*e557c1ddSBryan Venteicher 	struct vmxnet3_txring *txr;
2904*e557c1ddSBryan Venteicher 	struct buf_ring *br;
2905*e557c1ddSBryan Venteicher 	struct ifnet *ifp;
2906*e557c1ddSBryan Venteicher 	int tx, avail, error;
2907*e557c1ddSBryan Venteicher 
2908*e557c1ddSBryan Venteicher 	sc = txq->vxtxq_sc;
2909*e557c1ddSBryan Venteicher 	br = txq->vxtxq_br;
2910*e557c1ddSBryan Venteicher 	ifp = sc->vmx_ifp;
2911*e557c1ddSBryan Venteicher 	txr = &txq->vxtxq_cmd_ring;
2912*e557c1ddSBryan Venteicher 	tx = 0;
2913*e557c1ddSBryan Venteicher 	error = 0;
2914*e557c1ddSBryan Venteicher 
2915*e557c1ddSBryan Venteicher 	VMXNET3_TXQ_LOCK_ASSERT(txq);
2916*e557c1ddSBryan Venteicher 
2917*e557c1ddSBryan Venteicher 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
2918*e557c1ddSBryan Venteicher 	    sc->vmx_link_active == 0) {
2919*e557c1ddSBryan Venteicher 		if (m != NULL)
2920*e557c1ddSBryan Venteicher 			error = drbr_enqueue(ifp, br, m);
2921*e557c1ddSBryan Venteicher 		return (error);
2922*e557c1ddSBryan Venteicher 	}
2923*e557c1ddSBryan Venteicher 
2924*e557c1ddSBryan Venteicher 	if (m != NULL) {
2925*e557c1ddSBryan Venteicher 		error = drbr_enqueue(ifp, br, m);
2926*e557c1ddSBryan Venteicher 		if (error)
2927*e557c1ddSBryan Venteicher 			return (error);
2928*e557c1ddSBryan Venteicher 	}
2929*e557c1ddSBryan Venteicher 
2930*e557c1ddSBryan Venteicher 	while ((avail = VMXNET3_TXRING_AVAIL(txr)) >= 2) {
2931*e557c1ddSBryan Venteicher 		m = drbr_peek(ifp, br);
2932*e557c1ddSBryan Venteicher 		if (m == NULL)
2933*e557c1ddSBryan Venteicher 			break;
2934*e557c1ddSBryan Venteicher 
2935*e557c1ddSBryan Venteicher 		/* Assume worse case if this mbuf is the head of a chain. */
2936*e557c1ddSBryan Venteicher 		if (m->m_next != NULL && avail < VMXNET3_TX_MAXSEGS) {
2937*e557c1ddSBryan Venteicher 			drbr_putback(ifp, br, m);
2938*e557c1ddSBryan Venteicher 			error = ENOBUFS;
2939*e557c1ddSBryan Venteicher 			break;
2940*e557c1ddSBryan Venteicher 		}
2941*e557c1ddSBryan Venteicher 
2942*e557c1ddSBryan Venteicher 		error = vmxnet3_txq_encap(txq, &m);
2943*e557c1ddSBryan Venteicher 		if (error) {
2944*e557c1ddSBryan Venteicher 			if (m != NULL)
2945*e557c1ddSBryan Venteicher 				drbr_putback(ifp, br, m);
2946*e557c1ddSBryan Venteicher 			else
2947*e557c1ddSBryan Venteicher 				drbr_advance(ifp, br);
2948*e557c1ddSBryan Venteicher 			break;
2949*e557c1ddSBryan Venteicher 		}
2950*e557c1ddSBryan Venteicher 		drbr_advance(ifp, br);
2951*e557c1ddSBryan Venteicher 
2952*e557c1ddSBryan Venteicher 		tx++;
2953*e557c1ddSBryan Venteicher 		ETHER_BPF_MTAP(ifp, m);
2954*e557c1ddSBryan Venteicher 	}
2955*e557c1ddSBryan Venteicher 
2956*e557c1ddSBryan Venteicher 	if (tx > 0) {
2957*e557c1ddSBryan Venteicher 		vmxnet3_txq_update_pending(txq);
2958*e557c1ddSBryan Venteicher 		txq->vxtxq_watchdog = VMXNET3_WATCHDOG_TIMEOUT;
2959*e557c1ddSBryan Venteicher 	}
2960*e557c1ddSBryan Venteicher 
2961*e557c1ddSBryan Venteicher 	return (error);
2962*e557c1ddSBryan Venteicher }
2963*e557c1ddSBryan Venteicher 
2964*e557c1ddSBryan Venteicher static int
2965*e557c1ddSBryan Venteicher vmxnet3_txq_mq_start(struct ifnet *ifp, struct mbuf *m)
2966*e557c1ddSBryan Venteicher {
2967*e557c1ddSBryan Venteicher 	struct vmxnet3_softc *sc;
2968*e557c1ddSBryan Venteicher 	struct vmxnet3_txqueue *txq;
2969*e557c1ddSBryan Venteicher 	int i, ntxq, error;
2970*e557c1ddSBryan Venteicher 
2971*e557c1ddSBryan Venteicher 	sc = ifp->if_softc;
2972*e557c1ddSBryan Venteicher 	ntxq = sc->vmx_ntxqueues;
2973*e557c1ddSBryan Venteicher 
2974*e557c1ddSBryan Venteicher 	if (m->m_flags & M_FLOWID)
2975*e557c1ddSBryan Venteicher 		i = m->m_pkthdr.flowid % ntxq;
2976*e557c1ddSBryan Venteicher 	else
2977*e557c1ddSBryan Venteicher 		i = curcpu % ntxq;
2978*e557c1ddSBryan Venteicher 
2979*e557c1ddSBryan Venteicher 	txq = &sc->vmx_txq[i];
2980*e557c1ddSBryan Venteicher 
2981*e557c1ddSBryan Venteicher 	if (VMXNET3_TXQ_TRYLOCK(txq) != 0) {
2982*e557c1ddSBryan Venteicher 		error = vmxnet3_txq_mq_start_locked(txq, m);
2983*e557c1ddSBryan Venteicher 		VMXNET3_TXQ_UNLOCK(txq);
2984*e557c1ddSBryan Venteicher 	} else {
2985*e557c1ddSBryan Venteicher 		error = drbr_enqueue(ifp, txq->vxtxq_br, m);
2986*e557c1ddSBryan Venteicher 		taskqueue_enqueue(sc->vmx_tq, &txq->vxtxq_defrtask);
2987*e557c1ddSBryan Venteicher 	}
2988*e557c1ddSBryan Venteicher 
2989*e557c1ddSBryan Venteicher 	return (error);
2990*e557c1ddSBryan Venteicher }
2991*e557c1ddSBryan Venteicher 
2992*e557c1ddSBryan Venteicher static void
2993*e557c1ddSBryan Venteicher vmxnet3_txq_tq_deferred(void *xtxq, int pending)
2994*e557c1ddSBryan Venteicher {
2995*e557c1ddSBryan Venteicher 	struct vmxnet3_softc *sc;
2996*e557c1ddSBryan Venteicher 	struct vmxnet3_txqueue *txq;
2997*e557c1ddSBryan Venteicher 
2998*e557c1ddSBryan Venteicher 	txq = xtxq;
2999*e557c1ddSBryan Venteicher 	sc = txq->vxtxq_sc;
3000*e557c1ddSBryan Venteicher 
3001*e557c1ddSBryan Venteicher 	VMXNET3_TXQ_LOCK(txq);
3002*e557c1ddSBryan Venteicher 	if (!drbr_empty(sc->vmx_ifp, txq->vxtxq_br))
3003*e557c1ddSBryan Venteicher 		vmxnet3_txq_mq_start_locked(txq, NULL);
3004*e557c1ddSBryan Venteicher 	VMXNET3_TXQ_UNLOCK(txq);
3005*e557c1ddSBryan Venteicher }
3006*e557c1ddSBryan Venteicher 
3007*e557c1ddSBryan Venteicher #endif /* VMXNET3_LEGACY_TX */
3008*e557c1ddSBryan Venteicher 
3009*e557c1ddSBryan Venteicher static void
3010*e557c1ddSBryan Venteicher vmxnet3_txq_start(struct vmxnet3_txqueue *txq)
3011*e557c1ddSBryan Venteicher {
3012*e557c1ddSBryan Venteicher 	struct vmxnet3_softc *sc;
3013*e557c1ddSBryan Venteicher 	struct ifnet *ifp;
3014*e557c1ddSBryan Venteicher 
3015*e557c1ddSBryan Venteicher 	sc = txq->vxtxq_sc;
3016*e557c1ddSBryan Venteicher 	ifp = sc->vmx_ifp;
3017*e557c1ddSBryan Venteicher 
3018*e557c1ddSBryan Venteicher #ifdef VMXNET3_LEGACY_TX
3019*e557c1ddSBryan Venteicher 	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
3020*e557c1ddSBryan Venteicher 		vmxnet3_start_locked(ifp);
3021*e557c1ddSBryan Venteicher #else
3022*e557c1ddSBryan Venteicher 	if (!drbr_empty(ifp, txq->vxtxq_br))
3023*e557c1ddSBryan Venteicher 		vmxnet3_txq_mq_start_locked(txq, NULL);
3024*e557c1ddSBryan Venteicher #endif
3025*e557c1ddSBryan Venteicher }
3026*e557c1ddSBryan Venteicher 
3027*e557c1ddSBryan Venteicher static void
3028*e557c1ddSBryan Venteicher vmxnet3_tx_start_all(struct vmxnet3_softc *sc)
3029*e557c1ddSBryan Venteicher {
3030*e557c1ddSBryan Venteicher 	struct vmxnet3_txqueue *txq;
3031*e557c1ddSBryan Venteicher 	int i;
3032*e557c1ddSBryan Venteicher 
3033*e557c1ddSBryan Venteicher 	VMXNET3_CORE_LOCK_ASSERT(sc);
3034*e557c1ddSBryan Venteicher 
3035*e557c1ddSBryan Venteicher 	for (i = 0; i < sc->vmx_ntxqueues; i++) {
3036*e557c1ddSBryan Venteicher 		txq = &sc->vmx_txq[i];
3037*e557c1ddSBryan Venteicher 
3038*e557c1ddSBryan Venteicher 		VMXNET3_TXQ_LOCK(txq);
3039*e557c1ddSBryan Venteicher 		vmxnet3_txq_start(txq);
3040*e557c1ddSBryan Venteicher 		VMXNET3_TXQ_UNLOCK(txq);
3041*e557c1ddSBryan Venteicher 	}
3042*e557c1ddSBryan Venteicher }
3043*e557c1ddSBryan Venteicher 
3044e3c97c2cSBryan Venteicher static void
3045e3c97c2cSBryan Venteicher vmxnet3_update_vlan_filter(struct vmxnet3_softc *sc, int add, uint16_t tag)
3046e3c97c2cSBryan Venteicher {
3047e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
3048e3c97c2cSBryan Venteicher 	int idx, bit;
3049e3c97c2cSBryan Venteicher 
3050e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
3051e3c97c2cSBryan Venteicher 	idx = (tag >> 5) & 0x7F;
3052e3c97c2cSBryan Venteicher 	bit = tag & 0x1F;
3053e3c97c2cSBryan Venteicher 
3054e3c97c2cSBryan Venteicher 	if (tag == 0 || tag > 4095)
3055e3c97c2cSBryan Venteicher 		return;
3056e3c97c2cSBryan Venteicher 
3057e3c97c2cSBryan Venteicher 	VMXNET3_CORE_LOCK(sc);
3058e3c97c2cSBryan Venteicher 
3059e3c97c2cSBryan Venteicher 	/* Update our private VLAN bitvector. */
3060e3c97c2cSBryan Venteicher 	if (add)
3061e3c97c2cSBryan Venteicher 		sc->vmx_vlan_filter[idx] |= (1 << bit);
3062e3c97c2cSBryan Venteicher 	else
3063e3c97c2cSBryan Venteicher 		sc->vmx_vlan_filter[idx] &= ~(1 << bit);
3064e3c97c2cSBryan Venteicher 
3065e3c97c2cSBryan Venteicher 	if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) {
3066e3c97c2cSBryan Venteicher 		if (add)
3067e3c97c2cSBryan Venteicher 			sc->vmx_ds->vlan_filter[idx] |= (1 << bit);
3068e3c97c2cSBryan Venteicher 		else
3069e3c97c2cSBryan Venteicher 			sc->vmx_ds->vlan_filter[idx] &= ~(1 << bit);
3070e3c97c2cSBryan Venteicher 		vmxnet3_write_cmd(sc, VMXNET3_CMD_VLAN_FILTER);
3071e3c97c2cSBryan Venteicher 	}
3072e3c97c2cSBryan Venteicher 
3073e3c97c2cSBryan Venteicher 	VMXNET3_CORE_UNLOCK(sc);
3074e3c97c2cSBryan Venteicher }
3075e3c97c2cSBryan Venteicher 
3076e3c97c2cSBryan Venteicher static void
3077e3c97c2cSBryan Venteicher vmxnet3_register_vlan(void *arg, struct ifnet *ifp, uint16_t tag)
3078e3c97c2cSBryan Venteicher {
3079e3c97c2cSBryan Venteicher 
3080e3c97c2cSBryan Venteicher 	if (ifp->if_softc == arg)
3081e3c97c2cSBryan Venteicher 		vmxnet3_update_vlan_filter(arg, 1, tag);
3082e3c97c2cSBryan Venteicher }
3083e3c97c2cSBryan Venteicher 
3084e3c97c2cSBryan Venteicher static void
3085e3c97c2cSBryan Venteicher vmxnet3_unregister_vlan(void *arg, struct ifnet *ifp, uint16_t tag)
3086e3c97c2cSBryan Venteicher {
3087e3c97c2cSBryan Venteicher 
3088e3c97c2cSBryan Venteicher 	if (ifp->if_softc == arg)
3089e3c97c2cSBryan Venteicher 		vmxnet3_update_vlan_filter(arg, 0, tag);
3090e3c97c2cSBryan Venteicher }
3091e3c97c2cSBryan Venteicher 
3092e3c97c2cSBryan Venteicher static void
3093e3c97c2cSBryan Venteicher vmxnet3_set_rxfilter(struct vmxnet3_softc *sc)
3094e3c97c2cSBryan Venteicher {
3095e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
3096e3c97c2cSBryan Venteicher 	struct vmxnet3_driver_shared *ds;
3097e3c97c2cSBryan Venteicher 	struct ifmultiaddr *ifma;
3098e3c97c2cSBryan Venteicher 	u_int mode;
3099e3c97c2cSBryan Venteicher 
3100e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
3101e3c97c2cSBryan Venteicher 	ds = sc->vmx_ds;
3102e3c97c2cSBryan Venteicher 
3103*e557c1ddSBryan Venteicher 	mode = VMXNET3_RXMODE_UCAST | VMXNET3_RXMODE_BCAST;
3104e3c97c2cSBryan Venteicher 	if (ifp->if_flags & IFF_PROMISC)
3105e3c97c2cSBryan Venteicher 		mode |= VMXNET3_RXMODE_PROMISC;
3106e3c97c2cSBryan Venteicher 	if (ifp->if_flags & IFF_ALLMULTI)
3107e3c97c2cSBryan Venteicher 		mode |= VMXNET3_RXMODE_ALLMULTI;
3108e3c97c2cSBryan Venteicher 	else {
3109e3c97c2cSBryan Venteicher 		int cnt = 0, overflow = 0;
3110e3c97c2cSBryan Venteicher 
3111e3c97c2cSBryan Venteicher 		if_maddr_rlock(ifp);
3112e3c97c2cSBryan Venteicher 		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
3113e3c97c2cSBryan Venteicher 			if (ifma->ifma_addr->sa_family != AF_LINK)
3114e3c97c2cSBryan Venteicher 				continue;
3115e3c97c2cSBryan Venteicher 			else if (cnt == VMXNET3_MULTICAST_MAX) {
3116e3c97c2cSBryan Venteicher 				overflow = 1;
3117e3c97c2cSBryan Venteicher 				break;
3118e3c97c2cSBryan Venteicher 			}
3119e3c97c2cSBryan Venteicher 
3120e3c97c2cSBryan Venteicher 			bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
3121e3c97c2cSBryan Venteicher 			   &sc->vmx_mcast[cnt*ETHER_ADDR_LEN], ETHER_ADDR_LEN);
3122e3c97c2cSBryan Venteicher 			cnt++;
3123e3c97c2cSBryan Venteicher 		}
3124e3c97c2cSBryan Venteicher 		if_maddr_runlock(ifp);
3125e3c97c2cSBryan Venteicher 
3126e3c97c2cSBryan Venteicher 		if (overflow != 0) {
3127e3c97c2cSBryan Venteicher 			cnt = 0;
3128e3c97c2cSBryan Venteicher 			mode |= VMXNET3_RXMODE_ALLMULTI;
3129e3c97c2cSBryan Venteicher 		} else if (cnt > 0)
3130e3c97c2cSBryan Venteicher 			mode |= VMXNET3_RXMODE_MCAST;
3131e3c97c2cSBryan Venteicher 		ds->mcast_tablelen = cnt * ETHER_ADDR_LEN;
3132e3c97c2cSBryan Venteicher 	}
3133e3c97c2cSBryan Venteicher 
3134e3c97c2cSBryan Venteicher 	ds->rxmode = mode;
3135e3c97c2cSBryan Venteicher 
3136e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_SET_FILTER);
3137e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_SET_RXMODE);
3138e3c97c2cSBryan Venteicher }
3139e3c97c2cSBryan Venteicher 
3140e3c97c2cSBryan Venteicher static int
3141e3c97c2cSBryan Venteicher vmxnet3_change_mtu(struct vmxnet3_softc *sc, int mtu)
3142e3c97c2cSBryan Venteicher {
3143e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
3144e3c97c2cSBryan Venteicher 
3145e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
3146e3c97c2cSBryan Venteicher 
3147e3c97c2cSBryan Venteicher 	if (mtu < VMXNET3_MIN_MTU || mtu > VMXNET3_MAX_MTU)
3148e3c97c2cSBryan Venteicher 		return (EINVAL);
3149e3c97c2cSBryan Venteicher 
3150e3c97c2cSBryan Venteicher 	ifp->if_mtu = mtu;
3151e3c97c2cSBryan Venteicher 
3152e3c97c2cSBryan Venteicher 	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
3153e3c97c2cSBryan Venteicher 		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
3154e3c97c2cSBryan Venteicher 		vmxnet3_init_locked(sc);
3155e3c97c2cSBryan Venteicher 	}
3156e3c97c2cSBryan Venteicher 
3157e3c97c2cSBryan Venteicher 	return (0);
3158e3c97c2cSBryan Venteicher }
3159e3c97c2cSBryan Venteicher 
3160e3c97c2cSBryan Venteicher static int
3161e3c97c2cSBryan Venteicher vmxnet3_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
3162e3c97c2cSBryan Venteicher {
3163e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
3164e3c97c2cSBryan Venteicher 	struct ifreq *ifr;
3165e3c97c2cSBryan Venteicher 	int reinit, mask, error;
3166e3c97c2cSBryan Venteicher 
3167e3c97c2cSBryan Venteicher 	sc = ifp->if_softc;
3168e3c97c2cSBryan Venteicher 	ifr = (struct ifreq *) data;
3169e3c97c2cSBryan Venteicher 	error = 0;
3170e3c97c2cSBryan Venteicher 
3171e3c97c2cSBryan Venteicher 	switch (cmd) {
3172e3c97c2cSBryan Venteicher 	case SIOCSIFMTU:
3173e3c97c2cSBryan Venteicher 		if (ifp->if_mtu != ifr->ifr_mtu) {
3174e3c97c2cSBryan Venteicher 			VMXNET3_CORE_LOCK(sc);
3175e3c97c2cSBryan Venteicher 			error = vmxnet3_change_mtu(sc, ifr->ifr_mtu);
3176e3c97c2cSBryan Venteicher 			VMXNET3_CORE_UNLOCK(sc);
3177e3c97c2cSBryan Venteicher 		}
3178e3c97c2cSBryan Venteicher 		break;
3179e3c97c2cSBryan Venteicher 
3180e3c97c2cSBryan Venteicher 	case SIOCSIFFLAGS:
3181e3c97c2cSBryan Venteicher 		VMXNET3_CORE_LOCK(sc);
3182e3c97c2cSBryan Venteicher 		if (ifp->if_flags & IFF_UP) {
3183e3c97c2cSBryan Venteicher 			if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
3184e3c97c2cSBryan Venteicher 				if ((ifp->if_flags ^ sc->vmx_if_flags) &
3185e3c97c2cSBryan Venteicher 				    (IFF_PROMISC | IFF_ALLMULTI)) {
3186e3c97c2cSBryan Venteicher 					vmxnet3_set_rxfilter(sc);
3187e3c97c2cSBryan Venteicher 				}
3188e3c97c2cSBryan Venteicher 			} else
3189e3c97c2cSBryan Venteicher 				vmxnet3_init_locked(sc);
3190e3c97c2cSBryan Venteicher 		} else {
3191e3c97c2cSBryan Venteicher 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
3192e3c97c2cSBryan Venteicher 				vmxnet3_stop(sc);
3193e3c97c2cSBryan Venteicher 		}
3194e3c97c2cSBryan Venteicher 		sc->vmx_if_flags = ifp->if_flags;
3195e3c97c2cSBryan Venteicher 		VMXNET3_CORE_UNLOCK(sc);
3196e3c97c2cSBryan Venteicher 		break;
3197e3c97c2cSBryan Venteicher 
3198e3c97c2cSBryan Venteicher 	case SIOCADDMULTI:
3199e3c97c2cSBryan Venteicher 	case SIOCDELMULTI:
3200e3c97c2cSBryan Venteicher 		VMXNET3_CORE_LOCK(sc);
3201e3c97c2cSBryan Venteicher 		if (ifp->if_drv_flags & IFF_DRV_RUNNING)
3202e3c97c2cSBryan Venteicher 			vmxnet3_set_rxfilter(sc);
3203e3c97c2cSBryan Venteicher 		VMXNET3_CORE_UNLOCK(sc);
3204e3c97c2cSBryan Venteicher 		break;
3205e3c97c2cSBryan Venteicher 
3206e3c97c2cSBryan Venteicher 	case SIOCSIFMEDIA:
3207e3c97c2cSBryan Venteicher 	case SIOCGIFMEDIA:
3208e3c97c2cSBryan Venteicher 		error = ifmedia_ioctl(ifp, ifr, &sc->vmx_media, cmd);
3209e3c97c2cSBryan Venteicher 		break;
3210e3c97c2cSBryan Venteicher 
3211e3c97c2cSBryan Venteicher 	case SIOCSIFCAP:
3212e3c97c2cSBryan Venteicher 		VMXNET3_CORE_LOCK(sc);
3213e3c97c2cSBryan Venteicher 		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
3214e3c97c2cSBryan Venteicher 
3215e3c97c2cSBryan Venteicher 		if (mask & IFCAP_TXCSUM)
3216e3c97c2cSBryan Venteicher 			ifp->if_capenable ^= IFCAP_TXCSUM;
3217e3c97c2cSBryan Venteicher 		if (mask & IFCAP_TXCSUM_IPV6)
3218e3c97c2cSBryan Venteicher 			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
3219e3c97c2cSBryan Venteicher 		if (mask & IFCAP_TSO4)
3220e3c97c2cSBryan Venteicher 			ifp->if_capenable ^= IFCAP_TSO4;
3221e3c97c2cSBryan Venteicher 		if (mask & IFCAP_TSO6)
3222e3c97c2cSBryan Venteicher 			ifp->if_capenable ^= IFCAP_TSO6;
3223e3c97c2cSBryan Venteicher 
3224e3c97c2cSBryan Venteicher 		if (mask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6 | IFCAP_LRO |
32253c5dfe89SBryan Venteicher 		    IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWFILTER)) {
32263c5dfe89SBryan Venteicher 			/* Changing these features requires us to reinit. */
3227e3c97c2cSBryan Venteicher 			reinit = 1;
3228e3c97c2cSBryan Venteicher 
3229e3c97c2cSBryan Venteicher 			if (mask & IFCAP_RXCSUM)
3230e3c97c2cSBryan Venteicher 				ifp->if_capenable ^= IFCAP_RXCSUM;
3231e3c97c2cSBryan Venteicher 			if (mask & IFCAP_RXCSUM_IPV6)
3232e3c97c2cSBryan Venteicher 				ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
3233e3c97c2cSBryan Venteicher 			if (mask & IFCAP_LRO)
3234e3c97c2cSBryan Venteicher 				ifp->if_capenable ^= IFCAP_LRO;
32353c5dfe89SBryan Venteicher 			if (mask & IFCAP_VLAN_HWTAGGING)
32363c5dfe89SBryan Venteicher 				ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
3237e3c97c2cSBryan Venteicher 			if (mask & IFCAP_VLAN_HWFILTER)
3238e3c97c2cSBryan Venteicher 				ifp->if_capenable ^= IFCAP_VLAN_HWFILTER;
3239e3c97c2cSBryan Venteicher 		} else
3240e3c97c2cSBryan Venteicher 			reinit = 0;
3241e3c97c2cSBryan Venteicher 
3242e3c97c2cSBryan Venteicher 		if (mask & IFCAP_VLAN_HWTSO)
3243e3c97c2cSBryan Venteicher 			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
3244e3c97c2cSBryan Venteicher 
3245e3c97c2cSBryan Venteicher 		if (reinit && (ifp->if_drv_flags & IFF_DRV_RUNNING)) {
3246e3c97c2cSBryan Venteicher 			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
3247e3c97c2cSBryan Venteicher 			vmxnet3_init_locked(sc);
3248e3c97c2cSBryan Venteicher 		}
3249e3c97c2cSBryan Venteicher 
3250e3c97c2cSBryan Venteicher 		VMXNET3_CORE_UNLOCK(sc);
3251e3c97c2cSBryan Venteicher 		VLAN_CAPABILITIES(ifp);
3252e3c97c2cSBryan Venteicher 		break;
3253e3c97c2cSBryan Venteicher 
3254e3c97c2cSBryan Venteicher 	default:
3255e3c97c2cSBryan Venteicher 		error = ether_ioctl(ifp, cmd, data);
3256e3c97c2cSBryan Venteicher 		break;
3257e3c97c2cSBryan Venteicher 	}
3258e3c97c2cSBryan Venteicher 
3259e3c97c2cSBryan Venteicher 	VMXNET3_CORE_LOCK_ASSERT_NOTOWNED(sc);
3260e3c97c2cSBryan Venteicher 
3261e3c97c2cSBryan Venteicher 	return (error);
3262e3c97c2cSBryan Venteicher }
3263e3c97c2cSBryan Venteicher 
3264*e557c1ddSBryan Venteicher #ifndef VMXNET3_LEGACY_TX
3265*e557c1ddSBryan Venteicher static void
3266*e557c1ddSBryan Venteicher vmxnet3_qflush(struct ifnet *ifp)
3267*e557c1ddSBryan Venteicher {
3268*e557c1ddSBryan Venteicher 	struct vmxnet3_softc *sc;
3269*e557c1ddSBryan Venteicher 	struct vmxnet3_txqueue *txq;
3270*e557c1ddSBryan Venteicher 	struct mbuf *m;
3271*e557c1ddSBryan Venteicher 	int i;
3272*e557c1ddSBryan Venteicher 
3273*e557c1ddSBryan Venteicher 	sc = ifp->if_softc;
3274*e557c1ddSBryan Venteicher 
3275*e557c1ddSBryan Venteicher 	for (i = 0; i < sc->vmx_ntxqueues; i++) {
3276*e557c1ddSBryan Venteicher 		txq = &sc->vmx_txq[i];
3277*e557c1ddSBryan Venteicher 
3278*e557c1ddSBryan Venteicher 		VMXNET3_TXQ_LOCK(txq);
3279*e557c1ddSBryan Venteicher 		while ((m = buf_ring_dequeue_sc(txq->vxtxq_br)) != NULL)
3280*e557c1ddSBryan Venteicher 			m_freem(m);
3281*e557c1ddSBryan Venteicher 		VMXNET3_TXQ_UNLOCK(txq);
3282*e557c1ddSBryan Venteicher 	}
3283*e557c1ddSBryan Venteicher 
3284*e557c1ddSBryan Venteicher 	if_qflush(ifp);
3285*e557c1ddSBryan Venteicher }
3286*e557c1ddSBryan Venteicher #endif
3287*e557c1ddSBryan Venteicher 
3288e3c97c2cSBryan Venteicher static int
3289e3c97c2cSBryan Venteicher vmxnet3_watchdog(struct vmxnet3_txqueue *txq)
3290e3c97c2cSBryan Venteicher {
3291e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
3292e3c97c2cSBryan Venteicher 
3293e3c97c2cSBryan Venteicher 	sc = txq->vxtxq_sc;
3294e3c97c2cSBryan Venteicher 
3295e3c97c2cSBryan Venteicher 	VMXNET3_TXQ_LOCK(txq);
3296e3c97c2cSBryan Venteicher 	if (txq->vxtxq_watchdog == 0 || --txq->vxtxq_watchdog) {
3297e3c97c2cSBryan Venteicher 		VMXNET3_TXQ_UNLOCK(txq);
3298e3c97c2cSBryan Venteicher 		return (0);
3299e3c97c2cSBryan Venteicher 	}
3300e3c97c2cSBryan Venteicher 	VMXNET3_TXQ_UNLOCK(txq);
3301e3c97c2cSBryan Venteicher 
3302e3c97c2cSBryan Venteicher 	if_printf(sc->vmx_ifp, "watchdog timeout on queue %d\n",
3303e3c97c2cSBryan Venteicher 	    txq->vxtxq_id);
3304e3c97c2cSBryan Venteicher 	return (1);
3305e3c97c2cSBryan Venteicher }
3306e3c97c2cSBryan Venteicher 
3307e3c97c2cSBryan Venteicher static void
3308*e557c1ddSBryan Venteicher vmxnet3_refresh_host_stats(struct vmxnet3_softc *sc)
3309e3c97c2cSBryan Venteicher {
3310e3c97c2cSBryan Venteicher 
3311e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, VMXNET3_CMD_GET_STATS);
3312e3c97c2cSBryan Venteicher }
3313e3c97c2cSBryan Venteicher 
3314e3c97c2cSBryan Venteicher static void
3315*e557c1ddSBryan Venteicher vmxnet3_txq_accum_stats(struct vmxnet3_txqueue *txq,
3316*e557c1ddSBryan Venteicher     struct vmxnet3_txq_stats *accum)
3317*e557c1ddSBryan Venteicher {
3318*e557c1ddSBryan Venteicher 	struct vmxnet3_txq_stats *st;
3319*e557c1ddSBryan Venteicher 
3320*e557c1ddSBryan Venteicher 	st = &txq->vxtxq_stats;
3321*e557c1ddSBryan Venteicher 
3322*e557c1ddSBryan Venteicher 	accum->vmtxs_opackets += st->vmtxs_opackets;
3323*e557c1ddSBryan Venteicher 	accum->vmtxs_obytes += st->vmtxs_obytes;
3324*e557c1ddSBryan Venteicher 	accum->vmtxs_omcasts += st->vmtxs_omcasts;
3325*e557c1ddSBryan Venteicher 	accum->vmtxs_csum += st->vmtxs_csum;
3326*e557c1ddSBryan Venteicher 	accum->vmtxs_tso += st->vmtxs_tso;
3327*e557c1ddSBryan Venteicher 	accum->vmtxs_full += st->vmtxs_full;
3328*e557c1ddSBryan Venteicher 	accum->vmtxs_offload_failed += st->vmtxs_offload_failed;
3329*e557c1ddSBryan Venteicher }
3330*e557c1ddSBryan Venteicher 
3331*e557c1ddSBryan Venteicher static void
3332*e557c1ddSBryan Venteicher vmxnet3_rxq_accum_stats(struct vmxnet3_rxqueue *rxq,
3333*e557c1ddSBryan Venteicher     struct vmxnet3_rxq_stats *accum)
3334*e557c1ddSBryan Venteicher {
3335*e557c1ddSBryan Venteicher 	struct vmxnet3_rxq_stats *st;
3336*e557c1ddSBryan Venteicher 
3337*e557c1ddSBryan Venteicher 	st = &rxq->vxrxq_stats;
3338*e557c1ddSBryan Venteicher 
3339*e557c1ddSBryan Venteicher 	accum->vmrxs_ipackets += st->vmrxs_ipackets;
3340*e557c1ddSBryan Venteicher 	accum->vmrxs_ibytes += st->vmrxs_ibytes;
3341*e557c1ddSBryan Venteicher 	accum->vmrxs_iqdrops += st->vmrxs_iqdrops;
3342*e557c1ddSBryan Venteicher 	accum->vmrxs_ierrors += st->vmrxs_ierrors;
3343*e557c1ddSBryan Venteicher }
3344*e557c1ddSBryan Venteicher 
3345*e557c1ddSBryan Venteicher static void
3346*e557c1ddSBryan Venteicher vmxnet3_accumulate_stats(struct vmxnet3_softc *sc)
3347*e557c1ddSBryan Venteicher {
3348*e557c1ddSBryan Venteicher 	struct ifnet *ifp;
3349*e557c1ddSBryan Venteicher 	struct vmxnet3_statistics *st;
3350*e557c1ddSBryan Venteicher 	struct vmxnet3_txq_stats txaccum;
3351*e557c1ddSBryan Venteicher 	struct vmxnet3_rxq_stats rxaccum;
3352*e557c1ddSBryan Venteicher 	int i;
3353*e557c1ddSBryan Venteicher 
3354*e557c1ddSBryan Venteicher 	ifp = sc->vmx_ifp;
3355*e557c1ddSBryan Venteicher 	st = &sc->vmx_stats;
3356*e557c1ddSBryan Venteicher 
3357*e557c1ddSBryan Venteicher 	bzero(&txaccum, sizeof(struct vmxnet3_txq_stats));
3358*e557c1ddSBryan Venteicher 	bzero(&rxaccum, sizeof(struct vmxnet3_rxq_stats));
3359*e557c1ddSBryan Venteicher 
3360*e557c1ddSBryan Venteicher 	for (i = 0; i < sc->vmx_ntxqueues; i++)
3361*e557c1ddSBryan Venteicher 		vmxnet3_txq_accum_stats(&sc->vmx_txq[i], &txaccum);
3362*e557c1ddSBryan Venteicher 	for (i = 0; i < sc->vmx_nrxqueues; i++)
3363*e557c1ddSBryan Venteicher 		vmxnet3_rxq_accum_stats(&sc->vmx_rxq[i], &rxaccum);
3364*e557c1ddSBryan Venteicher 
3365*e557c1ddSBryan Venteicher 	/*
3366*e557c1ddSBryan Venteicher 	 * With the exception of if_ierrors, these ifnet statistics are
3367*e557c1ddSBryan Venteicher 	 * only updated in the driver, so just set them to our accumulated
3368*e557c1ddSBryan Venteicher 	 * values. if_ierrors is updated in ether_input() for malformed
3369*e557c1ddSBryan Venteicher 	 * frames that we should have already discarded.
3370*e557c1ddSBryan Venteicher 	 */
3371*e557c1ddSBryan Venteicher 	ifp->if_ipackets = rxaccum.vmrxs_ipackets;
3372*e557c1ddSBryan Venteicher 	ifp->if_iqdrops = rxaccum.vmrxs_iqdrops;
3373*e557c1ddSBryan Venteicher 	ifp->if_ierrors = rxaccum.vmrxs_ierrors;
3374*e557c1ddSBryan Venteicher 	ifp->if_opackets = txaccum.vmtxs_opackets;
3375*e557c1ddSBryan Venteicher #ifndef VMXNET3_LEGACY_TX
3376*e557c1ddSBryan Venteicher 	ifp->if_obytes = txaccum.vmtxs_obytes;
3377*e557c1ddSBryan Venteicher 	ifp->if_omcasts = txaccum.vmtxs_omcasts;
3378*e557c1ddSBryan Venteicher #endif
3379*e557c1ddSBryan Venteicher }
3380*e557c1ddSBryan Venteicher 
3381*e557c1ddSBryan Venteicher static void
3382e3c97c2cSBryan Venteicher vmxnet3_tick(void *xsc)
3383e3c97c2cSBryan Venteicher {
3384e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
3385e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
3386e3c97c2cSBryan Venteicher 	int i, timedout;
3387e3c97c2cSBryan Venteicher 
3388e3c97c2cSBryan Venteicher 	sc = xsc;
3389e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
3390e3c97c2cSBryan Venteicher 	timedout = 0;
3391e3c97c2cSBryan Venteicher 
3392e3c97c2cSBryan Venteicher 	VMXNET3_CORE_LOCK_ASSERT(sc);
3393*e557c1ddSBryan Venteicher 
3394*e557c1ddSBryan Venteicher 	vmxnet3_accumulate_stats(sc);
3395*e557c1ddSBryan Venteicher 	vmxnet3_refresh_host_stats(sc);
3396e3c97c2cSBryan Venteicher 
3397e3c97c2cSBryan Venteicher 	for (i = 0; i < sc->vmx_ntxqueues; i++)
3398e3c97c2cSBryan Venteicher 		timedout |= vmxnet3_watchdog(&sc->vmx_txq[i]);
3399e3c97c2cSBryan Venteicher 
3400e3c97c2cSBryan Venteicher 	if (timedout != 0) {
3401e3c97c2cSBryan Venteicher 		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
3402e3c97c2cSBryan Venteicher 		vmxnet3_init_locked(sc);
3403e3c97c2cSBryan Venteicher 	} else
3404e3c97c2cSBryan Venteicher 		callout_reset(&sc->vmx_tick, hz, vmxnet3_tick, sc);
3405e3c97c2cSBryan Venteicher }
3406e3c97c2cSBryan Venteicher 
3407e3c97c2cSBryan Venteicher static int
3408e3c97c2cSBryan Venteicher vmxnet3_link_is_up(struct vmxnet3_softc *sc)
3409e3c97c2cSBryan Venteicher {
3410e3c97c2cSBryan Venteicher 	uint32_t status;
3411e3c97c2cSBryan Venteicher 
3412e3c97c2cSBryan Venteicher 	/* Also update the link speed while here. */
3413e3c97c2cSBryan Venteicher 	status = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_LINK);
3414e3c97c2cSBryan Venteicher 	sc->vmx_link_speed = status >> 16;
3415e3c97c2cSBryan Venteicher 	return !!(status & 0x1);
3416e3c97c2cSBryan Venteicher }
3417e3c97c2cSBryan Venteicher 
3418e3c97c2cSBryan Venteicher static void
3419e3c97c2cSBryan Venteicher vmxnet3_link_status(struct vmxnet3_softc *sc)
3420e3c97c2cSBryan Venteicher {
3421e3c97c2cSBryan Venteicher 	struct ifnet *ifp;
3422e3c97c2cSBryan Venteicher 	int link;
3423e3c97c2cSBryan Venteicher 
3424e3c97c2cSBryan Venteicher 	ifp = sc->vmx_ifp;
3425e3c97c2cSBryan Venteicher 	link = vmxnet3_link_is_up(sc);
3426e3c97c2cSBryan Venteicher 
3427e3c97c2cSBryan Venteicher 	if (link != 0 && sc->vmx_link_active == 0) {
3428e3c97c2cSBryan Venteicher 		sc->vmx_link_active = 1;
3429e3c97c2cSBryan Venteicher 		if_link_state_change(ifp, LINK_STATE_UP);
3430e3c97c2cSBryan Venteicher 	} else if (link == 0 && sc->vmx_link_active != 0) {
3431e3c97c2cSBryan Venteicher 		sc->vmx_link_active = 0;
3432e3c97c2cSBryan Venteicher 		if_link_state_change(ifp, LINK_STATE_DOWN);
3433e3c97c2cSBryan Venteicher 	}
3434e3c97c2cSBryan Venteicher }
3435e3c97c2cSBryan Venteicher 
3436e3c97c2cSBryan Venteicher static void
3437e3c97c2cSBryan Venteicher vmxnet3_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
3438e3c97c2cSBryan Venteicher {
3439e3c97c2cSBryan Venteicher 	struct vmxnet3_softc *sc;
3440e3c97c2cSBryan Venteicher 
3441e3c97c2cSBryan Venteicher 	sc = ifp->if_softc;
3442e3c97c2cSBryan Venteicher 
3443e3c97c2cSBryan Venteicher 	ifmr->ifm_active = IFM_ETHER | IFM_AUTO;
3444e3c97c2cSBryan Venteicher 	ifmr->ifm_status = IFM_AVALID;
3445e3c97c2cSBryan Venteicher 
3446e3c97c2cSBryan Venteicher 	VMXNET3_CORE_LOCK(sc);
3447e3c97c2cSBryan Venteicher 	if (vmxnet3_link_is_up(sc) != 0)
3448e3c97c2cSBryan Venteicher 		ifmr->ifm_status |= IFM_ACTIVE;
3449e3c97c2cSBryan Venteicher 	else
3450e3c97c2cSBryan Venteicher 		ifmr->ifm_status |= IFM_NONE;
3451e3c97c2cSBryan Venteicher 	VMXNET3_CORE_UNLOCK(sc);
3452e3c97c2cSBryan Venteicher }
3453e3c97c2cSBryan Venteicher 
3454e3c97c2cSBryan Venteicher static int
3455e3c97c2cSBryan Venteicher vmxnet3_media_change(struct ifnet *ifp)
3456e3c97c2cSBryan Venteicher {
3457e3c97c2cSBryan Venteicher 
3458e3c97c2cSBryan Venteicher 	/* Ignore. */
3459e3c97c2cSBryan Venteicher 	return (0);
3460e3c97c2cSBryan Venteicher }
3461e3c97c2cSBryan Venteicher 
3462e3c97c2cSBryan Venteicher static void
3463e3c97c2cSBryan Venteicher vmxnet3_set_lladdr(struct vmxnet3_softc *sc)
3464e3c97c2cSBryan Venteicher {
3465e3c97c2cSBryan Venteicher 	uint32_t ml, mh;
3466e3c97c2cSBryan Venteicher 
3467e3c97c2cSBryan Venteicher 	ml  = sc->vmx_lladdr[0];
3468e3c97c2cSBryan Venteicher 	ml |= sc->vmx_lladdr[1] << 8;
3469e3c97c2cSBryan Venteicher 	ml |= sc->vmx_lladdr[2] << 16;
3470e3c97c2cSBryan Venteicher 	ml |= sc->vmx_lladdr[3] << 24;
3471e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_MACL, ml);
3472e3c97c2cSBryan Venteicher 
3473e3c97c2cSBryan Venteicher 	mh  = sc->vmx_lladdr[4];
3474e3c97c2cSBryan Venteicher 	mh |= sc->vmx_lladdr[5] << 8;
3475e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_MACH, mh);
3476e3c97c2cSBryan Venteicher }
3477e3c97c2cSBryan Venteicher 
3478e3c97c2cSBryan Venteicher static void
3479e3c97c2cSBryan Venteicher vmxnet3_get_lladdr(struct vmxnet3_softc *sc)
3480e3c97c2cSBryan Venteicher {
3481e3c97c2cSBryan Venteicher 	uint32_t ml, mh;
3482e3c97c2cSBryan Venteicher 
3483e3c97c2cSBryan Venteicher 	ml = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_MACL);
3484e3c97c2cSBryan Venteicher 	mh = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_MACH);
3485e3c97c2cSBryan Venteicher 
3486e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[0] = ml;
3487e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[1] = ml >> 8;
3488e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[2] = ml >> 16;
3489e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[3] = ml >> 24;
3490e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[4] = mh;
3491e3c97c2cSBryan Venteicher 	sc->vmx_lladdr[5] = mh >> 8;
3492e3c97c2cSBryan Venteicher }
3493e3c97c2cSBryan Venteicher 
3494e3c97c2cSBryan Venteicher static void
3495e3c97c2cSBryan Venteicher vmxnet3_setup_txq_sysctl(struct vmxnet3_txqueue *txq,
3496e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
3497e3c97c2cSBryan Venteicher {
3498e3c97c2cSBryan Venteicher 	struct sysctl_oid *node, *txsnode;
3499e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *list, *txslist;
3500e3c97c2cSBryan Venteicher 	struct vmxnet3_txq_stats *stats;
3501e3c97c2cSBryan Venteicher 	struct UPT1_TxStats *txstats;
3502e3c97c2cSBryan Venteicher 	char namebuf[16];
3503e3c97c2cSBryan Venteicher 
3504e3c97c2cSBryan Venteicher 	stats = &txq->vxtxq_stats;
3505e3c97c2cSBryan Venteicher 	txstats = &txq->vxtxq_ts->stats;
3506e3c97c2cSBryan Venteicher 
3507e3c97c2cSBryan Venteicher 	snprintf(namebuf, sizeof(namebuf), "txq%d", txq->vxtxq_id);
3508e3c97c2cSBryan Venteicher 	node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, CTLFLAG_RD,
3509e3c97c2cSBryan Venteicher 	    NULL, "Transmit Queue");
3510e3c97c2cSBryan Venteicher 	txq->vxtxq_sysctl = list = SYSCTL_CHILDREN(node);
3511e3c97c2cSBryan Venteicher 
3512*e557c1ddSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "opackets", CTLFLAG_RD,
3513*e557c1ddSBryan Venteicher 	    &stats->vmtxs_opackets, "Transmit packets");
3514*e557c1ddSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "obytes", CTLFLAG_RD,
3515*e557c1ddSBryan Venteicher 	    &stats->vmtxs_obytes, "Transmit bytes");
3516*e557c1ddSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "omcasts", CTLFLAG_RD,
3517*e557c1ddSBryan Venteicher 	    &stats->vmtxs_omcasts, "Transmit multicasts");
3518*e557c1ddSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "csum", CTLFLAG_RD,
3519*e557c1ddSBryan Venteicher 	    &stats->vmtxs_csum, "Transmit checksum offloaded");
3520*e557c1ddSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "tso", CTLFLAG_RD,
3521*e557c1ddSBryan Venteicher 	    &stats->vmtxs_tso, "Transmit TCP segmentation offloaded");
3522e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "ringfull", CTLFLAG_RD,
3523*e557c1ddSBryan Venteicher 	    &stats->vmtxs_full, "Transmit ring full");
3524e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "offload_failed", CTLFLAG_RD,
3525*e557c1ddSBryan Venteicher 	    &stats->vmtxs_offload_failed, "Transmit checksum offload failed");
3526e3c97c2cSBryan Venteicher 
3527e3c97c2cSBryan Venteicher 	/*
3528e3c97c2cSBryan Venteicher 	 * Add statistics reported by the host. These are updated once
3529e3c97c2cSBryan Venteicher 	 * per second.
3530e3c97c2cSBryan Venteicher 	 */
3531e3c97c2cSBryan Venteicher 	txsnode = SYSCTL_ADD_NODE(ctx, list, OID_AUTO, "hstats", CTLFLAG_RD,
3532e3c97c2cSBryan Venteicher 	    NULL, "Host Statistics");
3533e3c97c2cSBryan Venteicher 	txslist = SYSCTL_CHILDREN(txsnode);
3534e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "tso_packets", CTLFLAG_RD,
3535e3c97c2cSBryan Venteicher 	    &txstats->TSO_packets, "TSO packets");
3536e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "tso_bytes", CTLFLAG_RD,
3537e3c97c2cSBryan Venteicher 	    &txstats->TSO_bytes, "TSO bytes");
3538e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "ucast_packets", CTLFLAG_RD,
3539e3c97c2cSBryan Venteicher 	    &txstats->ucast_packets, "Unicast packets");
3540e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "unicast_bytes", CTLFLAG_RD,
3541e3c97c2cSBryan Venteicher 	    &txstats->ucast_bytes, "Unicast bytes");
3542e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "mcast_packets", CTLFLAG_RD,
3543e3c97c2cSBryan Venteicher 	    &txstats->mcast_packets, "Multicast packets");
3544e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "mcast_bytes", CTLFLAG_RD,
3545e3c97c2cSBryan Venteicher 	    &txstats->mcast_bytes, "Multicast bytes");
3546e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "error", CTLFLAG_RD,
3547e3c97c2cSBryan Venteicher 	    &txstats->error, "Errors");
3548e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, txslist, OID_AUTO, "discard", CTLFLAG_RD,
3549e3c97c2cSBryan Venteicher 	    &txstats->discard, "Discards");
3550e3c97c2cSBryan Venteicher }
3551e3c97c2cSBryan Venteicher 
3552e3c97c2cSBryan Venteicher static void
3553e3c97c2cSBryan Venteicher vmxnet3_setup_rxq_sysctl(struct vmxnet3_rxqueue *rxq,
3554e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
3555e3c97c2cSBryan Venteicher {
3556e3c97c2cSBryan Venteicher 	struct sysctl_oid *node, *rxsnode;
3557e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *list, *rxslist;
3558e3c97c2cSBryan Venteicher 	struct vmxnet3_rxq_stats *stats;
3559e3c97c2cSBryan Venteicher 	struct UPT1_RxStats *rxstats;
3560e3c97c2cSBryan Venteicher 	char namebuf[16];
3561e3c97c2cSBryan Venteicher 
3562e3c97c2cSBryan Venteicher 	stats = &rxq->vxrxq_stats;
3563e3c97c2cSBryan Venteicher 	rxstats = &rxq->vxrxq_rs->stats;
3564e3c97c2cSBryan Venteicher 
3565e3c97c2cSBryan Venteicher 	snprintf(namebuf, sizeof(namebuf), "rxq%d", rxq->vxrxq_id);
3566e3c97c2cSBryan Venteicher 	node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, CTLFLAG_RD,
3567e3c97c2cSBryan Venteicher 	    NULL, "Receive Queue");
3568e3c97c2cSBryan Venteicher 	rxq->vxrxq_sysctl = list = SYSCTL_CHILDREN(node);
3569e3c97c2cSBryan Venteicher 
3570*e557c1ddSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "ipackets", CTLFLAG_RD,
3571*e557c1ddSBryan Venteicher 	    &stats->vmrxs_ipackets, "Receive packets");
3572*e557c1ddSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "ibytes", CTLFLAG_RD,
3573*e557c1ddSBryan Venteicher 	    &stats->vmrxs_ibytes, "Receive bytes");
3574*e557c1ddSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "iqdrops", CTLFLAG_RD,
3575*e557c1ddSBryan Venteicher 	    &stats->vmrxs_iqdrops, "Receive drops");
3576*e557c1ddSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, list, OID_AUTO, "ierrors", CTLFLAG_RD,
3577*e557c1ddSBryan Venteicher 	    &stats->vmrxs_ierrors, "Receive errors");
3578*e557c1ddSBryan Venteicher 
3579e3c97c2cSBryan Venteicher 	/*
3580e3c97c2cSBryan Venteicher 	 * Add statistics reported by the host. These are updated once
3581e3c97c2cSBryan Venteicher 	 * per second.
3582e3c97c2cSBryan Venteicher 	 */
3583e3c97c2cSBryan Venteicher 	rxsnode = SYSCTL_ADD_NODE(ctx, list, OID_AUTO, "hstats", CTLFLAG_RD,
3584e3c97c2cSBryan Venteicher 	    NULL, "Host Statistics");
3585e3c97c2cSBryan Venteicher 	rxslist = SYSCTL_CHILDREN(rxsnode);
3586e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "lro_packets", CTLFLAG_RD,
3587e3c97c2cSBryan Venteicher 	    &rxstats->LRO_packets, "LRO packets");
3588e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "lro_bytes", CTLFLAG_RD,
3589e3c97c2cSBryan Venteicher 	    &rxstats->LRO_bytes, "LRO bytes");
3590e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "ucast_packets", CTLFLAG_RD,
3591e3c97c2cSBryan Venteicher 	    &rxstats->ucast_packets, "Unicast packets");
3592e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "unicast_bytes", CTLFLAG_RD,
3593e3c97c2cSBryan Venteicher 	    &rxstats->ucast_bytes, "Unicast bytes");
3594e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "mcast_packets", CTLFLAG_RD,
3595e3c97c2cSBryan Venteicher 	    &rxstats->mcast_packets, "Multicast packets");
3596e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "mcast_bytes", CTLFLAG_RD,
3597e3c97c2cSBryan Venteicher 	    &rxstats->mcast_bytes, "Multicast bytes");
3598e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "bcast_packets", CTLFLAG_RD,
3599e3c97c2cSBryan Venteicher 	    &rxstats->bcast_packets, "Broadcast packets");
3600e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "bcast_bytes", CTLFLAG_RD,
3601e3c97c2cSBryan Venteicher 	    &rxstats->bcast_bytes, "Broadcast bytes");
3602e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "nobuffer", CTLFLAG_RD,
3603e3c97c2cSBryan Venteicher 	    &rxstats->nobuffer, "No buffer");
3604e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UQUAD(ctx, rxslist, OID_AUTO, "error", CTLFLAG_RD,
3605e3c97c2cSBryan Venteicher 	    &rxstats->error, "Errors");
3606e3c97c2cSBryan Venteicher }
3607e3c97c2cSBryan Venteicher 
3608e3c97c2cSBryan Venteicher static void
3609e3c97c2cSBryan Venteicher vmxnet3_setup_debug_sysctl(struct vmxnet3_softc *sc,
3610e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
3611e3c97c2cSBryan Venteicher {
3612e3c97c2cSBryan Venteicher 	struct sysctl_oid *node;
3613e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *list;
3614e3c97c2cSBryan Venteicher 	int i;
3615e3c97c2cSBryan Venteicher 
3616e3c97c2cSBryan Venteicher 	for (i = 0; i < sc->vmx_ntxqueues; i++) {
3617e3c97c2cSBryan Venteicher 		struct vmxnet3_txqueue *txq = &sc->vmx_txq[i];
3618e3c97c2cSBryan Venteicher 
3619e3c97c2cSBryan Venteicher 		node = SYSCTL_ADD_NODE(ctx, txq->vxtxq_sysctl, OID_AUTO,
3620e3c97c2cSBryan Venteicher 		    "debug", CTLFLAG_RD, NULL, "");
3621e3c97c2cSBryan Venteicher 		list = SYSCTL_CHILDREN(node);
3622e3c97c2cSBryan Venteicher 
3623e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd_head", CTLFLAG_RD,
3624e3c97c2cSBryan Venteicher 		    &txq->vxtxq_cmd_ring.vxtxr_head, 0, "");
3625e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd_next", CTLFLAG_RD,
3626e3c97c2cSBryan Venteicher 		    &txq->vxtxq_cmd_ring.vxtxr_next, 0, "");
3627e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd_ndesc", CTLFLAG_RD,
3628e3c97c2cSBryan Venteicher 		    &txq->vxtxq_cmd_ring.vxtxr_ndesc, 0, "");
3629e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd_gen", CTLFLAG_RD,
3630e3c97c2cSBryan Venteicher 		    &txq->vxtxq_cmd_ring.vxtxr_gen, 0, "");
3631e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_next", CTLFLAG_RD,
3632e3c97c2cSBryan Venteicher 		    &txq->vxtxq_comp_ring.vxcr_next, 0, "");
3633e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_ndesc", CTLFLAG_RD,
3634e3c97c2cSBryan Venteicher 		    &txq->vxtxq_comp_ring.vxcr_ndesc, 0,"");
3635e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "comp_gen", CTLFLAG_RD,
3636e3c97c2cSBryan Venteicher 		    &txq->vxtxq_comp_ring.vxcr_gen, 0, "");
3637e3c97c2cSBryan Venteicher 	}
3638e3c97c2cSBryan Venteicher 
3639e3c97c2cSBryan Venteicher 	for (i = 0; i < sc->vmx_nrxqueues; i++) {
3640e3c97c2cSBryan Venteicher 		struct vmxnet3_rxqueue *rxq = &sc->vmx_rxq[i];
3641e3c97c2cSBryan Venteicher 
3642e3c97c2cSBryan Venteicher 		node = SYSCTL_ADD_NODE(ctx, rxq->vxrxq_sysctl, OID_AUTO,
3643e3c97c2cSBryan Venteicher 		    "debug", CTLFLAG_RD, NULL, "");
3644e3c97c2cSBryan Venteicher 		list = SYSCTL_CHILDREN(node);
3645e3c97c2cSBryan Venteicher 
3646e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd0_fill", CTLFLAG_RD,
3647e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[0].vxrxr_fill, 0, "");
3648e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd0_ndesc", CTLFLAG_RD,
3649e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[0].vxrxr_ndesc, 0, "");
3650e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd0_gen", CTLFLAG_RD,
3651e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[0].vxrxr_gen, 0, "");
3652e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd1_fill", CTLFLAG_RD,
3653e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[1].vxrxr_fill, 0, "");
3654e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "cmd1_ndesc", CTLFLAG_RD,
3655e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[1].vxrxr_ndesc, 0, "");
3656e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "cmd1_gen", CTLFLAG_RD,
3657e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_cmd_ring[1].vxrxr_gen, 0, "");
3658e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_next", CTLFLAG_RD,
3659e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_comp_ring.vxcr_next, 0, "");
3660e3c97c2cSBryan Venteicher 		SYSCTL_ADD_UINT(ctx, list, OID_AUTO, "comp_ndesc", CTLFLAG_RD,
3661e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_comp_ring.vxcr_ndesc, 0,"");
3662e3c97c2cSBryan Venteicher 		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "comp_gen", CTLFLAG_RD,
3663e3c97c2cSBryan Venteicher 		    &rxq->vxrxq_comp_ring.vxcr_gen, 0, "");
3664e3c97c2cSBryan Venteicher 	}
3665e3c97c2cSBryan Venteicher }
3666e3c97c2cSBryan Venteicher 
3667e3c97c2cSBryan Venteicher static void
3668e3c97c2cSBryan Venteicher vmxnet3_setup_queue_sysctl(struct vmxnet3_softc *sc,
3669e3c97c2cSBryan Venteicher     struct sysctl_ctx_list *ctx, struct sysctl_oid_list *child)
3670e3c97c2cSBryan Venteicher {
3671e3c97c2cSBryan Venteicher 	int i;
3672e3c97c2cSBryan Venteicher 
3673e3c97c2cSBryan Venteicher 	for (i = 0; i < sc->vmx_ntxqueues; i++)
3674e3c97c2cSBryan Venteicher 		vmxnet3_setup_txq_sysctl(&sc->vmx_txq[i], ctx, child);
3675e3c97c2cSBryan Venteicher 	for (i = 0; i < sc->vmx_nrxqueues; i++)
3676e3c97c2cSBryan Venteicher 		vmxnet3_setup_rxq_sysctl(&sc->vmx_rxq[i], ctx, child);
3677e3c97c2cSBryan Venteicher 
3678e3c97c2cSBryan Venteicher 	vmxnet3_setup_debug_sysctl(sc, ctx, child);
3679e3c97c2cSBryan Venteicher }
3680e3c97c2cSBryan Venteicher 
3681e3c97c2cSBryan Venteicher static void
3682e3c97c2cSBryan Venteicher vmxnet3_setup_sysctl(struct vmxnet3_softc *sc)
3683e3c97c2cSBryan Venteicher {
3684e3c97c2cSBryan Venteicher 	device_t dev;
3685e3c97c2cSBryan Venteicher 	struct vmxnet3_statistics *stats;
3686e3c97c2cSBryan Venteicher 	struct sysctl_ctx_list *ctx;
3687e3c97c2cSBryan Venteicher 	struct sysctl_oid *tree;
3688e3c97c2cSBryan Venteicher 	struct sysctl_oid_list *child;
3689e3c97c2cSBryan Venteicher 
3690e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
3691e3c97c2cSBryan Venteicher 	ctx = device_get_sysctl_ctx(dev);
3692e3c97c2cSBryan Venteicher 	tree = device_get_sysctl_tree(dev);
3693e3c97c2cSBryan Venteicher 	child = SYSCTL_CHILDREN(tree);
3694e3c97c2cSBryan Venteicher 
3695*e557c1ddSBryan Venteicher 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "max_ntxqueues", CTLFLAG_RD,
3696*e557c1ddSBryan Venteicher 	    &sc->vmx_max_ntxqueues, 0, "Maximum number of Tx queues");
3697*e557c1ddSBryan Venteicher 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "max_nrxqueues", CTLFLAG_RD,
3698*e557c1ddSBryan Venteicher 	    &sc->vmx_max_nrxqueues, 0, "Maximum number of Rx queues");
3699e3c97c2cSBryan Venteicher 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "ntxqueues", CTLFLAG_RD,
3700e3c97c2cSBryan Venteicher 	    &sc->vmx_ntxqueues, 0, "Number of Tx queues");
3701e3c97c2cSBryan Venteicher 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "nrxqueues", CTLFLAG_RD,
3702e3c97c2cSBryan Venteicher 	    &sc->vmx_nrxqueues, 0, "Number of Rx queues");
3703e3c97c2cSBryan Venteicher 
3704e3c97c2cSBryan Venteicher 	stats = &sc->vmx_stats;
3705*e557c1ddSBryan Venteicher 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "defragged", CTLFLAG_RD,
3706*e557c1ddSBryan Venteicher 	    &stats->vmst_defragged, 0, "Tx mbuf chains defragged");
3707*e557c1ddSBryan Venteicher 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "defrag_failed", CTLFLAG_RD,
3708*e557c1ddSBryan Venteicher 	    &stats->vmst_defrag_failed, 0,
3709*e557c1ddSBryan Venteicher 	    "Tx mbuf dropped because defrag failed");
3710e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "mgetcl_failed", CTLFLAG_RD,
3711e3c97c2cSBryan Venteicher 	    &stats->vmst_mgetcl_failed, 0, "mbuf cluster allocation failed");
3712e3c97c2cSBryan Venteicher 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "mbuf_load_failed", CTLFLAG_RD,
3713e3c97c2cSBryan Venteicher 	    &stats->vmst_mbuf_load_failed, 0, "mbuf load segments failed");
3714e3c97c2cSBryan Venteicher 
3715e3c97c2cSBryan Venteicher 	vmxnet3_setup_queue_sysctl(sc, ctx, child);
3716e3c97c2cSBryan Venteicher }
3717e3c97c2cSBryan Venteicher 
3718e3c97c2cSBryan Venteicher static void
3719e3c97c2cSBryan Venteicher vmxnet3_write_bar0(struct vmxnet3_softc *sc, bus_size_t r, uint32_t v)
3720e3c97c2cSBryan Venteicher {
3721e3c97c2cSBryan Venteicher 
3722e3c97c2cSBryan Venteicher 	bus_space_write_4(sc->vmx_iot0, sc->vmx_ioh0, r, v);
3723e3c97c2cSBryan Venteicher }
3724e3c97c2cSBryan Venteicher 
3725e3c97c2cSBryan Venteicher static uint32_t
3726e3c97c2cSBryan Venteicher vmxnet3_read_bar1(struct vmxnet3_softc *sc, bus_size_t r)
3727e3c97c2cSBryan Venteicher {
3728e3c97c2cSBryan Venteicher 
3729e3c97c2cSBryan Venteicher 	return (bus_space_read_4(sc->vmx_iot1, sc->vmx_ioh1, r));
3730e3c97c2cSBryan Venteicher }
3731e3c97c2cSBryan Venteicher 
3732e3c97c2cSBryan Venteicher static void
3733e3c97c2cSBryan Venteicher vmxnet3_write_bar1(struct vmxnet3_softc *sc, bus_size_t r, uint32_t v)
3734e3c97c2cSBryan Venteicher {
3735e3c97c2cSBryan Venteicher 
3736e3c97c2cSBryan Venteicher 	bus_space_write_4(sc->vmx_iot1, sc->vmx_ioh1, r, v);
3737e3c97c2cSBryan Venteicher }
3738e3c97c2cSBryan Venteicher 
3739e3c97c2cSBryan Venteicher static void
3740e3c97c2cSBryan Venteicher vmxnet3_write_cmd(struct vmxnet3_softc *sc, uint32_t cmd)
3741e3c97c2cSBryan Venteicher {
3742e3c97c2cSBryan Venteicher 
3743e3c97c2cSBryan Venteicher 	vmxnet3_write_bar1(sc, VMXNET3_BAR1_CMD, cmd);
3744e3c97c2cSBryan Venteicher }
3745e3c97c2cSBryan Venteicher 
3746e3c97c2cSBryan Venteicher static uint32_t
3747e3c97c2cSBryan Venteicher vmxnet3_read_cmd(struct vmxnet3_softc *sc, uint32_t cmd)
3748e3c97c2cSBryan Venteicher {
3749e3c97c2cSBryan Venteicher 
3750e3c97c2cSBryan Venteicher 	vmxnet3_write_cmd(sc, cmd);
3751e3c97c2cSBryan Venteicher 	bus_space_barrier(sc->vmx_iot1, sc->vmx_ioh1, 0, 0,
3752e3c97c2cSBryan Venteicher 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
3753e3c97c2cSBryan Venteicher 	return (vmxnet3_read_bar1(sc, VMXNET3_BAR1_CMD));
3754e3c97c2cSBryan Venteicher }
3755e3c97c2cSBryan Venteicher 
3756e3c97c2cSBryan Venteicher static void
3757e3c97c2cSBryan Venteicher vmxnet3_enable_intr(struct vmxnet3_softc *sc, int irq)
3758e3c97c2cSBryan Venteicher {
3759e3c97c2cSBryan Venteicher 
3760e3c97c2cSBryan Venteicher 	vmxnet3_write_bar0(sc, VMXNET3_BAR0_IMASK(irq), 0);
3761e3c97c2cSBryan Venteicher }
3762e3c97c2cSBryan Venteicher 
3763e3c97c2cSBryan Venteicher static void
3764e3c97c2cSBryan Venteicher vmxnet3_disable_intr(struct vmxnet3_softc *sc, int irq)
3765e3c97c2cSBryan Venteicher {
3766e3c97c2cSBryan Venteicher 
3767e3c97c2cSBryan Venteicher 	vmxnet3_write_bar0(sc, VMXNET3_BAR0_IMASK(irq), 1);
3768e3c97c2cSBryan Venteicher }
3769e3c97c2cSBryan Venteicher 
3770e3c97c2cSBryan Venteicher static void
3771e3c97c2cSBryan Venteicher vmxnet3_enable_all_intrs(struct vmxnet3_softc *sc)
3772e3c97c2cSBryan Venteicher {
3773e3c97c2cSBryan Venteicher 	int i;
3774e3c97c2cSBryan Venteicher 
3775e3c97c2cSBryan Venteicher 	sc->vmx_ds->ictrl &= ~VMXNET3_ICTRL_DISABLE_ALL;
3776e3c97c2cSBryan Venteicher 	for (i = 0; i < sc->vmx_nintrs; i++)
3777e3c97c2cSBryan Venteicher 		vmxnet3_enable_intr(sc, i);
3778e3c97c2cSBryan Venteicher }
3779e3c97c2cSBryan Venteicher 
3780e3c97c2cSBryan Venteicher static void
3781e3c97c2cSBryan Venteicher vmxnet3_disable_all_intrs(struct vmxnet3_softc *sc)
3782e3c97c2cSBryan Venteicher {
3783e3c97c2cSBryan Venteicher 	int i;
3784e3c97c2cSBryan Venteicher 
3785e3c97c2cSBryan Venteicher 	sc->vmx_ds->ictrl |= VMXNET3_ICTRL_DISABLE_ALL;
3786e3c97c2cSBryan Venteicher 	for (i = 0; i < sc->vmx_nintrs; i++)
3787e3c97c2cSBryan Venteicher 		vmxnet3_disable_intr(sc, i);
3788e3c97c2cSBryan Venteicher }
3789e3c97c2cSBryan Venteicher 
3790e3c97c2cSBryan Venteicher static void
3791e3c97c2cSBryan Venteicher vmxnet3_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
3792e3c97c2cSBryan Venteicher {
3793e3c97c2cSBryan Venteicher 	bus_addr_t *baddr = arg;
3794e3c97c2cSBryan Venteicher 
3795e3c97c2cSBryan Venteicher 	if (error == 0)
3796e3c97c2cSBryan Venteicher 		*baddr = segs->ds_addr;
3797e3c97c2cSBryan Venteicher }
3798e3c97c2cSBryan Venteicher 
3799e3c97c2cSBryan Venteicher static int
3800e3c97c2cSBryan Venteicher vmxnet3_dma_malloc(struct vmxnet3_softc *sc, bus_size_t size, bus_size_t align,
3801e3c97c2cSBryan Venteicher     struct vmxnet3_dma_alloc *dma)
3802e3c97c2cSBryan Venteicher {
3803e3c97c2cSBryan Venteicher 	device_t dev;
3804e3c97c2cSBryan Venteicher 	int error;
3805e3c97c2cSBryan Venteicher 
3806e3c97c2cSBryan Venteicher 	dev = sc->vmx_dev;
3807e3c97c2cSBryan Venteicher 	bzero(dma, sizeof(struct vmxnet3_dma_alloc));
3808e3c97c2cSBryan Venteicher 
3809e3c97c2cSBryan Venteicher 	error = bus_dma_tag_create(bus_get_dma_tag(dev),
3810e3c97c2cSBryan Venteicher 	    align, 0,		/* alignment, bounds */
3811e3c97c2cSBryan Venteicher 	    BUS_SPACE_MAXADDR,	/* lowaddr */
3812e3c97c2cSBryan Venteicher 	    BUS_SPACE_MAXADDR,	/* highaddr */
3813e3c97c2cSBryan Venteicher 	    NULL, NULL,		/* filter, filterarg */
3814e3c97c2cSBryan Venteicher 	    size,		/* maxsize */
3815e3c97c2cSBryan Venteicher 	    1,			/* nsegments */
3816e3c97c2cSBryan Venteicher 	    size,		/* maxsegsize */
3817e3c97c2cSBryan Venteicher 	    BUS_DMA_ALLOCNOW,	/* flags */
3818e3c97c2cSBryan Venteicher 	    NULL,		/* lockfunc */
3819e3c97c2cSBryan Venteicher 	    NULL,		/* lockfuncarg */
3820e3c97c2cSBryan Venteicher 	    &dma->dma_tag);
3821e3c97c2cSBryan Venteicher 	if (error) {
3822e3c97c2cSBryan Venteicher 		device_printf(dev, "bus_dma_tag_create failed: %d\n", error);
3823e3c97c2cSBryan Venteicher 		goto fail;
3824e3c97c2cSBryan Venteicher 	}
3825e3c97c2cSBryan Venteicher 
3826e3c97c2cSBryan Venteicher 	error = bus_dmamem_alloc(dma->dma_tag, (void **)&dma->dma_vaddr,
3827e3c97c2cSBryan Venteicher 	    BUS_DMA_ZERO | BUS_DMA_NOWAIT, &dma->dma_map);
3828e3c97c2cSBryan Venteicher 	if (error) {
3829e3c97c2cSBryan Venteicher 		device_printf(dev, "bus_dmamem_alloc failed: %d\n", error);
3830e3c97c2cSBryan Venteicher 		goto fail;
3831e3c97c2cSBryan Venteicher 	}
3832e3c97c2cSBryan Venteicher 
3833e3c97c2cSBryan Venteicher 	error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr,
3834e3c97c2cSBryan Venteicher 	    size, vmxnet3_dmamap_cb, &dma->dma_paddr, BUS_DMA_NOWAIT);
3835e3c97c2cSBryan Venteicher 	if (error) {
3836e3c97c2cSBryan Venteicher 		device_printf(dev, "bus_dmamap_load failed: %d\n", error);
3837e3c97c2cSBryan Venteicher 		goto fail;
3838e3c97c2cSBryan Venteicher 	}
3839e3c97c2cSBryan Venteicher 
3840e3c97c2cSBryan Venteicher 	dma->dma_size = size;
3841e3c97c2cSBryan Venteicher 
3842e3c97c2cSBryan Venteicher fail:
3843e3c97c2cSBryan Venteicher 	if (error)
3844e3c97c2cSBryan Venteicher 		vmxnet3_dma_free(sc, dma);
3845e3c97c2cSBryan Venteicher 
3846e3c97c2cSBryan Venteicher 	return (error);
3847e3c97c2cSBryan Venteicher }
3848e3c97c2cSBryan Venteicher 
3849e3c97c2cSBryan Venteicher static void
3850e3c97c2cSBryan Venteicher vmxnet3_dma_free(struct vmxnet3_softc *sc, struct vmxnet3_dma_alloc *dma)
3851e3c97c2cSBryan Venteicher {
3852e3c97c2cSBryan Venteicher 
3853e3c97c2cSBryan Venteicher 	if (dma->dma_tag != NULL) {
3854e3c97c2cSBryan Venteicher 		if (dma->dma_map != NULL) {
3855e3c97c2cSBryan Venteicher 			bus_dmamap_sync(dma->dma_tag, dma->dma_map,
3856e3c97c2cSBryan Venteicher 			    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
3857e3c97c2cSBryan Venteicher 			bus_dmamap_unload(dma->dma_tag, dma->dma_map);
3858e3c97c2cSBryan Venteicher 		}
3859e3c97c2cSBryan Venteicher 
3860e3c97c2cSBryan Venteicher 		if (dma->dma_vaddr != NULL) {
3861e3c97c2cSBryan Venteicher 			bus_dmamem_free(dma->dma_tag, dma->dma_vaddr,
3862e3c97c2cSBryan Venteicher 			    dma->dma_map);
3863e3c97c2cSBryan Venteicher 		}
3864e3c97c2cSBryan Venteicher 
3865e3c97c2cSBryan Venteicher 		bus_dma_tag_destroy(dma->dma_tag);
3866e3c97c2cSBryan Venteicher 	}
3867e3c97c2cSBryan Venteicher 	bzero(dma, sizeof(struct vmxnet3_dma_alloc));
3868e3c97c2cSBryan Venteicher }
3869e3c97c2cSBryan Venteicher 
38703c5dfe89SBryan Venteicher static int
38713c5dfe89SBryan Venteicher vmxnet3_tunable_int(struct vmxnet3_softc *sc, const char *knob, int def)
38723c5dfe89SBryan Venteicher {
38733c5dfe89SBryan Venteicher 	char path[64];
38743c5dfe89SBryan Venteicher 
38753c5dfe89SBryan Venteicher 	snprintf(path, sizeof(path),
38763c5dfe89SBryan Venteicher 	    "hw.vmx.%d.%s", device_get_unit(sc->vmx_dev), knob);
38773c5dfe89SBryan Venteicher 	TUNABLE_INT_FETCH(path, &def);
38783c5dfe89SBryan Venteicher 
38793c5dfe89SBryan Venteicher 	return (def);
38803c5dfe89SBryan Venteicher }
38813c5dfe89SBryan Venteicher 
3882e3c97c2cSBryan Venteicher /*
3883e3c97c2cSBryan Venteicher  * Since this is a purely paravirtualized device, we do not have
3884e3c97c2cSBryan Venteicher  * to worry about DMA coherency. But at times, we must make sure
3885e3c97c2cSBryan Venteicher  * both the compiler and CPU do not reorder memory operations.
3886e3c97c2cSBryan Venteicher  */
3887e3c97c2cSBryan Venteicher static inline void
3888e3c97c2cSBryan Venteicher vmxnet3_barrier(struct vmxnet3_softc *sc, vmxnet3_barrier_t type)
3889e3c97c2cSBryan Venteicher {
3890e3c97c2cSBryan Venteicher 
3891e3c97c2cSBryan Venteicher 	switch (type) {
3892e3c97c2cSBryan Venteicher 	case VMXNET3_BARRIER_RD:
3893e3c97c2cSBryan Venteicher 		rmb();
3894e3c97c2cSBryan Venteicher 		break;
3895e3c97c2cSBryan Venteicher 	case VMXNET3_BARRIER_WR:
3896e3c97c2cSBryan Venteicher 		wmb();
3897e3c97c2cSBryan Venteicher 		break;
3898e3c97c2cSBryan Venteicher 	case VMXNET3_BARRIER_RDWR:
3899e3c97c2cSBryan Venteicher 		mb();
3900e3c97c2cSBryan Venteicher 		break;
3901e3c97c2cSBryan Venteicher 	default:
3902e3c97c2cSBryan Venteicher 		panic("%s: bad barrier type %d", __func__, type);
3903e3c97c2cSBryan Venteicher 	}
3904e3c97c2cSBryan Venteicher }
3905