xref: /freebsd/sys/dev/hyperv/netvsc/if_hn.c (revision 80c3eb7bc64b745b2a0bda953e29a26e32dff9d7)
115516c77SSepherosa Ziehau /*-
215516c77SSepherosa Ziehau  * Copyright (c) 2010-2012 Citrix Inc.
393b4e111SSepherosa Ziehau  * Copyright (c) 2009-2012,2016-2017 Microsoft Corp.
415516c77SSepherosa Ziehau  * Copyright (c) 2012 NetApp Inc.
515516c77SSepherosa Ziehau  * All rights reserved.
615516c77SSepherosa Ziehau  *
715516c77SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
815516c77SSepherosa Ziehau  * modification, are permitted provided that the following conditions
915516c77SSepherosa Ziehau  * are met:
1015516c77SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
1115516c77SSepherosa Ziehau  *    notice unmodified, this list of conditions, and the following
1215516c77SSepherosa Ziehau  *    disclaimer.
1315516c77SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
1415516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
1515516c77SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
1615516c77SSepherosa Ziehau  *
1715516c77SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1815516c77SSepherosa Ziehau  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1915516c77SSepherosa Ziehau  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2015516c77SSepherosa Ziehau  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2115516c77SSepherosa Ziehau  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2215516c77SSepherosa Ziehau  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2315516c77SSepherosa Ziehau  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2415516c77SSepherosa Ziehau  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2515516c77SSepherosa Ziehau  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2615516c77SSepherosa Ziehau  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2715516c77SSepherosa Ziehau  */
2815516c77SSepherosa Ziehau 
2915516c77SSepherosa Ziehau /*-
3015516c77SSepherosa Ziehau  * Copyright (c) 2004-2006 Kip Macy
3115516c77SSepherosa Ziehau  * All rights reserved.
3215516c77SSepherosa Ziehau  *
3315516c77SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
3415516c77SSepherosa Ziehau  * modification, are permitted provided that the following conditions
3515516c77SSepherosa Ziehau  * are met:
3615516c77SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
3715516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer.
3815516c77SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
3915516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
4015516c77SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
4115516c77SSepherosa Ziehau  *
4215516c77SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
4315516c77SSepherosa Ziehau  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4415516c77SSepherosa Ziehau  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4515516c77SSepherosa Ziehau  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4615516c77SSepherosa Ziehau  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4715516c77SSepherosa Ziehau  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4815516c77SSepherosa Ziehau  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4915516c77SSepherosa Ziehau  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5015516c77SSepherosa Ziehau  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5115516c77SSepherosa Ziehau  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5215516c77SSepherosa Ziehau  * SUCH DAMAGE.
5315516c77SSepherosa Ziehau  */
5415516c77SSepherosa Ziehau 
5515516c77SSepherosa Ziehau #include <sys/cdefs.h>
5615516c77SSepherosa Ziehau __FBSDID("$FreeBSD$");
5715516c77SSepherosa Ziehau 
5834d68912SSepherosa Ziehau #include "opt_hn.h"
5915516c77SSepherosa Ziehau #include "opt_inet6.h"
6015516c77SSepherosa Ziehau #include "opt_inet.h"
6134d68912SSepherosa Ziehau #include "opt_rss.h"
6215516c77SSepherosa Ziehau 
6315516c77SSepherosa Ziehau #include <sys/param.h>
6435203574SSepherosa Ziehau #include <sys/systm.h>
6515516c77SSepherosa Ziehau #include <sys/bus.h>
662be266caSSepherosa Ziehau #include <sys/counter.h>
6715516c77SSepherosa Ziehau #include <sys/kernel.h>
6815516c77SSepherosa Ziehau #include <sys/limits.h>
6915516c77SSepherosa Ziehau #include <sys/malloc.h>
7015516c77SSepherosa Ziehau #include <sys/mbuf.h>
7115516c77SSepherosa Ziehau #include <sys/module.h>
7215516c77SSepherosa Ziehau #include <sys/queue.h>
7315516c77SSepherosa Ziehau #include <sys/lock.h>
74b3460f44SWei Hu #include <sys/proc.h>
75499c3e17SSepherosa Ziehau #include <sys/rmlock.h>
76499c3e17SSepherosa Ziehau #include <sys/sbuf.h>
77b3460f44SWei Hu #include <sys/sched.h>
7815516c77SSepherosa Ziehau #include <sys/smp.h>
7915516c77SSepherosa Ziehau #include <sys/socket.h>
8015516c77SSepherosa Ziehau #include <sys/sockio.h>
8115516c77SSepherosa Ziehau #include <sys/sx.h>
8215516c77SSepherosa Ziehau #include <sys/sysctl.h>
8315516c77SSepherosa Ziehau #include <sys/taskqueue.h>
8415516c77SSepherosa Ziehau #include <sys/buf_ring.h>
855bdfd3fdSDexuan Cui #include <sys/eventhandler.h>
8626d79d40SMichael Tuexen #include <sys/epoch.h>
8715516c77SSepherosa Ziehau 
8815516c77SSepherosa Ziehau #include <machine/atomic.h>
8915516c77SSepherosa Ziehau #include <machine/in_cksum.h>
9015516c77SSepherosa Ziehau 
9115516c77SSepherosa Ziehau #include <net/bpf.h>
9215516c77SSepherosa Ziehau #include <net/ethernet.h>
9315516c77SSepherosa Ziehau #include <net/if.h>
945bdfd3fdSDexuan Cui #include <net/if_dl.h>
9515516c77SSepherosa Ziehau #include <net/if_media.h>
9615516c77SSepherosa Ziehau #include <net/if_types.h>
9715516c77SSepherosa Ziehau #include <net/if_var.h>
9815516c77SSepherosa Ziehau #include <net/rndis.h>
9934d68912SSepherosa Ziehau #ifdef RSS
10034d68912SSepherosa Ziehau #include <net/rss_config.h>
10134d68912SSepherosa Ziehau #endif
10215516c77SSepherosa Ziehau 
10315516c77SSepherosa Ziehau #include <netinet/in_systm.h>
10415516c77SSepherosa Ziehau #include <netinet/in.h>
10515516c77SSepherosa Ziehau #include <netinet/ip.h>
10615516c77SSepherosa Ziehau #include <netinet/ip6.h>
10715516c77SSepherosa Ziehau #include <netinet/tcp.h>
10815516c77SSepherosa Ziehau #include <netinet/tcp_lro.h>
10915516c77SSepherosa Ziehau #include <netinet/udp.h>
11015516c77SSepherosa Ziehau 
11115516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h>
11215516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv_busdma.h>
11315516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus.h>
11415516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus_xact.h>
11515516c77SSepherosa Ziehau 
11615516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/ndis.h>
11715516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnreg.h>
11815516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnvar.h>
11915516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_nvs.h>
12015516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_rndis.h>
12115516c77SSepherosa Ziehau 
12215516c77SSepherosa Ziehau #include "vmbus_if.h"
12315516c77SSepherosa Ziehau 
12423bf9e15SSepherosa Ziehau #define HN_IFSTART_SUPPORT
12523bf9e15SSepherosa Ziehau 
12615516c77SSepherosa Ziehau #define HN_RING_CNT_DEF_MAX		8
12715516c77SSepherosa Ziehau 
128499c3e17SSepherosa Ziehau #define HN_VFMAP_SIZE_DEF		8
129499c3e17SSepherosa Ziehau 
1309c6cae24SSepherosa Ziehau #define HN_XPNT_VF_ATTWAIT_MIN		2	/* seconds */
1319c6cae24SSepherosa Ziehau 
13215516c77SSepherosa Ziehau /* YYY should get it from the underlying channel */
13315516c77SSepherosa Ziehau #define HN_TX_DESC_CNT			512
13415516c77SSepherosa Ziehau 
13515516c77SSepherosa Ziehau #define HN_RNDIS_PKT_LEN					\
13615516c77SSepherosa Ziehau 	(sizeof(struct rndis_packet_msg) +			\
13715516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) +	\
13815516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) +		\
13915516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) +		\
14015516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_TXCSUM_INFO_SIZE))
14115516c77SSepherosa Ziehau #define HN_RNDIS_PKT_BOUNDARY		PAGE_SIZE
14215516c77SSepherosa Ziehau #define HN_RNDIS_PKT_ALIGN		CACHE_LINE_SIZE
14315516c77SSepherosa Ziehau 
14415516c77SSepherosa Ziehau #define HN_TX_DATA_BOUNDARY		PAGE_SIZE
14515516c77SSepherosa Ziehau #define HN_TX_DATA_MAXSIZE		IP_MAXPACKET
14615516c77SSepherosa Ziehau #define HN_TX_DATA_SEGSIZE		PAGE_SIZE
14715516c77SSepherosa Ziehau /* -1 for RNDIS packet message */
14815516c77SSepherosa Ziehau #define HN_TX_DATA_SEGCNT_MAX		(HN_GPACNT_MAX - 1)
14915516c77SSepherosa Ziehau 
15015516c77SSepherosa Ziehau #define HN_DIRECT_TX_SIZE_DEF		128
15115516c77SSepherosa Ziehau 
15215516c77SSepherosa Ziehau #define HN_EARLY_TXEOF_THRESH		8
15315516c77SSepherosa Ziehau 
15415516c77SSepherosa Ziehau #define HN_PKTBUF_LEN_DEF		(16 * 1024)
15515516c77SSepherosa Ziehau 
15615516c77SSepherosa Ziehau #define HN_LROENT_CNT_DEF		128
15715516c77SSepherosa Ziehau 
15815516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MULTIRX_DEF	(12 * ETHERMTU)
15915516c77SSepherosa Ziehau #define HN_LRO_LENLIM_DEF		(25 * ETHERMTU)
16015516c77SSepherosa Ziehau /* YYY 2*MTU is a bit rough, but should be good enough. */
16115516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MIN(ifp)		(2 * (ifp)->if_mtu)
16215516c77SSepherosa Ziehau 
16315516c77SSepherosa Ziehau #define HN_LRO_ACKCNT_DEF		1
16415516c77SSepherosa Ziehau 
16515516c77SSepherosa Ziehau #define HN_LOCK_INIT(sc)		\
16615516c77SSepherosa Ziehau 	sx_init(&(sc)->hn_lock, device_get_nameunit((sc)->hn_dev))
16715516c77SSepherosa Ziehau #define HN_LOCK_DESTROY(sc)		sx_destroy(&(sc)->hn_lock)
16815516c77SSepherosa Ziehau #define HN_LOCK_ASSERT(sc)		sx_assert(&(sc)->hn_lock, SA_XLOCKED)
169fdc4f478SSepherosa Ziehau #define HN_LOCK(sc)					\
170fdc4f478SSepherosa Ziehau do {							\
171b3460f44SWei Hu 	while (sx_try_xlock(&(sc)->hn_lock) == 0) {	\
172b3460f44SWei Hu 		/* Relinquish cpu to avoid deadlock */	\
173b3460f44SWei Hu 		sched_relinquish(curthread);		\
174fdc4f478SSepherosa Ziehau 		DELAY(1000);				\
175b3460f44SWei Hu 	}						\
176fdc4f478SSepherosa Ziehau } while (0)
17715516c77SSepherosa Ziehau #define HN_UNLOCK(sc)			sx_xunlock(&(sc)->hn_lock)
17815516c77SSepherosa Ziehau 
17915516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK			(CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP)
18015516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK		(CSUM_IP6_TCP | CSUM_IP6_UDP)
18115516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc)		\
18215516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK)
18315516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc)	\
18415516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK)
18515516c77SSepherosa Ziehau 
186dc13fee6SSepherosa Ziehau #define HN_PKTSIZE_MIN(align)		\
187dc13fee6SSepherosa Ziehau 	roundup2(ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN + \
188dc13fee6SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN, (align))
189dc13fee6SSepherosa Ziehau #define HN_PKTSIZE(m, align)		\
190dc13fee6SSepherosa Ziehau 	roundup2((m)->m_pkthdr.len + HN_RNDIS_PKT_LEN, (align))
191dc13fee6SSepherosa Ziehau 
19234d68912SSepherosa Ziehau #ifdef RSS
19334d68912SSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx)	rss_getcpu((idx) % rss_getnumbuckets())
19434d68912SSepherosa Ziehau #else
1950e11868dSSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx)	(((sc)->hn_cpu + (idx)) % mp_ncpus)
19634d68912SSepherosa Ziehau #endif
1970e11868dSSepherosa Ziehau 
19815516c77SSepherosa Ziehau struct hn_txdesc {
19915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
20015516c77SSepherosa Ziehau 	SLIST_ENTRY(hn_txdesc)		link;
20115516c77SSepherosa Ziehau #endif
202dc13fee6SSepherosa Ziehau 	STAILQ_ENTRY(hn_txdesc)		agg_link;
203dc13fee6SSepherosa Ziehau 
204dc13fee6SSepherosa Ziehau 	/* Aggregated txdescs, in sending order. */
205dc13fee6SSepherosa Ziehau 	STAILQ_HEAD(, hn_txdesc)	agg_list;
206dc13fee6SSepherosa Ziehau 
207dc13fee6SSepherosa Ziehau 	/* The oldest packet, if transmission aggregation happens. */
20815516c77SSepherosa Ziehau 	struct mbuf			*m;
20915516c77SSepherosa Ziehau 	struct hn_tx_ring		*txr;
21015516c77SSepherosa Ziehau 	int				refs;
21115516c77SSepherosa Ziehau 	uint32_t			flags;	/* HN_TXD_FLAG_ */
21215516c77SSepherosa Ziehau 	struct hn_nvs_sendctx		send_ctx;
21315516c77SSepherosa Ziehau 	uint32_t			chim_index;
21415516c77SSepherosa Ziehau 	int				chim_size;
21515516c77SSepherosa Ziehau 
21615516c77SSepherosa Ziehau 	bus_dmamap_t			data_dmap;
21715516c77SSepherosa Ziehau 
21815516c77SSepherosa Ziehau 	bus_addr_t			rndis_pkt_paddr;
21915516c77SSepherosa Ziehau 	struct rndis_packet_msg		*rndis_pkt;
22015516c77SSepherosa Ziehau 	bus_dmamap_t			rndis_pkt_dmap;
22115516c77SSepherosa Ziehau };
22215516c77SSepherosa Ziehau 
22315516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST		0x0001
22415516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP		0x0002
225dc13fee6SSepherosa Ziehau #define HN_TXD_FLAG_ONAGG		0x0004
22615516c77SSepherosa Ziehau 
227a491581fSWei Hu #define	HN_NDIS_PKTINFO_SUBALLOC	0x01
228a491581fSWei Hu #define	HN_NDIS_PKTINFO_1ST_FRAG	0x02
229a491581fSWei Hu #define	HN_NDIS_PKTINFO_LAST_FRAG	0x04
230a491581fSWei Hu 
231a491581fSWei Hu struct packet_info_id {
232a491581fSWei Hu 	uint8_t				ver;
233a491581fSWei Hu 	uint8_t				flag;
234a491581fSWei Hu 	uint16_t			pkt_id;
235a491581fSWei Hu };
236a491581fSWei Hu 
237a491581fSWei Hu #define NDIS_PKTINFOID_SZ		sizeof(struct packet_info_id)
238a491581fSWei Hu 
239a491581fSWei Hu 
24015516c77SSepherosa Ziehau struct hn_rxinfo {
241a491581fSWei Hu 	const uint32_t			*vlan_info;
242a491581fSWei Hu 	const uint32_t			*csum_info;
243a491581fSWei Hu 	const uint32_t			*hash_info;
244a491581fSWei Hu 	const uint32_t			*hash_value;
245a491581fSWei Hu 	const struct packet_info_id	*pktinfo_id;
24615516c77SSepherosa Ziehau };
24715516c77SSepherosa Ziehau 
248962f0357SSepherosa Ziehau struct hn_rxvf_setarg {
2495bdfd3fdSDexuan Cui 	struct hn_rx_ring	*rxr;
250962f0357SSepherosa Ziehau 	struct ifnet		*vf_ifp;
2515bdfd3fdSDexuan Cui };
2525bdfd3fdSDexuan Cui 
25315516c77SSepherosa Ziehau #define HN_RXINFO_VLAN			0x0001
25415516c77SSepherosa Ziehau #define HN_RXINFO_CSUM			0x0002
25515516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF		0x0004
25615516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL		0x0008
257a491581fSWei Hu #define HN_RXINFO_PKTINFO_ID		0x0010
25815516c77SSepherosa Ziehau #define HN_RXINFO_ALL			\
25915516c77SSepherosa Ziehau 	(HN_RXINFO_VLAN |		\
26015516c77SSepherosa Ziehau 	 HN_RXINFO_CSUM |		\
26115516c77SSepherosa Ziehau 	 HN_RXINFO_HASHINF |		\
262a491581fSWei Hu 	 HN_RXINFO_HASHVAL |		\
263a491581fSWei Hu 	 HN_RXINFO_PKTINFO_ID)
26415516c77SSepherosa Ziehau 
26515516c77SSepherosa Ziehau static int			hn_probe(device_t);
26615516c77SSepherosa Ziehau static int			hn_attach(device_t);
26715516c77SSepherosa Ziehau static int			hn_detach(device_t);
26815516c77SSepherosa Ziehau static int			hn_shutdown(device_t);
26915516c77SSepherosa Ziehau static void			hn_chan_callback(struct vmbus_channel *,
27015516c77SSepherosa Ziehau 				    void *);
27115516c77SSepherosa Ziehau 
27215516c77SSepherosa Ziehau static void			hn_init(void *);
27315516c77SSepherosa Ziehau static int			hn_ioctl(struct ifnet *, u_long, caddr_t);
27423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
27515516c77SSepherosa Ziehau static void			hn_start(struct ifnet *);
27623bf9e15SSepherosa Ziehau #endif
27715516c77SSepherosa Ziehau static int			hn_transmit(struct ifnet *, struct mbuf *);
27815516c77SSepherosa Ziehau static void			hn_xmit_qflush(struct ifnet *);
27915516c77SSepherosa Ziehau static int			hn_ifmedia_upd(struct ifnet *);
28015516c77SSepherosa Ziehau static void			hn_ifmedia_sts(struct ifnet *,
28115516c77SSepherosa Ziehau 				    struct ifmediareq *);
28215516c77SSepherosa Ziehau 
283499c3e17SSepherosa Ziehau static void			hn_ifnet_event(void *, struct ifnet *, int);
284499c3e17SSepherosa Ziehau static void			hn_ifaddr_event(void *, struct ifnet *);
285499c3e17SSepherosa Ziehau static void			hn_ifnet_attevent(void *, struct ifnet *);
286499c3e17SSepherosa Ziehau static void			hn_ifnet_detevent(void *, struct ifnet *);
2879c6cae24SSepherosa Ziehau static void			hn_ifnet_lnkevent(void *, struct ifnet *, int);
288499c3e17SSepherosa Ziehau 
289962f0357SSepherosa Ziehau static bool			hn_ismyvf(const struct hn_softc *,
290962f0357SSepherosa Ziehau 				    const struct ifnet *);
291962f0357SSepherosa Ziehau static void			hn_rxvf_change(struct hn_softc *,
292962f0357SSepherosa Ziehau 				    struct ifnet *, bool);
293962f0357SSepherosa Ziehau static void			hn_rxvf_set(struct hn_softc *, struct ifnet *);
294962f0357SSepherosa Ziehau static void			hn_rxvf_set_task(void *, int);
2959c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_input(struct ifnet *, struct mbuf *);
2969c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_iocsetflags(struct hn_softc *);
2979c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_iocsetcaps(struct hn_softc *,
2989c6cae24SSepherosa Ziehau 				    struct ifreq *);
2999c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_saveifflags(struct hn_softc *);
3009c6cae24SSepherosa Ziehau static bool			hn_xpnt_vf_isready(struct hn_softc *);
3019c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_setready(struct hn_softc *);
3029c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_init_taskfunc(void *, int);
3039c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_init(struct hn_softc *);
304a97fff19SSepherosa Ziehau static void			hn_xpnt_vf_setenable(struct hn_softc *);
305a97fff19SSepherosa Ziehau static void			hn_xpnt_vf_setdisable(struct hn_softc *, bool);
306642ec226SSepherosa Ziehau static void			hn_vf_rss_fixup(struct hn_softc *, bool);
307642ec226SSepherosa Ziehau static void			hn_vf_rss_restore(struct hn_softc *);
308962f0357SSepherosa Ziehau 
30915516c77SSepherosa Ziehau static int			hn_rndis_rxinfo(const void *, int,
31015516c77SSepherosa Ziehau 				    struct hn_rxinfo *);
31115516c77SSepherosa Ziehau static void			hn_rndis_rx_data(struct hn_rx_ring *,
31215516c77SSepherosa Ziehau 				    const void *, int);
31315516c77SSepherosa Ziehau static void			hn_rndis_rx_status(struct hn_softc *,
31415516c77SSepherosa Ziehau 				    const void *, int);
315b3b75d9cSSepherosa Ziehau static void			hn_rndis_init_fixat(struct hn_softc *, int);
31615516c77SSepherosa Ziehau 
31715516c77SSepherosa Ziehau static void			hn_nvs_handle_notify(struct hn_softc *,
31815516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
31915516c77SSepherosa Ziehau static void			hn_nvs_handle_comp(struct hn_softc *,
32015516c77SSepherosa Ziehau 				    struct vmbus_channel *,
32115516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
32215516c77SSepherosa Ziehau static void			hn_nvs_handle_rxbuf(struct hn_rx_ring *,
32315516c77SSepherosa Ziehau 				    struct vmbus_channel *,
32415516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
32515516c77SSepherosa Ziehau static void			hn_nvs_ack_rxbuf(struct hn_rx_ring *,
32615516c77SSepherosa Ziehau 				    struct vmbus_channel *, uint64_t);
32715516c77SSepherosa Ziehau 
32815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
32915516c77SSepherosa Ziehau static int			hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS);
33015516c77SSepherosa Ziehau static int			hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS);
33115516c77SSepherosa Ziehau #endif
33215516c77SSepherosa Ziehau static int			hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS);
33315516c77SSepherosa Ziehau static int			hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS);
33415516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
33515516c77SSepherosa Ziehau static int			hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS);
33615516c77SSepherosa Ziehau #else
33715516c77SSepherosa Ziehau static int			hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS);
33815516c77SSepherosa Ziehau #endif
33915516c77SSepherosa Ziehau static int			hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
34015516c77SSepherosa Ziehau static int			hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
34115516c77SSepherosa Ziehau static int			hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS);
34215516c77SSepherosa Ziehau static int			hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS);
34315516c77SSepherosa Ziehau static int			hn_caps_sysctl(SYSCTL_HANDLER_ARGS);
34415516c77SSepherosa Ziehau static int			hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS);
34515516c77SSepherosa Ziehau static int			hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS);
34634d68912SSepherosa Ziehau #ifndef RSS
34715516c77SSepherosa Ziehau static int			hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS);
34815516c77SSepherosa Ziehau static int			hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS);
34934d68912SSepherosa Ziehau #endif
35015516c77SSepherosa Ziehau static int			hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS);
351642ec226SSepherosa Ziehau static int			hn_rss_hcap_sysctl(SYSCTL_HANDLER_ARGS);
352642ec226SSepherosa Ziehau static int			hn_rss_mbuf_sysctl(SYSCTL_HANDLER_ARGS);
353dc13fee6SSepherosa Ziehau static int			hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS);
354dc13fee6SSepherosa Ziehau static int			hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS);
355dc13fee6SSepherosa Ziehau static int			hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS);
356dc13fee6SSepherosa Ziehau static int			hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS);
3576c1204dfSSepherosa Ziehau static int			hn_polling_sysctl(SYSCTL_HANDLER_ARGS);
35840d60d6eSDexuan Cui static int			hn_vf_sysctl(SYSCTL_HANDLER_ARGS);
359499c3e17SSepherosa Ziehau static int			hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS);
360499c3e17SSepherosa Ziehau static int			hn_vflist_sysctl(SYSCTL_HANDLER_ARGS);
361499c3e17SSepherosa Ziehau static int			hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS);
3629c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS);
3639c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS);
36415516c77SSepherosa Ziehau 
3655bdfd3fdSDexuan Cui static void			hn_stop(struct hn_softc *, bool);
36615516c77SSepherosa Ziehau static void			hn_init_locked(struct hn_softc *);
36715516c77SSepherosa Ziehau static int			hn_chan_attach(struct hn_softc *,
36815516c77SSepherosa Ziehau 				    struct vmbus_channel *);
36915516c77SSepherosa Ziehau static void			hn_chan_detach(struct hn_softc *,
37015516c77SSepherosa Ziehau 				    struct vmbus_channel *);
37115516c77SSepherosa Ziehau static int			hn_attach_subchans(struct hn_softc *);
37215516c77SSepherosa Ziehau static void			hn_detach_allchans(struct hn_softc *);
37315516c77SSepherosa Ziehau static void			hn_chan_rollup(struct hn_rx_ring *,
37415516c77SSepherosa Ziehau 				    struct hn_tx_ring *);
37515516c77SSepherosa Ziehau static void			hn_set_ring_inuse(struct hn_softc *, int);
37615516c77SSepherosa Ziehau static int			hn_synth_attach(struct hn_softc *, int);
37715516c77SSepherosa Ziehau static void			hn_synth_detach(struct hn_softc *);
37815516c77SSepherosa Ziehau static int			hn_synth_alloc_subchans(struct hn_softc *,
37915516c77SSepherosa Ziehau 				    int *);
3802494d735SSepherosa Ziehau static bool			hn_synth_attachable(const struct hn_softc *);
38115516c77SSepherosa Ziehau static void			hn_suspend(struct hn_softc *);
38215516c77SSepherosa Ziehau static void			hn_suspend_data(struct hn_softc *);
38315516c77SSepherosa Ziehau static void			hn_suspend_mgmt(struct hn_softc *);
38415516c77SSepherosa Ziehau static void			hn_resume(struct hn_softc *);
38515516c77SSepherosa Ziehau static void			hn_resume_data(struct hn_softc *);
38615516c77SSepherosa Ziehau static void			hn_resume_mgmt(struct hn_softc *);
38715516c77SSepherosa Ziehau static void			hn_suspend_mgmt_taskfunc(void *, int);
38825641fc7SSepherosa Ziehau static void			hn_chan_drain(struct hn_softc *,
38925641fc7SSepherosa Ziehau 				    struct vmbus_channel *);
390b3b75d9cSSepherosa Ziehau static void			hn_disable_rx(struct hn_softc *);
391b3b75d9cSSepherosa Ziehau static void			hn_drain_rxtx(struct hn_softc *, int);
3926c1204dfSSepherosa Ziehau static void			hn_polling(struct hn_softc *, u_int);
3936c1204dfSSepherosa Ziehau static void			hn_chan_polling(struct vmbus_channel *, u_int);
3949c6cae24SSepherosa Ziehau static void			hn_mtu_change_fixup(struct hn_softc *);
39515516c77SSepherosa Ziehau 
39615516c77SSepherosa Ziehau static void			hn_update_link_status(struct hn_softc *);
39715516c77SSepherosa Ziehau static void			hn_change_network(struct hn_softc *);
39815516c77SSepherosa Ziehau static void			hn_link_taskfunc(void *, int);
39915516c77SSepherosa Ziehau static void			hn_netchg_init_taskfunc(void *, int);
40015516c77SSepherosa Ziehau static void			hn_netchg_status_taskfunc(void *, int);
40115516c77SSepherosa Ziehau static void			hn_link_status(struct hn_softc *);
40215516c77SSepherosa Ziehau 
40315516c77SSepherosa Ziehau static int			hn_create_rx_data(struct hn_softc *, int);
40415516c77SSepherosa Ziehau static void			hn_destroy_rx_data(struct hn_softc *);
40515516c77SSepherosa Ziehau static int			hn_check_iplen(const struct mbuf *, int);
406db76829bSSepherosa Ziehau static void			hn_rxpkt_proto(const struct mbuf *, int *, int *);
407f1b0a43fSSepherosa Ziehau static int			hn_set_rxfilter(struct hn_softc *, uint32_t);
408c08f7b2cSSepherosa Ziehau static int			hn_rxfilter_config(struct hn_softc *);
40915516c77SSepherosa Ziehau static int			hn_rss_reconfig(struct hn_softc *);
410afd4971bSSepherosa Ziehau static void			hn_rss_ind_fixup(struct hn_softc *);
411642ec226SSepherosa Ziehau static void			hn_rss_mbuf_hash(struct hn_softc *, uint32_t);
412a491581fSWei Hu static int			hn_rxpkt(struct hn_rx_ring *);
413642ec226SSepherosa Ziehau static uint32_t			hn_rss_type_fromndis(uint32_t);
414642ec226SSepherosa Ziehau static uint32_t			hn_rss_type_tondis(uint32_t);
41515516c77SSepherosa Ziehau 
41615516c77SSepherosa Ziehau static int			hn_tx_ring_create(struct hn_softc *, int);
41715516c77SSepherosa Ziehau static void			hn_tx_ring_destroy(struct hn_tx_ring *);
41815516c77SSepherosa Ziehau static int			hn_create_tx_data(struct hn_softc *, int);
41915516c77SSepherosa Ziehau static void			hn_fixup_tx_data(struct hn_softc *);
420db76829bSSepherosa Ziehau static void			hn_fixup_rx_data(struct hn_softc *);
42115516c77SSepherosa Ziehau static void			hn_destroy_tx_data(struct hn_softc *);
42215516c77SSepherosa Ziehau static void			hn_txdesc_dmamap_destroy(struct hn_txdesc *);
42325641fc7SSepherosa Ziehau static void			hn_txdesc_gc(struct hn_tx_ring *,
42425641fc7SSepherosa Ziehau 				    struct hn_txdesc *);
425dc13fee6SSepherosa Ziehau static int			hn_encap(struct ifnet *, struct hn_tx_ring *,
42615516c77SSepherosa Ziehau 				    struct hn_txdesc *, struct mbuf **);
42715516c77SSepherosa Ziehau static int			hn_txpkt(struct ifnet *, struct hn_tx_ring *,
42815516c77SSepherosa Ziehau 				    struct hn_txdesc *);
42915516c77SSepherosa Ziehau static void			hn_set_chim_size(struct hn_softc *, int);
43015516c77SSepherosa Ziehau static void			hn_set_tso_maxsize(struct hn_softc *, int, int);
43115516c77SSepherosa Ziehau static bool			hn_tx_ring_pending(struct hn_tx_ring *);
43215516c77SSepherosa Ziehau static void			hn_tx_ring_qflush(struct hn_tx_ring *);
43315516c77SSepherosa Ziehau static void			hn_resume_tx(struct hn_softc *, int);
434dc13fee6SSepherosa Ziehau static void			hn_set_txagg(struct hn_softc *);
435dc13fee6SSepherosa Ziehau static void			*hn_try_txagg(struct ifnet *,
436dc13fee6SSepherosa Ziehau 				    struct hn_tx_ring *, struct hn_txdesc *,
437dc13fee6SSepherosa Ziehau 				    int);
43815516c77SSepherosa Ziehau static int			hn_get_txswq_depth(const struct hn_tx_ring *);
43915516c77SSepherosa Ziehau static void			hn_txpkt_done(struct hn_nvs_sendctx *,
44015516c77SSepherosa Ziehau 				    struct hn_softc *, struct vmbus_channel *,
44115516c77SSepherosa Ziehau 				    const void *, int);
44215516c77SSepherosa Ziehau static int			hn_txpkt_sglist(struct hn_tx_ring *,
44315516c77SSepherosa Ziehau 				    struct hn_txdesc *);
44415516c77SSepherosa Ziehau static int			hn_txpkt_chim(struct hn_tx_ring *,
44515516c77SSepherosa Ziehau 				    struct hn_txdesc *);
44615516c77SSepherosa Ziehau static int			hn_xmit(struct hn_tx_ring *, int);
44715516c77SSepherosa Ziehau static void			hn_xmit_taskfunc(void *, int);
44815516c77SSepherosa Ziehau static void			hn_xmit_txeof(struct hn_tx_ring *);
44915516c77SSepherosa Ziehau static void			hn_xmit_txeof_taskfunc(void *, int);
45023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
45115516c77SSepherosa Ziehau static int			hn_start_locked(struct hn_tx_ring *, int);
45215516c77SSepherosa Ziehau static void			hn_start_taskfunc(void *, int);
45315516c77SSepherosa Ziehau static void			hn_start_txeof(struct hn_tx_ring *);
45415516c77SSepherosa Ziehau static void			hn_start_txeof_taskfunc(void *, int);
45523bf9e15SSepherosa Ziehau #endif
45615516c77SSepherosa Ziehau 
457*80c3eb7bSWei Hu static int			hn_rsc_sysctl(SYSCTL_HANDLER_ARGS);
458*80c3eb7bSWei Hu 
45915516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
46015516c77SSepherosa Ziehau     "Hyper-V network interface");
46115516c77SSepherosa Ziehau 
462b15a632cSGordon Bergling /* Trust tcp segment verification on host side. */
46315516c77SSepherosa Ziehau static int			hn_trust_hosttcp = 1;
46415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN,
46515516c77SSepherosa Ziehau     &hn_trust_hosttcp, 0,
466b15a632cSGordon Bergling     "Trust tcp segment verification on host side, "
46715516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
46815516c77SSepherosa Ziehau 
46915516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */
47015516c77SSepherosa Ziehau static int			hn_trust_hostudp = 1;
47115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN,
47215516c77SSepherosa Ziehau     &hn_trust_hostudp, 0,
47315516c77SSepherosa Ziehau     "Trust udp datagram verification on host side, "
47415516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
47515516c77SSepherosa Ziehau 
47615516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */
47715516c77SSepherosa Ziehau static int			hn_trust_hostip = 1;
47815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN,
47915516c77SSepherosa Ziehau     &hn_trust_hostip, 0,
48015516c77SSepherosa Ziehau     "Trust ip packet verification on host side, "
48115516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
48215516c77SSepherosa Ziehau 
4832be266caSSepherosa Ziehau /*
4842be266caSSepherosa Ziehau  * Offload UDP/IPv4 checksum.
4852be266caSSepherosa Ziehau  */
4862be266caSSepherosa Ziehau static int			hn_enable_udp4cs = 1;
4872be266caSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, enable_udp4cs, CTLFLAG_RDTUN,
4882be266caSSepherosa Ziehau     &hn_enable_udp4cs, 0, "Offload UDP/IPv4 checksum");
4892be266caSSepherosa Ziehau 
4902be266caSSepherosa Ziehau /*
4912be266caSSepherosa Ziehau  * Offload UDP/IPv6 checksum.
4922be266caSSepherosa Ziehau  */
4932be266caSSepherosa Ziehau static int			hn_enable_udp6cs = 1;
4942be266caSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, enable_udp6cs, CTLFLAG_RDTUN,
4952be266caSSepherosa Ziehau     &hn_enable_udp6cs, 0, "Offload UDP/IPv6 checksum");
4962be266caSSepherosa Ziehau 
4972be266caSSepherosa Ziehau /* Stats. */
4982be266caSSepherosa Ziehau static counter_u64_t		hn_udpcs_fixup;
4992be266caSSepherosa Ziehau SYSCTL_COUNTER_U64(_hw_hn, OID_AUTO, udpcs_fixup, CTLFLAG_RW,
5002be266caSSepherosa Ziehau     &hn_udpcs_fixup, "# of UDP checksum fixup");
5012be266caSSepherosa Ziehau 
5022be266caSSepherosa Ziehau /*
5032be266caSSepherosa Ziehau  * See hn_set_hlen().
5042be266caSSepherosa Ziehau  *
5052be266caSSepherosa Ziehau  * This value is for Azure.  For Hyper-V, set this above
5062be266caSSepherosa Ziehau  * 65536 to disable UDP datagram checksum fixup.
5072be266caSSepherosa Ziehau  */
5082be266caSSepherosa Ziehau static int			hn_udpcs_fixup_mtu = 1420;
5092be266caSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, udpcs_fixup_mtu, CTLFLAG_RWTUN,
5102be266caSSepherosa Ziehau     &hn_udpcs_fixup_mtu, 0, "UDP checksum fixup MTU threshold");
5112be266caSSepherosa Ziehau 
51215516c77SSepherosa Ziehau /* Limit TSO burst size */
51315516c77SSepherosa Ziehau static int			hn_tso_maxlen = IP_MAXPACKET;
51415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN,
51515516c77SSepherosa Ziehau     &hn_tso_maxlen, 0, "TSO burst limit");
51615516c77SSepherosa Ziehau 
51715516c77SSepherosa Ziehau /* Limit chimney send size */
51815516c77SSepherosa Ziehau static int			hn_tx_chimney_size = 0;
51915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN,
52015516c77SSepherosa Ziehau     &hn_tx_chimney_size, 0, "Chimney send packet size limit");
52115516c77SSepherosa Ziehau 
52215516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */
52315516c77SSepherosa Ziehau static int			hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF;
52415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN,
52515516c77SSepherosa Ziehau     &hn_direct_tx_size, 0, "Size of the packet for direct transmission");
52615516c77SSepherosa Ziehau 
52715516c77SSepherosa Ziehau /* # of LRO entries per RX ring */
52815516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
52915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
53015516c77SSepherosa Ziehau static int			hn_lro_entry_count = HN_LROENT_CNT_DEF;
53115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN,
53215516c77SSepherosa Ziehau     &hn_lro_entry_count, 0, "LRO entry count");
53315516c77SSepherosa Ziehau #endif
53415516c77SSepherosa Ziehau #endif
53515516c77SSepherosa Ziehau 
536fdd0222aSSepherosa Ziehau static int			hn_tx_taskq_cnt = 1;
537fdd0222aSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_cnt, CTLFLAG_RDTUN,
538fdd0222aSSepherosa Ziehau     &hn_tx_taskq_cnt, 0, "# of TX taskqueues");
539fdd0222aSSepherosa Ziehau 
5400e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_INDEP	0
5410e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_GLOBAL	1
5420e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_EVTTQ	2
5430e11868dSSepherosa Ziehau 
5440e11868dSSepherosa Ziehau static int			hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
5450e11868dSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_mode, CTLFLAG_RDTUN,
5460e11868dSSepherosa Ziehau     &hn_tx_taskq_mode, 0, "TX taskqueue modes: "
5470e11868dSSepherosa Ziehau     "0 - independent, 1 - share global tx taskqs, 2 - share event taskqs");
5480e11868dSSepherosa Ziehau 
54915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
55015516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 0;
55115516c77SSepherosa Ziehau #else
55215516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 1;
55315516c77SSepherosa Ziehau #endif
55415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD,
55515516c77SSepherosa Ziehau     &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors");
55615516c77SSepherosa Ziehau 
55723bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
55815516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */
55915516c77SSepherosa Ziehau static int			hn_use_if_start = 0;
56015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN,
56115516c77SSepherosa Ziehau     &hn_use_if_start, 0, "Use if_start TX method");
56223bf9e15SSepherosa Ziehau #endif
56315516c77SSepherosa Ziehau 
56415516c77SSepherosa Ziehau /* # of channels to use */
56515516c77SSepherosa Ziehau static int			hn_chan_cnt = 0;
56615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN,
56715516c77SSepherosa Ziehau     &hn_chan_cnt, 0,
56815516c77SSepherosa Ziehau     "# of channels to use; each channel has one RX ring and one TX ring");
56915516c77SSepherosa Ziehau 
57015516c77SSepherosa Ziehau /* # of transmit rings to use */
57115516c77SSepherosa Ziehau static int			hn_tx_ring_cnt = 0;
57215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN,
57315516c77SSepherosa Ziehau     &hn_tx_ring_cnt, 0, "# of TX rings to use");
57415516c77SSepherosa Ziehau 
57515516c77SSepherosa Ziehau /* Software TX ring deptch */
57615516c77SSepherosa Ziehau static int			hn_tx_swq_depth = 0;
57715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN,
57815516c77SSepherosa Ziehau     &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING");
57915516c77SSepherosa Ziehau 
58015516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */
58115516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
58215516c77SSepherosa Ziehau static u_int			hn_lro_mbufq_depth = 0;
58315516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN,
58415516c77SSepherosa Ziehau     &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue");
58515516c77SSepherosa Ziehau #endif
58615516c77SSepherosa Ziehau 
587dc13fee6SSepherosa Ziehau /* Packet transmission aggregation size limit */
588dc13fee6SSepherosa Ziehau static int			hn_tx_agg_size = -1;
589dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN,
590dc13fee6SSepherosa Ziehau     &hn_tx_agg_size, 0, "Packet transmission aggregation size limit");
591dc13fee6SSepherosa Ziehau 
592dc13fee6SSepherosa Ziehau /* Packet transmission aggregation count limit */
593fa915c4dSSepherosa Ziehau static int			hn_tx_agg_pkts = -1;
594dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN,
595dc13fee6SSepherosa Ziehau     &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit");
596dc13fee6SSepherosa Ziehau 
597499c3e17SSepherosa Ziehau /* VF list */
5987029da5cSPawel Biernacki SYSCTL_PROC(_hw_hn, OID_AUTO, vflist,
5997029da5cSPawel Biernacki     CTLFLAG_RD | CTLTYPE_STRING | CTLFLAG_NEEDGIANT, 0, 0,
6007029da5cSPawel Biernacki     hn_vflist_sysctl, "A",
6017029da5cSPawel Biernacki     "VF list");
602499c3e17SSepherosa Ziehau 
603499c3e17SSepherosa Ziehau /* VF mapping */
6047029da5cSPawel Biernacki SYSCTL_PROC(_hw_hn, OID_AUTO, vfmap,
6057029da5cSPawel Biernacki     CTLFLAG_RD | CTLTYPE_STRING | CTLFLAG_NEEDGIANT, 0, 0,
6067029da5cSPawel Biernacki     hn_vfmap_sysctl, "A",
6077029da5cSPawel Biernacki     "VF mapping");
608499c3e17SSepherosa Ziehau 
6099c6cae24SSepherosa Ziehau /* Transparent VF */
61078e46963SSepherosa Ziehau static int			hn_xpnt_vf = 1;
6119c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_transparent, CTLFLAG_RDTUN,
6129c6cae24SSepherosa Ziehau     &hn_xpnt_vf, 0, "Transparent VF mod");
6139c6cae24SSepherosa Ziehau 
6149c6cae24SSepherosa Ziehau /* Accurate BPF support for Transparent VF */
6159c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_accbpf = 0;
6169c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_xpnt_accbpf, CTLFLAG_RDTUN,
6179c6cae24SSepherosa Ziehau     &hn_xpnt_vf_accbpf, 0, "Accurate BPF for transparent VF");
6189c6cae24SSepherosa Ziehau 
6199c6cae24SSepherosa Ziehau /* Extra wait for transparent VF attach routing; unit seconds. */
6209c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN;
6219c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_xpnt_attwait, CTLFLAG_RWTUN,
6229c6cae24SSepherosa Ziehau     &hn_xpnt_vf_attwait, 0,
6239c6cae24SSepherosa Ziehau     "Extra wait for transparent VF attach routing; unit: seconds");
6249c6cae24SSepherosa Ziehau 
62515516c77SSepherosa Ziehau static u_int			hn_cpu_index;	/* next CPU for channel */
626fdd0222aSSepherosa Ziehau static struct taskqueue		**hn_tx_taskque;/* shared TX taskqueues */
62715516c77SSepherosa Ziehau 
628499c3e17SSepherosa Ziehau static struct rmlock		hn_vfmap_lock;
629499c3e17SSepherosa Ziehau static int			hn_vfmap_size;
630499c3e17SSepherosa Ziehau static struct ifnet		**hn_vfmap;
631499c3e17SSepherosa Ziehau 
63234d68912SSepherosa Ziehau #ifndef RSS
63315516c77SSepherosa Ziehau static const uint8_t
63415516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
63515516c77SSepherosa Ziehau 	0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
63615516c77SSepherosa Ziehau 	0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
63715516c77SSepherosa Ziehau 	0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
63815516c77SSepherosa Ziehau 	0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
63915516c77SSepherosa Ziehau 	0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
64015516c77SSepherosa Ziehau };
64134d68912SSepherosa Ziehau #endif	/* !RSS */
64215516c77SSepherosa Ziehau 
643c2d50b26SSepherosa Ziehau static const struct hyperv_guid	hn_guid = {
644c2d50b26SSepherosa Ziehau 	.hv_guid = {
645c2d50b26SSepherosa Ziehau 	    0x63, 0x51, 0x61, 0xf8, 0x3e, 0xdf, 0xc5, 0x46,
646c2d50b26SSepherosa Ziehau 	    0x91, 0x3f, 0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e }
647c2d50b26SSepherosa Ziehau };
648c2d50b26SSepherosa Ziehau 
64915516c77SSepherosa Ziehau static device_method_t hn_methods[] = {
65015516c77SSepherosa Ziehau 	/* Device interface */
65115516c77SSepherosa Ziehau 	DEVMETHOD(device_probe,		hn_probe),
65215516c77SSepherosa Ziehau 	DEVMETHOD(device_attach,	hn_attach),
65315516c77SSepherosa Ziehau 	DEVMETHOD(device_detach,	hn_detach),
65415516c77SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	hn_shutdown),
65515516c77SSepherosa Ziehau 	DEVMETHOD_END
65615516c77SSepherosa Ziehau };
65715516c77SSepherosa Ziehau 
65815516c77SSepherosa Ziehau static driver_t hn_driver = {
65915516c77SSepherosa Ziehau 	"hn",
66015516c77SSepherosa Ziehau 	hn_methods,
66115516c77SSepherosa Ziehau 	sizeof(struct hn_softc)
66215516c77SSepherosa Ziehau };
66315516c77SSepherosa Ziehau 
66415516c77SSepherosa Ziehau static devclass_t hn_devclass;
66515516c77SSepherosa Ziehau 
66615516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0);
66715516c77SSepherosa Ziehau MODULE_VERSION(hn, 1);
66815516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1);
66915516c77SSepherosa Ziehau 
67015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
67115516c77SSepherosa Ziehau static void
67215516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim)
67315516c77SSepherosa Ziehau {
67415516c77SSepherosa Ziehau 	int i;
67515516c77SSepherosa Ziehau 
676a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
67715516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim;
67815516c77SSepherosa Ziehau }
67915516c77SSepherosa Ziehau #endif
68015516c77SSepherosa Ziehau 
68115516c77SSepherosa Ziehau static int
68215516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd)
68315516c77SSepherosa Ziehau {
68415516c77SSepherosa Ziehau 
68515516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
68615516c77SSepherosa Ziehau 	    txd->chim_size == 0, ("invalid rndis sglist txd"));
68715516c77SSepherosa Ziehau 	return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA,
68815516c77SSepherosa Ziehau 	    &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt));
68915516c77SSepherosa Ziehau }
69015516c77SSepherosa Ziehau 
69115516c77SSepherosa Ziehau static int
69215516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd)
69315516c77SSepherosa Ziehau {
69415516c77SSepherosa Ziehau 	struct hn_nvs_rndis rndis;
69515516c77SSepherosa Ziehau 
69615516c77SSepherosa Ziehau 	KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID &&
69715516c77SSepherosa Ziehau 	    txd->chim_size > 0, ("invalid rndis chim txd"));
69815516c77SSepherosa Ziehau 
69915516c77SSepherosa Ziehau 	rndis.nvs_type = HN_NVS_TYPE_RNDIS;
70015516c77SSepherosa Ziehau 	rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA;
70115516c77SSepherosa Ziehau 	rndis.nvs_chim_idx = txd->chim_index;
70215516c77SSepherosa Ziehau 	rndis.nvs_chim_sz = txd->chim_size;
70315516c77SSepherosa Ziehau 
70415516c77SSepherosa Ziehau 	return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC,
70515516c77SSepherosa Ziehau 	    &rndis, sizeof(rndis), &txd->send_ctx));
70615516c77SSepherosa Ziehau }
70715516c77SSepherosa Ziehau 
70815516c77SSepherosa Ziehau static __inline uint32_t
70915516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc)
71015516c77SSepherosa Ziehau {
71115516c77SSepherosa Ziehau 	int i, bmap_cnt = sc->hn_chim_bmap_cnt;
71215516c77SSepherosa Ziehau 	u_long *bmap = sc->hn_chim_bmap;
71315516c77SSepherosa Ziehau 	uint32_t ret = HN_NVS_CHIM_IDX_INVALID;
71415516c77SSepherosa Ziehau 
71515516c77SSepherosa Ziehau 	for (i = 0; i < bmap_cnt; ++i) {
71615516c77SSepherosa Ziehau 		int idx;
71715516c77SSepherosa Ziehau 
71815516c77SSepherosa Ziehau 		idx = ffsl(~bmap[i]);
71915516c77SSepherosa Ziehau 		if (idx == 0)
72015516c77SSepherosa Ziehau 			continue;
72115516c77SSepherosa Ziehau 
72215516c77SSepherosa Ziehau 		--idx; /* ffsl is 1-based */
72315516c77SSepherosa Ziehau 		KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt,
72415516c77SSepherosa Ziehau 		    ("invalid i %d and idx %d", i, idx));
72515516c77SSepherosa Ziehau 
72615516c77SSepherosa Ziehau 		if (atomic_testandset_long(&bmap[i], idx))
72715516c77SSepherosa Ziehau 			continue;
72815516c77SSepherosa Ziehau 
72915516c77SSepherosa Ziehau 		ret = i * LONG_BIT + idx;
73015516c77SSepherosa Ziehau 		break;
73115516c77SSepherosa Ziehau 	}
73215516c77SSepherosa Ziehau 	return (ret);
73315516c77SSepherosa Ziehau }
73415516c77SSepherosa Ziehau 
73515516c77SSepherosa Ziehau static __inline void
73615516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx)
73715516c77SSepherosa Ziehau {
73815516c77SSepherosa Ziehau 	u_long mask;
73915516c77SSepherosa Ziehau 	uint32_t idx;
74015516c77SSepherosa Ziehau 
74115516c77SSepherosa Ziehau 	idx = chim_idx / LONG_BIT;
74215516c77SSepherosa Ziehau 	KASSERT(idx < sc->hn_chim_bmap_cnt,
74315516c77SSepherosa Ziehau 	    ("invalid chimney index 0x%x", chim_idx));
74415516c77SSepherosa Ziehau 
74515516c77SSepherosa Ziehau 	mask = 1UL << (chim_idx % LONG_BIT);
74615516c77SSepherosa Ziehau 	KASSERT(sc->hn_chim_bmap[idx] & mask,
74715516c77SSepherosa Ziehau 	    ("index bitmap 0x%lx, chimney index %u, "
74815516c77SSepherosa Ziehau 	     "bitmap idx %d, bitmask 0x%lx",
74915516c77SSepherosa Ziehau 	     sc->hn_chim_bmap[idx], chim_idx, idx, mask));
75015516c77SSepherosa Ziehau 
75115516c77SSepherosa Ziehau 	atomic_clear_long(&sc->hn_chim_bmap[idx], mask);
75215516c77SSepherosa Ziehau }
75315516c77SSepherosa Ziehau 
754edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
755cc0c6ebcSSepherosa Ziehau 
756cc0c6ebcSSepherosa Ziehau #define PULLUP_HDR(m, len)				\
757cc0c6ebcSSepherosa Ziehau do {							\
758cc0c6ebcSSepherosa Ziehau 	if (__predict_false((m)->m_len < (len))) {	\
759cc0c6ebcSSepherosa Ziehau 		(m) = m_pullup((m), (len));		\
760cc0c6ebcSSepherosa Ziehau 		if ((m) == NULL)			\
761cc0c6ebcSSepherosa Ziehau 			return (NULL);			\
762cc0c6ebcSSepherosa Ziehau 	}						\
763cc0c6ebcSSepherosa Ziehau } while (0)
764cc0c6ebcSSepherosa Ziehau 
765edd3f315SSepherosa Ziehau /*
766edd3f315SSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
767edd3f315SSepherosa Ziehau  */
768edd3f315SSepherosa Ziehau static __inline struct mbuf *
769edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head)
770edd3f315SSepherosa Ziehau {
771edd3f315SSepherosa Ziehau 	struct ether_vlan_header *evl;
772edd3f315SSepherosa Ziehau 	struct tcphdr *th;
773edd3f315SSepherosa Ziehau 	int ehlen;
774edd3f315SSepherosa Ziehau 
775edd3f315SSepherosa Ziehau 	KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable"));
776edd3f315SSepherosa Ziehau 
777edd3f315SSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
778edd3f315SSepherosa Ziehau 	evl = mtod(m_head, struct ether_vlan_header *);
779edd3f315SSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
780edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
781edd3f315SSepherosa Ziehau 	else
782edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
783c49d47daSSepherosa Ziehau 	m_head->m_pkthdr.l2hlen = ehlen;
784edd3f315SSepherosa Ziehau 
785edd3f315SSepherosa Ziehau #ifdef INET
786edd3f315SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
787edd3f315SSepherosa Ziehau 		struct ip *ip;
788edd3f315SSepherosa Ziehau 		int iphlen;
789edd3f315SSepherosa Ziehau 
790edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
791edd3f315SSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
792edd3f315SSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
793c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = iphlen;
794edd3f315SSepherosa Ziehau 
795edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
796edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + iphlen);
797edd3f315SSepherosa Ziehau 
798edd3f315SSepherosa Ziehau 		ip->ip_len = 0;
799edd3f315SSepherosa Ziehau 		ip->ip_sum = 0;
800edd3f315SSepherosa Ziehau 		th->th_sum = in_pseudo(ip->ip_src.s_addr,
801edd3f315SSepherosa Ziehau 		    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
802edd3f315SSepherosa Ziehau 	}
803edd3f315SSepherosa Ziehau #endif
804edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET)
805edd3f315SSepherosa Ziehau 	else
806edd3f315SSepherosa Ziehau #endif
807edd3f315SSepherosa Ziehau #ifdef INET6
808edd3f315SSepherosa Ziehau 	{
809edd3f315SSepherosa Ziehau 		struct ip6_hdr *ip6;
810edd3f315SSepherosa Ziehau 
811edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
812edd3f315SSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
813edd3f315SSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP) {
814edd3f315SSepherosa Ziehau 			m_freem(m_head);
815edd3f315SSepherosa Ziehau 			return (NULL);
816edd3f315SSepherosa Ziehau 		}
817c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = sizeof(*ip6);
818edd3f315SSepherosa Ziehau 
819edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
820edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + sizeof(*ip6));
821edd3f315SSepherosa Ziehau 
822edd3f315SSepherosa Ziehau 		ip6->ip6_plen = 0;
823edd3f315SSepherosa Ziehau 		th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
824edd3f315SSepherosa Ziehau 	}
825edd3f315SSepherosa Ziehau #endif
826edd3f315SSepherosa Ziehau 	return (m_head);
827edd3f315SSepherosa Ziehau }
828cc0c6ebcSSepherosa Ziehau 
829cc0c6ebcSSepherosa Ziehau /*
830cc0c6ebcSSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
831cc0c6ebcSSepherosa Ziehau  */
832cc0c6ebcSSepherosa Ziehau static __inline struct mbuf *
833c49d47daSSepherosa Ziehau hn_set_hlen(struct mbuf *m_head)
834cc0c6ebcSSepherosa Ziehau {
835cc0c6ebcSSepherosa Ziehau 	const struct ether_vlan_header *evl;
836cc0c6ebcSSepherosa Ziehau 	int ehlen;
837cc0c6ebcSSepherosa Ziehau 
838cc0c6ebcSSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
839cc0c6ebcSSepherosa Ziehau 	evl = mtod(m_head, const struct ether_vlan_header *);
840cc0c6ebcSSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
841cc0c6ebcSSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
842cc0c6ebcSSepherosa Ziehau 	else
843cc0c6ebcSSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
844c49d47daSSepherosa Ziehau 	m_head->m_pkthdr.l2hlen = ehlen;
845cc0c6ebcSSepherosa Ziehau 
846cc0c6ebcSSepherosa Ziehau #ifdef INET
847c49d47daSSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP_UDP)) {
848cc0c6ebcSSepherosa Ziehau 		const struct ip *ip;
849cc0c6ebcSSepherosa Ziehau 		int iphlen;
850cc0c6ebcSSepherosa Ziehau 
851cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
852cc0c6ebcSSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
853cc0c6ebcSSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
854c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = iphlen;
8552be266caSSepherosa Ziehau 
8562be266caSSepherosa Ziehau 		/*
8572be266caSSepherosa Ziehau 		 * UDP checksum offload does not work in Azure, if the
8582be266caSSepherosa Ziehau 		 * following conditions meet:
8592be266caSSepherosa Ziehau 		 * - sizeof(IP hdr + UDP hdr + payload) > 1420.
8602be266caSSepherosa Ziehau 		 * - IP_DF is not set in the IP hdr.
8612be266caSSepherosa Ziehau 		 *
8622be266caSSepherosa Ziehau 		 * Fallback to software checksum for these UDP datagrams.
8632be266caSSepherosa Ziehau 		 */
8642be266caSSepherosa Ziehau 		if ((m_head->m_pkthdr.csum_flags & CSUM_IP_UDP) &&
8652be266caSSepherosa Ziehau 		    m_head->m_pkthdr.len > hn_udpcs_fixup_mtu + ehlen &&
8662be266caSSepherosa Ziehau 		    (ntohs(ip->ip_off) & IP_DF) == 0) {
8672be266caSSepherosa Ziehau 			uint16_t off = ehlen + iphlen;
8682be266caSSepherosa Ziehau 
8692be266caSSepherosa Ziehau 			counter_u64_add(hn_udpcs_fixup, 1);
8702be266caSSepherosa Ziehau 			PULLUP_HDR(m_head, off + sizeof(struct udphdr));
8712be266caSSepherosa Ziehau 			*(uint16_t *)(m_head->m_data + off +
8722be266caSSepherosa Ziehau                             m_head->m_pkthdr.csum_data) = in_cksum_skip(
8732be266caSSepherosa Ziehau 			    m_head, m_head->m_pkthdr.len, off);
8742be266caSSepherosa Ziehau 			m_head->m_pkthdr.csum_flags &= ~CSUM_IP_UDP;
8752be266caSSepherosa Ziehau 		}
876cc0c6ebcSSepherosa Ziehau 	}
877cc0c6ebcSSepherosa Ziehau #endif
878cc0c6ebcSSepherosa Ziehau #if defined(INET6) && defined(INET)
879cc0c6ebcSSepherosa Ziehau 	else
880cc0c6ebcSSepherosa Ziehau #endif
881cc0c6ebcSSepherosa Ziehau #ifdef INET6
882cc0c6ebcSSepherosa Ziehau 	{
883cc0c6ebcSSepherosa Ziehau 		const struct ip6_hdr *ip6;
884cc0c6ebcSSepherosa Ziehau 
885cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
886cc0c6ebcSSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
887f0319886SWei Hu 		if (ip6->ip6_nxt != IPPROTO_TCP &&
888f0319886SWei Hu 		    ip6->ip6_nxt != IPPROTO_UDP) {
889c49d47daSSepherosa Ziehau 			m_freem(m_head);
890c49d47daSSepherosa Ziehau 			return (NULL);
891c49d47daSSepherosa Ziehau 		}
892c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = sizeof(*ip6);
893cc0c6ebcSSepherosa Ziehau 	}
894cc0c6ebcSSepherosa Ziehau #endif
895cc0c6ebcSSepherosa Ziehau 	return (m_head);
896cc0c6ebcSSepherosa Ziehau }
897cc0c6ebcSSepherosa Ziehau 
898c49d47daSSepherosa Ziehau /*
899c49d47daSSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
900c49d47daSSepherosa Ziehau  */
901c49d47daSSepherosa Ziehau static __inline struct mbuf *
902c49d47daSSepherosa Ziehau hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn)
903c49d47daSSepherosa Ziehau {
904c49d47daSSepherosa Ziehau 	const struct tcphdr *th;
905c49d47daSSepherosa Ziehau 	int ehlen, iphlen;
906c49d47daSSepherosa Ziehau 
907c49d47daSSepherosa Ziehau 	*tcpsyn = 0;
908c49d47daSSepherosa Ziehau 	ehlen = m_head->m_pkthdr.l2hlen;
909c49d47daSSepherosa Ziehau 	iphlen = m_head->m_pkthdr.l3hlen;
910c49d47daSSepherosa Ziehau 
911c49d47daSSepherosa Ziehau 	PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
912c49d47daSSepherosa Ziehau 	th = mtodo(m_head, ehlen + iphlen);
913c49d47daSSepherosa Ziehau 	if (th->th_flags & TH_SYN)
914c49d47daSSepherosa Ziehau 		*tcpsyn = 1;
915c49d47daSSepherosa Ziehau 	return (m_head);
916c49d47daSSepherosa Ziehau }
917c49d47daSSepherosa Ziehau 
918cc0c6ebcSSepherosa Ziehau #undef PULLUP_HDR
919cc0c6ebcSSepherosa Ziehau 
920edd3f315SSepherosa Ziehau #endif	/* INET6 || INET */
921edd3f315SSepherosa Ziehau 
92215516c77SSepherosa Ziehau static int
923f1b0a43fSSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc, uint32_t filter)
924f1b0a43fSSepherosa Ziehau {
925f1b0a43fSSepherosa Ziehau 	int error = 0;
926f1b0a43fSSepherosa Ziehau 
927f1b0a43fSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
928f1b0a43fSSepherosa Ziehau 
929f1b0a43fSSepherosa Ziehau 	if (sc->hn_rx_filter != filter) {
930f1b0a43fSSepherosa Ziehau 		error = hn_rndis_set_rxfilter(sc, filter);
931f1b0a43fSSepherosa Ziehau 		if (!error)
932f1b0a43fSSepherosa Ziehau 			sc->hn_rx_filter = filter;
933f1b0a43fSSepherosa Ziehau 	}
934f1b0a43fSSepherosa Ziehau 	return (error);
935f1b0a43fSSepherosa Ziehau }
936f1b0a43fSSepherosa Ziehau 
937f1b0a43fSSepherosa Ziehau static int
938c08f7b2cSSepherosa Ziehau hn_rxfilter_config(struct hn_softc *sc)
93915516c77SSepherosa Ziehau {
94015516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
94115516c77SSepherosa Ziehau 	uint32_t filter;
94215516c77SSepherosa Ziehau 
94315516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
94415516c77SSepherosa Ziehau 
9459c6cae24SSepherosa Ziehau 	/*
9469c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, we don't know how
9479c6cae24SSepherosa Ziehau 	 * its RX filter is configured, so stick the synthetic device in
9489c6cae24SSepherosa Ziehau 	 * the promiscous mode.
9499c6cae24SSepherosa Ziehau 	 */
9509c6cae24SSepherosa Ziehau 	if ((ifp->if_flags & IFF_PROMISC) || (sc->hn_flags & HN_FLAG_RXVF)) {
95115516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_PROMISCUOUS;
95215516c77SSepherosa Ziehau 	} else {
95315516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_DIRECTED;
95415516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_BROADCAST)
95515516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_BROADCAST;
95615516c77SSepherosa Ziehau 		/* TODO: support multicast list */
95715516c77SSepherosa Ziehau 		if ((ifp->if_flags & IFF_ALLMULTI) ||
958d7c5a620SMatt Macy 		    !CK_STAILQ_EMPTY(&ifp->if_multiaddrs))
95915516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
96015516c77SSepherosa Ziehau 	}
961f1b0a43fSSepherosa Ziehau 	return (hn_set_rxfilter(sc, filter));
96215516c77SSepherosa Ziehau }
96315516c77SSepherosa Ziehau 
964dc13fee6SSepherosa Ziehau static void
965dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc)
966dc13fee6SSepherosa Ziehau {
967dc13fee6SSepherosa Ziehau 	uint32_t size, pkts;
968dc13fee6SSepherosa Ziehau 	int i;
969dc13fee6SSepherosa Ziehau 
970dc13fee6SSepherosa Ziehau 	/*
971dc13fee6SSepherosa Ziehau 	 * Setup aggregation size.
972dc13fee6SSepherosa Ziehau 	 */
973dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_size < 0)
974dc13fee6SSepherosa Ziehau 		size = UINT32_MAX;
975dc13fee6SSepherosa Ziehau 	else
976dc13fee6SSepherosa Ziehau 		size = sc->hn_agg_size;
977dc13fee6SSepherosa Ziehau 
978dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_size < size)
979dc13fee6SSepherosa Ziehau 		size = sc->hn_rndis_agg_size;
980dc13fee6SSepherosa Ziehau 
981a4364cfeSSepherosa Ziehau 	/* NOTE: We only aggregate packets using chimney sending buffers. */
982a4364cfeSSepherosa Ziehau 	if (size > (uint32_t)sc->hn_chim_szmax)
983a4364cfeSSepherosa Ziehau 		size = sc->hn_chim_szmax;
984a4364cfeSSepherosa Ziehau 
985dc13fee6SSepherosa Ziehau 	if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) {
986dc13fee6SSepherosa Ziehau 		/* Disable */
987dc13fee6SSepherosa Ziehau 		size = 0;
988dc13fee6SSepherosa Ziehau 		pkts = 0;
989dc13fee6SSepherosa Ziehau 		goto done;
990dc13fee6SSepherosa Ziehau 	}
991dc13fee6SSepherosa Ziehau 
992dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'int'. */
993dc13fee6SSepherosa Ziehau 	if (size > INT_MAX)
994dc13fee6SSepherosa Ziehau 		size = INT_MAX;
995dc13fee6SSepherosa Ziehau 
996dc13fee6SSepherosa Ziehau 	/*
997dc13fee6SSepherosa Ziehau 	 * Setup aggregation packet count.
998dc13fee6SSepherosa Ziehau 	 */
999dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_pkts < 0)
1000dc13fee6SSepherosa Ziehau 		pkts = UINT32_MAX;
1001dc13fee6SSepherosa Ziehau 	else
1002dc13fee6SSepherosa Ziehau 		pkts = sc->hn_agg_pkts;
1003dc13fee6SSepherosa Ziehau 
1004dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_pkts < pkts)
1005dc13fee6SSepherosa Ziehau 		pkts = sc->hn_rndis_agg_pkts;
1006dc13fee6SSepherosa Ziehau 
1007dc13fee6SSepherosa Ziehau 	if (pkts <= 1) {
1008dc13fee6SSepherosa Ziehau 		/* Disable */
1009dc13fee6SSepherosa Ziehau 		size = 0;
1010dc13fee6SSepherosa Ziehau 		pkts = 0;
1011dc13fee6SSepherosa Ziehau 		goto done;
1012dc13fee6SSepherosa Ziehau 	}
1013dc13fee6SSepherosa Ziehau 
1014dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
1015dc13fee6SSepherosa Ziehau 	if (pkts > SHRT_MAX)
1016dc13fee6SSepherosa Ziehau 		pkts = SHRT_MAX;
1017dc13fee6SSepherosa Ziehau 
1018dc13fee6SSepherosa Ziehau done:
1019dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
1020dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_align > SHRT_MAX) {
1021dc13fee6SSepherosa Ziehau 		/* Disable */
1022dc13fee6SSepherosa Ziehau 		size = 0;
1023dc13fee6SSepherosa Ziehau 		pkts = 0;
1024dc13fee6SSepherosa Ziehau 	}
1025dc13fee6SSepherosa Ziehau 
1026dc13fee6SSepherosa Ziehau 	if (bootverbose) {
1027dc13fee6SSepherosa Ziehau 		if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n",
1028dc13fee6SSepherosa Ziehau 		    size, pkts, sc->hn_rndis_agg_align);
1029dc13fee6SSepherosa Ziehau 	}
1030dc13fee6SSepherosa Ziehau 
1031dc13fee6SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
1032dc13fee6SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
1033dc13fee6SSepherosa Ziehau 
1034dc13fee6SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
1035dc13fee6SSepherosa Ziehau 		txr->hn_agg_szmax = size;
1036dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktmax = pkts;
1037dc13fee6SSepherosa Ziehau 		txr->hn_agg_align = sc->hn_rndis_agg_align;
1038dc13fee6SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
1039dc13fee6SSepherosa Ziehau 	}
1040dc13fee6SSepherosa Ziehau }
1041dc13fee6SSepherosa Ziehau 
104215516c77SSepherosa Ziehau static int
104315516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr)
104415516c77SSepherosa Ziehau {
104515516c77SSepherosa Ziehau 
104615516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet"));
104715516c77SSepherosa Ziehau 	if (hn_tx_swq_depth < txr->hn_txdesc_cnt)
104815516c77SSepherosa Ziehau 		return txr->hn_txdesc_cnt;
104915516c77SSepherosa Ziehau 	return hn_tx_swq_depth;
105015516c77SSepherosa Ziehau }
105115516c77SSepherosa Ziehau 
105215516c77SSepherosa Ziehau static int
105315516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc)
105415516c77SSepherosa Ziehau {
105515516c77SSepherosa Ziehau 	int error;
105615516c77SSepherosa Ziehau 
105715516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
105815516c77SSepherosa Ziehau 
105915516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
106015516c77SSepherosa Ziehau 		return (ENXIO);
106115516c77SSepherosa Ziehau 
106215516c77SSepherosa Ziehau 	/*
106315516c77SSepherosa Ziehau 	 * Disable RSS first.
106415516c77SSepherosa Ziehau 	 *
106515516c77SSepherosa Ziehau 	 * NOTE:
106615516c77SSepherosa Ziehau 	 * Direct reconfiguration by setting the UNCHG flags does
106715516c77SSepherosa Ziehau 	 * _not_ work properly.
106815516c77SSepherosa Ziehau 	 */
106915516c77SSepherosa Ziehau 	if (bootverbose)
107015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "disable RSS\n");
107115516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE);
107215516c77SSepherosa Ziehau 	if (error) {
107315516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS disable failed\n");
107415516c77SSepherosa Ziehau 		return (error);
107515516c77SSepherosa Ziehau 	}
107615516c77SSepherosa Ziehau 
107715516c77SSepherosa Ziehau 	/*
107815516c77SSepherosa Ziehau 	 * Reenable the RSS w/ the updated RSS key or indirect
107915516c77SSepherosa Ziehau 	 * table.
108015516c77SSepherosa Ziehau 	 */
108115516c77SSepherosa Ziehau 	if (bootverbose)
108215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "reconfig RSS\n");
108315516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
108415516c77SSepherosa Ziehau 	if (error) {
108515516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS reconfig failed\n");
108615516c77SSepherosa Ziehau 		return (error);
108715516c77SSepherosa Ziehau 	}
108815516c77SSepherosa Ziehau 	return (0);
108915516c77SSepherosa Ziehau }
109015516c77SSepherosa Ziehau 
109115516c77SSepherosa Ziehau static void
1092afd4971bSSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc)
109315516c77SSepherosa Ziehau {
109415516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
1095afd4971bSSepherosa Ziehau 	int i, nchan;
109615516c77SSepherosa Ziehau 
1097afd4971bSSepherosa Ziehau 	nchan = sc->hn_rx_ring_inuse;
109815516c77SSepherosa Ziehau 	KASSERT(nchan > 1, ("invalid # of channels %d", nchan));
109915516c77SSepherosa Ziehau 
110015516c77SSepherosa Ziehau 	/*
110115516c77SSepherosa Ziehau 	 * Check indirect table to make sure that all channels in it
110215516c77SSepherosa Ziehau 	 * can be used.
110315516c77SSepherosa Ziehau 	 */
110415516c77SSepherosa Ziehau 	for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
110515516c77SSepherosa Ziehau 		if (rss->rss_ind[i] >= nchan) {
110615516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp,
110715516c77SSepherosa Ziehau 			    "RSS indirect table %d fixup: %u -> %d\n",
110815516c77SSepherosa Ziehau 			    i, rss->rss_ind[i], nchan - 1);
110915516c77SSepherosa Ziehau 			rss->rss_ind[i] = nchan - 1;
111015516c77SSepherosa Ziehau 		}
111115516c77SSepherosa Ziehau 	}
111215516c77SSepherosa Ziehau }
111315516c77SSepherosa Ziehau 
111415516c77SSepherosa Ziehau static int
111515516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused)
111615516c77SSepherosa Ziehau {
111715516c77SSepherosa Ziehau 
111815516c77SSepherosa Ziehau 	return EOPNOTSUPP;
111915516c77SSepherosa Ziehau }
112015516c77SSepherosa Ziehau 
112115516c77SSepherosa Ziehau static void
112215516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
112315516c77SSepherosa Ziehau {
112415516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
112515516c77SSepherosa Ziehau 
112615516c77SSepherosa Ziehau 	ifmr->ifm_status = IFM_AVALID;
112715516c77SSepherosa Ziehau 	ifmr->ifm_active = IFM_ETHER;
112815516c77SSepherosa Ziehau 
112915516c77SSepherosa Ziehau 	if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) {
113015516c77SSepherosa Ziehau 		ifmr->ifm_active |= IFM_NONE;
113115516c77SSepherosa Ziehau 		return;
113215516c77SSepherosa Ziehau 	}
113315516c77SSepherosa Ziehau 	ifmr->ifm_status |= IFM_ACTIVE;
113415516c77SSepherosa Ziehau 	ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
113515516c77SSepherosa Ziehau }
113615516c77SSepherosa Ziehau 
11375bdfd3fdSDexuan Cui static void
1138962f0357SSepherosa Ziehau hn_rxvf_set_task(void *xarg, int pending __unused)
11395bdfd3fdSDexuan Cui {
1140962f0357SSepherosa Ziehau 	struct hn_rxvf_setarg *arg = xarg;
11415bdfd3fdSDexuan Cui 
1142962f0357SSepherosa Ziehau 	arg->rxr->hn_rxvf_ifp = arg->vf_ifp;
11435bdfd3fdSDexuan Cui }
11445bdfd3fdSDexuan Cui 
11455bdfd3fdSDexuan Cui static void
1146962f0357SSepherosa Ziehau hn_rxvf_set(struct hn_softc *sc, struct ifnet *vf_ifp)
11475bdfd3fdSDexuan Cui {
11485bdfd3fdSDexuan Cui 	struct hn_rx_ring *rxr;
1149962f0357SSepherosa Ziehau 	struct hn_rxvf_setarg arg;
11505bdfd3fdSDexuan Cui 	struct task task;
11515bdfd3fdSDexuan Cui 	int i;
11525bdfd3fdSDexuan Cui 
11535bdfd3fdSDexuan Cui 	HN_LOCK_ASSERT(sc);
11545bdfd3fdSDexuan Cui 
1155962f0357SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_rxvf_set_task, &arg);
11565bdfd3fdSDexuan Cui 
11575bdfd3fdSDexuan Cui 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
11585bdfd3fdSDexuan Cui 		rxr = &sc->hn_rx_ring[i];
11595bdfd3fdSDexuan Cui 
11605bdfd3fdSDexuan Cui 		if (i < sc->hn_rx_ring_inuse) {
1161962f0357SSepherosa Ziehau 			arg.rxr = rxr;
1162962f0357SSepherosa Ziehau 			arg.vf_ifp = vf_ifp;
11635bdfd3fdSDexuan Cui 			vmbus_chan_run_task(rxr->hn_chan, &task);
11645bdfd3fdSDexuan Cui 		} else {
1165962f0357SSepherosa Ziehau 			rxr->hn_rxvf_ifp = vf_ifp;
11665bdfd3fdSDexuan Cui 		}
11675bdfd3fdSDexuan Cui 	}
11685bdfd3fdSDexuan Cui }
11695bdfd3fdSDexuan Cui 
1170962f0357SSepherosa Ziehau static bool
1171499c3e17SSepherosa Ziehau hn_ismyvf(const struct hn_softc *sc, const struct ifnet *ifp)
1172499c3e17SSepherosa Ziehau {
1173499c3e17SSepherosa Ziehau 	const struct ifnet *hn_ifp;
1174499c3e17SSepherosa Ziehau 
1175499c3e17SSepherosa Ziehau 	hn_ifp = sc->hn_ifp;
1176499c3e17SSepherosa Ziehau 
1177499c3e17SSepherosa Ziehau 	if (ifp == hn_ifp)
1178499c3e17SSepherosa Ziehau 		return (false);
1179499c3e17SSepherosa Ziehau 
1180499c3e17SSepherosa Ziehau 	if (ifp->if_alloctype != IFT_ETHER)
1181499c3e17SSepherosa Ziehau 		return (false);
1182499c3e17SSepherosa Ziehau 
1183499c3e17SSepherosa Ziehau 	/* Ignore lagg/vlan interfaces */
1184499c3e17SSepherosa Ziehau 	if (strcmp(ifp->if_dname, "lagg") == 0 ||
1185499c3e17SSepherosa Ziehau 	    strcmp(ifp->if_dname, "vlan") == 0)
1186499c3e17SSepherosa Ziehau 		return (false);
1187499c3e17SSepherosa Ziehau 
1188d76fb49fSDexuan Cui 	/*
1189d76fb49fSDexuan Cui 	 * During detach events ifp->if_addr might be NULL.
1190d76fb49fSDexuan Cui 	 * Make sure the bcmp() below doesn't panic on that:
1191d76fb49fSDexuan Cui 	 */
1192d76fb49fSDexuan Cui 	if (ifp->if_addr == NULL || hn_ifp->if_addr == NULL)
1193d76fb49fSDexuan Cui 		return (false);
1194d76fb49fSDexuan Cui 
1195499c3e17SSepherosa Ziehau 	if (bcmp(IF_LLADDR(ifp), IF_LLADDR(hn_ifp), ETHER_ADDR_LEN) != 0)
1196499c3e17SSepherosa Ziehau 		return (false);
1197499c3e17SSepherosa Ziehau 
1198499c3e17SSepherosa Ziehau 	return (true);
1199499c3e17SSepherosa Ziehau }
1200499c3e17SSepherosa Ziehau 
12015bdfd3fdSDexuan Cui static void
1202962f0357SSepherosa Ziehau hn_rxvf_change(struct hn_softc *sc, struct ifnet *ifp, bool rxvf)
12035bdfd3fdSDexuan Cui {
12045bdfd3fdSDexuan Cui 	struct ifnet *hn_ifp;
12055bdfd3fdSDexuan Cui 
12065bdfd3fdSDexuan Cui 	HN_LOCK(sc);
12075bdfd3fdSDexuan Cui 
12085bdfd3fdSDexuan Cui 	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
12095bdfd3fdSDexuan Cui 		goto out;
12105bdfd3fdSDexuan Cui 
1211499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1212499c3e17SSepherosa Ziehau 		goto out;
12135bdfd3fdSDexuan Cui 	hn_ifp = sc->hn_ifp;
12145bdfd3fdSDexuan Cui 
1215962f0357SSepherosa Ziehau 	if (rxvf) {
1216962f0357SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_RXVF)
12175bdfd3fdSDexuan Cui 			goto out;
12185bdfd3fdSDexuan Cui 
1219962f0357SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_RXVF;
12205bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
12215bdfd3fdSDexuan Cui 	} else {
1222962f0357SSepherosa Ziehau 		if (!(sc->hn_flags & HN_FLAG_RXVF))
12235bdfd3fdSDexuan Cui 			goto out;
12245bdfd3fdSDexuan Cui 
1225962f0357SSepherosa Ziehau 		sc->hn_flags &= ~HN_FLAG_RXVF;
1226499c3e17SSepherosa Ziehau 		if (hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
12275bdfd3fdSDexuan Cui 			hn_rxfilter_config(sc);
12285bdfd3fdSDexuan Cui 		else
12295bdfd3fdSDexuan Cui 			hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE);
12305bdfd3fdSDexuan Cui 	}
12315bdfd3fdSDexuan Cui 
12325bdfd3fdSDexuan Cui 	hn_nvs_set_datapath(sc,
12339c6cae24SSepherosa Ziehau 	    rxvf ? HN_NVS_DATAPATH_VF : HN_NVS_DATAPATH_SYNTH);
12345bdfd3fdSDexuan Cui 
1235962f0357SSepherosa Ziehau 	hn_rxvf_set(sc, rxvf ? ifp : NULL);
12365bdfd3fdSDexuan Cui 
1237962f0357SSepherosa Ziehau 	if (rxvf) {
1238642ec226SSepherosa Ziehau 		hn_vf_rss_fixup(sc, true);
12395bdfd3fdSDexuan Cui 		hn_suspend_mgmt(sc);
12405bdfd3fdSDexuan Cui 		sc->hn_link_flags &=
12415bdfd3fdSDexuan Cui 		    ~(HN_LINK_FLAG_LINKUP | HN_LINK_FLAG_NETCHG);
1242499c3e17SSepherosa Ziehau 		if_link_state_change(hn_ifp, LINK_STATE_DOWN);
12435bdfd3fdSDexuan Cui 	} else {
1244642ec226SSepherosa Ziehau 		hn_vf_rss_restore(sc);
12455bdfd3fdSDexuan Cui 		hn_resume_mgmt(sc);
12465bdfd3fdSDexuan Cui 	}
12475bdfd3fdSDexuan Cui 
1248962f0357SSepherosa Ziehau 	devctl_notify("HYPERV_NIC_VF", hn_ifp->if_xname,
1249962f0357SSepherosa Ziehau 	    rxvf ? "VF_UP" : "VF_DOWN", NULL);
125033408a34SDexuan Cui 
1251962f0357SSepherosa Ziehau 	if (bootverbose) {
1252962f0357SSepherosa Ziehau 		if_printf(hn_ifp, "datapath is switched %s %s\n",
1253962f0357SSepherosa Ziehau 		    rxvf ? "to" : "from", ifp->if_xname);
1254962f0357SSepherosa Ziehau 	}
12555bdfd3fdSDexuan Cui out:
12565bdfd3fdSDexuan Cui 	HN_UNLOCK(sc);
12575bdfd3fdSDexuan Cui }
12585bdfd3fdSDexuan Cui 
12595bdfd3fdSDexuan Cui static void
12605bdfd3fdSDexuan Cui hn_ifnet_event(void *arg, struct ifnet *ifp, int event)
12615bdfd3fdSDexuan Cui {
1262962f0357SSepherosa Ziehau 
12635bdfd3fdSDexuan Cui 	if (event != IFNET_EVENT_UP && event != IFNET_EVENT_DOWN)
12645bdfd3fdSDexuan Cui 		return;
1265962f0357SSepherosa Ziehau 	hn_rxvf_change(arg, ifp, event == IFNET_EVENT_UP);
12665bdfd3fdSDexuan Cui }
12675bdfd3fdSDexuan Cui 
12685bdfd3fdSDexuan Cui static void
12695bdfd3fdSDexuan Cui hn_ifaddr_event(void *arg, struct ifnet *ifp)
12705bdfd3fdSDexuan Cui {
1271962f0357SSepherosa Ziehau 
1272962f0357SSepherosa Ziehau 	hn_rxvf_change(arg, ifp, ifp->if_flags & IFF_UP);
12735bdfd3fdSDexuan Cui }
12745bdfd3fdSDexuan Cui 
12759c6cae24SSepherosa Ziehau static int
12769c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetcaps(struct hn_softc *sc, struct ifreq *ifr)
12779c6cae24SSepherosa Ziehau {
12789c6cae24SSepherosa Ziehau 	struct ifnet *ifp, *vf_ifp;
12799c6cae24SSepherosa Ziehau 	uint64_t tmp;
12809c6cae24SSepherosa Ziehau 	int error;
12819c6cae24SSepherosa Ziehau 
12829c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
12839c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
12849c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
12859c6cae24SSepherosa Ziehau 
12869c6cae24SSepherosa Ziehau 	/*
12879c6cae24SSepherosa Ziehau 	 * Fix up requested capabilities w/ supported capabilities,
12889c6cae24SSepherosa Ziehau 	 * since the supported capabilities could have been changed.
12899c6cae24SSepherosa Ziehau 	 */
12909c6cae24SSepherosa Ziehau 	ifr->ifr_reqcap &= ifp->if_capabilities;
12919c6cae24SSepherosa Ziehau 	/* Pass SIOCSIFCAP to VF. */
12929c6cae24SSepherosa Ziehau 	error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFCAP, (caddr_t)ifr);
12939c6cae24SSepherosa Ziehau 
12949c6cae24SSepherosa Ziehau 	/*
12959c6cae24SSepherosa Ziehau 	 * NOTE:
12969c6cae24SSepherosa Ziehau 	 * The error will be propagated to the callers, however, it
12979c6cae24SSepherosa Ziehau 	 * is _not_ useful here.
12989c6cae24SSepherosa Ziehau 	 */
12999c6cae24SSepherosa Ziehau 
13009c6cae24SSepherosa Ziehau 	/*
13019c6cae24SSepherosa Ziehau 	 * Merge VF's enabled capabilities.
13029c6cae24SSepherosa Ziehau 	 */
13039c6cae24SSepherosa Ziehau 	ifp->if_capenable = vf_ifp->if_capenable & ifp->if_capabilities;
13049c6cae24SSepherosa Ziehau 
13059c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & HN_CSUM_IP_HWASSIST(sc);
13069c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TXCSUM)
13079c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
13089c6cae24SSepherosa Ziehau 	else
13099c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
13109c6cae24SSepherosa Ziehau 
13119c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & HN_CSUM_IP6_HWASSIST(sc);
13129c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
13139c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
13149c6cae24SSepherosa Ziehau 	else
13159c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
13169c6cae24SSepherosa Ziehau 
13179c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & CSUM_IP_TSO;
13189c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TSO4)
13199c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
13209c6cae24SSepherosa Ziehau 	else
13219c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
13229c6cae24SSepherosa Ziehau 
13239c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & CSUM_IP6_TSO;
13249c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TSO6)
13259c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
13269c6cae24SSepherosa Ziehau 	else
13279c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
13289c6cae24SSepherosa Ziehau 
13299c6cae24SSepherosa Ziehau 	return (error);
13309c6cae24SSepherosa Ziehau }
13319c6cae24SSepherosa Ziehau 
13329c6cae24SSepherosa Ziehau static int
13339c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetflags(struct hn_softc *sc)
13349c6cae24SSepherosa Ziehau {
13359c6cae24SSepherosa Ziehau 	struct ifnet *vf_ifp;
13369c6cae24SSepherosa Ziehau 	struct ifreq ifr;
13379c6cae24SSepherosa Ziehau 
13389c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
13399c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
13409c6cae24SSepherosa Ziehau 
13419c6cae24SSepherosa Ziehau 	memset(&ifr, 0, sizeof(ifr));
13429c6cae24SSepherosa Ziehau 	strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
13439c6cae24SSepherosa Ziehau 	ifr.ifr_flags = vf_ifp->if_flags & 0xffff;
13449c6cae24SSepherosa Ziehau 	ifr.ifr_flagshigh = vf_ifp->if_flags >> 16;
13459c6cae24SSepherosa Ziehau 	return (vf_ifp->if_ioctl(vf_ifp, SIOCSIFFLAGS, (caddr_t)&ifr));
13469c6cae24SSepherosa Ziehau }
13479c6cae24SSepherosa Ziehau 
13489c6cae24SSepherosa Ziehau static void
13499c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(struct hn_softc *sc)
13509c6cae24SSepherosa Ziehau {
13519c6cae24SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
13529c6cae24SSepherosa Ziehau 	int allmulti = 0;
13539c6cae24SSepherosa Ziehau 
13549c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
13559c6cae24SSepherosa Ziehau 
13569c6cae24SSepherosa Ziehau 	/* XXX vlan(4) style mcast addr maintenance */
1357d7c5a620SMatt Macy 	if (!CK_STAILQ_EMPTY(&ifp->if_multiaddrs))
13589c6cae24SSepherosa Ziehau 		allmulti = IFF_ALLMULTI;
13599c6cae24SSepherosa Ziehau 
13609c6cae24SSepherosa Ziehau 	/* Always set the VF's if_flags */
13619c6cae24SSepherosa Ziehau 	sc->hn_vf_ifp->if_flags = ifp->if_flags | allmulti;
13629c6cae24SSepherosa Ziehau }
13639c6cae24SSepherosa Ziehau 
13649c6cae24SSepherosa Ziehau static void
13659c6cae24SSepherosa Ziehau hn_xpnt_vf_input(struct ifnet *vf_ifp, struct mbuf *m)
13669c6cae24SSepherosa Ziehau {
13679c6cae24SSepherosa Ziehau 	struct rm_priotracker pt;
13689c6cae24SSepherosa Ziehau 	struct ifnet *hn_ifp = NULL;
13699c6cae24SSepherosa Ziehau 	struct mbuf *mn;
13709c6cae24SSepherosa Ziehau 
13719c6cae24SSepherosa Ziehau 	/*
13729c6cae24SSepherosa Ziehau 	 * XXX racy, if hn(4) ever detached.
13739c6cae24SSepherosa Ziehau 	 */
13749c6cae24SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
13759c6cae24SSepherosa Ziehau 	if (vf_ifp->if_index < hn_vfmap_size)
13769c6cae24SSepherosa Ziehau 		hn_ifp = hn_vfmap[vf_ifp->if_index];
13779c6cae24SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
13789c6cae24SSepherosa Ziehau 
13799c6cae24SSepherosa Ziehau 	if (hn_ifp != NULL) {
13809c6cae24SSepherosa Ziehau 		for (mn = m; mn != NULL; mn = mn->m_nextpkt) {
13813bed4e54SSepherosa Ziehau 			/*
13823bed4e54SSepherosa Ziehau 			 * Allow tapping on the VF.
13833bed4e54SSepherosa Ziehau 			 */
13849c6cae24SSepherosa Ziehau 			ETHER_BPF_MTAP(vf_ifp, mn);
13853bed4e54SSepherosa Ziehau 
13863bed4e54SSepherosa Ziehau 			/*
13873bed4e54SSepherosa Ziehau 			 * Update VF stats.
13883bed4e54SSepherosa Ziehau 			 */
13893bed4e54SSepherosa Ziehau 			if ((vf_ifp->if_capenable & IFCAP_HWSTATS) == 0) {
13903bed4e54SSepherosa Ziehau 				if_inc_counter(vf_ifp, IFCOUNTER_IBYTES,
13913bed4e54SSepherosa Ziehau 				    mn->m_pkthdr.len);
13923bed4e54SSepherosa Ziehau 			}
13933bed4e54SSepherosa Ziehau 			/*
13943bed4e54SSepherosa Ziehau 			 * XXX IFCOUNTER_IMCAST
13953bed4e54SSepherosa Ziehau 			 * This stat updating is kinda invasive, since it
13963bed4e54SSepherosa Ziehau 			 * requires two checks on the mbuf: the length check
13973bed4e54SSepherosa Ziehau 			 * and the ethernet header check.  As of this write,
13983bed4e54SSepherosa Ziehau 			 * all multicast packets go directly to hn(4), which
13993bed4e54SSepherosa Ziehau 			 * makes imcast stat updating in the VF a try in vian.
14003bed4e54SSepherosa Ziehau 			 */
14013bed4e54SSepherosa Ziehau 
14023bed4e54SSepherosa Ziehau 			/*
14033bed4e54SSepherosa Ziehau 			 * Fix up rcvif and increase hn(4)'s ipackets.
14043bed4e54SSepherosa Ziehau 			 */
14059c6cae24SSepherosa Ziehau 			mn->m_pkthdr.rcvif = hn_ifp;
14069c6cae24SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1);
14079c6cae24SSepherosa Ziehau 		}
14083bed4e54SSepherosa Ziehau 		/*
14093bed4e54SSepherosa Ziehau 		 * Go through hn(4)'s if_input.
14103bed4e54SSepherosa Ziehau 		 */
14119c6cae24SSepherosa Ziehau 		hn_ifp->if_input(hn_ifp, m);
14129c6cae24SSepherosa Ziehau 	} else {
14139c6cae24SSepherosa Ziehau 		/*
14149c6cae24SSepherosa Ziehau 		 * In the middle of the transition; free this
14159c6cae24SSepherosa Ziehau 		 * mbuf chain.
14169c6cae24SSepherosa Ziehau 		 */
14179c6cae24SSepherosa Ziehau 		while (m != NULL) {
14189c6cae24SSepherosa Ziehau 			mn = m->m_nextpkt;
14199c6cae24SSepherosa Ziehau 			m->m_nextpkt = NULL;
14209c6cae24SSepherosa Ziehau 			m_freem(m);
14219c6cae24SSepherosa Ziehau 			m = mn;
14229c6cae24SSepherosa Ziehau 		}
14239c6cae24SSepherosa Ziehau 	}
14249c6cae24SSepherosa Ziehau }
14259c6cae24SSepherosa Ziehau 
14269c6cae24SSepherosa Ziehau static void
14279c6cae24SSepherosa Ziehau hn_mtu_change_fixup(struct hn_softc *sc)
14289c6cae24SSepherosa Ziehau {
14299c6cae24SSepherosa Ziehau 	struct ifnet *ifp;
14309c6cae24SSepherosa Ziehau 
14319c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
14329c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
14339c6cae24SSepherosa Ziehau 
14349c6cae24SSepherosa Ziehau 	hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu);
14359c6cae24SSepherosa Ziehau #if __FreeBSD_version >= 1100099
14369c6cae24SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_lro.lro_length_lim < HN_LRO_LENLIM_MIN(ifp))
14379c6cae24SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
14389c6cae24SSepherosa Ziehau #endif
14399c6cae24SSepherosa Ziehau }
14409c6cae24SSepherosa Ziehau 
1441642ec226SSepherosa Ziehau static uint32_t
1442642ec226SSepherosa Ziehau hn_rss_type_fromndis(uint32_t rss_hash)
1443642ec226SSepherosa Ziehau {
1444642ec226SSepherosa Ziehau 	uint32_t types = 0;
1445642ec226SSepherosa Ziehau 
1446642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_IPV4)
1447642ec226SSepherosa Ziehau 		types |= RSS_TYPE_IPV4;
1448642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_TCP_IPV4)
1449642ec226SSepherosa Ziehau 		types |= RSS_TYPE_TCP_IPV4;
1450642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_IPV6)
1451642ec226SSepherosa Ziehau 		types |= RSS_TYPE_IPV6;
1452642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_IPV6_EX)
1453642ec226SSepherosa Ziehau 		types |= RSS_TYPE_IPV6_EX;
1454642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_TCP_IPV6)
1455642ec226SSepherosa Ziehau 		types |= RSS_TYPE_TCP_IPV6;
1456642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_TCP_IPV6_EX)
1457642ec226SSepherosa Ziehau 		types |= RSS_TYPE_TCP_IPV6_EX;
14586f12c42eSSepherosa Ziehau 	if (rss_hash & NDIS_HASH_UDP_IPV4_X)
14596f12c42eSSepherosa Ziehau 		types |= RSS_TYPE_UDP_IPV4;
1460642ec226SSepherosa Ziehau 	return (types);
1461642ec226SSepherosa Ziehau }
1462642ec226SSepherosa Ziehau 
1463642ec226SSepherosa Ziehau static uint32_t
1464642ec226SSepherosa Ziehau hn_rss_type_tondis(uint32_t types)
1465642ec226SSepherosa Ziehau {
1466642ec226SSepherosa Ziehau 	uint32_t rss_hash = 0;
1467642ec226SSepherosa Ziehau 
14686f12c42eSSepherosa Ziehau 	KASSERT((types & (RSS_TYPE_UDP_IPV6 | RSS_TYPE_UDP_IPV6_EX)) == 0,
14696f12c42eSSepherosa Ziehau 	    ("UDP6 and UDP6EX are not supported"));
1470642ec226SSepherosa Ziehau 
1471642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_IPV4)
1472642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_IPV4;
1473642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_TCP_IPV4)
1474642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_TCP_IPV4;
1475642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_IPV6)
1476642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_IPV6;
1477642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_IPV6_EX)
1478642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_IPV6_EX;
1479642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_TCP_IPV6)
1480642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_TCP_IPV6;
1481642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_TCP_IPV6_EX)
1482642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_TCP_IPV6_EX;
14836f12c42eSSepherosa Ziehau 	if (types & RSS_TYPE_UDP_IPV4)
14846f12c42eSSepherosa Ziehau 		rss_hash |= NDIS_HASH_UDP_IPV4_X;
1485642ec226SSepherosa Ziehau 	return (rss_hash);
1486642ec226SSepherosa Ziehau }
1487642ec226SSepherosa Ziehau 
1488642ec226SSepherosa Ziehau static void
1489642ec226SSepherosa Ziehau hn_rss_mbuf_hash(struct hn_softc *sc, uint32_t mbuf_hash)
1490642ec226SSepherosa Ziehau {
1491642ec226SSepherosa Ziehau 	int i;
1492642ec226SSepherosa Ziehau 
1493642ec226SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1494642ec226SSepherosa Ziehau 
1495642ec226SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1496642ec226SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_mbuf_hash = mbuf_hash;
1497642ec226SSepherosa Ziehau }
1498642ec226SSepherosa Ziehau 
1499642ec226SSepherosa Ziehau static void
1500642ec226SSepherosa Ziehau hn_vf_rss_fixup(struct hn_softc *sc, bool reconf)
1501642ec226SSepherosa Ziehau {
1502642ec226SSepherosa Ziehau 	struct ifnet *ifp, *vf_ifp;
1503642ec226SSepherosa Ziehau 	struct ifrsshash ifrh;
1504642ec226SSepherosa Ziehau 	struct ifrsskey ifrk;
1505642ec226SSepherosa Ziehau 	int error;
1506642ec226SSepherosa Ziehau 	uint32_t my_types, diff_types, mbuf_types = 0;
1507642ec226SSepherosa Ziehau 
1508642ec226SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1509642ec226SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
1510642ec226SSepherosa Ziehau 	    ("%s: synthetic parts are not attached", sc->hn_ifp->if_xname));
1511642ec226SSepherosa Ziehau 
1512642ec226SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
1513642ec226SSepherosa Ziehau 		/* No RSS on synthetic parts; done. */
1514642ec226SSepherosa Ziehau 		return;
1515642ec226SSepherosa Ziehau 	}
1516642ec226SSepherosa Ziehau 	if ((sc->hn_rss_hcap & NDIS_HASH_FUNCTION_TOEPLITZ) == 0) {
1517642ec226SSepherosa Ziehau 		/* Synthetic parts do not support Toeplitz; done. */
1518642ec226SSepherosa Ziehau 		return;
1519642ec226SSepherosa Ziehau 	}
1520642ec226SSepherosa Ziehau 
1521642ec226SSepherosa Ziehau 	ifp = sc->hn_ifp;
1522642ec226SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
1523642ec226SSepherosa Ziehau 
1524642ec226SSepherosa Ziehau 	/*
1525642ec226SSepherosa Ziehau 	 * Extract VF's RSS key.  Only 40 bytes key for Toeplitz is
1526642ec226SSepherosa Ziehau 	 * supported.
1527642ec226SSepherosa Ziehau 	 */
1528642ec226SSepherosa Ziehau 	memset(&ifrk, 0, sizeof(ifrk));
1529642ec226SSepherosa Ziehau 	strlcpy(ifrk.ifrk_name, vf_ifp->if_xname, sizeof(ifrk.ifrk_name));
1530642ec226SSepherosa Ziehau 	error = vf_ifp->if_ioctl(vf_ifp, SIOCGIFRSSKEY, (caddr_t)&ifrk);
1531642ec226SSepherosa Ziehau 	if (error) {
1532a3b413afSHans Petter Selasky 		if_printf(ifp, "%s SIOCGIFRSSKEY failed: %d\n",
1533642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, error);
1534642ec226SSepherosa Ziehau 		goto done;
1535642ec226SSepherosa Ziehau 	}
1536642ec226SSepherosa Ziehau 	if (ifrk.ifrk_func != RSS_FUNC_TOEPLITZ) {
1537642ec226SSepherosa Ziehau 		if_printf(ifp, "%s RSS function %u is not Toeplitz\n",
1538642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, ifrk.ifrk_func);
1539642ec226SSepherosa Ziehau 		goto done;
1540642ec226SSepherosa Ziehau 	}
1541642ec226SSepherosa Ziehau 	if (ifrk.ifrk_keylen != NDIS_HASH_KEYSIZE_TOEPLITZ) {
1542642ec226SSepherosa Ziehau 		if_printf(ifp, "%s invalid RSS Toeplitz key length %d\n",
1543642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, ifrk.ifrk_keylen);
1544642ec226SSepherosa Ziehau 		goto done;
1545642ec226SSepherosa Ziehau 	}
1546642ec226SSepherosa Ziehau 
1547642ec226SSepherosa Ziehau 	/*
1548642ec226SSepherosa Ziehau 	 * Extract VF's RSS hash.  Only Toeplitz is supported.
1549642ec226SSepherosa Ziehau 	 */
1550642ec226SSepherosa Ziehau 	memset(&ifrh, 0, sizeof(ifrh));
1551642ec226SSepherosa Ziehau 	strlcpy(ifrh.ifrh_name, vf_ifp->if_xname, sizeof(ifrh.ifrh_name));
1552642ec226SSepherosa Ziehau 	error = vf_ifp->if_ioctl(vf_ifp, SIOCGIFRSSHASH, (caddr_t)&ifrh);
1553642ec226SSepherosa Ziehau 	if (error) {
1554642ec226SSepherosa Ziehau 		if_printf(ifp, "%s SIOCGRSSHASH failed: %d\n",
1555642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, error);
1556642ec226SSepherosa Ziehau 		goto done;
1557642ec226SSepherosa Ziehau 	}
1558642ec226SSepherosa Ziehau 	if (ifrh.ifrh_func != RSS_FUNC_TOEPLITZ) {
1559642ec226SSepherosa Ziehau 		if_printf(ifp, "%s RSS function %u is not Toeplitz\n",
1560642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, ifrh.ifrh_func);
1561642ec226SSepherosa Ziehau 		goto done;
1562642ec226SSepherosa Ziehau 	}
1563642ec226SSepherosa Ziehau 
1564642ec226SSepherosa Ziehau 	my_types = hn_rss_type_fromndis(sc->hn_rss_hcap);
1565642ec226SSepherosa Ziehau 	if ((ifrh.ifrh_types & my_types) == 0) {
1566642ec226SSepherosa Ziehau 		/* This disables RSS; ignore it then */
1567642ec226SSepherosa Ziehau 		if_printf(ifp, "%s intersection of RSS types failed.  "
1568642ec226SSepherosa Ziehau 		    "VF %#x, mine %#x\n", vf_ifp->if_xname,
1569642ec226SSepherosa Ziehau 		    ifrh.ifrh_types, my_types);
1570642ec226SSepherosa Ziehau 		goto done;
1571642ec226SSepherosa Ziehau 	}
1572642ec226SSepherosa Ziehau 
1573642ec226SSepherosa Ziehau 	diff_types = my_types ^ ifrh.ifrh_types;
1574642ec226SSepherosa Ziehau 	my_types &= ifrh.ifrh_types;
1575642ec226SSepherosa Ziehau 	mbuf_types = my_types;
1576642ec226SSepherosa Ziehau 
1577642ec226SSepherosa Ziehau 	/*
1578642ec226SSepherosa Ziehau 	 * Detect RSS hash value/type confliction.
1579642ec226SSepherosa Ziehau 	 *
1580642ec226SSepherosa Ziehau 	 * NOTE:
1581642ec226SSepherosa Ziehau 	 * We don't disable the hash type, but stop delivery the hash
1582642ec226SSepherosa Ziehau 	 * value/type through mbufs on RX path.
15836f12c42eSSepherosa Ziehau 	 *
15846f12c42eSSepherosa Ziehau 	 * XXX If HN_CAP_UDPHASH is set in hn_caps, then UDP 4-tuple
15856f12c42eSSepherosa Ziehau 	 * hash is delivered with type of TCP_IPV4.  This means if
15866f12c42eSSepherosa Ziehau 	 * UDP_IPV4 is enabled, then TCP_IPV4 should be forced, at
15876f12c42eSSepherosa Ziehau 	 * least to hn_mbuf_hash.  However, given that _all_ of the
15886f12c42eSSepherosa Ziehau 	 * NICs implement TCP_IPV4, this will _not_ impose any issues
15896f12c42eSSepherosa Ziehau 	 * here.
1590642ec226SSepherosa Ziehau 	 */
1591642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_IPV4) &&
1592642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types &
1593642ec226SSepherosa Ziehau 	     (RSS_TYPE_TCP_IPV4 | RSS_TYPE_UDP_IPV4))) {
1594642ec226SSepherosa Ziehau 		/* Conflict; disable IPV4 hash type/value delivery. */
1595642ec226SSepherosa Ziehau 		if_printf(ifp, "disable IPV4 mbuf hash delivery\n");
1596642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_IPV4;
1597642ec226SSepherosa Ziehau 	}
1598642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_IPV6) &&
1599642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types &
1600642ec226SSepherosa Ziehau 	     (RSS_TYPE_TCP_IPV6 | RSS_TYPE_UDP_IPV6 |
1601642ec226SSepherosa Ziehau 	      RSS_TYPE_TCP_IPV6_EX | RSS_TYPE_UDP_IPV6_EX |
1602642ec226SSepherosa Ziehau 	      RSS_TYPE_IPV6_EX))) {
1603642ec226SSepherosa Ziehau 		/* Conflict; disable IPV6 hash type/value delivery. */
1604642ec226SSepherosa Ziehau 		if_printf(ifp, "disable IPV6 mbuf hash delivery\n");
1605642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_IPV6;
1606642ec226SSepherosa Ziehau 	}
1607642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_IPV6_EX) &&
1608642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types &
1609642ec226SSepherosa Ziehau 	     (RSS_TYPE_TCP_IPV6 | RSS_TYPE_UDP_IPV6 |
1610642ec226SSepherosa Ziehau 	      RSS_TYPE_TCP_IPV6_EX | RSS_TYPE_UDP_IPV6_EX |
1611642ec226SSepherosa Ziehau 	      RSS_TYPE_IPV6))) {
1612642ec226SSepherosa Ziehau 		/* Conflict; disable IPV6_EX hash type/value delivery. */
1613642ec226SSepherosa Ziehau 		if_printf(ifp, "disable IPV6_EX mbuf hash delivery\n");
1614642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_IPV6_EX;
1615642ec226SSepherosa Ziehau 	}
1616642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_TCP_IPV6) &&
1617642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_TCP_IPV6_EX)) {
1618642ec226SSepherosa Ziehau 		/* Conflict; disable TCP_IPV6 hash type/value delivery. */
1619642ec226SSepherosa Ziehau 		if_printf(ifp, "disable TCP_IPV6 mbuf hash delivery\n");
1620642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_TCP_IPV6;
1621642ec226SSepherosa Ziehau 	}
1622642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_TCP_IPV6_EX) &&
1623642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_TCP_IPV6)) {
1624642ec226SSepherosa Ziehau 		/* Conflict; disable TCP_IPV6_EX hash type/value delivery. */
1625642ec226SSepherosa Ziehau 		if_printf(ifp, "disable TCP_IPV6_EX mbuf hash delivery\n");
1626642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_TCP_IPV6_EX;
1627642ec226SSepherosa Ziehau 	}
1628642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_UDP_IPV6) &&
1629642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_UDP_IPV6_EX)) {
1630642ec226SSepherosa Ziehau 		/* Conflict; disable UDP_IPV6 hash type/value delivery. */
1631642ec226SSepherosa Ziehau 		if_printf(ifp, "disable UDP_IPV6 mbuf hash delivery\n");
1632642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_UDP_IPV6;
1633642ec226SSepherosa Ziehau 	}
1634642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_UDP_IPV6_EX) &&
1635642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_UDP_IPV6)) {
1636642ec226SSepherosa Ziehau 		/* Conflict; disable UDP_IPV6_EX hash type/value delivery. */
1637642ec226SSepherosa Ziehau 		if_printf(ifp, "disable UDP_IPV6_EX mbuf hash delivery\n");
1638642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_UDP_IPV6_EX;
1639642ec226SSepherosa Ziehau 	}
1640642ec226SSepherosa Ziehau 
1641642ec226SSepherosa Ziehau 	/*
1642642ec226SSepherosa Ziehau 	 * Indirect table does not matter.
1643642ec226SSepherosa Ziehau 	 */
1644642ec226SSepherosa Ziehau 
1645642ec226SSepherosa Ziehau 	sc->hn_rss_hash = (sc->hn_rss_hcap & NDIS_HASH_FUNCTION_MASK) |
1646642ec226SSepherosa Ziehau 	    hn_rss_type_tondis(my_types);
1647642ec226SSepherosa Ziehau 	memcpy(sc->hn_rss.rss_key, ifrk.ifrk_key, sizeof(sc->hn_rss.rss_key));
1648642ec226SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
1649642ec226SSepherosa Ziehau 
1650642ec226SSepherosa Ziehau 	if (reconf) {
1651642ec226SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
1652642ec226SSepherosa Ziehau 		if (error) {
1653642ec226SSepherosa Ziehau 			/* XXX roll-back? */
1654642ec226SSepherosa Ziehau 			if_printf(ifp, "hn_rss_reconfig failed: %d\n", error);
1655642ec226SSepherosa Ziehau 			/* XXX keep going. */
1656642ec226SSepherosa Ziehau 		}
1657642ec226SSepherosa Ziehau 	}
1658642ec226SSepherosa Ziehau done:
1659642ec226SSepherosa Ziehau 	/* Hash deliverability for mbufs. */
1660642ec226SSepherosa Ziehau 	hn_rss_mbuf_hash(sc, hn_rss_type_tondis(mbuf_types));
1661642ec226SSepherosa Ziehau }
1662642ec226SSepherosa Ziehau 
1663642ec226SSepherosa Ziehau static void
1664642ec226SSepherosa Ziehau hn_vf_rss_restore(struct hn_softc *sc)
1665642ec226SSepherosa Ziehau {
1666642ec226SSepherosa Ziehau 
1667642ec226SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1668642ec226SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
1669642ec226SSepherosa Ziehau 	    ("%s: synthetic parts are not attached", sc->hn_ifp->if_xname));
1670642ec226SSepherosa Ziehau 
1671642ec226SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1)
1672642ec226SSepherosa Ziehau 		goto done;
1673642ec226SSepherosa Ziehau 
1674642ec226SSepherosa Ziehau 	/*
1675642ec226SSepherosa Ziehau 	 * Restore hash types.  Key does _not_ matter.
1676642ec226SSepherosa Ziehau 	 */
1677642ec226SSepherosa Ziehau 	if (sc->hn_rss_hash != sc->hn_rss_hcap) {
1678642ec226SSepherosa Ziehau 		int error;
1679642ec226SSepherosa Ziehau 
1680642ec226SSepherosa Ziehau 		sc->hn_rss_hash = sc->hn_rss_hcap;
1681642ec226SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
1682642ec226SSepherosa Ziehau 		if (error) {
1683642ec226SSepherosa Ziehau 			if_printf(sc->hn_ifp, "hn_rss_reconfig failed: %d\n",
1684642ec226SSepherosa Ziehau 			    error);
1685642ec226SSepherosa Ziehau 			/* XXX keep going. */
1686642ec226SSepherosa Ziehau 		}
1687642ec226SSepherosa Ziehau 	}
1688642ec226SSepherosa Ziehau done:
1689642ec226SSepherosa Ziehau 	/* Hash deliverability for mbufs. */
1690642ec226SSepherosa Ziehau 	hn_rss_mbuf_hash(sc, NDIS_HASH_ALL);
1691642ec226SSepherosa Ziehau }
1692642ec226SSepherosa Ziehau 
16939c6cae24SSepherosa Ziehau static void
16949c6cae24SSepherosa Ziehau hn_xpnt_vf_setready(struct hn_softc *sc)
16959c6cae24SSepherosa Ziehau {
16969c6cae24SSepherosa Ziehau 	struct ifnet *ifp, *vf_ifp;
16979c6cae24SSepherosa Ziehau 	struct ifreq ifr;
16989c6cae24SSepherosa Ziehau 
16999c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
17009c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
17019c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
17029c6cae24SSepherosa Ziehau 
17039c6cae24SSepherosa Ziehau 	/*
17049c6cae24SSepherosa Ziehau 	 * Mark the VF ready.
17059c6cae24SSepherosa Ziehau 	 */
17069c6cae24SSepherosa Ziehau 	sc->hn_vf_rdytick = 0;
17079c6cae24SSepherosa Ziehau 
17089c6cae24SSepherosa Ziehau 	/*
17099c6cae24SSepherosa Ziehau 	 * Save information for restoration.
17109c6cae24SSepherosa Ziehau 	 */
17119c6cae24SSepherosa Ziehau 	sc->hn_saved_caps = ifp->if_capabilities;
17129c6cae24SSepherosa Ziehau 	sc->hn_saved_tsomax = ifp->if_hw_tsomax;
17139c6cae24SSepherosa Ziehau 	sc->hn_saved_tsosegcnt = ifp->if_hw_tsomaxsegcount;
17149c6cae24SSepherosa Ziehau 	sc->hn_saved_tsosegsz = ifp->if_hw_tsomaxsegsize;
17159c6cae24SSepherosa Ziehau 
17169c6cae24SSepherosa Ziehau 	/*
17179c6cae24SSepherosa Ziehau 	 * Intersect supported/enabled capabilities.
17189c6cae24SSepherosa Ziehau 	 *
17199c6cae24SSepherosa Ziehau 	 * NOTE:
17209c6cae24SSepherosa Ziehau 	 * if_hwassist is not changed here.
17219c6cae24SSepherosa Ziehau 	 */
17229c6cae24SSepherosa Ziehau 	ifp->if_capabilities &= vf_ifp->if_capabilities;
17239c6cae24SSepherosa Ziehau 	ifp->if_capenable &= ifp->if_capabilities;
17249c6cae24SSepherosa Ziehau 
17259c6cae24SSepherosa Ziehau 	/*
17269c6cae24SSepherosa Ziehau 	 * Fix TSO settings.
17279c6cae24SSepherosa Ziehau 	 */
17289c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomax > vf_ifp->if_hw_tsomax)
17299c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomax = vf_ifp->if_hw_tsomax;
17309c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomaxsegcount > vf_ifp->if_hw_tsomaxsegcount)
17319c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = vf_ifp->if_hw_tsomaxsegcount;
17329c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomaxsegsize > vf_ifp->if_hw_tsomaxsegsize)
17339c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = vf_ifp->if_hw_tsomaxsegsize;
17349c6cae24SSepherosa Ziehau 
17359c6cae24SSepherosa Ziehau 	/*
17369c6cae24SSepherosa Ziehau 	 * Change VF's enabled capabilities.
17379c6cae24SSepherosa Ziehau 	 */
17389c6cae24SSepherosa Ziehau 	memset(&ifr, 0, sizeof(ifr));
17399c6cae24SSepherosa Ziehau 	strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
17409c6cae24SSepherosa Ziehau 	ifr.ifr_reqcap = ifp->if_capenable;
17419c6cae24SSepherosa Ziehau 	hn_xpnt_vf_iocsetcaps(sc, &ifr);
17429c6cae24SSepherosa Ziehau 
17439c6cae24SSepherosa Ziehau 	if (ifp->if_mtu != ETHERMTU) {
17449c6cae24SSepherosa Ziehau 		int error;
17459c6cae24SSepherosa Ziehau 
17469c6cae24SSepherosa Ziehau 		/*
17479c6cae24SSepherosa Ziehau 		 * Change VF's MTU.
17489c6cae24SSepherosa Ziehau 		 */
17499c6cae24SSepherosa Ziehau 		memset(&ifr, 0, sizeof(ifr));
17509c6cae24SSepherosa Ziehau 		strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
17519c6cae24SSepherosa Ziehau 		ifr.ifr_mtu = ifp->if_mtu;
17529c6cae24SSepherosa Ziehau 		error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU, (caddr_t)&ifr);
17539c6cae24SSepherosa Ziehau 		if (error) {
17549c6cae24SSepherosa Ziehau 			if_printf(ifp, "%s SIOCSIFMTU %u failed\n",
17559c6cae24SSepherosa Ziehau 			    vf_ifp->if_xname, ifp->if_mtu);
17569c6cae24SSepherosa Ziehau 			if (ifp->if_mtu > ETHERMTU) {
17579c6cae24SSepherosa Ziehau 				if_printf(ifp, "change MTU to %d\n", ETHERMTU);
17589c6cae24SSepherosa Ziehau 
17599c6cae24SSepherosa Ziehau 				/*
17609c6cae24SSepherosa Ziehau 				 * XXX
17619c6cae24SSepherosa Ziehau 				 * No need to adjust the synthetic parts' MTU;
17629c6cae24SSepherosa Ziehau 				 * failure of the adjustment will cause us
17639c6cae24SSepherosa Ziehau 				 * infinite headache.
17649c6cae24SSepherosa Ziehau 				 */
17659c6cae24SSepherosa Ziehau 				ifp->if_mtu = ETHERMTU;
17669c6cae24SSepherosa Ziehau 				hn_mtu_change_fixup(sc);
17679c6cae24SSepherosa Ziehau 			}
17689c6cae24SSepherosa Ziehau 		}
17699c6cae24SSepherosa Ziehau 	}
17709c6cae24SSepherosa Ziehau }
17719c6cae24SSepherosa Ziehau 
17729c6cae24SSepherosa Ziehau static bool
17739c6cae24SSepherosa Ziehau hn_xpnt_vf_isready(struct hn_softc *sc)
17749c6cae24SSepherosa Ziehau {
17759c6cae24SSepherosa Ziehau 
17769c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
17779c6cae24SSepherosa Ziehau 
17789c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf || sc->hn_vf_ifp == NULL)
17799c6cae24SSepherosa Ziehau 		return (false);
17809c6cae24SSepherosa Ziehau 
17819c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick == 0)
17829c6cae24SSepherosa Ziehau 		return (true);
17839c6cae24SSepherosa Ziehau 
17849c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick > ticks)
17859c6cae24SSepherosa Ziehau 		return (false);
17869c6cae24SSepherosa Ziehau 
17879c6cae24SSepherosa Ziehau 	/* Mark VF as ready. */
17889c6cae24SSepherosa Ziehau 	hn_xpnt_vf_setready(sc);
17899c6cae24SSepherosa Ziehau 	return (true);
17909c6cae24SSepherosa Ziehau }
17919c6cae24SSepherosa Ziehau 
17929c6cae24SSepherosa Ziehau static void
1793a97fff19SSepherosa Ziehau hn_xpnt_vf_setenable(struct hn_softc *sc)
1794a97fff19SSepherosa Ziehau {
1795a97fff19SSepherosa Ziehau 	int i;
1796a97fff19SSepherosa Ziehau 
1797a97fff19SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1798a97fff19SSepherosa Ziehau 
1799a97fff19SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
1800a97fff19SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
1801a97fff19SSepherosa Ziehau 	sc->hn_xvf_flags |= HN_XVFFLAG_ENABLED;
1802a97fff19SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
1803a97fff19SSepherosa Ziehau 
1804a97fff19SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1805a97fff19SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_rx_flags |= HN_RX_FLAG_XPNT_VF;
1806a97fff19SSepherosa Ziehau }
1807a97fff19SSepherosa Ziehau 
1808a97fff19SSepherosa Ziehau static void
1809a97fff19SSepherosa Ziehau hn_xpnt_vf_setdisable(struct hn_softc *sc, bool clear_vf)
1810a97fff19SSepherosa Ziehau {
1811a97fff19SSepherosa Ziehau 	int i;
1812a97fff19SSepherosa Ziehau 
1813a97fff19SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1814a97fff19SSepherosa Ziehau 
1815a97fff19SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
1816a97fff19SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
1817a97fff19SSepherosa Ziehau 	sc->hn_xvf_flags &= ~HN_XVFFLAG_ENABLED;
1818a97fff19SSepherosa Ziehau 	if (clear_vf)
1819a97fff19SSepherosa Ziehau 		sc->hn_vf_ifp = NULL;
1820a97fff19SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
1821a97fff19SSepherosa Ziehau 
1822a97fff19SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1823a97fff19SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_rx_flags &= ~HN_RX_FLAG_XPNT_VF;
1824a97fff19SSepherosa Ziehau }
1825a97fff19SSepherosa Ziehau 
1826a97fff19SSepherosa Ziehau static void
18279c6cae24SSepherosa Ziehau hn_xpnt_vf_init(struct hn_softc *sc)
18289c6cae24SSepherosa Ziehau {
18299c6cae24SSepherosa Ziehau 	int error;
18309c6cae24SSepherosa Ziehau 
18319c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
18329c6cae24SSepherosa Ziehau 
18339c6cae24SSepherosa Ziehau 	KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0,
18349c6cae24SSepherosa Ziehau 	    ("%s: transparent VF was enabled", sc->hn_ifp->if_xname));
18359c6cae24SSepherosa Ziehau 
18369c6cae24SSepherosa Ziehau 	if (bootverbose) {
18379c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "try bringing up %s\n",
18389c6cae24SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname);
18399c6cae24SSepherosa Ziehau 	}
18409c6cae24SSepherosa Ziehau 
18419c6cae24SSepherosa Ziehau 	/*
18429c6cae24SSepherosa Ziehau 	 * Bring the VF up.
18439c6cae24SSepherosa Ziehau 	 */
18449c6cae24SSepherosa Ziehau 	hn_xpnt_vf_saveifflags(sc);
18459c6cae24SSepherosa Ziehau 	sc->hn_vf_ifp->if_flags |= IFF_UP;
18469c6cae24SSepherosa Ziehau 	error = hn_xpnt_vf_iocsetflags(sc);
18479c6cae24SSepherosa Ziehau 	if (error) {
18489c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "bringing up %s failed: %d\n",
18499c6cae24SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname, error);
18509c6cae24SSepherosa Ziehau 		return;
18519c6cae24SSepherosa Ziehau 	}
18529c6cae24SSepherosa Ziehau 
18539c6cae24SSepherosa Ziehau 	/*
18549c6cae24SSepherosa Ziehau 	 * NOTE:
18559c6cae24SSepherosa Ziehau 	 * Datapath setting must happen _after_ bringing the VF up.
18569c6cae24SSepherosa Ziehau 	 */
18579c6cae24SSepherosa Ziehau 	hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF);
18589c6cae24SSepherosa Ziehau 
1859642ec226SSepherosa Ziehau 	/*
1860642ec226SSepherosa Ziehau 	 * NOTE:
1861642ec226SSepherosa Ziehau 	 * Fixup RSS related bits _after_ the VF is brought up, since
1862642ec226SSepherosa Ziehau 	 * many VFs generate RSS key during it's initialization.
1863642ec226SSepherosa Ziehau 	 */
1864642ec226SSepherosa Ziehau 	hn_vf_rss_fixup(sc, true);
1865642ec226SSepherosa Ziehau 
1866a97fff19SSepherosa Ziehau 	/* Mark transparent mode VF as enabled. */
1867a97fff19SSepherosa Ziehau 	hn_xpnt_vf_setenable(sc);
18689c6cae24SSepherosa Ziehau }
18699c6cae24SSepherosa Ziehau 
18709c6cae24SSepherosa Ziehau static void
18719c6cae24SSepherosa Ziehau hn_xpnt_vf_init_taskfunc(void *xsc, int pending __unused)
18729c6cae24SSepherosa Ziehau {
18739c6cae24SSepherosa Ziehau 	struct hn_softc *sc = xsc;
18749c6cae24SSepherosa Ziehau 
18759c6cae24SSepherosa Ziehau 	HN_LOCK(sc);
18769c6cae24SSepherosa Ziehau 
18779c6cae24SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
18789c6cae24SSepherosa Ziehau 		goto done;
18799c6cae24SSepherosa Ziehau 	if (sc->hn_vf_ifp == NULL)
18809c6cae24SSepherosa Ziehau 		goto done;
18819c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
18829c6cae24SSepherosa Ziehau 		goto done;
18839c6cae24SSepherosa Ziehau 
18849c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick != 0) {
18859c6cae24SSepherosa Ziehau 		/* Mark VF as ready. */
18869c6cae24SSepherosa Ziehau 		hn_xpnt_vf_setready(sc);
18879c6cae24SSepherosa Ziehau 	}
18889c6cae24SSepherosa Ziehau 
18899c6cae24SSepherosa Ziehau 	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) {
18909c6cae24SSepherosa Ziehau 		/*
18919c6cae24SSepherosa Ziehau 		 * Delayed VF initialization.
18929c6cae24SSepherosa Ziehau 		 */
18939c6cae24SSepherosa Ziehau 		if (bootverbose) {
18949c6cae24SSepherosa Ziehau 			if_printf(sc->hn_ifp, "delayed initialize %s\n",
18959c6cae24SSepherosa Ziehau 			    sc->hn_vf_ifp->if_xname);
18969c6cae24SSepherosa Ziehau 		}
18979c6cae24SSepherosa Ziehau 		hn_xpnt_vf_init(sc);
18989c6cae24SSepherosa Ziehau 	}
18999c6cae24SSepherosa Ziehau done:
19009c6cae24SSepherosa Ziehau 	HN_UNLOCK(sc);
19019c6cae24SSepherosa Ziehau }
19029c6cae24SSepherosa Ziehau 
1903499c3e17SSepherosa Ziehau static void
1904499c3e17SSepherosa Ziehau hn_ifnet_attevent(void *xsc, struct ifnet *ifp)
1905499c3e17SSepherosa Ziehau {
1906499c3e17SSepherosa Ziehau 	struct hn_softc *sc = xsc;
1907499c3e17SSepherosa Ziehau 
1908499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
1909499c3e17SSepherosa Ziehau 
1910499c3e17SSepherosa Ziehau 	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
1911499c3e17SSepherosa Ziehau 		goto done;
1912499c3e17SSepherosa Ziehau 
1913499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1914499c3e17SSepherosa Ziehau 		goto done;
1915499c3e17SSepherosa Ziehau 
1916499c3e17SSepherosa Ziehau 	if (sc->hn_vf_ifp != NULL) {
1917499c3e17SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%s was attached as VF\n",
1918499c3e17SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname);
1919499c3e17SSepherosa Ziehau 		goto done;
1920499c3e17SSepherosa Ziehau 	}
1921499c3e17SSepherosa Ziehau 
19229c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && ifp->if_start != NULL) {
19239c6cae24SSepherosa Ziehau 		/*
19249c6cae24SSepherosa Ziehau 		 * ifnet.if_start is _not_ supported by transparent
19259c6cae24SSepherosa Ziehau 		 * mode VF; mainly due to the IFF_DRV_OACTIVE flag.
19269c6cae24SSepherosa Ziehau 		 */
19279c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%s uses if_start, which is unsupported "
19289c6cae24SSepherosa Ziehau 		    "in transparent VF mode.\n", ifp->if_xname);
19299c6cae24SSepherosa Ziehau 		goto done;
19309c6cae24SSepherosa Ziehau 	}
19319c6cae24SSepherosa Ziehau 
1932499c3e17SSepherosa Ziehau 	rm_wlock(&hn_vfmap_lock);
1933499c3e17SSepherosa Ziehau 
1934499c3e17SSepherosa Ziehau 	if (ifp->if_index >= hn_vfmap_size) {
1935499c3e17SSepherosa Ziehau 		struct ifnet **newmap;
1936499c3e17SSepherosa Ziehau 		int newsize;
1937499c3e17SSepherosa Ziehau 
1938499c3e17SSepherosa Ziehau 		newsize = ifp->if_index + HN_VFMAP_SIZE_DEF;
1939499c3e17SSepherosa Ziehau 		newmap = malloc(sizeof(struct ifnet *) * newsize, M_DEVBUF,
1940499c3e17SSepherosa Ziehau 		    M_WAITOK | M_ZERO);
1941499c3e17SSepherosa Ziehau 
1942499c3e17SSepherosa Ziehau 		memcpy(newmap, hn_vfmap,
1943499c3e17SSepherosa Ziehau 		    sizeof(struct ifnet *) * hn_vfmap_size);
1944499c3e17SSepherosa Ziehau 		free(hn_vfmap, M_DEVBUF);
1945499c3e17SSepherosa Ziehau 		hn_vfmap = newmap;
1946499c3e17SSepherosa Ziehau 		hn_vfmap_size = newsize;
1947499c3e17SSepherosa Ziehau 	}
1948499c3e17SSepherosa Ziehau 	KASSERT(hn_vfmap[ifp->if_index] == NULL,
1949499c3e17SSepherosa Ziehau 	    ("%s: ifindex %d was mapped to %s",
1950499c3e17SSepherosa Ziehau 	     ifp->if_xname, ifp->if_index, hn_vfmap[ifp->if_index]->if_xname));
1951499c3e17SSepherosa Ziehau 	hn_vfmap[ifp->if_index] = sc->hn_ifp;
1952499c3e17SSepherosa Ziehau 
1953499c3e17SSepherosa Ziehau 	rm_wunlock(&hn_vfmap_lock);
1954499c3e17SSepherosa Ziehau 
19559c6cae24SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
19569c6cae24SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
19579c6cae24SSepherosa Ziehau 	KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0,
19589c6cae24SSepherosa Ziehau 	    ("%s: transparent VF was enabled", sc->hn_ifp->if_xname));
1959499c3e17SSepherosa Ziehau 	sc->hn_vf_ifp = ifp;
19609c6cae24SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
19619c6cae24SSepherosa Ziehau 
19629c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
19639c6cae24SSepherosa Ziehau 		int wait_ticks;
19649c6cae24SSepherosa Ziehau 
19659c6cae24SSepherosa Ziehau 		/*
19669c6cae24SSepherosa Ziehau 		 * Install if_input for vf_ifp, which does vf_ifp -> hn_ifp.
19679c6cae24SSepherosa Ziehau 		 * Save vf_ifp's current if_input for later restoration.
19689c6cae24SSepherosa Ziehau 		 */
19699c6cae24SSepherosa Ziehau 		sc->hn_vf_input = ifp->if_input;
19709c6cae24SSepherosa Ziehau 		ifp->if_input = hn_xpnt_vf_input;
19719c6cae24SSepherosa Ziehau 
19729c6cae24SSepherosa Ziehau 		/*
19739c6cae24SSepherosa Ziehau 		 * Stop link status management; use the VF's.
19749c6cae24SSepherosa Ziehau 		 */
19759c6cae24SSepherosa Ziehau 		hn_suspend_mgmt(sc);
19769c6cae24SSepherosa Ziehau 
19779c6cae24SSepherosa Ziehau 		/*
19789c6cae24SSepherosa Ziehau 		 * Give VF sometime to complete its attach routing.
19799c6cae24SSepherosa Ziehau 		 */
19809c6cae24SSepherosa Ziehau 		wait_ticks = hn_xpnt_vf_attwait * hz;
19819c6cae24SSepherosa Ziehau 		sc->hn_vf_rdytick = ticks + wait_ticks;
19829c6cae24SSepherosa Ziehau 
19839c6cae24SSepherosa Ziehau 		taskqueue_enqueue_timeout(sc->hn_vf_taskq, &sc->hn_vf_init,
19849c6cae24SSepherosa Ziehau 		    wait_ticks);
19859c6cae24SSepherosa Ziehau 	}
1986499c3e17SSepherosa Ziehau done:
1987499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
1988499c3e17SSepherosa Ziehau }
1989499c3e17SSepherosa Ziehau 
1990499c3e17SSepherosa Ziehau static void
1991499c3e17SSepherosa Ziehau hn_ifnet_detevent(void *xsc, struct ifnet *ifp)
1992499c3e17SSepherosa Ziehau {
1993499c3e17SSepherosa Ziehau 	struct hn_softc *sc = xsc;
1994499c3e17SSepherosa Ziehau 
1995499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
1996499c3e17SSepherosa Ziehau 
1997499c3e17SSepherosa Ziehau 	if (sc->hn_vf_ifp == NULL)
1998499c3e17SSepherosa Ziehau 		goto done;
1999499c3e17SSepherosa Ziehau 
2000499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
2001499c3e17SSepherosa Ziehau 		goto done;
2002499c3e17SSepherosa Ziehau 
20039c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
20049c6cae24SSepherosa Ziehau 		/*
20059c6cae24SSepherosa Ziehau 		 * Make sure that the delayed initialization is not running.
20069c6cae24SSepherosa Ziehau 		 *
20079c6cae24SSepherosa Ziehau 		 * NOTE:
20089c6cae24SSepherosa Ziehau 		 * - This lock _must_ be released, since the hn_vf_init task
20099c6cae24SSepherosa Ziehau 		 *   will try holding this lock.
20109c6cae24SSepherosa Ziehau 		 * - It is safe to release this lock here, since the
20119c6cae24SSepherosa Ziehau 		 *   hn_ifnet_attevent() is interlocked by the hn_vf_ifp.
20129c6cae24SSepherosa Ziehau 		 *
20139c6cae24SSepherosa Ziehau 		 * XXX racy, if hn(4) ever detached.
20149c6cae24SSepherosa Ziehau 		 */
20159c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
20169c6cae24SSepherosa Ziehau 		taskqueue_drain_timeout(sc->hn_vf_taskq, &sc->hn_vf_init);
20179c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
20189c6cae24SSepherosa Ziehau 
20199c6cae24SSepherosa Ziehau 		KASSERT(sc->hn_vf_input != NULL, ("%s VF input is not saved",
20209c6cae24SSepherosa Ziehau 		    sc->hn_ifp->if_xname));
20219c6cae24SSepherosa Ziehau 		ifp->if_input = sc->hn_vf_input;
20229c6cae24SSepherosa Ziehau 		sc->hn_vf_input = NULL;
20239c6cae24SSepherosa Ziehau 
2024642ec226SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) &&
2025642ec226SSepherosa Ziehau 		    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED))
20269c6cae24SSepherosa Ziehau 			hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH);
20279c6cae24SSepherosa Ziehau 
20289c6cae24SSepherosa Ziehau 		if (sc->hn_vf_rdytick == 0) {
20299c6cae24SSepherosa Ziehau 			/*
20309c6cae24SSepherosa Ziehau 			 * The VF was ready; restore some settings.
20319c6cae24SSepherosa Ziehau 			 */
20329c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_capabilities = sc->hn_saved_caps;
20339c6cae24SSepherosa Ziehau 			/*
20349c6cae24SSepherosa Ziehau 			 * NOTE:
20359c6cae24SSepherosa Ziehau 			 * There is _no_ need to fixup if_capenable and
20369c6cae24SSepherosa Ziehau 			 * if_hwassist, since the if_capabilities before
20379c6cae24SSepherosa Ziehau 			 * restoration was an intersection of the VF's
20389c6cae24SSepherosa Ziehau 			 * if_capabilites and the synthetic device's
20399c6cae24SSepherosa Ziehau 			 * if_capabilites.
20409c6cae24SSepherosa Ziehau 			 */
20419c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomax = sc->hn_saved_tsomax;
20429c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomaxsegcount =
20439c6cae24SSepherosa Ziehau 			    sc->hn_saved_tsosegcnt;
20449c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomaxsegsize = sc->hn_saved_tsosegsz;
20459c6cae24SSepherosa Ziehau 		}
20469c6cae24SSepherosa Ziehau 
2047642ec226SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
2048642ec226SSepherosa Ziehau 			/*
2049642ec226SSepherosa Ziehau 			 * Restore RSS settings.
2050642ec226SSepherosa Ziehau 			 */
2051642ec226SSepherosa Ziehau 			hn_vf_rss_restore(sc);
2052642ec226SSepherosa Ziehau 
20539c6cae24SSepherosa Ziehau 			/*
20549c6cae24SSepherosa Ziehau 			 * Resume link status management, which was suspended
20559c6cae24SSepherosa Ziehau 			 * by hn_ifnet_attevent().
20569c6cae24SSepherosa Ziehau 			 */
20579c6cae24SSepherosa Ziehau 			hn_resume_mgmt(sc);
20589c6cae24SSepherosa Ziehau 		}
2059642ec226SSepherosa Ziehau 	}
20609c6cae24SSepherosa Ziehau 
2061a97fff19SSepherosa Ziehau 	/* Mark transparent mode VF as disabled. */
2062a97fff19SSepherosa Ziehau 	hn_xpnt_vf_setdisable(sc, true /* clear hn_vf_ifp */);
2063499c3e17SSepherosa Ziehau 
2064499c3e17SSepherosa Ziehau 	rm_wlock(&hn_vfmap_lock);
2065499c3e17SSepherosa Ziehau 
2066499c3e17SSepherosa Ziehau 	KASSERT(ifp->if_index < hn_vfmap_size,
2067499c3e17SSepherosa Ziehau 	    ("ifindex %d, vfmapsize %d", ifp->if_index, hn_vfmap_size));
2068499c3e17SSepherosa Ziehau 	if (hn_vfmap[ifp->if_index] != NULL) {
2069499c3e17SSepherosa Ziehau 		KASSERT(hn_vfmap[ifp->if_index] == sc->hn_ifp,
2070499c3e17SSepherosa Ziehau 		    ("%s: ifindex %d was mapped to %s",
2071499c3e17SSepherosa Ziehau 		     ifp->if_xname, ifp->if_index,
2072499c3e17SSepherosa Ziehau 		     hn_vfmap[ifp->if_index]->if_xname));
2073499c3e17SSepherosa Ziehau 		hn_vfmap[ifp->if_index] = NULL;
2074499c3e17SSepherosa Ziehau 	}
2075499c3e17SSepherosa Ziehau 
2076499c3e17SSepherosa Ziehau 	rm_wunlock(&hn_vfmap_lock);
2077499c3e17SSepherosa Ziehau done:
2078499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
2079499c3e17SSepherosa Ziehau }
2080499c3e17SSepherosa Ziehau 
20819c6cae24SSepherosa Ziehau static void
20829c6cae24SSepherosa Ziehau hn_ifnet_lnkevent(void *xsc, struct ifnet *ifp, int link_state)
20839c6cae24SSepherosa Ziehau {
20849c6cae24SSepherosa Ziehau 	struct hn_softc *sc = xsc;
20859c6cae24SSepherosa Ziehau 
20869c6cae24SSepherosa Ziehau 	if (sc->hn_vf_ifp == ifp)
20879c6cae24SSepherosa Ziehau 		if_link_state_change(sc->hn_ifp, link_state);
20889c6cae24SSepherosa Ziehau }
20899c6cae24SSepherosa Ziehau 
209015516c77SSepherosa Ziehau static int
209115516c77SSepherosa Ziehau hn_probe(device_t dev)
209215516c77SSepherosa Ziehau {
209315516c77SSepherosa Ziehau 
2094c2d50b26SSepherosa Ziehau 	if (VMBUS_PROBE_GUID(device_get_parent(dev), dev, &hn_guid) == 0) {
209515516c77SSepherosa Ziehau 		device_set_desc(dev, "Hyper-V Network Interface");
209615516c77SSepherosa Ziehau 		return BUS_PROBE_DEFAULT;
209715516c77SSepherosa Ziehau 	}
209815516c77SSepherosa Ziehau 	return ENXIO;
209915516c77SSepherosa Ziehau }
210015516c77SSepherosa Ziehau 
210115516c77SSepherosa Ziehau static int
210215516c77SSepherosa Ziehau hn_attach(device_t dev)
210315516c77SSepherosa Ziehau {
210415516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
210515516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
210615516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
210715516c77SSepherosa Ziehau 	uint8_t eaddr[ETHER_ADDR_LEN];
210815516c77SSepherosa Ziehau 	struct ifnet *ifp = NULL;
210915516c77SSepherosa Ziehau 	int error, ring_cnt, tx_ring_cnt;
2110eb2fe044SSepherosa Ziehau 	uint32_t mtu;
211115516c77SSepherosa Ziehau 
211215516c77SSepherosa Ziehau 	sc->hn_dev = dev;
211315516c77SSepherosa Ziehau 	sc->hn_prichan = vmbus_get_channel(dev);
211415516c77SSepherosa Ziehau 	HN_LOCK_INIT(sc);
21159c6cae24SSepherosa Ziehau 	rm_init(&sc->hn_vf_lock, "hnvf");
21169c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && hn_xpnt_vf_accbpf)
21179c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF;
211815516c77SSepherosa Ziehau 
211915516c77SSepherosa Ziehau 	/*
2120dc13fee6SSepherosa Ziehau 	 * Initialize these tunables once.
2121dc13fee6SSepherosa Ziehau 	 */
2122dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = hn_tx_agg_size;
2123dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = hn_tx_agg_pkts;
2124dc13fee6SSepherosa Ziehau 
2125dc13fee6SSepherosa Ziehau 	/*
212615516c77SSepherosa Ziehau 	 * Setup taskqueue for transmission.
212715516c77SSepherosa Ziehau 	 */
21280e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_INDEP) {
2129fdd0222aSSepherosa Ziehau 		int i;
2130fdd0222aSSepherosa Ziehau 
2131fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs =
2132fdd0222aSSepherosa Ziehau 		    malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
2133fdd0222aSSepherosa Ziehau 		    M_DEVBUF, M_WAITOK);
2134fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i) {
2135fdd0222aSSepherosa Ziehau 			sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx",
2136fdd0222aSSepherosa Ziehau 			    M_WAITOK, taskqueue_thread_enqueue,
2137fdd0222aSSepherosa Ziehau 			    &sc->hn_tx_taskqs[i]);
2138fdd0222aSSepherosa Ziehau 			taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET,
2139fdd0222aSSepherosa Ziehau 			    "%s tx%d", device_get_nameunit(dev), i);
2140fdd0222aSSepherosa Ziehau 		}
21410e11868dSSepherosa Ziehau 	} else if (hn_tx_taskq_mode == HN_TX_TASKQ_M_GLOBAL) {
2142fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs = hn_tx_taskque;
214315516c77SSepherosa Ziehau 	}
214415516c77SSepherosa Ziehau 
214515516c77SSepherosa Ziehau 	/*
214615516c77SSepherosa Ziehau 	 * Setup taskqueue for mangement tasks, e.g. link status.
214715516c77SSepherosa Ziehau 	 */
214815516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK,
214915516c77SSepherosa Ziehau 	    taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0);
215015516c77SSepherosa Ziehau 	taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
215115516c77SSepherosa Ziehau 	    device_get_nameunit(dev));
215215516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
215315516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc);
215415516c77SSepherosa Ziehau 	TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0,
215515516c77SSepherosa Ziehau 	    hn_netchg_status_taskfunc, sc);
215615516c77SSepherosa Ziehau 
21579c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
21589c6cae24SSepherosa Ziehau 		/*
21599c6cae24SSepherosa Ziehau 		 * Setup taskqueue for VF tasks, e.g. delayed VF bringing up.
21609c6cae24SSepherosa Ziehau 		 */
21619c6cae24SSepherosa Ziehau 		sc->hn_vf_taskq = taskqueue_create("hn_vf", M_WAITOK,
21629c6cae24SSepherosa Ziehau 		    taskqueue_thread_enqueue, &sc->hn_vf_taskq);
21639c6cae24SSepherosa Ziehau 		taskqueue_start_threads(&sc->hn_vf_taskq, 1, PI_NET, "%s vf",
21649c6cae24SSepherosa Ziehau 		    device_get_nameunit(dev));
21659c6cae24SSepherosa Ziehau 		TIMEOUT_TASK_INIT(sc->hn_vf_taskq, &sc->hn_vf_init, 0,
21669c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_init_taskfunc, sc);
21679c6cae24SSepherosa Ziehau 	}
21689c6cae24SSepherosa Ziehau 
216915516c77SSepherosa Ziehau 	/*
217015516c77SSepherosa Ziehau 	 * Allocate ifnet and setup its name earlier, so that if_printf
217115516c77SSepherosa Ziehau 	 * can be used by functions, which will be called after
217215516c77SSepherosa Ziehau 	 * ether_ifattach().
217315516c77SSepherosa Ziehau 	 */
217415516c77SSepherosa Ziehau 	ifp = sc->hn_ifp = if_alloc(IFT_ETHER);
217515516c77SSepherosa Ziehau 	ifp->if_softc = sc;
217615516c77SSepherosa Ziehau 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
217715516c77SSepherosa Ziehau 
217815516c77SSepherosa Ziehau 	/*
217915516c77SSepherosa Ziehau 	 * Initialize ifmedia earlier so that it can be unconditionally
218015516c77SSepherosa Ziehau 	 * destroyed, if error happened later on.
218115516c77SSepherosa Ziehau 	 */
218215516c77SSepherosa Ziehau 	ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts);
218315516c77SSepherosa Ziehau 
218415516c77SSepherosa Ziehau 	/*
218515516c77SSepherosa Ziehau 	 * Figure out the # of RX rings (ring_cnt) and the # of TX rings
218615516c77SSepherosa Ziehau 	 * to use (tx_ring_cnt).
218715516c77SSepherosa Ziehau 	 *
218815516c77SSepherosa Ziehau 	 * NOTE:
218915516c77SSepherosa Ziehau 	 * The # of RX rings to use is same as the # of channels to use.
219015516c77SSepherosa Ziehau 	 */
219115516c77SSepherosa Ziehau 	ring_cnt = hn_chan_cnt;
219215516c77SSepherosa Ziehau 	if (ring_cnt <= 0) {
219315516c77SSepherosa Ziehau 		/* Default */
219415516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
219515516c77SSepherosa Ziehau 		if (ring_cnt > HN_RING_CNT_DEF_MAX)
219615516c77SSepherosa Ziehau 			ring_cnt = HN_RING_CNT_DEF_MAX;
219715516c77SSepherosa Ziehau 	} else if (ring_cnt > mp_ncpus) {
219815516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
219915516c77SSepherosa Ziehau 	}
220034d68912SSepherosa Ziehau #ifdef RSS
220134d68912SSepherosa Ziehau 	if (ring_cnt > rss_getnumbuckets())
220234d68912SSepherosa Ziehau 		ring_cnt = rss_getnumbuckets();
220334d68912SSepherosa Ziehau #endif
220415516c77SSepherosa Ziehau 
220515516c77SSepherosa Ziehau 	tx_ring_cnt = hn_tx_ring_cnt;
220615516c77SSepherosa Ziehau 	if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt)
220715516c77SSepherosa Ziehau 		tx_ring_cnt = ring_cnt;
220823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
220915516c77SSepherosa Ziehau 	if (hn_use_if_start) {
221015516c77SSepherosa Ziehau 		/* ifnet.if_start only needs one TX ring. */
221115516c77SSepherosa Ziehau 		tx_ring_cnt = 1;
221215516c77SSepherosa Ziehau 	}
221323bf9e15SSepherosa Ziehau #endif
221415516c77SSepherosa Ziehau 
221515516c77SSepherosa Ziehau 	/*
221615516c77SSepherosa Ziehau 	 * Set the leader CPU for channels.
221715516c77SSepherosa Ziehau 	 */
221815516c77SSepherosa Ziehau 	sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus;
221915516c77SSepherosa Ziehau 
222015516c77SSepherosa Ziehau 	/*
222115516c77SSepherosa Ziehau 	 * Create enough TX/RX rings, even if only limited number of
222215516c77SSepherosa Ziehau 	 * channels can be allocated.
222315516c77SSepherosa Ziehau 	 */
222415516c77SSepherosa Ziehau 	error = hn_create_tx_data(sc, tx_ring_cnt);
222515516c77SSepherosa Ziehau 	if (error)
222615516c77SSepherosa Ziehau 		goto failed;
222715516c77SSepherosa Ziehau 	error = hn_create_rx_data(sc, ring_cnt);
222815516c77SSepherosa Ziehau 	if (error)
222915516c77SSepherosa Ziehau 		goto failed;
223015516c77SSepherosa Ziehau 
223115516c77SSepherosa Ziehau 	/*
223215516c77SSepherosa Ziehau 	 * Create transaction context for NVS and RNDIS transactions.
223315516c77SSepherosa Ziehau 	 */
223415516c77SSepherosa Ziehau 	sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
223515516c77SSepherosa Ziehau 	    HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
223625641fc7SSepherosa Ziehau 	if (sc->hn_xact == NULL) {
223725641fc7SSepherosa Ziehau 		error = ENXIO;
223815516c77SSepherosa Ziehau 		goto failed;
223925641fc7SSepherosa Ziehau 	}
224025641fc7SSepherosa Ziehau 
224125641fc7SSepherosa Ziehau 	/*
224225641fc7SSepherosa Ziehau 	 * Install orphan handler for the revocation of this device's
224325641fc7SSepherosa Ziehau 	 * primary channel.
224425641fc7SSepherosa Ziehau 	 *
224525641fc7SSepherosa Ziehau 	 * NOTE:
224625641fc7SSepherosa Ziehau 	 * The processing order is critical here:
224725641fc7SSepherosa Ziehau 	 * Install the orphan handler, _before_ testing whether this
224825641fc7SSepherosa Ziehau 	 * device's primary channel has been revoked or not.
224925641fc7SSepherosa Ziehau 	 */
225025641fc7SSepherosa Ziehau 	vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact);
225125641fc7SSepherosa Ziehau 	if (vmbus_chan_is_revoked(sc->hn_prichan)) {
225225641fc7SSepherosa Ziehau 		error = ENXIO;
225325641fc7SSepherosa Ziehau 		goto failed;
225425641fc7SSepherosa Ziehau 	}
225515516c77SSepherosa Ziehau 
225615516c77SSepherosa Ziehau 	/*
225715516c77SSepherosa Ziehau 	 * Attach the synthetic parts, i.e. NVS and RNDIS.
225815516c77SSepherosa Ziehau 	 */
225915516c77SSepherosa Ziehau 	error = hn_synth_attach(sc, ETHERMTU);
226015516c77SSepherosa Ziehau 	if (error)
226115516c77SSepherosa Ziehau 		goto failed;
226215516c77SSepherosa Ziehau 
226315516c77SSepherosa Ziehau 	error = hn_rndis_get_eaddr(sc, eaddr);
226415516c77SSepherosa Ziehau 	if (error)
226515516c77SSepherosa Ziehau 		goto failed;
226615516c77SSepherosa Ziehau 
2267eb2fe044SSepherosa Ziehau 	error = hn_rndis_get_mtu(sc, &mtu);
2268eb2fe044SSepherosa Ziehau 	if (error)
2269eb2fe044SSepherosa Ziehau 		mtu = ETHERMTU;
2270eb2fe044SSepherosa Ziehau 	else if (bootverbose)
2271eb2fe044SSepherosa Ziehau 		device_printf(dev, "RNDIS mtu %u\n", mtu);
2272eb2fe044SSepherosa Ziehau 
227315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
227415516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
227515516c77SSepherosa Ziehau 		/*
227615516c77SSepherosa Ziehau 		 * Reduce TCP segment aggregation limit for multiple
227715516c77SSepherosa Ziehau 		 * RX rings to increase ACK timeliness.
227815516c77SSepherosa Ziehau 		 */
227915516c77SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF);
228015516c77SSepherosa Ziehau 	}
228115516c77SSepherosa Ziehau #endif
228215516c77SSepherosa Ziehau 
228315516c77SSepherosa Ziehau 	/*
2284db76829bSSepherosa Ziehau 	 * Fixup TX/RX stuffs after synthetic parts are attached.
228515516c77SSepherosa Ziehau 	 */
228615516c77SSepherosa Ziehau 	hn_fixup_tx_data(sc);
2287db76829bSSepherosa Ziehau 	hn_fixup_rx_data(sc);
228815516c77SSepherosa Ziehau 
228915516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
229015516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
229115516c77SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD,
229215516c77SSepherosa Ziehau 	    &sc->hn_nvs_ver, 0, "NVS version");
229315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version",
229415516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
229515516c77SSepherosa Ziehau 	    hn_ndis_version_sysctl, "A", "NDIS version");
229615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps",
229715516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
229815516c77SSepherosa Ziehau 	    hn_caps_sysctl, "A", "capabilities");
229915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist",
230015516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
230115516c77SSepherosa Ziehau 	    hn_hwassist_sysctl, "A", "hwassist");
23029c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_max",
23039c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomax, 0, "max TSO size");
23049c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegcnt",
23059c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomaxsegcount, 0,
23069c6cae24SSepherosa Ziehau 	    "max # of TSO segments");
23079c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegsz",
23089c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomaxsegsize, 0,
23099c6cae24SSepherosa Ziehau 	    "max size of TSO segment");
231015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter",
231115516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
231215516c77SSepherosa Ziehau 	    hn_rxfilter_sysctl, "A", "rxfilter");
231315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash",
231415516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
231515516c77SSepherosa Ziehau 	    hn_rss_hash_sysctl, "A", "RSS hash");
2316642ec226SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hashcap",
2317642ec226SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2318642ec226SSepherosa Ziehau 	    hn_rss_hcap_sysctl, "A", "RSS hash capabilities");
2319642ec226SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "mbuf_hash",
2320642ec226SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2321642ec226SSepherosa Ziehau 	    hn_rss_mbuf_sysctl, "A", "RSS hash for mbufs");
232215516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size",
232315516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count");
232434d68912SSepherosa Ziehau #ifndef RSS
232534d68912SSepherosa Ziehau 	/*
232634d68912SSepherosa Ziehau 	 * Don't allow RSS key/indirect table changes, if RSS is defined.
232734d68912SSepherosa Ziehau 	 */
232815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key",
232915516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
233015516c77SSepherosa Ziehau 	    hn_rss_key_sysctl, "IU", "RSS key");
233115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind",
233215516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
233315516c77SSepherosa Ziehau 	    hn_rss_ind_sysctl, "IU", "RSS indirect table");
233434d68912SSepherosa Ziehau #endif
2335dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size",
2336dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_size, 0,
2337dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation size limit");
2338dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts",
2339dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0,
2340dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation count limit");
2341dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align",
2342dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_align, 0,
2343dc13fee6SSepherosa Ziehau 	    "RNDIS packet transmission aggregation alignment");
2344dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size",
2345dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
2346dc13fee6SSepherosa Ziehau 	    hn_txagg_size_sysctl, "I",
2347dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation size, 0 -- disable, -1 -- auto");
2348dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts",
2349dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
2350dc13fee6SSepherosa Ziehau 	    hn_txagg_pkts_sysctl, "I",
2351dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation packets, "
2352dc13fee6SSepherosa Ziehau 	    "0 -- disable, -1 -- auto");
23536c1204dfSSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "polling",
23546c1204dfSSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
23556c1204dfSSepherosa Ziehau 	    hn_polling_sysctl, "I",
23566c1204dfSSepherosa Ziehau 	    "Polling frequency: [100,1000000], 0 disable polling");
235740d60d6eSDexuan Cui 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf",
235840d60d6eSDexuan Cui 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
235940d60d6eSDexuan Cui 	    hn_vf_sysctl, "A", "Virtual Function's name");
23609c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf) {
2361499c3e17SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxvf",
2362499c3e17SSepherosa Ziehau 		    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2363499c3e17SSepherosa Ziehau 		    hn_rxvf_sysctl, "A", "activated Virtual Function's name");
23649c6cae24SSepherosa Ziehau 	} else {
23659c6cae24SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_enabled",
23669c6cae24SSepherosa Ziehau 		    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
23679c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_enabled_sysctl, "I",
23689c6cae24SSepherosa Ziehau 		    "Transparent VF enabled");
23699c6cae24SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_accbpf",
23709c6cae24SSepherosa Ziehau 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
23719c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_accbpf_sysctl, "I",
23729c6cae24SSepherosa Ziehau 		    "Accurate BPF for transparent VF");
23739c6cae24SSepherosa Ziehau 	}
237415516c77SSepherosa Ziehau 
2375*80c3eb7bSWei Hu 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rsc_switch",
2376*80c3eb7bSWei Hu 	    CTLTYPE_UINT | CTLFLAG_RW, sc, 0, hn_rsc_sysctl, "A",
2377*80c3eb7bSWei Hu 	    "switch to rsc");
2378*80c3eb7bSWei Hu 
237915516c77SSepherosa Ziehau 	/*
238015516c77SSepherosa Ziehau 	 * Setup the ifmedia, which has been initialized earlier.
238115516c77SSepherosa Ziehau 	 */
238215516c77SSepherosa Ziehau 	ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL);
238315516c77SSepherosa Ziehau 	ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO);
238415516c77SSepherosa Ziehau 	/* XXX ifmedia_set really should do this for us */
238515516c77SSepherosa Ziehau 	sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media;
238615516c77SSepherosa Ziehau 
238715516c77SSepherosa Ziehau 	/*
238815516c77SSepherosa Ziehau 	 * Setup the ifnet for this interface.
238915516c77SSepherosa Ziehau 	 */
239015516c77SSepherosa Ziehau 
239115516c77SSepherosa Ziehau 	ifp->if_baudrate = IF_Gbps(10);
2392e87c4940SGleb Smirnoff 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
239315516c77SSepherosa Ziehau 	ifp->if_ioctl = hn_ioctl;
239415516c77SSepherosa Ziehau 	ifp->if_init = hn_init;
239523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
239615516c77SSepherosa Ziehau 	if (hn_use_if_start) {
239715516c77SSepherosa Ziehau 		int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]);
239815516c77SSepherosa Ziehau 
239915516c77SSepherosa Ziehau 		ifp->if_start = hn_start;
240015516c77SSepherosa Ziehau 		IFQ_SET_MAXLEN(&ifp->if_snd, qdepth);
240115516c77SSepherosa Ziehau 		ifp->if_snd.ifq_drv_maxlen = qdepth - 1;
240215516c77SSepherosa Ziehau 		IFQ_SET_READY(&ifp->if_snd);
240323bf9e15SSepherosa Ziehau 	} else
240423bf9e15SSepherosa Ziehau #endif
240523bf9e15SSepherosa Ziehau 	{
240615516c77SSepherosa Ziehau 		ifp->if_transmit = hn_transmit;
240715516c77SSepherosa Ziehau 		ifp->if_qflush = hn_xmit_qflush;
240815516c77SSepherosa Ziehau 	}
240915516c77SSepherosa Ziehau 
24109c6cae24SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO | IFCAP_LINKSTATE;
241115516c77SSepherosa Ziehau #ifdef foo
241215516c77SSepherosa Ziehau 	/* We can't diff IPv6 packets from IPv4 packets on RX path. */
241315516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM_IPV6;
241415516c77SSepherosa Ziehau #endif
241515516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_VLAN) {
241615516c77SSepherosa Ziehau 		/* XXX not sure about VLAN_MTU. */
241715516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
241815516c77SSepherosa Ziehau 	}
241915516c77SSepherosa Ziehau 
242015516c77SSepherosa Ziehau 	ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist;
242115516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP_MASK)
242215516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM;
242315516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP6_MASK)
242415516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM_IPV6;
242515516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO4) {
242615516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO4;
242715516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP_TSO;
242815516c77SSepherosa Ziehau 	}
242915516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO6) {
243015516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO6;
243115516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP6_TSO;
243215516c77SSepherosa Ziehau 	}
243315516c77SSepherosa Ziehau 
243415516c77SSepherosa Ziehau 	/* Enable all available capabilities by default. */
243515516c77SSepherosa Ziehau 	ifp->if_capenable = ifp->if_capabilities;
243615516c77SSepherosa Ziehau 
24377960e6baSSepherosa Ziehau 	/*
24387960e6baSSepherosa Ziehau 	 * Disable IPv6 TSO and TXCSUM by default, they still can
24397960e6baSSepherosa Ziehau 	 * be enabled through SIOCSIFCAP.
24407960e6baSSepherosa Ziehau 	 */
24417960e6baSSepherosa Ziehau 	ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
24427960e6baSSepherosa Ziehau 	ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO);
24437960e6baSSepherosa Ziehau 
244415516c77SSepherosa Ziehau 	if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) {
24459c6cae24SSepherosa Ziehau 		/*
24469c6cae24SSepherosa Ziehau 		 * Lock hn_set_tso_maxsize() to simplify its
24479c6cae24SSepherosa Ziehau 		 * internal logic.
24489c6cae24SSepherosa Ziehau 		 */
24499c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
245015516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU);
24519c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
245215516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX;
245315516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = PAGE_SIZE;
245415516c77SSepherosa Ziehau 	}
245515516c77SSepherosa Ziehau 
245615516c77SSepherosa Ziehau 	ether_ifattach(ifp, eaddr);
245715516c77SSepherosa Ziehau 
245815516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) {
245915516c77SSepherosa Ziehau 		if_printf(ifp, "TSO segcnt %u segsz %u\n",
246015516c77SSepherosa Ziehau 		    ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize);
246115516c77SSepherosa Ziehau 	}
2462eb2fe044SSepherosa Ziehau 	if (mtu < ETHERMTU) {
2463eb2fe044SSepherosa Ziehau 		if_printf(ifp, "fixup mtu %u -> %u\n", ifp->if_mtu, mtu);
2464eb2fe044SSepherosa Ziehau 		ifp->if_mtu = mtu;
2465eb2fe044SSepherosa Ziehau 	}
246615516c77SSepherosa Ziehau 
246715516c77SSepherosa Ziehau 	/* Inform the upper layer about the long frame support. */
246815516c77SSepherosa Ziehau 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
246915516c77SSepherosa Ziehau 
247015516c77SSepherosa Ziehau 	/*
247115516c77SSepherosa Ziehau 	 * Kick off link status check.
247215516c77SSepherosa Ziehau 	 */
247315516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
247415516c77SSepherosa Ziehau 	hn_update_link_status(sc);
247515516c77SSepherosa Ziehau 
24769c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf) {
24775bdfd3fdSDexuan Cui 		sc->hn_ifnet_evthand = EVENTHANDLER_REGISTER(ifnet_event,
24785bdfd3fdSDexuan Cui 		    hn_ifnet_event, sc, EVENTHANDLER_PRI_ANY);
24795bdfd3fdSDexuan Cui 		sc->hn_ifaddr_evthand = EVENTHANDLER_REGISTER(ifaddr_event,
24805bdfd3fdSDexuan Cui 		    hn_ifaddr_event, sc, EVENTHANDLER_PRI_ANY);
24819c6cae24SSepherosa Ziehau 	} else {
24829c6cae24SSepherosa Ziehau 		sc->hn_ifnet_lnkhand = EVENTHANDLER_REGISTER(ifnet_link_event,
24839c6cae24SSepherosa Ziehau 		    hn_ifnet_lnkevent, sc, EVENTHANDLER_PRI_ANY);
24849c6cae24SSepherosa Ziehau 	}
24855bdfd3fdSDexuan Cui 
2486f41e0df4SSepherosa Ziehau 	/*
2487f41e0df4SSepherosa Ziehau 	 * NOTE:
2488f41e0df4SSepherosa Ziehau 	 * Subscribe ether_ifattach event, instead of ifnet_arrival event,
2489f41e0df4SSepherosa Ziehau 	 * since interface's LLADDR is needed; interface LLADDR is not
2490f41e0df4SSepherosa Ziehau 	 * available when ifnet_arrival event is triggered.
2491f41e0df4SSepherosa Ziehau 	 */
2492499c3e17SSepherosa Ziehau 	sc->hn_ifnet_atthand = EVENTHANDLER_REGISTER(ether_ifattach_event,
2493499c3e17SSepherosa Ziehau 	    hn_ifnet_attevent, sc, EVENTHANDLER_PRI_ANY);
2494499c3e17SSepherosa Ziehau 	sc->hn_ifnet_dethand = EVENTHANDLER_REGISTER(ifnet_departure_event,
2495499c3e17SSepherosa Ziehau 	    hn_ifnet_detevent, sc, EVENTHANDLER_PRI_ANY);
2496499c3e17SSepherosa Ziehau 
249715516c77SSepherosa Ziehau 	return (0);
249815516c77SSepherosa Ziehau failed:
249915516c77SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)
250015516c77SSepherosa Ziehau 		hn_synth_detach(sc);
250115516c77SSepherosa Ziehau 	hn_detach(dev);
250215516c77SSepherosa Ziehau 	return (error);
250315516c77SSepherosa Ziehau }
250415516c77SSepherosa Ziehau 
250515516c77SSepherosa Ziehau static int
250615516c77SSepherosa Ziehau hn_detach(device_t dev)
250715516c77SSepherosa Ziehau {
250815516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
2509499c3e17SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp, *vf_ifp;
251015516c77SSepherosa Ziehau 
25119c6cae24SSepherosa Ziehau 	if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) {
25129c6cae24SSepherosa Ziehau 		/*
25139c6cae24SSepherosa Ziehau 		 * In case that the vmbus missed the orphan handler
25149c6cae24SSepherosa Ziehau 		 * installation.
25159c6cae24SSepherosa Ziehau 		 */
25169c6cae24SSepherosa Ziehau 		vmbus_xact_ctx_orphan(sc->hn_xact);
25179c6cae24SSepherosa Ziehau 	}
25189c6cae24SSepherosa Ziehau 
25195bdfd3fdSDexuan Cui 	if (sc->hn_ifaddr_evthand != NULL)
25205bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifaddr_event, sc->hn_ifaddr_evthand);
25215bdfd3fdSDexuan Cui 	if (sc->hn_ifnet_evthand != NULL)
25225bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifnet_event, sc->hn_ifnet_evthand);
2523499c3e17SSepherosa Ziehau 	if (sc->hn_ifnet_atthand != NULL) {
2524499c3e17SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ether_ifattach_event,
2525499c3e17SSepherosa Ziehau 		    sc->hn_ifnet_atthand);
2526499c3e17SSepherosa Ziehau 	}
2527499c3e17SSepherosa Ziehau 	if (sc->hn_ifnet_dethand != NULL) {
2528499c3e17SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ifnet_departure_event,
2529499c3e17SSepherosa Ziehau 		    sc->hn_ifnet_dethand);
2530499c3e17SSepherosa Ziehau 	}
25319c6cae24SSepherosa Ziehau 	if (sc->hn_ifnet_lnkhand != NULL)
25329c6cae24SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ifnet_link_event, sc->hn_ifnet_lnkhand);
2533499c3e17SSepherosa Ziehau 
2534499c3e17SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
2535499c3e17SSepherosa Ziehau 	__compiler_membar();
2536499c3e17SSepherosa Ziehau 	if (vf_ifp != NULL)
2537499c3e17SSepherosa Ziehau 		hn_ifnet_detevent(sc, vf_ifp);
25385bdfd3fdSDexuan Cui 
253915516c77SSepherosa Ziehau 	if (device_is_attached(dev)) {
254015516c77SSepherosa Ziehau 		HN_LOCK(sc);
254115516c77SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
254215516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
25435bdfd3fdSDexuan Cui 				hn_stop(sc, true);
254415516c77SSepherosa Ziehau 			/*
254515516c77SSepherosa Ziehau 			 * NOTE:
254615516c77SSepherosa Ziehau 			 * hn_stop() only suspends data, so managment
254715516c77SSepherosa Ziehau 			 * stuffs have to be suspended manually here.
254815516c77SSepherosa Ziehau 			 */
254915516c77SSepherosa Ziehau 			hn_suspend_mgmt(sc);
255015516c77SSepherosa Ziehau 			hn_synth_detach(sc);
255115516c77SSepherosa Ziehau 		}
255215516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
255315516c77SSepherosa Ziehau 		ether_ifdetach(ifp);
255415516c77SSepherosa Ziehau 	}
255515516c77SSepherosa Ziehau 
255615516c77SSepherosa Ziehau 	ifmedia_removeall(&sc->hn_media);
255715516c77SSepherosa Ziehau 	hn_destroy_rx_data(sc);
255815516c77SSepherosa Ziehau 	hn_destroy_tx_data(sc);
255915516c77SSepherosa Ziehau 
25600e11868dSSepherosa Ziehau 	if (sc->hn_tx_taskqs != NULL && sc->hn_tx_taskqs != hn_tx_taskque) {
2561fdd0222aSSepherosa Ziehau 		int i;
2562fdd0222aSSepherosa Ziehau 
2563fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
2564fdd0222aSSepherosa Ziehau 			taskqueue_free(sc->hn_tx_taskqs[i]);
2565fdd0222aSSepherosa Ziehau 		free(sc->hn_tx_taskqs, M_DEVBUF);
2566fdd0222aSSepherosa Ziehau 	}
256715516c77SSepherosa Ziehau 	taskqueue_free(sc->hn_mgmt_taskq0);
25689c6cae24SSepherosa Ziehau 	if (sc->hn_vf_taskq != NULL)
25699c6cae24SSepherosa Ziehau 		taskqueue_free(sc->hn_vf_taskq);
257015516c77SSepherosa Ziehau 
257125641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL) {
257225641fc7SSepherosa Ziehau 		/*
257325641fc7SSepherosa Ziehau 		 * Uninstall the orphan handler _before_ the xact is
257425641fc7SSepherosa Ziehau 		 * destructed.
257525641fc7SSepherosa Ziehau 		 */
257625641fc7SSepherosa Ziehau 		vmbus_chan_unset_orphan(sc->hn_prichan);
257715516c77SSepherosa Ziehau 		vmbus_xact_ctx_destroy(sc->hn_xact);
257825641fc7SSepherosa Ziehau 	}
257915516c77SSepherosa Ziehau 
258015516c77SSepherosa Ziehau 	if_free(ifp);
258115516c77SSepherosa Ziehau 
258215516c77SSepherosa Ziehau 	HN_LOCK_DESTROY(sc);
25839c6cae24SSepherosa Ziehau 	rm_destroy(&sc->hn_vf_lock);
258415516c77SSepherosa Ziehau 	return (0);
258515516c77SSepherosa Ziehau }
258615516c77SSepherosa Ziehau 
258715516c77SSepherosa Ziehau static int
258815516c77SSepherosa Ziehau hn_shutdown(device_t dev)
258915516c77SSepherosa Ziehau {
259015516c77SSepherosa Ziehau 
259115516c77SSepherosa Ziehau 	return (0);
259215516c77SSepherosa Ziehau }
259315516c77SSepherosa Ziehau 
259415516c77SSepherosa Ziehau static void
259515516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc)
259615516c77SSepherosa Ziehau {
259715516c77SSepherosa Ziehau 	uint32_t link_status;
259815516c77SSepherosa Ziehau 	int error;
259915516c77SSepherosa Ziehau 
260015516c77SSepherosa Ziehau 	error = hn_rndis_get_linkstatus(sc, &link_status);
260115516c77SSepherosa Ziehau 	if (error) {
260215516c77SSepherosa Ziehau 		/* XXX what to do? */
260315516c77SSepherosa Ziehau 		return;
260415516c77SSepherosa Ziehau 	}
260515516c77SSepherosa Ziehau 
260615516c77SSepherosa Ziehau 	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
260715516c77SSepherosa Ziehau 		sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
260815516c77SSepherosa Ziehau 	else
260915516c77SSepherosa Ziehau 		sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
261015516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp,
261115516c77SSepherosa Ziehau 	    (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ?
261215516c77SSepherosa Ziehau 	    LINK_STATE_UP : LINK_STATE_DOWN);
261315516c77SSepherosa Ziehau }
261415516c77SSepherosa Ziehau 
261515516c77SSepherosa Ziehau static void
261615516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused)
261715516c77SSepherosa Ziehau {
261815516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
261915516c77SSepherosa Ziehau 
262015516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
262115516c77SSepherosa Ziehau 		return;
262215516c77SSepherosa Ziehau 	hn_link_status(sc);
262315516c77SSepherosa Ziehau }
262415516c77SSepherosa Ziehau 
262515516c77SSepherosa Ziehau static void
262615516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused)
262715516c77SSepherosa Ziehau {
262815516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
262915516c77SSepherosa Ziehau 
263015516c77SSepherosa Ziehau 	/* Prevent any link status checks from running. */
263115516c77SSepherosa Ziehau 	sc->hn_link_flags |= HN_LINK_FLAG_NETCHG;
263215516c77SSepherosa Ziehau 
263315516c77SSepherosa Ziehau 	/*
263415516c77SSepherosa Ziehau 	 * Fake up a [link down --> link up] state change; 5 seconds
263515516c77SSepherosa Ziehau 	 * delay is used, which closely simulates miibus reaction
263615516c77SSepherosa Ziehau 	 * upon link down event.
263715516c77SSepherosa Ziehau 	 */
263815516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
263915516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
264015516c77SSepherosa Ziehau 	taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0,
264115516c77SSepherosa Ziehau 	    &sc->hn_netchg_status, 5 * hz);
264215516c77SSepherosa Ziehau }
264315516c77SSepherosa Ziehau 
264415516c77SSepherosa Ziehau static void
264515516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused)
264615516c77SSepherosa Ziehau {
264715516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
264815516c77SSepherosa Ziehau 
264915516c77SSepherosa Ziehau 	/* Re-allow link status checks. */
265015516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG;
265115516c77SSepherosa Ziehau 	hn_link_status(sc);
265215516c77SSepherosa Ziehau }
265315516c77SSepherosa Ziehau 
265415516c77SSepherosa Ziehau static void
265515516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc)
265615516c77SSepherosa Ziehau {
265715516c77SSepherosa Ziehau 
265815516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
265915516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
266015516c77SSepherosa Ziehau }
266115516c77SSepherosa Ziehau 
266215516c77SSepherosa Ziehau static void
266315516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc)
266415516c77SSepherosa Ziehau {
266515516c77SSepherosa Ziehau 
266615516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
266715516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init);
266815516c77SSepherosa Ziehau }
266915516c77SSepherosa Ziehau 
267015516c77SSepherosa Ziehau static __inline int
267115516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
267215516c77SSepherosa Ziehau     struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
267315516c77SSepherosa Ziehau {
267415516c77SSepherosa Ziehau 	struct mbuf *m = *m_head;
267515516c77SSepherosa Ziehau 	int error;
267615516c77SSepherosa Ziehau 
267715516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim"));
267815516c77SSepherosa Ziehau 
267915516c77SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap,
268015516c77SSepherosa Ziehau 	    m, segs, nsegs, BUS_DMA_NOWAIT);
268115516c77SSepherosa Ziehau 	if (error == EFBIG) {
268215516c77SSepherosa Ziehau 		struct mbuf *m_new;
268315516c77SSepherosa Ziehau 
268415516c77SSepherosa Ziehau 		m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX);
268515516c77SSepherosa Ziehau 		if (m_new == NULL)
268615516c77SSepherosa Ziehau 			return ENOBUFS;
268715516c77SSepherosa Ziehau 		else
268815516c77SSepherosa Ziehau 			*m_head = m = m_new;
268915516c77SSepherosa Ziehau 		txr->hn_tx_collapsed++;
269015516c77SSepherosa Ziehau 
269115516c77SSepherosa Ziehau 		error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag,
269215516c77SSepherosa Ziehau 		    txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT);
269315516c77SSepherosa Ziehau 	}
269415516c77SSepherosa Ziehau 	if (!error) {
269515516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap,
269615516c77SSepherosa Ziehau 		    BUS_DMASYNC_PREWRITE);
269715516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_DMAMAP;
269815516c77SSepherosa Ziehau 	}
269915516c77SSepherosa Ziehau 	return error;
270015516c77SSepherosa Ziehau }
270115516c77SSepherosa Ziehau 
270215516c77SSepherosa Ziehau static __inline int
270315516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd)
270415516c77SSepherosa Ziehau {
270515516c77SSepherosa Ziehau 
270615516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0,
270715516c77SSepherosa Ziehau 	    ("put an onlist txd %#x", txd->flags));
2708dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2709dc13fee6SSepherosa Ziehau 	    ("put an onagg txd %#x", txd->flags));
271015516c77SSepherosa Ziehau 
271115516c77SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
271215516c77SSepherosa Ziehau 	if (atomic_fetchadd_int(&txd->refs, -1) != 1)
271315516c77SSepherosa Ziehau 		return 0;
271415516c77SSepherosa Ziehau 
2715dc13fee6SSepherosa Ziehau 	if (!STAILQ_EMPTY(&txd->agg_list)) {
2716dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tmp_txd;
2717dc13fee6SSepherosa Ziehau 
2718dc13fee6SSepherosa Ziehau 		while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) {
2719a0f49d67SMateusz Guzik 			int freed __diagused;
2720dc13fee6SSepherosa Ziehau 
2721dc13fee6SSepherosa Ziehau 			KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list),
2722dc13fee6SSepherosa Ziehau 			    ("resursive aggregation on aggregated txdesc"));
2723dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG),
2724dc13fee6SSepherosa Ziehau 			    ("not aggregated txdesc"));
2725dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
2726dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc uses dmamap"));
2727dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
2728dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc consumes "
2729dc13fee6SSepherosa Ziehau 			     "chimney sending buffer"));
2730dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_size == 0,
2731dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc has non-zero "
2732dc13fee6SSepherosa Ziehau 			     "chimney sending size"));
2733dc13fee6SSepherosa Ziehau 
2734dc13fee6SSepherosa Ziehau 			STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link);
2735dc13fee6SSepherosa Ziehau 			tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG;
2736dc13fee6SSepherosa Ziehau 			freed = hn_txdesc_put(txr, tmp_txd);
2737dc13fee6SSepherosa Ziehau 			KASSERT(freed, ("failed to free aggregated txdesc"));
2738dc13fee6SSepherosa Ziehau 		}
2739dc13fee6SSepherosa Ziehau 	}
2740dc13fee6SSepherosa Ziehau 
274115516c77SSepherosa Ziehau 	if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) {
274215516c77SSepherosa Ziehau 		KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
274315516c77SSepherosa Ziehau 		    ("chim txd uses dmamap"));
274415516c77SSepherosa Ziehau 		hn_chim_free(txr->hn_sc, txd->chim_index);
274515516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
2746dc13fee6SSepherosa Ziehau 		txd->chim_size = 0;
274715516c77SSepherosa Ziehau 	} else if (txd->flags & HN_TXD_FLAG_DMAMAP) {
274815516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag,
274915516c77SSepherosa Ziehau 		    txd->data_dmap, BUS_DMASYNC_POSTWRITE);
275015516c77SSepherosa Ziehau 		bus_dmamap_unload(txr->hn_tx_data_dtag,
275115516c77SSepherosa Ziehau 		    txd->data_dmap);
275215516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_DMAMAP;
275315516c77SSepherosa Ziehau 	}
275415516c77SSepherosa Ziehau 
275515516c77SSepherosa Ziehau 	if (txd->m != NULL) {
275615516c77SSepherosa Ziehau 		m_freem(txd->m);
275715516c77SSepherosa Ziehau 		txd->m = NULL;
275815516c77SSepherosa Ziehau 	}
275915516c77SSepherosa Ziehau 
276015516c77SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONLIST;
276115516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
276215516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
276315516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_avail >= 0 &&
276415516c77SSepherosa Ziehau 	    txr->hn_txdesc_avail < txr->hn_txdesc_cnt,
276515516c77SSepherosa Ziehau 	    ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail));
276615516c77SSepherosa Ziehau 	txr->hn_txdesc_avail++;
276715516c77SSepherosa Ziehau 	SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
276815516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
276985e4ae1eSSepherosa Ziehau #else	/* HN_USE_TXDESC_BUFRING */
277085e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
277115516c77SSepherosa Ziehau 	atomic_add_int(&txr->hn_txdesc_avail, 1);
277215516c77SSepherosa Ziehau #endif
277385e4ae1eSSepherosa Ziehau 	buf_ring_enqueue(txr->hn_txdesc_br, txd);
277485e4ae1eSSepherosa Ziehau #endif	/* !HN_USE_TXDESC_BUFRING */
277515516c77SSepherosa Ziehau 
277615516c77SSepherosa Ziehau 	return 1;
277715516c77SSepherosa Ziehau }
277815516c77SSepherosa Ziehau 
277915516c77SSepherosa Ziehau static __inline struct hn_txdesc *
278015516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr)
278115516c77SSepherosa Ziehau {
278215516c77SSepherosa Ziehau 	struct hn_txdesc *txd;
278315516c77SSepherosa Ziehau 
278415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
278515516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
278615516c77SSepherosa Ziehau 	txd = SLIST_FIRST(&txr->hn_txlist);
278715516c77SSepherosa Ziehau 	if (txd != NULL) {
278815516c77SSepherosa Ziehau 		KASSERT(txr->hn_txdesc_avail > 0,
278915516c77SSepherosa Ziehau 		    ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail));
279015516c77SSepherosa Ziehau 		txr->hn_txdesc_avail--;
279115516c77SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&txr->hn_txlist, link);
279215516c77SSepherosa Ziehau 	}
279315516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
279415516c77SSepherosa Ziehau #else
279515516c77SSepherosa Ziehau 	txd = buf_ring_dequeue_sc(txr->hn_txdesc_br);
279615516c77SSepherosa Ziehau #endif
279715516c77SSepherosa Ziehau 
279815516c77SSepherosa Ziehau 	if (txd != NULL) {
279915516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
280085e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
280115516c77SSepherosa Ziehau 		atomic_subtract_int(&txr->hn_txdesc_avail, 1);
280215516c77SSepherosa Ziehau #endif
280385e4ae1eSSepherosa Ziehau #endif	/* HN_USE_TXDESC_BUFRING */
280415516c77SSepherosa Ziehau 		KASSERT(txd->m == NULL && txd->refs == 0 &&
2805dc13fee6SSepherosa Ziehau 		    STAILQ_EMPTY(&txd->agg_list) &&
280615516c77SSepherosa Ziehau 		    txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
2807dc13fee6SSepherosa Ziehau 		    txd->chim_size == 0 &&
280815516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONLIST) &&
2809dc13fee6SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONAGG) == 0 &&
281015516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd"));
281115516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_ONLIST;
281215516c77SSepherosa Ziehau 		txd->refs = 1;
281315516c77SSepherosa Ziehau 	}
281415516c77SSepherosa Ziehau 	return txd;
281515516c77SSepherosa Ziehau }
281615516c77SSepherosa Ziehau 
281715516c77SSepherosa Ziehau static __inline void
281815516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd)
281915516c77SSepherosa Ziehau {
282015516c77SSepherosa Ziehau 
282115516c77SSepherosa Ziehau 	/* 0->1 transition will never work */
282225641fc7SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
282315516c77SSepherosa Ziehau 	atomic_add_int(&txd->refs, 1);
282415516c77SSepherosa Ziehau }
282515516c77SSepherosa Ziehau 
2826dc13fee6SSepherosa Ziehau static __inline void
2827dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd)
2828dc13fee6SSepherosa Ziehau {
2829dc13fee6SSepherosa Ziehau 
2830dc13fee6SSepherosa Ziehau 	KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2831dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on aggregating txdesc"));
2832dc13fee6SSepherosa Ziehau 
2833dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2834dc13fee6SSepherosa Ziehau 	    ("already aggregated"));
2835dc13fee6SSepherosa Ziehau 	KASSERT(STAILQ_EMPTY(&txd->agg_list),
2836dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on to-be-aggregated txdesc"));
2837dc13fee6SSepherosa Ziehau 
2838dc13fee6SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONAGG;
2839dc13fee6SSepherosa Ziehau 	STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link);
2840dc13fee6SSepherosa Ziehau }
2841dc13fee6SSepherosa Ziehau 
284215516c77SSepherosa Ziehau static bool
284315516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr)
284415516c77SSepherosa Ziehau {
284515516c77SSepherosa Ziehau 	bool pending = false;
284615516c77SSepherosa Ziehau 
284715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
284815516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
284915516c77SSepherosa Ziehau 	if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt)
285015516c77SSepherosa Ziehau 		pending = true;
285115516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
285215516c77SSepherosa Ziehau #else
285315516c77SSepherosa Ziehau 	if (!buf_ring_full(txr->hn_txdesc_br))
285415516c77SSepherosa Ziehau 		pending = true;
285515516c77SSepherosa Ziehau #endif
285615516c77SSepherosa Ziehau 	return (pending);
285715516c77SSepherosa Ziehau }
285815516c77SSepherosa Ziehau 
285915516c77SSepherosa Ziehau static __inline void
286015516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr)
286115516c77SSepherosa Ziehau {
286215516c77SSepherosa Ziehau 	txr->hn_has_txeof = 0;
286315516c77SSepherosa Ziehau 	txr->hn_txeof(txr);
286415516c77SSepherosa Ziehau }
286515516c77SSepherosa Ziehau 
286615516c77SSepherosa Ziehau static void
286715516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc,
286815516c77SSepherosa Ziehau     struct vmbus_channel *chan, const void *data __unused, int dlen __unused)
286915516c77SSepherosa Ziehau {
287015516c77SSepherosa Ziehau 	struct hn_txdesc *txd = sndc->hn_cbarg;
287115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
287215516c77SSepherosa Ziehau 
287315516c77SSepherosa Ziehau 	txr = txd->txr;
287415516c77SSepherosa Ziehau 	KASSERT(txr->hn_chan == chan,
287515516c77SSepherosa Ziehau 	    ("channel mismatch, on chan%u, should be chan%u",
2876aa1a2adcSSepherosa Ziehau 	     vmbus_chan_id(chan), vmbus_chan_id(txr->hn_chan)));
287715516c77SSepherosa Ziehau 
287815516c77SSepherosa Ziehau 	txr->hn_has_txeof = 1;
287915516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
288015516c77SSepherosa Ziehau 
288115516c77SSepherosa Ziehau 	++txr->hn_txdone_cnt;
288215516c77SSepherosa Ziehau 	if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) {
288315516c77SSepherosa Ziehau 		txr->hn_txdone_cnt = 0;
288415516c77SSepherosa Ziehau 		if (txr->hn_oactive)
288515516c77SSepherosa Ziehau 			hn_txeof(txr);
288615516c77SSepherosa Ziehau 	}
288715516c77SSepherosa Ziehau }
288815516c77SSepherosa Ziehau 
288915516c77SSepherosa Ziehau static void
289015516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
289115516c77SSepherosa Ziehau {
289215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
289326d79d40SMichael Tuexen 	struct epoch_tracker et;
289426d79d40SMichael Tuexen 
289526d79d40SMichael Tuexen 	NET_EPOCH_ENTER(et);
289615516c77SSepherosa Ziehau 	tcp_lro_flush_all(&rxr->hn_lro);
289726d79d40SMichael Tuexen 	NET_EPOCH_EXIT(et);
289815516c77SSepherosa Ziehau #endif
289915516c77SSepherosa Ziehau 
290015516c77SSepherosa Ziehau 	/*
290115516c77SSepherosa Ziehau 	 * NOTE:
290215516c77SSepherosa Ziehau 	 * 'txr' could be NULL, if multiple channels and
290315516c77SSepherosa Ziehau 	 * ifnet.if_start method are enabled.
290415516c77SSepherosa Ziehau 	 */
290515516c77SSepherosa Ziehau 	if (txr == NULL || !txr->hn_has_txeof)
290615516c77SSepherosa Ziehau 		return;
290715516c77SSepherosa Ziehau 
290815516c77SSepherosa Ziehau 	txr->hn_txdone_cnt = 0;
290915516c77SSepherosa Ziehau 	hn_txeof(txr);
291015516c77SSepherosa Ziehau }
291115516c77SSepherosa Ziehau 
291215516c77SSepherosa Ziehau static __inline uint32_t
291315516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs)
291415516c77SSepherosa Ziehau {
291515516c77SSepherosa Ziehau 
291615516c77SSepherosa Ziehau 	KASSERT(ofs >= sizeof(struct rndis_packet_msg),
291715516c77SSepherosa Ziehau 	    ("invalid RNDIS packet msg offset %u", ofs));
291815516c77SSepherosa Ziehau 	return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset));
291915516c77SSepherosa Ziehau }
292015516c77SSepherosa Ziehau 
292115516c77SSepherosa Ziehau static __inline void *
292215516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
292315516c77SSepherosa Ziehau     size_t pi_dlen, uint32_t pi_type)
292415516c77SSepherosa Ziehau {
292515516c77SSepherosa Ziehau 	const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
292615516c77SSepherosa Ziehau 	struct rndis_pktinfo *pi;
292715516c77SSepherosa Ziehau 
292815516c77SSepherosa Ziehau 	KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
292915516c77SSepherosa Ziehau 	    ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
293015516c77SSepherosa Ziehau 
293115516c77SSepherosa Ziehau 	/*
293215516c77SSepherosa Ziehau 	 * Per-packet-info does not move; it only grows.
293315516c77SSepherosa Ziehau 	 *
293415516c77SSepherosa Ziehau 	 * NOTE:
293515516c77SSepherosa Ziehau 	 * rm_pktinfooffset in this phase counts from the beginning
293615516c77SSepherosa Ziehau 	 * of rndis_packet_msg.
293715516c77SSepherosa Ziehau 	 */
293815516c77SSepherosa Ziehau 	KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
293915516c77SSepherosa Ziehau 	    ("%u pktinfo overflows RNDIS packet msg", pi_type));
294015516c77SSepherosa Ziehau 	pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
294115516c77SSepherosa Ziehau 	    pkt->rm_pktinfolen);
294215516c77SSepherosa Ziehau 	pkt->rm_pktinfolen += pi_size;
294315516c77SSepherosa Ziehau 
294415516c77SSepherosa Ziehau 	pi->rm_size = pi_size;
294515516c77SSepherosa Ziehau 	pi->rm_type = pi_type;
2946805dbff6SWei Hu 	pi->rm_internal = 0;
294715516c77SSepherosa Ziehau 	pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
294815516c77SSepherosa Ziehau 
294915516c77SSepherosa Ziehau 	return (pi->rm_data);
295015516c77SSepherosa Ziehau }
295115516c77SSepherosa Ziehau 
2952dc13fee6SSepherosa Ziehau static __inline int
2953dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr)
2954dc13fee6SSepherosa Ziehau {
2955dc13fee6SSepherosa Ziehau 	struct hn_txdesc *txd;
2956dc13fee6SSepherosa Ziehau 	struct mbuf *m;
2957dc13fee6SSepherosa Ziehau 	int error, pkts;
2958dc13fee6SSepherosa Ziehau 
2959dc13fee6SSepherosa Ziehau 	txd = txr->hn_agg_txd;
2960dc13fee6SSepherosa Ziehau 	KASSERT(txd != NULL, ("no aggregate txdesc"));
2961dc13fee6SSepherosa Ziehau 
2962dc13fee6SSepherosa Ziehau 	/*
2963dc13fee6SSepherosa Ziehau 	 * Since hn_txpkt() will reset this temporary stat, save
2964dc13fee6SSepherosa Ziehau 	 * it now, so that oerrors can be updated properly, if
2965dc13fee6SSepherosa Ziehau 	 * hn_txpkt() ever fails.
2966dc13fee6SSepherosa Ziehau 	 */
2967dc13fee6SSepherosa Ziehau 	pkts = txr->hn_stat_pkts;
2968dc13fee6SSepherosa Ziehau 
2969dc13fee6SSepherosa Ziehau 	/*
2970dc13fee6SSepherosa Ziehau 	 * Since txd's mbuf will _not_ be freed upon hn_txpkt()
2971dc13fee6SSepherosa Ziehau 	 * failure, save it for later freeing, if hn_txpkt() ever
2972dc13fee6SSepherosa Ziehau 	 * fails.
2973dc13fee6SSepherosa Ziehau 	 */
2974dc13fee6SSepherosa Ziehau 	m = txd->m;
2975dc13fee6SSepherosa Ziehau 	error = hn_txpkt(ifp, txr, txd);
2976dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
2977dc13fee6SSepherosa Ziehau 		/* txd is freed, but m is not. */
2978dc13fee6SSepherosa Ziehau 		m_freem(m);
2979dc13fee6SSepherosa Ziehau 
2980dc13fee6SSepherosa Ziehau 		txr->hn_flush_failed++;
2981dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts);
2982dc13fee6SSepherosa Ziehau 	}
2983dc13fee6SSepherosa Ziehau 
2984dc13fee6SSepherosa Ziehau 	/* Reset all aggregation states. */
2985dc13fee6SSepherosa Ziehau 	txr->hn_agg_txd = NULL;
2986dc13fee6SSepherosa Ziehau 	txr->hn_agg_szleft = 0;
2987dc13fee6SSepherosa Ziehau 	txr->hn_agg_pktleft = 0;
2988dc13fee6SSepherosa Ziehau 	txr->hn_agg_prevpkt = NULL;
2989dc13fee6SSepherosa Ziehau 
2990dc13fee6SSepherosa Ziehau 	return (error);
2991dc13fee6SSepherosa Ziehau }
2992dc13fee6SSepherosa Ziehau 
2993dc13fee6SSepherosa Ziehau static void *
2994dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
2995dc13fee6SSepherosa Ziehau     int pktsize)
2996dc13fee6SSepherosa Ziehau {
2997dc13fee6SSepherosa Ziehau 	void *chim;
2998dc13fee6SSepherosa Ziehau 
2999dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL) {
3000dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) {
3001dc13fee6SSepherosa Ziehau 			struct hn_txdesc *agg_txd = txr->hn_agg_txd;
3002dc13fee6SSepherosa Ziehau 			struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt;
3003dc13fee6SSepherosa Ziehau 			int olen;
3004dc13fee6SSepherosa Ziehau 
3005dc13fee6SSepherosa Ziehau 			/*
3006dc13fee6SSepherosa Ziehau 			 * Update the previous RNDIS packet's total length,
3007dc13fee6SSepherosa Ziehau 			 * it can be increased due to the mandatory alignment
3008dc13fee6SSepherosa Ziehau 			 * padding for this RNDIS packet.  And update the
3009dc13fee6SSepherosa Ziehau 			 * aggregating txdesc's chimney sending buffer size
3010dc13fee6SSepherosa Ziehau 			 * accordingly.
3011dc13fee6SSepherosa Ziehau 			 *
3012dc13fee6SSepherosa Ziehau 			 * XXX
3013dc13fee6SSepherosa Ziehau 			 * Zero-out the padding, as required by the RNDIS spec.
3014dc13fee6SSepherosa Ziehau 			 */
3015dc13fee6SSepherosa Ziehau 			olen = pkt->rm_len;
3016dc13fee6SSepherosa Ziehau 			pkt->rm_len = roundup2(olen, txr->hn_agg_align);
3017dc13fee6SSepherosa Ziehau 			agg_txd->chim_size += pkt->rm_len - olen;
3018dc13fee6SSepherosa Ziehau 
3019dc13fee6SSepherosa Ziehau 			/* Link this txdesc to the parent. */
3020dc13fee6SSepherosa Ziehau 			hn_txdesc_agg(agg_txd, txd);
3021dc13fee6SSepherosa Ziehau 
3022dc13fee6SSepherosa Ziehau 			chim = (uint8_t *)pkt + pkt->rm_len;
3023dc13fee6SSepherosa Ziehau 			/* Save the current packet for later fixup. */
3024dc13fee6SSepherosa Ziehau 			txr->hn_agg_prevpkt = chim;
3025dc13fee6SSepherosa Ziehau 
3026dc13fee6SSepherosa Ziehau 			txr->hn_agg_pktleft--;
3027dc13fee6SSepherosa Ziehau 			txr->hn_agg_szleft -= pktsize;
3028dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_szleft <=
3029dc13fee6SSepherosa Ziehau 			    HN_PKTSIZE_MIN(txr->hn_agg_align)) {
3030dc13fee6SSepherosa Ziehau 				/*
3031dc13fee6SSepherosa Ziehau 				 * Probably can't aggregate more packets,
3032dc13fee6SSepherosa Ziehau 				 * flush this aggregating txdesc proactively.
3033dc13fee6SSepherosa Ziehau 				 */
3034dc13fee6SSepherosa Ziehau 				txr->hn_agg_pktleft = 0;
3035dc13fee6SSepherosa Ziehau 			}
3036dc13fee6SSepherosa Ziehau 			/* Done! */
3037dc13fee6SSepherosa Ziehau 			return (chim);
3038dc13fee6SSepherosa Ziehau 		}
3039dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
3040dc13fee6SSepherosa Ziehau 	}
3041dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
3042dc13fee6SSepherosa Ziehau 
3043dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney_tried++;
3044dc13fee6SSepherosa Ziehau 	txd->chim_index = hn_chim_alloc(txr->hn_sc);
3045dc13fee6SSepherosa Ziehau 	if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID)
3046dc13fee6SSepherosa Ziehau 		return (NULL);
3047dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney++;
3048dc13fee6SSepherosa Ziehau 
3049dc13fee6SSepherosa Ziehau 	chim = txr->hn_sc->hn_chim +
3050dc13fee6SSepherosa Ziehau 	    (txd->chim_index * txr->hn_sc->hn_chim_szmax);
3051dc13fee6SSepherosa Ziehau 
3052dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_pktmax > 1 &&
3053dc13fee6SSepherosa Ziehau 	    txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) {
3054dc13fee6SSepherosa Ziehau 		txr->hn_agg_txd = txd;
3055dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1;
3056dc13fee6SSepherosa Ziehau 		txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize;
3057dc13fee6SSepherosa Ziehau 		txr->hn_agg_prevpkt = chim;
3058dc13fee6SSepherosa Ziehau 	}
3059dc13fee6SSepherosa Ziehau 	return (chim);
3060dc13fee6SSepherosa Ziehau }
3061dc13fee6SSepherosa Ziehau 
306215516c77SSepherosa Ziehau /*
306315516c77SSepherosa Ziehau  * NOTE:
306415516c77SSepherosa Ziehau  * If this function fails, then both txd and m_head0 will be freed.
306515516c77SSepherosa Ziehau  */
306615516c77SSepherosa Ziehau static int
3067dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
3068dc13fee6SSepherosa Ziehau     struct mbuf **m_head0)
306915516c77SSepherosa Ziehau {
307015516c77SSepherosa Ziehau 	bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX];
307115516c77SSepherosa Ziehau 	int error, nsegs, i;
307215516c77SSepherosa Ziehau 	struct mbuf *m_head = *m_head0;
307315516c77SSepherosa Ziehau 	struct rndis_packet_msg *pkt;
307415516c77SSepherosa Ziehau 	uint32_t *pi_data;
30758966e5d5SSepherosa Ziehau 	void *chim = NULL;
3076dc13fee6SSepherosa Ziehau 	int pkt_hlen, pkt_size;
307715516c77SSepherosa Ziehau 
307815516c77SSepherosa Ziehau 	pkt = txd->rndis_pkt;
3079dc13fee6SSepherosa Ziehau 	pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align);
3080dc13fee6SSepherosa Ziehau 	if (pkt_size < txr->hn_chim_size) {
3081dc13fee6SSepherosa Ziehau 		chim = hn_try_txagg(ifp, txr, txd, pkt_size);
3082dc13fee6SSepherosa Ziehau 		if (chim != NULL)
30838966e5d5SSepherosa Ziehau 			pkt = chim;
3084dc13fee6SSepherosa Ziehau 	} else {
3085dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL)
3086dc13fee6SSepherosa Ziehau 			hn_flush_txagg(ifp, txr);
30878966e5d5SSepherosa Ziehau 	}
30888966e5d5SSepherosa Ziehau 
308915516c77SSepherosa Ziehau 	pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
30908fe90f73SSepherosa Ziehau 	pkt->rm_len = m_head->m_pkthdr.len;
30919130c4f7SSepherosa Ziehau 	pkt->rm_dataoffset = 0;
309215516c77SSepherosa Ziehau 	pkt->rm_datalen = m_head->m_pkthdr.len;
3093dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataoffset = 0;
3094dc13fee6SSepherosa Ziehau 	pkt->rm_oobdatalen = 0;
3095dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataelements = 0;
309615516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = sizeof(*pkt);
309715516c77SSepherosa Ziehau 	pkt->rm_pktinfolen = 0;
3098dc13fee6SSepherosa Ziehau 	pkt->rm_vchandle = 0;
3099dc13fee6SSepherosa Ziehau 	pkt->rm_reserved = 0;
310015516c77SSepherosa Ziehau 
310115516c77SSepherosa Ziehau 	if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) {
310215516c77SSepherosa Ziehau 		/*
310380f39bd9SWei Hu 		 * Set the hash value for this packet.
310415516c77SSepherosa Ziehau 		 */
310515516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
310615516c77SSepherosa Ziehau 		    HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL);
310780f39bd9SWei Hu 
310880f39bd9SWei Hu 		if (M_HASHTYPE_ISHASH(m_head))
310980f39bd9SWei Hu 			/*
311080f39bd9SWei Hu 			 * The flowid field contains the hash value host
311180f39bd9SWei Hu 			 * set in the rx queue if it is a ip forwarding pkt.
311280f39bd9SWei Hu 			 * Set the same hash value so host can send on the
311380f39bd9SWei Hu 			 * cpu it was received.
311480f39bd9SWei Hu 			 */
311580f39bd9SWei Hu 			*pi_data = m_head->m_pkthdr.flowid;
311680f39bd9SWei Hu 		else
311780f39bd9SWei Hu 			/*
311880f39bd9SWei Hu 			 * Otherwise just put the tx queue index.
311980f39bd9SWei Hu 			 */
312015516c77SSepherosa Ziehau 			*pi_data = txr->hn_tx_idx;
312115516c77SSepherosa Ziehau 	}
312215516c77SSepherosa Ziehau 
312315516c77SSepherosa Ziehau 	if (m_head->m_flags & M_VLANTAG) {
312415516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
312515516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
312615516c77SSepherosa Ziehau 		*pi_data = NDIS_VLAN_INFO_MAKE(
312715516c77SSepherosa Ziehau 		    EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag),
312815516c77SSepherosa Ziehau 		    EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag),
312915516c77SSepherosa Ziehau 		    EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag));
313015516c77SSepherosa Ziehau 	}
313115516c77SSepherosa Ziehau 
313215516c77SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
313315516c77SSepherosa Ziehau #if defined(INET6) || defined(INET)
313415516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
313515516c77SSepherosa Ziehau 		    NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO);
313615516c77SSepherosa Ziehau #ifdef INET
313715516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
3138c49d47daSSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV4(
3139c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen,
314015516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
314115516c77SSepherosa Ziehau 		}
314215516c77SSepherosa Ziehau #endif
314315516c77SSepherosa Ziehau #if defined(INET6) && defined(INET)
314415516c77SSepherosa Ziehau 		else
314515516c77SSepherosa Ziehau #endif
314615516c77SSepherosa Ziehau #ifdef INET6
314715516c77SSepherosa Ziehau 		{
3148c49d47daSSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV6(
3149c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen,
315015516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
315115516c77SSepherosa Ziehau 		}
315215516c77SSepherosa Ziehau #endif
315315516c77SSepherosa Ziehau #endif	/* INET6 || INET */
315415516c77SSepherosa Ziehau 	} else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) {
315515516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
315615516c77SSepherosa Ziehau 		    NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
315715516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
315815516c77SSepherosa Ziehau 		    (CSUM_IP6_TCP | CSUM_IP6_UDP)) {
315915516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV6;
316015516c77SSepherosa Ziehau 		} else {
316115516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV4;
316215516c77SSepherosa Ziehau 			if (m_head->m_pkthdr.csum_flags & CSUM_IP)
316315516c77SSepherosa Ziehau 				*pi_data |= NDIS_TXCSUM_INFO_IPCS;
316415516c77SSepherosa Ziehau 		}
316515516c77SSepherosa Ziehau 
3166c49d47daSSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
3167c49d47daSSepherosa Ziehau 		    (CSUM_IP_TCP | CSUM_IP6_TCP)) {
3168c49d47daSSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_MKTCPCS(
3169c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen);
3170c49d47daSSepherosa Ziehau 		} else if (m_head->m_pkthdr.csum_flags &
3171c49d47daSSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP6_UDP)) {
3172c49d47daSSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_MKUDPCS(
3173c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen);
3174c49d47daSSepherosa Ziehau 		}
317515516c77SSepherosa Ziehau 	}
317615516c77SSepherosa Ziehau 
3177dc13fee6SSepherosa Ziehau 	pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
31788fe90f73SSepherosa Ziehau 	/* Fixup RNDIS packet message total length */
31798fe90f73SSepherosa Ziehau 	pkt->rm_len += pkt_hlen;
318015516c77SSepherosa Ziehau 	/* Convert RNDIS packet message offsets */
31819130c4f7SSepherosa Ziehau 	pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt_hlen);
318215516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset);
318315516c77SSepherosa Ziehau 
318415516c77SSepherosa Ziehau 	/*
31858966e5d5SSepherosa Ziehau 	 * Fast path: Chimney sending.
318615516c77SSepherosa Ziehau 	 */
31878966e5d5SSepherosa Ziehau 	if (chim != NULL) {
3188dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tgt_txd = txd;
3189dc13fee6SSepherosa Ziehau 
3190dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL) {
3191dc13fee6SSepherosa Ziehau 			tgt_txd = txr->hn_agg_txd;
3192dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
3193dc13fee6SSepherosa Ziehau 			*m_head0 = NULL;
3194dc13fee6SSepherosa Ziehau #endif
3195dc13fee6SSepherosa Ziehau 		}
3196dc13fee6SSepherosa Ziehau 
3197dc13fee6SSepherosa Ziehau 		KASSERT(pkt == chim,
3198dc13fee6SSepherosa Ziehau 		    ("RNDIS pkt not in chimney sending buffer"));
3199dc13fee6SSepherosa Ziehau 		KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID,
3200dc13fee6SSepherosa Ziehau 		    ("chimney sending buffer is not used"));
3201dc13fee6SSepherosa Ziehau 		tgt_txd->chim_size += pkt->rm_len;
320215516c77SSepherosa Ziehau 
32038966e5d5SSepherosa Ziehau 		m_copydata(m_head, 0, m_head->m_pkthdr.len,
3204dc13fee6SSepherosa Ziehau 		    ((uint8_t *)chim) + pkt_hlen);
320515516c77SSepherosa Ziehau 
320615516c77SSepherosa Ziehau 		txr->hn_gpa_cnt = 0;
320715516c77SSepherosa Ziehau 		txr->hn_sendpkt = hn_txpkt_chim;
320815516c77SSepherosa Ziehau 		goto done;
320915516c77SSepherosa Ziehau 	}
3210dc13fee6SSepherosa Ziehau 
3211dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc"));
32128966e5d5SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
32138966e5d5SSepherosa Ziehau 	    ("chimney buffer is used"));
32148966e5d5SSepherosa Ziehau 	KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc"));
321515516c77SSepherosa Ziehau 
321615516c77SSepherosa Ziehau 	error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs);
3217dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
3218a0f49d67SMateusz Guzik 		int freed __diagused;
321915516c77SSepherosa Ziehau 
322015516c77SSepherosa Ziehau 		/*
322115516c77SSepherosa Ziehau 		 * This mbuf is not linked w/ the txd yet, so free it now.
322215516c77SSepherosa Ziehau 		 */
322315516c77SSepherosa Ziehau 		m_freem(m_head);
322415516c77SSepherosa Ziehau 		*m_head0 = NULL;
322515516c77SSepherosa Ziehau 
322615516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
322715516c77SSepherosa Ziehau 		KASSERT(freed != 0,
322815516c77SSepherosa Ziehau 		    ("fail to free txd upon txdma error"));
322915516c77SSepherosa Ziehau 
323015516c77SSepherosa Ziehau 		txr->hn_txdma_failed++;
3231dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
323215516c77SSepherosa Ziehau 		return error;
323315516c77SSepherosa Ziehau 	}
323415516c77SSepherosa Ziehau 	*m_head0 = m_head;
323515516c77SSepherosa Ziehau 
323615516c77SSepherosa Ziehau 	/* +1 RNDIS packet message */
323715516c77SSepherosa Ziehau 	txr->hn_gpa_cnt = nsegs + 1;
323815516c77SSepherosa Ziehau 
323915516c77SSepherosa Ziehau 	/* send packet with page buffer */
324015516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr);
324115516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK;
3242dc13fee6SSepherosa Ziehau 	txr->hn_gpa[0].gpa_len = pkt_hlen;
324315516c77SSepherosa Ziehau 
324415516c77SSepherosa Ziehau 	/*
324515516c77SSepherosa Ziehau 	 * Fill the page buffers with mbuf info after the page
324615516c77SSepherosa Ziehau 	 * buffer for RNDIS packet message.
324715516c77SSepherosa Ziehau 	 */
324815516c77SSepherosa Ziehau 	for (i = 0; i < nsegs; ++i) {
324915516c77SSepherosa Ziehau 		struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1];
325015516c77SSepherosa Ziehau 
325115516c77SSepherosa Ziehau 		gpa->gpa_page = atop(segs[i].ds_addr);
325215516c77SSepherosa Ziehau 		gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK;
325315516c77SSepherosa Ziehau 		gpa->gpa_len = segs[i].ds_len;
325415516c77SSepherosa Ziehau 	}
325515516c77SSepherosa Ziehau 
325615516c77SSepherosa Ziehau 	txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
325715516c77SSepherosa Ziehau 	txd->chim_size = 0;
325815516c77SSepherosa Ziehau 	txr->hn_sendpkt = hn_txpkt_sglist;
325915516c77SSepherosa Ziehau done:
326015516c77SSepherosa Ziehau 	txd->m = m_head;
326115516c77SSepherosa Ziehau 
326215516c77SSepherosa Ziehau 	/* Set the completion routine */
326315516c77SSepherosa Ziehau 	hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd);
326415516c77SSepherosa Ziehau 
3265dc13fee6SSepherosa Ziehau 	/* Update temporary stats for later use. */
3266dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts++;
3267dc13fee6SSepherosa Ziehau 	txr->hn_stat_size += m_head->m_pkthdr.len;
3268dc13fee6SSepherosa Ziehau 	if (m_head->m_flags & M_MCAST)
3269dc13fee6SSepherosa Ziehau 		txr->hn_stat_mcasts++;
3270dc13fee6SSepherosa Ziehau 
327115516c77SSepherosa Ziehau 	return 0;
327215516c77SSepherosa Ziehau }
327315516c77SSepherosa Ziehau 
327415516c77SSepherosa Ziehau /*
327515516c77SSepherosa Ziehau  * NOTE:
327615516c77SSepherosa Ziehau  * If this function fails, then txd will be freed, but the mbuf
327715516c77SSepherosa Ziehau  * associated w/ the txd will _not_ be freed.
327815516c77SSepherosa Ziehau  */
327915516c77SSepherosa Ziehau static int
328015516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd)
328115516c77SSepherosa Ziehau {
32828e7d3136SSepherosa Ziehau 	int error, send_failed = 0, has_bpf;
328315516c77SSepherosa Ziehau 
328415516c77SSepherosa Ziehau again:
32858e7d3136SSepherosa Ziehau 	has_bpf = bpf_peers_present(ifp->if_bpf);
32868e7d3136SSepherosa Ziehau 	if (has_bpf) {
328715516c77SSepherosa Ziehau 		/*
32888e7d3136SSepherosa Ziehau 		 * Make sure that this txd and any aggregated txds are not
32898e7d3136SSepherosa Ziehau 		 * freed before ETHER_BPF_MTAP.
329015516c77SSepherosa Ziehau 		 */
329115516c77SSepherosa Ziehau 		hn_txdesc_hold(txd);
32928e7d3136SSepherosa Ziehau 	}
329315516c77SSepherosa Ziehau 	error = txr->hn_sendpkt(txr, txd);
329415516c77SSepherosa Ziehau 	if (!error) {
32958e7d3136SSepherosa Ziehau 		if (has_bpf) {
3296dc13fee6SSepherosa Ziehau 			const struct hn_txdesc *tmp_txd;
3297dc13fee6SSepherosa Ziehau 
329815516c77SSepherosa Ziehau 			ETHER_BPF_MTAP(ifp, txd->m);
3299dc13fee6SSepherosa Ziehau 			STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link)
3300dc13fee6SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, tmp_txd->m);
3301dc13fee6SSepherosa Ziehau 		}
3302dc13fee6SSepherosa Ziehau 
3303dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts);
330423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
330523bf9e15SSepherosa Ziehau 		if (!hn_use_if_start)
330623bf9e15SSepherosa Ziehau #endif
330723bf9e15SSepherosa Ziehau 		{
330815516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OBYTES,
3309dc13fee6SSepherosa Ziehau 			    txr->hn_stat_size);
3310dc13fee6SSepherosa Ziehau 			if (txr->hn_stat_mcasts != 0) {
3311dc13fee6SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OMCASTS,
3312dc13fee6SSepherosa Ziehau 				    txr->hn_stat_mcasts);
331315516c77SSepherosa Ziehau 			}
3314dc13fee6SSepherosa Ziehau 		}
3315dc13fee6SSepherosa Ziehau 		txr->hn_pkts += txr->hn_stat_pkts;
3316dc13fee6SSepherosa Ziehau 		txr->hn_sends++;
331715516c77SSepherosa Ziehau 	}
33188e7d3136SSepherosa Ziehau 	if (has_bpf)
331915516c77SSepherosa Ziehau 		hn_txdesc_put(txr, txd);
332015516c77SSepherosa Ziehau 
332115516c77SSepherosa Ziehau 	if (__predict_false(error)) {
3322a0f49d67SMateusz Guzik 		int freed __diagused;
332315516c77SSepherosa Ziehau 
332415516c77SSepherosa Ziehau 		/*
332515516c77SSepherosa Ziehau 		 * This should "really rarely" happen.
332615516c77SSepherosa Ziehau 		 *
332715516c77SSepherosa Ziehau 		 * XXX Too many RX to be acked or too many sideband
332815516c77SSepherosa Ziehau 		 * commands to run?  Ask netvsc_channel_rollup()
332915516c77SSepherosa Ziehau 		 * to kick start later.
333015516c77SSepherosa Ziehau 		 */
333115516c77SSepherosa Ziehau 		txr->hn_has_txeof = 1;
333215516c77SSepherosa Ziehau 		if (!send_failed) {
333315516c77SSepherosa Ziehau 			txr->hn_send_failed++;
333415516c77SSepherosa Ziehau 			send_failed = 1;
333515516c77SSepherosa Ziehau 			/*
333615516c77SSepherosa Ziehau 			 * Try sending again after set hn_has_txeof;
333715516c77SSepherosa Ziehau 			 * in case that we missed the last
333815516c77SSepherosa Ziehau 			 * netvsc_channel_rollup().
333915516c77SSepherosa Ziehau 			 */
334015516c77SSepherosa Ziehau 			goto again;
334115516c77SSepherosa Ziehau 		}
334215516c77SSepherosa Ziehau 		if_printf(ifp, "send failed\n");
334315516c77SSepherosa Ziehau 
334415516c77SSepherosa Ziehau 		/*
334515516c77SSepherosa Ziehau 		 * Caller will perform further processing on the
334615516c77SSepherosa Ziehau 		 * associated mbuf, so don't free it in hn_txdesc_put();
334715516c77SSepherosa Ziehau 		 * only unload it from the DMA map in hn_txdesc_put(),
334815516c77SSepherosa Ziehau 		 * if it was loaded.
334915516c77SSepherosa Ziehau 		 */
335015516c77SSepherosa Ziehau 		txd->m = NULL;
335115516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
335215516c77SSepherosa Ziehau 		KASSERT(freed != 0,
335315516c77SSepherosa Ziehau 		    ("fail to free txd upon send error"));
335415516c77SSepherosa Ziehau 
335515516c77SSepherosa Ziehau 		txr->hn_send_failed++;
335615516c77SSepherosa Ziehau 	}
3357dc13fee6SSepherosa Ziehau 
3358dc13fee6SSepherosa Ziehau 	/* Reset temporary stats, after this sending is done. */
3359dc13fee6SSepherosa Ziehau 	txr->hn_stat_size = 0;
3360dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts = 0;
3361dc13fee6SSepherosa Ziehau 	txr->hn_stat_mcasts = 0;
3362dc13fee6SSepherosa Ziehau 
3363dc13fee6SSepherosa Ziehau 	return (error);
336415516c77SSepherosa Ziehau }
336515516c77SSepherosa Ziehau 
336615516c77SSepherosa Ziehau /*
336715516c77SSepherosa Ziehau  * Append the specified data to the indicated mbuf chain,
336815516c77SSepherosa Ziehau  * Extend the mbuf chain if the new data does not fit in
336915516c77SSepherosa Ziehau  * existing space.
337015516c77SSepherosa Ziehau  *
337115516c77SSepherosa Ziehau  * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c.
337215516c77SSepherosa Ziehau  * There should be an equivalent in the kernel mbuf code,
337315516c77SSepherosa Ziehau  * but there does not appear to be one yet.
337415516c77SSepherosa Ziehau  *
337515516c77SSepherosa Ziehau  * Differs from m_append() in that additional mbufs are
337615516c77SSepherosa Ziehau  * allocated with cluster size MJUMPAGESIZE, and filled
337715516c77SSepherosa Ziehau  * accordingly.
337815516c77SSepherosa Ziehau  *
3379a491581fSWei Hu  * Return the last mbuf in the chain or NULL if failed to
3380a491581fSWei Hu  * allocate new mbuf.
338115516c77SSepherosa Ziehau  */
3382a491581fSWei Hu static struct mbuf *
338315516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp)
338415516c77SSepherosa Ziehau {
338515516c77SSepherosa Ziehau 	struct mbuf *m, *n;
338615516c77SSepherosa Ziehau 	int remainder, space;
338715516c77SSepherosa Ziehau 
338815516c77SSepherosa Ziehau 	for (m = m0; m->m_next != NULL; m = m->m_next)
338915516c77SSepherosa Ziehau 		;
339015516c77SSepherosa Ziehau 	remainder = len;
339115516c77SSepherosa Ziehau 	space = M_TRAILINGSPACE(m);
339215516c77SSepherosa Ziehau 	if (space > 0) {
339315516c77SSepherosa Ziehau 		/*
339415516c77SSepherosa Ziehau 		 * Copy into available space.
339515516c77SSepherosa Ziehau 		 */
339615516c77SSepherosa Ziehau 		if (space > remainder)
339715516c77SSepherosa Ziehau 			space = remainder;
339815516c77SSepherosa Ziehau 		bcopy(cp, mtod(m, caddr_t) + m->m_len, space);
339915516c77SSepherosa Ziehau 		m->m_len += space;
340015516c77SSepherosa Ziehau 		cp += space;
340115516c77SSepherosa Ziehau 		remainder -= space;
340215516c77SSepherosa Ziehau 	}
340315516c77SSepherosa Ziehau 	while (remainder > 0) {
340415516c77SSepherosa Ziehau 		/*
340515516c77SSepherosa Ziehau 		 * Allocate a new mbuf; could check space
340615516c77SSepherosa Ziehau 		 * and allocate a cluster instead.
340715516c77SSepherosa Ziehau 		 */
340815516c77SSepherosa Ziehau 		n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE);
340915516c77SSepherosa Ziehau 		if (n == NULL)
3410a491581fSWei Hu 			return NULL;
341115516c77SSepherosa Ziehau 		n->m_len = min(MJUMPAGESIZE, remainder);
341215516c77SSepherosa Ziehau 		bcopy(cp, mtod(n, caddr_t), n->m_len);
341315516c77SSepherosa Ziehau 		cp += n->m_len;
341415516c77SSepherosa Ziehau 		remainder -= n->m_len;
341515516c77SSepherosa Ziehau 		m->m_next = n;
341615516c77SSepherosa Ziehau 		m = n;
341715516c77SSepherosa Ziehau 	}
341815516c77SSepherosa Ziehau 
3419a491581fSWei Hu 	return m;
342015516c77SSepherosa Ziehau }
342115516c77SSepherosa Ziehau 
342215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
342315516c77SSepherosa Ziehau static __inline int
342415516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m)
342515516c77SSepherosa Ziehau {
342615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
342715516c77SSepherosa Ziehau 	if (hn_lro_mbufq_depth) {
342815516c77SSepherosa Ziehau 		tcp_lro_queue_mbuf(lc, m);
342915516c77SSepherosa Ziehau 		return 0;
343015516c77SSepherosa Ziehau 	}
343115516c77SSepherosa Ziehau #endif
343215516c77SSepherosa Ziehau 	return tcp_lro_rx(lc, m, 0);
343315516c77SSepherosa Ziehau }
343415516c77SSepherosa Ziehau #endif
343515516c77SSepherosa Ziehau 
343615516c77SSepherosa Ziehau static int
3437a491581fSWei Hu hn_rxpkt(struct hn_rx_ring *rxr)
343815516c77SSepherosa Ziehau {
3439a97fff19SSepherosa Ziehau 	struct ifnet *ifp, *hn_ifp = rxr->hn_ifp;
3440a491581fSWei Hu 	struct mbuf *m_new, *n;
3441642ec226SSepherosa Ziehau 	int size, do_lro = 0, do_csum = 1, is_vf = 0;
3442642ec226SSepherosa Ziehau 	int hash_type = M_HASHTYPE_NONE;
3443db76829bSSepherosa Ziehau 	int l3proto = ETHERTYPE_MAX, l4proto = IPPROTO_DONE;
3444a491581fSWei Hu 	int i;
344515516c77SSepherosa Ziehau 
3446642ec226SSepherosa Ziehau 	ifp = hn_ifp;
3447642ec226SSepherosa Ziehau 	if (rxr->hn_rxvf_ifp != NULL) {
3448a97fff19SSepherosa Ziehau 		/*
3449642ec226SSepherosa Ziehau 		 * Non-transparent mode VF; pretend this packet is from
3450642ec226SSepherosa Ziehau 		 * the VF.
3451a97fff19SSepherosa Ziehau 		 */
3452642ec226SSepherosa Ziehau 		ifp = rxr->hn_rxvf_ifp;
3453642ec226SSepherosa Ziehau 		is_vf = 1;
3454642ec226SSepherosa Ziehau 	} else if (rxr->hn_rx_flags & HN_RX_FLAG_XPNT_VF) {
3455642ec226SSepherosa Ziehau 		/* Transparent mode VF. */
3456642ec226SSepherosa Ziehau 		is_vf = 1;
3457642ec226SSepherosa Ziehau 	}
34585bdfd3fdSDexuan Cui 
3459b3b75d9cSSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
3460b3b75d9cSSepherosa Ziehau 		/*
3461b3b75d9cSSepherosa Ziehau 		 * NOTE:
3462b3b75d9cSSepherosa Ziehau 		 * See the NOTE of hn_rndis_init_fixat().  This
3463b3b75d9cSSepherosa Ziehau 		 * function can be reached, immediately after the
3464b3b75d9cSSepherosa Ziehau 		 * RNDIS is initialized but before the ifnet is
3465b3b75d9cSSepherosa Ziehau 		 * setup on the hn_attach() path; drop the unexpected
3466b3b75d9cSSepherosa Ziehau 		 * packets.
3467b3b75d9cSSepherosa Ziehau 		 */
3468b3b75d9cSSepherosa Ziehau 		return (0);
3469b3b75d9cSSepherosa Ziehau 	}
3470b3b75d9cSSepherosa Ziehau 
3471a491581fSWei Hu 	if (__predict_false(rxr->rsc.pktlen < ETHER_HDR_LEN)) {
3472a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IERRORS, 1);
3473a97fff19SSepherosa Ziehau 		return (0);
3474a97fff19SSepherosa Ziehau 	}
3475a97fff19SSepherosa Ziehau 
3476a491581fSWei Hu 	if (rxr->rsc.cnt == 1 && rxr->rsc.pktlen <= MHLEN) {
347715516c77SSepherosa Ziehau 		m_new = m_gethdr(M_NOWAIT, MT_DATA);
347815516c77SSepherosa Ziehau 		if (m_new == NULL) {
3479a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1);
348015516c77SSepherosa Ziehau 			return (0);
348115516c77SSepherosa Ziehau 		}
3482a491581fSWei Hu 		memcpy(mtod(m_new, void *), rxr->rsc.frag_data[0],
3483a491581fSWei Hu 		    rxr->rsc.frag_len[0]);
3484a491581fSWei Hu 		m_new->m_pkthdr.len = m_new->m_len = rxr->rsc.frag_len[0];
348515516c77SSepherosa Ziehau 	} else {
348615516c77SSepherosa Ziehau 		/*
348715516c77SSepherosa Ziehau 		 * Get an mbuf with a cluster.  For packets 2K or less,
348815516c77SSepherosa Ziehau 		 * get a standard 2K cluster.  For anything larger, get a
348915516c77SSepherosa Ziehau 		 * 4K cluster.  Any buffers larger than 4K can cause problems
349015516c77SSepherosa Ziehau 		 * if looped around to the Hyper-V TX channel, so avoid them.
349115516c77SSepherosa Ziehau 		 */
349215516c77SSepherosa Ziehau 		size = MCLBYTES;
3493a491581fSWei Hu 		if (rxr->rsc.pktlen > MCLBYTES) {
349415516c77SSepherosa Ziehau 			/* 4096 */
349515516c77SSepherosa Ziehau 			size = MJUMPAGESIZE;
349615516c77SSepherosa Ziehau 		}
349715516c77SSepherosa Ziehau 
349815516c77SSepherosa Ziehau 		m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size);
349915516c77SSepherosa Ziehau 		if (m_new == NULL) {
3500a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1);
350115516c77SSepherosa Ziehau 			return (0);
350215516c77SSepherosa Ziehau 		}
350315516c77SSepherosa Ziehau 
3504a491581fSWei Hu 		n = m_new;
3505a491581fSWei Hu 		for (i = 0; i < rxr->rsc.cnt; i++) {
3506a491581fSWei Hu 			n = hv_m_append(n, rxr->rsc.frag_len[i],
3507a491581fSWei Hu 			    rxr->rsc.frag_data[i]);
3508a491581fSWei Hu 			if (n == NULL) {
3509a491581fSWei Hu 				if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1);
3510a491581fSWei Hu 				return (0);
3511a491581fSWei Hu 			} else {
3512a491581fSWei Hu 				m_new->m_pkthdr.len += rxr->rsc.frag_len[i];
351315516c77SSepherosa Ziehau 			}
3514a491581fSWei Hu 		}
3515a491581fSWei Hu 	}
3516a491581fSWei Hu 	if (rxr->rsc.pktlen <= MHLEN)
3517a491581fSWei Hu 		rxr->hn_small_pkts++;
3518a491581fSWei Hu 
351915516c77SSepherosa Ziehau 	m_new->m_pkthdr.rcvif = ifp;
352015516c77SSepherosa Ziehau 
3521a97fff19SSepherosa Ziehau 	if (__predict_false((hn_ifp->if_capenable & IFCAP_RXCSUM) == 0))
352215516c77SSepherosa Ziehau 		do_csum = 0;
352315516c77SSepherosa Ziehau 
352415516c77SSepherosa Ziehau 	/* receive side checksum offload */
3525a491581fSWei Hu 	if (rxr->rsc.csum_info != NULL) {
352615516c77SSepherosa Ziehau 		/* IP csum offload */
3527a491581fSWei Hu 		if ((*(rxr->rsc.csum_info) & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) {
352815516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
352915516c77SSepherosa Ziehau 			    (CSUM_IP_CHECKED | CSUM_IP_VALID);
353015516c77SSepherosa Ziehau 			rxr->hn_csum_ip++;
353115516c77SSepherosa Ziehau 		}
353215516c77SSepherosa Ziehau 
353315516c77SSepherosa Ziehau 		/* TCP/UDP csum offload */
3534a491581fSWei Hu 		if ((*(rxr->rsc.csum_info) & (NDIS_RXCSUM_INFO_UDPCS_OK |
353515516c77SSepherosa Ziehau 		     NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) {
353615516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
353715516c77SSepherosa Ziehau 			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
353815516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_data = 0xffff;
3539a491581fSWei Hu 			if (*(rxr->rsc.csum_info) & NDIS_RXCSUM_INFO_TCPCS_OK)
354015516c77SSepherosa Ziehau 				rxr->hn_csum_tcp++;
354115516c77SSepherosa Ziehau 			else
354215516c77SSepherosa Ziehau 				rxr->hn_csum_udp++;
354315516c77SSepherosa Ziehau 		}
354415516c77SSepherosa Ziehau 
354515516c77SSepherosa Ziehau 		/*
354615516c77SSepherosa Ziehau 		 * XXX
354715516c77SSepherosa Ziehau 		 * As of this write (Oct 28th, 2016), host side will turn
354815516c77SSepherosa Ziehau 		 * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so
354915516c77SSepherosa Ziehau 		 * the do_lro setting here is actually _not_ accurate.  We
355015516c77SSepherosa Ziehau 		 * depend on the RSS hash type check to reset do_lro.
355115516c77SSepherosa Ziehau 		 */
3552a491581fSWei Hu 		if ((*(rxr->rsc.csum_info) &
355315516c77SSepherosa Ziehau 		     (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) ==
355415516c77SSepherosa Ziehau 		    (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK))
355515516c77SSepherosa Ziehau 			do_lro = 1;
355615516c77SSepherosa Ziehau 	} else {
3557db76829bSSepherosa Ziehau 		hn_rxpkt_proto(m_new, &l3proto, &l4proto);
3558db76829bSSepherosa Ziehau 		if (l3proto == ETHERTYPE_IP) {
3559db76829bSSepherosa Ziehau 			if (l4proto == IPPROTO_TCP) {
356015516c77SSepherosa Ziehau 				if (do_csum &&
356115516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
356215516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_TCP)) {
356315516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
356415516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
356515516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
356615516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
356715516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
356815516c77SSepherosa Ziehau 				}
356915516c77SSepherosa Ziehau 				do_lro = 1;
3570db76829bSSepherosa Ziehau 			} else if (l4proto == IPPROTO_UDP) {
357115516c77SSepherosa Ziehau 				if (do_csum &&
357215516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
357315516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_UDP)) {
357415516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
357515516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
357615516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
357715516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
357815516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
357915516c77SSepherosa Ziehau 				}
3580db76829bSSepherosa Ziehau 			} else if (l4proto != IPPROTO_DONE && do_csum &&
358115516c77SSepherosa Ziehau 			    (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) {
358215516c77SSepherosa Ziehau 				rxr->hn_csum_trusted++;
358315516c77SSepherosa Ziehau 				m_new->m_pkthdr.csum_flags |=
358415516c77SSepherosa Ziehau 				    (CSUM_IP_CHECKED | CSUM_IP_VALID);
358515516c77SSepherosa Ziehau 			}
358615516c77SSepherosa Ziehau 		}
358715516c77SSepherosa Ziehau 	}
3588db76829bSSepherosa Ziehau 
3589a491581fSWei Hu 	if (rxr->rsc.vlan_info != NULL) {
359015516c77SSepherosa Ziehau 		m_new->m_pkthdr.ether_vtag = EVL_MAKETAG(
3591a491581fSWei Hu 		    NDIS_VLAN_INFO_ID(*(rxr->rsc.vlan_info)),
3592a491581fSWei Hu 		    NDIS_VLAN_INFO_PRI(*(rxr->rsc.vlan_info)),
3593a491581fSWei Hu 		    NDIS_VLAN_INFO_CFI(*(rxr->rsc.vlan_info)));
359415516c77SSepherosa Ziehau 		m_new->m_flags |= M_VLANTAG;
359515516c77SSepherosa Ziehau 	}
359615516c77SSepherosa Ziehau 
3597a97fff19SSepherosa Ziehau 	/*
3598a97fff19SSepherosa Ziehau 	 * If VF is activated (tranparent/non-transparent mode does not
3599a97fff19SSepherosa Ziehau 	 * matter here).
3600a97fff19SSepherosa Ziehau 	 *
3601a97fff19SSepherosa Ziehau 	 * - Disable LRO
3602a97fff19SSepherosa Ziehau 	 *
3603a97fff19SSepherosa Ziehau 	 *   hn(4) will only receive broadcast packets, multicast packets,
3604a97fff19SSepherosa Ziehau 	 *   TCP SYN and SYN|ACK (in Azure), LRO is useless for these
3605a97fff19SSepherosa Ziehau 	 *   packet types.
3606a97fff19SSepherosa Ziehau 	 *
3607a97fff19SSepherosa Ziehau 	 *   For non-transparent, we definitely _cannot_ enable LRO at
3608a97fff19SSepherosa Ziehau 	 *   all, since the LRO flush will use hn(4) as the receiving
3609a97fff19SSepherosa Ziehau 	 *   interface; i.e. hn_ifp->if_input(hn_ifp, m).
3610a97fff19SSepherosa Ziehau 	 */
3611642ec226SSepherosa Ziehau 	if (is_vf)
3612642ec226SSepherosa Ziehau 		do_lro = 0;
3613a97fff19SSepherosa Ziehau 
3614642ec226SSepherosa Ziehau 	/*
3615642ec226SSepherosa Ziehau 	 * If VF is activated (tranparent/non-transparent mode does not
3616642ec226SSepherosa Ziehau 	 * matter here), do _not_ mess with unsupported hash types or
3617642ec226SSepherosa Ziehau 	 * functions.
3618642ec226SSepherosa Ziehau 	 */
3619a491581fSWei Hu 	if (rxr->rsc.hash_info != NULL) {
362015516c77SSepherosa Ziehau 		rxr->hn_rss_pkts++;
3621a491581fSWei Hu 		m_new->m_pkthdr.flowid = *(rxr->rsc.hash_value);
3622642ec226SSepherosa Ziehau 		if (!is_vf)
362315516c77SSepherosa Ziehau 			hash_type = M_HASHTYPE_OPAQUE_HASH;
3624a491581fSWei Hu 		if ((*(rxr->rsc.hash_info) & NDIS_HASH_FUNCTION_MASK) ==
362515516c77SSepherosa Ziehau 		    NDIS_HASH_FUNCTION_TOEPLITZ) {
3626a491581fSWei Hu 			uint32_t type = (*(rxr->rsc.hash_info) & NDIS_HASH_TYPE_MASK &
3627642ec226SSepherosa Ziehau 			    rxr->hn_mbuf_hash);
362815516c77SSepherosa Ziehau 
362915516c77SSepherosa Ziehau 			/*
363015516c77SSepherosa Ziehau 			 * NOTE:
363115516c77SSepherosa Ziehau 			 * do_lro is resetted, if the hash types are not TCP
363215516c77SSepherosa Ziehau 			 * related.  See the comment in the above csum_flags
363315516c77SSepherosa Ziehau 			 * setup section.
363415516c77SSepherosa Ziehau 			 */
363515516c77SSepherosa Ziehau 			switch (type) {
363615516c77SSepherosa Ziehau 			case NDIS_HASH_IPV4:
363715516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV4;
363815516c77SSepherosa Ziehau 				do_lro = 0;
363915516c77SSepherosa Ziehau 				break;
364015516c77SSepherosa Ziehau 
364115516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV4:
364215516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV4;
3643db76829bSSepherosa Ziehau 				if (rxr->hn_rx_flags & HN_RX_FLAG_UDP_HASH) {
3644db76829bSSepherosa Ziehau 					int def_htype = M_HASHTYPE_OPAQUE_HASH;
3645db76829bSSepherosa Ziehau 
3646db76829bSSepherosa Ziehau 					if (is_vf)
3647db76829bSSepherosa Ziehau 						def_htype = M_HASHTYPE_NONE;
3648db76829bSSepherosa Ziehau 
3649db76829bSSepherosa Ziehau 					/*
3650db76829bSSepherosa Ziehau 					 * UDP 4-tuple hash is delivered as
3651db76829bSSepherosa Ziehau 					 * TCP 4-tuple hash.
3652db76829bSSepherosa Ziehau 					 */
3653db76829bSSepherosa Ziehau 					if (l3proto == ETHERTYPE_MAX) {
3654db76829bSSepherosa Ziehau 						hn_rxpkt_proto(m_new,
3655db76829bSSepherosa Ziehau 						    &l3proto, &l4proto);
3656db76829bSSepherosa Ziehau 					}
3657db76829bSSepherosa Ziehau 					if (l3proto == ETHERTYPE_IP) {
36586f12c42eSSepherosa Ziehau 						if (l4proto == IPPROTO_UDP &&
36596f12c42eSSepherosa Ziehau 						    (rxr->hn_mbuf_hash &
36606f12c42eSSepherosa Ziehau 						     NDIS_HASH_UDP_IPV4_X)) {
3661db76829bSSepherosa Ziehau 							hash_type =
3662db76829bSSepherosa Ziehau 							M_HASHTYPE_RSS_UDP_IPV4;
3663db76829bSSepherosa Ziehau 							do_lro = 0;
3664db76829bSSepherosa Ziehau 						} else if (l4proto !=
3665db76829bSSepherosa Ziehau 						    IPPROTO_TCP) {
3666db76829bSSepherosa Ziehau 							hash_type = def_htype;
3667db76829bSSepherosa Ziehau 							do_lro = 0;
3668db76829bSSepherosa Ziehau 						}
3669db76829bSSepherosa Ziehau 					} else {
3670db76829bSSepherosa Ziehau 						hash_type = def_htype;
3671db76829bSSepherosa Ziehau 						do_lro = 0;
3672db76829bSSepherosa Ziehau 					}
3673db76829bSSepherosa Ziehau 				}
367415516c77SSepherosa Ziehau 				break;
367515516c77SSepherosa Ziehau 
367615516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6:
367715516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6;
367815516c77SSepherosa Ziehau 				do_lro = 0;
367915516c77SSepherosa Ziehau 				break;
368015516c77SSepherosa Ziehau 
368115516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6_EX:
368215516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6_EX;
368315516c77SSepherosa Ziehau 				do_lro = 0;
368415516c77SSepherosa Ziehau 				break;
368515516c77SSepherosa Ziehau 
368615516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6:
368715516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6;
368815516c77SSepherosa Ziehau 				break;
368915516c77SSepherosa Ziehau 
369015516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6_EX:
369115516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX;
369215516c77SSepherosa Ziehau 				break;
369315516c77SSepherosa Ziehau 			}
369415516c77SSepherosa Ziehau 		}
3695642ec226SSepherosa Ziehau 	} else if (!is_vf) {
369615516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
369715516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE;
369815516c77SSepherosa Ziehau 	}
369915516c77SSepherosa Ziehau 	M_HASHTYPE_SET(m_new, hash_type);
370015516c77SSepherosa Ziehau 
3701a97fff19SSepherosa Ziehau 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
3702a97fff19SSepherosa Ziehau 	if (hn_ifp != ifp) {
3703a97fff19SSepherosa Ziehau 		const struct ether_header *eh;
3704a97fff19SSepherosa Ziehau 
370515516c77SSepherosa Ziehau 		/*
3706a97fff19SSepherosa Ziehau 		 * Non-transparent mode VF is activated.
370715516c77SSepherosa Ziehau 		 */
370815516c77SSepherosa Ziehau 
3709a97fff19SSepherosa Ziehau 		/*
3710a97fff19SSepherosa Ziehau 		 * Allow tapping on hn(4).
3711a97fff19SSepherosa Ziehau 		 */
3712a97fff19SSepherosa Ziehau 		ETHER_BPF_MTAP(hn_ifp, m_new);
3713a97fff19SSepherosa Ziehau 
3714a97fff19SSepherosa Ziehau 		/*
3715a97fff19SSepherosa Ziehau 		 * Update hn(4)'s stats.
3716a97fff19SSepherosa Ziehau 		 */
3717a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1);
3718a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IBYTES, m_new->m_pkthdr.len);
3719a97fff19SSepherosa Ziehau 		/* Checked at the beginning of this function. */
3720a97fff19SSepherosa Ziehau 		KASSERT(m_new->m_len >= ETHER_HDR_LEN, ("not ethernet frame"));
3721a97fff19SSepherosa Ziehau 		eh = mtod(m_new, struct ether_header *);
3722a97fff19SSepherosa Ziehau 		if (ETHER_IS_MULTICAST(eh->ether_dhost))
3723a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IMCASTS, 1);
3724a97fff19SSepherosa Ziehau 	}
372515516c77SSepherosa Ziehau 	rxr->hn_pkts++;
372615516c77SSepherosa Ziehau 
3727a97fff19SSepherosa Ziehau 	if ((hn_ifp->if_capenable & IFCAP_LRO) && do_lro) {
372815516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
372915516c77SSepherosa Ziehau 		struct lro_ctrl *lro = &rxr->hn_lro;
373015516c77SSepherosa Ziehau 
373115516c77SSepherosa Ziehau 		if (lro->lro_cnt) {
373215516c77SSepherosa Ziehau 			rxr->hn_lro_tried++;
373315516c77SSepherosa Ziehau 			if (hn_lro_rx(lro, m_new) == 0) {
373415516c77SSepherosa Ziehau 				/* DONE! */
373515516c77SSepherosa Ziehau 				return 0;
373615516c77SSepherosa Ziehau 			}
373715516c77SSepherosa Ziehau 		}
373815516c77SSepherosa Ziehau #endif
373915516c77SSepherosa Ziehau 	}
3740a97fff19SSepherosa Ziehau 	ifp->if_input(ifp, m_new);
374115516c77SSepherosa Ziehau 
374215516c77SSepherosa Ziehau 	return (0);
374315516c77SSepherosa Ziehau }
374415516c77SSepherosa Ziehau 
374515516c77SSepherosa Ziehau static int
374615516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
374715516c77SSepherosa Ziehau {
374815516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
37499c6cae24SSepherosa Ziehau 	struct ifreq *ifr = (struct ifreq *)data, ifr_vf;
37509c6cae24SSepherosa Ziehau 	struct ifnet *vf_ifp;
375115516c77SSepherosa Ziehau 	int mask, error = 0;
37528c068aa5SSepherosa Ziehau 	struct ifrsskey *ifrk;
37538c068aa5SSepherosa Ziehau 	struct ifrsshash *ifrh;
3754eb2fe044SSepherosa Ziehau 	uint32_t mtu;
375515516c77SSepherosa Ziehau 
375615516c77SSepherosa Ziehau 	switch (cmd) {
375715516c77SSepherosa Ziehau 	case SIOCSIFMTU:
375815516c77SSepherosa Ziehau 		if (ifr->ifr_mtu > HN_MTU_MAX) {
375915516c77SSepherosa Ziehau 			error = EINVAL;
376015516c77SSepherosa Ziehau 			break;
376115516c77SSepherosa Ziehau 		}
376215516c77SSepherosa Ziehau 
376315516c77SSepherosa Ziehau 		HN_LOCK(sc);
376415516c77SSepherosa Ziehau 
376515516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
376615516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
376715516c77SSepherosa Ziehau 			break;
376815516c77SSepherosa Ziehau 		}
376915516c77SSepherosa Ziehau 
377015516c77SSepherosa Ziehau 		if ((sc->hn_caps & HN_CAP_MTU) == 0) {
377115516c77SSepherosa Ziehau 			/* Can't change MTU */
377215516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
377315516c77SSepherosa Ziehau 			error = EOPNOTSUPP;
377415516c77SSepherosa Ziehau 			break;
377515516c77SSepherosa Ziehau 		}
377615516c77SSepherosa Ziehau 
377715516c77SSepherosa Ziehau 		if (ifp->if_mtu == ifr->ifr_mtu) {
377815516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
377915516c77SSepherosa Ziehau 			break;
378015516c77SSepherosa Ziehau 		}
378115516c77SSepherosa Ziehau 
37829c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
37839c6cae24SSepherosa Ziehau 			vf_ifp = sc->hn_vf_ifp;
37849c6cae24SSepherosa Ziehau 			ifr_vf = *ifr;
37859c6cae24SSepherosa Ziehau 			strlcpy(ifr_vf.ifr_name, vf_ifp->if_xname,
37869c6cae24SSepherosa Ziehau 			    sizeof(ifr_vf.ifr_name));
37879c6cae24SSepherosa Ziehau 			error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU,
37889c6cae24SSepherosa Ziehau 			    (caddr_t)&ifr_vf);
37899c6cae24SSepherosa Ziehau 			if (error) {
37909c6cae24SSepherosa Ziehau 				HN_UNLOCK(sc);
37919c6cae24SSepherosa Ziehau 				if_printf(ifp, "%s SIOCSIFMTU %d failed: %d\n",
37929c6cae24SSepherosa Ziehau 				    vf_ifp->if_xname, ifr->ifr_mtu, error);
37939c6cae24SSepherosa Ziehau 				break;
37949c6cae24SSepherosa Ziehau 			}
37959c6cae24SSepherosa Ziehau 		}
37969c6cae24SSepherosa Ziehau 
379715516c77SSepherosa Ziehau 		/*
379815516c77SSepherosa Ziehau 		 * Suspend this interface before the synthetic parts
379915516c77SSepherosa Ziehau 		 * are ripped.
380015516c77SSepherosa Ziehau 		 */
380115516c77SSepherosa Ziehau 		hn_suspend(sc);
380215516c77SSepherosa Ziehau 
380315516c77SSepherosa Ziehau 		/*
380415516c77SSepherosa Ziehau 		 * Detach the synthetics parts, i.e. NVS and RNDIS.
380515516c77SSepherosa Ziehau 		 */
380615516c77SSepherosa Ziehau 		hn_synth_detach(sc);
380715516c77SSepherosa Ziehau 
380815516c77SSepherosa Ziehau 		/*
380915516c77SSepherosa Ziehau 		 * Reattach the synthetic parts, i.e. NVS and RNDIS,
381015516c77SSepherosa Ziehau 		 * with the new MTU setting.
381115516c77SSepherosa Ziehau 		 */
381215516c77SSepherosa Ziehau 		error = hn_synth_attach(sc, ifr->ifr_mtu);
381315516c77SSepherosa Ziehau 		if (error) {
381415516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
381515516c77SSepherosa Ziehau 			break;
381615516c77SSepherosa Ziehau 		}
381715516c77SSepherosa Ziehau 
3818eb2fe044SSepherosa Ziehau 		error = hn_rndis_get_mtu(sc, &mtu);
3819eb2fe044SSepherosa Ziehau 		if (error)
3820eb2fe044SSepherosa Ziehau 			mtu = ifr->ifr_mtu;
3821eb2fe044SSepherosa Ziehau 		else if (bootverbose)
3822eb2fe044SSepherosa Ziehau 			if_printf(ifp, "RNDIS mtu %u\n", mtu);
3823eb2fe044SSepherosa Ziehau 
382415516c77SSepherosa Ziehau 		/*
382515516c77SSepherosa Ziehau 		 * Commit the requested MTU, after the synthetic parts
382615516c77SSepherosa Ziehau 		 * have been successfully attached.
382715516c77SSepherosa Ziehau 		 */
3828eb2fe044SSepherosa Ziehau 		if (mtu >= ifr->ifr_mtu) {
3829eb2fe044SSepherosa Ziehau 			mtu = ifr->ifr_mtu;
3830eb2fe044SSepherosa Ziehau 		} else {
3831eb2fe044SSepherosa Ziehau 			if_printf(ifp, "fixup mtu %d -> %u\n",
3832eb2fe044SSepherosa Ziehau 			    ifr->ifr_mtu, mtu);
3833eb2fe044SSepherosa Ziehau 		}
3834eb2fe044SSepherosa Ziehau 		ifp->if_mtu = mtu;
383515516c77SSepherosa Ziehau 
383615516c77SSepherosa Ziehau 		/*
38379c6cae24SSepherosa Ziehau 		 * Synthetic parts' reattach may change the chimney
38389c6cae24SSepherosa Ziehau 		 * sending size; update it.
383915516c77SSepherosa Ziehau 		 */
384015516c77SSepherosa Ziehau 		if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax)
384115516c77SSepherosa Ziehau 			hn_set_chim_size(sc, sc->hn_chim_szmax);
38429c6cae24SSepherosa Ziehau 
38439c6cae24SSepherosa Ziehau 		/*
38449c6cae24SSepherosa Ziehau 		 * Make sure that various parameters based on MTU are
38459c6cae24SSepherosa Ziehau 		 * still valid, after the MTU change.
38469c6cae24SSepherosa Ziehau 		 */
38479c6cae24SSepherosa Ziehau 		hn_mtu_change_fixup(sc);
384815516c77SSepherosa Ziehau 
384915516c77SSepherosa Ziehau 		/*
385015516c77SSepherosa Ziehau 		 * All done!  Resume the interface now.
385115516c77SSepherosa Ziehau 		 */
385215516c77SSepherosa Ziehau 		hn_resume(sc);
385315516c77SSepherosa Ziehau 
3854d0cd8231SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXVF) ||
3855d0cd8231SSepherosa Ziehau 		    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
38569c6cae24SSepherosa Ziehau 			/*
38579c6cae24SSepherosa Ziehau 			 * Since we have reattached the NVS part,
38589c6cae24SSepherosa Ziehau 			 * change the datapath to VF again; in case
38599c6cae24SSepherosa Ziehau 			 * that it is lost, after the NVS was detached.
38609c6cae24SSepherosa Ziehau 			 */
38619c6cae24SSepherosa Ziehau 			hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF);
38629c6cae24SSepherosa Ziehau 		}
38639c6cae24SSepherosa Ziehau 
386415516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
386515516c77SSepherosa Ziehau 		break;
386615516c77SSepherosa Ziehau 
386715516c77SSepherosa Ziehau 	case SIOCSIFFLAGS:
386815516c77SSepherosa Ziehau 		HN_LOCK(sc);
386915516c77SSepherosa Ziehau 
387015516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
387115516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
387215516c77SSepherosa Ziehau 			break;
387315516c77SSepherosa Ziehau 		}
387415516c77SSepherosa Ziehau 
38759c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc))
38769c6cae24SSepherosa Ziehau 			hn_xpnt_vf_saveifflags(sc);
38779c6cae24SSepherosa Ziehau 
387815516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_UP) {
3879fdc4f478SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
3880fdc4f478SSepherosa Ziehau 				/*
3881fdc4f478SSepherosa Ziehau 				 * Caller meight hold mutex, e.g.
3882fdc4f478SSepherosa Ziehau 				 * bpf; use busy-wait for the RNDIS
3883fdc4f478SSepherosa Ziehau 				 * reply.
3884fdc4f478SSepherosa Ziehau 				 */
3885fdc4f478SSepherosa Ziehau 				HN_NO_SLEEPING(sc);
3886c08f7b2cSSepherosa Ziehau 				hn_rxfilter_config(sc);
3887fdc4f478SSepherosa Ziehau 				HN_SLEEPING_OK(sc);
38889c6cae24SSepherosa Ziehau 
38899c6cae24SSepherosa Ziehau 				if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
38909c6cae24SSepherosa Ziehau 					error = hn_xpnt_vf_iocsetflags(sc);
3891fdc4f478SSepherosa Ziehau 			} else {
389215516c77SSepherosa Ziehau 				hn_init_locked(sc);
3893fdc4f478SSepherosa Ziehau 			}
389415516c77SSepherosa Ziehau 		} else {
389515516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
38965bdfd3fdSDexuan Cui 				hn_stop(sc, false);
389715516c77SSepherosa Ziehau 		}
389815516c77SSepherosa Ziehau 		sc->hn_if_flags = ifp->if_flags;
389915516c77SSepherosa Ziehau 
390015516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
390115516c77SSepherosa Ziehau 		break;
390215516c77SSepherosa Ziehau 
390315516c77SSepherosa Ziehau 	case SIOCSIFCAP:
390415516c77SSepherosa Ziehau 		HN_LOCK(sc);
39059c6cae24SSepherosa Ziehau 
39069c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
39079c6cae24SSepherosa Ziehau 			ifr_vf = *ifr;
39089c6cae24SSepherosa Ziehau 			strlcpy(ifr_vf.ifr_name, sc->hn_vf_ifp->if_xname,
39099c6cae24SSepherosa Ziehau 			    sizeof(ifr_vf.ifr_name));
39109c6cae24SSepherosa Ziehau 			error = hn_xpnt_vf_iocsetcaps(sc, &ifr_vf);
39119c6cae24SSepherosa Ziehau 			HN_UNLOCK(sc);
39129c6cae24SSepherosa Ziehau 			break;
39139c6cae24SSepherosa Ziehau 		}
39149c6cae24SSepherosa Ziehau 
39159c6cae24SSepherosa Ziehau 		/*
39169c6cae24SSepherosa Ziehau 		 * Fix up requested capabilities w/ supported capabilities,
39179c6cae24SSepherosa Ziehau 		 * since the supported capabilities could have been changed.
39189c6cae24SSepherosa Ziehau 		 */
39199c6cae24SSepherosa Ziehau 		mask = (ifr->ifr_reqcap & ifp->if_capabilities) ^
39209c6cae24SSepherosa Ziehau 		    ifp->if_capenable;
392115516c77SSepherosa Ziehau 
392215516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM) {
392315516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM;
392415516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM)
392515516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc);
392615516c77SSepherosa Ziehau 			else
392715516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc);
392815516c77SSepherosa Ziehau 		}
392915516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM_IPV6) {
393015516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
393115516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
393215516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc);
393315516c77SSepherosa Ziehau 			else
393415516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc);
393515516c77SSepherosa Ziehau 		}
393615516c77SSepherosa Ziehau 
393715516c77SSepherosa Ziehau 		/* TODO: flip RNDIS offload parameters for RXCSUM. */
393815516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM)
393915516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM;
394015516c77SSepherosa Ziehau #ifdef foo
394115516c77SSepherosa Ziehau 		/* We can't diff IPv6 packets from IPv4 packets on RX path. */
394215516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM_IPV6)
394315516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
394415516c77SSepherosa Ziehau #endif
394515516c77SSepherosa Ziehau 
394615516c77SSepherosa Ziehau 		if (mask & IFCAP_LRO)
394715516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_LRO;
394815516c77SSepherosa Ziehau 
394915516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO4) {
395015516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO4;
395115516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO4)
395215516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP_TSO;
395315516c77SSepherosa Ziehau 			else
395415516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP_TSO;
395515516c77SSepherosa Ziehau 		}
395615516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO6) {
395715516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO6;
395815516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO6)
395915516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP6_TSO;
396015516c77SSepherosa Ziehau 			else
396115516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP6_TSO;
396215516c77SSepherosa Ziehau 		}
396315516c77SSepherosa Ziehau 
396415516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
396515516c77SSepherosa Ziehau 		break;
396615516c77SSepherosa Ziehau 
396715516c77SSepherosa Ziehau 	case SIOCADDMULTI:
396815516c77SSepherosa Ziehau 	case SIOCDELMULTI:
396915516c77SSepherosa Ziehau 		HN_LOCK(sc);
397015516c77SSepherosa Ziehau 
397115516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
397215516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
397315516c77SSepherosa Ziehau 			break;
397415516c77SSepherosa Ziehau 		}
3975fdc4f478SSepherosa Ziehau 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
3976fdc4f478SSepherosa Ziehau 			/*
3977fdc4f478SSepherosa Ziehau 			 * Multicast uses mutex; use busy-wait for
3978fdc4f478SSepherosa Ziehau 			 * the RNDIS reply.
3979fdc4f478SSepherosa Ziehau 			 */
3980fdc4f478SSepherosa Ziehau 			HN_NO_SLEEPING(sc);
3981c08f7b2cSSepherosa Ziehau 			hn_rxfilter_config(sc);
3982fdc4f478SSepherosa Ziehau 			HN_SLEEPING_OK(sc);
3983fdc4f478SSepherosa Ziehau 		}
398415516c77SSepherosa Ziehau 
39859c6cae24SSepherosa Ziehau 		/* XXX vlan(4) style mcast addr maintenance */
39869c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
39879c6cae24SSepherosa Ziehau 			int old_if_flags;
39889c6cae24SSepherosa Ziehau 
39899c6cae24SSepherosa Ziehau 			old_if_flags = sc->hn_vf_ifp->if_flags;
39909c6cae24SSepherosa Ziehau 			hn_xpnt_vf_saveifflags(sc);
39919c6cae24SSepherosa Ziehau 
39929c6cae24SSepherosa Ziehau 			if ((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) &&
39939c6cae24SSepherosa Ziehau 			    ((old_if_flags ^ sc->hn_vf_ifp->if_flags) &
39949c6cae24SSepherosa Ziehau 			     IFF_ALLMULTI))
39959c6cae24SSepherosa Ziehau 				error = hn_xpnt_vf_iocsetflags(sc);
39969c6cae24SSepherosa Ziehau 		}
39979c6cae24SSepherosa Ziehau 
399815516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
399915516c77SSepherosa Ziehau 		break;
400015516c77SSepherosa Ziehau 
400115516c77SSepherosa Ziehau 	case SIOCSIFMEDIA:
400215516c77SSepherosa Ziehau 	case SIOCGIFMEDIA:
40039c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
40049c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
40059c6cae24SSepherosa Ziehau 			/*
40069c6cae24SSepherosa Ziehau 			 * SIOCGIFMEDIA expects ifmediareq, so don't
40079c6cae24SSepherosa Ziehau 			 * create and pass ifr_vf to the VF here; just
40089c6cae24SSepherosa Ziehau 			 * replace the ifr_name.
40099c6cae24SSepherosa Ziehau 			 */
40109c6cae24SSepherosa Ziehau 			vf_ifp = sc->hn_vf_ifp;
40119c6cae24SSepherosa Ziehau 			strlcpy(ifr->ifr_name, vf_ifp->if_xname,
40129c6cae24SSepherosa Ziehau 			    sizeof(ifr->ifr_name));
40139c6cae24SSepherosa Ziehau 			error = vf_ifp->if_ioctl(vf_ifp, cmd, data);
40149c6cae24SSepherosa Ziehau 			/* Restore the ifr_name. */
40159c6cae24SSepherosa Ziehau 			strlcpy(ifr->ifr_name, ifp->if_xname,
40169c6cae24SSepherosa Ziehau 			    sizeof(ifr->ifr_name));
40179c6cae24SSepherosa Ziehau 			HN_UNLOCK(sc);
40189c6cae24SSepherosa Ziehau 			break;
40199c6cae24SSepherosa Ziehau 		}
40209c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
402115516c77SSepherosa Ziehau 		error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd);
402215516c77SSepherosa Ziehau 		break;
402315516c77SSepherosa Ziehau 
40248c068aa5SSepherosa Ziehau 	case SIOCGIFRSSHASH:
40258c068aa5SSepherosa Ziehau 		ifrh = (struct ifrsshash *)data;
40268c068aa5SSepherosa Ziehau 		HN_LOCK(sc);
40278c068aa5SSepherosa Ziehau 		if (sc->hn_rx_ring_inuse == 1) {
40288c068aa5SSepherosa Ziehau 			HN_UNLOCK(sc);
40298c068aa5SSepherosa Ziehau 			ifrh->ifrh_func = RSS_FUNC_NONE;
40308c068aa5SSepherosa Ziehau 			ifrh->ifrh_types = 0;
40318c068aa5SSepherosa Ziehau 			break;
40328c068aa5SSepherosa Ziehau 		}
40338c068aa5SSepherosa Ziehau 
40348c068aa5SSepherosa Ziehau 		if (sc->hn_rss_hash & NDIS_HASH_FUNCTION_TOEPLITZ)
40358c068aa5SSepherosa Ziehau 			ifrh->ifrh_func = RSS_FUNC_TOEPLITZ;
40368c068aa5SSepherosa Ziehau 		else
40378c068aa5SSepherosa Ziehau 			ifrh->ifrh_func = RSS_FUNC_PRIVATE;
4038642ec226SSepherosa Ziehau 		ifrh->ifrh_types = hn_rss_type_fromndis(sc->hn_rss_hash);
40398c068aa5SSepherosa Ziehau 		HN_UNLOCK(sc);
40408c068aa5SSepherosa Ziehau 		break;
40418c068aa5SSepherosa Ziehau 
40428c068aa5SSepherosa Ziehau 	case SIOCGIFRSSKEY:
40438c068aa5SSepherosa Ziehau 		ifrk = (struct ifrsskey *)data;
40448c068aa5SSepherosa Ziehau 		HN_LOCK(sc);
40458c068aa5SSepherosa Ziehau 		if (sc->hn_rx_ring_inuse == 1) {
40468c068aa5SSepherosa Ziehau 			HN_UNLOCK(sc);
40478c068aa5SSepherosa Ziehau 			ifrk->ifrk_func = RSS_FUNC_NONE;
40488c068aa5SSepherosa Ziehau 			ifrk->ifrk_keylen = 0;
40498c068aa5SSepherosa Ziehau 			break;
40508c068aa5SSepherosa Ziehau 		}
40518c068aa5SSepherosa Ziehau 		if (sc->hn_rss_hash & NDIS_HASH_FUNCTION_TOEPLITZ)
40528c068aa5SSepherosa Ziehau 			ifrk->ifrk_func = RSS_FUNC_TOEPLITZ;
40538c068aa5SSepherosa Ziehau 		else
40548c068aa5SSepherosa Ziehau 			ifrk->ifrk_func = RSS_FUNC_PRIVATE;
40558c068aa5SSepherosa Ziehau 		ifrk->ifrk_keylen = NDIS_HASH_KEYSIZE_TOEPLITZ;
40568c068aa5SSepherosa Ziehau 		memcpy(ifrk->ifrk_key, sc->hn_rss.rss_key,
40578c068aa5SSepherosa Ziehau 		    NDIS_HASH_KEYSIZE_TOEPLITZ);
40588c068aa5SSepherosa Ziehau 		HN_UNLOCK(sc);
40598c068aa5SSepherosa Ziehau 		break;
40608c068aa5SSepherosa Ziehau 
406115516c77SSepherosa Ziehau 	default:
406215516c77SSepherosa Ziehau 		error = ether_ioctl(ifp, cmd, data);
406315516c77SSepherosa Ziehau 		break;
406415516c77SSepherosa Ziehau 	}
406515516c77SSepherosa Ziehau 	return (error);
406615516c77SSepherosa Ziehau }
406715516c77SSepherosa Ziehau 
406815516c77SSepherosa Ziehau static void
40695bdfd3fdSDexuan Cui hn_stop(struct hn_softc *sc, bool detaching)
407015516c77SSepherosa Ziehau {
407115516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
407215516c77SSepherosa Ziehau 	int i;
407315516c77SSepherosa Ziehau 
407415516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
407515516c77SSepherosa Ziehau 
407615516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
407715516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
407815516c77SSepherosa Ziehau 
40799c6cae24SSepherosa Ziehau 	/* Clear RUNNING bit ASAP. */
40809c6cae24SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
40819c6cae24SSepherosa Ziehau 
40826c1204dfSSepherosa Ziehau 	/* Disable polling. */
40836c1204dfSSepherosa Ziehau 	hn_polling(sc, 0);
40846c1204dfSSepherosa Ziehau 
40859c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) {
40869c6cae24SSepherosa Ziehau 		KASSERT(sc->hn_vf_ifp != NULL,
40879c6cae24SSepherosa Ziehau 		    ("%s: VF is not attached", ifp->if_xname));
40889c6cae24SSepherosa Ziehau 
4089a97fff19SSepherosa Ziehau 		/* Mark transparent mode VF as disabled. */
4090a97fff19SSepherosa Ziehau 		hn_xpnt_vf_setdisable(sc, false /* keep hn_vf_ifp */);
40919c6cae24SSepherosa Ziehau 
40929c6cae24SSepherosa Ziehau 		/*
40939c6cae24SSepherosa Ziehau 		 * NOTE:
40949c6cae24SSepherosa Ziehau 		 * Datapath setting must happen _before_ bringing
40959c6cae24SSepherosa Ziehau 		 * the VF down.
40969c6cae24SSepherosa Ziehau 		 */
40979c6cae24SSepherosa Ziehau 		hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH);
40989c6cae24SSepherosa Ziehau 
40999c6cae24SSepherosa Ziehau 		/*
41009c6cae24SSepherosa Ziehau 		 * Bring the VF down.
41019c6cae24SSepherosa Ziehau 		 */
41029c6cae24SSepherosa Ziehau 		hn_xpnt_vf_saveifflags(sc);
41039c6cae24SSepherosa Ziehau 		sc->hn_vf_ifp->if_flags &= ~IFF_UP;
41049c6cae24SSepherosa Ziehau 		hn_xpnt_vf_iocsetflags(sc);
41059c6cae24SSepherosa Ziehau 	}
41069c6cae24SSepherosa Ziehau 
41079c6cae24SSepherosa Ziehau 	/* Suspend data transfers. */
410815516c77SSepherosa Ziehau 	hn_suspend_data(sc);
410915516c77SSepherosa Ziehau 
411015516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
411115516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
411215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
411315516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
41145bdfd3fdSDexuan Cui 
41155bdfd3fdSDexuan Cui 	/*
41169c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is active, make sure
41179c6cae24SSepherosa Ziehau 	 * that the RX filter still allows packet reception.
41185bdfd3fdSDexuan Cui 	 */
4119962f0357SSepherosa Ziehau 	if (!detaching && (sc->hn_flags & HN_FLAG_RXVF))
41205bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
412115516c77SSepherosa Ziehau }
412215516c77SSepherosa Ziehau 
412315516c77SSepherosa Ziehau static void
412415516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc)
412515516c77SSepherosa Ziehau {
412615516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
412715516c77SSepherosa Ziehau 	int i;
412815516c77SSepherosa Ziehau 
412915516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
413015516c77SSepherosa Ziehau 
413115516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
413215516c77SSepherosa Ziehau 		return;
413315516c77SSepherosa Ziehau 
413415516c77SSepherosa Ziehau 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
413515516c77SSepherosa Ziehau 		return;
413615516c77SSepherosa Ziehau 
413715516c77SSepherosa Ziehau 	/* Configure RX filter */
4138c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
413915516c77SSepherosa Ziehau 
414015516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
414115516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
414215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
414315516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
414415516c77SSepherosa Ziehau 
414515516c77SSepherosa Ziehau 	/* Clear TX 'suspended' bit. */
414615516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_inuse);
414715516c77SSepherosa Ziehau 
41489c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_isready(sc)) {
41499c6cae24SSepherosa Ziehau 		/* Initialize transparent VF. */
41509c6cae24SSepherosa Ziehau 		hn_xpnt_vf_init(sc);
41519c6cae24SSepherosa Ziehau 	}
41529c6cae24SSepherosa Ziehau 
415315516c77SSepherosa Ziehau 	/* Everything is ready; unleash! */
415415516c77SSepherosa Ziehau 	atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
41556c1204dfSSepherosa Ziehau 
41566c1204dfSSepherosa Ziehau 	/* Re-enable polling if requested. */
41576c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz > 0)
41586c1204dfSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
415915516c77SSepherosa Ziehau }
416015516c77SSepherosa Ziehau 
416115516c77SSepherosa Ziehau static void
416215516c77SSepherosa Ziehau hn_init(void *xsc)
416315516c77SSepherosa Ziehau {
416415516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
416515516c77SSepherosa Ziehau 
416615516c77SSepherosa Ziehau 	HN_LOCK(sc);
416715516c77SSepherosa Ziehau 	hn_init_locked(sc);
416815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
416915516c77SSepherosa Ziehau }
417015516c77SSepherosa Ziehau 
417115516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
417215516c77SSepherosa Ziehau 
417315516c77SSepherosa Ziehau static int
417415516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
417515516c77SSepherosa Ziehau {
417615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
417715516c77SSepherosa Ziehau 	unsigned int lenlim;
417815516c77SSepherosa Ziehau 	int error;
417915516c77SSepherosa Ziehau 
418015516c77SSepherosa Ziehau 	lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim;
418115516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &lenlim, 0, req);
418215516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
418315516c77SSepherosa Ziehau 		return error;
418415516c77SSepherosa Ziehau 
418515516c77SSepherosa Ziehau 	HN_LOCK(sc);
418615516c77SSepherosa Ziehau 	if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) ||
418715516c77SSepherosa Ziehau 	    lenlim > TCP_LRO_LENGTH_MAX) {
418815516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
418915516c77SSepherosa Ziehau 		return EINVAL;
419015516c77SSepherosa Ziehau 	}
419115516c77SSepherosa Ziehau 	hn_set_lro_lenlim(sc, lenlim);
419215516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
419315516c77SSepherosa Ziehau 
419415516c77SSepherosa Ziehau 	return 0;
419515516c77SSepherosa Ziehau }
419615516c77SSepherosa Ziehau 
419715516c77SSepherosa Ziehau static int
419815516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS)
419915516c77SSepherosa Ziehau {
420015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
420115516c77SSepherosa Ziehau 	int ackcnt, error, i;
420215516c77SSepherosa Ziehau 
420315516c77SSepherosa Ziehau 	/*
420415516c77SSepherosa Ziehau 	 * lro_ackcnt_lim is append count limit,
420515516c77SSepherosa Ziehau 	 * +1 to turn it into aggregation limit.
420615516c77SSepherosa Ziehau 	 */
420715516c77SSepherosa Ziehau 	ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1;
420815516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &ackcnt, 0, req);
420915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
421015516c77SSepherosa Ziehau 		return error;
421115516c77SSepherosa Ziehau 
421215516c77SSepherosa Ziehau 	if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1))
421315516c77SSepherosa Ziehau 		return EINVAL;
421415516c77SSepherosa Ziehau 
421515516c77SSepherosa Ziehau 	/*
421615516c77SSepherosa Ziehau 	 * Convert aggregation limit back to append
421715516c77SSepherosa Ziehau 	 * count limit.
421815516c77SSepherosa Ziehau 	 */
421915516c77SSepherosa Ziehau 	--ackcnt;
422015516c77SSepherosa Ziehau 	HN_LOCK(sc);
4221a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
422215516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt;
422315516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
422415516c77SSepherosa Ziehau 	return 0;
422515516c77SSepherosa Ziehau }
422615516c77SSepherosa Ziehau 
422715516c77SSepherosa Ziehau #endif
422815516c77SSepherosa Ziehau 
422915516c77SSepherosa Ziehau static int
423015516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS)
423115516c77SSepherosa Ziehau {
423215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
423315516c77SSepherosa Ziehau 	int hcsum = arg2;
423415516c77SSepherosa Ziehau 	int on, error, i;
423515516c77SSepherosa Ziehau 
423615516c77SSepherosa Ziehau 	on = 0;
423715516c77SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum)
423815516c77SSepherosa Ziehau 		on = 1;
423915516c77SSepherosa Ziehau 
424015516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &on, 0, req);
424115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
424215516c77SSepherosa Ziehau 		return error;
424315516c77SSepherosa Ziehau 
424415516c77SSepherosa Ziehau 	HN_LOCK(sc);
4245a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
424615516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
424715516c77SSepherosa Ziehau 
424815516c77SSepherosa Ziehau 		if (on)
424915516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= hcsum;
425015516c77SSepherosa Ziehau 		else
425115516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum &= ~hcsum;
425215516c77SSepherosa Ziehau 	}
425315516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
425415516c77SSepherosa Ziehau 	return 0;
425515516c77SSepherosa Ziehau }
425615516c77SSepherosa Ziehau 
425715516c77SSepherosa Ziehau static int
425815516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS)
425915516c77SSepherosa Ziehau {
426015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
426115516c77SSepherosa Ziehau 	int chim_size, error;
426215516c77SSepherosa Ziehau 
426315516c77SSepherosa Ziehau 	chim_size = sc->hn_tx_ring[0].hn_chim_size;
426415516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &chim_size, 0, req);
426515516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
426615516c77SSepherosa Ziehau 		return error;
426715516c77SSepherosa Ziehau 
426815516c77SSepherosa Ziehau 	if (chim_size > sc->hn_chim_szmax || chim_size <= 0)
426915516c77SSepherosa Ziehau 		return EINVAL;
427015516c77SSepherosa Ziehau 
427115516c77SSepherosa Ziehau 	HN_LOCK(sc);
427215516c77SSepherosa Ziehau 	hn_set_chim_size(sc, chim_size);
427315516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
427415516c77SSepherosa Ziehau 	return 0;
427515516c77SSepherosa Ziehau }
427615516c77SSepherosa Ziehau 
427715516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
427815516c77SSepherosa Ziehau static int
427915516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS)
428015516c77SSepherosa Ziehau {
428115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
428215516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
428315516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
428415516c77SSepherosa Ziehau 	uint64_t stat;
428515516c77SSepherosa Ziehau 
428615516c77SSepherosa Ziehau 	stat = 0;
428715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
428815516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
428915516c77SSepherosa Ziehau 		stat += *((int *)((uint8_t *)rxr + ofs));
429015516c77SSepherosa Ziehau 	}
429115516c77SSepherosa Ziehau 
429215516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
429315516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
429415516c77SSepherosa Ziehau 		return error;
429515516c77SSepherosa Ziehau 
429615516c77SSepherosa Ziehau 	/* Zero out this stat. */
429715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
429815516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
429915516c77SSepherosa Ziehau 		*((int *)((uint8_t *)rxr + ofs)) = 0;
430015516c77SSepherosa Ziehau 	}
430115516c77SSepherosa Ziehau 	return 0;
430215516c77SSepherosa Ziehau }
430315516c77SSepherosa Ziehau #else
430415516c77SSepherosa Ziehau static int
430515516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS)
430615516c77SSepherosa Ziehau {
430715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
430815516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
430915516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
431015516c77SSepherosa Ziehau 	uint64_t stat;
431115516c77SSepherosa Ziehau 
431215516c77SSepherosa Ziehau 	stat = 0;
4313a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
431415516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
431515516c77SSepherosa Ziehau 		stat += *((uint64_t *)((uint8_t *)rxr + ofs));
431615516c77SSepherosa Ziehau 	}
431715516c77SSepherosa Ziehau 
431815516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
431915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
432015516c77SSepherosa Ziehau 		return error;
432115516c77SSepherosa Ziehau 
432215516c77SSepherosa Ziehau 	/* Zero out this stat. */
4323a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
432415516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
432515516c77SSepherosa Ziehau 		*((uint64_t *)((uint8_t *)rxr + ofs)) = 0;
432615516c77SSepherosa Ziehau 	}
432715516c77SSepherosa Ziehau 	return 0;
432815516c77SSepherosa Ziehau }
432915516c77SSepherosa Ziehau 
433015516c77SSepherosa Ziehau #endif
433115516c77SSepherosa Ziehau 
433215516c77SSepherosa Ziehau static int
433315516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
433415516c77SSepherosa Ziehau {
433515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
433615516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
433715516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
433815516c77SSepherosa Ziehau 	u_long stat;
433915516c77SSepherosa Ziehau 
434015516c77SSepherosa Ziehau 	stat = 0;
4341a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
434215516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
434315516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)rxr + ofs));
434415516c77SSepherosa Ziehau 	}
434515516c77SSepherosa Ziehau 
434615516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
434715516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
434815516c77SSepherosa Ziehau 		return error;
434915516c77SSepherosa Ziehau 
435015516c77SSepherosa Ziehau 	/* Zero out this stat. */
4351a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
435215516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
435315516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)rxr + ofs)) = 0;
435415516c77SSepherosa Ziehau 	}
435515516c77SSepherosa Ziehau 	return 0;
435615516c77SSepherosa Ziehau }
435715516c77SSepherosa Ziehau 
435815516c77SSepherosa Ziehau static int
435915516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
436015516c77SSepherosa Ziehau {
436115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
436215516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
436315516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
436415516c77SSepherosa Ziehau 	u_long stat;
436515516c77SSepherosa Ziehau 
436615516c77SSepherosa Ziehau 	stat = 0;
4367a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
436815516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
436915516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)txr + ofs));
437015516c77SSepherosa Ziehau 	}
437115516c77SSepherosa Ziehau 
437215516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
437315516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
437415516c77SSepherosa Ziehau 		return error;
437515516c77SSepherosa Ziehau 
437615516c77SSepherosa Ziehau 	/* Zero out this stat. */
4377a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
437815516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
437915516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)txr + ofs)) = 0;
438015516c77SSepherosa Ziehau 	}
438115516c77SSepherosa Ziehau 	return 0;
438215516c77SSepherosa Ziehau }
438315516c77SSepherosa Ziehau 
438415516c77SSepherosa Ziehau static int
438515516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS)
438615516c77SSepherosa Ziehau {
438715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
438815516c77SSepherosa Ziehau 	int ofs = arg2, i, error, conf;
438915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
439015516c77SSepherosa Ziehau 
439115516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[0];
439215516c77SSepherosa Ziehau 	conf = *((int *)((uint8_t *)txr + ofs));
439315516c77SSepherosa Ziehau 
439415516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &conf, 0, req);
439515516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
439615516c77SSepherosa Ziehau 		return error;
439715516c77SSepherosa Ziehau 
439815516c77SSepherosa Ziehau 	HN_LOCK(sc);
4399a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
440015516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
440115516c77SSepherosa Ziehau 		*((int *)((uint8_t *)txr + ofs)) = conf;
440215516c77SSepherosa Ziehau 	}
440315516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
440415516c77SSepherosa Ziehau 
440515516c77SSepherosa Ziehau 	return 0;
440615516c77SSepherosa Ziehau }
440715516c77SSepherosa Ziehau 
440815516c77SSepherosa Ziehau static int
4409dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS)
4410dc13fee6SSepherosa Ziehau {
4411dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4412dc13fee6SSepherosa Ziehau 	int error, size;
4413dc13fee6SSepherosa Ziehau 
4414dc13fee6SSepherosa Ziehau 	size = sc->hn_agg_size;
4415dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &size, 0, req);
4416dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
4417dc13fee6SSepherosa Ziehau 		return (error);
4418dc13fee6SSepherosa Ziehau 
4419dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
4420dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = size;
4421dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
4422dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
4423dc13fee6SSepherosa Ziehau 
4424dc13fee6SSepherosa Ziehau 	return (0);
4425dc13fee6SSepherosa Ziehau }
4426dc13fee6SSepherosa Ziehau 
4427dc13fee6SSepherosa Ziehau static int
4428dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS)
4429dc13fee6SSepherosa Ziehau {
4430dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4431dc13fee6SSepherosa Ziehau 	int error, pkts;
4432dc13fee6SSepherosa Ziehau 
4433dc13fee6SSepherosa Ziehau 	pkts = sc->hn_agg_pkts;
4434dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pkts, 0, req);
4435dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
4436dc13fee6SSepherosa Ziehau 		return (error);
4437dc13fee6SSepherosa Ziehau 
4438dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
4439dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = pkts;
4440dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
4441dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
4442dc13fee6SSepherosa Ziehau 
4443dc13fee6SSepherosa Ziehau 	return (0);
4444dc13fee6SSepherosa Ziehau }
4445dc13fee6SSepherosa Ziehau 
4446dc13fee6SSepherosa Ziehau static int
4447dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS)
4448dc13fee6SSepherosa Ziehau {
4449dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4450dc13fee6SSepherosa Ziehau 	int pkts;
4451dc13fee6SSepherosa Ziehau 
4452dc13fee6SSepherosa Ziehau 	pkts = sc->hn_tx_ring[0].hn_agg_pktmax;
4453dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &pkts, 0, req));
4454dc13fee6SSepherosa Ziehau }
4455dc13fee6SSepherosa Ziehau 
4456dc13fee6SSepherosa Ziehau static int
4457dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS)
4458dc13fee6SSepherosa Ziehau {
4459dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4460dc13fee6SSepherosa Ziehau 	int align;
4461dc13fee6SSepherosa Ziehau 
4462dc13fee6SSepherosa Ziehau 	align = sc->hn_tx_ring[0].hn_agg_align;
4463dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &align, 0, req));
4464dc13fee6SSepherosa Ziehau }
4465dc13fee6SSepherosa Ziehau 
44666c1204dfSSepherosa Ziehau static void
44676c1204dfSSepherosa Ziehau hn_chan_polling(struct vmbus_channel *chan, u_int pollhz)
44686c1204dfSSepherosa Ziehau {
44696c1204dfSSepherosa Ziehau 	if (pollhz == 0)
44706c1204dfSSepherosa Ziehau 		vmbus_chan_poll_disable(chan);
44716c1204dfSSepherosa Ziehau 	else
44726c1204dfSSepherosa Ziehau 		vmbus_chan_poll_enable(chan, pollhz);
44736c1204dfSSepherosa Ziehau }
44746c1204dfSSepherosa Ziehau 
44756c1204dfSSepherosa Ziehau static void
44766c1204dfSSepherosa Ziehau hn_polling(struct hn_softc *sc, u_int pollhz)
44776c1204dfSSepherosa Ziehau {
44786c1204dfSSepherosa Ziehau 	int nsubch = sc->hn_rx_ring_inuse - 1;
44796c1204dfSSepherosa Ziehau 
44806c1204dfSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
44816c1204dfSSepherosa Ziehau 
44826c1204dfSSepherosa Ziehau 	if (nsubch > 0) {
44836c1204dfSSepherosa Ziehau 		struct vmbus_channel **subch;
44846c1204dfSSepherosa Ziehau 		int i;
44856c1204dfSSepherosa Ziehau 
44866c1204dfSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
44876c1204dfSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
44886c1204dfSSepherosa Ziehau 			hn_chan_polling(subch[i], pollhz);
44896c1204dfSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
44906c1204dfSSepherosa Ziehau 	}
44916c1204dfSSepherosa Ziehau 	hn_chan_polling(sc->hn_prichan, pollhz);
44926c1204dfSSepherosa Ziehau }
44936c1204dfSSepherosa Ziehau 
44946c1204dfSSepherosa Ziehau static int
44956c1204dfSSepherosa Ziehau hn_polling_sysctl(SYSCTL_HANDLER_ARGS)
44966c1204dfSSepherosa Ziehau {
44976c1204dfSSepherosa Ziehau 	struct hn_softc *sc = arg1;
44986c1204dfSSepherosa Ziehau 	int pollhz, error;
44996c1204dfSSepherosa Ziehau 
45006c1204dfSSepherosa Ziehau 	pollhz = sc->hn_pollhz;
45016c1204dfSSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pollhz, 0, req);
45026c1204dfSSepherosa Ziehau 	if (error || req->newptr == NULL)
45036c1204dfSSepherosa Ziehau 		return (error);
45046c1204dfSSepherosa Ziehau 
45056c1204dfSSepherosa Ziehau 	if (pollhz != 0 &&
45066c1204dfSSepherosa Ziehau 	    (pollhz < VMBUS_CHAN_POLLHZ_MIN || pollhz > VMBUS_CHAN_POLLHZ_MAX))
45076c1204dfSSepherosa Ziehau 		return (EINVAL);
45086c1204dfSSepherosa Ziehau 
45096c1204dfSSepherosa Ziehau 	HN_LOCK(sc);
45106c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz != pollhz) {
45116c1204dfSSepherosa Ziehau 		sc->hn_pollhz = pollhz;
45126c1204dfSSepherosa Ziehau 		if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) &&
45136c1204dfSSepherosa Ziehau 		    (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
45146c1204dfSSepherosa Ziehau 			hn_polling(sc, sc->hn_pollhz);
45156c1204dfSSepherosa Ziehau 	}
45166c1204dfSSepherosa Ziehau 	HN_UNLOCK(sc);
45176c1204dfSSepherosa Ziehau 
45186c1204dfSSepherosa Ziehau 	return (0);
45196c1204dfSSepherosa Ziehau }
45206c1204dfSSepherosa Ziehau 
4521dc13fee6SSepherosa Ziehau static int
452215516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS)
452315516c77SSepherosa Ziehau {
452415516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
452515516c77SSepherosa Ziehau 	char verstr[16];
452615516c77SSepherosa Ziehau 
452715516c77SSepherosa Ziehau 	snprintf(verstr, sizeof(verstr), "%u.%u",
452815516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
452915516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
453015516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
453115516c77SSepherosa Ziehau }
453215516c77SSepherosa Ziehau 
453315516c77SSepherosa Ziehau static int
453415516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS)
453515516c77SSepherosa Ziehau {
453615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
453715516c77SSepherosa Ziehau 	char caps_str[128];
453815516c77SSepherosa Ziehau 	uint32_t caps;
453915516c77SSepherosa Ziehau 
454015516c77SSepherosa Ziehau 	HN_LOCK(sc);
454115516c77SSepherosa Ziehau 	caps = sc->hn_caps;
454215516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
454315516c77SSepherosa Ziehau 	snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS);
454415516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req);
454515516c77SSepherosa Ziehau }
454615516c77SSepherosa Ziehau 
454715516c77SSepherosa Ziehau static int
454815516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS)
454915516c77SSepherosa Ziehau {
455015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
455115516c77SSepherosa Ziehau 	char assist_str[128];
455215516c77SSepherosa Ziehau 	uint32_t hwassist;
455315516c77SSepherosa Ziehau 
455415516c77SSepherosa Ziehau 	HN_LOCK(sc);
455515516c77SSepherosa Ziehau 	hwassist = sc->hn_ifp->if_hwassist;
455615516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
455715516c77SSepherosa Ziehau 	snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS);
455815516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req);
455915516c77SSepherosa Ziehau }
456015516c77SSepherosa Ziehau 
456115516c77SSepherosa Ziehau static int
456215516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS)
456315516c77SSepherosa Ziehau {
456415516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
456515516c77SSepherosa Ziehau 	char filter_str[128];
456615516c77SSepherosa Ziehau 	uint32_t filter;
456715516c77SSepherosa Ziehau 
456815516c77SSepherosa Ziehau 	HN_LOCK(sc);
456915516c77SSepherosa Ziehau 	filter = sc->hn_rx_filter;
457015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
457115516c77SSepherosa Ziehau 	snprintf(filter_str, sizeof(filter_str), "%b", filter,
457215516c77SSepherosa Ziehau 	    NDIS_PACKET_TYPES);
457315516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req);
457415516c77SSepherosa Ziehau }
457515516c77SSepherosa Ziehau 
4576*80c3eb7bSWei Hu static int
4577*80c3eb7bSWei Hu hn_rsc_sysctl(SYSCTL_HANDLER_ARGS)
4578*80c3eb7bSWei Hu {
4579*80c3eb7bSWei Hu 	struct hn_softc *sc = arg1;
4580*80c3eb7bSWei Hu 	uint32_t mtu;
4581*80c3eb7bSWei Hu 	int error;
4582*80c3eb7bSWei Hu 	HN_LOCK(sc);
4583*80c3eb7bSWei Hu 	error = hn_rndis_get_mtu(sc, &mtu);
4584*80c3eb7bSWei Hu 	if (error) {
4585*80c3eb7bSWei Hu 		if_printf(sc->hn_ifp, "failed to get mtu\n");
4586*80c3eb7bSWei Hu 		goto back;
4587*80c3eb7bSWei Hu 	}
4588*80c3eb7bSWei Hu 	error = SYSCTL_OUT(req, &(sc->hn_rsc_ctrl), sizeof(sc->hn_rsc_ctrl));
4589*80c3eb7bSWei Hu 	if (error || req->newptr == NULL)
4590*80c3eb7bSWei Hu 		goto back;
4591*80c3eb7bSWei Hu 
4592*80c3eb7bSWei Hu 	error = SYSCTL_IN(req, &(sc->hn_rsc_ctrl), sizeof(sc->hn_rsc_ctrl));
4593*80c3eb7bSWei Hu 	if (error)
4594*80c3eb7bSWei Hu 		goto back;
4595*80c3eb7bSWei Hu 	error = hn_rndis_reconf_offload(sc, mtu);
4596*80c3eb7bSWei Hu back:
4597*80c3eb7bSWei Hu 	HN_UNLOCK(sc);
4598*80c3eb7bSWei Hu 	return (error);
4599*80c3eb7bSWei Hu }
460034d68912SSepherosa Ziehau #ifndef RSS
460134d68912SSepherosa Ziehau 
460215516c77SSepherosa Ziehau static int
460315516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
460415516c77SSepherosa Ziehau {
460515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
460615516c77SSepherosa Ziehau 	int error;
460715516c77SSepherosa Ziehau 
460815516c77SSepherosa Ziehau 	HN_LOCK(sc);
460915516c77SSepherosa Ziehau 
461015516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
461115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
461215516c77SSepherosa Ziehau 		goto back;
461315516c77SSepherosa Ziehau 
4614642ec226SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) ||
4615642ec226SSepherosa Ziehau 	    (hn_xpnt_vf && sc->hn_vf_ifp != NULL)) {
4616642ec226SSepherosa Ziehau 		/*
4617642ec226SSepherosa Ziehau 		 * RSS key is synchronized w/ VF's, don't allow users
4618642ec226SSepherosa Ziehau 		 * to change it.
4619642ec226SSepherosa Ziehau 		 */
4620642ec226SSepherosa Ziehau 		error = EBUSY;
4621642ec226SSepherosa Ziehau 		goto back;
4622642ec226SSepherosa Ziehau 	}
4623642ec226SSepherosa Ziehau 
462415516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
462515516c77SSepherosa Ziehau 	if (error)
462615516c77SSepherosa Ziehau 		goto back;
462715516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
462815516c77SSepherosa Ziehau 
462915516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
463015516c77SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
463115516c77SSepherosa Ziehau 	} else {
463215516c77SSepherosa Ziehau 		/* Not RSS capable, at least for now; just save the RSS key. */
463315516c77SSepherosa Ziehau 		error = 0;
463415516c77SSepherosa Ziehau 	}
463515516c77SSepherosa Ziehau back:
463615516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
463715516c77SSepherosa Ziehau 	return (error);
463815516c77SSepherosa Ziehau }
463915516c77SSepherosa Ziehau 
464015516c77SSepherosa Ziehau static int
464115516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS)
464215516c77SSepherosa Ziehau {
464315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
464415516c77SSepherosa Ziehau 	int error;
464515516c77SSepherosa Ziehau 
464615516c77SSepherosa Ziehau 	HN_LOCK(sc);
464715516c77SSepherosa Ziehau 
464815516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
464915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
465015516c77SSepherosa Ziehau 		goto back;
465115516c77SSepherosa Ziehau 
465215516c77SSepherosa Ziehau 	/*
465315516c77SSepherosa Ziehau 	 * Don't allow RSS indirect table change, if this interface is not
465415516c77SSepherosa Ziehau 	 * RSS capable currently.
465515516c77SSepherosa Ziehau 	 */
465615516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
465715516c77SSepherosa Ziehau 		error = EOPNOTSUPP;
465815516c77SSepherosa Ziehau 		goto back;
465915516c77SSepherosa Ziehau 	}
466015516c77SSepherosa Ziehau 
466115516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
466215516c77SSepherosa Ziehau 	if (error)
466315516c77SSepherosa Ziehau 		goto back;
466415516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSIND;
466515516c77SSepherosa Ziehau 
4666afd4971bSSepherosa Ziehau 	hn_rss_ind_fixup(sc);
466715516c77SSepherosa Ziehau 	error = hn_rss_reconfig(sc);
466815516c77SSepherosa Ziehau back:
466915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
467015516c77SSepherosa Ziehau 	return (error);
467115516c77SSepherosa Ziehau }
467215516c77SSepherosa Ziehau 
467334d68912SSepherosa Ziehau #endif	/* !RSS */
467434d68912SSepherosa Ziehau 
467515516c77SSepherosa Ziehau static int
467615516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS)
467715516c77SSepherosa Ziehau {
467815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
467915516c77SSepherosa Ziehau 	char hash_str[128];
468015516c77SSepherosa Ziehau 	uint32_t hash;
468115516c77SSepherosa Ziehau 
468215516c77SSepherosa Ziehau 	HN_LOCK(sc);
468315516c77SSepherosa Ziehau 	hash = sc->hn_rss_hash;
468415516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
468515516c77SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
468615516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
468715516c77SSepherosa Ziehau }
468815516c77SSepherosa Ziehau 
468915516c77SSepherosa Ziehau static int
4690642ec226SSepherosa Ziehau hn_rss_hcap_sysctl(SYSCTL_HANDLER_ARGS)
4691642ec226SSepherosa Ziehau {
4692642ec226SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4693642ec226SSepherosa Ziehau 	char hash_str[128];
4694642ec226SSepherosa Ziehau 	uint32_t hash;
4695642ec226SSepherosa Ziehau 
4696642ec226SSepherosa Ziehau 	HN_LOCK(sc);
4697642ec226SSepherosa Ziehau 	hash = sc->hn_rss_hcap;
4698642ec226SSepherosa Ziehau 	HN_UNLOCK(sc);
4699642ec226SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
4700642ec226SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
4701642ec226SSepherosa Ziehau }
4702642ec226SSepherosa Ziehau 
4703642ec226SSepherosa Ziehau static int
4704642ec226SSepherosa Ziehau hn_rss_mbuf_sysctl(SYSCTL_HANDLER_ARGS)
4705642ec226SSepherosa Ziehau {
4706642ec226SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4707642ec226SSepherosa Ziehau 	char hash_str[128];
4708642ec226SSepherosa Ziehau 	uint32_t hash;
4709642ec226SSepherosa Ziehau 
4710642ec226SSepherosa Ziehau 	HN_LOCK(sc);
4711642ec226SSepherosa Ziehau 	hash = sc->hn_rx_ring[0].hn_mbuf_hash;
4712642ec226SSepherosa Ziehau 	HN_UNLOCK(sc);
4713642ec226SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
4714642ec226SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
4715642ec226SSepherosa Ziehau }
4716642ec226SSepherosa Ziehau 
4717642ec226SSepherosa Ziehau static int
471840d60d6eSDexuan Cui hn_vf_sysctl(SYSCTL_HANDLER_ARGS)
471940d60d6eSDexuan Cui {
472040d60d6eSDexuan Cui 	struct hn_softc *sc = arg1;
4721499c3e17SSepherosa Ziehau 	char vf_name[IFNAMSIZ + 1];
4722962f0357SSepherosa Ziehau 	struct ifnet *vf_ifp;
472340d60d6eSDexuan Cui 
472440d60d6eSDexuan Cui 	HN_LOCK(sc);
472540d60d6eSDexuan Cui 	vf_name[0] = '\0';
4726962f0357SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
4727962f0357SSepherosa Ziehau 	if (vf_ifp != NULL)
4728962f0357SSepherosa Ziehau 		snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname);
472940d60d6eSDexuan Cui 	HN_UNLOCK(sc);
473040d60d6eSDexuan Cui 	return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req);
473140d60d6eSDexuan Cui }
473240d60d6eSDexuan Cui 
473340d60d6eSDexuan Cui static int
4734499c3e17SSepherosa Ziehau hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS)
4735499c3e17SSepherosa Ziehau {
4736499c3e17SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4737499c3e17SSepherosa Ziehau 	char vf_name[IFNAMSIZ + 1];
4738962f0357SSepherosa Ziehau 	struct ifnet *vf_ifp;
4739499c3e17SSepherosa Ziehau 
4740499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
4741499c3e17SSepherosa Ziehau 	vf_name[0] = '\0';
4742962f0357SSepherosa Ziehau 	vf_ifp = sc->hn_rx_ring[0].hn_rxvf_ifp;
4743962f0357SSepherosa Ziehau 	if (vf_ifp != NULL)
4744962f0357SSepherosa Ziehau 		snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname);
4745499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
4746499c3e17SSepherosa Ziehau 	return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req);
4747499c3e17SSepherosa Ziehau }
4748499c3e17SSepherosa Ziehau 
4749499c3e17SSepherosa Ziehau static int
4750499c3e17SSepherosa Ziehau hn_vflist_sysctl(SYSCTL_HANDLER_ARGS)
4751499c3e17SSepherosa Ziehau {
4752499c3e17SSepherosa Ziehau 	struct rm_priotracker pt;
4753499c3e17SSepherosa Ziehau 	struct sbuf *sb;
4754499c3e17SSepherosa Ziehau 	int error, i;
4755499c3e17SSepherosa Ziehau 	bool first;
4756499c3e17SSepherosa Ziehau 
4757499c3e17SSepherosa Ziehau 	error = sysctl_wire_old_buffer(req, 0);
4758499c3e17SSepherosa Ziehau 	if (error != 0)
4759499c3e17SSepherosa Ziehau 		return (error);
4760499c3e17SSepherosa Ziehau 
4761499c3e17SSepherosa Ziehau 	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4762499c3e17SSepherosa Ziehau 	if (sb == NULL)
4763499c3e17SSepherosa Ziehau 		return (ENOMEM);
4764499c3e17SSepherosa Ziehau 
4765499c3e17SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
4766499c3e17SSepherosa Ziehau 
4767499c3e17SSepherosa Ziehau 	first = true;
4768499c3e17SSepherosa Ziehau 	for (i = 0; i < hn_vfmap_size; ++i) {
4769d74b7baeSGleb Smirnoff 		struct epoch_tracker et;
4770499c3e17SSepherosa Ziehau 		struct ifnet *ifp;
4771499c3e17SSepherosa Ziehau 
4772499c3e17SSepherosa Ziehau 		if (hn_vfmap[i] == NULL)
4773499c3e17SSepherosa Ziehau 			continue;
4774499c3e17SSepherosa Ziehau 
4775d74b7baeSGleb Smirnoff 		NET_EPOCH_ENTER(et);
4776499c3e17SSepherosa Ziehau 		ifp = ifnet_byindex(i);
4777499c3e17SSepherosa Ziehau 		if (ifp != NULL) {
4778499c3e17SSepherosa Ziehau 			if (first)
4779499c3e17SSepherosa Ziehau 				sbuf_printf(sb, "%s", ifp->if_xname);
4780499c3e17SSepherosa Ziehau 			else
4781499c3e17SSepherosa Ziehau 				sbuf_printf(sb, " %s", ifp->if_xname);
4782499c3e17SSepherosa Ziehau 			first = false;
4783499c3e17SSepherosa Ziehau 		}
4784d74b7baeSGleb Smirnoff 		NET_EPOCH_EXIT(et);
4785499c3e17SSepherosa Ziehau 	}
4786499c3e17SSepherosa Ziehau 
4787499c3e17SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
4788499c3e17SSepherosa Ziehau 
4789499c3e17SSepherosa Ziehau 	error = sbuf_finish(sb);
4790499c3e17SSepherosa Ziehau 	sbuf_delete(sb);
4791499c3e17SSepherosa Ziehau 	return (error);
4792499c3e17SSepherosa Ziehau }
4793499c3e17SSepherosa Ziehau 
4794499c3e17SSepherosa Ziehau static int
4795499c3e17SSepherosa Ziehau hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS)
4796499c3e17SSepherosa Ziehau {
4797499c3e17SSepherosa Ziehau 	struct rm_priotracker pt;
4798499c3e17SSepherosa Ziehau 	struct sbuf *sb;
4799499c3e17SSepherosa Ziehau 	int error, i;
4800499c3e17SSepherosa Ziehau 	bool first;
4801499c3e17SSepherosa Ziehau 
4802499c3e17SSepherosa Ziehau 	error = sysctl_wire_old_buffer(req, 0);
4803499c3e17SSepherosa Ziehau 	if (error != 0)
4804499c3e17SSepherosa Ziehau 		return (error);
4805499c3e17SSepherosa Ziehau 
4806499c3e17SSepherosa Ziehau 	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4807499c3e17SSepherosa Ziehau 	if (sb == NULL)
4808499c3e17SSepherosa Ziehau 		return (ENOMEM);
4809499c3e17SSepherosa Ziehau 
4810499c3e17SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
4811499c3e17SSepherosa Ziehau 
4812499c3e17SSepherosa Ziehau 	first = true;
4813499c3e17SSepherosa Ziehau 	for (i = 0; i < hn_vfmap_size; ++i) {
4814d74b7baeSGleb Smirnoff 		struct epoch_tracker et;
4815499c3e17SSepherosa Ziehau 		struct ifnet *ifp, *hn_ifp;
4816499c3e17SSepherosa Ziehau 
4817499c3e17SSepherosa Ziehau 		hn_ifp = hn_vfmap[i];
4818499c3e17SSepherosa Ziehau 		if (hn_ifp == NULL)
4819499c3e17SSepherosa Ziehau 			continue;
4820499c3e17SSepherosa Ziehau 
4821d74b7baeSGleb Smirnoff 		NET_EPOCH_ENTER(et);
4822499c3e17SSepherosa Ziehau 		ifp = ifnet_byindex(i);
4823499c3e17SSepherosa Ziehau 		if (ifp != NULL) {
4824499c3e17SSepherosa Ziehau 			if (first) {
4825499c3e17SSepherosa Ziehau 				sbuf_printf(sb, "%s:%s", ifp->if_xname,
4826499c3e17SSepherosa Ziehau 				    hn_ifp->if_xname);
4827499c3e17SSepherosa Ziehau 			} else {
4828499c3e17SSepherosa Ziehau 				sbuf_printf(sb, " %s:%s", ifp->if_xname,
4829499c3e17SSepherosa Ziehau 				    hn_ifp->if_xname);
4830499c3e17SSepherosa Ziehau 			}
4831499c3e17SSepherosa Ziehau 			first = false;
4832499c3e17SSepherosa Ziehau 		}
4833d74b7baeSGleb Smirnoff 		NET_EPOCH_EXIT(et);
4834499c3e17SSepherosa Ziehau 	}
4835499c3e17SSepherosa Ziehau 
4836499c3e17SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
4837499c3e17SSepherosa Ziehau 
4838499c3e17SSepherosa Ziehau 	error = sbuf_finish(sb);
4839499c3e17SSepherosa Ziehau 	sbuf_delete(sb);
4840499c3e17SSepherosa Ziehau 	return (error);
4841499c3e17SSepherosa Ziehau }
4842499c3e17SSepherosa Ziehau 
4843499c3e17SSepherosa Ziehau static int
48449c6cae24SSepherosa Ziehau hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS)
48459c6cae24SSepherosa Ziehau {
48469c6cae24SSepherosa Ziehau 	struct hn_softc *sc = arg1;
48479c6cae24SSepherosa Ziehau 	int error, onoff = 0;
48489c6cae24SSepherosa Ziehau 
48499c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF)
48509c6cae24SSepherosa Ziehau 		onoff = 1;
48519c6cae24SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &onoff, 0, req);
48529c6cae24SSepherosa Ziehau 	if (error || req->newptr == NULL)
48539c6cae24SSepherosa Ziehau 		return (error);
48549c6cae24SSepherosa Ziehau 
48559c6cae24SSepherosa Ziehau 	HN_LOCK(sc);
48569c6cae24SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit() */
48579c6cae24SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
48589c6cae24SSepherosa Ziehau 	if (onoff)
48599c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF;
48609c6cae24SSepherosa Ziehau 	else
48619c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags &= ~HN_XVFFLAG_ACCBPF;
48629c6cae24SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
48639c6cae24SSepherosa Ziehau 	HN_UNLOCK(sc);
48649c6cae24SSepherosa Ziehau 
48659c6cae24SSepherosa Ziehau 	return (0);
48669c6cae24SSepherosa Ziehau }
48679c6cae24SSepherosa Ziehau 
48689c6cae24SSepherosa Ziehau static int
48699c6cae24SSepherosa Ziehau hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS)
48709c6cae24SSepherosa Ziehau {
48719c6cae24SSepherosa Ziehau 	struct hn_softc *sc = arg1;
48729c6cae24SSepherosa Ziehau 	int enabled = 0;
48739c6cae24SSepherosa Ziehau 
48749c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
48759c6cae24SSepherosa Ziehau 		enabled = 1;
48769c6cae24SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &enabled, 0, req));
48779c6cae24SSepherosa Ziehau }
48789c6cae24SSepherosa Ziehau 
48799c6cae24SSepherosa Ziehau static int
488015516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff)
488115516c77SSepherosa Ziehau {
488215516c77SSepherosa Ziehau 	const struct ip *ip;
488315516c77SSepherosa Ziehau 	int len, iphlen, iplen;
488415516c77SSepherosa Ziehau 	const struct tcphdr *th;
488515516c77SSepherosa Ziehau 	int thoff;				/* TCP data offset */
488615516c77SSepherosa Ziehau 
488715516c77SSepherosa Ziehau 	len = hoff + sizeof(struct ip);
488815516c77SSepherosa Ziehau 
488915516c77SSepherosa Ziehau 	/* The packet must be at least the size of an IP header. */
489015516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < len)
489115516c77SSepherosa Ziehau 		return IPPROTO_DONE;
489215516c77SSepherosa Ziehau 
489315516c77SSepherosa Ziehau 	/* The fixed IP header must reside completely in the first mbuf. */
489415516c77SSepherosa Ziehau 	if (m->m_len < len)
489515516c77SSepherosa Ziehau 		return IPPROTO_DONE;
489615516c77SSepherosa Ziehau 
489715516c77SSepherosa Ziehau 	ip = mtodo(m, hoff);
489815516c77SSepherosa Ziehau 
489915516c77SSepherosa Ziehau 	/* Bound check the packet's stated IP header length. */
490015516c77SSepherosa Ziehau 	iphlen = ip->ip_hl << 2;
490115516c77SSepherosa Ziehau 	if (iphlen < sizeof(struct ip))		/* minimum header length */
490215516c77SSepherosa Ziehau 		return IPPROTO_DONE;
490315516c77SSepherosa Ziehau 
490415516c77SSepherosa Ziehau 	/* The full IP header must reside completely in the one mbuf. */
490515516c77SSepherosa Ziehau 	if (m->m_len < hoff + iphlen)
490615516c77SSepherosa Ziehau 		return IPPROTO_DONE;
490715516c77SSepherosa Ziehau 
490815516c77SSepherosa Ziehau 	iplen = ntohs(ip->ip_len);
490915516c77SSepherosa Ziehau 
491015516c77SSepherosa Ziehau 	/*
491115516c77SSepherosa Ziehau 	 * Check that the amount of data in the buffers is as
491215516c77SSepherosa Ziehau 	 * at least much as the IP header would have us expect.
491315516c77SSepherosa Ziehau 	 */
491415516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < hoff + iplen)
491515516c77SSepherosa Ziehau 		return IPPROTO_DONE;
491615516c77SSepherosa Ziehau 
491715516c77SSepherosa Ziehau 	/*
491815516c77SSepherosa Ziehau 	 * Ignore IP fragments.
491915516c77SSepherosa Ziehau 	 */
492015516c77SSepherosa Ziehau 	if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF))
492115516c77SSepherosa Ziehau 		return IPPROTO_DONE;
492215516c77SSepherosa Ziehau 
492315516c77SSepherosa Ziehau 	/*
492415516c77SSepherosa Ziehau 	 * The TCP/IP or UDP/IP header must be entirely contained within
492515516c77SSepherosa Ziehau 	 * the first fragment of a packet.
492615516c77SSepherosa Ziehau 	 */
492715516c77SSepherosa Ziehau 	switch (ip->ip_p) {
492815516c77SSepherosa Ziehau 	case IPPROTO_TCP:
492915516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct tcphdr))
493015516c77SSepherosa Ziehau 			return IPPROTO_DONE;
493115516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct tcphdr))
493215516c77SSepherosa Ziehau 			return IPPROTO_DONE;
493315516c77SSepherosa Ziehau 		th = (const struct tcphdr *)((const uint8_t *)ip + iphlen);
493415516c77SSepherosa Ziehau 		thoff = th->th_off << 2;
493515516c77SSepherosa Ziehau 		if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen)
493615516c77SSepherosa Ziehau 			return IPPROTO_DONE;
493715516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + thoff)
493815516c77SSepherosa Ziehau 			return IPPROTO_DONE;
493915516c77SSepherosa Ziehau 		break;
494015516c77SSepherosa Ziehau 	case IPPROTO_UDP:
494115516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct udphdr))
494215516c77SSepherosa Ziehau 			return IPPROTO_DONE;
494315516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct udphdr))
494415516c77SSepherosa Ziehau 			return IPPROTO_DONE;
494515516c77SSepherosa Ziehau 		break;
494615516c77SSepherosa Ziehau 	default:
494715516c77SSepherosa Ziehau 		if (iplen < iphlen)
494815516c77SSepherosa Ziehau 			return IPPROTO_DONE;
494915516c77SSepherosa Ziehau 		break;
495015516c77SSepherosa Ziehau 	}
495115516c77SSepherosa Ziehau 	return ip->ip_p;
495215516c77SSepherosa Ziehau }
495315516c77SSepherosa Ziehau 
4954db76829bSSepherosa Ziehau static void
4955db76829bSSepherosa Ziehau hn_rxpkt_proto(const struct mbuf *m_new, int *l3proto, int *l4proto)
4956db76829bSSepherosa Ziehau {
4957db76829bSSepherosa Ziehau 	const struct ether_header *eh;
4958db76829bSSepherosa Ziehau 	uint16_t etype;
4959db76829bSSepherosa Ziehau 	int hoff;
4960db76829bSSepherosa Ziehau 
4961db76829bSSepherosa Ziehau 	hoff = sizeof(*eh);
4962db76829bSSepherosa Ziehau 	/* Checked at the beginning of this function. */
4963db76829bSSepherosa Ziehau 	KASSERT(m_new->m_len >= hoff, ("not ethernet frame"));
4964db76829bSSepherosa Ziehau 
4965db76829bSSepherosa Ziehau 	eh = mtod(m_new, const struct ether_header *);
4966db76829bSSepherosa Ziehau 	etype = ntohs(eh->ether_type);
4967db76829bSSepherosa Ziehau 	if (etype == ETHERTYPE_VLAN) {
4968db76829bSSepherosa Ziehau 		const struct ether_vlan_header *evl;
4969db76829bSSepherosa Ziehau 
4970db76829bSSepherosa Ziehau 		hoff = sizeof(*evl);
4971db76829bSSepherosa Ziehau 		if (m_new->m_len < hoff)
4972db76829bSSepherosa Ziehau 			return;
4973db76829bSSepherosa Ziehau 		evl = mtod(m_new, const struct ether_vlan_header *);
4974db76829bSSepherosa Ziehau 		etype = ntohs(evl->evl_proto);
4975db76829bSSepherosa Ziehau 	}
4976db76829bSSepherosa Ziehau 	*l3proto = etype;
4977db76829bSSepherosa Ziehau 
4978db76829bSSepherosa Ziehau 	if (etype == ETHERTYPE_IP)
4979db76829bSSepherosa Ziehau 		*l4proto = hn_check_iplen(m_new, hoff);
4980db76829bSSepherosa Ziehau 	else
4981db76829bSSepherosa Ziehau 		*l4proto = IPPROTO_DONE;
4982db76829bSSepherosa Ziehau }
4983db76829bSSepherosa Ziehau 
498415516c77SSepherosa Ziehau static int
498515516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt)
498615516c77SSepherosa Ziehau {
498715516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
498815516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
498915516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
499015516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
499115516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
499215516c77SSepherosa Ziehau 	int lroent_cnt;
499315516c77SSepherosa Ziehau #endif
499415516c77SSepherosa Ziehau #endif
499515516c77SSepherosa Ziehau 	int i;
499615516c77SSepherosa Ziehau 
499715516c77SSepherosa Ziehau 	/*
499815516c77SSepherosa Ziehau 	 * Create RXBUF for reception.
499915516c77SSepherosa Ziehau 	 *
500015516c77SSepherosa Ziehau 	 * NOTE:
500115516c77SSepherosa Ziehau 	 * - It is shared by all channels.
500215516c77SSepherosa Ziehau 	 * - A large enough buffer is allocated, certain version of NVSes
500315516c77SSepherosa Ziehau 	 *   may further limit the usable space.
500415516c77SSepherosa Ziehau 	 */
500515516c77SSepherosa Ziehau 	sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
500615516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma,
500715516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
500815516c77SSepherosa Ziehau 	if (sc->hn_rxbuf == NULL) {
500915516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate rxbuf failed\n");
501015516c77SSepherosa Ziehau 		return (ENOMEM);
501115516c77SSepherosa Ziehau 	}
501215516c77SSepherosa Ziehau 
501315516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = ring_cnt;
501415516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt;
501515516c77SSepherosa Ziehau 
501615516c77SSepherosa Ziehau 	sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt,
501715516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
501815516c77SSepherosa Ziehau 
501915516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
502015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
502115516c77SSepherosa Ziehau 	lroent_cnt = hn_lro_entry_count;
502215516c77SSepherosa Ziehau 	if (lroent_cnt < TCP_LRO_ENTRIES)
502315516c77SSepherosa Ziehau 		lroent_cnt = TCP_LRO_ENTRIES;
502415516c77SSepherosa Ziehau 	if (bootverbose)
502515516c77SSepherosa Ziehau 		device_printf(dev, "LRO: entry count %d\n", lroent_cnt);
502615516c77SSepherosa Ziehau #endif
502715516c77SSepherosa Ziehau #endif	/* INET || INET6 */
502815516c77SSepherosa Ziehau 
502915516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
503015516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
503115516c77SSepherosa Ziehau 
503215516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.rx sysctl tree */
503315516c77SSepherosa Ziehau 	sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx",
503415516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
503515516c77SSepherosa Ziehau 
503615516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
503715516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
503815516c77SSepherosa Ziehau 
503915516c77SSepherosa Ziehau 		rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
504015516c77SSepherosa Ziehau 		    PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE,
504115516c77SSepherosa Ziehau 		    &rxr->hn_br_dma, BUS_DMA_WAITOK);
504215516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL) {
504315516c77SSepherosa Ziehau 			device_printf(dev, "allocate bufring failed\n");
504415516c77SSepherosa Ziehau 			return (ENOMEM);
504515516c77SSepherosa Ziehau 		}
504615516c77SSepherosa Ziehau 
504715516c77SSepherosa Ziehau 		if (hn_trust_hosttcp)
504815516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP;
504915516c77SSepherosa Ziehau 		if (hn_trust_hostudp)
505015516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP;
505115516c77SSepherosa Ziehau 		if (hn_trust_hostip)
505215516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP;
5053642ec226SSepherosa Ziehau 		rxr->hn_mbuf_hash = NDIS_HASH_ALL;
505415516c77SSepherosa Ziehau 		rxr->hn_ifp = sc->hn_ifp;
505515516c77SSepherosa Ziehau 		if (i < sc->hn_tx_ring_cnt)
505615516c77SSepherosa Ziehau 			rxr->hn_txr = &sc->hn_tx_ring[i];
505715516c77SSepherosa Ziehau 		rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF;
505815516c77SSepherosa Ziehau 		rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK);
505915516c77SSepherosa Ziehau 		rxr->hn_rx_idx = i;
506015516c77SSepherosa Ziehau 		rxr->hn_rxbuf = sc->hn_rxbuf;
506115516c77SSepherosa Ziehau 
506215516c77SSepherosa Ziehau 		/*
506315516c77SSepherosa Ziehau 		 * Initialize LRO.
506415516c77SSepherosa Ziehau 		 */
506515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
506615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
506715516c77SSepherosa Ziehau 		tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt,
506815516c77SSepherosa Ziehau 		    hn_lro_mbufq_depth);
506915516c77SSepherosa Ziehau #else
507015516c77SSepherosa Ziehau 		tcp_lro_init(&rxr->hn_lro);
507115516c77SSepherosa Ziehau 		rxr->hn_lro.ifp = sc->hn_ifp;
507215516c77SSepherosa Ziehau #endif
507315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
507415516c77SSepherosa Ziehau 		rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF;
507515516c77SSepherosa Ziehau 		rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF;
507615516c77SSepherosa Ziehau #endif
507715516c77SSepherosa Ziehau #endif	/* INET || INET6 */
507815516c77SSepherosa Ziehau 
507915516c77SSepherosa Ziehau 		if (sc->hn_rx_sysctl_tree != NULL) {
508015516c77SSepherosa Ziehau 			char name[16];
508115516c77SSepherosa Ziehau 
508215516c77SSepherosa Ziehau 			/*
508315516c77SSepherosa Ziehau 			 * Create per RX ring sysctl tree:
508415516c77SSepherosa Ziehau 			 * dev.hn.UNIT.rx.RINGID
508515516c77SSepherosa Ziehau 			 */
508615516c77SSepherosa Ziehau 			snprintf(name, sizeof(name), "%d", i);
508715516c77SSepherosa Ziehau 			rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx,
508815516c77SSepherosa Ziehau 			    SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree),
508915516c77SSepherosa Ziehau 			    OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
509015516c77SSepherosa Ziehau 
509115516c77SSepherosa Ziehau 			if (rxr->hn_rx_sysctl_tree != NULL) {
509215516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
509315516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
5094db0ac6deSCy Schubert 				    OID_AUTO, "packets",
5095db0ac6deSCy Schubert 				    CTLFLAG_RW | CTLFLAG_STATS, &rxr->hn_pkts,
5096db0ac6deSCy Schubert 				    "# of packets received");
509715516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
509815516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
5099db0ac6deSCy Schubert 				    OID_AUTO, "rss_pkts",
5100db0ac6deSCy Schubert 				    CTLFLAG_RW | CTLFLAG_STATS,
510115516c77SSepherosa Ziehau 				    &rxr->hn_rss_pkts,
510215516c77SSepherosa Ziehau 				    "# of packets w/ RSS info received");
5103a491581fSWei Hu 				SYSCTL_ADD_ULONG(ctx,
5104a491581fSWei Hu 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
5105db0ac6deSCy Schubert 				    OID_AUTO, "rsc_pkts",
5106db0ac6deSCy Schubert 				    CTLFLAG_RW | CTLFLAG_STATS,
5107a491581fSWei Hu 				    &rxr->hn_rsc_pkts,
5108a491581fSWei Hu 				    "# of RSC packets received");
5109a491581fSWei Hu 				SYSCTL_ADD_ULONG(ctx,
5110a491581fSWei Hu 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
5111db0ac6deSCy Schubert 				    OID_AUTO, "rsc_drop",
5112db0ac6deSCy Schubert 				    CTLFLAG_RW | CTLFLAG_STATS,
5113a491581fSWei Hu 				    &rxr->hn_rsc_drop,
5114a491581fSWei Hu 				    "# of RSC fragments dropped");
511515516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx,
511615516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
511715516c77SSepherosa Ziehau 				    OID_AUTO, "pktbuf_len", CTLFLAG_RD,
511815516c77SSepherosa Ziehau 				    &rxr->hn_pktbuf_len, 0,
511915516c77SSepherosa Ziehau 				    "Temporary channel packet buffer length");
512015516c77SSepherosa Ziehau 			}
512115516c77SSepherosa Ziehau 		}
512215516c77SSepherosa Ziehau 	}
512315516c77SSepherosa Ziehau 
512415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued",
5125db0ac6deSCy Schubert 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS , sc,
512615516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_queued),
512715516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
512815516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
512915516c77SSepherosa Ziehau #else
513015516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
513115516c77SSepherosa Ziehau #endif
513215516c77SSepherosa Ziehau 	    "LU", "LRO queued");
513315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed",
5134db0ac6deSCy Schubert 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS , sc,
513515516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_flushed),
513615516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
513715516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
513815516c77SSepherosa Ziehau #else
513915516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
514015516c77SSepherosa Ziehau #endif
514115516c77SSepherosa Ziehau 	    "LU", "LRO flushed");
514215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried",
5143db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS , sc,
514415516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro_tried),
514515516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries");
514615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
514715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim",
514815516c77SSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
514915516c77SSepherosa Ziehau 	    hn_lro_lenlim_sysctl, "IU",
515015516c77SSepherosa Ziehau 	    "Max # of data bytes to be aggregated by LRO");
515115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim",
515215516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
515315516c77SSepherosa Ziehau 	    hn_lro_ackcnt_sysctl, "I",
515415516c77SSepherosa Ziehau 	    "Max # of ACKs to be aggregated by LRO");
515515516c77SSepherosa Ziehau #endif
515615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp",
515715516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP,
515815516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
5159b15a632cSGordon Bergling 	    "Trust tcp segment verification on host side, "
516015516c77SSepherosa Ziehau 	    "when csum info is missing");
516115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp",
516215516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP,
516315516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
516415516c77SSepherosa Ziehau 	    "Trust udp datagram verification on host side, "
516515516c77SSepherosa Ziehau 	    "when csum info is missing");
516615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip",
516715516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP,
516815516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
516915516c77SSepherosa Ziehau 	    "Trust ip packet verification on host side, "
517015516c77SSepherosa Ziehau 	    "when csum info is missing");
517115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip",
5172db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS , sc,
517315516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_ip),
517415516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP");
517515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp",
5176db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS , sc,
517715516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_tcp),
517815516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP");
517915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp",
5180db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS , sc,
518115516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_udp),
518215516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP");
518315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted",
518415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
518515516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_trusted),
518615516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU",
518715516c77SSepherosa Ziehau 	    "# of packets that we trust host's csum verification");
518815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts",
5189db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS , sc,
519015516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_small_pkts),
519115516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of small packets received");
519215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed",
5193db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS , sc,
519415516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_ack_failed),
519515516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures");
519615516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt",
519715516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings");
519815516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse",
519915516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings");
520015516c77SSepherosa Ziehau 
520115516c77SSepherosa Ziehau 	return (0);
520215516c77SSepherosa Ziehau }
520315516c77SSepherosa Ziehau 
520415516c77SSepherosa Ziehau static void
520515516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc)
520615516c77SSepherosa Ziehau {
520715516c77SSepherosa Ziehau 	int i;
520815516c77SSepherosa Ziehau 
520915516c77SSepherosa Ziehau 	if (sc->hn_rxbuf != NULL) {
52102494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0)
521115516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf);
52122494d735SSepherosa Ziehau 		else
52132494d735SSepherosa Ziehau 			device_printf(sc->hn_dev, "RXBUF is referenced\n");
521415516c77SSepherosa Ziehau 		sc->hn_rxbuf = NULL;
521515516c77SSepherosa Ziehau 	}
521615516c77SSepherosa Ziehau 
521715516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_cnt == 0)
521815516c77SSepherosa Ziehau 		return;
521915516c77SSepherosa Ziehau 
522015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
522115516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
522215516c77SSepherosa Ziehau 
522315516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL)
522415516c77SSepherosa Ziehau 			continue;
52252494d735SSepherosa Ziehau 		if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) {
522615516c77SSepherosa Ziehau 			hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br);
52272494d735SSepherosa Ziehau 		} else {
52282494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
52292494d735SSepherosa Ziehau 			    "%dth channel bufring is referenced", i);
52302494d735SSepherosa Ziehau 		}
523115516c77SSepherosa Ziehau 		rxr->hn_br = NULL;
523215516c77SSepherosa Ziehau 
523315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
523415516c77SSepherosa Ziehau 		tcp_lro_free(&rxr->hn_lro);
523515516c77SSepherosa Ziehau #endif
523615516c77SSepherosa Ziehau 		free(rxr->hn_pktbuf, M_DEVBUF);
523715516c77SSepherosa Ziehau 	}
523815516c77SSepherosa Ziehau 	free(sc->hn_rx_ring, M_DEVBUF);
523915516c77SSepherosa Ziehau 	sc->hn_rx_ring = NULL;
524015516c77SSepherosa Ziehau 
524115516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = 0;
524215516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = 0;
524315516c77SSepherosa Ziehau }
524415516c77SSepherosa Ziehau 
524515516c77SSepherosa Ziehau static int
524615516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id)
524715516c77SSepherosa Ziehau {
524815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[id];
524915516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
525015516c77SSepherosa Ziehau 	bus_dma_tag_t parent_dtag;
525115516c77SSepherosa Ziehau 	int error, i;
525215516c77SSepherosa Ziehau 
525315516c77SSepherosa Ziehau 	txr->hn_sc = sc;
525415516c77SSepherosa Ziehau 	txr->hn_tx_idx = id;
525515516c77SSepherosa Ziehau 
525615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
525715516c77SSepherosa Ziehau 	mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN);
525815516c77SSepherosa Ziehau #endif
525915516c77SSepherosa Ziehau 	mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF);
526015516c77SSepherosa Ziehau 
526115516c77SSepherosa Ziehau 	txr->hn_txdesc_cnt = HN_TX_DESC_CNT;
526215516c77SSepherosa Ziehau 	txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt,
526315516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
526415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
526515516c77SSepherosa Ziehau 	SLIST_INIT(&txr->hn_txlist);
526615516c77SSepherosa Ziehau #else
526715516c77SSepherosa Ziehau 	txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF,
526815516c77SSepherosa Ziehau 	    M_WAITOK, &txr->hn_tx_lock);
526915516c77SSepherosa Ziehau #endif
527015516c77SSepherosa Ziehau 
52710e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_EVTTQ) {
52720e11868dSSepherosa Ziehau 		txr->hn_tx_taskq = VMBUS_GET_EVENT_TASKQ(
52730e11868dSSepherosa Ziehau 		    device_get_parent(dev), dev, HN_RING_IDX2CPU(sc, id));
52740e11868dSSepherosa Ziehau 	} else {
5275fdd0222aSSepherosa Ziehau 		txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt];
52760e11868dSSepherosa Ziehau 	}
527715516c77SSepherosa Ziehau 
527823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
527915516c77SSepherosa Ziehau 	if (hn_use_if_start) {
528015516c77SSepherosa Ziehau 		txr->hn_txeof = hn_start_txeof;
528115516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr);
528215516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr);
528323bf9e15SSepherosa Ziehau 	} else
528423bf9e15SSepherosa Ziehau #endif
528523bf9e15SSepherosa Ziehau 	{
528615516c77SSepherosa Ziehau 		int br_depth;
528715516c77SSepherosa Ziehau 
528815516c77SSepherosa Ziehau 		txr->hn_txeof = hn_xmit_txeof;
528915516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr);
529015516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr);
529115516c77SSepherosa Ziehau 
529215516c77SSepherosa Ziehau 		br_depth = hn_get_txswq_depth(txr);
529315516c77SSepherosa Ziehau 		txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF,
529415516c77SSepherosa Ziehau 		    M_WAITOK, &txr->hn_tx_lock);
529515516c77SSepherosa Ziehau 	}
529615516c77SSepherosa Ziehau 
529715516c77SSepherosa Ziehau 	txr->hn_direct_tx_size = hn_direct_tx_size;
529815516c77SSepherosa Ziehau 
529915516c77SSepherosa Ziehau 	/*
530015516c77SSepherosa Ziehau 	 * Always schedule transmission instead of trying to do direct
530115516c77SSepherosa Ziehau 	 * transmission.  This one gives the best performance so far.
530215516c77SSepherosa Ziehau 	 */
530315516c77SSepherosa Ziehau 	txr->hn_sched_tx = 1;
530415516c77SSepherosa Ziehau 
530515516c77SSepherosa Ziehau 	parent_dtag = bus_get_dma_tag(dev);
530615516c77SSepherosa Ziehau 
530715516c77SSepherosa Ziehau 	/* DMA tag for RNDIS packet messages. */
530815516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
530915516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_ALIGN,		/* alignment */
531015516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_BOUNDARY,	/* boundary */
531115516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
531215516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
531315516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
531415516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsize */
531515516c77SSepherosa Ziehau 	    1,				/* nsegments */
531615516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsegsize */
531715516c77SSepherosa Ziehau 	    0,				/* flags */
531815516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
531915516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
532015516c77SSepherosa Ziehau 	    &txr->hn_tx_rndis_dtag);
532115516c77SSepherosa Ziehau 	if (error) {
532215516c77SSepherosa Ziehau 		device_printf(dev, "failed to create rndis dmatag\n");
532315516c77SSepherosa Ziehau 		return error;
532415516c77SSepherosa Ziehau 	}
532515516c77SSepherosa Ziehau 
532615516c77SSepherosa Ziehau 	/* DMA tag for data. */
532715516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
532815516c77SSepherosa Ziehau 	    1,				/* alignment */
532915516c77SSepherosa Ziehau 	    HN_TX_DATA_BOUNDARY,	/* boundary */
533015516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
533115516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
533215516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
533315516c77SSepherosa Ziehau 	    HN_TX_DATA_MAXSIZE,		/* maxsize */
533415516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGCNT_MAX,	/* nsegments */
533515516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGSIZE,		/* maxsegsize */
533615516c77SSepherosa Ziehau 	    0,				/* flags */
533715516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
533815516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
533915516c77SSepherosa Ziehau 	    &txr->hn_tx_data_dtag);
534015516c77SSepherosa Ziehau 	if (error) {
534115516c77SSepherosa Ziehau 		device_printf(dev, "failed to create data dmatag\n");
534215516c77SSepherosa Ziehau 		return error;
534315516c77SSepherosa Ziehau 	}
534415516c77SSepherosa Ziehau 
534515516c77SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i) {
534615516c77SSepherosa Ziehau 		struct hn_txdesc *txd = &txr->hn_txdesc[i];
534715516c77SSepherosa Ziehau 
534815516c77SSepherosa Ziehau 		txd->txr = txr;
534915516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
5350dc13fee6SSepherosa Ziehau 		STAILQ_INIT(&txd->agg_list);
535115516c77SSepherosa Ziehau 
535215516c77SSepherosa Ziehau 		/*
535315516c77SSepherosa Ziehau 		 * Allocate and load RNDIS packet message.
535415516c77SSepherosa Ziehau 		 */
535515516c77SSepherosa Ziehau         	error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag,
535615516c77SSepherosa Ziehau 		    (void **)&txd->rndis_pkt,
535715516c77SSepherosa Ziehau 		    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
535815516c77SSepherosa Ziehau 		    &txd->rndis_pkt_dmap);
535915516c77SSepherosa Ziehau 		if (error) {
536015516c77SSepherosa Ziehau 			device_printf(dev,
536115516c77SSepherosa Ziehau 			    "failed to allocate rndis_packet_msg, %d\n", i);
536215516c77SSepherosa Ziehau 			return error;
536315516c77SSepherosa Ziehau 		}
536415516c77SSepherosa Ziehau 
536515516c77SSepherosa Ziehau 		error = bus_dmamap_load(txr->hn_tx_rndis_dtag,
536615516c77SSepherosa Ziehau 		    txd->rndis_pkt_dmap,
536715516c77SSepherosa Ziehau 		    txd->rndis_pkt, HN_RNDIS_PKT_LEN,
536815516c77SSepherosa Ziehau 		    hyperv_dma_map_paddr, &txd->rndis_pkt_paddr,
536915516c77SSepherosa Ziehau 		    BUS_DMA_NOWAIT);
537015516c77SSepherosa Ziehau 		if (error) {
537115516c77SSepherosa Ziehau 			device_printf(dev,
537215516c77SSepherosa Ziehau 			    "failed to load rndis_packet_msg, %d\n", i);
537315516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
537415516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
537515516c77SSepherosa Ziehau 			return error;
537615516c77SSepherosa Ziehau 		}
537715516c77SSepherosa Ziehau 
537815516c77SSepherosa Ziehau 		/* DMA map for TX data. */
537915516c77SSepherosa Ziehau 		error = bus_dmamap_create(txr->hn_tx_data_dtag, 0,
538015516c77SSepherosa Ziehau 		    &txd->data_dmap);
538115516c77SSepherosa Ziehau 		if (error) {
538215516c77SSepherosa Ziehau 			device_printf(dev,
538315516c77SSepherosa Ziehau 			    "failed to allocate tx data dmamap\n");
538415516c77SSepherosa Ziehau 			bus_dmamap_unload(txr->hn_tx_rndis_dtag,
538515516c77SSepherosa Ziehau 			    txd->rndis_pkt_dmap);
538615516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
538715516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
538815516c77SSepherosa Ziehau 			return error;
538915516c77SSepherosa Ziehau 		}
539015516c77SSepherosa Ziehau 
539115516c77SSepherosa Ziehau 		/* All set, put it to list */
539215516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_ONLIST;
539315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
539415516c77SSepherosa Ziehau 		SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
539515516c77SSepherosa Ziehau #else
539615516c77SSepherosa Ziehau 		buf_ring_enqueue(txr->hn_txdesc_br, txd);
539715516c77SSepherosa Ziehau #endif
539815516c77SSepherosa Ziehau 	}
539915516c77SSepherosa Ziehau 	txr->hn_txdesc_avail = txr->hn_txdesc_cnt;
540015516c77SSepherosa Ziehau 
540115516c77SSepherosa Ziehau 	if (sc->hn_tx_sysctl_tree != NULL) {
540215516c77SSepherosa Ziehau 		struct sysctl_oid_list *child;
540315516c77SSepherosa Ziehau 		struct sysctl_ctx_list *ctx;
540415516c77SSepherosa Ziehau 		char name[16];
540515516c77SSepherosa Ziehau 
540615516c77SSepherosa Ziehau 		/*
540715516c77SSepherosa Ziehau 		 * Create per TX ring sysctl tree:
540815516c77SSepherosa Ziehau 		 * dev.hn.UNIT.tx.RINGID
540915516c77SSepherosa Ziehau 		 */
541015516c77SSepherosa Ziehau 		ctx = device_get_sysctl_ctx(dev);
541115516c77SSepherosa Ziehau 		child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree);
541215516c77SSepherosa Ziehau 
541315516c77SSepherosa Ziehau 		snprintf(name, sizeof(name), "%d", id);
541415516c77SSepherosa Ziehau 		txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
541515516c77SSepherosa Ziehau 		    name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
541615516c77SSepherosa Ziehau 
541715516c77SSepherosa Ziehau 		if (txr->hn_tx_sysctl_tree != NULL) {
541815516c77SSepherosa Ziehau 			child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree);
541915516c77SSepherosa Ziehau 
542085e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
542115516c77SSepherosa Ziehau 			SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail",
542215516c77SSepherosa Ziehau 			    CTLFLAG_RD, &txr->hn_txdesc_avail, 0,
542315516c77SSepherosa Ziehau 			    "# of available TX descs");
542485e4ae1eSSepherosa Ziehau #endif
542523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
542623bf9e15SSepherosa Ziehau 			if (!hn_use_if_start)
542723bf9e15SSepherosa Ziehau #endif
542823bf9e15SSepherosa Ziehau 			{
542915516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive",
543015516c77SSepherosa Ziehau 				    CTLFLAG_RD, &txr->hn_oactive, 0,
543115516c77SSepherosa Ziehau 				    "over active");
543215516c77SSepherosa Ziehau 			}
543315516c77SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets",
5434db0ac6deSCy Schubert 			    CTLFLAG_RW | CTLFLAG_STATS, &txr->hn_pkts,
543515516c77SSepherosa Ziehau 			    "# of packets transmitted");
5436dc13fee6SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends",
5437db0ac6deSCy Schubert 			    CTLFLAG_RW | CTLFLAG_STATS, &txr->hn_sends,
5438db0ac6deSCy Schubert 			    "# of sends");
543915516c77SSepherosa Ziehau 		}
544015516c77SSepherosa Ziehau 	}
544115516c77SSepherosa Ziehau 
544215516c77SSepherosa Ziehau 	return 0;
544315516c77SSepherosa Ziehau }
544415516c77SSepherosa Ziehau 
544515516c77SSepherosa Ziehau static void
544615516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd)
544715516c77SSepherosa Ziehau {
544815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = txd->txr;
544915516c77SSepherosa Ziehau 
545015516c77SSepherosa Ziehau 	KASSERT(txd->m == NULL, ("still has mbuf installed"));
545115516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped"));
545215516c77SSepherosa Ziehau 
545315516c77SSepherosa Ziehau 	bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap);
545415516c77SSepherosa Ziehau 	bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt,
545515516c77SSepherosa Ziehau 	    txd->rndis_pkt_dmap);
545615516c77SSepherosa Ziehau 	bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap);
545715516c77SSepherosa Ziehau }
545815516c77SSepherosa Ziehau 
545915516c77SSepherosa Ziehau static void
546025641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd)
546125641fc7SSepherosa Ziehau {
546225641fc7SSepherosa Ziehau 
546325641fc7SSepherosa Ziehau 	KASSERT(txd->refs == 0 || txd->refs == 1,
546425641fc7SSepherosa Ziehau 	    ("invalid txd refs %d", txd->refs));
546525641fc7SSepherosa Ziehau 
546625641fc7SSepherosa Ziehau 	/* Aggregated txds will be freed by their aggregating txd. */
546725641fc7SSepherosa Ziehau 	if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) {
5468a0f49d67SMateusz Guzik 		int freed __diagused;
546925641fc7SSepherosa Ziehau 
547025641fc7SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
547125641fc7SSepherosa Ziehau 		KASSERT(freed, ("can't free txdesc"));
547225641fc7SSepherosa Ziehau 	}
547325641fc7SSepherosa Ziehau }
547425641fc7SSepherosa Ziehau 
547525641fc7SSepherosa Ziehau static void
547615516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr)
547715516c77SSepherosa Ziehau {
547825641fc7SSepherosa Ziehau 	int i;
547915516c77SSepherosa Ziehau 
548015516c77SSepherosa Ziehau 	if (txr->hn_txdesc == NULL)
548115516c77SSepherosa Ziehau 		return;
548215516c77SSepherosa Ziehau 
548325641fc7SSepherosa Ziehau 	/*
548425641fc7SSepherosa Ziehau 	 * NOTE:
548525641fc7SSepherosa Ziehau 	 * Because the freeing of aggregated txds will be deferred
548625641fc7SSepherosa Ziehau 	 * to the aggregating txd, two passes are used here:
548725641fc7SSepherosa Ziehau 	 * - The first pass GCes any pending txds.  This GC is necessary,
548825641fc7SSepherosa Ziehau 	 *   since if the channels are revoked, hypervisor will not
548925641fc7SSepherosa Ziehau 	 *   deliver send-done for all pending txds.
549025641fc7SSepherosa Ziehau 	 * - The second pass frees the busdma stuffs, i.e. after all txds
549125641fc7SSepherosa Ziehau 	 *   were freed.
549225641fc7SSepherosa Ziehau 	 */
549325641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
549425641fc7SSepherosa Ziehau 		hn_txdesc_gc(txr, &txr->hn_txdesc[i]);
549525641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
549625641fc7SSepherosa Ziehau 		hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]);
549715516c77SSepherosa Ziehau 
549815516c77SSepherosa Ziehau 	if (txr->hn_tx_data_dtag != NULL)
549915516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_data_dtag);
550015516c77SSepherosa Ziehau 	if (txr->hn_tx_rndis_dtag != NULL)
550115516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_rndis_dtag);
550215516c77SSepherosa Ziehau 
550315516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
550415516c77SSepherosa Ziehau 	buf_ring_free(txr->hn_txdesc_br, M_DEVBUF);
550515516c77SSepherosa Ziehau #endif
550615516c77SSepherosa Ziehau 
550715516c77SSepherosa Ziehau 	free(txr->hn_txdesc, M_DEVBUF);
550815516c77SSepherosa Ziehau 	txr->hn_txdesc = NULL;
550915516c77SSepherosa Ziehau 
551015516c77SSepherosa Ziehau 	if (txr->hn_mbuf_br != NULL)
551115516c77SSepherosa Ziehau 		buf_ring_free(txr->hn_mbuf_br, M_DEVBUF);
551215516c77SSepherosa Ziehau 
551315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
551415516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_txlist_spin);
551515516c77SSepherosa Ziehau #endif
551615516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_tx_lock);
551715516c77SSepherosa Ziehau }
551815516c77SSepherosa Ziehau 
551915516c77SSepherosa Ziehau static int
552015516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt)
552115516c77SSepherosa Ziehau {
552215516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
552315516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
552415516c77SSepherosa Ziehau 	int i;
552515516c77SSepherosa Ziehau 
552615516c77SSepherosa Ziehau 	/*
552715516c77SSepherosa Ziehau 	 * Create TXBUF for chimney sending.
552815516c77SSepherosa Ziehau 	 *
552915516c77SSepherosa Ziehau 	 * NOTE: It is shared by all channels.
553015516c77SSepherosa Ziehau 	 */
553115516c77SSepherosa Ziehau 	sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev),
553215516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma,
553315516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
553415516c77SSepherosa Ziehau 	if (sc->hn_chim == NULL) {
553515516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate txbuf failed\n");
553615516c77SSepherosa Ziehau 		return (ENOMEM);
553715516c77SSepherosa Ziehau 	}
553815516c77SSepherosa Ziehau 
553915516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = ring_cnt;
554015516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
554115516c77SSepherosa Ziehau 
554215516c77SSepherosa Ziehau 	sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt,
554315516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
554415516c77SSepherosa Ziehau 
554515516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(sc->hn_dev);
554615516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev));
554715516c77SSepherosa Ziehau 
554815516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.tx sysctl tree */
554915516c77SSepherosa Ziehau 	sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx",
555015516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
555115516c77SSepherosa Ziehau 
555215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
555315516c77SSepherosa Ziehau 		int error;
555415516c77SSepherosa Ziehau 
555515516c77SSepherosa Ziehau 		error = hn_tx_ring_create(sc, i);
555615516c77SSepherosa Ziehau 		if (error)
555715516c77SSepherosa Ziehau 			return error;
555815516c77SSepherosa Ziehau 	}
555915516c77SSepherosa Ziehau 
556015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs",
5561db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS, sc,
556215516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_no_txdescs),
556315516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs");
556415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed",
5565db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS, sc,
556615516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_send_failed),
556715516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure");
556815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed",
5569db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS, sc,
557015516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_txdma_failed),
557115516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure");
5572dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed",
5573db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS, sc,
5574dc13fee6SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_flush_failed),
5575dc13fee6SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU",
5576dc13fee6SSepherosa Ziehau 	    "# of packet transmission aggregation flush failure");
557715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed",
5578db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS, sc,
557915516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_collapsed),
558015516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed");
558115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney",
5582db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS, sc,
558315516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney),
558415516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send");
558515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried",
5586db0ac6deSCy Schubert 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE | CTLFLAG_STATS, sc,
558715516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney_tried),
558815516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries");
558915516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt",
559015516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0,
559115516c77SSepherosa Ziehau 	    "# of total TX descs");
559215516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max",
559315516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_chim_szmax, 0,
559415516c77SSepherosa Ziehau 	    "Chimney send packet size upper boundary");
559515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size",
559615516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
559715516c77SSepherosa Ziehau 	    hn_chim_size_sysctl, "I", "Chimney send packet size limit");
559815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size",
559915516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
560015516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_direct_tx_size),
560115516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
560215516c77SSepherosa Ziehau 	    "Size of the packet for direct transmission");
560315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx",
560415516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
560515516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_sched_tx),
560615516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
560715516c77SSepherosa Ziehau 	    "Always schedule transmission "
560815516c77SSepherosa Ziehau 	    "instead of doing direct transmission");
560915516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt",
561015516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings");
561115516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse",
561215516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings");
5613dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax",
5614dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0,
5615dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation size");
5616dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax",
5617dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
5618dc13fee6SSepherosa Ziehau 	    hn_txagg_pktmax_sysctl, "I",
5619dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation packets");
5620dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align",
5621dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
5622dc13fee6SSepherosa Ziehau 	    hn_txagg_align_sysctl, "I",
5623dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation alignment");
562415516c77SSepherosa Ziehau 
562515516c77SSepherosa Ziehau 	return 0;
562615516c77SSepherosa Ziehau }
562715516c77SSepherosa Ziehau 
562815516c77SSepherosa Ziehau static void
562915516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size)
563015516c77SSepherosa Ziehau {
563115516c77SSepherosa Ziehau 	int i;
563215516c77SSepherosa Ziehau 
5633a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
563415516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_chim_size = chim_size;
563515516c77SSepherosa Ziehau }
563615516c77SSepherosa Ziehau 
563715516c77SSepherosa Ziehau static void
563815516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu)
563915516c77SSepherosa Ziehau {
564015516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
56419c6cae24SSepherosa Ziehau 	u_int hw_tsomax;
564215516c77SSepherosa Ziehau 	int tso_minlen;
564315516c77SSepherosa Ziehau 
56449c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
56459c6cae24SSepherosa Ziehau 
564615516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0)
564715516c77SSepherosa Ziehau 		return;
564815516c77SSepherosa Ziehau 
564915516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_sgmin >= 2,
565015516c77SSepherosa Ziehau 	    ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin));
565115516c77SSepherosa Ziehau 	tso_minlen = sc->hn_ndis_tso_sgmin * mtu;
565215516c77SSepherosa Ziehau 
565315516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen &&
565415516c77SSepherosa Ziehau 	    sc->hn_ndis_tso_szmax <= IP_MAXPACKET,
565515516c77SSepherosa Ziehau 	    ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax));
565615516c77SSepherosa Ziehau 
565715516c77SSepherosa Ziehau 	if (tso_maxlen < tso_minlen)
565815516c77SSepherosa Ziehau 		tso_maxlen = tso_minlen;
565915516c77SSepherosa Ziehau 	else if (tso_maxlen > IP_MAXPACKET)
566015516c77SSepherosa Ziehau 		tso_maxlen = IP_MAXPACKET;
566115516c77SSepherosa Ziehau 	if (tso_maxlen > sc->hn_ndis_tso_szmax)
566215516c77SSepherosa Ziehau 		tso_maxlen = sc->hn_ndis_tso_szmax;
56639c6cae24SSepherosa Ziehau 	hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
56649c6cae24SSepherosa Ziehau 
56659c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_isready(sc)) {
56669c6cae24SSepherosa Ziehau 		if (hw_tsomax > sc->hn_vf_ifp->if_hw_tsomax)
56679c6cae24SSepherosa Ziehau 			hw_tsomax = sc->hn_vf_ifp->if_hw_tsomax;
56689c6cae24SSepherosa Ziehau 	}
56699c6cae24SSepherosa Ziehau 	ifp->if_hw_tsomax = hw_tsomax;
567015516c77SSepherosa Ziehau 	if (bootverbose)
567115516c77SSepherosa Ziehau 		if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax);
567215516c77SSepherosa Ziehau }
567315516c77SSepherosa Ziehau 
567415516c77SSepherosa Ziehau static void
567515516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc)
567615516c77SSepherosa Ziehau {
567715516c77SSepherosa Ziehau 	uint64_t csum_assist;
567815516c77SSepherosa Ziehau 	int i;
567915516c77SSepherosa Ziehau 
568015516c77SSepherosa Ziehau 	hn_set_chim_size(sc, sc->hn_chim_szmax);
568115516c77SSepherosa Ziehau 	if (hn_tx_chimney_size > 0 &&
568215516c77SSepherosa Ziehau 	    hn_tx_chimney_size < sc->hn_chim_szmax)
568315516c77SSepherosa Ziehau 		hn_set_chim_size(sc, hn_tx_chimney_size);
568415516c77SSepherosa Ziehau 
568515516c77SSepherosa Ziehau 	csum_assist = 0;
568615516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_IPCS)
568715516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP;
568815516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP4CS)
568915516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_TCP;
56902be266caSSepherosa Ziehau 	if ((sc->hn_caps & HN_CAP_UDP4CS) && hn_enable_udp4cs)
569115516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_UDP;
569215516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP6CS)
569315516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_TCP;
56942be266caSSepherosa Ziehau 	if ((sc->hn_caps & HN_CAP_UDP6CS) && hn_enable_udp6cs)
569515516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_UDP;
569615516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
569715516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_csum_assist = csum_assist;
569815516c77SSepherosa Ziehau 
569915516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_HASHVAL) {
570015516c77SSepherosa Ziehau 		/*
570115516c77SSepherosa Ziehau 		 * Support HASHVAL pktinfo on TX path.
570215516c77SSepherosa Ziehau 		 */
570315516c77SSepherosa Ziehau 		if (bootverbose)
570415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n");
570515516c77SSepherosa Ziehau 		for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
570615516c77SSepherosa Ziehau 			sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL;
570715516c77SSepherosa Ziehau 	}
570815516c77SSepherosa Ziehau }
570915516c77SSepherosa Ziehau 
571015516c77SSepherosa Ziehau static void
5711db76829bSSepherosa Ziehau hn_fixup_rx_data(struct hn_softc *sc)
5712db76829bSSepherosa Ziehau {
5713db76829bSSepherosa Ziehau 
5714db76829bSSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDPHASH) {
5715db76829bSSepherosa Ziehau 		int i;
5716db76829bSSepherosa Ziehau 
5717db76829bSSepherosa Ziehau 		for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
5718db76829bSSepherosa Ziehau 			sc->hn_rx_ring[i].hn_rx_flags |= HN_RX_FLAG_UDP_HASH;
5719db76829bSSepherosa Ziehau 	}
5720db76829bSSepherosa Ziehau }
5721db76829bSSepherosa Ziehau 
5722db76829bSSepherosa Ziehau static void
572315516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc)
572415516c77SSepherosa Ziehau {
572515516c77SSepherosa Ziehau 	int i;
572615516c77SSepherosa Ziehau 
572715516c77SSepherosa Ziehau 	if (sc->hn_chim != NULL) {
57282494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) {
572915516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim);
57302494d735SSepherosa Ziehau 		} else {
57312494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
57322494d735SSepherosa Ziehau 			    "chimney sending buffer is referenced");
57332494d735SSepherosa Ziehau 		}
573415516c77SSepherosa Ziehau 		sc->hn_chim = NULL;
573515516c77SSepherosa Ziehau 	}
573615516c77SSepherosa Ziehau 
573715516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt == 0)
573815516c77SSepherosa Ziehau 		return;
573915516c77SSepherosa Ziehau 
574015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
574115516c77SSepherosa Ziehau 		hn_tx_ring_destroy(&sc->hn_tx_ring[i]);
574215516c77SSepherosa Ziehau 
574315516c77SSepherosa Ziehau 	free(sc->hn_tx_ring, M_DEVBUF);
574415516c77SSepherosa Ziehau 	sc->hn_tx_ring = NULL;
574515516c77SSepherosa Ziehau 
574615516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = 0;
574715516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = 0;
574815516c77SSepherosa Ziehau }
574915516c77SSepherosa Ziehau 
575023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
575123bf9e15SSepherosa Ziehau 
575215516c77SSepherosa Ziehau static void
575315516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused)
575415516c77SSepherosa Ziehau {
575515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
575615516c77SSepherosa Ziehau 
575715516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
575815516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
575915516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
576015516c77SSepherosa Ziehau }
576115516c77SSepherosa Ziehau 
576223bf9e15SSepherosa Ziehau static int
576323bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len)
576423bf9e15SSepherosa Ziehau {
576523bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
576623bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
5767dc13fee6SSepherosa Ziehau 	int sched = 0;
576823bf9e15SSepherosa Ziehau 
576923bf9e15SSepherosa Ziehau 	KASSERT(hn_use_if_start,
577023bf9e15SSepherosa Ziehau 	    ("hn_start_locked is called, when if_start is disabled"));
577123bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
577223bf9e15SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
5773dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
577423bf9e15SSepherosa Ziehau 
577523bf9e15SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
5776dc13fee6SSepherosa Ziehau 		return (0);
577723bf9e15SSepherosa Ziehau 
577823bf9e15SSepherosa Ziehau 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
577923bf9e15SSepherosa Ziehau 	    IFF_DRV_RUNNING)
5780dc13fee6SSepherosa Ziehau 		return (0);
578123bf9e15SSepherosa Ziehau 
578223bf9e15SSepherosa Ziehau 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
578323bf9e15SSepherosa Ziehau 		struct hn_txdesc *txd;
578423bf9e15SSepherosa Ziehau 		struct mbuf *m_head;
578523bf9e15SSepherosa Ziehau 		int error;
578623bf9e15SSepherosa Ziehau 
578723bf9e15SSepherosa Ziehau 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
578823bf9e15SSepherosa Ziehau 		if (m_head == NULL)
578923bf9e15SSepherosa Ziehau 			break;
579023bf9e15SSepherosa Ziehau 
579123bf9e15SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
579223bf9e15SSepherosa Ziehau 			/*
579323bf9e15SSepherosa Ziehau 			 * This sending could be time consuming; let callers
579423bf9e15SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
579523bf9e15SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
579623bf9e15SSepherosa Ziehau 			 */
579723bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
5798dc13fee6SSepherosa Ziehau 			sched = 1;
5799dc13fee6SSepherosa Ziehau 			break;
580023bf9e15SSepherosa Ziehau 		}
580123bf9e15SSepherosa Ziehau 
5802edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
5803edd3f315SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
5804edd3f315SSepherosa Ziehau 			m_head = hn_tso_fixup(m_head);
5805edd3f315SSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
5806edd3f315SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5807edd3f315SSepherosa Ziehau 				continue;
5808edd3f315SSepherosa Ziehau 			}
5809c49d47daSSepherosa Ziehau 		} else if (m_head->m_pkthdr.csum_flags &
5810c49d47daSSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) {
5811c49d47daSSepherosa Ziehau 			m_head = hn_set_hlen(m_head);
5812c49d47daSSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
5813c49d47daSSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5814c49d47daSSepherosa Ziehau 				continue;
5815c49d47daSSepherosa Ziehau 			}
5816edd3f315SSepherosa Ziehau 		}
5817edd3f315SSepherosa Ziehau #endif
5818edd3f315SSepherosa Ziehau 
581923bf9e15SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
582023bf9e15SSepherosa Ziehau 		if (txd == NULL) {
582123bf9e15SSepherosa Ziehau 			txr->hn_no_txdescs++;
582223bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
582323bf9e15SSepherosa Ziehau 			atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
582423bf9e15SSepherosa Ziehau 			break;
582523bf9e15SSepherosa Ziehau 		}
582623bf9e15SSepherosa Ziehau 
5827dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
582823bf9e15SSepherosa Ziehau 		if (error) {
582923bf9e15SSepherosa Ziehau 			/* Both txd and m_head are freed */
5830dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
5831dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
583223bf9e15SSepherosa Ziehau 			continue;
583323bf9e15SSepherosa Ziehau 		}
583423bf9e15SSepherosa Ziehau 
5835dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
5836dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
5837dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
5838dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
5839dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
5840dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
5841dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
5842dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
5843dc13fee6SSepherosa Ziehau 					break;
5844dc13fee6SSepherosa Ziehau 				}
5845dc13fee6SSepherosa Ziehau 			} else {
5846dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
584723bf9e15SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
584823bf9e15SSepherosa Ziehau 				if (__predict_false(error)) {
584923bf9e15SSepherosa Ziehau 					/* txd is freed, but m_head is not */
585023bf9e15SSepherosa Ziehau 					IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
5851dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
5852dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
585323bf9e15SSepherosa Ziehau 					break;
585423bf9e15SSepherosa Ziehau 				}
585523bf9e15SSepherosa Ziehau 			}
5856dc13fee6SSepherosa Ziehau 		}
5857dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
5858dc13fee6SSepherosa Ziehau 		else {
5859dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
5860dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
5861dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
5862dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
5863dc13fee6SSepherosa Ziehau 		}
5864dc13fee6SSepherosa Ziehau #endif
5865dc13fee6SSepherosa Ziehau 	}
5866dc13fee6SSepherosa Ziehau 
5867dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
5868dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
5869dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
5870dc13fee6SSepherosa Ziehau 	return (sched);
587123bf9e15SSepherosa Ziehau }
587223bf9e15SSepherosa Ziehau 
587323bf9e15SSepherosa Ziehau static void
587423bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp)
587523bf9e15SSepherosa Ziehau {
587623bf9e15SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
587723bf9e15SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[0];
587823bf9e15SSepherosa Ziehau 
587923bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
588023bf9e15SSepherosa Ziehau 		goto do_sched;
588123bf9e15SSepherosa Ziehau 
588223bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
588323bf9e15SSepherosa Ziehau 		int sched;
588423bf9e15SSepherosa Ziehau 
588523bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
588623bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
588723bf9e15SSepherosa Ziehau 		if (!sched)
588823bf9e15SSepherosa Ziehau 			return;
588923bf9e15SSepherosa Ziehau 	}
589023bf9e15SSepherosa Ziehau do_sched:
589123bf9e15SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
589223bf9e15SSepherosa Ziehau }
589323bf9e15SSepherosa Ziehau 
589415516c77SSepherosa Ziehau static void
589515516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused)
589615516c77SSepherosa Ziehau {
589715516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
589815516c77SSepherosa Ziehau 
589915516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
590015516c77SSepherosa Ziehau 	atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE);
590115516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
590215516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
590315516c77SSepherosa Ziehau }
590415516c77SSepherosa Ziehau 
590523bf9e15SSepherosa Ziehau static void
590623bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr)
590723bf9e15SSepherosa Ziehau {
590823bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
590923bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
591023bf9e15SSepherosa Ziehau 
591123bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
591223bf9e15SSepherosa Ziehau 
591323bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
591423bf9e15SSepherosa Ziehau 		goto do_sched;
591523bf9e15SSepherosa Ziehau 
591623bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
591723bf9e15SSepherosa Ziehau 		int sched;
591823bf9e15SSepherosa Ziehau 
591923bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
592023bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
592123bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
592223bf9e15SSepherosa Ziehau 		if (sched) {
592323bf9e15SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
592423bf9e15SSepherosa Ziehau 			    &txr->hn_tx_task);
592523bf9e15SSepherosa Ziehau 		}
592623bf9e15SSepherosa Ziehau 	} else {
592723bf9e15SSepherosa Ziehau do_sched:
592823bf9e15SSepherosa Ziehau 		/*
592923bf9e15SSepherosa Ziehau 		 * Release the OACTIVE earlier, with the hope, that
593023bf9e15SSepherosa Ziehau 		 * others could catch up.  The task will clear the
593123bf9e15SSepherosa Ziehau 		 * flag again with the hn_tx_lock to avoid possible
593223bf9e15SSepherosa Ziehau 		 * races.
593323bf9e15SSepherosa Ziehau 		 */
593423bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
593523bf9e15SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
593623bf9e15SSepherosa Ziehau 	}
593723bf9e15SSepherosa Ziehau }
593823bf9e15SSepherosa Ziehau 
593923bf9e15SSepherosa Ziehau #endif	/* HN_IFSTART_SUPPORT */
594023bf9e15SSepherosa Ziehau 
594115516c77SSepherosa Ziehau static int
594215516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len)
594315516c77SSepherosa Ziehau {
594415516c77SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
594515516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
594615516c77SSepherosa Ziehau 	struct mbuf *m_head;
5947dc13fee6SSepherosa Ziehau 	int sched = 0;
594815516c77SSepherosa Ziehau 
594915516c77SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
595023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
595115516c77SSepherosa Ziehau 	KASSERT(hn_use_if_start == 0,
595215516c77SSepherosa Ziehau 	    ("hn_xmit is called, when if_start is enabled"));
595323bf9e15SSepherosa Ziehau #endif
5954dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
595515516c77SSepherosa Ziehau 
595615516c77SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
5957dc13fee6SSepherosa Ziehau 		return (0);
595815516c77SSepherosa Ziehau 
595915516c77SSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive)
5960dc13fee6SSepherosa Ziehau 		return (0);
596115516c77SSepherosa Ziehau 
596215516c77SSepherosa Ziehau 	while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) {
596315516c77SSepherosa Ziehau 		struct hn_txdesc *txd;
596415516c77SSepherosa Ziehau 		int error;
596515516c77SSepherosa Ziehau 
596615516c77SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
596715516c77SSepherosa Ziehau 			/*
596815516c77SSepherosa Ziehau 			 * This sending could be time consuming; let callers
596915516c77SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
597015516c77SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
597115516c77SSepherosa Ziehau 			 */
597215516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
5973dc13fee6SSepherosa Ziehau 			sched = 1;
5974dc13fee6SSepherosa Ziehau 			break;
597515516c77SSepherosa Ziehau 		}
597615516c77SSepherosa Ziehau 
597715516c77SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
597815516c77SSepherosa Ziehau 		if (txd == NULL) {
597915516c77SSepherosa Ziehau 			txr->hn_no_txdescs++;
598015516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
598115516c77SSepherosa Ziehau 			txr->hn_oactive = 1;
598215516c77SSepherosa Ziehau 			break;
598315516c77SSepherosa Ziehau 		}
598415516c77SSepherosa Ziehau 
5985dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
598615516c77SSepherosa Ziehau 		if (error) {
598715516c77SSepherosa Ziehau 			/* Both txd and m_head are freed; discard */
5988dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
5989dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
599015516c77SSepherosa Ziehau 			drbr_advance(ifp, txr->hn_mbuf_br);
599115516c77SSepherosa Ziehau 			continue;
599215516c77SSepherosa Ziehau 		}
599315516c77SSepherosa Ziehau 
5994dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
5995dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
5996dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
5997dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
5998dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
599915516c77SSepherosa Ziehau 				if (__predict_false(error)) {
600015516c77SSepherosa Ziehau 					txr->hn_oactive = 1;
600115516c77SSepherosa Ziehau 					break;
600215516c77SSepherosa Ziehau 				}
6003dc13fee6SSepherosa Ziehau 			} else {
6004dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
6005dc13fee6SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
6006dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
6007dc13fee6SSepherosa Ziehau 					/* txd is freed, but m_head is not */
6008dc13fee6SSepherosa Ziehau 					drbr_putback(ifp, txr->hn_mbuf_br,
6009dc13fee6SSepherosa Ziehau 					    m_head);
6010dc13fee6SSepherosa Ziehau 					txr->hn_oactive = 1;
6011dc13fee6SSepherosa Ziehau 					break;
6012dc13fee6SSepherosa Ziehau 				}
6013dc13fee6SSepherosa Ziehau 			}
6014dc13fee6SSepherosa Ziehau 		}
6015dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
6016dc13fee6SSepherosa Ziehau 		else {
6017dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
6018dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
6019dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
6020dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
6021dc13fee6SSepherosa Ziehau 		}
6022dc13fee6SSepherosa Ziehau #endif
602315516c77SSepherosa Ziehau 
602415516c77SSepherosa Ziehau 		/* Sent */
602515516c77SSepherosa Ziehau 		drbr_advance(ifp, txr->hn_mbuf_br);
602615516c77SSepherosa Ziehau 	}
6027dc13fee6SSepherosa Ziehau 
6028dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
6029dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
6030dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
6031dc13fee6SSepherosa Ziehau 	return (sched);
603215516c77SSepherosa Ziehau }
603315516c77SSepherosa Ziehau 
603415516c77SSepherosa Ziehau static int
603515516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m)
603615516c77SSepherosa Ziehau {
603715516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
603815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
603915516c77SSepherosa Ziehau 	int error, idx = 0;
604015516c77SSepherosa Ziehau 
60419c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) {
60429c6cae24SSepherosa Ziehau 		struct rm_priotracker pt;
60439c6cae24SSepherosa Ziehau 
60449c6cae24SSepherosa Ziehau 		rm_rlock(&sc->hn_vf_lock, &pt);
60459c6cae24SSepherosa Ziehau 		if (__predict_true(sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
60469c6cae24SSepherosa Ziehau 			struct mbuf *m_bpf = NULL;
60479c6cae24SSepherosa Ziehau 			int obytes, omcast;
60489c6cae24SSepherosa Ziehau 
60499c6cae24SSepherosa Ziehau 			obytes = m->m_pkthdr.len;
60507898a1f4SEric van Gyzen 			omcast = (m->m_flags & M_MCAST) != 0;
60519c6cae24SSepherosa Ziehau 
60529c6cae24SSepherosa Ziehau 			if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF) {
60539c6cae24SSepherosa Ziehau 				if (bpf_peers_present(ifp->if_bpf)) {
60549c6cae24SSepherosa Ziehau 					m_bpf = m_copypacket(m, M_NOWAIT);
60559c6cae24SSepherosa Ziehau 					if (m_bpf == NULL) {
60569c6cae24SSepherosa Ziehau 						/*
60579c6cae24SSepherosa Ziehau 						 * Failed to grab a shallow
60589c6cae24SSepherosa Ziehau 						 * copy; tap now.
60599c6cae24SSepherosa Ziehau 						 */
60609c6cae24SSepherosa Ziehau 						ETHER_BPF_MTAP(ifp, m);
60619c6cae24SSepherosa Ziehau 					}
60629c6cae24SSepherosa Ziehau 				}
60639c6cae24SSepherosa Ziehau 			} else {
60649c6cae24SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, m);
60659c6cae24SSepherosa Ziehau 			}
60669c6cae24SSepherosa Ziehau 
60679c6cae24SSepherosa Ziehau 			error = sc->hn_vf_ifp->if_transmit(sc->hn_vf_ifp, m);
60689c6cae24SSepherosa Ziehau 			rm_runlock(&sc->hn_vf_lock, &pt);
60699c6cae24SSepherosa Ziehau 
60709c6cae24SSepherosa Ziehau 			if (m_bpf != NULL) {
60719c6cae24SSepherosa Ziehau 				if (!error)
60729c6cae24SSepherosa Ziehau 					ETHER_BPF_MTAP(ifp, m_bpf);
60739c6cae24SSepherosa Ziehau 				m_freem(m_bpf);
60749c6cae24SSepherosa Ziehau 			}
60759c6cae24SSepherosa Ziehau 
60769c6cae24SSepherosa Ziehau 			if (error == ENOBUFS) {
60779c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
60789c6cae24SSepherosa Ziehau 			} else if (error) {
60799c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
60809c6cae24SSepherosa Ziehau 			} else {
60819c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
60829c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OBYTES, obytes);
60839c6cae24SSepherosa Ziehau 				if (omcast) {
60849c6cae24SSepherosa Ziehau 					if_inc_counter(ifp, IFCOUNTER_OMCASTS,
60859c6cae24SSepherosa Ziehau 					    omcast);
60869c6cae24SSepherosa Ziehau 				}
60879c6cae24SSepherosa Ziehau 			}
60889c6cae24SSepherosa Ziehau 			return (error);
60899c6cae24SSepherosa Ziehau 		}
60909c6cae24SSepherosa Ziehau 		rm_runlock(&sc->hn_vf_lock, &pt);
60919c6cae24SSepherosa Ziehau 	}
60929c6cae24SSepherosa Ziehau 
6093edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
6094edd3f315SSepherosa Ziehau 	/*
6095c49d47daSSepherosa Ziehau 	 * Perform TSO packet header fixup or get l2/l3 header length now,
6096c49d47daSSepherosa Ziehau 	 * since packet headers should be cache-hot.
6097edd3f315SSepherosa Ziehau 	 */
6098edd3f315SSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
6099edd3f315SSepherosa Ziehau 		m = hn_tso_fixup(m);
6100edd3f315SSepherosa Ziehau 		if (__predict_false(m == NULL)) {
6101edd3f315SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
6102edd3f315SSepherosa Ziehau 			return EIO;
6103edd3f315SSepherosa Ziehau 		}
6104c49d47daSSepherosa Ziehau 	} else if (m->m_pkthdr.csum_flags &
6105c49d47daSSepherosa Ziehau 	    (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) {
6106c49d47daSSepherosa Ziehau 		m = hn_set_hlen(m);
6107c49d47daSSepherosa Ziehau 		if (__predict_false(m == NULL)) {
6108c49d47daSSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
6109c49d47daSSepherosa Ziehau 			return EIO;
6110c49d47daSSepherosa Ziehau 		}
6111edd3f315SSepherosa Ziehau 	}
6112edd3f315SSepherosa Ziehau #endif
6113edd3f315SSepherosa Ziehau 
611415516c77SSepherosa Ziehau 	/*
611515516c77SSepherosa Ziehau 	 * Select the TX ring based on flowid
611615516c77SSepherosa Ziehau 	 */
611734d68912SSepherosa Ziehau 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
611834d68912SSepherosa Ziehau #ifdef RSS
611934d68912SSepherosa Ziehau 		uint32_t bid;
612034d68912SSepherosa Ziehau 
612134d68912SSepherosa Ziehau 		if (rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m),
612234d68912SSepherosa Ziehau 		    &bid) == 0)
612334d68912SSepherosa Ziehau 			idx = bid % sc->hn_tx_ring_inuse;
612434d68912SSepherosa Ziehau 		else
612534d68912SSepherosa Ziehau #endif
6126cc0c6ebcSSepherosa Ziehau 		{
6127cc0c6ebcSSepherosa Ziehau #if defined(INET6) || defined(INET)
6128cc0c6ebcSSepherosa Ziehau 			int tcpsyn = 0;
6129cc0c6ebcSSepherosa Ziehau 
6130cc0c6ebcSSepherosa Ziehau 			if (m->m_pkthdr.len < 128 &&
6131cc0c6ebcSSepherosa Ziehau 			    (m->m_pkthdr.csum_flags &
6132cc0c6ebcSSepherosa Ziehau 			     (CSUM_IP_TCP | CSUM_IP6_TCP)) &&
6133cc0c6ebcSSepherosa Ziehau 			    (m->m_pkthdr.csum_flags & CSUM_TSO) == 0) {
6134cc0c6ebcSSepherosa Ziehau 				m = hn_check_tcpsyn(m, &tcpsyn);
6135cc0c6ebcSSepherosa Ziehau 				if (__predict_false(m == NULL)) {
6136cc0c6ebcSSepherosa Ziehau 					if_inc_counter(ifp,
6137cc0c6ebcSSepherosa Ziehau 					    IFCOUNTER_OERRORS, 1);
6138cc0c6ebcSSepherosa Ziehau 					return (EIO);
6139cc0c6ebcSSepherosa Ziehau 				}
6140cc0c6ebcSSepherosa Ziehau 			}
6141cc0c6ebcSSepherosa Ziehau #else
6142cc0c6ebcSSepherosa Ziehau 			const int tcpsyn = 0;
6143cc0c6ebcSSepherosa Ziehau #endif
6144cc0c6ebcSSepherosa Ziehau 			if (tcpsyn)
6145cc0c6ebcSSepherosa Ziehau 				idx = 0;
6146cc0c6ebcSSepherosa Ziehau 			else
614715516c77SSepherosa Ziehau 				idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse;
614834d68912SSepherosa Ziehau 		}
6149cc0c6ebcSSepherosa Ziehau 	}
615015516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[idx];
615115516c77SSepherosa Ziehau 
615215516c77SSepherosa Ziehau 	error = drbr_enqueue(ifp, txr->hn_mbuf_br, m);
615315516c77SSepherosa Ziehau 	if (error) {
615415516c77SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
615515516c77SSepherosa Ziehau 		return error;
615615516c77SSepherosa Ziehau 	}
615715516c77SSepherosa Ziehau 
615815516c77SSepherosa Ziehau 	if (txr->hn_oactive)
615915516c77SSepherosa Ziehau 		return 0;
616015516c77SSepherosa Ziehau 
616115516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
616215516c77SSepherosa Ziehau 		goto do_sched;
616315516c77SSepherosa Ziehau 
616415516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
616515516c77SSepherosa Ziehau 		int sched;
616615516c77SSepherosa Ziehau 
616715516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
616815516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
616915516c77SSepherosa Ziehau 		if (!sched)
617015516c77SSepherosa Ziehau 			return 0;
617115516c77SSepherosa Ziehau 	}
617215516c77SSepherosa Ziehau do_sched:
617315516c77SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
617415516c77SSepherosa Ziehau 	return 0;
617515516c77SSepherosa Ziehau }
617615516c77SSepherosa Ziehau 
617715516c77SSepherosa Ziehau static void
617815516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr)
617915516c77SSepherosa Ziehau {
618015516c77SSepherosa Ziehau 	struct mbuf *m;
618115516c77SSepherosa Ziehau 
618215516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
618315516c77SSepherosa Ziehau 	while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL)
618415516c77SSepherosa Ziehau 		m_freem(m);
618515516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
618615516c77SSepherosa Ziehau }
618715516c77SSepherosa Ziehau 
618815516c77SSepherosa Ziehau static void
618915516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp)
619015516c77SSepherosa Ziehau {
619115516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
61929c6cae24SSepherosa Ziehau 	struct rm_priotracker pt;
619315516c77SSepherosa Ziehau 	int i;
619415516c77SSepherosa Ziehau 
619515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
619615516c77SSepherosa Ziehau 		hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
619715516c77SSepherosa Ziehau 	if_qflush(ifp);
61989c6cae24SSepherosa Ziehau 
61999c6cae24SSepherosa Ziehau 	rm_rlock(&sc->hn_vf_lock, &pt);
62009c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
62019c6cae24SSepherosa Ziehau 		sc->hn_vf_ifp->if_qflush(sc->hn_vf_ifp);
62029c6cae24SSepherosa Ziehau 	rm_runlock(&sc->hn_vf_lock, &pt);
620315516c77SSepherosa Ziehau }
620415516c77SSepherosa Ziehau 
620515516c77SSepherosa Ziehau static void
620615516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr)
620715516c77SSepherosa Ziehau {
620815516c77SSepherosa Ziehau 
620915516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
621015516c77SSepherosa Ziehau 		goto do_sched;
621115516c77SSepherosa Ziehau 
621215516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
621315516c77SSepherosa Ziehau 		int sched;
621415516c77SSepherosa Ziehau 
621515516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
621615516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
621715516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
621815516c77SSepherosa Ziehau 		if (sched) {
621915516c77SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
622015516c77SSepherosa Ziehau 			    &txr->hn_tx_task);
622115516c77SSepherosa Ziehau 		}
622215516c77SSepherosa Ziehau 	} else {
622315516c77SSepherosa Ziehau do_sched:
622415516c77SSepherosa Ziehau 		/*
622515516c77SSepherosa Ziehau 		 * Release the oactive earlier, with the hope, that
622615516c77SSepherosa Ziehau 		 * others could catch up.  The task will clear the
622715516c77SSepherosa Ziehau 		 * oactive again with the hn_tx_lock to avoid possible
622815516c77SSepherosa Ziehau 		 * races.
622915516c77SSepherosa Ziehau 		 */
623015516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
623115516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
623215516c77SSepherosa Ziehau 	}
623315516c77SSepherosa Ziehau }
623415516c77SSepherosa Ziehau 
623515516c77SSepherosa Ziehau static void
623615516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused)
623715516c77SSepherosa Ziehau {
623815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
623915516c77SSepherosa Ziehau 
624015516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
624115516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
624215516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
624315516c77SSepherosa Ziehau }
624415516c77SSepherosa Ziehau 
624515516c77SSepherosa Ziehau static void
624615516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused)
624715516c77SSepherosa Ziehau {
624815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
624915516c77SSepherosa Ziehau 
625015516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
625115516c77SSepherosa Ziehau 	txr->hn_oactive = 0;
625215516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
625315516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
625415516c77SSepherosa Ziehau }
625515516c77SSepherosa Ziehau 
625615516c77SSepherosa Ziehau static int
625715516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan)
625815516c77SSepherosa Ziehau {
625915516c77SSepherosa Ziehau 	struct vmbus_chan_br cbr;
626015516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
626115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = NULL;
626215516c77SSepherosa Ziehau 	int idx, error;
626315516c77SSepherosa Ziehau 
626415516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
626515516c77SSepherosa Ziehau 
626615516c77SSepherosa Ziehau 	/*
626715516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
626815516c77SSepherosa Ziehau 	 */
626915516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
627015516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
627115516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
627215516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
627315516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0,
627415516c77SSepherosa Ziehau 	    ("RX ring %d already attached", idx));
627515516c77SSepherosa Ziehau 	rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED;
62763ab0fea1SDexuan Cui 	rxr->hn_chan = chan;
627715516c77SSepherosa Ziehau 
627815516c77SSepherosa Ziehau 	if (bootverbose) {
627915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n",
628015516c77SSepherosa Ziehau 		    idx, vmbus_chan_id(chan));
628115516c77SSepherosa Ziehau 	}
628215516c77SSepherosa Ziehau 
628315516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
628415516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[idx];
628515516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0,
628615516c77SSepherosa Ziehau 		    ("TX ring %d already attached", idx));
628715516c77SSepherosa Ziehau 		txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED;
628815516c77SSepherosa Ziehau 
628915516c77SSepherosa Ziehau 		txr->hn_chan = chan;
629015516c77SSepherosa Ziehau 		if (bootverbose) {
629115516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n",
629215516c77SSepherosa Ziehau 			    idx, vmbus_chan_id(chan));
629315516c77SSepherosa Ziehau 		}
629415516c77SSepherosa Ziehau 	}
629515516c77SSepherosa Ziehau 
629615516c77SSepherosa Ziehau 	/* Bind this channel to a proper CPU. */
62970e11868dSSepherosa Ziehau 	vmbus_chan_cpu_set(chan, HN_RING_IDX2CPU(sc, idx));
629815516c77SSepherosa Ziehau 
629915516c77SSepherosa Ziehau 	/*
630015516c77SSepherosa Ziehau 	 * Open this channel
630115516c77SSepherosa Ziehau 	 */
630215516c77SSepherosa Ziehau 	cbr.cbr = rxr->hn_br;
630315516c77SSepherosa Ziehau 	cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr;
630415516c77SSepherosa Ziehau 	cbr.cbr_txsz = HN_TXBR_SIZE;
630515516c77SSepherosa Ziehau 	cbr.cbr_rxsz = HN_RXBR_SIZE;
630615516c77SSepherosa Ziehau 	error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr);
630715516c77SSepherosa Ziehau 	if (error) {
630871e8ac56SSepherosa Ziehau 		if (error == EISCONN) {
630971e8ac56SSepherosa Ziehau 			if_printf(sc->hn_ifp, "bufring is connected after "
631071e8ac56SSepherosa Ziehau 			    "chan%u open failure\n", vmbus_chan_id(chan));
631171e8ac56SSepherosa Ziehau 			rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
631271e8ac56SSepherosa Ziehau 		} else {
631315516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "open chan%u failed: %d\n",
631415516c77SSepherosa Ziehau 			    vmbus_chan_id(chan), error);
631571e8ac56SSepherosa Ziehau 		}
631615516c77SSepherosa Ziehau 	}
631715516c77SSepherosa Ziehau 	return (error);
631815516c77SSepherosa Ziehau }
631915516c77SSepherosa Ziehau 
632015516c77SSepherosa Ziehau static void
632115516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan)
632215516c77SSepherosa Ziehau {
632315516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
63242494d735SSepherosa Ziehau 	int idx, error;
632515516c77SSepherosa Ziehau 
632615516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
632715516c77SSepherosa Ziehau 
632815516c77SSepherosa Ziehau 	/*
632915516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
633015516c77SSepherosa Ziehau 	 */
633115516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
633215516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
633315516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
633415516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
633515516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED),
633615516c77SSepherosa Ziehau 	    ("RX ring %d is not attached", idx));
633715516c77SSepherosa Ziehau 	rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
633815516c77SSepherosa Ziehau 
633915516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
634015516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[idx];
634115516c77SSepherosa Ziehau 
634215516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED),
634315516c77SSepherosa Ziehau 		    ("TX ring %d is not attached attached", idx));
634415516c77SSepherosa Ziehau 		txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
634515516c77SSepherosa Ziehau 	}
634615516c77SSepherosa Ziehau 
634715516c77SSepherosa Ziehau 	/*
634815516c77SSepherosa Ziehau 	 * Close this channel.
634915516c77SSepherosa Ziehau 	 *
635015516c77SSepherosa Ziehau 	 * NOTE:
635115516c77SSepherosa Ziehau 	 * Channel closing does _not_ destroy the target channel.
635215516c77SSepherosa Ziehau 	 */
63532494d735SSepherosa Ziehau 	error = vmbus_chan_close_direct(chan);
63542494d735SSepherosa Ziehau 	if (error == EISCONN) {
6355aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u bufring is connected "
6356aa1a2adcSSepherosa Ziehau 		    "after being closed\n", vmbus_chan_id(chan));
63572494d735SSepherosa Ziehau 		rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
63582494d735SSepherosa Ziehau 	} else if (error) {
6359aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u close failed: %d\n",
6360aa1a2adcSSepherosa Ziehau 		    vmbus_chan_id(chan), error);
63612494d735SSepherosa Ziehau 	}
636215516c77SSepherosa Ziehau }
636315516c77SSepherosa Ziehau 
636415516c77SSepherosa Ziehau static int
636515516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc)
636615516c77SSepherosa Ziehau {
636715516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
636815516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
636915516c77SSepherosa Ziehau 	int i, error = 0;
637015516c77SSepherosa Ziehau 
637171e8ac56SSepherosa Ziehau 	KASSERT(subchan_cnt > 0, ("no sub-channels"));
637215516c77SSepherosa Ziehau 
637315516c77SSepherosa Ziehau 	/* Attach the sub-channels. */
637415516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
637515516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i) {
637671e8ac56SSepherosa Ziehau 		int error1;
637771e8ac56SSepherosa Ziehau 
637871e8ac56SSepherosa Ziehau 		error1 = hn_chan_attach(sc, subchans[i]);
637971e8ac56SSepherosa Ziehau 		if (error1) {
638071e8ac56SSepherosa Ziehau 			error = error1;
638171e8ac56SSepherosa Ziehau 			/* Move on; all channels will be detached later. */
638271e8ac56SSepherosa Ziehau 		}
638315516c77SSepherosa Ziehau 	}
638415516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
638515516c77SSepherosa Ziehau 
638615516c77SSepherosa Ziehau 	if (error) {
638715516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error);
638815516c77SSepherosa Ziehau 	} else {
638915516c77SSepherosa Ziehau 		if (bootverbose) {
639015516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "%d sub-channels attached\n",
639115516c77SSepherosa Ziehau 			    subchan_cnt);
639215516c77SSepherosa Ziehau 		}
639315516c77SSepherosa Ziehau 	}
639415516c77SSepherosa Ziehau 	return (error);
639515516c77SSepherosa Ziehau }
639615516c77SSepherosa Ziehau 
639715516c77SSepherosa Ziehau static void
639815516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc)
639915516c77SSepherosa Ziehau {
640015516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
640115516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
640215516c77SSepherosa Ziehau 	int i;
640315516c77SSepherosa Ziehau 
640415516c77SSepherosa Ziehau 	if (subchan_cnt == 0)
640515516c77SSepherosa Ziehau 		goto back;
640615516c77SSepherosa Ziehau 
640715516c77SSepherosa Ziehau 	/* Detach the sub-channels. */
640815516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
640915516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i)
641015516c77SSepherosa Ziehau 		hn_chan_detach(sc, subchans[i]);
641115516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
641215516c77SSepherosa Ziehau 
641315516c77SSepherosa Ziehau back:
641415516c77SSepherosa Ziehau 	/*
641515516c77SSepherosa Ziehau 	 * Detach the primary channel, _after_ all sub-channels
641615516c77SSepherosa Ziehau 	 * are detached.
641715516c77SSepherosa Ziehau 	 */
641815516c77SSepherosa Ziehau 	hn_chan_detach(sc, sc->hn_prichan);
641915516c77SSepherosa Ziehau 
642015516c77SSepherosa Ziehau 	/* Wait for sub-channels to be destroyed, if any. */
642115516c77SSepherosa Ziehau 	vmbus_subchan_drain(sc->hn_prichan);
642215516c77SSepherosa Ziehau 
642315516c77SSepherosa Ziehau #ifdef INVARIANTS
642415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
642515516c77SSepherosa Ziehau 		KASSERT((sc->hn_rx_ring[i].hn_rx_flags &
642615516c77SSepherosa Ziehau 		    HN_RX_FLAG_ATTACHED) == 0,
642715516c77SSepherosa Ziehau 		    ("%dth RX ring is still attached", i));
642815516c77SSepherosa Ziehau 	}
642915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
643015516c77SSepherosa Ziehau 		KASSERT((sc->hn_tx_ring[i].hn_tx_flags &
643115516c77SSepherosa Ziehau 		    HN_TX_FLAG_ATTACHED) == 0,
643215516c77SSepherosa Ziehau 		    ("%dth TX ring is still attached", i));
643315516c77SSepherosa Ziehau 	}
643415516c77SSepherosa Ziehau #endif
643515516c77SSepherosa Ziehau }
643615516c77SSepherosa Ziehau 
643715516c77SSepherosa Ziehau static int
643815516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch)
643915516c77SSepherosa Ziehau {
644015516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
644115516c77SSepherosa Ziehau 	int nchan, rxr_cnt, error;
644215516c77SSepherosa Ziehau 
644315516c77SSepherosa Ziehau 	nchan = *nsubch + 1;
644415516c77SSepherosa Ziehau 	if (nchan == 1) {
644515516c77SSepherosa Ziehau 		/*
644615516c77SSepherosa Ziehau 		 * Multiple RX/TX rings are not requested.
644715516c77SSepherosa Ziehau 		 */
644815516c77SSepherosa Ziehau 		*nsubch = 0;
644915516c77SSepherosa Ziehau 		return (0);
645015516c77SSepherosa Ziehau 	}
645115516c77SSepherosa Ziehau 
645215516c77SSepherosa Ziehau 	/*
645315516c77SSepherosa Ziehau 	 * Query RSS capabilities, e.g. # of RX rings, and # of indirect
645415516c77SSepherosa Ziehau 	 * table entries.
645515516c77SSepherosa Ziehau 	 */
645615516c77SSepherosa Ziehau 	error = hn_rndis_query_rsscaps(sc, &rxr_cnt);
645715516c77SSepherosa Ziehau 	if (error) {
645815516c77SSepherosa Ziehau 		/* No RSS; this is benign. */
645915516c77SSepherosa Ziehau 		*nsubch = 0;
646015516c77SSepherosa Ziehau 		return (0);
646115516c77SSepherosa Ziehau 	}
646215516c77SSepherosa Ziehau 	if (bootverbose) {
646315516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
646415516c77SSepherosa Ziehau 		    rxr_cnt, nchan);
646515516c77SSepherosa Ziehau 	}
646615516c77SSepherosa Ziehau 
646715516c77SSepherosa Ziehau 	if (nchan > rxr_cnt)
646815516c77SSepherosa Ziehau 		nchan = rxr_cnt;
646915516c77SSepherosa Ziehau 	if (nchan == 1) {
647015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n");
647115516c77SSepherosa Ziehau 		*nsubch = 0;
647215516c77SSepherosa Ziehau 		return (0);
647315516c77SSepherosa Ziehau 	}
647415516c77SSepherosa Ziehau 
647515516c77SSepherosa Ziehau 	/*
647615516c77SSepherosa Ziehau 	 * Allocate sub-channels from NVS.
647715516c77SSepherosa Ziehau 	 */
647815516c77SSepherosa Ziehau 	*nsubch = nchan - 1;
647915516c77SSepherosa Ziehau 	error = hn_nvs_alloc_subchans(sc, nsubch);
648015516c77SSepherosa Ziehau 	if (error || *nsubch == 0) {
648115516c77SSepherosa Ziehau 		/* Failed to allocate sub-channels. */
648215516c77SSepherosa Ziehau 		*nsubch = 0;
648315516c77SSepherosa Ziehau 		return (0);
648415516c77SSepherosa Ziehau 	}
648515516c77SSepherosa Ziehau 
648615516c77SSepherosa Ziehau 	/*
648715516c77SSepherosa Ziehau 	 * Wait for all sub-channels to become ready before moving on.
648815516c77SSepherosa Ziehau 	 */
648915516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch);
649015516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, *nsubch);
649115516c77SSepherosa Ziehau 	return (0);
649215516c77SSepherosa Ziehau }
649315516c77SSepherosa Ziehau 
64942494d735SSepherosa Ziehau static bool
64952494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc)
64962494d735SSepherosa Ziehau {
64972494d735SSepherosa Ziehau 	int i;
64982494d735SSepherosa Ziehau 
64992494d735SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_ERRORS)
65002494d735SSepherosa Ziehau 		return (false);
65012494d735SSepherosa Ziehau 
65022494d735SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
65032494d735SSepherosa Ziehau 		const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
65042494d735SSepherosa Ziehau 
65052494d735SSepherosa Ziehau 		if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF)
65062494d735SSepherosa Ziehau 			return (false);
65072494d735SSepherosa Ziehau 	}
65082494d735SSepherosa Ziehau 	return (true);
65092494d735SSepherosa Ziehau }
65102494d735SSepherosa Ziehau 
6511b3b75d9cSSepherosa Ziehau /*
6512b3b75d9cSSepherosa Ziehau  * Make sure that the RX filter is zero after the successful
6513b3b75d9cSSepherosa Ziehau  * RNDIS initialization.
6514b3b75d9cSSepherosa Ziehau  *
6515b3b75d9cSSepherosa Ziehau  * NOTE:
6516b3b75d9cSSepherosa Ziehau  * Under certain conditions on certain versions of Hyper-V,
6517b3b75d9cSSepherosa Ziehau  * the RNDIS rxfilter is _not_ zero on the hypervisor side
6518b3b75d9cSSepherosa Ziehau  * after the successful RNDIS initialization, which breaks
6519b3b75d9cSSepherosa Ziehau  * the assumption of any following code (well, it breaks the
6520b3b75d9cSSepherosa Ziehau  * RNDIS API contract actually).  Clear the RNDIS rxfilter
6521b3b75d9cSSepherosa Ziehau  * explicitly, drain packets sneaking through, and drain the
6522b3b75d9cSSepherosa Ziehau  * interrupt taskqueues scheduled due to the stealth packets.
6523b3b75d9cSSepherosa Ziehau  */
6524b3b75d9cSSepherosa Ziehau static void
6525b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(struct hn_softc *sc, int nchan)
6526b3b75d9cSSepherosa Ziehau {
6527b3b75d9cSSepherosa Ziehau 
6528b3b75d9cSSepherosa Ziehau 	hn_disable_rx(sc);
6529b3b75d9cSSepherosa Ziehau 	hn_drain_rxtx(sc, nchan);
6530b3b75d9cSSepherosa Ziehau }
6531b3b75d9cSSepherosa Ziehau 
653215516c77SSepherosa Ziehau static int
653315516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu)
653415516c77SSepherosa Ziehau {
653571e8ac56SSepherosa Ziehau #define ATTACHED_NVS		0x0002
653671e8ac56SSepherosa Ziehau #define ATTACHED_RNDIS		0x0004
653771e8ac56SSepherosa Ziehau 
653815516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
6539b3b75d9cSSepherosa Ziehau 	int error, nsubch, nchan = 1, i, rndis_inited;
654071e8ac56SSepherosa Ziehau 	uint32_t old_caps, attached = 0;
654115516c77SSepherosa Ziehau 
654215516c77SSepherosa Ziehau 	KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0,
654315516c77SSepherosa Ziehau 	    ("synthetic parts were attached"));
654415516c77SSepherosa Ziehau 
65452494d735SSepherosa Ziehau 	if (!hn_synth_attachable(sc))
65462494d735SSepherosa Ziehau 		return (ENXIO);
65472494d735SSepherosa Ziehau 
654815516c77SSepherosa Ziehau 	/* Save capabilities for later verification. */
654915516c77SSepherosa Ziehau 	old_caps = sc->hn_caps;
655015516c77SSepherosa Ziehau 	sc->hn_caps = 0;
655115516c77SSepherosa Ziehau 
655215516c77SSepherosa Ziehau 	/* Clear RSS stuffs. */
655315516c77SSepherosa Ziehau 	sc->hn_rss_ind_size = 0;
655415516c77SSepherosa Ziehau 	sc->hn_rss_hash = 0;
6555642ec226SSepherosa Ziehau 	sc->hn_rss_hcap = 0;
655615516c77SSepherosa Ziehau 
655715516c77SSepherosa Ziehau 	/*
655815516c77SSepherosa Ziehau 	 * Attach the primary channel _before_ attaching NVS and RNDIS.
655915516c77SSepherosa Ziehau 	 */
656015516c77SSepherosa Ziehau 	error = hn_chan_attach(sc, sc->hn_prichan);
656115516c77SSepherosa Ziehau 	if (error)
656271e8ac56SSepherosa Ziehau 		goto failed;
656315516c77SSepherosa Ziehau 
656415516c77SSepherosa Ziehau 	/*
656515516c77SSepherosa Ziehau 	 * Attach NVS.
656615516c77SSepherosa Ziehau 	 */
656715516c77SSepherosa Ziehau 	error = hn_nvs_attach(sc, mtu);
656815516c77SSepherosa Ziehau 	if (error)
656971e8ac56SSepherosa Ziehau 		goto failed;
657071e8ac56SSepherosa Ziehau 	attached |= ATTACHED_NVS;
657115516c77SSepherosa Ziehau 
657215516c77SSepherosa Ziehau 	/*
657315516c77SSepherosa Ziehau 	 * Attach RNDIS _after_ NVS is attached.
657415516c77SSepherosa Ziehau 	 */
6575b3b75d9cSSepherosa Ziehau 	error = hn_rndis_attach(sc, mtu, &rndis_inited);
6576b3b75d9cSSepherosa Ziehau 	if (rndis_inited)
6577b3b75d9cSSepherosa Ziehau 		attached |= ATTACHED_RNDIS;
657815516c77SSepherosa Ziehau 	if (error)
657971e8ac56SSepherosa Ziehau 		goto failed;
658015516c77SSepherosa Ziehau 
658115516c77SSepherosa Ziehau 	/*
658215516c77SSepherosa Ziehau 	 * Make sure capabilities are not changed.
658315516c77SSepherosa Ziehau 	 */
658415516c77SSepherosa Ziehau 	if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) {
658515516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n",
658615516c77SSepherosa Ziehau 		    old_caps, sc->hn_caps);
658771e8ac56SSepherosa Ziehau 		error = ENXIO;
658871e8ac56SSepherosa Ziehau 		goto failed;
658915516c77SSepherosa Ziehau 	}
659015516c77SSepherosa Ziehau 
659115516c77SSepherosa Ziehau 	/*
659215516c77SSepherosa Ziehau 	 * Allocate sub-channels for multi-TX/RX rings.
659315516c77SSepherosa Ziehau 	 *
659415516c77SSepherosa Ziehau 	 * NOTE:
659515516c77SSepherosa Ziehau 	 * The # of RX rings that can be used is equivalent to the # of
659615516c77SSepherosa Ziehau 	 * channels to be requested.
659715516c77SSepherosa Ziehau 	 */
659815516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_cnt - 1;
659915516c77SSepherosa Ziehau 	error = hn_synth_alloc_subchans(sc, &nsubch);
660015516c77SSepherosa Ziehau 	if (error)
660171e8ac56SSepherosa Ziehau 		goto failed;
660271e8ac56SSepherosa Ziehau 	/* NOTE: _Full_ synthetic parts detach is required now. */
660371e8ac56SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED;
660415516c77SSepherosa Ziehau 
660571e8ac56SSepherosa Ziehau 	/*
660671e8ac56SSepherosa Ziehau 	 * Set the # of TX/RX rings that could be used according to
660771e8ac56SSepherosa Ziehau 	 * the # of channels that NVS offered.
660871e8ac56SSepherosa Ziehau 	 */
660915516c77SSepherosa Ziehau 	nchan = nsubch + 1;
661071e8ac56SSepherosa Ziehau 	hn_set_ring_inuse(sc, nchan);
661115516c77SSepherosa Ziehau 	if (nchan == 1) {
661215516c77SSepherosa Ziehau 		/* Only the primary channel can be used; done */
661315516c77SSepherosa Ziehau 		goto back;
661415516c77SSepherosa Ziehau 	}
661515516c77SSepherosa Ziehau 
661615516c77SSepherosa Ziehau 	/*
661771e8ac56SSepherosa Ziehau 	 * Attach the sub-channels.
6618afd4971bSSepherosa Ziehau 	 *
6619afd4971bSSepherosa Ziehau 	 * NOTE: hn_set_ring_inuse() _must_ have been called.
662015516c77SSepherosa Ziehau 	 */
662171e8ac56SSepherosa Ziehau 	error = hn_attach_subchans(sc);
662271e8ac56SSepherosa Ziehau 	if (error)
662371e8ac56SSepherosa Ziehau 		goto failed;
662415516c77SSepherosa Ziehau 
662571e8ac56SSepherosa Ziehau 	/*
662671e8ac56SSepherosa Ziehau 	 * Configure RSS key and indirect table _after_ all sub-channels
662771e8ac56SSepherosa Ziehau 	 * are attached.
662871e8ac56SSepherosa Ziehau 	 */
662915516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) {
663015516c77SSepherosa Ziehau 		/*
663115516c77SSepherosa Ziehau 		 * RSS key is not set yet; set it to the default RSS key.
663215516c77SSepherosa Ziehau 		 */
663315516c77SSepherosa Ziehau 		if (bootverbose)
663415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS key\n");
663534d68912SSepherosa Ziehau #ifdef RSS
663634d68912SSepherosa Ziehau 		rss_getkey(rss->rss_key);
663734d68912SSepherosa Ziehau #else
663815516c77SSepherosa Ziehau 		memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key));
663934d68912SSepherosa Ziehau #endif
664015516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
664115516c77SSepherosa Ziehau 	}
664215516c77SSepherosa Ziehau 
664315516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) {
664415516c77SSepherosa Ziehau 		/*
664515516c77SSepherosa Ziehau 		 * RSS indirect table is not set yet; set it up in round-
664615516c77SSepherosa Ziehau 		 * robin fashion.
664715516c77SSepherosa Ziehau 		 */
664815516c77SSepherosa Ziehau 		if (bootverbose) {
664915516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS indirect "
665015516c77SSepherosa Ziehau 			    "table\n");
665115516c77SSepherosa Ziehau 		}
665234d68912SSepherosa Ziehau 		for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
665334d68912SSepherosa Ziehau 			uint32_t subidx;
665434d68912SSepherosa Ziehau 
665534d68912SSepherosa Ziehau #ifdef RSS
665634d68912SSepherosa Ziehau 			subidx = rss_get_indirection_to_bucket(i);
665734d68912SSepherosa Ziehau #else
665834d68912SSepherosa Ziehau 			subidx = i;
665934d68912SSepherosa Ziehau #endif
666034d68912SSepherosa Ziehau 			rss->rss_ind[i] = subidx % nchan;
666134d68912SSepherosa Ziehau 		}
666215516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSIND;
666315516c77SSepherosa Ziehau 	} else {
666415516c77SSepherosa Ziehau 		/*
666515516c77SSepherosa Ziehau 		 * # of usable channels may be changed, so we have to
666615516c77SSepherosa Ziehau 		 * make sure that all entries in RSS indirect table
666715516c77SSepherosa Ziehau 		 * are valid.
6668afd4971bSSepherosa Ziehau 		 *
6669afd4971bSSepherosa Ziehau 		 * NOTE: hn_set_ring_inuse() _must_ have been called.
667015516c77SSepherosa Ziehau 		 */
6671afd4971bSSepherosa Ziehau 		hn_rss_ind_fixup(sc);
667215516c77SSepherosa Ziehau 	}
667315516c77SSepherosa Ziehau 
6674642ec226SSepherosa Ziehau 	sc->hn_rss_hash = sc->hn_rss_hcap;
6675642ec226SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) ||
6676642ec226SSepherosa Ziehau 	    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
6677642ec226SSepherosa Ziehau 		/* NOTE: Don't reconfigure RSS; will do immediately. */
6678642ec226SSepherosa Ziehau 		hn_vf_rss_fixup(sc, false);
6679642ec226SSepherosa Ziehau 	}
668015516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
668115516c77SSepherosa Ziehau 	if (error)
668271e8ac56SSepherosa Ziehau 		goto failed;
668371e8ac56SSepherosa Ziehau back:
6684dc13fee6SSepherosa Ziehau 	/*
6685dc13fee6SSepherosa Ziehau 	 * Fixup transmission aggregation setup.
6686dc13fee6SSepherosa Ziehau 	 */
6687dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
6688b3b75d9cSSepherosa Ziehau 	hn_rndis_init_fixat(sc, nchan);
668915516c77SSepherosa Ziehau 	return (0);
669071e8ac56SSepherosa Ziehau 
669171e8ac56SSepherosa Ziehau failed:
669271e8ac56SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
6693b3b75d9cSSepherosa Ziehau 		hn_rndis_init_fixat(sc, nchan);
669471e8ac56SSepherosa Ziehau 		hn_synth_detach(sc);
669571e8ac56SSepherosa Ziehau 	} else {
6696b3b75d9cSSepherosa Ziehau 		if (attached & ATTACHED_RNDIS) {
6697b3b75d9cSSepherosa Ziehau 			hn_rndis_init_fixat(sc, nchan);
669871e8ac56SSepherosa Ziehau 			hn_rndis_detach(sc);
6699b3b75d9cSSepherosa Ziehau 		}
670071e8ac56SSepherosa Ziehau 		if (attached & ATTACHED_NVS)
670171e8ac56SSepherosa Ziehau 			hn_nvs_detach(sc);
670271e8ac56SSepherosa Ziehau 		hn_chan_detach(sc, sc->hn_prichan);
670371e8ac56SSepherosa Ziehau 		/* Restore old capabilities. */
670471e8ac56SSepherosa Ziehau 		sc->hn_caps = old_caps;
670571e8ac56SSepherosa Ziehau 	}
670671e8ac56SSepherosa Ziehau 	return (error);
670771e8ac56SSepherosa Ziehau 
670871e8ac56SSepherosa Ziehau #undef ATTACHED_RNDIS
670971e8ac56SSepherosa Ziehau #undef ATTACHED_NVS
671015516c77SSepherosa Ziehau }
671115516c77SSepherosa Ziehau 
671215516c77SSepherosa Ziehau /*
671315516c77SSepherosa Ziehau  * NOTE:
671415516c77SSepherosa Ziehau  * The interface must have been suspended though hn_suspend(), before
671515516c77SSepherosa Ziehau  * this function get called.
671615516c77SSepherosa Ziehau  */
671715516c77SSepherosa Ziehau static void
671815516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc)
671915516c77SSepherosa Ziehau {
672015516c77SSepherosa Ziehau 
672115516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
672215516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
672315516c77SSepherosa Ziehau 
672415516c77SSepherosa Ziehau 	/* Detach the RNDIS first. */
672515516c77SSepherosa Ziehau 	hn_rndis_detach(sc);
672615516c77SSepherosa Ziehau 
672715516c77SSepherosa Ziehau 	/* Detach NVS. */
672815516c77SSepherosa Ziehau 	hn_nvs_detach(sc);
672915516c77SSepherosa Ziehau 
673015516c77SSepherosa Ziehau 	/* Detach all of the channels. */
673115516c77SSepherosa Ziehau 	hn_detach_allchans(sc);
673215516c77SSepherosa Ziehau 
6733ace5ce7eSWei Hu 	if (vmbus_current_version >= VMBUS_VERSION_WIN10 && sc->hn_rxbuf_gpadl != 0) {
6734ace5ce7eSWei Hu 		/*
6735ace5ce7eSWei Hu 		 * Host is post-Win2016, disconnect RXBUF from primary channel here.
6736ace5ce7eSWei Hu 		 */
6737ace5ce7eSWei Hu 		int error;
6738ace5ce7eSWei Hu 
6739ace5ce7eSWei Hu 		error = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
6740ace5ce7eSWei Hu 		    sc->hn_rxbuf_gpadl);
6741ace5ce7eSWei Hu 		if (error) {
6742ace5ce7eSWei Hu 			if_printf(sc->hn_ifp,
6743ace5ce7eSWei Hu 			    "rxbuf gpadl disconn failed: %d\n", error);
6744ace5ce7eSWei Hu 			sc->hn_flags |= HN_FLAG_RXBUF_REF;
6745ace5ce7eSWei Hu 		}
6746ace5ce7eSWei Hu 		sc->hn_rxbuf_gpadl = 0;
6747ace5ce7eSWei Hu 	}
6748ace5ce7eSWei Hu 
6749ace5ce7eSWei Hu 	if (vmbus_current_version >= VMBUS_VERSION_WIN10 && sc->hn_chim_gpadl != 0) {
6750ace5ce7eSWei Hu 		/*
6751ace5ce7eSWei Hu 		 * Host is post-Win2016, disconnect chimney sending buffer from
6752ace5ce7eSWei Hu 		 * primary channel here.
6753ace5ce7eSWei Hu 		 */
6754ace5ce7eSWei Hu 		int error;
6755ace5ce7eSWei Hu 
6756ace5ce7eSWei Hu 		error = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
6757ace5ce7eSWei Hu 		    sc->hn_chim_gpadl);
6758ace5ce7eSWei Hu 		if (error) {
6759ace5ce7eSWei Hu 			if_printf(sc->hn_ifp,
6760ace5ce7eSWei Hu 			    "chim gpadl disconn failed: %d\n", error);
6761ace5ce7eSWei Hu 			sc->hn_flags |= HN_FLAG_CHIM_REF;
6762ace5ce7eSWei Hu 		}
6763ace5ce7eSWei Hu 		sc->hn_chim_gpadl = 0;
6764ace5ce7eSWei Hu 	}
676515516c77SSepherosa Ziehau 	sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED;
676615516c77SSepherosa Ziehau }
676715516c77SSepherosa Ziehau 
676815516c77SSepherosa Ziehau static void
676915516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt)
677015516c77SSepherosa Ziehau {
677115516c77SSepherosa Ziehau 	KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt,
677215516c77SSepherosa Ziehau 	    ("invalid ring count %d", ring_cnt));
677315516c77SSepherosa Ziehau 
677415516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt > ring_cnt)
677515516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = ring_cnt;
677615516c77SSepherosa Ziehau 	else
677715516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
677815516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = ring_cnt;
677915516c77SSepherosa Ziehau 
678034d68912SSepherosa Ziehau #ifdef RSS
678134d68912SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse != rss_getnumbuckets()) {
678234d68912SSepherosa Ziehau 		if_printf(sc->hn_ifp, "# of RX rings (%d) does not match "
678334d68912SSepherosa Ziehau 		    "# of RSS buckets (%d)\n", sc->hn_rx_ring_inuse,
678434d68912SSepherosa Ziehau 		    rss_getnumbuckets());
678534d68912SSepherosa Ziehau 	}
678634d68912SSepherosa Ziehau #endif
678734d68912SSepherosa Ziehau 
678815516c77SSepherosa Ziehau 	if (bootverbose) {
678915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n",
679015516c77SSepherosa Ziehau 		    sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
679115516c77SSepherosa Ziehau 	}
679215516c77SSepherosa Ziehau }
679315516c77SSepherosa Ziehau 
679415516c77SSepherosa Ziehau static void
679525641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan)
679615516c77SSepherosa Ziehau {
679715516c77SSepherosa Ziehau 
679825641fc7SSepherosa Ziehau 	/*
679925641fc7SSepherosa Ziehau 	 * NOTE:
680025641fc7SSepherosa Ziehau 	 * The TX bufring will not be drained by the hypervisor,
680125641fc7SSepherosa Ziehau 	 * if the primary channel is revoked.
680225641fc7SSepherosa Ziehau 	 */
680325641fc7SSepherosa Ziehau 	while (!vmbus_chan_rx_empty(chan) ||
680425641fc7SSepherosa Ziehau 	    (!vmbus_chan_is_revoked(sc->hn_prichan) &&
680525641fc7SSepherosa Ziehau 	     !vmbus_chan_tx_empty(chan)))
680615516c77SSepherosa Ziehau 		pause("waitch", 1);
680715516c77SSepherosa Ziehau 	vmbus_chan_intr_drain(chan);
680815516c77SSepherosa Ziehau }
680915516c77SSepherosa Ziehau 
681015516c77SSepherosa Ziehau static void
6811b3b75d9cSSepherosa Ziehau hn_disable_rx(struct hn_softc *sc)
6812b3b75d9cSSepherosa Ziehau {
6813b3b75d9cSSepherosa Ziehau 
6814b3b75d9cSSepherosa Ziehau 	/*
6815b3b75d9cSSepherosa Ziehau 	 * Disable RX by clearing RX filter forcefully.
6816b3b75d9cSSepherosa Ziehau 	 */
6817b3b75d9cSSepherosa Ziehau 	sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE;
6818b3b75d9cSSepherosa Ziehau 	hn_rndis_set_rxfilter(sc, sc->hn_rx_filter); /* ignore error */
6819b3b75d9cSSepherosa Ziehau 
6820b3b75d9cSSepherosa Ziehau 	/*
6821b3b75d9cSSepherosa Ziehau 	 * Give RNDIS enough time to flush all pending data packets.
6822b3b75d9cSSepherosa Ziehau 	 */
6823b3b75d9cSSepherosa Ziehau 	pause("waitrx", (200 * hz) / 1000);
6824b3b75d9cSSepherosa Ziehau }
6825b3b75d9cSSepherosa Ziehau 
6826b3b75d9cSSepherosa Ziehau /*
6827b3b75d9cSSepherosa Ziehau  * NOTE:
6828b3b75d9cSSepherosa Ziehau  * RX/TX _must_ have been suspended/disabled, before this function
6829b3b75d9cSSepherosa Ziehau  * is called.
6830b3b75d9cSSepherosa Ziehau  */
6831b3b75d9cSSepherosa Ziehau static void
6832b3b75d9cSSepherosa Ziehau hn_drain_rxtx(struct hn_softc *sc, int nchan)
683315516c77SSepherosa Ziehau {
683415516c77SSepherosa Ziehau 	struct vmbus_channel **subch = NULL;
6835b3b75d9cSSepherosa Ziehau 	int nsubch;
6836b3b75d9cSSepherosa Ziehau 
6837b3b75d9cSSepherosa Ziehau 	/*
6838b3b75d9cSSepherosa Ziehau 	 * Drain RX/TX bufrings and interrupts.
6839b3b75d9cSSepherosa Ziehau 	 */
6840b3b75d9cSSepherosa Ziehau 	nsubch = nchan - 1;
6841b3b75d9cSSepherosa Ziehau 	if (nsubch > 0)
6842b3b75d9cSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
6843b3b75d9cSSepherosa Ziehau 
6844b3b75d9cSSepherosa Ziehau 	if (subch != NULL) {
6845b3b75d9cSSepherosa Ziehau 		int i;
6846b3b75d9cSSepherosa Ziehau 
6847b3b75d9cSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
6848b3b75d9cSSepherosa Ziehau 			hn_chan_drain(sc, subch[i]);
6849b3b75d9cSSepherosa Ziehau 	}
6850b3b75d9cSSepherosa Ziehau 	hn_chan_drain(sc, sc->hn_prichan);
6851b3b75d9cSSepherosa Ziehau 
6852b3b75d9cSSepherosa Ziehau 	if (subch != NULL)
6853b3b75d9cSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
6854b3b75d9cSSepherosa Ziehau }
6855b3b75d9cSSepherosa Ziehau 
6856b3b75d9cSSepherosa Ziehau static void
6857b3b75d9cSSepherosa Ziehau hn_suspend_data(struct hn_softc *sc)
6858b3b75d9cSSepherosa Ziehau {
685925641fc7SSepherosa Ziehau 	struct hn_tx_ring *txr;
6860b3b75d9cSSepherosa Ziehau 	int i;
686115516c77SSepherosa Ziehau 
686215516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
686315516c77SSepherosa Ziehau 
686415516c77SSepherosa Ziehau 	/*
686515516c77SSepherosa Ziehau 	 * Suspend TX.
686615516c77SSepherosa Ziehau 	 */
686715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
686825641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
686915516c77SSepherosa Ziehau 
687015516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
687115516c77SSepherosa Ziehau 		txr->hn_suspended = 1;
687215516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
687315516c77SSepherosa Ziehau 		/* No one is able send more packets now. */
687415516c77SSepherosa Ziehau 
687525641fc7SSepherosa Ziehau 		/*
687625641fc7SSepherosa Ziehau 		 * Wait for all pending sends to finish.
687725641fc7SSepherosa Ziehau 		 *
687825641fc7SSepherosa Ziehau 		 * NOTE:
687925641fc7SSepherosa Ziehau 		 * We will _not_ receive all pending send-done, if the
688025641fc7SSepherosa Ziehau 		 * primary channel is revoked.
688125641fc7SSepherosa Ziehau 		 */
688225641fc7SSepherosa Ziehau 		while (hn_tx_ring_pending(txr) &&
688325641fc7SSepherosa Ziehau 		    !vmbus_chan_is_revoked(sc->hn_prichan))
688415516c77SSepherosa Ziehau 			pause("hnwtx", 1 /* 1 tick */);
688515516c77SSepherosa Ziehau 	}
688615516c77SSepherosa Ziehau 
688715516c77SSepherosa Ziehau 	/*
6888b3b75d9cSSepherosa Ziehau 	 * Disable RX.
688915516c77SSepherosa Ziehau 	 */
6890b3b75d9cSSepherosa Ziehau 	hn_disable_rx(sc);
689115516c77SSepherosa Ziehau 
689215516c77SSepherosa Ziehau 	/*
6893b3b75d9cSSepherosa Ziehau 	 * Drain RX/TX.
689415516c77SSepherosa Ziehau 	 */
6895b3b75d9cSSepherosa Ziehau 	hn_drain_rxtx(sc, sc->hn_rx_ring_inuse);
689625641fc7SSepherosa Ziehau 
689725641fc7SSepherosa Ziehau 	/*
689825641fc7SSepherosa Ziehau 	 * Drain any pending TX tasks.
689925641fc7SSepherosa Ziehau 	 *
690025641fc7SSepherosa Ziehau 	 * NOTE:
6901b3b75d9cSSepherosa Ziehau 	 * The above hn_drain_rxtx() can dispatch TX tasks, so the TX
6902b3b75d9cSSepherosa Ziehau 	 * tasks will have to be drained _after_ the above hn_drain_rxtx().
690325641fc7SSepherosa Ziehau 	 */
690425641fc7SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
690525641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
690625641fc7SSepherosa Ziehau 
690725641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task);
690825641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task);
690925641fc7SSepherosa Ziehau 	}
691015516c77SSepherosa Ziehau }
691115516c77SSepherosa Ziehau 
691215516c77SSepherosa Ziehau static void
691315516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused)
691415516c77SSepherosa Ziehau {
691515516c77SSepherosa Ziehau 
691615516c77SSepherosa Ziehau 	((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL;
691715516c77SSepherosa Ziehau }
691815516c77SSepherosa Ziehau 
691915516c77SSepherosa Ziehau static void
692015516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc)
692115516c77SSepherosa Ziehau {
692215516c77SSepherosa Ziehau 	struct task task;
692315516c77SSepherosa Ziehau 
692415516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
692515516c77SSepherosa Ziehau 
692615516c77SSepherosa Ziehau 	/*
692715516c77SSepherosa Ziehau 	 * Make sure that hn_mgmt_taskq0 can nolonger be accessed
692815516c77SSepherosa Ziehau 	 * through hn_mgmt_taskq.
692915516c77SSepherosa Ziehau 	 */
693015516c77SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc);
693115516c77SSepherosa Ziehau 	vmbus_chan_run_task(sc->hn_prichan, &task);
693215516c77SSepherosa Ziehau 
693315516c77SSepherosa Ziehau 	/*
693415516c77SSepherosa Ziehau 	 * Make sure that all pending management tasks are completed.
693515516c77SSepherosa Ziehau 	 */
693615516c77SSepherosa Ziehau 	taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init);
693715516c77SSepherosa Ziehau 	taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status);
693815516c77SSepherosa Ziehau 	taskqueue_drain_all(sc->hn_mgmt_taskq0);
693915516c77SSepherosa Ziehau }
694015516c77SSepherosa Ziehau 
694115516c77SSepherosa Ziehau static void
694215516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc)
694315516c77SSepherosa Ziehau {
694415516c77SSepherosa Ziehau 
694587f8129dSSepherosa Ziehau 	/* Disable polling. */
694687f8129dSSepherosa Ziehau 	hn_polling(sc, 0);
694787f8129dSSepherosa Ziehau 
69489c6cae24SSepherosa Ziehau 	/*
69499c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, the synthetic
69509c6cae24SSepherosa Ziehau 	 * device is receiving packets, so the data path of the
69519c6cae24SSepherosa Ziehau 	 * synthetic device must be suspended.
69529c6cae24SSepherosa Ziehau 	 */
69535bdfd3fdSDexuan Cui 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
6954962f0357SSepherosa Ziehau 	    (sc->hn_flags & HN_FLAG_RXVF))
695515516c77SSepherosa Ziehau 		hn_suspend_data(sc);
695615516c77SSepherosa Ziehau 	hn_suspend_mgmt(sc);
695715516c77SSepherosa Ziehau }
695815516c77SSepherosa Ziehau 
695915516c77SSepherosa Ziehau static void
696015516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt)
696115516c77SSepherosa Ziehau {
696215516c77SSepherosa Ziehau 	int i;
696315516c77SSepherosa Ziehau 
696415516c77SSepherosa Ziehau 	KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt,
696515516c77SSepherosa Ziehau 	    ("invalid TX ring count %d", tx_ring_cnt));
696615516c77SSepherosa Ziehau 
696715516c77SSepherosa Ziehau 	for (i = 0; i < tx_ring_cnt; ++i) {
696815516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
696915516c77SSepherosa Ziehau 
697015516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
697115516c77SSepherosa Ziehau 		txr->hn_suspended = 0;
697215516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
697315516c77SSepherosa Ziehau 	}
697415516c77SSepherosa Ziehau }
697515516c77SSepherosa Ziehau 
697615516c77SSepherosa Ziehau static void
697715516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc)
697815516c77SSepherosa Ziehau {
697915516c77SSepherosa Ziehau 	int i;
698015516c77SSepherosa Ziehau 
698115516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
698215516c77SSepherosa Ziehau 
698315516c77SSepherosa Ziehau 	/*
698415516c77SSepherosa Ziehau 	 * Re-enable RX.
698515516c77SSepherosa Ziehau 	 */
6986c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
698715516c77SSepherosa Ziehau 
698815516c77SSepherosa Ziehau 	/*
698915516c77SSepherosa Ziehau 	 * Make sure to clear suspend status on "all" TX rings,
699015516c77SSepherosa Ziehau 	 * since hn_tx_ring_inuse can be changed after
699115516c77SSepherosa Ziehau 	 * hn_suspend_data().
699215516c77SSepherosa Ziehau 	 */
699315516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_cnt);
699415516c77SSepherosa Ziehau 
699523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
699623bf9e15SSepherosa Ziehau 	if (!hn_use_if_start)
699723bf9e15SSepherosa Ziehau #endif
699823bf9e15SSepherosa Ziehau 	{
699915516c77SSepherosa Ziehau 		/*
700015516c77SSepherosa Ziehau 		 * Flush unused drbrs, since hn_tx_ring_inuse may be
700115516c77SSepherosa Ziehau 		 * reduced.
700215516c77SSepherosa Ziehau 		 */
700315516c77SSepherosa Ziehau 		for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i)
700415516c77SSepherosa Ziehau 			hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
700515516c77SSepherosa Ziehau 	}
700615516c77SSepherosa Ziehau 
700715516c77SSepherosa Ziehau 	/*
700815516c77SSepherosa Ziehau 	 * Kick start TX.
700915516c77SSepherosa Ziehau 	 */
701015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
701115516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
701215516c77SSepherosa Ziehau 
701315516c77SSepherosa Ziehau 		/*
701415516c77SSepherosa Ziehau 		 * Use txeof task, so that any pending oactive can be
701515516c77SSepherosa Ziehau 		 * cleared properly.
701615516c77SSepherosa Ziehau 		 */
701715516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
701815516c77SSepherosa Ziehau 	}
701915516c77SSepherosa Ziehau }
702015516c77SSepherosa Ziehau 
702115516c77SSepherosa Ziehau static void
702215516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc)
702315516c77SSepherosa Ziehau {
702415516c77SSepherosa Ziehau 
702515516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
702615516c77SSepherosa Ziehau 
702715516c77SSepherosa Ziehau 	/*
702815516c77SSepherosa Ziehau 	 * Kick off network change detection, if it was pending.
702915516c77SSepherosa Ziehau 	 * If no network change was pending, start link status
703015516c77SSepherosa Ziehau 	 * checks, which is more lightweight than network change
703115516c77SSepherosa Ziehau 	 * detection.
703215516c77SSepherosa Ziehau 	 */
703315516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
703415516c77SSepherosa Ziehau 		hn_change_network(sc);
703515516c77SSepherosa Ziehau 	else
703615516c77SSepherosa Ziehau 		hn_update_link_status(sc);
703715516c77SSepherosa Ziehau }
703815516c77SSepherosa Ziehau 
703915516c77SSepherosa Ziehau static void
704015516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc)
704115516c77SSepherosa Ziehau {
704215516c77SSepherosa Ziehau 
70439c6cae24SSepherosa Ziehau 	/*
70449c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, the synthetic
70459c6cae24SSepherosa Ziehau 	 * device have to receive packets, so the data path of the
70469c6cae24SSepherosa Ziehau 	 * synthetic device must be resumed.
70479c6cae24SSepherosa Ziehau 	 */
70485bdfd3fdSDexuan Cui 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
7049962f0357SSepherosa Ziehau 	    (sc->hn_flags & HN_FLAG_RXVF))
705015516c77SSepherosa Ziehau 		hn_resume_data(sc);
70515bdfd3fdSDexuan Cui 
70525bdfd3fdSDexuan Cui 	/*
70539c6cae24SSepherosa Ziehau 	 * Don't resume link status change if VF is attached/activated.
70549c6cae24SSepherosa Ziehau 	 * - In the non-transparent VF mode, the synthetic device marks
70559c6cae24SSepherosa Ziehau 	 *   link down until the VF is deactivated; i.e. VF is down.
70569c6cae24SSepherosa Ziehau 	 * - In transparent VF mode, VF's media status is used until
70579c6cae24SSepherosa Ziehau 	 *   the VF is detached.
70585bdfd3fdSDexuan Cui 	 */
70599c6cae24SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) == 0 &&
70609c6cae24SSepherosa Ziehau 	    !(hn_xpnt_vf && sc->hn_vf_ifp != NULL))
706115516c77SSepherosa Ziehau 		hn_resume_mgmt(sc);
706287f8129dSSepherosa Ziehau 
706387f8129dSSepherosa Ziehau 	/*
706487f8129dSSepherosa Ziehau 	 * Re-enable polling if this interface is running and
706587f8129dSSepherosa Ziehau 	 * the polling is requested.
706687f8129dSSepherosa Ziehau 	 */
706787f8129dSSepherosa Ziehau 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->hn_pollhz > 0)
706887f8129dSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
706915516c77SSepherosa Ziehau }
707015516c77SSepherosa Ziehau 
707115516c77SSepherosa Ziehau static void
707215516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen)
707315516c77SSepherosa Ziehau {
707415516c77SSepherosa Ziehau 	const struct rndis_status_msg *msg;
707515516c77SSepherosa Ziehau 	int ofs;
707615516c77SSepherosa Ziehau 
707715516c77SSepherosa Ziehau 	if (dlen < sizeof(*msg)) {
707815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid RNDIS status\n");
707915516c77SSepherosa Ziehau 		return;
708015516c77SSepherosa Ziehau 	}
708115516c77SSepherosa Ziehau 	msg = data;
708215516c77SSepherosa Ziehau 
708315516c77SSepherosa Ziehau 	switch (msg->rm_status) {
708415516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_CONNECT:
708515516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_DISCONNECT:
708615516c77SSepherosa Ziehau 		hn_update_link_status(sc);
708715516c77SSepherosa Ziehau 		break;
708815516c77SSepherosa Ziehau 
708915516c77SSepherosa Ziehau 	case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
709040905afaSSepherosa Ziehau 	case RNDIS_STATUS_LINK_SPEED_CHANGE:
709115516c77SSepherosa Ziehau 		/* Not really useful; ignore. */
709215516c77SSepherosa Ziehau 		break;
709315516c77SSepherosa Ziehau 
709415516c77SSepherosa Ziehau 	case RNDIS_STATUS_NETWORK_CHANGE:
709515516c77SSepherosa Ziehau 		ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
709615516c77SSepherosa Ziehau 		if (dlen < ofs + msg->rm_stbuflen ||
709715516c77SSepherosa Ziehau 		    msg->rm_stbuflen < sizeof(uint32_t)) {
709815516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed\n");
709915516c77SSepherosa Ziehau 		} else {
710015516c77SSepherosa Ziehau 			uint32_t change;
710115516c77SSepherosa Ziehau 
710215516c77SSepherosa Ziehau 			memcpy(&change, ((const uint8_t *)msg) + ofs,
710315516c77SSepherosa Ziehau 			    sizeof(change));
710415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed, change %u\n",
710515516c77SSepherosa Ziehau 			    change);
710615516c77SSepherosa Ziehau 		}
710715516c77SSepherosa Ziehau 		hn_change_network(sc);
710815516c77SSepherosa Ziehau 		break;
710915516c77SSepherosa Ziehau 
711015516c77SSepherosa Ziehau 	default:
711115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
711215516c77SSepherosa Ziehau 		    msg->rm_status);
711315516c77SSepherosa Ziehau 		break;
711415516c77SSepherosa Ziehau 	}
711515516c77SSepherosa Ziehau }
711615516c77SSepherosa Ziehau 
711715516c77SSepherosa Ziehau static int
711815516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info)
711915516c77SSepherosa Ziehau {
712015516c77SSepherosa Ziehau 	const struct rndis_pktinfo *pi = info_data;
712115516c77SSepherosa Ziehau 	uint32_t mask = 0;
712215516c77SSepherosa Ziehau 
712315516c77SSepherosa Ziehau 	while (info_dlen != 0) {
712415516c77SSepherosa Ziehau 		const void *data;
712515516c77SSepherosa Ziehau 		uint32_t dlen;
712615516c77SSepherosa Ziehau 
712715516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < sizeof(*pi)))
712815516c77SSepherosa Ziehau 			return (EINVAL);
712915516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < pi->rm_size))
713015516c77SSepherosa Ziehau 			return (EINVAL);
713115516c77SSepherosa Ziehau 		info_dlen -= pi->rm_size;
713215516c77SSepherosa Ziehau 
713315516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
713415516c77SSepherosa Ziehau 			return (EINVAL);
713515516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
713615516c77SSepherosa Ziehau 			return (EINVAL);
713715516c77SSepherosa Ziehau 		dlen = pi->rm_size - pi->rm_pktinfooffset;
713815516c77SSepherosa Ziehau 		data = pi->rm_data;
713915516c77SSepherosa Ziehau 
7140a491581fSWei Hu 		if (pi->rm_internal == 1) {
7141a491581fSWei Hu 			switch (pi->rm_type) {
7142a491581fSWei Hu 			case NDIS_PKTINFO_IT_PKTINFO_ID:
7143a491581fSWei Hu 				if (__predict_false(dlen < NDIS_PKTINFOID_SZ))
7144a491581fSWei Hu 					return (EINVAL);
7145a491581fSWei Hu 				info->pktinfo_id =
7146a491581fSWei Hu 				    (const struct packet_info_id *)data;
7147a491581fSWei Hu 				mask |= HN_RXINFO_PKTINFO_ID;
7148a491581fSWei Hu 				break;
7149a491581fSWei Hu 
7150a491581fSWei Hu 			default:
7151a491581fSWei Hu 				goto next;
7152a491581fSWei Hu 			}
7153a491581fSWei Hu 		} else {
715415516c77SSepherosa Ziehau 			switch (pi->rm_type) {
715515516c77SSepherosa Ziehau 			case NDIS_PKTINFO_TYPE_VLAN:
7156a491581fSWei Hu 				if (__predict_false(dlen
7157a491581fSWei Hu 				    < NDIS_VLAN_INFO_SIZE))
715815516c77SSepherosa Ziehau 					return (EINVAL);
7159a491581fSWei Hu 				info->vlan_info = (const uint32_t *)data;
716015516c77SSepherosa Ziehau 				mask |= HN_RXINFO_VLAN;
716115516c77SSepherosa Ziehau 				break;
716215516c77SSepherosa Ziehau 
716315516c77SSepherosa Ziehau 			case NDIS_PKTINFO_TYPE_CSUM:
7164a491581fSWei Hu 				if (__predict_false(dlen
7165a491581fSWei Hu 				    < NDIS_RXCSUM_INFO_SIZE))
716615516c77SSepherosa Ziehau 					return (EINVAL);
7167a491581fSWei Hu 				info->csum_info = (const uint32_t *)data;
716815516c77SSepherosa Ziehau 				mask |= HN_RXINFO_CSUM;
716915516c77SSepherosa Ziehau 				break;
717015516c77SSepherosa Ziehau 
717115516c77SSepherosa Ziehau 			case HN_NDIS_PKTINFO_TYPE_HASHVAL:
7172a491581fSWei Hu 				if (__predict_false(dlen
7173a491581fSWei Hu 				    < HN_NDIS_HASH_VALUE_SIZE))
717415516c77SSepherosa Ziehau 					return (EINVAL);
7175a491581fSWei Hu 				info->hash_value = (const uint32_t *)data;
717615516c77SSepherosa Ziehau 				mask |= HN_RXINFO_HASHVAL;
717715516c77SSepherosa Ziehau 				break;
717815516c77SSepherosa Ziehau 
717915516c77SSepherosa Ziehau 			case HN_NDIS_PKTINFO_TYPE_HASHINF:
7180a491581fSWei Hu 				if (__predict_false(dlen
7181a491581fSWei Hu 				    < HN_NDIS_HASH_INFO_SIZE))
718215516c77SSepherosa Ziehau 					return (EINVAL);
7183a491581fSWei Hu 				info->hash_info = (const uint32_t *)data;
718415516c77SSepherosa Ziehau 				mask |= HN_RXINFO_HASHINF;
718515516c77SSepherosa Ziehau 				break;
718615516c77SSepherosa Ziehau 
718715516c77SSepherosa Ziehau 			default:
718815516c77SSepherosa Ziehau 				goto next;
718915516c77SSepherosa Ziehau 			}
7190a491581fSWei Hu 		}
719115516c77SSepherosa Ziehau 
719215516c77SSepherosa Ziehau 		if (mask == HN_RXINFO_ALL) {
719315516c77SSepherosa Ziehau 			/* All found; done */
719415516c77SSepherosa Ziehau 			break;
719515516c77SSepherosa Ziehau 		}
719615516c77SSepherosa Ziehau next:
719715516c77SSepherosa Ziehau 		pi = (const struct rndis_pktinfo *)
719815516c77SSepherosa Ziehau 		    ((const uint8_t *)pi + pi->rm_size);
719915516c77SSepherosa Ziehau 	}
720015516c77SSepherosa Ziehau 
720115516c77SSepherosa Ziehau 	/*
720215516c77SSepherosa Ziehau 	 * Final fixup.
720315516c77SSepherosa Ziehau 	 * - If there is no hash value, invalidate the hash info.
720415516c77SSepherosa Ziehau 	 */
720515516c77SSepherosa Ziehau 	if ((mask & HN_RXINFO_HASHVAL) == 0)
7206a491581fSWei Hu 		info->hash_info = NULL;
720715516c77SSepherosa Ziehau 	return (0);
720815516c77SSepherosa Ziehau }
720915516c77SSepherosa Ziehau 
721015516c77SSepherosa Ziehau static __inline bool
721115516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
721215516c77SSepherosa Ziehau {
721315516c77SSepherosa Ziehau 
721415516c77SSepherosa Ziehau 	if (off < check_off) {
721515516c77SSepherosa Ziehau 		if (__predict_true(off + len <= check_off))
721615516c77SSepherosa Ziehau 			return (false);
721715516c77SSepherosa Ziehau 	} else if (off > check_off) {
721815516c77SSepherosa Ziehau 		if (__predict_true(check_off + check_len <= off))
721915516c77SSepherosa Ziehau 			return (false);
722015516c77SSepherosa Ziehau 	}
722115516c77SSepherosa Ziehau 	return (true);
722215516c77SSepherosa Ziehau }
722315516c77SSepherosa Ziehau 
7224a491581fSWei Hu static __inline void
7225a491581fSWei Hu hn_rsc_add_data(struct hn_rx_ring *rxr, const void *data,
7226a491581fSWei Hu 		uint32_t len, struct hn_rxinfo *info)
7227a491581fSWei Hu {
7228a491581fSWei Hu 	uint32_t cnt = rxr->rsc.cnt;
7229a491581fSWei Hu 
7230a491581fSWei Hu 	if (cnt) {
7231a491581fSWei Hu 		rxr->rsc.pktlen += len;
7232a491581fSWei Hu 	} else {
7233a491581fSWei Hu 		rxr->rsc.vlan_info = info->vlan_info;
7234a491581fSWei Hu 		rxr->rsc.csum_info = info->csum_info;
7235a491581fSWei Hu 		rxr->rsc.hash_info = info->hash_info;
7236a491581fSWei Hu 		rxr->rsc.hash_value = info->hash_value;
7237a491581fSWei Hu 		rxr->rsc.pktlen = len;
7238a491581fSWei Hu 	}
7239a491581fSWei Hu 
7240a491581fSWei Hu 	rxr->rsc.frag_data[cnt] = data;
7241a491581fSWei Hu 	rxr->rsc.frag_len[cnt] = len;
7242a491581fSWei Hu 	rxr->rsc.cnt++;
7243a491581fSWei Hu }
7244a491581fSWei Hu 
724515516c77SSepherosa Ziehau static void
724615516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen)
724715516c77SSepherosa Ziehau {
724815516c77SSepherosa Ziehau 	const struct rndis_packet_msg *pkt;
724915516c77SSepherosa Ziehau 	struct hn_rxinfo info;
725015516c77SSepherosa Ziehau 	int data_off, pktinfo_off, data_len, pktinfo_len;
7251a491581fSWei Hu 	bool rsc_more= false;
725215516c77SSepherosa Ziehau 
725315516c77SSepherosa Ziehau 	/*
725415516c77SSepherosa Ziehau 	 * Check length.
725515516c77SSepherosa Ziehau 	 */
725615516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*pkt))) {
725715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
725815516c77SSepherosa Ziehau 		return;
725915516c77SSepherosa Ziehau 	}
726015516c77SSepherosa Ziehau 	pkt = data;
726115516c77SSepherosa Ziehau 
726215516c77SSepherosa Ziehau 	if (__predict_false(dlen < pkt->rm_len)) {
726315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
726415516c77SSepherosa Ziehau 		    "dlen %d, msglen %u\n", dlen, pkt->rm_len);
726515516c77SSepherosa Ziehau 		return;
726615516c77SSepherosa Ziehau 	}
726715516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_len <
726815516c77SSepherosa Ziehau 	    pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
726915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
727015516c77SSepherosa Ziehau 		    "msglen %u, data %u, oob %u, pktinfo %u\n",
727115516c77SSepherosa Ziehau 		    pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
727215516c77SSepherosa Ziehau 		    pkt->rm_pktinfolen);
727315516c77SSepherosa Ziehau 		return;
727415516c77SSepherosa Ziehau 	}
727515516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_datalen == 0)) {
727615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
727715516c77SSepherosa Ziehau 		return;
727815516c77SSepherosa Ziehau 	}
727915516c77SSepherosa Ziehau 
728015516c77SSepherosa Ziehau 	/*
728115516c77SSepherosa Ziehau 	 * Check offests.
728215516c77SSepherosa Ziehau 	 */
728315516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs)			\
728415516c77SSepherosa Ziehau 	((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN ||	\
728515516c77SSepherosa Ziehau 	 ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
728615516c77SSepherosa Ziehau 
728715516c77SSepherosa Ziehau 	/* XXX Hyper-V does not meet data offset alignment requirement */
728815516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
728915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
729015516c77SSepherosa Ziehau 		    "data offset %u\n", pkt->rm_dataoffset);
729115516c77SSepherosa Ziehau 		return;
729215516c77SSepherosa Ziehau 	}
729315516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdataoffset > 0 &&
729415516c77SSepherosa Ziehau 	    IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
729515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
729615516c77SSepherosa Ziehau 		    "oob offset %u\n", pkt->rm_oobdataoffset);
729715516c77SSepherosa Ziehau 		return;
729815516c77SSepherosa Ziehau 	}
729915516c77SSepherosa Ziehau 	if (__predict_true(pkt->rm_pktinfooffset > 0) &&
730015516c77SSepherosa Ziehau 	    __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
730115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
730215516c77SSepherosa Ziehau 		    "pktinfo offset %u\n", pkt->rm_pktinfooffset);
730315516c77SSepherosa Ziehau 		return;
730415516c77SSepherosa Ziehau 	}
730515516c77SSepherosa Ziehau 
730615516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID
730715516c77SSepherosa Ziehau 
730815516c77SSepherosa Ziehau 	data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
730915516c77SSepherosa Ziehau 	data_len = pkt->rm_datalen;
731015516c77SSepherosa Ziehau 	pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
731115516c77SSepherosa Ziehau 	pktinfo_len = pkt->rm_pktinfolen;
731215516c77SSepherosa Ziehau 
731315516c77SSepherosa Ziehau 	/*
731415516c77SSepherosa Ziehau 	 * Check OOB coverage.
731515516c77SSepherosa Ziehau 	 */
731615516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdatalen != 0)) {
731715516c77SSepherosa Ziehau 		int oob_off, oob_len;
731815516c77SSepherosa Ziehau 
731915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "got oobdata\n");
732015516c77SSepherosa Ziehau 		oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
732115516c77SSepherosa Ziehau 		oob_len = pkt->rm_oobdatalen;
732215516c77SSepherosa Ziehau 
732315516c77SSepherosa Ziehau 		if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
732415516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
732515516c77SSepherosa Ziehau 			    "oob overflow, msglen %u, oob abs %d len %d\n",
732615516c77SSepherosa Ziehau 			    pkt->rm_len, oob_off, oob_len);
732715516c77SSepherosa Ziehau 			return;
732815516c77SSepherosa Ziehau 		}
732915516c77SSepherosa Ziehau 
733015516c77SSepherosa Ziehau 		/*
733115516c77SSepherosa Ziehau 		 * Check against data.
733215516c77SSepherosa Ziehau 		 */
733315516c77SSepherosa Ziehau 		if (hn_rndis_check_overlap(oob_off, oob_len,
733415516c77SSepherosa Ziehau 		    data_off, data_len)) {
733515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
733615516c77SSepherosa Ziehau 			    "oob overlaps data, oob abs %d len %d, "
733715516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
733815516c77SSepherosa Ziehau 			    oob_off, oob_len, data_off, data_len);
733915516c77SSepherosa Ziehau 			return;
734015516c77SSepherosa Ziehau 		}
734115516c77SSepherosa Ziehau 
734215516c77SSepherosa Ziehau 		/*
734315516c77SSepherosa Ziehau 		 * Check against pktinfo.
734415516c77SSepherosa Ziehau 		 */
734515516c77SSepherosa Ziehau 		if (pktinfo_len != 0 &&
734615516c77SSepherosa Ziehau 		    hn_rndis_check_overlap(oob_off, oob_len,
734715516c77SSepherosa Ziehau 		    pktinfo_off, pktinfo_len)) {
734815516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
734915516c77SSepherosa Ziehau 			    "oob overlaps pktinfo, oob abs %d len %d, "
735015516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
735115516c77SSepherosa Ziehau 			    oob_off, oob_len, pktinfo_off, pktinfo_len);
735215516c77SSepherosa Ziehau 			return;
735315516c77SSepherosa Ziehau 		}
735415516c77SSepherosa Ziehau 	}
735515516c77SSepherosa Ziehau 
735615516c77SSepherosa Ziehau 	/*
735715516c77SSepherosa Ziehau 	 * Check per-packet-info coverage and find useful per-packet-info.
735815516c77SSepherosa Ziehau 	 */
7359a491581fSWei Hu 	info.vlan_info = NULL;
7360a491581fSWei Hu 	info.csum_info = NULL;
7361a491581fSWei Hu 	info.hash_info = NULL;
7362a491581fSWei Hu 	info.pktinfo_id = NULL;
7363a491581fSWei Hu 
736415516c77SSepherosa Ziehau 	if (__predict_true(pktinfo_len != 0)) {
736515516c77SSepherosa Ziehau 		bool overlap;
736615516c77SSepherosa Ziehau 		int error;
736715516c77SSepherosa Ziehau 
736815516c77SSepherosa Ziehau 		if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
736915516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
737015516c77SSepherosa Ziehau 			    "pktinfo overflow, msglen %u, "
737115516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
737215516c77SSepherosa Ziehau 			    pkt->rm_len, pktinfo_off, pktinfo_len);
737315516c77SSepherosa Ziehau 			return;
737415516c77SSepherosa Ziehau 		}
737515516c77SSepherosa Ziehau 
737615516c77SSepherosa Ziehau 		/*
737715516c77SSepherosa Ziehau 		 * Check packet info coverage.
737815516c77SSepherosa Ziehau 		 */
737915516c77SSepherosa Ziehau 		overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
738015516c77SSepherosa Ziehau 		    data_off, data_len);
738115516c77SSepherosa Ziehau 		if (__predict_false(overlap)) {
738215516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
738315516c77SSepherosa Ziehau 			    "pktinfo overlap data, pktinfo abs %d len %d, "
738415516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
738515516c77SSepherosa Ziehau 			    pktinfo_off, pktinfo_len, data_off, data_len);
738615516c77SSepherosa Ziehau 			return;
738715516c77SSepherosa Ziehau 		}
738815516c77SSepherosa Ziehau 
738915516c77SSepherosa Ziehau 		/*
739015516c77SSepherosa Ziehau 		 * Find useful per-packet-info.
739115516c77SSepherosa Ziehau 		 */
739215516c77SSepherosa Ziehau 		error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
739315516c77SSepherosa Ziehau 		    pktinfo_len, &info);
739415516c77SSepherosa Ziehau 		if (__predict_false(error)) {
739515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
739615516c77SSepherosa Ziehau 			    "pktinfo\n");
739715516c77SSepherosa Ziehau 			return;
739815516c77SSepherosa Ziehau 		}
739915516c77SSepherosa Ziehau 	}
740015516c77SSepherosa Ziehau 
740115516c77SSepherosa Ziehau 	if (__predict_false(data_off + data_len > pkt->rm_len)) {
740215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
740315516c77SSepherosa Ziehau 		    "data overflow, msglen %u, data abs %d len %d\n",
740415516c77SSepherosa Ziehau 		    pkt->rm_len, data_off, data_len);
740515516c77SSepherosa Ziehau 		return;
740615516c77SSepherosa Ziehau 	}
7407a491581fSWei Hu 
7408a491581fSWei Hu 	/* Identify RSC fragments, drop invalid packets */
7409a491581fSWei Hu 	if ((info.pktinfo_id != NULL) &&
7410a491581fSWei Hu 	    (info.pktinfo_id->flag & HN_NDIS_PKTINFO_SUBALLOC)) {
7411a491581fSWei Hu 		if (info.pktinfo_id->flag & HN_NDIS_PKTINFO_1ST_FRAG) {
7412a491581fSWei Hu 			rxr->rsc.cnt = 0;
7413a491581fSWei Hu 			rxr->hn_rsc_pkts++;
7414a491581fSWei Hu 		} else if (rxr->rsc.cnt == 0)
7415a491581fSWei Hu 			goto drop;
7416a491581fSWei Hu 
7417a491581fSWei Hu 		rsc_more = true;
7418a491581fSWei Hu 
7419a491581fSWei Hu 		if (info.pktinfo_id->flag & HN_NDIS_PKTINFO_LAST_FRAG)
7420a491581fSWei Hu 			rsc_more = false;
7421a491581fSWei Hu 
7422a491581fSWei Hu 		if (rsc_more && rxr->rsc.is_last)
7423a491581fSWei Hu 			goto drop;
7424a491581fSWei Hu 	} else {
7425a491581fSWei Hu 		rxr->rsc.cnt = 0;
7426a491581fSWei Hu 	}
7427a491581fSWei Hu 
7428a491581fSWei Hu 	if (__predict_false(rxr->rsc.cnt >= HN_NVS_RSC_MAX))
7429a491581fSWei Hu 		goto drop;
7430a491581fSWei Hu 
7431a491581fSWei Hu 	/* Store data in per rx ring structure */
7432a491581fSWei Hu 	hn_rsc_add_data(rxr,((const uint8_t *)pkt) + data_off,
7433a491581fSWei Hu 	    data_len, &info);
7434a491581fSWei Hu 
7435a491581fSWei Hu 	if (rsc_more)
7436a491581fSWei Hu 		return;
7437a491581fSWei Hu 
7438a491581fSWei Hu 	hn_rxpkt(rxr);
7439a491581fSWei Hu 	rxr->rsc.cnt = 0;
7440a491581fSWei Hu 	return;
7441a491581fSWei Hu drop:
7442a491581fSWei Hu 	rxr->hn_rsc_drop++;
7443a491581fSWei Hu 	return;
744415516c77SSepherosa Ziehau }
744515516c77SSepherosa Ziehau 
744615516c77SSepherosa Ziehau static __inline void
744715516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen)
744815516c77SSepherosa Ziehau {
744915516c77SSepherosa Ziehau 	const struct rndis_msghdr *hdr;
745015516c77SSepherosa Ziehau 
745115516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*hdr))) {
745215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
745315516c77SSepherosa Ziehau 		return;
745415516c77SSepherosa Ziehau 	}
745515516c77SSepherosa Ziehau 	hdr = data;
745615516c77SSepherosa Ziehau 
745715516c77SSepherosa Ziehau 	if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) {
745815516c77SSepherosa Ziehau 		/* Hot data path. */
745915516c77SSepherosa Ziehau 		hn_rndis_rx_data(rxr, data, dlen);
746015516c77SSepherosa Ziehau 		/* Done! */
746115516c77SSepherosa Ziehau 		return;
746215516c77SSepherosa Ziehau 	}
746315516c77SSepherosa Ziehau 
746415516c77SSepherosa Ziehau 	if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG)
746515516c77SSepherosa Ziehau 		hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen);
746615516c77SSepherosa Ziehau 	else
746715516c77SSepherosa Ziehau 		hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen);
746815516c77SSepherosa Ziehau }
746915516c77SSepherosa Ziehau 
747015516c77SSepherosa Ziehau static void
747115516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
747215516c77SSepherosa Ziehau {
747315516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *hdr;
747415516c77SSepherosa Ziehau 
747515516c77SSepherosa Ziehau 	if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) {
747615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid nvs notify\n");
747715516c77SSepherosa Ziehau 		return;
747815516c77SSepherosa Ziehau 	}
747915516c77SSepherosa Ziehau 	hdr = VMBUS_CHANPKT_CONST_DATA(pkt);
748015516c77SSepherosa Ziehau 
748115516c77SSepherosa Ziehau 	if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) {
748215516c77SSepherosa Ziehau 		/* Useless; ignore */
748315516c77SSepherosa Ziehau 		return;
748415516c77SSepherosa Ziehau 	}
748515516c77SSepherosa Ziehau 	if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type);
748615516c77SSepherosa Ziehau }
748715516c77SSepherosa Ziehau 
748815516c77SSepherosa Ziehau static void
748915516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan,
749015516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkt)
749115516c77SSepherosa Ziehau {
749215516c77SSepherosa Ziehau 	struct hn_nvs_sendctx *sndc;
749315516c77SSepherosa Ziehau 
749415516c77SSepherosa Ziehau 	sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid;
749515516c77SSepherosa Ziehau 	sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt),
749615516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_DATALEN(pkt));
749715516c77SSepherosa Ziehau 	/*
749815516c77SSepherosa Ziehau 	 * NOTE:
749915516c77SSepherosa Ziehau 	 * 'sndc' CAN NOT be accessed anymore, since it can be freed by
750015516c77SSepherosa Ziehau 	 * its callback.
750115516c77SSepherosa Ziehau 	 */
750215516c77SSepherosa Ziehau }
750315516c77SSepherosa Ziehau 
750415516c77SSepherosa Ziehau static void
750515516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
750615516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkthdr)
750715516c77SSepherosa Ziehau {
750826d79d40SMichael Tuexen 	struct epoch_tracker et;
750915516c77SSepherosa Ziehau 	const struct vmbus_chanpkt_rxbuf *pkt;
751015516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *nvs_hdr;
751115516c77SSepherosa Ziehau 	int count, i, hlen;
751215516c77SSepherosa Ziehau 
751315516c77SSepherosa Ziehau 	if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) {
751415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n");
751515516c77SSepherosa Ziehau 		return;
751615516c77SSepherosa Ziehau 	}
751715516c77SSepherosa Ziehau 	nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr);
751815516c77SSepherosa Ziehau 
751915516c77SSepherosa Ziehau 	/* Make sure that this is a RNDIS message. */
752015516c77SSepherosa Ziehau 	if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) {
752115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n",
752215516c77SSepherosa Ziehau 		    nvs_hdr->nvs_type);
752315516c77SSepherosa Ziehau 		return;
752415516c77SSepherosa Ziehau 	}
752515516c77SSepherosa Ziehau 
752615516c77SSepherosa Ziehau 	hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen);
752715516c77SSepherosa Ziehau 	if (__predict_false(hlen < sizeof(*pkt))) {
752815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n");
752915516c77SSepherosa Ziehau 		return;
753015516c77SSepherosa Ziehau 	}
753115516c77SSepherosa Ziehau 	pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
753215516c77SSepherosa Ziehau 
753315516c77SSepherosa Ziehau 	if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) {
753415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n",
753515516c77SSepherosa Ziehau 		    pkt->cp_rxbuf_id);
753615516c77SSepherosa Ziehau 		return;
753715516c77SSepherosa Ziehau 	}
753815516c77SSepherosa Ziehau 
753915516c77SSepherosa Ziehau 	count = pkt->cp_rxbuf_cnt;
754015516c77SSepherosa Ziehau 	if (__predict_false(hlen <
754115516c77SSepherosa Ziehau 	    __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) {
754215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count);
754315516c77SSepherosa Ziehau 		return;
754415516c77SSepherosa Ziehau 	}
754515516c77SSepherosa Ziehau 
754626d79d40SMichael Tuexen 	NET_EPOCH_ENTER(et);
754715516c77SSepherosa Ziehau 	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
754815516c77SSepherosa Ziehau 	for (i = 0; i < count; ++i) {
754915516c77SSepherosa Ziehau 		int ofs, len;
755015516c77SSepherosa Ziehau 
755115516c77SSepherosa Ziehau 		ofs = pkt->cp_rxbuf[i].rb_ofs;
755215516c77SSepherosa Ziehau 		len = pkt->cp_rxbuf[i].rb_len;
755315516c77SSepherosa Ziehau 		if (__predict_false(ofs + len > HN_RXBUF_SIZE)) {
755415516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, "
755515516c77SSepherosa Ziehau 			    "ofs %d, len %d\n", i, ofs, len);
755615516c77SSepherosa Ziehau 			continue;
755715516c77SSepherosa Ziehau 		}
7558a491581fSWei Hu 
7559a491581fSWei Hu 		rxr->rsc.is_last = (i == (count - 1));
756015516c77SSepherosa Ziehau 		hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len);
756115516c77SSepherosa Ziehau 	}
756226d79d40SMichael Tuexen 	NET_EPOCH_EXIT(et);
756315516c77SSepherosa Ziehau 
756415516c77SSepherosa Ziehau 	/*
756515516c77SSepherosa Ziehau 	 * Ack the consumed RXBUF associated w/ this channel packet,
756615516c77SSepherosa Ziehau 	 * so that this RXBUF can be recycled by the hypervisor.
756715516c77SSepherosa Ziehau 	 */
756815516c77SSepherosa Ziehau 	hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid);
756915516c77SSepherosa Ziehau }
757015516c77SSepherosa Ziehau 
757115516c77SSepherosa Ziehau static void
757215516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
757315516c77SSepherosa Ziehau     uint64_t tid)
757415516c77SSepherosa Ziehau {
757515516c77SSepherosa Ziehau 	struct hn_nvs_rndis_ack ack;
757615516c77SSepherosa Ziehau 	int retries, error;
757715516c77SSepherosa Ziehau 
757815516c77SSepherosa Ziehau 	ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK;
757915516c77SSepherosa Ziehau 	ack.nvs_status = HN_NVS_STATUS_OK;
758015516c77SSepherosa Ziehau 
758115516c77SSepherosa Ziehau 	retries = 0;
758215516c77SSepherosa Ziehau again:
758315516c77SSepherosa Ziehau 	error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP,
758415516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid);
758515516c77SSepherosa Ziehau 	if (__predict_false(error == EAGAIN)) {
758615516c77SSepherosa Ziehau 		/*
758715516c77SSepherosa Ziehau 		 * NOTE:
758815516c77SSepherosa Ziehau 		 * This should _not_ happen in real world, since the
758915516c77SSepherosa Ziehau 		 * consumption of the TX bufring from the TX path is
759015516c77SSepherosa Ziehau 		 * controlled.
759115516c77SSepherosa Ziehau 		 */
759215516c77SSepherosa Ziehau 		if (rxr->hn_ack_failed == 0)
759315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "RXBUF ack retry\n");
759415516c77SSepherosa Ziehau 		rxr->hn_ack_failed++;
759515516c77SSepherosa Ziehau 		retries++;
759615516c77SSepherosa Ziehau 		if (retries < 10) {
759715516c77SSepherosa Ziehau 			DELAY(100);
759815516c77SSepherosa Ziehau 			goto again;
759915516c77SSepherosa Ziehau 		}
760015516c77SSepherosa Ziehau 		/* RXBUF leaks! */
760115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "RXBUF ack failed\n");
760215516c77SSepherosa Ziehau 	}
760315516c77SSepherosa Ziehau }
760415516c77SSepherosa Ziehau 
760515516c77SSepherosa Ziehau static void
760615516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr)
760715516c77SSepherosa Ziehau {
760815516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr = xrxr;
760915516c77SSepherosa Ziehau 	struct hn_softc *sc = rxr->hn_ifp->if_softc;
761015516c77SSepherosa Ziehau 
761115516c77SSepherosa Ziehau 	for (;;) {
761215516c77SSepherosa Ziehau 		struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf;
761315516c77SSepherosa Ziehau 		int error, pktlen;
761415516c77SSepherosa Ziehau 
761515516c77SSepherosa Ziehau 		pktlen = rxr->hn_pktbuf_len;
761615516c77SSepherosa Ziehau 		error = vmbus_chan_recv_pkt(chan, pkt, &pktlen);
761715516c77SSepherosa Ziehau 		if (__predict_false(error == ENOBUFS)) {
761815516c77SSepherosa Ziehau 			void *nbuf;
761915516c77SSepherosa Ziehau 			int nlen;
762015516c77SSepherosa Ziehau 
762115516c77SSepherosa Ziehau 			/*
762215516c77SSepherosa Ziehau 			 * Expand channel packet buffer.
762315516c77SSepherosa Ziehau 			 *
762415516c77SSepherosa Ziehau 			 * XXX
762515516c77SSepherosa Ziehau 			 * Use M_WAITOK here, since allocation failure
762615516c77SSepherosa Ziehau 			 * is fatal.
762715516c77SSepherosa Ziehau 			 */
762815516c77SSepherosa Ziehau 			nlen = rxr->hn_pktbuf_len * 2;
762915516c77SSepherosa Ziehau 			while (nlen < pktlen)
763015516c77SSepherosa Ziehau 				nlen *= 2;
763115516c77SSepherosa Ziehau 			nbuf = malloc(nlen, M_DEVBUF, M_WAITOK);
763215516c77SSepherosa Ziehau 
763315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n",
763415516c77SSepherosa Ziehau 			    rxr->hn_pktbuf_len, nlen);
763515516c77SSepherosa Ziehau 
763615516c77SSepherosa Ziehau 			free(rxr->hn_pktbuf, M_DEVBUF);
763715516c77SSepherosa Ziehau 			rxr->hn_pktbuf = nbuf;
763815516c77SSepherosa Ziehau 			rxr->hn_pktbuf_len = nlen;
763915516c77SSepherosa Ziehau 			/* Retry! */
764015516c77SSepherosa Ziehau 			continue;
764115516c77SSepherosa Ziehau 		} else if (__predict_false(error == EAGAIN)) {
764215516c77SSepherosa Ziehau 			/* No more channel packets; done! */
764315516c77SSepherosa Ziehau 			break;
764415516c77SSepherosa Ziehau 		}
764515516c77SSepherosa Ziehau 		KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error));
764615516c77SSepherosa Ziehau 
764715516c77SSepherosa Ziehau 		switch (pkt->cph_type) {
764815516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_COMP:
764915516c77SSepherosa Ziehau 			hn_nvs_handle_comp(sc, chan, pkt);
765015516c77SSepherosa Ziehau 			break;
765115516c77SSepherosa Ziehau 
765215516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_RXBUF:
765315516c77SSepherosa Ziehau 			hn_nvs_handle_rxbuf(rxr, chan, pkt);
765415516c77SSepherosa Ziehau 			break;
765515516c77SSepherosa Ziehau 
765615516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_INBAND:
765715516c77SSepherosa Ziehau 			hn_nvs_handle_notify(sc, pkt);
765815516c77SSepherosa Ziehau 			break;
765915516c77SSepherosa Ziehau 
766015516c77SSepherosa Ziehau 		default:
766115516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "unknown chan pkt %u\n",
766215516c77SSepherosa Ziehau 			    pkt->cph_type);
766315516c77SSepherosa Ziehau 			break;
766415516c77SSepherosa Ziehau 		}
766515516c77SSepherosa Ziehau 	}
766615516c77SSepherosa Ziehau 	hn_chan_rollup(rxr, rxr->hn_txr);
766715516c77SSepherosa Ziehau }
766815516c77SSepherosa Ziehau 
766915516c77SSepherosa Ziehau static void
7670499c3e17SSepherosa Ziehau hn_sysinit(void *arg __unused)
767115516c77SSepherosa Ziehau {
7672fdd0222aSSepherosa Ziehau 	int i;
7673fdd0222aSSepherosa Ziehau 
76742be266caSSepherosa Ziehau 	hn_udpcs_fixup = counter_u64_alloc(M_WAITOK);
76752be266caSSepherosa Ziehau 
76769c6cae24SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
76779c6cae24SSepherosa Ziehau 	/*
76789c6cae24SSepherosa Ziehau 	 * Don't use ifnet.if_start if transparent VF mode is requested;
76799c6cae24SSepherosa Ziehau 	 * mainly due to the IFF_DRV_OACTIVE flag.
76809c6cae24SSepherosa Ziehau 	 */
76819c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && hn_use_if_start) {
76829c6cae24SSepherosa Ziehau 		hn_use_if_start = 0;
76839c6cae24SSepherosa Ziehau 		printf("hn: tranparent VF mode, if_transmit will be used, "
76849c6cae24SSepherosa Ziehau 		    "instead of if_start\n");
76859c6cae24SSepherosa Ziehau 	}
76869c6cae24SSepherosa Ziehau #endif
76879c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_attwait < HN_XPNT_VF_ATTWAIT_MIN) {
76889c6cae24SSepherosa Ziehau 		printf("hn: invalid transparent VF attach routing "
76899c6cae24SSepherosa Ziehau 		    "wait timeout %d, reset to %d\n",
76909c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_attwait, HN_XPNT_VF_ATTWAIT_MIN);
76919c6cae24SSepherosa Ziehau 		hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN;
76929c6cae24SSepherosa Ziehau 	}
76939c6cae24SSepherosa Ziehau 
7694fdd0222aSSepherosa Ziehau 	/*
7695499c3e17SSepherosa Ziehau 	 * Initialize VF map.
7696499c3e17SSepherosa Ziehau 	 */
7697499c3e17SSepherosa Ziehau 	rm_init_flags(&hn_vfmap_lock, "hn_vfmap", RM_SLEEPABLE);
7698499c3e17SSepherosa Ziehau 	hn_vfmap_size = HN_VFMAP_SIZE_DEF;
7699499c3e17SSepherosa Ziehau 	hn_vfmap = malloc(sizeof(struct ifnet *) * hn_vfmap_size, M_DEVBUF,
7700499c3e17SSepherosa Ziehau 	    M_WAITOK | M_ZERO);
7701499c3e17SSepherosa Ziehau 
7702499c3e17SSepherosa Ziehau 	/*
7703fdd0222aSSepherosa Ziehau 	 * Fix the # of TX taskqueues.
7704fdd0222aSSepherosa Ziehau 	 */
7705fdd0222aSSepherosa Ziehau 	if (hn_tx_taskq_cnt <= 0)
7706fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = 1;
7707fdd0222aSSepherosa Ziehau 	else if (hn_tx_taskq_cnt > mp_ncpus)
7708fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = mp_ncpus;
770915516c77SSepherosa Ziehau 
77100e11868dSSepherosa Ziehau 	/*
77110e11868dSSepherosa Ziehau 	 * Fix the TX taskqueue mode.
77120e11868dSSepherosa Ziehau 	 */
77130e11868dSSepherosa Ziehau 	switch (hn_tx_taskq_mode) {
77140e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_INDEP:
77150e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_GLOBAL:
77160e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_EVTTQ:
77170e11868dSSepherosa Ziehau 		break;
77180e11868dSSepherosa Ziehau 	default:
77190e11868dSSepherosa Ziehau 		hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
77200e11868dSSepherosa Ziehau 		break;
77210e11868dSSepherosa Ziehau 	}
77220e11868dSSepherosa Ziehau 
772315516c77SSepherosa Ziehau 	if (vm_guest != VM_GUEST_HV)
772415516c77SSepherosa Ziehau 		return;
772515516c77SSepherosa Ziehau 
77260e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode != HN_TX_TASKQ_M_GLOBAL)
772715516c77SSepherosa Ziehau 		return;
772815516c77SSepherosa Ziehau 
7729fdd0222aSSepherosa Ziehau 	hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
7730fdd0222aSSepherosa Ziehau 	    M_DEVBUF, M_WAITOK);
7731fdd0222aSSepherosa Ziehau 	for (i = 0; i < hn_tx_taskq_cnt; ++i) {
7732fdd0222aSSepherosa Ziehau 		hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK,
7733fdd0222aSSepherosa Ziehau 		    taskqueue_thread_enqueue, &hn_tx_taskque[i]);
7734fdd0222aSSepherosa Ziehau 		taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET,
7735fdd0222aSSepherosa Ziehau 		    "hn tx%d", i);
7736fdd0222aSSepherosa Ziehau 	}
773715516c77SSepherosa Ziehau }
7738499c3e17SSepherosa Ziehau SYSINIT(hn_sysinit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysinit, NULL);
773915516c77SSepherosa Ziehau 
774015516c77SSepherosa Ziehau static void
7741499c3e17SSepherosa Ziehau hn_sysuninit(void *arg __unused)
774215516c77SSepherosa Ziehau {
774315516c77SSepherosa Ziehau 
7744fdd0222aSSepherosa Ziehau 	if (hn_tx_taskque != NULL) {
7745fdd0222aSSepherosa Ziehau 		int i;
7746fdd0222aSSepherosa Ziehau 
7747fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
7748fdd0222aSSepherosa Ziehau 			taskqueue_free(hn_tx_taskque[i]);
7749fdd0222aSSepherosa Ziehau 		free(hn_tx_taskque, M_DEVBUF);
7750fdd0222aSSepherosa Ziehau 	}
7751499c3e17SSepherosa Ziehau 
7752499c3e17SSepherosa Ziehau 	if (hn_vfmap != NULL)
7753499c3e17SSepherosa Ziehau 		free(hn_vfmap, M_DEVBUF);
7754499c3e17SSepherosa Ziehau 	rm_destroy(&hn_vfmap_lock);
77552be266caSSepherosa Ziehau 
77562be266caSSepherosa Ziehau 	counter_u64_free(hn_udpcs_fixup);
775715516c77SSepherosa Ziehau }
7758499c3e17SSepherosa Ziehau SYSUNINIT(hn_sysuninit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysuninit, NULL);
7759