xref: /freebsd/sys/dev/hyperv/netvsc/if_hn.c (revision 15516c776e393944ffd59ba796a26ab001dd4c97)
1*15516c77SSepherosa Ziehau /*-
2*15516c77SSepherosa Ziehau  * Copyright (c) 2010-2012 Citrix Inc.
3*15516c77SSepherosa Ziehau  * Copyright (c) 2009-2012,2016 Microsoft Corp.
4*15516c77SSepherosa Ziehau  * Copyright (c) 2012 NetApp Inc.
5*15516c77SSepherosa Ziehau  * All rights reserved.
6*15516c77SSepherosa Ziehau  *
7*15516c77SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
8*15516c77SSepherosa Ziehau  * modification, are permitted provided that the following conditions
9*15516c77SSepherosa Ziehau  * are met:
10*15516c77SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
11*15516c77SSepherosa Ziehau  *    notice unmodified, this list of conditions, and the following
12*15516c77SSepherosa Ziehau  *    disclaimer.
13*15516c77SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
14*15516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
15*15516c77SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
16*15516c77SSepherosa Ziehau  *
17*15516c77SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18*15516c77SSepherosa Ziehau  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19*15516c77SSepherosa Ziehau  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20*15516c77SSepherosa Ziehau  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21*15516c77SSepherosa Ziehau  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22*15516c77SSepherosa Ziehau  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23*15516c77SSepherosa Ziehau  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24*15516c77SSepherosa Ziehau  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25*15516c77SSepherosa Ziehau  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26*15516c77SSepherosa Ziehau  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27*15516c77SSepherosa Ziehau  */
28*15516c77SSepherosa Ziehau 
29*15516c77SSepherosa Ziehau /*-
30*15516c77SSepherosa Ziehau  * Copyright (c) 2004-2006 Kip Macy
31*15516c77SSepherosa Ziehau  * All rights reserved.
32*15516c77SSepherosa Ziehau  *
33*15516c77SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
34*15516c77SSepherosa Ziehau  * modification, are permitted provided that the following conditions
35*15516c77SSepherosa Ziehau  * are met:
36*15516c77SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
37*15516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer.
38*15516c77SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
39*15516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
40*15516c77SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
41*15516c77SSepherosa Ziehau  *
42*15516c77SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
43*15516c77SSepherosa Ziehau  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44*15516c77SSepherosa Ziehau  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45*15516c77SSepherosa Ziehau  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
46*15516c77SSepherosa Ziehau  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47*15516c77SSepherosa Ziehau  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48*15516c77SSepherosa Ziehau  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49*15516c77SSepherosa Ziehau  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50*15516c77SSepherosa Ziehau  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51*15516c77SSepherosa Ziehau  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52*15516c77SSepherosa Ziehau  * SUCH DAMAGE.
53*15516c77SSepherosa Ziehau  */
54*15516c77SSepherosa Ziehau 
55*15516c77SSepherosa Ziehau #include <sys/cdefs.h>
56*15516c77SSepherosa Ziehau __FBSDID("$FreeBSD$");
57*15516c77SSepherosa Ziehau 
58*15516c77SSepherosa Ziehau #include "opt_inet6.h"
59*15516c77SSepherosa Ziehau #include "opt_inet.h"
60*15516c77SSepherosa Ziehau 
61*15516c77SSepherosa Ziehau #include <sys/param.h>
62*15516c77SSepherosa Ziehau #include <sys/bus.h>
63*15516c77SSepherosa Ziehau #include <sys/kernel.h>
64*15516c77SSepherosa Ziehau #include <sys/limits.h>
65*15516c77SSepherosa Ziehau #include <sys/malloc.h>
66*15516c77SSepherosa Ziehau #include <sys/mbuf.h>
67*15516c77SSepherosa Ziehau #include <sys/module.h>
68*15516c77SSepherosa Ziehau #include <sys/queue.h>
69*15516c77SSepherosa Ziehau #include <sys/lock.h>
70*15516c77SSepherosa Ziehau #include <sys/smp.h>
71*15516c77SSepherosa Ziehau #include <sys/socket.h>
72*15516c77SSepherosa Ziehau #include <sys/sockio.h>
73*15516c77SSepherosa Ziehau #include <sys/sx.h>
74*15516c77SSepherosa Ziehau #include <sys/sysctl.h>
75*15516c77SSepherosa Ziehau #include <sys/systm.h>
76*15516c77SSepherosa Ziehau #include <sys/taskqueue.h>
77*15516c77SSepherosa Ziehau #include <sys/buf_ring.h>
78*15516c77SSepherosa Ziehau 
79*15516c77SSepherosa Ziehau #include <machine/atomic.h>
80*15516c77SSepherosa Ziehau #include <machine/in_cksum.h>
81*15516c77SSepherosa Ziehau 
82*15516c77SSepherosa Ziehau #include <net/bpf.h>
83*15516c77SSepherosa Ziehau #include <net/ethernet.h>
84*15516c77SSepherosa Ziehau #include <net/if.h>
85*15516c77SSepherosa Ziehau #include <net/if_media.h>
86*15516c77SSepherosa Ziehau #include <net/if_types.h>
87*15516c77SSepherosa Ziehau #include <net/if_var.h>
88*15516c77SSepherosa Ziehau #include <net/rndis.h>
89*15516c77SSepherosa Ziehau 
90*15516c77SSepherosa Ziehau #include <netinet/in_systm.h>
91*15516c77SSepherosa Ziehau #include <netinet/in.h>
92*15516c77SSepherosa Ziehau #include <netinet/ip.h>
93*15516c77SSepherosa Ziehau #include <netinet/ip6.h>
94*15516c77SSepherosa Ziehau #include <netinet/tcp.h>
95*15516c77SSepherosa Ziehau #include <netinet/tcp_lro.h>
96*15516c77SSepherosa Ziehau #include <netinet/udp.h>
97*15516c77SSepherosa Ziehau 
98*15516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h>
99*15516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv_busdma.h>
100*15516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus.h>
101*15516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus_xact.h>
102*15516c77SSepherosa Ziehau 
103*15516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/ndis.h>
104*15516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnreg.h>
105*15516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnvar.h>
106*15516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_nvs.h>
107*15516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_rndis.h>
108*15516c77SSepherosa Ziehau 
109*15516c77SSepherosa Ziehau #include "vmbus_if.h"
110*15516c77SSepherosa Ziehau 
111*15516c77SSepherosa Ziehau #define HN_RING_CNT_DEF_MAX		8
112*15516c77SSepherosa Ziehau 
113*15516c77SSepherosa Ziehau /* YYY should get it from the underlying channel */
114*15516c77SSepherosa Ziehau #define HN_TX_DESC_CNT			512
115*15516c77SSepherosa Ziehau 
116*15516c77SSepherosa Ziehau #define HN_RNDIS_PKT_LEN					\
117*15516c77SSepherosa Ziehau 	(sizeof(struct rndis_packet_msg) +			\
118*15516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) +	\
119*15516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) +		\
120*15516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) +		\
121*15516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_TXCSUM_INFO_SIZE))
122*15516c77SSepherosa Ziehau #define HN_RNDIS_PKT_BOUNDARY		PAGE_SIZE
123*15516c77SSepherosa Ziehau #define HN_RNDIS_PKT_ALIGN		CACHE_LINE_SIZE
124*15516c77SSepherosa Ziehau 
125*15516c77SSepherosa Ziehau #define HN_TX_DATA_BOUNDARY		PAGE_SIZE
126*15516c77SSepherosa Ziehau #define HN_TX_DATA_MAXSIZE		IP_MAXPACKET
127*15516c77SSepherosa Ziehau #define HN_TX_DATA_SEGSIZE		PAGE_SIZE
128*15516c77SSepherosa Ziehau /* -1 for RNDIS packet message */
129*15516c77SSepherosa Ziehau #define HN_TX_DATA_SEGCNT_MAX		(HN_GPACNT_MAX - 1)
130*15516c77SSepherosa Ziehau 
131*15516c77SSepherosa Ziehau #define HN_DIRECT_TX_SIZE_DEF		128
132*15516c77SSepherosa Ziehau 
133*15516c77SSepherosa Ziehau #define HN_EARLY_TXEOF_THRESH		8
134*15516c77SSepherosa Ziehau 
135*15516c77SSepherosa Ziehau #define HN_PKTBUF_LEN_DEF		(16 * 1024)
136*15516c77SSepherosa Ziehau 
137*15516c77SSepherosa Ziehau #define HN_LROENT_CNT_DEF		128
138*15516c77SSepherosa Ziehau 
139*15516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MULTIRX_DEF	(12 * ETHERMTU)
140*15516c77SSepherosa Ziehau #define HN_LRO_LENLIM_DEF		(25 * ETHERMTU)
141*15516c77SSepherosa Ziehau /* YYY 2*MTU is a bit rough, but should be good enough. */
142*15516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MIN(ifp)		(2 * (ifp)->if_mtu)
143*15516c77SSepherosa Ziehau 
144*15516c77SSepherosa Ziehau #define HN_LRO_ACKCNT_DEF		1
145*15516c77SSepherosa Ziehau 
146*15516c77SSepherosa Ziehau #define HN_LOCK_INIT(sc)		\
147*15516c77SSepherosa Ziehau 	sx_init(&(sc)->hn_lock, device_get_nameunit((sc)->hn_dev))
148*15516c77SSepherosa Ziehau #define HN_LOCK_DESTROY(sc)		sx_destroy(&(sc)->hn_lock)
149*15516c77SSepherosa Ziehau #define HN_LOCK_ASSERT(sc)		sx_assert(&(sc)->hn_lock, SA_XLOCKED)
150*15516c77SSepherosa Ziehau #define HN_LOCK(sc)			sx_xlock(&(sc)->hn_lock)
151*15516c77SSepherosa Ziehau #define HN_UNLOCK(sc)			sx_xunlock(&(sc)->hn_lock)
152*15516c77SSepherosa Ziehau 
153*15516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK			(CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP)
154*15516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK		(CSUM_IP6_TCP | CSUM_IP6_UDP)
155*15516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc)		\
156*15516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK)
157*15516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc)	\
158*15516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK)
159*15516c77SSepherosa Ziehau 
160*15516c77SSepherosa Ziehau struct hn_txdesc {
161*15516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
162*15516c77SSepherosa Ziehau 	SLIST_ENTRY(hn_txdesc)		link;
163*15516c77SSepherosa Ziehau #endif
164*15516c77SSepherosa Ziehau 	struct mbuf			*m;
165*15516c77SSepherosa Ziehau 	struct hn_tx_ring		*txr;
166*15516c77SSepherosa Ziehau 	int				refs;
167*15516c77SSepherosa Ziehau 	uint32_t			flags;	/* HN_TXD_FLAG_ */
168*15516c77SSepherosa Ziehau 	struct hn_nvs_sendctx		send_ctx;
169*15516c77SSepherosa Ziehau 	uint32_t			chim_index;
170*15516c77SSepherosa Ziehau 	int				chim_size;
171*15516c77SSepherosa Ziehau 
172*15516c77SSepherosa Ziehau 	bus_dmamap_t			data_dmap;
173*15516c77SSepherosa Ziehau 
174*15516c77SSepherosa Ziehau 	bus_addr_t			rndis_pkt_paddr;
175*15516c77SSepherosa Ziehau 	struct rndis_packet_msg		*rndis_pkt;
176*15516c77SSepherosa Ziehau 	bus_dmamap_t			rndis_pkt_dmap;
177*15516c77SSepherosa Ziehau };
178*15516c77SSepherosa Ziehau 
179*15516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST		0x0001
180*15516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP		0x0002
181*15516c77SSepherosa Ziehau 
182*15516c77SSepherosa Ziehau struct hn_rxinfo {
183*15516c77SSepherosa Ziehau 	uint32_t			vlan_info;
184*15516c77SSepherosa Ziehau 	uint32_t			csum_info;
185*15516c77SSepherosa Ziehau 	uint32_t			hash_info;
186*15516c77SSepherosa Ziehau 	uint32_t			hash_value;
187*15516c77SSepherosa Ziehau };
188*15516c77SSepherosa Ziehau 
189*15516c77SSepherosa Ziehau #define HN_RXINFO_VLAN			0x0001
190*15516c77SSepherosa Ziehau #define HN_RXINFO_CSUM			0x0002
191*15516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF		0x0004
192*15516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL		0x0008
193*15516c77SSepherosa Ziehau #define HN_RXINFO_ALL			\
194*15516c77SSepherosa Ziehau 	(HN_RXINFO_VLAN |		\
195*15516c77SSepherosa Ziehau 	 HN_RXINFO_CSUM |		\
196*15516c77SSepherosa Ziehau 	 HN_RXINFO_HASHINF |		\
197*15516c77SSepherosa Ziehau 	 HN_RXINFO_HASHVAL)
198*15516c77SSepherosa Ziehau 
199*15516c77SSepherosa Ziehau #define HN_NDIS_VLAN_INFO_INVALID	0xffffffff
200*15516c77SSepherosa Ziehau #define HN_NDIS_RXCSUM_INFO_INVALID	0
201*15516c77SSepherosa Ziehau #define HN_NDIS_HASH_INFO_INVALID	0
202*15516c77SSepherosa Ziehau 
203*15516c77SSepherosa Ziehau static int			hn_probe(device_t);
204*15516c77SSepherosa Ziehau static int			hn_attach(device_t);
205*15516c77SSepherosa Ziehau static int			hn_detach(device_t);
206*15516c77SSepherosa Ziehau static int			hn_shutdown(device_t);
207*15516c77SSepherosa Ziehau static void			hn_chan_callback(struct vmbus_channel *,
208*15516c77SSepherosa Ziehau 				    void *);
209*15516c77SSepherosa Ziehau 
210*15516c77SSepherosa Ziehau static void			hn_init(void *);
211*15516c77SSepherosa Ziehau static int			hn_ioctl(struct ifnet *, u_long, caddr_t);
212*15516c77SSepherosa Ziehau static void			hn_start(struct ifnet *);
213*15516c77SSepherosa Ziehau static int			hn_transmit(struct ifnet *, struct mbuf *);
214*15516c77SSepherosa Ziehau static void			hn_xmit_qflush(struct ifnet *);
215*15516c77SSepherosa Ziehau static int			hn_ifmedia_upd(struct ifnet *);
216*15516c77SSepherosa Ziehau static void			hn_ifmedia_sts(struct ifnet *,
217*15516c77SSepherosa Ziehau 				    struct ifmediareq *);
218*15516c77SSepherosa Ziehau 
219*15516c77SSepherosa Ziehau static int			hn_rndis_rxinfo(const void *, int,
220*15516c77SSepherosa Ziehau 				    struct hn_rxinfo *);
221*15516c77SSepherosa Ziehau static void			hn_rndis_rx_data(struct hn_rx_ring *,
222*15516c77SSepherosa Ziehau 				    const void *, int);
223*15516c77SSepherosa Ziehau static void			hn_rndis_rx_status(struct hn_softc *,
224*15516c77SSepherosa Ziehau 				    const void *, int);
225*15516c77SSepherosa Ziehau 
226*15516c77SSepherosa Ziehau static void			hn_nvs_handle_notify(struct hn_softc *,
227*15516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
228*15516c77SSepherosa Ziehau static void			hn_nvs_handle_comp(struct hn_softc *,
229*15516c77SSepherosa Ziehau 				    struct vmbus_channel *,
230*15516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
231*15516c77SSepherosa Ziehau static void			hn_nvs_handle_rxbuf(struct hn_rx_ring *,
232*15516c77SSepherosa Ziehau 				    struct vmbus_channel *,
233*15516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
234*15516c77SSepherosa Ziehau static void			hn_nvs_ack_rxbuf(struct hn_rx_ring *,
235*15516c77SSepherosa Ziehau 				    struct vmbus_channel *, uint64_t);
236*15516c77SSepherosa Ziehau 
237*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
238*15516c77SSepherosa Ziehau static int			hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS);
239*15516c77SSepherosa Ziehau static int			hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS);
240*15516c77SSepherosa Ziehau #endif
241*15516c77SSepherosa Ziehau static int			hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS);
242*15516c77SSepherosa Ziehau static int			hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS);
243*15516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
244*15516c77SSepherosa Ziehau static int			hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS);
245*15516c77SSepherosa Ziehau #else
246*15516c77SSepherosa Ziehau static int			hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS);
247*15516c77SSepherosa Ziehau #endif
248*15516c77SSepherosa Ziehau static int			hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
249*15516c77SSepherosa Ziehau static int			hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
250*15516c77SSepherosa Ziehau static int			hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS);
251*15516c77SSepherosa Ziehau static int			hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS);
252*15516c77SSepherosa Ziehau static int			hn_caps_sysctl(SYSCTL_HANDLER_ARGS);
253*15516c77SSepherosa Ziehau static int			hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS);
254*15516c77SSepherosa Ziehau static int			hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS);
255*15516c77SSepherosa Ziehau static int			hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS);
256*15516c77SSepherosa Ziehau static int			hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS);
257*15516c77SSepherosa Ziehau static int			hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS);
258*15516c77SSepherosa Ziehau 
259*15516c77SSepherosa Ziehau static void			hn_stop(struct hn_softc *);
260*15516c77SSepherosa Ziehau static void			hn_init_locked(struct hn_softc *);
261*15516c77SSepherosa Ziehau static int			hn_chan_attach(struct hn_softc *,
262*15516c77SSepherosa Ziehau 				    struct vmbus_channel *);
263*15516c77SSepherosa Ziehau static void			hn_chan_detach(struct hn_softc *,
264*15516c77SSepherosa Ziehau 				    struct vmbus_channel *);
265*15516c77SSepherosa Ziehau static int			hn_attach_subchans(struct hn_softc *);
266*15516c77SSepherosa Ziehau static void			hn_detach_allchans(struct hn_softc *);
267*15516c77SSepherosa Ziehau static void			hn_chan_rollup(struct hn_rx_ring *,
268*15516c77SSepherosa Ziehau 				    struct hn_tx_ring *);
269*15516c77SSepherosa Ziehau static void			hn_set_ring_inuse(struct hn_softc *, int);
270*15516c77SSepherosa Ziehau static int			hn_synth_attach(struct hn_softc *, int);
271*15516c77SSepherosa Ziehau static void			hn_synth_detach(struct hn_softc *);
272*15516c77SSepherosa Ziehau static int			hn_synth_alloc_subchans(struct hn_softc *,
273*15516c77SSepherosa Ziehau 				    int *);
274*15516c77SSepherosa Ziehau static void			hn_suspend(struct hn_softc *);
275*15516c77SSepherosa Ziehau static void			hn_suspend_data(struct hn_softc *);
276*15516c77SSepherosa Ziehau static void			hn_suspend_mgmt(struct hn_softc *);
277*15516c77SSepherosa Ziehau static void			hn_resume(struct hn_softc *);
278*15516c77SSepherosa Ziehau static void			hn_resume_data(struct hn_softc *);
279*15516c77SSepherosa Ziehau static void			hn_resume_mgmt(struct hn_softc *);
280*15516c77SSepherosa Ziehau static void			hn_suspend_mgmt_taskfunc(void *, int);
281*15516c77SSepherosa Ziehau static void			hn_chan_drain(struct vmbus_channel *);
282*15516c77SSepherosa Ziehau 
283*15516c77SSepherosa Ziehau static void			hn_update_link_status(struct hn_softc *);
284*15516c77SSepherosa Ziehau static void			hn_change_network(struct hn_softc *);
285*15516c77SSepherosa Ziehau static void			hn_link_taskfunc(void *, int);
286*15516c77SSepherosa Ziehau static void			hn_netchg_init_taskfunc(void *, int);
287*15516c77SSepherosa Ziehau static void			hn_netchg_status_taskfunc(void *, int);
288*15516c77SSepherosa Ziehau static void			hn_link_status(struct hn_softc *);
289*15516c77SSepherosa Ziehau 
290*15516c77SSepherosa Ziehau static int			hn_create_rx_data(struct hn_softc *, int);
291*15516c77SSepherosa Ziehau static void			hn_destroy_rx_data(struct hn_softc *);
292*15516c77SSepherosa Ziehau static int			hn_check_iplen(const struct mbuf *, int);
293*15516c77SSepherosa Ziehau static int			hn_set_rxfilter(struct hn_softc *);
294*15516c77SSepherosa Ziehau static int			hn_rss_reconfig(struct hn_softc *);
295*15516c77SSepherosa Ziehau static void			hn_rss_ind_fixup(struct hn_softc *, int);
296*15516c77SSepherosa Ziehau static int			hn_rxpkt(struct hn_rx_ring *, const void *,
297*15516c77SSepherosa Ziehau 				    int, const struct hn_rxinfo *);
298*15516c77SSepherosa Ziehau 
299*15516c77SSepherosa Ziehau static int			hn_tx_ring_create(struct hn_softc *, int);
300*15516c77SSepherosa Ziehau static void			hn_tx_ring_destroy(struct hn_tx_ring *);
301*15516c77SSepherosa Ziehau static int			hn_create_tx_data(struct hn_softc *, int);
302*15516c77SSepherosa Ziehau static void			hn_fixup_tx_data(struct hn_softc *);
303*15516c77SSepherosa Ziehau static void			hn_destroy_tx_data(struct hn_softc *);
304*15516c77SSepherosa Ziehau static void			hn_txdesc_dmamap_destroy(struct hn_txdesc *);
305*15516c77SSepherosa Ziehau static int			hn_encap(struct hn_tx_ring *,
306*15516c77SSepherosa Ziehau 				    struct hn_txdesc *, struct mbuf **);
307*15516c77SSepherosa Ziehau static int			hn_txpkt(struct ifnet *, struct hn_tx_ring *,
308*15516c77SSepherosa Ziehau 				    struct hn_txdesc *);
309*15516c77SSepherosa Ziehau static void			hn_set_chim_size(struct hn_softc *, int);
310*15516c77SSepherosa Ziehau static void			hn_set_tso_maxsize(struct hn_softc *, int, int);
311*15516c77SSepherosa Ziehau static bool			hn_tx_ring_pending(struct hn_tx_ring *);
312*15516c77SSepherosa Ziehau static void			hn_tx_ring_qflush(struct hn_tx_ring *);
313*15516c77SSepherosa Ziehau static void			hn_resume_tx(struct hn_softc *, int);
314*15516c77SSepherosa Ziehau static int			hn_get_txswq_depth(const struct hn_tx_ring *);
315*15516c77SSepherosa Ziehau static void			hn_txpkt_done(struct hn_nvs_sendctx *,
316*15516c77SSepherosa Ziehau 				    struct hn_softc *, struct vmbus_channel *,
317*15516c77SSepherosa Ziehau 				    const void *, int);
318*15516c77SSepherosa Ziehau static int			hn_txpkt_sglist(struct hn_tx_ring *,
319*15516c77SSepherosa Ziehau 				    struct hn_txdesc *);
320*15516c77SSepherosa Ziehau static int			hn_txpkt_chim(struct hn_tx_ring *,
321*15516c77SSepherosa Ziehau 				    struct hn_txdesc *);
322*15516c77SSepherosa Ziehau static int			hn_xmit(struct hn_tx_ring *, int);
323*15516c77SSepherosa Ziehau static void			hn_xmit_taskfunc(void *, int);
324*15516c77SSepherosa Ziehau static void			hn_xmit_txeof(struct hn_tx_ring *);
325*15516c77SSepherosa Ziehau static void			hn_xmit_txeof_taskfunc(void *, int);
326*15516c77SSepherosa Ziehau static int			hn_start_locked(struct hn_tx_ring *, int);
327*15516c77SSepherosa Ziehau static void			hn_start_taskfunc(void *, int);
328*15516c77SSepherosa Ziehau static void			hn_start_txeof(struct hn_tx_ring *);
329*15516c77SSepherosa Ziehau static void			hn_start_txeof_taskfunc(void *, int);
330*15516c77SSepherosa Ziehau 
331*15516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
332*15516c77SSepherosa Ziehau     "Hyper-V network interface");
333*15516c77SSepherosa Ziehau 
334*15516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */
335*15516c77SSepherosa Ziehau static int			hn_trust_hosttcp = 1;
336*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN,
337*15516c77SSepherosa Ziehau     &hn_trust_hosttcp, 0,
338*15516c77SSepherosa Ziehau     "Trust tcp segement verification on host side, "
339*15516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
340*15516c77SSepherosa Ziehau 
341*15516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */
342*15516c77SSepherosa Ziehau static int			hn_trust_hostudp = 1;
343*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN,
344*15516c77SSepherosa Ziehau     &hn_trust_hostudp, 0,
345*15516c77SSepherosa Ziehau     "Trust udp datagram verification on host side, "
346*15516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
347*15516c77SSepherosa Ziehau 
348*15516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */
349*15516c77SSepherosa Ziehau static int			hn_trust_hostip = 1;
350*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN,
351*15516c77SSepherosa Ziehau     &hn_trust_hostip, 0,
352*15516c77SSepherosa Ziehau     "Trust ip packet verification on host side, "
353*15516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
354*15516c77SSepherosa Ziehau 
355*15516c77SSepherosa Ziehau /* Limit TSO burst size */
356*15516c77SSepherosa Ziehau static int			hn_tso_maxlen = IP_MAXPACKET;
357*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN,
358*15516c77SSepherosa Ziehau     &hn_tso_maxlen, 0, "TSO burst limit");
359*15516c77SSepherosa Ziehau 
360*15516c77SSepherosa Ziehau /* Limit chimney send size */
361*15516c77SSepherosa Ziehau static int			hn_tx_chimney_size = 0;
362*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN,
363*15516c77SSepherosa Ziehau     &hn_tx_chimney_size, 0, "Chimney send packet size limit");
364*15516c77SSepherosa Ziehau 
365*15516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */
366*15516c77SSepherosa Ziehau static int			hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF;
367*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN,
368*15516c77SSepherosa Ziehau     &hn_direct_tx_size, 0, "Size of the packet for direct transmission");
369*15516c77SSepherosa Ziehau 
370*15516c77SSepherosa Ziehau /* # of LRO entries per RX ring */
371*15516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
372*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
373*15516c77SSepherosa Ziehau static int			hn_lro_entry_count = HN_LROENT_CNT_DEF;
374*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN,
375*15516c77SSepherosa Ziehau     &hn_lro_entry_count, 0, "LRO entry count");
376*15516c77SSepherosa Ziehau #endif
377*15516c77SSepherosa Ziehau #endif
378*15516c77SSepherosa Ziehau 
379*15516c77SSepherosa Ziehau /* Use shared TX taskqueue */
380*15516c77SSepherosa Ziehau static int			hn_share_tx_taskq = 0;
381*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, share_tx_taskq, CTLFLAG_RDTUN,
382*15516c77SSepherosa Ziehau     &hn_share_tx_taskq, 0, "Enable shared TX taskqueue");
383*15516c77SSepherosa Ziehau 
384*15516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
385*15516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 0;
386*15516c77SSepherosa Ziehau #else
387*15516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 1;
388*15516c77SSepherosa Ziehau #endif
389*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD,
390*15516c77SSepherosa Ziehau     &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors");
391*15516c77SSepherosa Ziehau 
392*15516c77SSepherosa Ziehau /* Bind TX taskqueue to the target CPU */
393*15516c77SSepherosa Ziehau static int			hn_bind_tx_taskq = -1;
394*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, bind_tx_taskq, CTLFLAG_RDTUN,
395*15516c77SSepherosa Ziehau     &hn_bind_tx_taskq, 0, "Bind TX taskqueue to the specified cpu");
396*15516c77SSepherosa Ziehau 
397*15516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */
398*15516c77SSepherosa Ziehau static int			hn_use_if_start = 0;
399*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN,
400*15516c77SSepherosa Ziehau     &hn_use_if_start, 0, "Use if_start TX method");
401*15516c77SSepherosa Ziehau 
402*15516c77SSepherosa Ziehau /* # of channels to use */
403*15516c77SSepherosa Ziehau static int			hn_chan_cnt = 0;
404*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN,
405*15516c77SSepherosa Ziehau     &hn_chan_cnt, 0,
406*15516c77SSepherosa Ziehau     "# of channels to use; each channel has one RX ring and one TX ring");
407*15516c77SSepherosa Ziehau 
408*15516c77SSepherosa Ziehau /* # of transmit rings to use */
409*15516c77SSepherosa Ziehau static int			hn_tx_ring_cnt = 0;
410*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN,
411*15516c77SSepherosa Ziehau     &hn_tx_ring_cnt, 0, "# of TX rings to use");
412*15516c77SSepherosa Ziehau 
413*15516c77SSepherosa Ziehau /* Software TX ring deptch */
414*15516c77SSepherosa Ziehau static int			hn_tx_swq_depth = 0;
415*15516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN,
416*15516c77SSepherosa Ziehau     &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING");
417*15516c77SSepherosa Ziehau 
418*15516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */
419*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
420*15516c77SSepherosa Ziehau static u_int			hn_lro_mbufq_depth = 0;
421*15516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN,
422*15516c77SSepherosa Ziehau     &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue");
423*15516c77SSepherosa Ziehau #endif
424*15516c77SSepherosa Ziehau 
425*15516c77SSepherosa Ziehau static u_int			hn_cpu_index;	/* next CPU for channel */
426*15516c77SSepherosa Ziehau static struct taskqueue		*hn_tx_taskq;	/* shared TX taskqueue */
427*15516c77SSepherosa Ziehau 
428*15516c77SSepherosa Ziehau static const uint8_t
429*15516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
430*15516c77SSepherosa Ziehau 	0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
431*15516c77SSepherosa Ziehau 	0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
432*15516c77SSepherosa Ziehau 	0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
433*15516c77SSepherosa Ziehau 	0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
434*15516c77SSepherosa Ziehau 	0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
435*15516c77SSepherosa Ziehau };
436*15516c77SSepherosa Ziehau 
437*15516c77SSepherosa Ziehau static device_method_t hn_methods[] = {
438*15516c77SSepherosa Ziehau 	/* Device interface */
439*15516c77SSepherosa Ziehau 	DEVMETHOD(device_probe,		hn_probe),
440*15516c77SSepherosa Ziehau 	DEVMETHOD(device_attach,	hn_attach),
441*15516c77SSepherosa Ziehau 	DEVMETHOD(device_detach,	hn_detach),
442*15516c77SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	hn_shutdown),
443*15516c77SSepherosa Ziehau 	DEVMETHOD_END
444*15516c77SSepherosa Ziehau };
445*15516c77SSepherosa Ziehau 
446*15516c77SSepherosa Ziehau static driver_t hn_driver = {
447*15516c77SSepherosa Ziehau 	"hn",
448*15516c77SSepherosa Ziehau 	hn_methods,
449*15516c77SSepherosa Ziehau 	sizeof(struct hn_softc)
450*15516c77SSepherosa Ziehau };
451*15516c77SSepherosa Ziehau 
452*15516c77SSepherosa Ziehau static devclass_t hn_devclass;
453*15516c77SSepherosa Ziehau 
454*15516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0);
455*15516c77SSepherosa Ziehau MODULE_VERSION(hn, 1);
456*15516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1);
457*15516c77SSepherosa Ziehau 
458*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
459*15516c77SSepherosa Ziehau static void
460*15516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim)
461*15516c77SSepherosa Ziehau {
462*15516c77SSepherosa Ziehau 	int i;
463*15516c77SSepherosa Ziehau 
464*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_inuse; ++i)
465*15516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim;
466*15516c77SSepherosa Ziehau }
467*15516c77SSepherosa Ziehau #endif
468*15516c77SSepherosa Ziehau 
469*15516c77SSepherosa Ziehau static int
470*15516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd)
471*15516c77SSepherosa Ziehau {
472*15516c77SSepherosa Ziehau 
473*15516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
474*15516c77SSepherosa Ziehau 	    txd->chim_size == 0, ("invalid rndis sglist txd"));
475*15516c77SSepherosa Ziehau 	return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA,
476*15516c77SSepherosa Ziehau 	    &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt));
477*15516c77SSepherosa Ziehau }
478*15516c77SSepherosa Ziehau 
479*15516c77SSepherosa Ziehau static int
480*15516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd)
481*15516c77SSepherosa Ziehau {
482*15516c77SSepherosa Ziehau 	struct hn_nvs_rndis rndis;
483*15516c77SSepherosa Ziehau 
484*15516c77SSepherosa Ziehau 	KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID &&
485*15516c77SSepherosa Ziehau 	    txd->chim_size > 0, ("invalid rndis chim txd"));
486*15516c77SSepherosa Ziehau 
487*15516c77SSepherosa Ziehau 	rndis.nvs_type = HN_NVS_TYPE_RNDIS;
488*15516c77SSepherosa Ziehau 	rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA;
489*15516c77SSepherosa Ziehau 	rndis.nvs_chim_idx = txd->chim_index;
490*15516c77SSepherosa Ziehau 	rndis.nvs_chim_sz = txd->chim_size;
491*15516c77SSepherosa Ziehau 
492*15516c77SSepherosa Ziehau 	return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC,
493*15516c77SSepherosa Ziehau 	    &rndis, sizeof(rndis), &txd->send_ctx));
494*15516c77SSepherosa Ziehau }
495*15516c77SSepherosa Ziehau 
496*15516c77SSepherosa Ziehau static __inline uint32_t
497*15516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc)
498*15516c77SSepherosa Ziehau {
499*15516c77SSepherosa Ziehau 	int i, bmap_cnt = sc->hn_chim_bmap_cnt;
500*15516c77SSepherosa Ziehau 	u_long *bmap = sc->hn_chim_bmap;
501*15516c77SSepherosa Ziehau 	uint32_t ret = HN_NVS_CHIM_IDX_INVALID;
502*15516c77SSepherosa Ziehau 
503*15516c77SSepherosa Ziehau 	for (i = 0; i < bmap_cnt; ++i) {
504*15516c77SSepherosa Ziehau 		int idx;
505*15516c77SSepherosa Ziehau 
506*15516c77SSepherosa Ziehau 		idx = ffsl(~bmap[i]);
507*15516c77SSepherosa Ziehau 		if (idx == 0)
508*15516c77SSepherosa Ziehau 			continue;
509*15516c77SSepherosa Ziehau 
510*15516c77SSepherosa Ziehau 		--idx; /* ffsl is 1-based */
511*15516c77SSepherosa Ziehau 		KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt,
512*15516c77SSepherosa Ziehau 		    ("invalid i %d and idx %d", i, idx));
513*15516c77SSepherosa Ziehau 
514*15516c77SSepherosa Ziehau 		if (atomic_testandset_long(&bmap[i], idx))
515*15516c77SSepherosa Ziehau 			continue;
516*15516c77SSepherosa Ziehau 
517*15516c77SSepherosa Ziehau 		ret = i * LONG_BIT + idx;
518*15516c77SSepherosa Ziehau 		break;
519*15516c77SSepherosa Ziehau 	}
520*15516c77SSepherosa Ziehau 	return (ret);
521*15516c77SSepherosa Ziehau }
522*15516c77SSepherosa Ziehau 
523*15516c77SSepherosa Ziehau static __inline void
524*15516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx)
525*15516c77SSepherosa Ziehau {
526*15516c77SSepherosa Ziehau 	u_long mask;
527*15516c77SSepherosa Ziehau 	uint32_t idx;
528*15516c77SSepherosa Ziehau 
529*15516c77SSepherosa Ziehau 	idx = chim_idx / LONG_BIT;
530*15516c77SSepherosa Ziehau 	KASSERT(idx < sc->hn_chim_bmap_cnt,
531*15516c77SSepherosa Ziehau 	    ("invalid chimney index 0x%x", chim_idx));
532*15516c77SSepherosa Ziehau 
533*15516c77SSepherosa Ziehau 	mask = 1UL << (chim_idx % LONG_BIT);
534*15516c77SSepherosa Ziehau 	KASSERT(sc->hn_chim_bmap[idx] & mask,
535*15516c77SSepherosa Ziehau 	    ("index bitmap 0x%lx, chimney index %u, "
536*15516c77SSepherosa Ziehau 	     "bitmap idx %d, bitmask 0x%lx",
537*15516c77SSepherosa Ziehau 	     sc->hn_chim_bmap[idx], chim_idx, idx, mask));
538*15516c77SSepherosa Ziehau 
539*15516c77SSepherosa Ziehau 	atomic_clear_long(&sc->hn_chim_bmap[idx], mask);
540*15516c77SSepherosa Ziehau }
541*15516c77SSepherosa Ziehau 
542*15516c77SSepherosa Ziehau static int
543*15516c77SSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc)
544*15516c77SSepherosa Ziehau {
545*15516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
546*15516c77SSepherosa Ziehau 	uint32_t filter;
547*15516c77SSepherosa Ziehau 	int error = 0;
548*15516c77SSepherosa Ziehau 
549*15516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
550*15516c77SSepherosa Ziehau 
551*15516c77SSepherosa Ziehau 	if (ifp->if_flags & IFF_PROMISC) {
552*15516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_PROMISCUOUS;
553*15516c77SSepherosa Ziehau 	} else {
554*15516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_DIRECTED;
555*15516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_BROADCAST)
556*15516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_BROADCAST;
557*15516c77SSepherosa Ziehau #ifdef notyet
558*15516c77SSepherosa Ziehau 		/*
559*15516c77SSepherosa Ziehau 		 * See the comment in SIOCADDMULTI/SIOCDELMULTI.
560*15516c77SSepherosa Ziehau 		 */
561*15516c77SSepherosa Ziehau 		/* TODO: support multicast list */
562*15516c77SSepherosa Ziehau 		if ((ifp->if_flags & IFF_ALLMULTI) ||
563*15516c77SSepherosa Ziehau 		    !TAILQ_EMPTY(&ifp->if_multiaddrs))
564*15516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
565*15516c77SSepherosa Ziehau #else
566*15516c77SSepherosa Ziehau 		/* Always enable ALLMULTI */
567*15516c77SSepherosa Ziehau 		filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
568*15516c77SSepherosa Ziehau #endif
569*15516c77SSepherosa Ziehau 	}
570*15516c77SSepherosa Ziehau 
571*15516c77SSepherosa Ziehau 	if (sc->hn_rx_filter != filter) {
572*15516c77SSepherosa Ziehau 		error = hn_rndis_set_rxfilter(sc, filter);
573*15516c77SSepherosa Ziehau 		if (!error)
574*15516c77SSepherosa Ziehau 			sc->hn_rx_filter = filter;
575*15516c77SSepherosa Ziehau 	}
576*15516c77SSepherosa Ziehau 	return (error);
577*15516c77SSepherosa Ziehau }
578*15516c77SSepherosa Ziehau 
579*15516c77SSepherosa Ziehau static int
580*15516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr)
581*15516c77SSepherosa Ziehau {
582*15516c77SSepherosa Ziehau 
583*15516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet"));
584*15516c77SSepherosa Ziehau 	if (hn_tx_swq_depth < txr->hn_txdesc_cnt)
585*15516c77SSepherosa Ziehau 		return txr->hn_txdesc_cnt;
586*15516c77SSepherosa Ziehau 	return hn_tx_swq_depth;
587*15516c77SSepherosa Ziehau }
588*15516c77SSepherosa Ziehau 
589*15516c77SSepherosa Ziehau static int
590*15516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc)
591*15516c77SSepherosa Ziehau {
592*15516c77SSepherosa Ziehau 	int error;
593*15516c77SSepherosa Ziehau 
594*15516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
595*15516c77SSepherosa Ziehau 
596*15516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
597*15516c77SSepherosa Ziehau 		return (ENXIO);
598*15516c77SSepherosa Ziehau 
599*15516c77SSepherosa Ziehau 	/*
600*15516c77SSepherosa Ziehau 	 * Disable RSS first.
601*15516c77SSepherosa Ziehau 	 *
602*15516c77SSepherosa Ziehau 	 * NOTE:
603*15516c77SSepherosa Ziehau 	 * Direct reconfiguration by setting the UNCHG flags does
604*15516c77SSepherosa Ziehau 	 * _not_ work properly.
605*15516c77SSepherosa Ziehau 	 */
606*15516c77SSepherosa Ziehau 	if (bootverbose)
607*15516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "disable RSS\n");
608*15516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE);
609*15516c77SSepherosa Ziehau 	if (error) {
610*15516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS disable failed\n");
611*15516c77SSepherosa Ziehau 		return (error);
612*15516c77SSepherosa Ziehau 	}
613*15516c77SSepherosa Ziehau 
614*15516c77SSepherosa Ziehau 	/*
615*15516c77SSepherosa Ziehau 	 * Reenable the RSS w/ the updated RSS key or indirect
616*15516c77SSepherosa Ziehau 	 * table.
617*15516c77SSepherosa Ziehau 	 */
618*15516c77SSepherosa Ziehau 	if (bootverbose)
619*15516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "reconfig RSS\n");
620*15516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
621*15516c77SSepherosa Ziehau 	if (error) {
622*15516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS reconfig failed\n");
623*15516c77SSepherosa Ziehau 		return (error);
624*15516c77SSepherosa Ziehau 	}
625*15516c77SSepherosa Ziehau 	return (0);
626*15516c77SSepherosa Ziehau }
627*15516c77SSepherosa Ziehau 
628*15516c77SSepherosa Ziehau static void
629*15516c77SSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc, int nchan)
630*15516c77SSepherosa Ziehau {
631*15516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
632*15516c77SSepherosa Ziehau 	int i;
633*15516c77SSepherosa Ziehau 
634*15516c77SSepherosa Ziehau 	KASSERT(nchan > 1, ("invalid # of channels %d", nchan));
635*15516c77SSepherosa Ziehau 
636*15516c77SSepherosa Ziehau 	/*
637*15516c77SSepherosa Ziehau 	 * Check indirect table to make sure that all channels in it
638*15516c77SSepherosa Ziehau 	 * can be used.
639*15516c77SSepherosa Ziehau 	 */
640*15516c77SSepherosa Ziehau 	for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
641*15516c77SSepherosa Ziehau 		if (rss->rss_ind[i] >= nchan) {
642*15516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp,
643*15516c77SSepherosa Ziehau 			    "RSS indirect table %d fixup: %u -> %d\n",
644*15516c77SSepherosa Ziehau 			    i, rss->rss_ind[i], nchan - 1);
645*15516c77SSepherosa Ziehau 			rss->rss_ind[i] = nchan - 1;
646*15516c77SSepherosa Ziehau 		}
647*15516c77SSepherosa Ziehau 	}
648*15516c77SSepherosa Ziehau }
649*15516c77SSepherosa Ziehau 
650*15516c77SSepherosa Ziehau static int
651*15516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused)
652*15516c77SSepherosa Ziehau {
653*15516c77SSepherosa Ziehau 
654*15516c77SSepherosa Ziehau 	return EOPNOTSUPP;
655*15516c77SSepherosa Ziehau }
656*15516c77SSepherosa Ziehau 
657*15516c77SSepherosa Ziehau static void
658*15516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
659*15516c77SSepherosa Ziehau {
660*15516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
661*15516c77SSepherosa Ziehau 
662*15516c77SSepherosa Ziehau 	ifmr->ifm_status = IFM_AVALID;
663*15516c77SSepherosa Ziehau 	ifmr->ifm_active = IFM_ETHER;
664*15516c77SSepherosa Ziehau 
665*15516c77SSepherosa Ziehau 	if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) {
666*15516c77SSepherosa Ziehau 		ifmr->ifm_active |= IFM_NONE;
667*15516c77SSepherosa Ziehau 		return;
668*15516c77SSepherosa Ziehau 	}
669*15516c77SSepherosa Ziehau 	ifmr->ifm_status |= IFM_ACTIVE;
670*15516c77SSepherosa Ziehau 	ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
671*15516c77SSepherosa Ziehau }
672*15516c77SSepherosa Ziehau 
673*15516c77SSepherosa Ziehau /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
674*15516c77SSepherosa Ziehau static const struct hyperv_guid g_net_vsc_device_type = {
675*15516c77SSepherosa Ziehau 	.hv_guid = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
676*15516c77SSepherosa Ziehau 		0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E}
677*15516c77SSepherosa Ziehau };
678*15516c77SSepherosa Ziehau 
679*15516c77SSepherosa Ziehau static int
680*15516c77SSepherosa Ziehau hn_probe(device_t dev)
681*15516c77SSepherosa Ziehau {
682*15516c77SSepherosa Ziehau 
683*15516c77SSepherosa Ziehau 	if (VMBUS_PROBE_GUID(device_get_parent(dev), dev,
684*15516c77SSepherosa Ziehau 	    &g_net_vsc_device_type) == 0) {
685*15516c77SSepherosa Ziehau 		device_set_desc(dev, "Hyper-V Network Interface");
686*15516c77SSepherosa Ziehau 		return BUS_PROBE_DEFAULT;
687*15516c77SSepherosa Ziehau 	}
688*15516c77SSepherosa Ziehau 	return ENXIO;
689*15516c77SSepherosa Ziehau }
690*15516c77SSepherosa Ziehau 
691*15516c77SSepherosa Ziehau static int
692*15516c77SSepherosa Ziehau hn_attach(device_t dev)
693*15516c77SSepherosa Ziehau {
694*15516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
695*15516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
696*15516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
697*15516c77SSepherosa Ziehau 	uint8_t eaddr[ETHER_ADDR_LEN];
698*15516c77SSepherosa Ziehau 	struct ifnet *ifp = NULL;
699*15516c77SSepherosa Ziehau 	int error, ring_cnt, tx_ring_cnt;
700*15516c77SSepherosa Ziehau 
701*15516c77SSepherosa Ziehau 	sc->hn_dev = dev;
702*15516c77SSepherosa Ziehau 	sc->hn_prichan = vmbus_get_channel(dev);
703*15516c77SSepherosa Ziehau 	HN_LOCK_INIT(sc);
704*15516c77SSepherosa Ziehau 
705*15516c77SSepherosa Ziehau 	/*
706*15516c77SSepherosa Ziehau 	 * Setup taskqueue for transmission.
707*15516c77SSepherosa Ziehau 	 */
708*15516c77SSepherosa Ziehau 	if (hn_tx_taskq == NULL) {
709*15516c77SSepherosa Ziehau 		sc->hn_tx_taskq = taskqueue_create("hn_tx", M_WAITOK,
710*15516c77SSepherosa Ziehau 		    taskqueue_thread_enqueue, &sc->hn_tx_taskq);
711*15516c77SSepherosa Ziehau 		if (hn_bind_tx_taskq >= 0) {
712*15516c77SSepherosa Ziehau 			int cpu = hn_bind_tx_taskq;
713*15516c77SSepherosa Ziehau 			cpuset_t cpu_set;
714*15516c77SSepherosa Ziehau 
715*15516c77SSepherosa Ziehau 			if (cpu > mp_ncpus - 1)
716*15516c77SSepherosa Ziehau 				cpu = mp_ncpus - 1;
717*15516c77SSepherosa Ziehau 			CPU_SETOF(cpu, &cpu_set);
718*15516c77SSepherosa Ziehau 			taskqueue_start_threads_cpuset(&sc->hn_tx_taskq, 1,
719*15516c77SSepherosa Ziehau 			    PI_NET, &cpu_set, "%s tx",
720*15516c77SSepherosa Ziehau 			    device_get_nameunit(dev));
721*15516c77SSepherosa Ziehau 		} else {
722*15516c77SSepherosa Ziehau 			taskqueue_start_threads(&sc->hn_tx_taskq, 1, PI_NET,
723*15516c77SSepherosa Ziehau 			    "%s tx", device_get_nameunit(dev));
724*15516c77SSepherosa Ziehau 		}
725*15516c77SSepherosa Ziehau 	} else {
726*15516c77SSepherosa Ziehau 		sc->hn_tx_taskq = hn_tx_taskq;
727*15516c77SSepherosa Ziehau 	}
728*15516c77SSepherosa Ziehau 
729*15516c77SSepherosa Ziehau 	/*
730*15516c77SSepherosa Ziehau 	 * Setup taskqueue for mangement tasks, e.g. link status.
731*15516c77SSepherosa Ziehau 	 */
732*15516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK,
733*15516c77SSepherosa Ziehau 	    taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0);
734*15516c77SSepherosa Ziehau 	taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
735*15516c77SSepherosa Ziehau 	    device_get_nameunit(dev));
736*15516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
737*15516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc);
738*15516c77SSepherosa Ziehau 	TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0,
739*15516c77SSepherosa Ziehau 	    hn_netchg_status_taskfunc, sc);
740*15516c77SSepherosa Ziehau 
741*15516c77SSepherosa Ziehau 	/*
742*15516c77SSepherosa Ziehau 	 * Allocate ifnet and setup its name earlier, so that if_printf
743*15516c77SSepherosa Ziehau 	 * can be used by functions, which will be called after
744*15516c77SSepherosa Ziehau 	 * ether_ifattach().
745*15516c77SSepherosa Ziehau 	 */
746*15516c77SSepherosa Ziehau 	ifp = sc->hn_ifp = if_alloc(IFT_ETHER);
747*15516c77SSepherosa Ziehau 	ifp->if_softc = sc;
748*15516c77SSepherosa Ziehau 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
749*15516c77SSepherosa Ziehau 
750*15516c77SSepherosa Ziehau 	/*
751*15516c77SSepherosa Ziehau 	 * Initialize ifmedia earlier so that it can be unconditionally
752*15516c77SSepherosa Ziehau 	 * destroyed, if error happened later on.
753*15516c77SSepherosa Ziehau 	 */
754*15516c77SSepherosa Ziehau 	ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts);
755*15516c77SSepherosa Ziehau 
756*15516c77SSepherosa Ziehau 	/*
757*15516c77SSepherosa Ziehau 	 * Figure out the # of RX rings (ring_cnt) and the # of TX rings
758*15516c77SSepherosa Ziehau 	 * to use (tx_ring_cnt).
759*15516c77SSepherosa Ziehau 	 *
760*15516c77SSepherosa Ziehau 	 * NOTE:
761*15516c77SSepherosa Ziehau 	 * The # of RX rings to use is same as the # of channels to use.
762*15516c77SSepherosa Ziehau 	 */
763*15516c77SSepherosa Ziehau 	ring_cnt = hn_chan_cnt;
764*15516c77SSepherosa Ziehau 	if (ring_cnt <= 0) {
765*15516c77SSepherosa Ziehau 		/* Default */
766*15516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
767*15516c77SSepherosa Ziehau 		if (ring_cnt > HN_RING_CNT_DEF_MAX)
768*15516c77SSepherosa Ziehau 			ring_cnt = HN_RING_CNT_DEF_MAX;
769*15516c77SSepherosa Ziehau 	} else if (ring_cnt > mp_ncpus) {
770*15516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
771*15516c77SSepherosa Ziehau 	}
772*15516c77SSepherosa Ziehau 
773*15516c77SSepherosa Ziehau 	tx_ring_cnt = hn_tx_ring_cnt;
774*15516c77SSepherosa Ziehau 	if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt)
775*15516c77SSepherosa Ziehau 		tx_ring_cnt = ring_cnt;
776*15516c77SSepherosa Ziehau 	if (hn_use_if_start) {
777*15516c77SSepherosa Ziehau 		/* ifnet.if_start only needs one TX ring. */
778*15516c77SSepherosa Ziehau 		tx_ring_cnt = 1;
779*15516c77SSepherosa Ziehau 	}
780*15516c77SSepherosa Ziehau 
781*15516c77SSepherosa Ziehau 	/*
782*15516c77SSepherosa Ziehau 	 * Set the leader CPU for channels.
783*15516c77SSepherosa Ziehau 	 */
784*15516c77SSepherosa Ziehau 	sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus;
785*15516c77SSepherosa Ziehau 
786*15516c77SSepherosa Ziehau 	/*
787*15516c77SSepherosa Ziehau 	 * Create enough TX/RX rings, even if only limited number of
788*15516c77SSepherosa Ziehau 	 * channels can be allocated.
789*15516c77SSepherosa Ziehau 	 */
790*15516c77SSepherosa Ziehau 	error = hn_create_tx_data(sc, tx_ring_cnt);
791*15516c77SSepherosa Ziehau 	if (error)
792*15516c77SSepherosa Ziehau 		goto failed;
793*15516c77SSepherosa Ziehau 	error = hn_create_rx_data(sc, ring_cnt);
794*15516c77SSepherosa Ziehau 	if (error)
795*15516c77SSepherosa Ziehau 		goto failed;
796*15516c77SSepherosa Ziehau 
797*15516c77SSepherosa Ziehau 	/*
798*15516c77SSepherosa Ziehau 	 * Create transaction context for NVS and RNDIS transactions.
799*15516c77SSepherosa Ziehau 	 */
800*15516c77SSepherosa Ziehau 	sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
801*15516c77SSepherosa Ziehau 	    HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
802*15516c77SSepherosa Ziehau 	if (sc->hn_xact == NULL)
803*15516c77SSepherosa Ziehau 		goto failed;
804*15516c77SSepherosa Ziehau 
805*15516c77SSepherosa Ziehau 	/*
806*15516c77SSepherosa Ziehau 	 * Attach the synthetic parts, i.e. NVS and RNDIS.
807*15516c77SSepherosa Ziehau 	 */
808*15516c77SSepherosa Ziehau 	error = hn_synth_attach(sc, ETHERMTU);
809*15516c77SSepherosa Ziehau 	if (error)
810*15516c77SSepherosa Ziehau 		goto failed;
811*15516c77SSepherosa Ziehau 
812*15516c77SSepherosa Ziehau 	error = hn_rndis_get_eaddr(sc, eaddr);
813*15516c77SSepherosa Ziehau 	if (error)
814*15516c77SSepherosa Ziehau 		goto failed;
815*15516c77SSepherosa Ziehau 
816*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
817*15516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
818*15516c77SSepherosa Ziehau 		/*
819*15516c77SSepherosa Ziehau 		 * Reduce TCP segment aggregation limit for multiple
820*15516c77SSepherosa Ziehau 		 * RX rings to increase ACK timeliness.
821*15516c77SSepherosa Ziehau 		 */
822*15516c77SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF);
823*15516c77SSepherosa Ziehau 	}
824*15516c77SSepherosa Ziehau #endif
825*15516c77SSepherosa Ziehau 
826*15516c77SSepherosa Ziehau 	/*
827*15516c77SSepherosa Ziehau 	 * Fixup TX stuffs after synthetic parts are attached.
828*15516c77SSepherosa Ziehau 	 */
829*15516c77SSepherosa Ziehau 	hn_fixup_tx_data(sc);
830*15516c77SSepherosa Ziehau 
831*15516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
832*15516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
833*15516c77SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD,
834*15516c77SSepherosa Ziehau 	    &sc->hn_nvs_ver, 0, "NVS version");
835*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version",
836*15516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
837*15516c77SSepherosa Ziehau 	    hn_ndis_version_sysctl, "A", "NDIS version");
838*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps",
839*15516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
840*15516c77SSepherosa Ziehau 	    hn_caps_sysctl, "A", "capabilities");
841*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist",
842*15516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
843*15516c77SSepherosa Ziehau 	    hn_hwassist_sysctl, "A", "hwassist");
844*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter",
845*15516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
846*15516c77SSepherosa Ziehau 	    hn_rxfilter_sysctl, "A", "rxfilter");
847*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash",
848*15516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
849*15516c77SSepherosa Ziehau 	    hn_rss_hash_sysctl, "A", "RSS hash");
850*15516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size",
851*15516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count");
852*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key",
853*15516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
854*15516c77SSepherosa Ziehau 	    hn_rss_key_sysctl, "IU", "RSS key");
855*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind",
856*15516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
857*15516c77SSepherosa Ziehau 	    hn_rss_ind_sysctl, "IU", "RSS indirect table");
858*15516c77SSepherosa Ziehau 
859*15516c77SSepherosa Ziehau 	/*
860*15516c77SSepherosa Ziehau 	 * Setup the ifmedia, which has been initialized earlier.
861*15516c77SSepherosa Ziehau 	 */
862*15516c77SSepherosa Ziehau 	ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL);
863*15516c77SSepherosa Ziehau 	ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO);
864*15516c77SSepherosa Ziehau 	/* XXX ifmedia_set really should do this for us */
865*15516c77SSepherosa Ziehau 	sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media;
866*15516c77SSepherosa Ziehau 
867*15516c77SSepherosa Ziehau 	/*
868*15516c77SSepherosa Ziehau 	 * Setup the ifnet for this interface.
869*15516c77SSepherosa Ziehau 	 */
870*15516c77SSepherosa Ziehau 
871*15516c77SSepherosa Ziehau 	ifp->if_baudrate = IF_Gbps(10);
872*15516c77SSepherosa Ziehau 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
873*15516c77SSepherosa Ziehau 	ifp->if_ioctl = hn_ioctl;
874*15516c77SSepherosa Ziehau 	ifp->if_init = hn_init;
875*15516c77SSepherosa Ziehau 	if (hn_use_if_start) {
876*15516c77SSepherosa Ziehau 		int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]);
877*15516c77SSepherosa Ziehau 
878*15516c77SSepherosa Ziehau 		ifp->if_start = hn_start;
879*15516c77SSepherosa Ziehau 		IFQ_SET_MAXLEN(&ifp->if_snd, qdepth);
880*15516c77SSepherosa Ziehau 		ifp->if_snd.ifq_drv_maxlen = qdepth - 1;
881*15516c77SSepherosa Ziehau 		IFQ_SET_READY(&ifp->if_snd);
882*15516c77SSepherosa Ziehau 	} else {
883*15516c77SSepherosa Ziehau 		ifp->if_transmit = hn_transmit;
884*15516c77SSepherosa Ziehau 		ifp->if_qflush = hn_xmit_qflush;
885*15516c77SSepherosa Ziehau 	}
886*15516c77SSepherosa Ziehau 
887*15516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO;
888*15516c77SSepherosa Ziehau #ifdef foo
889*15516c77SSepherosa Ziehau 	/* We can't diff IPv6 packets from IPv4 packets on RX path. */
890*15516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM_IPV6;
891*15516c77SSepherosa Ziehau #endif
892*15516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_VLAN) {
893*15516c77SSepherosa Ziehau 		/* XXX not sure about VLAN_MTU. */
894*15516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
895*15516c77SSepherosa Ziehau 	}
896*15516c77SSepherosa Ziehau 
897*15516c77SSepherosa Ziehau 	ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist;
898*15516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP_MASK)
899*15516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM;
900*15516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP6_MASK)
901*15516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM_IPV6;
902*15516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO4) {
903*15516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO4;
904*15516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP_TSO;
905*15516c77SSepherosa Ziehau 	}
906*15516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO6) {
907*15516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO6;
908*15516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP6_TSO;
909*15516c77SSepherosa Ziehau 	}
910*15516c77SSepherosa Ziehau 
911*15516c77SSepherosa Ziehau 	/* Enable all available capabilities by default. */
912*15516c77SSepherosa Ziehau 	ifp->if_capenable = ifp->if_capabilities;
913*15516c77SSepherosa Ziehau 
914*15516c77SSepherosa Ziehau 	if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) {
915*15516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU);
916*15516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX;
917*15516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = PAGE_SIZE;
918*15516c77SSepherosa Ziehau 	}
919*15516c77SSepherosa Ziehau 
920*15516c77SSepherosa Ziehau 	ether_ifattach(ifp, eaddr);
921*15516c77SSepherosa Ziehau 
922*15516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) {
923*15516c77SSepherosa Ziehau 		if_printf(ifp, "TSO segcnt %u segsz %u\n",
924*15516c77SSepherosa Ziehau 		    ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize);
925*15516c77SSepherosa Ziehau 	}
926*15516c77SSepherosa Ziehau 
927*15516c77SSepherosa Ziehau 	/* Inform the upper layer about the long frame support. */
928*15516c77SSepherosa Ziehau 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
929*15516c77SSepherosa Ziehau 
930*15516c77SSepherosa Ziehau 	/*
931*15516c77SSepherosa Ziehau 	 * Kick off link status check.
932*15516c77SSepherosa Ziehau 	 */
933*15516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
934*15516c77SSepherosa Ziehau 	hn_update_link_status(sc);
935*15516c77SSepherosa Ziehau 
936*15516c77SSepherosa Ziehau 	return (0);
937*15516c77SSepherosa Ziehau failed:
938*15516c77SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)
939*15516c77SSepherosa Ziehau 		hn_synth_detach(sc);
940*15516c77SSepherosa Ziehau 	hn_detach(dev);
941*15516c77SSepherosa Ziehau 	return (error);
942*15516c77SSepherosa Ziehau }
943*15516c77SSepherosa Ziehau 
944*15516c77SSepherosa Ziehau static int
945*15516c77SSepherosa Ziehau hn_detach(device_t dev)
946*15516c77SSepherosa Ziehau {
947*15516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
948*15516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
949*15516c77SSepherosa Ziehau 
950*15516c77SSepherosa Ziehau 	if (device_is_attached(dev)) {
951*15516c77SSepherosa Ziehau 		HN_LOCK(sc);
952*15516c77SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
953*15516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
954*15516c77SSepherosa Ziehau 				hn_stop(sc);
955*15516c77SSepherosa Ziehau 			/*
956*15516c77SSepherosa Ziehau 			 * NOTE:
957*15516c77SSepherosa Ziehau 			 * hn_stop() only suspends data, so managment
958*15516c77SSepherosa Ziehau 			 * stuffs have to be suspended manually here.
959*15516c77SSepherosa Ziehau 			 */
960*15516c77SSepherosa Ziehau 			hn_suspend_mgmt(sc);
961*15516c77SSepherosa Ziehau 			hn_synth_detach(sc);
962*15516c77SSepherosa Ziehau 		}
963*15516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
964*15516c77SSepherosa Ziehau 		ether_ifdetach(ifp);
965*15516c77SSepherosa Ziehau 	}
966*15516c77SSepherosa Ziehau 
967*15516c77SSepherosa Ziehau 	ifmedia_removeall(&sc->hn_media);
968*15516c77SSepherosa Ziehau 	hn_destroy_rx_data(sc);
969*15516c77SSepherosa Ziehau 	hn_destroy_tx_data(sc);
970*15516c77SSepherosa Ziehau 
971*15516c77SSepherosa Ziehau 	if (sc->hn_tx_taskq != hn_tx_taskq)
972*15516c77SSepherosa Ziehau 		taskqueue_free(sc->hn_tx_taskq);
973*15516c77SSepherosa Ziehau 	taskqueue_free(sc->hn_mgmt_taskq0);
974*15516c77SSepherosa Ziehau 
975*15516c77SSepherosa Ziehau 	if (sc->hn_xact != NULL)
976*15516c77SSepherosa Ziehau 		vmbus_xact_ctx_destroy(sc->hn_xact);
977*15516c77SSepherosa Ziehau 
978*15516c77SSepherosa Ziehau 	if_free(ifp);
979*15516c77SSepherosa Ziehau 
980*15516c77SSepherosa Ziehau 	HN_LOCK_DESTROY(sc);
981*15516c77SSepherosa Ziehau 	return (0);
982*15516c77SSepherosa Ziehau }
983*15516c77SSepherosa Ziehau 
984*15516c77SSepherosa Ziehau static int
985*15516c77SSepherosa Ziehau hn_shutdown(device_t dev)
986*15516c77SSepherosa Ziehau {
987*15516c77SSepherosa Ziehau 
988*15516c77SSepherosa Ziehau 	return (0);
989*15516c77SSepherosa Ziehau }
990*15516c77SSepherosa Ziehau 
991*15516c77SSepherosa Ziehau static void
992*15516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc)
993*15516c77SSepherosa Ziehau {
994*15516c77SSepherosa Ziehau 	uint32_t link_status;
995*15516c77SSepherosa Ziehau 	int error;
996*15516c77SSepherosa Ziehau 
997*15516c77SSepherosa Ziehau 	error = hn_rndis_get_linkstatus(sc, &link_status);
998*15516c77SSepherosa Ziehau 	if (error) {
999*15516c77SSepherosa Ziehau 		/* XXX what to do? */
1000*15516c77SSepherosa Ziehau 		return;
1001*15516c77SSepherosa Ziehau 	}
1002*15516c77SSepherosa Ziehau 
1003*15516c77SSepherosa Ziehau 	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
1004*15516c77SSepherosa Ziehau 		sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
1005*15516c77SSepherosa Ziehau 	else
1006*15516c77SSepherosa Ziehau 		sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
1007*15516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp,
1008*15516c77SSepherosa Ziehau 	    (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ?
1009*15516c77SSepherosa Ziehau 	    LINK_STATE_UP : LINK_STATE_DOWN);
1010*15516c77SSepherosa Ziehau }
1011*15516c77SSepherosa Ziehau 
1012*15516c77SSepherosa Ziehau static void
1013*15516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused)
1014*15516c77SSepherosa Ziehau {
1015*15516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
1016*15516c77SSepherosa Ziehau 
1017*15516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
1018*15516c77SSepherosa Ziehau 		return;
1019*15516c77SSepherosa Ziehau 	hn_link_status(sc);
1020*15516c77SSepherosa Ziehau }
1021*15516c77SSepherosa Ziehau 
1022*15516c77SSepherosa Ziehau static void
1023*15516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused)
1024*15516c77SSepherosa Ziehau {
1025*15516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
1026*15516c77SSepherosa Ziehau 
1027*15516c77SSepherosa Ziehau 	/* Prevent any link status checks from running. */
1028*15516c77SSepherosa Ziehau 	sc->hn_link_flags |= HN_LINK_FLAG_NETCHG;
1029*15516c77SSepherosa Ziehau 
1030*15516c77SSepherosa Ziehau 	/*
1031*15516c77SSepherosa Ziehau 	 * Fake up a [link down --> link up] state change; 5 seconds
1032*15516c77SSepherosa Ziehau 	 * delay is used, which closely simulates miibus reaction
1033*15516c77SSepherosa Ziehau 	 * upon link down event.
1034*15516c77SSepherosa Ziehau 	 */
1035*15516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
1036*15516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
1037*15516c77SSepherosa Ziehau 	taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0,
1038*15516c77SSepherosa Ziehau 	    &sc->hn_netchg_status, 5 * hz);
1039*15516c77SSepherosa Ziehau }
1040*15516c77SSepherosa Ziehau 
1041*15516c77SSepherosa Ziehau static void
1042*15516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused)
1043*15516c77SSepherosa Ziehau {
1044*15516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
1045*15516c77SSepherosa Ziehau 
1046*15516c77SSepherosa Ziehau 	/* Re-allow link status checks. */
1047*15516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG;
1048*15516c77SSepherosa Ziehau 	hn_link_status(sc);
1049*15516c77SSepherosa Ziehau }
1050*15516c77SSepherosa Ziehau 
1051*15516c77SSepherosa Ziehau static void
1052*15516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc)
1053*15516c77SSepherosa Ziehau {
1054*15516c77SSepherosa Ziehau 
1055*15516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
1056*15516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
1057*15516c77SSepherosa Ziehau }
1058*15516c77SSepherosa Ziehau 
1059*15516c77SSepherosa Ziehau static void
1060*15516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc)
1061*15516c77SSepherosa Ziehau {
1062*15516c77SSepherosa Ziehau 
1063*15516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
1064*15516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init);
1065*15516c77SSepherosa Ziehau }
1066*15516c77SSepherosa Ziehau 
1067*15516c77SSepherosa Ziehau static __inline int
1068*15516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
1069*15516c77SSepherosa Ziehau     struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
1070*15516c77SSepherosa Ziehau {
1071*15516c77SSepherosa Ziehau 	struct mbuf *m = *m_head;
1072*15516c77SSepherosa Ziehau 	int error;
1073*15516c77SSepherosa Ziehau 
1074*15516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim"));
1075*15516c77SSepherosa Ziehau 
1076*15516c77SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap,
1077*15516c77SSepherosa Ziehau 	    m, segs, nsegs, BUS_DMA_NOWAIT);
1078*15516c77SSepherosa Ziehau 	if (error == EFBIG) {
1079*15516c77SSepherosa Ziehau 		struct mbuf *m_new;
1080*15516c77SSepherosa Ziehau 
1081*15516c77SSepherosa Ziehau 		m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX);
1082*15516c77SSepherosa Ziehau 		if (m_new == NULL)
1083*15516c77SSepherosa Ziehau 			return ENOBUFS;
1084*15516c77SSepherosa Ziehau 		else
1085*15516c77SSepherosa Ziehau 			*m_head = m = m_new;
1086*15516c77SSepherosa Ziehau 		txr->hn_tx_collapsed++;
1087*15516c77SSepherosa Ziehau 
1088*15516c77SSepherosa Ziehau 		error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag,
1089*15516c77SSepherosa Ziehau 		    txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT);
1090*15516c77SSepherosa Ziehau 	}
1091*15516c77SSepherosa Ziehau 	if (!error) {
1092*15516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap,
1093*15516c77SSepherosa Ziehau 		    BUS_DMASYNC_PREWRITE);
1094*15516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_DMAMAP;
1095*15516c77SSepherosa Ziehau 	}
1096*15516c77SSepherosa Ziehau 	return error;
1097*15516c77SSepherosa Ziehau }
1098*15516c77SSepherosa Ziehau 
1099*15516c77SSepherosa Ziehau static __inline int
1100*15516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd)
1101*15516c77SSepherosa Ziehau {
1102*15516c77SSepherosa Ziehau 
1103*15516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0,
1104*15516c77SSepherosa Ziehau 	    ("put an onlist txd %#x", txd->flags));
1105*15516c77SSepherosa Ziehau 
1106*15516c77SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
1107*15516c77SSepherosa Ziehau 	if (atomic_fetchadd_int(&txd->refs, -1) != 1)
1108*15516c77SSepherosa Ziehau 		return 0;
1109*15516c77SSepherosa Ziehau 
1110*15516c77SSepherosa Ziehau 	if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) {
1111*15516c77SSepherosa Ziehau 		KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
1112*15516c77SSepherosa Ziehau 		    ("chim txd uses dmamap"));
1113*15516c77SSepherosa Ziehau 		hn_chim_free(txr->hn_sc, txd->chim_index);
1114*15516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
1115*15516c77SSepherosa Ziehau 	} else if (txd->flags & HN_TXD_FLAG_DMAMAP) {
1116*15516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag,
1117*15516c77SSepherosa Ziehau 		    txd->data_dmap, BUS_DMASYNC_POSTWRITE);
1118*15516c77SSepherosa Ziehau 		bus_dmamap_unload(txr->hn_tx_data_dtag,
1119*15516c77SSepherosa Ziehau 		    txd->data_dmap);
1120*15516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_DMAMAP;
1121*15516c77SSepherosa Ziehau 	}
1122*15516c77SSepherosa Ziehau 
1123*15516c77SSepherosa Ziehau 	if (txd->m != NULL) {
1124*15516c77SSepherosa Ziehau 		m_freem(txd->m);
1125*15516c77SSepherosa Ziehau 		txd->m = NULL;
1126*15516c77SSepherosa Ziehau 	}
1127*15516c77SSepherosa Ziehau 
1128*15516c77SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONLIST;
1129*15516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
1130*15516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
1131*15516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_avail >= 0 &&
1132*15516c77SSepherosa Ziehau 	    txr->hn_txdesc_avail < txr->hn_txdesc_cnt,
1133*15516c77SSepherosa Ziehau 	    ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail));
1134*15516c77SSepherosa Ziehau 	txr->hn_txdesc_avail++;
1135*15516c77SSepherosa Ziehau 	SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
1136*15516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
1137*15516c77SSepherosa Ziehau #else
1138*15516c77SSepherosa Ziehau 	atomic_add_int(&txr->hn_txdesc_avail, 1);
1139*15516c77SSepherosa Ziehau 	buf_ring_enqueue(txr->hn_txdesc_br, txd);
1140*15516c77SSepherosa Ziehau #endif
1141*15516c77SSepherosa Ziehau 
1142*15516c77SSepherosa Ziehau 	return 1;
1143*15516c77SSepherosa Ziehau }
1144*15516c77SSepherosa Ziehau 
1145*15516c77SSepherosa Ziehau static __inline struct hn_txdesc *
1146*15516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr)
1147*15516c77SSepherosa Ziehau {
1148*15516c77SSepherosa Ziehau 	struct hn_txdesc *txd;
1149*15516c77SSepherosa Ziehau 
1150*15516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
1151*15516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
1152*15516c77SSepherosa Ziehau 	txd = SLIST_FIRST(&txr->hn_txlist);
1153*15516c77SSepherosa Ziehau 	if (txd != NULL) {
1154*15516c77SSepherosa Ziehau 		KASSERT(txr->hn_txdesc_avail > 0,
1155*15516c77SSepherosa Ziehau 		    ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail));
1156*15516c77SSepherosa Ziehau 		txr->hn_txdesc_avail--;
1157*15516c77SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&txr->hn_txlist, link);
1158*15516c77SSepherosa Ziehau 	}
1159*15516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
1160*15516c77SSepherosa Ziehau #else
1161*15516c77SSepherosa Ziehau 	txd = buf_ring_dequeue_sc(txr->hn_txdesc_br);
1162*15516c77SSepherosa Ziehau #endif
1163*15516c77SSepherosa Ziehau 
1164*15516c77SSepherosa Ziehau 	if (txd != NULL) {
1165*15516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
1166*15516c77SSepherosa Ziehau 		atomic_subtract_int(&txr->hn_txdesc_avail, 1);
1167*15516c77SSepherosa Ziehau #endif
1168*15516c77SSepherosa Ziehau 		KASSERT(txd->m == NULL && txd->refs == 0 &&
1169*15516c77SSepherosa Ziehau 		    txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
1170*15516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONLIST) &&
1171*15516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd"));
1172*15516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_ONLIST;
1173*15516c77SSepherosa Ziehau 		txd->refs = 1;
1174*15516c77SSepherosa Ziehau 	}
1175*15516c77SSepherosa Ziehau 	return txd;
1176*15516c77SSepherosa Ziehau }
1177*15516c77SSepherosa Ziehau 
1178*15516c77SSepherosa Ziehau static __inline void
1179*15516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd)
1180*15516c77SSepherosa Ziehau {
1181*15516c77SSepherosa Ziehau 
1182*15516c77SSepherosa Ziehau 	/* 0->1 transition will never work */
1183*15516c77SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid refs %d", txd->refs));
1184*15516c77SSepherosa Ziehau 	atomic_add_int(&txd->refs, 1);
1185*15516c77SSepherosa Ziehau }
1186*15516c77SSepherosa Ziehau 
1187*15516c77SSepherosa Ziehau static bool
1188*15516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr)
1189*15516c77SSepherosa Ziehau {
1190*15516c77SSepherosa Ziehau 	bool pending = false;
1191*15516c77SSepherosa Ziehau 
1192*15516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
1193*15516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
1194*15516c77SSepherosa Ziehau 	if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt)
1195*15516c77SSepherosa Ziehau 		pending = true;
1196*15516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
1197*15516c77SSepherosa Ziehau #else
1198*15516c77SSepherosa Ziehau 	if (!buf_ring_full(txr->hn_txdesc_br))
1199*15516c77SSepherosa Ziehau 		pending = true;
1200*15516c77SSepherosa Ziehau #endif
1201*15516c77SSepherosa Ziehau 	return (pending);
1202*15516c77SSepherosa Ziehau }
1203*15516c77SSepherosa Ziehau 
1204*15516c77SSepherosa Ziehau static __inline void
1205*15516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr)
1206*15516c77SSepherosa Ziehau {
1207*15516c77SSepherosa Ziehau 	txr->hn_has_txeof = 0;
1208*15516c77SSepherosa Ziehau 	txr->hn_txeof(txr);
1209*15516c77SSepherosa Ziehau }
1210*15516c77SSepherosa Ziehau 
1211*15516c77SSepherosa Ziehau static void
1212*15516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc,
1213*15516c77SSepherosa Ziehau     struct vmbus_channel *chan, const void *data __unused, int dlen __unused)
1214*15516c77SSepherosa Ziehau {
1215*15516c77SSepherosa Ziehau 	struct hn_txdesc *txd = sndc->hn_cbarg;
1216*15516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
1217*15516c77SSepherosa Ziehau 
1218*15516c77SSepherosa Ziehau 	txr = txd->txr;
1219*15516c77SSepherosa Ziehau 	KASSERT(txr->hn_chan == chan,
1220*15516c77SSepherosa Ziehau 	    ("channel mismatch, on chan%u, should be chan%u",
1221*15516c77SSepherosa Ziehau 	     vmbus_chan_subidx(chan), vmbus_chan_subidx(txr->hn_chan)));
1222*15516c77SSepherosa Ziehau 
1223*15516c77SSepherosa Ziehau 	txr->hn_has_txeof = 1;
1224*15516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
1225*15516c77SSepherosa Ziehau 
1226*15516c77SSepherosa Ziehau 	++txr->hn_txdone_cnt;
1227*15516c77SSepherosa Ziehau 	if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) {
1228*15516c77SSepherosa Ziehau 		txr->hn_txdone_cnt = 0;
1229*15516c77SSepherosa Ziehau 		if (txr->hn_oactive)
1230*15516c77SSepherosa Ziehau 			hn_txeof(txr);
1231*15516c77SSepherosa Ziehau 	}
1232*15516c77SSepherosa Ziehau }
1233*15516c77SSepherosa Ziehau 
1234*15516c77SSepherosa Ziehau static void
1235*15516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
1236*15516c77SSepherosa Ziehau {
1237*15516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
1238*15516c77SSepherosa Ziehau 	tcp_lro_flush_all(&rxr->hn_lro);
1239*15516c77SSepherosa Ziehau #endif
1240*15516c77SSepherosa Ziehau 
1241*15516c77SSepherosa Ziehau 	/*
1242*15516c77SSepherosa Ziehau 	 * NOTE:
1243*15516c77SSepherosa Ziehau 	 * 'txr' could be NULL, if multiple channels and
1244*15516c77SSepherosa Ziehau 	 * ifnet.if_start method are enabled.
1245*15516c77SSepherosa Ziehau 	 */
1246*15516c77SSepherosa Ziehau 	if (txr == NULL || !txr->hn_has_txeof)
1247*15516c77SSepherosa Ziehau 		return;
1248*15516c77SSepherosa Ziehau 
1249*15516c77SSepherosa Ziehau 	txr->hn_txdone_cnt = 0;
1250*15516c77SSepherosa Ziehau 	hn_txeof(txr);
1251*15516c77SSepherosa Ziehau }
1252*15516c77SSepherosa Ziehau 
1253*15516c77SSepherosa Ziehau static __inline uint32_t
1254*15516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs)
1255*15516c77SSepherosa Ziehau {
1256*15516c77SSepherosa Ziehau 
1257*15516c77SSepherosa Ziehau 	KASSERT(ofs >= sizeof(struct rndis_packet_msg),
1258*15516c77SSepherosa Ziehau 	    ("invalid RNDIS packet msg offset %u", ofs));
1259*15516c77SSepherosa Ziehau 	return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset));
1260*15516c77SSepherosa Ziehau }
1261*15516c77SSepherosa Ziehau 
1262*15516c77SSepherosa Ziehau static __inline void *
1263*15516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
1264*15516c77SSepherosa Ziehau     size_t pi_dlen, uint32_t pi_type)
1265*15516c77SSepherosa Ziehau {
1266*15516c77SSepherosa Ziehau 	const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
1267*15516c77SSepherosa Ziehau 	struct rndis_pktinfo *pi;
1268*15516c77SSepherosa Ziehau 
1269*15516c77SSepherosa Ziehau 	KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
1270*15516c77SSepherosa Ziehau 	    ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
1271*15516c77SSepherosa Ziehau 
1272*15516c77SSepherosa Ziehau 	/*
1273*15516c77SSepherosa Ziehau 	 * Per-packet-info does not move; it only grows.
1274*15516c77SSepherosa Ziehau 	 *
1275*15516c77SSepherosa Ziehau 	 * NOTE:
1276*15516c77SSepherosa Ziehau 	 * rm_pktinfooffset in this phase counts from the beginning
1277*15516c77SSepherosa Ziehau 	 * of rndis_packet_msg.
1278*15516c77SSepherosa Ziehau 	 */
1279*15516c77SSepherosa Ziehau 	KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
1280*15516c77SSepherosa Ziehau 	    ("%u pktinfo overflows RNDIS packet msg", pi_type));
1281*15516c77SSepherosa Ziehau 	pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
1282*15516c77SSepherosa Ziehau 	    pkt->rm_pktinfolen);
1283*15516c77SSepherosa Ziehau 	pkt->rm_pktinfolen += pi_size;
1284*15516c77SSepherosa Ziehau 
1285*15516c77SSepherosa Ziehau 	pi->rm_size = pi_size;
1286*15516c77SSepherosa Ziehau 	pi->rm_type = pi_type;
1287*15516c77SSepherosa Ziehau 	pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
1288*15516c77SSepherosa Ziehau 
1289*15516c77SSepherosa Ziehau 	/* Data immediately follow per-packet-info. */
1290*15516c77SSepherosa Ziehau 	pkt->rm_dataoffset += pi_size;
1291*15516c77SSepherosa Ziehau 
1292*15516c77SSepherosa Ziehau 	/* Update RNDIS packet msg length */
1293*15516c77SSepherosa Ziehau 	pkt->rm_len += pi_size;
1294*15516c77SSepherosa Ziehau 
1295*15516c77SSepherosa Ziehau 	return (pi->rm_data);
1296*15516c77SSepherosa Ziehau }
1297*15516c77SSepherosa Ziehau 
1298*15516c77SSepherosa Ziehau /*
1299*15516c77SSepherosa Ziehau  * NOTE:
1300*15516c77SSepherosa Ziehau  * If this function fails, then both txd and m_head0 will be freed.
1301*15516c77SSepherosa Ziehau  */
1302*15516c77SSepherosa Ziehau static int
1303*15516c77SSepherosa Ziehau hn_encap(struct hn_tx_ring *txr, struct hn_txdesc *txd, struct mbuf **m_head0)
1304*15516c77SSepherosa Ziehau {
1305*15516c77SSepherosa Ziehau 	bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX];
1306*15516c77SSepherosa Ziehau 	int error, nsegs, i;
1307*15516c77SSepherosa Ziehau 	struct mbuf *m_head = *m_head0;
1308*15516c77SSepherosa Ziehau 	struct rndis_packet_msg *pkt;
1309*15516c77SSepherosa Ziehau 	uint32_t *pi_data;
1310*15516c77SSepherosa Ziehau 	int pktlen;
1311*15516c77SSepherosa Ziehau 
1312*15516c77SSepherosa Ziehau 	/*
1313*15516c77SSepherosa Ziehau 	 * extension points to the area reserved for the
1314*15516c77SSepherosa Ziehau 	 * rndis_filter_packet, which is placed just after
1315*15516c77SSepherosa Ziehau 	 * the netvsc_packet (and rppi struct, if present;
1316*15516c77SSepherosa Ziehau 	 * length is updated later).
1317*15516c77SSepherosa Ziehau 	 */
1318*15516c77SSepherosa Ziehau 	pkt = txd->rndis_pkt;
1319*15516c77SSepherosa Ziehau 	pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
1320*15516c77SSepherosa Ziehau 	pkt->rm_len = sizeof(*pkt) + m_head->m_pkthdr.len;
1321*15516c77SSepherosa Ziehau 	pkt->rm_dataoffset = sizeof(*pkt);
1322*15516c77SSepherosa Ziehau 	pkt->rm_datalen = m_head->m_pkthdr.len;
1323*15516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = sizeof(*pkt);
1324*15516c77SSepherosa Ziehau 	pkt->rm_pktinfolen = 0;
1325*15516c77SSepherosa Ziehau 
1326*15516c77SSepherosa Ziehau 	if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) {
1327*15516c77SSepherosa Ziehau 		/*
1328*15516c77SSepherosa Ziehau 		 * Set the hash value for this packet, so that the host could
1329*15516c77SSepherosa Ziehau 		 * dispatch the TX done event for this packet back to this TX
1330*15516c77SSepherosa Ziehau 		 * ring's channel.
1331*15516c77SSepherosa Ziehau 		 */
1332*15516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
1333*15516c77SSepherosa Ziehau 		    HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL);
1334*15516c77SSepherosa Ziehau 		*pi_data = txr->hn_tx_idx;
1335*15516c77SSepherosa Ziehau 	}
1336*15516c77SSepherosa Ziehau 
1337*15516c77SSepherosa Ziehau 	if (m_head->m_flags & M_VLANTAG) {
1338*15516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
1339*15516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
1340*15516c77SSepherosa Ziehau 		*pi_data = NDIS_VLAN_INFO_MAKE(
1341*15516c77SSepherosa Ziehau 		    EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag),
1342*15516c77SSepherosa Ziehau 		    EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag),
1343*15516c77SSepherosa Ziehau 		    EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag));
1344*15516c77SSepherosa Ziehau 	}
1345*15516c77SSepherosa Ziehau 
1346*15516c77SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
1347*15516c77SSepherosa Ziehau #if defined(INET6) || defined(INET)
1348*15516c77SSepherosa Ziehau 		struct ether_vlan_header *eh;
1349*15516c77SSepherosa Ziehau 		int ether_len;
1350*15516c77SSepherosa Ziehau 
1351*15516c77SSepherosa Ziehau 		/*
1352*15516c77SSepherosa Ziehau 		 * XXX need m_pullup and use mtodo
1353*15516c77SSepherosa Ziehau 		 */
1354*15516c77SSepherosa Ziehau 		eh = mtod(m_head, struct ether_vlan_header*);
1355*15516c77SSepherosa Ziehau 		if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN))
1356*15516c77SSepherosa Ziehau 			ether_len = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
1357*15516c77SSepherosa Ziehau 		else
1358*15516c77SSepherosa Ziehau 			ether_len = ETHER_HDR_LEN;
1359*15516c77SSepherosa Ziehau 
1360*15516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
1361*15516c77SSepherosa Ziehau 		    NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO);
1362*15516c77SSepherosa Ziehau #ifdef INET
1363*15516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
1364*15516c77SSepherosa Ziehau 			struct ip *ip =
1365*15516c77SSepherosa Ziehau 			    (struct ip *)(m_head->m_data + ether_len);
1366*15516c77SSepherosa Ziehau 			unsigned long iph_len = ip->ip_hl << 2;
1367*15516c77SSepherosa Ziehau 			struct tcphdr *th =
1368*15516c77SSepherosa Ziehau 			    (struct tcphdr *)((caddr_t)ip + iph_len);
1369*15516c77SSepherosa Ziehau 
1370*15516c77SSepherosa Ziehau 			ip->ip_len = 0;
1371*15516c77SSepherosa Ziehau 			ip->ip_sum = 0;
1372*15516c77SSepherosa Ziehau 			th->th_sum = in_pseudo(ip->ip_src.s_addr,
1373*15516c77SSepherosa Ziehau 			    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
1374*15516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV4(0,
1375*15516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
1376*15516c77SSepherosa Ziehau 		}
1377*15516c77SSepherosa Ziehau #endif
1378*15516c77SSepherosa Ziehau #if defined(INET6) && defined(INET)
1379*15516c77SSepherosa Ziehau 		else
1380*15516c77SSepherosa Ziehau #endif
1381*15516c77SSepherosa Ziehau #ifdef INET6
1382*15516c77SSepherosa Ziehau 		{
1383*15516c77SSepherosa Ziehau 			struct ip6_hdr *ip6 = (struct ip6_hdr *)
1384*15516c77SSepherosa Ziehau 			    (m_head->m_data + ether_len);
1385*15516c77SSepherosa Ziehau 			struct tcphdr *th = (struct tcphdr *)(ip6 + 1);
1386*15516c77SSepherosa Ziehau 
1387*15516c77SSepherosa Ziehau 			ip6->ip6_plen = 0;
1388*15516c77SSepherosa Ziehau 			th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
1389*15516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV6(0,
1390*15516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
1391*15516c77SSepherosa Ziehau 		}
1392*15516c77SSepherosa Ziehau #endif
1393*15516c77SSepherosa Ziehau #endif	/* INET6 || INET */
1394*15516c77SSepherosa Ziehau 	} else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) {
1395*15516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
1396*15516c77SSepherosa Ziehau 		    NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
1397*15516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
1398*15516c77SSepherosa Ziehau 		    (CSUM_IP6_TCP | CSUM_IP6_UDP)) {
1399*15516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV6;
1400*15516c77SSepherosa Ziehau 		} else {
1401*15516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV4;
1402*15516c77SSepherosa Ziehau 			if (m_head->m_pkthdr.csum_flags & CSUM_IP)
1403*15516c77SSepherosa Ziehau 				*pi_data |= NDIS_TXCSUM_INFO_IPCS;
1404*15516c77SSepherosa Ziehau 		}
1405*15516c77SSepherosa Ziehau 
1406*15516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP))
1407*15516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_TCPCS;
1408*15516c77SSepherosa Ziehau 		else if (m_head->m_pkthdr.csum_flags &
1409*15516c77SSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP6_UDP))
1410*15516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_UDPCS;
1411*15516c77SSepherosa Ziehau 	}
1412*15516c77SSepherosa Ziehau 
1413*15516c77SSepherosa Ziehau 	pktlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
1414*15516c77SSepherosa Ziehau 	/* Convert RNDIS packet message offsets */
1415*15516c77SSepherosa Ziehau 	pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt->rm_dataoffset);
1416*15516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset);
1417*15516c77SSepherosa Ziehau 
1418*15516c77SSepherosa Ziehau 	/*
1419*15516c77SSepherosa Ziehau 	 * Chimney send, if the packet could fit into one chimney buffer.
1420*15516c77SSepherosa Ziehau 	 */
1421*15516c77SSepherosa Ziehau 	if (pkt->rm_len < txr->hn_chim_size) {
1422*15516c77SSepherosa Ziehau 		txr->hn_tx_chimney_tried++;
1423*15516c77SSepherosa Ziehau 		txd->chim_index = hn_chim_alloc(txr->hn_sc);
1424*15516c77SSepherosa Ziehau 		if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) {
1425*15516c77SSepherosa Ziehau 			uint8_t *dest = txr->hn_sc->hn_chim +
1426*15516c77SSepherosa Ziehau 			    (txd->chim_index * txr->hn_sc->hn_chim_szmax);
1427*15516c77SSepherosa Ziehau 
1428*15516c77SSepherosa Ziehau 			memcpy(dest, pkt, pktlen);
1429*15516c77SSepherosa Ziehau 			dest += pktlen;
1430*15516c77SSepherosa Ziehau 			m_copydata(m_head, 0, m_head->m_pkthdr.len, dest);
1431*15516c77SSepherosa Ziehau 
1432*15516c77SSepherosa Ziehau 			txd->chim_size = pkt->rm_len;
1433*15516c77SSepherosa Ziehau 			txr->hn_gpa_cnt = 0;
1434*15516c77SSepherosa Ziehau 			txr->hn_tx_chimney++;
1435*15516c77SSepherosa Ziehau 			txr->hn_sendpkt = hn_txpkt_chim;
1436*15516c77SSepherosa Ziehau 			goto done;
1437*15516c77SSepherosa Ziehau 		}
1438*15516c77SSepherosa Ziehau 	}
1439*15516c77SSepherosa Ziehau 
1440*15516c77SSepherosa Ziehau 	error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs);
1441*15516c77SSepherosa Ziehau 	if (error) {
1442*15516c77SSepherosa Ziehau 		int freed;
1443*15516c77SSepherosa Ziehau 
1444*15516c77SSepherosa Ziehau 		/*
1445*15516c77SSepherosa Ziehau 		 * This mbuf is not linked w/ the txd yet, so free it now.
1446*15516c77SSepherosa Ziehau 		 */
1447*15516c77SSepherosa Ziehau 		m_freem(m_head);
1448*15516c77SSepherosa Ziehau 		*m_head0 = NULL;
1449*15516c77SSepherosa Ziehau 
1450*15516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
1451*15516c77SSepherosa Ziehau 		KASSERT(freed != 0,
1452*15516c77SSepherosa Ziehau 		    ("fail to free txd upon txdma error"));
1453*15516c77SSepherosa Ziehau 
1454*15516c77SSepherosa Ziehau 		txr->hn_txdma_failed++;
1455*15516c77SSepherosa Ziehau 		if_inc_counter(txr->hn_sc->hn_ifp, IFCOUNTER_OERRORS, 1);
1456*15516c77SSepherosa Ziehau 		return error;
1457*15516c77SSepherosa Ziehau 	}
1458*15516c77SSepherosa Ziehau 	*m_head0 = m_head;
1459*15516c77SSepherosa Ziehau 
1460*15516c77SSepherosa Ziehau 	/* +1 RNDIS packet message */
1461*15516c77SSepherosa Ziehau 	txr->hn_gpa_cnt = nsegs + 1;
1462*15516c77SSepherosa Ziehau 
1463*15516c77SSepherosa Ziehau 	/* send packet with page buffer */
1464*15516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr);
1465*15516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK;
1466*15516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_len = pktlen;
1467*15516c77SSepherosa Ziehau 
1468*15516c77SSepherosa Ziehau 	/*
1469*15516c77SSepherosa Ziehau 	 * Fill the page buffers with mbuf info after the page
1470*15516c77SSepherosa Ziehau 	 * buffer for RNDIS packet message.
1471*15516c77SSepherosa Ziehau 	 */
1472*15516c77SSepherosa Ziehau 	for (i = 0; i < nsegs; ++i) {
1473*15516c77SSepherosa Ziehau 		struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1];
1474*15516c77SSepherosa Ziehau 
1475*15516c77SSepherosa Ziehau 		gpa->gpa_page = atop(segs[i].ds_addr);
1476*15516c77SSepherosa Ziehau 		gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK;
1477*15516c77SSepherosa Ziehau 		gpa->gpa_len = segs[i].ds_len;
1478*15516c77SSepherosa Ziehau 	}
1479*15516c77SSepherosa Ziehau 
1480*15516c77SSepherosa Ziehau 	txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
1481*15516c77SSepherosa Ziehau 	txd->chim_size = 0;
1482*15516c77SSepherosa Ziehau 	txr->hn_sendpkt = hn_txpkt_sglist;
1483*15516c77SSepherosa Ziehau done:
1484*15516c77SSepherosa Ziehau 	txd->m = m_head;
1485*15516c77SSepherosa Ziehau 
1486*15516c77SSepherosa Ziehau 	/* Set the completion routine */
1487*15516c77SSepherosa Ziehau 	hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd);
1488*15516c77SSepherosa Ziehau 
1489*15516c77SSepherosa Ziehau 	return 0;
1490*15516c77SSepherosa Ziehau }
1491*15516c77SSepherosa Ziehau 
1492*15516c77SSepherosa Ziehau /*
1493*15516c77SSepherosa Ziehau  * NOTE:
1494*15516c77SSepherosa Ziehau  * If this function fails, then txd will be freed, but the mbuf
1495*15516c77SSepherosa Ziehau  * associated w/ the txd will _not_ be freed.
1496*15516c77SSepherosa Ziehau  */
1497*15516c77SSepherosa Ziehau static int
1498*15516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd)
1499*15516c77SSepherosa Ziehau {
1500*15516c77SSepherosa Ziehau 	int error, send_failed = 0;
1501*15516c77SSepherosa Ziehau 
1502*15516c77SSepherosa Ziehau again:
1503*15516c77SSepherosa Ziehau 	/*
1504*15516c77SSepherosa Ziehau 	 * Make sure that txd is not freed before ETHER_BPF_MTAP.
1505*15516c77SSepherosa Ziehau 	 */
1506*15516c77SSepherosa Ziehau 	hn_txdesc_hold(txd);
1507*15516c77SSepherosa Ziehau 	error = txr->hn_sendpkt(txr, txd);
1508*15516c77SSepherosa Ziehau 	if (!error) {
1509*15516c77SSepherosa Ziehau 		ETHER_BPF_MTAP(ifp, txd->m);
1510*15516c77SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
1511*15516c77SSepherosa Ziehau 		if (!hn_use_if_start) {
1512*15516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OBYTES,
1513*15516c77SSepherosa Ziehau 			    txd->m->m_pkthdr.len);
1514*15516c77SSepherosa Ziehau 			if (txd->m->m_flags & M_MCAST)
1515*15516c77SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
1516*15516c77SSepherosa Ziehau 		}
1517*15516c77SSepherosa Ziehau 		txr->hn_pkts++;
1518*15516c77SSepherosa Ziehau 	}
1519*15516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
1520*15516c77SSepherosa Ziehau 
1521*15516c77SSepherosa Ziehau 	if (__predict_false(error)) {
1522*15516c77SSepherosa Ziehau 		int freed;
1523*15516c77SSepherosa Ziehau 
1524*15516c77SSepherosa Ziehau 		/*
1525*15516c77SSepherosa Ziehau 		 * This should "really rarely" happen.
1526*15516c77SSepherosa Ziehau 		 *
1527*15516c77SSepherosa Ziehau 		 * XXX Too many RX to be acked or too many sideband
1528*15516c77SSepherosa Ziehau 		 * commands to run?  Ask netvsc_channel_rollup()
1529*15516c77SSepherosa Ziehau 		 * to kick start later.
1530*15516c77SSepherosa Ziehau 		 */
1531*15516c77SSepherosa Ziehau 		txr->hn_has_txeof = 1;
1532*15516c77SSepherosa Ziehau 		if (!send_failed) {
1533*15516c77SSepherosa Ziehau 			txr->hn_send_failed++;
1534*15516c77SSepherosa Ziehau 			send_failed = 1;
1535*15516c77SSepherosa Ziehau 			/*
1536*15516c77SSepherosa Ziehau 			 * Try sending again after set hn_has_txeof;
1537*15516c77SSepherosa Ziehau 			 * in case that we missed the last
1538*15516c77SSepherosa Ziehau 			 * netvsc_channel_rollup().
1539*15516c77SSepherosa Ziehau 			 */
1540*15516c77SSepherosa Ziehau 			goto again;
1541*15516c77SSepherosa Ziehau 		}
1542*15516c77SSepherosa Ziehau 		if_printf(ifp, "send failed\n");
1543*15516c77SSepherosa Ziehau 
1544*15516c77SSepherosa Ziehau 		/*
1545*15516c77SSepherosa Ziehau 		 * Caller will perform further processing on the
1546*15516c77SSepherosa Ziehau 		 * associated mbuf, so don't free it in hn_txdesc_put();
1547*15516c77SSepherosa Ziehau 		 * only unload it from the DMA map in hn_txdesc_put(),
1548*15516c77SSepherosa Ziehau 		 * if it was loaded.
1549*15516c77SSepherosa Ziehau 		 */
1550*15516c77SSepherosa Ziehau 		txd->m = NULL;
1551*15516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
1552*15516c77SSepherosa Ziehau 		KASSERT(freed != 0,
1553*15516c77SSepherosa Ziehau 		    ("fail to free txd upon send error"));
1554*15516c77SSepherosa Ziehau 
1555*15516c77SSepherosa Ziehau 		txr->hn_send_failed++;
1556*15516c77SSepherosa Ziehau 	}
1557*15516c77SSepherosa Ziehau 	return error;
1558*15516c77SSepherosa Ziehau }
1559*15516c77SSepherosa Ziehau 
1560*15516c77SSepherosa Ziehau /*
1561*15516c77SSepherosa Ziehau  * Start a transmit of one or more packets
1562*15516c77SSepherosa Ziehau  */
1563*15516c77SSepherosa Ziehau static int
1564*15516c77SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len)
1565*15516c77SSepherosa Ziehau {
1566*15516c77SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
1567*15516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
1568*15516c77SSepherosa Ziehau 
1569*15516c77SSepherosa Ziehau 	KASSERT(hn_use_if_start,
1570*15516c77SSepherosa Ziehau 	    ("hn_start_locked is called, when if_start is disabled"));
1571*15516c77SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
1572*15516c77SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
1573*15516c77SSepherosa Ziehau 
1574*15516c77SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
1575*15516c77SSepherosa Ziehau 		return 0;
1576*15516c77SSepherosa Ziehau 
1577*15516c77SSepherosa Ziehau 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
1578*15516c77SSepherosa Ziehau 	    IFF_DRV_RUNNING)
1579*15516c77SSepherosa Ziehau 		return 0;
1580*15516c77SSepherosa Ziehau 
1581*15516c77SSepherosa Ziehau 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
1582*15516c77SSepherosa Ziehau 		struct hn_txdesc *txd;
1583*15516c77SSepherosa Ziehau 		struct mbuf *m_head;
1584*15516c77SSepherosa Ziehau 		int error;
1585*15516c77SSepherosa Ziehau 
1586*15516c77SSepherosa Ziehau 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
1587*15516c77SSepherosa Ziehau 		if (m_head == NULL)
1588*15516c77SSepherosa Ziehau 			break;
1589*15516c77SSepherosa Ziehau 
1590*15516c77SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
1591*15516c77SSepherosa Ziehau 			/*
1592*15516c77SSepherosa Ziehau 			 * This sending could be time consuming; let callers
1593*15516c77SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
1594*15516c77SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
1595*15516c77SSepherosa Ziehau 			 */
1596*15516c77SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
1597*15516c77SSepherosa Ziehau 			return 1;
1598*15516c77SSepherosa Ziehau 		}
1599*15516c77SSepherosa Ziehau 
1600*15516c77SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
1601*15516c77SSepherosa Ziehau 		if (txd == NULL) {
1602*15516c77SSepherosa Ziehau 			txr->hn_no_txdescs++;
1603*15516c77SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
1604*15516c77SSepherosa Ziehau 			atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
1605*15516c77SSepherosa Ziehau 			break;
1606*15516c77SSepherosa Ziehau 		}
1607*15516c77SSepherosa Ziehau 
1608*15516c77SSepherosa Ziehau 		error = hn_encap(txr, txd, &m_head);
1609*15516c77SSepherosa Ziehau 		if (error) {
1610*15516c77SSepherosa Ziehau 			/* Both txd and m_head are freed */
1611*15516c77SSepherosa Ziehau 			continue;
1612*15516c77SSepherosa Ziehau 		}
1613*15516c77SSepherosa Ziehau 
1614*15516c77SSepherosa Ziehau 		error = hn_txpkt(ifp, txr, txd);
1615*15516c77SSepherosa Ziehau 		if (__predict_false(error)) {
1616*15516c77SSepherosa Ziehau 			/* txd is freed, but m_head is not */
1617*15516c77SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
1618*15516c77SSepherosa Ziehau 			atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
1619*15516c77SSepherosa Ziehau 			break;
1620*15516c77SSepherosa Ziehau 		}
1621*15516c77SSepherosa Ziehau 	}
1622*15516c77SSepherosa Ziehau 	return 0;
1623*15516c77SSepherosa Ziehau }
1624*15516c77SSepherosa Ziehau 
1625*15516c77SSepherosa Ziehau /*
1626*15516c77SSepherosa Ziehau  * Append the specified data to the indicated mbuf chain,
1627*15516c77SSepherosa Ziehau  * Extend the mbuf chain if the new data does not fit in
1628*15516c77SSepherosa Ziehau  * existing space.
1629*15516c77SSepherosa Ziehau  *
1630*15516c77SSepherosa Ziehau  * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c.
1631*15516c77SSepherosa Ziehau  * There should be an equivalent in the kernel mbuf code,
1632*15516c77SSepherosa Ziehau  * but there does not appear to be one yet.
1633*15516c77SSepherosa Ziehau  *
1634*15516c77SSepherosa Ziehau  * Differs from m_append() in that additional mbufs are
1635*15516c77SSepherosa Ziehau  * allocated with cluster size MJUMPAGESIZE, and filled
1636*15516c77SSepherosa Ziehau  * accordingly.
1637*15516c77SSepherosa Ziehau  *
1638*15516c77SSepherosa Ziehau  * Return 1 if able to complete the job; otherwise 0.
1639*15516c77SSepherosa Ziehau  */
1640*15516c77SSepherosa Ziehau static int
1641*15516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp)
1642*15516c77SSepherosa Ziehau {
1643*15516c77SSepherosa Ziehau 	struct mbuf *m, *n;
1644*15516c77SSepherosa Ziehau 	int remainder, space;
1645*15516c77SSepherosa Ziehau 
1646*15516c77SSepherosa Ziehau 	for (m = m0; m->m_next != NULL; m = m->m_next)
1647*15516c77SSepherosa Ziehau 		;
1648*15516c77SSepherosa Ziehau 	remainder = len;
1649*15516c77SSepherosa Ziehau 	space = M_TRAILINGSPACE(m);
1650*15516c77SSepherosa Ziehau 	if (space > 0) {
1651*15516c77SSepherosa Ziehau 		/*
1652*15516c77SSepherosa Ziehau 		 * Copy into available space.
1653*15516c77SSepherosa Ziehau 		 */
1654*15516c77SSepherosa Ziehau 		if (space > remainder)
1655*15516c77SSepherosa Ziehau 			space = remainder;
1656*15516c77SSepherosa Ziehau 		bcopy(cp, mtod(m, caddr_t) + m->m_len, space);
1657*15516c77SSepherosa Ziehau 		m->m_len += space;
1658*15516c77SSepherosa Ziehau 		cp += space;
1659*15516c77SSepherosa Ziehau 		remainder -= space;
1660*15516c77SSepherosa Ziehau 	}
1661*15516c77SSepherosa Ziehau 	while (remainder > 0) {
1662*15516c77SSepherosa Ziehau 		/*
1663*15516c77SSepherosa Ziehau 		 * Allocate a new mbuf; could check space
1664*15516c77SSepherosa Ziehau 		 * and allocate a cluster instead.
1665*15516c77SSepherosa Ziehau 		 */
1666*15516c77SSepherosa Ziehau 		n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE);
1667*15516c77SSepherosa Ziehau 		if (n == NULL)
1668*15516c77SSepherosa Ziehau 			break;
1669*15516c77SSepherosa Ziehau 		n->m_len = min(MJUMPAGESIZE, remainder);
1670*15516c77SSepherosa Ziehau 		bcopy(cp, mtod(n, caddr_t), n->m_len);
1671*15516c77SSepherosa Ziehau 		cp += n->m_len;
1672*15516c77SSepherosa Ziehau 		remainder -= n->m_len;
1673*15516c77SSepherosa Ziehau 		m->m_next = n;
1674*15516c77SSepherosa Ziehau 		m = n;
1675*15516c77SSepherosa Ziehau 	}
1676*15516c77SSepherosa Ziehau 	if (m0->m_flags & M_PKTHDR)
1677*15516c77SSepherosa Ziehau 		m0->m_pkthdr.len += len - remainder;
1678*15516c77SSepherosa Ziehau 
1679*15516c77SSepherosa Ziehau 	return (remainder == 0);
1680*15516c77SSepherosa Ziehau }
1681*15516c77SSepherosa Ziehau 
1682*15516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
1683*15516c77SSepherosa Ziehau static __inline int
1684*15516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m)
1685*15516c77SSepherosa Ziehau {
1686*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
1687*15516c77SSepherosa Ziehau 	if (hn_lro_mbufq_depth) {
1688*15516c77SSepherosa Ziehau 		tcp_lro_queue_mbuf(lc, m);
1689*15516c77SSepherosa Ziehau 		return 0;
1690*15516c77SSepherosa Ziehau 	}
1691*15516c77SSepherosa Ziehau #endif
1692*15516c77SSepherosa Ziehau 	return tcp_lro_rx(lc, m, 0);
1693*15516c77SSepherosa Ziehau }
1694*15516c77SSepherosa Ziehau #endif
1695*15516c77SSepherosa Ziehau 
1696*15516c77SSepherosa Ziehau static int
1697*15516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
1698*15516c77SSepherosa Ziehau     const struct hn_rxinfo *info)
1699*15516c77SSepherosa Ziehau {
1700*15516c77SSepherosa Ziehau 	struct ifnet *ifp = rxr->hn_ifp;
1701*15516c77SSepherosa Ziehau 	struct mbuf *m_new;
1702*15516c77SSepherosa Ziehau 	int size, do_lro = 0, do_csum = 1;
1703*15516c77SSepherosa Ziehau 	int hash_type;
1704*15516c77SSepherosa Ziehau 
1705*15516c77SSepherosa Ziehau 	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
1706*15516c77SSepherosa Ziehau 		return (0);
1707*15516c77SSepherosa Ziehau 
1708*15516c77SSepherosa Ziehau 	/*
1709*15516c77SSepherosa Ziehau 	 * Bail out if packet contains more data than configured MTU.
1710*15516c77SSepherosa Ziehau 	 */
1711*15516c77SSepherosa Ziehau 	if (dlen > (ifp->if_mtu + ETHER_HDR_LEN)) {
1712*15516c77SSepherosa Ziehau 		return (0);
1713*15516c77SSepherosa Ziehau 	} else if (dlen <= MHLEN) {
1714*15516c77SSepherosa Ziehau 		m_new = m_gethdr(M_NOWAIT, MT_DATA);
1715*15516c77SSepherosa Ziehau 		if (m_new == NULL) {
1716*15516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
1717*15516c77SSepherosa Ziehau 			return (0);
1718*15516c77SSepherosa Ziehau 		}
1719*15516c77SSepherosa Ziehau 		memcpy(mtod(m_new, void *), data, dlen);
1720*15516c77SSepherosa Ziehau 		m_new->m_pkthdr.len = m_new->m_len = dlen;
1721*15516c77SSepherosa Ziehau 		rxr->hn_small_pkts++;
1722*15516c77SSepherosa Ziehau 	} else {
1723*15516c77SSepherosa Ziehau 		/*
1724*15516c77SSepherosa Ziehau 		 * Get an mbuf with a cluster.  For packets 2K or less,
1725*15516c77SSepherosa Ziehau 		 * get a standard 2K cluster.  For anything larger, get a
1726*15516c77SSepherosa Ziehau 		 * 4K cluster.  Any buffers larger than 4K can cause problems
1727*15516c77SSepherosa Ziehau 		 * if looped around to the Hyper-V TX channel, so avoid them.
1728*15516c77SSepherosa Ziehau 		 */
1729*15516c77SSepherosa Ziehau 		size = MCLBYTES;
1730*15516c77SSepherosa Ziehau 		if (dlen > MCLBYTES) {
1731*15516c77SSepherosa Ziehau 			/* 4096 */
1732*15516c77SSepherosa Ziehau 			size = MJUMPAGESIZE;
1733*15516c77SSepherosa Ziehau 		}
1734*15516c77SSepherosa Ziehau 
1735*15516c77SSepherosa Ziehau 		m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size);
1736*15516c77SSepherosa Ziehau 		if (m_new == NULL) {
1737*15516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
1738*15516c77SSepherosa Ziehau 			return (0);
1739*15516c77SSepherosa Ziehau 		}
1740*15516c77SSepherosa Ziehau 
1741*15516c77SSepherosa Ziehau 		hv_m_append(m_new, dlen, data);
1742*15516c77SSepherosa Ziehau 	}
1743*15516c77SSepherosa Ziehau 	m_new->m_pkthdr.rcvif = ifp;
1744*15516c77SSepherosa Ziehau 
1745*15516c77SSepherosa Ziehau 	if (__predict_false((ifp->if_capenable & IFCAP_RXCSUM) == 0))
1746*15516c77SSepherosa Ziehau 		do_csum = 0;
1747*15516c77SSepherosa Ziehau 
1748*15516c77SSepherosa Ziehau 	/* receive side checksum offload */
1749*15516c77SSepherosa Ziehau 	if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) {
1750*15516c77SSepherosa Ziehau 		/* IP csum offload */
1751*15516c77SSepherosa Ziehau 		if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) {
1752*15516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
1753*15516c77SSepherosa Ziehau 			    (CSUM_IP_CHECKED | CSUM_IP_VALID);
1754*15516c77SSepherosa Ziehau 			rxr->hn_csum_ip++;
1755*15516c77SSepherosa Ziehau 		}
1756*15516c77SSepherosa Ziehau 
1757*15516c77SSepherosa Ziehau 		/* TCP/UDP csum offload */
1758*15516c77SSepherosa Ziehau 		if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK |
1759*15516c77SSepherosa Ziehau 		     NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) {
1760*15516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
1761*15516c77SSepherosa Ziehau 			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
1762*15516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_data = 0xffff;
1763*15516c77SSepherosa Ziehau 			if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK)
1764*15516c77SSepherosa Ziehau 				rxr->hn_csum_tcp++;
1765*15516c77SSepherosa Ziehau 			else
1766*15516c77SSepherosa Ziehau 				rxr->hn_csum_udp++;
1767*15516c77SSepherosa Ziehau 		}
1768*15516c77SSepherosa Ziehau 
1769*15516c77SSepherosa Ziehau 		/*
1770*15516c77SSepherosa Ziehau 		 * XXX
1771*15516c77SSepherosa Ziehau 		 * As of this write (Oct 28th, 2016), host side will turn
1772*15516c77SSepherosa Ziehau 		 * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so
1773*15516c77SSepherosa Ziehau 		 * the do_lro setting here is actually _not_ accurate.  We
1774*15516c77SSepherosa Ziehau 		 * depend on the RSS hash type check to reset do_lro.
1775*15516c77SSepherosa Ziehau 		 */
1776*15516c77SSepherosa Ziehau 		if ((info->csum_info &
1777*15516c77SSepherosa Ziehau 		     (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) ==
1778*15516c77SSepherosa Ziehau 		    (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK))
1779*15516c77SSepherosa Ziehau 			do_lro = 1;
1780*15516c77SSepherosa Ziehau 	} else {
1781*15516c77SSepherosa Ziehau 		const struct ether_header *eh;
1782*15516c77SSepherosa Ziehau 		uint16_t etype;
1783*15516c77SSepherosa Ziehau 		int hoff;
1784*15516c77SSepherosa Ziehau 
1785*15516c77SSepherosa Ziehau 		hoff = sizeof(*eh);
1786*15516c77SSepherosa Ziehau 		if (m_new->m_len < hoff)
1787*15516c77SSepherosa Ziehau 			goto skip;
1788*15516c77SSepherosa Ziehau 		eh = mtod(m_new, struct ether_header *);
1789*15516c77SSepherosa Ziehau 		etype = ntohs(eh->ether_type);
1790*15516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_VLAN) {
1791*15516c77SSepherosa Ziehau 			const struct ether_vlan_header *evl;
1792*15516c77SSepherosa Ziehau 
1793*15516c77SSepherosa Ziehau 			hoff = sizeof(*evl);
1794*15516c77SSepherosa Ziehau 			if (m_new->m_len < hoff)
1795*15516c77SSepherosa Ziehau 				goto skip;
1796*15516c77SSepherosa Ziehau 			evl = mtod(m_new, struct ether_vlan_header *);
1797*15516c77SSepherosa Ziehau 			etype = ntohs(evl->evl_proto);
1798*15516c77SSepherosa Ziehau 		}
1799*15516c77SSepherosa Ziehau 
1800*15516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_IP) {
1801*15516c77SSepherosa Ziehau 			int pr;
1802*15516c77SSepherosa Ziehau 
1803*15516c77SSepherosa Ziehau 			pr = hn_check_iplen(m_new, hoff);
1804*15516c77SSepherosa Ziehau 			if (pr == IPPROTO_TCP) {
1805*15516c77SSepherosa Ziehau 				if (do_csum &&
1806*15516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
1807*15516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_TCP)) {
1808*15516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
1809*15516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
1810*15516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
1811*15516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
1812*15516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
1813*15516c77SSepherosa Ziehau 				}
1814*15516c77SSepherosa Ziehau 				do_lro = 1;
1815*15516c77SSepherosa Ziehau 			} else if (pr == IPPROTO_UDP) {
1816*15516c77SSepherosa Ziehau 				if (do_csum &&
1817*15516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
1818*15516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_UDP)) {
1819*15516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
1820*15516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
1821*15516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
1822*15516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
1823*15516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
1824*15516c77SSepherosa Ziehau 				}
1825*15516c77SSepherosa Ziehau 			} else if (pr != IPPROTO_DONE && do_csum &&
1826*15516c77SSepherosa Ziehau 			    (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) {
1827*15516c77SSepherosa Ziehau 				rxr->hn_csum_trusted++;
1828*15516c77SSepherosa Ziehau 				m_new->m_pkthdr.csum_flags |=
1829*15516c77SSepherosa Ziehau 				    (CSUM_IP_CHECKED | CSUM_IP_VALID);
1830*15516c77SSepherosa Ziehau 			}
1831*15516c77SSepherosa Ziehau 		}
1832*15516c77SSepherosa Ziehau 	}
1833*15516c77SSepherosa Ziehau skip:
1834*15516c77SSepherosa Ziehau 	if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) {
1835*15516c77SSepherosa Ziehau 		m_new->m_pkthdr.ether_vtag = EVL_MAKETAG(
1836*15516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_ID(info->vlan_info),
1837*15516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_PRI(info->vlan_info),
1838*15516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_CFI(info->vlan_info));
1839*15516c77SSepherosa Ziehau 		m_new->m_flags |= M_VLANTAG;
1840*15516c77SSepherosa Ziehau 	}
1841*15516c77SSepherosa Ziehau 
1842*15516c77SSepherosa Ziehau 	if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) {
1843*15516c77SSepherosa Ziehau 		rxr->hn_rss_pkts++;
1844*15516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = info->hash_value;
1845*15516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE_HASH;
1846*15516c77SSepherosa Ziehau 		if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) ==
1847*15516c77SSepherosa Ziehau 		    NDIS_HASH_FUNCTION_TOEPLITZ) {
1848*15516c77SSepherosa Ziehau 			uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK);
1849*15516c77SSepherosa Ziehau 
1850*15516c77SSepherosa Ziehau 			/*
1851*15516c77SSepherosa Ziehau 			 * NOTE:
1852*15516c77SSepherosa Ziehau 			 * do_lro is resetted, if the hash types are not TCP
1853*15516c77SSepherosa Ziehau 			 * related.  See the comment in the above csum_flags
1854*15516c77SSepherosa Ziehau 			 * setup section.
1855*15516c77SSepherosa Ziehau 			 */
1856*15516c77SSepherosa Ziehau 			switch (type) {
1857*15516c77SSepherosa Ziehau 			case NDIS_HASH_IPV4:
1858*15516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV4;
1859*15516c77SSepherosa Ziehau 				do_lro = 0;
1860*15516c77SSepherosa Ziehau 				break;
1861*15516c77SSepherosa Ziehau 
1862*15516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV4:
1863*15516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV4;
1864*15516c77SSepherosa Ziehau 				break;
1865*15516c77SSepherosa Ziehau 
1866*15516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6:
1867*15516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6;
1868*15516c77SSepherosa Ziehau 				do_lro = 0;
1869*15516c77SSepherosa Ziehau 				break;
1870*15516c77SSepherosa Ziehau 
1871*15516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6_EX:
1872*15516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6_EX;
1873*15516c77SSepherosa Ziehau 				do_lro = 0;
1874*15516c77SSepherosa Ziehau 				break;
1875*15516c77SSepherosa Ziehau 
1876*15516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6:
1877*15516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6;
1878*15516c77SSepherosa Ziehau 				break;
1879*15516c77SSepherosa Ziehau 
1880*15516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6_EX:
1881*15516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX;
1882*15516c77SSepherosa Ziehau 				break;
1883*15516c77SSepherosa Ziehau 			}
1884*15516c77SSepherosa Ziehau 		}
1885*15516c77SSepherosa Ziehau 	} else {
1886*15516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
1887*15516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE;
1888*15516c77SSepherosa Ziehau 	}
1889*15516c77SSepherosa Ziehau 	M_HASHTYPE_SET(m_new, hash_type);
1890*15516c77SSepherosa Ziehau 
1891*15516c77SSepherosa Ziehau 	/*
1892*15516c77SSepherosa Ziehau 	 * Note:  Moved RX completion back to hv_nv_on_receive() so all
1893*15516c77SSepherosa Ziehau 	 * messages (not just data messages) will trigger a response.
1894*15516c77SSepherosa Ziehau 	 */
1895*15516c77SSepherosa Ziehau 
1896*15516c77SSepherosa Ziehau 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
1897*15516c77SSepherosa Ziehau 	rxr->hn_pkts++;
1898*15516c77SSepherosa Ziehau 
1899*15516c77SSepherosa Ziehau 	if ((ifp->if_capenable & IFCAP_LRO) && do_lro) {
1900*15516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
1901*15516c77SSepherosa Ziehau 		struct lro_ctrl *lro = &rxr->hn_lro;
1902*15516c77SSepherosa Ziehau 
1903*15516c77SSepherosa Ziehau 		if (lro->lro_cnt) {
1904*15516c77SSepherosa Ziehau 			rxr->hn_lro_tried++;
1905*15516c77SSepherosa Ziehau 			if (hn_lro_rx(lro, m_new) == 0) {
1906*15516c77SSepherosa Ziehau 				/* DONE! */
1907*15516c77SSepherosa Ziehau 				return 0;
1908*15516c77SSepherosa Ziehau 			}
1909*15516c77SSepherosa Ziehau 		}
1910*15516c77SSepherosa Ziehau #endif
1911*15516c77SSepherosa Ziehau 	}
1912*15516c77SSepherosa Ziehau 
1913*15516c77SSepherosa Ziehau 	/* We're not holding the lock here, so don't release it */
1914*15516c77SSepherosa Ziehau 	(*ifp->if_input)(ifp, m_new);
1915*15516c77SSepherosa Ziehau 
1916*15516c77SSepherosa Ziehau 	return (0);
1917*15516c77SSepherosa Ziehau }
1918*15516c77SSepherosa Ziehau 
1919*15516c77SSepherosa Ziehau static int
1920*15516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1921*15516c77SSepherosa Ziehau {
1922*15516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
1923*15516c77SSepherosa Ziehau 	struct ifreq *ifr = (struct ifreq *)data;
1924*15516c77SSepherosa Ziehau 	int mask, error = 0;
1925*15516c77SSepherosa Ziehau 
1926*15516c77SSepherosa Ziehau 	switch (cmd) {
1927*15516c77SSepherosa Ziehau 	case SIOCSIFMTU:
1928*15516c77SSepherosa Ziehau 		if (ifr->ifr_mtu > HN_MTU_MAX) {
1929*15516c77SSepherosa Ziehau 			error = EINVAL;
1930*15516c77SSepherosa Ziehau 			break;
1931*15516c77SSepherosa Ziehau 		}
1932*15516c77SSepherosa Ziehau 
1933*15516c77SSepherosa Ziehau 		HN_LOCK(sc);
1934*15516c77SSepherosa Ziehau 
1935*15516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
1936*15516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
1937*15516c77SSepherosa Ziehau 			break;
1938*15516c77SSepherosa Ziehau 		}
1939*15516c77SSepherosa Ziehau 
1940*15516c77SSepherosa Ziehau 		if ((sc->hn_caps & HN_CAP_MTU) == 0) {
1941*15516c77SSepherosa Ziehau 			/* Can't change MTU */
1942*15516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
1943*15516c77SSepherosa Ziehau 			error = EOPNOTSUPP;
1944*15516c77SSepherosa Ziehau 			break;
1945*15516c77SSepherosa Ziehau 		}
1946*15516c77SSepherosa Ziehau 
1947*15516c77SSepherosa Ziehau 		if (ifp->if_mtu == ifr->ifr_mtu) {
1948*15516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
1949*15516c77SSepherosa Ziehau 			break;
1950*15516c77SSepherosa Ziehau 		}
1951*15516c77SSepherosa Ziehau 
1952*15516c77SSepherosa Ziehau 		/*
1953*15516c77SSepherosa Ziehau 		 * Suspend this interface before the synthetic parts
1954*15516c77SSepherosa Ziehau 		 * are ripped.
1955*15516c77SSepherosa Ziehau 		 */
1956*15516c77SSepherosa Ziehau 		hn_suspend(sc);
1957*15516c77SSepherosa Ziehau 
1958*15516c77SSepherosa Ziehau 		/*
1959*15516c77SSepherosa Ziehau 		 * Detach the synthetics parts, i.e. NVS and RNDIS.
1960*15516c77SSepherosa Ziehau 		 */
1961*15516c77SSepherosa Ziehau 		hn_synth_detach(sc);
1962*15516c77SSepherosa Ziehau 
1963*15516c77SSepherosa Ziehau 		/*
1964*15516c77SSepherosa Ziehau 		 * Reattach the synthetic parts, i.e. NVS and RNDIS,
1965*15516c77SSepherosa Ziehau 		 * with the new MTU setting.
1966*15516c77SSepherosa Ziehau 		 */
1967*15516c77SSepherosa Ziehau 		error = hn_synth_attach(sc, ifr->ifr_mtu);
1968*15516c77SSepherosa Ziehau 		if (error) {
1969*15516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
1970*15516c77SSepherosa Ziehau 			break;
1971*15516c77SSepherosa Ziehau 		}
1972*15516c77SSepherosa Ziehau 
1973*15516c77SSepherosa Ziehau 		/*
1974*15516c77SSepherosa Ziehau 		 * Commit the requested MTU, after the synthetic parts
1975*15516c77SSepherosa Ziehau 		 * have been successfully attached.
1976*15516c77SSepherosa Ziehau 		 */
1977*15516c77SSepherosa Ziehau 		ifp->if_mtu = ifr->ifr_mtu;
1978*15516c77SSepherosa Ziehau 
1979*15516c77SSepherosa Ziehau 		/*
1980*15516c77SSepherosa Ziehau 		 * Make sure that various parameters based on MTU are
1981*15516c77SSepherosa Ziehau 		 * still valid, after the MTU change.
1982*15516c77SSepherosa Ziehau 		 */
1983*15516c77SSepherosa Ziehau 		if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax)
1984*15516c77SSepherosa Ziehau 			hn_set_chim_size(sc, sc->hn_chim_szmax);
1985*15516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu);
1986*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
1987*15516c77SSepherosa Ziehau 		if (sc->hn_rx_ring[0].hn_lro.lro_length_lim <
1988*15516c77SSepherosa Ziehau 		    HN_LRO_LENLIM_MIN(ifp))
1989*15516c77SSepherosa Ziehau 			hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
1990*15516c77SSepherosa Ziehau #endif
1991*15516c77SSepherosa Ziehau 
1992*15516c77SSepherosa Ziehau 		/*
1993*15516c77SSepherosa Ziehau 		 * All done!  Resume the interface now.
1994*15516c77SSepherosa Ziehau 		 */
1995*15516c77SSepherosa Ziehau 		hn_resume(sc);
1996*15516c77SSepherosa Ziehau 
1997*15516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
1998*15516c77SSepherosa Ziehau 		break;
1999*15516c77SSepherosa Ziehau 
2000*15516c77SSepherosa Ziehau 	case SIOCSIFFLAGS:
2001*15516c77SSepherosa Ziehau 		HN_LOCK(sc);
2002*15516c77SSepherosa Ziehau 
2003*15516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
2004*15516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
2005*15516c77SSepherosa Ziehau 			break;
2006*15516c77SSepherosa Ziehau 		}
2007*15516c77SSepherosa Ziehau 
2008*15516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_UP) {
2009*15516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
2010*15516c77SSepherosa Ziehau 				hn_set_rxfilter(sc);
2011*15516c77SSepherosa Ziehau 			else
2012*15516c77SSepherosa Ziehau 				hn_init_locked(sc);
2013*15516c77SSepherosa Ziehau 		} else {
2014*15516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
2015*15516c77SSepherosa Ziehau 				hn_stop(sc);
2016*15516c77SSepherosa Ziehau 		}
2017*15516c77SSepherosa Ziehau 		sc->hn_if_flags = ifp->if_flags;
2018*15516c77SSepherosa Ziehau 
2019*15516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
2020*15516c77SSepherosa Ziehau 		break;
2021*15516c77SSepherosa Ziehau 
2022*15516c77SSepherosa Ziehau 	case SIOCSIFCAP:
2023*15516c77SSepherosa Ziehau 		HN_LOCK(sc);
2024*15516c77SSepherosa Ziehau 		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
2025*15516c77SSepherosa Ziehau 
2026*15516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM) {
2027*15516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM;
2028*15516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM)
2029*15516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc);
2030*15516c77SSepherosa Ziehau 			else
2031*15516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc);
2032*15516c77SSepherosa Ziehau 		}
2033*15516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM_IPV6) {
2034*15516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
2035*15516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
2036*15516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc);
2037*15516c77SSepherosa Ziehau 			else
2038*15516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc);
2039*15516c77SSepherosa Ziehau 		}
2040*15516c77SSepherosa Ziehau 
2041*15516c77SSepherosa Ziehau 		/* TODO: flip RNDIS offload parameters for RXCSUM. */
2042*15516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM)
2043*15516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM;
2044*15516c77SSepherosa Ziehau #ifdef foo
2045*15516c77SSepherosa Ziehau 		/* We can't diff IPv6 packets from IPv4 packets on RX path. */
2046*15516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM_IPV6)
2047*15516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
2048*15516c77SSepherosa Ziehau #endif
2049*15516c77SSepherosa Ziehau 
2050*15516c77SSepherosa Ziehau 		if (mask & IFCAP_LRO)
2051*15516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_LRO;
2052*15516c77SSepherosa Ziehau 
2053*15516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO4) {
2054*15516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO4;
2055*15516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO4)
2056*15516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP_TSO;
2057*15516c77SSepherosa Ziehau 			else
2058*15516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP_TSO;
2059*15516c77SSepherosa Ziehau 		}
2060*15516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO6) {
2061*15516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO6;
2062*15516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO6)
2063*15516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP6_TSO;
2064*15516c77SSepherosa Ziehau 			else
2065*15516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP6_TSO;
2066*15516c77SSepherosa Ziehau 		}
2067*15516c77SSepherosa Ziehau 
2068*15516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
2069*15516c77SSepherosa Ziehau 		break;
2070*15516c77SSepherosa Ziehau 
2071*15516c77SSepherosa Ziehau 	case SIOCADDMULTI:
2072*15516c77SSepherosa Ziehau 	case SIOCDELMULTI:
2073*15516c77SSepherosa Ziehau #ifdef notyet
2074*15516c77SSepherosa Ziehau 		/*
2075*15516c77SSepherosa Ziehau 		 * XXX
2076*15516c77SSepherosa Ziehau 		 * Multicast uses mutex, while RNDIS RX filter setting
2077*15516c77SSepherosa Ziehau 		 * sleeps.  We workaround this by always enabling
2078*15516c77SSepherosa Ziehau 		 * ALLMULTI.  ALLMULTI would actually always be on, even
2079*15516c77SSepherosa Ziehau 		 * if we supported the SIOCADDMULTI/SIOCDELMULTI, since
2080*15516c77SSepherosa Ziehau 		 * we don't support multicast address list configuration
2081*15516c77SSepherosa Ziehau 		 * for this driver.
2082*15516c77SSepherosa Ziehau 		 */
2083*15516c77SSepherosa Ziehau 		HN_LOCK(sc);
2084*15516c77SSepherosa Ziehau 
2085*15516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
2086*15516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
2087*15516c77SSepherosa Ziehau 			break;
2088*15516c77SSepherosa Ziehau 		}
2089*15516c77SSepherosa Ziehau 		if (ifp->if_drv_flags & IFF_DRV_RUNNING)
2090*15516c77SSepherosa Ziehau 			hn_set_rxfilter(sc);
2091*15516c77SSepherosa Ziehau 
2092*15516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
2093*15516c77SSepherosa Ziehau #endif
2094*15516c77SSepherosa Ziehau 		break;
2095*15516c77SSepherosa Ziehau 
2096*15516c77SSepherosa Ziehau 	case SIOCSIFMEDIA:
2097*15516c77SSepherosa Ziehau 	case SIOCGIFMEDIA:
2098*15516c77SSepherosa Ziehau 		error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd);
2099*15516c77SSepherosa Ziehau 		break;
2100*15516c77SSepherosa Ziehau 
2101*15516c77SSepherosa Ziehau 	default:
2102*15516c77SSepherosa Ziehau 		error = ether_ioctl(ifp, cmd, data);
2103*15516c77SSepherosa Ziehau 		break;
2104*15516c77SSepherosa Ziehau 	}
2105*15516c77SSepherosa Ziehau 	return (error);
2106*15516c77SSepherosa Ziehau }
2107*15516c77SSepherosa Ziehau 
2108*15516c77SSepherosa Ziehau static void
2109*15516c77SSepherosa Ziehau hn_stop(struct hn_softc *sc)
2110*15516c77SSepherosa Ziehau {
2111*15516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
2112*15516c77SSepherosa Ziehau 	int i;
2113*15516c77SSepherosa Ziehau 
2114*15516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
2115*15516c77SSepherosa Ziehau 
2116*15516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
2117*15516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
2118*15516c77SSepherosa Ziehau 
2119*15516c77SSepherosa Ziehau 	/* Clear RUNNING bit _before_ hn_suspend_data() */
2120*15516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
2121*15516c77SSepherosa Ziehau 	hn_suspend_data(sc);
2122*15516c77SSepherosa Ziehau 
2123*15516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
2124*15516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
2125*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
2126*15516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
2127*15516c77SSepherosa Ziehau }
2128*15516c77SSepherosa Ziehau 
2129*15516c77SSepherosa Ziehau static void
2130*15516c77SSepherosa Ziehau hn_start(struct ifnet *ifp)
2131*15516c77SSepherosa Ziehau {
2132*15516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
2133*15516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[0];
2134*15516c77SSepherosa Ziehau 
2135*15516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
2136*15516c77SSepherosa Ziehau 		goto do_sched;
2137*15516c77SSepherosa Ziehau 
2138*15516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
2139*15516c77SSepherosa Ziehau 		int sched;
2140*15516c77SSepherosa Ziehau 
2141*15516c77SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
2142*15516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
2143*15516c77SSepherosa Ziehau 		if (!sched)
2144*15516c77SSepherosa Ziehau 			return;
2145*15516c77SSepherosa Ziehau 	}
2146*15516c77SSepherosa Ziehau do_sched:
2147*15516c77SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
2148*15516c77SSepherosa Ziehau }
2149*15516c77SSepherosa Ziehau 
2150*15516c77SSepherosa Ziehau static void
2151*15516c77SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr)
2152*15516c77SSepherosa Ziehau {
2153*15516c77SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
2154*15516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
2155*15516c77SSepherosa Ziehau 
2156*15516c77SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
2157*15516c77SSepherosa Ziehau 
2158*15516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
2159*15516c77SSepherosa Ziehau 		goto do_sched;
2160*15516c77SSepherosa Ziehau 
2161*15516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
2162*15516c77SSepherosa Ziehau 		int sched;
2163*15516c77SSepherosa Ziehau 
2164*15516c77SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
2165*15516c77SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
2166*15516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
2167*15516c77SSepherosa Ziehau 		if (sched) {
2168*15516c77SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
2169*15516c77SSepherosa Ziehau 			    &txr->hn_tx_task);
2170*15516c77SSepherosa Ziehau 		}
2171*15516c77SSepherosa Ziehau 	} else {
2172*15516c77SSepherosa Ziehau do_sched:
2173*15516c77SSepherosa Ziehau 		/*
2174*15516c77SSepherosa Ziehau 		 * Release the OACTIVE earlier, with the hope, that
2175*15516c77SSepherosa Ziehau 		 * others could catch up.  The task will clear the
2176*15516c77SSepherosa Ziehau 		 * flag again with the hn_tx_lock to avoid possible
2177*15516c77SSepherosa Ziehau 		 * races.
2178*15516c77SSepherosa Ziehau 		 */
2179*15516c77SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
2180*15516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
2181*15516c77SSepherosa Ziehau 	}
2182*15516c77SSepherosa Ziehau }
2183*15516c77SSepherosa Ziehau 
2184*15516c77SSepherosa Ziehau static void
2185*15516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc)
2186*15516c77SSepherosa Ziehau {
2187*15516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
2188*15516c77SSepherosa Ziehau 	int i;
2189*15516c77SSepherosa Ziehau 
2190*15516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
2191*15516c77SSepherosa Ziehau 
2192*15516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
2193*15516c77SSepherosa Ziehau 		return;
2194*15516c77SSepherosa Ziehau 
2195*15516c77SSepherosa Ziehau 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
2196*15516c77SSepherosa Ziehau 		return;
2197*15516c77SSepherosa Ziehau 
2198*15516c77SSepherosa Ziehau 	/* Configure RX filter */
2199*15516c77SSepherosa Ziehau 	hn_set_rxfilter(sc);
2200*15516c77SSepherosa Ziehau 
2201*15516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
2202*15516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
2203*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
2204*15516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
2205*15516c77SSepherosa Ziehau 
2206*15516c77SSepherosa Ziehau 	/* Clear TX 'suspended' bit. */
2207*15516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_inuse);
2208*15516c77SSepherosa Ziehau 
2209*15516c77SSepherosa Ziehau 	/* Everything is ready; unleash! */
2210*15516c77SSepherosa Ziehau 	atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
2211*15516c77SSepherosa Ziehau }
2212*15516c77SSepherosa Ziehau 
2213*15516c77SSepherosa Ziehau static void
2214*15516c77SSepherosa Ziehau hn_init(void *xsc)
2215*15516c77SSepherosa Ziehau {
2216*15516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
2217*15516c77SSepherosa Ziehau 
2218*15516c77SSepherosa Ziehau 	HN_LOCK(sc);
2219*15516c77SSepherosa Ziehau 	hn_init_locked(sc);
2220*15516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
2221*15516c77SSepherosa Ziehau }
2222*15516c77SSepherosa Ziehau 
2223*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
2224*15516c77SSepherosa Ziehau 
2225*15516c77SSepherosa Ziehau static int
2226*15516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
2227*15516c77SSepherosa Ziehau {
2228*15516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2229*15516c77SSepherosa Ziehau 	unsigned int lenlim;
2230*15516c77SSepherosa Ziehau 	int error;
2231*15516c77SSepherosa Ziehau 
2232*15516c77SSepherosa Ziehau 	lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim;
2233*15516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &lenlim, 0, req);
2234*15516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
2235*15516c77SSepherosa Ziehau 		return error;
2236*15516c77SSepherosa Ziehau 
2237*15516c77SSepherosa Ziehau 	HN_LOCK(sc);
2238*15516c77SSepherosa Ziehau 	if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) ||
2239*15516c77SSepherosa Ziehau 	    lenlim > TCP_LRO_LENGTH_MAX) {
2240*15516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
2241*15516c77SSepherosa Ziehau 		return EINVAL;
2242*15516c77SSepherosa Ziehau 	}
2243*15516c77SSepherosa Ziehau 	hn_set_lro_lenlim(sc, lenlim);
2244*15516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
2245*15516c77SSepherosa Ziehau 
2246*15516c77SSepherosa Ziehau 	return 0;
2247*15516c77SSepherosa Ziehau }
2248*15516c77SSepherosa Ziehau 
2249*15516c77SSepherosa Ziehau static int
2250*15516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS)
2251*15516c77SSepherosa Ziehau {
2252*15516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2253*15516c77SSepherosa Ziehau 	int ackcnt, error, i;
2254*15516c77SSepherosa Ziehau 
2255*15516c77SSepherosa Ziehau 	/*
2256*15516c77SSepherosa Ziehau 	 * lro_ackcnt_lim is append count limit,
2257*15516c77SSepherosa Ziehau 	 * +1 to turn it into aggregation limit.
2258*15516c77SSepherosa Ziehau 	 */
2259*15516c77SSepherosa Ziehau 	ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1;
2260*15516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &ackcnt, 0, req);
2261*15516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
2262*15516c77SSepherosa Ziehau 		return error;
2263*15516c77SSepherosa Ziehau 
2264*15516c77SSepherosa Ziehau 	if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1))
2265*15516c77SSepherosa Ziehau 		return EINVAL;
2266*15516c77SSepherosa Ziehau 
2267*15516c77SSepherosa Ziehau 	/*
2268*15516c77SSepherosa Ziehau 	 * Convert aggregation limit back to append
2269*15516c77SSepherosa Ziehau 	 * count limit.
2270*15516c77SSepherosa Ziehau 	 */
2271*15516c77SSepherosa Ziehau 	--ackcnt;
2272*15516c77SSepherosa Ziehau 	HN_LOCK(sc);
2273*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_inuse; ++i)
2274*15516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt;
2275*15516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
2276*15516c77SSepherosa Ziehau 	return 0;
2277*15516c77SSepherosa Ziehau }
2278*15516c77SSepherosa Ziehau 
2279*15516c77SSepherosa Ziehau #endif
2280*15516c77SSepherosa Ziehau 
2281*15516c77SSepherosa Ziehau static int
2282*15516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS)
2283*15516c77SSepherosa Ziehau {
2284*15516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2285*15516c77SSepherosa Ziehau 	int hcsum = arg2;
2286*15516c77SSepherosa Ziehau 	int on, error, i;
2287*15516c77SSepherosa Ziehau 
2288*15516c77SSepherosa Ziehau 	on = 0;
2289*15516c77SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum)
2290*15516c77SSepherosa Ziehau 		on = 1;
2291*15516c77SSepherosa Ziehau 
2292*15516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &on, 0, req);
2293*15516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
2294*15516c77SSepherosa Ziehau 		return error;
2295*15516c77SSepherosa Ziehau 
2296*15516c77SSepherosa Ziehau 	HN_LOCK(sc);
2297*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_inuse; ++i) {
2298*15516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
2299*15516c77SSepherosa Ziehau 
2300*15516c77SSepherosa Ziehau 		if (on)
2301*15516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= hcsum;
2302*15516c77SSepherosa Ziehau 		else
2303*15516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum &= ~hcsum;
2304*15516c77SSepherosa Ziehau 	}
2305*15516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
2306*15516c77SSepherosa Ziehau 	return 0;
2307*15516c77SSepherosa Ziehau }
2308*15516c77SSepherosa Ziehau 
2309*15516c77SSepherosa Ziehau static int
2310*15516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS)
2311*15516c77SSepherosa Ziehau {
2312*15516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2313*15516c77SSepherosa Ziehau 	int chim_size, error;
2314*15516c77SSepherosa Ziehau 
2315*15516c77SSepherosa Ziehau 	chim_size = sc->hn_tx_ring[0].hn_chim_size;
2316*15516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &chim_size, 0, req);
2317*15516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
2318*15516c77SSepherosa Ziehau 		return error;
2319*15516c77SSepherosa Ziehau 
2320*15516c77SSepherosa Ziehau 	if (chim_size > sc->hn_chim_szmax || chim_size <= 0)
2321*15516c77SSepherosa Ziehau 		return EINVAL;
2322*15516c77SSepherosa Ziehau 
2323*15516c77SSepherosa Ziehau 	HN_LOCK(sc);
2324*15516c77SSepherosa Ziehau 	hn_set_chim_size(sc, chim_size);
2325*15516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
2326*15516c77SSepherosa Ziehau 	return 0;
2327*15516c77SSepherosa Ziehau }
2328*15516c77SSepherosa Ziehau 
2329*15516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
2330*15516c77SSepherosa Ziehau static int
2331*15516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS)
2332*15516c77SSepherosa Ziehau {
2333*15516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2334*15516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
2335*15516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
2336*15516c77SSepherosa Ziehau 	uint64_t stat;
2337*15516c77SSepherosa Ziehau 
2338*15516c77SSepherosa Ziehau 	stat = 0;
2339*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
2340*15516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
2341*15516c77SSepherosa Ziehau 		stat += *((int *)((uint8_t *)rxr + ofs));
2342*15516c77SSepherosa Ziehau 	}
2343*15516c77SSepherosa Ziehau 
2344*15516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
2345*15516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
2346*15516c77SSepherosa Ziehau 		return error;
2347*15516c77SSepherosa Ziehau 
2348*15516c77SSepherosa Ziehau 	/* Zero out this stat. */
2349*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
2350*15516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
2351*15516c77SSepherosa Ziehau 		*((int *)((uint8_t *)rxr + ofs)) = 0;
2352*15516c77SSepherosa Ziehau 	}
2353*15516c77SSepherosa Ziehau 	return 0;
2354*15516c77SSepherosa Ziehau }
2355*15516c77SSepherosa Ziehau #else
2356*15516c77SSepherosa Ziehau static int
2357*15516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS)
2358*15516c77SSepherosa Ziehau {
2359*15516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2360*15516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
2361*15516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
2362*15516c77SSepherosa Ziehau 	uint64_t stat;
2363*15516c77SSepherosa Ziehau 
2364*15516c77SSepherosa Ziehau 	stat = 0;
2365*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_inuse; ++i) {
2366*15516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
2367*15516c77SSepherosa Ziehau 		stat += *((uint64_t *)((uint8_t *)rxr + ofs));
2368*15516c77SSepherosa Ziehau 	}
2369*15516c77SSepherosa Ziehau 
2370*15516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
2371*15516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
2372*15516c77SSepherosa Ziehau 		return error;
2373*15516c77SSepherosa Ziehau 
2374*15516c77SSepherosa Ziehau 	/* Zero out this stat. */
2375*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_inuse; ++i) {
2376*15516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
2377*15516c77SSepherosa Ziehau 		*((uint64_t *)((uint8_t *)rxr + ofs)) = 0;
2378*15516c77SSepherosa Ziehau 	}
2379*15516c77SSepherosa Ziehau 	return 0;
2380*15516c77SSepherosa Ziehau }
2381*15516c77SSepherosa Ziehau 
2382*15516c77SSepherosa Ziehau #endif
2383*15516c77SSepherosa Ziehau 
2384*15516c77SSepherosa Ziehau static int
2385*15516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
2386*15516c77SSepherosa Ziehau {
2387*15516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2388*15516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
2389*15516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
2390*15516c77SSepherosa Ziehau 	u_long stat;
2391*15516c77SSepherosa Ziehau 
2392*15516c77SSepherosa Ziehau 	stat = 0;
2393*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_inuse; ++i) {
2394*15516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
2395*15516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)rxr + ofs));
2396*15516c77SSepherosa Ziehau 	}
2397*15516c77SSepherosa Ziehau 
2398*15516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
2399*15516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
2400*15516c77SSepherosa Ziehau 		return error;
2401*15516c77SSepherosa Ziehau 
2402*15516c77SSepherosa Ziehau 	/* Zero out this stat. */
2403*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_inuse; ++i) {
2404*15516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
2405*15516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)rxr + ofs)) = 0;
2406*15516c77SSepherosa Ziehau 	}
2407*15516c77SSepherosa Ziehau 	return 0;
2408*15516c77SSepherosa Ziehau }
2409*15516c77SSepherosa Ziehau 
2410*15516c77SSepherosa Ziehau static int
2411*15516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
2412*15516c77SSepherosa Ziehau {
2413*15516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2414*15516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
2415*15516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
2416*15516c77SSepherosa Ziehau 	u_long stat;
2417*15516c77SSepherosa Ziehau 
2418*15516c77SSepherosa Ziehau 	stat = 0;
2419*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
2420*15516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
2421*15516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)txr + ofs));
2422*15516c77SSepherosa Ziehau 	}
2423*15516c77SSepherosa Ziehau 
2424*15516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
2425*15516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
2426*15516c77SSepherosa Ziehau 		return error;
2427*15516c77SSepherosa Ziehau 
2428*15516c77SSepherosa Ziehau 	/* Zero out this stat. */
2429*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
2430*15516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
2431*15516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)txr + ofs)) = 0;
2432*15516c77SSepherosa Ziehau 	}
2433*15516c77SSepherosa Ziehau 	return 0;
2434*15516c77SSepherosa Ziehau }
2435*15516c77SSepherosa Ziehau 
2436*15516c77SSepherosa Ziehau static int
2437*15516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS)
2438*15516c77SSepherosa Ziehau {
2439*15516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2440*15516c77SSepherosa Ziehau 	int ofs = arg2, i, error, conf;
2441*15516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
2442*15516c77SSepherosa Ziehau 
2443*15516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[0];
2444*15516c77SSepherosa Ziehau 	conf = *((int *)((uint8_t *)txr + ofs));
2445*15516c77SSepherosa Ziehau 
2446*15516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &conf, 0, req);
2447*15516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
2448*15516c77SSepherosa Ziehau 		return error;
2449*15516c77SSepherosa Ziehau 
2450*15516c77SSepherosa Ziehau 	HN_LOCK(sc);
2451*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
2452*15516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
2453*15516c77SSepherosa Ziehau 		*((int *)((uint8_t *)txr + ofs)) = conf;
2454*15516c77SSepherosa Ziehau 	}
2455*15516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
2456*15516c77SSepherosa Ziehau 
2457*15516c77SSepherosa Ziehau 	return 0;
2458*15516c77SSepherosa Ziehau }
2459*15516c77SSepherosa Ziehau 
2460*15516c77SSepherosa Ziehau static int
2461*15516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS)
2462*15516c77SSepherosa Ziehau {
2463*15516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2464*15516c77SSepherosa Ziehau 	char verstr[16];
2465*15516c77SSepherosa Ziehau 
2466*15516c77SSepherosa Ziehau 	snprintf(verstr, sizeof(verstr), "%u.%u",
2467*15516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
2468*15516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
2469*15516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
2470*15516c77SSepherosa Ziehau }
2471*15516c77SSepherosa Ziehau 
2472*15516c77SSepherosa Ziehau static int
2473*15516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS)
2474*15516c77SSepherosa Ziehau {
2475*15516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2476*15516c77SSepherosa Ziehau 	char caps_str[128];
2477*15516c77SSepherosa Ziehau 	uint32_t caps;
2478*15516c77SSepherosa Ziehau 
2479*15516c77SSepherosa Ziehau 	HN_LOCK(sc);
2480*15516c77SSepherosa Ziehau 	caps = sc->hn_caps;
2481*15516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
2482*15516c77SSepherosa Ziehau 	snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS);
2483*15516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req);
2484*15516c77SSepherosa Ziehau }
2485*15516c77SSepherosa Ziehau 
2486*15516c77SSepherosa Ziehau static int
2487*15516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS)
2488*15516c77SSepherosa Ziehau {
2489*15516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2490*15516c77SSepherosa Ziehau 	char assist_str[128];
2491*15516c77SSepherosa Ziehau 	uint32_t hwassist;
2492*15516c77SSepherosa Ziehau 
2493*15516c77SSepherosa Ziehau 	HN_LOCK(sc);
2494*15516c77SSepherosa Ziehau 	hwassist = sc->hn_ifp->if_hwassist;
2495*15516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
2496*15516c77SSepherosa Ziehau 	snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS);
2497*15516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req);
2498*15516c77SSepherosa Ziehau }
2499*15516c77SSepherosa Ziehau 
2500*15516c77SSepherosa Ziehau static int
2501*15516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS)
2502*15516c77SSepherosa Ziehau {
2503*15516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2504*15516c77SSepherosa Ziehau 	char filter_str[128];
2505*15516c77SSepherosa Ziehau 	uint32_t filter;
2506*15516c77SSepherosa Ziehau 
2507*15516c77SSepherosa Ziehau 	HN_LOCK(sc);
2508*15516c77SSepherosa Ziehau 	filter = sc->hn_rx_filter;
2509*15516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
2510*15516c77SSepherosa Ziehau 	snprintf(filter_str, sizeof(filter_str), "%b", filter,
2511*15516c77SSepherosa Ziehau 	    NDIS_PACKET_TYPES);
2512*15516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req);
2513*15516c77SSepherosa Ziehau }
2514*15516c77SSepherosa Ziehau 
2515*15516c77SSepherosa Ziehau static int
2516*15516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
2517*15516c77SSepherosa Ziehau {
2518*15516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2519*15516c77SSepherosa Ziehau 	int error;
2520*15516c77SSepherosa Ziehau 
2521*15516c77SSepherosa Ziehau 	HN_LOCK(sc);
2522*15516c77SSepherosa Ziehau 
2523*15516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
2524*15516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
2525*15516c77SSepherosa Ziehau 		goto back;
2526*15516c77SSepherosa Ziehau 
2527*15516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
2528*15516c77SSepherosa Ziehau 	if (error)
2529*15516c77SSepherosa Ziehau 		goto back;
2530*15516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
2531*15516c77SSepherosa Ziehau 
2532*15516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
2533*15516c77SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
2534*15516c77SSepherosa Ziehau 	} else {
2535*15516c77SSepherosa Ziehau 		/* Not RSS capable, at least for now; just save the RSS key. */
2536*15516c77SSepherosa Ziehau 		error = 0;
2537*15516c77SSepherosa Ziehau 	}
2538*15516c77SSepherosa Ziehau back:
2539*15516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
2540*15516c77SSepherosa Ziehau 	return (error);
2541*15516c77SSepherosa Ziehau }
2542*15516c77SSepherosa Ziehau 
2543*15516c77SSepherosa Ziehau static int
2544*15516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS)
2545*15516c77SSepherosa Ziehau {
2546*15516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2547*15516c77SSepherosa Ziehau 	int error;
2548*15516c77SSepherosa Ziehau 
2549*15516c77SSepherosa Ziehau 	HN_LOCK(sc);
2550*15516c77SSepherosa Ziehau 
2551*15516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
2552*15516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
2553*15516c77SSepherosa Ziehau 		goto back;
2554*15516c77SSepherosa Ziehau 
2555*15516c77SSepherosa Ziehau 	/*
2556*15516c77SSepherosa Ziehau 	 * Don't allow RSS indirect table change, if this interface is not
2557*15516c77SSepherosa Ziehau 	 * RSS capable currently.
2558*15516c77SSepherosa Ziehau 	 */
2559*15516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
2560*15516c77SSepherosa Ziehau 		error = EOPNOTSUPP;
2561*15516c77SSepherosa Ziehau 		goto back;
2562*15516c77SSepherosa Ziehau 	}
2563*15516c77SSepherosa Ziehau 
2564*15516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
2565*15516c77SSepherosa Ziehau 	if (error)
2566*15516c77SSepherosa Ziehau 		goto back;
2567*15516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSIND;
2568*15516c77SSepherosa Ziehau 
2569*15516c77SSepherosa Ziehau 	hn_rss_ind_fixup(sc, sc->hn_rx_ring_inuse);
2570*15516c77SSepherosa Ziehau 	error = hn_rss_reconfig(sc);
2571*15516c77SSepherosa Ziehau back:
2572*15516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
2573*15516c77SSepherosa Ziehau 	return (error);
2574*15516c77SSepherosa Ziehau }
2575*15516c77SSepherosa Ziehau 
2576*15516c77SSepherosa Ziehau static int
2577*15516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS)
2578*15516c77SSepherosa Ziehau {
2579*15516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2580*15516c77SSepherosa Ziehau 	char hash_str[128];
2581*15516c77SSepherosa Ziehau 	uint32_t hash;
2582*15516c77SSepherosa Ziehau 
2583*15516c77SSepherosa Ziehau 	HN_LOCK(sc);
2584*15516c77SSepherosa Ziehau 	hash = sc->hn_rss_hash;
2585*15516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
2586*15516c77SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
2587*15516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
2588*15516c77SSepherosa Ziehau }
2589*15516c77SSepherosa Ziehau 
2590*15516c77SSepherosa Ziehau static int
2591*15516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff)
2592*15516c77SSepherosa Ziehau {
2593*15516c77SSepherosa Ziehau 	const struct ip *ip;
2594*15516c77SSepherosa Ziehau 	int len, iphlen, iplen;
2595*15516c77SSepherosa Ziehau 	const struct tcphdr *th;
2596*15516c77SSepherosa Ziehau 	int thoff;				/* TCP data offset */
2597*15516c77SSepherosa Ziehau 
2598*15516c77SSepherosa Ziehau 	len = hoff + sizeof(struct ip);
2599*15516c77SSepherosa Ziehau 
2600*15516c77SSepherosa Ziehau 	/* The packet must be at least the size of an IP header. */
2601*15516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < len)
2602*15516c77SSepherosa Ziehau 		return IPPROTO_DONE;
2603*15516c77SSepherosa Ziehau 
2604*15516c77SSepherosa Ziehau 	/* The fixed IP header must reside completely in the first mbuf. */
2605*15516c77SSepherosa Ziehau 	if (m->m_len < len)
2606*15516c77SSepherosa Ziehau 		return IPPROTO_DONE;
2607*15516c77SSepherosa Ziehau 
2608*15516c77SSepherosa Ziehau 	ip = mtodo(m, hoff);
2609*15516c77SSepherosa Ziehau 
2610*15516c77SSepherosa Ziehau 	/* Bound check the packet's stated IP header length. */
2611*15516c77SSepherosa Ziehau 	iphlen = ip->ip_hl << 2;
2612*15516c77SSepherosa Ziehau 	if (iphlen < sizeof(struct ip))		/* minimum header length */
2613*15516c77SSepherosa Ziehau 		return IPPROTO_DONE;
2614*15516c77SSepherosa Ziehau 
2615*15516c77SSepherosa Ziehau 	/* The full IP header must reside completely in the one mbuf. */
2616*15516c77SSepherosa Ziehau 	if (m->m_len < hoff + iphlen)
2617*15516c77SSepherosa Ziehau 		return IPPROTO_DONE;
2618*15516c77SSepherosa Ziehau 
2619*15516c77SSepherosa Ziehau 	iplen = ntohs(ip->ip_len);
2620*15516c77SSepherosa Ziehau 
2621*15516c77SSepherosa Ziehau 	/*
2622*15516c77SSepherosa Ziehau 	 * Check that the amount of data in the buffers is as
2623*15516c77SSepherosa Ziehau 	 * at least much as the IP header would have us expect.
2624*15516c77SSepherosa Ziehau 	 */
2625*15516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < hoff + iplen)
2626*15516c77SSepherosa Ziehau 		return IPPROTO_DONE;
2627*15516c77SSepherosa Ziehau 
2628*15516c77SSepherosa Ziehau 	/*
2629*15516c77SSepherosa Ziehau 	 * Ignore IP fragments.
2630*15516c77SSepherosa Ziehau 	 */
2631*15516c77SSepherosa Ziehau 	if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF))
2632*15516c77SSepherosa Ziehau 		return IPPROTO_DONE;
2633*15516c77SSepherosa Ziehau 
2634*15516c77SSepherosa Ziehau 	/*
2635*15516c77SSepherosa Ziehau 	 * The TCP/IP or UDP/IP header must be entirely contained within
2636*15516c77SSepherosa Ziehau 	 * the first fragment of a packet.
2637*15516c77SSepherosa Ziehau 	 */
2638*15516c77SSepherosa Ziehau 	switch (ip->ip_p) {
2639*15516c77SSepherosa Ziehau 	case IPPROTO_TCP:
2640*15516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct tcphdr))
2641*15516c77SSepherosa Ziehau 			return IPPROTO_DONE;
2642*15516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct tcphdr))
2643*15516c77SSepherosa Ziehau 			return IPPROTO_DONE;
2644*15516c77SSepherosa Ziehau 		th = (const struct tcphdr *)((const uint8_t *)ip + iphlen);
2645*15516c77SSepherosa Ziehau 		thoff = th->th_off << 2;
2646*15516c77SSepherosa Ziehau 		if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen)
2647*15516c77SSepherosa Ziehau 			return IPPROTO_DONE;
2648*15516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + thoff)
2649*15516c77SSepherosa Ziehau 			return IPPROTO_DONE;
2650*15516c77SSepherosa Ziehau 		break;
2651*15516c77SSepherosa Ziehau 	case IPPROTO_UDP:
2652*15516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct udphdr))
2653*15516c77SSepherosa Ziehau 			return IPPROTO_DONE;
2654*15516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct udphdr))
2655*15516c77SSepherosa Ziehau 			return IPPROTO_DONE;
2656*15516c77SSepherosa Ziehau 		break;
2657*15516c77SSepherosa Ziehau 	default:
2658*15516c77SSepherosa Ziehau 		if (iplen < iphlen)
2659*15516c77SSepherosa Ziehau 			return IPPROTO_DONE;
2660*15516c77SSepherosa Ziehau 		break;
2661*15516c77SSepherosa Ziehau 	}
2662*15516c77SSepherosa Ziehau 	return ip->ip_p;
2663*15516c77SSepherosa Ziehau }
2664*15516c77SSepherosa Ziehau 
2665*15516c77SSepherosa Ziehau static int
2666*15516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt)
2667*15516c77SSepherosa Ziehau {
2668*15516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
2669*15516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
2670*15516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
2671*15516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
2672*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
2673*15516c77SSepherosa Ziehau 	int lroent_cnt;
2674*15516c77SSepherosa Ziehau #endif
2675*15516c77SSepherosa Ziehau #endif
2676*15516c77SSepherosa Ziehau 	int i;
2677*15516c77SSepherosa Ziehau 
2678*15516c77SSepherosa Ziehau 	/*
2679*15516c77SSepherosa Ziehau 	 * Create RXBUF for reception.
2680*15516c77SSepherosa Ziehau 	 *
2681*15516c77SSepherosa Ziehau 	 * NOTE:
2682*15516c77SSepherosa Ziehau 	 * - It is shared by all channels.
2683*15516c77SSepherosa Ziehau 	 * - A large enough buffer is allocated, certain version of NVSes
2684*15516c77SSepherosa Ziehau 	 *   may further limit the usable space.
2685*15516c77SSepherosa Ziehau 	 */
2686*15516c77SSepherosa Ziehau 	sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
2687*15516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma,
2688*15516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
2689*15516c77SSepherosa Ziehau 	if (sc->hn_rxbuf == NULL) {
2690*15516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate rxbuf failed\n");
2691*15516c77SSepherosa Ziehau 		return (ENOMEM);
2692*15516c77SSepherosa Ziehau 	}
2693*15516c77SSepherosa Ziehau 
2694*15516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = ring_cnt;
2695*15516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt;
2696*15516c77SSepherosa Ziehau 
2697*15516c77SSepherosa Ziehau 	sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt,
2698*15516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
2699*15516c77SSepherosa Ziehau 
2700*15516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
2701*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
2702*15516c77SSepherosa Ziehau 	lroent_cnt = hn_lro_entry_count;
2703*15516c77SSepherosa Ziehau 	if (lroent_cnt < TCP_LRO_ENTRIES)
2704*15516c77SSepherosa Ziehau 		lroent_cnt = TCP_LRO_ENTRIES;
2705*15516c77SSepherosa Ziehau 	if (bootverbose)
2706*15516c77SSepherosa Ziehau 		device_printf(dev, "LRO: entry count %d\n", lroent_cnt);
2707*15516c77SSepherosa Ziehau #endif
2708*15516c77SSepherosa Ziehau #endif	/* INET || INET6 */
2709*15516c77SSepherosa Ziehau 
2710*15516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
2711*15516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
2712*15516c77SSepherosa Ziehau 
2713*15516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.rx sysctl tree */
2714*15516c77SSepherosa Ziehau 	sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx",
2715*15516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
2716*15516c77SSepherosa Ziehau 
2717*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
2718*15516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
2719*15516c77SSepherosa Ziehau 
2720*15516c77SSepherosa Ziehau 		rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
2721*15516c77SSepherosa Ziehau 		    PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE,
2722*15516c77SSepherosa Ziehau 		    &rxr->hn_br_dma, BUS_DMA_WAITOK);
2723*15516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL) {
2724*15516c77SSepherosa Ziehau 			device_printf(dev, "allocate bufring failed\n");
2725*15516c77SSepherosa Ziehau 			return (ENOMEM);
2726*15516c77SSepherosa Ziehau 		}
2727*15516c77SSepherosa Ziehau 
2728*15516c77SSepherosa Ziehau 		if (hn_trust_hosttcp)
2729*15516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP;
2730*15516c77SSepherosa Ziehau 		if (hn_trust_hostudp)
2731*15516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP;
2732*15516c77SSepherosa Ziehau 		if (hn_trust_hostip)
2733*15516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP;
2734*15516c77SSepherosa Ziehau 		rxr->hn_ifp = sc->hn_ifp;
2735*15516c77SSepherosa Ziehau 		if (i < sc->hn_tx_ring_cnt)
2736*15516c77SSepherosa Ziehau 			rxr->hn_txr = &sc->hn_tx_ring[i];
2737*15516c77SSepherosa Ziehau 		rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF;
2738*15516c77SSepherosa Ziehau 		rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK);
2739*15516c77SSepherosa Ziehau 		rxr->hn_rx_idx = i;
2740*15516c77SSepherosa Ziehau 		rxr->hn_rxbuf = sc->hn_rxbuf;
2741*15516c77SSepherosa Ziehau 
2742*15516c77SSepherosa Ziehau 		/*
2743*15516c77SSepherosa Ziehau 		 * Initialize LRO.
2744*15516c77SSepherosa Ziehau 		 */
2745*15516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
2746*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
2747*15516c77SSepherosa Ziehau 		tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt,
2748*15516c77SSepherosa Ziehau 		    hn_lro_mbufq_depth);
2749*15516c77SSepherosa Ziehau #else
2750*15516c77SSepherosa Ziehau 		tcp_lro_init(&rxr->hn_lro);
2751*15516c77SSepherosa Ziehau 		rxr->hn_lro.ifp = sc->hn_ifp;
2752*15516c77SSepherosa Ziehau #endif
2753*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
2754*15516c77SSepherosa Ziehau 		rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF;
2755*15516c77SSepherosa Ziehau 		rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF;
2756*15516c77SSepherosa Ziehau #endif
2757*15516c77SSepherosa Ziehau #endif	/* INET || INET6 */
2758*15516c77SSepherosa Ziehau 
2759*15516c77SSepherosa Ziehau 		if (sc->hn_rx_sysctl_tree != NULL) {
2760*15516c77SSepherosa Ziehau 			char name[16];
2761*15516c77SSepherosa Ziehau 
2762*15516c77SSepherosa Ziehau 			/*
2763*15516c77SSepherosa Ziehau 			 * Create per RX ring sysctl tree:
2764*15516c77SSepherosa Ziehau 			 * dev.hn.UNIT.rx.RINGID
2765*15516c77SSepherosa Ziehau 			 */
2766*15516c77SSepherosa Ziehau 			snprintf(name, sizeof(name), "%d", i);
2767*15516c77SSepherosa Ziehau 			rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx,
2768*15516c77SSepherosa Ziehau 			    SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree),
2769*15516c77SSepherosa Ziehau 			    OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
2770*15516c77SSepherosa Ziehau 
2771*15516c77SSepherosa Ziehau 			if (rxr->hn_rx_sysctl_tree != NULL) {
2772*15516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
2773*15516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
2774*15516c77SSepherosa Ziehau 				    OID_AUTO, "packets", CTLFLAG_RW,
2775*15516c77SSepherosa Ziehau 				    &rxr->hn_pkts, "# of packets received");
2776*15516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
2777*15516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
2778*15516c77SSepherosa Ziehau 				    OID_AUTO, "rss_pkts", CTLFLAG_RW,
2779*15516c77SSepherosa Ziehau 				    &rxr->hn_rss_pkts,
2780*15516c77SSepherosa Ziehau 				    "# of packets w/ RSS info received");
2781*15516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx,
2782*15516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
2783*15516c77SSepherosa Ziehau 				    OID_AUTO, "pktbuf_len", CTLFLAG_RD,
2784*15516c77SSepherosa Ziehau 				    &rxr->hn_pktbuf_len, 0,
2785*15516c77SSepherosa Ziehau 				    "Temporary channel packet buffer length");
2786*15516c77SSepherosa Ziehau 			}
2787*15516c77SSepherosa Ziehau 		}
2788*15516c77SSepherosa Ziehau 	}
2789*15516c77SSepherosa Ziehau 
2790*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued",
2791*15516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
2792*15516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_queued),
2793*15516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
2794*15516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
2795*15516c77SSepherosa Ziehau #else
2796*15516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
2797*15516c77SSepherosa Ziehau #endif
2798*15516c77SSepherosa Ziehau 	    "LU", "LRO queued");
2799*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed",
2800*15516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
2801*15516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_flushed),
2802*15516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
2803*15516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
2804*15516c77SSepherosa Ziehau #else
2805*15516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
2806*15516c77SSepherosa Ziehau #endif
2807*15516c77SSepherosa Ziehau 	    "LU", "LRO flushed");
2808*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried",
2809*15516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
2810*15516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro_tried),
2811*15516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries");
2812*15516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
2813*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim",
2814*15516c77SSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
2815*15516c77SSepherosa Ziehau 	    hn_lro_lenlim_sysctl, "IU",
2816*15516c77SSepherosa Ziehau 	    "Max # of data bytes to be aggregated by LRO");
2817*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim",
2818*15516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
2819*15516c77SSepherosa Ziehau 	    hn_lro_ackcnt_sysctl, "I",
2820*15516c77SSepherosa Ziehau 	    "Max # of ACKs to be aggregated by LRO");
2821*15516c77SSepherosa Ziehau #endif
2822*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp",
2823*15516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP,
2824*15516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
2825*15516c77SSepherosa Ziehau 	    "Trust tcp segement verification on host side, "
2826*15516c77SSepherosa Ziehau 	    "when csum info is missing");
2827*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp",
2828*15516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP,
2829*15516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
2830*15516c77SSepherosa Ziehau 	    "Trust udp datagram verification on host side, "
2831*15516c77SSepherosa Ziehau 	    "when csum info is missing");
2832*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip",
2833*15516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP,
2834*15516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
2835*15516c77SSepherosa Ziehau 	    "Trust ip packet verification on host side, "
2836*15516c77SSepherosa Ziehau 	    "when csum info is missing");
2837*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip",
2838*15516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
2839*15516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_ip),
2840*15516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP");
2841*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp",
2842*15516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
2843*15516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_tcp),
2844*15516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP");
2845*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp",
2846*15516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
2847*15516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_udp),
2848*15516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP");
2849*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted",
2850*15516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
2851*15516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_trusted),
2852*15516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU",
2853*15516c77SSepherosa Ziehau 	    "# of packets that we trust host's csum verification");
2854*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts",
2855*15516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
2856*15516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_small_pkts),
2857*15516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of small packets received");
2858*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed",
2859*15516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
2860*15516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_ack_failed),
2861*15516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures");
2862*15516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt",
2863*15516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings");
2864*15516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse",
2865*15516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings");
2866*15516c77SSepherosa Ziehau 
2867*15516c77SSepherosa Ziehau 	return (0);
2868*15516c77SSepherosa Ziehau }
2869*15516c77SSepherosa Ziehau 
2870*15516c77SSepherosa Ziehau static void
2871*15516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc)
2872*15516c77SSepherosa Ziehau {
2873*15516c77SSepherosa Ziehau 	int i;
2874*15516c77SSepherosa Ziehau 
2875*15516c77SSepherosa Ziehau 	if (sc->hn_rxbuf != NULL) {
2876*15516c77SSepherosa Ziehau 		hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf);
2877*15516c77SSepherosa Ziehau 		sc->hn_rxbuf = NULL;
2878*15516c77SSepherosa Ziehau 	}
2879*15516c77SSepherosa Ziehau 
2880*15516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_cnt == 0)
2881*15516c77SSepherosa Ziehau 		return;
2882*15516c77SSepherosa Ziehau 
2883*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
2884*15516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
2885*15516c77SSepherosa Ziehau 
2886*15516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL)
2887*15516c77SSepherosa Ziehau 			continue;
2888*15516c77SSepherosa Ziehau 		hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br);
2889*15516c77SSepherosa Ziehau 		rxr->hn_br = NULL;
2890*15516c77SSepherosa Ziehau 
2891*15516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
2892*15516c77SSepherosa Ziehau 		tcp_lro_free(&rxr->hn_lro);
2893*15516c77SSepherosa Ziehau #endif
2894*15516c77SSepherosa Ziehau 		free(rxr->hn_pktbuf, M_DEVBUF);
2895*15516c77SSepherosa Ziehau 	}
2896*15516c77SSepherosa Ziehau 	free(sc->hn_rx_ring, M_DEVBUF);
2897*15516c77SSepherosa Ziehau 	sc->hn_rx_ring = NULL;
2898*15516c77SSepherosa Ziehau 
2899*15516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = 0;
2900*15516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = 0;
2901*15516c77SSepherosa Ziehau }
2902*15516c77SSepherosa Ziehau 
2903*15516c77SSepherosa Ziehau static int
2904*15516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id)
2905*15516c77SSepherosa Ziehau {
2906*15516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[id];
2907*15516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
2908*15516c77SSepherosa Ziehau 	bus_dma_tag_t parent_dtag;
2909*15516c77SSepherosa Ziehau 	int error, i;
2910*15516c77SSepherosa Ziehau 
2911*15516c77SSepherosa Ziehau 	txr->hn_sc = sc;
2912*15516c77SSepherosa Ziehau 	txr->hn_tx_idx = id;
2913*15516c77SSepherosa Ziehau 
2914*15516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
2915*15516c77SSepherosa Ziehau 	mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN);
2916*15516c77SSepherosa Ziehau #endif
2917*15516c77SSepherosa Ziehau 	mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF);
2918*15516c77SSepherosa Ziehau 
2919*15516c77SSepherosa Ziehau 	txr->hn_txdesc_cnt = HN_TX_DESC_CNT;
2920*15516c77SSepherosa Ziehau 	txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt,
2921*15516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
2922*15516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
2923*15516c77SSepherosa Ziehau 	SLIST_INIT(&txr->hn_txlist);
2924*15516c77SSepherosa Ziehau #else
2925*15516c77SSepherosa Ziehau 	txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF,
2926*15516c77SSepherosa Ziehau 	    M_WAITOK, &txr->hn_tx_lock);
2927*15516c77SSepherosa Ziehau #endif
2928*15516c77SSepherosa Ziehau 
2929*15516c77SSepherosa Ziehau 	txr->hn_tx_taskq = sc->hn_tx_taskq;
2930*15516c77SSepherosa Ziehau 
2931*15516c77SSepherosa Ziehau 	if (hn_use_if_start) {
2932*15516c77SSepherosa Ziehau 		txr->hn_txeof = hn_start_txeof;
2933*15516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr);
2934*15516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr);
2935*15516c77SSepherosa Ziehau 	} else {
2936*15516c77SSepherosa Ziehau 		int br_depth;
2937*15516c77SSepherosa Ziehau 
2938*15516c77SSepherosa Ziehau 		txr->hn_txeof = hn_xmit_txeof;
2939*15516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr);
2940*15516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr);
2941*15516c77SSepherosa Ziehau 
2942*15516c77SSepherosa Ziehau 		br_depth = hn_get_txswq_depth(txr);
2943*15516c77SSepherosa Ziehau 		txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF,
2944*15516c77SSepherosa Ziehau 		    M_WAITOK, &txr->hn_tx_lock);
2945*15516c77SSepherosa Ziehau 	}
2946*15516c77SSepherosa Ziehau 
2947*15516c77SSepherosa Ziehau 	txr->hn_direct_tx_size = hn_direct_tx_size;
2948*15516c77SSepherosa Ziehau 
2949*15516c77SSepherosa Ziehau 	/*
2950*15516c77SSepherosa Ziehau 	 * Always schedule transmission instead of trying to do direct
2951*15516c77SSepherosa Ziehau 	 * transmission.  This one gives the best performance so far.
2952*15516c77SSepherosa Ziehau 	 */
2953*15516c77SSepherosa Ziehau 	txr->hn_sched_tx = 1;
2954*15516c77SSepherosa Ziehau 
2955*15516c77SSepherosa Ziehau 	parent_dtag = bus_get_dma_tag(dev);
2956*15516c77SSepherosa Ziehau 
2957*15516c77SSepherosa Ziehau 	/* DMA tag for RNDIS packet messages. */
2958*15516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
2959*15516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_ALIGN,		/* alignment */
2960*15516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_BOUNDARY,	/* boundary */
2961*15516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
2962*15516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
2963*15516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
2964*15516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsize */
2965*15516c77SSepherosa Ziehau 	    1,				/* nsegments */
2966*15516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsegsize */
2967*15516c77SSepherosa Ziehau 	    0,				/* flags */
2968*15516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
2969*15516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
2970*15516c77SSepherosa Ziehau 	    &txr->hn_tx_rndis_dtag);
2971*15516c77SSepherosa Ziehau 	if (error) {
2972*15516c77SSepherosa Ziehau 		device_printf(dev, "failed to create rndis dmatag\n");
2973*15516c77SSepherosa Ziehau 		return error;
2974*15516c77SSepherosa Ziehau 	}
2975*15516c77SSepherosa Ziehau 
2976*15516c77SSepherosa Ziehau 	/* DMA tag for data. */
2977*15516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
2978*15516c77SSepherosa Ziehau 	    1,				/* alignment */
2979*15516c77SSepherosa Ziehau 	    HN_TX_DATA_BOUNDARY,	/* boundary */
2980*15516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
2981*15516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
2982*15516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
2983*15516c77SSepherosa Ziehau 	    HN_TX_DATA_MAXSIZE,		/* maxsize */
2984*15516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGCNT_MAX,	/* nsegments */
2985*15516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGSIZE,		/* maxsegsize */
2986*15516c77SSepherosa Ziehau 	    0,				/* flags */
2987*15516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
2988*15516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
2989*15516c77SSepherosa Ziehau 	    &txr->hn_tx_data_dtag);
2990*15516c77SSepherosa Ziehau 	if (error) {
2991*15516c77SSepherosa Ziehau 		device_printf(dev, "failed to create data dmatag\n");
2992*15516c77SSepherosa Ziehau 		return error;
2993*15516c77SSepherosa Ziehau 	}
2994*15516c77SSepherosa Ziehau 
2995*15516c77SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i) {
2996*15516c77SSepherosa Ziehau 		struct hn_txdesc *txd = &txr->hn_txdesc[i];
2997*15516c77SSepherosa Ziehau 
2998*15516c77SSepherosa Ziehau 		txd->txr = txr;
2999*15516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
3000*15516c77SSepherosa Ziehau 
3001*15516c77SSepherosa Ziehau 		/*
3002*15516c77SSepherosa Ziehau 		 * Allocate and load RNDIS packet message.
3003*15516c77SSepherosa Ziehau 		 */
3004*15516c77SSepherosa Ziehau         	error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag,
3005*15516c77SSepherosa Ziehau 		    (void **)&txd->rndis_pkt,
3006*15516c77SSepherosa Ziehau 		    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
3007*15516c77SSepherosa Ziehau 		    &txd->rndis_pkt_dmap);
3008*15516c77SSepherosa Ziehau 		if (error) {
3009*15516c77SSepherosa Ziehau 			device_printf(dev,
3010*15516c77SSepherosa Ziehau 			    "failed to allocate rndis_packet_msg, %d\n", i);
3011*15516c77SSepherosa Ziehau 			return error;
3012*15516c77SSepherosa Ziehau 		}
3013*15516c77SSepherosa Ziehau 
3014*15516c77SSepherosa Ziehau 		error = bus_dmamap_load(txr->hn_tx_rndis_dtag,
3015*15516c77SSepherosa Ziehau 		    txd->rndis_pkt_dmap,
3016*15516c77SSepherosa Ziehau 		    txd->rndis_pkt, HN_RNDIS_PKT_LEN,
3017*15516c77SSepherosa Ziehau 		    hyperv_dma_map_paddr, &txd->rndis_pkt_paddr,
3018*15516c77SSepherosa Ziehau 		    BUS_DMA_NOWAIT);
3019*15516c77SSepherosa Ziehau 		if (error) {
3020*15516c77SSepherosa Ziehau 			device_printf(dev,
3021*15516c77SSepherosa Ziehau 			    "failed to load rndis_packet_msg, %d\n", i);
3022*15516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
3023*15516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
3024*15516c77SSepherosa Ziehau 			return error;
3025*15516c77SSepherosa Ziehau 		}
3026*15516c77SSepherosa Ziehau 
3027*15516c77SSepherosa Ziehau 		/* DMA map for TX data. */
3028*15516c77SSepherosa Ziehau 		error = bus_dmamap_create(txr->hn_tx_data_dtag, 0,
3029*15516c77SSepherosa Ziehau 		    &txd->data_dmap);
3030*15516c77SSepherosa Ziehau 		if (error) {
3031*15516c77SSepherosa Ziehau 			device_printf(dev,
3032*15516c77SSepherosa Ziehau 			    "failed to allocate tx data dmamap\n");
3033*15516c77SSepherosa Ziehau 			bus_dmamap_unload(txr->hn_tx_rndis_dtag,
3034*15516c77SSepherosa Ziehau 			    txd->rndis_pkt_dmap);
3035*15516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
3036*15516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
3037*15516c77SSepherosa Ziehau 			return error;
3038*15516c77SSepherosa Ziehau 		}
3039*15516c77SSepherosa Ziehau 
3040*15516c77SSepherosa Ziehau 		/* All set, put it to list */
3041*15516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_ONLIST;
3042*15516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
3043*15516c77SSepherosa Ziehau 		SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
3044*15516c77SSepherosa Ziehau #else
3045*15516c77SSepherosa Ziehau 		buf_ring_enqueue(txr->hn_txdesc_br, txd);
3046*15516c77SSepherosa Ziehau #endif
3047*15516c77SSepherosa Ziehau 	}
3048*15516c77SSepherosa Ziehau 	txr->hn_txdesc_avail = txr->hn_txdesc_cnt;
3049*15516c77SSepherosa Ziehau 
3050*15516c77SSepherosa Ziehau 	if (sc->hn_tx_sysctl_tree != NULL) {
3051*15516c77SSepherosa Ziehau 		struct sysctl_oid_list *child;
3052*15516c77SSepherosa Ziehau 		struct sysctl_ctx_list *ctx;
3053*15516c77SSepherosa Ziehau 		char name[16];
3054*15516c77SSepherosa Ziehau 
3055*15516c77SSepherosa Ziehau 		/*
3056*15516c77SSepherosa Ziehau 		 * Create per TX ring sysctl tree:
3057*15516c77SSepherosa Ziehau 		 * dev.hn.UNIT.tx.RINGID
3058*15516c77SSepherosa Ziehau 		 */
3059*15516c77SSepherosa Ziehau 		ctx = device_get_sysctl_ctx(dev);
3060*15516c77SSepherosa Ziehau 		child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree);
3061*15516c77SSepherosa Ziehau 
3062*15516c77SSepherosa Ziehau 		snprintf(name, sizeof(name), "%d", id);
3063*15516c77SSepherosa Ziehau 		txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
3064*15516c77SSepherosa Ziehau 		    name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
3065*15516c77SSepherosa Ziehau 
3066*15516c77SSepherosa Ziehau 		if (txr->hn_tx_sysctl_tree != NULL) {
3067*15516c77SSepherosa Ziehau 			child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree);
3068*15516c77SSepherosa Ziehau 
3069*15516c77SSepherosa Ziehau 			SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail",
3070*15516c77SSepherosa Ziehau 			    CTLFLAG_RD, &txr->hn_txdesc_avail, 0,
3071*15516c77SSepherosa Ziehau 			    "# of available TX descs");
3072*15516c77SSepherosa Ziehau 			if (!hn_use_if_start) {
3073*15516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive",
3074*15516c77SSepherosa Ziehau 				    CTLFLAG_RD, &txr->hn_oactive, 0,
3075*15516c77SSepherosa Ziehau 				    "over active");
3076*15516c77SSepherosa Ziehau 			}
3077*15516c77SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets",
3078*15516c77SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_pkts,
3079*15516c77SSepherosa Ziehau 			    "# of packets transmitted");
3080*15516c77SSepherosa Ziehau 		}
3081*15516c77SSepherosa Ziehau 	}
3082*15516c77SSepherosa Ziehau 
3083*15516c77SSepherosa Ziehau 	return 0;
3084*15516c77SSepherosa Ziehau }
3085*15516c77SSepherosa Ziehau 
3086*15516c77SSepherosa Ziehau static void
3087*15516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd)
3088*15516c77SSepherosa Ziehau {
3089*15516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = txd->txr;
3090*15516c77SSepherosa Ziehau 
3091*15516c77SSepherosa Ziehau 	KASSERT(txd->m == NULL, ("still has mbuf installed"));
3092*15516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped"));
3093*15516c77SSepherosa Ziehau 
3094*15516c77SSepherosa Ziehau 	bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap);
3095*15516c77SSepherosa Ziehau 	bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt,
3096*15516c77SSepherosa Ziehau 	    txd->rndis_pkt_dmap);
3097*15516c77SSepherosa Ziehau 	bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap);
3098*15516c77SSepherosa Ziehau }
3099*15516c77SSepherosa Ziehau 
3100*15516c77SSepherosa Ziehau static void
3101*15516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr)
3102*15516c77SSepherosa Ziehau {
3103*15516c77SSepherosa Ziehau 	struct hn_txdesc *txd;
3104*15516c77SSepherosa Ziehau 
3105*15516c77SSepherosa Ziehau 	if (txr->hn_txdesc == NULL)
3106*15516c77SSepherosa Ziehau 		return;
3107*15516c77SSepherosa Ziehau 
3108*15516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
3109*15516c77SSepherosa Ziehau 	while ((txd = SLIST_FIRST(&txr->hn_txlist)) != NULL) {
3110*15516c77SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&txr->hn_txlist, link);
3111*15516c77SSepherosa Ziehau 		hn_txdesc_dmamap_destroy(txd);
3112*15516c77SSepherosa Ziehau 	}
3113*15516c77SSepherosa Ziehau #else
3114*15516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
3115*15516c77SSepherosa Ziehau 	while ((txd = buf_ring_dequeue_sc(txr->hn_txdesc_br)) != NULL)
3116*15516c77SSepherosa Ziehau 		hn_txdesc_dmamap_destroy(txd);
3117*15516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
3118*15516c77SSepherosa Ziehau #endif
3119*15516c77SSepherosa Ziehau 
3120*15516c77SSepherosa Ziehau 	if (txr->hn_tx_data_dtag != NULL)
3121*15516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_data_dtag);
3122*15516c77SSepherosa Ziehau 	if (txr->hn_tx_rndis_dtag != NULL)
3123*15516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_rndis_dtag);
3124*15516c77SSepherosa Ziehau 
3125*15516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
3126*15516c77SSepherosa Ziehau 	buf_ring_free(txr->hn_txdesc_br, M_DEVBUF);
3127*15516c77SSepherosa Ziehau #endif
3128*15516c77SSepherosa Ziehau 
3129*15516c77SSepherosa Ziehau 	free(txr->hn_txdesc, M_DEVBUF);
3130*15516c77SSepherosa Ziehau 	txr->hn_txdesc = NULL;
3131*15516c77SSepherosa Ziehau 
3132*15516c77SSepherosa Ziehau 	if (txr->hn_mbuf_br != NULL)
3133*15516c77SSepherosa Ziehau 		buf_ring_free(txr->hn_mbuf_br, M_DEVBUF);
3134*15516c77SSepherosa Ziehau 
3135*15516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
3136*15516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_txlist_spin);
3137*15516c77SSepherosa Ziehau #endif
3138*15516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_tx_lock);
3139*15516c77SSepherosa Ziehau }
3140*15516c77SSepherosa Ziehau 
3141*15516c77SSepherosa Ziehau static int
3142*15516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt)
3143*15516c77SSepherosa Ziehau {
3144*15516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
3145*15516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
3146*15516c77SSepherosa Ziehau 	int i;
3147*15516c77SSepherosa Ziehau 
3148*15516c77SSepherosa Ziehau 	/*
3149*15516c77SSepherosa Ziehau 	 * Create TXBUF for chimney sending.
3150*15516c77SSepherosa Ziehau 	 *
3151*15516c77SSepherosa Ziehau 	 * NOTE: It is shared by all channels.
3152*15516c77SSepherosa Ziehau 	 */
3153*15516c77SSepherosa Ziehau 	sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev),
3154*15516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma,
3155*15516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
3156*15516c77SSepherosa Ziehau 	if (sc->hn_chim == NULL) {
3157*15516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate txbuf failed\n");
3158*15516c77SSepherosa Ziehau 		return (ENOMEM);
3159*15516c77SSepherosa Ziehau 	}
3160*15516c77SSepherosa Ziehau 
3161*15516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = ring_cnt;
3162*15516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
3163*15516c77SSepherosa Ziehau 
3164*15516c77SSepherosa Ziehau 	sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt,
3165*15516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
3166*15516c77SSepherosa Ziehau 
3167*15516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(sc->hn_dev);
3168*15516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev));
3169*15516c77SSepherosa Ziehau 
3170*15516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.tx sysctl tree */
3171*15516c77SSepherosa Ziehau 	sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx",
3172*15516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
3173*15516c77SSepherosa Ziehau 
3174*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
3175*15516c77SSepherosa Ziehau 		int error;
3176*15516c77SSepherosa Ziehau 
3177*15516c77SSepherosa Ziehau 		error = hn_tx_ring_create(sc, i);
3178*15516c77SSepherosa Ziehau 		if (error)
3179*15516c77SSepherosa Ziehau 			return error;
3180*15516c77SSepherosa Ziehau 	}
3181*15516c77SSepherosa Ziehau 
3182*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs",
3183*15516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
3184*15516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_no_txdescs),
3185*15516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs");
3186*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed",
3187*15516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
3188*15516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_send_failed),
3189*15516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure");
3190*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed",
3191*15516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
3192*15516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_txdma_failed),
3193*15516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure");
3194*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed",
3195*15516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
3196*15516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_collapsed),
3197*15516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed");
3198*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney",
3199*15516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
3200*15516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney),
3201*15516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send");
3202*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried",
3203*15516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
3204*15516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney_tried),
3205*15516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries");
3206*15516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt",
3207*15516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0,
3208*15516c77SSepherosa Ziehau 	    "# of total TX descs");
3209*15516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max",
3210*15516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_chim_szmax, 0,
3211*15516c77SSepherosa Ziehau 	    "Chimney send packet size upper boundary");
3212*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size",
3213*15516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
3214*15516c77SSepherosa Ziehau 	    hn_chim_size_sysctl, "I", "Chimney send packet size limit");
3215*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size",
3216*15516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
3217*15516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_direct_tx_size),
3218*15516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
3219*15516c77SSepherosa Ziehau 	    "Size of the packet for direct transmission");
3220*15516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx",
3221*15516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
3222*15516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_sched_tx),
3223*15516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
3224*15516c77SSepherosa Ziehau 	    "Always schedule transmission "
3225*15516c77SSepherosa Ziehau 	    "instead of doing direct transmission");
3226*15516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt",
3227*15516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings");
3228*15516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse",
3229*15516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings");
3230*15516c77SSepherosa Ziehau 
3231*15516c77SSepherosa Ziehau 	return 0;
3232*15516c77SSepherosa Ziehau }
3233*15516c77SSepherosa Ziehau 
3234*15516c77SSepherosa Ziehau static void
3235*15516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size)
3236*15516c77SSepherosa Ziehau {
3237*15516c77SSepherosa Ziehau 	int i;
3238*15516c77SSepherosa Ziehau 
3239*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
3240*15516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_chim_size = chim_size;
3241*15516c77SSepherosa Ziehau }
3242*15516c77SSepherosa Ziehau 
3243*15516c77SSepherosa Ziehau static void
3244*15516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu)
3245*15516c77SSepherosa Ziehau {
3246*15516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
3247*15516c77SSepherosa Ziehau 	int tso_minlen;
3248*15516c77SSepherosa Ziehau 
3249*15516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0)
3250*15516c77SSepherosa Ziehau 		return;
3251*15516c77SSepherosa Ziehau 
3252*15516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_sgmin >= 2,
3253*15516c77SSepherosa Ziehau 	    ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin));
3254*15516c77SSepherosa Ziehau 	tso_minlen = sc->hn_ndis_tso_sgmin * mtu;
3255*15516c77SSepherosa Ziehau 
3256*15516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen &&
3257*15516c77SSepherosa Ziehau 	    sc->hn_ndis_tso_szmax <= IP_MAXPACKET,
3258*15516c77SSepherosa Ziehau 	    ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax));
3259*15516c77SSepherosa Ziehau 
3260*15516c77SSepherosa Ziehau 	if (tso_maxlen < tso_minlen)
3261*15516c77SSepherosa Ziehau 		tso_maxlen = tso_minlen;
3262*15516c77SSepherosa Ziehau 	else if (tso_maxlen > IP_MAXPACKET)
3263*15516c77SSepherosa Ziehau 		tso_maxlen = IP_MAXPACKET;
3264*15516c77SSepherosa Ziehau 	if (tso_maxlen > sc->hn_ndis_tso_szmax)
3265*15516c77SSepherosa Ziehau 		tso_maxlen = sc->hn_ndis_tso_szmax;
3266*15516c77SSepherosa Ziehau 	ifp->if_hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
3267*15516c77SSepherosa Ziehau 	if (bootverbose)
3268*15516c77SSepherosa Ziehau 		if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax);
3269*15516c77SSepherosa Ziehau }
3270*15516c77SSepherosa Ziehau 
3271*15516c77SSepherosa Ziehau static void
3272*15516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc)
3273*15516c77SSepherosa Ziehau {
3274*15516c77SSepherosa Ziehau 	uint64_t csum_assist;
3275*15516c77SSepherosa Ziehau 	int i;
3276*15516c77SSepherosa Ziehau 
3277*15516c77SSepherosa Ziehau 	hn_set_chim_size(sc, sc->hn_chim_szmax);
3278*15516c77SSepherosa Ziehau 	if (hn_tx_chimney_size > 0 &&
3279*15516c77SSepherosa Ziehau 	    hn_tx_chimney_size < sc->hn_chim_szmax)
3280*15516c77SSepherosa Ziehau 		hn_set_chim_size(sc, hn_tx_chimney_size);
3281*15516c77SSepherosa Ziehau 
3282*15516c77SSepherosa Ziehau 	csum_assist = 0;
3283*15516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_IPCS)
3284*15516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP;
3285*15516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP4CS)
3286*15516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_TCP;
3287*15516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP4CS)
3288*15516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_UDP;
3289*15516c77SSepherosa Ziehau #ifdef notyet
3290*15516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP6CS)
3291*15516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_TCP;
3292*15516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP6CS)
3293*15516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_UDP;
3294*15516c77SSepherosa Ziehau #endif
3295*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
3296*15516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_csum_assist = csum_assist;
3297*15516c77SSepherosa Ziehau 
3298*15516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_HASHVAL) {
3299*15516c77SSepherosa Ziehau 		/*
3300*15516c77SSepherosa Ziehau 		 * Support HASHVAL pktinfo on TX path.
3301*15516c77SSepherosa Ziehau 		 */
3302*15516c77SSepherosa Ziehau 		if (bootverbose)
3303*15516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n");
3304*15516c77SSepherosa Ziehau 		for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
3305*15516c77SSepherosa Ziehau 			sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL;
3306*15516c77SSepherosa Ziehau 	}
3307*15516c77SSepherosa Ziehau }
3308*15516c77SSepherosa Ziehau 
3309*15516c77SSepherosa Ziehau static void
3310*15516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc)
3311*15516c77SSepherosa Ziehau {
3312*15516c77SSepherosa Ziehau 	int i;
3313*15516c77SSepherosa Ziehau 
3314*15516c77SSepherosa Ziehau 	if (sc->hn_chim != NULL) {
3315*15516c77SSepherosa Ziehau 		hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim);
3316*15516c77SSepherosa Ziehau 		sc->hn_chim = NULL;
3317*15516c77SSepherosa Ziehau 	}
3318*15516c77SSepherosa Ziehau 
3319*15516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt == 0)
3320*15516c77SSepherosa Ziehau 		return;
3321*15516c77SSepherosa Ziehau 
3322*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
3323*15516c77SSepherosa Ziehau 		hn_tx_ring_destroy(&sc->hn_tx_ring[i]);
3324*15516c77SSepherosa Ziehau 
3325*15516c77SSepherosa Ziehau 	free(sc->hn_tx_ring, M_DEVBUF);
3326*15516c77SSepherosa Ziehau 	sc->hn_tx_ring = NULL;
3327*15516c77SSepherosa Ziehau 
3328*15516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = 0;
3329*15516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = 0;
3330*15516c77SSepherosa Ziehau }
3331*15516c77SSepherosa Ziehau 
3332*15516c77SSepherosa Ziehau static void
3333*15516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused)
3334*15516c77SSepherosa Ziehau {
3335*15516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
3336*15516c77SSepherosa Ziehau 
3337*15516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
3338*15516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
3339*15516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
3340*15516c77SSepherosa Ziehau }
3341*15516c77SSepherosa Ziehau 
3342*15516c77SSepherosa Ziehau static void
3343*15516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused)
3344*15516c77SSepherosa Ziehau {
3345*15516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
3346*15516c77SSepherosa Ziehau 
3347*15516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
3348*15516c77SSepherosa Ziehau 	atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE);
3349*15516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
3350*15516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
3351*15516c77SSepherosa Ziehau }
3352*15516c77SSepherosa Ziehau 
3353*15516c77SSepherosa Ziehau static int
3354*15516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len)
3355*15516c77SSepherosa Ziehau {
3356*15516c77SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
3357*15516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
3358*15516c77SSepherosa Ziehau 	struct mbuf *m_head;
3359*15516c77SSepherosa Ziehau 
3360*15516c77SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
3361*15516c77SSepherosa Ziehau 	KASSERT(hn_use_if_start == 0,
3362*15516c77SSepherosa Ziehau 	    ("hn_xmit is called, when if_start is enabled"));
3363*15516c77SSepherosa Ziehau 
3364*15516c77SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
3365*15516c77SSepherosa Ziehau 		return 0;
3366*15516c77SSepherosa Ziehau 
3367*15516c77SSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive)
3368*15516c77SSepherosa Ziehau 		return 0;
3369*15516c77SSepherosa Ziehau 
3370*15516c77SSepherosa Ziehau 	while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) {
3371*15516c77SSepherosa Ziehau 		struct hn_txdesc *txd;
3372*15516c77SSepherosa Ziehau 		int error;
3373*15516c77SSepherosa Ziehau 
3374*15516c77SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
3375*15516c77SSepherosa Ziehau 			/*
3376*15516c77SSepherosa Ziehau 			 * This sending could be time consuming; let callers
3377*15516c77SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
3378*15516c77SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
3379*15516c77SSepherosa Ziehau 			 */
3380*15516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
3381*15516c77SSepherosa Ziehau 			return 1;
3382*15516c77SSepherosa Ziehau 		}
3383*15516c77SSepherosa Ziehau 
3384*15516c77SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
3385*15516c77SSepherosa Ziehau 		if (txd == NULL) {
3386*15516c77SSepherosa Ziehau 			txr->hn_no_txdescs++;
3387*15516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
3388*15516c77SSepherosa Ziehau 			txr->hn_oactive = 1;
3389*15516c77SSepherosa Ziehau 			break;
3390*15516c77SSepherosa Ziehau 		}
3391*15516c77SSepherosa Ziehau 
3392*15516c77SSepherosa Ziehau 		error = hn_encap(txr, txd, &m_head);
3393*15516c77SSepherosa Ziehau 		if (error) {
3394*15516c77SSepherosa Ziehau 			/* Both txd and m_head are freed; discard */
3395*15516c77SSepherosa Ziehau 			drbr_advance(ifp, txr->hn_mbuf_br);
3396*15516c77SSepherosa Ziehau 			continue;
3397*15516c77SSepherosa Ziehau 		}
3398*15516c77SSepherosa Ziehau 
3399*15516c77SSepherosa Ziehau 		error = hn_txpkt(ifp, txr, txd);
3400*15516c77SSepherosa Ziehau 		if (__predict_false(error)) {
3401*15516c77SSepherosa Ziehau 			/* txd is freed, but m_head is not */
3402*15516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
3403*15516c77SSepherosa Ziehau 			txr->hn_oactive = 1;
3404*15516c77SSepherosa Ziehau 			break;
3405*15516c77SSepherosa Ziehau 		}
3406*15516c77SSepherosa Ziehau 
3407*15516c77SSepherosa Ziehau 		/* Sent */
3408*15516c77SSepherosa Ziehau 		drbr_advance(ifp, txr->hn_mbuf_br);
3409*15516c77SSepherosa Ziehau 	}
3410*15516c77SSepherosa Ziehau 	return 0;
3411*15516c77SSepherosa Ziehau }
3412*15516c77SSepherosa Ziehau 
3413*15516c77SSepherosa Ziehau static int
3414*15516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m)
3415*15516c77SSepherosa Ziehau {
3416*15516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
3417*15516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
3418*15516c77SSepherosa Ziehau 	int error, idx = 0;
3419*15516c77SSepherosa Ziehau 
3420*15516c77SSepherosa Ziehau 	/*
3421*15516c77SSepherosa Ziehau 	 * Select the TX ring based on flowid
3422*15516c77SSepherosa Ziehau 	 */
3423*15516c77SSepherosa Ziehau 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
3424*15516c77SSepherosa Ziehau 		idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse;
3425*15516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[idx];
3426*15516c77SSepherosa Ziehau 
3427*15516c77SSepherosa Ziehau 	error = drbr_enqueue(ifp, txr->hn_mbuf_br, m);
3428*15516c77SSepherosa Ziehau 	if (error) {
3429*15516c77SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
3430*15516c77SSepherosa Ziehau 		return error;
3431*15516c77SSepherosa Ziehau 	}
3432*15516c77SSepherosa Ziehau 
3433*15516c77SSepherosa Ziehau 	if (txr->hn_oactive)
3434*15516c77SSepherosa Ziehau 		return 0;
3435*15516c77SSepherosa Ziehau 
3436*15516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
3437*15516c77SSepherosa Ziehau 		goto do_sched;
3438*15516c77SSepherosa Ziehau 
3439*15516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
3440*15516c77SSepherosa Ziehau 		int sched;
3441*15516c77SSepherosa Ziehau 
3442*15516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
3443*15516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
3444*15516c77SSepherosa Ziehau 		if (!sched)
3445*15516c77SSepherosa Ziehau 			return 0;
3446*15516c77SSepherosa Ziehau 	}
3447*15516c77SSepherosa Ziehau do_sched:
3448*15516c77SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
3449*15516c77SSepherosa Ziehau 	return 0;
3450*15516c77SSepherosa Ziehau }
3451*15516c77SSepherosa Ziehau 
3452*15516c77SSepherosa Ziehau static void
3453*15516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr)
3454*15516c77SSepherosa Ziehau {
3455*15516c77SSepherosa Ziehau 	struct mbuf *m;
3456*15516c77SSepherosa Ziehau 
3457*15516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
3458*15516c77SSepherosa Ziehau 	while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL)
3459*15516c77SSepherosa Ziehau 		m_freem(m);
3460*15516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
3461*15516c77SSepherosa Ziehau }
3462*15516c77SSepherosa Ziehau 
3463*15516c77SSepherosa Ziehau static void
3464*15516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp)
3465*15516c77SSepherosa Ziehau {
3466*15516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
3467*15516c77SSepherosa Ziehau 	int i;
3468*15516c77SSepherosa Ziehau 
3469*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
3470*15516c77SSepherosa Ziehau 		hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
3471*15516c77SSepherosa Ziehau 	if_qflush(ifp);
3472*15516c77SSepherosa Ziehau }
3473*15516c77SSepherosa Ziehau 
3474*15516c77SSepherosa Ziehau static void
3475*15516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr)
3476*15516c77SSepherosa Ziehau {
3477*15516c77SSepherosa Ziehau 
3478*15516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
3479*15516c77SSepherosa Ziehau 		goto do_sched;
3480*15516c77SSepherosa Ziehau 
3481*15516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
3482*15516c77SSepherosa Ziehau 		int sched;
3483*15516c77SSepherosa Ziehau 
3484*15516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
3485*15516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
3486*15516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
3487*15516c77SSepherosa Ziehau 		if (sched) {
3488*15516c77SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
3489*15516c77SSepherosa Ziehau 			    &txr->hn_tx_task);
3490*15516c77SSepherosa Ziehau 		}
3491*15516c77SSepherosa Ziehau 	} else {
3492*15516c77SSepherosa Ziehau do_sched:
3493*15516c77SSepherosa Ziehau 		/*
3494*15516c77SSepherosa Ziehau 		 * Release the oactive earlier, with the hope, that
3495*15516c77SSepherosa Ziehau 		 * others could catch up.  The task will clear the
3496*15516c77SSepherosa Ziehau 		 * oactive again with the hn_tx_lock to avoid possible
3497*15516c77SSepherosa Ziehau 		 * races.
3498*15516c77SSepherosa Ziehau 		 */
3499*15516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
3500*15516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
3501*15516c77SSepherosa Ziehau 	}
3502*15516c77SSepherosa Ziehau }
3503*15516c77SSepherosa Ziehau 
3504*15516c77SSepherosa Ziehau static void
3505*15516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused)
3506*15516c77SSepherosa Ziehau {
3507*15516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
3508*15516c77SSepherosa Ziehau 
3509*15516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
3510*15516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
3511*15516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
3512*15516c77SSepherosa Ziehau }
3513*15516c77SSepherosa Ziehau 
3514*15516c77SSepherosa Ziehau static void
3515*15516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused)
3516*15516c77SSepherosa Ziehau {
3517*15516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
3518*15516c77SSepherosa Ziehau 
3519*15516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
3520*15516c77SSepherosa Ziehau 	txr->hn_oactive = 0;
3521*15516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
3522*15516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
3523*15516c77SSepherosa Ziehau }
3524*15516c77SSepherosa Ziehau 
3525*15516c77SSepherosa Ziehau static int
3526*15516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan)
3527*15516c77SSepherosa Ziehau {
3528*15516c77SSepherosa Ziehau 	struct vmbus_chan_br cbr;
3529*15516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
3530*15516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = NULL;
3531*15516c77SSepherosa Ziehau 	int idx, error;
3532*15516c77SSepherosa Ziehau 
3533*15516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
3534*15516c77SSepherosa Ziehau 
3535*15516c77SSepherosa Ziehau 	/*
3536*15516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
3537*15516c77SSepherosa Ziehau 	 */
3538*15516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
3539*15516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
3540*15516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
3541*15516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
3542*15516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0,
3543*15516c77SSepherosa Ziehau 	    ("RX ring %d already attached", idx));
3544*15516c77SSepherosa Ziehau 	rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED;
3545*15516c77SSepherosa Ziehau 
3546*15516c77SSepherosa Ziehau 	if (bootverbose) {
3547*15516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n",
3548*15516c77SSepherosa Ziehau 		    idx, vmbus_chan_id(chan));
3549*15516c77SSepherosa Ziehau 	}
3550*15516c77SSepherosa Ziehau 
3551*15516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
3552*15516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[idx];
3553*15516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0,
3554*15516c77SSepherosa Ziehau 		    ("TX ring %d already attached", idx));
3555*15516c77SSepherosa Ziehau 		txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED;
3556*15516c77SSepherosa Ziehau 
3557*15516c77SSepherosa Ziehau 		txr->hn_chan = chan;
3558*15516c77SSepherosa Ziehau 		if (bootverbose) {
3559*15516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n",
3560*15516c77SSepherosa Ziehau 			    idx, vmbus_chan_id(chan));
3561*15516c77SSepherosa Ziehau 		}
3562*15516c77SSepherosa Ziehau 	}
3563*15516c77SSepherosa Ziehau 
3564*15516c77SSepherosa Ziehau 	/* Bind this channel to a proper CPU. */
3565*15516c77SSepherosa Ziehau 	vmbus_chan_cpu_set(chan, (sc->hn_cpu + idx) % mp_ncpus);
3566*15516c77SSepherosa Ziehau 
3567*15516c77SSepherosa Ziehau 	/*
3568*15516c77SSepherosa Ziehau 	 * Open this channel
3569*15516c77SSepherosa Ziehau 	 */
3570*15516c77SSepherosa Ziehau 	cbr.cbr = rxr->hn_br;
3571*15516c77SSepherosa Ziehau 	cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr;
3572*15516c77SSepherosa Ziehau 	cbr.cbr_txsz = HN_TXBR_SIZE;
3573*15516c77SSepherosa Ziehau 	cbr.cbr_rxsz = HN_RXBR_SIZE;
3574*15516c77SSepherosa Ziehau 	error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr);
3575*15516c77SSepherosa Ziehau 	if (error) {
3576*15516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "open chan%u failed: %d\n",
3577*15516c77SSepherosa Ziehau 		    vmbus_chan_id(chan), error);
3578*15516c77SSepherosa Ziehau 		rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
3579*15516c77SSepherosa Ziehau 		if (txr != NULL)
3580*15516c77SSepherosa Ziehau 			txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
3581*15516c77SSepherosa Ziehau 	}
3582*15516c77SSepherosa Ziehau 	return (error);
3583*15516c77SSepherosa Ziehau }
3584*15516c77SSepherosa Ziehau 
3585*15516c77SSepherosa Ziehau static void
3586*15516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan)
3587*15516c77SSepherosa Ziehau {
3588*15516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
3589*15516c77SSepherosa Ziehau 	int idx;
3590*15516c77SSepherosa Ziehau 
3591*15516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
3592*15516c77SSepherosa Ziehau 
3593*15516c77SSepherosa Ziehau 	/*
3594*15516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
3595*15516c77SSepherosa Ziehau 	 */
3596*15516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
3597*15516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
3598*15516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
3599*15516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
3600*15516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED),
3601*15516c77SSepherosa Ziehau 	    ("RX ring %d is not attached", idx));
3602*15516c77SSepherosa Ziehau 	rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
3603*15516c77SSepherosa Ziehau 
3604*15516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
3605*15516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[idx];
3606*15516c77SSepherosa Ziehau 
3607*15516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED),
3608*15516c77SSepherosa Ziehau 		    ("TX ring %d is not attached attached", idx));
3609*15516c77SSepherosa Ziehau 		txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
3610*15516c77SSepherosa Ziehau 	}
3611*15516c77SSepherosa Ziehau 
3612*15516c77SSepherosa Ziehau 	/*
3613*15516c77SSepherosa Ziehau 	 * Close this channel.
3614*15516c77SSepherosa Ziehau 	 *
3615*15516c77SSepherosa Ziehau 	 * NOTE:
3616*15516c77SSepherosa Ziehau 	 * Channel closing does _not_ destroy the target channel.
3617*15516c77SSepherosa Ziehau 	 */
3618*15516c77SSepherosa Ziehau 	vmbus_chan_close(chan);
3619*15516c77SSepherosa Ziehau }
3620*15516c77SSepherosa Ziehau 
3621*15516c77SSepherosa Ziehau static int
3622*15516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc)
3623*15516c77SSepherosa Ziehau {
3624*15516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
3625*15516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
3626*15516c77SSepherosa Ziehau 	int i, error = 0;
3627*15516c77SSepherosa Ziehau 
3628*15516c77SSepherosa Ziehau 	if (subchan_cnt == 0)
3629*15516c77SSepherosa Ziehau 		return (0);
3630*15516c77SSepherosa Ziehau 
3631*15516c77SSepherosa Ziehau 	/* Attach the sub-channels. */
3632*15516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
3633*15516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i) {
3634*15516c77SSepherosa Ziehau 		error = hn_chan_attach(sc, subchans[i]);
3635*15516c77SSepherosa Ziehau 		if (error)
3636*15516c77SSepherosa Ziehau 			break;
3637*15516c77SSepherosa Ziehau 	}
3638*15516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
3639*15516c77SSepherosa Ziehau 
3640*15516c77SSepherosa Ziehau 	if (error) {
3641*15516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error);
3642*15516c77SSepherosa Ziehau 	} else {
3643*15516c77SSepherosa Ziehau 		if (bootverbose) {
3644*15516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "%d sub-channels attached\n",
3645*15516c77SSepherosa Ziehau 			    subchan_cnt);
3646*15516c77SSepherosa Ziehau 		}
3647*15516c77SSepherosa Ziehau 	}
3648*15516c77SSepherosa Ziehau 	return (error);
3649*15516c77SSepherosa Ziehau }
3650*15516c77SSepherosa Ziehau 
3651*15516c77SSepherosa Ziehau static void
3652*15516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc)
3653*15516c77SSepherosa Ziehau {
3654*15516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
3655*15516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
3656*15516c77SSepherosa Ziehau 	int i;
3657*15516c77SSepherosa Ziehau 
3658*15516c77SSepherosa Ziehau 	if (subchan_cnt == 0)
3659*15516c77SSepherosa Ziehau 		goto back;
3660*15516c77SSepherosa Ziehau 
3661*15516c77SSepherosa Ziehau 	/* Detach the sub-channels. */
3662*15516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
3663*15516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i)
3664*15516c77SSepherosa Ziehau 		hn_chan_detach(sc, subchans[i]);
3665*15516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
3666*15516c77SSepherosa Ziehau 
3667*15516c77SSepherosa Ziehau back:
3668*15516c77SSepherosa Ziehau 	/*
3669*15516c77SSepherosa Ziehau 	 * Detach the primary channel, _after_ all sub-channels
3670*15516c77SSepherosa Ziehau 	 * are detached.
3671*15516c77SSepherosa Ziehau 	 */
3672*15516c77SSepherosa Ziehau 	hn_chan_detach(sc, sc->hn_prichan);
3673*15516c77SSepherosa Ziehau 
3674*15516c77SSepherosa Ziehau 	/* Wait for sub-channels to be destroyed, if any. */
3675*15516c77SSepherosa Ziehau 	vmbus_subchan_drain(sc->hn_prichan);
3676*15516c77SSepherosa Ziehau 
3677*15516c77SSepherosa Ziehau #ifdef INVARIANTS
3678*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
3679*15516c77SSepherosa Ziehau 		KASSERT((sc->hn_rx_ring[i].hn_rx_flags &
3680*15516c77SSepherosa Ziehau 		    HN_RX_FLAG_ATTACHED) == 0,
3681*15516c77SSepherosa Ziehau 		    ("%dth RX ring is still attached", i));
3682*15516c77SSepherosa Ziehau 	}
3683*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
3684*15516c77SSepherosa Ziehau 		KASSERT((sc->hn_tx_ring[i].hn_tx_flags &
3685*15516c77SSepherosa Ziehau 		    HN_TX_FLAG_ATTACHED) == 0,
3686*15516c77SSepherosa Ziehau 		    ("%dth TX ring is still attached", i));
3687*15516c77SSepherosa Ziehau 	}
3688*15516c77SSepherosa Ziehau #endif
3689*15516c77SSepherosa Ziehau }
3690*15516c77SSepherosa Ziehau 
3691*15516c77SSepherosa Ziehau static int
3692*15516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch)
3693*15516c77SSepherosa Ziehau {
3694*15516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
3695*15516c77SSepherosa Ziehau 	int nchan, rxr_cnt, error;
3696*15516c77SSepherosa Ziehau 
3697*15516c77SSepherosa Ziehau 	nchan = *nsubch + 1;
3698*15516c77SSepherosa Ziehau 	if (nchan == 1) {
3699*15516c77SSepherosa Ziehau 		/*
3700*15516c77SSepherosa Ziehau 		 * Multiple RX/TX rings are not requested.
3701*15516c77SSepherosa Ziehau 		 */
3702*15516c77SSepherosa Ziehau 		*nsubch = 0;
3703*15516c77SSepherosa Ziehau 		return (0);
3704*15516c77SSepherosa Ziehau 	}
3705*15516c77SSepherosa Ziehau 
3706*15516c77SSepherosa Ziehau 	/*
3707*15516c77SSepherosa Ziehau 	 * Query RSS capabilities, e.g. # of RX rings, and # of indirect
3708*15516c77SSepherosa Ziehau 	 * table entries.
3709*15516c77SSepherosa Ziehau 	 */
3710*15516c77SSepherosa Ziehau 	error = hn_rndis_query_rsscaps(sc, &rxr_cnt);
3711*15516c77SSepherosa Ziehau 	if (error) {
3712*15516c77SSepherosa Ziehau 		/* No RSS; this is benign. */
3713*15516c77SSepherosa Ziehau 		*nsubch = 0;
3714*15516c77SSepherosa Ziehau 		return (0);
3715*15516c77SSepherosa Ziehau 	}
3716*15516c77SSepherosa Ziehau 	if (bootverbose) {
3717*15516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
3718*15516c77SSepherosa Ziehau 		    rxr_cnt, nchan);
3719*15516c77SSepherosa Ziehau 	}
3720*15516c77SSepherosa Ziehau 
3721*15516c77SSepherosa Ziehau 	if (nchan > rxr_cnt)
3722*15516c77SSepherosa Ziehau 		nchan = rxr_cnt;
3723*15516c77SSepherosa Ziehau 	if (nchan == 1) {
3724*15516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n");
3725*15516c77SSepherosa Ziehau 		*nsubch = 0;
3726*15516c77SSepherosa Ziehau 		return (0);
3727*15516c77SSepherosa Ziehau 	}
3728*15516c77SSepherosa Ziehau 
3729*15516c77SSepherosa Ziehau 	/*
3730*15516c77SSepherosa Ziehau 	 * Allocate sub-channels from NVS.
3731*15516c77SSepherosa Ziehau 	 */
3732*15516c77SSepherosa Ziehau 	*nsubch = nchan - 1;
3733*15516c77SSepherosa Ziehau 	error = hn_nvs_alloc_subchans(sc, nsubch);
3734*15516c77SSepherosa Ziehau 	if (error || *nsubch == 0) {
3735*15516c77SSepherosa Ziehau 		/* Failed to allocate sub-channels. */
3736*15516c77SSepherosa Ziehau 		*nsubch = 0;
3737*15516c77SSepherosa Ziehau 		return (0);
3738*15516c77SSepherosa Ziehau 	}
3739*15516c77SSepherosa Ziehau 
3740*15516c77SSepherosa Ziehau 	/*
3741*15516c77SSepherosa Ziehau 	 * Wait for all sub-channels to become ready before moving on.
3742*15516c77SSepherosa Ziehau 	 */
3743*15516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch);
3744*15516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, *nsubch);
3745*15516c77SSepherosa Ziehau 	return (0);
3746*15516c77SSepherosa Ziehau }
3747*15516c77SSepherosa Ziehau 
3748*15516c77SSepherosa Ziehau static int
3749*15516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu)
3750*15516c77SSepherosa Ziehau {
3751*15516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
3752*15516c77SSepherosa Ziehau 	int error, nsubch, nchan, i;
3753*15516c77SSepherosa Ziehau 	uint32_t old_caps;
3754*15516c77SSepherosa Ziehau 
3755*15516c77SSepherosa Ziehau 	KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0,
3756*15516c77SSepherosa Ziehau 	    ("synthetic parts were attached"));
3757*15516c77SSepherosa Ziehau 
3758*15516c77SSepherosa Ziehau 	/* Save capabilities for later verification. */
3759*15516c77SSepherosa Ziehau 	old_caps = sc->hn_caps;
3760*15516c77SSepherosa Ziehau 	sc->hn_caps = 0;
3761*15516c77SSepherosa Ziehau 
3762*15516c77SSepherosa Ziehau 	/* Clear RSS stuffs. */
3763*15516c77SSepherosa Ziehau 	sc->hn_rss_ind_size = 0;
3764*15516c77SSepherosa Ziehau 	sc->hn_rss_hash = 0;
3765*15516c77SSepherosa Ziehau 
3766*15516c77SSepherosa Ziehau 	/*
3767*15516c77SSepherosa Ziehau 	 * Attach the primary channel _before_ attaching NVS and RNDIS.
3768*15516c77SSepherosa Ziehau 	 */
3769*15516c77SSepherosa Ziehau 	error = hn_chan_attach(sc, sc->hn_prichan);
3770*15516c77SSepherosa Ziehau 	if (error)
3771*15516c77SSepherosa Ziehau 		return (error);
3772*15516c77SSepherosa Ziehau 
3773*15516c77SSepherosa Ziehau 	/*
3774*15516c77SSepherosa Ziehau 	 * Attach NVS.
3775*15516c77SSepherosa Ziehau 	 */
3776*15516c77SSepherosa Ziehau 	error = hn_nvs_attach(sc, mtu);
3777*15516c77SSepherosa Ziehau 	if (error)
3778*15516c77SSepherosa Ziehau 		return (error);
3779*15516c77SSepherosa Ziehau 
3780*15516c77SSepherosa Ziehau 	/*
3781*15516c77SSepherosa Ziehau 	 * Attach RNDIS _after_ NVS is attached.
3782*15516c77SSepherosa Ziehau 	 */
3783*15516c77SSepherosa Ziehau 	error = hn_rndis_attach(sc, mtu);
3784*15516c77SSepherosa Ziehau 	if (error)
3785*15516c77SSepherosa Ziehau 		return (error);
3786*15516c77SSepherosa Ziehau 
3787*15516c77SSepherosa Ziehau 	/*
3788*15516c77SSepherosa Ziehau 	 * Make sure capabilities are not changed.
3789*15516c77SSepherosa Ziehau 	 */
3790*15516c77SSepherosa Ziehau 	if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) {
3791*15516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n",
3792*15516c77SSepherosa Ziehau 		    old_caps, sc->hn_caps);
3793*15516c77SSepherosa Ziehau 		/* Restore old capabilities and abort. */
3794*15516c77SSepherosa Ziehau 		sc->hn_caps = old_caps;
3795*15516c77SSepherosa Ziehau 		return ENXIO;
3796*15516c77SSepherosa Ziehau 	}
3797*15516c77SSepherosa Ziehau 
3798*15516c77SSepherosa Ziehau 	/*
3799*15516c77SSepherosa Ziehau 	 * Allocate sub-channels for multi-TX/RX rings.
3800*15516c77SSepherosa Ziehau 	 *
3801*15516c77SSepherosa Ziehau 	 * NOTE:
3802*15516c77SSepherosa Ziehau 	 * The # of RX rings that can be used is equivalent to the # of
3803*15516c77SSepherosa Ziehau 	 * channels to be requested.
3804*15516c77SSepherosa Ziehau 	 */
3805*15516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_cnt - 1;
3806*15516c77SSepherosa Ziehau 	error = hn_synth_alloc_subchans(sc, &nsubch);
3807*15516c77SSepherosa Ziehau 	if (error)
3808*15516c77SSepherosa Ziehau 		return (error);
3809*15516c77SSepherosa Ziehau 
3810*15516c77SSepherosa Ziehau 	nchan = nsubch + 1;
3811*15516c77SSepherosa Ziehau 	if (nchan == 1) {
3812*15516c77SSepherosa Ziehau 		/* Only the primary channel can be used; done */
3813*15516c77SSepherosa Ziehau 		goto back;
3814*15516c77SSepherosa Ziehau 	}
3815*15516c77SSepherosa Ziehau 
3816*15516c77SSepherosa Ziehau 	/*
3817*15516c77SSepherosa Ziehau 	 * Configure RSS key and indirect table _after_ all sub-channels
3818*15516c77SSepherosa Ziehau 	 * are allocated.
3819*15516c77SSepherosa Ziehau 	 */
3820*15516c77SSepherosa Ziehau 
3821*15516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) {
3822*15516c77SSepherosa Ziehau 		/*
3823*15516c77SSepherosa Ziehau 		 * RSS key is not set yet; set it to the default RSS key.
3824*15516c77SSepherosa Ziehau 		 */
3825*15516c77SSepherosa Ziehau 		if (bootverbose)
3826*15516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS key\n");
3827*15516c77SSepherosa Ziehau 		memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key));
3828*15516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
3829*15516c77SSepherosa Ziehau 	}
3830*15516c77SSepherosa Ziehau 
3831*15516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) {
3832*15516c77SSepherosa Ziehau 		/*
3833*15516c77SSepherosa Ziehau 		 * RSS indirect table is not set yet; set it up in round-
3834*15516c77SSepherosa Ziehau 		 * robin fashion.
3835*15516c77SSepherosa Ziehau 		 */
3836*15516c77SSepherosa Ziehau 		if (bootverbose) {
3837*15516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS indirect "
3838*15516c77SSepherosa Ziehau 			    "table\n");
3839*15516c77SSepherosa Ziehau 		}
3840*15516c77SSepherosa Ziehau 		for (i = 0; i < NDIS_HASH_INDCNT; ++i)
3841*15516c77SSepherosa Ziehau 			rss->rss_ind[i] = i % nchan;
3842*15516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSIND;
3843*15516c77SSepherosa Ziehau 	} else {
3844*15516c77SSepherosa Ziehau 		/*
3845*15516c77SSepherosa Ziehau 		 * # of usable channels may be changed, so we have to
3846*15516c77SSepherosa Ziehau 		 * make sure that all entries in RSS indirect table
3847*15516c77SSepherosa Ziehau 		 * are valid.
3848*15516c77SSepherosa Ziehau 		 */
3849*15516c77SSepherosa Ziehau 		hn_rss_ind_fixup(sc, nchan);
3850*15516c77SSepherosa Ziehau 	}
3851*15516c77SSepherosa Ziehau 
3852*15516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
3853*15516c77SSepherosa Ziehau 	if (error) {
3854*15516c77SSepherosa Ziehau 		/*
3855*15516c77SSepherosa Ziehau 		 * Failed to configure RSS key or indirect table; only
3856*15516c77SSepherosa Ziehau 		 * the primary channel can be used.
3857*15516c77SSepherosa Ziehau 		 */
3858*15516c77SSepherosa Ziehau 		nchan = 1;
3859*15516c77SSepherosa Ziehau 	}
3860*15516c77SSepherosa Ziehau back:
3861*15516c77SSepherosa Ziehau 	/*
3862*15516c77SSepherosa Ziehau 	 * Set the # of TX/RX rings that could be used according to
3863*15516c77SSepherosa Ziehau 	 * the # of channels that NVS offered.
3864*15516c77SSepherosa Ziehau 	 */
3865*15516c77SSepherosa Ziehau 	hn_set_ring_inuse(sc, nchan);
3866*15516c77SSepherosa Ziehau 
3867*15516c77SSepherosa Ziehau 	/*
3868*15516c77SSepherosa Ziehau 	 * Attach the sub-channels, if any.
3869*15516c77SSepherosa Ziehau 	 */
3870*15516c77SSepherosa Ziehau 	error = hn_attach_subchans(sc);
3871*15516c77SSepherosa Ziehau 	if (error)
3872*15516c77SSepherosa Ziehau 		return (error);
3873*15516c77SSepherosa Ziehau 
3874*15516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED;
3875*15516c77SSepherosa Ziehau 	return (0);
3876*15516c77SSepherosa Ziehau }
3877*15516c77SSepherosa Ziehau 
3878*15516c77SSepherosa Ziehau /*
3879*15516c77SSepherosa Ziehau  * NOTE:
3880*15516c77SSepherosa Ziehau  * The interface must have been suspended though hn_suspend(), before
3881*15516c77SSepherosa Ziehau  * this function get called.
3882*15516c77SSepherosa Ziehau  */
3883*15516c77SSepherosa Ziehau static void
3884*15516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc)
3885*15516c77SSepherosa Ziehau {
3886*15516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
3887*15516c77SSepherosa Ziehau 
3888*15516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
3889*15516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
3890*15516c77SSepherosa Ziehau 
3891*15516c77SSepherosa Ziehau 	/* Detach the RNDIS first. */
3892*15516c77SSepherosa Ziehau 	hn_rndis_detach(sc);
3893*15516c77SSepherosa Ziehau 
3894*15516c77SSepherosa Ziehau 	/* Detach NVS. */
3895*15516c77SSepherosa Ziehau 	hn_nvs_detach(sc);
3896*15516c77SSepherosa Ziehau 
3897*15516c77SSepherosa Ziehau 	/* Detach all of the channels. */
3898*15516c77SSepherosa Ziehau 	hn_detach_allchans(sc);
3899*15516c77SSepherosa Ziehau 
3900*15516c77SSepherosa Ziehau 	sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED;
3901*15516c77SSepherosa Ziehau }
3902*15516c77SSepherosa Ziehau 
3903*15516c77SSepherosa Ziehau static void
3904*15516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt)
3905*15516c77SSepherosa Ziehau {
3906*15516c77SSepherosa Ziehau 	KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt,
3907*15516c77SSepherosa Ziehau 	    ("invalid ring count %d", ring_cnt));
3908*15516c77SSepherosa Ziehau 
3909*15516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt > ring_cnt)
3910*15516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = ring_cnt;
3911*15516c77SSepherosa Ziehau 	else
3912*15516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
3913*15516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = ring_cnt;
3914*15516c77SSepherosa Ziehau 
3915*15516c77SSepherosa Ziehau 	if (bootverbose) {
3916*15516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n",
3917*15516c77SSepherosa Ziehau 		    sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
3918*15516c77SSepherosa Ziehau 	}
3919*15516c77SSepherosa Ziehau }
3920*15516c77SSepherosa Ziehau 
3921*15516c77SSepherosa Ziehau static void
3922*15516c77SSepherosa Ziehau hn_chan_drain(struct vmbus_channel *chan)
3923*15516c77SSepherosa Ziehau {
3924*15516c77SSepherosa Ziehau 
3925*15516c77SSepherosa Ziehau 	while (!vmbus_chan_rx_empty(chan) || !vmbus_chan_tx_empty(chan))
3926*15516c77SSepherosa Ziehau 		pause("waitch", 1);
3927*15516c77SSepherosa Ziehau 	vmbus_chan_intr_drain(chan);
3928*15516c77SSepherosa Ziehau }
3929*15516c77SSepherosa Ziehau 
3930*15516c77SSepherosa Ziehau static void
3931*15516c77SSepherosa Ziehau hn_suspend_data(struct hn_softc *sc)
3932*15516c77SSepherosa Ziehau {
3933*15516c77SSepherosa Ziehau 	struct vmbus_channel **subch = NULL;
3934*15516c77SSepherosa Ziehau 	int i, nsubch;
3935*15516c77SSepherosa Ziehau 
3936*15516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
3937*15516c77SSepherosa Ziehau 
3938*15516c77SSepherosa Ziehau 	/*
3939*15516c77SSepherosa Ziehau 	 * Suspend TX.
3940*15516c77SSepherosa Ziehau 	 */
3941*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
3942*15516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
3943*15516c77SSepherosa Ziehau 
3944*15516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
3945*15516c77SSepherosa Ziehau 		txr->hn_suspended = 1;
3946*15516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
3947*15516c77SSepherosa Ziehau 		/* No one is able send more packets now. */
3948*15516c77SSepherosa Ziehau 
3949*15516c77SSepherosa Ziehau 		/* Wait for all pending sends to finish. */
3950*15516c77SSepherosa Ziehau 		while (hn_tx_ring_pending(txr))
3951*15516c77SSepherosa Ziehau 			pause("hnwtx", 1 /* 1 tick */);
3952*15516c77SSepherosa Ziehau 
3953*15516c77SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task);
3954*15516c77SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task);
3955*15516c77SSepherosa Ziehau 	}
3956*15516c77SSepherosa Ziehau 
3957*15516c77SSepherosa Ziehau 	/*
3958*15516c77SSepherosa Ziehau 	 * Disable RX by clearing RX filter.
3959*15516c77SSepherosa Ziehau 	 */
3960*15516c77SSepherosa Ziehau 	sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE;
3961*15516c77SSepherosa Ziehau 	hn_rndis_set_rxfilter(sc, sc->hn_rx_filter);
3962*15516c77SSepherosa Ziehau 
3963*15516c77SSepherosa Ziehau 	/*
3964*15516c77SSepherosa Ziehau 	 * Give RNDIS enough time to flush all pending data packets.
3965*15516c77SSepherosa Ziehau 	 */
3966*15516c77SSepherosa Ziehau 	pause("waitrx", (200 * hz) / 1000);
3967*15516c77SSepherosa Ziehau 
3968*15516c77SSepherosa Ziehau 	/*
3969*15516c77SSepherosa Ziehau 	 * Drain RX/TX bufrings and interrupts.
3970*15516c77SSepherosa Ziehau 	 */
3971*15516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_inuse - 1;
3972*15516c77SSepherosa Ziehau 	if (nsubch > 0)
3973*15516c77SSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
3974*15516c77SSepherosa Ziehau 
3975*15516c77SSepherosa Ziehau 	if (subch != NULL) {
3976*15516c77SSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
3977*15516c77SSepherosa Ziehau 			hn_chan_drain(subch[i]);
3978*15516c77SSepherosa Ziehau 	}
3979*15516c77SSepherosa Ziehau 	hn_chan_drain(sc->hn_prichan);
3980*15516c77SSepherosa Ziehau 
3981*15516c77SSepherosa Ziehau 	if (subch != NULL)
3982*15516c77SSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
3983*15516c77SSepherosa Ziehau }
3984*15516c77SSepherosa Ziehau 
3985*15516c77SSepherosa Ziehau static void
3986*15516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused)
3987*15516c77SSepherosa Ziehau {
3988*15516c77SSepherosa Ziehau 
3989*15516c77SSepherosa Ziehau 	((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL;
3990*15516c77SSepherosa Ziehau }
3991*15516c77SSepherosa Ziehau 
3992*15516c77SSepherosa Ziehau static void
3993*15516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc)
3994*15516c77SSepherosa Ziehau {
3995*15516c77SSepherosa Ziehau 	struct task task;
3996*15516c77SSepherosa Ziehau 
3997*15516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
3998*15516c77SSepherosa Ziehau 
3999*15516c77SSepherosa Ziehau 	/*
4000*15516c77SSepherosa Ziehau 	 * Make sure that hn_mgmt_taskq0 can nolonger be accessed
4001*15516c77SSepherosa Ziehau 	 * through hn_mgmt_taskq.
4002*15516c77SSepherosa Ziehau 	 */
4003*15516c77SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc);
4004*15516c77SSepherosa Ziehau 	vmbus_chan_run_task(sc->hn_prichan, &task);
4005*15516c77SSepherosa Ziehau 
4006*15516c77SSepherosa Ziehau 	/*
4007*15516c77SSepherosa Ziehau 	 * Make sure that all pending management tasks are completed.
4008*15516c77SSepherosa Ziehau 	 */
4009*15516c77SSepherosa Ziehau 	taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init);
4010*15516c77SSepherosa Ziehau 	taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status);
4011*15516c77SSepherosa Ziehau 	taskqueue_drain_all(sc->hn_mgmt_taskq0);
4012*15516c77SSepherosa Ziehau }
4013*15516c77SSepherosa Ziehau 
4014*15516c77SSepherosa Ziehau static void
4015*15516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc)
4016*15516c77SSepherosa Ziehau {
4017*15516c77SSepherosa Ziehau 
4018*15516c77SSepherosa Ziehau 	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
4019*15516c77SSepherosa Ziehau 		hn_suspend_data(sc);
4020*15516c77SSepherosa Ziehau 	hn_suspend_mgmt(sc);
4021*15516c77SSepherosa Ziehau }
4022*15516c77SSepherosa Ziehau 
4023*15516c77SSepherosa Ziehau static void
4024*15516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt)
4025*15516c77SSepherosa Ziehau {
4026*15516c77SSepherosa Ziehau 	int i;
4027*15516c77SSepherosa Ziehau 
4028*15516c77SSepherosa Ziehau 	KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt,
4029*15516c77SSepherosa Ziehau 	    ("invalid TX ring count %d", tx_ring_cnt));
4030*15516c77SSepherosa Ziehau 
4031*15516c77SSepherosa Ziehau 	for (i = 0; i < tx_ring_cnt; ++i) {
4032*15516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
4033*15516c77SSepherosa Ziehau 
4034*15516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
4035*15516c77SSepherosa Ziehau 		txr->hn_suspended = 0;
4036*15516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
4037*15516c77SSepherosa Ziehau 	}
4038*15516c77SSepherosa Ziehau }
4039*15516c77SSepherosa Ziehau 
4040*15516c77SSepherosa Ziehau static void
4041*15516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc)
4042*15516c77SSepherosa Ziehau {
4043*15516c77SSepherosa Ziehau 	int i;
4044*15516c77SSepherosa Ziehau 
4045*15516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
4046*15516c77SSepherosa Ziehau 
4047*15516c77SSepherosa Ziehau 	/*
4048*15516c77SSepherosa Ziehau 	 * Re-enable RX.
4049*15516c77SSepherosa Ziehau 	 */
4050*15516c77SSepherosa Ziehau 	hn_set_rxfilter(sc);
4051*15516c77SSepherosa Ziehau 
4052*15516c77SSepherosa Ziehau 	/*
4053*15516c77SSepherosa Ziehau 	 * Make sure to clear suspend status on "all" TX rings,
4054*15516c77SSepherosa Ziehau 	 * since hn_tx_ring_inuse can be changed after
4055*15516c77SSepherosa Ziehau 	 * hn_suspend_data().
4056*15516c77SSepherosa Ziehau 	 */
4057*15516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_cnt);
4058*15516c77SSepherosa Ziehau 
4059*15516c77SSepherosa Ziehau 	if (!hn_use_if_start) {
4060*15516c77SSepherosa Ziehau 		/*
4061*15516c77SSepherosa Ziehau 		 * Flush unused drbrs, since hn_tx_ring_inuse may be
4062*15516c77SSepherosa Ziehau 		 * reduced.
4063*15516c77SSepherosa Ziehau 		 */
4064*15516c77SSepherosa Ziehau 		for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i)
4065*15516c77SSepherosa Ziehau 			hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
4066*15516c77SSepherosa Ziehau 	}
4067*15516c77SSepherosa Ziehau 
4068*15516c77SSepherosa Ziehau 	/*
4069*15516c77SSepherosa Ziehau 	 * Kick start TX.
4070*15516c77SSepherosa Ziehau 	 */
4071*15516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
4072*15516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
4073*15516c77SSepherosa Ziehau 
4074*15516c77SSepherosa Ziehau 		/*
4075*15516c77SSepherosa Ziehau 		 * Use txeof task, so that any pending oactive can be
4076*15516c77SSepherosa Ziehau 		 * cleared properly.
4077*15516c77SSepherosa Ziehau 		 */
4078*15516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
4079*15516c77SSepherosa Ziehau 	}
4080*15516c77SSepherosa Ziehau }
4081*15516c77SSepherosa Ziehau 
4082*15516c77SSepherosa Ziehau static void
4083*15516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc)
4084*15516c77SSepherosa Ziehau {
4085*15516c77SSepherosa Ziehau 
4086*15516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
4087*15516c77SSepherosa Ziehau 
4088*15516c77SSepherosa Ziehau 	/*
4089*15516c77SSepherosa Ziehau 	 * Kick off network change detection, if it was pending.
4090*15516c77SSepherosa Ziehau 	 * If no network change was pending, start link status
4091*15516c77SSepherosa Ziehau 	 * checks, which is more lightweight than network change
4092*15516c77SSepherosa Ziehau 	 * detection.
4093*15516c77SSepherosa Ziehau 	 */
4094*15516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
4095*15516c77SSepherosa Ziehau 		hn_change_network(sc);
4096*15516c77SSepherosa Ziehau 	else
4097*15516c77SSepherosa Ziehau 		hn_update_link_status(sc);
4098*15516c77SSepherosa Ziehau }
4099*15516c77SSepherosa Ziehau 
4100*15516c77SSepherosa Ziehau static void
4101*15516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc)
4102*15516c77SSepherosa Ziehau {
4103*15516c77SSepherosa Ziehau 
4104*15516c77SSepherosa Ziehau 	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
4105*15516c77SSepherosa Ziehau 		hn_resume_data(sc);
4106*15516c77SSepherosa Ziehau 	hn_resume_mgmt(sc);
4107*15516c77SSepherosa Ziehau }
4108*15516c77SSepherosa Ziehau 
4109*15516c77SSepherosa Ziehau static void
4110*15516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen)
4111*15516c77SSepherosa Ziehau {
4112*15516c77SSepherosa Ziehau 	const struct rndis_status_msg *msg;
4113*15516c77SSepherosa Ziehau 	int ofs;
4114*15516c77SSepherosa Ziehau 
4115*15516c77SSepherosa Ziehau 	if (dlen < sizeof(*msg)) {
4116*15516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid RNDIS status\n");
4117*15516c77SSepherosa Ziehau 		return;
4118*15516c77SSepherosa Ziehau 	}
4119*15516c77SSepherosa Ziehau 	msg = data;
4120*15516c77SSepherosa Ziehau 
4121*15516c77SSepherosa Ziehau 	switch (msg->rm_status) {
4122*15516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_CONNECT:
4123*15516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_DISCONNECT:
4124*15516c77SSepherosa Ziehau 		hn_update_link_status(sc);
4125*15516c77SSepherosa Ziehau 		break;
4126*15516c77SSepherosa Ziehau 
4127*15516c77SSepherosa Ziehau 	case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
4128*15516c77SSepherosa Ziehau 		/* Not really useful; ignore. */
4129*15516c77SSepherosa Ziehau 		break;
4130*15516c77SSepherosa Ziehau 
4131*15516c77SSepherosa Ziehau 	case RNDIS_STATUS_NETWORK_CHANGE:
4132*15516c77SSepherosa Ziehau 		ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
4133*15516c77SSepherosa Ziehau 		if (dlen < ofs + msg->rm_stbuflen ||
4134*15516c77SSepherosa Ziehau 		    msg->rm_stbuflen < sizeof(uint32_t)) {
4135*15516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed\n");
4136*15516c77SSepherosa Ziehau 		} else {
4137*15516c77SSepherosa Ziehau 			uint32_t change;
4138*15516c77SSepherosa Ziehau 
4139*15516c77SSepherosa Ziehau 			memcpy(&change, ((const uint8_t *)msg) + ofs,
4140*15516c77SSepherosa Ziehau 			    sizeof(change));
4141*15516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed, change %u\n",
4142*15516c77SSepherosa Ziehau 			    change);
4143*15516c77SSepherosa Ziehau 		}
4144*15516c77SSepherosa Ziehau 		hn_change_network(sc);
4145*15516c77SSepherosa Ziehau 		break;
4146*15516c77SSepherosa Ziehau 
4147*15516c77SSepherosa Ziehau 	default:
4148*15516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
4149*15516c77SSepherosa Ziehau 		    msg->rm_status);
4150*15516c77SSepherosa Ziehau 		break;
4151*15516c77SSepherosa Ziehau 	}
4152*15516c77SSepherosa Ziehau }
4153*15516c77SSepherosa Ziehau 
4154*15516c77SSepherosa Ziehau static int
4155*15516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info)
4156*15516c77SSepherosa Ziehau {
4157*15516c77SSepherosa Ziehau 	const struct rndis_pktinfo *pi = info_data;
4158*15516c77SSepherosa Ziehau 	uint32_t mask = 0;
4159*15516c77SSepherosa Ziehau 
4160*15516c77SSepherosa Ziehau 	while (info_dlen != 0) {
4161*15516c77SSepherosa Ziehau 		const void *data;
4162*15516c77SSepherosa Ziehau 		uint32_t dlen;
4163*15516c77SSepherosa Ziehau 
4164*15516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < sizeof(*pi)))
4165*15516c77SSepherosa Ziehau 			return (EINVAL);
4166*15516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < pi->rm_size))
4167*15516c77SSepherosa Ziehau 			return (EINVAL);
4168*15516c77SSepherosa Ziehau 		info_dlen -= pi->rm_size;
4169*15516c77SSepherosa Ziehau 
4170*15516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
4171*15516c77SSepherosa Ziehau 			return (EINVAL);
4172*15516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
4173*15516c77SSepherosa Ziehau 			return (EINVAL);
4174*15516c77SSepherosa Ziehau 		dlen = pi->rm_size - pi->rm_pktinfooffset;
4175*15516c77SSepherosa Ziehau 		data = pi->rm_data;
4176*15516c77SSepherosa Ziehau 
4177*15516c77SSepherosa Ziehau 		switch (pi->rm_type) {
4178*15516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_VLAN:
4179*15516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
4180*15516c77SSepherosa Ziehau 				return (EINVAL);
4181*15516c77SSepherosa Ziehau 			info->vlan_info = *((const uint32_t *)data);
4182*15516c77SSepherosa Ziehau 			mask |= HN_RXINFO_VLAN;
4183*15516c77SSepherosa Ziehau 			break;
4184*15516c77SSepherosa Ziehau 
4185*15516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_CSUM:
4186*15516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
4187*15516c77SSepherosa Ziehau 				return (EINVAL);
4188*15516c77SSepherosa Ziehau 			info->csum_info = *((const uint32_t *)data);
4189*15516c77SSepherosa Ziehau 			mask |= HN_RXINFO_CSUM;
4190*15516c77SSepherosa Ziehau 			break;
4191*15516c77SSepherosa Ziehau 
4192*15516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHVAL:
4193*15516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
4194*15516c77SSepherosa Ziehau 				return (EINVAL);
4195*15516c77SSepherosa Ziehau 			info->hash_value = *((const uint32_t *)data);
4196*15516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHVAL;
4197*15516c77SSepherosa Ziehau 			break;
4198*15516c77SSepherosa Ziehau 
4199*15516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHINF:
4200*15516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
4201*15516c77SSepherosa Ziehau 				return (EINVAL);
4202*15516c77SSepherosa Ziehau 			info->hash_info = *((const uint32_t *)data);
4203*15516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHINF;
4204*15516c77SSepherosa Ziehau 			break;
4205*15516c77SSepherosa Ziehau 
4206*15516c77SSepherosa Ziehau 		default:
4207*15516c77SSepherosa Ziehau 			goto next;
4208*15516c77SSepherosa Ziehau 		}
4209*15516c77SSepherosa Ziehau 
4210*15516c77SSepherosa Ziehau 		if (mask == HN_RXINFO_ALL) {
4211*15516c77SSepherosa Ziehau 			/* All found; done */
4212*15516c77SSepherosa Ziehau 			break;
4213*15516c77SSepherosa Ziehau 		}
4214*15516c77SSepherosa Ziehau next:
4215*15516c77SSepherosa Ziehau 		pi = (const struct rndis_pktinfo *)
4216*15516c77SSepherosa Ziehau 		    ((const uint8_t *)pi + pi->rm_size);
4217*15516c77SSepherosa Ziehau 	}
4218*15516c77SSepherosa Ziehau 
4219*15516c77SSepherosa Ziehau 	/*
4220*15516c77SSepherosa Ziehau 	 * Final fixup.
4221*15516c77SSepherosa Ziehau 	 * - If there is no hash value, invalidate the hash info.
4222*15516c77SSepherosa Ziehau 	 */
4223*15516c77SSepherosa Ziehau 	if ((mask & HN_RXINFO_HASHVAL) == 0)
4224*15516c77SSepherosa Ziehau 		info->hash_info = HN_NDIS_HASH_INFO_INVALID;
4225*15516c77SSepherosa Ziehau 	return (0);
4226*15516c77SSepherosa Ziehau }
4227*15516c77SSepherosa Ziehau 
4228*15516c77SSepherosa Ziehau static __inline bool
4229*15516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
4230*15516c77SSepherosa Ziehau {
4231*15516c77SSepherosa Ziehau 
4232*15516c77SSepherosa Ziehau 	if (off < check_off) {
4233*15516c77SSepherosa Ziehau 		if (__predict_true(off + len <= check_off))
4234*15516c77SSepherosa Ziehau 			return (false);
4235*15516c77SSepherosa Ziehau 	} else if (off > check_off) {
4236*15516c77SSepherosa Ziehau 		if (__predict_true(check_off + check_len <= off))
4237*15516c77SSepherosa Ziehau 			return (false);
4238*15516c77SSepherosa Ziehau 	}
4239*15516c77SSepherosa Ziehau 	return (true);
4240*15516c77SSepherosa Ziehau }
4241*15516c77SSepherosa Ziehau 
4242*15516c77SSepherosa Ziehau static void
4243*15516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen)
4244*15516c77SSepherosa Ziehau {
4245*15516c77SSepherosa Ziehau 	const struct rndis_packet_msg *pkt;
4246*15516c77SSepherosa Ziehau 	struct hn_rxinfo info;
4247*15516c77SSepherosa Ziehau 	int data_off, pktinfo_off, data_len, pktinfo_len;
4248*15516c77SSepherosa Ziehau 
4249*15516c77SSepherosa Ziehau 	/*
4250*15516c77SSepherosa Ziehau 	 * Check length.
4251*15516c77SSepherosa Ziehau 	 */
4252*15516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*pkt))) {
4253*15516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
4254*15516c77SSepherosa Ziehau 		return;
4255*15516c77SSepherosa Ziehau 	}
4256*15516c77SSepherosa Ziehau 	pkt = data;
4257*15516c77SSepherosa Ziehau 
4258*15516c77SSepherosa Ziehau 	if (__predict_false(dlen < pkt->rm_len)) {
4259*15516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
4260*15516c77SSepherosa Ziehau 		    "dlen %d, msglen %u\n", dlen, pkt->rm_len);
4261*15516c77SSepherosa Ziehau 		return;
4262*15516c77SSepherosa Ziehau 	}
4263*15516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_len <
4264*15516c77SSepherosa Ziehau 	    pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
4265*15516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
4266*15516c77SSepherosa Ziehau 		    "msglen %u, data %u, oob %u, pktinfo %u\n",
4267*15516c77SSepherosa Ziehau 		    pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
4268*15516c77SSepherosa Ziehau 		    pkt->rm_pktinfolen);
4269*15516c77SSepherosa Ziehau 		return;
4270*15516c77SSepherosa Ziehau 	}
4271*15516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_datalen == 0)) {
4272*15516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
4273*15516c77SSepherosa Ziehau 		return;
4274*15516c77SSepherosa Ziehau 	}
4275*15516c77SSepherosa Ziehau 
4276*15516c77SSepherosa Ziehau 	/*
4277*15516c77SSepherosa Ziehau 	 * Check offests.
4278*15516c77SSepherosa Ziehau 	 */
4279*15516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs)			\
4280*15516c77SSepherosa Ziehau 	((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN ||	\
4281*15516c77SSepherosa Ziehau 	 ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
4282*15516c77SSepherosa Ziehau 
4283*15516c77SSepherosa Ziehau 	/* XXX Hyper-V does not meet data offset alignment requirement */
4284*15516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
4285*15516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
4286*15516c77SSepherosa Ziehau 		    "data offset %u\n", pkt->rm_dataoffset);
4287*15516c77SSepherosa Ziehau 		return;
4288*15516c77SSepherosa Ziehau 	}
4289*15516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdataoffset > 0 &&
4290*15516c77SSepherosa Ziehau 	    IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
4291*15516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
4292*15516c77SSepherosa Ziehau 		    "oob offset %u\n", pkt->rm_oobdataoffset);
4293*15516c77SSepherosa Ziehau 		return;
4294*15516c77SSepherosa Ziehau 	}
4295*15516c77SSepherosa Ziehau 	if (__predict_true(pkt->rm_pktinfooffset > 0) &&
4296*15516c77SSepherosa Ziehau 	    __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
4297*15516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
4298*15516c77SSepherosa Ziehau 		    "pktinfo offset %u\n", pkt->rm_pktinfooffset);
4299*15516c77SSepherosa Ziehau 		return;
4300*15516c77SSepherosa Ziehau 	}
4301*15516c77SSepherosa Ziehau 
4302*15516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID
4303*15516c77SSepherosa Ziehau 
4304*15516c77SSepherosa Ziehau 	data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
4305*15516c77SSepherosa Ziehau 	data_len = pkt->rm_datalen;
4306*15516c77SSepherosa Ziehau 	pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
4307*15516c77SSepherosa Ziehau 	pktinfo_len = pkt->rm_pktinfolen;
4308*15516c77SSepherosa Ziehau 
4309*15516c77SSepherosa Ziehau 	/*
4310*15516c77SSepherosa Ziehau 	 * Check OOB coverage.
4311*15516c77SSepherosa Ziehau 	 */
4312*15516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdatalen != 0)) {
4313*15516c77SSepherosa Ziehau 		int oob_off, oob_len;
4314*15516c77SSepherosa Ziehau 
4315*15516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "got oobdata\n");
4316*15516c77SSepherosa Ziehau 		oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
4317*15516c77SSepherosa Ziehau 		oob_len = pkt->rm_oobdatalen;
4318*15516c77SSepherosa Ziehau 
4319*15516c77SSepherosa Ziehau 		if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
4320*15516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
4321*15516c77SSepherosa Ziehau 			    "oob overflow, msglen %u, oob abs %d len %d\n",
4322*15516c77SSepherosa Ziehau 			    pkt->rm_len, oob_off, oob_len);
4323*15516c77SSepherosa Ziehau 			return;
4324*15516c77SSepherosa Ziehau 		}
4325*15516c77SSepherosa Ziehau 
4326*15516c77SSepherosa Ziehau 		/*
4327*15516c77SSepherosa Ziehau 		 * Check against data.
4328*15516c77SSepherosa Ziehau 		 */
4329*15516c77SSepherosa Ziehau 		if (hn_rndis_check_overlap(oob_off, oob_len,
4330*15516c77SSepherosa Ziehau 		    data_off, data_len)) {
4331*15516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
4332*15516c77SSepherosa Ziehau 			    "oob overlaps data, oob abs %d len %d, "
4333*15516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
4334*15516c77SSepherosa Ziehau 			    oob_off, oob_len, data_off, data_len);
4335*15516c77SSepherosa Ziehau 			return;
4336*15516c77SSepherosa Ziehau 		}
4337*15516c77SSepherosa Ziehau 
4338*15516c77SSepherosa Ziehau 		/*
4339*15516c77SSepherosa Ziehau 		 * Check against pktinfo.
4340*15516c77SSepherosa Ziehau 		 */
4341*15516c77SSepherosa Ziehau 		if (pktinfo_len != 0 &&
4342*15516c77SSepherosa Ziehau 		    hn_rndis_check_overlap(oob_off, oob_len,
4343*15516c77SSepherosa Ziehau 		    pktinfo_off, pktinfo_len)) {
4344*15516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
4345*15516c77SSepherosa Ziehau 			    "oob overlaps pktinfo, oob abs %d len %d, "
4346*15516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
4347*15516c77SSepherosa Ziehau 			    oob_off, oob_len, pktinfo_off, pktinfo_len);
4348*15516c77SSepherosa Ziehau 			return;
4349*15516c77SSepherosa Ziehau 		}
4350*15516c77SSepherosa Ziehau 	}
4351*15516c77SSepherosa Ziehau 
4352*15516c77SSepherosa Ziehau 	/*
4353*15516c77SSepherosa Ziehau 	 * Check per-packet-info coverage and find useful per-packet-info.
4354*15516c77SSepherosa Ziehau 	 */
4355*15516c77SSepherosa Ziehau 	info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
4356*15516c77SSepherosa Ziehau 	info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
4357*15516c77SSepherosa Ziehau 	info.hash_info = HN_NDIS_HASH_INFO_INVALID;
4358*15516c77SSepherosa Ziehau 	if (__predict_true(pktinfo_len != 0)) {
4359*15516c77SSepherosa Ziehau 		bool overlap;
4360*15516c77SSepherosa Ziehau 		int error;
4361*15516c77SSepherosa Ziehau 
4362*15516c77SSepherosa Ziehau 		if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
4363*15516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
4364*15516c77SSepherosa Ziehau 			    "pktinfo overflow, msglen %u, "
4365*15516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
4366*15516c77SSepherosa Ziehau 			    pkt->rm_len, pktinfo_off, pktinfo_len);
4367*15516c77SSepherosa Ziehau 			return;
4368*15516c77SSepherosa Ziehau 		}
4369*15516c77SSepherosa Ziehau 
4370*15516c77SSepherosa Ziehau 		/*
4371*15516c77SSepherosa Ziehau 		 * Check packet info coverage.
4372*15516c77SSepherosa Ziehau 		 */
4373*15516c77SSepherosa Ziehau 		overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
4374*15516c77SSepherosa Ziehau 		    data_off, data_len);
4375*15516c77SSepherosa Ziehau 		if (__predict_false(overlap)) {
4376*15516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
4377*15516c77SSepherosa Ziehau 			    "pktinfo overlap data, pktinfo abs %d len %d, "
4378*15516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
4379*15516c77SSepherosa Ziehau 			    pktinfo_off, pktinfo_len, data_off, data_len);
4380*15516c77SSepherosa Ziehau 			return;
4381*15516c77SSepherosa Ziehau 		}
4382*15516c77SSepherosa Ziehau 
4383*15516c77SSepherosa Ziehau 		/*
4384*15516c77SSepherosa Ziehau 		 * Find useful per-packet-info.
4385*15516c77SSepherosa Ziehau 		 */
4386*15516c77SSepherosa Ziehau 		error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
4387*15516c77SSepherosa Ziehau 		    pktinfo_len, &info);
4388*15516c77SSepherosa Ziehau 		if (__predict_false(error)) {
4389*15516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
4390*15516c77SSepherosa Ziehau 			    "pktinfo\n");
4391*15516c77SSepherosa Ziehau 			return;
4392*15516c77SSepherosa Ziehau 		}
4393*15516c77SSepherosa Ziehau 	}
4394*15516c77SSepherosa Ziehau 
4395*15516c77SSepherosa Ziehau 	if (__predict_false(data_off + data_len > pkt->rm_len)) {
4396*15516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
4397*15516c77SSepherosa Ziehau 		    "data overflow, msglen %u, data abs %d len %d\n",
4398*15516c77SSepherosa Ziehau 		    pkt->rm_len, data_off, data_len);
4399*15516c77SSepherosa Ziehau 		return;
4400*15516c77SSepherosa Ziehau 	}
4401*15516c77SSepherosa Ziehau 	hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
4402*15516c77SSepherosa Ziehau }
4403*15516c77SSepherosa Ziehau 
4404*15516c77SSepherosa Ziehau static __inline void
4405*15516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen)
4406*15516c77SSepherosa Ziehau {
4407*15516c77SSepherosa Ziehau 	const struct rndis_msghdr *hdr;
4408*15516c77SSepherosa Ziehau 
4409*15516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*hdr))) {
4410*15516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
4411*15516c77SSepherosa Ziehau 		return;
4412*15516c77SSepherosa Ziehau 	}
4413*15516c77SSepherosa Ziehau 	hdr = data;
4414*15516c77SSepherosa Ziehau 
4415*15516c77SSepherosa Ziehau 	if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) {
4416*15516c77SSepherosa Ziehau 		/* Hot data path. */
4417*15516c77SSepherosa Ziehau 		hn_rndis_rx_data(rxr, data, dlen);
4418*15516c77SSepherosa Ziehau 		/* Done! */
4419*15516c77SSepherosa Ziehau 		return;
4420*15516c77SSepherosa Ziehau 	}
4421*15516c77SSepherosa Ziehau 
4422*15516c77SSepherosa Ziehau 	if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG)
4423*15516c77SSepherosa Ziehau 		hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen);
4424*15516c77SSepherosa Ziehau 	else
4425*15516c77SSepherosa Ziehau 		hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen);
4426*15516c77SSepherosa Ziehau }
4427*15516c77SSepherosa Ziehau 
4428*15516c77SSepherosa Ziehau static void
4429*15516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
4430*15516c77SSepherosa Ziehau {
4431*15516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *hdr;
4432*15516c77SSepherosa Ziehau 
4433*15516c77SSepherosa Ziehau 	if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) {
4434*15516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid nvs notify\n");
4435*15516c77SSepherosa Ziehau 		return;
4436*15516c77SSepherosa Ziehau 	}
4437*15516c77SSepherosa Ziehau 	hdr = VMBUS_CHANPKT_CONST_DATA(pkt);
4438*15516c77SSepherosa Ziehau 
4439*15516c77SSepherosa Ziehau 	if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) {
4440*15516c77SSepherosa Ziehau 		/* Useless; ignore */
4441*15516c77SSepherosa Ziehau 		return;
4442*15516c77SSepherosa Ziehau 	}
4443*15516c77SSepherosa Ziehau 	if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type);
4444*15516c77SSepherosa Ziehau }
4445*15516c77SSepherosa Ziehau 
4446*15516c77SSepherosa Ziehau static void
4447*15516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan,
4448*15516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkt)
4449*15516c77SSepherosa Ziehau {
4450*15516c77SSepherosa Ziehau 	struct hn_nvs_sendctx *sndc;
4451*15516c77SSepherosa Ziehau 
4452*15516c77SSepherosa Ziehau 	sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid;
4453*15516c77SSepherosa Ziehau 	sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt),
4454*15516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_DATALEN(pkt));
4455*15516c77SSepherosa Ziehau 	/*
4456*15516c77SSepherosa Ziehau 	 * NOTE:
4457*15516c77SSepherosa Ziehau 	 * 'sndc' CAN NOT be accessed anymore, since it can be freed by
4458*15516c77SSepherosa Ziehau 	 * its callback.
4459*15516c77SSepherosa Ziehau 	 */
4460*15516c77SSepherosa Ziehau }
4461*15516c77SSepherosa Ziehau 
4462*15516c77SSepherosa Ziehau static void
4463*15516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
4464*15516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkthdr)
4465*15516c77SSepherosa Ziehau {
4466*15516c77SSepherosa Ziehau 	const struct vmbus_chanpkt_rxbuf *pkt;
4467*15516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *nvs_hdr;
4468*15516c77SSepherosa Ziehau 	int count, i, hlen;
4469*15516c77SSepherosa Ziehau 
4470*15516c77SSepherosa Ziehau 	if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) {
4471*15516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n");
4472*15516c77SSepherosa Ziehau 		return;
4473*15516c77SSepherosa Ziehau 	}
4474*15516c77SSepherosa Ziehau 	nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr);
4475*15516c77SSepherosa Ziehau 
4476*15516c77SSepherosa Ziehau 	/* Make sure that this is a RNDIS message. */
4477*15516c77SSepherosa Ziehau 	if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) {
4478*15516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n",
4479*15516c77SSepherosa Ziehau 		    nvs_hdr->nvs_type);
4480*15516c77SSepherosa Ziehau 		return;
4481*15516c77SSepherosa Ziehau 	}
4482*15516c77SSepherosa Ziehau 
4483*15516c77SSepherosa Ziehau 	hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen);
4484*15516c77SSepherosa Ziehau 	if (__predict_false(hlen < sizeof(*pkt))) {
4485*15516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n");
4486*15516c77SSepherosa Ziehau 		return;
4487*15516c77SSepherosa Ziehau 	}
4488*15516c77SSepherosa Ziehau 	pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
4489*15516c77SSepherosa Ziehau 
4490*15516c77SSepherosa Ziehau 	if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) {
4491*15516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n",
4492*15516c77SSepherosa Ziehau 		    pkt->cp_rxbuf_id);
4493*15516c77SSepherosa Ziehau 		return;
4494*15516c77SSepherosa Ziehau 	}
4495*15516c77SSepherosa Ziehau 
4496*15516c77SSepherosa Ziehau 	count = pkt->cp_rxbuf_cnt;
4497*15516c77SSepherosa Ziehau 	if (__predict_false(hlen <
4498*15516c77SSepherosa Ziehau 	    __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) {
4499*15516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count);
4500*15516c77SSepherosa Ziehau 		return;
4501*15516c77SSepherosa Ziehau 	}
4502*15516c77SSepherosa Ziehau 
4503*15516c77SSepherosa Ziehau 	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
4504*15516c77SSepherosa Ziehau 	for (i = 0; i < count; ++i) {
4505*15516c77SSepherosa Ziehau 		int ofs, len;
4506*15516c77SSepherosa Ziehau 
4507*15516c77SSepherosa Ziehau 		ofs = pkt->cp_rxbuf[i].rb_ofs;
4508*15516c77SSepherosa Ziehau 		len = pkt->cp_rxbuf[i].rb_len;
4509*15516c77SSepherosa Ziehau 		if (__predict_false(ofs + len > HN_RXBUF_SIZE)) {
4510*15516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, "
4511*15516c77SSepherosa Ziehau 			    "ofs %d, len %d\n", i, ofs, len);
4512*15516c77SSepherosa Ziehau 			continue;
4513*15516c77SSepherosa Ziehau 		}
4514*15516c77SSepherosa Ziehau 		hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len);
4515*15516c77SSepherosa Ziehau 	}
4516*15516c77SSepherosa Ziehau 
4517*15516c77SSepherosa Ziehau 	/*
4518*15516c77SSepherosa Ziehau 	 * Ack the consumed RXBUF associated w/ this channel packet,
4519*15516c77SSepherosa Ziehau 	 * so that this RXBUF can be recycled by the hypervisor.
4520*15516c77SSepherosa Ziehau 	 */
4521*15516c77SSepherosa Ziehau 	hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid);
4522*15516c77SSepherosa Ziehau }
4523*15516c77SSepherosa Ziehau 
4524*15516c77SSepherosa Ziehau static void
4525*15516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
4526*15516c77SSepherosa Ziehau     uint64_t tid)
4527*15516c77SSepherosa Ziehau {
4528*15516c77SSepherosa Ziehau 	struct hn_nvs_rndis_ack ack;
4529*15516c77SSepherosa Ziehau 	int retries, error;
4530*15516c77SSepherosa Ziehau 
4531*15516c77SSepherosa Ziehau 	ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK;
4532*15516c77SSepherosa Ziehau 	ack.nvs_status = HN_NVS_STATUS_OK;
4533*15516c77SSepherosa Ziehau 
4534*15516c77SSepherosa Ziehau 	retries = 0;
4535*15516c77SSepherosa Ziehau again:
4536*15516c77SSepherosa Ziehau 	error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP,
4537*15516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid);
4538*15516c77SSepherosa Ziehau 	if (__predict_false(error == EAGAIN)) {
4539*15516c77SSepherosa Ziehau 		/*
4540*15516c77SSepherosa Ziehau 		 * NOTE:
4541*15516c77SSepherosa Ziehau 		 * This should _not_ happen in real world, since the
4542*15516c77SSepherosa Ziehau 		 * consumption of the TX bufring from the TX path is
4543*15516c77SSepherosa Ziehau 		 * controlled.
4544*15516c77SSepherosa Ziehau 		 */
4545*15516c77SSepherosa Ziehau 		if (rxr->hn_ack_failed == 0)
4546*15516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "RXBUF ack retry\n");
4547*15516c77SSepherosa Ziehau 		rxr->hn_ack_failed++;
4548*15516c77SSepherosa Ziehau 		retries++;
4549*15516c77SSepherosa Ziehau 		if (retries < 10) {
4550*15516c77SSepherosa Ziehau 			DELAY(100);
4551*15516c77SSepherosa Ziehau 			goto again;
4552*15516c77SSepherosa Ziehau 		}
4553*15516c77SSepherosa Ziehau 		/* RXBUF leaks! */
4554*15516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "RXBUF ack failed\n");
4555*15516c77SSepherosa Ziehau 	}
4556*15516c77SSepherosa Ziehau }
4557*15516c77SSepherosa Ziehau 
4558*15516c77SSepherosa Ziehau static void
4559*15516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr)
4560*15516c77SSepherosa Ziehau {
4561*15516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr = xrxr;
4562*15516c77SSepherosa Ziehau 	struct hn_softc *sc = rxr->hn_ifp->if_softc;
4563*15516c77SSepherosa Ziehau 
4564*15516c77SSepherosa Ziehau 	for (;;) {
4565*15516c77SSepherosa Ziehau 		struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf;
4566*15516c77SSepherosa Ziehau 		int error, pktlen;
4567*15516c77SSepherosa Ziehau 
4568*15516c77SSepherosa Ziehau 		pktlen = rxr->hn_pktbuf_len;
4569*15516c77SSepherosa Ziehau 		error = vmbus_chan_recv_pkt(chan, pkt, &pktlen);
4570*15516c77SSepherosa Ziehau 		if (__predict_false(error == ENOBUFS)) {
4571*15516c77SSepherosa Ziehau 			void *nbuf;
4572*15516c77SSepherosa Ziehau 			int nlen;
4573*15516c77SSepherosa Ziehau 
4574*15516c77SSepherosa Ziehau 			/*
4575*15516c77SSepherosa Ziehau 			 * Expand channel packet buffer.
4576*15516c77SSepherosa Ziehau 			 *
4577*15516c77SSepherosa Ziehau 			 * XXX
4578*15516c77SSepherosa Ziehau 			 * Use M_WAITOK here, since allocation failure
4579*15516c77SSepherosa Ziehau 			 * is fatal.
4580*15516c77SSepherosa Ziehau 			 */
4581*15516c77SSepherosa Ziehau 			nlen = rxr->hn_pktbuf_len * 2;
4582*15516c77SSepherosa Ziehau 			while (nlen < pktlen)
4583*15516c77SSepherosa Ziehau 				nlen *= 2;
4584*15516c77SSepherosa Ziehau 			nbuf = malloc(nlen, M_DEVBUF, M_WAITOK);
4585*15516c77SSepherosa Ziehau 
4586*15516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n",
4587*15516c77SSepherosa Ziehau 			    rxr->hn_pktbuf_len, nlen);
4588*15516c77SSepherosa Ziehau 
4589*15516c77SSepherosa Ziehau 			free(rxr->hn_pktbuf, M_DEVBUF);
4590*15516c77SSepherosa Ziehau 			rxr->hn_pktbuf = nbuf;
4591*15516c77SSepherosa Ziehau 			rxr->hn_pktbuf_len = nlen;
4592*15516c77SSepherosa Ziehau 			/* Retry! */
4593*15516c77SSepherosa Ziehau 			continue;
4594*15516c77SSepherosa Ziehau 		} else if (__predict_false(error == EAGAIN)) {
4595*15516c77SSepherosa Ziehau 			/* No more channel packets; done! */
4596*15516c77SSepherosa Ziehau 			break;
4597*15516c77SSepherosa Ziehau 		}
4598*15516c77SSepherosa Ziehau 		KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error));
4599*15516c77SSepherosa Ziehau 
4600*15516c77SSepherosa Ziehau 		switch (pkt->cph_type) {
4601*15516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_COMP:
4602*15516c77SSepherosa Ziehau 			hn_nvs_handle_comp(sc, chan, pkt);
4603*15516c77SSepherosa Ziehau 			break;
4604*15516c77SSepherosa Ziehau 
4605*15516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_RXBUF:
4606*15516c77SSepherosa Ziehau 			hn_nvs_handle_rxbuf(rxr, chan, pkt);
4607*15516c77SSepherosa Ziehau 			break;
4608*15516c77SSepherosa Ziehau 
4609*15516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_INBAND:
4610*15516c77SSepherosa Ziehau 			hn_nvs_handle_notify(sc, pkt);
4611*15516c77SSepherosa Ziehau 			break;
4612*15516c77SSepherosa Ziehau 
4613*15516c77SSepherosa Ziehau 		default:
4614*15516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "unknown chan pkt %u\n",
4615*15516c77SSepherosa Ziehau 			    pkt->cph_type);
4616*15516c77SSepherosa Ziehau 			break;
4617*15516c77SSepherosa Ziehau 		}
4618*15516c77SSepherosa Ziehau 	}
4619*15516c77SSepherosa Ziehau 	hn_chan_rollup(rxr, rxr->hn_txr);
4620*15516c77SSepherosa Ziehau }
4621*15516c77SSepherosa Ziehau 
4622*15516c77SSepherosa Ziehau static void
4623*15516c77SSepherosa Ziehau hn_tx_taskq_create(void *arg __unused)
4624*15516c77SSepherosa Ziehau {
4625*15516c77SSepherosa Ziehau 
4626*15516c77SSepherosa Ziehau 	if (vm_guest != VM_GUEST_HV)
4627*15516c77SSepherosa Ziehau 		return;
4628*15516c77SSepherosa Ziehau 
4629*15516c77SSepherosa Ziehau 	if (!hn_share_tx_taskq)
4630*15516c77SSepherosa Ziehau 		return;
4631*15516c77SSepherosa Ziehau 
4632*15516c77SSepherosa Ziehau 	hn_tx_taskq = taskqueue_create("hn_tx", M_WAITOK,
4633*15516c77SSepherosa Ziehau 	    taskqueue_thread_enqueue, &hn_tx_taskq);
4634*15516c77SSepherosa Ziehau 	if (hn_bind_tx_taskq >= 0) {
4635*15516c77SSepherosa Ziehau 		int cpu = hn_bind_tx_taskq;
4636*15516c77SSepherosa Ziehau 		cpuset_t cpu_set;
4637*15516c77SSepherosa Ziehau 
4638*15516c77SSepherosa Ziehau 		if (cpu > mp_ncpus - 1)
4639*15516c77SSepherosa Ziehau 			cpu = mp_ncpus - 1;
4640*15516c77SSepherosa Ziehau 		CPU_SETOF(cpu, &cpu_set);
4641*15516c77SSepherosa Ziehau 		taskqueue_start_threads_cpuset(&hn_tx_taskq, 1, PI_NET,
4642*15516c77SSepherosa Ziehau 		    &cpu_set, "hn tx");
4643*15516c77SSepherosa Ziehau 	} else {
4644*15516c77SSepherosa Ziehau 		taskqueue_start_threads(&hn_tx_taskq, 1, PI_NET, "hn tx");
4645*15516c77SSepherosa Ziehau 	}
4646*15516c77SSepherosa Ziehau }
4647*15516c77SSepherosa Ziehau SYSINIT(hn_txtq_create, SI_SUB_DRIVERS, SI_ORDER_SECOND,
4648*15516c77SSepherosa Ziehau     hn_tx_taskq_create, NULL);
4649*15516c77SSepherosa Ziehau 
4650*15516c77SSepherosa Ziehau static void
4651*15516c77SSepherosa Ziehau hn_tx_taskq_destroy(void *arg __unused)
4652*15516c77SSepherosa Ziehau {
4653*15516c77SSepherosa Ziehau 
4654*15516c77SSepherosa Ziehau 	if (hn_tx_taskq != NULL)
4655*15516c77SSepherosa Ziehau 		taskqueue_free(hn_tx_taskq);
4656*15516c77SSepherosa Ziehau }
4657*15516c77SSepherosa Ziehau SYSUNINIT(hn_txtq_destroy, SI_SUB_DRIVERS, SI_ORDER_SECOND,
4658*15516c77SSepherosa Ziehau     hn_tx_taskq_destroy, NULL);
4659