xref: /freebsd/sys/dev/hyperv/netvsc/if_hn.c (revision 78e46963b60ece0d41c3eaa6050e52f029415269)
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>
74499c3e17SSepherosa Ziehau #include <sys/rmlock.h>
75499c3e17SSepherosa Ziehau #include <sys/sbuf.h>
7615516c77SSepherosa Ziehau #include <sys/smp.h>
7715516c77SSepherosa Ziehau #include <sys/socket.h>
7815516c77SSepherosa Ziehau #include <sys/sockio.h>
7915516c77SSepherosa Ziehau #include <sys/sx.h>
8015516c77SSepherosa Ziehau #include <sys/sysctl.h>
8115516c77SSepherosa Ziehau #include <sys/taskqueue.h>
8215516c77SSepherosa Ziehau #include <sys/buf_ring.h>
835bdfd3fdSDexuan Cui #include <sys/eventhandler.h>
8415516c77SSepherosa Ziehau 
8515516c77SSepherosa Ziehau #include <machine/atomic.h>
8615516c77SSepherosa Ziehau #include <machine/in_cksum.h>
8715516c77SSepherosa Ziehau 
8815516c77SSepherosa Ziehau #include <net/bpf.h>
8915516c77SSepherosa Ziehau #include <net/ethernet.h>
9015516c77SSepherosa Ziehau #include <net/if.h>
915bdfd3fdSDexuan Cui #include <net/if_dl.h>
9215516c77SSepherosa Ziehau #include <net/if_media.h>
9315516c77SSepherosa Ziehau #include <net/if_types.h>
9415516c77SSepherosa Ziehau #include <net/if_var.h>
9515516c77SSepherosa Ziehau #include <net/rndis.h>
9634d68912SSepherosa Ziehau #ifdef RSS
9734d68912SSepherosa Ziehau #include <net/rss_config.h>
9834d68912SSepherosa Ziehau #endif
9915516c77SSepherosa Ziehau 
10015516c77SSepherosa Ziehau #include <netinet/in_systm.h>
10115516c77SSepherosa Ziehau #include <netinet/in.h>
10215516c77SSepherosa Ziehau #include <netinet/ip.h>
10315516c77SSepherosa Ziehau #include <netinet/ip6.h>
10415516c77SSepherosa Ziehau #include <netinet/tcp.h>
10515516c77SSepherosa Ziehau #include <netinet/tcp_lro.h>
10615516c77SSepherosa Ziehau #include <netinet/udp.h>
10715516c77SSepherosa Ziehau 
10815516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h>
10915516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv_busdma.h>
11015516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus.h>
11115516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus_xact.h>
11215516c77SSepherosa Ziehau 
11315516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/ndis.h>
11415516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnreg.h>
11515516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnvar.h>
11615516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_nvs.h>
11715516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_rndis.h>
11815516c77SSepherosa Ziehau 
11915516c77SSepherosa Ziehau #include "vmbus_if.h"
12015516c77SSepherosa Ziehau 
12123bf9e15SSepherosa Ziehau #define HN_IFSTART_SUPPORT
12223bf9e15SSepherosa Ziehau 
12315516c77SSepherosa Ziehau #define HN_RING_CNT_DEF_MAX		8
12415516c77SSepherosa Ziehau 
125499c3e17SSepherosa Ziehau #define HN_VFMAP_SIZE_DEF		8
126499c3e17SSepherosa Ziehau 
1279c6cae24SSepherosa Ziehau #define HN_XPNT_VF_ATTWAIT_MIN		2	/* seconds */
1289c6cae24SSepherosa Ziehau 
12915516c77SSepherosa Ziehau /* YYY should get it from the underlying channel */
13015516c77SSepherosa Ziehau #define HN_TX_DESC_CNT			512
13115516c77SSepherosa Ziehau 
13215516c77SSepherosa Ziehau #define HN_RNDIS_PKT_LEN					\
13315516c77SSepherosa Ziehau 	(sizeof(struct rndis_packet_msg) +			\
13415516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) +	\
13515516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) +		\
13615516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) +		\
13715516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_TXCSUM_INFO_SIZE))
13815516c77SSepherosa Ziehau #define HN_RNDIS_PKT_BOUNDARY		PAGE_SIZE
13915516c77SSepherosa Ziehau #define HN_RNDIS_PKT_ALIGN		CACHE_LINE_SIZE
14015516c77SSepherosa Ziehau 
14115516c77SSepherosa Ziehau #define HN_TX_DATA_BOUNDARY		PAGE_SIZE
14215516c77SSepherosa Ziehau #define HN_TX_DATA_MAXSIZE		IP_MAXPACKET
14315516c77SSepherosa Ziehau #define HN_TX_DATA_SEGSIZE		PAGE_SIZE
14415516c77SSepherosa Ziehau /* -1 for RNDIS packet message */
14515516c77SSepherosa Ziehau #define HN_TX_DATA_SEGCNT_MAX		(HN_GPACNT_MAX - 1)
14615516c77SSepherosa Ziehau 
14715516c77SSepherosa Ziehau #define HN_DIRECT_TX_SIZE_DEF		128
14815516c77SSepherosa Ziehau 
14915516c77SSepherosa Ziehau #define HN_EARLY_TXEOF_THRESH		8
15015516c77SSepherosa Ziehau 
15115516c77SSepherosa Ziehau #define HN_PKTBUF_LEN_DEF		(16 * 1024)
15215516c77SSepherosa Ziehau 
15315516c77SSepherosa Ziehau #define HN_LROENT_CNT_DEF		128
15415516c77SSepherosa Ziehau 
15515516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MULTIRX_DEF	(12 * ETHERMTU)
15615516c77SSepherosa Ziehau #define HN_LRO_LENLIM_DEF		(25 * ETHERMTU)
15715516c77SSepherosa Ziehau /* YYY 2*MTU is a bit rough, but should be good enough. */
15815516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MIN(ifp)		(2 * (ifp)->if_mtu)
15915516c77SSepherosa Ziehau 
16015516c77SSepherosa Ziehau #define HN_LRO_ACKCNT_DEF		1
16115516c77SSepherosa Ziehau 
16215516c77SSepherosa Ziehau #define HN_LOCK_INIT(sc)		\
16315516c77SSepherosa Ziehau 	sx_init(&(sc)->hn_lock, device_get_nameunit((sc)->hn_dev))
16415516c77SSepherosa Ziehau #define HN_LOCK_DESTROY(sc)		sx_destroy(&(sc)->hn_lock)
16515516c77SSepherosa Ziehau #define HN_LOCK_ASSERT(sc)		sx_assert(&(sc)->hn_lock, SA_XLOCKED)
166fdc4f478SSepherosa Ziehau #define HN_LOCK(sc)					\
167fdc4f478SSepherosa Ziehau do {							\
168fdc4f478SSepherosa Ziehau 	while (sx_try_xlock(&(sc)->hn_lock) == 0)	\
169fdc4f478SSepherosa Ziehau 		DELAY(1000);				\
170fdc4f478SSepherosa Ziehau } while (0)
17115516c77SSepherosa Ziehau #define HN_UNLOCK(sc)			sx_xunlock(&(sc)->hn_lock)
17215516c77SSepherosa Ziehau 
17315516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK			(CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP)
17415516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK		(CSUM_IP6_TCP | CSUM_IP6_UDP)
17515516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc)		\
17615516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK)
17715516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc)	\
17815516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK)
17915516c77SSepherosa Ziehau 
180dc13fee6SSepherosa Ziehau #define HN_PKTSIZE_MIN(align)		\
181dc13fee6SSepherosa Ziehau 	roundup2(ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN + \
182dc13fee6SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN, (align))
183dc13fee6SSepherosa Ziehau #define HN_PKTSIZE(m, align)		\
184dc13fee6SSepherosa Ziehau 	roundup2((m)->m_pkthdr.len + HN_RNDIS_PKT_LEN, (align))
185dc13fee6SSepherosa Ziehau 
18634d68912SSepherosa Ziehau #ifdef RSS
18734d68912SSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx)	rss_getcpu((idx) % rss_getnumbuckets())
18834d68912SSepherosa Ziehau #else
1890e11868dSSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx)	(((sc)->hn_cpu + (idx)) % mp_ncpus)
19034d68912SSepherosa Ziehau #endif
1910e11868dSSepherosa Ziehau 
19215516c77SSepherosa Ziehau struct hn_txdesc {
19315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
19415516c77SSepherosa Ziehau 	SLIST_ENTRY(hn_txdesc)		link;
19515516c77SSepherosa Ziehau #endif
196dc13fee6SSepherosa Ziehau 	STAILQ_ENTRY(hn_txdesc)		agg_link;
197dc13fee6SSepherosa Ziehau 
198dc13fee6SSepherosa Ziehau 	/* Aggregated txdescs, in sending order. */
199dc13fee6SSepherosa Ziehau 	STAILQ_HEAD(, hn_txdesc)	agg_list;
200dc13fee6SSepherosa Ziehau 
201dc13fee6SSepherosa Ziehau 	/* The oldest packet, if transmission aggregation happens. */
20215516c77SSepherosa Ziehau 	struct mbuf			*m;
20315516c77SSepherosa Ziehau 	struct hn_tx_ring		*txr;
20415516c77SSepherosa Ziehau 	int				refs;
20515516c77SSepherosa Ziehau 	uint32_t			flags;	/* HN_TXD_FLAG_ */
20615516c77SSepherosa Ziehau 	struct hn_nvs_sendctx		send_ctx;
20715516c77SSepherosa Ziehau 	uint32_t			chim_index;
20815516c77SSepherosa Ziehau 	int				chim_size;
20915516c77SSepherosa Ziehau 
21015516c77SSepherosa Ziehau 	bus_dmamap_t			data_dmap;
21115516c77SSepherosa Ziehau 
21215516c77SSepherosa Ziehau 	bus_addr_t			rndis_pkt_paddr;
21315516c77SSepherosa Ziehau 	struct rndis_packet_msg		*rndis_pkt;
21415516c77SSepherosa Ziehau 	bus_dmamap_t			rndis_pkt_dmap;
21515516c77SSepherosa Ziehau };
21615516c77SSepherosa Ziehau 
21715516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST		0x0001
21815516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP		0x0002
219dc13fee6SSepherosa Ziehau #define HN_TXD_FLAG_ONAGG		0x0004
22015516c77SSepherosa Ziehau 
22115516c77SSepherosa Ziehau struct hn_rxinfo {
22215516c77SSepherosa Ziehau 	uint32_t			vlan_info;
22315516c77SSepherosa Ziehau 	uint32_t			csum_info;
22415516c77SSepherosa Ziehau 	uint32_t			hash_info;
22515516c77SSepherosa Ziehau 	uint32_t			hash_value;
22615516c77SSepherosa Ziehau };
22715516c77SSepherosa Ziehau 
228962f0357SSepherosa Ziehau struct hn_rxvf_setarg {
2295bdfd3fdSDexuan Cui 	struct hn_rx_ring	*rxr;
230962f0357SSepherosa Ziehau 	struct ifnet		*vf_ifp;
2315bdfd3fdSDexuan Cui };
2325bdfd3fdSDexuan Cui 
23315516c77SSepherosa Ziehau #define HN_RXINFO_VLAN			0x0001
23415516c77SSepherosa Ziehau #define HN_RXINFO_CSUM			0x0002
23515516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF		0x0004
23615516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL		0x0008
23715516c77SSepherosa Ziehau #define HN_RXINFO_ALL			\
23815516c77SSepherosa Ziehau 	(HN_RXINFO_VLAN |		\
23915516c77SSepherosa Ziehau 	 HN_RXINFO_CSUM |		\
24015516c77SSepherosa Ziehau 	 HN_RXINFO_HASHINF |		\
24115516c77SSepherosa Ziehau 	 HN_RXINFO_HASHVAL)
24215516c77SSepherosa Ziehau 
24315516c77SSepherosa Ziehau #define HN_NDIS_VLAN_INFO_INVALID	0xffffffff
24415516c77SSepherosa Ziehau #define HN_NDIS_RXCSUM_INFO_INVALID	0
24515516c77SSepherosa Ziehau #define HN_NDIS_HASH_INFO_INVALID	0
24615516c77SSepherosa Ziehau 
24715516c77SSepherosa Ziehau static int			hn_probe(device_t);
24815516c77SSepherosa Ziehau static int			hn_attach(device_t);
24915516c77SSepherosa Ziehau static int			hn_detach(device_t);
25015516c77SSepherosa Ziehau static int			hn_shutdown(device_t);
25115516c77SSepherosa Ziehau static void			hn_chan_callback(struct vmbus_channel *,
25215516c77SSepherosa Ziehau 				    void *);
25315516c77SSepherosa Ziehau 
25415516c77SSepherosa Ziehau static void			hn_init(void *);
25515516c77SSepherosa Ziehau static int			hn_ioctl(struct ifnet *, u_long, caddr_t);
25623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
25715516c77SSepherosa Ziehau static void			hn_start(struct ifnet *);
25823bf9e15SSepherosa Ziehau #endif
25915516c77SSepherosa Ziehau static int			hn_transmit(struct ifnet *, struct mbuf *);
26015516c77SSepherosa Ziehau static void			hn_xmit_qflush(struct ifnet *);
26115516c77SSepherosa Ziehau static int			hn_ifmedia_upd(struct ifnet *);
26215516c77SSepherosa Ziehau static void			hn_ifmedia_sts(struct ifnet *,
26315516c77SSepherosa Ziehau 				    struct ifmediareq *);
26415516c77SSepherosa Ziehau 
265499c3e17SSepherosa Ziehau static void			hn_ifnet_event(void *, struct ifnet *, int);
266499c3e17SSepherosa Ziehau static void			hn_ifaddr_event(void *, struct ifnet *);
267499c3e17SSepherosa Ziehau static void			hn_ifnet_attevent(void *, struct ifnet *);
268499c3e17SSepherosa Ziehau static void			hn_ifnet_detevent(void *, struct ifnet *);
2699c6cae24SSepherosa Ziehau static void			hn_ifnet_lnkevent(void *, struct ifnet *, int);
270499c3e17SSepherosa Ziehau 
271962f0357SSepherosa Ziehau static bool			hn_ismyvf(const struct hn_softc *,
272962f0357SSepherosa Ziehau 				    const struct ifnet *);
273962f0357SSepherosa Ziehau static void			hn_rxvf_change(struct hn_softc *,
274962f0357SSepherosa Ziehau 				    struct ifnet *, bool);
275962f0357SSepherosa Ziehau static void			hn_rxvf_set(struct hn_softc *, struct ifnet *);
276962f0357SSepherosa Ziehau static void			hn_rxvf_set_task(void *, int);
2779c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_input(struct ifnet *, struct mbuf *);
2789c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_iocsetflags(struct hn_softc *);
2799c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_iocsetcaps(struct hn_softc *,
2809c6cae24SSepherosa Ziehau 				    struct ifreq *);
2819c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_saveifflags(struct hn_softc *);
2829c6cae24SSepherosa Ziehau static bool			hn_xpnt_vf_isready(struct hn_softc *);
2839c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_setready(struct hn_softc *);
2849c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_init_taskfunc(void *, int);
2859c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_init(struct hn_softc *);
286a97fff19SSepherosa Ziehau static void			hn_xpnt_vf_setenable(struct hn_softc *);
287a97fff19SSepherosa Ziehau static void			hn_xpnt_vf_setdisable(struct hn_softc *, bool);
288642ec226SSepherosa Ziehau static void			hn_vf_rss_fixup(struct hn_softc *, bool);
289642ec226SSepherosa Ziehau static void			hn_vf_rss_restore(struct hn_softc *);
290962f0357SSepherosa Ziehau 
29115516c77SSepherosa Ziehau static int			hn_rndis_rxinfo(const void *, int,
29215516c77SSepherosa Ziehau 				    struct hn_rxinfo *);
29315516c77SSepherosa Ziehau static void			hn_rndis_rx_data(struct hn_rx_ring *,
29415516c77SSepherosa Ziehau 				    const void *, int);
29515516c77SSepherosa Ziehau static void			hn_rndis_rx_status(struct hn_softc *,
29615516c77SSepherosa Ziehau 				    const void *, int);
297b3b75d9cSSepherosa Ziehau static void			hn_rndis_init_fixat(struct hn_softc *, int);
29815516c77SSepherosa Ziehau 
29915516c77SSepherosa Ziehau static void			hn_nvs_handle_notify(struct hn_softc *,
30015516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
30115516c77SSepherosa Ziehau static void			hn_nvs_handle_comp(struct hn_softc *,
30215516c77SSepherosa Ziehau 				    struct vmbus_channel *,
30315516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
30415516c77SSepherosa Ziehau static void			hn_nvs_handle_rxbuf(struct hn_rx_ring *,
30515516c77SSepherosa Ziehau 				    struct vmbus_channel *,
30615516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
30715516c77SSepherosa Ziehau static void			hn_nvs_ack_rxbuf(struct hn_rx_ring *,
30815516c77SSepherosa Ziehau 				    struct vmbus_channel *, uint64_t);
30915516c77SSepherosa Ziehau 
31015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
31115516c77SSepherosa Ziehau static int			hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS);
31215516c77SSepherosa Ziehau static int			hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS);
31315516c77SSepherosa Ziehau #endif
31415516c77SSepherosa Ziehau static int			hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS);
31515516c77SSepherosa Ziehau static int			hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS);
31615516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
31715516c77SSepherosa Ziehau static int			hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS);
31815516c77SSepherosa Ziehau #else
31915516c77SSepherosa Ziehau static int			hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS);
32015516c77SSepherosa Ziehau #endif
32115516c77SSepherosa Ziehau static int			hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
32215516c77SSepherosa Ziehau static int			hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
32315516c77SSepherosa Ziehau static int			hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS);
32415516c77SSepherosa Ziehau static int			hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS);
32515516c77SSepherosa Ziehau static int			hn_caps_sysctl(SYSCTL_HANDLER_ARGS);
32615516c77SSepherosa Ziehau static int			hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS);
32715516c77SSepherosa Ziehau static int			hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS);
32834d68912SSepherosa Ziehau #ifndef RSS
32915516c77SSepherosa Ziehau static int			hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS);
33015516c77SSepherosa Ziehau static int			hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS);
33134d68912SSepherosa Ziehau #endif
33215516c77SSepherosa Ziehau static int			hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS);
333642ec226SSepherosa Ziehau static int			hn_rss_hcap_sysctl(SYSCTL_HANDLER_ARGS);
334642ec226SSepherosa Ziehau static int			hn_rss_mbuf_sysctl(SYSCTL_HANDLER_ARGS);
335dc13fee6SSepherosa Ziehau static int			hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS);
336dc13fee6SSepherosa Ziehau static int			hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS);
337dc13fee6SSepherosa Ziehau static int			hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS);
338dc13fee6SSepherosa Ziehau static int			hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS);
3396c1204dfSSepherosa Ziehau static int			hn_polling_sysctl(SYSCTL_HANDLER_ARGS);
34040d60d6eSDexuan Cui static int			hn_vf_sysctl(SYSCTL_HANDLER_ARGS);
341499c3e17SSepherosa Ziehau static int			hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS);
342499c3e17SSepherosa Ziehau static int			hn_vflist_sysctl(SYSCTL_HANDLER_ARGS);
343499c3e17SSepherosa Ziehau static int			hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS);
3449c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS);
3459c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS);
34615516c77SSepherosa Ziehau 
3475bdfd3fdSDexuan Cui static void			hn_stop(struct hn_softc *, bool);
34815516c77SSepherosa Ziehau static void			hn_init_locked(struct hn_softc *);
34915516c77SSepherosa Ziehau static int			hn_chan_attach(struct hn_softc *,
35015516c77SSepherosa Ziehau 				    struct vmbus_channel *);
35115516c77SSepherosa Ziehau static void			hn_chan_detach(struct hn_softc *,
35215516c77SSepherosa Ziehau 				    struct vmbus_channel *);
35315516c77SSepherosa Ziehau static int			hn_attach_subchans(struct hn_softc *);
35415516c77SSepherosa Ziehau static void			hn_detach_allchans(struct hn_softc *);
35515516c77SSepherosa Ziehau static void			hn_chan_rollup(struct hn_rx_ring *,
35615516c77SSepherosa Ziehau 				    struct hn_tx_ring *);
35715516c77SSepherosa Ziehau static void			hn_set_ring_inuse(struct hn_softc *, int);
35815516c77SSepherosa Ziehau static int			hn_synth_attach(struct hn_softc *, int);
35915516c77SSepherosa Ziehau static void			hn_synth_detach(struct hn_softc *);
36015516c77SSepherosa Ziehau static int			hn_synth_alloc_subchans(struct hn_softc *,
36115516c77SSepherosa Ziehau 				    int *);
3622494d735SSepherosa Ziehau static bool			hn_synth_attachable(const struct hn_softc *);
36315516c77SSepherosa Ziehau static void			hn_suspend(struct hn_softc *);
36415516c77SSepherosa Ziehau static void			hn_suspend_data(struct hn_softc *);
36515516c77SSepherosa Ziehau static void			hn_suspend_mgmt(struct hn_softc *);
36615516c77SSepherosa Ziehau static void			hn_resume(struct hn_softc *);
36715516c77SSepherosa Ziehau static void			hn_resume_data(struct hn_softc *);
36815516c77SSepherosa Ziehau static void			hn_resume_mgmt(struct hn_softc *);
36915516c77SSepherosa Ziehau static void			hn_suspend_mgmt_taskfunc(void *, int);
37025641fc7SSepherosa Ziehau static void			hn_chan_drain(struct hn_softc *,
37125641fc7SSepherosa Ziehau 				    struct vmbus_channel *);
372b3b75d9cSSepherosa Ziehau static void			hn_disable_rx(struct hn_softc *);
373b3b75d9cSSepherosa Ziehau static void			hn_drain_rxtx(struct hn_softc *, int);
3746c1204dfSSepherosa Ziehau static void			hn_polling(struct hn_softc *, u_int);
3756c1204dfSSepherosa Ziehau static void			hn_chan_polling(struct vmbus_channel *, u_int);
3769c6cae24SSepherosa Ziehau static void			hn_mtu_change_fixup(struct hn_softc *);
37715516c77SSepherosa Ziehau 
37815516c77SSepherosa Ziehau static void			hn_update_link_status(struct hn_softc *);
37915516c77SSepherosa Ziehau static void			hn_change_network(struct hn_softc *);
38015516c77SSepherosa Ziehau static void			hn_link_taskfunc(void *, int);
38115516c77SSepherosa Ziehau static void			hn_netchg_init_taskfunc(void *, int);
38215516c77SSepherosa Ziehau static void			hn_netchg_status_taskfunc(void *, int);
38315516c77SSepherosa Ziehau static void			hn_link_status(struct hn_softc *);
38415516c77SSepherosa Ziehau 
38515516c77SSepherosa Ziehau static int			hn_create_rx_data(struct hn_softc *, int);
38615516c77SSepherosa Ziehau static void			hn_destroy_rx_data(struct hn_softc *);
38715516c77SSepherosa Ziehau static int			hn_check_iplen(const struct mbuf *, int);
388db76829bSSepherosa Ziehau static void			hn_rxpkt_proto(const struct mbuf *, int *, int *);
389f1b0a43fSSepherosa Ziehau static int			hn_set_rxfilter(struct hn_softc *, uint32_t);
390c08f7b2cSSepherosa Ziehau static int			hn_rxfilter_config(struct hn_softc *);
39115516c77SSepherosa Ziehau static int			hn_rss_reconfig(struct hn_softc *);
392afd4971bSSepherosa Ziehau static void			hn_rss_ind_fixup(struct hn_softc *);
393642ec226SSepherosa Ziehau static void			hn_rss_mbuf_hash(struct hn_softc *, uint32_t);
39415516c77SSepherosa Ziehau static int			hn_rxpkt(struct hn_rx_ring *, const void *,
39515516c77SSepherosa Ziehau 				    int, const struct hn_rxinfo *);
396642ec226SSepherosa Ziehau static uint32_t			hn_rss_type_fromndis(uint32_t);
397642ec226SSepherosa Ziehau static uint32_t			hn_rss_type_tondis(uint32_t);
39815516c77SSepherosa Ziehau 
39915516c77SSepherosa Ziehau static int			hn_tx_ring_create(struct hn_softc *, int);
40015516c77SSepherosa Ziehau static void			hn_tx_ring_destroy(struct hn_tx_ring *);
40115516c77SSepherosa Ziehau static int			hn_create_tx_data(struct hn_softc *, int);
40215516c77SSepherosa Ziehau static void			hn_fixup_tx_data(struct hn_softc *);
403db76829bSSepherosa Ziehau static void			hn_fixup_rx_data(struct hn_softc *);
40415516c77SSepherosa Ziehau static void			hn_destroy_tx_data(struct hn_softc *);
40515516c77SSepherosa Ziehau static void			hn_txdesc_dmamap_destroy(struct hn_txdesc *);
40625641fc7SSepherosa Ziehau static void			hn_txdesc_gc(struct hn_tx_ring *,
40725641fc7SSepherosa Ziehau 				    struct hn_txdesc *);
408dc13fee6SSepherosa Ziehau static int			hn_encap(struct ifnet *, struct hn_tx_ring *,
40915516c77SSepherosa Ziehau 				    struct hn_txdesc *, struct mbuf **);
41015516c77SSepherosa Ziehau static int			hn_txpkt(struct ifnet *, struct hn_tx_ring *,
41115516c77SSepherosa Ziehau 				    struct hn_txdesc *);
41215516c77SSepherosa Ziehau static void			hn_set_chim_size(struct hn_softc *, int);
41315516c77SSepherosa Ziehau static void			hn_set_tso_maxsize(struct hn_softc *, int, int);
41415516c77SSepherosa Ziehau static bool			hn_tx_ring_pending(struct hn_tx_ring *);
41515516c77SSepherosa Ziehau static void			hn_tx_ring_qflush(struct hn_tx_ring *);
41615516c77SSepherosa Ziehau static void			hn_resume_tx(struct hn_softc *, int);
417dc13fee6SSepherosa Ziehau static void			hn_set_txagg(struct hn_softc *);
418dc13fee6SSepherosa Ziehau static void			*hn_try_txagg(struct ifnet *,
419dc13fee6SSepherosa Ziehau 				    struct hn_tx_ring *, struct hn_txdesc *,
420dc13fee6SSepherosa Ziehau 				    int);
42115516c77SSepherosa Ziehau static int			hn_get_txswq_depth(const struct hn_tx_ring *);
42215516c77SSepherosa Ziehau static void			hn_txpkt_done(struct hn_nvs_sendctx *,
42315516c77SSepherosa Ziehau 				    struct hn_softc *, struct vmbus_channel *,
42415516c77SSepherosa Ziehau 				    const void *, int);
42515516c77SSepherosa Ziehau static int			hn_txpkt_sglist(struct hn_tx_ring *,
42615516c77SSepherosa Ziehau 				    struct hn_txdesc *);
42715516c77SSepherosa Ziehau static int			hn_txpkt_chim(struct hn_tx_ring *,
42815516c77SSepherosa Ziehau 				    struct hn_txdesc *);
42915516c77SSepherosa Ziehau static int			hn_xmit(struct hn_tx_ring *, int);
43015516c77SSepherosa Ziehau static void			hn_xmit_taskfunc(void *, int);
43115516c77SSepherosa Ziehau static void			hn_xmit_txeof(struct hn_tx_ring *);
43215516c77SSepherosa Ziehau static void			hn_xmit_txeof_taskfunc(void *, int);
43323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
43415516c77SSepherosa Ziehau static int			hn_start_locked(struct hn_tx_ring *, int);
43515516c77SSepherosa Ziehau static void			hn_start_taskfunc(void *, int);
43615516c77SSepherosa Ziehau static void			hn_start_txeof(struct hn_tx_ring *);
43715516c77SSepherosa Ziehau static void			hn_start_txeof_taskfunc(void *, int);
43823bf9e15SSepherosa Ziehau #endif
43915516c77SSepherosa Ziehau 
44015516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
44115516c77SSepherosa Ziehau     "Hyper-V network interface");
44215516c77SSepherosa Ziehau 
44315516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */
44415516c77SSepherosa Ziehau static int			hn_trust_hosttcp = 1;
44515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN,
44615516c77SSepherosa Ziehau     &hn_trust_hosttcp, 0,
44715516c77SSepherosa Ziehau     "Trust tcp segement verification on host side, "
44815516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
44915516c77SSepherosa Ziehau 
45015516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */
45115516c77SSepherosa Ziehau static int			hn_trust_hostudp = 1;
45215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN,
45315516c77SSepherosa Ziehau     &hn_trust_hostudp, 0,
45415516c77SSepherosa Ziehau     "Trust udp datagram verification on host side, "
45515516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
45615516c77SSepherosa Ziehau 
45715516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */
45815516c77SSepherosa Ziehau static int			hn_trust_hostip = 1;
45915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN,
46015516c77SSepherosa Ziehau     &hn_trust_hostip, 0,
46115516c77SSepherosa Ziehau     "Trust ip packet verification on host side, "
46215516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
46315516c77SSepherosa Ziehau 
4642be266caSSepherosa Ziehau /*
4652be266caSSepherosa Ziehau  * Offload UDP/IPv4 checksum.
4662be266caSSepherosa Ziehau  */
4672be266caSSepherosa Ziehau static int			hn_enable_udp4cs = 1;
4682be266caSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, enable_udp4cs, CTLFLAG_RDTUN,
4692be266caSSepherosa Ziehau     &hn_enable_udp4cs, 0, "Offload UDP/IPv4 checksum");
4702be266caSSepherosa Ziehau 
4712be266caSSepherosa Ziehau /*
4722be266caSSepherosa Ziehau  * Offload UDP/IPv6 checksum.
4732be266caSSepherosa Ziehau  */
4742be266caSSepherosa Ziehau static int			hn_enable_udp6cs = 1;
4752be266caSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, enable_udp6cs, CTLFLAG_RDTUN,
4762be266caSSepherosa Ziehau     &hn_enable_udp6cs, 0, "Offload UDP/IPv6 checksum");
4772be266caSSepherosa Ziehau 
4782be266caSSepherosa Ziehau /* Stats. */
4792be266caSSepherosa Ziehau static counter_u64_t		hn_udpcs_fixup;
4802be266caSSepherosa Ziehau SYSCTL_COUNTER_U64(_hw_hn, OID_AUTO, udpcs_fixup, CTLFLAG_RW,
4812be266caSSepherosa Ziehau     &hn_udpcs_fixup, "# of UDP checksum fixup");
4822be266caSSepherosa Ziehau 
4832be266caSSepherosa Ziehau /*
4842be266caSSepherosa Ziehau  * See hn_set_hlen().
4852be266caSSepherosa Ziehau  *
4862be266caSSepherosa Ziehau  * This value is for Azure.  For Hyper-V, set this above
4872be266caSSepherosa Ziehau  * 65536 to disable UDP datagram checksum fixup.
4882be266caSSepherosa Ziehau  */
4892be266caSSepherosa Ziehau static int			hn_udpcs_fixup_mtu = 1420;
4902be266caSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, udpcs_fixup_mtu, CTLFLAG_RWTUN,
4912be266caSSepherosa Ziehau     &hn_udpcs_fixup_mtu, 0, "UDP checksum fixup MTU threshold");
4922be266caSSepherosa Ziehau 
49315516c77SSepherosa Ziehau /* Limit TSO burst size */
49415516c77SSepherosa Ziehau static int			hn_tso_maxlen = IP_MAXPACKET;
49515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN,
49615516c77SSepherosa Ziehau     &hn_tso_maxlen, 0, "TSO burst limit");
49715516c77SSepherosa Ziehau 
49815516c77SSepherosa Ziehau /* Limit chimney send size */
49915516c77SSepherosa Ziehau static int			hn_tx_chimney_size = 0;
50015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN,
50115516c77SSepherosa Ziehau     &hn_tx_chimney_size, 0, "Chimney send packet size limit");
50215516c77SSepherosa Ziehau 
50315516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */
50415516c77SSepherosa Ziehau static int			hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF;
50515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN,
50615516c77SSepherosa Ziehau     &hn_direct_tx_size, 0, "Size of the packet for direct transmission");
50715516c77SSepherosa Ziehau 
50815516c77SSepherosa Ziehau /* # of LRO entries per RX ring */
50915516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
51015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
51115516c77SSepherosa Ziehau static int			hn_lro_entry_count = HN_LROENT_CNT_DEF;
51215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN,
51315516c77SSepherosa Ziehau     &hn_lro_entry_count, 0, "LRO entry count");
51415516c77SSepherosa Ziehau #endif
51515516c77SSepherosa Ziehau #endif
51615516c77SSepherosa Ziehau 
517fdd0222aSSepherosa Ziehau static int			hn_tx_taskq_cnt = 1;
518fdd0222aSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_cnt, CTLFLAG_RDTUN,
519fdd0222aSSepherosa Ziehau     &hn_tx_taskq_cnt, 0, "# of TX taskqueues");
520fdd0222aSSepherosa Ziehau 
5210e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_INDEP	0
5220e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_GLOBAL	1
5230e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_EVTTQ	2
5240e11868dSSepherosa Ziehau 
5250e11868dSSepherosa Ziehau static int			hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
5260e11868dSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_mode, CTLFLAG_RDTUN,
5270e11868dSSepherosa Ziehau     &hn_tx_taskq_mode, 0, "TX taskqueue modes: "
5280e11868dSSepherosa Ziehau     "0 - independent, 1 - share global tx taskqs, 2 - share event taskqs");
5290e11868dSSepherosa Ziehau 
53015516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
53115516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 0;
53215516c77SSepherosa Ziehau #else
53315516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 1;
53415516c77SSepherosa Ziehau #endif
53515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD,
53615516c77SSepherosa Ziehau     &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors");
53715516c77SSepherosa Ziehau 
53823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
53915516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */
54015516c77SSepherosa Ziehau static int			hn_use_if_start = 0;
54115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN,
54215516c77SSepherosa Ziehau     &hn_use_if_start, 0, "Use if_start TX method");
54323bf9e15SSepherosa Ziehau #endif
54415516c77SSepherosa Ziehau 
54515516c77SSepherosa Ziehau /* # of channels to use */
54615516c77SSepherosa Ziehau static int			hn_chan_cnt = 0;
54715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN,
54815516c77SSepherosa Ziehau     &hn_chan_cnt, 0,
54915516c77SSepherosa Ziehau     "# of channels to use; each channel has one RX ring and one TX ring");
55015516c77SSepherosa Ziehau 
55115516c77SSepherosa Ziehau /* # of transmit rings to use */
55215516c77SSepherosa Ziehau static int			hn_tx_ring_cnt = 0;
55315516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN,
55415516c77SSepherosa Ziehau     &hn_tx_ring_cnt, 0, "# of TX rings to use");
55515516c77SSepherosa Ziehau 
55615516c77SSepherosa Ziehau /* Software TX ring deptch */
55715516c77SSepherosa Ziehau static int			hn_tx_swq_depth = 0;
55815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN,
55915516c77SSepherosa Ziehau     &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING");
56015516c77SSepherosa Ziehau 
56115516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */
56215516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
56315516c77SSepherosa Ziehau static u_int			hn_lro_mbufq_depth = 0;
56415516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN,
56515516c77SSepherosa Ziehau     &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue");
56615516c77SSepherosa Ziehau #endif
56715516c77SSepherosa Ziehau 
568dc13fee6SSepherosa Ziehau /* Packet transmission aggregation size limit */
569dc13fee6SSepherosa Ziehau static int			hn_tx_agg_size = -1;
570dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN,
571dc13fee6SSepherosa Ziehau     &hn_tx_agg_size, 0, "Packet transmission aggregation size limit");
572dc13fee6SSepherosa Ziehau 
573dc13fee6SSepherosa Ziehau /* Packet transmission aggregation count limit */
574fa915c4dSSepherosa Ziehau static int			hn_tx_agg_pkts = -1;
575dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN,
576dc13fee6SSepherosa Ziehau     &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit");
577dc13fee6SSepherosa Ziehau 
578499c3e17SSepherosa Ziehau /* VF list */
579499c3e17SSepherosa Ziehau SYSCTL_PROC(_hw_hn, OID_AUTO, vflist, CTLFLAG_RD | CTLTYPE_STRING,
580499c3e17SSepherosa Ziehau     0, 0, hn_vflist_sysctl, "A", "VF list");
581499c3e17SSepherosa Ziehau 
582499c3e17SSepherosa Ziehau /* VF mapping */
583499c3e17SSepherosa Ziehau SYSCTL_PROC(_hw_hn, OID_AUTO, vfmap, CTLFLAG_RD | CTLTYPE_STRING,
584499c3e17SSepherosa Ziehau     0, 0, hn_vfmap_sysctl, "A", "VF mapping");
585499c3e17SSepherosa Ziehau 
5869c6cae24SSepherosa Ziehau /* Transparent VF */
587*78e46963SSepherosa Ziehau static int			hn_xpnt_vf = 1;
5889c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_transparent, CTLFLAG_RDTUN,
5899c6cae24SSepherosa Ziehau     &hn_xpnt_vf, 0, "Transparent VF mod");
5909c6cae24SSepherosa Ziehau 
5919c6cae24SSepherosa Ziehau /* Accurate BPF support for Transparent VF */
5929c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_accbpf = 0;
5939c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_xpnt_accbpf, CTLFLAG_RDTUN,
5949c6cae24SSepherosa Ziehau     &hn_xpnt_vf_accbpf, 0, "Accurate BPF for transparent VF");
5959c6cae24SSepherosa Ziehau 
5969c6cae24SSepherosa Ziehau /* Extra wait for transparent VF attach routing; unit seconds. */
5979c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN;
5989c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_xpnt_attwait, CTLFLAG_RWTUN,
5999c6cae24SSepherosa Ziehau     &hn_xpnt_vf_attwait, 0,
6009c6cae24SSepherosa Ziehau     "Extra wait for transparent VF attach routing; unit: seconds");
6019c6cae24SSepherosa Ziehau 
60215516c77SSepherosa Ziehau static u_int			hn_cpu_index;	/* next CPU for channel */
603fdd0222aSSepherosa Ziehau static struct taskqueue		**hn_tx_taskque;/* shared TX taskqueues */
60415516c77SSepherosa Ziehau 
605499c3e17SSepherosa Ziehau static struct rmlock		hn_vfmap_lock;
606499c3e17SSepherosa Ziehau static int			hn_vfmap_size;
607499c3e17SSepherosa Ziehau static struct ifnet		**hn_vfmap;
608499c3e17SSepherosa Ziehau 
60934d68912SSepherosa Ziehau #ifndef RSS
61015516c77SSepherosa Ziehau static const uint8_t
61115516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
61215516c77SSepherosa Ziehau 	0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
61315516c77SSepherosa Ziehau 	0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
61415516c77SSepherosa Ziehau 	0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
61515516c77SSepherosa Ziehau 	0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
61615516c77SSepherosa Ziehau 	0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
61715516c77SSepherosa Ziehau };
61834d68912SSepherosa Ziehau #endif	/* !RSS */
61915516c77SSepherosa Ziehau 
620c2d50b26SSepherosa Ziehau static const struct hyperv_guid	hn_guid = {
621c2d50b26SSepherosa Ziehau 	.hv_guid = {
622c2d50b26SSepherosa Ziehau 	    0x63, 0x51, 0x61, 0xf8, 0x3e, 0xdf, 0xc5, 0x46,
623c2d50b26SSepherosa Ziehau 	    0x91, 0x3f, 0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e }
624c2d50b26SSepherosa Ziehau };
625c2d50b26SSepherosa Ziehau 
62615516c77SSepherosa Ziehau static device_method_t hn_methods[] = {
62715516c77SSepherosa Ziehau 	/* Device interface */
62815516c77SSepherosa Ziehau 	DEVMETHOD(device_probe,		hn_probe),
62915516c77SSepherosa Ziehau 	DEVMETHOD(device_attach,	hn_attach),
63015516c77SSepherosa Ziehau 	DEVMETHOD(device_detach,	hn_detach),
63115516c77SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	hn_shutdown),
63215516c77SSepherosa Ziehau 	DEVMETHOD_END
63315516c77SSepherosa Ziehau };
63415516c77SSepherosa Ziehau 
63515516c77SSepherosa Ziehau static driver_t hn_driver = {
63615516c77SSepherosa Ziehau 	"hn",
63715516c77SSepherosa Ziehau 	hn_methods,
63815516c77SSepherosa Ziehau 	sizeof(struct hn_softc)
63915516c77SSepherosa Ziehau };
64015516c77SSepherosa Ziehau 
64115516c77SSepherosa Ziehau static devclass_t hn_devclass;
64215516c77SSepherosa Ziehau 
64315516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0);
64415516c77SSepherosa Ziehau MODULE_VERSION(hn, 1);
64515516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1);
64615516c77SSepherosa Ziehau 
64715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
64815516c77SSepherosa Ziehau static void
64915516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim)
65015516c77SSepherosa Ziehau {
65115516c77SSepherosa Ziehau 	int i;
65215516c77SSepherosa Ziehau 
653a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
65415516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim;
65515516c77SSepherosa Ziehau }
65615516c77SSepherosa Ziehau #endif
65715516c77SSepherosa Ziehau 
65815516c77SSepherosa Ziehau static int
65915516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd)
66015516c77SSepherosa Ziehau {
66115516c77SSepherosa Ziehau 
66215516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
66315516c77SSepherosa Ziehau 	    txd->chim_size == 0, ("invalid rndis sglist txd"));
66415516c77SSepherosa Ziehau 	return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA,
66515516c77SSepherosa Ziehau 	    &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt));
66615516c77SSepherosa Ziehau }
66715516c77SSepherosa Ziehau 
66815516c77SSepherosa Ziehau static int
66915516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd)
67015516c77SSepherosa Ziehau {
67115516c77SSepherosa Ziehau 	struct hn_nvs_rndis rndis;
67215516c77SSepherosa Ziehau 
67315516c77SSepherosa Ziehau 	KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID &&
67415516c77SSepherosa Ziehau 	    txd->chim_size > 0, ("invalid rndis chim txd"));
67515516c77SSepherosa Ziehau 
67615516c77SSepherosa Ziehau 	rndis.nvs_type = HN_NVS_TYPE_RNDIS;
67715516c77SSepherosa Ziehau 	rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA;
67815516c77SSepherosa Ziehau 	rndis.nvs_chim_idx = txd->chim_index;
67915516c77SSepherosa Ziehau 	rndis.nvs_chim_sz = txd->chim_size;
68015516c77SSepherosa Ziehau 
68115516c77SSepherosa Ziehau 	return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC,
68215516c77SSepherosa Ziehau 	    &rndis, sizeof(rndis), &txd->send_ctx));
68315516c77SSepherosa Ziehau }
68415516c77SSepherosa Ziehau 
68515516c77SSepherosa Ziehau static __inline uint32_t
68615516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc)
68715516c77SSepherosa Ziehau {
68815516c77SSepherosa Ziehau 	int i, bmap_cnt = sc->hn_chim_bmap_cnt;
68915516c77SSepherosa Ziehau 	u_long *bmap = sc->hn_chim_bmap;
69015516c77SSepherosa Ziehau 	uint32_t ret = HN_NVS_CHIM_IDX_INVALID;
69115516c77SSepherosa Ziehau 
69215516c77SSepherosa Ziehau 	for (i = 0; i < bmap_cnt; ++i) {
69315516c77SSepherosa Ziehau 		int idx;
69415516c77SSepherosa Ziehau 
69515516c77SSepherosa Ziehau 		idx = ffsl(~bmap[i]);
69615516c77SSepherosa Ziehau 		if (idx == 0)
69715516c77SSepherosa Ziehau 			continue;
69815516c77SSepherosa Ziehau 
69915516c77SSepherosa Ziehau 		--idx; /* ffsl is 1-based */
70015516c77SSepherosa Ziehau 		KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt,
70115516c77SSepherosa Ziehau 		    ("invalid i %d and idx %d", i, idx));
70215516c77SSepherosa Ziehau 
70315516c77SSepherosa Ziehau 		if (atomic_testandset_long(&bmap[i], idx))
70415516c77SSepherosa Ziehau 			continue;
70515516c77SSepherosa Ziehau 
70615516c77SSepherosa Ziehau 		ret = i * LONG_BIT + idx;
70715516c77SSepherosa Ziehau 		break;
70815516c77SSepherosa Ziehau 	}
70915516c77SSepherosa Ziehau 	return (ret);
71015516c77SSepherosa Ziehau }
71115516c77SSepherosa Ziehau 
71215516c77SSepherosa Ziehau static __inline void
71315516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx)
71415516c77SSepherosa Ziehau {
71515516c77SSepherosa Ziehau 	u_long mask;
71615516c77SSepherosa Ziehau 	uint32_t idx;
71715516c77SSepherosa Ziehau 
71815516c77SSepherosa Ziehau 	idx = chim_idx / LONG_BIT;
71915516c77SSepherosa Ziehau 	KASSERT(idx < sc->hn_chim_bmap_cnt,
72015516c77SSepherosa Ziehau 	    ("invalid chimney index 0x%x", chim_idx));
72115516c77SSepherosa Ziehau 
72215516c77SSepherosa Ziehau 	mask = 1UL << (chim_idx % LONG_BIT);
72315516c77SSepherosa Ziehau 	KASSERT(sc->hn_chim_bmap[idx] & mask,
72415516c77SSepherosa Ziehau 	    ("index bitmap 0x%lx, chimney index %u, "
72515516c77SSepherosa Ziehau 	     "bitmap idx %d, bitmask 0x%lx",
72615516c77SSepherosa Ziehau 	     sc->hn_chim_bmap[idx], chim_idx, idx, mask));
72715516c77SSepherosa Ziehau 
72815516c77SSepherosa Ziehau 	atomic_clear_long(&sc->hn_chim_bmap[idx], mask);
72915516c77SSepherosa Ziehau }
73015516c77SSepherosa Ziehau 
731edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
732cc0c6ebcSSepherosa Ziehau 
733cc0c6ebcSSepherosa Ziehau #define PULLUP_HDR(m, len)				\
734cc0c6ebcSSepherosa Ziehau do {							\
735cc0c6ebcSSepherosa Ziehau 	if (__predict_false((m)->m_len < (len))) {	\
736cc0c6ebcSSepherosa Ziehau 		(m) = m_pullup((m), (len));		\
737cc0c6ebcSSepherosa Ziehau 		if ((m) == NULL)			\
738cc0c6ebcSSepherosa Ziehau 			return (NULL);			\
739cc0c6ebcSSepherosa Ziehau 	}						\
740cc0c6ebcSSepherosa Ziehau } while (0)
741cc0c6ebcSSepherosa Ziehau 
742edd3f315SSepherosa Ziehau /*
743edd3f315SSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
744edd3f315SSepherosa Ziehau  */
745edd3f315SSepherosa Ziehau static __inline struct mbuf *
746edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head)
747edd3f315SSepherosa Ziehau {
748edd3f315SSepherosa Ziehau 	struct ether_vlan_header *evl;
749edd3f315SSepherosa Ziehau 	struct tcphdr *th;
750edd3f315SSepherosa Ziehau 	int ehlen;
751edd3f315SSepherosa Ziehau 
752edd3f315SSepherosa Ziehau 	KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable"));
753edd3f315SSepherosa Ziehau 
754edd3f315SSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
755edd3f315SSepherosa Ziehau 	evl = mtod(m_head, struct ether_vlan_header *);
756edd3f315SSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
757edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
758edd3f315SSepherosa Ziehau 	else
759edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
760c49d47daSSepherosa Ziehau 	m_head->m_pkthdr.l2hlen = ehlen;
761edd3f315SSepherosa Ziehau 
762edd3f315SSepherosa Ziehau #ifdef INET
763edd3f315SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
764edd3f315SSepherosa Ziehau 		struct ip *ip;
765edd3f315SSepherosa Ziehau 		int iphlen;
766edd3f315SSepherosa Ziehau 
767edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
768edd3f315SSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
769edd3f315SSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
770c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = iphlen;
771edd3f315SSepherosa Ziehau 
772edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
773edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + iphlen);
774edd3f315SSepherosa Ziehau 
775edd3f315SSepherosa Ziehau 		ip->ip_len = 0;
776edd3f315SSepherosa Ziehau 		ip->ip_sum = 0;
777edd3f315SSepherosa Ziehau 		th->th_sum = in_pseudo(ip->ip_src.s_addr,
778edd3f315SSepherosa Ziehau 		    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
779edd3f315SSepherosa Ziehau 	}
780edd3f315SSepherosa Ziehau #endif
781edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET)
782edd3f315SSepherosa Ziehau 	else
783edd3f315SSepherosa Ziehau #endif
784edd3f315SSepherosa Ziehau #ifdef INET6
785edd3f315SSepherosa Ziehau 	{
786edd3f315SSepherosa Ziehau 		struct ip6_hdr *ip6;
787edd3f315SSepherosa Ziehau 
788edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
789edd3f315SSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
790edd3f315SSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP) {
791edd3f315SSepherosa Ziehau 			m_freem(m_head);
792edd3f315SSepherosa Ziehau 			return (NULL);
793edd3f315SSepherosa Ziehau 		}
794c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = sizeof(*ip6);
795edd3f315SSepherosa Ziehau 
796edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
797edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + sizeof(*ip6));
798edd3f315SSepherosa Ziehau 
799edd3f315SSepherosa Ziehau 		ip6->ip6_plen = 0;
800edd3f315SSepherosa Ziehau 		th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
801edd3f315SSepherosa Ziehau 	}
802edd3f315SSepherosa Ziehau #endif
803edd3f315SSepherosa Ziehau 	return (m_head);
804edd3f315SSepherosa Ziehau }
805cc0c6ebcSSepherosa Ziehau 
806cc0c6ebcSSepherosa Ziehau /*
807cc0c6ebcSSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
808cc0c6ebcSSepherosa Ziehau  */
809cc0c6ebcSSepherosa Ziehau static __inline struct mbuf *
810c49d47daSSepherosa Ziehau hn_set_hlen(struct mbuf *m_head)
811cc0c6ebcSSepherosa Ziehau {
812cc0c6ebcSSepherosa Ziehau 	const struct ether_vlan_header *evl;
813cc0c6ebcSSepherosa Ziehau 	int ehlen;
814cc0c6ebcSSepherosa Ziehau 
815cc0c6ebcSSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
816cc0c6ebcSSepherosa Ziehau 	evl = mtod(m_head, const struct ether_vlan_header *);
817cc0c6ebcSSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
818cc0c6ebcSSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
819cc0c6ebcSSepherosa Ziehau 	else
820cc0c6ebcSSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
821c49d47daSSepherosa Ziehau 	m_head->m_pkthdr.l2hlen = ehlen;
822cc0c6ebcSSepherosa Ziehau 
823cc0c6ebcSSepherosa Ziehau #ifdef INET
824c49d47daSSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP_UDP)) {
825cc0c6ebcSSepherosa Ziehau 		const struct ip *ip;
826cc0c6ebcSSepherosa Ziehau 		int iphlen;
827cc0c6ebcSSepherosa Ziehau 
828cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
829cc0c6ebcSSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
830cc0c6ebcSSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
831c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = iphlen;
8322be266caSSepherosa Ziehau 
8332be266caSSepherosa Ziehau 		/*
8342be266caSSepherosa Ziehau 		 * UDP checksum offload does not work in Azure, if the
8352be266caSSepherosa Ziehau 		 * following conditions meet:
8362be266caSSepherosa Ziehau 		 * - sizeof(IP hdr + UDP hdr + payload) > 1420.
8372be266caSSepherosa Ziehau 		 * - IP_DF is not set in the IP hdr.
8382be266caSSepherosa Ziehau 		 *
8392be266caSSepherosa Ziehau 		 * Fallback to software checksum for these UDP datagrams.
8402be266caSSepherosa Ziehau 		 */
8412be266caSSepherosa Ziehau 		if ((m_head->m_pkthdr.csum_flags & CSUM_IP_UDP) &&
8422be266caSSepherosa Ziehau 		    m_head->m_pkthdr.len > hn_udpcs_fixup_mtu + ehlen &&
8432be266caSSepherosa Ziehau 		    (ntohs(ip->ip_off) & IP_DF) == 0) {
8442be266caSSepherosa Ziehau 			uint16_t off = ehlen + iphlen;
8452be266caSSepherosa Ziehau 
8462be266caSSepherosa Ziehau 			counter_u64_add(hn_udpcs_fixup, 1);
8472be266caSSepherosa Ziehau 			PULLUP_HDR(m_head, off + sizeof(struct udphdr));
8482be266caSSepherosa Ziehau 			*(uint16_t *)(m_head->m_data + off +
8492be266caSSepherosa Ziehau                             m_head->m_pkthdr.csum_data) = in_cksum_skip(
8502be266caSSepherosa Ziehau 			    m_head, m_head->m_pkthdr.len, off);
8512be266caSSepherosa Ziehau 			m_head->m_pkthdr.csum_flags &= ~CSUM_IP_UDP;
8522be266caSSepherosa Ziehau 		}
853cc0c6ebcSSepherosa Ziehau 	}
854cc0c6ebcSSepherosa Ziehau #endif
855cc0c6ebcSSepherosa Ziehau #if defined(INET6) && defined(INET)
856cc0c6ebcSSepherosa Ziehau 	else
857cc0c6ebcSSepherosa Ziehau #endif
858cc0c6ebcSSepherosa Ziehau #ifdef INET6
859cc0c6ebcSSepherosa Ziehau 	{
860cc0c6ebcSSepherosa Ziehau 		const struct ip6_hdr *ip6;
861cc0c6ebcSSepherosa Ziehau 
862cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
863cc0c6ebcSSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
864c49d47daSSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP) {
865c49d47daSSepherosa Ziehau 			m_freem(m_head);
866c49d47daSSepherosa Ziehau 			return (NULL);
867c49d47daSSepherosa Ziehau 		}
868c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = sizeof(*ip6);
869cc0c6ebcSSepherosa Ziehau 	}
870cc0c6ebcSSepherosa Ziehau #endif
871cc0c6ebcSSepherosa Ziehau 	return (m_head);
872cc0c6ebcSSepherosa Ziehau }
873cc0c6ebcSSepherosa Ziehau 
874c49d47daSSepherosa Ziehau /*
875c49d47daSSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
876c49d47daSSepherosa Ziehau  */
877c49d47daSSepherosa Ziehau static __inline struct mbuf *
878c49d47daSSepherosa Ziehau hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn)
879c49d47daSSepherosa Ziehau {
880c49d47daSSepherosa Ziehau 	const struct tcphdr *th;
881c49d47daSSepherosa Ziehau 	int ehlen, iphlen;
882c49d47daSSepherosa Ziehau 
883c49d47daSSepherosa Ziehau 	*tcpsyn = 0;
884c49d47daSSepherosa Ziehau 	ehlen = m_head->m_pkthdr.l2hlen;
885c49d47daSSepherosa Ziehau 	iphlen = m_head->m_pkthdr.l3hlen;
886c49d47daSSepherosa Ziehau 
887c49d47daSSepherosa Ziehau 	PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
888c49d47daSSepherosa Ziehau 	th = mtodo(m_head, ehlen + iphlen);
889c49d47daSSepherosa Ziehau 	if (th->th_flags & TH_SYN)
890c49d47daSSepherosa Ziehau 		*tcpsyn = 1;
891c49d47daSSepherosa Ziehau 	return (m_head);
892c49d47daSSepherosa Ziehau }
893c49d47daSSepherosa Ziehau 
894cc0c6ebcSSepherosa Ziehau #undef PULLUP_HDR
895cc0c6ebcSSepherosa Ziehau 
896edd3f315SSepherosa Ziehau #endif	/* INET6 || INET */
897edd3f315SSepherosa Ziehau 
89815516c77SSepherosa Ziehau static int
899f1b0a43fSSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc, uint32_t filter)
900f1b0a43fSSepherosa Ziehau {
901f1b0a43fSSepherosa Ziehau 	int error = 0;
902f1b0a43fSSepherosa Ziehau 
903f1b0a43fSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
904f1b0a43fSSepherosa Ziehau 
905f1b0a43fSSepherosa Ziehau 	if (sc->hn_rx_filter != filter) {
906f1b0a43fSSepherosa Ziehau 		error = hn_rndis_set_rxfilter(sc, filter);
907f1b0a43fSSepherosa Ziehau 		if (!error)
908f1b0a43fSSepherosa Ziehau 			sc->hn_rx_filter = filter;
909f1b0a43fSSepherosa Ziehau 	}
910f1b0a43fSSepherosa Ziehau 	return (error);
911f1b0a43fSSepherosa Ziehau }
912f1b0a43fSSepherosa Ziehau 
913f1b0a43fSSepherosa Ziehau static int
914c08f7b2cSSepherosa Ziehau hn_rxfilter_config(struct hn_softc *sc)
91515516c77SSepherosa Ziehau {
91615516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
91715516c77SSepherosa Ziehau 	uint32_t filter;
91815516c77SSepherosa Ziehau 
91915516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
92015516c77SSepherosa Ziehau 
9219c6cae24SSepherosa Ziehau 	/*
9229c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, we don't know how
9239c6cae24SSepherosa Ziehau 	 * its RX filter is configured, so stick the synthetic device in
9249c6cae24SSepherosa Ziehau 	 * the promiscous mode.
9259c6cae24SSepherosa Ziehau 	 */
9269c6cae24SSepherosa Ziehau 	if ((ifp->if_flags & IFF_PROMISC) || (sc->hn_flags & HN_FLAG_RXVF)) {
92715516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_PROMISCUOUS;
92815516c77SSepherosa Ziehau 	} else {
92915516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_DIRECTED;
93015516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_BROADCAST)
93115516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_BROADCAST;
93215516c77SSepherosa Ziehau 		/* TODO: support multicast list */
93315516c77SSepherosa Ziehau 		if ((ifp->if_flags & IFF_ALLMULTI) ||
93415516c77SSepherosa Ziehau 		    !TAILQ_EMPTY(&ifp->if_multiaddrs))
93515516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
93615516c77SSepherosa Ziehau 	}
937f1b0a43fSSepherosa Ziehau 	return (hn_set_rxfilter(sc, filter));
93815516c77SSepherosa Ziehau }
93915516c77SSepherosa Ziehau 
940dc13fee6SSepherosa Ziehau static void
941dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc)
942dc13fee6SSepherosa Ziehau {
943dc13fee6SSepherosa Ziehau 	uint32_t size, pkts;
944dc13fee6SSepherosa Ziehau 	int i;
945dc13fee6SSepherosa Ziehau 
946dc13fee6SSepherosa Ziehau 	/*
947dc13fee6SSepherosa Ziehau 	 * Setup aggregation size.
948dc13fee6SSepherosa Ziehau 	 */
949dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_size < 0)
950dc13fee6SSepherosa Ziehau 		size = UINT32_MAX;
951dc13fee6SSepherosa Ziehau 	else
952dc13fee6SSepherosa Ziehau 		size = sc->hn_agg_size;
953dc13fee6SSepherosa Ziehau 
954dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_size < size)
955dc13fee6SSepherosa Ziehau 		size = sc->hn_rndis_agg_size;
956dc13fee6SSepherosa Ziehau 
957a4364cfeSSepherosa Ziehau 	/* NOTE: We only aggregate packets using chimney sending buffers. */
958a4364cfeSSepherosa Ziehau 	if (size > (uint32_t)sc->hn_chim_szmax)
959a4364cfeSSepherosa Ziehau 		size = sc->hn_chim_szmax;
960a4364cfeSSepherosa Ziehau 
961dc13fee6SSepherosa Ziehau 	if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) {
962dc13fee6SSepherosa Ziehau 		/* Disable */
963dc13fee6SSepherosa Ziehau 		size = 0;
964dc13fee6SSepherosa Ziehau 		pkts = 0;
965dc13fee6SSepherosa Ziehau 		goto done;
966dc13fee6SSepherosa Ziehau 	}
967dc13fee6SSepherosa Ziehau 
968dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'int'. */
969dc13fee6SSepherosa Ziehau 	if (size > INT_MAX)
970dc13fee6SSepherosa Ziehau 		size = INT_MAX;
971dc13fee6SSepherosa Ziehau 
972dc13fee6SSepherosa Ziehau 	/*
973dc13fee6SSepherosa Ziehau 	 * Setup aggregation packet count.
974dc13fee6SSepherosa Ziehau 	 */
975dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_pkts < 0)
976dc13fee6SSepherosa Ziehau 		pkts = UINT32_MAX;
977dc13fee6SSepherosa Ziehau 	else
978dc13fee6SSepherosa Ziehau 		pkts = sc->hn_agg_pkts;
979dc13fee6SSepherosa Ziehau 
980dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_pkts < pkts)
981dc13fee6SSepherosa Ziehau 		pkts = sc->hn_rndis_agg_pkts;
982dc13fee6SSepherosa Ziehau 
983dc13fee6SSepherosa Ziehau 	if (pkts <= 1) {
984dc13fee6SSepherosa Ziehau 		/* Disable */
985dc13fee6SSepherosa Ziehau 		size = 0;
986dc13fee6SSepherosa Ziehau 		pkts = 0;
987dc13fee6SSepherosa Ziehau 		goto done;
988dc13fee6SSepherosa Ziehau 	}
989dc13fee6SSepherosa Ziehau 
990dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
991dc13fee6SSepherosa Ziehau 	if (pkts > SHRT_MAX)
992dc13fee6SSepherosa Ziehau 		pkts = SHRT_MAX;
993dc13fee6SSepherosa Ziehau 
994dc13fee6SSepherosa Ziehau done:
995dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
996dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_align > SHRT_MAX) {
997dc13fee6SSepherosa Ziehau 		/* Disable */
998dc13fee6SSepherosa Ziehau 		size = 0;
999dc13fee6SSepherosa Ziehau 		pkts = 0;
1000dc13fee6SSepherosa Ziehau 	}
1001dc13fee6SSepherosa Ziehau 
1002dc13fee6SSepherosa Ziehau 	if (bootverbose) {
1003dc13fee6SSepherosa Ziehau 		if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n",
1004dc13fee6SSepherosa Ziehau 		    size, pkts, sc->hn_rndis_agg_align);
1005dc13fee6SSepherosa Ziehau 	}
1006dc13fee6SSepherosa Ziehau 
1007dc13fee6SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
1008dc13fee6SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
1009dc13fee6SSepherosa Ziehau 
1010dc13fee6SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
1011dc13fee6SSepherosa Ziehau 		txr->hn_agg_szmax = size;
1012dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktmax = pkts;
1013dc13fee6SSepherosa Ziehau 		txr->hn_agg_align = sc->hn_rndis_agg_align;
1014dc13fee6SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
1015dc13fee6SSepherosa Ziehau 	}
1016dc13fee6SSepherosa Ziehau }
1017dc13fee6SSepherosa Ziehau 
101815516c77SSepherosa Ziehau static int
101915516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr)
102015516c77SSepherosa Ziehau {
102115516c77SSepherosa Ziehau 
102215516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet"));
102315516c77SSepherosa Ziehau 	if (hn_tx_swq_depth < txr->hn_txdesc_cnt)
102415516c77SSepherosa Ziehau 		return txr->hn_txdesc_cnt;
102515516c77SSepherosa Ziehau 	return hn_tx_swq_depth;
102615516c77SSepherosa Ziehau }
102715516c77SSepherosa Ziehau 
102815516c77SSepherosa Ziehau static int
102915516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc)
103015516c77SSepherosa Ziehau {
103115516c77SSepherosa Ziehau 	int error;
103215516c77SSepherosa Ziehau 
103315516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
103415516c77SSepherosa Ziehau 
103515516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
103615516c77SSepherosa Ziehau 		return (ENXIO);
103715516c77SSepherosa Ziehau 
103815516c77SSepherosa Ziehau 	/*
103915516c77SSepherosa Ziehau 	 * Disable RSS first.
104015516c77SSepherosa Ziehau 	 *
104115516c77SSepherosa Ziehau 	 * NOTE:
104215516c77SSepherosa Ziehau 	 * Direct reconfiguration by setting the UNCHG flags does
104315516c77SSepherosa Ziehau 	 * _not_ work properly.
104415516c77SSepherosa Ziehau 	 */
104515516c77SSepherosa Ziehau 	if (bootverbose)
104615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "disable RSS\n");
104715516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE);
104815516c77SSepherosa Ziehau 	if (error) {
104915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS disable failed\n");
105015516c77SSepherosa Ziehau 		return (error);
105115516c77SSepherosa Ziehau 	}
105215516c77SSepherosa Ziehau 
105315516c77SSepherosa Ziehau 	/*
105415516c77SSepherosa Ziehau 	 * Reenable the RSS w/ the updated RSS key or indirect
105515516c77SSepherosa Ziehau 	 * table.
105615516c77SSepherosa Ziehau 	 */
105715516c77SSepherosa Ziehau 	if (bootverbose)
105815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "reconfig RSS\n");
105915516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
106015516c77SSepherosa Ziehau 	if (error) {
106115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS reconfig failed\n");
106215516c77SSepherosa Ziehau 		return (error);
106315516c77SSepherosa Ziehau 	}
106415516c77SSepherosa Ziehau 	return (0);
106515516c77SSepherosa Ziehau }
106615516c77SSepherosa Ziehau 
106715516c77SSepherosa Ziehau static void
1068afd4971bSSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc)
106915516c77SSepherosa Ziehau {
107015516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
1071afd4971bSSepherosa Ziehau 	int i, nchan;
107215516c77SSepherosa Ziehau 
1073afd4971bSSepherosa Ziehau 	nchan = sc->hn_rx_ring_inuse;
107415516c77SSepherosa Ziehau 	KASSERT(nchan > 1, ("invalid # of channels %d", nchan));
107515516c77SSepherosa Ziehau 
107615516c77SSepherosa Ziehau 	/*
107715516c77SSepherosa Ziehau 	 * Check indirect table to make sure that all channels in it
107815516c77SSepherosa Ziehau 	 * can be used.
107915516c77SSepherosa Ziehau 	 */
108015516c77SSepherosa Ziehau 	for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
108115516c77SSepherosa Ziehau 		if (rss->rss_ind[i] >= nchan) {
108215516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp,
108315516c77SSepherosa Ziehau 			    "RSS indirect table %d fixup: %u -> %d\n",
108415516c77SSepherosa Ziehau 			    i, rss->rss_ind[i], nchan - 1);
108515516c77SSepherosa Ziehau 			rss->rss_ind[i] = nchan - 1;
108615516c77SSepherosa Ziehau 		}
108715516c77SSepherosa Ziehau 	}
108815516c77SSepherosa Ziehau }
108915516c77SSepherosa Ziehau 
109015516c77SSepherosa Ziehau static int
109115516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused)
109215516c77SSepherosa Ziehau {
109315516c77SSepherosa Ziehau 
109415516c77SSepherosa Ziehau 	return EOPNOTSUPP;
109515516c77SSepherosa Ziehau }
109615516c77SSepherosa Ziehau 
109715516c77SSepherosa Ziehau static void
109815516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
109915516c77SSepherosa Ziehau {
110015516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
110115516c77SSepherosa Ziehau 
110215516c77SSepherosa Ziehau 	ifmr->ifm_status = IFM_AVALID;
110315516c77SSepherosa Ziehau 	ifmr->ifm_active = IFM_ETHER;
110415516c77SSepherosa Ziehau 
110515516c77SSepherosa Ziehau 	if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) {
110615516c77SSepherosa Ziehau 		ifmr->ifm_active |= IFM_NONE;
110715516c77SSepherosa Ziehau 		return;
110815516c77SSepherosa Ziehau 	}
110915516c77SSepherosa Ziehau 	ifmr->ifm_status |= IFM_ACTIVE;
111015516c77SSepherosa Ziehau 	ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
111115516c77SSepherosa Ziehau }
111215516c77SSepherosa Ziehau 
11135bdfd3fdSDexuan Cui static void
1114962f0357SSepherosa Ziehau hn_rxvf_set_task(void *xarg, int pending __unused)
11155bdfd3fdSDexuan Cui {
1116962f0357SSepherosa Ziehau 	struct hn_rxvf_setarg *arg = xarg;
11175bdfd3fdSDexuan Cui 
1118962f0357SSepherosa Ziehau 	arg->rxr->hn_rxvf_ifp = arg->vf_ifp;
11195bdfd3fdSDexuan Cui }
11205bdfd3fdSDexuan Cui 
11215bdfd3fdSDexuan Cui static void
1122962f0357SSepherosa Ziehau hn_rxvf_set(struct hn_softc *sc, struct ifnet *vf_ifp)
11235bdfd3fdSDexuan Cui {
11245bdfd3fdSDexuan Cui 	struct hn_rx_ring *rxr;
1125962f0357SSepherosa Ziehau 	struct hn_rxvf_setarg arg;
11265bdfd3fdSDexuan Cui 	struct task task;
11275bdfd3fdSDexuan Cui 	int i;
11285bdfd3fdSDexuan Cui 
11295bdfd3fdSDexuan Cui 	HN_LOCK_ASSERT(sc);
11305bdfd3fdSDexuan Cui 
1131962f0357SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_rxvf_set_task, &arg);
11325bdfd3fdSDexuan Cui 
11335bdfd3fdSDexuan Cui 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
11345bdfd3fdSDexuan Cui 		rxr = &sc->hn_rx_ring[i];
11355bdfd3fdSDexuan Cui 
11365bdfd3fdSDexuan Cui 		if (i < sc->hn_rx_ring_inuse) {
1137962f0357SSepherosa Ziehau 			arg.rxr = rxr;
1138962f0357SSepherosa Ziehau 			arg.vf_ifp = vf_ifp;
11395bdfd3fdSDexuan Cui 			vmbus_chan_run_task(rxr->hn_chan, &task);
11405bdfd3fdSDexuan Cui 		} else {
1141962f0357SSepherosa Ziehau 			rxr->hn_rxvf_ifp = vf_ifp;
11425bdfd3fdSDexuan Cui 		}
11435bdfd3fdSDexuan Cui 	}
11445bdfd3fdSDexuan Cui }
11455bdfd3fdSDexuan Cui 
1146962f0357SSepherosa Ziehau static bool
1147499c3e17SSepherosa Ziehau hn_ismyvf(const struct hn_softc *sc, const struct ifnet *ifp)
1148499c3e17SSepherosa Ziehau {
1149499c3e17SSepherosa Ziehau 	const struct ifnet *hn_ifp;
1150499c3e17SSepherosa Ziehau 
1151499c3e17SSepherosa Ziehau 	hn_ifp = sc->hn_ifp;
1152499c3e17SSepherosa Ziehau 
1153499c3e17SSepherosa Ziehau 	if (ifp == hn_ifp)
1154499c3e17SSepherosa Ziehau 		return (false);
1155499c3e17SSepherosa Ziehau 
1156499c3e17SSepherosa Ziehau 	if (ifp->if_alloctype != IFT_ETHER)
1157499c3e17SSepherosa Ziehau 		return (false);
1158499c3e17SSepherosa Ziehau 
1159499c3e17SSepherosa Ziehau 	/* Ignore lagg/vlan interfaces */
1160499c3e17SSepherosa Ziehau 	if (strcmp(ifp->if_dname, "lagg") == 0 ||
1161499c3e17SSepherosa Ziehau 	    strcmp(ifp->if_dname, "vlan") == 0)
1162499c3e17SSepherosa Ziehau 		return (false);
1163499c3e17SSepherosa Ziehau 
1164499c3e17SSepherosa Ziehau 	if (bcmp(IF_LLADDR(ifp), IF_LLADDR(hn_ifp), ETHER_ADDR_LEN) != 0)
1165499c3e17SSepherosa Ziehau 		return (false);
1166499c3e17SSepherosa Ziehau 
1167499c3e17SSepherosa Ziehau 	return (true);
1168499c3e17SSepherosa Ziehau }
1169499c3e17SSepherosa Ziehau 
11705bdfd3fdSDexuan Cui static void
1171962f0357SSepherosa Ziehau hn_rxvf_change(struct hn_softc *sc, struct ifnet *ifp, bool rxvf)
11725bdfd3fdSDexuan Cui {
11735bdfd3fdSDexuan Cui 	struct ifnet *hn_ifp;
11745bdfd3fdSDexuan Cui 
11755bdfd3fdSDexuan Cui 	HN_LOCK(sc);
11765bdfd3fdSDexuan Cui 
11775bdfd3fdSDexuan Cui 	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
11785bdfd3fdSDexuan Cui 		goto out;
11795bdfd3fdSDexuan Cui 
1180499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1181499c3e17SSepherosa Ziehau 		goto out;
11825bdfd3fdSDexuan Cui 	hn_ifp = sc->hn_ifp;
11835bdfd3fdSDexuan Cui 
1184962f0357SSepherosa Ziehau 	if (rxvf) {
1185962f0357SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_RXVF)
11865bdfd3fdSDexuan Cui 			goto out;
11875bdfd3fdSDexuan Cui 
1188962f0357SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_RXVF;
11895bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
11905bdfd3fdSDexuan Cui 	} else {
1191962f0357SSepherosa Ziehau 		if (!(sc->hn_flags & HN_FLAG_RXVF))
11925bdfd3fdSDexuan Cui 			goto out;
11935bdfd3fdSDexuan Cui 
1194962f0357SSepherosa Ziehau 		sc->hn_flags &= ~HN_FLAG_RXVF;
1195499c3e17SSepherosa Ziehau 		if (hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
11965bdfd3fdSDexuan Cui 			hn_rxfilter_config(sc);
11975bdfd3fdSDexuan Cui 		else
11985bdfd3fdSDexuan Cui 			hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE);
11995bdfd3fdSDexuan Cui 	}
12005bdfd3fdSDexuan Cui 
12015bdfd3fdSDexuan Cui 	hn_nvs_set_datapath(sc,
12029c6cae24SSepherosa Ziehau 	    rxvf ? HN_NVS_DATAPATH_VF : HN_NVS_DATAPATH_SYNTH);
12035bdfd3fdSDexuan Cui 
1204962f0357SSepherosa Ziehau 	hn_rxvf_set(sc, rxvf ? ifp : NULL);
12055bdfd3fdSDexuan Cui 
1206962f0357SSepherosa Ziehau 	if (rxvf) {
1207642ec226SSepherosa Ziehau 		hn_vf_rss_fixup(sc, true);
12085bdfd3fdSDexuan Cui 		hn_suspend_mgmt(sc);
12095bdfd3fdSDexuan Cui 		sc->hn_link_flags &=
12105bdfd3fdSDexuan Cui 		    ~(HN_LINK_FLAG_LINKUP | HN_LINK_FLAG_NETCHG);
1211499c3e17SSepherosa Ziehau 		if_link_state_change(hn_ifp, LINK_STATE_DOWN);
12125bdfd3fdSDexuan Cui 	} else {
1213642ec226SSepherosa Ziehau 		hn_vf_rss_restore(sc);
12145bdfd3fdSDexuan Cui 		hn_resume_mgmt(sc);
12155bdfd3fdSDexuan Cui 	}
12165bdfd3fdSDexuan Cui 
1217962f0357SSepherosa Ziehau 	devctl_notify("HYPERV_NIC_VF", hn_ifp->if_xname,
1218962f0357SSepherosa Ziehau 	    rxvf ? "VF_UP" : "VF_DOWN", NULL);
121933408a34SDexuan Cui 
1220962f0357SSepherosa Ziehau 	if (bootverbose) {
1221962f0357SSepherosa Ziehau 		if_printf(hn_ifp, "datapath is switched %s %s\n",
1222962f0357SSepherosa Ziehau 		    rxvf ? "to" : "from", ifp->if_xname);
1223962f0357SSepherosa Ziehau 	}
12245bdfd3fdSDexuan Cui out:
12255bdfd3fdSDexuan Cui 	HN_UNLOCK(sc);
12265bdfd3fdSDexuan Cui }
12275bdfd3fdSDexuan Cui 
12285bdfd3fdSDexuan Cui static void
12295bdfd3fdSDexuan Cui hn_ifnet_event(void *arg, struct ifnet *ifp, int event)
12305bdfd3fdSDexuan Cui {
1231962f0357SSepherosa Ziehau 
12325bdfd3fdSDexuan Cui 	if (event != IFNET_EVENT_UP && event != IFNET_EVENT_DOWN)
12335bdfd3fdSDexuan Cui 		return;
1234962f0357SSepherosa Ziehau 	hn_rxvf_change(arg, ifp, event == IFNET_EVENT_UP);
12355bdfd3fdSDexuan Cui }
12365bdfd3fdSDexuan Cui 
12375bdfd3fdSDexuan Cui static void
12385bdfd3fdSDexuan Cui hn_ifaddr_event(void *arg, struct ifnet *ifp)
12395bdfd3fdSDexuan Cui {
1240962f0357SSepherosa Ziehau 
1241962f0357SSepherosa Ziehau 	hn_rxvf_change(arg, ifp, ifp->if_flags & IFF_UP);
12425bdfd3fdSDexuan Cui }
12435bdfd3fdSDexuan Cui 
12449c6cae24SSepherosa Ziehau static int
12459c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetcaps(struct hn_softc *sc, struct ifreq *ifr)
12469c6cae24SSepherosa Ziehau {
12479c6cae24SSepherosa Ziehau 	struct ifnet *ifp, *vf_ifp;
12489c6cae24SSepherosa Ziehau 	uint64_t tmp;
12499c6cae24SSepherosa Ziehau 	int error;
12509c6cae24SSepherosa Ziehau 
12519c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
12529c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
12539c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
12549c6cae24SSepherosa Ziehau 
12559c6cae24SSepherosa Ziehau 	/*
12569c6cae24SSepherosa Ziehau 	 * Fix up requested capabilities w/ supported capabilities,
12579c6cae24SSepherosa Ziehau 	 * since the supported capabilities could have been changed.
12589c6cae24SSepherosa Ziehau 	 */
12599c6cae24SSepherosa Ziehau 	ifr->ifr_reqcap &= ifp->if_capabilities;
12609c6cae24SSepherosa Ziehau 	/* Pass SIOCSIFCAP to VF. */
12619c6cae24SSepherosa Ziehau 	error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFCAP, (caddr_t)ifr);
12629c6cae24SSepherosa Ziehau 
12639c6cae24SSepherosa Ziehau 	/*
12649c6cae24SSepherosa Ziehau 	 * NOTE:
12659c6cae24SSepherosa Ziehau 	 * The error will be propagated to the callers, however, it
12669c6cae24SSepherosa Ziehau 	 * is _not_ useful here.
12679c6cae24SSepherosa Ziehau 	 */
12689c6cae24SSepherosa Ziehau 
12699c6cae24SSepherosa Ziehau 	/*
12709c6cae24SSepherosa Ziehau 	 * Merge VF's enabled capabilities.
12719c6cae24SSepherosa Ziehau 	 */
12729c6cae24SSepherosa Ziehau 	ifp->if_capenable = vf_ifp->if_capenable & ifp->if_capabilities;
12739c6cae24SSepherosa Ziehau 
12749c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & HN_CSUM_IP_HWASSIST(sc);
12759c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TXCSUM)
12769c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
12779c6cae24SSepherosa Ziehau 	else
12789c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
12799c6cae24SSepherosa Ziehau 
12809c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & HN_CSUM_IP6_HWASSIST(sc);
12819c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
12829c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
12839c6cae24SSepherosa Ziehau 	else
12849c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
12859c6cae24SSepherosa Ziehau 
12869c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & CSUM_IP_TSO;
12879c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TSO4)
12889c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
12899c6cae24SSepherosa Ziehau 	else
12909c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
12919c6cae24SSepherosa Ziehau 
12929c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & CSUM_IP6_TSO;
12939c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TSO6)
12949c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
12959c6cae24SSepherosa Ziehau 	else
12969c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
12979c6cae24SSepherosa Ziehau 
12989c6cae24SSepherosa Ziehau 	return (error);
12999c6cae24SSepherosa Ziehau }
13009c6cae24SSepherosa Ziehau 
13019c6cae24SSepherosa Ziehau static int
13029c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetflags(struct hn_softc *sc)
13039c6cae24SSepherosa Ziehau {
13049c6cae24SSepherosa Ziehau 	struct ifnet *vf_ifp;
13059c6cae24SSepherosa Ziehau 	struct ifreq ifr;
13069c6cae24SSepherosa Ziehau 
13079c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
13089c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
13099c6cae24SSepherosa Ziehau 
13109c6cae24SSepherosa Ziehau 	memset(&ifr, 0, sizeof(ifr));
13119c6cae24SSepherosa Ziehau 	strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
13129c6cae24SSepherosa Ziehau 	ifr.ifr_flags = vf_ifp->if_flags & 0xffff;
13139c6cae24SSepherosa Ziehau 	ifr.ifr_flagshigh = vf_ifp->if_flags >> 16;
13149c6cae24SSepherosa Ziehau 	return (vf_ifp->if_ioctl(vf_ifp, SIOCSIFFLAGS, (caddr_t)&ifr));
13159c6cae24SSepherosa Ziehau }
13169c6cae24SSepherosa Ziehau 
13179c6cae24SSepherosa Ziehau static void
13189c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(struct hn_softc *sc)
13199c6cae24SSepherosa Ziehau {
13209c6cae24SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
13219c6cae24SSepherosa Ziehau 	int allmulti = 0;
13229c6cae24SSepherosa Ziehau 
13239c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
13249c6cae24SSepherosa Ziehau 
13259c6cae24SSepherosa Ziehau 	/* XXX vlan(4) style mcast addr maintenance */
13269c6cae24SSepherosa Ziehau 	if (!TAILQ_EMPTY(&ifp->if_multiaddrs))
13279c6cae24SSepherosa Ziehau 		allmulti = IFF_ALLMULTI;
13289c6cae24SSepherosa Ziehau 
13299c6cae24SSepherosa Ziehau 	/* Always set the VF's if_flags */
13309c6cae24SSepherosa Ziehau 	sc->hn_vf_ifp->if_flags = ifp->if_flags | allmulti;
13319c6cae24SSepherosa Ziehau }
13329c6cae24SSepherosa Ziehau 
13339c6cae24SSepherosa Ziehau static void
13349c6cae24SSepherosa Ziehau hn_xpnt_vf_input(struct ifnet *vf_ifp, struct mbuf *m)
13359c6cae24SSepherosa Ziehau {
13369c6cae24SSepherosa Ziehau 	struct rm_priotracker pt;
13379c6cae24SSepherosa Ziehau 	struct ifnet *hn_ifp = NULL;
13389c6cae24SSepherosa Ziehau 	struct mbuf *mn;
13399c6cae24SSepherosa Ziehau 
13409c6cae24SSepherosa Ziehau 	/*
13419c6cae24SSepherosa Ziehau 	 * XXX racy, if hn(4) ever detached.
13429c6cae24SSepherosa Ziehau 	 */
13439c6cae24SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
13449c6cae24SSepherosa Ziehau 	if (vf_ifp->if_index < hn_vfmap_size)
13459c6cae24SSepherosa Ziehau 		hn_ifp = hn_vfmap[vf_ifp->if_index];
13469c6cae24SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
13479c6cae24SSepherosa Ziehau 
13489c6cae24SSepherosa Ziehau 	if (hn_ifp != NULL) {
13499c6cae24SSepherosa Ziehau 		for (mn = m; mn != NULL; mn = mn->m_nextpkt) {
13503bed4e54SSepherosa Ziehau 			/*
13513bed4e54SSepherosa Ziehau 			 * Allow tapping on the VF.
13523bed4e54SSepherosa Ziehau 			 */
13539c6cae24SSepherosa Ziehau 			ETHER_BPF_MTAP(vf_ifp, mn);
13543bed4e54SSepherosa Ziehau 
13553bed4e54SSepherosa Ziehau 			/*
13563bed4e54SSepherosa Ziehau 			 * Update VF stats.
13573bed4e54SSepherosa Ziehau 			 */
13583bed4e54SSepherosa Ziehau 			if ((vf_ifp->if_capenable & IFCAP_HWSTATS) == 0) {
13593bed4e54SSepherosa Ziehau 				if_inc_counter(vf_ifp, IFCOUNTER_IBYTES,
13603bed4e54SSepherosa Ziehau 				    mn->m_pkthdr.len);
13613bed4e54SSepherosa Ziehau 			}
13623bed4e54SSepherosa Ziehau 			/*
13633bed4e54SSepherosa Ziehau 			 * XXX IFCOUNTER_IMCAST
13643bed4e54SSepherosa Ziehau 			 * This stat updating is kinda invasive, since it
13653bed4e54SSepherosa Ziehau 			 * requires two checks on the mbuf: the length check
13663bed4e54SSepherosa Ziehau 			 * and the ethernet header check.  As of this write,
13673bed4e54SSepherosa Ziehau 			 * all multicast packets go directly to hn(4), which
13683bed4e54SSepherosa Ziehau 			 * makes imcast stat updating in the VF a try in vian.
13693bed4e54SSepherosa Ziehau 			 */
13703bed4e54SSepherosa Ziehau 
13713bed4e54SSepherosa Ziehau 			/*
13723bed4e54SSepherosa Ziehau 			 * Fix up rcvif and increase hn(4)'s ipackets.
13733bed4e54SSepherosa Ziehau 			 */
13749c6cae24SSepherosa Ziehau 			mn->m_pkthdr.rcvif = hn_ifp;
13759c6cae24SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1);
13769c6cae24SSepherosa Ziehau 		}
13773bed4e54SSepherosa Ziehau 		/*
13783bed4e54SSepherosa Ziehau 		 * Go through hn(4)'s if_input.
13793bed4e54SSepherosa Ziehau 		 */
13809c6cae24SSepherosa Ziehau 		hn_ifp->if_input(hn_ifp, m);
13819c6cae24SSepherosa Ziehau 	} else {
13829c6cae24SSepherosa Ziehau 		/*
13839c6cae24SSepherosa Ziehau 		 * In the middle of the transition; free this
13849c6cae24SSepherosa Ziehau 		 * mbuf chain.
13859c6cae24SSepherosa Ziehau 		 */
13869c6cae24SSepherosa Ziehau 		while (m != NULL) {
13879c6cae24SSepherosa Ziehau 			mn = m->m_nextpkt;
13889c6cae24SSepherosa Ziehau 			m->m_nextpkt = NULL;
13899c6cae24SSepherosa Ziehau 			m_freem(m);
13909c6cae24SSepherosa Ziehau 			m = mn;
13919c6cae24SSepherosa Ziehau 		}
13929c6cae24SSepherosa Ziehau 	}
13939c6cae24SSepherosa Ziehau }
13949c6cae24SSepherosa Ziehau 
13959c6cae24SSepherosa Ziehau static void
13969c6cae24SSepherosa Ziehau hn_mtu_change_fixup(struct hn_softc *sc)
13979c6cae24SSepherosa Ziehau {
13989c6cae24SSepherosa Ziehau 	struct ifnet *ifp;
13999c6cae24SSepherosa Ziehau 
14009c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
14019c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
14029c6cae24SSepherosa Ziehau 
14039c6cae24SSepherosa Ziehau 	hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu);
14049c6cae24SSepherosa Ziehau #if __FreeBSD_version >= 1100099
14059c6cae24SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_lro.lro_length_lim < HN_LRO_LENLIM_MIN(ifp))
14069c6cae24SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
14079c6cae24SSepherosa Ziehau #endif
14089c6cae24SSepherosa Ziehau }
14099c6cae24SSepherosa Ziehau 
1410642ec226SSepherosa Ziehau static uint32_t
1411642ec226SSepherosa Ziehau hn_rss_type_fromndis(uint32_t rss_hash)
1412642ec226SSepherosa Ziehau {
1413642ec226SSepherosa Ziehau 	uint32_t types = 0;
1414642ec226SSepherosa Ziehau 
1415642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_IPV4)
1416642ec226SSepherosa Ziehau 		types |= RSS_TYPE_IPV4;
1417642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_TCP_IPV4)
1418642ec226SSepherosa Ziehau 		types |= RSS_TYPE_TCP_IPV4;
1419642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_IPV6)
1420642ec226SSepherosa Ziehau 		types |= RSS_TYPE_IPV6;
1421642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_IPV6_EX)
1422642ec226SSepherosa Ziehau 		types |= RSS_TYPE_IPV6_EX;
1423642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_TCP_IPV6)
1424642ec226SSepherosa Ziehau 		types |= RSS_TYPE_TCP_IPV6;
1425642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_TCP_IPV6_EX)
1426642ec226SSepherosa Ziehau 		types |= RSS_TYPE_TCP_IPV6_EX;
14276f12c42eSSepherosa Ziehau 	if (rss_hash & NDIS_HASH_UDP_IPV4_X)
14286f12c42eSSepherosa Ziehau 		types |= RSS_TYPE_UDP_IPV4;
1429642ec226SSepherosa Ziehau 	return (types);
1430642ec226SSepherosa Ziehau }
1431642ec226SSepherosa Ziehau 
1432642ec226SSepherosa Ziehau static uint32_t
1433642ec226SSepherosa Ziehau hn_rss_type_tondis(uint32_t types)
1434642ec226SSepherosa Ziehau {
1435642ec226SSepherosa Ziehau 	uint32_t rss_hash = 0;
1436642ec226SSepherosa Ziehau 
14376f12c42eSSepherosa Ziehau 	KASSERT((types & (RSS_TYPE_UDP_IPV6 | RSS_TYPE_UDP_IPV6_EX)) == 0,
14386f12c42eSSepherosa Ziehau 	    ("UDP6 and UDP6EX are not supported"));
1439642ec226SSepherosa Ziehau 
1440642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_IPV4)
1441642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_IPV4;
1442642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_TCP_IPV4)
1443642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_TCP_IPV4;
1444642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_IPV6)
1445642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_IPV6;
1446642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_IPV6_EX)
1447642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_IPV6_EX;
1448642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_TCP_IPV6)
1449642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_TCP_IPV6;
1450642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_TCP_IPV6_EX)
1451642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_TCP_IPV6_EX;
14526f12c42eSSepherosa Ziehau 	if (types & RSS_TYPE_UDP_IPV4)
14536f12c42eSSepherosa Ziehau 		rss_hash |= NDIS_HASH_UDP_IPV4_X;
1454642ec226SSepherosa Ziehau 	return (rss_hash);
1455642ec226SSepherosa Ziehau }
1456642ec226SSepherosa Ziehau 
1457642ec226SSepherosa Ziehau static void
1458642ec226SSepherosa Ziehau hn_rss_mbuf_hash(struct hn_softc *sc, uint32_t mbuf_hash)
1459642ec226SSepherosa Ziehau {
1460642ec226SSepherosa Ziehau 	int i;
1461642ec226SSepherosa Ziehau 
1462642ec226SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1463642ec226SSepherosa Ziehau 
1464642ec226SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1465642ec226SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_mbuf_hash = mbuf_hash;
1466642ec226SSepherosa Ziehau }
1467642ec226SSepherosa Ziehau 
1468642ec226SSepherosa Ziehau static void
1469642ec226SSepherosa Ziehau hn_vf_rss_fixup(struct hn_softc *sc, bool reconf)
1470642ec226SSepherosa Ziehau {
1471642ec226SSepherosa Ziehau 	struct ifnet *ifp, *vf_ifp;
1472642ec226SSepherosa Ziehau 	struct ifrsshash ifrh;
1473642ec226SSepherosa Ziehau 	struct ifrsskey ifrk;
1474642ec226SSepherosa Ziehau 	int error;
1475642ec226SSepherosa Ziehau 	uint32_t my_types, diff_types, mbuf_types = 0;
1476642ec226SSepherosa Ziehau 
1477642ec226SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1478642ec226SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
1479642ec226SSepherosa Ziehau 	    ("%s: synthetic parts are not attached", sc->hn_ifp->if_xname));
1480642ec226SSepherosa Ziehau 
1481642ec226SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
1482642ec226SSepherosa Ziehau 		/* No RSS on synthetic parts; done. */
1483642ec226SSepherosa Ziehau 		return;
1484642ec226SSepherosa Ziehau 	}
1485642ec226SSepherosa Ziehau 	if ((sc->hn_rss_hcap & NDIS_HASH_FUNCTION_TOEPLITZ) == 0) {
1486642ec226SSepherosa Ziehau 		/* Synthetic parts do not support Toeplitz; done. */
1487642ec226SSepherosa Ziehau 		return;
1488642ec226SSepherosa Ziehau 	}
1489642ec226SSepherosa Ziehau 
1490642ec226SSepherosa Ziehau 	ifp = sc->hn_ifp;
1491642ec226SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
1492642ec226SSepherosa Ziehau 
1493642ec226SSepherosa Ziehau 	/*
1494642ec226SSepherosa Ziehau 	 * Extract VF's RSS key.  Only 40 bytes key for Toeplitz is
1495642ec226SSepherosa Ziehau 	 * supported.
1496642ec226SSepherosa Ziehau 	 */
1497642ec226SSepherosa Ziehau 	memset(&ifrk, 0, sizeof(ifrk));
1498642ec226SSepherosa Ziehau 	strlcpy(ifrk.ifrk_name, vf_ifp->if_xname, sizeof(ifrk.ifrk_name));
1499642ec226SSepherosa Ziehau 	error = vf_ifp->if_ioctl(vf_ifp, SIOCGIFRSSKEY, (caddr_t)&ifrk);
1500642ec226SSepherosa Ziehau 	if (error) {
1501642ec226SSepherosa Ziehau 		if_printf(ifp, "%s SIOCGRSSKEY failed: %d\n",
1502642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, error);
1503642ec226SSepherosa Ziehau 		goto done;
1504642ec226SSepherosa Ziehau 	}
1505642ec226SSepherosa Ziehau 	if (ifrk.ifrk_func != RSS_FUNC_TOEPLITZ) {
1506642ec226SSepherosa Ziehau 		if_printf(ifp, "%s RSS function %u is not Toeplitz\n",
1507642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, ifrk.ifrk_func);
1508642ec226SSepherosa Ziehau 		goto done;
1509642ec226SSepherosa Ziehau 	}
1510642ec226SSepherosa Ziehau 	if (ifrk.ifrk_keylen != NDIS_HASH_KEYSIZE_TOEPLITZ) {
1511642ec226SSepherosa Ziehau 		if_printf(ifp, "%s invalid RSS Toeplitz key length %d\n",
1512642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, ifrk.ifrk_keylen);
1513642ec226SSepherosa Ziehau 		goto done;
1514642ec226SSepherosa Ziehau 	}
1515642ec226SSepherosa Ziehau 
1516642ec226SSepherosa Ziehau 	/*
1517642ec226SSepherosa Ziehau 	 * Extract VF's RSS hash.  Only Toeplitz is supported.
1518642ec226SSepherosa Ziehau 	 */
1519642ec226SSepherosa Ziehau 	memset(&ifrh, 0, sizeof(ifrh));
1520642ec226SSepherosa Ziehau 	strlcpy(ifrh.ifrh_name, vf_ifp->if_xname, sizeof(ifrh.ifrh_name));
1521642ec226SSepherosa Ziehau 	error = vf_ifp->if_ioctl(vf_ifp, SIOCGIFRSSHASH, (caddr_t)&ifrh);
1522642ec226SSepherosa Ziehau 	if (error) {
1523642ec226SSepherosa Ziehau 		if_printf(ifp, "%s SIOCGRSSHASH failed: %d\n",
1524642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, error);
1525642ec226SSepherosa Ziehau 		goto done;
1526642ec226SSepherosa Ziehau 	}
1527642ec226SSepherosa Ziehau 	if (ifrh.ifrh_func != RSS_FUNC_TOEPLITZ) {
1528642ec226SSepherosa Ziehau 		if_printf(ifp, "%s RSS function %u is not Toeplitz\n",
1529642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, ifrh.ifrh_func);
1530642ec226SSepherosa Ziehau 		goto done;
1531642ec226SSepherosa Ziehau 	}
1532642ec226SSepherosa Ziehau 
1533642ec226SSepherosa Ziehau 	my_types = hn_rss_type_fromndis(sc->hn_rss_hcap);
1534642ec226SSepherosa Ziehau 	if ((ifrh.ifrh_types & my_types) == 0) {
1535642ec226SSepherosa Ziehau 		/* This disables RSS; ignore it then */
1536642ec226SSepherosa Ziehau 		if_printf(ifp, "%s intersection of RSS types failed.  "
1537642ec226SSepherosa Ziehau 		    "VF %#x, mine %#x\n", vf_ifp->if_xname,
1538642ec226SSepherosa Ziehau 		    ifrh.ifrh_types, my_types);
1539642ec226SSepherosa Ziehau 		goto done;
1540642ec226SSepherosa Ziehau 	}
1541642ec226SSepherosa Ziehau 
1542642ec226SSepherosa Ziehau 	diff_types = my_types ^ ifrh.ifrh_types;
1543642ec226SSepherosa Ziehau 	my_types &= ifrh.ifrh_types;
1544642ec226SSepherosa Ziehau 	mbuf_types = my_types;
1545642ec226SSepherosa Ziehau 
1546642ec226SSepherosa Ziehau 	/*
1547642ec226SSepherosa Ziehau 	 * Detect RSS hash value/type confliction.
1548642ec226SSepherosa Ziehau 	 *
1549642ec226SSepherosa Ziehau 	 * NOTE:
1550642ec226SSepherosa Ziehau 	 * We don't disable the hash type, but stop delivery the hash
1551642ec226SSepherosa Ziehau 	 * value/type through mbufs on RX path.
15526f12c42eSSepherosa Ziehau 	 *
15536f12c42eSSepherosa Ziehau 	 * XXX If HN_CAP_UDPHASH is set in hn_caps, then UDP 4-tuple
15546f12c42eSSepherosa Ziehau 	 * hash is delivered with type of TCP_IPV4.  This means if
15556f12c42eSSepherosa Ziehau 	 * UDP_IPV4 is enabled, then TCP_IPV4 should be forced, at
15566f12c42eSSepherosa Ziehau 	 * least to hn_mbuf_hash.  However, given that _all_ of the
15576f12c42eSSepherosa Ziehau 	 * NICs implement TCP_IPV4, this will _not_ impose any issues
15586f12c42eSSepherosa Ziehau 	 * here.
1559642ec226SSepherosa Ziehau 	 */
1560642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_IPV4) &&
1561642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types &
1562642ec226SSepherosa Ziehau 	     (RSS_TYPE_TCP_IPV4 | RSS_TYPE_UDP_IPV4))) {
1563642ec226SSepherosa Ziehau 		/* Conflict; disable IPV4 hash type/value delivery. */
1564642ec226SSepherosa Ziehau 		if_printf(ifp, "disable IPV4 mbuf hash delivery\n");
1565642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_IPV4;
1566642ec226SSepherosa Ziehau 	}
1567642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_IPV6) &&
1568642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types &
1569642ec226SSepherosa Ziehau 	     (RSS_TYPE_TCP_IPV6 | RSS_TYPE_UDP_IPV6 |
1570642ec226SSepherosa Ziehau 	      RSS_TYPE_TCP_IPV6_EX | RSS_TYPE_UDP_IPV6_EX |
1571642ec226SSepherosa Ziehau 	      RSS_TYPE_IPV6_EX))) {
1572642ec226SSepherosa Ziehau 		/* Conflict; disable IPV6 hash type/value delivery. */
1573642ec226SSepherosa Ziehau 		if_printf(ifp, "disable IPV6 mbuf hash delivery\n");
1574642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_IPV6;
1575642ec226SSepherosa Ziehau 	}
1576642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_IPV6_EX) &&
1577642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types &
1578642ec226SSepherosa Ziehau 	     (RSS_TYPE_TCP_IPV6 | RSS_TYPE_UDP_IPV6 |
1579642ec226SSepherosa Ziehau 	      RSS_TYPE_TCP_IPV6_EX | RSS_TYPE_UDP_IPV6_EX |
1580642ec226SSepherosa Ziehau 	      RSS_TYPE_IPV6))) {
1581642ec226SSepherosa Ziehau 		/* Conflict; disable IPV6_EX hash type/value delivery. */
1582642ec226SSepherosa Ziehau 		if_printf(ifp, "disable IPV6_EX mbuf hash delivery\n");
1583642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_IPV6_EX;
1584642ec226SSepherosa Ziehau 	}
1585642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_TCP_IPV6) &&
1586642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_TCP_IPV6_EX)) {
1587642ec226SSepherosa Ziehau 		/* Conflict; disable TCP_IPV6 hash type/value delivery. */
1588642ec226SSepherosa Ziehau 		if_printf(ifp, "disable TCP_IPV6 mbuf hash delivery\n");
1589642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_TCP_IPV6;
1590642ec226SSepherosa Ziehau 	}
1591642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_TCP_IPV6_EX) &&
1592642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_TCP_IPV6)) {
1593642ec226SSepherosa Ziehau 		/* Conflict; disable TCP_IPV6_EX hash type/value delivery. */
1594642ec226SSepherosa Ziehau 		if_printf(ifp, "disable TCP_IPV6_EX mbuf hash delivery\n");
1595642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_TCP_IPV6_EX;
1596642ec226SSepherosa Ziehau 	}
1597642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_UDP_IPV6) &&
1598642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_UDP_IPV6_EX)) {
1599642ec226SSepherosa Ziehau 		/* Conflict; disable UDP_IPV6 hash type/value delivery. */
1600642ec226SSepherosa Ziehau 		if_printf(ifp, "disable UDP_IPV6 mbuf hash delivery\n");
1601642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_UDP_IPV6;
1602642ec226SSepherosa Ziehau 	}
1603642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_UDP_IPV6_EX) &&
1604642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_UDP_IPV6)) {
1605642ec226SSepherosa Ziehau 		/* Conflict; disable UDP_IPV6_EX hash type/value delivery. */
1606642ec226SSepherosa Ziehau 		if_printf(ifp, "disable UDP_IPV6_EX mbuf hash delivery\n");
1607642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_UDP_IPV6_EX;
1608642ec226SSepherosa Ziehau 	}
1609642ec226SSepherosa Ziehau 
1610642ec226SSepherosa Ziehau 	/*
1611642ec226SSepherosa Ziehau 	 * Indirect table does not matter.
1612642ec226SSepherosa Ziehau 	 */
1613642ec226SSepherosa Ziehau 
1614642ec226SSepherosa Ziehau 	sc->hn_rss_hash = (sc->hn_rss_hcap & NDIS_HASH_FUNCTION_MASK) |
1615642ec226SSepherosa Ziehau 	    hn_rss_type_tondis(my_types);
1616642ec226SSepherosa Ziehau 	memcpy(sc->hn_rss.rss_key, ifrk.ifrk_key, sizeof(sc->hn_rss.rss_key));
1617642ec226SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
1618642ec226SSepherosa Ziehau 
1619642ec226SSepherosa Ziehau 	if (reconf) {
1620642ec226SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
1621642ec226SSepherosa Ziehau 		if (error) {
1622642ec226SSepherosa Ziehau 			/* XXX roll-back? */
1623642ec226SSepherosa Ziehau 			if_printf(ifp, "hn_rss_reconfig failed: %d\n", error);
1624642ec226SSepherosa Ziehau 			/* XXX keep going. */
1625642ec226SSepherosa Ziehau 		}
1626642ec226SSepherosa Ziehau 	}
1627642ec226SSepherosa Ziehau done:
1628642ec226SSepherosa Ziehau 	/* Hash deliverability for mbufs. */
1629642ec226SSepherosa Ziehau 	hn_rss_mbuf_hash(sc, hn_rss_type_tondis(mbuf_types));
1630642ec226SSepherosa Ziehau }
1631642ec226SSepherosa Ziehau 
1632642ec226SSepherosa Ziehau static void
1633642ec226SSepherosa Ziehau hn_vf_rss_restore(struct hn_softc *sc)
1634642ec226SSepherosa Ziehau {
1635642ec226SSepherosa Ziehau 
1636642ec226SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1637642ec226SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
1638642ec226SSepherosa Ziehau 	    ("%s: synthetic parts are not attached", sc->hn_ifp->if_xname));
1639642ec226SSepherosa Ziehau 
1640642ec226SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1)
1641642ec226SSepherosa Ziehau 		goto done;
1642642ec226SSepherosa Ziehau 
1643642ec226SSepherosa Ziehau 	/*
1644642ec226SSepherosa Ziehau 	 * Restore hash types.  Key does _not_ matter.
1645642ec226SSepherosa Ziehau 	 */
1646642ec226SSepherosa Ziehau 	if (sc->hn_rss_hash != sc->hn_rss_hcap) {
1647642ec226SSepherosa Ziehau 		int error;
1648642ec226SSepherosa Ziehau 
1649642ec226SSepherosa Ziehau 		sc->hn_rss_hash = sc->hn_rss_hcap;
1650642ec226SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
1651642ec226SSepherosa Ziehau 		if (error) {
1652642ec226SSepherosa Ziehau 			if_printf(sc->hn_ifp, "hn_rss_reconfig failed: %d\n",
1653642ec226SSepherosa Ziehau 			    error);
1654642ec226SSepherosa Ziehau 			/* XXX keep going. */
1655642ec226SSepherosa Ziehau 		}
1656642ec226SSepherosa Ziehau 	}
1657642ec226SSepherosa Ziehau done:
1658642ec226SSepherosa Ziehau 	/* Hash deliverability for mbufs. */
1659642ec226SSepherosa Ziehau 	hn_rss_mbuf_hash(sc, NDIS_HASH_ALL);
1660642ec226SSepherosa Ziehau }
1661642ec226SSepherosa Ziehau 
16629c6cae24SSepherosa Ziehau static void
16639c6cae24SSepherosa Ziehau hn_xpnt_vf_setready(struct hn_softc *sc)
16649c6cae24SSepherosa Ziehau {
16659c6cae24SSepherosa Ziehau 	struct ifnet *ifp, *vf_ifp;
16669c6cae24SSepherosa Ziehau 	struct ifreq ifr;
16679c6cae24SSepherosa Ziehau 
16689c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
16699c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
16709c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
16719c6cae24SSepherosa Ziehau 
16729c6cae24SSepherosa Ziehau 	/*
16739c6cae24SSepherosa Ziehau 	 * Mark the VF ready.
16749c6cae24SSepherosa Ziehau 	 */
16759c6cae24SSepherosa Ziehau 	sc->hn_vf_rdytick = 0;
16769c6cae24SSepherosa Ziehau 
16779c6cae24SSepherosa Ziehau 	/*
16789c6cae24SSepherosa Ziehau 	 * Save information for restoration.
16799c6cae24SSepherosa Ziehau 	 */
16809c6cae24SSepherosa Ziehau 	sc->hn_saved_caps = ifp->if_capabilities;
16819c6cae24SSepherosa Ziehau 	sc->hn_saved_tsomax = ifp->if_hw_tsomax;
16829c6cae24SSepherosa Ziehau 	sc->hn_saved_tsosegcnt = ifp->if_hw_tsomaxsegcount;
16839c6cae24SSepherosa Ziehau 	sc->hn_saved_tsosegsz = ifp->if_hw_tsomaxsegsize;
16849c6cae24SSepherosa Ziehau 
16859c6cae24SSepherosa Ziehau 	/*
16869c6cae24SSepherosa Ziehau 	 * Intersect supported/enabled capabilities.
16879c6cae24SSepherosa Ziehau 	 *
16889c6cae24SSepherosa Ziehau 	 * NOTE:
16899c6cae24SSepherosa Ziehau 	 * if_hwassist is not changed here.
16909c6cae24SSepherosa Ziehau 	 */
16919c6cae24SSepherosa Ziehau 	ifp->if_capabilities &= vf_ifp->if_capabilities;
16929c6cae24SSepherosa Ziehau 	ifp->if_capenable &= ifp->if_capabilities;
16939c6cae24SSepherosa Ziehau 
16949c6cae24SSepherosa Ziehau 	/*
16959c6cae24SSepherosa Ziehau 	 * Fix TSO settings.
16969c6cae24SSepherosa Ziehau 	 */
16979c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomax > vf_ifp->if_hw_tsomax)
16989c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomax = vf_ifp->if_hw_tsomax;
16999c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomaxsegcount > vf_ifp->if_hw_tsomaxsegcount)
17009c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = vf_ifp->if_hw_tsomaxsegcount;
17019c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomaxsegsize > vf_ifp->if_hw_tsomaxsegsize)
17029c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = vf_ifp->if_hw_tsomaxsegsize;
17039c6cae24SSepherosa Ziehau 
17049c6cae24SSepherosa Ziehau 	/*
17059c6cae24SSepherosa Ziehau 	 * Change VF's enabled capabilities.
17069c6cae24SSepherosa Ziehau 	 */
17079c6cae24SSepherosa Ziehau 	memset(&ifr, 0, sizeof(ifr));
17089c6cae24SSepherosa Ziehau 	strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
17099c6cae24SSepherosa Ziehau 	ifr.ifr_reqcap = ifp->if_capenable;
17109c6cae24SSepherosa Ziehau 	hn_xpnt_vf_iocsetcaps(sc, &ifr);
17119c6cae24SSepherosa Ziehau 
17129c6cae24SSepherosa Ziehau 	if (ifp->if_mtu != ETHERMTU) {
17139c6cae24SSepherosa Ziehau 		int error;
17149c6cae24SSepherosa Ziehau 
17159c6cae24SSepherosa Ziehau 		/*
17169c6cae24SSepherosa Ziehau 		 * Change VF's MTU.
17179c6cae24SSepherosa Ziehau 		 */
17189c6cae24SSepherosa Ziehau 		memset(&ifr, 0, sizeof(ifr));
17199c6cae24SSepherosa Ziehau 		strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
17209c6cae24SSepherosa Ziehau 		ifr.ifr_mtu = ifp->if_mtu;
17219c6cae24SSepherosa Ziehau 		error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU, (caddr_t)&ifr);
17229c6cae24SSepherosa Ziehau 		if (error) {
17239c6cae24SSepherosa Ziehau 			if_printf(ifp, "%s SIOCSIFMTU %u failed\n",
17249c6cae24SSepherosa Ziehau 			    vf_ifp->if_xname, ifp->if_mtu);
17259c6cae24SSepherosa Ziehau 			if (ifp->if_mtu > ETHERMTU) {
17269c6cae24SSepherosa Ziehau 				if_printf(ifp, "change MTU to %d\n", ETHERMTU);
17279c6cae24SSepherosa Ziehau 
17289c6cae24SSepherosa Ziehau 				/*
17299c6cae24SSepherosa Ziehau 				 * XXX
17309c6cae24SSepherosa Ziehau 				 * No need to adjust the synthetic parts' MTU;
17319c6cae24SSepherosa Ziehau 				 * failure of the adjustment will cause us
17329c6cae24SSepherosa Ziehau 				 * infinite headache.
17339c6cae24SSepherosa Ziehau 				 */
17349c6cae24SSepherosa Ziehau 				ifp->if_mtu = ETHERMTU;
17359c6cae24SSepherosa Ziehau 				hn_mtu_change_fixup(sc);
17369c6cae24SSepherosa Ziehau 			}
17379c6cae24SSepherosa Ziehau 		}
17389c6cae24SSepherosa Ziehau 	}
17399c6cae24SSepherosa Ziehau }
17409c6cae24SSepherosa Ziehau 
17419c6cae24SSepherosa Ziehau static bool
17429c6cae24SSepherosa Ziehau hn_xpnt_vf_isready(struct hn_softc *sc)
17439c6cae24SSepherosa Ziehau {
17449c6cae24SSepherosa Ziehau 
17459c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
17469c6cae24SSepherosa Ziehau 
17479c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf || sc->hn_vf_ifp == NULL)
17489c6cae24SSepherosa Ziehau 		return (false);
17499c6cae24SSepherosa Ziehau 
17509c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick == 0)
17519c6cae24SSepherosa Ziehau 		return (true);
17529c6cae24SSepherosa Ziehau 
17539c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick > ticks)
17549c6cae24SSepherosa Ziehau 		return (false);
17559c6cae24SSepherosa Ziehau 
17569c6cae24SSepherosa Ziehau 	/* Mark VF as ready. */
17579c6cae24SSepherosa Ziehau 	hn_xpnt_vf_setready(sc);
17589c6cae24SSepherosa Ziehau 	return (true);
17599c6cae24SSepherosa Ziehau }
17609c6cae24SSepherosa Ziehau 
17619c6cae24SSepherosa Ziehau static void
1762a97fff19SSepherosa Ziehau hn_xpnt_vf_setenable(struct hn_softc *sc)
1763a97fff19SSepherosa Ziehau {
1764a97fff19SSepherosa Ziehau 	int i;
1765a97fff19SSepherosa Ziehau 
1766a97fff19SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1767a97fff19SSepherosa Ziehau 
1768a97fff19SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
1769a97fff19SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
1770a97fff19SSepherosa Ziehau 	sc->hn_xvf_flags |= HN_XVFFLAG_ENABLED;
1771a97fff19SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
1772a97fff19SSepherosa Ziehau 
1773a97fff19SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1774a97fff19SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_rx_flags |= HN_RX_FLAG_XPNT_VF;
1775a97fff19SSepherosa Ziehau }
1776a97fff19SSepherosa Ziehau 
1777a97fff19SSepherosa Ziehau static void
1778a97fff19SSepherosa Ziehau hn_xpnt_vf_setdisable(struct hn_softc *sc, bool clear_vf)
1779a97fff19SSepherosa Ziehau {
1780a97fff19SSepherosa Ziehau 	int i;
1781a97fff19SSepherosa Ziehau 
1782a97fff19SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1783a97fff19SSepherosa Ziehau 
1784a97fff19SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
1785a97fff19SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
1786a97fff19SSepherosa Ziehau 	sc->hn_xvf_flags &= ~HN_XVFFLAG_ENABLED;
1787a97fff19SSepherosa Ziehau 	if (clear_vf)
1788a97fff19SSepherosa Ziehau 		sc->hn_vf_ifp = NULL;
1789a97fff19SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
1790a97fff19SSepherosa Ziehau 
1791a97fff19SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1792a97fff19SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_rx_flags &= ~HN_RX_FLAG_XPNT_VF;
1793a97fff19SSepherosa Ziehau }
1794a97fff19SSepherosa Ziehau 
1795a97fff19SSepherosa Ziehau static void
17969c6cae24SSepherosa Ziehau hn_xpnt_vf_init(struct hn_softc *sc)
17979c6cae24SSepherosa Ziehau {
17989c6cae24SSepherosa Ziehau 	int error;
17999c6cae24SSepherosa Ziehau 
18009c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
18019c6cae24SSepherosa Ziehau 
18029c6cae24SSepherosa Ziehau 	KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0,
18039c6cae24SSepherosa Ziehau 	    ("%s: transparent VF was enabled", sc->hn_ifp->if_xname));
18049c6cae24SSepherosa Ziehau 
18059c6cae24SSepherosa Ziehau 	if (bootverbose) {
18069c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "try bringing up %s\n",
18079c6cae24SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname);
18089c6cae24SSepherosa Ziehau 	}
18099c6cae24SSepherosa Ziehau 
18109c6cae24SSepherosa Ziehau 	/*
18119c6cae24SSepherosa Ziehau 	 * Bring the VF up.
18129c6cae24SSepherosa Ziehau 	 */
18139c6cae24SSepherosa Ziehau 	hn_xpnt_vf_saveifflags(sc);
18149c6cae24SSepherosa Ziehau 	sc->hn_vf_ifp->if_flags |= IFF_UP;
18159c6cae24SSepherosa Ziehau 	error = hn_xpnt_vf_iocsetflags(sc);
18169c6cae24SSepherosa Ziehau 	if (error) {
18179c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "bringing up %s failed: %d\n",
18189c6cae24SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname, error);
18199c6cae24SSepherosa Ziehau 		return;
18209c6cae24SSepherosa Ziehau 	}
18219c6cae24SSepherosa Ziehau 
18229c6cae24SSepherosa Ziehau 	/*
18239c6cae24SSepherosa Ziehau 	 * NOTE:
18249c6cae24SSepherosa Ziehau 	 * Datapath setting must happen _after_ bringing the VF up.
18259c6cae24SSepherosa Ziehau 	 */
18269c6cae24SSepherosa Ziehau 	hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF);
18279c6cae24SSepherosa Ziehau 
1828642ec226SSepherosa Ziehau 	/*
1829642ec226SSepherosa Ziehau 	 * NOTE:
1830642ec226SSepherosa Ziehau 	 * Fixup RSS related bits _after_ the VF is brought up, since
1831642ec226SSepherosa Ziehau 	 * many VFs generate RSS key during it's initialization.
1832642ec226SSepherosa Ziehau 	 */
1833642ec226SSepherosa Ziehau 	hn_vf_rss_fixup(sc, true);
1834642ec226SSepherosa Ziehau 
1835a97fff19SSepherosa Ziehau 	/* Mark transparent mode VF as enabled. */
1836a97fff19SSepherosa Ziehau 	hn_xpnt_vf_setenable(sc);
18379c6cae24SSepherosa Ziehau }
18389c6cae24SSepherosa Ziehau 
18399c6cae24SSepherosa Ziehau static void
18409c6cae24SSepherosa Ziehau hn_xpnt_vf_init_taskfunc(void *xsc, int pending __unused)
18419c6cae24SSepherosa Ziehau {
18429c6cae24SSepherosa Ziehau 	struct hn_softc *sc = xsc;
18439c6cae24SSepherosa Ziehau 
18449c6cae24SSepherosa Ziehau 	HN_LOCK(sc);
18459c6cae24SSepherosa Ziehau 
18469c6cae24SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
18479c6cae24SSepherosa Ziehau 		goto done;
18489c6cae24SSepherosa Ziehau 	if (sc->hn_vf_ifp == NULL)
18499c6cae24SSepherosa Ziehau 		goto done;
18509c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
18519c6cae24SSepherosa Ziehau 		goto done;
18529c6cae24SSepherosa Ziehau 
18539c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick != 0) {
18549c6cae24SSepherosa Ziehau 		/* Mark VF as ready. */
18559c6cae24SSepherosa Ziehau 		hn_xpnt_vf_setready(sc);
18569c6cae24SSepherosa Ziehau 	}
18579c6cae24SSepherosa Ziehau 
18589c6cae24SSepherosa Ziehau 	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) {
18599c6cae24SSepherosa Ziehau 		/*
18609c6cae24SSepherosa Ziehau 		 * Delayed VF initialization.
18619c6cae24SSepherosa Ziehau 		 */
18629c6cae24SSepherosa Ziehau 		if (bootverbose) {
18639c6cae24SSepherosa Ziehau 			if_printf(sc->hn_ifp, "delayed initialize %s\n",
18649c6cae24SSepherosa Ziehau 			    sc->hn_vf_ifp->if_xname);
18659c6cae24SSepherosa Ziehau 		}
18669c6cae24SSepherosa Ziehau 		hn_xpnt_vf_init(sc);
18679c6cae24SSepherosa Ziehau 	}
18689c6cae24SSepherosa Ziehau done:
18699c6cae24SSepherosa Ziehau 	HN_UNLOCK(sc);
18709c6cae24SSepherosa Ziehau }
18719c6cae24SSepherosa Ziehau 
1872499c3e17SSepherosa Ziehau static void
1873499c3e17SSepherosa Ziehau hn_ifnet_attevent(void *xsc, struct ifnet *ifp)
1874499c3e17SSepherosa Ziehau {
1875499c3e17SSepherosa Ziehau 	struct hn_softc *sc = xsc;
1876499c3e17SSepherosa Ziehau 
1877499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
1878499c3e17SSepherosa Ziehau 
1879499c3e17SSepherosa Ziehau 	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
1880499c3e17SSepherosa Ziehau 		goto done;
1881499c3e17SSepherosa Ziehau 
1882499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1883499c3e17SSepherosa Ziehau 		goto done;
1884499c3e17SSepherosa Ziehau 
1885499c3e17SSepherosa Ziehau 	if (sc->hn_vf_ifp != NULL) {
1886499c3e17SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%s was attached as VF\n",
1887499c3e17SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname);
1888499c3e17SSepherosa Ziehau 		goto done;
1889499c3e17SSepherosa Ziehau 	}
1890499c3e17SSepherosa Ziehau 
18919c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && ifp->if_start != NULL) {
18929c6cae24SSepherosa Ziehau 		/*
18939c6cae24SSepherosa Ziehau 		 * ifnet.if_start is _not_ supported by transparent
18949c6cae24SSepherosa Ziehau 		 * mode VF; mainly due to the IFF_DRV_OACTIVE flag.
18959c6cae24SSepherosa Ziehau 		 */
18969c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%s uses if_start, which is unsupported "
18979c6cae24SSepherosa Ziehau 		    "in transparent VF mode.\n", ifp->if_xname);
18989c6cae24SSepherosa Ziehau 		goto done;
18999c6cae24SSepherosa Ziehau 	}
19009c6cae24SSepherosa Ziehau 
1901499c3e17SSepherosa Ziehau 	rm_wlock(&hn_vfmap_lock);
1902499c3e17SSepherosa Ziehau 
1903499c3e17SSepherosa Ziehau 	if (ifp->if_index >= hn_vfmap_size) {
1904499c3e17SSepherosa Ziehau 		struct ifnet **newmap;
1905499c3e17SSepherosa Ziehau 		int newsize;
1906499c3e17SSepherosa Ziehau 
1907499c3e17SSepherosa Ziehau 		newsize = ifp->if_index + HN_VFMAP_SIZE_DEF;
1908499c3e17SSepherosa Ziehau 		newmap = malloc(sizeof(struct ifnet *) * newsize, M_DEVBUF,
1909499c3e17SSepherosa Ziehau 		    M_WAITOK | M_ZERO);
1910499c3e17SSepherosa Ziehau 
1911499c3e17SSepherosa Ziehau 		memcpy(newmap, hn_vfmap,
1912499c3e17SSepherosa Ziehau 		    sizeof(struct ifnet *) * hn_vfmap_size);
1913499c3e17SSepherosa Ziehau 		free(hn_vfmap, M_DEVBUF);
1914499c3e17SSepherosa Ziehau 		hn_vfmap = newmap;
1915499c3e17SSepherosa Ziehau 		hn_vfmap_size = newsize;
1916499c3e17SSepherosa Ziehau 	}
1917499c3e17SSepherosa Ziehau 	KASSERT(hn_vfmap[ifp->if_index] == NULL,
1918499c3e17SSepherosa Ziehau 	    ("%s: ifindex %d was mapped to %s",
1919499c3e17SSepherosa Ziehau 	     ifp->if_xname, ifp->if_index, hn_vfmap[ifp->if_index]->if_xname));
1920499c3e17SSepherosa Ziehau 	hn_vfmap[ifp->if_index] = sc->hn_ifp;
1921499c3e17SSepherosa Ziehau 
1922499c3e17SSepherosa Ziehau 	rm_wunlock(&hn_vfmap_lock);
1923499c3e17SSepherosa Ziehau 
19249c6cae24SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
19259c6cae24SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
19269c6cae24SSepherosa Ziehau 	KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0,
19279c6cae24SSepherosa Ziehau 	    ("%s: transparent VF was enabled", sc->hn_ifp->if_xname));
1928499c3e17SSepherosa Ziehau 	sc->hn_vf_ifp = ifp;
19299c6cae24SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
19309c6cae24SSepherosa Ziehau 
19319c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
19329c6cae24SSepherosa Ziehau 		int wait_ticks;
19339c6cae24SSepherosa Ziehau 
19349c6cae24SSepherosa Ziehau 		/*
19359c6cae24SSepherosa Ziehau 		 * Install if_input for vf_ifp, which does vf_ifp -> hn_ifp.
19369c6cae24SSepherosa Ziehau 		 * Save vf_ifp's current if_input for later restoration.
19379c6cae24SSepherosa Ziehau 		 */
19389c6cae24SSepherosa Ziehau 		sc->hn_vf_input = ifp->if_input;
19399c6cae24SSepherosa Ziehau 		ifp->if_input = hn_xpnt_vf_input;
19409c6cae24SSepherosa Ziehau 
19419c6cae24SSepherosa Ziehau 		/*
19429c6cae24SSepherosa Ziehau 		 * Stop link status management; use the VF's.
19439c6cae24SSepherosa Ziehau 		 */
19449c6cae24SSepherosa Ziehau 		hn_suspend_mgmt(sc);
19459c6cae24SSepherosa Ziehau 
19469c6cae24SSepherosa Ziehau 		/*
19479c6cae24SSepherosa Ziehau 		 * Give VF sometime to complete its attach routing.
19489c6cae24SSepherosa Ziehau 		 */
19499c6cae24SSepherosa Ziehau 		wait_ticks = hn_xpnt_vf_attwait * hz;
19509c6cae24SSepherosa Ziehau 		sc->hn_vf_rdytick = ticks + wait_ticks;
19519c6cae24SSepherosa Ziehau 
19529c6cae24SSepherosa Ziehau 		taskqueue_enqueue_timeout(sc->hn_vf_taskq, &sc->hn_vf_init,
19539c6cae24SSepherosa Ziehau 		    wait_ticks);
19549c6cae24SSepherosa Ziehau 	}
1955499c3e17SSepherosa Ziehau done:
1956499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
1957499c3e17SSepherosa Ziehau }
1958499c3e17SSepherosa Ziehau 
1959499c3e17SSepherosa Ziehau static void
1960499c3e17SSepherosa Ziehau hn_ifnet_detevent(void *xsc, struct ifnet *ifp)
1961499c3e17SSepherosa Ziehau {
1962499c3e17SSepherosa Ziehau 	struct hn_softc *sc = xsc;
1963499c3e17SSepherosa Ziehau 
1964499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
1965499c3e17SSepherosa Ziehau 
1966499c3e17SSepherosa Ziehau 	if (sc->hn_vf_ifp == NULL)
1967499c3e17SSepherosa Ziehau 		goto done;
1968499c3e17SSepherosa Ziehau 
1969499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1970499c3e17SSepherosa Ziehau 		goto done;
1971499c3e17SSepherosa Ziehau 
19729c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
19739c6cae24SSepherosa Ziehau 		/*
19749c6cae24SSepherosa Ziehau 		 * Make sure that the delayed initialization is not running.
19759c6cae24SSepherosa Ziehau 		 *
19769c6cae24SSepherosa Ziehau 		 * NOTE:
19779c6cae24SSepherosa Ziehau 		 * - This lock _must_ be released, since the hn_vf_init task
19789c6cae24SSepherosa Ziehau 		 *   will try holding this lock.
19799c6cae24SSepherosa Ziehau 		 * - It is safe to release this lock here, since the
19809c6cae24SSepherosa Ziehau 		 *   hn_ifnet_attevent() is interlocked by the hn_vf_ifp.
19819c6cae24SSepherosa Ziehau 		 *
19829c6cae24SSepherosa Ziehau 		 * XXX racy, if hn(4) ever detached.
19839c6cae24SSepherosa Ziehau 		 */
19849c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
19859c6cae24SSepherosa Ziehau 		taskqueue_drain_timeout(sc->hn_vf_taskq, &sc->hn_vf_init);
19869c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
19879c6cae24SSepherosa Ziehau 
19889c6cae24SSepherosa Ziehau 		KASSERT(sc->hn_vf_input != NULL, ("%s VF input is not saved",
19899c6cae24SSepherosa Ziehau 		    sc->hn_ifp->if_xname));
19909c6cae24SSepherosa Ziehau 		ifp->if_input = sc->hn_vf_input;
19919c6cae24SSepherosa Ziehau 		sc->hn_vf_input = NULL;
19929c6cae24SSepherosa Ziehau 
1993642ec226SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) &&
1994642ec226SSepherosa Ziehau 		    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED))
19959c6cae24SSepherosa Ziehau 			hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH);
19969c6cae24SSepherosa Ziehau 
19979c6cae24SSepherosa Ziehau 		if (sc->hn_vf_rdytick == 0) {
19989c6cae24SSepherosa Ziehau 			/*
19999c6cae24SSepherosa Ziehau 			 * The VF was ready; restore some settings.
20009c6cae24SSepherosa Ziehau 			 */
20019c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_capabilities = sc->hn_saved_caps;
20029c6cae24SSepherosa Ziehau 			/*
20039c6cae24SSepherosa Ziehau 			 * NOTE:
20049c6cae24SSepherosa Ziehau 			 * There is _no_ need to fixup if_capenable and
20059c6cae24SSepherosa Ziehau 			 * if_hwassist, since the if_capabilities before
20069c6cae24SSepherosa Ziehau 			 * restoration was an intersection of the VF's
20079c6cae24SSepherosa Ziehau 			 * if_capabilites and the synthetic device's
20089c6cae24SSepherosa Ziehau 			 * if_capabilites.
20099c6cae24SSepherosa Ziehau 			 */
20109c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomax = sc->hn_saved_tsomax;
20119c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomaxsegcount =
20129c6cae24SSepherosa Ziehau 			    sc->hn_saved_tsosegcnt;
20139c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomaxsegsize = sc->hn_saved_tsosegsz;
20149c6cae24SSepherosa Ziehau 		}
20159c6cae24SSepherosa Ziehau 
2016642ec226SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
2017642ec226SSepherosa Ziehau 			/*
2018642ec226SSepherosa Ziehau 			 * Restore RSS settings.
2019642ec226SSepherosa Ziehau 			 */
2020642ec226SSepherosa Ziehau 			hn_vf_rss_restore(sc);
2021642ec226SSepherosa Ziehau 
20229c6cae24SSepherosa Ziehau 			/*
20239c6cae24SSepherosa Ziehau 			 * Resume link status management, which was suspended
20249c6cae24SSepherosa Ziehau 			 * by hn_ifnet_attevent().
20259c6cae24SSepherosa Ziehau 			 */
20269c6cae24SSepherosa Ziehau 			hn_resume_mgmt(sc);
20279c6cae24SSepherosa Ziehau 		}
2028642ec226SSepherosa Ziehau 	}
20299c6cae24SSepherosa Ziehau 
2030a97fff19SSepherosa Ziehau 	/* Mark transparent mode VF as disabled. */
2031a97fff19SSepherosa Ziehau 	hn_xpnt_vf_setdisable(sc, true /* clear hn_vf_ifp */);
2032499c3e17SSepherosa Ziehau 
2033499c3e17SSepherosa Ziehau 	rm_wlock(&hn_vfmap_lock);
2034499c3e17SSepherosa Ziehau 
2035499c3e17SSepherosa Ziehau 	KASSERT(ifp->if_index < hn_vfmap_size,
2036499c3e17SSepherosa Ziehau 	    ("ifindex %d, vfmapsize %d", ifp->if_index, hn_vfmap_size));
2037499c3e17SSepherosa Ziehau 	if (hn_vfmap[ifp->if_index] != NULL) {
2038499c3e17SSepherosa Ziehau 		KASSERT(hn_vfmap[ifp->if_index] == sc->hn_ifp,
2039499c3e17SSepherosa Ziehau 		    ("%s: ifindex %d was mapped to %s",
2040499c3e17SSepherosa Ziehau 		     ifp->if_xname, ifp->if_index,
2041499c3e17SSepherosa Ziehau 		     hn_vfmap[ifp->if_index]->if_xname));
2042499c3e17SSepherosa Ziehau 		hn_vfmap[ifp->if_index] = NULL;
2043499c3e17SSepherosa Ziehau 	}
2044499c3e17SSepherosa Ziehau 
2045499c3e17SSepherosa Ziehau 	rm_wunlock(&hn_vfmap_lock);
2046499c3e17SSepherosa Ziehau done:
2047499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
2048499c3e17SSepherosa Ziehau }
2049499c3e17SSepherosa Ziehau 
20509c6cae24SSepherosa Ziehau static void
20519c6cae24SSepherosa Ziehau hn_ifnet_lnkevent(void *xsc, struct ifnet *ifp, int link_state)
20529c6cae24SSepherosa Ziehau {
20539c6cae24SSepherosa Ziehau 	struct hn_softc *sc = xsc;
20549c6cae24SSepherosa Ziehau 
20559c6cae24SSepherosa Ziehau 	if (sc->hn_vf_ifp == ifp)
20569c6cae24SSepherosa Ziehau 		if_link_state_change(sc->hn_ifp, link_state);
20579c6cae24SSepherosa Ziehau }
20589c6cae24SSepherosa Ziehau 
205915516c77SSepherosa Ziehau static int
206015516c77SSepherosa Ziehau hn_probe(device_t dev)
206115516c77SSepherosa Ziehau {
206215516c77SSepherosa Ziehau 
2063c2d50b26SSepherosa Ziehau 	if (VMBUS_PROBE_GUID(device_get_parent(dev), dev, &hn_guid) == 0) {
206415516c77SSepherosa Ziehau 		device_set_desc(dev, "Hyper-V Network Interface");
206515516c77SSepherosa Ziehau 		return BUS_PROBE_DEFAULT;
206615516c77SSepherosa Ziehau 	}
206715516c77SSepherosa Ziehau 	return ENXIO;
206815516c77SSepherosa Ziehau }
206915516c77SSepherosa Ziehau 
207015516c77SSepherosa Ziehau static int
207115516c77SSepherosa Ziehau hn_attach(device_t dev)
207215516c77SSepherosa Ziehau {
207315516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
207415516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
207515516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
207615516c77SSepherosa Ziehau 	uint8_t eaddr[ETHER_ADDR_LEN];
207715516c77SSepherosa Ziehau 	struct ifnet *ifp = NULL;
207815516c77SSepherosa Ziehau 	int error, ring_cnt, tx_ring_cnt;
2079eb2fe044SSepherosa Ziehau 	uint32_t mtu;
208015516c77SSepherosa Ziehau 
208115516c77SSepherosa Ziehau 	sc->hn_dev = dev;
208215516c77SSepherosa Ziehau 	sc->hn_prichan = vmbus_get_channel(dev);
208315516c77SSepherosa Ziehau 	HN_LOCK_INIT(sc);
20849c6cae24SSepherosa Ziehau 	rm_init(&sc->hn_vf_lock, "hnvf");
20859c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && hn_xpnt_vf_accbpf)
20869c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF;
208715516c77SSepherosa Ziehau 
208815516c77SSepherosa Ziehau 	/*
2089dc13fee6SSepherosa Ziehau 	 * Initialize these tunables once.
2090dc13fee6SSepherosa Ziehau 	 */
2091dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = hn_tx_agg_size;
2092dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = hn_tx_agg_pkts;
2093dc13fee6SSepherosa Ziehau 
2094dc13fee6SSepherosa Ziehau 	/*
209515516c77SSepherosa Ziehau 	 * Setup taskqueue for transmission.
209615516c77SSepherosa Ziehau 	 */
20970e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_INDEP) {
2098fdd0222aSSepherosa Ziehau 		int i;
2099fdd0222aSSepherosa Ziehau 
2100fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs =
2101fdd0222aSSepherosa Ziehau 		    malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
2102fdd0222aSSepherosa Ziehau 		    M_DEVBUF, M_WAITOK);
2103fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i) {
2104fdd0222aSSepherosa Ziehau 			sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx",
2105fdd0222aSSepherosa Ziehau 			    M_WAITOK, taskqueue_thread_enqueue,
2106fdd0222aSSepherosa Ziehau 			    &sc->hn_tx_taskqs[i]);
2107fdd0222aSSepherosa Ziehau 			taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET,
2108fdd0222aSSepherosa Ziehau 			    "%s tx%d", device_get_nameunit(dev), i);
2109fdd0222aSSepherosa Ziehau 		}
21100e11868dSSepherosa Ziehau 	} else if (hn_tx_taskq_mode == HN_TX_TASKQ_M_GLOBAL) {
2111fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs = hn_tx_taskque;
211215516c77SSepherosa Ziehau 	}
211315516c77SSepherosa Ziehau 
211415516c77SSepherosa Ziehau 	/*
211515516c77SSepherosa Ziehau 	 * Setup taskqueue for mangement tasks, e.g. link status.
211615516c77SSepherosa Ziehau 	 */
211715516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK,
211815516c77SSepherosa Ziehau 	    taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0);
211915516c77SSepherosa Ziehau 	taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
212015516c77SSepherosa Ziehau 	    device_get_nameunit(dev));
212115516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
212215516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc);
212315516c77SSepherosa Ziehau 	TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0,
212415516c77SSepherosa Ziehau 	    hn_netchg_status_taskfunc, sc);
212515516c77SSepherosa Ziehau 
21269c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
21279c6cae24SSepherosa Ziehau 		/*
21289c6cae24SSepherosa Ziehau 		 * Setup taskqueue for VF tasks, e.g. delayed VF bringing up.
21299c6cae24SSepherosa Ziehau 		 */
21309c6cae24SSepherosa Ziehau 		sc->hn_vf_taskq = taskqueue_create("hn_vf", M_WAITOK,
21319c6cae24SSepherosa Ziehau 		    taskqueue_thread_enqueue, &sc->hn_vf_taskq);
21329c6cae24SSepherosa Ziehau 		taskqueue_start_threads(&sc->hn_vf_taskq, 1, PI_NET, "%s vf",
21339c6cae24SSepherosa Ziehau 		    device_get_nameunit(dev));
21349c6cae24SSepherosa Ziehau 		TIMEOUT_TASK_INIT(sc->hn_vf_taskq, &sc->hn_vf_init, 0,
21359c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_init_taskfunc, sc);
21369c6cae24SSepherosa Ziehau 	}
21379c6cae24SSepherosa Ziehau 
213815516c77SSepherosa Ziehau 	/*
213915516c77SSepherosa Ziehau 	 * Allocate ifnet and setup its name earlier, so that if_printf
214015516c77SSepherosa Ziehau 	 * can be used by functions, which will be called after
214115516c77SSepherosa Ziehau 	 * ether_ifattach().
214215516c77SSepherosa Ziehau 	 */
214315516c77SSepherosa Ziehau 	ifp = sc->hn_ifp = if_alloc(IFT_ETHER);
214415516c77SSepherosa Ziehau 	ifp->if_softc = sc;
214515516c77SSepherosa Ziehau 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
214615516c77SSepherosa Ziehau 
214715516c77SSepherosa Ziehau 	/*
214815516c77SSepherosa Ziehau 	 * Initialize ifmedia earlier so that it can be unconditionally
214915516c77SSepherosa Ziehau 	 * destroyed, if error happened later on.
215015516c77SSepherosa Ziehau 	 */
215115516c77SSepherosa Ziehau 	ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts);
215215516c77SSepherosa Ziehau 
215315516c77SSepherosa Ziehau 	/*
215415516c77SSepherosa Ziehau 	 * Figure out the # of RX rings (ring_cnt) and the # of TX rings
215515516c77SSepherosa Ziehau 	 * to use (tx_ring_cnt).
215615516c77SSepherosa Ziehau 	 *
215715516c77SSepherosa Ziehau 	 * NOTE:
215815516c77SSepherosa Ziehau 	 * The # of RX rings to use is same as the # of channels to use.
215915516c77SSepherosa Ziehau 	 */
216015516c77SSepherosa Ziehau 	ring_cnt = hn_chan_cnt;
216115516c77SSepherosa Ziehau 	if (ring_cnt <= 0) {
216215516c77SSepherosa Ziehau 		/* Default */
216315516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
216415516c77SSepherosa Ziehau 		if (ring_cnt > HN_RING_CNT_DEF_MAX)
216515516c77SSepherosa Ziehau 			ring_cnt = HN_RING_CNT_DEF_MAX;
216615516c77SSepherosa Ziehau 	} else if (ring_cnt > mp_ncpus) {
216715516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
216815516c77SSepherosa Ziehau 	}
216934d68912SSepherosa Ziehau #ifdef RSS
217034d68912SSepherosa Ziehau 	if (ring_cnt > rss_getnumbuckets())
217134d68912SSepherosa Ziehau 		ring_cnt = rss_getnumbuckets();
217234d68912SSepherosa Ziehau #endif
217315516c77SSepherosa Ziehau 
217415516c77SSepherosa Ziehau 	tx_ring_cnt = hn_tx_ring_cnt;
217515516c77SSepherosa Ziehau 	if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt)
217615516c77SSepherosa Ziehau 		tx_ring_cnt = ring_cnt;
217723bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
217815516c77SSepherosa Ziehau 	if (hn_use_if_start) {
217915516c77SSepherosa Ziehau 		/* ifnet.if_start only needs one TX ring. */
218015516c77SSepherosa Ziehau 		tx_ring_cnt = 1;
218115516c77SSepherosa Ziehau 	}
218223bf9e15SSepherosa Ziehau #endif
218315516c77SSepherosa Ziehau 
218415516c77SSepherosa Ziehau 	/*
218515516c77SSepherosa Ziehau 	 * Set the leader CPU for channels.
218615516c77SSepherosa Ziehau 	 */
218715516c77SSepherosa Ziehau 	sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus;
218815516c77SSepherosa Ziehau 
218915516c77SSepherosa Ziehau 	/*
219015516c77SSepherosa Ziehau 	 * Create enough TX/RX rings, even if only limited number of
219115516c77SSepherosa Ziehau 	 * channels can be allocated.
219215516c77SSepherosa Ziehau 	 */
219315516c77SSepherosa Ziehau 	error = hn_create_tx_data(sc, tx_ring_cnt);
219415516c77SSepherosa Ziehau 	if (error)
219515516c77SSepherosa Ziehau 		goto failed;
219615516c77SSepherosa Ziehau 	error = hn_create_rx_data(sc, ring_cnt);
219715516c77SSepherosa Ziehau 	if (error)
219815516c77SSepherosa Ziehau 		goto failed;
219915516c77SSepherosa Ziehau 
220015516c77SSepherosa Ziehau 	/*
220115516c77SSepherosa Ziehau 	 * Create transaction context for NVS and RNDIS transactions.
220215516c77SSepherosa Ziehau 	 */
220315516c77SSepherosa Ziehau 	sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
220415516c77SSepherosa Ziehau 	    HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
220525641fc7SSepherosa Ziehau 	if (sc->hn_xact == NULL) {
220625641fc7SSepherosa Ziehau 		error = ENXIO;
220715516c77SSepherosa Ziehau 		goto failed;
220825641fc7SSepherosa Ziehau 	}
220925641fc7SSepherosa Ziehau 
221025641fc7SSepherosa Ziehau 	/*
221125641fc7SSepherosa Ziehau 	 * Install orphan handler for the revocation of this device's
221225641fc7SSepherosa Ziehau 	 * primary channel.
221325641fc7SSepherosa Ziehau 	 *
221425641fc7SSepherosa Ziehau 	 * NOTE:
221525641fc7SSepherosa Ziehau 	 * The processing order is critical here:
221625641fc7SSepherosa Ziehau 	 * Install the orphan handler, _before_ testing whether this
221725641fc7SSepherosa Ziehau 	 * device's primary channel has been revoked or not.
221825641fc7SSepherosa Ziehau 	 */
221925641fc7SSepherosa Ziehau 	vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact);
222025641fc7SSepherosa Ziehau 	if (vmbus_chan_is_revoked(sc->hn_prichan)) {
222125641fc7SSepherosa Ziehau 		error = ENXIO;
222225641fc7SSepherosa Ziehau 		goto failed;
222325641fc7SSepherosa Ziehau 	}
222415516c77SSepherosa Ziehau 
222515516c77SSepherosa Ziehau 	/*
222615516c77SSepherosa Ziehau 	 * Attach the synthetic parts, i.e. NVS and RNDIS.
222715516c77SSepherosa Ziehau 	 */
222815516c77SSepherosa Ziehau 	error = hn_synth_attach(sc, ETHERMTU);
222915516c77SSepherosa Ziehau 	if (error)
223015516c77SSepherosa Ziehau 		goto failed;
223115516c77SSepherosa Ziehau 
223215516c77SSepherosa Ziehau 	error = hn_rndis_get_eaddr(sc, eaddr);
223315516c77SSepherosa Ziehau 	if (error)
223415516c77SSepherosa Ziehau 		goto failed;
223515516c77SSepherosa Ziehau 
2236eb2fe044SSepherosa Ziehau 	error = hn_rndis_get_mtu(sc, &mtu);
2237eb2fe044SSepherosa Ziehau 	if (error)
2238eb2fe044SSepherosa Ziehau 		mtu = ETHERMTU;
2239eb2fe044SSepherosa Ziehau 	else if (bootverbose)
2240eb2fe044SSepherosa Ziehau 		device_printf(dev, "RNDIS mtu %u\n", mtu);
2241eb2fe044SSepherosa Ziehau 
224215516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
224315516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
224415516c77SSepherosa Ziehau 		/*
224515516c77SSepherosa Ziehau 		 * Reduce TCP segment aggregation limit for multiple
224615516c77SSepherosa Ziehau 		 * RX rings to increase ACK timeliness.
224715516c77SSepherosa Ziehau 		 */
224815516c77SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF);
224915516c77SSepherosa Ziehau 	}
225015516c77SSepherosa Ziehau #endif
225115516c77SSepherosa Ziehau 
225215516c77SSepherosa Ziehau 	/*
2253db76829bSSepherosa Ziehau 	 * Fixup TX/RX stuffs after synthetic parts are attached.
225415516c77SSepherosa Ziehau 	 */
225515516c77SSepherosa Ziehau 	hn_fixup_tx_data(sc);
2256db76829bSSepherosa Ziehau 	hn_fixup_rx_data(sc);
225715516c77SSepherosa Ziehau 
225815516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
225915516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
226015516c77SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD,
226115516c77SSepherosa Ziehau 	    &sc->hn_nvs_ver, 0, "NVS version");
226215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version",
226315516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
226415516c77SSepherosa Ziehau 	    hn_ndis_version_sysctl, "A", "NDIS version");
226515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps",
226615516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
226715516c77SSepherosa Ziehau 	    hn_caps_sysctl, "A", "capabilities");
226815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist",
226915516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
227015516c77SSepherosa Ziehau 	    hn_hwassist_sysctl, "A", "hwassist");
22719c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_max",
22729c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomax, 0, "max TSO size");
22739c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegcnt",
22749c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomaxsegcount, 0,
22759c6cae24SSepherosa Ziehau 	    "max # of TSO segments");
22769c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegsz",
22779c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomaxsegsize, 0,
22789c6cae24SSepherosa Ziehau 	    "max size of TSO segment");
227915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter",
228015516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
228115516c77SSepherosa Ziehau 	    hn_rxfilter_sysctl, "A", "rxfilter");
228215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash",
228315516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
228415516c77SSepherosa Ziehau 	    hn_rss_hash_sysctl, "A", "RSS hash");
2285642ec226SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hashcap",
2286642ec226SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2287642ec226SSepherosa Ziehau 	    hn_rss_hcap_sysctl, "A", "RSS hash capabilities");
2288642ec226SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "mbuf_hash",
2289642ec226SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2290642ec226SSepherosa Ziehau 	    hn_rss_mbuf_sysctl, "A", "RSS hash for mbufs");
229115516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size",
229215516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count");
229334d68912SSepherosa Ziehau #ifndef RSS
229434d68912SSepherosa Ziehau 	/*
229534d68912SSepherosa Ziehau 	 * Don't allow RSS key/indirect table changes, if RSS is defined.
229634d68912SSepherosa Ziehau 	 */
229715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key",
229815516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
229915516c77SSepherosa Ziehau 	    hn_rss_key_sysctl, "IU", "RSS key");
230015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind",
230115516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
230215516c77SSepherosa Ziehau 	    hn_rss_ind_sysctl, "IU", "RSS indirect table");
230334d68912SSepherosa Ziehau #endif
2304dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size",
2305dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_size, 0,
2306dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation size limit");
2307dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts",
2308dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0,
2309dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation count limit");
2310dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align",
2311dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_align, 0,
2312dc13fee6SSepherosa Ziehau 	    "RNDIS packet transmission aggregation alignment");
2313dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size",
2314dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
2315dc13fee6SSepherosa Ziehau 	    hn_txagg_size_sysctl, "I",
2316dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation size, 0 -- disable, -1 -- auto");
2317dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts",
2318dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
2319dc13fee6SSepherosa Ziehau 	    hn_txagg_pkts_sysctl, "I",
2320dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation packets, "
2321dc13fee6SSepherosa Ziehau 	    "0 -- disable, -1 -- auto");
23226c1204dfSSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "polling",
23236c1204dfSSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
23246c1204dfSSepherosa Ziehau 	    hn_polling_sysctl, "I",
23256c1204dfSSepherosa Ziehau 	    "Polling frequency: [100,1000000], 0 disable polling");
232640d60d6eSDexuan Cui 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf",
232740d60d6eSDexuan Cui 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
232840d60d6eSDexuan Cui 	    hn_vf_sysctl, "A", "Virtual Function's name");
23299c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf) {
2330499c3e17SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxvf",
2331499c3e17SSepherosa Ziehau 		    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2332499c3e17SSepherosa Ziehau 		    hn_rxvf_sysctl, "A", "activated Virtual Function's name");
23339c6cae24SSepherosa Ziehau 	} else {
23349c6cae24SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_enabled",
23359c6cae24SSepherosa Ziehau 		    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
23369c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_enabled_sysctl, "I",
23379c6cae24SSepherosa Ziehau 		    "Transparent VF enabled");
23389c6cae24SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_accbpf",
23399c6cae24SSepherosa Ziehau 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
23409c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_accbpf_sysctl, "I",
23419c6cae24SSepherosa Ziehau 		    "Accurate BPF for transparent VF");
23429c6cae24SSepherosa Ziehau 	}
234315516c77SSepherosa Ziehau 
234415516c77SSepherosa Ziehau 	/*
234515516c77SSepherosa Ziehau 	 * Setup the ifmedia, which has been initialized earlier.
234615516c77SSepherosa Ziehau 	 */
234715516c77SSepherosa Ziehau 	ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL);
234815516c77SSepherosa Ziehau 	ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO);
234915516c77SSepherosa Ziehau 	/* XXX ifmedia_set really should do this for us */
235015516c77SSepherosa Ziehau 	sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media;
235115516c77SSepherosa Ziehau 
235215516c77SSepherosa Ziehau 	/*
235315516c77SSepherosa Ziehau 	 * Setup the ifnet for this interface.
235415516c77SSepherosa Ziehau 	 */
235515516c77SSepherosa Ziehau 
235615516c77SSepherosa Ziehau 	ifp->if_baudrate = IF_Gbps(10);
235715516c77SSepherosa Ziehau 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
235815516c77SSepherosa Ziehau 	ifp->if_ioctl = hn_ioctl;
235915516c77SSepherosa Ziehau 	ifp->if_init = hn_init;
236023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
236115516c77SSepherosa Ziehau 	if (hn_use_if_start) {
236215516c77SSepherosa Ziehau 		int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]);
236315516c77SSepherosa Ziehau 
236415516c77SSepherosa Ziehau 		ifp->if_start = hn_start;
236515516c77SSepherosa Ziehau 		IFQ_SET_MAXLEN(&ifp->if_snd, qdepth);
236615516c77SSepherosa Ziehau 		ifp->if_snd.ifq_drv_maxlen = qdepth - 1;
236715516c77SSepherosa Ziehau 		IFQ_SET_READY(&ifp->if_snd);
236823bf9e15SSepherosa Ziehau 	} else
236923bf9e15SSepherosa Ziehau #endif
237023bf9e15SSepherosa Ziehau 	{
237115516c77SSepherosa Ziehau 		ifp->if_transmit = hn_transmit;
237215516c77SSepherosa Ziehau 		ifp->if_qflush = hn_xmit_qflush;
237315516c77SSepherosa Ziehau 	}
237415516c77SSepherosa Ziehau 
23759c6cae24SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO | IFCAP_LINKSTATE;
237615516c77SSepherosa Ziehau #ifdef foo
237715516c77SSepherosa Ziehau 	/* We can't diff IPv6 packets from IPv4 packets on RX path. */
237815516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM_IPV6;
237915516c77SSepherosa Ziehau #endif
238015516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_VLAN) {
238115516c77SSepherosa Ziehau 		/* XXX not sure about VLAN_MTU. */
238215516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
238315516c77SSepherosa Ziehau 	}
238415516c77SSepherosa Ziehau 
238515516c77SSepherosa Ziehau 	ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist;
238615516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP_MASK)
238715516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM;
238815516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP6_MASK)
238915516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM_IPV6;
239015516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO4) {
239115516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO4;
239215516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP_TSO;
239315516c77SSepherosa Ziehau 	}
239415516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO6) {
239515516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO6;
239615516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP6_TSO;
239715516c77SSepherosa Ziehau 	}
239815516c77SSepherosa Ziehau 
239915516c77SSepherosa Ziehau 	/* Enable all available capabilities by default. */
240015516c77SSepherosa Ziehau 	ifp->if_capenable = ifp->if_capabilities;
240115516c77SSepherosa Ziehau 
24027960e6baSSepherosa Ziehau 	/*
24037960e6baSSepherosa Ziehau 	 * Disable IPv6 TSO and TXCSUM by default, they still can
24047960e6baSSepherosa Ziehau 	 * be enabled through SIOCSIFCAP.
24057960e6baSSepherosa Ziehau 	 */
24067960e6baSSepherosa Ziehau 	ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
24077960e6baSSepherosa Ziehau 	ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO);
24087960e6baSSepherosa Ziehau 
240915516c77SSepherosa Ziehau 	if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) {
24109c6cae24SSepherosa Ziehau 		/*
24119c6cae24SSepherosa Ziehau 		 * Lock hn_set_tso_maxsize() to simplify its
24129c6cae24SSepherosa Ziehau 		 * internal logic.
24139c6cae24SSepherosa Ziehau 		 */
24149c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
241515516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU);
24169c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
241715516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX;
241815516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = PAGE_SIZE;
241915516c77SSepherosa Ziehau 	}
242015516c77SSepherosa Ziehau 
242115516c77SSepherosa Ziehau 	ether_ifattach(ifp, eaddr);
242215516c77SSepherosa Ziehau 
242315516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) {
242415516c77SSepherosa Ziehau 		if_printf(ifp, "TSO segcnt %u segsz %u\n",
242515516c77SSepherosa Ziehau 		    ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize);
242615516c77SSepherosa Ziehau 	}
2427eb2fe044SSepherosa Ziehau 	if (mtu < ETHERMTU) {
2428eb2fe044SSepherosa Ziehau 		if_printf(ifp, "fixup mtu %u -> %u\n", ifp->if_mtu, mtu);
2429eb2fe044SSepherosa Ziehau 		ifp->if_mtu = mtu;
2430eb2fe044SSepherosa Ziehau 	}
243115516c77SSepherosa Ziehau 
243215516c77SSepherosa Ziehau 	/* Inform the upper layer about the long frame support. */
243315516c77SSepherosa Ziehau 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
243415516c77SSepherosa Ziehau 
243515516c77SSepherosa Ziehau 	/*
243615516c77SSepherosa Ziehau 	 * Kick off link status check.
243715516c77SSepherosa Ziehau 	 */
243815516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
243915516c77SSepherosa Ziehau 	hn_update_link_status(sc);
244015516c77SSepherosa Ziehau 
24419c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf) {
24425bdfd3fdSDexuan Cui 		sc->hn_ifnet_evthand = EVENTHANDLER_REGISTER(ifnet_event,
24435bdfd3fdSDexuan Cui 		    hn_ifnet_event, sc, EVENTHANDLER_PRI_ANY);
24445bdfd3fdSDexuan Cui 		sc->hn_ifaddr_evthand = EVENTHANDLER_REGISTER(ifaddr_event,
24455bdfd3fdSDexuan Cui 		    hn_ifaddr_event, sc, EVENTHANDLER_PRI_ANY);
24469c6cae24SSepherosa Ziehau 	} else {
24479c6cae24SSepherosa Ziehau 		sc->hn_ifnet_lnkhand = EVENTHANDLER_REGISTER(ifnet_link_event,
24489c6cae24SSepherosa Ziehau 		    hn_ifnet_lnkevent, sc, EVENTHANDLER_PRI_ANY);
24499c6cae24SSepherosa Ziehau 	}
24505bdfd3fdSDexuan Cui 
2451f41e0df4SSepherosa Ziehau 	/*
2452f41e0df4SSepherosa Ziehau 	 * NOTE:
2453f41e0df4SSepherosa Ziehau 	 * Subscribe ether_ifattach event, instead of ifnet_arrival event,
2454f41e0df4SSepherosa Ziehau 	 * since interface's LLADDR is needed; interface LLADDR is not
2455f41e0df4SSepherosa Ziehau 	 * available when ifnet_arrival event is triggered.
2456f41e0df4SSepherosa Ziehau 	 */
2457499c3e17SSepherosa Ziehau 	sc->hn_ifnet_atthand = EVENTHANDLER_REGISTER(ether_ifattach_event,
2458499c3e17SSepherosa Ziehau 	    hn_ifnet_attevent, sc, EVENTHANDLER_PRI_ANY);
2459499c3e17SSepherosa Ziehau 	sc->hn_ifnet_dethand = EVENTHANDLER_REGISTER(ifnet_departure_event,
2460499c3e17SSepherosa Ziehau 	    hn_ifnet_detevent, sc, EVENTHANDLER_PRI_ANY);
2461499c3e17SSepherosa Ziehau 
246215516c77SSepherosa Ziehau 	return (0);
246315516c77SSepherosa Ziehau failed:
246415516c77SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)
246515516c77SSepherosa Ziehau 		hn_synth_detach(sc);
246615516c77SSepherosa Ziehau 	hn_detach(dev);
246715516c77SSepherosa Ziehau 	return (error);
246815516c77SSepherosa Ziehau }
246915516c77SSepherosa Ziehau 
247015516c77SSepherosa Ziehau static int
247115516c77SSepherosa Ziehau hn_detach(device_t dev)
247215516c77SSepherosa Ziehau {
247315516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
2474499c3e17SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp, *vf_ifp;
247515516c77SSepherosa Ziehau 
24769c6cae24SSepherosa Ziehau 	if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) {
24779c6cae24SSepherosa Ziehau 		/*
24789c6cae24SSepherosa Ziehau 		 * In case that the vmbus missed the orphan handler
24799c6cae24SSepherosa Ziehau 		 * installation.
24809c6cae24SSepherosa Ziehau 		 */
24819c6cae24SSepherosa Ziehau 		vmbus_xact_ctx_orphan(sc->hn_xact);
24829c6cae24SSepherosa Ziehau 	}
24839c6cae24SSepherosa Ziehau 
24845bdfd3fdSDexuan Cui 	if (sc->hn_ifaddr_evthand != NULL)
24855bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifaddr_event, sc->hn_ifaddr_evthand);
24865bdfd3fdSDexuan Cui 	if (sc->hn_ifnet_evthand != NULL)
24875bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifnet_event, sc->hn_ifnet_evthand);
2488499c3e17SSepherosa Ziehau 	if (sc->hn_ifnet_atthand != NULL) {
2489499c3e17SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ether_ifattach_event,
2490499c3e17SSepherosa Ziehau 		    sc->hn_ifnet_atthand);
2491499c3e17SSepherosa Ziehau 	}
2492499c3e17SSepherosa Ziehau 	if (sc->hn_ifnet_dethand != NULL) {
2493499c3e17SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ifnet_departure_event,
2494499c3e17SSepherosa Ziehau 		    sc->hn_ifnet_dethand);
2495499c3e17SSepherosa Ziehau 	}
24969c6cae24SSepherosa Ziehau 	if (sc->hn_ifnet_lnkhand != NULL)
24979c6cae24SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ifnet_link_event, sc->hn_ifnet_lnkhand);
2498499c3e17SSepherosa Ziehau 
2499499c3e17SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
2500499c3e17SSepherosa Ziehau 	__compiler_membar();
2501499c3e17SSepherosa Ziehau 	if (vf_ifp != NULL)
2502499c3e17SSepherosa Ziehau 		hn_ifnet_detevent(sc, vf_ifp);
25035bdfd3fdSDexuan Cui 
250415516c77SSepherosa Ziehau 	if (device_is_attached(dev)) {
250515516c77SSepherosa Ziehau 		HN_LOCK(sc);
250615516c77SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
250715516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
25085bdfd3fdSDexuan Cui 				hn_stop(sc, true);
250915516c77SSepherosa Ziehau 			/*
251015516c77SSepherosa Ziehau 			 * NOTE:
251115516c77SSepherosa Ziehau 			 * hn_stop() only suspends data, so managment
251215516c77SSepherosa Ziehau 			 * stuffs have to be suspended manually here.
251315516c77SSepherosa Ziehau 			 */
251415516c77SSepherosa Ziehau 			hn_suspend_mgmt(sc);
251515516c77SSepherosa Ziehau 			hn_synth_detach(sc);
251615516c77SSepherosa Ziehau 		}
251715516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
251815516c77SSepherosa Ziehau 		ether_ifdetach(ifp);
251915516c77SSepherosa Ziehau 	}
252015516c77SSepherosa Ziehau 
252115516c77SSepherosa Ziehau 	ifmedia_removeall(&sc->hn_media);
252215516c77SSepherosa Ziehau 	hn_destroy_rx_data(sc);
252315516c77SSepherosa Ziehau 	hn_destroy_tx_data(sc);
252415516c77SSepherosa Ziehau 
25250e11868dSSepherosa Ziehau 	if (sc->hn_tx_taskqs != NULL && sc->hn_tx_taskqs != hn_tx_taskque) {
2526fdd0222aSSepherosa Ziehau 		int i;
2527fdd0222aSSepherosa Ziehau 
2528fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
2529fdd0222aSSepherosa Ziehau 			taskqueue_free(sc->hn_tx_taskqs[i]);
2530fdd0222aSSepherosa Ziehau 		free(sc->hn_tx_taskqs, M_DEVBUF);
2531fdd0222aSSepherosa Ziehau 	}
253215516c77SSepherosa Ziehau 	taskqueue_free(sc->hn_mgmt_taskq0);
25339c6cae24SSepherosa Ziehau 	if (sc->hn_vf_taskq != NULL)
25349c6cae24SSepherosa Ziehau 		taskqueue_free(sc->hn_vf_taskq);
253515516c77SSepherosa Ziehau 
253625641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL) {
253725641fc7SSepherosa Ziehau 		/*
253825641fc7SSepherosa Ziehau 		 * Uninstall the orphan handler _before_ the xact is
253925641fc7SSepherosa Ziehau 		 * destructed.
254025641fc7SSepherosa Ziehau 		 */
254125641fc7SSepherosa Ziehau 		vmbus_chan_unset_orphan(sc->hn_prichan);
254215516c77SSepherosa Ziehau 		vmbus_xact_ctx_destroy(sc->hn_xact);
254325641fc7SSepherosa Ziehau 	}
254415516c77SSepherosa Ziehau 
254515516c77SSepherosa Ziehau 	if_free(ifp);
254615516c77SSepherosa Ziehau 
254715516c77SSepherosa Ziehau 	HN_LOCK_DESTROY(sc);
25489c6cae24SSepherosa Ziehau 	rm_destroy(&sc->hn_vf_lock);
254915516c77SSepherosa Ziehau 	return (0);
255015516c77SSepherosa Ziehau }
255115516c77SSepherosa Ziehau 
255215516c77SSepherosa Ziehau static int
255315516c77SSepherosa Ziehau hn_shutdown(device_t dev)
255415516c77SSepherosa Ziehau {
255515516c77SSepherosa Ziehau 
255615516c77SSepherosa Ziehau 	return (0);
255715516c77SSepherosa Ziehau }
255815516c77SSepherosa Ziehau 
255915516c77SSepherosa Ziehau static void
256015516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc)
256115516c77SSepherosa Ziehau {
256215516c77SSepherosa Ziehau 	uint32_t link_status;
256315516c77SSepherosa Ziehau 	int error;
256415516c77SSepherosa Ziehau 
256515516c77SSepherosa Ziehau 	error = hn_rndis_get_linkstatus(sc, &link_status);
256615516c77SSepherosa Ziehau 	if (error) {
256715516c77SSepherosa Ziehau 		/* XXX what to do? */
256815516c77SSepherosa Ziehau 		return;
256915516c77SSepherosa Ziehau 	}
257015516c77SSepherosa Ziehau 
257115516c77SSepherosa Ziehau 	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
257215516c77SSepherosa Ziehau 		sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
257315516c77SSepherosa Ziehau 	else
257415516c77SSepherosa Ziehau 		sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
257515516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp,
257615516c77SSepherosa Ziehau 	    (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ?
257715516c77SSepherosa Ziehau 	    LINK_STATE_UP : LINK_STATE_DOWN);
257815516c77SSepherosa Ziehau }
257915516c77SSepherosa Ziehau 
258015516c77SSepherosa Ziehau static void
258115516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused)
258215516c77SSepherosa Ziehau {
258315516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
258415516c77SSepherosa Ziehau 
258515516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
258615516c77SSepherosa Ziehau 		return;
258715516c77SSepherosa Ziehau 	hn_link_status(sc);
258815516c77SSepherosa Ziehau }
258915516c77SSepherosa Ziehau 
259015516c77SSepherosa Ziehau static void
259115516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused)
259215516c77SSepherosa Ziehau {
259315516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
259415516c77SSepherosa Ziehau 
259515516c77SSepherosa Ziehau 	/* Prevent any link status checks from running. */
259615516c77SSepherosa Ziehau 	sc->hn_link_flags |= HN_LINK_FLAG_NETCHG;
259715516c77SSepherosa Ziehau 
259815516c77SSepherosa Ziehau 	/*
259915516c77SSepherosa Ziehau 	 * Fake up a [link down --> link up] state change; 5 seconds
260015516c77SSepherosa Ziehau 	 * delay is used, which closely simulates miibus reaction
260115516c77SSepherosa Ziehau 	 * upon link down event.
260215516c77SSepherosa Ziehau 	 */
260315516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
260415516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
260515516c77SSepherosa Ziehau 	taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0,
260615516c77SSepherosa Ziehau 	    &sc->hn_netchg_status, 5 * hz);
260715516c77SSepherosa Ziehau }
260815516c77SSepherosa Ziehau 
260915516c77SSepherosa Ziehau static void
261015516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused)
261115516c77SSepherosa Ziehau {
261215516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
261315516c77SSepherosa Ziehau 
261415516c77SSepherosa Ziehau 	/* Re-allow link status checks. */
261515516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG;
261615516c77SSepherosa Ziehau 	hn_link_status(sc);
261715516c77SSepherosa Ziehau }
261815516c77SSepherosa Ziehau 
261915516c77SSepherosa Ziehau static void
262015516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc)
262115516c77SSepherosa Ziehau {
262215516c77SSepherosa Ziehau 
262315516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
262415516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
262515516c77SSepherosa Ziehau }
262615516c77SSepherosa Ziehau 
262715516c77SSepherosa Ziehau static void
262815516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc)
262915516c77SSepherosa Ziehau {
263015516c77SSepherosa Ziehau 
263115516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
263215516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init);
263315516c77SSepherosa Ziehau }
263415516c77SSepherosa Ziehau 
263515516c77SSepherosa Ziehau static __inline int
263615516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
263715516c77SSepherosa Ziehau     struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
263815516c77SSepherosa Ziehau {
263915516c77SSepherosa Ziehau 	struct mbuf *m = *m_head;
264015516c77SSepherosa Ziehau 	int error;
264115516c77SSepherosa Ziehau 
264215516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim"));
264315516c77SSepherosa Ziehau 
264415516c77SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap,
264515516c77SSepherosa Ziehau 	    m, segs, nsegs, BUS_DMA_NOWAIT);
264615516c77SSepherosa Ziehau 	if (error == EFBIG) {
264715516c77SSepherosa Ziehau 		struct mbuf *m_new;
264815516c77SSepherosa Ziehau 
264915516c77SSepherosa Ziehau 		m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX);
265015516c77SSepherosa Ziehau 		if (m_new == NULL)
265115516c77SSepherosa Ziehau 			return ENOBUFS;
265215516c77SSepherosa Ziehau 		else
265315516c77SSepherosa Ziehau 			*m_head = m = m_new;
265415516c77SSepherosa Ziehau 		txr->hn_tx_collapsed++;
265515516c77SSepherosa Ziehau 
265615516c77SSepherosa Ziehau 		error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag,
265715516c77SSepherosa Ziehau 		    txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT);
265815516c77SSepherosa Ziehau 	}
265915516c77SSepherosa Ziehau 	if (!error) {
266015516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap,
266115516c77SSepherosa Ziehau 		    BUS_DMASYNC_PREWRITE);
266215516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_DMAMAP;
266315516c77SSepherosa Ziehau 	}
266415516c77SSepherosa Ziehau 	return error;
266515516c77SSepherosa Ziehau }
266615516c77SSepherosa Ziehau 
266715516c77SSepherosa Ziehau static __inline int
266815516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd)
266915516c77SSepherosa Ziehau {
267015516c77SSepherosa Ziehau 
267115516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0,
267215516c77SSepherosa Ziehau 	    ("put an onlist txd %#x", txd->flags));
2673dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2674dc13fee6SSepherosa Ziehau 	    ("put an onagg txd %#x", txd->flags));
267515516c77SSepherosa Ziehau 
267615516c77SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
267715516c77SSepherosa Ziehau 	if (atomic_fetchadd_int(&txd->refs, -1) != 1)
267815516c77SSepherosa Ziehau 		return 0;
267915516c77SSepherosa Ziehau 
2680dc13fee6SSepherosa Ziehau 	if (!STAILQ_EMPTY(&txd->agg_list)) {
2681dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tmp_txd;
2682dc13fee6SSepherosa Ziehau 
2683dc13fee6SSepherosa Ziehau 		while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) {
2684dc13fee6SSepherosa Ziehau 			int freed;
2685dc13fee6SSepherosa Ziehau 
2686dc13fee6SSepherosa Ziehau 			KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list),
2687dc13fee6SSepherosa Ziehau 			    ("resursive aggregation on aggregated txdesc"));
2688dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG),
2689dc13fee6SSepherosa Ziehau 			    ("not aggregated txdesc"));
2690dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
2691dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc uses dmamap"));
2692dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
2693dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc consumes "
2694dc13fee6SSepherosa Ziehau 			     "chimney sending buffer"));
2695dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_size == 0,
2696dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc has non-zero "
2697dc13fee6SSepherosa Ziehau 			     "chimney sending size"));
2698dc13fee6SSepherosa Ziehau 
2699dc13fee6SSepherosa Ziehau 			STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link);
2700dc13fee6SSepherosa Ziehau 			tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG;
2701dc13fee6SSepherosa Ziehau 			freed = hn_txdesc_put(txr, tmp_txd);
2702dc13fee6SSepherosa Ziehau 			KASSERT(freed, ("failed to free aggregated txdesc"));
2703dc13fee6SSepherosa Ziehau 		}
2704dc13fee6SSepherosa Ziehau 	}
2705dc13fee6SSepherosa Ziehau 
270615516c77SSepherosa Ziehau 	if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) {
270715516c77SSepherosa Ziehau 		KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
270815516c77SSepherosa Ziehau 		    ("chim txd uses dmamap"));
270915516c77SSepherosa Ziehau 		hn_chim_free(txr->hn_sc, txd->chim_index);
271015516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
2711dc13fee6SSepherosa Ziehau 		txd->chim_size = 0;
271215516c77SSepherosa Ziehau 	} else if (txd->flags & HN_TXD_FLAG_DMAMAP) {
271315516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag,
271415516c77SSepherosa Ziehau 		    txd->data_dmap, BUS_DMASYNC_POSTWRITE);
271515516c77SSepherosa Ziehau 		bus_dmamap_unload(txr->hn_tx_data_dtag,
271615516c77SSepherosa Ziehau 		    txd->data_dmap);
271715516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_DMAMAP;
271815516c77SSepherosa Ziehau 	}
271915516c77SSepherosa Ziehau 
272015516c77SSepherosa Ziehau 	if (txd->m != NULL) {
272115516c77SSepherosa Ziehau 		m_freem(txd->m);
272215516c77SSepherosa Ziehau 		txd->m = NULL;
272315516c77SSepherosa Ziehau 	}
272415516c77SSepherosa Ziehau 
272515516c77SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONLIST;
272615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
272715516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
272815516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_avail >= 0 &&
272915516c77SSepherosa Ziehau 	    txr->hn_txdesc_avail < txr->hn_txdesc_cnt,
273015516c77SSepherosa Ziehau 	    ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail));
273115516c77SSepherosa Ziehau 	txr->hn_txdesc_avail++;
273215516c77SSepherosa Ziehau 	SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
273315516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
273485e4ae1eSSepherosa Ziehau #else	/* HN_USE_TXDESC_BUFRING */
273585e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
273615516c77SSepherosa Ziehau 	atomic_add_int(&txr->hn_txdesc_avail, 1);
273715516c77SSepherosa Ziehau #endif
273885e4ae1eSSepherosa Ziehau 	buf_ring_enqueue(txr->hn_txdesc_br, txd);
273985e4ae1eSSepherosa Ziehau #endif	/* !HN_USE_TXDESC_BUFRING */
274015516c77SSepherosa Ziehau 
274115516c77SSepherosa Ziehau 	return 1;
274215516c77SSepherosa Ziehau }
274315516c77SSepherosa Ziehau 
274415516c77SSepherosa Ziehau static __inline struct hn_txdesc *
274515516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr)
274615516c77SSepherosa Ziehau {
274715516c77SSepherosa Ziehau 	struct hn_txdesc *txd;
274815516c77SSepherosa Ziehau 
274915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
275015516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
275115516c77SSepherosa Ziehau 	txd = SLIST_FIRST(&txr->hn_txlist);
275215516c77SSepherosa Ziehau 	if (txd != NULL) {
275315516c77SSepherosa Ziehau 		KASSERT(txr->hn_txdesc_avail > 0,
275415516c77SSepherosa Ziehau 		    ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail));
275515516c77SSepherosa Ziehau 		txr->hn_txdesc_avail--;
275615516c77SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&txr->hn_txlist, link);
275715516c77SSepherosa Ziehau 	}
275815516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
275915516c77SSepherosa Ziehau #else
276015516c77SSepherosa Ziehau 	txd = buf_ring_dequeue_sc(txr->hn_txdesc_br);
276115516c77SSepherosa Ziehau #endif
276215516c77SSepherosa Ziehau 
276315516c77SSepherosa Ziehau 	if (txd != NULL) {
276415516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
276585e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
276615516c77SSepherosa Ziehau 		atomic_subtract_int(&txr->hn_txdesc_avail, 1);
276715516c77SSepherosa Ziehau #endif
276885e4ae1eSSepherosa Ziehau #endif	/* HN_USE_TXDESC_BUFRING */
276915516c77SSepherosa Ziehau 		KASSERT(txd->m == NULL && txd->refs == 0 &&
2770dc13fee6SSepherosa Ziehau 		    STAILQ_EMPTY(&txd->agg_list) &&
277115516c77SSepherosa Ziehau 		    txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
2772dc13fee6SSepherosa Ziehau 		    txd->chim_size == 0 &&
277315516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONLIST) &&
2774dc13fee6SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONAGG) == 0 &&
277515516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd"));
277615516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_ONLIST;
277715516c77SSepherosa Ziehau 		txd->refs = 1;
277815516c77SSepherosa Ziehau 	}
277915516c77SSepherosa Ziehau 	return txd;
278015516c77SSepherosa Ziehau }
278115516c77SSepherosa Ziehau 
278215516c77SSepherosa Ziehau static __inline void
278315516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd)
278415516c77SSepherosa Ziehau {
278515516c77SSepherosa Ziehau 
278615516c77SSepherosa Ziehau 	/* 0->1 transition will never work */
278725641fc7SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
278815516c77SSepherosa Ziehau 	atomic_add_int(&txd->refs, 1);
278915516c77SSepherosa Ziehau }
279015516c77SSepherosa Ziehau 
2791dc13fee6SSepherosa Ziehau static __inline void
2792dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd)
2793dc13fee6SSepherosa Ziehau {
2794dc13fee6SSepherosa Ziehau 
2795dc13fee6SSepherosa Ziehau 	KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2796dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on aggregating txdesc"));
2797dc13fee6SSepherosa Ziehau 
2798dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2799dc13fee6SSepherosa Ziehau 	    ("already aggregated"));
2800dc13fee6SSepherosa Ziehau 	KASSERT(STAILQ_EMPTY(&txd->agg_list),
2801dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on to-be-aggregated txdesc"));
2802dc13fee6SSepherosa Ziehau 
2803dc13fee6SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONAGG;
2804dc13fee6SSepherosa Ziehau 	STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link);
2805dc13fee6SSepherosa Ziehau }
2806dc13fee6SSepherosa Ziehau 
280715516c77SSepherosa Ziehau static bool
280815516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr)
280915516c77SSepherosa Ziehau {
281015516c77SSepherosa Ziehau 	bool pending = false;
281115516c77SSepherosa Ziehau 
281215516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
281315516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
281415516c77SSepherosa Ziehau 	if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt)
281515516c77SSepherosa Ziehau 		pending = true;
281615516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
281715516c77SSepherosa Ziehau #else
281815516c77SSepherosa Ziehau 	if (!buf_ring_full(txr->hn_txdesc_br))
281915516c77SSepherosa Ziehau 		pending = true;
282015516c77SSepherosa Ziehau #endif
282115516c77SSepherosa Ziehau 	return (pending);
282215516c77SSepherosa Ziehau }
282315516c77SSepherosa Ziehau 
282415516c77SSepherosa Ziehau static __inline void
282515516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr)
282615516c77SSepherosa Ziehau {
282715516c77SSepherosa Ziehau 	txr->hn_has_txeof = 0;
282815516c77SSepherosa Ziehau 	txr->hn_txeof(txr);
282915516c77SSepherosa Ziehau }
283015516c77SSepherosa Ziehau 
283115516c77SSepherosa Ziehau static void
283215516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc,
283315516c77SSepherosa Ziehau     struct vmbus_channel *chan, const void *data __unused, int dlen __unused)
283415516c77SSepherosa Ziehau {
283515516c77SSepherosa Ziehau 	struct hn_txdesc *txd = sndc->hn_cbarg;
283615516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
283715516c77SSepherosa Ziehau 
283815516c77SSepherosa Ziehau 	txr = txd->txr;
283915516c77SSepherosa Ziehau 	KASSERT(txr->hn_chan == chan,
284015516c77SSepherosa Ziehau 	    ("channel mismatch, on chan%u, should be chan%u",
2841aa1a2adcSSepherosa Ziehau 	     vmbus_chan_id(chan), vmbus_chan_id(txr->hn_chan)));
284215516c77SSepherosa Ziehau 
284315516c77SSepherosa Ziehau 	txr->hn_has_txeof = 1;
284415516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
284515516c77SSepherosa Ziehau 
284615516c77SSepherosa Ziehau 	++txr->hn_txdone_cnt;
284715516c77SSepherosa Ziehau 	if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) {
284815516c77SSepherosa Ziehau 		txr->hn_txdone_cnt = 0;
284915516c77SSepherosa Ziehau 		if (txr->hn_oactive)
285015516c77SSepherosa Ziehau 			hn_txeof(txr);
285115516c77SSepherosa Ziehau 	}
285215516c77SSepherosa Ziehau }
285315516c77SSepherosa Ziehau 
285415516c77SSepherosa Ziehau static void
285515516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
285615516c77SSepherosa Ziehau {
285715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
285815516c77SSepherosa Ziehau 	tcp_lro_flush_all(&rxr->hn_lro);
285915516c77SSepherosa Ziehau #endif
286015516c77SSepherosa Ziehau 
286115516c77SSepherosa Ziehau 	/*
286215516c77SSepherosa Ziehau 	 * NOTE:
286315516c77SSepherosa Ziehau 	 * 'txr' could be NULL, if multiple channels and
286415516c77SSepherosa Ziehau 	 * ifnet.if_start method are enabled.
286515516c77SSepherosa Ziehau 	 */
286615516c77SSepherosa Ziehau 	if (txr == NULL || !txr->hn_has_txeof)
286715516c77SSepherosa Ziehau 		return;
286815516c77SSepherosa Ziehau 
286915516c77SSepherosa Ziehau 	txr->hn_txdone_cnt = 0;
287015516c77SSepherosa Ziehau 	hn_txeof(txr);
287115516c77SSepherosa Ziehau }
287215516c77SSepherosa Ziehau 
287315516c77SSepherosa Ziehau static __inline uint32_t
287415516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs)
287515516c77SSepherosa Ziehau {
287615516c77SSepherosa Ziehau 
287715516c77SSepherosa Ziehau 	KASSERT(ofs >= sizeof(struct rndis_packet_msg),
287815516c77SSepherosa Ziehau 	    ("invalid RNDIS packet msg offset %u", ofs));
287915516c77SSepherosa Ziehau 	return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset));
288015516c77SSepherosa Ziehau }
288115516c77SSepherosa Ziehau 
288215516c77SSepherosa Ziehau static __inline void *
288315516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
288415516c77SSepherosa Ziehau     size_t pi_dlen, uint32_t pi_type)
288515516c77SSepherosa Ziehau {
288615516c77SSepherosa Ziehau 	const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
288715516c77SSepherosa Ziehau 	struct rndis_pktinfo *pi;
288815516c77SSepherosa Ziehau 
288915516c77SSepherosa Ziehau 	KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
289015516c77SSepherosa Ziehau 	    ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
289115516c77SSepherosa Ziehau 
289215516c77SSepherosa Ziehau 	/*
289315516c77SSepherosa Ziehau 	 * Per-packet-info does not move; it only grows.
289415516c77SSepherosa Ziehau 	 *
289515516c77SSepherosa Ziehau 	 * NOTE:
289615516c77SSepherosa Ziehau 	 * rm_pktinfooffset in this phase counts from the beginning
289715516c77SSepherosa Ziehau 	 * of rndis_packet_msg.
289815516c77SSepherosa Ziehau 	 */
289915516c77SSepherosa Ziehau 	KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
290015516c77SSepherosa Ziehau 	    ("%u pktinfo overflows RNDIS packet msg", pi_type));
290115516c77SSepherosa Ziehau 	pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
290215516c77SSepherosa Ziehau 	    pkt->rm_pktinfolen);
290315516c77SSepherosa Ziehau 	pkt->rm_pktinfolen += pi_size;
290415516c77SSepherosa Ziehau 
290515516c77SSepherosa Ziehau 	pi->rm_size = pi_size;
290615516c77SSepherosa Ziehau 	pi->rm_type = pi_type;
290715516c77SSepherosa Ziehau 	pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
290815516c77SSepherosa Ziehau 
290915516c77SSepherosa Ziehau 	return (pi->rm_data);
291015516c77SSepherosa Ziehau }
291115516c77SSepherosa Ziehau 
2912dc13fee6SSepherosa Ziehau static __inline int
2913dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr)
2914dc13fee6SSepherosa Ziehau {
2915dc13fee6SSepherosa Ziehau 	struct hn_txdesc *txd;
2916dc13fee6SSepherosa Ziehau 	struct mbuf *m;
2917dc13fee6SSepherosa Ziehau 	int error, pkts;
2918dc13fee6SSepherosa Ziehau 
2919dc13fee6SSepherosa Ziehau 	txd = txr->hn_agg_txd;
2920dc13fee6SSepherosa Ziehau 	KASSERT(txd != NULL, ("no aggregate txdesc"));
2921dc13fee6SSepherosa Ziehau 
2922dc13fee6SSepherosa Ziehau 	/*
2923dc13fee6SSepherosa Ziehau 	 * Since hn_txpkt() will reset this temporary stat, save
2924dc13fee6SSepherosa Ziehau 	 * it now, so that oerrors can be updated properly, if
2925dc13fee6SSepherosa Ziehau 	 * hn_txpkt() ever fails.
2926dc13fee6SSepherosa Ziehau 	 */
2927dc13fee6SSepherosa Ziehau 	pkts = txr->hn_stat_pkts;
2928dc13fee6SSepherosa Ziehau 
2929dc13fee6SSepherosa Ziehau 	/*
2930dc13fee6SSepherosa Ziehau 	 * Since txd's mbuf will _not_ be freed upon hn_txpkt()
2931dc13fee6SSepherosa Ziehau 	 * failure, save it for later freeing, if hn_txpkt() ever
2932dc13fee6SSepherosa Ziehau 	 * fails.
2933dc13fee6SSepherosa Ziehau 	 */
2934dc13fee6SSepherosa Ziehau 	m = txd->m;
2935dc13fee6SSepherosa Ziehau 	error = hn_txpkt(ifp, txr, txd);
2936dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
2937dc13fee6SSepherosa Ziehau 		/* txd is freed, but m is not. */
2938dc13fee6SSepherosa Ziehau 		m_freem(m);
2939dc13fee6SSepherosa Ziehau 
2940dc13fee6SSepherosa Ziehau 		txr->hn_flush_failed++;
2941dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts);
2942dc13fee6SSepherosa Ziehau 	}
2943dc13fee6SSepherosa Ziehau 
2944dc13fee6SSepherosa Ziehau 	/* Reset all aggregation states. */
2945dc13fee6SSepherosa Ziehau 	txr->hn_agg_txd = NULL;
2946dc13fee6SSepherosa Ziehau 	txr->hn_agg_szleft = 0;
2947dc13fee6SSepherosa Ziehau 	txr->hn_agg_pktleft = 0;
2948dc13fee6SSepherosa Ziehau 	txr->hn_agg_prevpkt = NULL;
2949dc13fee6SSepherosa Ziehau 
2950dc13fee6SSepherosa Ziehau 	return (error);
2951dc13fee6SSepherosa Ziehau }
2952dc13fee6SSepherosa Ziehau 
2953dc13fee6SSepherosa Ziehau static void *
2954dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
2955dc13fee6SSepherosa Ziehau     int pktsize)
2956dc13fee6SSepherosa Ziehau {
2957dc13fee6SSepherosa Ziehau 	void *chim;
2958dc13fee6SSepherosa Ziehau 
2959dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL) {
2960dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) {
2961dc13fee6SSepherosa Ziehau 			struct hn_txdesc *agg_txd = txr->hn_agg_txd;
2962dc13fee6SSepherosa Ziehau 			struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt;
2963dc13fee6SSepherosa Ziehau 			int olen;
2964dc13fee6SSepherosa Ziehau 
2965dc13fee6SSepherosa Ziehau 			/*
2966dc13fee6SSepherosa Ziehau 			 * Update the previous RNDIS packet's total length,
2967dc13fee6SSepherosa Ziehau 			 * it can be increased due to the mandatory alignment
2968dc13fee6SSepherosa Ziehau 			 * padding for this RNDIS packet.  And update the
2969dc13fee6SSepherosa Ziehau 			 * aggregating txdesc's chimney sending buffer size
2970dc13fee6SSepherosa Ziehau 			 * accordingly.
2971dc13fee6SSepherosa Ziehau 			 *
2972dc13fee6SSepherosa Ziehau 			 * XXX
2973dc13fee6SSepherosa Ziehau 			 * Zero-out the padding, as required by the RNDIS spec.
2974dc13fee6SSepherosa Ziehau 			 */
2975dc13fee6SSepherosa Ziehau 			olen = pkt->rm_len;
2976dc13fee6SSepherosa Ziehau 			pkt->rm_len = roundup2(olen, txr->hn_agg_align);
2977dc13fee6SSepherosa Ziehau 			agg_txd->chim_size += pkt->rm_len - olen;
2978dc13fee6SSepherosa Ziehau 
2979dc13fee6SSepherosa Ziehau 			/* Link this txdesc to the parent. */
2980dc13fee6SSepherosa Ziehau 			hn_txdesc_agg(agg_txd, txd);
2981dc13fee6SSepherosa Ziehau 
2982dc13fee6SSepherosa Ziehau 			chim = (uint8_t *)pkt + pkt->rm_len;
2983dc13fee6SSepherosa Ziehau 			/* Save the current packet for later fixup. */
2984dc13fee6SSepherosa Ziehau 			txr->hn_agg_prevpkt = chim;
2985dc13fee6SSepherosa Ziehau 
2986dc13fee6SSepherosa Ziehau 			txr->hn_agg_pktleft--;
2987dc13fee6SSepherosa Ziehau 			txr->hn_agg_szleft -= pktsize;
2988dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_szleft <=
2989dc13fee6SSepherosa Ziehau 			    HN_PKTSIZE_MIN(txr->hn_agg_align)) {
2990dc13fee6SSepherosa Ziehau 				/*
2991dc13fee6SSepherosa Ziehau 				 * Probably can't aggregate more packets,
2992dc13fee6SSepherosa Ziehau 				 * flush this aggregating txdesc proactively.
2993dc13fee6SSepherosa Ziehau 				 */
2994dc13fee6SSepherosa Ziehau 				txr->hn_agg_pktleft = 0;
2995dc13fee6SSepherosa Ziehau 			}
2996dc13fee6SSepherosa Ziehau 			/* Done! */
2997dc13fee6SSepherosa Ziehau 			return (chim);
2998dc13fee6SSepherosa Ziehau 		}
2999dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
3000dc13fee6SSepherosa Ziehau 	}
3001dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
3002dc13fee6SSepherosa Ziehau 
3003dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney_tried++;
3004dc13fee6SSepherosa Ziehau 	txd->chim_index = hn_chim_alloc(txr->hn_sc);
3005dc13fee6SSepherosa Ziehau 	if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID)
3006dc13fee6SSepherosa Ziehau 		return (NULL);
3007dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney++;
3008dc13fee6SSepherosa Ziehau 
3009dc13fee6SSepherosa Ziehau 	chim = txr->hn_sc->hn_chim +
3010dc13fee6SSepherosa Ziehau 	    (txd->chim_index * txr->hn_sc->hn_chim_szmax);
3011dc13fee6SSepherosa Ziehau 
3012dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_pktmax > 1 &&
3013dc13fee6SSepherosa Ziehau 	    txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) {
3014dc13fee6SSepherosa Ziehau 		txr->hn_agg_txd = txd;
3015dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1;
3016dc13fee6SSepherosa Ziehau 		txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize;
3017dc13fee6SSepherosa Ziehau 		txr->hn_agg_prevpkt = chim;
3018dc13fee6SSepherosa Ziehau 	}
3019dc13fee6SSepherosa Ziehau 	return (chim);
3020dc13fee6SSepherosa Ziehau }
3021dc13fee6SSepherosa Ziehau 
302215516c77SSepherosa Ziehau /*
302315516c77SSepherosa Ziehau  * NOTE:
302415516c77SSepherosa Ziehau  * If this function fails, then both txd and m_head0 will be freed.
302515516c77SSepherosa Ziehau  */
302615516c77SSepherosa Ziehau static int
3027dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
3028dc13fee6SSepherosa Ziehau     struct mbuf **m_head0)
302915516c77SSepherosa Ziehau {
303015516c77SSepherosa Ziehau 	bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX];
303115516c77SSepherosa Ziehau 	int error, nsegs, i;
303215516c77SSepherosa Ziehau 	struct mbuf *m_head = *m_head0;
303315516c77SSepherosa Ziehau 	struct rndis_packet_msg *pkt;
303415516c77SSepherosa Ziehau 	uint32_t *pi_data;
30358966e5d5SSepherosa Ziehau 	void *chim = NULL;
3036dc13fee6SSepherosa Ziehau 	int pkt_hlen, pkt_size;
303715516c77SSepherosa Ziehau 
303815516c77SSepherosa Ziehau 	pkt = txd->rndis_pkt;
3039dc13fee6SSepherosa Ziehau 	pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align);
3040dc13fee6SSepherosa Ziehau 	if (pkt_size < txr->hn_chim_size) {
3041dc13fee6SSepherosa Ziehau 		chim = hn_try_txagg(ifp, txr, txd, pkt_size);
3042dc13fee6SSepherosa Ziehau 		if (chim != NULL)
30438966e5d5SSepherosa Ziehau 			pkt = chim;
3044dc13fee6SSepherosa Ziehau 	} else {
3045dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL)
3046dc13fee6SSepherosa Ziehau 			hn_flush_txagg(ifp, txr);
30478966e5d5SSepherosa Ziehau 	}
30488966e5d5SSepherosa Ziehau 
304915516c77SSepherosa Ziehau 	pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
30508fe90f73SSepherosa Ziehau 	pkt->rm_len = m_head->m_pkthdr.len;
30519130c4f7SSepherosa Ziehau 	pkt->rm_dataoffset = 0;
305215516c77SSepherosa Ziehau 	pkt->rm_datalen = m_head->m_pkthdr.len;
3053dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataoffset = 0;
3054dc13fee6SSepherosa Ziehau 	pkt->rm_oobdatalen = 0;
3055dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataelements = 0;
305615516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = sizeof(*pkt);
305715516c77SSepherosa Ziehau 	pkt->rm_pktinfolen = 0;
3058dc13fee6SSepherosa Ziehau 	pkt->rm_vchandle = 0;
3059dc13fee6SSepherosa Ziehau 	pkt->rm_reserved = 0;
306015516c77SSepherosa Ziehau 
306115516c77SSepherosa Ziehau 	if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) {
306215516c77SSepherosa Ziehau 		/*
306315516c77SSepherosa Ziehau 		 * Set the hash value for this packet, so that the host could
306415516c77SSepherosa Ziehau 		 * dispatch the TX done event for this packet back to this TX
306515516c77SSepherosa Ziehau 		 * ring's channel.
306615516c77SSepherosa Ziehau 		 */
306715516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
306815516c77SSepherosa Ziehau 		    HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL);
306915516c77SSepherosa Ziehau 		*pi_data = txr->hn_tx_idx;
307015516c77SSepherosa Ziehau 	}
307115516c77SSepherosa Ziehau 
307215516c77SSepherosa Ziehau 	if (m_head->m_flags & M_VLANTAG) {
307315516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
307415516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
307515516c77SSepherosa Ziehau 		*pi_data = NDIS_VLAN_INFO_MAKE(
307615516c77SSepherosa Ziehau 		    EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag),
307715516c77SSepherosa Ziehau 		    EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag),
307815516c77SSepherosa Ziehau 		    EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag));
307915516c77SSepherosa Ziehau 	}
308015516c77SSepherosa Ziehau 
308115516c77SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
308215516c77SSepherosa Ziehau #if defined(INET6) || defined(INET)
308315516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
308415516c77SSepherosa Ziehau 		    NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO);
308515516c77SSepherosa Ziehau #ifdef INET
308615516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
3087c49d47daSSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV4(
3088c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen,
308915516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
309015516c77SSepherosa Ziehau 		}
309115516c77SSepherosa Ziehau #endif
309215516c77SSepherosa Ziehau #if defined(INET6) && defined(INET)
309315516c77SSepherosa Ziehau 		else
309415516c77SSepherosa Ziehau #endif
309515516c77SSepherosa Ziehau #ifdef INET6
309615516c77SSepherosa Ziehau 		{
3097c49d47daSSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV6(
3098c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen,
309915516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
310015516c77SSepherosa Ziehau 		}
310115516c77SSepherosa Ziehau #endif
310215516c77SSepherosa Ziehau #endif	/* INET6 || INET */
310315516c77SSepherosa Ziehau 	} else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) {
310415516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
310515516c77SSepherosa Ziehau 		    NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
310615516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
310715516c77SSepherosa Ziehau 		    (CSUM_IP6_TCP | CSUM_IP6_UDP)) {
310815516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV6;
310915516c77SSepherosa Ziehau 		} else {
311015516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV4;
311115516c77SSepherosa Ziehau 			if (m_head->m_pkthdr.csum_flags & CSUM_IP)
311215516c77SSepherosa Ziehau 				*pi_data |= NDIS_TXCSUM_INFO_IPCS;
311315516c77SSepherosa Ziehau 		}
311415516c77SSepherosa Ziehau 
3115c49d47daSSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
3116c49d47daSSepherosa Ziehau 		    (CSUM_IP_TCP | CSUM_IP6_TCP)) {
3117c49d47daSSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_MKTCPCS(
3118c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen);
3119c49d47daSSepherosa Ziehau 		} else if (m_head->m_pkthdr.csum_flags &
3120c49d47daSSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP6_UDP)) {
3121c49d47daSSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_MKUDPCS(
3122c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen);
3123c49d47daSSepherosa Ziehau 		}
312415516c77SSepherosa Ziehau 	}
312515516c77SSepherosa Ziehau 
3126dc13fee6SSepherosa Ziehau 	pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
31278fe90f73SSepherosa Ziehau 	/* Fixup RNDIS packet message total length */
31288fe90f73SSepherosa Ziehau 	pkt->rm_len += pkt_hlen;
312915516c77SSepherosa Ziehau 	/* Convert RNDIS packet message offsets */
31309130c4f7SSepherosa Ziehau 	pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt_hlen);
313115516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset);
313215516c77SSepherosa Ziehau 
313315516c77SSepherosa Ziehau 	/*
31348966e5d5SSepherosa Ziehau 	 * Fast path: Chimney sending.
313515516c77SSepherosa Ziehau 	 */
31368966e5d5SSepherosa Ziehau 	if (chim != NULL) {
3137dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tgt_txd = txd;
3138dc13fee6SSepherosa Ziehau 
3139dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL) {
3140dc13fee6SSepherosa Ziehau 			tgt_txd = txr->hn_agg_txd;
3141dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
3142dc13fee6SSepherosa Ziehau 			*m_head0 = NULL;
3143dc13fee6SSepherosa Ziehau #endif
3144dc13fee6SSepherosa Ziehau 		}
3145dc13fee6SSepherosa Ziehau 
3146dc13fee6SSepherosa Ziehau 		KASSERT(pkt == chim,
3147dc13fee6SSepherosa Ziehau 		    ("RNDIS pkt not in chimney sending buffer"));
3148dc13fee6SSepherosa Ziehau 		KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID,
3149dc13fee6SSepherosa Ziehau 		    ("chimney sending buffer is not used"));
3150dc13fee6SSepherosa Ziehau 		tgt_txd->chim_size += pkt->rm_len;
315115516c77SSepherosa Ziehau 
31528966e5d5SSepherosa Ziehau 		m_copydata(m_head, 0, m_head->m_pkthdr.len,
3153dc13fee6SSepherosa Ziehau 		    ((uint8_t *)chim) + pkt_hlen);
315415516c77SSepherosa Ziehau 
315515516c77SSepherosa Ziehau 		txr->hn_gpa_cnt = 0;
315615516c77SSepherosa Ziehau 		txr->hn_sendpkt = hn_txpkt_chim;
315715516c77SSepherosa Ziehau 		goto done;
315815516c77SSepherosa Ziehau 	}
3159dc13fee6SSepherosa Ziehau 
3160dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc"));
31618966e5d5SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
31628966e5d5SSepherosa Ziehau 	    ("chimney buffer is used"));
31638966e5d5SSepherosa Ziehau 	KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc"));
316415516c77SSepherosa Ziehau 
316515516c77SSepherosa Ziehau 	error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs);
3166dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
316715516c77SSepherosa Ziehau 		int freed;
316815516c77SSepherosa Ziehau 
316915516c77SSepherosa Ziehau 		/*
317015516c77SSepherosa Ziehau 		 * This mbuf is not linked w/ the txd yet, so free it now.
317115516c77SSepherosa Ziehau 		 */
317215516c77SSepherosa Ziehau 		m_freem(m_head);
317315516c77SSepherosa Ziehau 		*m_head0 = NULL;
317415516c77SSepherosa Ziehau 
317515516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
317615516c77SSepherosa Ziehau 		KASSERT(freed != 0,
317715516c77SSepherosa Ziehau 		    ("fail to free txd upon txdma error"));
317815516c77SSepherosa Ziehau 
317915516c77SSepherosa Ziehau 		txr->hn_txdma_failed++;
3180dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
318115516c77SSepherosa Ziehau 		return error;
318215516c77SSepherosa Ziehau 	}
318315516c77SSepherosa Ziehau 	*m_head0 = m_head;
318415516c77SSepherosa Ziehau 
318515516c77SSepherosa Ziehau 	/* +1 RNDIS packet message */
318615516c77SSepherosa Ziehau 	txr->hn_gpa_cnt = nsegs + 1;
318715516c77SSepherosa Ziehau 
318815516c77SSepherosa Ziehau 	/* send packet with page buffer */
318915516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr);
319015516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK;
3191dc13fee6SSepherosa Ziehau 	txr->hn_gpa[0].gpa_len = pkt_hlen;
319215516c77SSepherosa Ziehau 
319315516c77SSepherosa Ziehau 	/*
319415516c77SSepherosa Ziehau 	 * Fill the page buffers with mbuf info after the page
319515516c77SSepherosa Ziehau 	 * buffer for RNDIS packet message.
319615516c77SSepherosa Ziehau 	 */
319715516c77SSepherosa Ziehau 	for (i = 0; i < nsegs; ++i) {
319815516c77SSepherosa Ziehau 		struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1];
319915516c77SSepherosa Ziehau 
320015516c77SSepherosa Ziehau 		gpa->gpa_page = atop(segs[i].ds_addr);
320115516c77SSepherosa Ziehau 		gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK;
320215516c77SSepherosa Ziehau 		gpa->gpa_len = segs[i].ds_len;
320315516c77SSepherosa Ziehau 	}
320415516c77SSepherosa Ziehau 
320515516c77SSepherosa Ziehau 	txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
320615516c77SSepherosa Ziehau 	txd->chim_size = 0;
320715516c77SSepherosa Ziehau 	txr->hn_sendpkt = hn_txpkt_sglist;
320815516c77SSepherosa Ziehau done:
320915516c77SSepherosa Ziehau 	txd->m = m_head;
321015516c77SSepherosa Ziehau 
321115516c77SSepherosa Ziehau 	/* Set the completion routine */
321215516c77SSepherosa Ziehau 	hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd);
321315516c77SSepherosa Ziehau 
3214dc13fee6SSepherosa Ziehau 	/* Update temporary stats for later use. */
3215dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts++;
3216dc13fee6SSepherosa Ziehau 	txr->hn_stat_size += m_head->m_pkthdr.len;
3217dc13fee6SSepherosa Ziehau 	if (m_head->m_flags & M_MCAST)
3218dc13fee6SSepherosa Ziehau 		txr->hn_stat_mcasts++;
3219dc13fee6SSepherosa Ziehau 
322015516c77SSepherosa Ziehau 	return 0;
322115516c77SSepherosa Ziehau }
322215516c77SSepherosa Ziehau 
322315516c77SSepherosa Ziehau /*
322415516c77SSepherosa Ziehau  * NOTE:
322515516c77SSepherosa Ziehau  * If this function fails, then txd will be freed, but the mbuf
322615516c77SSepherosa Ziehau  * associated w/ the txd will _not_ be freed.
322715516c77SSepherosa Ziehau  */
322815516c77SSepherosa Ziehau static int
322915516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd)
323015516c77SSepherosa Ziehau {
32318e7d3136SSepherosa Ziehau 	int error, send_failed = 0, has_bpf;
323215516c77SSepherosa Ziehau 
323315516c77SSepherosa Ziehau again:
32348e7d3136SSepherosa Ziehau 	has_bpf = bpf_peers_present(ifp->if_bpf);
32358e7d3136SSepherosa Ziehau 	if (has_bpf) {
323615516c77SSepherosa Ziehau 		/*
32378e7d3136SSepherosa Ziehau 		 * Make sure that this txd and any aggregated txds are not
32388e7d3136SSepherosa Ziehau 		 * freed before ETHER_BPF_MTAP.
323915516c77SSepherosa Ziehau 		 */
324015516c77SSepherosa Ziehau 		hn_txdesc_hold(txd);
32418e7d3136SSepherosa Ziehau 	}
324215516c77SSepherosa Ziehau 	error = txr->hn_sendpkt(txr, txd);
324315516c77SSepherosa Ziehau 	if (!error) {
32448e7d3136SSepherosa Ziehau 		if (has_bpf) {
3245dc13fee6SSepherosa Ziehau 			const struct hn_txdesc *tmp_txd;
3246dc13fee6SSepherosa Ziehau 
324715516c77SSepherosa Ziehau 			ETHER_BPF_MTAP(ifp, txd->m);
3248dc13fee6SSepherosa Ziehau 			STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link)
3249dc13fee6SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, tmp_txd->m);
3250dc13fee6SSepherosa Ziehau 		}
3251dc13fee6SSepherosa Ziehau 
3252dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts);
325323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
325423bf9e15SSepherosa Ziehau 		if (!hn_use_if_start)
325523bf9e15SSepherosa Ziehau #endif
325623bf9e15SSepherosa Ziehau 		{
325715516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OBYTES,
3258dc13fee6SSepherosa Ziehau 			    txr->hn_stat_size);
3259dc13fee6SSepherosa Ziehau 			if (txr->hn_stat_mcasts != 0) {
3260dc13fee6SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OMCASTS,
3261dc13fee6SSepherosa Ziehau 				    txr->hn_stat_mcasts);
326215516c77SSepherosa Ziehau 			}
3263dc13fee6SSepherosa Ziehau 		}
3264dc13fee6SSepherosa Ziehau 		txr->hn_pkts += txr->hn_stat_pkts;
3265dc13fee6SSepherosa Ziehau 		txr->hn_sends++;
326615516c77SSepherosa Ziehau 	}
32678e7d3136SSepherosa Ziehau 	if (has_bpf)
326815516c77SSepherosa Ziehau 		hn_txdesc_put(txr, txd);
326915516c77SSepherosa Ziehau 
327015516c77SSepherosa Ziehau 	if (__predict_false(error)) {
327115516c77SSepherosa Ziehau 		int freed;
327215516c77SSepherosa Ziehau 
327315516c77SSepherosa Ziehau 		/*
327415516c77SSepherosa Ziehau 		 * This should "really rarely" happen.
327515516c77SSepherosa Ziehau 		 *
327615516c77SSepherosa Ziehau 		 * XXX Too many RX to be acked or too many sideband
327715516c77SSepherosa Ziehau 		 * commands to run?  Ask netvsc_channel_rollup()
327815516c77SSepherosa Ziehau 		 * to kick start later.
327915516c77SSepherosa Ziehau 		 */
328015516c77SSepherosa Ziehau 		txr->hn_has_txeof = 1;
328115516c77SSepherosa Ziehau 		if (!send_failed) {
328215516c77SSepherosa Ziehau 			txr->hn_send_failed++;
328315516c77SSepherosa Ziehau 			send_failed = 1;
328415516c77SSepherosa Ziehau 			/*
328515516c77SSepherosa Ziehau 			 * Try sending again after set hn_has_txeof;
328615516c77SSepherosa Ziehau 			 * in case that we missed the last
328715516c77SSepherosa Ziehau 			 * netvsc_channel_rollup().
328815516c77SSepherosa Ziehau 			 */
328915516c77SSepherosa Ziehau 			goto again;
329015516c77SSepherosa Ziehau 		}
329115516c77SSepherosa Ziehau 		if_printf(ifp, "send failed\n");
329215516c77SSepherosa Ziehau 
329315516c77SSepherosa Ziehau 		/*
329415516c77SSepherosa Ziehau 		 * Caller will perform further processing on the
329515516c77SSepherosa Ziehau 		 * associated mbuf, so don't free it in hn_txdesc_put();
329615516c77SSepherosa Ziehau 		 * only unload it from the DMA map in hn_txdesc_put(),
329715516c77SSepherosa Ziehau 		 * if it was loaded.
329815516c77SSepherosa Ziehau 		 */
329915516c77SSepherosa Ziehau 		txd->m = NULL;
330015516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
330115516c77SSepherosa Ziehau 		KASSERT(freed != 0,
330215516c77SSepherosa Ziehau 		    ("fail to free txd upon send error"));
330315516c77SSepherosa Ziehau 
330415516c77SSepherosa Ziehau 		txr->hn_send_failed++;
330515516c77SSepherosa Ziehau 	}
3306dc13fee6SSepherosa Ziehau 
3307dc13fee6SSepherosa Ziehau 	/* Reset temporary stats, after this sending is done. */
3308dc13fee6SSepherosa Ziehau 	txr->hn_stat_size = 0;
3309dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts = 0;
3310dc13fee6SSepherosa Ziehau 	txr->hn_stat_mcasts = 0;
3311dc13fee6SSepherosa Ziehau 
3312dc13fee6SSepherosa Ziehau 	return (error);
331315516c77SSepherosa Ziehau }
331415516c77SSepherosa Ziehau 
331515516c77SSepherosa Ziehau /*
331615516c77SSepherosa Ziehau  * Append the specified data to the indicated mbuf chain,
331715516c77SSepherosa Ziehau  * Extend the mbuf chain if the new data does not fit in
331815516c77SSepherosa Ziehau  * existing space.
331915516c77SSepherosa Ziehau  *
332015516c77SSepherosa Ziehau  * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c.
332115516c77SSepherosa Ziehau  * There should be an equivalent in the kernel mbuf code,
332215516c77SSepherosa Ziehau  * but there does not appear to be one yet.
332315516c77SSepherosa Ziehau  *
332415516c77SSepherosa Ziehau  * Differs from m_append() in that additional mbufs are
332515516c77SSepherosa Ziehau  * allocated with cluster size MJUMPAGESIZE, and filled
332615516c77SSepherosa Ziehau  * accordingly.
332715516c77SSepherosa Ziehau  *
332815516c77SSepherosa Ziehau  * Return 1 if able to complete the job; otherwise 0.
332915516c77SSepherosa Ziehau  */
333015516c77SSepherosa Ziehau static int
333115516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp)
333215516c77SSepherosa Ziehau {
333315516c77SSepherosa Ziehau 	struct mbuf *m, *n;
333415516c77SSepherosa Ziehau 	int remainder, space;
333515516c77SSepherosa Ziehau 
333615516c77SSepherosa Ziehau 	for (m = m0; m->m_next != NULL; m = m->m_next)
333715516c77SSepherosa Ziehau 		;
333815516c77SSepherosa Ziehau 	remainder = len;
333915516c77SSepherosa Ziehau 	space = M_TRAILINGSPACE(m);
334015516c77SSepherosa Ziehau 	if (space > 0) {
334115516c77SSepherosa Ziehau 		/*
334215516c77SSepherosa Ziehau 		 * Copy into available space.
334315516c77SSepherosa Ziehau 		 */
334415516c77SSepherosa Ziehau 		if (space > remainder)
334515516c77SSepherosa Ziehau 			space = remainder;
334615516c77SSepherosa Ziehau 		bcopy(cp, mtod(m, caddr_t) + m->m_len, space);
334715516c77SSepherosa Ziehau 		m->m_len += space;
334815516c77SSepherosa Ziehau 		cp += space;
334915516c77SSepherosa Ziehau 		remainder -= space;
335015516c77SSepherosa Ziehau 	}
335115516c77SSepherosa Ziehau 	while (remainder > 0) {
335215516c77SSepherosa Ziehau 		/*
335315516c77SSepherosa Ziehau 		 * Allocate a new mbuf; could check space
335415516c77SSepherosa Ziehau 		 * and allocate a cluster instead.
335515516c77SSepherosa Ziehau 		 */
335615516c77SSepherosa Ziehau 		n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE);
335715516c77SSepherosa Ziehau 		if (n == NULL)
335815516c77SSepherosa Ziehau 			break;
335915516c77SSepherosa Ziehau 		n->m_len = min(MJUMPAGESIZE, remainder);
336015516c77SSepherosa Ziehau 		bcopy(cp, mtod(n, caddr_t), n->m_len);
336115516c77SSepherosa Ziehau 		cp += n->m_len;
336215516c77SSepherosa Ziehau 		remainder -= n->m_len;
336315516c77SSepherosa Ziehau 		m->m_next = n;
336415516c77SSepherosa Ziehau 		m = n;
336515516c77SSepherosa Ziehau 	}
336615516c77SSepherosa Ziehau 	if (m0->m_flags & M_PKTHDR)
336715516c77SSepherosa Ziehau 		m0->m_pkthdr.len += len - remainder;
336815516c77SSepherosa Ziehau 
336915516c77SSepherosa Ziehau 	return (remainder == 0);
337015516c77SSepherosa Ziehau }
337115516c77SSepherosa Ziehau 
337215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
337315516c77SSepherosa Ziehau static __inline int
337415516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m)
337515516c77SSepherosa Ziehau {
337615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
337715516c77SSepherosa Ziehau 	if (hn_lro_mbufq_depth) {
337815516c77SSepherosa Ziehau 		tcp_lro_queue_mbuf(lc, m);
337915516c77SSepherosa Ziehau 		return 0;
338015516c77SSepherosa Ziehau 	}
338115516c77SSepherosa Ziehau #endif
338215516c77SSepherosa Ziehau 	return tcp_lro_rx(lc, m, 0);
338315516c77SSepherosa Ziehau }
338415516c77SSepherosa Ziehau #endif
338515516c77SSepherosa Ziehau 
338615516c77SSepherosa Ziehau static int
338715516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
338815516c77SSepherosa Ziehau     const struct hn_rxinfo *info)
338915516c77SSepherosa Ziehau {
3390a97fff19SSepherosa Ziehau 	struct ifnet *ifp, *hn_ifp = rxr->hn_ifp;
339115516c77SSepherosa Ziehau 	struct mbuf *m_new;
3392642ec226SSepherosa Ziehau 	int size, do_lro = 0, do_csum = 1, is_vf = 0;
3393642ec226SSepherosa Ziehau 	int hash_type = M_HASHTYPE_NONE;
3394db76829bSSepherosa Ziehau 	int l3proto = ETHERTYPE_MAX, l4proto = IPPROTO_DONE;
339515516c77SSepherosa Ziehau 
3396642ec226SSepherosa Ziehau 	ifp = hn_ifp;
3397642ec226SSepherosa Ziehau 	if (rxr->hn_rxvf_ifp != NULL) {
3398a97fff19SSepherosa Ziehau 		/*
3399642ec226SSepherosa Ziehau 		 * Non-transparent mode VF; pretend this packet is from
3400642ec226SSepherosa Ziehau 		 * the VF.
3401a97fff19SSepherosa Ziehau 		 */
3402642ec226SSepherosa Ziehau 		ifp = rxr->hn_rxvf_ifp;
3403642ec226SSepherosa Ziehau 		is_vf = 1;
3404642ec226SSepherosa Ziehau 	} else if (rxr->hn_rx_flags & HN_RX_FLAG_XPNT_VF) {
3405642ec226SSepherosa Ziehau 		/* Transparent mode VF. */
3406642ec226SSepherosa Ziehau 		is_vf = 1;
3407642ec226SSepherosa Ziehau 	}
34085bdfd3fdSDexuan Cui 
3409b3b75d9cSSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
3410b3b75d9cSSepherosa Ziehau 		/*
3411b3b75d9cSSepherosa Ziehau 		 * NOTE:
3412b3b75d9cSSepherosa Ziehau 		 * See the NOTE of hn_rndis_init_fixat().  This
3413b3b75d9cSSepherosa Ziehau 		 * function can be reached, immediately after the
3414b3b75d9cSSepherosa Ziehau 		 * RNDIS is initialized but before the ifnet is
3415b3b75d9cSSepherosa Ziehau 		 * setup on the hn_attach() path; drop the unexpected
3416b3b75d9cSSepherosa Ziehau 		 * packets.
3417b3b75d9cSSepherosa Ziehau 		 */
3418b3b75d9cSSepherosa Ziehau 		return (0);
3419b3b75d9cSSepherosa Ziehau 	}
3420b3b75d9cSSepherosa Ziehau 
3421a97fff19SSepherosa Ziehau 	if (__predict_false(dlen < ETHER_HDR_LEN)) {
3422a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IERRORS, 1);
3423a97fff19SSepherosa Ziehau 		return (0);
3424a97fff19SSepherosa Ziehau 	}
3425a97fff19SSepherosa Ziehau 
3426c927d681SDexuan Cui 	if (dlen <= MHLEN) {
342715516c77SSepherosa Ziehau 		m_new = m_gethdr(M_NOWAIT, MT_DATA);
342815516c77SSepherosa Ziehau 		if (m_new == NULL) {
3429a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1);
343015516c77SSepherosa Ziehau 			return (0);
343115516c77SSepherosa Ziehau 		}
343215516c77SSepherosa Ziehau 		memcpy(mtod(m_new, void *), data, dlen);
343315516c77SSepherosa Ziehau 		m_new->m_pkthdr.len = m_new->m_len = dlen;
343415516c77SSepherosa Ziehau 		rxr->hn_small_pkts++;
343515516c77SSepherosa Ziehau 	} else {
343615516c77SSepherosa Ziehau 		/*
343715516c77SSepherosa Ziehau 		 * Get an mbuf with a cluster.  For packets 2K or less,
343815516c77SSepherosa Ziehau 		 * get a standard 2K cluster.  For anything larger, get a
343915516c77SSepherosa Ziehau 		 * 4K cluster.  Any buffers larger than 4K can cause problems
344015516c77SSepherosa Ziehau 		 * if looped around to the Hyper-V TX channel, so avoid them.
344115516c77SSepherosa Ziehau 		 */
344215516c77SSepherosa Ziehau 		size = MCLBYTES;
344315516c77SSepherosa Ziehau 		if (dlen > MCLBYTES) {
344415516c77SSepherosa Ziehau 			/* 4096 */
344515516c77SSepherosa Ziehau 			size = MJUMPAGESIZE;
344615516c77SSepherosa Ziehau 		}
344715516c77SSepherosa Ziehau 
344815516c77SSepherosa Ziehau 		m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size);
344915516c77SSepherosa Ziehau 		if (m_new == NULL) {
3450a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1);
345115516c77SSepherosa Ziehau 			return (0);
345215516c77SSepherosa Ziehau 		}
345315516c77SSepherosa Ziehau 
345415516c77SSepherosa Ziehau 		hv_m_append(m_new, dlen, data);
345515516c77SSepherosa Ziehau 	}
345615516c77SSepherosa Ziehau 	m_new->m_pkthdr.rcvif = ifp;
345715516c77SSepherosa Ziehau 
3458a97fff19SSepherosa Ziehau 	if (__predict_false((hn_ifp->if_capenable & IFCAP_RXCSUM) == 0))
345915516c77SSepherosa Ziehau 		do_csum = 0;
346015516c77SSepherosa Ziehau 
346115516c77SSepherosa Ziehau 	/* receive side checksum offload */
346215516c77SSepherosa Ziehau 	if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) {
346315516c77SSepherosa Ziehau 		/* IP csum offload */
346415516c77SSepherosa Ziehau 		if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) {
346515516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
346615516c77SSepherosa Ziehau 			    (CSUM_IP_CHECKED | CSUM_IP_VALID);
346715516c77SSepherosa Ziehau 			rxr->hn_csum_ip++;
346815516c77SSepherosa Ziehau 		}
346915516c77SSepherosa Ziehau 
347015516c77SSepherosa Ziehau 		/* TCP/UDP csum offload */
347115516c77SSepherosa Ziehau 		if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK |
347215516c77SSepherosa Ziehau 		     NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) {
347315516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
347415516c77SSepherosa Ziehau 			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
347515516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_data = 0xffff;
347615516c77SSepherosa Ziehau 			if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK)
347715516c77SSepherosa Ziehau 				rxr->hn_csum_tcp++;
347815516c77SSepherosa Ziehau 			else
347915516c77SSepherosa Ziehau 				rxr->hn_csum_udp++;
348015516c77SSepherosa Ziehau 		}
348115516c77SSepherosa Ziehau 
348215516c77SSepherosa Ziehau 		/*
348315516c77SSepherosa Ziehau 		 * XXX
348415516c77SSepherosa Ziehau 		 * As of this write (Oct 28th, 2016), host side will turn
348515516c77SSepherosa Ziehau 		 * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so
348615516c77SSepherosa Ziehau 		 * the do_lro setting here is actually _not_ accurate.  We
348715516c77SSepherosa Ziehau 		 * depend on the RSS hash type check to reset do_lro.
348815516c77SSepherosa Ziehau 		 */
348915516c77SSepherosa Ziehau 		if ((info->csum_info &
349015516c77SSepherosa Ziehau 		     (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) ==
349115516c77SSepherosa Ziehau 		    (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK))
349215516c77SSepherosa Ziehau 			do_lro = 1;
349315516c77SSepherosa Ziehau 	} else {
3494db76829bSSepherosa Ziehau 		hn_rxpkt_proto(m_new, &l3proto, &l4proto);
3495db76829bSSepherosa Ziehau 		if (l3proto == ETHERTYPE_IP) {
3496db76829bSSepherosa Ziehau 			if (l4proto == IPPROTO_TCP) {
349715516c77SSepherosa Ziehau 				if (do_csum &&
349815516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
349915516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_TCP)) {
350015516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
350115516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
350215516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
350315516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
350415516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
350515516c77SSepherosa Ziehau 				}
350615516c77SSepherosa Ziehau 				do_lro = 1;
3507db76829bSSepherosa Ziehau 			} else if (l4proto == IPPROTO_UDP) {
350815516c77SSepherosa Ziehau 				if (do_csum &&
350915516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
351015516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_UDP)) {
351115516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
351215516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
351315516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
351415516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
351515516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
351615516c77SSepherosa Ziehau 				}
3517db76829bSSepherosa Ziehau 			} else if (l4proto != IPPROTO_DONE && do_csum &&
351815516c77SSepherosa Ziehau 			    (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) {
351915516c77SSepherosa Ziehau 				rxr->hn_csum_trusted++;
352015516c77SSepherosa Ziehau 				m_new->m_pkthdr.csum_flags |=
352115516c77SSepherosa Ziehau 				    (CSUM_IP_CHECKED | CSUM_IP_VALID);
352215516c77SSepherosa Ziehau 			}
352315516c77SSepherosa Ziehau 		}
352415516c77SSepherosa Ziehau 	}
3525db76829bSSepherosa Ziehau 
352615516c77SSepherosa Ziehau 	if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) {
352715516c77SSepherosa Ziehau 		m_new->m_pkthdr.ether_vtag = EVL_MAKETAG(
352815516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_ID(info->vlan_info),
352915516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_PRI(info->vlan_info),
353015516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_CFI(info->vlan_info));
353115516c77SSepherosa Ziehau 		m_new->m_flags |= M_VLANTAG;
353215516c77SSepherosa Ziehau 	}
353315516c77SSepherosa Ziehau 
3534a97fff19SSepherosa Ziehau 	/*
3535a97fff19SSepherosa Ziehau 	 * If VF is activated (tranparent/non-transparent mode does not
3536a97fff19SSepherosa Ziehau 	 * matter here).
3537a97fff19SSepherosa Ziehau 	 *
3538a97fff19SSepherosa Ziehau 	 * - Disable LRO
3539a97fff19SSepherosa Ziehau 	 *
3540a97fff19SSepherosa Ziehau 	 *   hn(4) will only receive broadcast packets, multicast packets,
3541a97fff19SSepherosa Ziehau 	 *   TCP SYN and SYN|ACK (in Azure), LRO is useless for these
3542a97fff19SSepherosa Ziehau 	 *   packet types.
3543a97fff19SSepherosa Ziehau 	 *
3544a97fff19SSepherosa Ziehau 	 *   For non-transparent, we definitely _cannot_ enable LRO at
3545a97fff19SSepherosa Ziehau 	 *   all, since the LRO flush will use hn(4) as the receiving
3546a97fff19SSepherosa Ziehau 	 *   interface; i.e. hn_ifp->if_input(hn_ifp, m).
3547a97fff19SSepherosa Ziehau 	 */
3548642ec226SSepherosa Ziehau 	if (is_vf)
3549642ec226SSepherosa Ziehau 		do_lro = 0;
3550a97fff19SSepherosa Ziehau 
3551642ec226SSepherosa Ziehau 	/*
3552642ec226SSepherosa Ziehau 	 * If VF is activated (tranparent/non-transparent mode does not
3553642ec226SSepherosa Ziehau 	 * matter here), do _not_ mess with unsupported hash types or
3554642ec226SSepherosa Ziehau 	 * functions.
3555642ec226SSepherosa Ziehau 	 */
355615516c77SSepherosa Ziehau 	if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) {
355715516c77SSepherosa Ziehau 		rxr->hn_rss_pkts++;
355815516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = info->hash_value;
3559642ec226SSepherosa Ziehau 		if (!is_vf)
356015516c77SSepherosa Ziehau 			hash_type = M_HASHTYPE_OPAQUE_HASH;
356115516c77SSepherosa Ziehau 		if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) ==
356215516c77SSepherosa Ziehau 		    NDIS_HASH_FUNCTION_TOEPLITZ) {
3563642ec226SSepherosa Ziehau 			uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK &
3564642ec226SSepherosa Ziehau 			    rxr->hn_mbuf_hash);
356515516c77SSepherosa Ziehau 
356615516c77SSepherosa Ziehau 			/*
356715516c77SSepherosa Ziehau 			 * NOTE:
356815516c77SSepherosa Ziehau 			 * do_lro is resetted, if the hash types are not TCP
356915516c77SSepherosa Ziehau 			 * related.  See the comment in the above csum_flags
357015516c77SSepherosa Ziehau 			 * setup section.
357115516c77SSepherosa Ziehau 			 */
357215516c77SSepherosa Ziehau 			switch (type) {
357315516c77SSepherosa Ziehau 			case NDIS_HASH_IPV4:
357415516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV4;
357515516c77SSepherosa Ziehau 				do_lro = 0;
357615516c77SSepherosa Ziehau 				break;
357715516c77SSepherosa Ziehau 
357815516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV4:
357915516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV4;
3580db76829bSSepherosa Ziehau 				if (rxr->hn_rx_flags & HN_RX_FLAG_UDP_HASH) {
3581db76829bSSepherosa Ziehau 					int def_htype = M_HASHTYPE_OPAQUE_HASH;
3582db76829bSSepherosa Ziehau 
3583db76829bSSepherosa Ziehau 					if (is_vf)
3584db76829bSSepherosa Ziehau 						def_htype = M_HASHTYPE_NONE;
3585db76829bSSepherosa Ziehau 
3586db76829bSSepherosa Ziehau 					/*
3587db76829bSSepherosa Ziehau 					 * UDP 4-tuple hash is delivered as
3588db76829bSSepherosa Ziehau 					 * TCP 4-tuple hash.
3589db76829bSSepherosa Ziehau 					 */
3590db76829bSSepherosa Ziehau 					if (l3proto == ETHERTYPE_MAX) {
3591db76829bSSepherosa Ziehau 						hn_rxpkt_proto(m_new,
3592db76829bSSepherosa Ziehau 						    &l3proto, &l4proto);
3593db76829bSSepherosa Ziehau 					}
3594db76829bSSepherosa Ziehau 					if (l3proto == ETHERTYPE_IP) {
35956f12c42eSSepherosa Ziehau 						if (l4proto == IPPROTO_UDP &&
35966f12c42eSSepherosa Ziehau 						    (rxr->hn_mbuf_hash &
35976f12c42eSSepherosa Ziehau 						     NDIS_HASH_UDP_IPV4_X)) {
3598db76829bSSepherosa Ziehau 							hash_type =
3599db76829bSSepherosa Ziehau 							M_HASHTYPE_RSS_UDP_IPV4;
3600db76829bSSepherosa Ziehau 							do_lro = 0;
3601db76829bSSepherosa Ziehau 						} else if (l4proto !=
3602db76829bSSepherosa Ziehau 						    IPPROTO_TCP) {
3603db76829bSSepherosa Ziehau 							hash_type = def_htype;
3604db76829bSSepherosa Ziehau 							do_lro = 0;
3605db76829bSSepherosa Ziehau 						}
3606db76829bSSepherosa Ziehau 					} else {
3607db76829bSSepherosa Ziehau 						hash_type = def_htype;
3608db76829bSSepherosa Ziehau 						do_lro = 0;
3609db76829bSSepherosa Ziehau 					}
3610db76829bSSepherosa Ziehau 				}
361115516c77SSepherosa Ziehau 				break;
361215516c77SSepherosa Ziehau 
361315516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6:
361415516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6;
361515516c77SSepherosa Ziehau 				do_lro = 0;
361615516c77SSepherosa Ziehau 				break;
361715516c77SSepherosa Ziehau 
361815516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6_EX:
361915516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6_EX;
362015516c77SSepherosa Ziehau 				do_lro = 0;
362115516c77SSepherosa Ziehau 				break;
362215516c77SSepherosa Ziehau 
362315516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6:
362415516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6;
362515516c77SSepherosa Ziehau 				break;
362615516c77SSepherosa Ziehau 
362715516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6_EX:
362815516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX;
362915516c77SSepherosa Ziehau 				break;
363015516c77SSepherosa Ziehau 			}
363115516c77SSepherosa Ziehau 		}
3632642ec226SSepherosa Ziehau 	} else if (!is_vf) {
363315516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
363415516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE;
363515516c77SSepherosa Ziehau 	}
363615516c77SSepherosa Ziehau 	M_HASHTYPE_SET(m_new, hash_type);
363715516c77SSepherosa Ziehau 
3638a97fff19SSepherosa Ziehau 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
3639a97fff19SSepherosa Ziehau 	if (hn_ifp != ifp) {
3640a97fff19SSepherosa Ziehau 		const struct ether_header *eh;
3641a97fff19SSepherosa Ziehau 
364215516c77SSepherosa Ziehau 		/*
3643a97fff19SSepherosa Ziehau 		 * Non-transparent mode VF is activated.
364415516c77SSepherosa Ziehau 		 */
364515516c77SSepherosa Ziehau 
3646a97fff19SSepherosa Ziehau 		/*
3647a97fff19SSepherosa Ziehau 		 * Allow tapping on hn(4).
3648a97fff19SSepherosa Ziehau 		 */
3649a97fff19SSepherosa Ziehau 		ETHER_BPF_MTAP(hn_ifp, m_new);
3650a97fff19SSepherosa Ziehau 
3651a97fff19SSepherosa Ziehau 		/*
3652a97fff19SSepherosa Ziehau 		 * Update hn(4)'s stats.
3653a97fff19SSepherosa Ziehau 		 */
3654a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1);
3655a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IBYTES, m_new->m_pkthdr.len);
3656a97fff19SSepherosa Ziehau 		/* Checked at the beginning of this function. */
3657a97fff19SSepherosa Ziehau 		KASSERT(m_new->m_len >= ETHER_HDR_LEN, ("not ethernet frame"));
3658a97fff19SSepherosa Ziehau 		eh = mtod(m_new, struct ether_header *);
3659a97fff19SSepherosa Ziehau 		if (ETHER_IS_MULTICAST(eh->ether_dhost))
3660a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IMCASTS, 1);
3661a97fff19SSepherosa Ziehau 	}
366215516c77SSepherosa Ziehau 	rxr->hn_pkts++;
366315516c77SSepherosa Ziehau 
3664a97fff19SSepherosa Ziehau 	if ((hn_ifp->if_capenable & IFCAP_LRO) && do_lro) {
366515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
366615516c77SSepherosa Ziehau 		struct lro_ctrl *lro = &rxr->hn_lro;
366715516c77SSepherosa Ziehau 
366815516c77SSepherosa Ziehau 		if (lro->lro_cnt) {
366915516c77SSepherosa Ziehau 			rxr->hn_lro_tried++;
367015516c77SSepherosa Ziehau 			if (hn_lro_rx(lro, m_new) == 0) {
367115516c77SSepherosa Ziehau 				/* DONE! */
367215516c77SSepherosa Ziehau 				return 0;
367315516c77SSepherosa Ziehau 			}
367415516c77SSepherosa Ziehau 		}
367515516c77SSepherosa Ziehau #endif
367615516c77SSepherosa Ziehau 	}
3677a97fff19SSepherosa Ziehau 	ifp->if_input(ifp, m_new);
367815516c77SSepherosa Ziehau 
367915516c77SSepherosa Ziehau 	return (0);
368015516c77SSepherosa Ziehau }
368115516c77SSepherosa Ziehau 
368215516c77SSepherosa Ziehau static int
368315516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
368415516c77SSepherosa Ziehau {
368515516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
36869c6cae24SSepherosa Ziehau 	struct ifreq *ifr = (struct ifreq *)data, ifr_vf;
36879c6cae24SSepherosa Ziehau 	struct ifnet *vf_ifp;
368815516c77SSepherosa Ziehau 	int mask, error = 0;
36898c068aa5SSepherosa Ziehau 	struct ifrsskey *ifrk;
36908c068aa5SSepherosa Ziehau 	struct ifrsshash *ifrh;
3691eb2fe044SSepherosa Ziehau 	uint32_t mtu;
369215516c77SSepherosa Ziehau 
369315516c77SSepherosa Ziehau 	switch (cmd) {
369415516c77SSepherosa Ziehau 	case SIOCSIFMTU:
369515516c77SSepherosa Ziehau 		if (ifr->ifr_mtu > HN_MTU_MAX) {
369615516c77SSepherosa Ziehau 			error = EINVAL;
369715516c77SSepherosa Ziehau 			break;
369815516c77SSepherosa Ziehau 		}
369915516c77SSepherosa Ziehau 
370015516c77SSepherosa Ziehau 		HN_LOCK(sc);
370115516c77SSepherosa Ziehau 
370215516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
370315516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
370415516c77SSepherosa Ziehau 			break;
370515516c77SSepherosa Ziehau 		}
370615516c77SSepherosa Ziehau 
370715516c77SSepherosa Ziehau 		if ((sc->hn_caps & HN_CAP_MTU) == 0) {
370815516c77SSepherosa Ziehau 			/* Can't change MTU */
370915516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
371015516c77SSepherosa Ziehau 			error = EOPNOTSUPP;
371115516c77SSepherosa Ziehau 			break;
371215516c77SSepherosa Ziehau 		}
371315516c77SSepherosa Ziehau 
371415516c77SSepherosa Ziehau 		if (ifp->if_mtu == ifr->ifr_mtu) {
371515516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
371615516c77SSepherosa Ziehau 			break;
371715516c77SSepherosa Ziehau 		}
371815516c77SSepherosa Ziehau 
37199c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
37209c6cae24SSepherosa Ziehau 			vf_ifp = sc->hn_vf_ifp;
37219c6cae24SSepherosa Ziehau 			ifr_vf = *ifr;
37229c6cae24SSepherosa Ziehau 			strlcpy(ifr_vf.ifr_name, vf_ifp->if_xname,
37239c6cae24SSepherosa Ziehau 			    sizeof(ifr_vf.ifr_name));
37249c6cae24SSepherosa Ziehau 			error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU,
37259c6cae24SSepherosa Ziehau 			    (caddr_t)&ifr_vf);
37269c6cae24SSepherosa Ziehau 			if (error) {
37279c6cae24SSepherosa Ziehau 				HN_UNLOCK(sc);
37289c6cae24SSepherosa Ziehau 				if_printf(ifp, "%s SIOCSIFMTU %d failed: %d\n",
37299c6cae24SSepherosa Ziehau 				    vf_ifp->if_xname, ifr->ifr_mtu, error);
37309c6cae24SSepherosa Ziehau 				break;
37319c6cae24SSepherosa Ziehau 			}
37329c6cae24SSepherosa Ziehau 		}
37339c6cae24SSepherosa Ziehau 
373415516c77SSepherosa Ziehau 		/*
373515516c77SSepherosa Ziehau 		 * Suspend this interface before the synthetic parts
373615516c77SSepherosa Ziehau 		 * are ripped.
373715516c77SSepherosa Ziehau 		 */
373815516c77SSepherosa Ziehau 		hn_suspend(sc);
373915516c77SSepherosa Ziehau 
374015516c77SSepherosa Ziehau 		/*
374115516c77SSepherosa Ziehau 		 * Detach the synthetics parts, i.e. NVS and RNDIS.
374215516c77SSepherosa Ziehau 		 */
374315516c77SSepherosa Ziehau 		hn_synth_detach(sc);
374415516c77SSepherosa Ziehau 
374515516c77SSepherosa Ziehau 		/*
374615516c77SSepherosa Ziehau 		 * Reattach the synthetic parts, i.e. NVS and RNDIS,
374715516c77SSepherosa Ziehau 		 * with the new MTU setting.
374815516c77SSepherosa Ziehau 		 */
374915516c77SSepherosa Ziehau 		error = hn_synth_attach(sc, ifr->ifr_mtu);
375015516c77SSepherosa Ziehau 		if (error) {
375115516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
375215516c77SSepherosa Ziehau 			break;
375315516c77SSepherosa Ziehau 		}
375415516c77SSepherosa Ziehau 
3755eb2fe044SSepherosa Ziehau 		error = hn_rndis_get_mtu(sc, &mtu);
3756eb2fe044SSepherosa Ziehau 		if (error)
3757eb2fe044SSepherosa Ziehau 			mtu = ifr->ifr_mtu;
3758eb2fe044SSepherosa Ziehau 		else if (bootverbose)
3759eb2fe044SSepherosa Ziehau 			if_printf(ifp, "RNDIS mtu %u\n", mtu);
3760eb2fe044SSepherosa Ziehau 
376115516c77SSepherosa Ziehau 		/*
376215516c77SSepherosa Ziehau 		 * Commit the requested MTU, after the synthetic parts
376315516c77SSepherosa Ziehau 		 * have been successfully attached.
376415516c77SSepherosa Ziehau 		 */
3765eb2fe044SSepherosa Ziehau 		if (mtu >= ifr->ifr_mtu) {
3766eb2fe044SSepherosa Ziehau 			mtu = ifr->ifr_mtu;
3767eb2fe044SSepherosa Ziehau 		} else {
3768eb2fe044SSepherosa Ziehau 			if_printf(ifp, "fixup mtu %d -> %u\n",
3769eb2fe044SSepherosa Ziehau 			    ifr->ifr_mtu, mtu);
3770eb2fe044SSepherosa Ziehau 		}
3771eb2fe044SSepherosa Ziehau 		ifp->if_mtu = mtu;
377215516c77SSepherosa Ziehau 
377315516c77SSepherosa Ziehau 		/*
37749c6cae24SSepherosa Ziehau 		 * Synthetic parts' reattach may change the chimney
37759c6cae24SSepherosa Ziehau 		 * sending size; update it.
377615516c77SSepherosa Ziehau 		 */
377715516c77SSepherosa Ziehau 		if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax)
377815516c77SSepherosa Ziehau 			hn_set_chim_size(sc, sc->hn_chim_szmax);
37799c6cae24SSepherosa Ziehau 
37809c6cae24SSepherosa Ziehau 		/*
37819c6cae24SSepherosa Ziehau 		 * Make sure that various parameters based on MTU are
37829c6cae24SSepherosa Ziehau 		 * still valid, after the MTU change.
37839c6cae24SSepherosa Ziehau 		 */
37849c6cae24SSepherosa Ziehau 		hn_mtu_change_fixup(sc);
378515516c77SSepherosa Ziehau 
378615516c77SSepherosa Ziehau 		/*
378715516c77SSepherosa Ziehau 		 * All done!  Resume the interface now.
378815516c77SSepherosa Ziehau 		 */
378915516c77SSepherosa Ziehau 		hn_resume(sc);
379015516c77SSepherosa Ziehau 
3791d0cd8231SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXVF) ||
3792d0cd8231SSepherosa Ziehau 		    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
37939c6cae24SSepherosa Ziehau 			/*
37949c6cae24SSepherosa Ziehau 			 * Since we have reattached the NVS part,
37959c6cae24SSepherosa Ziehau 			 * change the datapath to VF again; in case
37969c6cae24SSepherosa Ziehau 			 * that it is lost, after the NVS was detached.
37979c6cae24SSepherosa Ziehau 			 */
37989c6cae24SSepherosa Ziehau 			hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF);
37999c6cae24SSepherosa Ziehau 		}
38009c6cae24SSepherosa Ziehau 
380115516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
380215516c77SSepherosa Ziehau 		break;
380315516c77SSepherosa Ziehau 
380415516c77SSepherosa Ziehau 	case SIOCSIFFLAGS:
380515516c77SSepherosa Ziehau 		HN_LOCK(sc);
380615516c77SSepherosa Ziehau 
380715516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
380815516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
380915516c77SSepherosa Ziehau 			break;
381015516c77SSepherosa Ziehau 		}
381115516c77SSepherosa Ziehau 
38129c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc))
38139c6cae24SSepherosa Ziehau 			hn_xpnt_vf_saveifflags(sc);
38149c6cae24SSepherosa Ziehau 
381515516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_UP) {
3816fdc4f478SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
3817fdc4f478SSepherosa Ziehau 				/*
3818fdc4f478SSepherosa Ziehau 				 * Caller meight hold mutex, e.g.
3819fdc4f478SSepherosa Ziehau 				 * bpf; use busy-wait for the RNDIS
3820fdc4f478SSepherosa Ziehau 				 * reply.
3821fdc4f478SSepherosa Ziehau 				 */
3822fdc4f478SSepherosa Ziehau 				HN_NO_SLEEPING(sc);
3823c08f7b2cSSepherosa Ziehau 				hn_rxfilter_config(sc);
3824fdc4f478SSepherosa Ziehau 				HN_SLEEPING_OK(sc);
38259c6cae24SSepherosa Ziehau 
38269c6cae24SSepherosa Ziehau 				if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
38279c6cae24SSepherosa Ziehau 					error = hn_xpnt_vf_iocsetflags(sc);
3828fdc4f478SSepherosa Ziehau 			} else {
382915516c77SSepherosa Ziehau 				hn_init_locked(sc);
3830fdc4f478SSepherosa Ziehau 			}
383115516c77SSepherosa Ziehau 		} else {
383215516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
38335bdfd3fdSDexuan Cui 				hn_stop(sc, false);
383415516c77SSepherosa Ziehau 		}
383515516c77SSepherosa Ziehau 		sc->hn_if_flags = ifp->if_flags;
383615516c77SSepherosa Ziehau 
383715516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
383815516c77SSepherosa Ziehau 		break;
383915516c77SSepherosa Ziehau 
384015516c77SSepherosa Ziehau 	case SIOCSIFCAP:
384115516c77SSepherosa Ziehau 		HN_LOCK(sc);
38429c6cae24SSepherosa Ziehau 
38439c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
38449c6cae24SSepherosa Ziehau 			ifr_vf = *ifr;
38459c6cae24SSepherosa Ziehau 			strlcpy(ifr_vf.ifr_name, sc->hn_vf_ifp->if_xname,
38469c6cae24SSepherosa Ziehau 			    sizeof(ifr_vf.ifr_name));
38479c6cae24SSepherosa Ziehau 			error = hn_xpnt_vf_iocsetcaps(sc, &ifr_vf);
38489c6cae24SSepherosa Ziehau 			HN_UNLOCK(sc);
38499c6cae24SSepherosa Ziehau 			break;
38509c6cae24SSepherosa Ziehau 		}
38519c6cae24SSepherosa Ziehau 
38529c6cae24SSepherosa Ziehau 		/*
38539c6cae24SSepherosa Ziehau 		 * Fix up requested capabilities w/ supported capabilities,
38549c6cae24SSepherosa Ziehau 		 * since the supported capabilities could have been changed.
38559c6cae24SSepherosa Ziehau 		 */
38569c6cae24SSepherosa Ziehau 		mask = (ifr->ifr_reqcap & ifp->if_capabilities) ^
38579c6cae24SSepherosa Ziehau 		    ifp->if_capenable;
385815516c77SSepherosa Ziehau 
385915516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM) {
386015516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM;
386115516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM)
386215516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc);
386315516c77SSepherosa Ziehau 			else
386415516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc);
386515516c77SSepherosa Ziehau 		}
386615516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM_IPV6) {
386715516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
386815516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
386915516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc);
387015516c77SSepherosa Ziehau 			else
387115516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc);
387215516c77SSepherosa Ziehau 		}
387315516c77SSepherosa Ziehau 
387415516c77SSepherosa Ziehau 		/* TODO: flip RNDIS offload parameters for RXCSUM. */
387515516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM)
387615516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM;
387715516c77SSepherosa Ziehau #ifdef foo
387815516c77SSepherosa Ziehau 		/* We can't diff IPv6 packets from IPv4 packets on RX path. */
387915516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM_IPV6)
388015516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
388115516c77SSepherosa Ziehau #endif
388215516c77SSepherosa Ziehau 
388315516c77SSepherosa Ziehau 		if (mask & IFCAP_LRO)
388415516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_LRO;
388515516c77SSepherosa Ziehau 
388615516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO4) {
388715516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO4;
388815516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO4)
388915516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP_TSO;
389015516c77SSepherosa Ziehau 			else
389115516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP_TSO;
389215516c77SSepherosa Ziehau 		}
389315516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO6) {
389415516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO6;
389515516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO6)
389615516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP6_TSO;
389715516c77SSepherosa Ziehau 			else
389815516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP6_TSO;
389915516c77SSepherosa Ziehau 		}
390015516c77SSepherosa Ziehau 
390115516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
390215516c77SSepherosa Ziehau 		break;
390315516c77SSepherosa Ziehau 
390415516c77SSepherosa Ziehau 	case SIOCADDMULTI:
390515516c77SSepherosa Ziehau 	case SIOCDELMULTI:
390615516c77SSepherosa Ziehau 		HN_LOCK(sc);
390715516c77SSepherosa Ziehau 
390815516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
390915516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
391015516c77SSepherosa Ziehau 			break;
391115516c77SSepherosa Ziehau 		}
3912fdc4f478SSepherosa Ziehau 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
3913fdc4f478SSepherosa Ziehau 			/*
3914fdc4f478SSepherosa Ziehau 			 * Multicast uses mutex; use busy-wait for
3915fdc4f478SSepherosa Ziehau 			 * the RNDIS reply.
3916fdc4f478SSepherosa Ziehau 			 */
3917fdc4f478SSepherosa Ziehau 			HN_NO_SLEEPING(sc);
3918c08f7b2cSSepherosa Ziehau 			hn_rxfilter_config(sc);
3919fdc4f478SSepherosa Ziehau 			HN_SLEEPING_OK(sc);
3920fdc4f478SSepherosa Ziehau 		}
392115516c77SSepherosa Ziehau 
39229c6cae24SSepherosa Ziehau 		/* XXX vlan(4) style mcast addr maintenance */
39239c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
39249c6cae24SSepherosa Ziehau 			int old_if_flags;
39259c6cae24SSepherosa Ziehau 
39269c6cae24SSepherosa Ziehau 			old_if_flags = sc->hn_vf_ifp->if_flags;
39279c6cae24SSepherosa Ziehau 			hn_xpnt_vf_saveifflags(sc);
39289c6cae24SSepherosa Ziehau 
39299c6cae24SSepherosa Ziehau 			if ((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) &&
39309c6cae24SSepherosa Ziehau 			    ((old_if_flags ^ sc->hn_vf_ifp->if_flags) &
39319c6cae24SSepherosa Ziehau 			     IFF_ALLMULTI))
39329c6cae24SSepherosa Ziehau 				error = hn_xpnt_vf_iocsetflags(sc);
39339c6cae24SSepherosa Ziehau 		}
39349c6cae24SSepherosa Ziehau 
393515516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
393615516c77SSepherosa Ziehau 		break;
393715516c77SSepherosa Ziehau 
393815516c77SSepherosa Ziehau 	case SIOCSIFMEDIA:
393915516c77SSepherosa Ziehau 	case SIOCGIFMEDIA:
39409c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
39419c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
39429c6cae24SSepherosa Ziehau 			/*
39439c6cae24SSepherosa Ziehau 			 * SIOCGIFMEDIA expects ifmediareq, so don't
39449c6cae24SSepherosa Ziehau 			 * create and pass ifr_vf to the VF here; just
39459c6cae24SSepherosa Ziehau 			 * replace the ifr_name.
39469c6cae24SSepherosa Ziehau 			 */
39479c6cae24SSepherosa Ziehau 			vf_ifp = sc->hn_vf_ifp;
39489c6cae24SSepherosa Ziehau 			strlcpy(ifr->ifr_name, vf_ifp->if_xname,
39499c6cae24SSepherosa Ziehau 			    sizeof(ifr->ifr_name));
39509c6cae24SSepherosa Ziehau 			error = vf_ifp->if_ioctl(vf_ifp, cmd, data);
39519c6cae24SSepherosa Ziehau 			/* Restore the ifr_name. */
39529c6cae24SSepherosa Ziehau 			strlcpy(ifr->ifr_name, ifp->if_xname,
39539c6cae24SSepherosa Ziehau 			    sizeof(ifr->ifr_name));
39549c6cae24SSepherosa Ziehau 			HN_UNLOCK(sc);
39559c6cae24SSepherosa Ziehau 			break;
39569c6cae24SSepherosa Ziehau 		}
39579c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
395815516c77SSepherosa Ziehau 		error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd);
395915516c77SSepherosa Ziehau 		break;
396015516c77SSepherosa Ziehau 
39618c068aa5SSepherosa Ziehau 	case SIOCGIFRSSHASH:
39628c068aa5SSepherosa Ziehau 		ifrh = (struct ifrsshash *)data;
39638c068aa5SSepherosa Ziehau 		HN_LOCK(sc);
39648c068aa5SSepherosa Ziehau 		if (sc->hn_rx_ring_inuse == 1) {
39658c068aa5SSepherosa Ziehau 			HN_UNLOCK(sc);
39668c068aa5SSepherosa Ziehau 			ifrh->ifrh_func = RSS_FUNC_NONE;
39678c068aa5SSepherosa Ziehau 			ifrh->ifrh_types = 0;
39688c068aa5SSepherosa Ziehau 			break;
39698c068aa5SSepherosa Ziehau 		}
39708c068aa5SSepherosa Ziehau 
39718c068aa5SSepherosa Ziehau 		if (sc->hn_rss_hash & NDIS_HASH_FUNCTION_TOEPLITZ)
39728c068aa5SSepherosa Ziehau 			ifrh->ifrh_func = RSS_FUNC_TOEPLITZ;
39738c068aa5SSepherosa Ziehau 		else
39748c068aa5SSepherosa Ziehau 			ifrh->ifrh_func = RSS_FUNC_PRIVATE;
3975642ec226SSepherosa Ziehau 		ifrh->ifrh_types = hn_rss_type_fromndis(sc->hn_rss_hash);
39768c068aa5SSepherosa Ziehau 		HN_UNLOCK(sc);
39778c068aa5SSepherosa Ziehau 		break;
39788c068aa5SSepherosa Ziehau 
39798c068aa5SSepherosa Ziehau 	case SIOCGIFRSSKEY:
39808c068aa5SSepherosa Ziehau 		ifrk = (struct ifrsskey *)data;
39818c068aa5SSepherosa Ziehau 		HN_LOCK(sc);
39828c068aa5SSepherosa Ziehau 		if (sc->hn_rx_ring_inuse == 1) {
39838c068aa5SSepherosa Ziehau 			HN_UNLOCK(sc);
39848c068aa5SSepherosa Ziehau 			ifrk->ifrk_func = RSS_FUNC_NONE;
39858c068aa5SSepherosa Ziehau 			ifrk->ifrk_keylen = 0;
39868c068aa5SSepherosa Ziehau 			break;
39878c068aa5SSepherosa Ziehau 		}
39888c068aa5SSepherosa Ziehau 		if (sc->hn_rss_hash & NDIS_HASH_FUNCTION_TOEPLITZ)
39898c068aa5SSepherosa Ziehau 			ifrk->ifrk_func = RSS_FUNC_TOEPLITZ;
39908c068aa5SSepherosa Ziehau 		else
39918c068aa5SSepherosa Ziehau 			ifrk->ifrk_func = RSS_FUNC_PRIVATE;
39928c068aa5SSepherosa Ziehau 		ifrk->ifrk_keylen = NDIS_HASH_KEYSIZE_TOEPLITZ;
39938c068aa5SSepherosa Ziehau 		memcpy(ifrk->ifrk_key, sc->hn_rss.rss_key,
39948c068aa5SSepherosa Ziehau 		    NDIS_HASH_KEYSIZE_TOEPLITZ);
39958c068aa5SSepherosa Ziehau 		HN_UNLOCK(sc);
39968c068aa5SSepherosa Ziehau 		break;
39978c068aa5SSepherosa Ziehau 
399815516c77SSepherosa Ziehau 	default:
399915516c77SSepherosa Ziehau 		error = ether_ioctl(ifp, cmd, data);
400015516c77SSepherosa Ziehau 		break;
400115516c77SSepherosa Ziehau 	}
400215516c77SSepherosa Ziehau 	return (error);
400315516c77SSepherosa Ziehau }
400415516c77SSepherosa Ziehau 
400515516c77SSepherosa Ziehau static void
40065bdfd3fdSDexuan Cui hn_stop(struct hn_softc *sc, bool detaching)
400715516c77SSepherosa Ziehau {
400815516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
400915516c77SSepherosa Ziehau 	int i;
401015516c77SSepherosa Ziehau 
401115516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
401215516c77SSepherosa Ziehau 
401315516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
401415516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
401515516c77SSepherosa Ziehau 
40169c6cae24SSepherosa Ziehau 	/* Clear RUNNING bit ASAP. */
40179c6cae24SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
40189c6cae24SSepherosa Ziehau 
40196c1204dfSSepherosa Ziehau 	/* Disable polling. */
40206c1204dfSSepherosa Ziehau 	hn_polling(sc, 0);
40216c1204dfSSepherosa Ziehau 
40229c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) {
40239c6cae24SSepherosa Ziehau 		KASSERT(sc->hn_vf_ifp != NULL,
40249c6cae24SSepherosa Ziehau 		    ("%s: VF is not attached", ifp->if_xname));
40259c6cae24SSepherosa Ziehau 
4026a97fff19SSepherosa Ziehau 		/* Mark transparent mode VF as disabled. */
4027a97fff19SSepherosa Ziehau 		hn_xpnt_vf_setdisable(sc, false /* keep hn_vf_ifp */);
40289c6cae24SSepherosa Ziehau 
40299c6cae24SSepherosa Ziehau 		/*
40309c6cae24SSepherosa Ziehau 		 * NOTE:
40319c6cae24SSepherosa Ziehau 		 * Datapath setting must happen _before_ bringing
40329c6cae24SSepherosa Ziehau 		 * the VF down.
40339c6cae24SSepherosa Ziehau 		 */
40349c6cae24SSepherosa Ziehau 		hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH);
40359c6cae24SSepherosa Ziehau 
40369c6cae24SSepherosa Ziehau 		/*
40379c6cae24SSepherosa Ziehau 		 * Bring the VF down.
40389c6cae24SSepherosa Ziehau 		 */
40399c6cae24SSepherosa Ziehau 		hn_xpnt_vf_saveifflags(sc);
40409c6cae24SSepherosa Ziehau 		sc->hn_vf_ifp->if_flags &= ~IFF_UP;
40419c6cae24SSepherosa Ziehau 		hn_xpnt_vf_iocsetflags(sc);
40429c6cae24SSepherosa Ziehau 	}
40439c6cae24SSepherosa Ziehau 
40449c6cae24SSepherosa Ziehau 	/* Suspend data transfers. */
404515516c77SSepherosa Ziehau 	hn_suspend_data(sc);
404615516c77SSepherosa Ziehau 
404715516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
404815516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
404915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
405015516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
40515bdfd3fdSDexuan Cui 
40525bdfd3fdSDexuan Cui 	/*
40539c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is active, make sure
40549c6cae24SSepherosa Ziehau 	 * that the RX filter still allows packet reception.
40555bdfd3fdSDexuan Cui 	 */
4056962f0357SSepherosa Ziehau 	if (!detaching && (sc->hn_flags & HN_FLAG_RXVF))
40575bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
405815516c77SSepherosa Ziehau }
405915516c77SSepherosa Ziehau 
406015516c77SSepherosa Ziehau static void
406115516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc)
406215516c77SSepherosa Ziehau {
406315516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
406415516c77SSepherosa Ziehau 	int i;
406515516c77SSepherosa Ziehau 
406615516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
406715516c77SSepherosa Ziehau 
406815516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
406915516c77SSepherosa Ziehau 		return;
407015516c77SSepherosa Ziehau 
407115516c77SSepherosa Ziehau 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
407215516c77SSepherosa Ziehau 		return;
407315516c77SSepherosa Ziehau 
407415516c77SSepherosa Ziehau 	/* Configure RX filter */
4075c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
407615516c77SSepherosa Ziehau 
407715516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
407815516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
407915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
408015516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
408115516c77SSepherosa Ziehau 
408215516c77SSepherosa Ziehau 	/* Clear TX 'suspended' bit. */
408315516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_inuse);
408415516c77SSepherosa Ziehau 
40859c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_isready(sc)) {
40869c6cae24SSepherosa Ziehau 		/* Initialize transparent VF. */
40879c6cae24SSepherosa Ziehau 		hn_xpnt_vf_init(sc);
40889c6cae24SSepherosa Ziehau 	}
40899c6cae24SSepherosa Ziehau 
409015516c77SSepherosa Ziehau 	/* Everything is ready; unleash! */
409115516c77SSepherosa Ziehau 	atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
40926c1204dfSSepherosa Ziehau 
40936c1204dfSSepherosa Ziehau 	/* Re-enable polling if requested. */
40946c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz > 0)
40956c1204dfSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
409615516c77SSepherosa Ziehau }
409715516c77SSepherosa Ziehau 
409815516c77SSepherosa Ziehau static void
409915516c77SSepherosa Ziehau hn_init(void *xsc)
410015516c77SSepherosa Ziehau {
410115516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
410215516c77SSepherosa Ziehau 
410315516c77SSepherosa Ziehau 	HN_LOCK(sc);
410415516c77SSepherosa Ziehau 	hn_init_locked(sc);
410515516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
410615516c77SSepherosa Ziehau }
410715516c77SSepherosa Ziehau 
410815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
410915516c77SSepherosa Ziehau 
411015516c77SSepherosa Ziehau static int
411115516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
411215516c77SSepherosa Ziehau {
411315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
411415516c77SSepherosa Ziehau 	unsigned int lenlim;
411515516c77SSepherosa Ziehau 	int error;
411615516c77SSepherosa Ziehau 
411715516c77SSepherosa Ziehau 	lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim;
411815516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &lenlim, 0, req);
411915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
412015516c77SSepherosa Ziehau 		return error;
412115516c77SSepherosa Ziehau 
412215516c77SSepherosa Ziehau 	HN_LOCK(sc);
412315516c77SSepherosa Ziehau 	if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) ||
412415516c77SSepherosa Ziehau 	    lenlim > TCP_LRO_LENGTH_MAX) {
412515516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
412615516c77SSepherosa Ziehau 		return EINVAL;
412715516c77SSepherosa Ziehau 	}
412815516c77SSepherosa Ziehau 	hn_set_lro_lenlim(sc, lenlim);
412915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
413015516c77SSepherosa Ziehau 
413115516c77SSepherosa Ziehau 	return 0;
413215516c77SSepherosa Ziehau }
413315516c77SSepherosa Ziehau 
413415516c77SSepherosa Ziehau static int
413515516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS)
413615516c77SSepherosa Ziehau {
413715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
413815516c77SSepherosa Ziehau 	int ackcnt, error, i;
413915516c77SSepherosa Ziehau 
414015516c77SSepherosa Ziehau 	/*
414115516c77SSepherosa Ziehau 	 * lro_ackcnt_lim is append count limit,
414215516c77SSepherosa Ziehau 	 * +1 to turn it into aggregation limit.
414315516c77SSepherosa Ziehau 	 */
414415516c77SSepherosa Ziehau 	ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1;
414515516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &ackcnt, 0, req);
414615516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
414715516c77SSepherosa Ziehau 		return error;
414815516c77SSepherosa Ziehau 
414915516c77SSepherosa Ziehau 	if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1))
415015516c77SSepherosa Ziehau 		return EINVAL;
415115516c77SSepherosa Ziehau 
415215516c77SSepherosa Ziehau 	/*
415315516c77SSepherosa Ziehau 	 * Convert aggregation limit back to append
415415516c77SSepherosa Ziehau 	 * count limit.
415515516c77SSepherosa Ziehau 	 */
415615516c77SSepherosa Ziehau 	--ackcnt;
415715516c77SSepherosa Ziehau 	HN_LOCK(sc);
4158a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
415915516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt;
416015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
416115516c77SSepherosa Ziehau 	return 0;
416215516c77SSepherosa Ziehau }
416315516c77SSepherosa Ziehau 
416415516c77SSepherosa Ziehau #endif
416515516c77SSepherosa Ziehau 
416615516c77SSepherosa Ziehau static int
416715516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS)
416815516c77SSepherosa Ziehau {
416915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
417015516c77SSepherosa Ziehau 	int hcsum = arg2;
417115516c77SSepherosa Ziehau 	int on, error, i;
417215516c77SSepherosa Ziehau 
417315516c77SSepherosa Ziehau 	on = 0;
417415516c77SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum)
417515516c77SSepherosa Ziehau 		on = 1;
417615516c77SSepherosa Ziehau 
417715516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &on, 0, req);
417815516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
417915516c77SSepherosa Ziehau 		return error;
418015516c77SSepherosa Ziehau 
418115516c77SSepherosa Ziehau 	HN_LOCK(sc);
4182a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
418315516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
418415516c77SSepherosa Ziehau 
418515516c77SSepherosa Ziehau 		if (on)
418615516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= hcsum;
418715516c77SSepherosa Ziehau 		else
418815516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum &= ~hcsum;
418915516c77SSepherosa Ziehau 	}
419015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
419115516c77SSepherosa Ziehau 	return 0;
419215516c77SSepherosa Ziehau }
419315516c77SSepherosa Ziehau 
419415516c77SSepherosa Ziehau static int
419515516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS)
419615516c77SSepherosa Ziehau {
419715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
419815516c77SSepherosa Ziehau 	int chim_size, error;
419915516c77SSepherosa Ziehau 
420015516c77SSepherosa Ziehau 	chim_size = sc->hn_tx_ring[0].hn_chim_size;
420115516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &chim_size, 0, req);
420215516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
420315516c77SSepherosa Ziehau 		return error;
420415516c77SSepherosa Ziehau 
420515516c77SSepherosa Ziehau 	if (chim_size > sc->hn_chim_szmax || chim_size <= 0)
420615516c77SSepherosa Ziehau 		return EINVAL;
420715516c77SSepherosa Ziehau 
420815516c77SSepherosa Ziehau 	HN_LOCK(sc);
420915516c77SSepherosa Ziehau 	hn_set_chim_size(sc, chim_size);
421015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
421115516c77SSepherosa Ziehau 	return 0;
421215516c77SSepherosa Ziehau }
421315516c77SSepherosa Ziehau 
421415516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
421515516c77SSepherosa Ziehau static int
421615516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS)
421715516c77SSepherosa Ziehau {
421815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
421915516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
422015516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
422115516c77SSepherosa Ziehau 	uint64_t stat;
422215516c77SSepherosa Ziehau 
422315516c77SSepherosa Ziehau 	stat = 0;
422415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
422515516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
422615516c77SSepherosa Ziehau 		stat += *((int *)((uint8_t *)rxr + ofs));
422715516c77SSepherosa Ziehau 	}
422815516c77SSepherosa Ziehau 
422915516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
423015516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
423115516c77SSepherosa Ziehau 		return error;
423215516c77SSepherosa Ziehau 
423315516c77SSepherosa Ziehau 	/* Zero out this stat. */
423415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
423515516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
423615516c77SSepherosa Ziehau 		*((int *)((uint8_t *)rxr + ofs)) = 0;
423715516c77SSepherosa Ziehau 	}
423815516c77SSepherosa Ziehau 	return 0;
423915516c77SSepherosa Ziehau }
424015516c77SSepherosa Ziehau #else
424115516c77SSepherosa Ziehau static int
424215516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS)
424315516c77SSepherosa Ziehau {
424415516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
424515516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
424615516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
424715516c77SSepherosa Ziehau 	uint64_t stat;
424815516c77SSepherosa Ziehau 
424915516c77SSepherosa Ziehau 	stat = 0;
4250a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
425115516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
425215516c77SSepherosa Ziehau 		stat += *((uint64_t *)((uint8_t *)rxr + ofs));
425315516c77SSepherosa Ziehau 	}
425415516c77SSepherosa Ziehau 
425515516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
425615516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
425715516c77SSepherosa Ziehau 		return error;
425815516c77SSepherosa Ziehau 
425915516c77SSepherosa Ziehau 	/* Zero out this stat. */
4260a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
426115516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
426215516c77SSepherosa Ziehau 		*((uint64_t *)((uint8_t *)rxr + ofs)) = 0;
426315516c77SSepherosa Ziehau 	}
426415516c77SSepherosa Ziehau 	return 0;
426515516c77SSepherosa Ziehau }
426615516c77SSepherosa Ziehau 
426715516c77SSepherosa Ziehau #endif
426815516c77SSepherosa Ziehau 
426915516c77SSepherosa Ziehau static int
427015516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
427115516c77SSepherosa Ziehau {
427215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
427315516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
427415516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
427515516c77SSepherosa Ziehau 	u_long stat;
427615516c77SSepherosa Ziehau 
427715516c77SSepherosa Ziehau 	stat = 0;
4278a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
427915516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
428015516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)rxr + ofs));
428115516c77SSepherosa Ziehau 	}
428215516c77SSepherosa Ziehau 
428315516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
428415516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
428515516c77SSepherosa Ziehau 		return error;
428615516c77SSepherosa Ziehau 
428715516c77SSepherosa Ziehau 	/* Zero out this stat. */
4288a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
428915516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
429015516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)rxr + ofs)) = 0;
429115516c77SSepherosa Ziehau 	}
429215516c77SSepherosa Ziehau 	return 0;
429315516c77SSepherosa Ziehau }
429415516c77SSepherosa Ziehau 
429515516c77SSepherosa Ziehau static int
429615516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
429715516c77SSepherosa Ziehau {
429815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
429915516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
430015516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
430115516c77SSepherosa Ziehau 	u_long stat;
430215516c77SSepherosa Ziehau 
430315516c77SSepherosa Ziehau 	stat = 0;
4304a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
430515516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
430615516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)txr + ofs));
430715516c77SSepherosa Ziehau 	}
430815516c77SSepherosa Ziehau 
430915516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
431015516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
431115516c77SSepherosa Ziehau 		return error;
431215516c77SSepherosa Ziehau 
431315516c77SSepherosa Ziehau 	/* Zero out this stat. */
4314a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
431515516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
431615516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)txr + ofs)) = 0;
431715516c77SSepherosa Ziehau 	}
431815516c77SSepherosa Ziehau 	return 0;
431915516c77SSepherosa Ziehau }
432015516c77SSepherosa Ziehau 
432115516c77SSepherosa Ziehau static int
432215516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS)
432315516c77SSepherosa Ziehau {
432415516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
432515516c77SSepherosa Ziehau 	int ofs = arg2, i, error, conf;
432615516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
432715516c77SSepherosa Ziehau 
432815516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[0];
432915516c77SSepherosa Ziehau 	conf = *((int *)((uint8_t *)txr + ofs));
433015516c77SSepherosa Ziehau 
433115516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &conf, 0, req);
433215516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
433315516c77SSepherosa Ziehau 		return error;
433415516c77SSepherosa Ziehau 
433515516c77SSepherosa Ziehau 	HN_LOCK(sc);
4336a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
433715516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
433815516c77SSepherosa Ziehau 		*((int *)((uint8_t *)txr + ofs)) = conf;
433915516c77SSepherosa Ziehau 	}
434015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
434115516c77SSepherosa Ziehau 
434215516c77SSepherosa Ziehau 	return 0;
434315516c77SSepherosa Ziehau }
434415516c77SSepherosa Ziehau 
434515516c77SSepherosa Ziehau static int
4346dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS)
4347dc13fee6SSepherosa Ziehau {
4348dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4349dc13fee6SSepherosa Ziehau 	int error, size;
4350dc13fee6SSepherosa Ziehau 
4351dc13fee6SSepherosa Ziehau 	size = sc->hn_agg_size;
4352dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &size, 0, req);
4353dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
4354dc13fee6SSepherosa Ziehau 		return (error);
4355dc13fee6SSepherosa Ziehau 
4356dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
4357dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = size;
4358dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
4359dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
4360dc13fee6SSepherosa Ziehau 
4361dc13fee6SSepherosa Ziehau 	return (0);
4362dc13fee6SSepherosa Ziehau }
4363dc13fee6SSepherosa Ziehau 
4364dc13fee6SSepherosa Ziehau static int
4365dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS)
4366dc13fee6SSepherosa Ziehau {
4367dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4368dc13fee6SSepherosa Ziehau 	int error, pkts;
4369dc13fee6SSepherosa Ziehau 
4370dc13fee6SSepherosa Ziehau 	pkts = sc->hn_agg_pkts;
4371dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pkts, 0, req);
4372dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
4373dc13fee6SSepherosa Ziehau 		return (error);
4374dc13fee6SSepherosa Ziehau 
4375dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
4376dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = pkts;
4377dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
4378dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
4379dc13fee6SSepherosa Ziehau 
4380dc13fee6SSepherosa Ziehau 	return (0);
4381dc13fee6SSepherosa Ziehau }
4382dc13fee6SSepherosa Ziehau 
4383dc13fee6SSepherosa Ziehau static int
4384dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS)
4385dc13fee6SSepherosa Ziehau {
4386dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4387dc13fee6SSepherosa Ziehau 	int pkts;
4388dc13fee6SSepherosa Ziehau 
4389dc13fee6SSepherosa Ziehau 	pkts = sc->hn_tx_ring[0].hn_agg_pktmax;
4390dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &pkts, 0, req));
4391dc13fee6SSepherosa Ziehau }
4392dc13fee6SSepherosa Ziehau 
4393dc13fee6SSepherosa Ziehau static int
4394dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS)
4395dc13fee6SSepherosa Ziehau {
4396dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4397dc13fee6SSepherosa Ziehau 	int align;
4398dc13fee6SSepherosa Ziehau 
4399dc13fee6SSepherosa Ziehau 	align = sc->hn_tx_ring[0].hn_agg_align;
4400dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &align, 0, req));
4401dc13fee6SSepherosa Ziehau }
4402dc13fee6SSepherosa Ziehau 
44036c1204dfSSepherosa Ziehau static void
44046c1204dfSSepherosa Ziehau hn_chan_polling(struct vmbus_channel *chan, u_int pollhz)
44056c1204dfSSepherosa Ziehau {
44066c1204dfSSepherosa Ziehau 	if (pollhz == 0)
44076c1204dfSSepherosa Ziehau 		vmbus_chan_poll_disable(chan);
44086c1204dfSSepherosa Ziehau 	else
44096c1204dfSSepherosa Ziehau 		vmbus_chan_poll_enable(chan, pollhz);
44106c1204dfSSepherosa Ziehau }
44116c1204dfSSepherosa Ziehau 
44126c1204dfSSepherosa Ziehau static void
44136c1204dfSSepherosa Ziehau hn_polling(struct hn_softc *sc, u_int pollhz)
44146c1204dfSSepherosa Ziehau {
44156c1204dfSSepherosa Ziehau 	int nsubch = sc->hn_rx_ring_inuse - 1;
44166c1204dfSSepherosa Ziehau 
44176c1204dfSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
44186c1204dfSSepherosa Ziehau 
44196c1204dfSSepherosa Ziehau 	if (nsubch > 0) {
44206c1204dfSSepherosa Ziehau 		struct vmbus_channel **subch;
44216c1204dfSSepherosa Ziehau 		int i;
44226c1204dfSSepherosa Ziehau 
44236c1204dfSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
44246c1204dfSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
44256c1204dfSSepherosa Ziehau 			hn_chan_polling(subch[i], pollhz);
44266c1204dfSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
44276c1204dfSSepherosa Ziehau 	}
44286c1204dfSSepherosa Ziehau 	hn_chan_polling(sc->hn_prichan, pollhz);
44296c1204dfSSepherosa Ziehau }
44306c1204dfSSepherosa Ziehau 
44316c1204dfSSepherosa Ziehau static int
44326c1204dfSSepherosa Ziehau hn_polling_sysctl(SYSCTL_HANDLER_ARGS)
44336c1204dfSSepherosa Ziehau {
44346c1204dfSSepherosa Ziehau 	struct hn_softc *sc = arg1;
44356c1204dfSSepherosa Ziehau 	int pollhz, error;
44366c1204dfSSepherosa Ziehau 
44376c1204dfSSepherosa Ziehau 	pollhz = sc->hn_pollhz;
44386c1204dfSSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pollhz, 0, req);
44396c1204dfSSepherosa Ziehau 	if (error || req->newptr == NULL)
44406c1204dfSSepherosa Ziehau 		return (error);
44416c1204dfSSepherosa Ziehau 
44426c1204dfSSepherosa Ziehau 	if (pollhz != 0 &&
44436c1204dfSSepherosa Ziehau 	    (pollhz < VMBUS_CHAN_POLLHZ_MIN || pollhz > VMBUS_CHAN_POLLHZ_MAX))
44446c1204dfSSepherosa Ziehau 		return (EINVAL);
44456c1204dfSSepherosa Ziehau 
44466c1204dfSSepherosa Ziehau 	HN_LOCK(sc);
44476c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz != pollhz) {
44486c1204dfSSepherosa Ziehau 		sc->hn_pollhz = pollhz;
44496c1204dfSSepherosa Ziehau 		if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) &&
44506c1204dfSSepherosa Ziehau 		    (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
44516c1204dfSSepherosa Ziehau 			hn_polling(sc, sc->hn_pollhz);
44526c1204dfSSepherosa Ziehau 	}
44536c1204dfSSepherosa Ziehau 	HN_UNLOCK(sc);
44546c1204dfSSepherosa Ziehau 
44556c1204dfSSepherosa Ziehau 	return (0);
44566c1204dfSSepherosa Ziehau }
44576c1204dfSSepherosa Ziehau 
4458dc13fee6SSepherosa Ziehau static int
445915516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS)
446015516c77SSepherosa Ziehau {
446115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
446215516c77SSepherosa Ziehau 	char verstr[16];
446315516c77SSepherosa Ziehau 
446415516c77SSepherosa Ziehau 	snprintf(verstr, sizeof(verstr), "%u.%u",
446515516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
446615516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
446715516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
446815516c77SSepherosa Ziehau }
446915516c77SSepherosa Ziehau 
447015516c77SSepherosa Ziehau static int
447115516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS)
447215516c77SSepherosa Ziehau {
447315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
447415516c77SSepherosa Ziehau 	char caps_str[128];
447515516c77SSepherosa Ziehau 	uint32_t caps;
447615516c77SSepherosa Ziehau 
447715516c77SSepherosa Ziehau 	HN_LOCK(sc);
447815516c77SSepherosa Ziehau 	caps = sc->hn_caps;
447915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
448015516c77SSepherosa Ziehau 	snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS);
448115516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req);
448215516c77SSepherosa Ziehau }
448315516c77SSepherosa Ziehau 
448415516c77SSepherosa Ziehau static int
448515516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS)
448615516c77SSepherosa Ziehau {
448715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
448815516c77SSepherosa Ziehau 	char assist_str[128];
448915516c77SSepherosa Ziehau 	uint32_t hwassist;
449015516c77SSepherosa Ziehau 
449115516c77SSepherosa Ziehau 	HN_LOCK(sc);
449215516c77SSepherosa Ziehau 	hwassist = sc->hn_ifp->if_hwassist;
449315516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
449415516c77SSepherosa Ziehau 	snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS);
449515516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req);
449615516c77SSepherosa Ziehau }
449715516c77SSepherosa Ziehau 
449815516c77SSepherosa Ziehau static int
449915516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS)
450015516c77SSepherosa Ziehau {
450115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
450215516c77SSepherosa Ziehau 	char filter_str[128];
450315516c77SSepherosa Ziehau 	uint32_t filter;
450415516c77SSepherosa Ziehau 
450515516c77SSepherosa Ziehau 	HN_LOCK(sc);
450615516c77SSepherosa Ziehau 	filter = sc->hn_rx_filter;
450715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
450815516c77SSepherosa Ziehau 	snprintf(filter_str, sizeof(filter_str), "%b", filter,
450915516c77SSepherosa Ziehau 	    NDIS_PACKET_TYPES);
451015516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req);
451115516c77SSepherosa Ziehau }
451215516c77SSepherosa Ziehau 
451334d68912SSepherosa Ziehau #ifndef RSS
451434d68912SSepherosa Ziehau 
451515516c77SSepherosa Ziehau static int
451615516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
451715516c77SSepherosa Ziehau {
451815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
451915516c77SSepherosa Ziehau 	int error;
452015516c77SSepherosa Ziehau 
452115516c77SSepherosa Ziehau 	HN_LOCK(sc);
452215516c77SSepherosa Ziehau 
452315516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
452415516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
452515516c77SSepherosa Ziehau 		goto back;
452615516c77SSepherosa Ziehau 
4527642ec226SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) ||
4528642ec226SSepherosa Ziehau 	    (hn_xpnt_vf && sc->hn_vf_ifp != NULL)) {
4529642ec226SSepherosa Ziehau 		/*
4530642ec226SSepherosa Ziehau 		 * RSS key is synchronized w/ VF's, don't allow users
4531642ec226SSepherosa Ziehau 		 * to change it.
4532642ec226SSepherosa Ziehau 		 */
4533642ec226SSepherosa Ziehau 		error = EBUSY;
4534642ec226SSepherosa Ziehau 		goto back;
4535642ec226SSepherosa Ziehau 	}
4536642ec226SSepherosa Ziehau 
453715516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
453815516c77SSepherosa Ziehau 	if (error)
453915516c77SSepherosa Ziehau 		goto back;
454015516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
454115516c77SSepherosa Ziehau 
454215516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
454315516c77SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
454415516c77SSepherosa Ziehau 	} else {
454515516c77SSepherosa Ziehau 		/* Not RSS capable, at least for now; just save the RSS key. */
454615516c77SSepherosa Ziehau 		error = 0;
454715516c77SSepherosa Ziehau 	}
454815516c77SSepherosa Ziehau back:
454915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
455015516c77SSepherosa Ziehau 	return (error);
455115516c77SSepherosa Ziehau }
455215516c77SSepherosa Ziehau 
455315516c77SSepherosa Ziehau static int
455415516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS)
455515516c77SSepherosa Ziehau {
455615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
455715516c77SSepherosa Ziehau 	int error;
455815516c77SSepherosa Ziehau 
455915516c77SSepherosa Ziehau 	HN_LOCK(sc);
456015516c77SSepherosa Ziehau 
456115516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
456215516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
456315516c77SSepherosa Ziehau 		goto back;
456415516c77SSepherosa Ziehau 
456515516c77SSepherosa Ziehau 	/*
456615516c77SSepherosa Ziehau 	 * Don't allow RSS indirect table change, if this interface is not
456715516c77SSepherosa Ziehau 	 * RSS capable currently.
456815516c77SSepherosa Ziehau 	 */
456915516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
457015516c77SSepherosa Ziehau 		error = EOPNOTSUPP;
457115516c77SSepherosa Ziehau 		goto back;
457215516c77SSepherosa Ziehau 	}
457315516c77SSepherosa Ziehau 
457415516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
457515516c77SSepherosa Ziehau 	if (error)
457615516c77SSepherosa Ziehau 		goto back;
457715516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSIND;
457815516c77SSepherosa Ziehau 
4579afd4971bSSepherosa Ziehau 	hn_rss_ind_fixup(sc);
458015516c77SSepherosa Ziehau 	error = hn_rss_reconfig(sc);
458115516c77SSepherosa Ziehau back:
458215516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
458315516c77SSepherosa Ziehau 	return (error);
458415516c77SSepherosa Ziehau }
458515516c77SSepherosa Ziehau 
458634d68912SSepherosa Ziehau #endif	/* !RSS */
458734d68912SSepherosa Ziehau 
458815516c77SSepherosa Ziehau static int
458915516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS)
459015516c77SSepherosa Ziehau {
459115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
459215516c77SSepherosa Ziehau 	char hash_str[128];
459315516c77SSepherosa Ziehau 	uint32_t hash;
459415516c77SSepherosa Ziehau 
459515516c77SSepherosa Ziehau 	HN_LOCK(sc);
459615516c77SSepherosa Ziehau 	hash = sc->hn_rss_hash;
459715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
459815516c77SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
459915516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
460015516c77SSepherosa Ziehau }
460115516c77SSepherosa Ziehau 
460215516c77SSepherosa Ziehau static int
4603642ec226SSepherosa Ziehau hn_rss_hcap_sysctl(SYSCTL_HANDLER_ARGS)
4604642ec226SSepherosa Ziehau {
4605642ec226SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4606642ec226SSepherosa Ziehau 	char hash_str[128];
4607642ec226SSepherosa Ziehau 	uint32_t hash;
4608642ec226SSepherosa Ziehau 
4609642ec226SSepherosa Ziehau 	HN_LOCK(sc);
4610642ec226SSepherosa Ziehau 	hash = sc->hn_rss_hcap;
4611642ec226SSepherosa Ziehau 	HN_UNLOCK(sc);
4612642ec226SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
4613642ec226SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
4614642ec226SSepherosa Ziehau }
4615642ec226SSepherosa Ziehau 
4616642ec226SSepherosa Ziehau static int
4617642ec226SSepherosa Ziehau hn_rss_mbuf_sysctl(SYSCTL_HANDLER_ARGS)
4618642ec226SSepherosa Ziehau {
4619642ec226SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4620642ec226SSepherosa Ziehau 	char hash_str[128];
4621642ec226SSepherosa Ziehau 	uint32_t hash;
4622642ec226SSepherosa Ziehau 
4623642ec226SSepherosa Ziehau 	HN_LOCK(sc);
4624642ec226SSepherosa Ziehau 	hash = sc->hn_rx_ring[0].hn_mbuf_hash;
4625642ec226SSepherosa Ziehau 	HN_UNLOCK(sc);
4626642ec226SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
4627642ec226SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
4628642ec226SSepherosa Ziehau }
4629642ec226SSepherosa Ziehau 
4630642ec226SSepherosa Ziehau static int
463140d60d6eSDexuan Cui hn_vf_sysctl(SYSCTL_HANDLER_ARGS)
463240d60d6eSDexuan Cui {
463340d60d6eSDexuan Cui 	struct hn_softc *sc = arg1;
4634499c3e17SSepherosa Ziehau 	char vf_name[IFNAMSIZ + 1];
4635962f0357SSepherosa Ziehau 	struct ifnet *vf_ifp;
463640d60d6eSDexuan Cui 
463740d60d6eSDexuan Cui 	HN_LOCK(sc);
463840d60d6eSDexuan Cui 	vf_name[0] = '\0';
4639962f0357SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
4640962f0357SSepherosa Ziehau 	if (vf_ifp != NULL)
4641962f0357SSepherosa Ziehau 		snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname);
464240d60d6eSDexuan Cui 	HN_UNLOCK(sc);
464340d60d6eSDexuan Cui 	return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req);
464440d60d6eSDexuan Cui }
464540d60d6eSDexuan Cui 
464640d60d6eSDexuan Cui static int
4647499c3e17SSepherosa Ziehau hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS)
4648499c3e17SSepherosa Ziehau {
4649499c3e17SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4650499c3e17SSepherosa Ziehau 	char vf_name[IFNAMSIZ + 1];
4651962f0357SSepherosa Ziehau 	struct ifnet *vf_ifp;
4652499c3e17SSepherosa Ziehau 
4653499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
4654499c3e17SSepherosa Ziehau 	vf_name[0] = '\0';
4655962f0357SSepherosa Ziehau 	vf_ifp = sc->hn_rx_ring[0].hn_rxvf_ifp;
4656962f0357SSepherosa Ziehau 	if (vf_ifp != NULL)
4657962f0357SSepherosa Ziehau 		snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname);
4658499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
4659499c3e17SSepherosa Ziehau 	return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req);
4660499c3e17SSepherosa Ziehau }
4661499c3e17SSepherosa Ziehau 
4662499c3e17SSepherosa Ziehau static int
4663499c3e17SSepherosa Ziehau hn_vflist_sysctl(SYSCTL_HANDLER_ARGS)
4664499c3e17SSepherosa Ziehau {
4665499c3e17SSepherosa Ziehau 	struct rm_priotracker pt;
4666499c3e17SSepherosa Ziehau 	struct sbuf *sb;
4667499c3e17SSepherosa Ziehau 	int error, i;
4668499c3e17SSepherosa Ziehau 	bool first;
4669499c3e17SSepherosa Ziehau 
4670499c3e17SSepherosa Ziehau 	error = sysctl_wire_old_buffer(req, 0);
4671499c3e17SSepherosa Ziehau 	if (error != 0)
4672499c3e17SSepherosa Ziehau 		return (error);
4673499c3e17SSepherosa Ziehau 
4674499c3e17SSepherosa Ziehau 	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4675499c3e17SSepherosa Ziehau 	if (sb == NULL)
4676499c3e17SSepherosa Ziehau 		return (ENOMEM);
4677499c3e17SSepherosa Ziehau 
4678499c3e17SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
4679499c3e17SSepherosa Ziehau 
4680499c3e17SSepherosa Ziehau 	first = true;
4681499c3e17SSepherosa Ziehau 	for (i = 0; i < hn_vfmap_size; ++i) {
4682499c3e17SSepherosa Ziehau 		struct ifnet *ifp;
4683499c3e17SSepherosa Ziehau 
4684499c3e17SSepherosa Ziehau 		if (hn_vfmap[i] == NULL)
4685499c3e17SSepherosa Ziehau 			continue;
4686499c3e17SSepherosa Ziehau 
4687499c3e17SSepherosa Ziehau 		ifp = ifnet_byindex(i);
4688499c3e17SSepherosa Ziehau 		if (ifp != NULL) {
4689499c3e17SSepherosa Ziehau 			if (first)
4690499c3e17SSepherosa Ziehau 				sbuf_printf(sb, "%s", ifp->if_xname);
4691499c3e17SSepherosa Ziehau 			else
4692499c3e17SSepherosa Ziehau 				sbuf_printf(sb, " %s", ifp->if_xname);
4693499c3e17SSepherosa Ziehau 			first = false;
4694499c3e17SSepherosa Ziehau 		}
4695499c3e17SSepherosa Ziehau 	}
4696499c3e17SSepherosa Ziehau 
4697499c3e17SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
4698499c3e17SSepherosa Ziehau 
4699499c3e17SSepherosa Ziehau 	error = sbuf_finish(sb);
4700499c3e17SSepherosa Ziehau 	sbuf_delete(sb);
4701499c3e17SSepherosa Ziehau 	return (error);
4702499c3e17SSepherosa Ziehau }
4703499c3e17SSepherosa Ziehau 
4704499c3e17SSepherosa Ziehau static int
4705499c3e17SSepherosa Ziehau hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS)
4706499c3e17SSepherosa Ziehau {
4707499c3e17SSepherosa Ziehau 	struct rm_priotracker pt;
4708499c3e17SSepherosa Ziehau 	struct sbuf *sb;
4709499c3e17SSepherosa Ziehau 	int error, i;
4710499c3e17SSepherosa Ziehau 	bool first;
4711499c3e17SSepherosa Ziehau 
4712499c3e17SSepherosa Ziehau 	error = sysctl_wire_old_buffer(req, 0);
4713499c3e17SSepherosa Ziehau 	if (error != 0)
4714499c3e17SSepherosa Ziehau 		return (error);
4715499c3e17SSepherosa Ziehau 
4716499c3e17SSepherosa Ziehau 	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4717499c3e17SSepherosa Ziehau 	if (sb == NULL)
4718499c3e17SSepherosa Ziehau 		return (ENOMEM);
4719499c3e17SSepherosa Ziehau 
4720499c3e17SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
4721499c3e17SSepherosa Ziehau 
4722499c3e17SSepherosa Ziehau 	first = true;
4723499c3e17SSepherosa Ziehau 	for (i = 0; i < hn_vfmap_size; ++i) {
4724499c3e17SSepherosa Ziehau 		struct ifnet *ifp, *hn_ifp;
4725499c3e17SSepherosa Ziehau 
4726499c3e17SSepherosa Ziehau 		hn_ifp = hn_vfmap[i];
4727499c3e17SSepherosa Ziehau 		if (hn_ifp == NULL)
4728499c3e17SSepherosa Ziehau 			continue;
4729499c3e17SSepherosa Ziehau 
4730499c3e17SSepherosa Ziehau 		ifp = ifnet_byindex(i);
4731499c3e17SSepherosa Ziehau 		if (ifp != NULL) {
4732499c3e17SSepherosa Ziehau 			if (first) {
4733499c3e17SSepherosa Ziehau 				sbuf_printf(sb, "%s:%s", ifp->if_xname,
4734499c3e17SSepherosa Ziehau 				    hn_ifp->if_xname);
4735499c3e17SSepherosa Ziehau 			} else {
4736499c3e17SSepherosa Ziehau 				sbuf_printf(sb, " %s:%s", ifp->if_xname,
4737499c3e17SSepherosa Ziehau 				    hn_ifp->if_xname);
4738499c3e17SSepherosa Ziehau 			}
4739499c3e17SSepherosa Ziehau 			first = false;
4740499c3e17SSepherosa Ziehau 		}
4741499c3e17SSepherosa Ziehau 	}
4742499c3e17SSepherosa Ziehau 
4743499c3e17SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
4744499c3e17SSepherosa Ziehau 
4745499c3e17SSepherosa Ziehau 	error = sbuf_finish(sb);
4746499c3e17SSepherosa Ziehau 	sbuf_delete(sb);
4747499c3e17SSepherosa Ziehau 	return (error);
4748499c3e17SSepherosa Ziehau }
4749499c3e17SSepherosa Ziehau 
4750499c3e17SSepherosa Ziehau static int
47519c6cae24SSepherosa Ziehau hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS)
47529c6cae24SSepherosa Ziehau {
47539c6cae24SSepherosa Ziehau 	struct hn_softc *sc = arg1;
47549c6cae24SSepherosa Ziehau 	int error, onoff = 0;
47559c6cae24SSepherosa Ziehau 
47569c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF)
47579c6cae24SSepherosa Ziehau 		onoff = 1;
47589c6cae24SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &onoff, 0, req);
47599c6cae24SSepherosa Ziehau 	if (error || req->newptr == NULL)
47609c6cae24SSepherosa Ziehau 		return (error);
47619c6cae24SSepherosa Ziehau 
47629c6cae24SSepherosa Ziehau 	HN_LOCK(sc);
47639c6cae24SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit() */
47649c6cae24SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
47659c6cae24SSepherosa Ziehau 	if (onoff)
47669c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF;
47679c6cae24SSepherosa Ziehau 	else
47689c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags &= ~HN_XVFFLAG_ACCBPF;
47699c6cae24SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
47709c6cae24SSepherosa Ziehau 	HN_UNLOCK(sc);
47719c6cae24SSepherosa Ziehau 
47729c6cae24SSepherosa Ziehau 	return (0);
47739c6cae24SSepherosa Ziehau }
47749c6cae24SSepherosa Ziehau 
47759c6cae24SSepherosa Ziehau static int
47769c6cae24SSepherosa Ziehau hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS)
47779c6cae24SSepherosa Ziehau {
47789c6cae24SSepherosa Ziehau 	struct hn_softc *sc = arg1;
47799c6cae24SSepherosa Ziehau 	int enabled = 0;
47809c6cae24SSepherosa Ziehau 
47819c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
47829c6cae24SSepherosa Ziehau 		enabled = 1;
47839c6cae24SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &enabled, 0, req));
47849c6cae24SSepherosa Ziehau }
47859c6cae24SSepherosa Ziehau 
47869c6cae24SSepherosa Ziehau static int
478715516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff)
478815516c77SSepherosa Ziehau {
478915516c77SSepherosa Ziehau 	const struct ip *ip;
479015516c77SSepherosa Ziehau 	int len, iphlen, iplen;
479115516c77SSepherosa Ziehau 	const struct tcphdr *th;
479215516c77SSepherosa Ziehau 	int thoff;				/* TCP data offset */
479315516c77SSepherosa Ziehau 
479415516c77SSepherosa Ziehau 	len = hoff + sizeof(struct ip);
479515516c77SSepherosa Ziehau 
479615516c77SSepherosa Ziehau 	/* The packet must be at least the size of an IP header. */
479715516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < len)
479815516c77SSepherosa Ziehau 		return IPPROTO_DONE;
479915516c77SSepherosa Ziehau 
480015516c77SSepherosa Ziehau 	/* The fixed IP header must reside completely in the first mbuf. */
480115516c77SSepherosa Ziehau 	if (m->m_len < len)
480215516c77SSepherosa Ziehau 		return IPPROTO_DONE;
480315516c77SSepherosa Ziehau 
480415516c77SSepherosa Ziehau 	ip = mtodo(m, hoff);
480515516c77SSepherosa Ziehau 
480615516c77SSepherosa Ziehau 	/* Bound check the packet's stated IP header length. */
480715516c77SSepherosa Ziehau 	iphlen = ip->ip_hl << 2;
480815516c77SSepherosa Ziehau 	if (iphlen < sizeof(struct ip))		/* minimum header length */
480915516c77SSepherosa Ziehau 		return IPPROTO_DONE;
481015516c77SSepherosa Ziehau 
481115516c77SSepherosa Ziehau 	/* The full IP header must reside completely in the one mbuf. */
481215516c77SSepherosa Ziehau 	if (m->m_len < hoff + iphlen)
481315516c77SSepherosa Ziehau 		return IPPROTO_DONE;
481415516c77SSepherosa Ziehau 
481515516c77SSepherosa Ziehau 	iplen = ntohs(ip->ip_len);
481615516c77SSepherosa Ziehau 
481715516c77SSepherosa Ziehau 	/*
481815516c77SSepherosa Ziehau 	 * Check that the amount of data in the buffers is as
481915516c77SSepherosa Ziehau 	 * at least much as the IP header would have us expect.
482015516c77SSepherosa Ziehau 	 */
482115516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < hoff + iplen)
482215516c77SSepherosa Ziehau 		return IPPROTO_DONE;
482315516c77SSepherosa Ziehau 
482415516c77SSepherosa Ziehau 	/*
482515516c77SSepherosa Ziehau 	 * Ignore IP fragments.
482615516c77SSepherosa Ziehau 	 */
482715516c77SSepherosa Ziehau 	if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF))
482815516c77SSepherosa Ziehau 		return IPPROTO_DONE;
482915516c77SSepherosa Ziehau 
483015516c77SSepherosa Ziehau 	/*
483115516c77SSepherosa Ziehau 	 * The TCP/IP or UDP/IP header must be entirely contained within
483215516c77SSepherosa Ziehau 	 * the first fragment of a packet.
483315516c77SSepherosa Ziehau 	 */
483415516c77SSepherosa Ziehau 	switch (ip->ip_p) {
483515516c77SSepherosa Ziehau 	case IPPROTO_TCP:
483615516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct tcphdr))
483715516c77SSepherosa Ziehau 			return IPPROTO_DONE;
483815516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct tcphdr))
483915516c77SSepherosa Ziehau 			return IPPROTO_DONE;
484015516c77SSepherosa Ziehau 		th = (const struct tcphdr *)((const uint8_t *)ip + iphlen);
484115516c77SSepherosa Ziehau 		thoff = th->th_off << 2;
484215516c77SSepherosa Ziehau 		if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen)
484315516c77SSepherosa Ziehau 			return IPPROTO_DONE;
484415516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + thoff)
484515516c77SSepherosa Ziehau 			return IPPROTO_DONE;
484615516c77SSepherosa Ziehau 		break;
484715516c77SSepherosa Ziehau 	case IPPROTO_UDP:
484815516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct udphdr))
484915516c77SSepherosa Ziehau 			return IPPROTO_DONE;
485015516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct udphdr))
485115516c77SSepherosa Ziehau 			return IPPROTO_DONE;
485215516c77SSepherosa Ziehau 		break;
485315516c77SSepherosa Ziehau 	default:
485415516c77SSepherosa Ziehau 		if (iplen < iphlen)
485515516c77SSepherosa Ziehau 			return IPPROTO_DONE;
485615516c77SSepherosa Ziehau 		break;
485715516c77SSepherosa Ziehau 	}
485815516c77SSepherosa Ziehau 	return ip->ip_p;
485915516c77SSepherosa Ziehau }
486015516c77SSepherosa Ziehau 
4861db76829bSSepherosa Ziehau static void
4862db76829bSSepherosa Ziehau hn_rxpkt_proto(const struct mbuf *m_new, int *l3proto, int *l4proto)
4863db76829bSSepherosa Ziehau {
4864db76829bSSepherosa Ziehau 	const struct ether_header *eh;
4865db76829bSSepherosa Ziehau 	uint16_t etype;
4866db76829bSSepherosa Ziehau 	int hoff;
4867db76829bSSepherosa Ziehau 
4868db76829bSSepherosa Ziehau 	hoff = sizeof(*eh);
4869db76829bSSepherosa Ziehau 	/* Checked at the beginning of this function. */
4870db76829bSSepherosa Ziehau 	KASSERT(m_new->m_len >= hoff, ("not ethernet frame"));
4871db76829bSSepherosa Ziehau 
4872db76829bSSepherosa Ziehau 	eh = mtod(m_new, const struct ether_header *);
4873db76829bSSepherosa Ziehau 	etype = ntohs(eh->ether_type);
4874db76829bSSepherosa Ziehau 	if (etype == ETHERTYPE_VLAN) {
4875db76829bSSepherosa Ziehau 		const struct ether_vlan_header *evl;
4876db76829bSSepherosa Ziehau 
4877db76829bSSepherosa Ziehau 		hoff = sizeof(*evl);
4878db76829bSSepherosa Ziehau 		if (m_new->m_len < hoff)
4879db76829bSSepherosa Ziehau 			return;
4880db76829bSSepherosa Ziehau 		evl = mtod(m_new, const struct ether_vlan_header *);
4881db76829bSSepherosa Ziehau 		etype = ntohs(evl->evl_proto);
4882db76829bSSepherosa Ziehau 	}
4883db76829bSSepherosa Ziehau 	*l3proto = etype;
4884db76829bSSepherosa Ziehau 
4885db76829bSSepherosa Ziehau 	if (etype == ETHERTYPE_IP)
4886db76829bSSepherosa Ziehau 		*l4proto = hn_check_iplen(m_new, hoff);
4887db76829bSSepherosa Ziehau 	else
4888db76829bSSepherosa Ziehau 		*l4proto = IPPROTO_DONE;
4889db76829bSSepherosa Ziehau }
4890db76829bSSepherosa Ziehau 
489115516c77SSepherosa Ziehau static int
489215516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt)
489315516c77SSepherosa Ziehau {
489415516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
489515516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
489615516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
489715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
489815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
489915516c77SSepherosa Ziehau 	int lroent_cnt;
490015516c77SSepherosa Ziehau #endif
490115516c77SSepherosa Ziehau #endif
490215516c77SSepherosa Ziehau 	int i;
490315516c77SSepherosa Ziehau 
490415516c77SSepherosa Ziehau 	/*
490515516c77SSepherosa Ziehau 	 * Create RXBUF for reception.
490615516c77SSepherosa Ziehau 	 *
490715516c77SSepherosa Ziehau 	 * NOTE:
490815516c77SSepherosa Ziehau 	 * - It is shared by all channels.
490915516c77SSepherosa Ziehau 	 * - A large enough buffer is allocated, certain version of NVSes
491015516c77SSepherosa Ziehau 	 *   may further limit the usable space.
491115516c77SSepherosa Ziehau 	 */
491215516c77SSepherosa Ziehau 	sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
491315516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma,
491415516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
491515516c77SSepherosa Ziehau 	if (sc->hn_rxbuf == NULL) {
491615516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate rxbuf failed\n");
491715516c77SSepherosa Ziehau 		return (ENOMEM);
491815516c77SSepherosa Ziehau 	}
491915516c77SSepherosa Ziehau 
492015516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = ring_cnt;
492115516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt;
492215516c77SSepherosa Ziehau 
492315516c77SSepherosa Ziehau 	sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt,
492415516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
492515516c77SSepherosa Ziehau 
492615516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
492715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
492815516c77SSepherosa Ziehau 	lroent_cnt = hn_lro_entry_count;
492915516c77SSepherosa Ziehau 	if (lroent_cnt < TCP_LRO_ENTRIES)
493015516c77SSepherosa Ziehau 		lroent_cnt = TCP_LRO_ENTRIES;
493115516c77SSepherosa Ziehau 	if (bootverbose)
493215516c77SSepherosa Ziehau 		device_printf(dev, "LRO: entry count %d\n", lroent_cnt);
493315516c77SSepherosa Ziehau #endif
493415516c77SSepherosa Ziehau #endif	/* INET || INET6 */
493515516c77SSepherosa Ziehau 
493615516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
493715516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
493815516c77SSepherosa Ziehau 
493915516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.rx sysctl tree */
494015516c77SSepherosa Ziehau 	sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx",
494115516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
494215516c77SSepherosa Ziehau 
494315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
494415516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
494515516c77SSepherosa Ziehau 
494615516c77SSepherosa Ziehau 		rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
494715516c77SSepherosa Ziehau 		    PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE,
494815516c77SSepherosa Ziehau 		    &rxr->hn_br_dma, BUS_DMA_WAITOK);
494915516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL) {
495015516c77SSepherosa Ziehau 			device_printf(dev, "allocate bufring failed\n");
495115516c77SSepherosa Ziehau 			return (ENOMEM);
495215516c77SSepherosa Ziehau 		}
495315516c77SSepherosa Ziehau 
495415516c77SSepherosa Ziehau 		if (hn_trust_hosttcp)
495515516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP;
495615516c77SSepherosa Ziehau 		if (hn_trust_hostudp)
495715516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP;
495815516c77SSepherosa Ziehau 		if (hn_trust_hostip)
495915516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP;
4960642ec226SSepherosa Ziehau 		rxr->hn_mbuf_hash = NDIS_HASH_ALL;
496115516c77SSepherosa Ziehau 		rxr->hn_ifp = sc->hn_ifp;
496215516c77SSepherosa Ziehau 		if (i < sc->hn_tx_ring_cnt)
496315516c77SSepherosa Ziehau 			rxr->hn_txr = &sc->hn_tx_ring[i];
496415516c77SSepherosa Ziehau 		rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF;
496515516c77SSepherosa Ziehau 		rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK);
496615516c77SSepherosa Ziehau 		rxr->hn_rx_idx = i;
496715516c77SSepherosa Ziehau 		rxr->hn_rxbuf = sc->hn_rxbuf;
496815516c77SSepherosa Ziehau 
496915516c77SSepherosa Ziehau 		/*
497015516c77SSepherosa Ziehau 		 * Initialize LRO.
497115516c77SSepherosa Ziehau 		 */
497215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
497315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
497415516c77SSepherosa Ziehau 		tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt,
497515516c77SSepherosa Ziehau 		    hn_lro_mbufq_depth);
497615516c77SSepherosa Ziehau #else
497715516c77SSepherosa Ziehau 		tcp_lro_init(&rxr->hn_lro);
497815516c77SSepherosa Ziehau 		rxr->hn_lro.ifp = sc->hn_ifp;
497915516c77SSepherosa Ziehau #endif
498015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
498115516c77SSepherosa Ziehau 		rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF;
498215516c77SSepherosa Ziehau 		rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF;
498315516c77SSepherosa Ziehau #endif
498415516c77SSepherosa Ziehau #endif	/* INET || INET6 */
498515516c77SSepherosa Ziehau 
498615516c77SSepherosa Ziehau 		if (sc->hn_rx_sysctl_tree != NULL) {
498715516c77SSepherosa Ziehau 			char name[16];
498815516c77SSepherosa Ziehau 
498915516c77SSepherosa Ziehau 			/*
499015516c77SSepherosa Ziehau 			 * Create per RX ring sysctl tree:
499115516c77SSepherosa Ziehau 			 * dev.hn.UNIT.rx.RINGID
499215516c77SSepherosa Ziehau 			 */
499315516c77SSepherosa Ziehau 			snprintf(name, sizeof(name), "%d", i);
499415516c77SSepherosa Ziehau 			rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx,
499515516c77SSepherosa Ziehau 			    SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree),
499615516c77SSepherosa Ziehau 			    OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
499715516c77SSepherosa Ziehau 
499815516c77SSepherosa Ziehau 			if (rxr->hn_rx_sysctl_tree != NULL) {
499915516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
500015516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
500115516c77SSepherosa Ziehau 				    OID_AUTO, "packets", CTLFLAG_RW,
500215516c77SSepherosa Ziehau 				    &rxr->hn_pkts, "# of packets received");
500315516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
500415516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
500515516c77SSepherosa Ziehau 				    OID_AUTO, "rss_pkts", CTLFLAG_RW,
500615516c77SSepherosa Ziehau 				    &rxr->hn_rss_pkts,
500715516c77SSepherosa Ziehau 				    "# of packets w/ RSS info received");
500815516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx,
500915516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
501015516c77SSepherosa Ziehau 				    OID_AUTO, "pktbuf_len", CTLFLAG_RD,
501115516c77SSepherosa Ziehau 				    &rxr->hn_pktbuf_len, 0,
501215516c77SSepherosa Ziehau 				    "Temporary channel packet buffer length");
501315516c77SSepherosa Ziehau 			}
501415516c77SSepherosa Ziehau 		}
501515516c77SSepherosa Ziehau 	}
501615516c77SSepherosa Ziehau 
501715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued",
501815516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
501915516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_queued),
502015516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
502115516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
502215516c77SSepherosa Ziehau #else
502315516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
502415516c77SSepherosa Ziehau #endif
502515516c77SSepherosa Ziehau 	    "LU", "LRO queued");
502615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed",
502715516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
502815516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_flushed),
502915516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
503015516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
503115516c77SSepherosa Ziehau #else
503215516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
503315516c77SSepherosa Ziehau #endif
503415516c77SSepherosa Ziehau 	    "LU", "LRO flushed");
503515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried",
503615516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
503715516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro_tried),
503815516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries");
503915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
504015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim",
504115516c77SSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
504215516c77SSepherosa Ziehau 	    hn_lro_lenlim_sysctl, "IU",
504315516c77SSepherosa Ziehau 	    "Max # of data bytes to be aggregated by LRO");
504415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim",
504515516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
504615516c77SSepherosa Ziehau 	    hn_lro_ackcnt_sysctl, "I",
504715516c77SSepherosa Ziehau 	    "Max # of ACKs to be aggregated by LRO");
504815516c77SSepherosa Ziehau #endif
504915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp",
505015516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP,
505115516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
505215516c77SSepherosa Ziehau 	    "Trust tcp segement verification on host side, "
505315516c77SSepherosa Ziehau 	    "when csum info is missing");
505415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp",
505515516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP,
505615516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
505715516c77SSepherosa Ziehau 	    "Trust udp datagram verification on host side, "
505815516c77SSepherosa Ziehau 	    "when csum info is missing");
505915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip",
506015516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP,
506115516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
506215516c77SSepherosa Ziehau 	    "Trust ip packet verification on host side, "
506315516c77SSepherosa Ziehau 	    "when csum info is missing");
506415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip",
506515516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
506615516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_ip),
506715516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP");
506815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp",
506915516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
507015516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_tcp),
507115516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP");
507215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp",
507315516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
507415516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_udp),
507515516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP");
507615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted",
507715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
507815516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_trusted),
507915516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU",
508015516c77SSepherosa Ziehau 	    "# of packets that we trust host's csum verification");
508115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts",
508215516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
508315516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_small_pkts),
508415516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of small packets received");
508515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed",
508615516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
508715516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_ack_failed),
508815516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures");
508915516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt",
509015516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings");
509115516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse",
509215516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings");
509315516c77SSepherosa Ziehau 
509415516c77SSepherosa Ziehau 	return (0);
509515516c77SSepherosa Ziehau }
509615516c77SSepherosa Ziehau 
509715516c77SSepherosa Ziehau static void
509815516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc)
509915516c77SSepherosa Ziehau {
510015516c77SSepherosa Ziehau 	int i;
510115516c77SSepherosa Ziehau 
510215516c77SSepherosa Ziehau 	if (sc->hn_rxbuf != NULL) {
51032494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0)
510415516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf);
51052494d735SSepherosa Ziehau 		else
51062494d735SSepherosa Ziehau 			device_printf(sc->hn_dev, "RXBUF is referenced\n");
510715516c77SSepherosa Ziehau 		sc->hn_rxbuf = NULL;
510815516c77SSepherosa Ziehau 	}
510915516c77SSepherosa Ziehau 
511015516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_cnt == 0)
511115516c77SSepherosa Ziehau 		return;
511215516c77SSepherosa Ziehau 
511315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
511415516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
511515516c77SSepherosa Ziehau 
511615516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL)
511715516c77SSepherosa Ziehau 			continue;
51182494d735SSepherosa Ziehau 		if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) {
511915516c77SSepherosa Ziehau 			hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br);
51202494d735SSepherosa Ziehau 		} else {
51212494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
51222494d735SSepherosa Ziehau 			    "%dth channel bufring is referenced", i);
51232494d735SSepherosa Ziehau 		}
512415516c77SSepherosa Ziehau 		rxr->hn_br = NULL;
512515516c77SSepherosa Ziehau 
512615516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
512715516c77SSepherosa Ziehau 		tcp_lro_free(&rxr->hn_lro);
512815516c77SSepherosa Ziehau #endif
512915516c77SSepherosa Ziehau 		free(rxr->hn_pktbuf, M_DEVBUF);
513015516c77SSepherosa Ziehau 	}
513115516c77SSepherosa Ziehau 	free(sc->hn_rx_ring, M_DEVBUF);
513215516c77SSepherosa Ziehau 	sc->hn_rx_ring = NULL;
513315516c77SSepherosa Ziehau 
513415516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = 0;
513515516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = 0;
513615516c77SSepherosa Ziehau }
513715516c77SSepherosa Ziehau 
513815516c77SSepherosa Ziehau static int
513915516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id)
514015516c77SSepherosa Ziehau {
514115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[id];
514215516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
514315516c77SSepherosa Ziehau 	bus_dma_tag_t parent_dtag;
514415516c77SSepherosa Ziehau 	int error, i;
514515516c77SSepherosa Ziehau 
514615516c77SSepherosa Ziehau 	txr->hn_sc = sc;
514715516c77SSepherosa Ziehau 	txr->hn_tx_idx = id;
514815516c77SSepherosa Ziehau 
514915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
515015516c77SSepherosa Ziehau 	mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN);
515115516c77SSepherosa Ziehau #endif
515215516c77SSepherosa Ziehau 	mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF);
515315516c77SSepherosa Ziehau 
515415516c77SSepherosa Ziehau 	txr->hn_txdesc_cnt = HN_TX_DESC_CNT;
515515516c77SSepherosa Ziehau 	txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt,
515615516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
515715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
515815516c77SSepherosa Ziehau 	SLIST_INIT(&txr->hn_txlist);
515915516c77SSepherosa Ziehau #else
516015516c77SSepherosa Ziehau 	txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF,
516115516c77SSepherosa Ziehau 	    M_WAITOK, &txr->hn_tx_lock);
516215516c77SSepherosa Ziehau #endif
516315516c77SSepherosa Ziehau 
51640e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_EVTTQ) {
51650e11868dSSepherosa Ziehau 		txr->hn_tx_taskq = VMBUS_GET_EVENT_TASKQ(
51660e11868dSSepherosa Ziehau 		    device_get_parent(dev), dev, HN_RING_IDX2CPU(sc, id));
51670e11868dSSepherosa Ziehau 	} else {
5168fdd0222aSSepherosa Ziehau 		txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt];
51690e11868dSSepherosa Ziehau 	}
517015516c77SSepherosa Ziehau 
517123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
517215516c77SSepherosa Ziehau 	if (hn_use_if_start) {
517315516c77SSepherosa Ziehau 		txr->hn_txeof = hn_start_txeof;
517415516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr);
517515516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr);
517623bf9e15SSepherosa Ziehau 	} else
517723bf9e15SSepherosa Ziehau #endif
517823bf9e15SSepherosa Ziehau 	{
517915516c77SSepherosa Ziehau 		int br_depth;
518015516c77SSepherosa Ziehau 
518115516c77SSepherosa Ziehau 		txr->hn_txeof = hn_xmit_txeof;
518215516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr);
518315516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr);
518415516c77SSepherosa Ziehau 
518515516c77SSepherosa Ziehau 		br_depth = hn_get_txswq_depth(txr);
518615516c77SSepherosa Ziehau 		txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF,
518715516c77SSepherosa Ziehau 		    M_WAITOK, &txr->hn_tx_lock);
518815516c77SSepherosa Ziehau 	}
518915516c77SSepherosa Ziehau 
519015516c77SSepherosa Ziehau 	txr->hn_direct_tx_size = hn_direct_tx_size;
519115516c77SSepherosa Ziehau 
519215516c77SSepherosa Ziehau 	/*
519315516c77SSepherosa Ziehau 	 * Always schedule transmission instead of trying to do direct
519415516c77SSepherosa Ziehau 	 * transmission.  This one gives the best performance so far.
519515516c77SSepherosa Ziehau 	 */
519615516c77SSepherosa Ziehau 	txr->hn_sched_tx = 1;
519715516c77SSepherosa Ziehau 
519815516c77SSepherosa Ziehau 	parent_dtag = bus_get_dma_tag(dev);
519915516c77SSepherosa Ziehau 
520015516c77SSepherosa Ziehau 	/* DMA tag for RNDIS packet messages. */
520115516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
520215516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_ALIGN,		/* alignment */
520315516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_BOUNDARY,	/* boundary */
520415516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
520515516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
520615516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
520715516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsize */
520815516c77SSepherosa Ziehau 	    1,				/* nsegments */
520915516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsegsize */
521015516c77SSepherosa Ziehau 	    0,				/* flags */
521115516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
521215516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
521315516c77SSepherosa Ziehau 	    &txr->hn_tx_rndis_dtag);
521415516c77SSepherosa Ziehau 	if (error) {
521515516c77SSepherosa Ziehau 		device_printf(dev, "failed to create rndis dmatag\n");
521615516c77SSepherosa Ziehau 		return error;
521715516c77SSepherosa Ziehau 	}
521815516c77SSepherosa Ziehau 
521915516c77SSepherosa Ziehau 	/* DMA tag for data. */
522015516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
522115516c77SSepherosa Ziehau 	    1,				/* alignment */
522215516c77SSepherosa Ziehau 	    HN_TX_DATA_BOUNDARY,	/* boundary */
522315516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
522415516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
522515516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
522615516c77SSepherosa Ziehau 	    HN_TX_DATA_MAXSIZE,		/* maxsize */
522715516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGCNT_MAX,	/* nsegments */
522815516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGSIZE,		/* maxsegsize */
522915516c77SSepherosa Ziehau 	    0,				/* flags */
523015516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
523115516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
523215516c77SSepherosa Ziehau 	    &txr->hn_tx_data_dtag);
523315516c77SSepherosa Ziehau 	if (error) {
523415516c77SSepherosa Ziehau 		device_printf(dev, "failed to create data dmatag\n");
523515516c77SSepherosa Ziehau 		return error;
523615516c77SSepherosa Ziehau 	}
523715516c77SSepherosa Ziehau 
523815516c77SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i) {
523915516c77SSepherosa Ziehau 		struct hn_txdesc *txd = &txr->hn_txdesc[i];
524015516c77SSepherosa Ziehau 
524115516c77SSepherosa Ziehau 		txd->txr = txr;
524215516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
5243dc13fee6SSepherosa Ziehau 		STAILQ_INIT(&txd->agg_list);
524415516c77SSepherosa Ziehau 
524515516c77SSepherosa Ziehau 		/*
524615516c77SSepherosa Ziehau 		 * Allocate and load RNDIS packet message.
524715516c77SSepherosa Ziehau 		 */
524815516c77SSepherosa Ziehau         	error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag,
524915516c77SSepherosa Ziehau 		    (void **)&txd->rndis_pkt,
525015516c77SSepherosa Ziehau 		    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
525115516c77SSepherosa Ziehau 		    &txd->rndis_pkt_dmap);
525215516c77SSepherosa Ziehau 		if (error) {
525315516c77SSepherosa Ziehau 			device_printf(dev,
525415516c77SSepherosa Ziehau 			    "failed to allocate rndis_packet_msg, %d\n", i);
525515516c77SSepherosa Ziehau 			return error;
525615516c77SSepherosa Ziehau 		}
525715516c77SSepherosa Ziehau 
525815516c77SSepherosa Ziehau 		error = bus_dmamap_load(txr->hn_tx_rndis_dtag,
525915516c77SSepherosa Ziehau 		    txd->rndis_pkt_dmap,
526015516c77SSepherosa Ziehau 		    txd->rndis_pkt, HN_RNDIS_PKT_LEN,
526115516c77SSepherosa Ziehau 		    hyperv_dma_map_paddr, &txd->rndis_pkt_paddr,
526215516c77SSepherosa Ziehau 		    BUS_DMA_NOWAIT);
526315516c77SSepherosa Ziehau 		if (error) {
526415516c77SSepherosa Ziehau 			device_printf(dev,
526515516c77SSepherosa Ziehau 			    "failed to load rndis_packet_msg, %d\n", i);
526615516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
526715516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
526815516c77SSepherosa Ziehau 			return error;
526915516c77SSepherosa Ziehau 		}
527015516c77SSepherosa Ziehau 
527115516c77SSepherosa Ziehau 		/* DMA map for TX data. */
527215516c77SSepherosa Ziehau 		error = bus_dmamap_create(txr->hn_tx_data_dtag, 0,
527315516c77SSepherosa Ziehau 		    &txd->data_dmap);
527415516c77SSepherosa Ziehau 		if (error) {
527515516c77SSepherosa Ziehau 			device_printf(dev,
527615516c77SSepherosa Ziehau 			    "failed to allocate tx data dmamap\n");
527715516c77SSepherosa Ziehau 			bus_dmamap_unload(txr->hn_tx_rndis_dtag,
527815516c77SSepherosa Ziehau 			    txd->rndis_pkt_dmap);
527915516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
528015516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
528115516c77SSepherosa Ziehau 			return error;
528215516c77SSepherosa Ziehau 		}
528315516c77SSepherosa Ziehau 
528415516c77SSepherosa Ziehau 		/* All set, put it to list */
528515516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_ONLIST;
528615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
528715516c77SSepherosa Ziehau 		SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
528815516c77SSepherosa Ziehau #else
528915516c77SSepherosa Ziehau 		buf_ring_enqueue(txr->hn_txdesc_br, txd);
529015516c77SSepherosa Ziehau #endif
529115516c77SSepherosa Ziehau 	}
529215516c77SSepherosa Ziehau 	txr->hn_txdesc_avail = txr->hn_txdesc_cnt;
529315516c77SSepherosa Ziehau 
529415516c77SSepherosa Ziehau 	if (sc->hn_tx_sysctl_tree != NULL) {
529515516c77SSepherosa Ziehau 		struct sysctl_oid_list *child;
529615516c77SSepherosa Ziehau 		struct sysctl_ctx_list *ctx;
529715516c77SSepherosa Ziehau 		char name[16];
529815516c77SSepherosa Ziehau 
529915516c77SSepherosa Ziehau 		/*
530015516c77SSepherosa Ziehau 		 * Create per TX ring sysctl tree:
530115516c77SSepherosa Ziehau 		 * dev.hn.UNIT.tx.RINGID
530215516c77SSepherosa Ziehau 		 */
530315516c77SSepherosa Ziehau 		ctx = device_get_sysctl_ctx(dev);
530415516c77SSepherosa Ziehau 		child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree);
530515516c77SSepherosa Ziehau 
530615516c77SSepherosa Ziehau 		snprintf(name, sizeof(name), "%d", id);
530715516c77SSepherosa Ziehau 		txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
530815516c77SSepherosa Ziehau 		    name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
530915516c77SSepherosa Ziehau 
531015516c77SSepherosa Ziehau 		if (txr->hn_tx_sysctl_tree != NULL) {
531115516c77SSepherosa Ziehau 			child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree);
531215516c77SSepherosa Ziehau 
531385e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
531415516c77SSepherosa Ziehau 			SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail",
531515516c77SSepherosa Ziehau 			    CTLFLAG_RD, &txr->hn_txdesc_avail, 0,
531615516c77SSepherosa Ziehau 			    "# of available TX descs");
531785e4ae1eSSepherosa Ziehau #endif
531823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
531923bf9e15SSepherosa Ziehau 			if (!hn_use_if_start)
532023bf9e15SSepherosa Ziehau #endif
532123bf9e15SSepherosa Ziehau 			{
532215516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive",
532315516c77SSepherosa Ziehau 				    CTLFLAG_RD, &txr->hn_oactive, 0,
532415516c77SSepherosa Ziehau 				    "over active");
532515516c77SSepherosa Ziehau 			}
532615516c77SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets",
532715516c77SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_pkts,
532815516c77SSepherosa Ziehau 			    "# of packets transmitted");
5329dc13fee6SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends",
5330dc13fee6SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_sends, "# of sends");
533115516c77SSepherosa Ziehau 		}
533215516c77SSepherosa Ziehau 	}
533315516c77SSepherosa Ziehau 
533415516c77SSepherosa Ziehau 	return 0;
533515516c77SSepherosa Ziehau }
533615516c77SSepherosa Ziehau 
533715516c77SSepherosa Ziehau static void
533815516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd)
533915516c77SSepherosa Ziehau {
534015516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = txd->txr;
534115516c77SSepherosa Ziehau 
534215516c77SSepherosa Ziehau 	KASSERT(txd->m == NULL, ("still has mbuf installed"));
534315516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped"));
534415516c77SSepherosa Ziehau 
534515516c77SSepherosa Ziehau 	bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap);
534615516c77SSepherosa Ziehau 	bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt,
534715516c77SSepherosa Ziehau 	    txd->rndis_pkt_dmap);
534815516c77SSepherosa Ziehau 	bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap);
534915516c77SSepherosa Ziehau }
535015516c77SSepherosa Ziehau 
535115516c77SSepherosa Ziehau static void
535225641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd)
535325641fc7SSepherosa Ziehau {
535425641fc7SSepherosa Ziehau 
535525641fc7SSepherosa Ziehau 	KASSERT(txd->refs == 0 || txd->refs == 1,
535625641fc7SSepherosa Ziehau 	    ("invalid txd refs %d", txd->refs));
535725641fc7SSepherosa Ziehau 
535825641fc7SSepherosa Ziehau 	/* Aggregated txds will be freed by their aggregating txd. */
535925641fc7SSepherosa Ziehau 	if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) {
536025641fc7SSepherosa Ziehau 		int freed;
536125641fc7SSepherosa Ziehau 
536225641fc7SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
536325641fc7SSepherosa Ziehau 		KASSERT(freed, ("can't free txdesc"));
536425641fc7SSepherosa Ziehau 	}
536525641fc7SSepherosa Ziehau }
536625641fc7SSepherosa Ziehau 
536725641fc7SSepherosa Ziehau static void
536815516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr)
536915516c77SSepherosa Ziehau {
537025641fc7SSepherosa Ziehau 	int i;
537115516c77SSepherosa Ziehau 
537215516c77SSepherosa Ziehau 	if (txr->hn_txdesc == NULL)
537315516c77SSepherosa Ziehau 		return;
537415516c77SSepherosa Ziehau 
537525641fc7SSepherosa Ziehau 	/*
537625641fc7SSepherosa Ziehau 	 * NOTE:
537725641fc7SSepherosa Ziehau 	 * Because the freeing of aggregated txds will be deferred
537825641fc7SSepherosa Ziehau 	 * to the aggregating txd, two passes are used here:
537925641fc7SSepherosa Ziehau 	 * - The first pass GCes any pending txds.  This GC is necessary,
538025641fc7SSepherosa Ziehau 	 *   since if the channels are revoked, hypervisor will not
538125641fc7SSepherosa Ziehau 	 *   deliver send-done for all pending txds.
538225641fc7SSepherosa Ziehau 	 * - The second pass frees the busdma stuffs, i.e. after all txds
538325641fc7SSepherosa Ziehau 	 *   were freed.
538425641fc7SSepherosa Ziehau 	 */
538525641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
538625641fc7SSepherosa Ziehau 		hn_txdesc_gc(txr, &txr->hn_txdesc[i]);
538725641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
538825641fc7SSepherosa Ziehau 		hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]);
538915516c77SSepherosa Ziehau 
539015516c77SSepherosa Ziehau 	if (txr->hn_tx_data_dtag != NULL)
539115516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_data_dtag);
539215516c77SSepherosa Ziehau 	if (txr->hn_tx_rndis_dtag != NULL)
539315516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_rndis_dtag);
539415516c77SSepherosa Ziehau 
539515516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
539615516c77SSepherosa Ziehau 	buf_ring_free(txr->hn_txdesc_br, M_DEVBUF);
539715516c77SSepherosa Ziehau #endif
539815516c77SSepherosa Ziehau 
539915516c77SSepherosa Ziehau 	free(txr->hn_txdesc, M_DEVBUF);
540015516c77SSepherosa Ziehau 	txr->hn_txdesc = NULL;
540115516c77SSepherosa Ziehau 
540215516c77SSepherosa Ziehau 	if (txr->hn_mbuf_br != NULL)
540315516c77SSepherosa Ziehau 		buf_ring_free(txr->hn_mbuf_br, M_DEVBUF);
540415516c77SSepherosa Ziehau 
540515516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
540615516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_txlist_spin);
540715516c77SSepherosa Ziehau #endif
540815516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_tx_lock);
540915516c77SSepherosa Ziehau }
541015516c77SSepherosa Ziehau 
541115516c77SSepherosa Ziehau static int
541215516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt)
541315516c77SSepherosa Ziehau {
541415516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
541515516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
541615516c77SSepherosa Ziehau 	int i;
541715516c77SSepherosa Ziehau 
541815516c77SSepherosa Ziehau 	/*
541915516c77SSepherosa Ziehau 	 * Create TXBUF for chimney sending.
542015516c77SSepherosa Ziehau 	 *
542115516c77SSepherosa Ziehau 	 * NOTE: It is shared by all channels.
542215516c77SSepherosa Ziehau 	 */
542315516c77SSepherosa Ziehau 	sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev),
542415516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma,
542515516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
542615516c77SSepherosa Ziehau 	if (sc->hn_chim == NULL) {
542715516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate txbuf failed\n");
542815516c77SSepherosa Ziehau 		return (ENOMEM);
542915516c77SSepherosa Ziehau 	}
543015516c77SSepherosa Ziehau 
543115516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = ring_cnt;
543215516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
543315516c77SSepherosa Ziehau 
543415516c77SSepherosa Ziehau 	sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt,
543515516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
543615516c77SSepherosa Ziehau 
543715516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(sc->hn_dev);
543815516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev));
543915516c77SSepherosa Ziehau 
544015516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.tx sysctl tree */
544115516c77SSepherosa Ziehau 	sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx",
544215516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
544315516c77SSepherosa Ziehau 
544415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
544515516c77SSepherosa Ziehau 		int error;
544615516c77SSepherosa Ziehau 
544715516c77SSepherosa Ziehau 		error = hn_tx_ring_create(sc, i);
544815516c77SSepherosa Ziehau 		if (error)
544915516c77SSepherosa Ziehau 			return error;
545015516c77SSepherosa Ziehau 	}
545115516c77SSepherosa Ziehau 
545215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs",
545315516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
545415516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_no_txdescs),
545515516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs");
545615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed",
545715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
545815516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_send_failed),
545915516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure");
546015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed",
546115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
546215516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_txdma_failed),
546315516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure");
5464dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed",
5465dc13fee6SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
5466dc13fee6SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_flush_failed),
5467dc13fee6SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU",
5468dc13fee6SSepherosa Ziehau 	    "# of packet transmission aggregation flush failure");
546915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed",
547015516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
547115516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_collapsed),
547215516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed");
547315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney",
547415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
547515516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney),
547615516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send");
547715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried",
547815516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
547915516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney_tried),
548015516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries");
548115516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt",
548215516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0,
548315516c77SSepherosa Ziehau 	    "# of total TX descs");
548415516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max",
548515516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_chim_szmax, 0,
548615516c77SSepherosa Ziehau 	    "Chimney send packet size upper boundary");
548715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size",
548815516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
548915516c77SSepherosa Ziehau 	    hn_chim_size_sysctl, "I", "Chimney send packet size limit");
549015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size",
549115516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
549215516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_direct_tx_size),
549315516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
549415516c77SSepherosa Ziehau 	    "Size of the packet for direct transmission");
549515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx",
549615516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
549715516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_sched_tx),
549815516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
549915516c77SSepherosa Ziehau 	    "Always schedule transmission "
550015516c77SSepherosa Ziehau 	    "instead of doing direct transmission");
550115516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt",
550215516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings");
550315516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse",
550415516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings");
5505dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax",
5506dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0,
5507dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation size");
5508dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax",
5509dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
5510dc13fee6SSepherosa Ziehau 	    hn_txagg_pktmax_sysctl, "I",
5511dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation packets");
5512dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align",
5513dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
5514dc13fee6SSepherosa Ziehau 	    hn_txagg_align_sysctl, "I",
5515dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation alignment");
551615516c77SSepherosa Ziehau 
551715516c77SSepherosa Ziehau 	return 0;
551815516c77SSepherosa Ziehau }
551915516c77SSepherosa Ziehau 
552015516c77SSepherosa Ziehau static void
552115516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size)
552215516c77SSepherosa Ziehau {
552315516c77SSepherosa Ziehau 	int i;
552415516c77SSepherosa Ziehau 
5525a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
552615516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_chim_size = chim_size;
552715516c77SSepherosa Ziehau }
552815516c77SSepherosa Ziehau 
552915516c77SSepherosa Ziehau static void
553015516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu)
553115516c77SSepherosa Ziehau {
553215516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
55339c6cae24SSepherosa Ziehau 	u_int hw_tsomax;
553415516c77SSepherosa Ziehau 	int tso_minlen;
553515516c77SSepherosa Ziehau 
55369c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
55379c6cae24SSepherosa Ziehau 
553815516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0)
553915516c77SSepherosa Ziehau 		return;
554015516c77SSepherosa Ziehau 
554115516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_sgmin >= 2,
554215516c77SSepherosa Ziehau 	    ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin));
554315516c77SSepherosa Ziehau 	tso_minlen = sc->hn_ndis_tso_sgmin * mtu;
554415516c77SSepherosa Ziehau 
554515516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen &&
554615516c77SSepherosa Ziehau 	    sc->hn_ndis_tso_szmax <= IP_MAXPACKET,
554715516c77SSepherosa Ziehau 	    ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax));
554815516c77SSepherosa Ziehau 
554915516c77SSepherosa Ziehau 	if (tso_maxlen < tso_minlen)
555015516c77SSepherosa Ziehau 		tso_maxlen = tso_minlen;
555115516c77SSepherosa Ziehau 	else if (tso_maxlen > IP_MAXPACKET)
555215516c77SSepherosa Ziehau 		tso_maxlen = IP_MAXPACKET;
555315516c77SSepherosa Ziehau 	if (tso_maxlen > sc->hn_ndis_tso_szmax)
555415516c77SSepherosa Ziehau 		tso_maxlen = sc->hn_ndis_tso_szmax;
55559c6cae24SSepherosa Ziehau 	hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
55569c6cae24SSepherosa Ziehau 
55579c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_isready(sc)) {
55589c6cae24SSepherosa Ziehau 		if (hw_tsomax > sc->hn_vf_ifp->if_hw_tsomax)
55599c6cae24SSepherosa Ziehau 			hw_tsomax = sc->hn_vf_ifp->if_hw_tsomax;
55609c6cae24SSepherosa Ziehau 	}
55619c6cae24SSepherosa Ziehau 	ifp->if_hw_tsomax = hw_tsomax;
556215516c77SSepherosa Ziehau 	if (bootverbose)
556315516c77SSepherosa Ziehau 		if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax);
556415516c77SSepherosa Ziehau }
556515516c77SSepherosa Ziehau 
556615516c77SSepherosa Ziehau static void
556715516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc)
556815516c77SSepherosa Ziehau {
556915516c77SSepherosa Ziehau 	uint64_t csum_assist;
557015516c77SSepherosa Ziehau 	int i;
557115516c77SSepherosa Ziehau 
557215516c77SSepherosa Ziehau 	hn_set_chim_size(sc, sc->hn_chim_szmax);
557315516c77SSepherosa Ziehau 	if (hn_tx_chimney_size > 0 &&
557415516c77SSepherosa Ziehau 	    hn_tx_chimney_size < sc->hn_chim_szmax)
557515516c77SSepherosa Ziehau 		hn_set_chim_size(sc, hn_tx_chimney_size);
557615516c77SSepherosa Ziehau 
557715516c77SSepherosa Ziehau 	csum_assist = 0;
557815516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_IPCS)
557915516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP;
558015516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP4CS)
558115516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_TCP;
55822be266caSSepherosa Ziehau 	if ((sc->hn_caps & HN_CAP_UDP4CS) && hn_enable_udp4cs)
558315516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_UDP;
558415516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP6CS)
558515516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_TCP;
55862be266caSSepherosa Ziehau 	if ((sc->hn_caps & HN_CAP_UDP6CS) && hn_enable_udp6cs)
558715516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_UDP;
558815516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
558915516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_csum_assist = csum_assist;
559015516c77SSepherosa Ziehau 
559115516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_HASHVAL) {
559215516c77SSepherosa Ziehau 		/*
559315516c77SSepherosa Ziehau 		 * Support HASHVAL pktinfo on TX path.
559415516c77SSepherosa Ziehau 		 */
559515516c77SSepherosa Ziehau 		if (bootverbose)
559615516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n");
559715516c77SSepherosa Ziehau 		for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
559815516c77SSepherosa Ziehau 			sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL;
559915516c77SSepherosa Ziehau 	}
560015516c77SSepherosa Ziehau }
560115516c77SSepherosa Ziehau 
560215516c77SSepherosa Ziehau static void
5603db76829bSSepherosa Ziehau hn_fixup_rx_data(struct hn_softc *sc)
5604db76829bSSepherosa Ziehau {
5605db76829bSSepherosa Ziehau 
5606db76829bSSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDPHASH) {
5607db76829bSSepherosa Ziehau 		int i;
5608db76829bSSepherosa Ziehau 
5609db76829bSSepherosa Ziehau 		for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
5610db76829bSSepherosa Ziehau 			sc->hn_rx_ring[i].hn_rx_flags |= HN_RX_FLAG_UDP_HASH;
5611db76829bSSepherosa Ziehau 	}
5612db76829bSSepherosa Ziehau }
5613db76829bSSepherosa Ziehau 
5614db76829bSSepherosa Ziehau static void
561515516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc)
561615516c77SSepherosa Ziehau {
561715516c77SSepherosa Ziehau 	int i;
561815516c77SSepherosa Ziehau 
561915516c77SSepherosa Ziehau 	if (sc->hn_chim != NULL) {
56202494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) {
562115516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim);
56222494d735SSepherosa Ziehau 		} else {
56232494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
56242494d735SSepherosa Ziehau 			    "chimney sending buffer is referenced");
56252494d735SSepherosa Ziehau 		}
562615516c77SSepherosa Ziehau 		sc->hn_chim = NULL;
562715516c77SSepherosa Ziehau 	}
562815516c77SSepherosa Ziehau 
562915516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt == 0)
563015516c77SSepherosa Ziehau 		return;
563115516c77SSepherosa Ziehau 
563215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
563315516c77SSepherosa Ziehau 		hn_tx_ring_destroy(&sc->hn_tx_ring[i]);
563415516c77SSepherosa Ziehau 
563515516c77SSepherosa Ziehau 	free(sc->hn_tx_ring, M_DEVBUF);
563615516c77SSepherosa Ziehau 	sc->hn_tx_ring = NULL;
563715516c77SSepherosa Ziehau 
563815516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = 0;
563915516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = 0;
564015516c77SSepherosa Ziehau }
564115516c77SSepherosa Ziehau 
564223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
564323bf9e15SSepherosa Ziehau 
564415516c77SSepherosa Ziehau static void
564515516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused)
564615516c77SSepherosa Ziehau {
564715516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
564815516c77SSepherosa Ziehau 
564915516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
565015516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
565115516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
565215516c77SSepherosa Ziehau }
565315516c77SSepherosa Ziehau 
565423bf9e15SSepherosa Ziehau static int
565523bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len)
565623bf9e15SSepherosa Ziehau {
565723bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
565823bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
5659dc13fee6SSepherosa Ziehau 	int sched = 0;
566023bf9e15SSepherosa Ziehau 
566123bf9e15SSepherosa Ziehau 	KASSERT(hn_use_if_start,
566223bf9e15SSepherosa Ziehau 	    ("hn_start_locked is called, when if_start is disabled"));
566323bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
566423bf9e15SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
5665dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
566623bf9e15SSepherosa Ziehau 
566723bf9e15SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
5668dc13fee6SSepherosa Ziehau 		return (0);
566923bf9e15SSepherosa Ziehau 
567023bf9e15SSepherosa Ziehau 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
567123bf9e15SSepherosa Ziehau 	    IFF_DRV_RUNNING)
5672dc13fee6SSepherosa Ziehau 		return (0);
567323bf9e15SSepherosa Ziehau 
567423bf9e15SSepherosa Ziehau 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
567523bf9e15SSepherosa Ziehau 		struct hn_txdesc *txd;
567623bf9e15SSepherosa Ziehau 		struct mbuf *m_head;
567723bf9e15SSepherosa Ziehau 		int error;
567823bf9e15SSepherosa Ziehau 
567923bf9e15SSepherosa Ziehau 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
568023bf9e15SSepherosa Ziehau 		if (m_head == NULL)
568123bf9e15SSepherosa Ziehau 			break;
568223bf9e15SSepherosa Ziehau 
568323bf9e15SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
568423bf9e15SSepherosa Ziehau 			/*
568523bf9e15SSepherosa Ziehau 			 * This sending could be time consuming; let callers
568623bf9e15SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
568723bf9e15SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
568823bf9e15SSepherosa Ziehau 			 */
568923bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
5690dc13fee6SSepherosa Ziehau 			sched = 1;
5691dc13fee6SSepherosa Ziehau 			break;
569223bf9e15SSepherosa Ziehau 		}
569323bf9e15SSepherosa Ziehau 
5694edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
5695edd3f315SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
5696edd3f315SSepherosa Ziehau 			m_head = hn_tso_fixup(m_head);
5697edd3f315SSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
5698edd3f315SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5699edd3f315SSepherosa Ziehau 				continue;
5700edd3f315SSepherosa Ziehau 			}
5701c49d47daSSepherosa Ziehau 		} else if (m_head->m_pkthdr.csum_flags &
5702c49d47daSSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) {
5703c49d47daSSepherosa Ziehau 			m_head = hn_set_hlen(m_head);
5704c49d47daSSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
5705c49d47daSSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5706c49d47daSSepherosa Ziehau 				continue;
5707c49d47daSSepherosa Ziehau 			}
5708edd3f315SSepherosa Ziehau 		}
5709edd3f315SSepherosa Ziehau #endif
5710edd3f315SSepherosa Ziehau 
571123bf9e15SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
571223bf9e15SSepherosa Ziehau 		if (txd == NULL) {
571323bf9e15SSepherosa Ziehau 			txr->hn_no_txdescs++;
571423bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
571523bf9e15SSepherosa Ziehau 			atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
571623bf9e15SSepherosa Ziehau 			break;
571723bf9e15SSepherosa Ziehau 		}
571823bf9e15SSepherosa Ziehau 
5719dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
572023bf9e15SSepherosa Ziehau 		if (error) {
572123bf9e15SSepherosa Ziehau 			/* Both txd and m_head are freed */
5722dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
5723dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
572423bf9e15SSepherosa Ziehau 			continue;
572523bf9e15SSepherosa Ziehau 		}
572623bf9e15SSepherosa Ziehau 
5727dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
5728dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
5729dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
5730dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
5731dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
5732dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
5733dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
5734dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
5735dc13fee6SSepherosa Ziehau 					break;
5736dc13fee6SSepherosa Ziehau 				}
5737dc13fee6SSepherosa Ziehau 			} else {
5738dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
573923bf9e15SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
574023bf9e15SSepherosa Ziehau 				if (__predict_false(error)) {
574123bf9e15SSepherosa Ziehau 					/* txd is freed, but m_head is not */
574223bf9e15SSepherosa Ziehau 					IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
5743dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
5744dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
574523bf9e15SSepherosa Ziehau 					break;
574623bf9e15SSepherosa Ziehau 				}
574723bf9e15SSepherosa Ziehau 			}
5748dc13fee6SSepherosa Ziehau 		}
5749dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
5750dc13fee6SSepherosa Ziehau 		else {
5751dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
5752dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
5753dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
5754dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
5755dc13fee6SSepherosa Ziehau 		}
5756dc13fee6SSepherosa Ziehau #endif
5757dc13fee6SSepherosa Ziehau 	}
5758dc13fee6SSepherosa Ziehau 
5759dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
5760dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
5761dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
5762dc13fee6SSepherosa Ziehau 	return (sched);
576323bf9e15SSepherosa Ziehau }
576423bf9e15SSepherosa Ziehau 
576523bf9e15SSepherosa Ziehau static void
576623bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp)
576723bf9e15SSepherosa Ziehau {
576823bf9e15SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
576923bf9e15SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[0];
577023bf9e15SSepherosa Ziehau 
577123bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
577223bf9e15SSepherosa Ziehau 		goto do_sched;
577323bf9e15SSepherosa Ziehau 
577423bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
577523bf9e15SSepherosa Ziehau 		int sched;
577623bf9e15SSepherosa Ziehau 
577723bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
577823bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
577923bf9e15SSepherosa Ziehau 		if (!sched)
578023bf9e15SSepherosa Ziehau 			return;
578123bf9e15SSepherosa Ziehau 	}
578223bf9e15SSepherosa Ziehau do_sched:
578323bf9e15SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
578423bf9e15SSepherosa Ziehau }
578523bf9e15SSepherosa Ziehau 
578615516c77SSepherosa Ziehau static void
578715516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused)
578815516c77SSepherosa Ziehau {
578915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
579015516c77SSepherosa Ziehau 
579115516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
579215516c77SSepherosa Ziehau 	atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE);
579315516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
579415516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
579515516c77SSepherosa Ziehau }
579615516c77SSepherosa Ziehau 
579723bf9e15SSepherosa Ziehau static void
579823bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr)
579923bf9e15SSepherosa Ziehau {
580023bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
580123bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
580223bf9e15SSepherosa Ziehau 
580323bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
580423bf9e15SSepherosa Ziehau 
580523bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
580623bf9e15SSepherosa Ziehau 		goto do_sched;
580723bf9e15SSepherosa Ziehau 
580823bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
580923bf9e15SSepherosa Ziehau 		int sched;
581023bf9e15SSepherosa Ziehau 
581123bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
581223bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
581323bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
581423bf9e15SSepherosa Ziehau 		if (sched) {
581523bf9e15SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
581623bf9e15SSepherosa Ziehau 			    &txr->hn_tx_task);
581723bf9e15SSepherosa Ziehau 		}
581823bf9e15SSepherosa Ziehau 	} else {
581923bf9e15SSepherosa Ziehau do_sched:
582023bf9e15SSepherosa Ziehau 		/*
582123bf9e15SSepherosa Ziehau 		 * Release the OACTIVE earlier, with the hope, that
582223bf9e15SSepherosa Ziehau 		 * others could catch up.  The task will clear the
582323bf9e15SSepherosa Ziehau 		 * flag again with the hn_tx_lock to avoid possible
582423bf9e15SSepherosa Ziehau 		 * races.
582523bf9e15SSepherosa Ziehau 		 */
582623bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
582723bf9e15SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
582823bf9e15SSepherosa Ziehau 	}
582923bf9e15SSepherosa Ziehau }
583023bf9e15SSepherosa Ziehau 
583123bf9e15SSepherosa Ziehau #endif	/* HN_IFSTART_SUPPORT */
583223bf9e15SSepherosa Ziehau 
583315516c77SSepherosa Ziehau static int
583415516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len)
583515516c77SSepherosa Ziehau {
583615516c77SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
583715516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
583815516c77SSepherosa Ziehau 	struct mbuf *m_head;
5839dc13fee6SSepherosa Ziehau 	int sched = 0;
584015516c77SSepherosa Ziehau 
584115516c77SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
584223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
584315516c77SSepherosa Ziehau 	KASSERT(hn_use_if_start == 0,
584415516c77SSepherosa Ziehau 	    ("hn_xmit is called, when if_start is enabled"));
584523bf9e15SSepherosa Ziehau #endif
5846dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
584715516c77SSepherosa Ziehau 
584815516c77SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
5849dc13fee6SSepherosa Ziehau 		return (0);
585015516c77SSepherosa Ziehau 
585115516c77SSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive)
5852dc13fee6SSepherosa Ziehau 		return (0);
585315516c77SSepherosa Ziehau 
585415516c77SSepherosa Ziehau 	while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) {
585515516c77SSepherosa Ziehau 		struct hn_txdesc *txd;
585615516c77SSepherosa Ziehau 		int error;
585715516c77SSepherosa Ziehau 
585815516c77SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
585915516c77SSepherosa Ziehau 			/*
586015516c77SSepherosa Ziehau 			 * This sending could be time consuming; let callers
586115516c77SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
586215516c77SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
586315516c77SSepherosa Ziehau 			 */
586415516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
5865dc13fee6SSepherosa Ziehau 			sched = 1;
5866dc13fee6SSepherosa Ziehau 			break;
586715516c77SSepherosa Ziehau 		}
586815516c77SSepherosa Ziehau 
586915516c77SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
587015516c77SSepherosa Ziehau 		if (txd == NULL) {
587115516c77SSepherosa Ziehau 			txr->hn_no_txdescs++;
587215516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
587315516c77SSepherosa Ziehau 			txr->hn_oactive = 1;
587415516c77SSepherosa Ziehau 			break;
587515516c77SSepherosa Ziehau 		}
587615516c77SSepherosa Ziehau 
5877dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
587815516c77SSepherosa Ziehau 		if (error) {
587915516c77SSepherosa Ziehau 			/* Both txd and m_head are freed; discard */
5880dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
5881dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
588215516c77SSepherosa Ziehau 			drbr_advance(ifp, txr->hn_mbuf_br);
588315516c77SSepherosa Ziehau 			continue;
588415516c77SSepherosa Ziehau 		}
588515516c77SSepherosa Ziehau 
5886dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
5887dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
5888dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
5889dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
5890dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
589115516c77SSepherosa Ziehau 				if (__predict_false(error)) {
589215516c77SSepherosa Ziehau 					txr->hn_oactive = 1;
589315516c77SSepherosa Ziehau 					break;
589415516c77SSepherosa Ziehau 				}
5895dc13fee6SSepherosa Ziehau 			} else {
5896dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
5897dc13fee6SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
5898dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
5899dc13fee6SSepherosa Ziehau 					/* txd is freed, but m_head is not */
5900dc13fee6SSepherosa Ziehau 					drbr_putback(ifp, txr->hn_mbuf_br,
5901dc13fee6SSepherosa Ziehau 					    m_head);
5902dc13fee6SSepherosa Ziehau 					txr->hn_oactive = 1;
5903dc13fee6SSepherosa Ziehau 					break;
5904dc13fee6SSepherosa Ziehau 				}
5905dc13fee6SSepherosa Ziehau 			}
5906dc13fee6SSepherosa Ziehau 		}
5907dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
5908dc13fee6SSepherosa Ziehau 		else {
5909dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
5910dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
5911dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
5912dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
5913dc13fee6SSepherosa Ziehau 		}
5914dc13fee6SSepherosa Ziehau #endif
591515516c77SSepherosa Ziehau 
591615516c77SSepherosa Ziehau 		/* Sent */
591715516c77SSepherosa Ziehau 		drbr_advance(ifp, txr->hn_mbuf_br);
591815516c77SSepherosa Ziehau 	}
5919dc13fee6SSepherosa Ziehau 
5920dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
5921dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
5922dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
5923dc13fee6SSepherosa Ziehau 	return (sched);
592415516c77SSepherosa Ziehau }
592515516c77SSepherosa Ziehau 
592615516c77SSepherosa Ziehau static int
592715516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m)
592815516c77SSepherosa Ziehau {
592915516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
593015516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
593115516c77SSepherosa Ziehau 	int error, idx = 0;
593215516c77SSepherosa Ziehau 
59339c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) {
59349c6cae24SSepherosa Ziehau 		struct rm_priotracker pt;
59359c6cae24SSepherosa Ziehau 
59369c6cae24SSepherosa Ziehau 		rm_rlock(&sc->hn_vf_lock, &pt);
59379c6cae24SSepherosa Ziehau 		if (__predict_true(sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
59389c6cae24SSepherosa Ziehau 			struct mbuf *m_bpf = NULL;
59399c6cae24SSepherosa Ziehau 			int obytes, omcast;
59409c6cae24SSepherosa Ziehau 
59419c6cae24SSepherosa Ziehau 			obytes = m->m_pkthdr.len;
59429c6cae24SSepherosa Ziehau 			if (m->m_flags & M_MCAST)
59439c6cae24SSepherosa Ziehau 				omcast = 1;
59449c6cae24SSepherosa Ziehau 
59459c6cae24SSepherosa Ziehau 			if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF) {
59469c6cae24SSepherosa Ziehau 				if (bpf_peers_present(ifp->if_bpf)) {
59479c6cae24SSepherosa Ziehau 					m_bpf = m_copypacket(m, M_NOWAIT);
59489c6cae24SSepherosa Ziehau 					if (m_bpf == NULL) {
59499c6cae24SSepherosa Ziehau 						/*
59509c6cae24SSepherosa Ziehau 						 * Failed to grab a shallow
59519c6cae24SSepherosa Ziehau 						 * copy; tap now.
59529c6cae24SSepherosa Ziehau 						 */
59539c6cae24SSepherosa Ziehau 						ETHER_BPF_MTAP(ifp, m);
59549c6cae24SSepherosa Ziehau 					}
59559c6cae24SSepherosa Ziehau 				}
59569c6cae24SSepherosa Ziehau 			} else {
59579c6cae24SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, m);
59589c6cae24SSepherosa Ziehau 			}
59599c6cae24SSepherosa Ziehau 
59609c6cae24SSepherosa Ziehau 			error = sc->hn_vf_ifp->if_transmit(sc->hn_vf_ifp, m);
59619c6cae24SSepherosa Ziehau 			rm_runlock(&sc->hn_vf_lock, &pt);
59629c6cae24SSepherosa Ziehau 
59639c6cae24SSepherosa Ziehau 			if (m_bpf != NULL) {
59649c6cae24SSepherosa Ziehau 				if (!error)
59659c6cae24SSepherosa Ziehau 					ETHER_BPF_MTAP(ifp, m_bpf);
59669c6cae24SSepherosa Ziehau 				m_freem(m_bpf);
59679c6cae24SSepherosa Ziehau 			}
59689c6cae24SSepherosa Ziehau 
59699c6cae24SSepherosa Ziehau 			if (error == ENOBUFS) {
59709c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
59719c6cae24SSepherosa Ziehau 			} else if (error) {
59729c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
59739c6cae24SSepherosa Ziehau 			} else {
59749c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
59759c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OBYTES, obytes);
59769c6cae24SSepherosa Ziehau 				if (omcast) {
59779c6cae24SSepherosa Ziehau 					if_inc_counter(ifp, IFCOUNTER_OMCASTS,
59789c6cae24SSepherosa Ziehau 					    omcast);
59799c6cae24SSepherosa Ziehau 				}
59809c6cae24SSepherosa Ziehau 			}
59819c6cae24SSepherosa Ziehau 			return (error);
59829c6cae24SSepherosa Ziehau 		}
59839c6cae24SSepherosa Ziehau 		rm_runlock(&sc->hn_vf_lock, &pt);
59849c6cae24SSepherosa Ziehau 	}
59859c6cae24SSepherosa Ziehau 
5986edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
5987edd3f315SSepherosa Ziehau 	/*
5988c49d47daSSepherosa Ziehau 	 * Perform TSO packet header fixup or get l2/l3 header length now,
5989c49d47daSSepherosa Ziehau 	 * since packet headers should be cache-hot.
5990edd3f315SSepherosa Ziehau 	 */
5991edd3f315SSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
5992edd3f315SSepherosa Ziehau 		m = hn_tso_fixup(m);
5993edd3f315SSepherosa Ziehau 		if (__predict_false(m == NULL)) {
5994edd3f315SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5995edd3f315SSepherosa Ziehau 			return EIO;
5996edd3f315SSepherosa Ziehau 		}
5997c49d47daSSepherosa Ziehau 	} else if (m->m_pkthdr.csum_flags &
5998c49d47daSSepherosa Ziehau 	    (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) {
5999c49d47daSSepherosa Ziehau 		m = hn_set_hlen(m);
6000c49d47daSSepherosa Ziehau 		if (__predict_false(m == NULL)) {
6001c49d47daSSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
6002c49d47daSSepherosa Ziehau 			return EIO;
6003c49d47daSSepherosa Ziehau 		}
6004edd3f315SSepherosa Ziehau 	}
6005edd3f315SSepherosa Ziehau #endif
6006edd3f315SSepherosa Ziehau 
600715516c77SSepherosa Ziehau 	/*
600815516c77SSepherosa Ziehau 	 * Select the TX ring based on flowid
600915516c77SSepherosa Ziehau 	 */
601034d68912SSepherosa Ziehau 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
601134d68912SSepherosa Ziehau #ifdef RSS
601234d68912SSepherosa Ziehau 		uint32_t bid;
601334d68912SSepherosa Ziehau 
601434d68912SSepherosa Ziehau 		if (rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m),
601534d68912SSepherosa Ziehau 		    &bid) == 0)
601634d68912SSepherosa Ziehau 			idx = bid % sc->hn_tx_ring_inuse;
601734d68912SSepherosa Ziehau 		else
601834d68912SSepherosa Ziehau #endif
6019cc0c6ebcSSepherosa Ziehau 		{
6020cc0c6ebcSSepherosa Ziehau #if defined(INET6) || defined(INET)
6021cc0c6ebcSSepherosa Ziehau 			int tcpsyn = 0;
6022cc0c6ebcSSepherosa Ziehau 
6023cc0c6ebcSSepherosa Ziehau 			if (m->m_pkthdr.len < 128 &&
6024cc0c6ebcSSepherosa Ziehau 			    (m->m_pkthdr.csum_flags &
6025cc0c6ebcSSepherosa Ziehau 			     (CSUM_IP_TCP | CSUM_IP6_TCP)) &&
6026cc0c6ebcSSepherosa Ziehau 			    (m->m_pkthdr.csum_flags & CSUM_TSO) == 0) {
6027cc0c6ebcSSepherosa Ziehau 				m = hn_check_tcpsyn(m, &tcpsyn);
6028cc0c6ebcSSepherosa Ziehau 				if (__predict_false(m == NULL)) {
6029cc0c6ebcSSepherosa Ziehau 					if_inc_counter(ifp,
6030cc0c6ebcSSepherosa Ziehau 					    IFCOUNTER_OERRORS, 1);
6031cc0c6ebcSSepherosa Ziehau 					return (EIO);
6032cc0c6ebcSSepherosa Ziehau 				}
6033cc0c6ebcSSepherosa Ziehau 			}
6034cc0c6ebcSSepherosa Ziehau #else
6035cc0c6ebcSSepherosa Ziehau 			const int tcpsyn = 0;
6036cc0c6ebcSSepherosa Ziehau #endif
6037cc0c6ebcSSepherosa Ziehau 			if (tcpsyn)
6038cc0c6ebcSSepherosa Ziehau 				idx = 0;
6039cc0c6ebcSSepherosa Ziehau 			else
604015516c77SSepherosa Ziehau 				idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse;
604134d68912SSepherosa Ziehau 		}
6042cc0c6ebcSSepherosa Ziehau 	}
604315516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[idx];
604415516c77SSepherosa Ziehau 
604515516c77SSepherosa Ziehau 	error = drbr_enqueue(ifp, txr->hn_mbuf_br, m);
604615516c77SSepherosa Ziehau 	if (error) {
604715516c77SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
604815516c77SSepherosa Ziehau 		return error;
604915516c77SSepherosa Ziehau 	}
605015516c77SSepherosa Ziehau 
605115516c77SSepherosa Ziehau 	if (txr->hn_oactive)
605215516c77SSepherosa Ziehau 		return 0;
605315516c77SSepherosa Ziehau 
605415516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
605515516c77SSepherosa Ziehau 		goto do_sched;
605615516c77SSepherosa Ziehau 
605715516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
605815516c77SSepherosa Ziehau 		int sched;
605915516c77SSepherosa Ziehau 
606015516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
606115516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
606215516c77SSepherosa Ziehau 		if (!sched)
606315516c77SSepherosa Ziehau 			return 0;
606415516c77SSepherosa Ziehau 	}
606515516c77SSepherosa Ziehau do_sched:
606615516c77SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
606715516c77SSepherosa Ziehau 	return 0;
606815516c77SSepherosa Ziehau }
606915516c77SSepherosa Ziehau 
607015516c77SSepherosa Ziehau static void
607115516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr)
607215516c77SSepherosa Ziehau {
607315516c77SSepherosa Ziehau 	struct mbuf *m;
607415516c77SSepherosa Ziehau 
607515516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
607615516c77SSepherosa Ziehau 	while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL)
607715516c77SSepherosa Ziehau 		m_freem(m);
607815516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
607915516c77SSepherosa Ziehau }
608015516c77SSepherosa Ziehau 
608115516c77SSepherosa Ziehau static void
608215516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp)
608315516c77SSepherosa Ziehau {
608415516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
60859c6cae24SSepherosa Ziehau 	struct rm_priotracker pt;
608615516c77SSepherosa Ziehau 	int i;
608715516c77SSepherosa Ziehau 
608815516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
608915516c77SSepherosa Ziehau 		hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
609015516c77SSepherosa Ziehau 	if_qflush(ifp);
60919c6cae24SSepherosa Ziehau 
60929c6cae24SSepherosa Ziehau 	rm_rlock(&sc->hn_vf_lock, &pt);
60939c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
60949c6cae24SSepherosa Ziehau 		sc->hn_vf_ifp->if_qflush(sc->hn_vf_ifp);
60959c6cae24SSepherosa Ziehau 	rm_runlock(&sc->hn_vf_lock, &pt);
609615516c77SSepherosa Ziehau }
609715516c77SSepherosa Ziehau 
609815516c77SSepherosa Ziehau static void
609915516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr)
610015516c77SSepherosa Ziehau {
610115516c77SSepherosa Ziehau 
610215516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
610315516c77SSepherosa Ziehau 		goto do_sched;
610415516c77SSepherosa Ziehau 
610515516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
610615516c77SSepherosa Ziehau 		int sched;
610715516c77SSepherosa Ziehau 
610815516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
610915516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
611015516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
611115516c77SSepherosa Ziehau 		if (sched) {
611215516c77SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
611315516c77SSepherosa Ziehau 			    &txr->hn_tx_task);
611415516c77SSepherosa Ziehau 		}
611515516c77SSepherosa Ziehau 	} else {
611615516c77SSepherosa Ziehau do_sched:
611715516c77SSepherosa Ziehau 		/*
611815516c77SSepherosa Ziehau 		 * Release the oactive earlier, with the hope, that
611915516c77SSepherosa Ziehau 		 * others could catch up.  The task will clear the
612015516c77SSepherosa Ziehau 		 * oactive again with the hn_tx_lock to avoid possible
612115516c77SSepherosa Ziehau 		 * races.
612215516c77SSepherosa Ziehau 		 */
612315516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
612415516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
612515516c77SSepherosa Ziehau 	}
612615516c77SSepherosa Ziehau }
612715516c77SSepherosa Ziehau 
612815516c77SSepherosa Ziehau static void
612915516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused)
613015516c77SSepherosa Ziehau {
613115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
613215516c77SSepherosa Ziehau 
613315516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
613415516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
613515516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
613615516c77SSepherosa Ziehau }
613715516c77SSepherosa Ziehau 
613815516c77SSepherosa Ziehau static void
613915516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused)
614015516c77SSepherosa Ziehau {
614115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
614215516c77SSepherosa Ziehau 
614315516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
614415516c77SSepherosa Ziehau 	txr->hn_oactive = 0;
614515516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
614615516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
614715516c77SSepherosa Ziehau }
614815516c77SSepherosa Ziehau 
614915516c77SSepherosa Ziehau static int
615015516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan)
615115516c77SSepherosa Ziehau {
615215516c77SSepherosa Ziehau 	struct vmbus_chan_br cbr;
615315516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
615415516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = NULL;
615515516c77SSepherosa Ziehau 	int idx, error;
615615516c77SSepherosa Ziehau 
615715516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
615815516c77SSepherosa Ziehau 
615915516c77SSepherosa Ziehau 	/*
616015516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
616115516c77SSepherosa Ziehau 	 */
616215516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
616315516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
616415516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
616515516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
616615516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0,
616715516c77SSepherosa Ziehau 	    ("RX ring %d already attached", idx));
616815516c77SSepherosa Ziehau 	rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED;
61693ab0fea1SDexuan Cui 	rxr->hn_chan = chan;
617015516c77SSepherosa Ziehau 
617115516c77SSepherosa Ziehau 	if (bootverbose) {
617215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n",
617315516c77SSepherosa Ziehau 		    idx, vmbus_chan_id(chan));
617415516c77SSepherosa Ziehau 	}
617515516c77SSepherosa Ziehau 
617615516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
617715516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[idx];
617815516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0,
617915516c77SSepherosa Ziehau 		    ("TX ring %d already attached", idx));
618015516c77SSepherosa Ziehau 		txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED;
618115516c77SSepherosa Ziehau 
618215516c77SSepherosa Ziehau 		txr->hn_chan = chan;
618315516c77SSepherosa Ziehau 		if (bootverbose) {
618415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n",
618515516c77SSepherosa Ziehau 			    idx, vmbus_chan_id(chan));
618615516c77SSepherosa Ziehau 		}
618715516c77SSepherosa Ziehau 	}
618815516c77SSepherosa Ziehau 
618915516c77SSepherosa Ziehau 	/* Bind this channel to a proper CPU. */
61900e11868dSSepherosa Ziehau 	vmbus_chan_cpu_set(chan, HN_RING_IDX2CPU(sc, idx));
619115516c77SSepherosa Ziehau 
619215516c77SSepherosa Ziehau 	/*
619315516c77SSepherosa Ziehau 	 * Open this channel
619415516c77SSepherosa Ziehau 	 */
619515516c77SSepherosa Ziehau 	cbr.cbr = rxr->hn_br;
619615516c77SSepherosa Ziehau 	cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr;
619715516c77SSepherosa Ziehau 	cbr.cbr_txsz = HN_TXBR_SIZE;
619815516c77SSepherosa Ziehau 	cbr.cbr_rxsz = HN_RXBR_SIZE;
619915516c77SSepherosa Ziehau 	error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr);
620015516c77SSepherosa Ziehau 	if (error) {
620171e8ac56SSepherosa Ziehau 		if (error == EISCONN) {
620271e8ac56SSepherosa Ziehau 			if_printf(sc->hn_ifp, "bufring is connected after "
620371e8ac56SSepherosa Ziehau 			    "chan%u open failure\n", vmbus_chan_id(chan));
620471e8ac56SSepherosa Ziehau 			rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
620571e8ac56SSepherosa Ziehau 		} else {
620615516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "open chan%u failed: %d\n",
620715516c77SSepherosa Ziehau 			    vmbus_chan_id(chan), error);
620871e8ac56SSepherosa Ziehau 		}
620915516c77SSepherosa Ziehau 	}
621015516c77SSepherosa Ziehau 	return (error);
621115516c77SSepherosa Ziehau }
621215516c77SSepherosa Ziehau 
621315516c77SSepherosa Ziehau static void
621415516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan)
621515516c77SSepherosa Ziehau {
621615516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
62172494d735SSepherosa Ziehau 	int idx, error;
621815516c77SSepherosa Ziehau 
621915516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
622015516c77SSepherosa Ziehau 
622115516c77SSepherosa Ziehau 	/*
622215516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
622315516c77SSepherosa Ziehau 	 */
622415516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
622515516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
622615516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
622715516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
622815516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED),
622915516c77SSepherosa Ziehau 	    ("RX ring %d is not attached", idx));
623015516c77SSepherosa Ziehau 	rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
623115516c77SSepherosa Ziehau 
623215516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
623315516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[idx];
623415516c77SSepherosa Ziehau 
623515516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED),
623615516c77SSepherosa Ziehau 		    ("TX ring %d is not attached attached", idx));
623715516c77SSepherosa Ziehau 		txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
623815516c77SSepherosa Ziehau 	}
623915516c77SSepherosa Ziehau 
624015516c77SSepherosa Ziehau 	/*
624115516c77SSepherosa Ziehau 	 * Close this channel.
624215516c77SSepherosa Ziehau 	 *
624315516c77SSepherosa Ziehau 	 * NOTE:
624415516c77SSepherosa Ziehau 	 * Channel closing does _not_ destroy the target channel.
624515516c77SSepherosa Ziehau 	 */
62462494d735SSepherosa Ziehau 	error = vmbus_chan_close_direct(chan);
62472494d735SSepherosa Ziehau 	if (error == EISCONN) {
6248aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u bufring is connected "
6249aa1a2adcSSepherosa Ziehau 		    "after being closed\n", vmbus_chan_id(chan));
62502494d735SSepherosa Ziehau 		rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
62512494d735SSepherosa Ziehau 	} else if (error) {
6252aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u close failed: %d\n",
6253aa1a2adcSSepherosa Ziehau 		    vmbus_chan_id(chan), error);
62542494d735SSepherosa Ziehau 	}
625515516c77SSepherosa Ziehau }
625615516c77SSepherosa Ziehau 
625715516c77SSepherosa Ziehau static int
625815516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc)
625915516c77SSepherosa Ziehau {
626015516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
626115516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
626215516c77SSepherosa Ziehau 	int i, error = 0;
626315516c77SSepherosa Ziehau 
626471e8ac56SSepherosa Ziehau 	KASSERT(subchan_cnt > 0, ("no sub-channels"));
626515516c77SSepherosa Ziehau 
626615516c77SSepherosa Ziehau 	/* Attach the sub-channels. */
626715516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
626815516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i) {
626971e8ac56SSepherosa Ziehau 		int error1;
627071e8ac56SSepherosa Ziehau 
627171e8ac56SSepherosa Ziehau 		error1 = hn_chan_attach(sc, subchans[i]);
627271e8ac56SSepherosa Ziehau 		if (error1) {
627371e8ac56SSepherosa Ziehau 			error = error1;
627471e8ac56SSepherosa Ziehau 			/* Move on; all channels will be detached later. */
627571e8ac56SSepherosa Ziehau 		}
627615516c77SSepherosa Ziehau 	}
627715516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
627815516c77SSepherosa Ziehau 
627915516c77SSepherosa Ziehau 	if (error) {
628015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error);
628115516c77SSepherosa Ziehau 	} else {
628215516c77SSepherosa Ziehau 		if (bootverbose) {
628315516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "%d sub-channels attached\n",
628415516c77SSepherosa Ziehau 			    subchan_cnt);
628515516c77SSepherosa Ziehau 		}
628615516c77SSepherosa Ziehau 	}
628715516c77SSepherosa Ziehau 	return (error);
628815516c77SSepherosa Ziehau }
628915516c77SSepherosa Ziehau 
629015516c77SSepherosa Ziehau static void
629115516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc)
629215516c77SSepherosa Ziehau {
629315516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
629415516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
629515516c77SSepherosa Ziehau 	int i;
629615516c77SSepherosa Ziehau 
629715516c77SSepherosa Ziehau 	if (subchan_cnt == 0)
629815516c77SSepherosa Ziehau 		goto back;
629915516c77SSepherosa Ziehau 
630015516c77SSepherosa Ziehau 	/* Detach the sub-channels. */
630115516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
630215516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i)
630315516c77SSepherosa Ziehau 		hn_chan_detach(sc, subchans[i]);
630415516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
630515516c77SSepherosa Ziehau 
630615516c77SSepherosa Ziehau back:
630715516c77SSepherosa Ziehau 	/*
630815516c77SSepherosa Ziehau 	 * Detach the primary channel, _after_ all sub-channels
630915516c77SSepherosa Ziehau 	 * are detached.
631015516c77SSepherosa Ziehau 	 */
631115516c77SSepherosa Ziehau 	hn_chan_detach(sc, sc->hn_prichan);
631215516c77SSepherosa Ziehau 
631315516c77SSepherosa Ziehau 	/* Wait for sub-channels to be destroyed, if any. */
631415516c77SSepherosa Ziehau 	vmbus_subchan_drain(sc->hn_prichan);
631515516c77SSepherosa Ziehau 
631615516c77SSepherosa Ziehau #ifdef INVARIANTS
631715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
631815516c77SSepherosa Ziehau 		KASSERT((sc->hn_rx_ring[i].hn_rx_flags &
631915516c77SSepherosa Ziehau 		    HN_RX_FLAG_ATTACHED) == 0,
632015516c77SSepherosa Ziehau 		    ("%dth RX ring is still attached", i));
632115516c77SSepherosa Ziehau 	}
632215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
632315516c77SSepherosa Ziehau 		KASSERT((sc->hn_tx_ring[i].hn_tx_flags &
632415516c77SSepherosa Ziehau 		    HN_TX_FLAG_ATTACHED) == 0,
632515516c77SSepherosa Ziehau 		    ("%dth TX ring is still attached", i));
632615516c77SSepherosa Ziehau 	}
632715516c77SSepherosa Ziehau #endif
632815516c77SSepherosa Ziehau }
632915516c77SSepherosa Ziehau 
633015516c77SSepherosa Ziehau static int
633115516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch)
633215516c77SSepherosa Ziehau {
633315516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
633415516c77SSepherosa Ziehau 	int nchan, rxr_cnt, error;
633515516c77SSepherosa Ziehau 
633615516c77SSepherosa Ziehau 	nchan = *nsubch + 1;
633715516c77SSepherosa Ziehau 	if (nchan == 1) {
633815516c77SSepherosa Ziehau 		/*
633915516c77SSepherosa Ziehau 		 * Multiple RX/TX rings are not requested.
634015516c77SSepherosa Ziehau 		 */
634115516c77SSepherosa Ziehau 		*nsubch = 0;
634215516c77SSepherosa Ziehau 		return (0);
634315516c77SSepherosa Ziehau 	}
634415516c77SSepherosa Ziehau 
634515516c77SSepherosa Ziehau 	/*
634615516c77SSepherosa Ziehau 	 * Query RSS capabilities, e.g. # of RX rings, and # of indirect
634715516c77SSepherosa Ziehau 	 * table entries.
634815516c77SSepherosa Ziehau 	 */
634915516c77SSepherosa Ziehau 	error = hn_rndis_query_rsscaps(sc, &rxr_cnt);
635015516c77SSepherosa Ziehau 	if (error) {
635115516c77SSepherosa Ziehau 		/* No RSS; this is benign. */
635215516c77SSepherosa Ziehau 		*nsubch = 0;
635315516c77SSepherosa Ziehau 		return (0);
635415516c77SSepherosa Ziehau 	}
635515516c77SSepherosa Ziehau 	if (bootverbose) {
635615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
635715516c77SSepherosa Ziehau 		    rxr_cnt, nchan);
635815516c77SSepherosa Ziehau 	}
635915516c77SSepherosa Ziehau 
636015516c77SSepherosa Ziehau 	if (nchan > rxr_cnt)
636115516c77SSepherosa Ziehau 		nchan = rxr_cnt;
636215516c77SSepherosa Ziehau 	if (nchan == 1) {
636315516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n");
636415516c77SSepherosa Ziehau 		*nsubch = 0;
636515516c77SSepherosa Ziehau 		return (0);
636615516c77SSepherosa Ziehau 	}
636715516c77SSepherosa Ziehau 
636815516c77SSepherosa Ziehau 	/*
636915516c77SSepherosa Ziehau 	 * Allocate sub-channels from NVS.
637015516c77SSepherosa Ziehau 	 */
637115516c77SSepherosa Ziehau 	*nsubch = nchan - 1;
637215516c77SSepherosa Ziehau 	error = hn_nvs_alloc_subchans(sc, nsubch);
637315516c77SSepherosa Ziehau 	if (error || *nsubch == 0) {
637415516c77SSepherosa Ziehau 		/* Failed to allocate sub-channels. */
637515516c77SSepherosa Ziehau 		*nsubch = 0;
637615516c77SSepherosa Ziehau 		return (0);
637715516c77SSepherosa Ziehau 	}
637815516c77SSepherosa Ziehau 
637915516c77SSepherosa Ziehau 	/*
638015516c77SSepherosa Ziehau 	 * Wait for all sub-channels to become ready before moving on.
638115516c77SSepherosa Ziehau 	 */
638215516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch);
638315516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, *nsubch);
638415516c77SSepherosa Ziehau 	return (0);
638515516c77SSepherosa Ziehau }
638615516c77SSepherosa Ziehau 
63872494d735SSepherosa Ziehau static bool
63882494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc)
63892494d735SSepherosa Ziehau {
63902494d735SSepherosa Ziehau 	int i;
63912494d735SSepherosa Ziehau 
63922494d735SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_ERRORS)
63932494d735SSepherosa Ziehau 		return (false);
63942494d735SSepherosa Ziehau 
63952494d735SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
63962494d735SSepherosa Ziehau 		const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
63972494d735SSepherosa Ziehau 
63982494d735SSepherosa Ziehau 		if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF)
63992494d735SSepherosa Ziehau 			return (false);
64002494d735SSepherosa Ziehau 	}
64012494d735SSepherosa Ziehau 	return (true);
64022494d735SSepherosa Ziehau }
64032494d735SSepherosa Ziehau 
6404b3b75d9cSSepherosa Ziehau /*
6405b3b75d9cSSepherosa Ziehau  * Make sure that the RX filter is zero after the successful
6406b3b75d9cSSepherosa Ziehau  * RNDIS initialization.
6407b3b75d9cSSepherosa Ziehau  *
6408b3b75d9cSSepherosa Ziehau  * NOTE:
6409b3b75d9cSSepherosa Ziehau  * Under certain conditions on certain versions of Hyper-V,
6410b3b75d9cSSepherosa Ziehau  * the RNDIS rxfilter is _not_ zero on the hypervisor side
6411b3b75d9cSSepherosa Ziehau  * after the successful RNDIS initialization, which breaks
6412b3b75d9cSSepherosa Ziehau  * the assumption of any following code (well, it breaks the
6413b3b75d9cSSepherosa Ziehau  * RNDIS API contract actually).  Clear the RNDIS rxfilter
6414b3b75d9cSSepherosa Ziehau  * explicitly, drain packets sneaking through, and drain the
6415b3b75d9cSSepherosa Ziehau  * interrupt taskqueues scheduled due to the stealth packets.
6416b3b75d9cSSepherosa Ziehau  */
6417b3b75d9cSSepherosa Ziehau static void
6418b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(struct hn_softc *sc, int nchan)
6419b3b75d9cSSepherosa Ziehau {
6420b3b75d9cSSepherosa Ziehau 
6421b3b75d9cSSepherosa Ziehau 	hn_disable_rx(sc);
6422b3b75d9cSSepherosa Ziehau 	hn_drain_rxtx(sc, nchan);
6423b3b75d9cSSepherosa Ziehau }
6424b3b75d9cSSepherosa Ziehau 
642515516c77SSepherosa Ziehau static int
642615516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu)
642715516c77SSepherosa Ziehau {
642871e8ac56SSepherosa Ziehau #define ATTACHED_NVS		0x0002
642971e8ac56SSepherosa Ziehau #define ATTACHED_RNDIS		0x0004
643071e8ac56SSepherosa Ziehau 
643115516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
6432b3b75d9cSSepherosa Ziehau 	int error, nsubch, nchan = 1, i, rndis_inited;
643371e8ac56SSepherosa Ziehau 	uint32_t old_caps, attached = 0;
643415516c77SSepherosa Ziehau 
643515516c77SSepherosa Ziehau 	KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0,
643615516c77SSepherosa Ziehau 	    ("synthetic parts were attached"));
643715516c77SSepherosa Ziehau 
64382494d735SSepherosa Ziehau 	if (!hn_synth_attachable(sc))
64392494d735SSepherosa Ziehau 		return (ENXIO);
64402494d735SSepherosa Ziehau 
644115516c77SSepherosa Ziehau 	/* Save capabilities for later verification. */
644215516c77SSepherosa Ziehau 	old_caps = sc->hn_caps;
644315516c77SSepherosa Ziehau 	sc->hn_caps = 0;
644415516c77SSepherosa Ziehau 
644515516c77SSepherosa Ziehau 	/* Clear RSS stuffs. */
644615516c77SSepherosa Ziehau 	sc->hn_rss_ind_size = 0;
644715516c77SSepherosa Ziehau 	sc->hn_rss_hash = 0;
6448642ec226SSepherosa Ziehau 	sc->hn_rss_hcap = 0;
644915516c77SSepherosa Ziehau 
645015516c77SSepherosa Ziehau 	/*
645115516c77SSepherosa Ziehau 	 * Attach the primary channel _before_ attaching NVS and RNDIS.
645215516c77SSepherosa Ziehau 	 */
645315516c77SSepherosa Ziehau 	error = hn_chan_attach(sc, sc->hn_prichan);
645415516c77SSepherosa Ziehau 	if (error)
645571e8ac56SSepherosa Ziehau 		goto failed;
645615516c77SSepherosa Ziehau 
645715516c77SSepherosa Ziehau 	/*
645815516c77SSepherosa Ziehau 	 * Attach NVS.
645915516c77SSepherosa Ziehau 	 */
646015516c77SSepherosa Ziehau 	error = hn_nvs_attach(sc, mtu);
646115516c77SSepherosa Ziehau 	if (error)
646271e8ac56SSepherosa Ziehau 		goto failed;
646371e8ac56SSepherosa Ziehau 	attached |= ATTACHED_NVS;
646415516c77SSepherosa Ziehau 
646515516c77SSepherosa Ziehau 	/*
646615516c77SSepherosa Ziehau 	 * Attach RNDIS _after_ NVS is attached.
646715516c77SSepherosa Ziehau 	 */
6468b3b75d9cSSepherosa Ziehau 	error = hn_rndis_attach(sc, mtu, &rndis_inited);
6469b3b75d9cSSepherosa Ziehau 	if (rndis_inited)
6470b3b75d9cSSepherosa Ziehau 		attached |= ATTACHED_RNDIS;
647115516c77SSepherosa Ziehau 	if (error)
647271e8ac56SSepherosa Ziehau 		goto failed;
647315516c77SSepherosa Ziehau 
647415516c77SSepherosa Ziehau 	/*
647515516c77SSepherosa Ziehau 	 * Make sure capabilities are not changed.
647615516c77SSepherosa Ziehau 	 */
647715516c77SSepherosa Ziehau 	if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) {
647815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n",
647915516c77SSepherosa Ziehau 		    old_caps, sc->hn_caps);
648071e8ac56SSepherosa Ziehau 		error = ENXIO;
648171e8ac56SSepherosa Ziehau 		goto failed;
648215516c77SSepherosa Ziehau 	}
648315516c77SSepherosa Ziehau 
648415516c77SSepherosa Ziehau 	/*
648515516c77SSepherosa Ziehau 	 * Allocate sub-channels for multi-TX/RX rings.
648615516c77SSepherosa Ziehau 	 *
648715516c77SSepherosa Ziehau 	 * NOTE:
648815516c77SSepherosa Ziehau 	 * The # of RX rings that can be used is equivalent to the # of
648915516c77SSepherosa Ziehau 	 * channels to be requested.
649015516c77SSepherosa Ziehau 	 */
649115516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_cnt - 1;
649215516c77SSepherosa Ziehau 	error = hn_synth_alloc_subchans(sc, &nsubch);
649315516c77SSepherosa Ziehau 	if (error)
649471e8ac56SSepherosa Ziehau 		goto failed;
649571e8ac56SSepherosa Ziehau 	/* NOTE: _Full_ synthetic parts detach is required now. */
649671e8ac56SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED;
649715516c77SSepherosa Ziehau 
649871e8ac56SSepherosa Ziehau 	/*
649971e8ac56SSepherosa Ziehau 	 * Set the # of TX/RX rings that could be used according to
650071e8ac56SSepherosa Ziehau 	 * the # of channels that NVS offered.
650171e8ac56SSepherosa Ziehau 	 */
650215516c77SSepherosa Ziehau 	nchan = nsubch + 1;
650371e8ac56SSepherosa Ziehau 	hn_set_ring_inuse(sc, nchan);
650415516c77SSepherosa Ziehau 	if (nchan == 1) {
650515516c77SSepherosa Ziehau 		/* Only the primary channel can be used; done */
650615516c77SSepherosa Ziehau 		goto back;
650715516c77SSepherosa Ziehau 	}
650815516c77SSepherosa Ziehau 
650915516c77SSepherosa Ziehau 	/*
651071e8ac56SSepherosa Ziehau 	 * Attach the sub-channels.
6511afd4971bSSepherosa Ziehau 	 *
6512afd4971bSSepherosa Ziehau 	 * NOTE: hn_set_ring_inuse() _must_ have been called.
651315516c77SSepherosa Ziehau 	 */
651471e8ac56SSepherosa Ziehau 	error = hn_attach_subchans(sc);
651571e8ac56SSepherosa Ziehau 	if (error)
651671e8ac56SSepherosa Ziehau 		goto failed;
651715516c77SSepherosa Ziehau 
651871e8ac56SSepherosa Ziehau 	/*
651971e8ac56SSepherosa Ziehau 	 * Configure RSS key and indirect table _after_ all sub-channels
652071e8ac56SSepherosa Ziehau 	 * are attached.
652171e8ac56SSepherosa Ziehau 	 */
652215516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) {
652315516c77SSepherosa Ziehau 		/*
652415516c77SSepherosa Ziehau 		 * RSS key is not set yet; set it to the default RSS key.
652515516c77SSepherosa Ziehau 		 */
652615516c77SSepherosa Ziehau 		if (bootverbose)
652715516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS key\n");
652834d68912SSepherosa Ziehau #ifdef RSS
652934d68912SSepherosa Ziehau 		rss_getkey(rss->rss_key);
653034d68912SSepherosa Ziehau #else
653115516c77SSepherosa Ziehau 		memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key));
653234d68912SSepherosa Ziehau #endif
653315516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
653415516c77SSepherosa Ziehau 	}
653515516c77SSepherosa Ziehau 
653615516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) {
653715516c77SSepherosa Ziehau 		/*
653815516c77SSepherosa Ziehau 		 * RSS indirect table is not set yet; set it up in round-
653915516c77SSepherosa Ziehau 		 * robin fashion.
654015516c77SSepherosa Ziehau 		 */
654115516c77SSepherosa Ziehau 		if (bootverbose) {
654215516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS indirect "
654315516c77SSepherosa Ziehau 			    "table\n");
654415516c77SSepherosa Ziehau 		}
654534d68912SSepherosa Ziehau 		for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
654634d68912SSepherosa Ziehau 			uint32_t subidx;
654734d68912SSepherosa Ziehau 
654834d68912SSepherosa Ziehau #ifdef RSS
654934d68912SSepherosa Ziehau 			subidx = rss_get_indirection_to_bucket(i);
655034d68912SSepherosa Ziehau #else
655134d68912SSepherosa Ziehau 			subidx = i;
655234d68912SSepherosa Ziehau #endif
655334d68912SSepherosa Ziehau 			rss->rss_ind[i] = subidx % nchan;
655434d68912SSepherosa Ziehau 		}
655515516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSIND;
655615516c77SSepherosa Ziehau 	} else {
655715516c77SSepherosa Ziehau 		/*
655815516c77SSepherosa Ziehau 		 * # of usable channels may be changed, so we have to
655915516c77SSepherosa Ziehau 		 * make sure that all entries in RSS indirect table
656015516c77SSepherosa Ziehau 		 * are valid.
6561afd4971bSSepherosa Ziehau 		 *
6562afd4971bSSepherosa Ziehau 		 * NOTE: hn_set_ring_inuse() _must_ have been called.
656315516c77SSepherosa Ziehau 		 */
6564afd4971bSSepherosa Ziehau 		hn_rss_ind_fixup(sc);
656515516c77SSepherosa Ziehau 	}
656615516c77SSepherosa Ziehau 
6567642ec226SSepherosa Ziehau 	sc->hn_rss_hash = sc->hn_rss_hcap;
6568642ec226SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) ||
6569642ec226SSepherosa Ziehau 	    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
6570642ec226SSepherosa Ziehau 		/* NOTE: Don't reconfigure RSS; will do immediately. */
6571642ec226SSepherosa Ziehau 		hn_vf_rss_fixup(sc, false);
6572642ec226SSepherosa Ziehau 	}
657315516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
657415516c77SSepherosa Ziehau 	if (error)
657571e8ac56SSepherosa Ziehau 		goto failed;
657671e8ac56SSepherosa Ziehau back:
6577dc13fee6SSepherosa Ziehau 	/*
6578dc13fee6SSepherosa Ziehau 	 * Fixup transmission aggregation setup.
6579dc13fee6SSepherosa Ziehau 	 */
6580dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
6581b3b75d9cSSepherosa Ziehau 	hn_rndis_init_fixat(sc, nchan);
658215516c77SSepherosa Ziehau 	return (0);
658371e8ac56SSepherosa Ziehau 
658471e8ac56SSepherosa Ziehau failed:
658571e8ac56SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
6586b3b75d9cSSepherosa Ziehau 		hn_rndis_init_fixat(sc, nchan);
658771e8ac56SSepherosa Ziehau 		hn_synth_detach(sc);
658871e8ac56SSepherosa Ziehau 	} else {
6589b3b75d9cSSepherosa Ziehau 		if (attached & ATTACHED_RNDIS) {
6590b3b75d9cSSepherosa Ziehau 			hn_rndis_init_fixat(sc, nchan);
659171e8ac56SSepherosa Ziehau 			hn_rndis_detach(sc);
6592b3b75d9cSSepherosa Ziehau 		}
659371e8ac56SSepherosa Ziehau 		if (attached & ATTACHED_NVS)
659471e8ac56SSepherosa Ziehau 			hn_nvs_detach(sc);
659571e8ac56SSepherosa Ziehau 		hn_chan_detach(sc, sc->hn_prichan);
659671e8ac56SSepherosa Ziehau 		/* Restore old capabilities. */
659771e8ac56SSepherosa Ziehau 		sc->hn_caps = old_caps;
659871e8ac56SSepherosa Ziehau 	}
659971e8ac56SSepherosa Ziehau 	return (error);
660071e8ac56SSepherosa Ziehau 
660171e8ac56SSepherosa Ziehau #undef ATTACHED_RNDIS
660271e8ac56SSepherosa Ziehau #undef ATTACHED_NVS
660315516c77SSepherosa Ziehau }
660415516c77SSepherosa Ziehau 
660515516c77SSepherosa Ziehau /*
660615516c77SSepherosa Ziehau  * NOTE:
660715516c77SSepherosa Ziehau  * The interface must have been suspended though hn_suspend(), before
660815516c77SSepherosa Ziehau  * this function get called.
660915516c77SSepherosa Ziehau  */
661015516c77SSepherosa Ziehau static void
661115516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc)
661215516c77SSepherosa Ziehau {
661315516c77SSepherosa Ziehau 
661415516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
661515516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
661615516c77SSepherosa Ziehau 
661715516c77SSepherosa Ziehau 	/* Detach the RNDIS first. */
661815516c77SSepherosa Ziehau 	hn_rndis_detach(sc);
661915516c77SSepherosa Ziehau 
662015516c77SSepherosa Ziehau 	/* Detach NVS. */
662115516c77SSepherosa Ziehau 	hn_nvs_detach(sc);
662215516c77SSepherosa Ziehau 
662315516c77SSepherosa Ziehau 	/* Detach all of the channels. */
662415516c77SSepherosa Ziehau 	hn_detach_allchans(sc);
662515516c77SSepherosa Ziehau 
662615516c77SSepherosa Ziehau 	sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED;
662715516c77SSepherosa Ziehau }
662815516c77SSepherosa Ziehau 
662915516c77SSepherosa Ziehau static void
663015516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt)
663115516c77SSepherosa Ziehau {
663215516c77SSepherosa Ziehau 	KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt,
663315516c77SSepherosa Ziehau 	    ("invalid ring count %d", ring_cnt));
663415516c77SSepherosa Ziehau 
663515516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt > ring_cnt)
663615516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = ring_cnt;
663715516c77SSepherosa Ziehau 	else
663815516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
663915516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = ring_cnt;
664015516c77SSepherosa Ziehau 
664134d68912SSepherosa Ziehau #ifdef RSS
664234d68912SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse != rss_getnumbuckets()) {
664334d68912SSepherosa Ziehau 		if_printf(sc->hn_ifp, "# of RX rings (%d) does not match "
664434d68912SSepherosa Ziehau 		    "# of RSS buckets (%d)\n", sc->hn_rx_ring_inuse,
664534d68912SSepherosa Ziehau 		    rss_getnumbuckets());
664634d68912SSepherosa Ziehau 	}
664734d68912SSepherosa Ziehau #endif
664834d68912SSepherosa Ziehau 
664915516c77SSepherosa Ziehau 	if (bootverbose) {
665015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n",
665115516c77SSepherosa Ziehau 		    sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
665215516c77SSepherosa Ziehau 	}
665315516c77SSepherosa Ziehau }
665415516c77SSepherosa Ziehau 
665515516c77SSepherosa Ziehau static void
665625641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan)
665715516c77SSepherosa Ziehau {
665815516c77SSepherosa Ziehau 
665925641fc7SSepherosa Ziehau 	/*
666025641fc7SSepherosa Ziehau 	 * NOTE:
666125641fc7SSepherosa Ziehau 	 * The TX bufring will not be drained by the hypervisor,
666225641fc7SSepherosa Ziehau 	 * if the primary channel is revoked.
666325641fc7SSepherosa Ziehau 	 */
666425641fc7SSepherosa Ziehau 	while (!vmbus_chan_rx_empty(chan) ||
666525641fc7SSepherosa Ziehau 	    (!vmbus_chan_is_revoked(sc->hn_prichan) &&
666625641fc7SSepherosa Ziehau 	     !vmbus_chan_tx_empty(chan)))
666715516c77SSepherosa Ziehau 		pause("waitch", 1);
666815516c77SSepherosa Ziehau 	vmbus_chan_intr_drain(chan);
666915516c77SSepherosa Ziehau }
667015516c77SSepherosa Ziehau 
667115516c77SSepherosa Ziehau static void
6672b3b75d9cSSepherosa Ziehau hn_disable_rx(struct hn_softc *sc)
6673b3b75d9cSSepherosa Ziehau {
6674b3b75d9cSSepherosa Ziehau 
6675b3b75d9cSSepherosa Ziehau 	/*
6676b3b75d9cSSepherosa Ziehau 	 * Disable RX by clearing RX filter forcefully.
6677b3b75d9cSSepherosa Ziehau 	 */
6678b3b75d9cSSepherosa Ziehau 	sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE;
6679b3b75d9cSSepherosa Ziehau 	hn_rndis_set_rxfilter(sc, sc->hn_rx_filter); /* ignore error */
6680b3b75d9cSSepherosa Ziehau 
6681b3b75d9cSSepherosa Ziehau 	/*
6682b3b75d9cSSepherosa Ziehau 	 * Give RNDIS enough time to flush all pending data packets.
6683b3b75d9cSSepherosa Ziehau 	 */
6684b3b75d9cSSepherosa Ziehau 	pause("waitrx", (200 * hz) / 1000);
6685b3b75d9cSSepherosa Ziehau }
6686b3b75d9cSSepherosa Ziehau 
6687b3b75d9cSSepherosa Ziehau /*
6688b3b75d9cSSepherosa Ziehau  * NOTE:
6689b3b75d9cSSepherosa Ziehau  * RX/TX _must_ have been suspended/disabled, before this function
6690b3b75d9cSSepherosa Ziehau  * is called.
6691b3b75d9cSSepherosa Ziehau  */
6692b3b75d9cSSepherosa Ziehau static void
6693b3b75d9cSSepherosa Ziehau hn_drain_rxtx(struct hn_softc *sc, int nchan)
669415516c77SSepherosa Ziehau {
669515516c77SSepherosa Ziehau 	struct vmbus_channel **subch = NULL;
6696b3b75d9cSSepherosa Ziehau 	int nsubch;
6697b3b75d9cSSepherosa Ziehau 
6698b3b75d9cSSepherosa Ziehau 	/*
6699b3b75d9cSSepherosa Ziehau 	 * Drain RX/TX bufrings and interrupts.
6700b3b75d9cSSepherosa Ziehau 	 */
6701b3b75d9cSSepherosa Ziehau 	nsubch = nchan - 1;
6702b3b75d9cSSepherosa Ziehau 	if (nsubch > 0)
6703b3b75d9cSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
6704b3b75d9cSSepherosa Ziehau 
6705b3b75d9cSSepherosa Ziehau 	if (subch != NULL) {
6706b3b75d9cSSepherosa Ziehau 		int i;
6707b3b75d9cSSepherosa Ziehau 
6708b3b75d9cSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
6709b3b75d9cSSepherosa Ziehau 			hn_chan_drain(sc, subch[i]);
6710b3b75d9cSSepherosa Ziehau 	}
6711b3b75d9cSSepherosa Ziehau 	hn_chan_drain(sc, sc->hn_prichan);
6712b3b75d9cSSepherosa Ziehau 
6713b3b75d9cSSepherosa Ziehau 	if (subch != NULL)
6714b3b75d9cSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
6715b3b75d9cSSepherosa Ziehau }
6716b3b75d9cSSepherosa Ziehau 
6717b3b75d9cSSepherosa Ziehau static void
6718b3b75d9cSSepherosa Ziehau hn_suspend_data(struct hn_softc *sc)
6719b3b75d9cSSepherosa Ziehau {
672025641fc7SSepherosa Ziehau 	struct hn_tx_ring *txr;
6721b3b75d9cSSepherosa Ziehau 	int i;
672215516c77SSepherosa Ziehau 
672315516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
672415516c77SSepherosa Ziehau 
672515516c77SSepherosa Ziehau 	/*
672615516c77SSepherosa Ziehau 	 * Suspend TX.
672715516c77SSepherosa Ziehau 	 */
672815516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
672925641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
673015516c77SSepherosa Ziehau 
673115516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
673215516c77SSepherosa Ziehau 		txr->hn_suspended = 1;
673315516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
673415516c77SSepherosa Ziehau 		/* No one is able send more packets now. */
673515516c77SSepherosa Ziehau 
673625641fc7SSepherosa Ziehau 		/*
673725641fc7SSepherosa Ziehau 		 * Wait for all pending sends to finish.
673825641fc7SSepherosa Ziehau 		 *
673925641fc7SSepherosa Ziehau 		 * NOTE:
674025641fc7SSepherosa Ziehau 		 * We will _not_ receive all pending send-done, if the
674125641fc7SSepherosa Ziehau 		 * primary channel is revoked.
674225641fc7SSepherosa Ziehau 		 */
674325641fc7SSepherosa Ziehau 		while (hn_tx_ring_pending(txr) &&
674425641fc7SSepherosa Ziehau 		    !vmbus_chan_is_revoked(sc->hn_prichan))
674515516c77SSepherosa Ziehau 			pause("hnwtx", 1 /* 1 tick */);
674615516c77SSepherosa Ziehau 	}
674715516c77SSepherosa Ziehau 
674815516c77SSepherosa Ziehau 	/*
6749b3b75d9cSSepherosa Ziehau 	 * Disable RX.
675015516c77SSepherosa Ziehau 	 */
6751b3b75d9cSSepherosa Ziehau 	hn_disable_rx(sc);
675215516c77SSepherosa Ziehau 
675315516c77SSepherosa Ziehau 	/*
6754b3b75d9cSSepherosa Ziehau 	 * Drain RX/TX.
675515516c77SSepherosa Ziehau 	 */
6756b3b75d9cSSepherosa Ziehau 	hn_drain_rxtx(sc, sc->hn_rx_ring_inuse);
675725641fc7SSepherosa Ziehau 
675825641fc7SSepherosa Ziehau 	/*
675925641fc7SSepherosa Ziehau 	 * Drain any pending TX tasks.
676025641fc7SSepherosa Ziehau 	 *
676125641fc7SSepherosa Ziehau 	 * NOTE:
6762b3b75d9cSSepherosa Ziehau 	 * The above hn_drain_rxtx() can dispatch TX tasks, so the TX
6763b3b75d9cSSepherosa Ziehau 	 * tasks will have to be drained _after_ the above hn_drain_rxtx().
676425641fc7SSepherosa Ziehau 	 */
676525641fc7SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
676625641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
676725641fc7SSepherosa Ziehau 
676825641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task);
676925641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task);
677025641fc7SSepherosa Ziehau 	}
677115516c77SSepherosa Ziehau }
677215516c77SSepherosa Ziehau 
677315516c77SSepherosa Ziehau static void
677415516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused)
677515516c77SSepherosa Ziehau {
677615516c77SSepherosa Ziehau 
677715516c77SSepherosa Ziehau 	((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL;
677815516c77SSepherosa Ziehau }
677915516c77SSepherosa Ziehau 
678015516c77SSepherosa Ziehau static void
678115516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc)
678215516c77SSepherosa Ziehau {
678315516c77SSepherosa Ziehau 	struct task task;
678415516c77SSepherosa Ziehau 
678515516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
678615516c77SSepherosa Ziehau 
678715516c77SSepherosa Ziehau 	/*
678815516c77SSepherosa Ziehau 	 * Make sure that hn_mgmt_taskq0 can nolonger be accessed
678915516c77SSepherosa Ziehau 	 * through hn_mgmt_taskq.
679015516c77SSepherosa Ziehau 	 */
679115516c77SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc);
679215516c77SSepherosa Ziehau 	vmbus_chan_run_task(sc->hn_prichan, &task);
679315516c77SSepherosa Ziehau 
679415516c77SSepherosa Ziehau 	/*
679515516c77SSepherosa Ziehau 	 * Make sure that all pending management tasks are completed.
679615516c77SSepherosa Ziehau 	 */
679715516c77SSepherosa Ziehau 	taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init);
679815516c77SSepherosa Ziehau 	taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status);
679915516c77SSepherosa Ziehau 	taskqueue_drain_all(sc->hn_mgmt_taskq0);
680015516c77SSepherosa Ziehau }
680115516c77SSepherosa Ziehau 
680215516c77SSepherosa Ziehau static void
680315516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc)
680415516c77SSepherosa Ziehau {
680515516c77SSepherosa Ziehau 
680687f8129dSSepherosa Ziehau 	/* Disable polling. */
680787f8129dSSepherosa Ziehau 	hn_polling(sc, 0);
680887f8129dSSepherosa Ziehau 
68099c6cae24SSepherosa Ziehau 	/*
68109c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, the synthetic
68119c6cae24SSepherosa Ziehau 	 * device is receiving packets, so the data path of the
68129c6cae24SSepherosa Ziehau 	 * synthetic device must be suspended.
68139c6cae24SSepherosa Ziehau 	 */
68145bdfd3fdSDexuan Cui 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
6815962f0357SSepherosa Ziehau 	    (sc->hn_flags & HN_FLAG_RXVF))
681615516c77SSepherosa Ziehau 		hn_suspend_data(sc);
681715516c77SSepherosa Ziehau 	hn_suspend_mgmt(sc);
681815516c77SSepherosa Ziehau }
681915516c77SSepherosa Ziehau 
682015516c77SSepherosa Ziehau static void
682115516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt)
682215516c77SSepherosa Ziehau {
682315516c77SSepherosa Ziehau 	int i;
682415516c77SSepherosa Ziehau 
682515516c77SSepherosa Ziehau 	KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt,
682615516c77SSepherosa Ziehau 	    ("invalid TX ring count %d", tx_ring_cnt));
682715516c77SSepherosa Ziehau 
682815516c77SSepherosa Ziehau 	for (i = 0; i < tx_ring_cnt; ++i) {
682915516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
683015516c77SSepherosa Ziehau 
683115516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
683215516c77SSepherosa Ziehau 		txr->hn_suspended = 0;
683315516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
683415516c77SSepherosa Ziehau 	}
683515516c77SSepherosa Ziehau }
683615516c77SSepherosa Ziehau 
683715516c77SSepherosa Ziehau static void
683815516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc)
683915516c77SSepherosa Ziehau {
684015516c77SSepherosa Ziehau 	int i;
684115516c77SSepherosa Ziehau 
684215516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
684315516c77SSepherosa Ziehau 
684415516c77SSepherosa Ziehau 	/*
684515516c77SSepherosa Ziehau 	 * Re-enable RX.
684615516c77SSepherosa Ziehau 	 */
6847c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
684815516c77SSepherosa Ziehau 
684915516c77SSepherosa Ziehau 	/*
685015516c77SSepherosa Ziehau 	 * Make sure to clear suspend status on "all" TX rings,
685115516c77SSepherosa Ziehau 	 * since hn_tx_ring_inuse can be changed after
685215516c77SSepherosa Ziehau 	 * hn_suspend_data().
685315516c77SSepherosa Ziehau 	 */
685415516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_cnt);
685515516c77SSepherosa Ziehau 
685623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
685723bf9e15SSepherosa Ziehau 	if (!hn_use_if_start)
685823bf9e15SSepherosa Ziehau #endif
685923bf9e15SSepherosa Ziehau 	{
686015516c77SSepherosa Ziehau 		/*
686115516c77SSepherosa Ziehau 		 * Flush unused drbrs, since hn_tx_ring_inuse may be
686215516c77SSepherosa Ziehau 		 * reduced.
686315516c77SSepherosa Ziehau 		 */
686415516c77SSepherosa Ziehau 		for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i)
686515516c77SSepherosa Ziehau 			hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
686615516c77SSepherosa Ziehau 	}
686715516c77SSepherosa Ziehau 
686815516c77SSepherosa Ziehau 	/*
686915516c77SSepherosa Ziehau 	 * Kick start TX.
687015516c77SSepherosa Ziehau 	 */
687115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
687215516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
687315516c77SSepherosa Ziehau 
687415516c77SSepherosa Ziehau 		/*
687515516c77SSepherosa Ziehau 		 * Use txeof task, so that any pending oactive can be
687615516c77SSepherosa Ziehau 		 * cleared properly.
687715516c77SSepherosa Ziehau 		 */
687815516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
687915516c77SSepherosa Ziehau 	}
688015516c77SSepherosa Ziehau }
688115516c77SSepherosa Ziehau 
688215516c77SSepherosa Ziehau static void
688315516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc)
688415516c77SSepherosa Ziehau {
688515516c77SSepherosa Ziehau 
688615516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
688715516c77SSepherosa Ziehau 
688815516c77SSepherosa Ziehau 	/*
688915516c77SSepherosa Ziehau 	 * Kick off network change detection, if it was pending.
689015516c77SSepherosa Ziehau 	 * If no network change was pending, start link status
689115516c77SSepherosa Ziehau 	 * checks, which is more lightweight than network change
689215516c77SSepherosa Ziehau 	 * detection.
689315516c77SSepherosa Ziehau 	 */
689415516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
689515516c77SSepherosa Ziehau 		hn_change_network(sc);
689615516c77SSepherosa Ziehau 	else
689715516c77SSepherosa Ziehau 		hn_update_link_status(sc);
689815516c77SSepherosa Ziehau }
689915516c77SSepherosa Ziehau 
690015516c77SSepherosa Ziehau static void
690115516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc)
690215516c77SSepherosa Ziehau {
690315516c77SSepherosa Ziehau 
69049c6cae24SSepherosa Ziehau 	/*
69059c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, the synthetic
69069c6cae24SSepherosa Ziehau 	 * device have to receive packets, so the data path of the
69079c6cae24SSepherosa Ziehau 	 * synthetic device must be resumed.
69089c6cae24SSepherosa Ziehau 	 */
69095bdfd3fdSDexuan Cui 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
6910962f0357SSepherosa Ziehau 	    (sc->hn_flags & HN_FLAG_RXVF))
691115516c77SSepherosa Ziehau 		hn_resume_data(sc);
69125bdfd3fdSDexuan Cui 
69135bdfd3fdSDexuan Cui 	/*
69149c6cae24SSepherosa Ziehau 	 * Don't resume link status change if VF is attached/activated.
69159c6cae24SSepherosa Ziehau 	 * - In the non-transparent VF mode, the synthetic device marks
69169c6cae24SSepherosa Ziehau 	 *   link down until the VF is deactivated; i.e. VF is down.
69179c6cae24SSepherosa Ziehau 	 * - In transparent VF mode, VF's media status is used until
69189c6cae24SSepherosa Ziehau 	 *   the VF is detached.
69195bdfd3fdSDexuan Cui 	 */
69209c6cae24SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) == 0 &&
69219c6cae24SSepherosa Ziehau 	    !(hn_xpnt_vf && sc->hn_vf_ifp != NULL))
692215516c77SSepherosa Ziehau 		hn_resume_mgmt(sc);
692387f8129dSSepherosa Ziehau 
692487f8129dSSepherosa Ziehau 	/*
692587f8129dSSepherosa Ziehau 	 * Re-enable polling if this interface is running and
692687f8129dSSepherosa Ziehau 	 * the polling is requested.
692787f8129dSSepherosa Ziehau 	 */
692887f8129dSSepherosa Ziehau 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->hn_pollhz > 0)
692987f8129dSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
693015516c77SSepherosa Ziehau }
693115516c77SSepherosa Ziehau 
693215516c77SSepherosa Ziehau static void
693315516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen)
693415516c77SSepherosa Ziehau {
693515516c77SSepherosa Ziehau 	const struct rndis_status_msg *msg;
693615516c77SSepherosa Ziehau 	int ofs;
693715516c77SSepherosa Ziehau 
693815516c77SSepherosa Ziehau 	if (dlen < sizeof(*msg)) {
693915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid RNDIS status\n");
694015516c77SSepherosa Ziehau 		return;
694115516c77SSepherosa Ziehau 	}
694215516c77SSepherosa Ziehau 	msg = data;
694315516c77SSepherosa Ziehau 
694415516c77SSepherosa Ziehau 	switch (msg->rm_status) {
694515516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_CONNECT:
694615516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_DISCONNECT:
694715516c77SSepherosa Ziehau 		hn_update_link_status(sc);
694815516c77SSepherosa Ziehau 		break;
694915516c77SSepherosa Ziehau 
695015516c77SSepherosa Ziehau 	case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
695140905afaSSepherosa Ziehau 	case RNDIS_STATUS_LINK_SPEED_CHANGE:
695215516c77SSepherosa Ziehau 		/* Not really useful; ignore. */
695315516c77SSepherosa Ziehau 		break;
695415516c77SSepherosa Ziehau 
695515516c77SSepherosa Ziehau 	case RNDIS_STATUS_NETWORK_CHANGE:
695615516c77SSepherosa Ziehau 		ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
695715516c77SSepherosa Ziehau 		if (dlen < ofs + msg->rm_stbuflen ||
695815516c77SSepherosa Ziehau 		    msg->rm_stbuflen < sizeof(uint32_t)) {
695915516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed\n");
696015516c77SSepherosa Ziehau 		} else {
696115516c77SSepherosa Ziehau 			uint32_t change;
696215516c77SSepherosa Ziehau 
696315516c77SSepherosa Ziehau 			memcpy(&change, ((const uint8_t *)msg) + ofs,
696415516c77SSepherosa Ziehau 			    sizeof(change));
696515516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed, change %u\n",
696615516c77SSepherosa Ziehau 			    change);
696715516c77SSepherosa Ziehau 		}
696815516c77SSepherosa Ziehau 		hn_change_network(sc);
696915516c77SSepherosa Ziehau 		break;
697015516c77SSepherosa Ziehau 
697115516c77SSepherosa Ziehau 	default:
697215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
697315516c77SSepherosa Ziehau 		    msg->rm_status);
697415516c77SSepherosa Ziehau 		break;
697515516c77SSepherosa Ziehau 	}
697615516c77SSepherosa Ziehau }
697715516c77SSepherosa Ziehau 
697815516c77SSepherosa Ziehau static int
697915516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info)
698015516c77SSepherosa Ziehau {
698115516c77SSepherosa Ziehau 	const struct rndis_pktinfo *pi = info_data;
698215516c77SSepherosa Ziehau 	uint32_t mask = 0;
698315516c77SSepherosa Ziehau 
698415516c77SSepherosa Ziehau 	while (info_dlen != 0) {
698515516c77SSepherosa Ziehau 		const void *data;
698615516c77SSepherosa Ziehau 		uint32_t dlen;
698715516c77SSepherosa Ziehau 
698815516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < sizeof(*pi)))
698915516c77SSepherosa Ziehau 			return (EINVAL);
699015516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < pi->rm_size))
699115516c77SSepherosa Ziehau 			return (EINVAL);
699215516c77SSepherosa Ziehau 		info_dlen -= pi->rm_size;
699315516c77SSepherosa Ziehau 
699415516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
699515516c77SSepherosa Ziehau 			return (EINVAL);
699615516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
699715516c77SSepherosa Ziehau 			return (EINVAL);
699815516c77SSepherosa Ziehau 		dlen = pi->rm_size - pi->rm_pktinfooffset;
699915516c77SSepherosa Ziehau 		data = pi->rm_data;
700015516c77SSepherosa Ziehau 
700115516c77SSepherosa Ziehau 		switch (pi->rm_type) {
700215516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_VLAN:
700315516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
700415516c77SSepherosa Ziehau 				return (EINVAL);
700515516c77SSepherosa Ziehau 			info->vlan_info = *((const uint32_t *)data);
700615516c77SSepherosa Ziehau 			mask |= HN_RXINFO_VLAN;
700715516c77SSepherosa Ziehau 			break;
700815516c77SSepherosa Ziehau 
700915516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_CSUM:
701015516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
701115516c77SSepherosa Ziehau 				return (EINVAL);
701215516c77SSepherosa Ziehau 			info->csum_info = *((const uint32_t *)data);
701315516c77SSepherosa Ziehau 			mask |= HN_RXINFO_CSUM;
701415516c77SSepherosa Ziehau 			break;
701515516c77SSepherosa Ziehau 
701615516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHVAL:
701715516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
701815516c77SSepherosa Ziehau 				return (EINVAL);
701915516c77SSepherosa Ziehau 			info->hash_value = *((const uint32_t *)data);
702015516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHVAL;
702115516c77SSepherosa Ziehau 			break;
702215516c77SSepherosa Ziehau 
702315516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHINF:
702415516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
702515516c77SSepherosa Ziehau 				return (EINVAL);
702615516c77SSepherosa Ziehau 			info->hash_info = *((const uint32_t *)data);
702715516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHINF;
702815516c77SSepherosa Ziehau 			break;
702915516c77SSepherosa Ziehau 
703015516c77SSepherosa Ziehau 		default:
703115516c77SSepherosa Ziehau 			goto next;
703215516c77SSepherosa Ziehau 		}
703315516c77SSepherosa Ziehau 
703415516c77SSepherosa Ziehau 		if (mask == HN_RXINFO_ALL) {
703515516c77SSepherosa Ziehau 			/* All found; done */
703615516c77SSepherosa Ziehau 			break;
703715516c77SSepherosa Ziehau 		}
703815516c77SSepherosa Ziehau next:
703915516c77SSepherosa Ziehau 		pi = (const struct rndis_pktinfo *)
704015516c77SSepherosa Ziehau 		    ((const uint8_t *)pi + pi->rm_size);
704115516c77SSepherosa Ziehau 	}
704215516c77SSepherosa Ziehau 
704315516c77SSepherosa Ziehau 	/*
704415516c77SSepherosa Ziehau 	 * Final fixup.
704515516c77SSepherosa Ziehau 	 * - If there is no hash value, invalidate the hash info.
704615516c77SSepherosa Ziehau 	 */
704715516c77SSepherosa Ziehau 	if ((mask & HN_RXINFO_HASHVAL) == 0)
704815516c77SSepherosa Ziehau 		info->hash_info = HN_NDIS_HASH_INFO_INVALID;
704915516c77SSepherosa Ziehau 	return (0);
705015516c77SSepherosa Ziehau }
705115516c77SSepherosa Ziehau 
705215516c77SSepherosa Ziehau static __inline bool
705315516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
705415516c77SSepherosa Ziehau {
705515516c77SSepherosa Ziehau 
705615516c77SSepherosa Ziehau 	if (off < check_off) {
705715516c77SSepherosa Ziehau 		if (__predict_true(off + len <= check_off))
705815516c77SSepherosa Ziehau 			return (false);
705915516c77SSepherosa Ziehau 	} else if (off > check_off) {
706015516c77SSepherosa Ziehau 		if (__predict_true(check_off + check_len <= off))
706115516c77SSepherosa Ziehau 			return (false);
706215516c77SSepherosa Ziehau 	}
706315516c77SSepherosa Ziehau 	return (true);
706415516c77SSepherosa Ziehau }
706515516c77SSepherosa Ziehau 
706615516c77SSepherosa Ziehau static void
706715516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen)
706815516c77SSepherosa Ziehau {
706915516c77SSepherosa Ziehau 	const struct rndis_packet_msg *pkt;
707015516c77SSepherosa Ziehau 	struct hn_rxinfo info;
707115516c77SSepherosa Ziehau 	int data_off, pktinfo_off, data_len, pktinfo_len;
707215516c77SSepherosa Ziehau 
707315516c77SSepherosa Ziehau 	/*
707415516c77SSepherosa Ziehau 	 * Check length.
707515516c77SSepherosa Ziehau 	 */
707615516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*pkt))) {
707715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
707815516c77SSepherosa Ziehau 		return;
707915516c77SSepherosa Ziehau 	}
708015516c77SSepherosa Ziehau 	pkt = data;
708115516c77SSepherosa Ziehau 
708215516c77SSepherosa Ziehau 	if (__predict_false(dlen < pkt->rm_len)) {
708315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
708415516c77SSepherosa Ziehau 		    "dlen %d, msglen %u\n", dlen, pkt->rm_len);
708515516c77SSepherosa Ziehau 		return;
708615516c77SSepherosa Ziehau 	}
708715516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_len <
708815516c77SSepherosa Ziehau 	    pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
708915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
709015516c77SSepherosa Ziehau 		    "msglen %u, data %u, oob %u, pktinfo %u\n",
709115516c77SSepherosa Ziehau 		    pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
709215516c77SSepherosa Ziehau 		    pkt->rm_pktinfolen);
709315516c77SSepherosa Ziehau 		return;
709415516c77SSepherosa Ziehau 	}
709515516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_datalen == 0)) {
709615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
709715516c77SSepherosa Ziehau 		return;
709815516c77SSepherosa Ziehau 	}
709915516c77SSepherosa Ziehau 
710015516c77SSepherosa Ziehau 	/*
710115516c77SSepherosa Ziehau 	 * Check offests.
710215516c77SSepherosa Ziehau 	 */
710315516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs)			\
710415516c77SSepherosa Ziehau 	((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN ||	\
710515516c77SSepherosa Ziehau 	 ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
710615516c77SSepherosa Ziehau 
710715516c77SSepherosa Ziehau 	/* XXX Hyper-V does not meet data offset alignment requirement */
710815516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
710915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
711015516c77SSepherosa Ziehau 		    "data offset %u\n", pkt->rm_dataoffset);
711115516c77SSepherosa Ziehau 		return;
711215516c77SSepherosa Ziehau 	}
711315516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdataoffset > 0 &&
711415516c77SSepherosa Ziehau 	    IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
711515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
711615516c77SSepherosa Ziehau 		    "oob offset %u\n", pkt->rm_oobdataoffset);
711715516c77SSepherosa Ziehau 		return;
711815516c77SSepherosa Ziehau 	}
711915516c77SSepherosa Ziehau 	if (__predict_true(pkt->rm_pktinfooffset > 0) &&
712015516c77SSepherosa Ziehau 	    __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
712115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
712215516c77SSepherosa Ziehau 		    "pktinfo offset %u\n", pkt->rm_pktinfooffset);
712315516c77SSepherosa Ziehau 		return;
712415516c77SSepherosa Ziehau 	}
712515516c77SSepherosa Ziehau 
712615516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID
712715516c77SSepherosa Ziehau 
712815516c77SSepherosa Ziehau 	data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
712915516c77SSepherosa Ziehau 	data_len = pkt->rm_datalen;
713015516c77SSepherosa Ziehau 	pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
713115516c77SSepherosa Ziehau 	pktinfo_len = pkt->rm_pktinfolen;
713215516c77SSepherosa Ziehau 
713315516c77SSepherosa Ziehau 	/*
713415516c77SSepherosa Ziehau 	 * Check OOB coverage.
713515516c77SSepherosa Ziehau 	 */
713615516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdatalen != 0)) {
713715516c77SSepherosa Ziehau 		int oob_off, oob_len;
713815516c77SSepherosa Ziehau 
713915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "got oobdata\n");
714015516c77SSepherosa Ziehau 		oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
714115516c77SSepherosa Ziehau 		oob_len = pkt->rm_oobdatalen;
714215516c77SSepherosa Ziehau 
714315516c77SSepherosa Ziehau 		if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
714415516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
714515516c77SSepherosa Ziehau 			    "oob overflow, msglen %u, oob abs %d len %d\n",
714615516c77SSepherosa Ziehau 			    pkt->rm_len, oob_off, oob_len);
714715516c77SSepherosa Ziehau 			return;
714815516c77SSepherosa Ziehau 		}
714915516c77SSepherosa Ziehau 
715015516c77SSepherosa Ziehau 		/*
715115516c77SSepherosa Ziehau 		 * Check against data.
715215516c77SSepherosa Ziehau 		 */
715315516c77SSepherosa Ziehau 		if (hn_rndis_check_overlap(oob_off, oob_len,
715415516c77SSepherosa Ziehau 		    data_off, data_len)) {
715515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
715615516c77SSepherosa Ziehau 			    "oob overlaps data, oob abs %d len %d, "
715715516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
715815516c77SSepherosa Ziehau 			    oob_off, oob_len, data_off, data_len);
715915516c77SSepherosa Ziehau 			return;
716015516c77SSepherosa Ziehau 		}
716115516c77SSepherosa Ziehau 
716215516c77SSepherosa Ziehau 		/*
716315516c77SSepherosa Ziehau 		 * Check against pktinfo.
716415516c77SSepherosa Ziehau 		 */
716515516c77SSepherosa Ziehau 		if (pktinfo_len != 0 &&
716615516c77SSepherosa Ziehau 		    hn_rndis_check_overlap(oob_off, oob_len,
716715516c77SSepherosa Ziehau 		    pktinfo_off, pktinfo_len)) {
716815516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
716915516c77SSepherosa Ziehau 			    "oob overlaps pktinfo, oob abs %d len %d, "
717015516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
717115516c77SSepherosa Ziehau 			    oob_off, oob_len, pktinfo_off, pktinfo_len);
717215516c77SSepherosa Ziehau 			return;
717315516c77SSepherosa Ziehau 		}
717415516c77SSepherosa Ziehau 	}
717515516c77SSepherosa Ziehau 
717615516c77SSepherosa Ziehau 	/*
717715516c77SSepherosa Ziehau 	 * Check per-packet-info coverage and find useful per-packet-info.
717815516c77SSepherosa Ziehau 	 */
717915516c77SSepherosa Ziehau 	info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
718015516c77SSepherosa Ziehau 	info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
718115516c77SSepherosa Ziehau 	info.hash_info = HN_NDIS_HASH_INFO_INVALID;
718215516c77SSepherosa Ziehau 	if (__predict_true(pktinfo_len != 0)) {
718315516c77SSepherosa Ziehau 		bool overlap;
718415516c77SSepherosa Ziehau 		int error;
718515516c77SSepherosa Ziehau 
718615516c77SSepherosa Ziehau 		if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
718715516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
718815516c77SSepherosa Ziehau 			    "pktinfo overflow, msglen %u, "
718915516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
719015516c77SSepherosa Ziehau 			    pkt->rm_len, pktinfo_off, pktinfo_len);
719115516c77SSepherosa Ziehau 			return;
719215516c77SSepherosa Ziehau 		}
719315516c77SSepherosa Ziehau 
719415516c77SSepherosa Ziehau 		/*
719515516c77SSepherosa Ziehau 		 * Check packet info coverage.
719615516c77SSepherosa Ziehau 		 */
719715516c77SSepherosa Ziehau 		overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
719815516c77SSepherosa Ziehau 		    data_off, data_len);
719915516c77SSepherosa Ziehau 		if (__predict_false(overlap)) {
720015516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
720115516c77SSepherosa Ziehau 			    "pktinfo overlap data, pktinfo abs %d len %d, "
720215516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
720315516c77SSepherosa Ziehau 			    pktinfo_off, pktinfo_len, data_off, data_len);
720415516c77SSepherosa Ziehau 			return;
720515516c77SSepherosa Ziehau 		}
720615516c77SSepherosa Ziehau 
720715516c77SSepherosa Ziehau 		/*
720815516c77SSepherosa Ziehau 		 * Find useful per-packet-info.
720915516c77SSepherosa Ziehau 		 */
721015516c77SSepherosa Ziehau 		error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
721115516c77SSepherosa Ziehau 		    pktinfo_len, &info);
721215516c77SSepherosa Ziehau 		if (__predict_false(error)) {
721315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
721415516c77SSepherosa Ziehau 			    "pktinfo\n");
721515516c77SSepherosa Ziehau 			return;
721615516c77SSepherosa Ziehau 		}
721715516c77SSepherosa Ziehau 	}
721815516c77SSepherosa Ziehau 
721915516c77SSepherosa Ziehau 	if (__predict_false(data_off + data_len > pkt->rm_len)) {
722015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
722115516c77SSepherosa Ziehau 		    "data overflow, msglen %u, data abs %d len %d\n",
722215516c77SSepherosa Ziehau 		    pkt->rm_len, data_off, data_len);
722315516c77SSepherosa Ziehau 		return;
722415516c77SSepherosa Ziehau 	}
722515516c77SSepherosa Ziehau 	hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
722615516c77SSepherosa Ziehau }
722715516c77SSepherosa Ziehau 
722815516c77SSepherosa Ziehau static __inline void
722915516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen)
723015516c77SSepherosa Ziehau {
723115516c77SSepherosa Ziehau 	const struct rndis_msghdr *hdr;
723215516c77SSepherosa Ziehau 
723315516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*hdr))) {
723415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
723515516c77SSepherosa Ziehau 		return;
723615516c77SSepherosa Ziehau 	}
723715516c77SSepherosa Ziehau 	hdr = data;
723815516c77SSepherosa Ziehau 
723915516c77SSepherosa Ziehau 	if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) {
724015516c77SSepherosa Ziehau 		/* Hot data path. */
724115516c77SSepherosa Ziehau 		hn_rndis_rx_data(rxr, data, dlen);
724215516c77SSepherosa Ziehau 		/* Done! */
724315516c77SSepherosa Ziehau 		return;
724415516c77SSepherosa Ziehau 	}
724515516c77SSepherosa Ziehau 
724615516c77SSepherosa Ziehau 	if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG)
724715516c77SSepherosa Ziehau 		hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen);
724815516c77SSepherosa Ziehau 	else
724915516c77SSepherosa Ziehau 		hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen);
725015516c77SSepherosa Ziehau }
725115516c77SSepherosa Ziehau 
725215516c77SSepherosa Ziehau static void
725315516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
725415516c77SSepherosa Ziehau {
725515516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *hdr;
725615516c77SSepherosa Ziehau 
725715516c77SSepherosa Ziehau 	if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) {
725815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid nvs notify\n");
725915516c77SSepherosa Ziehau 		return;
726015516c77SSepherosa Ziehau 	}
726115516c77SSepherosa Ziehau 	hdr = VMBUS_CHANPKT_CONST_DATA(pkt);
726215516c77SSepherosa Ziehau 
726315516c77SSepherosa Ziehau 	if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) {
726415516c77SSepherosa Ziehau 		/* Useless; ignore */
726515516c77SSepherosa Ziehau 		return;
726615516c77SSepherosa Ziehau 	}
726715516c77SSepherosa Ziehau 	if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type);
726815516c77SSepherosa Ziehau }
726915516c77SSepherosa Ziehau 
727015516c77SSepherosa Ziehau static void
727115516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan,
727215516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkt)
727315516c77SSepherosa Ziehau {
727415516c77SSepherosa Ziehau 	struct hn_nvs_sendctx *sndc;
727515516c77SSepherosa Ziehau 
727615516c77SSepherosa Ziehau 	sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid;
727715516c77SSepherosa Ziehau 	sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt),
727815516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_DATALEN(pkt));
727915516c77SSepherosa Ziehau 	/*
728015516c77SSepherosa Ziehau 	 * NOTE:
728115516c77SSepherosa Ziehau 	 * 'sndc' CAN NOT be accessed anymore, since it can be freed by
728215516c77SSepherosa Ziehau 	 * its callback.
728315516c77SSepherosa Ziehau 	 */
728415516c77SSepherosa Ziehau }
728515516c77SSepherosa Ziehau 
728615516c77SSepherosa Ziehau static void
728715516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
728815516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkthdr)
728915516c77SSepherosa Ziehau {
729015516c77SSepherosa Ziehau 	const struct vmbus_chanpkt_rxbuf *pkt;
729115516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *nvs_hdr;
729215516c77SSepherosa Ziehau 	int count, i, hlen;
729315516c77SSepherosa Ziehau 
729415516c77SSepherosa Ziehau 	if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) {
729515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n");
729615516c77SSepherosa Ziehau 		return;
729715516c77SSepherosa Ziehau 	}
729815516c77SSepherosa Ziehau 	nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr);
729915516c77SSepherosa Ziehau 
730015516c77SSepherosa Ziehau 	/* Make sure that this is a RNDIS message. */
730115516c77SSepherosa Ziehau 	if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) {
730215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n",
730315516c77SSepherosa Ziehau 		    nvs_hdr->nvs_type);
730415516c77SSepherosa Ziehau 		return;
730515516c77SSepherosa Ziehau 	}
730615516c77SSepherosa Ziehau 
730715516c77SSepherosa Ziehau 	hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen);
730815516c77SSepherosa Ziehau 	if (__predict_false(hlen < sizeof(*pkt))) {
730915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n");
731015516c77SSepherosa Ziehau 		return;
731115516c77SSepherosa Ziehau 	}
731215516c77SSepherosa Ziehau 	pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
731315516c77SSepherosa Ziehau 
731415516c77SSepherosa Ziehau 	if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) {
731515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n",
731615516c77SSepherosa Ziehau 		    pkt->cp_rxbuf_id);
731715516c77SSepherosa Ziehau 		return;
731815516c77SSepherosa Ziehau 	}
731915516c77SSepherosa Ziehau 
732015516c77SSepherosa Ziehau 	count = pkt->cp_rxbuf_cnt;
732115516c77SSepherosa Ziehau 	if (__predict_false(hlen <
732215516c77SSepherosa Ziehau 	    __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) {
732315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count);
732415516c77SSepherosa Ziehau 		return;
732515516c77SSepherosa Ziehau 	}
732615516c77SSepherosa Ziehau 
732715516c77SSepherosa Ziehau 	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
732815516c77SSepherosa Ziehau 	for (i = 0; i < count; ++i) {
732915516c77SSepherosa Ziehau 		int ofs, len;
733015516c77SSepherosa Ziehau 
733115516c77SSepherosa Ziehau 		ofs = pkt->cp_rxbuf[i].rb_ofs;
733215516c77SSepherosa Ziehau 		len = pkt->cp_rxbuf[i].rb_len;
733315516c77SSepherosa Ziehau 		if (__predict_false(ofs + len > HN_RXBUF_SIZE)) {
733415516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, "
733515516c77SSepherosa Ziehau 			    "ofs %d, len %d\n", i, ofs, len);
733615516c77SSepherosa Ziehau 			continue;
733715516c77SSepherosa Ziehau 		}
733815516c77SSepherosa Ziehau 		hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len);
733915516c77SSepherosa Ziehau 	}
734015516c77SSepherosa Ziehau 
734115516c77SSepherosa Ziehau 	/*
734215516c77SSepherosa Ziehau 	 * Ack the consumed RXBUF associated w/ this channel packet,
734315516c77SSepherosa Ziehau 	 * so that this RXBUF can be recycled by the hypervisor.
734415516c77SSepherosa Ziehau 	 */
734515516c77SSepherosa Ziehau 	hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid);
734615516c77SSepherosa Ziehau }
734715516c77SSepherosa Ziehau 
734815516c77SSepherosa Ziehau static void
734915516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
735015516c77SSepherosa Ziehau     uint64_t tid)
735115516c77SSepherosa Ziehau {
735215516c77SSepherosa Ziehau 	struct hn_nvs_rndis_ack ack;
735315516c77SSepherosa Ziehau 	int retries, error;
735415516c77SSepherosa Ziehau 
735515516c77SSepherosa Ziehau 	ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK;
735615516c77SSepherosa Ziehau 	ack.nvs_status = HN_NVS_STATUS_OK;
735715516c77SSepherosa Ziehau 
735815516c77SSepherosa Ziehau 	retries = 0;
735915516c77SSepherosa Ziehau again:
736015516c77SSepherosa Ziehau 	error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP,
736115516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid);
736215516c77SSepherosa Ziehau 	if (__predict_false(error == EAGAIN)) {
736315516c77SSepherosa Ziehau 		/*
736415516c77SSepherosa Ziehau 		 * NOTE:
736515516c77SSepherosa Ziehau 		 * This should _not_ happen in real world, since the
736615516c77SSepherosa Ziehau 		 * consumption of the TX bufring from the TX path is
736715516c77SSepherosa Ziehau 		 * controlled.
736815516c77SSepherosa Ziehau 		 */
736915516c77SSepherosa Ziehau 		if (rxr->hn_ack_failed == 0)
737015516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "RXBUF ack retry\n");
737115516c77SSepherosa Ziehau 		rxr->hn_ack_failed++;
737215516c77SSepherosa Ziehau 		retries++;
737315516c77SSepherosa Ziehau 		if (retries < 10) {
737415516c77SSepherosa Ziehau 			DELAY(100);
737515516c77SSepherosa Ziehau 			goto again;
737615516c77SSepherosa Ziehau 		}
737715516c77SSepherosa Ziehau 		/* RXBUF leaks! */
737815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "RXBUF ack failed\n");
737915516c77SSepherosa Ziehau 	}
738015516c77SSepherosa Ziehau }
738115516c77SSepherosa Ziehau 
738215516c77SSepherosa Ziehau static void
738315516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr)
738415516c77SSepherosa Ziehau {
738515516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr = xrxr;
738615516c77SSepherosa Ziehau 	struct hn_softc *sc = rxr->hn_ifp->if_softc;
738715516c77SSepherosa Ziehau 
738815516c77SSepherosa Ziehau 	for (;;) {
738915516c77SSepherosa Ziehau 		struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf;
739015516c77SSepherosa Ziehau 		int error, pktlen;
739115516c77SSepherosa Ziehau 
739215516c77SSepherosa Ziehau 		pktlen = rxr->hn_pktbuf_len;
739315516c77SSepherosa Ziehau 		error = vmbus_chan_recv_pkt(chan, pkt, &pktlen);
739415516c77SSepherosa Ziehau 		if (__predict_false(error == ENOBUFS)) {
739515516c77SSepherosa Ziehau 			void *nbuf;
739615516c77SSepherosa Ziehau 			int nlen;
739715516c77SSepherosa Ziehau 
739815516c77SSepherosa Ziehau 			/*
739915516c77SSepherosa Ziehau 			 * Expand channel packet buffer.
740015516c77SSepherosa Ziehau 			 *
740115516c77SSepherosa Ziehau 			 * XXX
740215516c77SSepherosa Ziehau 			 * Use M_WAITOK here, since allocation failure
740315516c77SSepherosa Ziehau 			 * is fatal.
740415516c77SSepherosa Ziehau 			 */
740515516c77SSepherosa Ziehau 			nlen = rxr->hn_pktbuf_len * 2;
740615516c77SSepherosa Ziehau 			while (nlen < pktlen)
740715516c77SSepherosa Ziehau 				nlen *= 2;
740815516c77SSepherosa Ziehau 			nbuf = malloc(nlen, M_DEVBUF, M_WAITOK);
740915516c77SSepherosa Ziehau 
741015516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n",
741115516c77SSepherosa Ziehau 			    rxr->hn_pktbuf_len, nlen);
741215516c77SSepherosa Ziehau 
741315516c77SSepherosa Ziehau 			free(rxr->hn_pktbuf, M_DEVBUF);
741415516c77SSepherosa Ziehau 			rxr->hn_pktbuf = nbuf;
741515516c77SSepherosa Ziehau 			rxr->hn_pktbuf_len = nlen;
741615516c77SSepherosa Ziehau 			/* Retry! */
741715516c77SSepherosa Ziehau 			continue;
741815516c77SSepherosa Ziehau 		} else if (__predict_false(error == EAGAIN)) {
741915516c77SSepherosa Ziehau 			/* No more channel packets; done! */
742015516c77SSepherosa Ziehau 			break;
742115516c77SSepherosa Ziehau 		}
742215516c77SSepherosa Ziehau 		KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error));
742315516c77SSepherosa Ziehau 
742415516c77SSepherosa Ziehau 		switch (pkt->cph_type) {
742515516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_COMP:
742615516c77SSepherosa Ziehau 			hn_nvs_handle_comp(sc, chan, pkt);
742715516c77SSepherosa Ziehau 			break;
742815516c77SSepherosa Ziehau 
742915516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_RXBUF:
743015516c77SSepherosa Ziehau 			hn_nvs_handle_rxbuf(rxr, chan, pkt);
743115516c77SSepherosa Ziehau 			break;
743215516c77SSepherosa Ziehau 
743315516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_INBAND:
743415516c77SSepherosa Ziehau 			hn_nvs_handle_notify(sc, pkt);
743515516c77SSepherosa Ziehau 			break;
743615516c77SSepherosa Ziehau 
743715516c77SSepherosa Ziehau 		default:
743815516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "unknown chan pkt %u\n",
743915516c77SSepherosa Ziehau 			    pkt->cph_type);
744015516c77SSepherosa Ziehau 			break;
744115516c77SSepherosa Ziehau 		}
744215516c77SSepherosa Ziehau 	}
744315516c77SSepherosa Ziehau 	hn_chan_rollup(rxr, rxr->hn_txr);
744415516c77SSepherosa Ziehau }
744515516c77SSepherosa Ziehau 
744615516c77SSepherosa Ziehau static void
7447499c3e17SSepherosa Ziehau hn_sysinit(void *arg __unused)
744815516c77SSepherosa Ziehau {
7449fdd0222aSSepherosa Ziehau 	int i;
7450fdd0222aSSepherosa Ziehau 
74512be266caSSepherosa Ziehau 	hn_udpcs_fixup = counter_u64_alloc(M_WAITOK);
74522be266caSSepherosa Ziehau 
74539c6cae24SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
74549c6cae24SSepherosa Ziehau 	/*
74559c6cae24SSepherosa Ziehau 	 * Don't use ifnet.if_start if transparent VF mode is requested;
74569c6cae24SSepherosa Ziehau 	 * mainly due to the IFF_DRV_OACTIVE flag.
74579c6cae24SSepherosa Ziehau 	 */
74589c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && hn_use_if_start) {
74599c6cae24SSepherosa Ziehau 		hn_use_if_start = 0;
74609c6cae24SSepherosa Ziehau 		printf("hn: tranparent VF mode, if_transmit will be used, "
74619c6cae24SSepherosa Ziehau 		    "instead of if_start\n");
74629c6cae24SSepherosa Ziehau 	}
74639c6cae24SSepherosa Ziehau #endif
74649c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_attwait < HN_XPNT_VF_ATTWAIT_MIN) {
74659c6cae24SSepherosa Ziehau 		printf("hn: invalid transparent VF attach routing "
74669c6cae24SSepherosa Ziehau 		    "wait timeout %d, reset to %d\n",
74679c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_attwait, HN_XPNT_VF_ATTWAIT_MIN);
74689c6cae24SSepherosa Ziehau 		hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN;
74699c6cae24SSepherosa Ziehau 	}
74709c6cae24SSepherosa Ziehau 
7471fdd0222aSSepherosa Ziehau 	/*
7472499c3e17SSepherosa Ziehau 	 * Initialize VF map.
7473499c3e17SSepherosa Ziehau 	 */
7474499c3e17SSepherosa Ziehau 	rm_init_flags(&hn_vfmap_lock, "hn_vfmap", RM_SLEEPABLE);
7475499c3e17SSepherosa Ziehau 	hn_vfmap_size = HN_VFMAP_SIZE_DEF;
7476499c3e17SSepherosa Ziehau 	hn_vfmap = malloc(sizeof(struct ifnet *) * hn_vfmap_size, M_DEVBUF,
7477499c3e17SSepherosa Ziehau 	    M_WAITOK | M_ZERO);
7478499c3e17SSepherosa Ziehau 
7479499c3e17SSepherosa Ziehau 	/*
7480fdd0222aSSepherosa Ziehau 	 * Fix the # of TX taskqueues.
7481fdd0222aSSepherosa Ziehau 	 */
7482fdd0222aSSepherosa Ziehau 	if (hn_tx_taskq_cnt <= 0)
7483fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = 1;
7484fdd0222aSSepherosa Ziehau 	else if (hn_tx_taskq_cnt > mp_ncpus)
7485fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = mp_ncpus;
748615516c77SSepherosa Ziehau 
74870e11868dSSepherosa Ziehau 	/*
74880e11868dSSepherosa Ziehau 	 * Fix the TX taskqueue mode.
74890e11868dSSepherosa Ziehau 	 */
74900e11868dSSepherosa Ziehau 	switch (hn_tx_taskq_mode) {
74910e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_INDEP:
74920e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_GLOBAL:
74930e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_EVTTQ:
74940e11868dSSepherosa Ziehau 		break;
74950e11868dSSepherosa Ziehau 	default:
74960e11868dSSepherosa Ziehau 		hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
74970e11868dSSepherosa Ziehau 		break;
74980e11868dSSepherosa Ziehau 	}
74990e11868dSSepherosa Ziehau 
750015516c77SSepherosa Ziehau 	if (vm_guest != VM_GUEST_HV)
750115516c77SSepherosa Ziehau 		return;
750215516c77SSepherosa Ziehau 
75030e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode != HN_TX_TASKQ_M_GLOBAL)
750415516c77SSepherosa Ziehau 		return;
750515516c77SSepherosa Ziehau 
7506fdd0222aSSepherosa Ziehau 	hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
7507fdd0222aSSepherosa Ziehau 	    M_DEVBUF, M_WAITOK);
7508fdd0222aSSepherosa Ziehau 	for (i = 0; i < hn_tx_taskq_cnt; ++i) {
7509fdd0222aSSepherosa Ziehau 		hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK,
7510fdd0222aSSepherosa Ziehau 		    taskqueue_thread_enqueue, &hn_tx_taskque[i]);
7511fdd0222aSSepherosa Ziehau 		taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET,
7512fdd0222aSSepherosa Ziehau 		    "hn tx%d", i);
7513fdd0222aSSepherosa Ziehau 	}
751415516c77SSepherosa Ziehau }
7515499c3e17SSepherosa Ziehau SYSINIT(hn_sysinit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysinit, NULL);
751615516c77SSepherosa Ziehau 
751715516c77SSepherosa Ziehau static void
7518499c3e17SSepherosa Ziehau hn_sysuninit(void *arg __unused)
751915516c77SSepherosa Ziehau {
752015516c77SSepherosa Ziehau 
7521fdd0222aSSepherosa Ziehau 	if (hn_tx_taskque != NULL) {
7522fdd0222aSSepherosa Ziehau 		int i;
7523fdd0222aSSepherosa Ziehau 
7524fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
7525fdd0222aSSepherosa Ziehau 			taskqueue_free(hn_tx_taskque[i]);
7526fdd0222aSSepherosa Ziehau 		free(hn_tx_taskque, M_DEVBUF);
7527fdd0222aSSepherosa Ziehau 	}
7528499c3e17SSepherosa Ziehau 
7529499c3e17SSepherosa Ziehau 	if (hn_vfmap != NULL)
7530499c3e17SSepherosa Ziehau 		free(hn_vfmap, M_DEVBUF);
7531499c3e17SSepherosa Ziehau 	rm_destroy(&hn_vfmap_lock);
75322be266caSSepherosa Ziehau 
75332be266caSSepherosa Ziehau 	counter_u64_free(hn_udpcs_fixup);
753415516c77SSepherosa Ziehau }
7535499c3e17SSepherosa Ziehau SYSUNINIT(hn_sysuninit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysuninit, NULL);
7536