xref: /freebsd/sys/dev/hyperv/netvsc/if_hn.c (revision d76fb49fd89f7b783798a2a2b76a03c9f988621f)
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 */
58778e46963SSepherosa 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) ||
934d7c5a620SMatt Macy 		    !CK_STAILQ_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 
1164*d76fb49fSDexuan Cui 	/*
1165*d76fb49fSDexuan Cui 	 * During detach events ifp->if_addr might be NULL.
1166*d76fb49fSDexuan Cui 	 * Make sure the bcmp() below doesn't panic on that:
1167*d76fb49fSDexuan Cui 	 */
1168*d76fb49fSDexuan Cui 	if (ifp->if_addr == NULL || hn_ifp->if_addr == NULL)
1169*d76fb49fSDexuan Cui 		return (false);
1170*d76fb49fSDexuan Cui 
1171499c3e17SSepherosa Ziehau 	if (bcmp(IF_LLADDR(ifp), IF_LLADDR(hn_ifp), ETHER_ADDR_LEN) != 0)
1172499c3e17SSepherosa Ziehau 		return (false);
1173499c3e17SSepherosa Ziehau 
1174499c3e17SSepherosa Ziehau 	return (true);
1175499c3e17SSepherosa Ziehau }
1176499c3e17SSepherosa Ziehau 
11775bdfd3fdSDexuan Cui static void
1178962f0357SSepherosa Ziehau hn_rxvf_change(struct hn_softc *sc, struct ifnet *ifp, bool rxvf)
11795bdfd3fdSDexuan Cui {
11805bdfd3fdSDexuan Cui 	struct ifnet *hn_ifp;
11815bdfd3fdSDexuan Cui 
11825bdfd3fdSDexuan Cui 	HN_LOCK(sc);
11835bdfd3fdSDexuan Cui 
11845bdfd3fdSDexuan Cui 	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
11855bdfd3fdSDexuan Cui 		goto out;
11865bdfd3fdSDexuan Cui 
1187499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1188499c3e17SSepherosa Ziehau 		goto out;
11895bdfd3fdSDexuan Cui 	hn_ifp = sc->hn_ifp;
11905bdfd3fdSDexuan Cui 
1191962f0357SSepherosa Ziehau 	if (rxvf) {
1192962f0357SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_RXVF)
11935bdfd3fdSDexuan Cui 			goto out;
11945bdfd3fdSDexuan Cui 
1195962f0357SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_RXVF;
11965bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
11975bdfd3fdSDexuan Cui 	} else {
1198962f0357SSepherosa Ziehau 		if (!(sc->hn_flags & HN_FLAG_RXVF))
11995bdfd3fdSDexuan Cui 			goto out;
12005bdfd3fdSDexuan Cui 
1201962f0357SSepherosa Ziehau 		sc->hn_flags &= ~HN_FLAG_RXVF;
1202499c3e17SSepherosa Ziehau 		if (hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
12035bdfd3fdSDexuan Cui 			hn_rxfilter_config(sc);
12045bdfd3fdSDexuan Cui 		else
12055bdfd3fdSDexuan Cui 			hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE);
12065bdfd3fdSDexuan Cui 	}
12075bdfd3fdSDexuan Cui 
12085bdfd3fdSDexuan Cui 	hn_nvs_set_datapath(sc,
12099c6cae24SSepherosa Ziehau 	    rxvf ? HN_NVS_DATAPATH_VF : HN_NVS_DATAPATH_SYNTH);
12105bdfd3fdSDexuan Cui 
1211962f0357SSepherosa Ziehau 	hn_rxvf_set(sc, rxvf ? ifp : NULL);
12125bdfd3fdSDexuan Cui 
1213962f0357SSepherosa Ziehau 	if (rxvf) {
1214642ec226SSepherosa Ziehau 		hn_vf_rss_fixup(sc, true);
12155bdfd3fdSDexuan Cui 		hn_suspend_mgmt(sc);
12165bdfd3fdSDexuan Cui 		sc->hn_link_flags &=
12175bdfd3fdSDexuan Cui 		    ~(HN_LINK_FLAG_LINKUP | HN_LINK_FLAG_NETCHG);
1218499c3e17SSepherosa Ziehau 		if_link_state_change(hn_ifp, LINK_STATE_DOWN);
12195bdfd3fdSDexuan Cui 	} else {
1220642ec226SSepherosa Ziehau 		hn_vf_rss_restore(sc);
12215bdfd3fdSDexuan Cui 		hn_resume_mgmt(sc);
12225bdfd3fdSDexuan Cui 	}
12235bdfd3fdSDexuan Cui 
1224962f0357SSepherosa Ziehau 	devctl_notify("HYPERV_NIC_VF", hn_ifp->if_xname,
1225962f0357SSepherosa Ziehau 	    rxvf ? "VF_UP" : "VF_DOWN", NULL);
122633408a34SDexuan Cui 
1227962f0357SSepherosa Ziehau 	if (bootverbose) {
1228962f0357SSepherosa Ziehau 		if_printf(hn_ifp, "datapath is switched %s %s\n",
1229962f0357SSepherosa Ziehau 		    rxvf ? "to" : "from", ifp->if_xname);
1230962f0357SSepherosa Ziehau 	}
12315bdfd3fdSDexuan Cui out:
12325bdfd3fdSDexuan Cui 	HN_UNLOCK(sc);
12335bdfd3fdSDexuan Cui }
12345bdfd3fdSDexuan Cui 
12355bdfd3fdSDexuan Cui static void
12365bdfd3fdSDexuan Cui hn_ifnet_event(void *arg, struct ifnet *ifp, int event)
12375bdfd3fdSDexuan Cui {
1238962f0357SSepherosa Ziehau 
12395bdfd3fdSDexuan Cui 	if (event != IFNET_EVENT_UP && event != IFNET_EVENT_DOWN)
12405bdfd3fdSDexuan Cui 		return;
1241962f0357SSepherosa Ziehau 	hn_rxvf_change(arg, ifp, event == IFNET_EVENT_UP);
12425bdfd3fdSDexuan Cui }
12435bdfd3fdSDexuan Cui 
12445bdfd3fdSDexuan Cui static void
12455bdfd3fdSDexuan Cui hn_ifaddr_event(void *arg, struct ifnet *ifp)
12465bdfd3fdSDexuan Cui {
1247962f0357SSepherosa Ziehau 
1248962f0357SSepherosa Ziehau 	hn_rxvf_change(arg, ifp, ifp->if_flags & IFF_UP);
12495bdfd3fdSDexuan Cui }
12505bdfd3fdSDexuan Cui 
12519c6cae24SSepherosa Ziehau static int
12529c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetcaps(struct hn_softc *sc, struct ifreq *ifr)
12539c6cae24SSepherosa Ziehau {
12549c6cae24SSepherosa Ziehau 	struct ifnet *ifp, *vf_ifp;
12559c6cae24SSepherosa Ziehau 	uint64_t tmp;
12569c6cae24SSepherosa Ziehau 	int error;
12579c6cae24SSepherosa Ziehau 
12589c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
12599c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
12609c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
12619c6cae24SSepherosa Ziehau 
12629c6cae24SSepherosa Ziehau 	/*
12639c6cae24SSepherosa Ziehau 	 * Fix up requested capabilities w/ supported capabilities,
12649c6cae24SSepherosa Ziehau 	 * since the supported capabilities could have been changed.
12659c6cae24SSepherosa Ziehau 	 */
12669c6cae24SSepherosa Ziehau 	ifr->ifr_reqcap &= ifp->if_capabilities;
12679c6cae24SSepherosa Ziehau 	/* Pass SIOCSIFCAP to VF. */
12689c6cae24SSepherosa Ziehau 	error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFCAP, (caddr_t)ifr);
12699c6cae24SSepherosa Ziehau 
12709c6cae24SSepherosa Ziehau 	/*
12719c6cae24SSepherosa Ziehau 	 * NOTE:
12729c6cae24SSepherosa Ziehau 	 * The error will be propagated to the callers, however, it
12739c6cae24SSepherosa Ziehau 	 * is _not_ useful here.
12749c6cae24SSepherosa Ziehau 	 */
12759c6cae24SSepherosa Ziehau 
12769c6cae24SSepherosa Ziehau 	/*
12779c6cae24SSepherosa Ziehau 	 * Merge VF's enabled capabilities.
12789c6cae24SSepherosa Ziehau 	 */
12799c6cae24SSepherosa Ziehau 	ifp->if_capenable = vf_ifp->if_capenable & ifp->if_capabilities;
12809c6cae24SSepherosa Ziehau 
12819c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & HN_CSUM_IP_HWASSIST(sc);
12829c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TXCSUM)
12839c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
12849c6cae24SSepherosa Ziehau 	else
12859c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
12869c6cae24SSepherosa Ziehau 
12879c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & HN_CSUM_IP6_HWASSIST(sc);
12889c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
12899c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
12909c6cae24SSepherosa Ziehau 	else
12919c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
12929c6cae24SSepherosa Ziehau 
12939c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & CSUM_IP_TSO;
12949c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TSO4)
12959c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
12969c6cae24SSepherosa Ziehau 	else
12979c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
12989c6cae24SSepherosa Ziehau 
12999c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & CSUM_IP6_TSO;
13009c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TSO6)
13019c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
13029c6cae24SSepherosa Ziehau 	else
13039c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
13049c6cae24SSepherosa Ziehau 
13059c6cae24SSepherosa Ziehau 	return (error);
13069c6cae24SSepherosa Ziehau }
13079c6cae24SSepherosa Ziehau 
13089c6cae24SSepherosa Ziehau static int
13099c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetflags(struct hn_softc *sc)
13109c6cae24SSepherosa Ziehau {
13119c6cae24SSepherosa Ziehau 	struct ifnet *vf_ifp;
13129c6cae24SSepherosa Ziehau 	struct ifreq ifr;
13139c6cae24SSepherosa Ziehau 
13149c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
13159c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
13169c6cae24SSepherosa Ziehau 
13179c6cae24SSepherosa Ziehau 	memset(&ifr, 0, sizeof(ifr));
13189c6cae24SSepherosa Ziehau 	strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
13199c6cae24SSepherosa Ziehau 	ifr.ifr_flags = vf_ifp->if_flags & 0xffff;
13209c6cae24SSepherosa Ziehau 	ifr.ifr_flagshigh = vf_ifp->if_flags >> 16;
13219c6cae24SSepherosa Ziehau 	return (vf_ifp->if_ioctl(vf_ifp, SIOCSIFFLAGS, (caddr_t)&ifr));
13229c6cae24SSepherosa Ziehau }
13239c6cae24SSepherosa Ziehau 
13249c6cae24SSepherosa Ziehau static void
13259c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(struct hn_softc *sc)
13269c6cae24SSepherosa Ziehau {
13279c6cae24SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
13289c6cae24SSepherosa Ziehau 	int allmulti = 0;
13299c6cae24SSepherosa Ziehau 
13309c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
13319c6cae24SSepherosa Ziehau 
13329c6cae24SSepherosa Ziehau 	/* XXX vlan(4) style mcast addr maintenance */
1333d7c5a620SMatt Macy 	if (!CK_STAILQ_EMPTY(&ifp->if_multiaddrs))
13349c6cae24SSepherosa Ziehau 		allmulti = IFF_ALLMULTI;
13359c6cae24SSepherosa Ziehau 
13369c6cae24SSepherosa Ziehau 	/* Always set the VF's if_flags */
13379c6cae24SSepherosa Ziehau 	sc->hn_vf_ifp->if_flags = ifp->if_flags | allmulti;
13389c6cae24SSepherosa Ziehau }
13399c6cae24SSepherosa Ziehau 
13409c6cae24SSepherosa Ziehau static void
13419c6cae24SSepherosa Ziehau hn_xpnt_vf_input(struct ifnet *vf_ifp, struct mbuf *m)
13429c6cae24SSepherosa Ziehau {
13439c6cae24SSepherosa Ziehau 	struct rm_priotracker pt;
13449c6cae24SSepherosa Ziehau 	struct ifnet *hn_ifp = NULL;
13459c6cae24SSepherosa Ziehau 	struct mbuf *mn;
13469c6cae24SSepherosa Ziehau 
13479c6cae24SSepherosa Ziehau 	/*
13489c6cae24SSepherosa Ziehau 	 * XXX racy, if hn(4) ever detached.
13499c6cae24SSepherosa Ziehau 	 */
13509c6cae24SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
13519c6cae24SSepherosa Ziehau 	if (vf_ifp->if_index < hn_vfmap_size)
13529c6cae24SSepherosa Ziehau 		hn_ifp = hn_vfmap[vf_ifp->if_index];
13539c6cae24SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
13549c6cae24SSepherosa Ziehau 
13559c6cae24SSepherosa Ziehau 	if (hn_ifp != NULL) {
13569c6cae24SSepherosa Ziehau 		for (mn = m; mn != NULL; mn = mn->m_nextpkt) {
13573bed4e54SSepherosa Ziehau 			/*
13583bed4e54SSepherosa Ziehau 			 * Allow tapping on the VF.
13593bed4e54SSepherosa Ziehau 			 */
13609c6cae24SSepherosa Ziehau 			ETHER_BPF_MTAP(vf_ifp, mn);
13613bed4e54SSepherosa Ziehau 
13623bed4e54SSepherosa Ziehau 			/*
13633bed4e54SSepherosa Ziehau 			 * Update VF stats.
13643bed4e54SSepherosa Ziehau 			 */
13653bed4e54SSepherosa Ziehau 			if ((vf_ifp->if_capenable & IFCAP_HWSTATS) == 0) {
13663bed4e54SSepherosa Ziehau 				if_inc_counter(vf_ifp, IFCOUNTER_IBYTES,
13673bed4e54SSepherosa Ziehau 				    mn->m_pkthdr.len);
13683bed4e54SSepherosa Ziehau 			}
13693bed4e54SSepherosa Ziehau 			/*
13703bed4e54SSepherosa Ziehau 			 * XXX IFCOUNTER_IMCAST
13713bed4e54SSepherosa Ziehau 			 * This stat updating is kinda invasive, since it
13723bed4e54SSepherosa Ziehau 			 * requires two checks on the mbuf: the length check
13733bed4e54SSepherosa Ziehau 			 * and the ethernet header check.  As of this write,
13743bed4e54SSepherosa Ziehau 			 * all multicast packets go directly to hn(4), which
13753bed4e54SSepherosa Ziehau 			 * makes imcast stat updating in the VF a try in vian.
13763bed4e54SSepherosa Ziehau 			 */
13773bed4e54SSepherosa Ziehau 
13783bed4e54SSepherosa Ziehau 			/*
13793bed4e54SSepherosa Ziehau 			 * Fix up rcvif and increase hn(4)'s ipackets.
13803bed4e54SSepherosa Ziehau 			 */
13819c6cae24SSepherosa Ziehau 			mn->m_pkthdr.rcvif = hn_ifp;
13829c6cae24SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1);
13839c6cae24SSepherosa Ziehau 		}
13843bed4e54SSepherosa Ziehau 		/*
13853bed4e54SSepherosa Ziehau 		 * Go through hn(4)'s if_input.
13863bed4e54SSepherosa Ziehau 		 */
13879c6cae24SSepherosa Ziehau 		hn_ifp->if_input(hn_ifp, m);
13889c6cae24SSepherosa Ziehau 	} else {
13899c6cae24SSepherosa Ziehau 		/*
13909c6cae24SSepherosa Ziehau 		 * In the middle of the transition; free this
13919c6cae24SSepherosa Ziehau 		 * mbuf chain.
13929c6cae24SSepherosa Ziehau 		 */
13939c6cae24SSepherosa Ziehau 		while (m != NULL) {
13949c6cae24SSepherosa Ziehau 			mn = m->m_nextpkt;
13959c6cae24SSepherosa Ziehau 			m->m_nextpkt = NULL;
13969c6cae24SSepherosa Ziehau 			m_freem(m);
13979c6cae24SSepherosa Ziehau 			m = mn;
13989c6cae24SSepherosa Ziehau 		}
13999c6cae24SSepherosa Ziehau 	}
14009c6cae24SSepherosa Ziehau }
14019c6cae24SSepherosa Ziehau 
14029c6cae24SSepherosa Ziehau static void
14039c6cae24SSepherosa Ziehau hn_mtu_change_fixup(struct hn_softc *sc)
14049c6cae24SSepherosa Ziehau {
14059c6cae24SSepherosa Ziehau 	struct ifnet *ifp;
14069c6cae24SSepherosa Ziehau 
14079c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
14089c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
14099c6cae24SSepherosa Ziehau 
14109c6cae24SSepherosa Ziehau 	hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu);
14119c6cae24SSepherosa Ziehau #if __FreeBSD_version >= 1100099
14129c6cae24SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_lro.lro_length_lim < HN_LRO_LENLIM_MIN(ifp))
14139c6cae24SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
14149c6cae24SSepherosa Ziehau #endif
14159c6cae24SSepherosa Ziehau }
14169c6cae24SSepherosa Ziehau 
1417642ec226SSepherosa Ziehau static uint32_t
1418642ec226SSepherosa Ziehau hn_rss_type_fromndis(uint32_t rss_hash)
1419642ec226SSepherosa Ziehau {
1420642ec226SSepherosa Ziehau 	uint32_t types = 0;
1421642ec226SSepherosa Ziehau 
1422642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_IPV4)
1423642ec226SSepherosa Ziehau 		types |= RSS_TYPE_IPV4;
1424642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_TCP_IPV4)
1425642ec226SSepherosa Ziehau 		types |= RSS_TYPE_TCP_IPV4;
1426642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_IPV6)
1427642ec226SSepherosa Ziehau 		types |= RSS_TYPE_IPV6;
1428642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_IPV6_EX)
1429642ec226SSepherosa Ziehau 		types |= RSS_TYPE_IPV6_EX;
1430642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_TCP_IPV6)
1431642ec226SSepherosa Ziehau 		types |= RSS_TYPE_TCP_IPV6;
1432642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_TCP_IPV6_EX)
1433642ec226SSepherosa Ziehau 		types |= RSS_TYPE_TCP_IPV6_EX;
14346f12c42eSSepherosa Ziehau 	if (rss_hash & NDIS_HASH_UDP_IPV4_X)
14356f12c42eSSepherosa Ziehau 		types |= RSS_TYPE_UDP_IPV4;
1436642ec226SSepherosa Ziehau 	return (types);
1437642ec226SSepherosa Ziehau }
1438642ec226SSepherosa Ziehau 
1439642ec226SSepherosa Ziehau static uint32_t
1440642ec226SSepherosa Ziehau hn_rss_type_tondis(uint32_t types)
1441642ec226SSepherosa Ziehau {
1442642ec226SSepherosa Ziehau 	uint32_t rss_hash = 0;
1443642ec226SSepherosa Ziehau 
14446f12c42eSSepherosa Ziehau 	KASSERT((types & (RSS_TYPE_UDP_IPV6 | RSS_TYPE_UDP_IPV6_EX)) == 0,
14456f12c42eSSepherosa Ziehau 	    ("UDP6 and UDP6EX are not supported"));
1446642ec226SSepherosa Ziehau 
1447642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_IPV4)
1448642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_IPV4;
1449642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_TCP_IPV4)
1450642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_TCP_IPV4;
1451642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_IPV6)
1452642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_IPV6;
1453642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_IPV6_EX)
1454642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_IPV6_EX;
1455642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_TCP_IPV6)
1456642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_TCP_IPV6;
1457642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_TCP_IPV6_EX)
1458642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_TCP_IPV6_EX;
14596f12c42eSSepherosa Ziehau 	if (types & RSS_TYPE_UDP_IPV4)
14606f12c42eSSepherosa Ziehau 		rss_hash |= NDIS_HASH_UDP_IPV4_X;
1461642ec226SSepherosa Ziehau 	return (rss_hash);
1462642ec226SSepherosa Ziehau }
1463642ec226SSepherosa Ziehau 
1464642ec226SSepherosa Ziehau static void
1465642ec226SSepherosa Ziehau hn_rss_mbuf_hash(struct hn_softc *sc, uint32_t mbuf_hash)
1466642ec226SSepherosa Ziehau {
1467642ec226SSepherosa Ziehau 	int i;
1468642ec226SSepherosa Ziehau 
1469642ec226SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1470642ec226SSepherosa Ziehau 
1471642ec226SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1472642ec226SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_mbuf_hash = mbuf_hash;
1473642ec226SSepherosa Ziehau }
1474642ec226SSepherosa Ziehau 
1475642ec226SSepherosa Ziehau static void
1476642ec226SSepherosa Ziehau hn_vf_rss_fixup(struct hn_softc *sc, bool reconf)
1477642ec226SSepherosa Ziehau {
1478642ec226SSepherosa Ziehau 	struct ifnet *ifp, *vf_ifp;
1479642ec226SSepherosa Ziehau 	struct ifrsshash ifrh;
1480642ec226SSepherosa Ziehau 	struct ifrsskey ifrk;
1481642ec226SSepherosa Ziehau 	int error;
1482642ec226SSepherosa Ziehau 	uint32_t my_types, diff_types, mbuf_types = 0;
1483642ec226SSepherosa Ziehau 
1484642ec226SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1485642ec226SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
1486642ec226SSepherosa Ziehau 	    ("%s: synthetic parts are not attached", sc->hn_ifp->if_xname));
1487642ec226SSepherosa Ziehau 
1488642ec226SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
1489642ec226SSepherosa Ziehau 		/* No RSS on synthetic parts; done. */
1490642ec226SSepherosa Ziehau 		return;
1491642ec226SSepherosa Ziehau 	}
1492642ec226SSepherosa Ziehau 	if ((sc->hn_rss_hcap & NDIS_HASH_FUNCTION_TOEPLITZ) == 0) {
1493642ec226SSepherosa Ziehau 		/* Synthetic parts do not support Toeplitz; done. */
1494642ec226SSepherosa Ziehau 		return;
1495642ec226SSepherosa Ziehau 	}
1496642ec226SSepherosa Ziehau 
1497642ec226SSepherosa Ziehau 	ifp = sc->hn_ifp;
1498642ec226SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
1499642ec226SSepherosa Ziehau 
1500642ec226SSepherosa Ziehau 	/*
1501642ec226SSepherosa Ziehau 	 * Extract VF's RSS key.  Only 40 bytes key for Toeplitz is
1502642ec226SSepherosa Ziehau 	 * supported.
1503642ec226SSepherosa Ziehau 	 */
1504642ec226SSepherosa Ziehau 	memset(&ifrk, 0, sizeof(ifrk));
1505642ec226SSepherosa Ziehau 	strlcpy(ifrk.ifrk_name, vf_ifp->if_xname, sizeof(ifrk.ifrk_name));
1506642ec226SSepherosa Ziehau 	error = vf_ifp->if_ioctl(vf_ifp, SIOCGIFRSSKEY, (caddr_t)&ifrk);
1507642ec226SSepherosa Ziehau 	if (error) {
1508642ec226SSepherosa Ziehau 		if_printf(ifp, "%s SIOCGRSSKEY failed: %d\n",
1509642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, error);
1510642ec226SSepherosa Ziehau 		goto done;
1511642ec226SSepherosa Ziehau 	}
1512642ec226SSepherosa Ziehau 	if (ifrk.ifrk_func != RSS_FUNC_TOEPLITZ) {
1513642ec226SSepherosa Ziehau 		if_printf(ifp, "%s RSS function %u is not Toeplitz\n",
1514642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, ifrk.ifrk_func);
1515642ec226SSepherosa Ziehau 		goto done;
1516642ec226SSepherosa Ziehau 	}
1517642ec226SSepherosa Ziehau 	if (ifrk.ifrk_keylen != NDIS_HASH_KEYSIZE_TOEPLITZ) {
1518642ec226SSepherosa Ziehau 		if_printf(ifp, "%s invalid RSS Toeplitz key length %d\n",
1519642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, ifrk.ifrk_keylen);
1520642ec226SSepherosa Ziehau 		goto done;
1521642ec226SSepherosa Ziehau 	}
1522642ec226SSepherosa Ziehau 
1523642ec226SSepherosa Ziehau 	/*
1524642ec226SSepherosa Ziehau 	 * Extract VF's RSS hash.  Only Toeplitz is supported.
1525642ec226SSepherosa Ziehau 	 */
1526642ec226SSepherosa Ziehau 	memset(&ifrh, 0, sizeof(ifrh));
1527642ec226SSepherosa Ziehau 	strlcpy(ifrh.ifrh_name, vf_ifp->if_xname, sizeof(ifrh.ifrh_name));
1528642ec226SSepherosa Ziehau 	error = vf_ifp->if_ioctl(vf_ifp, SIOCGIFRSSHASH, (caddr_t)&ifrh);
1529642ec226SSepherosa Ziehau 	if (error) {
1530642ec226SSepherosa Ziehau 		if_printf(ifp, "%s SIOCGRSSHASH failed: %d\n",
1531642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, error);
1532642ec226SSepherosa Ziehau 		goto done;
1533642ec226SSepherosa Ziehau 	}
1534642ec226SSepherosa Ziehau 	if (ifrh.ifrh_func != RSS_FUNC_TOEPLITZ) {
1535642ec226SSepherosa Ziehau 		if_printf(ifp, "%s RSS function %u is not Toeplitz\n",
1536642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, ifrh.ifrh_func);
1537642ec226SSepherosa Ziehau 		goto done;
1538642ec226SSepherosa Ziehau 	}
1539642ec226SSepherosa Ziehau 
1540642ec226SSepherosa Ziehau 	my_types = hn_rss_type_fromndis(sc->hn_rss_hcap);
1541642ec226SSepherosa Ziehau 	if ((ifrh.ifrh_types & my_types) == 0) {
1542642ec226SSepherosa Ziehau 		/* This disables RSS; ignore it then */
1543642ec226SSepherosa Ziehau 		if_printf(ifp, "%s intersection of RSS types failed.  "
1544642ec226SSepherosa Ziehau 		    "VF %#x, mine %#x\n", vf_ifp->if_xname,
1545642ec226SSepherosa Ziehau 		    ifrh.ifrh_types, my_types);
1546642ec226SSepherosa Ziehau 		goto done;
1547642ec226SSepherosa Ziehau 	}
1548642ec226SSepherosa Ziehau 
1549642ec226SSepherosa Ziehau 	diff_types = my_types ^ ifrh.ifrh_types;
1550642ec226SSepherosa Ziehau 	my_types &= ifrh.ifrh_types;
1551642ec226SSepherosa Ziehau 	mbuf_types = my_types;
1552642ec226SSepherosa Ziehau 
1553642ec226SSepherosa Ziehau 	/*
1554642ec226SSepherosa Ziehau 	 * Detect RSS hash value/type confliction.
1555642ec226SSepherosa Ziehau 	 *
1556642ec226SSepherosa Ziehau 	 * NOTE:
1557642ec226SSepherosa Ziehau 	 * We don't disable the hash type, but stop delivery the hash
1558642ec226SSepherosa Ziehau 	 * value/type through mbufs on RX path.
15596f12c42eSSepherosa Ziehau 	 *
15606f12c42eSSepherosa Ziehau 	 * XXX If HN_CAP_UDPHASH is set in hn_caps, then UDP 4-tuple
15616f12c42eSSepherosa Ziehau 	 * hash is delivered with type of TCP_IPV4.  This means if
15626f12c42eSSepherosa Ziehau 	 * UDP_IPV4 is enabled, then TCP_IPV4 should be forced, at
15636f12c42eSSepherosa Ziehau 	 * least to hn_mbuf_hash.  However, given that _all_ of the
15646f12c42eSSepherosa Ziehau 	 * NICs implement TCP_IPV4, this will _not_ impose any issues
15656f12c42eSSepherosa Ziehau 	 * here.
1566642ec226SSepherosa Ziehau 	 */
1567642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_IPV4) &&
1568642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types &
1569642ec226SSepherosa Ziehau 	     (RSS_TYPE_TCP_IPV4 | RSS_TYPE_UDP_IPV4))) {
1570642ec226SSepherosa Ziehau 		/* Conflict; disable IPV4 hash type/value delivery. */
1571642ec226SSepherosa Ziehau 		if_printf(ifp, "disable IPV4 mbuf hash delivery\n");
1572642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_IPV4;
1573642ec226SSepherosa Ziehau 	}
1574642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_IPV6) &&
1575642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types &
1576642ec226SSepherosa Ziehau 	     (RSS_TYPE_TCP_IPV6 | RSS_TYPE_UDP_IPV6 |
1577642ec226SSepherosa Ziehau 	      RSS_TYPE_TCP_IPV6_EX | RSS_TYPE_UDP_IPV6_EX |
1578642ec226SSepherosa Ziehau 	      RSS_TYPE_IPV6_EX))) {
1579642ec226SSepherosa Ziehau 		/* Conflict; disable IPV6 hash type/value delivery. */
1580642ec226SSepherosa Ziehau 		if_printf(ifp, "disable IPV6 mbuf hash delivery\n");
1581642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_IPV6;
1582642ec226SSepherosa Ziehau 	}
1583642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_IPV6_EX) &&
1584642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types &
1585642ec226SSepherosa Ziehau 	     (RSS_TYPE_TCP_IPV6 | RSS_TYPE_UDP_IPV6 |
1586642ec226SSepherosa Ziehau 	      RSS_TYPE_TCP_IPV6_EX | RSS_TYPE_UDP_IPV6_EX |
1587642ec226SSepherosa Ziehau 	      RSS_TYPE_IPV6))) {
1588642ec226SSepherosa Ziehau 		/* Conflict; disable IPV6_EX hash type/value delivery. */
1589642ec226SSepherosa Ziehau 		if_printf(ifp, "disable IPV6_EX mbuf hash delivery\n");
1590642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_IPV6_EX;
1591642ec226SSepherosa Ziehau 	}
1592642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_TCP_IPV6) &&
1593642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_TCP_IPV6_EX)) {
1594642ec226SSepherosa Ziehau 		/* Conflict; disable TCP_IPV6 hash type/value delivery. */
1595642ec226SSepherosa Ziehau 		if_printf(ifp, "disable TCP_IPV6 mbuf hash delivery\n");
1596642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_TCP_IPV6;
1597642ec226SSepherosa Ziehau 	}
1598642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_TCP_IPV6_EX) &&
1599642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_TCP_IPV6)) {
1600642ec226SSepherosa Ziehau 		/* Conflict; disable TCP_IPV6_EX hash type/value delivery. */
1601642ec226SSepherosa Ziehau 		if_printf(ifp, "disable TCP_IPV6_EX mbuf hash delivery\n");
1602642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_TCP_IPV6_EX;
1603642ec226SSepherosa Ziehau 	}
1604642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_UDP_IPV6) &&
1605642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_UDP_IPV6_EX)) {
1606642ec226SSepherosa Ziehau 		/* Conflict; disable UDP_IPV6 hash type/value delivery. */
1607642ec226SSepherosa Ziehau 		if_printf(ifp, "disable UDP_IPV6 mbuf hash delivery\n");
1608642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_UDP_IPV6;
1609642ec226SSepherosa Ziehau 	}
1610642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_UDP_IPV6_EX) &&
1611642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_UDP_IPV6)) {
1612642ec226SSepherosa Ziehau 		/* Conflict; disable UDP_IPV6_EX hash type/value delivery. */
1613642ec226SSepherosa Ziehau 		if_printf(ifp, "disable UDP_IPV6_EX mbuf hash delivery\n");
1614642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_UDP_IPV6_EX;
1615642ec226SSepherosa Ziehau 	}
1616642ec226SSepherosa Ziehau 
1617642ec226SSepherosa Ziehau 	/*
1618642ec226SSepherosa Ziehau 	 * Indirect table does not matter.
1619642ec226SSepherosa Ziehau 	 */
1620642ec226SSepherosa Ziehau 
1621642ec226SSepherosa Ziehau 	sc->hn_rss_hash = (sc->hn_rss_hcap & NDIS_HASH_FUNCTION_MASK) |
1622642ec226SSepherosa Ziehau 	    hn_rss_type_tondis(my_types);
1623642ec226SSepherosa Ziehau 	memcpy(sc->hn_rss.rss_key, ifrk.ifrk_key, sizeof(sc->hn_rss.rss_key));
1624642ec226SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
1625642ec226SSepherosa Ziehau 
1626642ec226SSepherosa Ziehau 	if (reconf) {
1627642ec226SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
1628642ec226SSepherosa Ziehau 		if (error) {
1629642ec226SSepherosa Ziehau 			/* XXX roll-back? */
1630642ec226SSepherosa Ziehau 			if_printf(ifp, "hn_rss_reconfig failed: %d\n", error);
1631642ec226SSepherosa Ziehau 			/* XXX keep going. */
1632642ec226SSepherosa Ziehau 		}
1633642ec226SSepherosa Ziehau 	}
1634642ec226SSepherosa Ziehau done:
1635642ec226SSepherosa Ziehau 	/* Hash deliverability for mbufs. */
1636642ec226SSepherosa Ziehau 	hn_rss_mbuf_hash(sc, hn_rss_type_tondis(mbuf_types));
1637642ec226SSepherosa Ziehau }
1638642ec226SSepherosa Ziehau 
1639642ec226SSepherosa Ziehau static void
1640642ec226SSepherosa Ziehau hn_vf_rss_restore(struct hn_softc *sc)
1641642ec226SSepherosa Ziehau {
1642642ec226SSepherosa Ziehau 
1643642ec226SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1644642ec226SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
1645642ec226SSepherosa Ziehau 	    ("%s: synthetic parts are not attached", sc->hn_ifp->if_xname));
1646642ec226SSepherosa Ziehau 
1647642ec226SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1)
1648642ec226SSepherosa Ziehau 		goto done;
1649642ec226SSepherosa Ziehau 
1650642ec226SSepherosa Ziehau 	/*
1651642ec226SSepherosa Ziehau 	 * Restore hash types.  Key does _not_ matter.
1652642ec226SSepherosa Ziehau 	 */
1653642ec226SSepherosa Ziehau 	if (sc->hn_rss_hash != sc->hn_rss_hcap) {
1654642ec226SSepherosa Ziehau 		int error;
1655642ec226SSepherosa Ziehau 
1656642ec226SSepherosa Ziehau 		sc->hn_rss_hash = sc->hn_rss_hcap;
1657642ec226SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
1658642ec226SSepherosa Ziehau 		if (error) {
1659642ec226SSepherosa Ziehau 			if_printf(sc->hn_ifp, "hn_rss_reconfig failed: %d\n",
1660642ec226SSepherosa Ziehau 			    error);
1661642ec226SSepherosa Ziehau 			/* XXX keep going. */
1662642ec226SSepherosa Ziehau 		}
1663642ec226SSepherosa Ziehau 	}
1664642ec226SSepherosa Ziehau done:
1665642ec226SSepherosa Ziehau 	/* Hash deliverability for mbufs. */
1666642ec226SSepherosa Ziehau 	hn_rss_mbuf_hash(sc, NDIS_HASH_ALL);
1667642ec226SSepherosa Ziehau }
1668642ec226SSepherosa Ziehau 
16699c6cae24SSepherosa Ziehau static void
16709c6cae24SSepherosa Ziehau hn_xpnt_vf_setready(struct hn_softc *sc)
16719c6cae24SSepherosa Ziehau {
16729c6cae24SSepherosa Ziehau 	struct ifnet *ifp, *vf_ifp;
16739c6cae24SSepherosa Ziehau 	struct ifreq ifr;
16749c6cae24SSepherosa Ziehau 
16759c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
16769c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
16779c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
16789c6cae24SSepherosa Ziehau 
16799c6cae24SSepherosa Ziehau 	/*
16809c6cae24SSepherosa Ziehau 	 * Mark the VF ready.
16819c6cae24SSepherosa Ziehau 	 */
16829c6cae24SSepherosa Ziehau 	sc->hn_vf_rdytick = 0;
16839c6cae24SSepherosa Ziehau 
16849c6cae24SSepherosa Ziehau 	/*
16859c6cae24SSepherosa Ziehau 	 * Save information for restoration.
16869c6cae24SSepherosa Ziehau 	 */
16879c6cae24SSepherosa Ziehau 	sc->hn_saved_caps = ifp->if_capabilities;
16889c6cae24SSepherosa Ziehau 	sc->hn_saved_tsomax = ifp->if_hw_tsomax;
16899c6cae24SSepherosa Ziehau 	sc->hn_saved_tsosegcnt = ifp->if_hw_tsomaxsegcount;
16909c6cae24SSepherosa Ziehau 	sc->hn_saved_tsosegsz = ifp->if_hw_tsomaxsegsize;
16919c6cae24SSepherosa Ziehau 
16929c6cae24SSepherosa Ziehau 	/*
16939c6cae24SSepherosa Ziehau 	 * Intersect supported/enabled capabilities.
16949c6cae24SSepherosa Ziehau 	 *
16959c6cae24SSepherosa Ziehau 	 * NOTE:
16969c6cae24SSepherosa Ziehau 	 * if_hwassist is not changed here.
16979c6cae24SSepherosa Ziehau 	 */
16989c6cae24SSepherosa Ziehau 	ifp->if_capabilities &= vf_ifp->if_capabilities;
16999c6cae24SSepherosa Ziehau 	ifp->if_capenable &= ifp->if_capabilities;
17009c6cae24SSepherosa Ziehau 
17019c6cae24SSepherosa Ziehau 	/*
17029c6cae24SSepherosa Ziehau 	 * Fix TSO settings.
17039c6cae24SSepherosa Ziehau 	 */
17049c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomax > vf_ifp->if_hw_tsomax)
17059c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomax = vf_ifp->if_hw_tsomax;
17069c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomaxsegcount > vf_ifp->if_hw_tsomaxsegcount)
17079c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = vf_ifp->if_hw_tsomaxsegcount;
17089c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomaxsegsize > vf_ifp->if_hw_tsomaxsegsize)
17099c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = vf_ifp->if_hw_tsomaxsegsize;
17109c6cae24SSepherosa Ziehau 
17119c6cae24SSepherosa Ziehau 	/*
17129c6cae24SSepherosa Ziehau 	 * Change VF's enabled capabilities.
17139c6cae24SSepherosa Ziehau 	 */
17149c6cae24SSepherosa Ziehau 	memset(&ifr, 0, sizeof(ifr));
17159c6cae24SSepherosa Ziehau 	strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
17169c6cae24SSepherosa Ziehau 	ifr.ifr_reqcap = ifp->if_capenable;
17179c6cae24SSepherosa Ziehau 	hn_xpnt_vf_iocsetcaps(sc, &ifr);
17189c6cae24SSepherosa Ziehau 
17199c6cae24SSepherosa Ziehau 	if (ifp->if_mtu != ETHERMTU) {
17209c6cae24SSepherosa Ziehau 		int error;
17219c6cae24SSepherosa Ziehau 
17229c6cae24SSepherosa Ziehau 		/*
17239c6cae24SSepherosa Ziehau 		 * Change VF's MTU.
17249c6cae24SSepherosa Ziehau 		 */
17259c6cae24SSepherosa Ziehau 		memset(&ifr, 0, sizeof(ifr));
17269c6cae24SSepherosa Ziehau 		strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
17279c6cae24SSepherosa Ziehau 		ifr.ifr_mtu = ifp->if_mtu;
17289c6cae24SSepherosa Ziehau 		error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU, (caddr_t)&ifr);
17299c6cae24SSepherosa Ziehau 		if (error) {
17309c6cae24SSepherosa Ziehau 			if_printf(ifp, "%s SIOCSIFMTU %u failed\n",
17319c6cae24SSepherosa Ziehau 			    vf_ifp->if_xname, ifp->if_mtu);
17329c6cae24SSepherosa Ziehau 			if (ifp->if_mtu > ETHERMTU) {
17339c6cae24SSepherosa Ziehau 				if_printf(ifp, "change MTU to %d\n", ETHERMTU);
17349c6cae24SSepherosa Ziehau 
17359c6cae24SSepherosa Ziehau 				/*
17369c6cae24SSepherosa Ziehau 				 * XXX
17379c6cae24SSepherosa Ziehau 				 * No need to adjust the synthetic parts' MTU;
17389c6cae24SSepherosa Ziehau 				 * failure of the adjustment will cause us
17399c6cae24SSepherosa Ziehau 				 * infinite headache.
17409c6cae24SSepherosa Ziehau 				 */
17419c6cae24SSepherosa Ziehau 				ifp->if_mtu = ETHERMTU;
17429c6cae24SSepherosa Ziehau 				hn_mtu_change_fixup(sc);
17439c6cae24SSepherosa Ziehau 			}
17449c6cae24SSepherosa Ziehau 		}
17459c6cae24SSepherosa Ziehau 	}
17469c6cae24SSepherosa Ziehau }
17479c6cae24SSepherosa Ziehau 
17489c6cae24SSepherosa Ziehau static bool
17499c6cae24SSepherosa Ziehau hn_xpnt_vf_isready(struct hn_softc *sc)
17509c6cae24SSepherosa Ziehau {
17519c6cae24SSepherosa Ziehau 
17529c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
17539c6cae24SSepherosa Ziehau 
17549c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf || sc->hn_vf_ifp == NULL)
17559c6cae24SSepherosa Ziehau 		return (false);
17569c6cae24SSepherosa Ziehau 
17579c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick == 0)
17589c6cae24SSepherosa Ziehau 		return (true);
17599c6cae24SSepherosa Ziehau 
17609c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick > ticks)
17619c6cae24SSepherosa Ziehau 		return (false);
17629c6cae24SSepherosa Ziehau 
17639c6cae24SSepherosa Ziehau 	/* Mark VF as ready. */
17649c6cae24SSepherosa Ziehau 	hn_xpnt_vf_setready(sc);
17659c6cae24SSepherosa Ziehau 	return (true);
17669c6cae24SSepherosa Ziehau }
17679c6cae24SSepherosa Ziehau 
17689c6cae24SSepherosa Ziehau static void
1769a97fff19SSepherosa Ziehau hn_xpnt_vf_setenable(struct hn_softc *sc)
1770a97fff19SSepherosa Ziehau {
1771a97fff19SSepherosa Ziehau 	int i;
1772a97fff19SSepherosa Ziehau 
1773a97fff19SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1774a97fff19SSepherosa Ziehau 
1775a97fff19SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
1776a97fff19SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
1777a97fff19SSepherosa Ziehau 	sc->hn_xvf_flags |= HN_XVFFLAG_ENABLED;
1778a97fff19SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
1779a97fff19SSepherosa Ziehau 
1780a97fff19SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1781a97fff19SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_rx_flags |= HN_RX_FLAG_XPNT_VF;
1782a97fff19SSepherosa Ziehau }
1783a97fff19SSepherosa Ziehau 
1784a97fff19SSepherosa Ziehau static void
1785a97fff19SSepherosa Ziehau hn_xpnt_vf_setdisable(struct hn_softc *sc, bool clear_vf)
1786a97fff19SSepherosa Ziehau {
1787a97fff19SSepherosa Ziehau 	int i;
1788a97fff19SSepherosa Ziehau 
1789a97fff19SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1790a97fff19SSepherosa Ziehau 
1791a97fff19SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
1792a97fff19SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
1793a97fff19SSepherosa Ziehau 	sc->hn_xvf_flags &= ~HN_XVFFLAG_ENABLED;
1794a97fff19SSepherosa Ziehau 	if (clear_vf)
1795a97fff19SSepherosa Ziehau 		sc->hn_vf_ifp = NULL;
1796a97fff19SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
1797a97fff19SSepherosa Ziehau 
1798a97fff19SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1799a97fff19SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_rx_flags &= ~HN_RX_FLAG_XPNT_VF;
1800a97fff19SSepherosa Ziehau }
1801a97fff19SSepherosa Ziehau 
1802a97fff19SSepherosa Ziehau static void
18039c6cae24SSepherosa Ziehau hn_xpnt_vf_init(struct hn_softc *sc)
18049c6cae24SSepherosa Ziehau {
18059c6cae24SSepherosa Ziehau 	int error;
18069c6cae24SSepherosa Ziehau 
18079c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
18089c6cae24SSepherosa Ziehau 
18099c6cae24SSepherosa Ziehau 	KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0,
18109c6cae24SSepherosa Ziehau 	    ("%s: transparent VF was enabled", sc->hn_ifp->if_xname));
18119c6cae24SSepherosa Ziehau 
18129c6cae24SSepherosa Ziehau 	if (bootverbose) {
18139c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "try bringing up %s\n",
18149c6cae24SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname);
18159c6cae24SSepherosa Ziehau 	}
18169c6cae24SSepherosa Ziehau 
18179c6cae24SSepherosa Ziehau 	/*
18189c6cae24SSepherosa Ziehau 	 * Bring the VF up.
18199c6cae24SSepherosa Ziehau 	 */
18209c6cae24SSepherosa Ziehau 	hn_xpnt_vf_saveifflags(sc);
18219c6cae24SSepherosa Ziehau 	sc->hn_vf_ifp->if_flags |= IFF_UP;
18229c6cae24SSepherosa Ziehau 	error = hn_xpnt_vf_iocsetflags(sc);
18239c6cae24SSepherosa Ziehau 	if (error) {
18249c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "bringing up %s failed: %d\n",
18259c6cae24SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname, error);
18269c6cae24SSepherosa Ziehau 		return;
18279c6cae24SSepherosa Ziehau 	}
18289c6cae24SSepherosa Ziehau 
18299c6cae24SSepherosa Ziehau 	/*
18309c6cae24SSepherosa Ziehau 	 * NOTE:
18319c6cae24SSepherosa Ziehau 	 * Datapath setting must happen _after_ bringing the VF up.
18329c6cae24SSepherosa Ziehau 	 */
18339c6cae24SSepherosa Ziehau 	hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF);
18349c6cae24SSepherosa Ziehau 
1835642ec226SSepherosa Ziehau 	/*
1836642ec226SSepherosa Ziehau 	 * NOTE:
1837642ec226SSepherosa Ziehau 	 * Fixup RSS related bits _after_ the VF is brought up, since
1838642ec226SSepherosa Ziehau 	 * many VFs generate RSS key during it's initialization.
1839642ec226SSepherosa Ziehau 	 */
1840642ec226SSepherosa Ziehau 	hn_vf_rss_fixup(sc, true);
1841642ec226SSepherosa Ziehau 
1842a97fff19SSepherosa Ziehau 	/* Mark transparent mode VF as enabled. */
1843a97fff19SSepherosa Ziehau 	hn_xpnt_vf_setenable(sc);
18449c6cae24SSepherosa Ziehau }
18459c6cae24SSepherosa Ziehau 
18469c6cae24SSepherosa Ziehau static void
18479c6cae24SSepherosa Ziehau hn_xpnt_vf_init_taskfunc(void *xsc, int pending __unused)
18489c6cae24SSepherosa Ziehau {
18499c6cae24SSepherosa Ziehau 	struct hn_softc *sc = xsc;
18509c6cae24SSepherosa Ziehau 
18519c6cae24SSepherosa Ziehau 	HN_LOCK(sc);
18529c6cae24SSepherosa Ziehau 
18539c6cae24SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
18549c6cae24SSepherosa Ziehau 		goto done;
18559c6cae24SSepherosa Ziehau 	if (sc->hn_vf_ifp == NULL)
18569c6cae24SSepherosa Ziehau 		goto done;
18579c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
18589c6cae24SSepherosa Ziehau 		goto done;
18599c6cae24SSepherosa Ziehau 
18609c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick != 0) {
18619c6cae24SSepherosa Ziehau 		/* Mark VF as ready. */
18629c6cae24SSepherosa Ziehau 		hn_xpnt_vf_setready(sc);
18639c6cae24SSepherosa Ziehau 	}
18649c6cae24SSepherosa Ziehau 
18659c6cae24SSepherosa Ziehau 	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) {
18669c6cae24SSepherosa Ziehau 		/*
18679c6cae24SSepherosa Ziehau 		 * Delayed VF initialization.
18689c6cae24SSepherosa Ziehau 		 */
18699c6cae24SSepherosa Ziehau 		if (bootverbose) {
18709c6cae24SSepherosa Ziehau 			if_printf(sc->hn_ifp, "delayed initialize %s\n",
18719c6cae24SSepherosa Ziehau 			    sc->hn_vf_ifp->if_xname);
18729c6cae24SSepherosa Ziehau 		}
18739c6cae24SSepherosa Ziehau 		hn_xpnt_vf_init(sc);
18749c6cae24SSepherosa Ziehau 	}
18759c6cae24SSepherosa Ziehau done:
18769c6cae24SSepherosa Ziehau 	HN_UNLOCK(sc);
18779c6cae24SSepherosa Ziehau }
18789c6cae24SSepherosa Ziehau 
1879499c3e17SSepherosa Ziehau static void
1880499c3e17SSepherosa Ziehau hn_ifnet_attevent(void *xsc, struct ifnet *ifp)
1881499c3e17SSepherosa Ziehau {
1882499c3e17SSepherosa Ziehau 	struct hn_softc *sc = xsc;
1883499c3e17SSepherosa Ziehau 
1884499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
1885499c3e17SSepherosa Ziehau 
1886499c3e17SSepherosa Ziehau 	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
1887499c3e17SSepherosa Ziehau 		goto done;
1888499c3e17SSepherosa Ziehau 
1889499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1890499c3e17SSepherosa Ziehau 		goto done;
1891499c3e17SSepherosa Ziehau 
1892499c3e17SSepherosa Ziehau 	if (sc->hn_vf_ifp != NULL) {
1893499c3e17SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%s was attached as VF\n",
1894499c3e17SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname);
1895499c3e17SSepherosa Ziehau 		goto done;
1896499c3e17SSepherosa Ziehau 	}
1897499c3e17SSepherosa Ziehau 
18989c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && ifp->if_start != NULL) {
18999c6cae24SSepherosa Ziehau 		/*
19009c6cae24SSepherosa Ziehau 		 * ifnet.if_start is _not_ supported by transparent
19019c6cae24SSepherosa Ziehau 		 * mode VF; mainly due to the IFF_DRV_OACTIVE flag.
19029c6cae24SSepherosa Ziehau 		 */
19039c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%s uses if_start, which is unsupported "
19049c6cae24SSepherosa Ziehau 		    "in transparent VF mode.\n", ifp->if_xname);
19059c6cae24SSepherosa Ziehau 		goto done;
19069c6cae24SSepherosa Ziehau 	}
19079c6cae24SSepherosa Ziehau 
1908499c3e17SSepherosa Ziehau 	rm_wlock(&hn_vfmap_lock);
1909499c3e17SSepherosa Ziehau 
1910499c3e17SSepherosa Ziehau 	if (ifp->if_index >= hn_vfmap_size) {
1911499c3e17SSepherosa Ziehau 		struct ifnet **newmap;
1912499c3e17SSepherosa Ziehau 		int newsize;
1913499c3e17SSepherosa Ziehau 
1914499c3e17SSepherosa Ziehau 		newsize = ifp->if_index + HN_VFMAP_SIZE_DEF;
1915499c3e17SSepherosa Ziehau 		newmap = malloc(sizeof(struct ifnet *) * newsize, M_DEVBUF,
1916499c3e17SSepherosa Ziehau 		    M_WAITOK | M_ZERO);
1917499c3e17SSepherosa Ziehau 
1918499c3e17SSepherosa Ziehau 		memcpy(newmap, hn_vfmap,
1919499c3e17SSepherosa Ziehau 		    sizeof(struct ifnet *) * hn_vfmap_size);
1920499c3e17SSepherosa Ziehau 		free(hn_vfmap, M_DEVBUF);
1921499c3e17SSepherosa Ziehau 		hn_vfmap = newmap;
1922499c3e17SSepherosa Ziehau 		hn_vfmap_size = newsize;
1923499c3e17SSepherosa Ziehau 	}
1924499c3e17SSepherosa Ziehau 	KASSERT(hn_vfmap[ifp->if_index] == NULL,
1925499c3e17SSepherosa Ziehau 	    ("%s: ifindex %d was mapped to %s",
1926499c3e17SSepherosa Ziehau 	     ifp->if_xname, ifp->if_index, hn_vfmap[ifp->if_index]->if_xname));
1927499c3e17SSepherosa Ziehau 	hn_vfmap[ifp->if_index] = sc->hn_ifp;
1928499c3e17SSepherosa Ziehau 
1929499c3e17SSepherosa Ziehau 	rm_wunlock(&hn_vfmap_lock);
1930499c3e17SSepherosa Ziehau 
19319c6cae24SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
19329c6cae24SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
19339c6cae24SSepherosa Ziehau 	KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0,
19349c6cae24SSepherosa Ziehau 	    ("%s: transparent VF was enabled", sc->hn_ifp->if_xname));
1935499c3e17SSepherosa Ziehau 	sc->hn_vf_ifp = ifp;
19369c6cae24SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
19379c6cae24SSepherosa Ziehau 
19389c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
19399c6cae24SSepherosa Ziehau 		int wait_ticks;
19409c6cae24SSepherosa Ziehau 
19419c6cae24SSepherosa Ziehau 		/*
19429c6cae24SSepherosa Ziehau 		 * Install if_input for vf_ifp, which does vf_ifp -> hn_ifp.
19439c6cae24SSepherosa Ziehau 		 * Save vf_ifp's current if_input for later restoration.
19449c6cae24SSepherosa Ziehau 		 */
19459c6cae24SSepherosa Ziehau 		sc->hn_vf_input = ifp->if_input;
19469c6cae24SSepherosa Ziehau 		ifp->if_input = hn_xpnt_vf_input;
19479c6cae24SSepherosa Ziehau 
19489c6cae24SSepherosa Ziehau 		/*
19499c6cae24SSepherosa Ziehau 		 * Stop link status management; use the VF's.
19509c6cae24SSepherosa Ziehau 		 */
19519c6cae24SSepherosa Ziehau 		hn_suspend_mgmt(sc);
19529c6cae24SSepherosa Ziehau 
19539c6cae24SSepherosa Ziehau 		/*
19549c6cae24SSepherosa Ziehau 		 * Give VF sometime to complete its attach routing.
19559c6cae24SSepherosa Ziehau 		 */
19569c6cae24SSepherosa Ziehau 		wait_ticks = hn_xpnt_vf_attwait * hz;
19579c6cae24SSepherosa Ziehau 		sc->hn_vf_rdytick = ticks + wait_ticks;
19589c6cae24SSepherosa Ziehau 
19599c6cae24SSepherosa Ziehau 		taskqueue_enqueue_timeout(sc->hn_vf_taskq, &sc->hn_vf_init,
19609c6cae24SSepherosa Ziehau 		    wait_ticks);
19619c6cae24SSepherosa Ziehau 	}
1962499c3e17SSepherosa Ziehau done:
1963499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
1964499c3e17SSepherosa Ziehau }
1965499c3e17SSepherosa Ziehau 
1966499c3e17SSepherosa Ziehau static void
1967499c3e17SSepherosa Ziehau hn_ifnet_detevent(void *xsc, struct ifnet *ifp)
1968499c3e17SSepherosa Ziehau {
1969499c3e17SSepherosa Ziehau 	struct hn_softc *sc = xsc;
1970499c3e17SSepherosa Ziehau 
1971499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
1972499c3e17SSepherosa Ziehau 
1973499c3e17SSepherosa Ziehau 	if (sc->hn_vf_ifp == NULL)
1974499c3e17SSepherosa Ziehau 		goto done;
1975499c3e17SSepherosa Ziehau 
1976499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1977499c3e17SSepherosa Ziehau 		goto done;
1978499c3e17SSepherosa Ziehau 
19799c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
19809c6cae24SSepherosa Ziehau 		/*
19819c6cae24SSepherosa Ziehau 		 * Make sure that the delayed initialization is not running.
19829c6cae24SSepherosa Ziehau 		 *
19839c6cae24SSepherosa Ziehau 		 * NOTE:
19849c6cae24SSepherosa Ziehau 		 * - This lock _must_ be released, since the hn_vf_init task
19859c6cae24SSepherosa Ziehau 		 *   will try holding this lock.
19869c6cae24SSepherosa Ziehau 		 * - It is safe to release this lock here, since the
19879c6cae24SSepherosa Ziehau 		 *   hn_ifnet_attevent() is interlocked by the hn_vf_ifp.
19889c6cae24SSepherosa Ziehau 		 *
19899c6cae24SSepherosa Ziehau 		 * XXX racy, if hn(4) ever detached.
19909c6cae24SSepherosa Ziehau 		 */
19919c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
19929c6cae24SSepherosa Ziehau 		taskqueue_drain_timeout(sc->hn_vf_taskq, &sc->hn_vf_init);
19939c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
19949c6cae24SSepherosa Ziehau 
19959c6cae24SSepherosa Ziehau 		KASSERT(sc->hn_vf_input != NULL, ("%s VF input is not saved",
19969c6cae24SSepherosa Ziehau 		    sc->hn_ifp->if_xname));
19979c6cae24SSepherosa Ziehau 		ifp->if_input = sc->hn_vf_input;
19989c6cae24SSepherosa Ziehau 		sc->hn_vf_input = NULL;
19999c6cae24SSepherosa Ziehau 
2000642ec226SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) &&
2001642ec226SSepherosa Ziehau 		    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED))
20029c6cae24SSepherosa Ziehau 			hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH);
20039c6cae24SSepherosa Ziehau 
20049c6cae24SSepherosa Ziehau 		if (sc->hn_vf_rdytick == 0) {
20059c6cae24SSepherosa Ziehau 			/*
20069c6cae24SSepherosa Ziehau 			 * The VF was ready; restore some settings.
20079c6cae24SSepherosa Ziehau 			 */
20089c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_capabilities = sc->hn_saved_caps;
20099c6cae24SSepherosa Ziehau 			/*
20109c6cae24SSepherosa Ziehau 			 * NOTE:
20119c6cae24SSepherosa Ziehau 			 * There is _no_ need to fixup if_capenable and
20129c6cae24SSepherosa Ziehau 			 * if_hwassist, since the if_capabilities before
20139c6cae24SSepherosa Ziehau 			 * restoration was an intersection of the VF's
20149c6cae24SSepherosa Ziehau 			 * if_capabilites and the synthetic device's
20159c6cae24SSepherosa Ziehau 			 * if_capabilites.
20169c6cae24SSepherosa Ziehau 			 */
20179c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomax = sc->hn_saved_tsomax;
20189c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomaxsegcount =
20199c6cae24SSepherosa Ziehau 			    sc->hn_saved_tsosegcnt;
20209c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomaxsegsize = sc->hn_saved_tsosegsz;
20219c6cae24SSepherosa Ziehau 		}
20229c6cae24SSepherosa Ziehau 
2023642ec226SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
2024642ec226SSepherosa Ziehau 			/*
2025642ec226SSepherosa Ziehau 			 * Restore RSS settings.
2026642ec226SSepherosa Ziehau 			 */
2027642ec226SSepherosa Ziehau 			hn_vf_rss_restore(sc);
2028642ec226SSepherosa Ziehau 
20299c6cae24SSepherosa Ziehau 			/*
20309c6cae24SSepherosa Ziehau 			 * Resume link status management, which was suspended
20319c6cae24SSepherosa Ziehau 			 * by hn_ifnet_attevent().
20329c6cae24SSepherosa Ziehau 			 */
20339c6cae24SSepherosa Ziehau 			hn_resume_mgmt(sc);
20349c6cae24SSepherosa Ziehau 		}
2035642ec226SSepherosa Ziehau 	}
20369c6cae24SSepherosa Ziehau 
2037a97fff19SSepherosa Ziehau 	/* Mark transparent mode VF as disabled. */
2038a97fff19SSepherosa Ziehau 	hn_xpnt_vf_setdisable(sc, true /* clear hn_vf_ifp */);
2039499c3e17SSepherosa Ziehau 
2040499c3e17SSepherosa Ziehau 	rm_wlock(&hn_vfmap_lock);
2041499c3e17SSepherosa Ziehau 
2042499c3e17SSepherosa Ziehau 	KASSERT(ifp->if_index < hn_vfmap_size,
2043499c3e17SSepherosa Ziehau 	    ("ifindex %d, vfmapsize %d", ifp->if_index, hn_vfmap_size));
2044499c3e17SSepherosa Ziehau 	if (hn_vfmap[ifp->if_index] != NULL) {
2045499c3e17SSepherosa Ziehau 		KASSERT(hn_vfmap[ifp->if_index] == sc->hn_ifp,
2046499c3e17SSepherosa Ziehau 		    ("%s: ifindex %d was mapped to %s",
2047499c3e17SSepherosa Ziehau 		     ifp->if_xname, ifp->if_index,
2048499c3e17SSepherosa Ziehau 		     hn_vfmap[ifp->if_index]->if_xname));
2049499c3e17SSepherosa Ziehau 		hn_vfmap[ifp->if_index] = NULL;
2050499c3e17SSepherosa Ziehau 	}
2051499c3e17SSepherosa Ziehau 
2052499c3e17SSepherosa Ziehau 	rm_wunlock(&hn_vfmap_lock);
2053499c3e17SSepherosa Ziehau done:
2054499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
2055499c3e17SSepherosa Ziehau }
2056499c3e17SSepherosa Ziehau 
20579c6cae24SSepherosa Ziehau static void
20589c6cae24SSepherosa Ziehau hn_ifnet_lnkevent(void *xsc, struct ifnet *ifp, int link_state)
20599c6cae24SSepherosa Ziehau {
20609c6cae24SSepherosa Ziehau 	struct hn_softc *sc = xsc;
20619c6cae24SSepherosa Ziehau 
20629c6cae24SSepherosa Ziehau 	if (sc->hn_vf_ifp == ifp)
20639c6cae24SSepherosa Ziehau 		if_link_state_change(sc->hn_ifp, link_state);
20649c6cae24SSepherosa Ziehau }
20659c6cae24SSepherosa Ziehau 
206615516c77SSepherosa Ziehau static int
206715516c77SSepherosa Ziehau hn_probe(device_t dev)
206815516c77SSepherosa Ziehau {
206915516c77SSepherosa Ziehau 
2070c2d50b26SSepherosa Ziehau 	if (VMBUS_PROBE_GUID(device_get_parent(dev), dev, &hn_guid) == 0) {
207115516c77SSepherosa Ziehau 		device_set_desc(dev, "Hyper-V Network Interface");
207215516c77SSepherosa Ziehau 		return BUS_PROBE_DEFAULT;
207315516c77SSepherosa Ziehau 	}
207415516c77SSepherosa Ziehau 	return ENXIO;
207515516c77SSepherosa Ziehau }
207615516c77SSepherosa Ziehau 
207715516c77SSepherosa Ziehau static int
207815516c77SSepherosa Ziehau hn_attach(device_t dev)
207915516c77SSepherosa Ziehau {
208015516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
208115516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
208215516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
208315516c77SSepherosa Ziehau 	uint8_t eaddr[ETHER_ADDR_LEN];
208415516c77SSepherosa Ziehau 	struct ifnet *ifp = NULL;
208515516c77SSepherosa Ziehau 	int error, ring_cnt, tx_ring_cnt;
2086eb2fe044SSepherosa Ziehau 	uint32_t mtu;
208715516c77SSepherosa Ziehau 
208815516c77SSepherosa Ziehau 	sc->hn_dev = dev;
208915516c77SSepherosa Ziehau 	sc->hn_prichan = vmbus_get_channel(dev);
209015516c77SSepherosa Ziehau 	HN_LOCK_INIT(sc);
20919c6cae24SSepherosa Ziehau 	rm_init(&sc->hn_vf_lock, "hnvf");
20929c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && hn_xpnt_vf_accbpf)
20939c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF;
209415516c77SSepherosa Ziehau 
209515516c77SSepherosa Ziehau 	/*
2096dc13fee6SSepherosa Ziehau 	 * Initialize these tunables once.
2097dc13fee6SSepherosa Ziehau 	 */
2098dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = hn_tx_agg_size;
2099dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = hn_tx_agg_pkts;
2100dc13fee6SSepherosa Ziehau 
2101dc13fee6SSepherosa Ziehau 	/*
210215516c77SSepherosa Ziehau 	 * Setup taskqueue for transmission.
210315516c77SSepherosa Ziehau 	 */
21040e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_INDEP) {
2105fdd0222aSSepherosa Ziehau 		int i;
2106fdd0222aSSepherosa Ziehau 
2107fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs =
2108fdd0222aSSepherosa Ziehau 		    malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
2109fdd0222aSSepherosa Ziehau 		    M_DEVBUF, M_WAITOK);
2110fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i) {
2111fdd0222aSSepherosa Ziehau 			sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx",
2112fdd0222aSSepherosa Ziehau 			    M_WAITOK, taskqueue_thread_enqueue,
2113fdd0222aSSepherosa Ziehau 			    &sc->hn_tx_taskqs[i]);
2114fdd0222aSSepherosa Ziehau 			taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET,
2115fdd0222aSSepherosa Ziehau 			    "%s tx%d", device_get_nameunit(dev), i);
2116fdd0222aSSepherosa Ziehau 		}
21170e11868dSSepherosa Ziehau 	} else if (hn_tx_taskq_mode == HN_TX_TASKQ_M_GLOBAL) {
2118fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs = hn_tx_taskque;
211915516c77SSepherosa Ziehau 	}
212015516c77SSepherosa Ziehau 
212115516c77SSepherosa Ziehau 	/*
212215516c77SSepherosa Ziehau 	 * Setup taskqueue for mangement tasks, e.g. link status.
212315516c77SSepherosa Ziehau 	 */
212415516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK,
212515516c77SSepherosa Ziehau 	    taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0);
212615516c77SSepherosa Ziehau 	taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
212715516c77SSepherosa Ziehau 	    device_get_nameunit(dev));
212815516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
212915516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc);
213015516c77SSepherosa Ziehau 	TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0,
213115516c77SSepherosa Ziehau 	    hn_netchg_status_taskfunc, sc);
213215516c77SSepherosa Ziehau 
21339c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
21349c6cae24SSepherosa Ziehau 		/*
21359c6cae24SSepherosa Ziehau 		 * Setup taskqueue for VF tasks, e.g. delayed VF bringing up.
21369c6cae24SSepherosa Ziehau 		 */
21379c6cae24SSepherosa Ziehau 		sc->hn_vf_taskq = taskqueue_create("hn_vf", M_WAITOK,
21389c6cae24SSepherosa Ziehau 		    taskqueue_thread_enqueue, &sc->hn_vf_taskq);
21399c6cae24SSepherosa Ziehau 		taskqueue_start_threads(&sc->hn_vf_taskq, 1, PI_NET, "%s vf",
21409c6cae24SSepherosa Ziehau 		    device_get_nameunit(dev));
21419c6cae24SSepherosa Ziehau 		TIMEOUT_TASK_INIT(sc->hn_vf_taskq, &sc->hn_vf_init, 0,
21429c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_init_taskfunc, sc);
21439c6cae24SSepherosa Ziehau 	}
21449c6cae24SSepherosa Ziehau 
214515516c77SSepherosa Ziehau 	/*
214615516c77SSepherosa Ziehau 	 * Allocate ifnet and setup its name earlier, so that if_printf
214715516c77SSepherosa Ziehau 	 * can be used by functions, which will be called after
214815516c77SSepherosa Ziehau 	 * ether_ifattach().
214915516c77SSepherosa Ziehau 	 */
215015516c77SSepherosa Ziehau 	ifp = sc->hn_ifp = if_alloc(IFT_ETHER);
215115516c77SSepherosa Ziehau 	ifp->if_softc = sc;
215215516c77SSepherosa Ziehau 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
215315516c77SSepherosa Ziehau 
215415516c77SSepherosa Ziehau 	/*
215515516c77SSepherosa Ziehau 	 * Initialize ifmedia earlier so that it can be unconditionally
215615516c77SSepherosa Ziehau 	 * destroyed, if error happened later on.
215715516c77SSepherosa Ziehau 	 */
215815516c77SSepherosa Ziehau 	ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts);
215915516c77SSepherosa Ziehau 
216015516c77SSepherosa Ziehau 	/*
216115516c77SSepherosa Ziehau 	 * Figure out the # of RX rings (ring_cnt) and the # of TX rings
216215516c77SSepherosa Ziehau 	 * to use (tx_ring_cnt).
216315516c77SSepherosa Ziehau 	 *
216415516c77SSepherosa Ziehau 	 * NOTE:
216515516c77SSepherosa Ziehau 	 * The # of RX rings to use is same as the # of channels to use.
216615516c77SSepherosa Ziehau 	 */
216715516c77SSepherosa Ziehau 	ring_cnt = hn_chan_cnt;
216815516c77SSepherosa Ziehau 	if (ring_cnt <= 0) {
216915516c77SSepherosa Ziehau 		/* Default */
217015516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
217115516c77SSepherosa Ziehau 		if (ring_cnt > HN_RING_CNT_DEF_MAX)
217215516c77SSepherosa Ziehau 			ring_cnt = HN_RING_CNT_DEF_MAX;
217315516c77SSepherosa Ziehau 	} else if (ring_cnt > mp_ncpus) {
217415516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
217515516c77SSepherosa Ziehau 	}
217634d68912SSepherosa Ziehau #ifdef RSS
217734d68912SSepherosa Ziehau 	if (ring_cnt > rss_getnumbuckets())
217834d68912SSepherosa Ziehau 		ring_cnt = rss_getnumbuckets();
217934d68912SSepherosa Ziehau #endif
218015516c77SSepherosa Ziehau 
218115516c77SSepherosa Ziehau 	tx_ring_cnt = hn_tx_ring_cnt;
218215516c77SSepherosa Ziehau 	if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt)
218315516c77SSepherosa Ziehau 		tx_ring_cnt = ring_cnt;
218423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
218515516c77SSepherosa Ziehau 	if (hn_use_if_start) {
218615516c77SSepherosa Ziehau 		/* ifnet.if_start only needs one TX ring. */
218715516c77SSepherosa Ziehau 		tx_ring_cnt = 1;
218815516c77SSepherosa Ziehau 	}
218923bf9e15SSepherosa Ziehau #endif
219015516c77SSepherosa Ziehau 
219115516c77SSepherosa Ziehau 	/*
219215516c77SSepherosa Ziehau 	 * Set the leader CPU for channels.
219315516c77SSepherosa Ziehau 	 */
219415516c77SSepherosa Ziehau 	sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus;
219515516c77SSepherosa Ziehau 
219615516c77SSepherosa Ziehau 	/*
219715516c77SSepherosa Ziehau 	 * Create enough TX/RX rings, even if only limited number of
219815516c77SSepherosa Ziehau 	 * channels can be allocated.
219915516c77SSepherosa Ziehau 	 */
220015516c77SSepherosa Ziehau 	error = hn_create_tx_data(sc, tx_ring_cnt);
220115516c77SSepherosa Ziehau 	if (error)
220215516c77SSepherosa Ziehau 		goto failed;
220315516c77SSepherosa Ziehau 	error = hn_create_rx_data(sc, ring_cnt);
220415516c77SSepherosa Ziehau 	if (error)
220515516c77SSepherosa Ziehau 		goto failed;
220615516c77SSepherosa Ziehau 
220715516c77SSepherosa Ziehau 	/*
220815516c77SSepherosa Ziehau 	 * Create transaction context for NVS and RNDIS transactions.
220915516c77SSepherosa Ziehau 	 */
221015516c77SSepherosa Ziehau 	sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
221115516c77SSepherosa Ziehau 	    HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
221225641fc7SSepherosa Ziehau 	if (sc->hn_xact == NULL) {
221325641fc7SSepherosa Ziehau 		error = ENXIO;
221415516c77SSepherosa Ziehau 		goto failed;
221525641fc7SSepherosa Ziehau 	}
221625641fc7SSepherosa Ziehau 
221725641fc7SSepherosa Ziehau 	/*
221825641fc7SSepherosa Ziehau 	 * Install orphan handler for the revocation of this device's
221925641fc7SSepherosa Ziehau 	 * primary channel.
222025641fc7SSepherosa Ziehau 	 *
222125641fc7SSepherosa Ziehau 	 * NOTE:
222225641fc7SSepherosa Ziehau 	 * The processing order is critical here:
222325641fc7SSepherosa Ziehau 	 * Install the orphan handler, _before_ testing whether this
222425641fc7SSepherosa Ziehau 	 * device's primary channel has been revoked or not.
222525641fc7SSepherosa Ziehau 	 */
222625641fc7SSepherosa Ziehau 	vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact);
222725641fc7SSepherosa Ziehau 	if (vmbus_chan_is_revoked(sc->hn_prichan)) {
222825641fc7SSepherosa Ziehau 		error = ENXIO;
222925641fc7SSepherosa Ziehau 		goto failed;
223025641fc7SSepherosa Ziehau 	}
223115516c77SSepherosa Ziehau 
223215516c77SSepherosa Ziehau 	/*
223315516c77SSepherosa Ziehau 	 * Attach the synthetic parts, i.e. NVS and RNDIS.
223415516c77SSepherosa Ziehau 	 */
223515516c77SSepherosa Ziehau 	error = hn_synth_attach(sc, ETHERMTU);
223615516c77SSepherosa Ziehau 	if (error)
223715516c77SSepherosa Ziehau 		goto failed;
223815516c77SSepherosa Ziehau 
223915516c77SSepherosa Ziehau 	error = hn_rndis_get_eaddr(sc, eaddr);
224015516c77SSepherosa Ziehau 	if (error)
224115516c77SSepherosa Ziehau 		goto failed;
224215516c77SSepherosa Ziehau 
2243eb2fe044SSepherosa Ziehau 	error = hn_rndis_get_mtu(sc, &mtu);
2244eb2fe044SSepherosa Ziehau 	if (error)
2245eb2fe044SSepherosa Ziehau 		mtu = ETHERMTU;
2246eb2fe044SSepherosa Ziehau 	else if (bootverbose)
2247eb2fe044SSepherosa Ziehau 		device_printf(dev, "RNDIS mtu %u\n", mtu);
2248eb2fe044SSepherosa Ziehau 
224915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
225015516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
225115516c77SSepherosa Ziehau 		/*
225215516c77SSepherosa Ziehau 		 * Reduce TCP segment aggregation limit for multiple
225315516c77SSepherosa Ziehau 		 * RX rings to increase ACK timeliness.
225415516c77SSepherosa Ziehau 		 */
225515516c77SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF);
225615516c77SSepherosa Ziehau 	}
225715516c77SSepherosa Ziehau #endif
225815516c77SSepherosa Ziehau 
225915516c77SSepherosa Ziehau 	/*
2260db76829bSSepherosa Ziehau 	 * Fixup TX/RX stuffs after synthetic parts are attached.
226115516c77SSepherosa Ziehau 	 */
226215516c77SSepherosa Ziehau 	hn_fixup_tx_data(sc);
2263db76829bSSepherosa Ziehau 	hn_fixup_rx_data(sc);
226415516c77SSepherosa Ziehau 
226515516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
226615516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
226715516c77SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD,
226815516c77SSepherosa Ziehau 	    &sc->hn_nvs_ver, 0, "NVS version");
226915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version",
227015516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
227115516c77SSepherosa Ziehau 	    hn_ndis_version_sysctl, "A", "NDIS version");
227215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps",
227315516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
227415516c77SSepherosa Ziehau 	    hn_caps_sysctl, "A", "capabilities");
227515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist",
227615516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
227715516c77SSepherosa Ziehau 	    hn_hwassist_sysctl, "A", "hwassist");
22789c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_max",
22799c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomax, 0, "max TSO size");
22809c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegcnt",
22819c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomaxsegcount, 0,
22829c6cae24SSepherosa Ziehau 	    "max # of TSO segments");
22839c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegsz",
22849c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomaxsegsize, 0,
22859c6cae24SSepherosa Ziehau 	    "max size of TSO segment");
228615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter",
228715516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
228815516c77SSepherosa Ziehau 	    hn_rxfilter_sysctl, "A", "rxfilter");
228915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash",
229015516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
229115516c77SSepherosa Ziehau 	    hn_rss_hash_sysctl, "A", "RSS hash");
2292642ec226SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hashcap",
2293642ec226SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2294642ec226SSepherosa Ziehau 	    hn_rss_hcap_sysctl, "A", "RSS hash capabilities");
2295642ec226SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "mbuf_hash",
2296642ec226SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2297642ec226SSepherosa Ziehau 	    hn_rss_mbuf_sysctl, "A", "RSS hash for mbufs");
229815516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size",
229915516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count");
230034d68912SSepherosa Ziehau #ifndef RSS
230134d68912SSepherosa Ziehau 	/*
230234d68912SSepherosa Ziehau 	 * Don't allow RSS key/indirect table changes, if RSS is defined.
230334d68912SSepherosa Ziehau 	 */
230415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key",
230515516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
230615516c77SSepherosa Ziehau 	    hn_rss_key_sysctl, "IU", "RSS key");
230715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind",
230815516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
230915516c77SSepherosa Ziehau 	    hn_rss_ind_sysctl, "IU", "RSS indirect table");
231034d68912SSepherosa Ziehau #endif
2311dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size",
2312dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_size, 0,
2313dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation size limit");
2314dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts",
2315dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0,
2316dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation count limit");
2317dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align",
2318dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_align, 0,
2319dc13fee6SSepherosa Ziehau 	    "RNDIS packet transmission aggregation alignment");
2320dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size",
2321dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
2322dc13fee6SSepherosa Ziehau 	    hn_txagg_size_sysctl, "I",
2323dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation size, 0 -- disable, -1 -- auto");
2324dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts",
2325dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
2326dc13fee6SSepherosa Ziehau 	    hn_txagg_pkts_sysctl, "I",
2327dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation packets, "
2328dc13fee6SSepherosa Ziehau 	    "0 -- disable, -1 -- auto");
23296c1204dfSSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "polling",
23306c1204dfSSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
23316c1204dfSSepherosa Ziehau 	    hn_polling_sysctl, "I",
23326c1204dfSSepherosa Ziehau 	    "Polling frequency: [100,1000000], 0 disable polling");
233340d60d6eSDexuan Cui 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf",
233440d60d6eSDexuan Cui 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
233540d60d6eSDexuan Cui 	    hn_vf_sysctl, "A", "Virtual Function's name");
23369c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf) {
2337499c3e17SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxvf",
2338499c3e17SSepherosa Ziehau 		    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2339499c3e17SSepherosa Ziehau 		    hn_rxvf_sysctl, "A", "activated Virtual Function's name");
23409c6cae24SSepherosa Ziehau 	} else {
23419c6cae24SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_enabled",
23429c6cae24SSepherosa Ziehau 		    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
23439c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_enabled_sysctl, "I",
23449c6cae24SSepherosa Ziehau 		    "Transparent VF enabled");
23459c6cae24SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_accbpf",
23469c6cae24SSepherosa Ziehau 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
23479c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_accbpf_sysctl, "I",
23489c6cae24SSepherosa Ziehau 		    "Accurate BPF for transparent VF");
23499c6cae24SSepherosa Ziehau 	}
235015516c77SSepherosa Ziehau 
235115516c77SSepherosa Ziehau 	/*
235215516c77SSepherosa Ziehau 	 * Setup the ifmedia, which has been initialized earlier.
235315516c77SSepherosa Ziehau 	 */
235415516c77SSepherosa Ziehau 	ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL);
235515516c77SSepherosa Ziehau 	ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO);
235615516c77SSepherosa Ziehau 	/* XXX ifmedia_set really should do this for us */
235715516c77SSepherosa Ziehau 	sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media;
235815516c77SSepherosa Ziehau 
235915516c77SSepherosa Ziehau 	/*
236015516c77SSepherosa Ziehau 	 * Setup the ifnet for this interface.
236115516c77SSepherosa Ziehau 	 */
236215516c77SSepherosa Ziehau 
236315516c77SSepherosa Ziehau 	ifp->if_baudrate = IF_Gbps(10);
236415516c77SSepherosa Ziehau 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
236515516c77SSepherosa Ziehau 	ifp->if_ioctl = hn_ioctl;
236615516c77SSepherosa Ziehau 	ifp->if_init = hn_init;
236723bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
236815516c77SSepherosa Ziehau 	if (hn_use_if_start) {
236915516c77SSepherosa Ziehau 		int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]);
237015516c77SSepherosa Ziehau 
237115516c77SSepherosa Ziehau 		ifp->if_start = hn_start;
237215516c77SSepherosa Ziehau 		IFQ_SET_MAXLEN(&ifp->if_snd, qdepth);
237315516c77SSepherosa Ziehau 		ifp->if_snd.ifq_drv_maxlen = qdepth - 1;
237415516c77SSepherosa Ziehau 		IFQ_SET_READY(&ifp->if_snd);
237523bf9e15SSepherosa Ziehau 	} else
237623bf9e15SSepherosa Ziehau #endif
237723bf9e15SSepherosa Ziehau 	{
237815516c77SSepherosa Ziehau 		ifp->if_transmit = hn_transmit;
237915516c77SSepherosa Ziehau 		ifp->if_qflush = hn_xmit_qflush;
238015516c77SSepherosa Ziehau 	}
238115516c77SSepherosa Ziehau 
23829c6cae24SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO | IFCAP_LINKSTATE;
238315516c77SSepherosa Ziehau #ifdef foo
238415516c77SSepherosa Ziehau 	/* We can't diff IPv6 packets from IPv4 packets on RX path. */
238515516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM_IPV6;
238615516c77SSepherosa Ziehau #endif
238715516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_VLAN) {
238815516c77SSepherosa Ziehau 		/* XXX not sure about VLAN_MTU. */
238915516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
239015516c77SSepherosa Ziehau 	}
239115516c77SSepherosa Ziehau 
239215516c77SSepherosa Ziehau 	ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist;
239315516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP_MASK)
239415516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM;
239515516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP6_MASK)
239615516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM_IPV6;
239715516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO4) {
239815516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO4;
239915516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP_TSO;
240015516c77SSepherosa Ziehau 	}
240115516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO6) {
240215516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO6;
240315516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP6_TSO;
240415516c77SSepherosa Ziehau 	}
240515516c77SSepherosa Ziehau 
240615516c77SSepherosa Ziehau 	/* Enable all available capabilities by default. */
240715516c77SSepherosa Ziehau 	ifp->if_capenable = ifp->if_capabilities;
240815516c77SSepherosa Ziehau 
24097960e6baSSepherosa Ziehau 	/*
24107960e6baSSepherosa Ziehau 	 * Disable IPv6 TSO and TXCSUM by default, they still can
24117960e6baSSepherosa Ziehau 	 * be enabled through SIOCSIFCAP.
24127960e6baSSepherosa Ziehau 	 */
24137960e6baSSepherosa Ziehau 	ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
24147960e6baSSepherosa Ziehau 	ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO);
24157960e6baSSepherosa Ziehau 
241615516c77SSepherosa Ziehau 	if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) {
24179c6cae24SSepherosa Ziehau 		/*
24189c6cae24SSepherosa Ziehau 		 * Lock hn_set_tso_maxsize() to simplify its
24199c6cae24SSepherosa Ziehau 		 * internal logic.
24209c6cae24SSepherosa Ziehau 		 */
24219c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
242215516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU);
24239c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
242415516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX;
242515516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = PAGE_SIZE;
242615516c77SSepherosa Ziehau 	}
242715516c77SSepherosa Ziehau 
242815516c77SSepherosa Ziehau 	ether_ifattach(ifp, eaddr);
242915516c77SSepherosa Ziehau 
243015516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) {
243115516c77SSepherosa Ziehau 		if_printf(ifp, "TSO segcnt %u segsz %u\n",
243215516c77SSepherosa Ziehau 		    ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize);
243315516c77SSepherosa Ziehau 	}
2434eb2fe044SSepherosa Ziehau 	if (mtu < ETHERMTU) {
2435eb2fe044SSepherosa Ziehau 		if_printf(ifp, "fixup mtu %u -> %u\n", ifp->if_mtu, mtu);
2436eb2fe044SSepherosa Ziehau 		ifp->if_mtu = mtu;
2437eb2fe044SSepherosa Ziehau 	}
243815516c77SSepherosa Ziehau 
243915516c77SSepherosa Ziehau 	/* Inform the upper layer about the long frame support. */
244015516c77SSepherosa Ziehau 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
244115516c77SSepherosa Ziehau 
244215516c77SSepherosa Ziehau 	/*
244315516c77SSepherosa Ziehau 	 * Kick off link status check.
244415516c77SSepherosa Ziehau 	 */
244515516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
244615516c77SSepherosa Ziehau 	hn_update_link_status(sc);
244715516c77SSepherosa Ziehau 
24489c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf) {
24495bdfd3fdSDexuan Cui 		sc->hn_ifnet_evthand = EVENTHANDLER_REGISTER(ifnet_event,
24505bdfd3fdSDexuan Cui 		    hn_ifnet_event, sc, EVENTHANDLER_PRI_ANY);
24515bdfd3fdSDexuan Cui 		sc->hn_ifaddr_evthand = EVENTHANDLER_REGISTER(ifaddr_event,
24525bdfd3fdSDexuan Cui 		    hn_ifaddr_event, sc, EVENTHANDLER_PRI_ANY);
24539c6cae24SSepherosa Ziehau 	} else {
24549c6cae24SSepherosa Ziehau 		sc->hn_ifnet_lnkhand = EVENTHANDLER_REGISTER(ifnet_link_event,
24559c6cae24SSepherosa Ziehau 		    hn_ifnet_lnkevent, sc, EVENTHANDLER_PRI_ANY);
24569c6cae24SSepherosa Ziehau 	}
24575bdfd3fdSDexuan Cui 
2458f41e0df4SSepherosa Ziehau 	/*
2459f41e0df4SSepherosa Ziehau 	 * NOTE:
2460f41e0df4SSepherosa Ziehau 	 * Subscribe ether_ifattach event, instead of ifnet_arrival event,
2461f41e0df4SSepherosa Ziehau 	 * since interface's LLADDR is needed; interface LLADDR is not
2462f41e0df4SSepherosa Ziehau 	 * available when ifnet_arrival event is triggered.
2463f41e0df4SSepherosa Ziehau 	 */
2464499c3e17SSepherosa Ziehau 	sc->hn_ifnet_atthand = EVENTHANDLER_REGISTER(ether_ifattach_event,
2465499c3e17SSepherosa Ziehau 	    hn_ifnet_attevent, sc, EVENTHANDLER_PRI_ANY);
2466499c3e17SSepherosa Ziehau 	sc->hn_ifnet_dethand = EVENTHANDLER_REGISTER(ifnet_departure_event,
2467499c3e17SSepherosa Ziehau 	    hn_ifnet_detevent, sc, EVENTHANDLER_PRI_ANY);
2468499c3e17SSepherosa Ziehau 
246915516c77SSepherosa Ziehau 	return (0);
247015516c77SSepherosa Ziehau failed:
247115516c77SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)
247215516c77SSepherosa Ziehau 		hn_synth_detach(sc);
247315516c77SSepherosa Ziehau 	hn_detach(dev);
247415516c77SSepherosa Ziehau 	return (error);
247515516c77SSepherosa Ziehau }
247615516c77SSepherosa Ziehau 
247715516c77SSepherosa Ziehau static int
247815516c77SSepherosa Ziehau hn_detach(device_t dev)
247915516c77SSepherosa Ziehau {
248015516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
2481499c3e17SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp, *vf_ifp;
248215516c77SSepherosa Ziehau 
24839c6cae24SSepherosa Ziehau 	if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) {
24849c6cae24SSepherosa Ziehau 		/*
24859c6cae24SSepherosa Ziehau 		 * In case that the vmbus missed the orphan handler
24869c6cae24SSepherosa Ziehau 		 * installation.
24879c6cae24SSepherosa Ziehau 		 */
24889c6cae24SSepherosa Ziehau 		vmbus_xact_ctx_orphan(sc->hn_xact);
24899c6cae24SSepherosa Ziehau 	}
24909c6cae24SSepherosa Ziehau 
24915bdfd3fdSDexuan Cui 	if (sc->hn_ifaddr_evthand != NULL)
24925bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifaddr_event, sc->hn_ifaddr_evthand);
24935bdfd3fdSDexuan Cui 	if (sc->hn_ifnet_evthand != NULL)
24945bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifnet_event, sc->hn_ifnet_evthand);
2495499c3e17SSepherosa Ziehau 	if (sc->hn_ifnet_atthand != NULL) {
2496499c3e17SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ether_ifattach_event,
2497499c3e17SSepherosa Ziehau 		    sc->hn_ifnet_atthand);
2498499c3e17SSepherosa Ziehau 	}
2499499c3e17SSepherosa Ziehau 	if (sc->hn_ifnet_dethand != NULL) {
2500499c3e17SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ifnet_departure_event,
2501499c3e17SSepherosa Ziehau 		    sc->hn_ifnet_dethand);
2502499c3e17SSepherosa Ziehau 	}
25039c6cae24SSepherosa Ziehau 	if (sc->hn_ifnet_lnkhand != NULL)
25049c6cae24SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ifnet_link_event, sc->hn_ifnet_lnkhand);
2505499c3e17SSepherosa Ziehau 
2506499c3e17SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
2507499c3e17SSepherosa Ziehau 	__compiler_membar();
2508499c3e17SSepherosa Ziehau 	if (vf_ifp != NULL)
2509499c3e17SSepherosa Ziehau 		hn_ifnet_detevent(sc, vf_ifp);
25105bdfd3fdSDexuan Cui 
251115516c77SSepherosa Ziehau 	if (device_is_attached(dev)) {
251215516c77SSepherosa Ziehau 		HN_LOCK(sc);
251315516c77SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
251415516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
25155bdfd3fdSDexuan Cui 				hn_stop(sc, true);
251615516c77SSepherosa Ziehau 			/*
251715516c77SSepherosa Ziehau 			 * NOTE:
251815516c77SSepherosa Ziehau 			 * hn_stop() only suspends data, so managment
251915516c77SSepherosa Ziehau 			 * stuffs have to be suspended manually here.
252015516c77SSepherosa Ziehau 			 */
252115516c77SSepherosa Ziehau 			hn_suspend_mgmt(sc);
252215516c77SSepherosa Ziehau 			hn_synth_detach(sc);
252315516c77SSepherosa Ziehau 		}
252415516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
252515516c77SSepherosa Ziehau 		ether_ifdetach(ifp);
252615516c77SSepherosa Ziehau 	}
252715516c77SSepherosa Ziehau 
252815516c77SSepherosa Ziehau 	ifmedia_removeall(&sc->hn_media);
252915516c77SSepherosa Ziehau 	hn_destroy_rx_data(sc);
253015516c77SSepherosa Ziehau 	hn_destroy_tx_data(sc);
253115516c77SSepherosa Ziehau 
25320e11868dSSepherosa Ziehau 	if (sc->hn_tx_taskqs != NULL && sc->hn_tx_taskqs != hn_tx_taskque) {
2533fdd0222aSSepherosa Ziehau 		int i;
2534fdd0222aSSepherosa Ziehau 
2535fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
2536fdd0222aSSepherosa Ziehau 			taskqueue_free(sc->hn_tx_taskqs[i]);
2537fdd0222aSSepherosa Ziehau 		free(sc->hn_tx_taskqs, M_DEVBUF);
2538fdd0222aSSepherosa Ziehau 	}
253915516c77SSepherosa Ziehau 	taskqueue_free(sc->hn_mgmt_taskq0);
25409c6cae24SSepherosa Ziehau 	if (sc->hn_vf_taskq != NULL)
25419c6cae24SSepherosa Ziehau 		taskqueue_free(sc->hn_vf_taskq);
254215516c77SSepherosa Ziehau 
254325641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL) {
254425641fc7SSepherosa Ziehau 		/*
254525641fc7SSepherosa Ziehau 		 * Uninstall the orphan handler _before_ the xact is
254625641fc7SSepherosa Ziehau 		 * destructed.
254725641fc7SSepherosa Ziehau 		 */
254825641fc7SSepherosa Ziehau 		vmbus_chan_unset_orphan(sc->hn_prichan);
254915516c77SSepherosa Ziehau 		vmbus_xact_ctx_destroy(sc->hn_xact);
255025641fc7SSepherosa Ziehau 	}
255115516c77SSepherosa Ziehau 
255215516c77SSepherosa Ziehau 	if_free(ifp);
255315516c77SSepherosa Ziehau 
255415516c77SSepherosa Ziehau 	HN_LOCK_DESTROY(sc);
25559c6cae24SSepherosa Ziehau 	rm_destroy(&sc->hn_vf_lock);
255615516c77SSepherosa Ziehau 	return (0);
255715516c77SSepherosa Ziehau }
255815516c77SSepherosa Ziehau 
255915516c77SSepherosa Ziehau static int
256015516c77SSepherosa Ziehau hn_shutdown(device_t dev)
256115516c77SSepherosa Ziehau {
256215516c77SSepherosa Ziehau 
256315516c77SSepherosa Ziehau 	return (0);
256415516c77SSepherosa Ziehau }
256515516c77SSepherosa Ziehau 
256615516c77SSepherosa Ziehau static void
256715516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc)
256815516c77SSepherosa Ziehau {
256915516c77SSepherosa Ziehau 	uint32_t link_status;
257015516c77SSepherosa Ziehau 	int error;
257115516c77SSepherosa Ziehau 
257215516c77SSepherosa Ziehau 	error = hn_rndis_get_linkstatus(sc, &link_status);
257315516c77SSepherosa Ziehau 	if (error) {
257415516c77SSepherosa Ziehau 		/* XXX what to do? */
257515516c77SSepherosa Ziehau 		return;
257615516c77SSepherosa Ziehau 	}
257715516c77SSepherosa Ziehau 
257815516c77SSepherosa Ziehau 	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
257915516c77SSepherosa Ziehau 		sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
258015516c77SSepherosa Ziehau 	else
258115516c77SSepherosa Ziehau 		sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
258215516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp,
258315516c77SSepherosa Ziehau 	    (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ?
258415516c77SSepherosa Ziehau 	    LINK_STATE_UP : LINK_STATE_DOWN);
258515516c77SSepherosa Ziehau }
258615516c77SSepherosa Ziehau 
258715516c77SSepherosa Ziehau static void
258815516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused)
258915516c77SSepherosa Ziehau {
259015516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
259115516c77SSepherosa Ziehau 
259215516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
259315516c77SSepherosa Ziehau 		return;
259415516c77SSepherosa Ziehau 	hn_link_status(sc);
259515516c77SSepherosa Ziehau }
259615516c77SSepherosa Ziehau 
259715516c77SSepherosa Ziehau static void
259815516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused)
259915516c77SSepherosa Ziehau {
260015516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
260115516c77SSepherosa Ziehau 
260215516c77SSepherosa Ziehau 	/* Prevent any link status checks from running. */
260315516c77SSepherosa Ziehau 	sc->hn_link_flags |= HN_LINK_FLAG_NETCHG;
260415516c77SSepherosa Ziehau 
260515516c77SSepherosa Ziehau 	/*
260615516c77SSepherosa Ziehau 	 * Fake up a [link down --> link up] state change; 5 seconds
260715516c77SSepherosa Ziehau 	 * delay is used, which closely simulates miibus reaction
260815516c77SSepherosa Ziehau 	 * upon link down event.
260915516c77SSepherosa Ziehau 	 */
261015516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
261115516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
261215516c77SSepherosa Ziehau 	taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0,
261315516c77SSepherosa Ziehau 	    &sc->hn_netchg_status, 5 * hz);
261415516c77SSepherosa Ziehau }
261515516c77SSepherosa Ziehau 
261615516c77SSepherosa Ziehau static void
261715516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused)
261815516c77SSepherosa Ziehau {
261915516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
262015516c77SSepherosa Ziehau 
262115516c77SSepherosa Ziehau 	/* Re-allow link status checks. */
262215516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG;
262315516c77SSepherosa Ziehau 	hn_link_status(sc);
262415516c77SSepherosa Ziehau }
262515516c77SSepherosa Ziehau 
262615516c77SSepherosa Ziehau static void
262715516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc)
262815516c77SSepherosa Ziehau {
262915516c77SSepherosa Ziehau 
263015516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
263115516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
263215516c77SSepherosa Ziehau }
263315516c77SSepherosa Ziehau 
263415516c77SSepherosa Ziehau static void
263515516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc)
263615516c77SSepherosa Ziehau {
263715516c77SSepherosa Ziehau 
263815516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
263915516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init);
264015516c77SSepherosa Ziehau }
264115516c77SSepherosa Ziehau 
264215516c77SSepherosa Ziehau static __inline int
264315516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
264415516c77SSepherosa Ziehau     struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
264515516c77SSepherosa Ziehau {
264615516c77SSepherosa Ziehau 	struct mbuf *m = *m_head;
264715516c77SSepherosa Ziehau 	int error;
264815516c77SSepherosa Ziehau 
264915516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim"));
265015516c77SSepherosa Ziehau 
265115516c77SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap,
265215516c77SSepherosa Ziehau 	    m, segs, nsegs, BUS_DMA_NOWAIT);
265315516c77SSepherosa Ziehau 	if (error == EFBIG) {
265415516c77SSepherosa Ziehau 		struct mbuf *m_new;
265515516c77SSepherosa Ziehau 
265615516c77SSepherosa Ziehau 		m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX);
265715516c77SSepherosa Ziehau 		if (m_new == NULL)
265815516c77SSepherosa Ziehau 			return ENOBUFS;
265915516c77SSepherosa Ziehau 		else
266015516c77SSepherosa Ziehau 			*m_head = m = m_new;
266115516c77SSepherosa Ziehau 		txr->hn_tx_collapsed++;
266215516c77SSepherosa Ziehau 
266315516c77SSepherosa Ziehau 		error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag,
266415516c77SSepherosa Ziehau 		    txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT);
266515516c77SSepherosa Ziehau 	}
266615516c77SSepherosa Ziehau 	if (!error) {
266715516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap,
266815516c77SSepherosa Ziehau 		    BUS_DMASYNC_PREWRITE);
266915516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_DMAMAP;
267015516c77SSepherosa Ziehau 	}
267115516c77SSepherosa Ziehau 	return error;
267215516c77SSepherosa Ziehau }
267315516c77SSepherosa Ziehau 
267415516c77SSepherosa Ziehau static __inline int
267515516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd)
267615516c77SSepherosa Ziehau {
267715516c77SSepherosa Ziehau 
267815516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0,
267915516c77SSepherosa Ziehau 	    ("put an onlist txd %#x", txd->flags));
2680dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2681dc13fee6SSepherosa Ziehau 	    ("put an onagg txd %#x", txd->flags));
268215516c77SSepherosa Ziehau 
268315516c77SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
268415516c77SSepherosa Ziehau 	if (atomic_fetchadd_int(&txd->refs, -1) != 1)
268515516c77SSepherosa Ziehau 		return 0;
268615516c77SSepherosa Ziehau 
2687dc13fee6SSepherosa Ziehau 	if (!STAILQ_EMPTY(&txd->agg_list)) {
2688dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tmp_txd;
2689dc13fee6SSepherosa Ziehau 
2690dc13fee6SSepherosa Ziehau 		while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) {
2691dc13fee6SSepherosa Ziehau 			int freed;
2692dc13fee6SSepherosa Ziehau 
2693dc13fee6SSepherosa Ziehau 			KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list),
2694dc13fee6SSepherosa Ziehau 			    ("resursive aggregation on aggregated txdesc"));
2695dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG),
2696dc13fee6SSepherosa Ziehau 			    ("not aggregated txdesc"));
2697dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
2698dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc uses dmamap"));
2699dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
2700dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc consumes "
2701dc13fee6SSepherosa Ziehau 			     "chimney sending buffer"));
2702dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_size == 0,
2703dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc has non-zero "
2704dc13fee6SSepherosa Ziehau 			     "chimney sending size"));
2705dc13fee6SSepherosa Ziehau 
2706dc13fee6SSepherosa Ziehau 			STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link);
2707dc13fee6SSepherosa Ziehau 			tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG;
2708dc13fee6SSepherosa Ziehau 			freed = hn_txdesc_put(txr, tmp_txd);
2709dc13fee6SSepherosa Ziehau 			KASSERT(freed, ("failed to free aggregated txdesc"));
2710dc13fee6SSepherosa Ziehau 		}
2711dc13fee6SSepherosa Ziehau 	}
2712dc13fee6SSepherosa Ziehau 
271315516c77SSepherosa Ziehau 	if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) {
271415516c77SSepherosa Ziehau 		KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
271515516c77SSepherosa Ziehau 		    ("chim txd uses dmamap"));
271615516c77SSepherosa Ziehau 		hn_chim_free(txr->hn_sc, txd->chim_index);
271715516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
2718dc13fee6SSepherosa Ziehau 		txd->chim_size = 0;
271915516c77SSepherosa Ziehau 	} else if (txd->flags & HN_TXD_FLAG_DMAMAP) {
272015516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag,
272115516c77SSepherosa Ziehau 		    txd->data_dmap, BUS_DMASYNC_POSTWRITE);
272215516c77SSepherosa Ziehau 		bus_dmamap_unload(txr->hn_tx_data_dtag,
272315516c77SSepherosa Ziehau 		    txd->data_dmap);
272415516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_DMAMAP;
272515516c77SSepherosa Ziehau 	}
272615516c77SSepherosa Ziehau 
272715516c77SSepherosa Ziehau 	if (txd->m != NULL) {
272815516c77SSepherosa Ziehau 		m_freem(txd->m);
272915516c77SSepherosa Ziehau 		txd->m = NULL;
273015516c77SSepherosa Ziehau 	}
273115516c77SSepherosa Ziehau 
273215516c77SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONLIST;
273315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
273415516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
273515516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_avail >= 0 &&
273615516c77SSepherosa Ziehau 	    txr->hn_txdesc_avail < txr->hn_txdesc_cnt,
273715516c77SSepherosa Ziehau 	    ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail));
273815516c77SSepherosa Ziehau 	txr->hn_txdesc_avail++;
273915516c77SSepherosa Ziehau 	SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
274015516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
274185e4ae1eSSepherosa Ziehau #else	/* HN_USE_TXDESC_BUFRING */
274285e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
274315516c77SSepherosa Ziehau 	atomic_add_int(&txr->hn_txdesc_avail, 1);
274415516c77SSepherosa Ziehau #endif
274585e4ae1eSSepherosa Ziehau 	buf_ring_enqueue(txr->hn_txdesc_br, txd);
274685e4ae1eSSepherosa Ziehau #endif	/* !HN_USE_TXDESC_BUFRING */
274715516c77SSepherosa Ziehau 
274815516c77SSepherosa Ziehau 	return 1;
274915516c77SSepherosa Ziehau }
275015516c77SSepherosa Ziehau 
275115516c77SSepherosa Ziehau static __inline struct hn_txdesc *
275215516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr)
275315516c77SSepherosa Ziehau {
275415516c77SSepherosa Ziehau 	struct hn_txdesc *txd;
275515516c77SSepherosa Ziehau 
275615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
275715516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
275815516c77SSepherosa Ziehau 	txd = SLIST_FIRST(&txr->hn_txlist);
275915516c77SSepherosa Ziehau 	if (txd != NULL) {
276015516c77SSepherosa Ziehau 		KASSERT(txr->hn_txdesc_avail > 0,
276115516c77SSepherosa Ziehau 		    ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail));
276215516c77SSepherosa Ziehau 		txr->hn_txdesc_avail--;
276315516c77SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&txr->hn_txlist, link);
276415516c77SSepherosa Ziehau 	}
276515516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
276615516c77SSepherosa Ziehau #else
276715516c77SSepherosa Ziehau 	txd = buf_ring_dequeue_sc(txr->hn_txdesc_br);
276815516c77SSepherosa Ziehau #endif
276915516c77SSepherosa Ziehau 
277015516c77SSepherosa Ziehau 	if (txd != NULL) {
277115516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
277285e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
277315516c77SSepherosa Ziehau 		atomic_subtract_int(&txr->hn_txdesc_avail, 1);
277415516c77SSepherosa Ziehau #endif
277585e4ae1eSSepherosa Ziehau #endif	/* HN_USE_TXDESC_BUFRING */
277615516c77SSepherosa Ziehau 		KASSERT(txd->m == NULL && txd->refs == 0 &&
2777dc13fee6SSepherosa Ziehau 		    STAILQ_EMPTY(&txd->agg_list) &&
277815516c77SSepherosa Ziehau 		    txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
2779dc13fee6SSepherosa Ziehau 		    txd->chim_size == 0 &&
278015516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONLIST) &&
2781dc13fee6SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONAGG) == 0 &&
278215516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd"));
278315516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_ONLIST;
278415516c77SSepherosa Ziehau 		txd->refs = 1;
278515516c77SSepherosa Ziehau 	}
278615516c77SSepherosa Ziehau 	return txd;
278715516c77SSepherosa Ziehau }
278815516c77SSepherosa Ziehau 
278915516c77SSepherosa Ziehau static __inline void
279015516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd)
279115516c77SSepherosa Ziehau {
279215516c77SSepherosa Ziehau 
279315516c77SSepherosa Ziehau 	/* 0->1 transition will never work */
279425641fc7SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
279515516c77SSepherosa Ziehau 	atomic_add_int(&txd->refs, 1);
279615516c77SSepherosa Ziehau }
279715516c77SSepherosa Ziehau 
2798dc13fee6SSepherosa Ziehau static __inline void
2799dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd)
2800dc13fee6SSepherosa Ziehau {
2801dc13fee6SSepherosa Ziehau 
2802dc13fee6SSepherosa Ziehau 	KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2803dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on aggregating txdesc"));
2804dc13fee6SSepherosa Ziehau 
2805dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2806dc13fee6SSepherosa Ziehau 	    ("already aggregated"));
2807dc13fee6SSepherosa Ziehau 	KASSERT(STAILQ_EMPTY(&txd->agg_list),
2808dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on to-be-aggregated txdesc"));
2809dc13fee6SSepherosa Ziehau 
2810dc13fee6SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONAGG;
2811dc13fee6SSepherosa Ziehau 	STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link);
2812dc13fee6SSepherosa Ziehau }
2813dc13fee6SSepherosa Ziehau 
281415516c77SSepherosa Ziehau static bool
281515516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr)
281615516c77SSepherosa Ziehau {
281715516c77SSepherosa Ziehau 	bool pending = false;
281815516c77SSepherosa Ziehau 
281915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
282015516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
282115516c77SSepherosa Ziehau 	if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt)
282215516c77SSepherosa Ziehau 		pending = true;
282315516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
282415516c77SSepherosa Ziehau #else
282515516c77SSepherosa Ziehau 	if (!buf_ring_full(txr->hn_txdesc_br))
282615516c77SSepherosa Ziehau 		pending = true;
282715516c77SSepherosa Ziehau #endif
282815516c77SSepherosa Ziehau 	return (pending);
282915516c77SSepherosa Ziehau }
283015516c77SSepherosa Ziehau 
283115516c77SSepherosa Ziehau static __inline void
283215516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr)
283315516c77SSepherosa Ziehau {
283415516c77SSepherosa Ziehau 	txr->hn_has_txeof = 0;
283515516c77SSepherosa Ziehau 	txr->hn_txeof(txr);
283615516c77SSepherosa Ziehau }
283715516c77SSepherosa Ziehau 
283815516c77SSepherosa Ziehau static void
283915516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc,
284015516c77SSepherosa Ziehau     struct vmbus_channel *chan, const void *data __unused, int dlen __unused)
284115516c77SSepherosa Ziehau {
284215516c77SSepherosa Ziehau 	struct hn_txdesc *txd = sndc->hn_cbarg;
284315516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
284415516c77SSepherosa Ziehau 
284515516c77SSepherosa Ziehau 	txr = txd->txr;
284615516c77SSepherosa Ziehau 	KASSERT(txr->hn_chan == chan,
284715516c77SSepherosa Ziehau 	    ("channel mismatch, on chan%u, should be chan%u",
2848aa1a2adcSSepherosa Ziehau 	     vmbus_chan_id(chan), vmbus_chan_id(txr->hn_chan)));
284915516c77SSepherosa Ziehau 
285015516c77SSepherosa Ziehau 	txr->hn_has_txeof = 1;
285115516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
285215516c77SSepherosa Ziehau 
285315516c77SSepherosa Ziehau 	++txr->hn_txdone_cnt;
285415516c77SSepherosa Ziehau 	if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) {
285515516c77SSepherosa Ziehau 		txr->hn_txdone_cnt = 0;
285615516c77SSepherosa Ziehau 		if (txr->hn_oactive)
285715516c77SSepherosa Ziehau 			hn_txeof(txr);
285815516c77SSepherosa Ziehau 	}
285915516c77SSepherosa Ziehau }
286015516c77SSepherosa Ziehau 
286115516c77SSepherosa Ziehau static void
286215516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
286315516c77SSepherosa Ziehau {
286415516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
286515516c77SSepherosa Ziehau 	tcp_lro_flush_all(&rxr->hn_lro);
286615516c77SSepherosa Ziehau #endif
286715516c77SSepherosa Ziehau 
286815516c77SSepherosa Ziehau 	/*
286915516c77SSepherosa Ziehau 	 * NOTE:
287015516c77SSepherosa Ziehau 	 * 'txr' could be NULL, if multiple channels and
287115516c77SSepherosa Ziehau 	 * ifnet.if_start method are enabled.
287215516c77SSepherosa Ziehau 	 */
287315516c77SSepherosa Ziehau 	if (txr == NULL || !txr->hn_has_txeof)
287415516c77SSepherosa Ziehau 		return;
287515516c77SSepherosa Ziehau 
287615516c77SSepherosa Ziehau 	txr->hn_txdone_cnt = 0;
287715516c77SSepherosa Ziehau 	hn_txeof(txr);
287815516c77SSepherosa Ziehau }
287915516c77SSepherosa Ziehau 
288015516c77SSepherosa Ziehau static __inline uint32_t
288115516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs)
288215516c77SSepherosa Ziehau {
288315516c77SSepherosa Ziehau 
288415516c77SSepherosa Ziehau 	KASSERT(ofs >= sizeof(struct rndis_packet_msg),
288515516c77SSepherosa Ziehau 	    ("invalid RNDIS packet msg offset %u", ofs));
288615516c77SSepherosa Ziehau 	return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset));
288715516c77SSepherosa Ziehau }
288815516c77SSepherosa Ziehau 
288915516c77SSepherosa Ziehau static __inline void *
289015516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
289115516c77SSepherosa Ziehau     size_t pi_dlen, uint32_t pi_type)
289215516c77SSepherosa Ziehau {
289315516c77SSepherosa Ziehau 	const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
289415516c77SSepherosa Ziehau 	struct rndis_pktinfo *pi;
289515516c77SSepherosa Ziehau 
289615516c77SSepherosa Ziehau 	KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
289715516c77SSepherosa Ziehau 	    ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
289815516c77SSepherosa Ziehau 
289915516c77SSepherosa Ziehau 	/*
290015516c77SSepherosa Ziehau 	 * Per-packet-info does not move; it only grows.
290115516c77SSepherosa Ziehau 	 *
290215516c77SSepherosa Ziehau 	 * NOTE:
290315516c77SSepherosa Ziehau 	 * rm_pktinfooffset in this phase counts from the beginning
290415516c77SSepherosa Ziehau 	 * of rndis_packet_msg.
290515516c77SSepherosa Ziehau 	 */
290615516c77SSepherosa Ziehau 	KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
290715516c77SSepherosa Ziehau 	    ("%u pktinfo overflows RNDIS packet msg", pi_type));
290815516c77SSepherosa Ziehau 	pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
290915516c77SSepherosa Ziehau 	    pkt->rm_pktinfolen);
291015516c77SSepherosa Ziehau 	pkt->rm_pktinfolen += pi_size;
291115516c77SSepherosa Ziehau 
291215516c77SSepherosa Ziehau 	pi->rm_size = pi_size;
291315516c77SSepherosa Ziehau 	pi->rm_type = pi_type;
291415516c77SSepherosa Ziehau 	pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
291515516c77SSepherosa Ziehau 
291615516c77SSepherosa Ziehau 	return (pi->rm_data);
291715516c77SSepherosa Ziehau }
291815516c77SSepherosa Ziehau 
2919dc13fee6SSepherosa Ziehau static __inline int
2920dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr)
2921dc13fee6SSepherosa Ziehau {
2922dc13fee6SSepherosa Ziehau 	struct hn_txdesc *txd;
2923dc13fee6SSepherosa Ziehau 	struct mbuf *m;
2924dc13fee6SSepherosa Ziehau 	int error, pkts;
2925dc13fee6SSepherosa Ziehau 
2926dc13fee6SSepherosa Ziehau 	txd = txr->hn_agg_txd;
2927dc13fee6SSepherosa Ziehau 	KASSERT(txd != NULL, ("no aggregate txdesc"));
2928dc13fee6SSepherosa Ziehau 
2929dc13fee6SSepherosa Ziehau 	/*
2930dc13fee6SSepherosa Ziehau 	 * Since hn_txpkt() will reset this temporary stat, save
2931dc13fee6SSepherosa Ziehau 	 * it now, so that oerrors can be updated properly, if
2932dc13fee6SSepherosa Ziehau 	 * hn_txpkt() ever fails.
2933dc13fee6SSepherosa Ziehau 	 */
2934dc13fee6SSepherosa Ziehau 	pkts = txr->hn_stat_pkts;
2935dc13fee6SSepherosa Ziehau 
2936dc13fee6SSepherosa Ziehau 	/*
2937dc13fee6SSepherosa Ziehau 	 * Since txd's mbuf will _not_ be freed upon hn_txpkt()
2938dc13fee6SSepherosa Ziehau 	 * failure, save it for later freeing, if hn_txpkt() ever
2939dc13fee6SSepherosa Ziehau 	 * fails.
2940dc13fee6SSepherosa Ziehau 	 */
2941dc13fee6SSepherosa Ziehau 	m = txd->m;
2942dc13fee6SSepherosa Ziehau 	error = hn_txpkt(ifp, txr, txd);
2943dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
2944dc13fee6SSepherosa Ziehau 		/* txd is freed, but m is not. */
2945dc13fee6SSepherosa Ziehau 		m_freem(m);
2946dc13fee6SSepherosa Ziehau 
2947dc13fee6SSepherosa Ziehau 		txr->hn_flush_failed++;
2948dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts);
2949dc13fee6SSepherosa Ziehau 	}
2950dc13fee6SSepherosa Ziehau 
2951dc13fee6SSepherosa Ziehau 	/* Reset all aggregation states. */
2952dc13fee6SSepherosa Ziehau 	txr->hn_agg_txd = NULL;
2953dc13fee6SSepherosa Ziehau 	txr->hn_agg_szleft = 0;
2954dc13fee6SSepherosa Ziehau 	txr->hn_agg_pktleft = 0;
2955dc13fee6SSepherosa Ziehau 	txr->hn_agg_prevpkt = NULL;
2956dc13fee6SSepherosa Ziehau 
2957dc13fee6SSepherosa Ziehau 	return (error);
2958dc13fee6SSepherosa Ziehau }
2959dc13fee6SSepherosa Ziehau 
2960dc13fee6SSepherosa Ziehau static void *
2961dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
2962dc13fee6SSepherosa Ziehau     int pktsize)
2963dc13fee6SSepherosa Ziehau {
2964dc13fee6SSepherosa Ziehau 	void *chim;
2965dc13fee6SSepherosa Ziehau 
2966dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL) {
2967dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) {
2968dc13fee6SSepherosa Ziehau 			struct hn_txdesc *agg_txd = txr->hn_agg_txd;
2969dc13fee6SSepherosa Ziehau 			struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt;
2970dc13fee6SSepherosa Ziehau 			int olen;
2971dc13fee6SSepherosa Ziehau 
2972dc13fee6SSepherosa Ziehau 			/*
2973dc13fee6SSepherosa Ziehau 			 * Update the previous RNDIS packet's total length,
2974dc13fee6SSepherosa Ziehau 			 * it can be increased due to the mandatory alignment
2975dc13fee6SSepherosa Ziehau 			 * padding for this RNDIS packet.  And update the
2976dc13fee6SSepherosa Ziehau 			 * aggregating txdesc's chimney sending buffer size
2977dc13fee6SSepherosa Ziehau 			 * accordingly.
2978dc13fee6SSepherosa Ziehau 			 *
2979dc13fee6SSepherosa Ziehau 			 * XXX
2980dc13fee6SSepherosa Ziehau 			 * Zero-out the padding, as required by the RNDIS spec.
2981dc13fee6SSepherosa Ziehau 			 */
2982dc13fee6SSepherosa Ziehau 			olen = pkt->rm_len;
2983dc13fee6SSepherosa Ziehau 			pkt->rm_len = roundup2(olen, txr->hn_agg_align);
2984dc13fee6SSepherosa Ziehau 			agg_txd->chim_size += pkt->rm_len - olen;
2985dc13fee6SSepherosa Ziehau 
2986dc13fee6SSepherosa Ziehau 			/* Link this txdesc to the parent. */
2987dc13fee6SSepherosa Ziehau 			hn_txdesc_agg(agg_txd, txd);
2988dc13fee6SSepherosa Ziehau 
2989dc13fee6SSepherosa Ziehau 			chim = (uint8_t *)pkt + pkt->rm_len;
2990dc13fee6SSepherosa Ziehau 			/* Save the current packet for later fixup. */
2991dc13fee6SSepherosa Ziehau 			txr->hn_agg_prevpkt = chim;
2992dc13fee6SSepherosa Ziehau 
2993dc13fee6SSepherosa Ziehau 			txr->hn_agg_pktleft--;
2994dc13fee6SSepherosa Ziehau 			txr->hn_agg_szleft -= pktsize;
2995dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_szleft <=
2996dc13fee6SSepherosa Ziehau 			    HN_PKTSIZE_MIN(txr->hn_agg_align)) {
2997dc13fee6SSepherosa Ziehau 				/*
2998dc13fee6SSepherosa Ziehau 				 * Probably can't aggregate more packets,
2999dc13fee6SSepherosa Ziehau 				 * flush this aggregating txdesc proactively.
3000dc13fee6SSepherosa Ziehau 				 */
3001dc13fee6SSepherosa Ziehau 				txr->hn_agg_pktleft = 0;
3002dc13fee6SSepherosa Ziehau 			}
3003dc13fee6SSepherosa Ziehau 			/* Done! */
3004dc13fee6SSepherosa Ziehau 			return (chim);
3005dc13fee6SSepherosa Ziehau 		}
3006dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
3007dc13fee6SSepherosa Ziehau 	}
3008dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
3009dc13fee6SSepherosa Ziehau 
3010dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney_tried++;
3011dc13fee6SSepherosa Ziehau 	txd->chim_index = hn_chim_alloc(txr->hn_sc);
3012dc13fee6SSepherosa Ziehau 	if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID)
3013dc13fee6SSepherosa Ziehau 		return (NULL);
3014dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney++;
3015dc13fee6SSepherosa Ziehau 
3016dc13fee6SSepherosa Ziehau 	chim = txr->hn_sc->hn_chim +
3017dc13fee6SSepherosa Ziehau 	    (txd->chim_index * txr->hn_sc->hn_chim_szmax);
3018dc13fee6SSepherosa Ziehau 
3019dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_pktmax > 1 &&
3020dc13fee6SSepherosa Ziehau 	    txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) {
3021dc13fee6SSepherosa Ziehau 		txr->hn_agg_txd = txd;
3022dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1;
3023dc13fee6SSepherosa Ziehau 		txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize;
3024dc13fee6SSepherosa Ziehau 		txr->hn_agg_prevpkt = chim;
3025dc13fee6SSepherosa Ziehau 	}
3026dc13fee6SSepherosa Ziehau 	return (chim);
3027dc13fee6SSepherosa Ziehau }
3028dc13fee6SSepherosa Ziehau 
302915516c77SSepherosa Ziehau /*
303015516c77SSepherosa Ziehau  * NOTE:
303115516c77SSepherosa Ziehau  * If this function fails, then both txd and m_head0 will be freed.
303215516c77SSepherosa Ziehau  */
303315516c77SSepherosa Ziehau static int
3034dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
3035dc13fee6SSepherosa Ziehau     struct mbuf **m_head0)
303615516c77SSepherosa Ziehau {
303715516c77SSepherosa Ziehau 	bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX];
303815516c77SSepherosa Ziehau 	int error, nsegs, i;
303915516c77SSepherosa Ziehau 	struct mbuf *m_head = *m_head0;
304015516c77SSepherosa Ziehau 	struct rndis_packet_msg *pkt;
304115516c77SSepherosa Ziehau 	uint32_t *pi_data;
30428966e5d5SSepherosa Ziehau 	void *chim = NULL;
3043dc13fee6SSepherosa Ziehau 	int pkt_hlen, pkt_size;
304415516c77SSepherosa Ziehau 
304515516c77SSepherosa Ziehau 	pkt = txd->rndis_pkt;
3046dc13fee6SSepherosa Ziehau 	pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align);
3047dc13fee6SSepherosa Ziehau 	if (pkt_size < txr->hn_chim_size) {
3048dc13fee6SSepherosa Ziehau 		chim = hn_try_txagg(ifp, txr, txd, pkt_size);
3049dc13fee6SSepherosa Ziehau 		if (chim != NULL)
30508966e5d5SSepherosa Ziehau 			pkt = chim;
3051dc13fee6SSepherosa Ziehau 	} else {
3052dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL)
3053dc13fee6SSepherosa Ziehau 			hn_flush_txagg(ifp, txr);
30548966e5d5SSepherosa Ziehau 	}
30558966e5d5SSepherosa Ziehau 
305615516c77SSepherosa Ziehau 	pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
30578fe90f73SSepherosa Ziehau 	pkt->rm_len = m_head->m_pkthdr.len;
30589130c4f7SSepherosa Ziehau 	pkt->rm_dataoffset = 0;
305915516c77SSepherosa Ziehau 	pkt->rm_datalen = m_head->m_pkthdr.len;
3060dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataoffset = 0;
3061dc13fee6SSepherosa Ziehau 	pkt->rm_oobdatalen = 0;
3062dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataelements = 0;
306315516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = sizeof(*pkt);
306415516c77SSepherosa Ziehau 	pkt->rm_pktinfolen = 0;
3065dc13fee6SSepherosa Ziehau 	pkt->rm_vchandle = 0;
3066dc13fee6SSepherosa Ziehau 	pkt->rm_reserved = 0;
306715516c77SSepherosa Ziehau 
306815516c77SSepherosa Ziehau 	if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) {
306915516c77SSepherosa Ziehau 		/*
307015516c77SSepherosa Ziehau 		 * Set the hash value for this packet, so that the host could
307115516c77SSepherosa Ziehau 		 * dispatch the TX done event for this packet back to this TX
307215516c77SSepherosa Ziehau 		 * ring's channel.
307315516c77SSepherosa Ziehau 		 */
307415516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
307515516c77SSepherosa Ziehau 		    HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL);
307615516c77SSepherosa Ziehau 		*pi_data = txr->hn_tx_idx;
307715516c77SSepherosa Ziehau 	}
307815516c77SSepherosa Ziehau 
307915516c77SSepherosa Ziehau 	if (m_head->m_flags & M_VLANTAG) {
308015516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
308115516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
308215516c77SSepherosa Ziehau 		*pi_data = NDIS_VLAN_INFO_MAKE(
308315516c77SSepherosa Ziehau 		    EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag),
308415516c77SSepherosa Ziehau 		    EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag),
308515516c77SSepherosa Ziehau 		    EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag));
308615516c77SSepherosa Ziehau 	}
308715516c77SSepherosa Ziehau 
308815516c77SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
308915516c77SSepherosa Ziehau #if defined(INET6) || defined(INET)
309015516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
309115516c77SSepherosa Ziehau 		    NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO);
309215516c77SSepherosa Ziehau #ifdef INET
309315516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
3094c49d47daSSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV4(
3095c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen,
309615516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
309715516c77SSepherosa Ziehau 		}
309815516c77SSepherosa Ziehau #endif
309915516c77SSepherosa Ziehau #if defined(INET6) && defined(INET)
310015516c77SSepherosa Ziehau 		else
310115516c77SSepherosa Ziehau #endif
310215516c77SSepherosa Ziehau #ifdef INET6
310315516c77SSepherosa Ziehau 		{
3104c49d47daSSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV6(
3105c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen,
310615516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
310715516c77SSepherosa Ziehau 		}
310815516c77SSepherosa Ziehau #endif
310915516c77SSepherosa Ziehau #endif	/* INET6 || INET */
311015516c77SSepherosa Ziehau 	} else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) {
311115516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
311215516c77SSepherosa Ziehau 		    NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
311315516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
311415516c77SSepherosa Ziehau 		    (CSUM_IP6_TCP | CSUM_IP6_UDP)) {
311515516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV6;
311615516c77SSepherosa Ziehau 		} else {
311715516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV4;
311815516c77SSepherosa Ziehau 			if (m_head->m_pkthdr.csum_flags & CSUM_IP)
311915516c77SSepherosa Ziehau 				*pi_data |= NDIS_TXCSUM_INFO_IPCS;
312015516c77SSepherosa Ziehau 		}
312115516c77SSepherosa Ziehau 
3122c49d47daSSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
3123c49d47daSSepherosa Ziehau 		    (CSUM_IP_TCP | CSUM_IP6_TCP)) {
3124c49d47daSSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_MKTCPCS(
3125c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen);
3126c49d47daSSepherosa Ziehau 		} else if (m_head->m_pkthdr.csum_flags &
3127c49d47daSSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP6_UDP)) {
3128c49d47daSSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_MKUDPCS(
3129c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen);
3130c49d47daSSepherosa Ziehau 		}
313115516c77SSepherosa Ziehau 	}
313215516c77SSepherosa Ziehau 
3133dc13fee6SSepherosa Ziehau 	pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
31348fe90f73SSepherosa Ziehau 	/* Fixup RNDIS packet message total length */
31358fe90f73SSepherosa Ziehau 	pkt->rm_len += pkt_hlen;
313615516c77SSepherosa Ziehau 	/* Convert RNDIS packet message offsets */
31379130c4f7SSepherosa Ziehau 	pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt_hlen);
313815516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset);
313915516c77SSepherosa Ziehau 
314015516c77SSepherosa Ziehau 	/*
31418966e5d5SSepherosa Ziehau 	 * Fast path: Chimney sending.
314215516c77SSepherosa Ziehau 	 */
31438966e5d5SSepherosa Ziehau 	if (chim != NULL) {
3144dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tgt_txd = txd;
3145dc13fee6SSepherosa Ziehau 
3146dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL) {
3147dc13fee6SSepherosa Ziehau 			tgt_txd = txr->hn_agg_txd;
3148dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
3149dc13fee6SSepherosa Ziehau 			*m_head0 = NULL;
3150dc13fee6SSepherosa Ziehau #endif
3151dc13fee6SSepherosa Ziehau 		}
3152dc13fee6SSepherosa Ziehau 
3153dc13fee6SSepherosa Ziehau 		KASSERT(pkt == chim,
3154dc13fee6SSepherosa Ziehau 		    ("RNDIS pkt not in chimney sending buffer"));
3155dc13fee6SSepherosa Ziehau 		KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID,
3156dc13fee6SSepherosa Ziehau 		    ("chimney sending buffer is not used"));
3157dc13fee6SSepherosa Ziehau 		tgt_txd->chim_size += pkt->rm_len;
315815516c77SSepherosa Ziehau 
31598966e5d5SSepherosa Ziehau 		m_copydata(m_head, 0, m_head->m_pkthdr.len,
3160dc13fee6SSepherosa Ziehau 		    ((uint8_t *)chim) + pkt_hlen);
316115516c77SSepherosa Ziehau 
316215516c77SSepherosa Ziehau 		txr->hn_gpa_cnt = 0;
316315516c77SSepherosa Ziehau 		txr->hn_sendpkt = hn_txpkt_chim;
316415516c77SSepherosa Ziehau 		goto done;
316515516c77SSepherosa Ziehau 	}
3166dc13fee6SSepherosa Ziehau 
3167dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc"));
31688966e5d5SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
31698966e5d5SSepherosa Ziehau 	    ("chimney buffer is used"));
31708966e5d5SSepherosa Ziehau 	KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc"));
317115516c77SSepherosa Ziehau 
317215516c77SSepherosa Ziehau 	error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs);
3173dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
317415516c77SSepherosa Ziehau 		int freed;
317515516c77SSepherosa Ziehau 
317615516c77SSepherosa Ziehau 		/*
317715516c77SSepherosa Ziehau 		 * This mbuf is not linked w/ the txd yet, so free it now.
317815516c77SSepherosa Ziehau 		 */
317915516c77SSepherosa Ziehau 		m_freem(m_head);
318015516c77SSepherosa Ziehau 		*m_head0 = NULL;
318115516c77SSepherosa Ziehau 
318215516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
318315516c77SSepherosa Ziehau 		KASSERT(freed != 0,
318415516c77SSepherosa Ziehau 		    ("fail to free txd upon txdma error"));
318515516c77SSepherosa Ziehau 
318615516c77SSepherosa Ziehau 		txr->hn_txdma_failed++;
3187dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
318815516c77SSepherosa Ziehau 		return error;
318915516c77SSepherosa Ziehau 	}
319015516c77SSepherosa Ziehau 	*m_head0 = m_head;
319115516c77SSepherosa Ziehau 
319215516c77SSepherosa Ziehau 	/* +1 RNDIS packet message */
319315516c77SSepherosa Ziehau 	txr->hn_gpa_cnt = nsegs + 1;
319415516c77SSepherosa Ziehau 
319515516c77SSepherosa Ziehau 	/* send packet with page buffer */
319615516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr);
319715516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK;
3198dc13fee6SSepherosa Ziehau 	txr->hn_gpa[0].gpa_len = pkt_hlen;
319915516c77SSepherosa Ziehau 
320015516c77SSepherosa Ziehau 	/*
320115516c77SSepherosa Ziehau 	 * Fill the page buffers with mbuf info after the page
320215516c77SSepherosa Ziehau 	 * buffer for RNDIS packet message.
320315516c77SSepherosa Ziehau 	 */
320415516c77SSepherosa Ziehau 	for (i = 0; i < nsegs; ++i) {
320515516c77SSepherosa Ziehau 		struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1];
320615516c77SSepherosa Ziehau 
320715516c77SSepherosa Ziehau 		gpa->gpa_page = atop(segs[i].ds_addr);
320815516c77SSepherosa Ziehau 		gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK;
320915516c77SSepherosa Ziehau 		gpa->gpa_len = segs[i].ds_len;
321015516c77SSepherosa Ziehau 	}
321115516c77SSepherosa Ziehau 
321215516c77SSepherosa Ziehau 	txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
321315516c77SSepherosa Ziehau 	txd->chim_size = 0;
321415516c77SSepherosa Ziehau 	txr->hn_sendpkt = hn_txpkt_sglist;
321515516c77SSepherosa Ziehau done:
321615516c77SSepherosa Ziehau 	txd->m = m_head;
321715516c77SSepherosa Ziehau 
321815516c77SSepherosa Ziehau 	/* Set the completion routine */
321915516c77SSepherosa Ziehau 	hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd);
322015516c77SSepherosa Ziehau 
3221dc13fee6SSepherosa Ziehau 	/* Update temporary stats for later use. */
3222dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts++;
3223dc13fee6SSepherosa Ziehau 	txr->hn_stat_size += m_head->m_pkthdr.len;
3224dc13fee6SSepherosa Ziehau 	if (m_head->m_flags & M_MCAST)
3225dc13fee6SSepherosa Ziehau 		txr->hn_stat_mcasts++;
3226dc13fee6SSepherosa Ziehau 
322715516c77SSepherosa Ziehau 	return 0;
322815516c77SSepherosa Ziehau }
322915516c77SSepherosa Ziehau 
323015516c77SSepherosa Ziehau /*
323115516c77SSepherosa Ziehau  * NOTE:
323215516c77SSepherosa Ziehau  * If this function fails, then txd will be freed, but the mbuf
323315516c77SSepherosa Ziehau  * associated w/ the txd will _not_ be freed.
323415516c77SSepherosa Ziehau  */
323515516c77SSepherosa Ziehau static int
323615516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd)
323715516c77SSepherosa Ziehau {
32388e7d3136SSepherosa Ziehau 	int error, send_failed = 0, has_bpf;
323915516c77SSepherosa Ziehau 
324015516c77SSepherosa Ziehau again:
32418e7d3136SSepherosa Ziehau 	has_bpf = bpf_peers_present(ifp->if_bpf);
32428e7d3136SSepherosa Ziehau 	if (has_bpf) {
324315516c77SSepherosa Ziehau 		/*
32448e7d3136SSepherosa Ziehau 		 * Make sure that this txd and any aggregated txds are not
32458e7d3136SSepherosa Ziehau 		 * freed before ETHER_BPF_MTAP.
324615516c77SSepherosa Ziehau 		 */
324715516c77SSepherosa Ziehau 		hn_txdesc_hold(txd);
32488e7d3136SSepherosa Ziehau 	}
324915516c77SSepherosa Ziehau 	error = txr->hn_sendpkt(txr, txd);
325015516c77SSepherosa Ziehau 	if (!error) {
32518e7d3136SSepherosa Ziehau 		if (has_bpf) {
3252dc13fee6SSepherosa Ziehau 			const struct hn_txdesc *tmp_txd;
3253dc13fee6SSepherosa Ziehau 
325415516c77SSepherosa Ziehau 			ETHER_BPF_MTAP(ifp, txd->m);
3255dc13fee6SSepherosa Ziehau 			STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link)
3256dc13fee6SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, tmp_txd->m);
3257dc13fee6SSepherosa Ziehau 		}
3258dc13fee6SSepherosa Ziehau 
3259dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts);
326023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
326123bf9e15SSepherosa Ziehau 		if (!hn_use_if_start)
326223bf9e15SSepherosa Ziehau #endif
326323bf9e15SSepherosa Ziehau 		{
326415516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OBYTES,
3265dc13fee6SSepherosa Ziehau 			    txr->hn_stat_size);
3266dc13fee6SSepherosa Ziehau 			if (txr->hn_stat_mcasts != 0) {
3267dc13fee6SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OMCASTS,
3268dc13fee6SSepherosa Ziehau 				    txr->hn_stat_mcasts);
326915516c77SSepherosa Ziehau 			}
3270dc13fee6SSepherosa Ziehau 		}
3271dc13fee6SSepherosa Ziehau 		txr->hn_pkts += txr->hn_stat_pkts;
3272dc13fee6SSepherosa Ziehau 		txr->hn_sends++;
327315516c77SSepherosa Ziehau 	}
32748e7d3136SSepherosa Ziehau 	if (has_bpf)
327515516c77SSepherosa Ziehau 		hn_txdesc_put(txr, txd);
327615516c77SSepherosa Ziehau 
327715516c77SSepherosa Ziehau 	if (__predict_false(error)) {
327815516c77SSepherosa Ziehau 		int freed;
327915516c77SSepherosa Ziehau 
328015516c77SSepherosa Ziehau 		/*
328115516c77SSepherosa Ziehau 		 * This should "really rarely" happen.
328215516c77SSepherosa Ziehau 		 *
328315516c77SSepherosa Ziehau 		 * XXX Too many RX to be acked or too many sideband
328415516c77SSepherosa Ziehau 		 * commands to run?  Ask netvsc_channel_rollup()
328515516c77SSepherosa Ziehau 		 * to kick start later.
328615516c77SSepherosa Ziehau 		 */
328715516c77SSepherosa Ziehau 		txr->hn_has_txeof = 1;
328815516c77SSepherosa Ziehau 		if (!send_failed) {
328915516c77SSepherosa Ziehau 			txr->hn_send_failed++;
329015516c77SSepherosa Ziehau 			send_failed = 1;
329115516c77SSepherosa Ziehau 			/*
329215516c77SSepherosa Ziehau 			 * Try sending again after set hn_has_txeof;
329315516c77SSepherosa Ziehau 			 * in case that we missed the last
329415516c77SSepherosa Ziehau 			 * netvsc_channel_rollup().
329515516c77SSepherosa Ziehau 			 */
329615516c77SSepherosa Ziehau 			goto again;
329715516c77SSepherosa Ziehau 		}
329815516c77SSepherosa Ziehau 		if_printf(ifp, "send failed\n");
329915516c77SSepherosa Ziehau 
330015516c77SSepherosa Ziehau 		/*
330115516c77SSepherosa Ziehau 		 * Caller will perform further processing on the
330215516c77SSepherosa Ziehau 		 * associated mbuf, so don't free it in hn_txdesc_put();
330315516c77SSepherosa Ziehau 		 * only unload it from the DMA map in hn_txdesc_put(),
330415516c77SSepherosa Ziehau 		 * if it was loaded.
330515516c77SSepherosa Ziehau 		 */
330615516c77SSepherosa Ziehau 		txd->m = NULL;
330715516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
330815516c77SSepherosa Ziehau 		KASSERT(freed != 0,
330915516c77SSepherosa Ziehau 		    ("fail to free txd upon send error"));
331015516c77SSepherosa Ziehau 
331115516c77SSepherosa Ziehau 		txr->hn_send_failed++;
331215516c77SSepherosa Ziehau 	}
3313dc13fee6SSepherosa Ziehau 
3314dc13fee6SSepherosa Ziehau 	/* Reset temporary stats, after this sending is done. */
3315dc13fee6SSepherosa Ziehau 	txr->hn_stat_size = 0;
3316dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts = 0;
3317dc13fee6SSepherosa Ziehau 	txr->hn_stat_mcasts = 0;
3318dc13fee6SSepherosa Ziehau 
3319dc13fee6SSepherosa Ziehau 	return (error);
332015516c77SSepherosa Ziehau }
332115516c77SSepherosa Ziehau 
332215516c77SSepherosa Ziehau /*
332315516c77SSepherosa Ziehau  * Append the specified data to the indicated mbuf chain,
332415516c77SSepherosa Ziehau  * Extend the mbuf chain if the new data does not fit in
332515516c77SSepherosa Ziehau  * existing space.
332615516c77SSepherosa Ziehau  *
332715516c77SSepherosa Ziehau  * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c.
332815516c77SSepherosa Ziehau  * There should be an equivalent in the kernel mbuf code,
332915516c77SSepherosa Ziehau  * but there does not appear to be one yet.
333015516c77SSepherosa Ziehau  *
333115516c77SSepherosa Ziehau  * Differs from m_append() in that additional mbufs are
333215516c77SSepherosa Ziehau  * allocated with cluster size MJUMPAGESIZE, and filled
333315516c77SSepherosa Ziehau  * accordingly.
333415516c77SSepherosa Ziehau  *
333515516c77SSepherosa Ziehau  * Return 1 if able to complete the job; otherwise 0.
333615516c77SSepherosa Ziehau  */
333715516c77SSepherosa Ziehau static int
333815516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp)
333915516c77SSepherosa Ziehau {
334015516c77SSepherosa Ziehau 	struct mbuf *m, *n;
334115516c77SSepherosa Ziehau 	int remainder, space;
334215516c77SSepherosa Ziehau 
334315516c77SSepherosa Ziehau 	for (m = m0; m->m_next != NULL; m = m->m_next)
334415516c77SSepherosa Ziehau 		;
334515516c77SSepherosa Ziehau 	remainder = len;
334615516c77SSepherosa Ziehau 	space = M_TRAILINGSPACE(m);
334715516c77SSepherosa Ziehau 	if (space > 0) {
334815516c77SSepherosa Ziehau 		/*
334915516c77SSepherosa Ziehau 		 * Copy into available space.
335015516c77SSepherosa Ziehau 		 */
335115516c77SSepherosa Ziehau 		if (space > remainder)
335215516c77SSepherosa Ziehau 			space = remainder;
335315516c77SSepherosa Ziehau 		bcopy(cp, mtod(m, caddr_t) + m->m_len, space);
335415516c77SSepherosa Ziehau 		m->m_len += space;
335515516c77SSepherosa Ziehau 		cp += space;
335615516c77SSepherosa Ziehau 		remainder -= space;
335715516c77SSepherosa Ziehau 	}
335815516c77SSepherosa Ziehau 	while (remainder > 0) {
335915516c77SSepherosa Ziehau 		/*
336015516c77SSepherosa Ziehau 		 * Allocate a new mbuf; could check space
336115516c77SSepherosa Ziehau 		 * and allocate a cluster instead.
336215516c77SSepherosa Ziehau 		 */
336315516c77SSepherosa Ziehau 		n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE);
336415516c77SSepherosa Ziehau 		if (n == NULL)
336515516c77SSepherosa Ziehau 			break;
336615516c77SSepherosa Ziehau 		n->m_len = min(MJUMPAGESIZE, remainder);
336715516c77SSepherosa Ziehau 		bcopy(cp, mtod(n, caddr_t), n->m_len);
336815516c77SSepherosa Ziehau 		cp += n->m_len;
336915516c77SSepherosa Ziehau 		remainder -= n->m_len;
337015516c77SSepherosa Ziehau 		m->m_next = n;
337115516c77SSepherosa Ziehau 		m = n;
337215516c77SSepherosa Ziehau 	}
337315516c77SSepherosa Ziehau 	if (m0->m_flags & M_PKTHDR)
337415516c77SSepherosa Ziehau 		m0->m_pkthdr.len += len - remainder;
337515516c77SSepherosa Ziehau 
337615516c77SSepherosa Ziehau 	return (remainder == 0);
337715516c77SSepherosa Ziehau }
337815516c77SSepherosa Ziehau 
337915516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
338015516c77SSepherosa Ziehau static __inline int
338115516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m)
338215516c77SSepherosa Ziehau {
338315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
338415516c77SSepherosa Ziehau 	if (hn_lro_mbufq_depth) {
338515516c77SSepherosa Ziehau 		tcp_lro_queue_mbuf(lc, m);
338615516c77SSepherosa Ziehau 		return 0;
338715516c77SSepherosa Ziehau 	}
338815516c77SSepherosa Ziehau #endif
338915516c77SSepherosa Ziehau 	return tcp_lro_rx(lc, m, 0);
339015516c77SSepherosa Ziehau }
339115516c77SSepherosa Ziehau #endif
339215516c77SSepherosa Ziehau 
339315516c77SSepherosa Ziehau static int
339415516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
339515516c77SSepherosa Ziehau     const struct hn_rxinfo *info)
339615516c77SSepherosa Ziehau {
3397a97fff19SSepherosa Ziehau 	struct ifnet *ifp, *hn_ifp = rxr->hn_ifp;
339815516c77SSepherosa Ziehau 	struct mbuf *m_new;
3399642ec226SSepherosa Ziehau 	int size, do_lro = 0, do_csum = 1, is_vf = 0;
3400642ec226SSepherosa Ziehau 	int hash_type = M_HASHTYPE_NONE;
3401db76829bSSepherosa Ziehau 	int l3proto = ETHERTYPE_MAX, l4proto = IPPROTO_DONE;
340215516c77SSepherosa Ziehau 
3403642ec226SSepherosa Ziehau 	ifp = hn_ifp;
3404642ec226SSepherosa Ziehau 	if (rxr->hn_rxvf_ifp != NULL) {
3405a97fff19SSepherosa Ziehau 		/*
3406642ec226SSepherosa Ziehau 		 * Non-transparent mode VF; pretend this packet is from
3407642ec226SSepherosa Ziehau 		 * the VF.
3408a97fff19SSepherosa Ziehau 		 */
3409642ec226SSepherosa Ziehau 		ifp = rxr->hn_rxvf_ifp;
3410642ec226SSepherosa Ziehau 		is_vf = 1;
3411642ec226SSepherosa Ziehau 	} else if (rxr->hn_rx_flags & HN_RX_FLAG_XPNT_VF) {
3412642ec226SSepherosa Ziehau 		/* Transparent mode VF. */
3413642ec226SSepherosa Ziehau 		is_vf = 1;
3414642ec226SSepherosa Ziehau 	}
34155bdfd3fdSDexuan Cui 
3416b3b75d9cSSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
3417b3b75d9cSSepherosa Ziehau 		/*
3418b3b75d9cSSepherosa Ziehau 		 * NOTE:
3419b3b75d9cSSepherosa Ziehau 		 * See the NOTE of hn_rndis_init_fixat().  This
3420b3b75d9cSSepherosa Ziehau 		 * function can be reached, immediately after the
3421b3b75d9cSSepherosa Ziehau 		 * RNDIS is initialized but before the ifnet is
3422b3b75d9cSSepherosa Ziehau 		 * setup on the hn_attach() path; drop the unexpected
3423b3b75d9cSSepherosa Ziehau 		 * packets.
3424b3b75d9cSSepherosa Ziehau 		 */
3425b3b75d9cSSepherosa Ziehau 		return (0);
3426b3b75d9cSSepherosa Ziehau 	}
3427b3b75d9cSSepherosa Ziehau 
3428a97fff19SSepherosa Ziehau 	if (__predict_false(dlen < ETHER_HDR_LEN)) {
3429a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IERRORS, 1);
3430a97fff19SSepherosa Ziehau 		return (0);
3431a97fff19SSepherosa Ziehau 	}
3432a97fff19SSepherosa Ziehau 
3433c927d681SDexuan Cui 	if (dlen <= MHLEN) {
343415516c77SSepherosa Ziehau 		m_new = m_gethdr(M_NOWAIT, MT_DATA);
343515516c77SSepherosa Ziehau 		if (m_new == NULL) {
3436a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1);
343715516c77SSepherosa Ziehau 			return (0);
343815516c77SSepherosa Ziehau 		}
343915516c77SSepherosa Ziehau 		memcpy(mtod(m_new, void *), data, dlen);
344015516c77SSepherosa Ziehau 		m_new->m_pkthdr.len = m_new->m_len = dlen;
344115516c77SSepherosa Ziehau 		rxr->hn_small_pkts++;
344215516c77SSepherosa Ziehau 	} else {
344315516c77SSepherosa Ziehau 		/*
344415516c77SSepherosa Ziehau 		 * Get an mbuf with a cluster.  For packets 2K or less,
344515516c77SSepherosa Ziehau 		 * get a standard 2K cluster.  For anything larger, get a
344615516c77SSepherosa Ziehau 		 * 4K cluster.  Any buffers larger than 4K can cause problems
344715516c77SSepherosa Ziehau 		 * if looped around to the Hyper-V TX channel, so avoid them.
344815516c77SSepherosa Ziehau 		 */
344915516c77SSepherosa Ziehau 		size = MCLBYTES;
345015516c77SSepherosa Ziehau 		if (dlen > MCLBYTES) {
345115516c77SSepherosa Ziehau 			/* 4096 */
345215516c77SSepherosa Ziehau 			size = MJUMPAGESIZE;
345315516c77SSepherosa Ziehau 		}
345415516c77SSepherosa Ziehau 
345515516c77SSepherosa Ziehau 		m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size);
345615516c77SSepherosa Ziehau 		if (m_new == NULL) {
3457a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1);
345815516c77SSepherosa Ziehau 			return (0);
345915516c77SSepherosa Ziehau 		}
346015516c77SSepherosa Ziehau 
346115516c77SSepherosa Ziehau 		hv_m_append(m_new, dlen, data);
346215516c77SSepherosa Ziehau 	}
346315516c77SSepherosa Ziehau 	m_new->m_pkthdr.rcvif = ifp;
346415516c77SSepherosa Ziehau 
3465a97fff19SSepherosa Ziehau 	if (__predict_false((hn_ifp->if_capenable & IFCAP_RXCSUM) == 0))
346615516c77SSepherosa Ziehau 		do_csum = 0;
346715516c77SSepherosa Ziehau 
346815516c77SSepherosa Ziehau 	/* receive side checksum offload */
346915516c77SSepherosa Ziehau 	if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) {
347015516c77SSepherosa Ziehau 		/* IP csum offload */
347115516c77SSepherosa Ziehau 		if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) {
347215516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
347315516c77SSepherosa Ziehau 			    (CSUM_IP_CHECKED | CSUM_IP_VALID);
347415516c77SSepherosa Ziehau 			rxr->hn_csum_ip++;
347515516c77SSepherosa Ziehau 		}
347615516c77SSepherosa Ziehau 
347715516c77SSepherosa Ziehau 		/* TCP/UDP csum offload */
347815516c77SSepherosa Ziehau 		if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK |
347915516c77SSepherosa Ziehau 		     NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) {
348015516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
348115516c77SSepherosa Ziehau 			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
348215516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_data = 0xffff;
348315516c77SSepherosa Ziehau 			if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK)
348415516c77SSepherosa Ziehau 				rxr->hn_csum_tcp++;
348515516c77SSepherosa Ziehau 			else
348615516c77SSepherosa Ziehau 				rxr->hn_csum_udp++;
348715516c77SSepherosa Ziehau 		}
348815516c77SSepherosa Ziehau 
348915516c77SSepherosa Ziehau 		/*
349015516c77SSepherosa Ziehau 		 * XXX
349115516c77SSepherosa Ziehau 		 * As of this write (Oct 28th, 2016), host side will turn
349215516c77SSepherosa Ziehau 		 * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so
349315516c77SSepherosa Ziehau 		 * the do_lro setting here is actually _not_ accurate.  We
349415516c77SSepherosa Ziehau 		 * depend on the RSS hash type check to reset do_lro.
349515516c77SSepherosa Ziehau 		 */
349615516c77SSepherosa Ziehau 		if ((info->csum_info &
349715516c77SSepherosa Ziehau 		     (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) ==
349815516c77SSepherosa Ziehau 		    (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK))
349915516c77SSepherosa Ziehau 			do_lro = 1;
350015516c77SSepherosa Ziehau 	} else {
3501db76829bSSepherosa Ziehau 		hn_rxpkt_proto(m_new, &l3proto, &l4proto);
3502db76829bSSepherosa Ziehau 		if (l3proto == ETHERTYPE_IP) {
3503db76829bSSepherosa Ziehau 			if (l4proto == IPPROTO_TCP) {
350415516c77SSepherosa Ziehau 				if (do_csum &&
350515516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
350615516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_TCP)) {
350715516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
350815516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
350915516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
351015516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
351115516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
351215516c77SSepherosa Ziehau 				}
351315516c77SSepherosa Ziehau 				do_lro = 1;
3514db76829bSSepherosa Ziehau 			} else if (l4proto == IPPROTO_UDP) {
351515516c77SSepherosa Ziehau 				if (do_csum &&
351615516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
351715516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_UDP)) {
351815516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
351915516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
352015516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
352115516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
352215516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
352315516c77SSepherosa Ziehau 				}
3524db76829bSSepherosa Ziehau 			} else if (l4proto != IPPROTO_DONE && do_csum &&
352515516c77SSepherosa Ziehau 			    (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) {
352615516c77SSepherosa Ziehau 				rxr->hn_csum_trusted++;
352715516c77SSepherosa Ziehau 				m_new->m_pkthdr.csum_flags |=
352815516c77SSepherosa Ziehau 				    (CSUM_IP_CHECKED | CSUM_IP_VALID);
352915516c77SSepherosa Ziehau 			}
353015516c77SSepherosa Ziehau 		}
353115516c77SSepherosa Ziehau 	}
3532db76829bSSepherosa Ziehau 
353315516c77SSepherosa Ziehau 	if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) {
353415516c77SSepherosa Ziehau 		m_new->m_pkthdr.ether_vtag = EVL_MAKETAG(
353515516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_ID(info->vlan_info),
353615516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_PRI(info->vlan_info),
353715516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_CFI(info->vlan_info));
353815516c77SSepherosa Ziehau 		m_new->m_flags |= M_VLANTAG;
353915516c77SSepherosa Ziehau 	}
354015516c77SSepherosa Ziehau 
3541a97fff19SSepherosa Ziehau 	/*
3542a97fff19SSepherosa Ziehau 	 * If VF is activated (tranparent/non-transparent mode does not
3543a97fff19SSepherosa Ziehau 	 * matter here).
3544a97fff19SSepherosa Ziehau 	 *
3545a97fff19SSepherosa Ziehau 	 * - Disable LRO
3546a97fff19SSepherosa Ziehau 	 *
3547a97fff19SSepherosa Ziehau 	 *   hn(4) will only receive broadcast packets, multicast packets,
3548a97fff19SSepherosa Ziehau 	 *   TCP SYN and SYN|ACK (in Azure), LRO is useless for these
3549a97fff19SSepherosa Ziehau 	 *   packet types.
3550a97fff19SSepherosa Ziehau 	 *
3551a97fff19SSepherosa Ziehau 	 *   For non-transparent, we definitely _cannot_ enable LRO at
3552a97fff19SSepherosa Ziehau 	 *   all, since the LRO flush will use hn(4) as the receiving
3553a97fff19SSepherosa Ziehau 	 *   interface; i.e. hn_ifp->if_input(hn_ifp, m).
3554a97fff19SSepherosa Ziehau 	 */
3555642ec226SSepherosa Ziehau 	if (is_vf)
3556642ec226SSepherosa Ziehau 		do_lro = 0;
3557a97fff19SSepherosa Ziehau 
3558642ec226SSepherosa Ziehau 	/*
3559642ec226SSepherosa Ziehau 	 * If VF is activated (tranparent/non-transparent mode does not
3560642ec226SSepherosa Ziehau 	 * matter here), do _not_ mess with unsupported hash types or
3561642ec226SSepherosa Ziehau 	 * functions.
3562642ec226SSepherosa Ziehau 	 */
356315516c77SSepherosa Ziehau 	if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) {
356415516c77SSepherosa Ziehau 		rxr->hn_rss_pkts++;
356515516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = info->hash_value;
3566642ec226SSepherosa Ziehau 		if (!is_vf)
356715516c77SSepherosa Ziehau 			hash_type = M_HASHTYPE_OPAQUE_HASH;
356815516c77SSepherosa Ziehau 		if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) ==
356915516c77SSepherosa Ziehau 		    NDIS_HASH_FUNCTION_TOEPLITZ) {
3570642ec226SSepherosa Ziehau 			uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK &
3571642ec226SSepherosa Ziehau 			    rxr->hn_mbuf_hash);
357215516c77SSepherosa Ziehau 
357315516c77SSepherosa Ziehau 			/*
357415516c77SSepherosa Ziehau 			 * NOTE:
357515516c77SSepherosa Ziehau 			 * do_lro is resetted, if the hash types are not TCP
357615516c77SSepherosa Ziehau 			 * related.  See the comment in the above csum_flags
357715516c77SSepherosa Ziehau 			 * setup section.
357815516c77SSepherosa Ziehau 			 */
357915516c77SSepherosa Ziehau 			switch (type) {
358015516c77SSepherosa Ziehau 			case NDIS_HASH_IPV4:
358115516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV4;
358215516c77SSepherosa Ziehau 				do_lro = 0;
358315516c77SSepherosa Ziehau 				break;
358415516c77SSepherosa Ziehau 
358515516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV4:
358615516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV4;
3587db76829bSSepherosa Ziehau 				if (rxr->hn_rx_flags & HN_RX_FLAG_UDP_HASH) {
3588db76829bSSepherosa Ziehau 					int def_htype = M_HASHTYPE_OPAQUE_HASH;
3589db76829bSSepherosa Ziehau 
3590db76829bSSepherosa Ziehau 					if (is_vf)
3591db76829bSSepherosa Ziehau 						def_htype = M_HASHTYPE_NONE;
3592db76829bSSepherosa Ziehau 
3593db76829bSSepherosa Ziehau 					/*
3594db76829bSSepherosa Ziehau 					 * UDP 4-tuple hash is delivered as
3595db76829bSSepherosa Ziehau 					 * TCP 4-tuple hash.
3596db76829bSSepherosa Ziehau 					 */
3597db76829bSSepherosa Ziehau 					if (l3proto == ETHERTYPE_MAX) {
3598db76829bSSepherosa Ziehau 						hn_rxpkt_proto(m_new,
3599db76829bSSepherosa Ziehau 						    &l3proto, &l4proto);
3600db76829bSSepherosa Ziehau 					}
3601db76829bSSepherosa Ziehau 					if (l3proto == ETHERTYPE_IP) {
36026f12c42eSSepherosa Ziehau 						if (l4proto == IPPROTO_UDP &&
36036f12c42eSSepherosa Ziehau 						    (rxr->hn_mbuf_hash &
36046f12c42eSSepherosa Ziehau 						     NDIS_HASH_UDP_IPV4_X)) {
3605db76829bSSepherosa Ziehau 							hash_type =
3606db76829bSSepherosa Ziehau 							M_HASHTYPE_RSS_UDP_IPV4;
3607db76829bSSepherosa Ziehau 							do_lro = 0;
3608db76829bSSepherosa Ziehau 						} else if (l4proto !=
3609db76829bSSepherosa Ziehau 						    IPPROTO_TCP) {
3610db76829bSSepherosa Ziehau 							hash_type = def_htype;
3611db76829bSSepherosa Ziehau 							do_lro = 0;
3612db76829bSSepherosa Ziehau 						}
3613db76829bSSepherosa Ziehau 					} else {
3614db76829bSSepherosa Ziehau 						hash_type = def_htype;
3615db76829bSSepherosa Ziehau 						do_lro = 0;
3616db76829bSSepherosa Ziehau 					}
3617db76829bSSepherosa Ziehau 				}
361815516c77SSepherosa Ziehau 				break;
361915516c77SSepherosa Ziehau 
362015516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6:
362115516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6;
362215516c77SSepherosa Ziehau 				do_lro = 0;
362315516c77SSepherosa Ziehau 				break;
362415516c77SSepherosa Ziehau 
362515516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6_EX:
362615516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6_EX;
362715516c77SSepherosa Ziehau 				do_lro = 0;
362815516c77SSepherosa Ziehau 				break;
362915516c77SSepherosa Ziehau 
363015516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6:
363115516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6;
363215516c77SSepherosa Ziehau 				break;
363315516c77SSepherosa Ziehau 
363415516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6_EX:
363515516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX;
363615516c77SSepherosa Ziehau 				break;
363715516c77SSepherosa Ziehau 			}
363815516c77SSepherosa Ziehau 		}
3639642ec226SSepherosa Ziehau 	} else if (!is_vf) {
364015516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
364115516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE;
364215516c77SSepherosa Ziehau 	}
364315516c77SSepherosa Ziehau 	M_HASHTYPE_SET(m_new, hash_type);
364415516c77SSepherosa Ziehau 
3645a97fff19SSepherosa Ziehau 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
3646a97fff19SSepherosa Ziehau 	if (hn_ifp != ifp) {
3647a97fff19SSepherosa Ziehau 		const struct ether_header *eh;
3648a97fff19SSepherosa Ziehau 
364915516c77SSepherosa Ziehau 		/*
3650a97fff19SSepherosa Ziehau 		 * Non-transparent mode VF is activated.
365115516c77SSepherosa Ziehau 		 */
365215516c77SSepherosa Ziehau 
3653a97fff19SSepherosa Ziehau 		/*
3654a97fff19SSepherosa Ziehau 		 * Allow tapping on hn(4).
3655a97fff19SSepherosa Ziehau 		 */
3656a97fff19SSepherosa Ziehau 		ETHER_BPF_MTAP(hn_ifp, m_new);
3657a97fff19SSepherosa Ziehau 
3658a97fff19SSepherosa Ziehau 		/*
3659a97fff19SSepherosa Ziehau 		 * Update hn(4)'s stats.
3660a97fff19SSepherosa Ziehau 		 */
3661a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1);
3662a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IBYTES, m_new->m_pkthdr.len);
3663a97fff19SSepherosa Ziehau 		/* Checked at the beginning of this function. */
3664a97fff19SSepherosa Ziehau 		KASSERT(m_new->m_len >= ETHER_HDR_LEN, ("not ethernet frame"));
3665a97fff19SSepherosa Ziehau 		eh = mtod(m_new, struct ether_header *);
3666a97fff19SSepherosa Ziehau 		if (ETHER_IS_MULTICAST(eh->ether_dhost))
3667a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IMCASTS, 1);
3668a97fff19SSepherosa Ziehau 	}
366915516c77SSepherosa Ziehau 	rxr->hn_pkts++;
367015516c77SSepherosa Ziehau 
3671a97fff19SSepherosa Ziehau 	if ((hn_ifp->if_capenable & IFCAP_LRO) && do_lro) {
367215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
367315516c77SSepherosa Ziehau 		struct lro_ctrl *lro = &rxr->hn_lro;
367415516c77SSepherosa Ziehau 
367515516c77SSepherosa Ziehau 		if (lro->lro_cnt) {
367615516c77SSepherosa Ziehau 			rxr->hn_lro_tried++;
367715516c77SSepherosa Ziehau 			if (hn_lro_rx(lro, m_new) == 0) {
367815516c77SSepherosa Ziehau 				/* DONE! */
367915516c77SSepherosa Ziehau 				return 0;
368015516c77SSepherosa Ziehau 			}
368115516c77SSepherosa Ziehau 		}
368215516c77SSepherosa Ziehau #endif
368315516c77SSepherosa Ziehau 	}
3684a97fff19SSepherosa Ziehau 	ifp->if_input(ifp, m_new);
368515516c77SSepherosa Ziehau 
368615516c77SSepherosa Ziehau 	return (0);
368715516c77SSepherosa Ziehau }
368815516c77SSepherosa Ziehau 
368915516c77SSepherosa Ziehau static int
369015516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
369115516c77SSepherosa Ziehau {
369215516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
36939c6cae24SSepherosa Ziehau 	struct ifreq *ifr = (struct ifreq *)data, ifr_vf;
36949c6cae24SSepherosa Ziehau 	struct ifnet *vf_ifp;
369515516c77SSepherosa Ziehau 	int mask, error = 0;
36968c068aa5SSepherosa Ziehau 	struct ifrsskey *ifrk;
36978c068aa5SSepherosa Ziehau 	struct ifrsshash *ifrh;
3698eb2fe044SSepherosa Ziehau 	uint32_t mtu;
369915516c77SSepherosa Ziehau 
370015516c77SSepherosa Ziehau 	switch (cmd) {
370115516c77SSepherosa Ziehau 	case SIOCSIFMTU:
370215516c77SSepherosa Ziehau 		if (ifr->ifr_mtu > HN_MTU_MAX) {
370315516c77SSepherosa Ziehau 			error = EINVAL;
370415516c77SSepherosa Ziehau 			break;
370515516c77SSepherosa Ziehau 		}
370615516c77SSepherosa Ziehau 
370715516c77SSepherosa Ziehau 		HN_LOCK(sc);
370815516c77SSepherosa Ziehau 
370915516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
371015516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
371115516c77SSepherosa Ziehau 			break;
371215516c77SSepherosa Ziehau 		}
371315516c77SSepherosa Ziehau 
371415516c77SSepherosa Ziehau 		if ((sc->hn_caps & HN_CAP_MTU) == 0) {
371515516c77SSepherosa Ziehau 			/* Can't change MTU */
371615516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
371715516c77SSepherosa Ziehau 			error = EOPNOTSUPP;
371815516c77SSepherosa Ziehau 			break;
371915516c77SSepherosa Ziehau 		}
372015516c77SSepherosa Ziehau 
372115516c77SSepherosa Ziehau 		if (ifp->if_mtu == ifr->ifr_mtu) {
372215516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
372315516c77SSepherosa Ziehau 			break;
372415516c77SSepherosa Ziehau 		}
372515516c77SSepherosa Ziehau 
37269c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
37279c6cae24SSepherosa Ziehau 			vf_ifp = sc->hn_vf_ifp;
37289c6cae24SSepherosa Ziehau 			ifr_vf = *ifr;
37299c6cae24SSepherosa Ziehau 			strlcpy(ifr_vf.ifr_name, vf_ifp->if_xname,
37309c6cae24SSepherosa Ziehau 			    sizeof(ifr_vf.ifr_name));
37319c6cae24SSepherosa Ziehau 			error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU,
37329c6cae24SSepherosa Ziehau 			    (caddr_t)&ifr_vf);
37339c6cae24SSepherosa Ziehau 			if (error) {
37349c6cae24SSepherosa Ziehau 				HN_UNLOCK(sc);
37359c6cae24SSepherosa Ziehau 				if_printf(ifp, "%s SIOCSIFMTU %d failed: %d\n",
37369c6cae24SSepherosa Ziehau 				    vf_ifp->if_xname, ifr->ifr_mtu, error);
37379c6cae24SSepherosa Ziehau 				break;
37389c6cae24SSepherosa Ziehau 			}
37399c6cae24SSepherosa Ziehau 		}
37409c6cae24SSepherosa Ziehau 
374115516c77SSepherosa Ziehau 		/*
374215516c77SSepherosa Ziehau 		 * Suspend this interface before the synthetic parts
374315516c77SSepherosa Ziehau 		 * are ripped.
374415516c77SSepherosa Ziehau 		 */
374515516c77SSepherosa Ziehau 		hn_suspend(sc);
374615516c77SSepherosa Ziehau 
374715516c77SSepherosa Ziehau 		/*
374815516c77SSepherosa Ziehau 		 * Detach the synthetics parts, i.e. NVS and RNDIS.
374915516c77SSepherosa Ziehau 		 */
375015516c77SSepherosa Ziehau 		hn_synth_detach(sc);
375115516c77SSepherosa Ziehau 
375215516c77SSepherosa Ziehau 		/*
375315516c77SSepherosa Ziehau 		 * Reattach the synthetic parts, i.e. NVS and RNDIS,
375415516c77SSepherosa Ziehau 		 * with the new MTU setting.
375515516c77SSepherosa Ziehau 		 */
375615516c77SSepherosa Ziehau 		error = hn_synth_attach(sc, ifr->ifr_mtu);
375715516c77SSepherosa Ziehau 		if (error) {
375815516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
375915516c77SSepherosa Ziehau 			break;
376015516c77SSepherosa Ziehau 		}
376115516c77SSepherosa Ziehau 
3762eb2fe044SSepherosa Ziehau 		error = hn_rndis_get_mtu(sc, &mtu);
3763eb2fe044SSepherosa Ziehau 		if (error)
3764eb2fe044SSepherosa Ziehau 			mtu = ifr->ifr_mtu;
3765eb2fe044SSepherosa Ziehau 		else if (bootverbose)
3766eb2fe044SSepherosa Ziehau 			if_printf(ifp, "RNDIS mtu %u\n", mtu);
3767eb2fe044SSepherosa Ziehau 
376815516c77SSepherosa Ziehau 		/*
376915516c77SSepherosa Ziehau 		 * Commit the requested MTU, after the synthetic parts
377015516c77SSepherosa Ziehau 		 * have been successfully attached.
377115516c77SSepherosa Ziehau 		 */
3772eb2fe044SSepherosa Ziehau 		if (mtu >= ifr->ifr_mtu) {
3773eb2fe044SSepherosa Ziehau 			mtu = ifr->ifr_mtu;
3774eb2fe044SSepherosa Ziehau 		} else {
3775eb2fe044SSepherosa Ziehau 			if_printf(ifp, "fixup mtu %d -> %u\n",
3776eb2fe044SSepherosa Ziehau 			    ifr->ifr_mtu, mtu);
3777eb2fe044SSepherosa Ziehau 		}
3778eb2fe044SSepherosa Ziehau 		ifp->if_mtu = mtu;
377915516c77SSepherosa Ziehau 
378015516c77SSepherosa Ziehau 		/*
37819c6cae24SSepherosa Ziehau 		 * Synthetic parts' reattach may change the chimney
37829c6cae24SSepherosa Ziehau 		 * sending size; update it.
378315516c77SSepherosa Ziehau 		 */
378415516c77SSepherosa Ziehau 		if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax)
378515516c77SSepherosa Ziehau 			hn_set_chim_size(sc, sc->hn_chim_szmax);
37869c6cae24SSepherosa Ziehau 
37879c6cae24SSepherosa Ziehau 		/*
37889c6cae24SSepherosa Ziehau 		 * Make sure that various parameters based on MTU are
37899c6cae24SSepherosa Ziehau 		 * still valid, after the MTU change.
37909c6cae24SSepherosa Ziehau 		 */
37919c6cae24SSepherosa Ziehau 		hn_mtu_change_fixup(sc);
379215516c77SSepherosa Ziehau 
379315516c77SSepherosa Ziehau 		/*
379415516c77SSepherosa Ziehau 		 * All done!  Resume the interface now.
379515516c77SSepherosa Ziehau 		 */
379615516c77SSepherosa Ziehau 		hn_resume(sc);
379715516c77SSepherosa Ziehau 
3798d0cd8231SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXVF) ||
3799d0cd8231SSepherosa Ziehau 		    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
38009c6cae24SSepherosa Ziehau 			/*
38019c6cae24SSepherosa Ziehau 			 * Since we have reattached the NVS part,
38029c6cae24SSepherosa Ziehau 			 * change the datapath to VF again; in case
38039c6cae24SSepherosa Ziehau 			 * that it is lost, after the NVS was detached.
38049c6cae24SSepherosa Ziehau 			 */
38059c6cae24SSepherosa Ziehau 			hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF);
38069c6cae24SSepherosa Ziehau 		}
38079c6cae24SSepherosa Ziehau 
380815516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
380915516c77SSepherosa Ziehau 		break;
381015516c77SSepherosa Ziehau 
381115516c77SSepherosa Ziehau 	case SIOCSIFFLAGS:
381215516c77SSepherosa Ziehau 		HN_LOCK(sc);
381315516c77SSepherosa Ziehau 
381415516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
381515516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
381615516c77SSepherosa Ziehau 			break;
381715516c77SSepherosa Ziehau 		}
381815516c77SSepherosa Ziehau 
38199c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc))
38209c6cae24SSepherosa Ziehau 			hn_xpnt_vf_saveifflags(sc);
38219c6cae24SSepherosa Ziehau 
382215516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_UP) {
3823fdc4f478SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
3824fdc4f478SSepherosa Ziehau 				/*
3825fdc4f478SSepherosa Ziehau 				 * Caller meight hold mutex, e.g.
3826fdc4f478SSepherosa Ziehau 				 * bpf; use busy-wait for the RNDIS
3827fdc4f478SSepherosa Ziehau 				 * reply.
3828fdc4f478SSepherosa Ziehau 				 */
3829fdc4f478SSepherosa Ziehau 				HN_NO_SLEEPING(sc);
3830c08f7b2cSSepherosa Ziehau 				hn_rxfilter_config(sc);
3831fdc4f478SSepherosa Ziehau 				HN_SLEEPING_OK(sc);
38329c6cae24SSepherosa Ziehau 
38339c6cae24SSepherosa Ziehau 				if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
38349c6cae24SSepherosa Ziehau 					error = hn_xpnt_vf_iocsetflags(sc);
3835fdc4f478SSepherosa Ziehau 			} else {
383615516c77SSepherosa Ziehau 				hn_init_locked(sc);
3837fdc4f478SSepherosa Ziehau 			}
383815516c77SSepherosa Ziehau 		} else {
383915516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
38405bdfd3fdSDexuan Cui 				hn_stop(sc, false);
384115516c77SSepherosa Ziehau 		}
384215516c77SSepherosa Ziehau 		sc->hn_if_flags = ifp->if_flags;
384315516c77SSepherosa Ziehau 
384415516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
384515516c77SSepherosa Ziehau 		break;
384615516c77SSepherosa Ziehau 
384715516c77SSepherosa Ziehau 	case SIOCSIFCAP:
384815516c77SSepherosa Ziehau 		HN_LOCK(sc);
38499c6cae24SSepherosa Ziehau 
38509c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
38519c6cae24SSepherosa Ziehau 			ifr_vf = *ifr;
38529c6cae24SSepherosa Ziehau 			strlcpy(ifr_vf.ifr_name, sc->hn_vf_ifp->if_xname,
38539c6cae24SSepherosa Ziehau 			    sizeof(ifr_vf.ifr_name));
38549c6cae24SSepherosa Ziehau 			error = hn_xpnt_vf_iocsetcaps(sc, &ifr_vf);
38559c6cae24SSepherosa Ziehau 			HN_UNLOCK(sc);
38569c6cae24SSepherosa Ziehau 			break;
38579c6cae24SSepherosa Ziehau 		}
38589c6cae24SSepherosa Ziehau 
38599c6cae24SSepherosa Ziehau 		/*
38609c6cae24SSepherosa Ziehau 		 * Fix up requested capabilities w/ supported capabilities,
38619c6cae24SSepherosa Ziehau 		 * since the supported capabilities could have been changed.
38629c6cae24SSepherosa Ziehau 		 */
38639c6cae24SSepherosa Ziehau 		mask = (ifr->ifr_reqcap & ifp->if_capabilities) ^
38649c6cae24SSepherosa Ziehau 		    ifp->if_capenable;
386515516c77SSepherosa Ziehau 
386615516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM) {
386715516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM;
386815516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM)
386915516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc);
387015516c77SSepherosa Ziehau 			else
387115516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc);
387215516c77SSepherosa Ziehau 		}
387315516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM_IPV6) {
387415516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
387515516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
387615516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc);
387715516c77SSepherosa Ziehau 			else
387815516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc);
387915516c77SSepherosa Ziehau 		}
388015516c77SSepherosa Ziehau 
388115516c77SSepherosa Ziehau 		/* TODO: flip RNDIS offload parameters for RXCSUM. */
388215516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM)
388315516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM;
388415516c77SSepherosa Ziehau #ifdef foo
388515516c77SSepherosa Ziehau 		/* We can't diff IPv6 packets from IPv4 packets on RX path. */
388615516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM_IPV6)
388715516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
388815516c77SSepherosa Ziehau #endif
388915516c77SSepherosa Ziehau 
389015516c77SSepherosa Ziehau 		if (mask & IFCAP_LRO)
389115516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_LRO;
389215516c77SSepherosa Ziehau 
389315516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO4) {
389415516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO4;
389515516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO4)
389615516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP_TSO;
389715516c77SSepherosa Ziehau 			else
389815516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP_TSO;
389915516c77SSepherosa Ziehau 		}
390015516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO6) {
390115516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO6;
390215516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO6)
390315516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP6_TSO;
390415516c77SSepherosa Ziehau 			else
390515516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP6_TSO;
390615516c77SSepherosa Ziehau 		}
390715516c77SSepherosa Ziehau 
390815516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
390915516c77SSepherosa Ziehau 		break;
391015516c77SSepherosa Ziehau 
391115516c77SSepherosa Ziehau 	case SIOCADDMULTI:
391215516c77SSepherosa Ziehau 	case SIOCDELMULTI:
391315516c77SSepherosa Ziehau 		HN_LOCK(sc);
391415516c77SSepherosa Ziehau 
391515516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
391615516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
391715516c77SSepherosa Ziehau 			break;
391815516c77SSepherosa Ziehau 		}
3919fdc4f478SSepherosa Ziehau 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
3920fdc4f478SSepherosa Ziehau 			/*
3921fdc4f478SSepherosa Ziehau 			 * Multicast uses mutex; use busy-wait for
3922fdc4f478SSepherosa Ziehau 			 * the RNDIS reply.
3923fdc4f478SSepherosa Ziehau 			 */
3924fdc4f478SSepherosa Ziehau 			HN_NO_SLEEPING(sc);
3925c08f7b2cSSepherosa Ziehau 			hn_rxfilter_config(sc);
3926fdc4f478SSepherosa Ziehau 			HN_SLEEPING_OK(sc);
3927fdc4f478SSepherosa Ziehau 		}
392815516c77SSepherosa Ziehau 
39299c6cae24SSepherosa Ziehau 		/* XXX vlan(4) style mcast addr maintenance */
39309c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
39319c6cae24SSepherosa Ziehau 			int old_if_flags;
39329c6cae24SSepherosa Ziehau 
39339c6cae24SSepherosa Ziehau 			old_if_flags = sc->hn_vf_ifp->if_flags;
39349c6cae24SSepherosa Ziehau 			hn_xpnt_vf_saveifflags(sc);
39359c6cae24SSepherosa Ziehau 
39369c6cae24SSepherosa Ziehau 			if ((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) &&
39379c6cae24SSepherosa Ziehau 			    ((old_if_flags ^ sc->hn_vf_ifp->if_flags) &
39389c6cae24SSepherosa Ziehau 			     IFF_ALLMULTI))
39399c6cae24SSepherosa Ziehau 				error = hn_xpnt_vf_iocsetflags(sc);
39409c6cae24SSepherosa Ziehau 		}
39419c6cae24SSepherosa Ziehau 
394215516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
394315516c77SSepherosa Ziehau 		break;
394415516c77SSepherosa Ziehau 
394515516c77SSepherosa Ziehau 	case SIOCSIFMEDIA:
394615516c77SSepherosa Ziehau 	case SIOCGIFMEDIA:
39479c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
39489c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
39499c6cae24SSepherosa Ziehau 			/*
39509c6cae24SSepherosa Ziehau 			 * SIOCGIFMEDIA expects ifmediareq, so don't
39519c6cae24SSepherosa Ziehau 			 * create and pass ifr_vf to the VF here; just
39529c6cae24SSepherosa Ziehau 			 * replace the ifr_name.
39539c6cae24SSepherosa Ziehau 			 */
39549c6cae24SSepherosa Ziehau 			vf_ifp = sc->hn_vf_ifp;
39559c6cae24SSepherosa Ziehau 			strlcpy(ifr->ifr_name, vf_ifp->if_xname,
39569c6cae24SSepherosa Ziehau 			    sizeof(ifr->ifr_name));
39579c6cae24SSepherosa Ziehau 			error = vf_ifp->if_ioctl(vf_ifp, cmd, data);
39589c6cae24SSepherosa Ziehau 			/* Restore the ifr_name. */
39599c6cae24SSepherosa Ziehau 			strlcpy(ifr->ifr_name, ifp->if_xname,
39609c6cae24SSepherosa Ziehau 			    sizeof(ifr->ifr_name));
39619c6cae24SSepherosa Ziehau 			HN_UNLOCK(sc);
39629c6cae24SSepherosa Ziehau 			break;
39639c6cae24SSepherosa Ziehau 		}
39649c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
396515516c77SSepherosa Ziehau 		error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd);
396615516c77SSepherosa Ziehau 		break;
396715516c77SSepherosa Ziehau 
39688c068aa5SSepherosa Ziehau 	case SIOCGIFRSSHASH:
39698c068aa5SSepherosa Ziehau 		ifrh = (struct ifrsshash *)data;
39708c068aa5SSepherosa Ziehau 		HN_LOCK(sc);
39718c068aa5SSepherosa Ziehau 		if (sc->hn_rx_ring_inuse == 1) {
39728c068aa5SSepherosa Ziehau 			HN_UNLOCK(sc);
39738c068aa5SSepherosa Ziehau 			ifrh->ifrh_func = RSS_FUNC_NONE;
39748c068aa5SSepherosa Ziehau 			ifrh->ifrh_types = 0;
39758c068aa5SSepherosa Ziehau 			break;
39768c068aa5SSepherosa Ziehau 		}
39778c068aa5SSepherosa Ziehau 
39788c068aa5SSepherosa Ziehau 		if (sc->hn_rss_hash & NDIS_HASH_FUNCTION_TOEPLITZ)
39798c068aa5SSepherosa Ziehau 			ifrh->ifrh_func = RSS_FUNC_TOEPLITZ;
39808c068aa5SSepherosa Ziehau 		else
39818c068aa5SSepherosa Ziehau 			ifrh->ifrh_func = RSS_FUNC_PRIVATE;
3982642ec226SSepherosa Ziehau 		ifrh->ifrh_types = hn_rss_type_fromndis(sc->hn_rss_hash);
39838c068aa5SSepherosa Ziehau 		HN_UNLOCK(sc);
39848c068aa5SSepherosa Ziehau 		break;
39858c068aa5SSepherosa Ziehau 
39868c068aa5SSepherosa Ziehau 	case SIOCGIFRSSKEY:
39878c068aa5SSepherosa Ziehau 		ifrk = (struct ifrsskey *)data;
39888c068aa5SSepherosa Ziehau 		HN_LOCK(sc);
39898c068aa5SSepherosa Ziehau 		if (sc->hn_rx_ring_inuse == 1) {
39908c068aa5SSepherosa Ziehau 			HN_UNLOCK(sc);
39918c068aa5SSepherosa Ziehau 			ifrk->ifrk_func = RSS_FUNC_NONE;
39928c068aa5SSepherosa Ziehau 			ifrk->ifrk_keylen = 0;
39938c068aa5SSepherosa Ziehau 			break;
39948c068aa5SSepherosa Ziehau 		}
39958c068aa5SSepherosa Ziehau 		if (sc->hn_rss_hash & NDIS_HASH_FUNCTION_TOEPLITZ)
39968c068aa5SSepherosa Ziehau 			ifrk->ifrk_func = RSS_FUNC_TOEPLITZ;
39978c068aa5SSepherosa Ziehau 		else
39988c068aa5SSepherosa Ziehau 			ifrk->ifrk_func = RSS_FUNC_PRIVATE;
39998c068aa5SSepherosa Ziehau 		ifrk->ifrk_keylen = NDIS_HASH_KEYSIZE_TOEPLITZ;
40008c068aa5SSepherosa Ziehau 		memcpy(ifrk->ifrk_key, sc->hn_rss.rss_key,
40018c068aa5SSepherosa Ziehau 		    NDIS_HASH_KEYSIZE_TOEPLITZ);
40028c068aa5SSepherosa Ziehau 		HN_UNLOCK(sc);
40038c068aa5SSepherosa Ziehau 		break;
40048c068aa5SSepherosa Ziehau 
400515516c77SSepherosa Ziehau 	default:
400615516c77SSepherosa Ziehau 		error = ether_ioctl(ifp, cmd, data);
400715516c77SSepherosa Ziehau 		break;
400815516c77SSepherosa Ziehau 	}
400915516c77SSepherosa Ziehau 	return (error);
401015516c77SSepherosa Ziehau }
401115516c77SSepherosa Ziehau 
401215516c77SSepherosa Ziehau static void
40135bdfd3fdSDexuan Cui hn_stop(struct hn_softc *sc, bool detaching)
401415516c77SSepherosa Ziehau {
401515516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
401615516c77SSepherosa Ziehau 	int i;
401715516c77SSepherosa Ziehau 
401815516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
401915516c77SSepherosa Ziehau 
402015516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
402115516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
402215516c77SSepherosa Ziehau 
40239c6cae24SSepherosa Ziehau 	/* Clear RUNNING bit ASAP. */
40249c6cae24SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
40259c6cae24SSepherosa Ziehau 
40266c1204dfSSepherosa Ziehau 	/* Disable polling. */
40276c1204dfSSepherosa Ziehau 	hn_polling(sc, 0);
40286c1204dfSSepherosa Ziehau 
40299c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) {
40309c6cae24SSepherosa Ziehau 		KASSERT(sc->hn_vf_ifp != NULL,
40319c6cae24SSepherosa Ziehau 		    ("%s: VF is not attached", ifp->if_xname));
40329c6cae24SSepherosa Ziehau 
4033a97fff19SSepherosa Ziehau 		/* Mark transparent mode VF as disabled. */
4034a97fff19SSepherosa Ziehau 		hn_xpnt_vf_setdisable(sc, false /* keep hn_vf_ifp */);
40359c6cae24SSepherosa Ziehau 
40369c6cae24SSepherosa Ziehau 		/*
40379c6cae24SSepherosa Ziehau 		 * NOTE:
40389c6cae24SSepherosa Ziehau 		 * Datapath setting must happen _before_ bringing
40399c6cae24SSepherosa Ziehau 		 * the VF down.
40409c6cae24SSepherosa Ziehau 		 */
40419c6cae24SSepherosa Ziehau 		hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH);
40429c6cae24SSepherosa Ziehau 
40439c6cae24SSepherosa Ziehau 		/*
40449c6cae24SSepherosa Ziehau 		 * Bring the VF down.
40459c6cae24SSepherosa Ziehau 		 */
40469c6cae24SSepherosa Ziehau 		hn_xpnt_vf_saveifflags(sc);
40479c6cae24SSepherosa Ziehau 		sc->hn_vf_ifp->if_flags &= ~IFF_UP;
40489c6cae24SSepherosa Ziehau 		hn_xpnt_vf_iocsetflags(sc);
40499c6cae24SSepherosa Ziehau 	}
40509c6cae24SSepherosa Ziehau 
40519c6cae24SSepherosa Ziehau 	/* Suspend data transfers. */
405215516c77SSepherosa Ziehau 	hn_suspend_data(sc);
405315516c77SSepherosa Ziehau 
405415516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
405515516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
405615516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
405715516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
40585bdfd3fdSDexuan Cui 
40595bdfd3fdSDexuan Cui 	/*
40609c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is active, make sure
40619c6cae24SSepherosa Ziehau 	 * that the RX filter still allows packet reception.
40625bdfd3fdSDexuan Cui 	 */
4063962f0357SSepherosa Ziehau 	if (!detaching && (sc->hn_flags & HN_FLAG_RXVF))
40645bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
406515516c77SSepherosa Ziehau }
406615516c77SSepherosa Ziehau 
406715516c77SSepherosa Ziehau static void
406815516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc)
406915516c77SSepherosa Ziehau {
407015516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
407115516c77SSepherosa Ziehau 	int i;
407215516c77SSepherosa Ziehau 
407315516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
407415516c77SSepherosa Ziehau 
407515516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
407615516c77SSepherosa Ziehau 		return;
407715516c77SSepherosa Ziehau 
407815516c77SSepherosa Ziehau 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
407915516c77SSepherosa Ziehau 		return;
408015516c77SSepherosa Ziehau 
408115516c77SSepherosa Ziehau 	/* Configure RX filter */
4082c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
408315516c77SSepherosa Ziehau 
408415516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
408515516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
408615516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
408715516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
408815516c77SSepherosa Ziehau 
408915516c77SSepherosa Ziehau 	/* Clear TX 'suspended' bit. */
409015516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_inuse);
409115516c77SSepherosa Ziehau 
40929c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_isready(sc)) {
40939c6cae24SSepherosa Ziehau 		/* Initialize transparent VF. */
40949c6cae24SSepherosa Ziehau 		hn_xpnt_vf_init(sc);
40959c6cae24SSepherosa Ziehau 	}
40969c6cae24SSepherosa Ziehau 
409715516c77SSepherosa Ziehau 	/* Everything is ready; unleash! */
409815516c77SSepherosa Ziehau 	atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
40996c1204dfSSepherosa Ziehau 
41006c1204dfSSepherosa Ziehau 	/* Re-enable polling if requested. */
41016c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz > 0)
41026c1204dfSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
410315516c77SSepherosa Ziehau }
410415516c77SSepherosa Ziehau 
410515516c77SSepherosa Ziehau static void
410615516c77SSepherosa Ziehau hn_init(void *xsc)
410715516c77SSepherosa Ziehau {
410815516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
410915516c77SSepherosa Ziehau 
411015516c77SSepherosa Ziehau 	HN_LOCK(sc);
411115516c77SSepherosa Ziehau 	hn_init_locked(sc);
411215516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
411315516c77SSepherosa Ziehau }
411415516c77SSepherosa Ziehau 
411515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
411615516c77SSepherosa Ziehau 
411715516c77SSepherosa Ziehau static int
411815516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
411915516c77SSepherosa Ziehau {
412015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
412115516c77SSepherosa Ziehau 	unsigned int lenlim;
412215516c77SSepherosa Ziehau 	int error;
412315516c77SSepherosa Ziehau 
412415516c77SSepherosa Ziehau 	lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim;
412515516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &lenlim, 0, req);
412615516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
412715516c77SSepherosa Ziehau 		return error;
412815516c77SSepherosa Ziehau 
412915516c77SSepherosa Ziehau 	HN_LOCK(sc);
413015516c77SSepherosa Ziehau 	if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) ||
413115516c77SSepherosa Ziehau 	    lenlim > TCP_LRO_LENGTH_MAX) {
413215516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
413315516c77SSepherosa Ziehau 		return EINVAL;
413415516c77SSepherosa Ziehau 	}
413515516c77SSepherosa Ziehau 	hn_set_lro_lenlim(sc, lenlim);
413615516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
413715516c77SSepherosa Ziehau 
413815516c77SSepherosa Ziehau 	return 0;
413915516c77SSepherosa Ziehau }
414015516c77SSepherosa Ziehau 
414115516c77SSepherosa Ziehau static int
414215516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS)
414315516c77SSepherosa Ziehau {
414415516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
414515516c77SSepherosa Ziehau 	int ackcnt, error, i;
414615516c77SSepherosa Ziehau 
414715516c77SSepherosa Ziehau 	/*
414815516c77SSepherosa Ziehau 	 * lro_ackcnt_lim is append count limit,
414915516c77SSepherosa Ziehau 	 * +1 to turn it into aggregation limit.
415015516c77SSepherosa Ziehau 	 */
415115516c77SSepherosa Ziehau 	ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1;
415215516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &ackcnt, 0, req);
415315516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
415415516c77SSepherosa Ziehau 		return error;
415515516c77SSepherosa Ziehau 
415615516c77SSepherosa Ziehau 	if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1))
415715516c77SSepherosa Ziehau 		return EINVAL;
415815516c77SSepherosa Ziehau 
415915516c77SSepherosa Ziehau 	/*
416015516c77SSepherosa Ziehau 	 * Convert aggregation limit back to append
416115516c77SSepherosa Ziehau 	 * count limit.
416215516c77SSepherosa Ziehau 	 */
416315516c77SSepherosa Ziehau 	--ackcnt;
416415516c77SSepherosa Ziehau 	HN_LOCK(sc);
4165a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
416615516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt;
416715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
416815516c77SSepherosa Ziehau 	return 0;
416915516c77SSepherosa Ziehau }
417015516c77SSepherosa Ziehau 
417115516c77SSepherosa Ziehau #endif
417215516c77SSepherosa Ziehau 
417315516c77SSepherosa Ziehau static int
417415516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS)
417515516c77SSepherosa Ziehau {
417615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
417715516c77SSepherosa Ziehau 	int hcsum = arg2;
417815516c77SSepherosa Ziehau 	int on, error, i;
417915516c77SSepherosa Ziehau 
418015516c77SSepherosa Ziehau 	on = 0;
418115516c77SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum)
418215516c77SSepherosa Ziehau 		on = 1;
418315516c77SSepherosa Ziehau 
418415516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &on, 0, req);
418515516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
418615516c77SSepherosa Ziehau 		return error;
418715516c77SSepherosa Ziehau 
418815516c77SSepherosa Ziehau 	HN_LOCK(sc);
4189a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
419015516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
419115516c77SSepherosa Ziehau 
419215516c77SSepherosa Ziehau 		if (on)
419315516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= hcsum;
419415516c77SSepherosa Ziehau 		else
419515516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum &= ~hcsum;
419615516c77SSepherosa Ziehau 	}
419715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
419815516c77SSepherosa Ziehau 	return 0;
419915516c77SSepherosa Ziehau }
420015516c77SSepherosa Ziehau 
420115516c77SSepherosa Ziehau static int
420215516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS)
420315516c77SSepherosa Ziehau {
420415516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
420515516c77SSepherosa Ziehau 	int chim_size, error;
420615516c77SSepherosa Ziehau 
420715516c77SSepherosa Ziehau 	chim_size = sc->hn_tx_ring[0].hn_chim_size;
420815516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &chim_size, 0, req);
420915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
421015516c77SSepherosa Ziehau 		return error;
421115516c77SSepherosa Ziehau 
421215516c77SSepherosa Ziehau 	if (chim_size > sc->hn_chim_szmax || chim_size <= 0)
421315516c77SSepherosa Ziehau 		return EINVAL;
421415516c77SSepherosa Ziehau 
421515516c77SSepherosa Ziehau 	HN_LOCK(sc);
421615516c77SSepherosa Ziehau 	hn_set_chim_size(sc, chim_size);
421715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
421815516c77SSepherosa Ziehau 	return 0;
421915516c77SSepherosa Ziehau }
422015516c77SSepherosa Ziehau 
422115516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
422215516c77SSepherosa Ziehau static int
422315516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS)
422415516c77SSepherosa Ziehau {
422515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
422615516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
422715516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
422815516c77SSepherosa Ziehau 	uint64_t stat;
422915516c77SSepherosa Ziehau 
423015516c77SSepherosa Ziehau 	stat = 0;
423115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
423215516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
423315516c77SSepherosa Ziehau 		stat += *((int *)((uint8_t *)rxr + ofs));
423415516c77SSepherosa Ziehau 	}
423515516c77SSepherosa Ziehau 
423615516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
423715516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
423815516c77SSepherosa Ziehau 		return error;
423915516c77SSepherosa Ziehau 
424015516c77SSepherosa Ziehau 	/* Zero out this stat. */
424115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
424215516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
424315516c77SSepherosa Ziehau 		*((int *)((uint8_t *)rxr + ofs)) = 0;
424415516c77SSepherosa Ziehau 	}
424515516c77SSepherosa Ziehau 	return 0;
424615516c77SSepherosa Ziehau }
424715516c77SSepherosa Ziehau #else
424815516c77SSepherosa Ziehau static int
424915516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS)
425015516c77SSepherosa Ziehau {
425115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
425215516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
425315516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
425415516c77SSepherosa Ziehau 	uint64_t stat;
425515516c77SSepherosa Ziehau 
425615516c77SSepherosa Ziehau 	stat = 0;
4257a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
425815516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
425915516c77SSepherosa Ziehau 		stat += *((uint64_t *)((uint8_t *)rxr + ofs));
426015516c77SSepherosa Ziehau 	}
426115516c77SSepherosa Ziehau 
426215516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
426315516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
426415516c77SSepherosa Ziehau 		return error;
426515516c77SSepherosa Ziehau 
426615516c77SSepherosa Ziehau 	/* Zero out this stat. */
4267a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
426815516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
426915516c77SSepherosa Ziehau 		*((uint64_t *)((uint8_t *)rxr + ofs)) = 0;
427015516c77SSepherosa Ziehau 	}
427115516c77SSepherosa Ziehau 	return 0;
427215516c77SSepherosa Ziehau }
427315516c77SSepherosa Ziehau 
427415516c77SSepherosa Ziehau #endif
427515516c77SSepherosa Ziehau 
427615516c77SSepherosa Ziehau static int
427715516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
427815516c77SSepherosa Ziehau {
427915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
428015516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
428115516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
428215516c77SSepherosa Ziehau 	u_long stat;
428315516c77SSepherosa Ziehau 
428415516c77SSepherosa Ziehau 	stat = 0;
4285a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
428615516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
428715516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)rxr + ofs));
428815516c77SSepherosa Ziehau 	}
428915516c77SSepherosa Ziehau 
429015516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
429115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
429215516c77SSepherosa Ziehau 		return error;
429315516c77SSepherosa Ziehau 
429415516c77SSepherosa Ziehau 	/* Zero out this stat. */
4295a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
429615516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
429715516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)rxr + ofs)) = 0;
429815516c77SSepherosa Ziehau 	}
429915516c77SSepherosa Ziehau 	return 0;
430015516c77SSepherosa Ziehau }
430115516c77SSepherosa Ziehau 
430215516c77SSepherosa Ziehau static int
430315516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
430415516c77SSepherosa Ziehau {
430515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
430615516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
430715516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
430815516c77SSepherosa Ziehau 	u_long stat;
430915516c77SSepherosa Ziehau 
431015516c77SSepherosa Ziehau 	stat = 0;
4311a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
431215516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
431315516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)txr + ofs));
431415516c77SSepherosa Ziehau 	}
431515516c77SSepherosa Ziehau 
431615516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
431715516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
431815516c77SSepherosa Ziehau 		return error;
431915516c77SSepherosa Ziehau 
432015516c77SSepherosa Ziehau 	/* Zero out this stat. */
4321a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
432215516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
432315516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)txr + ofs)) = 0;
432415516c77SSepherosa Ziehau 	}
432515516c77SSepherosa Ziehau 	return 0;
432615516c77SSepherosa Ziehau }
432715516c77SSepherosa Ziehau 
432815516c77SSepherosa Ziehau static int
432915516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS)
433015516c77SSepherosa Ziehau {
433115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
433215516c77SSepherosa Ziehau 	int ofs = arg2, i, error, conf;
433315516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
433415516c77SSepherosa Ziehau 
433515516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[0];
433615516c77SSepherosa Ziehau 	conf = *((int *)((uint8_t *)txr + ofs));
433715516c77SSepherosa Ziehau 
433815516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &conf, 0, req);
433915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
434015516c77SSepherosa Ziehau 		return error;
434115516c77SSepherosa Ziehau 
434215516c77SSepherosa Ziehau 	HN_LOCK(sc);
4343a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
434415516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
434515516c77SSepherosa Ziehau 		*((int *)((uint8_t *)txr + ofs)) = conf;
434615516c77SSepherosa Ziehau 	}
434715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
434815516c77SSepherosa Ziehau 
434915516c77SSepherosa Ziehau 	return 0;
435015516c77SSepherosa Ziehau }
435115516c77SSepherosa Ziehau 
435215516c77SSepherosa Ziehau static int
4353dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS)
4354dc13fee6SSepherosa Ziehau {
4355dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4356dc13fee6SSepherosa Ziehau 	int error, size;
4357dc13fee6SSepherosa Ziehau 
4358dc13fee6SSepherosa Ziehau 	size = sc->hn_agg_size;
4359dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &size, 0, req);
4360dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
4361dc13fee6SSepherosa Ziehau 		return (error);
4362dc13fee6SSepherosa Ziehau 
4363dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
4364dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = size;
4365dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
4366dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
4367dc13fee6SSepherosa Ziehau 
4368dc13fee6SSepherosa Ziehau 	return (0);
4369dc13fee6SSepherosa Ziehau }
4370dc13fee6SSepherosa Ziehau 
4371dc13fee6SSepherosa Ziehau static int
4372dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS)
4373dc13fee6SSepherosa Ziehau {
4374dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4375dc13fee6SSepherosa Ziehau 	int error, pkts;
4376dc13fee6SSepherosa Ziehau 
4377dc13fee6SSepherosa Ziehau 	pkts = sc->hn_agg_pkts;
4378dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pkts, 0, req);
4379dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
4380dc13fee6SSepherosa Ziehau 		return (error);
4381dc13fee6SSepherosa Ziehau 
4382dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
4383dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = pkts;
4384dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
4385dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
4386dc13fee6SSepherosa Ziehau 
4387dc13fee6SSepherosa Ziehau 	return (0);
4388dc13fee6SSepherosa Ziehau }
4389dc13fee6SSepherosa Ziehau 
4390dc13fee6SSepherosa Ziehau static int
4391dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS)
4392dc13fee6SSepherosa Ziehau {
4393dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4394dc13fee6SSepherosa Ziehau 	int pkts;
4395dc13fee6SSepherosa Ziehau 
4396dc13fee6SSepherosa Ziehau 	pkts = sc->hn_tx_ring[0].hn_agg_pktmax;
4397dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &pkts, 0, req));
4398dc13fee6SSepherosa Ziehau }
4399dc13fee6SSepherosa Ziehau 
4400dc13fee6SSepherosa Ziehau static int
4401dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS)
4402dc13fee6SSepherosa Ziehau {
4403dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4404dc13fee6SSepherosa Ziehau 	int align;
4405dc13fee6SSepherosa Ziehau 
4406dc13fee6SSepherosa Ziehau 	align = sc->hn_tx_ring[0].hn_agg_align;
4407dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &align, 0, req));
4408dc13fee6SSepherosa Ziehau }
4409dc13fee6SSepherosa Ziehau 
44106c1204dfSSepherosa Ziehau static void
44116c1204dfSSepherosa Ziehau hn_chan_polling(struct vmbus_channel *chan, u_int pollhz)
44126c1204dfSSepherosa Ziehau {
44136c1204dfSSepherosa Ziehau 	if (pollhz == 0)
44146c1204dfSSepherosa Ziehau 		vmbus_chan_poll_disable(chan);
44156c1204dfSSepherosa Ziehau 	else
44166c1204dfSSepherosa Ziehau 		vmbus_chan_poll_enable(chan, pollhz);
44176c1204dfSSepherosa Ziehau }
44186c1204dfSSepherosa Ziehau 
44196c1204dfSSepherosa Ziehau static void
44206c1204dfSSepherosa Ziehau hn_polling(struct hn_softc *sc, u_int pollhz)
44216c1204dfSSepherosa Ziehau {
44226c1204dfSSepherosa Ziehau 	int nsubch = sc->hn_rx_ring_inuse - 1;
44236c1204dfSSepherosa Ziehau 
44246c1204dfSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
44256c1204dfSSepherosa Ziehau 
44266c1204dfSSepherosa Ziehau 	if (nsubch > 0) {
44276c1204dfSSepherosa Ziehau 		struct vmbus_channel **subch;
44286c1204dfSSepherosa Ziehau 		int i;
44296c1204dfSSepherosa Ziehau 
44306c1204dfSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
44316c1204dfSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
44326c1204dfSSepherosa Ziehau 			hn_chan_polling(subch[i], pollhz);
44336c1204dfSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
44346c1204dfSSepherosa Ziehau 	}
44356c1204dfSSepherosa Ziehau 	hn_chan_polling(sc->hn_prichan, pollhz);
44366c1204dfSSepherosa Ziehau }
44376c1204dfSSepherosa Ziehau 
44386c1204dfSSepherosa Ziehau static int
44396c1204dfSSepherosa Ziehau hn_polling_sysctl(SYSCTL_HANDLER_ARGS)
44406c1204dfSSepherosa Ziehau {
44416c1204dfSSepherosa Ziehau 	struct hn_softc *sc = arg1;
44426c1204dfSSepherosa Ziehau 	int pollhz, error;
44436c1204dfSSepherosa Ziehau 
44446c1204dfSSepherosa Ziehau 	pollhz = sc->hn_pollhz;
44456c1204dfSSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pollhz, 0, req);
44466c1204dfSSepherosa Ziehau 	if (error || req->newptr == NULL)
44476c1204dfSSepherosa Ziehau 		return (error);
44486c1204dfSSepherosa Ziehau 
44496c1204dfSSepherosa Ziehau 	if (pollhz != 0 &&
44506c1204dfSSepherosa Ziehau 	    (pollhz < VMBUS_CHAN_POLLHZ_MIN || pollhz > VMBUS_CHAN_POLLHZ_MAX))
44516c1204dfSSepherosa Ziehau 		return (EINVAL);
44526c1204dfSSepherosa Ziehau 
44536c1204dfSSepherosa Ziehau 	HN_LOCK(sc);
44546c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz != pollhz) {
44556c1204dfSSepherosa Ziehau 		sc->hn_pollhz = pollhz;
44566c1204dfSSepherosa Ziehau 		if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) &&
44576c1204dfSSepherosa Ziehau 		    (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
44586c1204dfSSepherosa Ziehau 			hn_polling(sc, sc->hn_pollhz);
44596c1204dfSSepherosa Ziehau 	}
44606c1204dfSSepherosa Ziehau 	HN_UNLOCK(sc);
44616c1204dfSSepherosa Ziehau 
44626c1204dfSSepherosa Ziehau 	return (0);
44636c1204dfSSepherosa Ziehau }
44646c1204dfSSepherosa Ziehau 
4465dc13fee6SSepherosa Ziehau static int
446615516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS)
446715516c77SSepherosa Ziehau {
446815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
446915516c77SSepherosa Ziehau 	char verstr[16];
447015516c77SSepherosa Ziehau 
447115516c77SSepherosa Ziehau 	snprintf(verstr, sizeof(verstr), "%u.%u",
447215516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
447315516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
447415516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
447515516c77SSepherosa Ziehau }
447615516c77SSepherosa Ziehau 
447715516c77SSepherosa Ziehau static int
447815516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS)
447915516c77SSepherosa Ziehau {
448015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
448115516c77SSepherosa Ziehau 	char caps_str[128];
448215516c77SSepherosa Ziehau 	uint32_t caps;
448315516c77SSepherosa Ziehau 
448415516c77SSepherosa Ziehau 	HN_LOCK(sc);
448515516c77SSepherosa Ziehau 	caps = sc->hn_caps;
448615516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
448715516c77SSepherosa Ziehau 	snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS);
448815516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req);
448915516c77SSepherosa Ziehau }
449015516c77SSepherosa Ziehau 
449115516c77SSepherosa Ziehau static int
449215516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS)
449315516c77SSepherosa Ziehau {
449415516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
449515516c77SSepherosa Ziehau 	char assist_str[128];
449615516c77SSepherosa Ziehau 	uint32_t hwassist;
449715516c77SSepherosa Ziehau 
449815516c77SSepherosa Ziehau 	HN_LOCK(sc);
449915516c77SSepherosa Ziehau 	hwassist = sc->hn_ifp->if_hwassist;
450015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
450115516c77SSepherosa Ziehau 	snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS);
450215516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req);
450315516c77SSepherosa Ziehau }
450415516c77SSepherosa Ziehau 
450515516c77SSepherosa Ziehau static int
450615516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS)
450715516c77SSepherosa Ziehau {
450815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
450915516c77SSepherosa Ziehau 	char filter_str[128];
451015516c77SSepherosa Ziehau 	uint32_t filter;
451115516c77SSepherosa Ziehau 
451215516c77SSepherosa Ziehau 	HN_LOCK(sc);
451315516c77SSepherosa Ziehau 	filter = sc->hn_rx_filter;
451415516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
451515516c77SSepherosa Ziehau 	snprintf(filter_str, sizeof(filter_str), "%b", filter,
451615516c77SSepherosa Ziehau 	    NDIS_PACKET_TYPES);
451715516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req);
451815516c77SSepherosa Ziehau }
451915516c77SSepherosa Ziehau 
452034d68912SSepherosa Ziehau #ifndef RSS
452134d68912SSepherosa Ziehau 
452215516c77SSepherosa Ziehau static int
452315516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
452415516c77SSepherosa Ziehau {
452515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
452615516c77SSepherosa Ziehau 	int error;
452715516c77SSepherosa Ziehau 
452815516c77SSepherosa Ziehau 	HN_LOCK(sc);
452915516c77SSepherosa Ziehau 
453015516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
453115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
453215516c77SSepherosa Ziehau 		goto back;
453315516c77SSepherosa Ziehau 
4534642ec226SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) ||
4535642ec226SSepherosa Ziehau 	    (hn_xpnt_vf && sc->hn_vf_ifp != NULL)) {
4536642ec226SSepherosa Ziehau 		/*
4537642ec226SSepherosa Ziehau 		 * RSS key is synchronized w/ VF's, don't allow users
4538642ec226SSepherosa Ziehau 		 * to change it.
4539642ec226SSepherosa Ziehau 		 */
4540642ec226SSepherosa Ziehau 		error = EBUSY;
4541642ec226SSepherosa Ziehau 		goto back;
4542642ec226SSepherosa Ziehau 	}
4543642ec226SSepherosa Ziehau 
454415516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
454515516c77SSepherosa Ziehau 	if (error)
454615516c77SSepherosa Ziehau 		goto back;
454715516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
454815516c77SSepherosa Ziehau 
454915516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
455015516c77SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
455115516c77SSepherosa Ziehau 	} else {
455215516c77SSepherosa Ziehau 		/* Not RSS capable, at least for now; just save the RSS key. */
455315516c77SSepherosa Ziehau 		error = 0;
455415516c77SSepherosa Ziehau 	}
455515516c77SSepherosa Ziehau back:
455615516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
455715516c77SSepherosa Ziehau 	return (error);
455815516c77SSepherosa Ziehau }
455915516c77SSepherosa Ziehau 
456015516c77SSepherosa Ziehau static int
456115516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS)
456215516c77SSepherosa Ziehau {
456315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
456415516c77SSepherosa Ziehau 	int error;
456515516c77SSepherosa Ziehau 
456615516c77SSepherosa Ziehau 	HN_LOCK(sc);
456715516c77SSepherosa Ziehau 
456815516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
456915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
457015516c77SSepherosa Ziehau 		goto back;
457115516c77SSepherosa Ziehau 
457215516c77SSepherosa Ziehau 	/*
457315516c77SSepherosa Ziehau 	 * Don't allow RSS indirect table change, if this interface is not
457415516c77SSepherosa Ziehau 	 * RSS capable currently.
457515516c77SSepherosa Ziehau 	 */
457615516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
457715516c77SSepherosa Ziehau 		error = EOPNOTSUPP;
457815516c77SSepherosa Ziehau 		goto back;
457915516c77SSepherosa Ziehau 	}
458015516c77SSepherosa Ziehau 
458115516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
458215516c77SSepherosa Ziehau 	if (error)
458315516c77SSepherosa Ziehau 		goto back;
458415516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSIND;
458515516c77SSepherosa Ziehau 
4586afd4971bSSepherosa Ziehau 	hn_rss_ind_fixup(sc);
458715516c77SSepherosa Ziehau 	error = hn_rss_reconfig(sc);
458815516c77SSepherosa Ziehau back:
458915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
459015516c77SSepherosa Ziehau 	return (error);
459115516c77SSepherosa Ziehau }
459215516c77SSepherosa Ziehau 
459334d68912SSepherosa Ziehau #endif	/* !RSS */
459434d68912SSepherosa Ziehau 
459515516c77SSepherosa Ziehau static int
459615516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS)
459715516c77SSepherosa Ziehau {
459815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
459915516c77SSepherosa Ziehau 	char hash_str[128];
460015516c77SSepherosa Ziehau 	uint32_t hash;
460115516c77SSepherosa Ziehau 
460215516c77SSepherosa Ziehau 	HN_LOCK(sc);
460315516c77SSepherosa Ziehau 	hash = sc->hn_rss_hash;
460415516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
460515516c77SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
460615516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
460715516c77SSepherosa Ziehau }
460815516c77SSepherosa Ziehau 
460915516c77SSepherosa Ziehau static int
4610642ec226SSepherosa Ziehau hn_rss_hcap_sysctl(SYSCTL_HANDLER_ARGS)
4611642ec226SSepherosa Ziehau {
4612642ec226SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4613642ec226SSepherosa Ziehau 	char hash_str[128];
4614642ec226SSepherosa Ziehau 	uint32_t hash;
4615642ec226SSepherosa Ziehau 
4616642ec226SSepherosa Ziehau 	HN_LOCK(sc);
4617642ec226SSepherosa Ziehau 	hash = sc->hn_rss_hcap;
4618642ec226SSepherosa Ziehau 	HN_UNLOCK(sc);
4619642ec226SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
4620642ec226SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
4621642ec226SSepherosa Ziehau }
4622642ec226SSepherosa Ziehau 
4623642ec226SSepherosa Ziehau static int
4624642ec226SSepherosa Ziehau hn_rss_mbuf_sysctl(SYSCTL_HANDLER_ARGS)
4625642ec226SSepherosa Ziehau {
4626642ec226SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4627642ec226SSepherosa Ziehau 	char hash_str[128];
4628642ec226SSepherosa Ziehau 	uint32_t hash;
4629642ec226SSepherosa Ziehau 
4630642ec226SSepherosa Ziehau 	HN_LOCK(sc);
4631642ec226SSepherosa Ziehau 	hash = sc->hn_rx_ring[0].hn_mbuf_hash;
4632642ec226SSepherosa Ziehau 	HN_UNLOCK(sc);
4633642ec226SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
4634642ec226SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
4635642ec226SSepherosa Ziehau }
4636642ec226SSepherosa Ziehau 
4637642ec226SSepherosa Ziehau static int
463840d60d6eSDexuan Cui hn_vf_sysctl(SYSCTL_HANDLER_ARGS)
463940d60d6eSDexuan Cui {
464040d60d6eSDexuan Cui 	struct hn_softc *sc = arg1;
4641499c3e17SSepherosa Ziehau 	char vf_name[IFNAMSIZ + 1];
4642962f0357SSepherosa Ziehau 	struct ifnet *vf_ifp;
464340d60d6eSDexuan Cui 
464440d60d6eSDexuan Cui 	HN_LOCK(sc);
464540d60d6eSDexuan Cui 	vf_name[0] = '\0';
4646962f0357SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
4647962f0357SSepherosa Ziehau 	if (vf_ifp != NULL)
4648962f0357SSepherosa Ziehau 		snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname);
464940d60d6eSDexuan Cui 	HN_UNLOCK(sc);
465040d60d6eSDexuan Cui 	return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req);
465140d60d6eSDexuan Cui }
465240d60d6eSDexuan Cui 
465340d60d6eSDexuan Cui static int
4654499c3e17SSepherosa Ziehau hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS)
4655499c3e17SSepherosa Ziehau {
4656499c3e17SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4657499c3e17SSepherosa Ziehau 	char vf_name[IFNAMSIZ + 1];
4658962f0357SSepherosa Ziehau 	struct ifnet *vf_ifp;
4659499c3e17SSepherosa Ziehau 
4660499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
4661499c3e17SSepherosa Ziehau 	vf_name[0] = '\0';
4662962f0357SSepherosa Ziehau 	vf_ifp = sc->hn_rx_ring[0].hn_rxvf_ifp;
4663962f0357SSepherosa Ziehau 	if (vf_ifp != NULL)
4664962f0357SSepherosa Ziehau 		snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname);
4665499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
4666499c3e17SSepherosa Ziehau 	return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req);
4667499c3e17SSepherosa Ziehau }
4668499c3e17SSepherosa Ziehau 
4669499c3e17SSepherosa Ziehau static int
4670499c3e17SSepherosa Ziehau hn_vflist_sysctl(SYSCTL_HANDLER_ARGS)
4671499c3e17SSepherosa Ziehau {
4672499c3e17SSepherosa Ziehau 	struct rm_priotracker pt;
4673499c3e17SSepherosa Ziehau 	struct sbuf *sb;
4674499c3e17SSepherosa Ziehau 	int error, i;
4675499c3e17SSepherosa Ziehau 	bool first;
4676499c3e17SSepherosa Ziehau 
4677499c3e17SSepherosa Ziehau 	error = sysctl_wire_old_buffer(req, 0);
4678499c3e17SSepherosa Ziehau 	if (error != 0)
4679499c3e17SSepherosa Ziehau 		return (error);
4680499c3e17SSepherosa Ziehau 
4681499c3e17SSepherosa Ziehau 	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4682499c3e17SSepherosa Ziehau 	if (sb == NULL)
4683499c3e17SSepherosa Ziehau 		return (ENOMEM);
4684499c3e17SSepherosa Ziehau 
4685499c3e17SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
4686499c3e17SSepherosa Ziehau 
4687499c3e17SSepherosa Ziehau 	first = true;
4688499c3e17SSepherosa Ziehau 	for (i = 0; i < hn_vfmap_size; ++i) {
4689499c3e17SSepherosa Ziehau 		struct ifnet *ifp;
4690499c3e17SSepherosa Ziehau 
4691499c3e17SSepherosa Ziehau 		if (hn_vfmap[i] == NULL)
4692499c3e17SSepherosa Ziehau 			continue;
4693499c3e17SSepherosa Ziehau 
4694499c3e17SSepherosa Ziehau 		ifp = ifnet_byindex(i);
4695499c3e17SSepherosa Ziehau 		if (ifp != NULL) {
4696499c3e17SSepherosa Ziehau 			if (first)
4697499c3e17SSepherosa Ziehau 				sbuf_printf(sb, "%s", ifp->if_xname);
4698499c3e17SSepherosa Ziehau 			else
4699499c3e17SSepherosa Ziehau 				sbuf_printf(sb, " %s", ifp->if_xname);
4700499c3e17SSepherosa Ziehau 			first = false;
4701499c3e17SSepherosa Ziehau 		}
4702499c3e17SSepherosa Ziehau 	}
4703499c3e17SSepherosa Ziehau 
4704499c3e17SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
4705499c3e17SSepherosa Ziehau 
4706499c3e17SSepherosa Ziehau 	error = sbuf_finish(sb);
4707499c3e17SSepherosa Ziehau 	sbuf_delete(sb);
4708499c3e17SSepherosa Ziehau 	return (error);
4709499c3e17SSepherosa Ziehau }
4710499c3e17SSepherosa Ziehau 
4711499c3e17SSepherosa Ziehau static int
4712499c3e17SSepherosa Ziehau hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS)
4713499c3e17SSepherosa Ziehau {
4714499c3e17SSepherosa Ziehau 	struct rm_priotracker pt;
4715499c3e17SSepherosa Ziehau 	struct sbuf *sb;
4716499c3e17SSepherosa Ziehau 	int error, i;
4717499c3e17SSepherosa Ziehau 	bool first;
4718499c3e17SSepherosa Ziehau 
4719499c3e17SSepherosa Ziehau 	error = sysctl_wire_old_buffer(req, 0);
4720499c3e17SSepherosa Ziehau 	if (error != 0)
4721499c3e17SSepherosa Ziehau 		return (error);
4722499c3e17SSepherosa Ziehau 
4723499c3e17SSepherosa Ziehau 	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4724499c3e17SSepherosa Ziehau 	if (sb == NULL)
4725499c3e17SSepherosa Ziehau 		return (ENOMEM);
4726499c3e17SSepherosa Ziehau 
4727499c3e17SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
4728499c3e17SSepherosa Ziehau 
4729499c3e17SSepherosa Ziehau 	first = true;
4730499c3e17SSepherosa Ziehau 	for (i = 0; i < hn_vfmap_size; ++i) {
4731499c3e17SSepherosa Ziehau 		struct ifnet *ifp, *hn_ifp;
4732499c3e17SSepherosa Ziehau 
4733499c3e17SSepherosa Ziehau 		hn_ifp = hn_vfmap[i];
4734499c3e17SSepherosa Ziehau 		if (hn_ifp == NULL)
4735499c3e17SSepherosa Ziehau 			continue;
4736499c3e17SSepherosa Ziehau 
4737499c3e17SSepherosa Ziehau 		ifp = ifnet_byindex(i);
4738499c3e17SSepherosa Ziehau 		if (ifp != NULL) {
4739499c3e17SSepherosa Ziehau 			if (first) {
4740499c3e17SSepherosa Ziehau 				sbuf_printf(sb, "%s:%s", ifp->if_xname,
4741499c3e17SSepherosa Ziehau 				    hn_ifp->if_xname);
4742499c3e17SSepherosa Ziehau 			} else {
4743499c3e17SSepherosa Ziehau 				sbuf_printf(sb, " %s:%s", ifp->if_xname,
4744499c3e17SSepherosa Ziehau 				    hn_ifp->if_xname);
4745499c3e17SSepherosa Ziehau 			}
4746499c3e17SSepherosa Ziehau 			first = false;
4747499c3e17SSepherosa Ziehau 		}
4748499c3e17SSepherosa Ziehau 	}
4749499c3e17SSepherosa Ziehau 
4750499c3e17SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
4751499c3e17SSepherosa Ziehau 
4752499c3e17SSepherosa Ziehau 	error = sbuf_finish(sb);
4753499c3e17SSepherosa Ziehau 	sbuf_delete(sb);
4754499c3e17SSepherosa Ziehau 	return (error);
4755499c3e17SSepherosa Ziehau }
4756499c3e17SSepherosa Ziehau 
4757499c3e17SSepherosa Ziehau static int
47589c6cae24SSepherosa Ziehau hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS)
47599c6cae24SSepherosa Ziehau {
47609c6cae24SSepherosa Ziehau 	struct hn_softc *sc = arg1;
47619c6cae24SSepherosa Ziehau 	int error, onoff = 0;
47629c6cae24SSepherosa Ziehau 
47639c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF)
47649c6cae24SSepherosa Ziehau 		onoff = 1;
47659c6cae24SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &onoff, 0, req);
47669c6cae24SSepherosa Ziehau 	if (error || req->newptr == NULL)
47679c6cae24SSepherosa Ziehau 		return (error);
47689c6cae24SSepherosa Ziehau 
47699c6cae24SSepherosa Ziehau 	HN_LOCK(sc);
47709c6cae24SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit() */
47719c6cae24SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
47729c6cae24SSepherosa Ziehau 	if (onoff)
47739c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF;
47749c6cae24SSepherosa Ziehau 	else
47759c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags &= ~HN_XVFFLAG_ACCBPF;
47769c6cae24SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
47779c6cae24SSepherosa Ziehau 	HN_UNLOCK(sc);
47789c6cae24SSepherosa Ziehau 
47799c6cae24SSepherosa Ziehau 	return (0);
47809c6cae24SSepherosa Ziehau }
47819c6cae24SSepherosa Ziehau 
47829c6cae24SSepherosa Ziehau static int
47839c6cae24SSepherosa Ziehau hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS)
47849c6cae24SSepherosa Ziehau {
47859c6cae24SSepherosa Ziehau 	struct hn_softc *sc = arg1;
47869c6cae24SSepherosa Ziehau 	int enabled = 0;
47879c6cae24SSepherosa Ziehau 
47889c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
47899c6cae24SSepherosa Ziehau 		enabled = 1;
47909c6cae24SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &enabled, 0, req));
47919c6cae24SSepherosa Ziehau }
47929c6cae24SSepherosa Ziehau 
47939c6cae24SSepherosa Ziehau static int
479415516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff)
479515516c77SSepherosa Ziehau {
479615516c77SSepherosa Ziehau 	const struct ip *ip;
479715516c77SSepherosa Ziehau 	int len, iphlen, iplen;
479815516c77SSepherosa Ziehau 	const struct tcphdr *th;
479915516c77SSepherosa Ziehau 	int thoff;				/* TCP data offset */
480015516c77SSepherosa Ziehau 
480115516c77SSepherosa Ziehau 	len = hoff + sizeof(struct ip);
480215516c77SSepherosa Ziehau 
480315516c77SSepherosa Ziehau 	/* The packet must be at least the size of an IP header. */
480415516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < len)
480515516c77SSepherosa Ziehau 		return IPPROTO_DONE;
480615516c77SSepherosa Ziehau 
480715516c77SSepherosa Ziehau 	/* The fixed IP header must reside completely in the first mbuf. */
480815516c77SSepherosa Ziehau 	if (m->m_len < len)
480915516c77SSepherosa Ziehau 		return IPPROTO_DONE;
481015516c77SSepherosa Ziehau 
481115516c77SSepherosa Ziehau 	ip = mtodo(m, hoff);
481215516c77SSepherosa Ziehau 
481315516c77SSepherosa Ziehau 	/* Bound check the packet's stated IP header length. */
481415516c77SSepherosa Ziehau 	iphlen = ip->ip_hl << 2;
481515516c77SSepherosa Ziehau 	if (iphlen < sizeof(struct ip))		/* minimum header length */
481615516c77SSepherosa Ziehau 		return IPPROTO_DONE;
481715516c77SSepherosa Ziehau 
481815516c77SSepherosa Ziehau 	/* The full IP header must reside completely in the one mbuf. */
481915516c77SSepherosa Ziehau 	if (m->m_len < hoff + iphlen)
482015516c77SSepherosa Ziehau 		return IPPROTO_DONE;
482115516c77SSepherosa Ziehau 
482215516c77SSepherosa Ziehau 	iplen = ntohs(ip->ip_len);
482315516c77SSepherosa Ziehau 
482415516c77SSepherosa Ziehau 	/*
482515516c77SSepherosa Ziehau 	 * Check that the amount of data in the buffers is as
482615516c77SSepherosa Ziehau 	 * at least much as the IP header would have us expect.
482715516c77SSepherosa Ziehau 	 */
482815516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < hoff + iplen)
482915516c77SSepherosa Ziehau 		return IPPROTO_DONE;
483015516c77SSepherosa Ziehau 
483115516c77SSepherosa Ziehau 	/*
483215516c77SSepherosa Ziehau 	 * Ignore IP fragments.
483315516c77SSepherosa Ziehau 	 */
483415516c77SSepherosa Ziehau 	if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF))
483515516c77SSepherosa Ziehau 		return IPPROTO_DONE;
483615516c77SSepherosa Ziehau 
483715516c77SSepherosa Ziehau 	/*
483815516c77SSepherosa Ziehau 	 * The TCP/IP or UDP/IP header must be entirely contained within
483915516c77SSepherosa Ziehau 	 * the first fragment of a packet.
484015516c77SSepherosa Ziehau 	 */
484115516c77SSepherosa Ziehau 	switch (ip->ip_p) {
484215516c77SSepherosa Ziehau 	case IPPROTO_TCP:
484315516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct tcphdr))
484415516c77SSepherosa Ziehau 			return IPPROTO_DONE;
484515516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct tcphdr))
484615516c77SSepherosa Ziehau 			return IPPROTO_DONE;
484715516c77SSepherosa Ziehau 		th = (const struct tcphdr *)((const uint8_t *)ip + iphlen);
484815516c77SSepherosa Ziehau 		thoff = th->th_off << 2;
484915516c77SSepherosa Ziehau 		if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen)
485015516c77SSepherosa Ziehau 			return IPPROTO_DONE;
485115516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + thoff)
485215516c77SSepherosa Ziehau 			return IPPROTO_DONE;
485315516c77SSepherosa Ziehau 		break;
485415516c77SSepherosa Ziehau 	case IPPROTO_UDP:
485515516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct udphdr))
485615516c77SSepherosa Ziehau 			return IPPROTO_DONE;
485715516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct udphdr))
485815516c77SSepherosa Ziehau 			return IPPROTO_DONE;
485915516c77SSepherosa Ziehau 		break;
486015516c77SSepherosa Ziehau 	default:
486115516c77SSepherosa Ziehau 		if (iplen < iphlen)
486215516c77SSepherosa Ziehau 			return IPPROTO_DONE;
486315516c77SSepherosa Ziehau 		break;
486415516c77SSepherosa Ziehau 	}
486515516c77SSepherosa Ziehau 	return ip->ip_p;
486615516c77SSepherosa Ziehau }
486715516c77SSepherosa Ziehau 
4868db76829bSSepherosa Ziehau static void
4869db76829bSSepherosa Ziehau hn_rxpkt_proto(const struct mbuf *m_new, int *l3proto, int *l4proto)
4870db76829bSSepherosa Ziehau {
4871db76829bSSepherosa Ziehau 	const struct ether_header *eh;
4872db76829bSSepherosa Ziehau 	uint16_t etype;
4873db76829bSSepherosa Ziehau 	int hoff;
4874db76829bSSepherosa Ziehau 
4875db76829bSSepherosa Ziehau 	hoff = sizeof(*eh);
4876db76829bSSepherosa Ziehau 	/* Checked at the beginning of this function. */
4877db76829bSSepherosa Ziehau 	KASSERT(m_new->m_len >= hoff, ("not ethernet frame"));
4878db76829bSSepherosa Ziehau 
4879db76829bSSepherosa Ziehau 	eh = mtod(m_new, const struct ether_header *);
4880db76829bSSepherosa Ziehau 	etype = ntohs(eh->ether_type);
4881db76829bSSepherosa Ziehau 	if (etype == ETHERTYPE_VLAN) {
4882db76829bSSepherosa Ziehau 		const struct ether_vlan_header *evl;
4883db76829bSSepherosa Ziehau 
4884db76829bSSepherosa Ziehau 		hoff = sizeof(*evl);
4885db76829bSSepherosa Ziehau 		if (m_new->m_len < hoff)
4886db76829bSSepherosa Ziehau 			return;
4887db76829bSSepherosa Ziehau 		evl = mtod(m_new, const struct ether_vlan_header *);
4888db76829bSSepherosa Ziehau 		etype = ntohs(evl->evl_proto);
4889db76829bSSepherosa Ziehau 	}
4890db76829bSSepherosa Ziehau 	*l3proto = etype;
4891db76829bSSepherosa Ziehau 
4892db76829bSSepherosa Ziehau 	if (etype == ETHERTYPE_IP)
4893db76829bSSepherosa Ziehau 		*l4proto = hn_check_iplen(m_new, hoff);
4894db76829bSSepherosa Ziehau 	else
4895db76829bSSepherosa Ziehau 		*l4proto = IPPROTO_DONE;
4896db76829bSSepherosa Ziehau }
4897db76829bSSepherosa Ziehau 
489815516c77SSepherosa Ziehau static int
489915516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt)
490015516c77SSepherosa Ziehau {
490115516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
490215516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
490315516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
490415516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
490515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
490615516c77SSepherosa Ziehau 	int lroent_cnt;
490715516c77SSepherosa Ziehau #endif
490815516c77SSepherosa Ziehau #endif
490915516c77SSepherosa Ziehau 	int i;
491015516c77SSepherosa Ziehau 
491115516c77SSepherosa Ziehau 	/*
491215516c77SSepherosa Ziehau 	 * Create RXBUF for reception.
491315516c77SSepherosa Ziehau 	 *
491415516c77SSepherosa Ziehau 	 * NOTE:
491515516c77SSepherosa Ziehau 	 * - It is shared by all channels.
491615516c77SSepherosa Ziehau 	 * - A large enough buffer is allocated, certain version of NVSes
491715516c77SSepherosa Ziehau 	 *   may further limit the usable space.
491815516c77SSepherosa Ziehau 	 */
491915516c77SSepherosa Ziehau 	sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
492015516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma,
492115516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
492215516c77SSepherosa Ziehau 	if (sc->hn_rxbuf == NULL) {
492315516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate rxbuf failed\n");
492415516c77SSepherosa Ziehau 		return (ENOMEM);
492515516c77SSepherosa Ziehau 	}
492615516c77SSepherosa Ziehau 
492715516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = ring_cnt;
492815516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt;
492915516c77SSepherosa Ziehau 
493015516c77SSepherosa Ziehau 	sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt,
493115516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
493215516c77SSepherosa Ziehau 
493315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
493415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
493515516c77SSepherosa Ziehau 	lroent_cnt = hn_lro_entry_count;
493615516c77SSepherosa Ziehau 	if (lroent_cnt < TCP_LRO_ENTRIES)
493715516c77SSepherosa Ziehau 		lroent_cnt = TCP_LRO_ENTRIES;
493815516c77SSepherosa Ziehau 	if (bootverbose)
493915516c77SSepherosa Ziehau 		device_printf(dev, "LRO: entry count %d\n", lroent_cnt);
494015516c77SSepherosa Ziehau #endif
494115516c77SSepherosa Ziehau #endif	/* INET || INET6 */
494215516c77SSepherosa Ziehau 
494315516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
494415516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
494515516c77SSepherosa Ziehau 
494615516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.rx sysctl tree */
494715516c77SSepherosa Ziehau 	sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx",
494815516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
494915516c77SSepherosa Ziehau 
495015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
495115516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
495215516c77SSepherosa Ziehau 
495315516c77SSepherosa Ziehau 		rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
495415516c77SSepherosa Ziehau 		    PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE,
495515516c77SSepherosa Ziehau 		    &rxr->hn_br_dma, BUS_DMA_WAITOK);
495615516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL) {
495715516c77SSepherosa Ziehau 			device_printf(dev, "allocate bufring failed\n");
495815516c77SSepherosa Ziehau 			return (ENOMEM);
495915516c77SSepherosa Ziehau 		}
496015516c77SSepherosa Ziehau 
496115516c77SSepherosa Ziehau 		if (hn_trust_hosttcp)
496215516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP;
496315516c77SSepherosa Ziehau 		if (hn_trust_hostudp)
496415516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP;
496515516c77SSepherosa Ziehau 		if (hn_trust_hostip)
496615516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP;
4967642ec226SSepherosa Ziehau 		rxr->hn_mbuf_hash = NDIS_HASH_ALL;
496815516c77SSepherosa Ziehau 		rxr->hn_ifp = sc->hn_ifp;
496915516c77SSepherosa Ziehau 		if (i < sc->hn_tx_ring_cnt)
497015516c77SSepherosa Ziehau 			rxr->hn_txr = &sc->hn_tx_ring[i];
497115516c77SSepherosa Ziehau 		rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF;
497215516c77SSepherosa Ziehau 		rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK);
497315516c77SSepherosa Ziehau 		rxr->hn_rx_idx = i;
497415516c77SSepherosa Ziehau 		rxr->hn_rxbuf = sc->hn_rxbuf;
497515516c77SSepherosa Ziehau 
497615516c77SSepherosa Ziehau 		/*
497715516c77SSepherosa Ziehau 		 * Initialize LRO.
497815516c77SSepherosa Ziehau 		 */
497915516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
498015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
498115516c77SSepherosa Ziehau 		tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt,
498215516c77SSepherosa Ziehau 		    hn_lro_mbufq_depth);
498315516c77SSepherosa Ziehau #else
498415516c77SSepherosa Ziehau 		tcp_lro_init(&rxr->hn_lro);
498515516c77SSepherosa Ziehau 		rxr->hn_lro.ifp = sc->hn_ifp;
498615516c77SSepherosa Ziehau #endif
498715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
498815516c77SSepherosa Ziehau 		rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF;
498915516c77SSepherosa Ziehau 		rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF;
499015516c77SSepherosa Ziehau #endif
499115516c77SSepherosa Ziehau #endif	/* INET || INET6 */
499215516c77SSepherosa Ziehau 
499315516c77SSepherosa Ziehau 		if (sc->hn_rx_sysctl_tree != NULL) {
499415516c77SSepherosa Ziehau 			char name[16];
499515516c77SSepherosa Ziehau 
499615516c77SSepherosa Ziehau 			/*
499715516c77SSepherosa Ziehau 			 * Create per RX ring sysctl tree:
499815516c77SSepherosa Ziehau 			 * dev.hn.UNIT.rx.RINGID
499915516c77SSepherosa Ziehau 			 */
500015516c77SSepherosa Ziehau 			snprintf(name, sizeof(name), "%d", i);
500115516c77SSepherosa Ziehau 			rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx,
500215516c77SSepherosa Ziehau 			    SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree),
500315516c77SSepherosa Ziehau 			    OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
500415516c77SSepherosa Ziehau 
500515516c77SSepherosa Ziehau 			if (rxr->hn_rx_sysctl_tree != NULL) {
500615516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
500715516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
500815516c77SSepherosa Ziehau 				    OID_AUTO, "packets", CTLFLAG_RW,
500915516c77SSepherosa Ziehau 				    &rxr->hn_pkts, "# of packets received");
501015516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
501115516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
501215516c77SSepherosa Ziehau 				    OID_AUTO, "rss_pkts", CTLFLAG_RW,
501315516c77SSepherosa Ziehau 				    &rxr->hn_rss_pkts,
501415516c77SSepherosa Ziehau 				    "# of packets w/ RSS info received");
501515516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx,
501615516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
501715516c77SSepherosa Ziehau 				    OID_AUTO, "pktbuf_len", CTLFLAG_RD,
501815516c77SSepherosa Ziehau 				    &rxr->hn_pktbuf_len, 0,
501915516c77SSepherosa Ziehau 				    "Temporary channel packet buffer length");
502015516c77SSepherosa Ziehau 			}
502115516c77SSepherosa Ziehau 		}
502215516c77SSepherosa Ziehau 	}
502315516c77SSepherosa Ziehau 
502415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued",
502515516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
502615516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_queued),
502715516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
502815516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
502915516c77SSepherosa Ziehau #else
503015516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
503115516c77SSepherosa Ziehau #endif
503215516c77SSepherosa Ziehau 	    "LU", "LRO queued");
503315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed",
503415516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
503515516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_flushed),
503615516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
503715516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
503815516c77SSepherosa Ziehau #else
503915516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
504015516c77SSepherosa Ziehau #endif
504115516c77SSepherosa Ziehau 	    "LU", "LRO flushed");
504215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried",
504315516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
504415516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro_tried),
504515516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries");
504615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
504715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim",
504815516c77SSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
504915516c77SSepherosa Ziehau 	    hn_lro_lenlim_sysctl, "IU",
505015516c77SSepherosa Ziehau 	    "Max # of data bytes to be aggregated by LRO");
505115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim",
505215516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
505315516c77SSepherosa Ziehau 	    hn_lro_ackcnt_sysctl, "I",
505415516c77SSepherosa Ziehau 	    "Max # of ACKs to be aggregated by LRO");
505515516c77SSepherosa Ziehau #endif
505615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp",
505715516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP,
505815516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
505915516c77SSepherosa Ziehau 	    "Trust tcp segement verification on host side, "
506015516c77SSepherosa Ziehau 	    "when csum info is missing");
506115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp",
506215516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP,
506315516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
506415516c77SSepherosa Ziehau 	    "Trust udp datagram verification on host side, "
506515516c77SSepherosa Ziehau 	    "when csum info is missing");
506615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip",
506715516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP,
506815516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
506915516c77SSepherosa Ziehau 	    "Trust ip packet verification on host side, "
507015516c77SSepherosa Ziehau 	    "when csum info is missing");
507115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip",
507215516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
507315516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_ip),
507415516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP");
507515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp",
507615516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
507715516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_tcp),
507815516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP");
507915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp",
508015516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
508115516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_udp),
508215516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP");
508315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted",
508415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
508515516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_trusted),
508615516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU",
508715516c77SSepherosa Ziehau 	    "# of packets that we trust host's csum verification");
508815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts",
508915516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
509015516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_small_pkts),
509115516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of small packets received");
509215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed",
509315516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
509415516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_ack_failed),
509515516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures");
509615516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt",
509715516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings");
509815516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse",
509915516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings");
510015516c77SSepherosa Ziehau 
510115516c77SSepherosa Ziehau 	return (0);
510215516c77SSepherosa Ziehau }
510315516c77SSepherosa Ziehau 
510415516c77SSepherosa Ziehau static void
510515516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc)
510615516c77SSepherosa Ziehau {
510715516c77SSepherosa Ziehau 	int i;
510815516c77SSepherosa Ziehau 
510915516c77SSepherosa Ziehau 	if (sc->hn_rxbuf != NULL) {
51102494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0)
511115516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf);
51122494d735SSepherosa Ziehau 		else
51132494d735SSepherosa Ziehau 			device_printf(sc->hn_dev, "RXBUF is referenced\n");
511415516c77SSepherosa Ziehau 		sc->hn_rxbuf = NULL;
511515516c77SSepherosa Ziehau 	}
511615516c77SSepherosa Ziehau 
511715516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_cnt == 0)
511815516c77SSepherosa Ziehau 		return;
511915516c77SSepherosa Ziehau 
512015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
512115516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
512215516c77SSepherosa Ziehau 
512315516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL)
512415516c77SSepherosa Ziehau 			continue;
51252494d735SSepherosa Ziehau 		if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) {
512615516c77SSepherosa Ziehau 			hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br);
51272494d735SSepherosa Ziehau 		} else {
51282494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
51292494d735SSepherosa Ziehau 			    "%dth channel bufring is referenced", i);
51302494d735SSepherosa Ziehau 		}
513115516c77SSepherosa Ziehau 		rxr->hn_br = NULL;
513215516c77SSepherosa Ziehau 
513315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
513415516c77SSepherosa Ziehau 		tcp_lro_free(&rxr->hn_lro);
513515516c77SSepherosa Ziehau #endif
513615516c77SSepherosa Ziehau 		free(rxr->hn_pktbuf, M_DEVBUF);
513715516c77SSepherosa Ziehau 	}
513815516c77SSepherosa Ziehau 	free(sc->hn_rx_ring, M_DEVBUF);
513915516c77SSepherosa Ziehau 	sc->hn_rx_ring = NULL;
514015516c77SSepherosa Ziehau 
514115516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = 0;
514215516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = 0;
514315516c77SSepherosa Ziehau }
514415516c77SSepherosa Ziehau 
514515516c77SSepherosa Ziehau static int
514615516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id)
514715516c77SSepherosa Ziehau {
514815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[id];
514915516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
515015516c77SSepherosa Ziehau 	bus_dma_tag_t parent_dtag;
515115516c77SSepherosa Ziehau 	int error, i;
515215516c77SSepherosa Ziehau 
515315516c77SSepherosa Ziehau 	txr->hn_sc = sc;
515415516c77SSepherosa Ziehau 	txr->hn_tx_idx = id;
515515516c77SSepherosa Ziehau 
515615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
515715516c77SSepherosa Ziehau 	mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN);
515815516c77SSepherosa Ziehau #endif
515915516c77SSepherosa Ziehau 	mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF);
516015516c77SSepherosa Ziehau 
516115516c77SSepherosa Ziehau 	txr->hn_txdesc_cnt = HN_TX_DESC_CNT;
516215516c77SSepherosa Ziehau 	txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt,
516315516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
516415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
516515516c77SSepherosa Ziehau 	SLIST_INIT(&txr->hn_txlist);
516615516c77SSepherosa Ziehau #else
516715516c77SSepherosa Ziehau 	txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF,
516815516c77SSepherosa Ziehau 	    M_WAITOK, &txr->hn_tx_lock);
516915516c77SSepherosa Ziehau #endif
517015516c77SSepherosa Ziehau 
51710e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_EVTTQ) {
51720e11868dSSepherosa Ziehau 		txr->hn_tx_taskq = VMBUS_GET_EVENT_TASKQ(
51730e11868dSSepherosa Ziehau 		    device_get_parent(dev), dev, HN_RING_IDX2CPU(sc, id));
51740e11868dSSepherosa Ziehau 	} else {
5175fdd0222aSSepherosa Ziehau 		txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt];
51760e11868dSSepherosa Ziehau 	}
517715516c77SSepherosa Ziehau 
517823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
517915516c77SSepherosa Ziehau 	if (hn_use_if_start) {
518015516c77SSepherosa Ziehau 		txr->hn_txeof = hn_start_txeof;
518115516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr);
518215516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr);
518323bf9e15SSepherosa Ziehau 	} else
518423bf9e15SSepherosa Ziehau #endif
518523bf9e15SSepherosa Ziehau 	{
518615516c77SSepherosa Ziehau 		int br_depth;
518715516c77SSepherosa Ziehau 
518815516c77SSepherosa Ziehau 		txr->hn_txeof = hn_xmit_txeof;
518915516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr);
519015516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr);
519115516c77SSepherosa Ziehau 
519215516c77SSepherosa Ziehau 		br_depth = hn_get_txswq_depth(txr);
519315516c77SSepherosa Ziehau 		txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF,
519415516c77SSepherosa Ziehau 		    M_WAITOK, &txr->hn_tx_lock);
519515516c77SSepherosa Ziehau 	}
519615516c77SSepherosa Ziehau 
519715516c77SSepherosa Ziehau 	txr->hn_direct_tx_size = hn_direct_tx_size;
519815516c77SSepherosa Ziehau 
519915516c77SSepherosa Ziehau 	/*
520015516c77SSepherosa Ziehau 	 * Always schedule transmission instead of trying to do direct
520115516c77SSepherosa Ziehau 	 * transmission.  This one gives the best performance so far.
520215516c77SSepherosa Ziehau 	 */
520315516c77SSepherosa Ziehau 	txr->hn_sched_tx = 1;
520415516c77SSepherosa Ziehau 
520515516c77SSepherosa Ziehau 	parent_dtag = bus_get_dma_tag(dev);
520615516c77SSepherosa Ziehau 
520715516c77SSepherosa Ziehau 	/* DMA tag for RNDIS packet messages. */
520815516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
520915516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_ALIGN,		/* alignment */
521015516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_BOUNDARY,	/* boundary */
521115516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
521215516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
521315516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
521415516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsize */
521515516c77SSepherosa Ziehau 	    1,				/* nsegments */
521615516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsegsize */
521715516c77SSepherosa Ziehau 	    0,				/* flags */
521815516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
521915516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
522015516c77SSepherosa Ziehau 	    &txr->hn_tx_rndis_dtag);
522115516c77SSepherosa Ziehau 	if (error) {
522215516c77SSepherosa Ziehau 		device_printf(dev, "failed to create rndis dmatag\n");
522315516c77SSepherosa Ziehau 		return error;
522415516c77SSepherosa Ziehau 	}
522515516c77SSepherosa Ziehau 
522615516c77SSepherosa Ziehau 	/* DMA tag for data. */
522715516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
522815516c77SSepherosa Ziehau 	    1,				/* alignment */
522915516c77SSepherosa Ziehau 	    HN_TX_DATA_BOUNDARY,	/* boundary */
523015516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
523115516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
523215516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
523315516c77SSepherosa Ziehau 	    HN_TX_DATA_MAXSIZE,		/* maxsize */
523415516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGCNT_MAX,	/* nsegments */
523515516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGSIZE,		/* maxsegsize */
523615516c77SSepherosa Ziehau 	    0,				/* flags */
523715516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
523815516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
523915516c77SSepherosa Ziehau 	    &txr->hn_tx_data_dtag);
524015516c77SSepherosa Ziehau 	if (error) {
524115516c77SSepherosa Ziehau 		device_printf(dev, "failed to create data dmatag\n");
524215516c77SSepherosa Ziehau 		return error;
524315516c77SSepherosa Ziehau 	}
524415516c77SSepherosa Ziehau 
524515516c77SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i) {
524615516c77SSepherosa Ziehau 		struct hn_txdesc *txd = &txr->hn_txdesc[i];
524715516c77SSepherosa Ziehau 
524815516c77SSepherosa Ziehau 		txd->txr = txr;
524915516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
5250dc13fee6SSepherosa Ziehau 		STAILQ_INIT(&txd->agg_list);
525115516c77SSepherosa Ziehau 
525215516c77SSepherosa Ziehau 		/*
525315516c77SSepherosa Ziehau 		 * Allocate and load RNDIS packet message.
525415516c77SSepherosa Ziehau 		 */
525515516c77SSepherosa Ziehau         	error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag,
525615516c77SSepherosa Ziehau 		    (void **)&txd->rndis_pkt,
525715516c77SSepherosa Ziehau 		    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
525815516c77SSepherosa Ziehau 		    &txd->rndis_pkt_dmap);
525915516c77SSepherosa Ziehau 		if (error) {
526015516c77SSepherosa Ziehau 			device_printf(dev,
526115516c77SSepherosa Ziehau 			    "failed to allocate rndis_packet_msg, %d\n", i);
526215516c77SSepherosa Ziehau 			return error;
526315516c77SSepherosa Ziehau 		}
526415516c77SSepherosa Ziehau 
526515516c77SSepherosa Ziehau 		error = bus_dmamap_load(txr->hn_tx_rndis_dtag,
526615516c77SSepherosa Ziehau 		    txd->rndis_pkt_dmap,
526715516c77SSepherosa Ziehau 		    txd->rndis_pkt, HN_RNDIS_PKT_LEN,
526815516c77SSepherosa Ziehau 		    hyperv_dma_map_paddr, &txd->rndis_pkt_paddr,
526915516c77SSepherosa Ziehau 		    BUS_DMA_NOWAIT);
527015516c77SSepherosa Ziehau 		if (error) {
527115516c77SSepherosa Ziehau 			device_printf(dev,
527215516c77SSepherosa Ziehau 			    "failed to load rndis_packet_msg, %d\n", i);
527315516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
527415516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
527515516c77SSepherosa Ziehau 			return error;
527615516c77SSepherosa Ziehau 		}
527715516c77SSepherosa Ziehau 
527815516c77SSepherosa Ziehau 		/* DMA map for TX data. */
527915516c77SSepherosa Ziehau 		error = bus_dmamap_create(txr->hn_tx_data_dtag, 0,
528015516c77SSepherosa Ziehau 		    &txd->data_dmap);
528115516c77SSepherosa Ziehau 		if (error) {
528215516c77SSepherosa Ziehau 			device_printf(dev,
528315516c77SSepherosa Ziehau 			    "failed to allocate tx data dmamap\n");
528415516c77SSepherosa Ziehau 			bus_dmamap_unload(txr->hn_tx_rndis_dtag,
528515516c77SSepherosa Ziehau 			    txd->rndis_pkt_dmap);
528615516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
528715516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
528815516c77SSepherosa Ziehau 			return error;
528915516c77SSepherosa Ziehau 		}
529015516c77SSepherosa Ziehau 
529115516c77SSepherosa Ziehau 		/* All set, put it to list */
529215516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_ONLIST;
529315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
529415516c77SSepherosa Ziehau 		SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
529515516c77SSepherosa Ziehau #else
529615516c77SSepherosa Ziehau 		buf_ring_enqueue(txr->hn_txdesc_br, txd);
529715516c77SSepherosa Ziehau #endif
529815516c77SSepherosa Ziehau 	}
529915516c77SSepherosa Ziehau 	txr->hn_txdesc_avail = txr->hn_txdesc_cnt;
530015516c77SSepherosa Ziehau 
530115516c77SSepherosa Ziehau 	if (sc->hn_tx_sysctl_tree != NULL) {
530215516c77SSepherosa Ziehau 		struct sysctl_oid_list *child;
530315516c77SSepherosa Ziehau 		struct sysctl_ctx_list *ctx;
530415516c77SSepherosa Ziehau 		char name[16];
530515516c77SSepherosa Ziehau 
530615516c77SSepherosa Ziehau 		/*
530715516c77SSepherosa Ziehau 		 * Create per TX ring sysctl tree:
530815516c77SSepherosa Ziehau 		 * dev.hn.UNIT.tx.RINGID
530915516c77SSepherosa Ziehau 		 */
531015516c77SSepherosa Ziehau 		ctx = device_get_sysctl_ctx(dev);
531115516c77SSepherosa Ziehau 		child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree);
531215516c77SSepherosa Ziehau 
531315516c77SSepherosa Ziehau 		snprintf(name, sizeof(name), "%d", id);
531415516c77SSepherosa Ziehau 		txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
531515516c77SSepherosa Ziehau 		    name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
531615516c77SSepherosa Ziehau 
531715516c77SSepherosa Ziehau 		if (txr->hn_tx_sysctl_tree != NULL) {
531815516c77SSepherosa Ziehau 			child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree);
531915516c77SSepherosa Ziehau 
532085e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
532115516c77SSepherosa Ziehau 			SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail",
532215516c77SSepherosa Ziehau 			    CTLFLAG_RD, &txr->hn_txdesc_avail, 0,
532315516c77SSepherosa Ziehau 			    "# of available TX descs");
532485e4ae1eSSepherosa Ziehau #endif
532523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
532623bf9e15SSepherosa Ziehau 			if (!hn_use_if_start)
532723bf9e15SSepherosa Ziehau #endif
532823bf9e15SSepherosa Ziehau 			{
532915516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive",
533015516c77SSepherosa Ziehau 				    CTLFLAG_RD, &txr->hn_oactive, 0,
533115516c77SSepherosa Ziehau 				    "over active");
533215516c77SSepherosa Ziehau 			}
533315516c77SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets",
533415516c77SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_pkts,
533515516c77SSepherosa Ziehau 			    "# of packets transmitted");
5336dc13fee6SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends",
5337dc13fee6SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_sends, "# of sends");
533815516c77SSepherosa Ziehau 		}
533915516c77SSepherosa Ziehau 	}
534015516c77SSepherosa Ziehau 
534115516c77SSepherosa Ziehau 	return 0;
534215516c77SSepherosa Ziehau }
534315516c77SSepherosa Ziehau 
534415516c77SSepherosa Ziehau static void
534515516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd)
534615516c77SSepherosa Ziehau {
534715516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = txd->txr;
534815516c77SSepherosa Ziehau 
534915516c77SSepherosa Ziehau 	KASSERT(txd->m == NULL, ("still has mbuf installed"));
535015516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped"));
535115516c77SSepherosa Ziehau 
535215516c77SSepherosa Ziehau 	bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap);
535315516c77SSepherosa Ziehau 	bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt,
535415516c77SSepherosa Ziehau 	    txd->rndis_pkt_dmap);
535515516c77SSepherosa Ziehau 	bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap);
535615516c77SSepherosa Ziehau }
535715516c77SSepherosa Ziehau 
535815516c77SSepherosa Ziehau static void
535925641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd)
536025641fc7SSepherosa Ziehau {
536125641fc7SSepherosa Ziehau 
536225641fc7SSepherosa Ziehau 	KASSERT(txd->refs == 0 || txd->refs == 1,
536325641fc7SSepherosa Ziehau 	    ("invalid txd refs %d", txd->refs));
536425641fc7SSepherosa Ziehau 
536525641fc7SSepherosa Ziehau 	/* Aggregated txds will be freed by their aggregating txd. */
536625641fc7SSepherosa Ziehau 	if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) {
536725641fc7SSepherosa Ziehau 		int freed;
536825641fc7SSepherosa Ziehau 
536925641fc7SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
537025641fc7SSepherosa Ziehau 		KASSERT(freed, ("can't free txdesc"));
537125641fc7SSepherosa Ziehau 	}
537225641fc7SSepherosa Ziehau }
537325641fc7SSepherosa Ziehau 
537425641fc7SSepherosa Ziehau static void
537515516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr)
537615516c77SSepherosa Ziehau {
537725641fc7SSepherosa Ziehau 	int i;
537815516c77SSepherosa Ziehau 
537915516c77SSepherosa Ziehau 	if (txr->hn_txdesc == NULL)
538015516c77SSepherosa Ziehau 		return;
538115516c77SSepherosa Ziehau 
538225641fc7SSepherosa Ziehau 	/*
538325641fc7SSepherosa Ziehau 	 * NOTE:
538425641fc7SSepherosa Ziehau 	 * Because the freeing of aggregated txds will be deferred
538525641fc7SSepherosa Ziehau 	 * to the aggregating txd, two passes are used here:
538625641fc7SSepherosa Ziehau 	 * - The first pass GCes any pending txds.  This GC is necessary,
538725641fc7SSepherosa Ziehau 	 *   since if the channels are revoked, hypervisor will not
538825641fc7SSepherosa Ziehau 	 *   deliver send-done for all pending txds.
538925641fc7SSepherosa Ziehau 	 * - The second pass frees the busdma stuffs, i.e. after all txds
539025641fc7SSepherosa Ziehau 	 *   were freed.
539125641fc7SSepherosa Ziehau 	 */
539225641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
539325641fc7SSepherosa Ziehau 		hn_txdesc_gc(txr, &txr->hn_txdesc[i]);
539425641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
539525641fc7SSepherosa Ziehau 		hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]);
539615516c77SSepherosa Ziehau 
539715516c77SSepherosa Ziehau 	if (txr->hn_tx_data_dtag != NULL)
539815516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_data_dtag);
539915516c77SSepherosa Ziehau 	if (txr->hn_tx_rndis_dtag != NULL)
540015516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_rndis_dtag);
540115516c77SSepherosa Ziehau 
540215516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
540315516c77SSepherosa Ziehau 	buf_ring_free(txr->hn_txdesc_br, M_DEVBUF);
540415516c77SSepherosa Ziehau #endif
540515516c77SSepherosa Ziehau 
540615516c77SSepherosa Ziehau 	free(txr->hn_txdesc, M_DEVBUF);
540715516c77SSepherosa Ziehau 	txr->hn_txdesc = NULL;
540815516c77SSepherosa Ziehau 
540915516c77SSepherosa Ziehau 	if (txr->hn_mbuf_br != NULL)
541015516c77SSepherosa Ziehau 		buf_ring_free(txr->hn_mbuf_br, M_DEVBUF);
541115516c77SSepherosa Ziehau 
541215516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
541315516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_txlist_spin);
541415516c77SSepherosa Ziehau #endif
541515516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_tx_lock);
541615516c77SSepherosa Ziehau }
541715516c77SSepherosa Ziehau 
541815516c77SSepherosa Ziehau static int
541915516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt)
542015516c77SSepherosa Ziehau {
542115516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
542215516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
542315516c77SSepherosa Ziehau 	int i;
542415516c77SSepherosa Ziehau 
542515516c77SSepherosa Ziehau 	/*
542615516c77SSepherosa Ziehau 	 * Create TXBUF for chimney sending.
542715516c77SSepherosa Ziehau 	 *
542815516c77SSepherosa Ziehau 	 * NOTE: It is shared by all channels.
542915516c77SSepherosa Ziehau 	 */
543015516c77SSepherosa Ziehau 	sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev),
543115516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma,
543215516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
543315516c77SSepherosa Ziehau 	if (sc->hn_chim == NULL) {
543415516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate txbuf failed\n");
543515516c77SSepherosa Ziehau 		return (ENOMEM);
543615516c77SSepherosa Ziehau 	}
543715516c77SSepherosa Ziehau 
543815516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = ring_cnt;
543915516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
544015516c77SSepherosa Ziehau 
544115516c77SSepherosa Ziehau 	sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt,
544215516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
544315516c77SSepherosa Ziehau 
544415516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(sc->hn_dev);
544515516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev));
544615516c77SSepherosa Ziehau 
544715516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.tx sysctl tree */
544815516c77SSepherosa Ziehau 	sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx",
544915516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
545015516c77SSepherosa Ziehau 
545115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
545215516c77SSepherosa Ziehau 		int error;
545315516c77SSepherosa Ziehau 
545415516c77SSepherosa Ziehau 		error = hn_tx_ring_create(sc, i);
545515516c77SSepherosa Ziehau 		if (error)
545615516c77SSepherosa Ziehau 			return error;
545715516c77SSepherosa Ziehau 	}
545815516c77SSepherosa Ziehau 
545915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs",
546015516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
546115516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_no_txdescs),
546215516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs");
546315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed",
546415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
546515516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_send_failed),
546615516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure");
546715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed",
546815516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
546915516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_txdma_failed),
547015516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure");
5471dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed",
5472dc13fee6SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
5473dc13fee6SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_flush_failed),
5474dc13fee6SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU",
5475dc13fee6SSepherosa Ziehau 	    "# of packet transmission aggregation flush failure");
547615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed",
547715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
547815516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_collapsed),
547915516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed");
548015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney",
548115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
548215516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney),
548315516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send");
548415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried",
548515516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
548615516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney_tried),
548715516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries");
548815516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt",
548915516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0,
549015516c77SSepherosa Ziehau 	    "# of total TX descs");
549115516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max",
549215516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_chim_szmax, 0,
549315516c77SSepherosa Ziehau 	    "Chimney send packet size upper boundary");
549415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size",
549515516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
549615516c77SSepherosa Ziehau 	    hn_chim_size_sysctl, "I", "Chimney send packet size limit");
549715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size",
549815516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
549915516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_direct_tx_size),
550015516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
550115516c77SSepherosa Ziehau 	    "Size of the packet for direct transmission");
550215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx",
550315516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
550415516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_sched_tx),
550515516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
550615516c77SSepherosa Ziehau 	    "Always schedule transmission "
550715516c77SSepherosa Ziehau 	    "instead of doing direct transmission");
550815516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt",
550915516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings");
551015516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse",
551115516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings");
5512dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax",
5513dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0,
5514dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation size");
5515dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax",
5516dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
5517dc13fee6SSepherosa Ziehau 	    hn_txagg_pktmax_sysctl, "I",
5518dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation packets");
5519dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align",
5520dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
5521dc13fee6SSepherosa Ziehau 	    hn_txagg_align_sysctl, "I",
5522dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation alignment");
552315516c77SSepherosa Ziehau 
552415516c77SSepherosa Ziehau 	return 0;
552515516c77SSepherosa Ziehau }
552615516c77SSepherosa Ziehau 
552715516c77SSepherosa Ziehau static void
552815516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size)
552915516c77SSepherosa Ziehau {
553015516c77SSepherosa Ziehau 	int i;
553115516c77SSepherosa Ziehau 
5532a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
553315516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_chim_size = chim_size;
553415516c77SSepherosa Ziehau }
553515516c77SSepherosa Ziehau 
553615516c77SSepherosa Ziehau static void
553715516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu)
553815516c77SSepherosa Ziehau {
553915516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
55409c6cae24SSepherosa Ziehau 	u_int hw_tsomax;
554115516c77SSepherosa Ziehau 	int tso_minlen;
554215516c77SSepherosa Ziehau 
55439c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
55449c6cae24SSepherosa Ziehau 
554515516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0)
554615516c77SSepherosa Ziehau 		return;
554715516c77SSepherosa Ziehau 
554815516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_sgmin >= 2,
554915516c77SSepherosa Ziehau 	    ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin));
555015516c77SSepherosa Ziehau 	tso_minlen = sc->hn_ndis_tso_sgmin * mtu;
555115516c77SSepherosa Ziehau 
555215516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen &&
555315516c77SSepherosa Ziehau 	    sc->hn_ndis_tso_szmax <= IP_MAXPACKET,
555415516c77SSepherosa Ziehau 	    ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax));
555515516c77SSepherosa Ziehau 
555615516c77SSepherosa Ziehau 	if (tso_maxlen < tso_minlen)
555715516c77SSepherosa Ziehau 		tso_maxlen = tso_minlen;
555815516c77SSepherosa Ziehau 	else if (tso_maxlen > IP_MAXPACKET)
555915516c77SSepherosa Ziehau 		tso_maxlen = IP_MAXPACKET;
556015516c77SSepherosa Ziehau 	if (tso_maxlen > sc->hn_ndis_tso_szmax)
556115516c77SSepherosa Ziehau 		tso_maxlen = sc->hn_ndis_tso_szmax;
55629c6cae24SSepherosa Ziehau 	hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
55639c6cae24SSepherosa Ziehau 
55649c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_isready(sc)) {
55659c6cae24SSepherosa Ziehau 		if (hw_tsomax > sc->hn_vf_ifp->if_hw_tsomax)
55669c6cae24SSepherosa Ziehau 			hw_tsomax = sc->hn_vf_ifp->if_hw_tsomax;
55679c6cae24SSepherosa Ziehau 	}
55689c6cae24SSepherosa Ziehau 	ifp->if_hw_tsomax = hw_tsomax;
556915516c77SSepherosa Ziehau 	if (bootverbose)
557015516c77SSepherosa Ziehau 		if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax);
557115516c77SSepherosa Ziehau }
557215516c77SSepherosa Ziehau 
557315516c77SSepherosa Ziehau static void
557415516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc)
557515516c77SSepherosa Ziehau {
557615516c77SSepherosa Ziehau 	uint64_t csum_assist;
557715516c77SSepherosa Ziehau 	int i;
557815516c77SSepherosa Ziehau 
557915516c77SSepherosa Ziehau 	hn_set_chim_size(sc, sc->hn_chim_szmax);
558015516c77SSepherosa Ziehau 	if (hn_tx_chimney_size > 0 &&
558115516c77SSepherosa Ziehau 	    hn_tx_chimney_size < sc->hn_chim_szmax)
558215516c77SSepherosa Ziehau 		hn_set_chim_size(sc, hn_tx_chimney_size);
558315516c77SSepherosa Ziehau 
558415516c77SSepherosa Ziehau 	csum_assist = 0;
558515516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_IPCS)
558615516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP;
558715516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP4CS)
558815516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_TCP;
55892be266caSSepherosa Ziehau 	if ((sc->hn_caps & HN_CAP_UDP4CS) && hn_enable_udp4cs)
559015516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_UDP;
559115516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP6CS)
559215516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_TCP;
55932be266caSSepherosa Ziehau 	if ((sc->hn_caps & HN_CAP_UDP6CS) && hn_enable_udp6cs)
559415516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_UDP;
559515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
559615516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_csum_assist = csum_assist;
559715516c77SSepherosa Ziehau 
559815516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_HASHVAL) {
559915516c77SSepherosa Ziehau 		/*
560015516c77SSepherosa Ziehau 		 * Support HASHVAL pktinfo on TX path.
560115516c77SSepherosa Ziehau 		 */
560215516c77SSepherosa Ziehau 		if (bootverbose)
560315516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n");
560415516c77SSepherosa Ziehau 		for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
560515516c77SSepherosa Ziehau 			sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL;
560615516c77SSepherosa Ziehau 	}
560715516c77SSepherosa Ziehau }
560815516c77SSepherosa Ziehau 
560915516c77SSepherosa Ziehau static void
5610db76829bSSepherosa Ziehau hn_fixup_rx_data(struct hn_softc *sc)
5611db76829bSSepherosa Ziehau {
5612db76829bSSepherosa Ziehau 
5613db76829bSSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDPHASH) {
5614db76829bSSepherosa Ziehau 		int i;
5615db76829bSSepherosa Ziehau 
5616db76829bSSepherosa Ziehau 		for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
5617db76829bSSepherosa Ziehau 			sc->hn_rx_ring[i].hn_rx_flags |= HN_RX_FLAG_UDP_HASH;
5618db76829bSSepherosa Ziehau 	}
5619db76829bSSepherosa Ziehau }
5620db76829bSSepherosa Ziehau 
5621db76829bSSepherosa Ziehau static void
562215516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc)
562315516c77SSepherosa Ziehau {
562415516c77SSepherosa Ziehau 	int i;
562515516c77SSepherosa Ziehau 
562615516c77SSepherosa Ziehau 	if (sc->hn_chim != NULL) {
56272494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) {
562815516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim);
56292494d735SSepherosa Ziehau 		} else {
56302494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
56312494d735SSepherosa Ziehau 			    "chimney sending buffer is referenced");
56322494d735SSepherosa Ziehau 		}
563315516c77SSepherosa Ziehau 		sc->hn_chim = NULL;
563415516c77SSepherosa Ziehau 	}
563515516c77SSepherosa Ziehau 
563615516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt == 0)
563715516c77SSepherosa Ziehau 		return;
563815516c77SSepherosa Ziehau 
563915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
564015516c77SSepherosa Ziehau 		hn_tx_ring_destroy(&sc->hn_tx_ring[i]);
564115516c77SSepherosa Ziehau 
564215516c77SSepherosa Ziehau 	free(sc->hn_tx_ring, M_DEVBUF);
564315516c77SSepherosa Ziehau 	sc->hn_tx_ring = NULL;
564415516c77SSepherosa Ziehau 
564515516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = 0;
564615516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = 0;
564715516c77SSepherosa Ziehau }
564815516c77SSepherosa Ziehau 
564923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
565023bf9e15SSepherosa Ziehau 
565115516c77SSepherosa Ziehau static void
565215516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused)
565315516c77SSepherosa Ziehau {
565415516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
565515516c77SSepherosa Ziehau 
565615516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
565715516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
565815516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
565915516c77SSepherosa Ziehau }
566015516c77SSepherosa Ziehau 
566123bf9e15SSepherosa Ziehau static int
566223bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len)
566323bf9e15SSepherosa Ziehau {
566423bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
566523bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
5666dc13fee6SSepherosa Ziehau 	int sched = 0;
566723bf9e15SSepherosa Ziehau 
566823bf9e15SSepherosa Ziehau 	KASSERT(hn_use_if_start,
566923bf9e15SSepherosa Ziehau 	    ("hn_start_locked is called, when if_start is disabled"));
567023bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
567123bf9e15SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
5672dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
567323bf9e15SSepherosa Ziehau 
567423bf9e15SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
5675dc13fee6SSepherosa Ziehau 		return (0);
567623bf9e15SSepherosa Ziehau 
567723bf9e15SSepherosa Ziehau 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
567823bf9e15SSepherosa Ziehau 	    IFF_DRV_RUNNING)
5679dc13fee6SSepherosa Ziehau 		return (0);
568023bf9e15SSepherosa Ziehau 
568123bf9e15SSepherosa Ziehau 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
568223bf9e15SSepherosa Ziehau 		struct hn_txdesc *txd;
568323bf9e15SSepherosa Ziehau 		struct mbuf *m_head;
568423bf9e15SSepherosa Ziehau 		int error;
568523bf9e15SSepherosa Ziehau 
568623bf9e15SSepherosa Ziehau 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
568723bf9e15SSepherosa Ziehau 		if (m_head == NULL)
568823bf9e15SSepherosa Ziehau 			break;
568923bf9e15SSepherosa Ziehau 
569023bf9e15SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
569123bf9e15SSepherosa Ziehau 			/*
569223bf9e15SSepherosa Ziehau 			 * This sending could be time consuming; let callers
569323bf9e15SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
569423bf9e15SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
569523bf9e15SSepherosa Ziehau 			 */
569623bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
5697dc13fee6SSepherosa Ziehau 			sched = 1;
5698dc13fee6SSepherosa Ziehau 			break;
569923bf9e15SSepherosa Ziehau 		}
570023bf9e15SSepherosa Ziehau 
5701edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
5702edd3f315SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
5703edd3f315SSepherosa Ziehau 			m_head = hn_tso_fixup(m_head);
5704edd3f315SSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
5705edd3f315SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5706edd3f315SSepherosa Ziehau 				continue;
5707edd3f315SSepherosa Ziehau 			}
5708c49d47daSSepherosa Ziehau 		} else if (m_head->m_pkthdr.csum_flags &
5709c49d47daSSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) {
5710c49d47daSSepherosa Ziehau 			m_head = hn_set_hlen(m_head);
5711c49d47daSSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
5712c49d47daSSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5713c49d47daSSepherosa Ziehau 				continue;
5714c49d47daSSepherosa Ziehau 			}
5715edd3f315SSepherosa Ziehau 		}
5716edd3f315SSepherosa Ziehau #endif
5717edd3f315SSepherosa Ziehau 
571823bf9e15SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
571923bf9e15SSepherosa Ziehau 		if (txd == NULL) {
572023bf9e15SSepherosa Ziehau 			txr->hn_no_txdescs++;
572123bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
572223bf9e15SSepherosa Ziehau 			atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
572323bf9e15SSepherosa Ziehau 			break;
572423bf9e15SSepherosa Ziehau 		}
572523bf9e15SSepherosa Ziehau 
5726dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
572723bf9e15SSepherosa Ziehau 		if (error) {
572823bf9e15SSepherosa Ziehau 			/* Both txd and m_head are freed */
5729dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
5730dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
573123bf9e15SSepherosa Ziehau 			continue;
573223bf9e15SSepherosa Ziehau 		}
573323bf9e15SSepherosa Ziehau 
5734dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
5735dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
5736dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
5737dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
5738dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
5739dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
5740dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
5741dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
5742dc13fee6SSepherosa Ziehau 					break;
5743dc13fee6SSepherosa Ziehau 				}
5744dc13fee6SSepherosa Ziehau 			} else {
5745dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
574623bf9e15SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
574723bf9e15SSepherosa Ziehau 				if (__predict_false(error)) {
574823bf9e15SSepherosa Ziehau 					/* txd is freed, but m_head is not */
574923bf9e15SSepherosa Ziehau 					IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
5750dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
5751dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
575223bf9e15SSepherosa Ziehau 					break;
575323bf9e15SSepherosa Ziehau 				}
575423bf9e15SSepherosa Ziehau 			}
5755dc13fee6SSepherosa Ziehau 		}
5756dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
5757dc13fee6SSepherosa Ziehau 		else {
5758dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
5759dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
5760dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
5761dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
5762dc13fee6SSepherosa Ziehau 		}
5763dc13fee6SSepherosa Ziehau #endif
5764dc13fee6SSepherosa Ziehau 	}
5765dc13fee6SSepherosa Ziehau 
5766dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
5767dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
5768dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
5769dc13fee6SSepherosa Ziehau 	return (sched);
577023bf9e15SSepherosa Ziehau }
577123bf9e15SSepherosa Ziehau 
577223bf9e15SSepherosa Ziehau static void
577323bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp)
577423bf9e15SSepherosa Ziehau {
577523bf9e15SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
577623bf9e15SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[0];
577723bf9e15SSepherosa Ziehau 
577823bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
577923bf9e15SSepherosa Ziehau 		goto do_sched;
578023bf9e15SSepherosa Ziehau 
578123bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
578223bf9e15SSepherosa Ziehau 		int sched;
578323bf9e15SSepherosa Ziehau 
578423bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
578523bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
578623bf9e15SSepherosa Ziehau 		if (!sched)
578723bf9e15SSepherosa Ziehau 			return;
578823bf9e15SSepherosa Ziehau 	}
578923bf9e15SSepherosa Ziehau do_sched:
579023bf9e15SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
579123bf9e15SSepherosa Ziehau }
579223bf9e15SSepherosa Ziehau 
579315516c77SSepherosa Ziehau static void
579415516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused)
579515516c77SSepherosa Ziehau {
579615516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
579715516c77SSepherosa Ziehau 
579815516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
579915516c77SSepherosa Ziehau 	atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE);
580015516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
580115516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
580215516c77SSepherosa Ziehau }
580315516c77SSepherosa Ziehau 
580423bf9e15SSepherosa Ziehau static void
580523bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr)
580623bf9e15SSepherosa Ziehau {
580723bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
580823bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
580923bf9e15SSepherosa Ziehau 
581023bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
581123bf9e15SSepherosa Ziehau 
581223bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
581323bf9e15SSepherosa Ziehau 		goto do_sched;
581423bf9e15SSepherosa Ziehau 
581523bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
581623bf9e15SSepherosa Ziehau 		int sched;
581723bf9e15SSepherosa Ziehau 
581823bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
581923bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
582023bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
582123bf9e15SSepherosa Ziehau 		if (sched) {
582223bf9e15SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
582323bf9e15SSepherosa Ziehau 			    &txr->hn_tx_task);
582423bf9e15SSepherosa Ziehau 		}
582523bf9e15SSepherosa Ziehau 	} else {
582623bf9e15SSepherosa Ziehau do_sched:
582723bf9e15SSepherosa Ziehau 		/*
582823bf9e15SSepherosa Ziehau 		 * Release the OACTIVE earlier, with the hope, that
582923bf9e15SSepherosa Ziehau 		 * others could catch up.  The task will clear the
583023bf9e15SSepherosa Ziehau 		 * flag again with the hn_tx_lock to avoid possible
583123bf9e15SSepherosa Ziehau 		 * races.
583223bf9e15SSepherosa Ziehau 		 */
583323bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
583423bf9e15SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
583523bf9e15SSepherosa Ziehau 	}
583623bf9e15SSepherosa Ziehau }
583723bf9e15SSepherosa Ziehau 
583823bf9e15SSepherosa Ziehau #endif	/* HN_IFSTART_SUPPORT */
583923bf9e15SSepherosa Ziehau 
584015516c77SSepherosa Ziehau static int
584115516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len)
584215516c77SSepherosa Ziehau {
584315516c77SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
584415516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
584515516c77SSepherosa Ziehau 	struct mbuf *m_head;
5846dc13fee6SSepherosa Ziehau 	int sched = 0;
584715516c77SSepherosa Ziehau 
584815516c77SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
584923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
585015516c77SSepherosa Ziehau 	KASSERT(hn_use_if_start == 0,
585115516c77SSepherosa Ziehau 	    ("hn_xmit is called, when if_start is enabled"));
585223bf9e15SSepherosa Ziehau #endif
5853dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
585415516c77SSepherosa Ziehau 
585515516c77SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
5856dc13fee6SSepherosa Ziehau 		return (0);
585715516c77SSepherosa Ziehau 
585815516c77SSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive)
5859dc13fee6SSepherosa Ziehau 		return (0);
586015516c77SSepherosa Ziehau 
586115516c77SSepherosa Ziehau 	while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) {
586215516c77SSepherosa Ziehau 		struct hn_txdesc *txd;
586315516c77SSepherosa Ziehau 		int error;
586415516c77SSepherosa Ziehau 
586515516c77SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
586615516c77SSepherosa Ziehau 			/*
586715516c77SSepherosa Ziehau 			 * This sending could be time consuming; let callers
586815516c77SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
586915516c77SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
587015516c77SSepherosa Ziehau 			 */
587115516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
5872dc13fee6SSepherosa Ziehau 			sched = 1;
5873dc13fee6SSepherosa Ziehau 			break;
587415516c77SSepherosa Ziehau 		}
587515516c77SSepherosa Ziehau 
587615516c77SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
587715516c77SSepherosa Ziehau 		if (txd == NULL) {
587815516c77SSepherosa Ziehau 			txr->hn_no_txdescs++;
587915516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
588015516c77SSepherosa Ziehau 			txr->hn_oactive = 1;
588115516c77SSepherosa Ziehau 			break;
588215516c77SSepherosa Ziehau 		}
588315516c77SSepherosa Ziehau 
5884dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
588515516c77SSepherosa Ziehau 		if (error) {
588615516c77SSepherosa Ziehau 			/* Both txd and m_head are freed; discard */
5887dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
5888dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
588915516c77SSepherosa Ziehau 			drbr_advance(ifp, txr->hn_mbuf_br);
589015516c77SSepherosa Ziehau 			continue;
589115516c77SSepherosa Ziehau 		}
589215516c77SSepherosa Ziehau 
5893dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
5894dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
5895dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
5896dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
5897dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
589815516c77SSepherosa Ziehau 				if (__predict_false(error)) {
589915516c77SSepherosa Ziehau 					txr->hn_oactive = 1;
590015516c77SSepherosa Ziehau 					break;
590115516c77SSepherosa Ziehau 				}
5902dc13fee6SSepherosa Ziehau 			} else {
5903dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
5904dc13fee6SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
5905dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
5906dc13fee6SSepherosa Ziehau 					/* txd is freed, but m_head is not */
5907dc13fee6SSepherosa Ziehau 					drbr_putback(ifp, txr->hn_mbuf_br,
5908dc13fee6SSepherosa Ziehau 					    m_head);
5909dc13fee6SSepherosa Ziehau 					txr->hn_oactive = 1;
5910dc13fee6SSepherosa Ziehau 					break;
5911dc13fee6SSepherosa Ziehau 				}
5912dc13fee6SSepherosa Ziehau 			}
5913dc13fee6SSepherosa Ziehau 		}
5914dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
5915dc13fee6SSepherosa Ziehau 		else {
5916dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
5917dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
5918dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
5919dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
5920dc13fee6SSepherosa Ziehau 		}
5921dc13fee6SSepherosa Ziehau #endif
592215516c77SSepherosa Ziehau 
592315516c77SSepherosa Ziehau 		/* Sent */
592415516c77SSepherosa Ziehau 		drbr_advance(ifp, txr->hn_mbuf_br);
592515516c77SSepherosa Ziehau 	}
5926dc13fee6SSepherosa Ziehau 
5927dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
5928dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
5929dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
5930dc13fee6SSepherosa Ziehau 	return (sched);
593115516c77SSepherosa Ziehau }
593215516c77SSepherosa Ziehau 
593315516c77SSepherosa Ziehau static int
593415516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m)
593515516c77SSepherosa Ziehau {
593615516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
593715516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
593815516c77SSepherosa Ziehau 	int error, idx = 0;
593915516c77SSepherosa Ziehau 
59409c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) {
59419c6cae24SSepherosa Ziehau 		struct rm_priotracker pt;
59429c6cae24SSepherosa Ziehau 
59439c6cae24SSepherosa Ziehau 		rm_rlock(&sc->hn_vf_lock, &pt);
59449c6cae24SSepherosa Ziehau 		if (__predict_true(sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
59459c6cae24SSepherosa Ziehau 			struct mbuf *m_bpf = NULL;
59469c6cae24SSepherosa Ziehau 			int obytes, omcast;
59479c6cae24SSepherosa Ziehau 
59489c6cae24SSepherosa Ziehau 			obytes = m->m_pkthdr.len;
59497898a1f4SEric van Gyzen 			omcast = (m->m_flags & M_MCAST) != 0;
59509c6cae24SSepherosa Ziehau 
59519c6cae24SSepherosa Ziehau 			if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF) {
59529c6cae24SSepherosa Ziehau 				if (bpf_peers_present(ifp->if_bpf)) {
59539c6cae24SSepherosa Ziehau 					m_bpf = m_copypacket(m, M_NOWAIT);
59549c6cae24SSepherosa Ziehau 					if (m_bpf == NULL) {
59559c6cae24SSepherosa Ziehau 						/*
59569c6cae24SSepherosa Ziehau 						 * Failed to grab a shallow
59579c6cae24SSepherosa Ziehau 						 * copy; tap now.
59589c6cae24SSepherosa Ziehau 						 */
59599c6cae24SSepherosa Ziehau 						ETHER_BPF_MTAP(ifp, m);
59609c6cae24SSepherosa Ziehau 					}
59619c6cae24SSepherosa Ziehau 				}
59629c6cae24SSepherosa Ziehau 			} else {
59639c6cae24SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, m);
59649c6cae24SSepherosa Ziehau 			}
59659c6cae24SSepherosa Ziehau 
59669c6cae24SSepherosa Ziehau 			error = sc->hn_vf_ifp->if_transmit(sc->hn_vf_ifp, m);
59679c6cae24SSepherosa Ziehau 			rm_runlock(&sc->hn_vf_lock, &pt);
59689c6cae24SSepherosa Ziehau 
59699c6cae24SSepherosa Ziehau 			if (m_bpf != NULL) {
59709c6cae24SSepherosa Ziehau 				if (!error)
59719c6cae24SSepherosa Ziehau 					ETHER_BPF_MTAP(ifp, m_bpf);
59729c6cae24SSepherosa Ziehau 				m_freem(m_bpf);
59739c6cae24SSepherosa Ziehau 			}
59749c6cae24SSepherosa Ziehau 
59759c6cae24SSepherosa Ziehau 			if (error == ENOBUFS) {
59769c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
59779c6cae24SSepherosa Ziehau 			} else if (error) {
59789c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
59799c6cae24SSepherosa Ziehau 			} else {
59809c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
59819c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OBYTES, obytes);
59829c6cae24SSepherosa Ziehau 				if (omcast) {
59839c6cae24SSepherosa Ziehau 					if_inc_counter(ifp, IFCOUNTER_OMCASTS,
59849c6cae24SSepherosa Ziehau 					    omcast);
59859c6cae24SSepherosa Ziehau 				}
59869c6cae24SSepherosa Ziehau 			}
59879c6cae24SSepherosa Ziehau 			return (error);
59889c6cae24SSepherosa Ziehau 		}
59899c6cae24SSepherosa Ziehau 		rm_runlock(&sc->hn_vf_lock, &pt);
59909c6cae24SSepherosa Ziehau 	}
59919c6cae24SSepherosa Ziehau 
5992edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
5993edd3f315SSepherosa Ziehau 	/*
5994c49d47daSSepherosa Ziehau 	 * Perform TSO packet header fixup or get l2/l3 header length now,
5995c49d47daSSepherosa Ziehau 	 * since packet headers should be cache-hot.
5996edd3f315SSepherosa Ziehau 	 */
5997edd3f315SSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
5998edd3f315SSepherosa Ziehau 		m = hn_tso_fixup(m);
5999edd3f315SSepherosa Ziehau 		if (__predict_false(m == NULL)) {
6000edd3f315SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
6001edd3f315SSepherosa Ziehau 			return EIO;
6002edd3f315SSepherosa Ziehau 		}
6003c49d47daSSepherosa Ziehau 	} else if (m->m_pkthdr.csum_flags &
6004c49d47daSSepherosa Ziehau 	    (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) {
6005c49d47daSSepherosa Ziehau 		m = hn_set_hlen(m);
6006c49d47daSSepherosa Ziehau 		if (__predict_false(m == NULL)) {
6007c49d47daSSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
6008c49d47daSSepherosa Ziehau 			return EIO;
6009c49d47daSSepherosa Ziehau 		}
6010edd3f315SSepherosa Ziehau 	}
6011edd3f315SSepherosa Ziehau #endif
6012edd3f315SSepherosa Ziehau 
601315516c77SSepherosa Ziehau 	/*
601415516c77SSepherosa Ziehau 	 * Select the TX ring based on flowid
601515516c77SSepherosa Ziehau 	 */
601634d68912SSepherosa Ziehau 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
601734d68912SSepherosa Ziehau #ifdef RSS
601834d68912SSepherosa Ziehau 		uint32_t bid;
601934d68912SSepherosa Ziehau 
602034d68912SSepherosa Ziehau 		if (rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m),
602134d68912SSepherosa Ziehau 		    &bid) == 0)
602234d68912SSepherosa Ziehau 			idx = bid % sc->hn_tx_ring_inuse;
602334d68912SSepherosa Ziehau 		else
602434d68912SSepherosa Ziehau #endif
6025cc0c6ebcSSepherosa Ziehau 		{
6026cc0c6ebcSSepherosa Ziehau #if defined(INET6) || defined(INET)
6027cc0c6ebcSSepherosa Ziehau 			int tcpsyn = 0;
6028cc0c6ebcSSepherosa Ziehau 
6029cc0c6ebcSSepherosa Ziehau 			if (m->m_pkthdr.len < 128 &&
6030cc0c6ebcSSepherosa Ziehau 			    (m->m_pkthdr.csum_flags &
6031cc0c6ebcSSepherosa Ziehau 			     (CSUM_IP_TCP | CSUM_IP6_TCP)) &&
6032cc0c6ebcSSepherosa Ziehau 			    (m->m_pkthdr.csum_flags & CSUM_TSO) == 0) {
6033cc0c6ebcSSepherosa Ziehau 				m = hn_check_tcpsyn(m, &tcpsyn);
6034cc0c6ebcSSepherosa Ziehau 				if (__predict_false(m == NULL)) {
6035cc0c6ebcSSepherosa Ziehau 					if_inc_counter(ifp,
6036cc0c6ebcSSepherosa Ziehau 					    IFCOUNTER_OERRORS, 1);
6037cc0c6ebcSSepherosa Ziehau 					return (EIO);
6038cc0c6ebcSSepherosa Ziehau 				}
6039cc0c6ebcSSepherosa Ziehau 			}
6040cc0c6ebcSSepherosa Ziehau #else
6041cc0c6ebcSSepherosa Ziehau 			const int tcpsyn = 0;
6042cc0c6ebcSSepherosa Ziehau #endif
6043cc0c6ebcSSepherosa Ziehau 			if (tcpsyn)
6044cc0c6ebcSSepherosa Ziehau 				idx = 0;
6045cc0c6ebcSSepherosa Ziehau 			else
604615516c77SSepherosa Ziehau 				idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse;
604734d68912SSepherosa Ziehau 		}
6048cc0c6ebcSSepherosa Ziehau 	}
604915516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[idx];
605015516c77SSepherosa Ziehau 
605115516c77SSepherosa Ziehau 	error = drbr_enqueue(ifp, txr->hn_mbuf_br, m);
605215516c77SSepherosa Ziehau 	if (error) {
605315516c77SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
605415516c77SSepherosa Ziehau 		return error;
605515516c77SSepherosa Ziehau 	}
605615516c77SSepherosa Ziehau 
605715516c77SSepherosa Ziehau 	if (txr->hn_oactive)
605815516c77SSepherosa Ziehau 		return 0;
605915516c77SSepherosa Ziehau 
606015516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
606115516c77SSepherosa Ziehau 		goto do_sched;
606215516c77SSepherosa Ziehau 
606315516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
606415516c77SSepherosa Ziehau 		int sched;
606515516c77SSepherosa Ziehau 
606615516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
606715516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
606815516c77SSepherosa Ziehau 		if (!sched)
606915516c77SSepherosa Ziehau 			return 0;
607015516c77SSepherosa Ziehau 	}
607115516c77SSepherosa Ziehau do_sched:
607215516c77SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
607315516c77SSepherosa Ziehau 	return 0;
607415516c77SSepherosa Ziehau }
607515516c77SSepherosa Ziehau 
607615516c77SSepherosa Ziehau static void
607715516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr)
607815516c77SSepherosa Ziehau {
607915516c77SSepherosa Ziehau 	struct mbuf *m;
608015516c77SSepherosa Ziehau 
608115516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
608215516c77SSepherosa Ziehau 	while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL)
608315516c77SSepherosa Ziehau 		m_freem(m);
608415516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
608515516c77SSepherosa Ziehau }
608615516c77SSepherosa Ziehau 
608715516c77SSepherosa Ziehau static void
608815516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp)
608915516c77SSepherosa Ziehau {
609015516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
60919c6cae24SSepherosa Ziehau 	struct rm_priotracker pt;
609215516c77SSepherosa Ziehau 	int i;
609315516c77SSepherosa Ziehau 
609415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
609515516c77SSepherosa Ziehau 		hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
609615516c77SSepherosa Ziehau 	if_qflush(ifp);
60979c6cae24SSepherosa Ziehau 
60989c6cae24SSepherosa Ziehau 	rm_rlock(&sc->hn_vf_lock, &pt);
60999c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
61009c6cae24SSepherosa Ziehau 		sc->hn_vf_ifp->if_qflush(sc->hn_vf_ifp);
61019c6cae24SSepherosa Ziehau 	rm_runlock(&sc->hn_vf_lock, &pt);
610215516c77SSepherosa Ziehau }
610315516c77SSepherosa Ziehau 
610415516c77SSepherosa Ziehau static void
610515516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr)
610615516c77SSepherosa Ziehau {
610715516c77SSepherosa Ziehau 
610815516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
610915516c77SSepherosa Ziehau 		goto do_sched;
611015516c77SSepherosa Ziehau 
611115516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
611215516c77SSepherosa Ziehau 		int sched;
611315516c77SSepherosa Ziehau 
611415516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
611515516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
611615516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
611715516c77SSepherosa Ziehau 		if (sched) {
611815516c77SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
611915516c77SSepherosa Ziehau 			    &txr->hn_tx_task);
612015516c77SSepherosa Ziehau 		}
612115516c77SSepherosa Ziehau 	} else {
612215516c77SSepherosa Ziehau do_sched:
612315516c77SSepherosa Ziehau 		/*
612415516c77SSepherosa Ziehau 		 * Release the oactive earlier, with the hope, that
612515516c77SSepherosa Ziehau 		 * others could catch up.  The task will clear the
612615516c77SSepherosa Ziehau 		 * oactive again with the hn_tx_lock to avoid possible
612715516c77SSepherosa Ziehau 		 * races.
612815516c77SSepherosa Ziehau 		 */
612915516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
613015516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
613115516c77SSepherosa Ziehau 	}
613215516c77SSepherosa Ziehau }
613315516c77SSepherosa Ziehau 
613415516c77SSepherosa Ziehau static void
613515516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused)
613615516c77SSepherosa Ziehau {
613715516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
613815516c77SSepherosa Ziehau 
613915516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
614015516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
614115516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
614215516c77SSepherosa Ziehau }
614315516c77SSepherosa Ziehau 
614415516c77SSepherosa Ziehau static void
614515516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused)
614615516c77SSepherosa Ziehau {
614715516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
614815516c77SSepherosa Ziehau 
614915516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
615015516c77SSepherosa Ziehau 	txr->hn_oactive = 0;
615115516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
615215516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
615315516c77SSepherosa Ziehau }
615415516c77SSepherosa Ziehau 
615515516c77SSepherosa Ziehau static int
615615516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan)
615715516c77SSepherosa Ziehau {
615815516c77SSepherosa Ziehau 	struct vmbus_chan_br cbr;
615915516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
616015516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = NULL;
616115516c77SSepherosa Ziehau 	int idx, error;
616215516c77SSepherosa Ziehau 
616315516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
616415516c77SSepherosa Ziehau 
616515516c77SSepherosa Ziehau 	/*
616615516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
616715516c77SSepherosa Ziehau 	 */
616815516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
616915516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
617015516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
617115516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
617215516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0,
617315516c77SSepherosa Ziehau 	    ("RX ring %d already attached", idx));
617415516c77SSepherosa Ziehau 	rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED;
61753ab0fea1SDexuan Cui 	rxr->hn_chan = chan;
617615516c77SSepherosa Ziehau 
617715516c77SSepherosa Ziehau 	if (bootverbose) {
617815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n",
617915516c77SSepherosa Ziehau 		    idx, vmbus_chan_id(chan));
618015516c77SSepherosa Ziehau 	}
618115516c77SSepherosa Ziehau 
618215516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
618315516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[idx];
618415516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0,
618515516c77SSepherosa Ziehau 		    ("TX ring %d already attached", idx));
618615516c77SSepherosa Ziehau 		txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED;
618715516c77SSepherosa Ziehau 
618815516c77SSepherosa Ziehau 		txr->hn_chan = chan;
618915516c77SSepherosa Ziehau 		if (bootverbose) {
619015516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n",
619115516c77SSepherosa Ziehau 			    idx, vmbus_chan_id(chan));
619215516c77SSepherosa Ziehau 		}
619315516c77SSepherosa Ziehau 	}
619415516c77SSepherosa Ziehau 
619515516c77SSepherosa Ziehau 	/* Bind this channel to a proper CPU. */
61960e11868dSSepherosa Ziehau 	vmbus_chan_cpu_set(chan, HN_RING_IDX2CPU(sc, idx));
619715516c77SSepherosa Ziehau 
619815516c77SSepherosa Ziehau 	/*
619915516c77SSepherosa Ziehau 	 * Open this channel
620015516c77SSepherosa Ziehau 	 */
620115516c77SSepherosa Ziehau 	cbr.cbr = rxr->hn_br;
620215516c77SSepherosa Ziehau 	cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr;
620315516c77SSepherosa Ziehau 	cbr.cbr_txsz = HN_TXBR_SIZE;
620415516c77SSepherosa Ziehau 	cbr.cbr_rxsz = HN_RXBR_SIZE;
620515516c77SSepherosa Ziehau 	error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr);
620615516c77SSepherosa Ziehau 	if (error) {
620771e8ac56SSepherosa Ziehau 		if (error == EISCONN) {
620871e8ac56SSepherosa Ziehau 			if_printf(sc->hn_ifp, "bufring is connected after "
620971e8ac56SSepherosa Ziehau 			    "chan%u open failure\n", vmbus_chan_id(chan));
621071e8ac56SSepherosa Ziehau 			rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
621171e8ac56SSepherosa Ziehau 		} else {
621215516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "open chan%u failed: %d\n",
621315516c77SSepherosa Ziehau 			    vmbus_chan_id(chan), error);
621471e8ac56SSepherosa Ziehau 		}
621515516c77SSepherosa Ziehau 	}
621615516c77SSepherosa Ziehau 	return (error);
621715516c77SSepherosa Ziehau }
621815516c77SSepherosa Ziehau 
621915516c77SSepherosa Ziehau static void
622015516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan)
622115516c77SSepherosa Ziehau {
622215516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
62232494d735SSepherosa Ziehau 	int idx, error;
622415516c77SSepherosa Ziehau 
622515516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
622615516c77SSepherosa Ziehau 
622715516c77SSepherosa Ziehau 	/*
622815516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
622915516c77SSepherosa Ziehau 	 */
623015516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
623115516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
623215516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
623315516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
623415516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED),
623515516c77SSepherosa Ziehau 	    ("RX ring %d is not attached", idx));
623615516c77SSepherosa Ziehau 	rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
623715516c77SSepherosa Ziehau 
623815516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
623915516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[idx];
624015516c77SSepherosa Ziehau 
624115516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED),
624215516c77SSepherosa Ziehau 		    ("TX ring %d is not attached attached", idx));
624315516c77SSepherosa Ziehau 		txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
624415516c77SSepherosa Ziehau 	}
624515516c77SSepherosa Ziehau 
624615516c77SSepherosa Ziehau 	/*
624715516c77SSepherosa Ziehau 	 * Close this channel.
624815516c77SSepherosa Ziehau 	 *
624915516c77SSepherosa Ziehau 	 * NOTE:
625015516c77SSepherosa Ziehau 	 * Channel closing does _not_ destroy the target channel.
625115516c77SSepherosa Ziehau 	 */
62522494d735SSepherosa Ziehau 	error = vmbus_chan_close_direct(chan);
62532494d735SSepherosa Ziehau 	if (error == EISCONN) {
6254aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u bufring is connected "
6255aa1a2adcSSepherosa Ziehau 		    "after being closed\n", vmbus_chan_id(chan));
62562494d735SSepherosa Ziehau 		rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
62572494d735SSepherosa Ziehau 	} else if (error) {
6258aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u close failed: %d\n",
6259aa1a2adcSSepherosa Ziehau 		    vmbus_chan_id(chan), error);
62602494d735SSepherosa Ziehau 	}
626115516c77SSepherosa Ziehau }
626215516c77SSepherosa Ziehau 
626315516c77SSepherosa Ziehau static int
626415516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc)
626515516c77SSepherosa Ziehau {
626615516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
626715516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
626815516c77SSepherosa Ziehau 	int i, error = 0;
626915516c77SSepherosa Ziehau 
627071e8ac56SSepherosa Ziehau 	KASSERT(subchan_cnt > 0, ("no sub-channels"));
627115516c77SSepherosa Ziehau 
627215516c77SSepherosa Ziehau 	/* Attach the sub-channels. */
627315516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
627415516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i) {
627571e8ac56SSepherosa Ziehau 		int error1;
627671e8ac56SSepherosa Ziehau 
627771e8ac56SSepherosa Ziehau 		error1 = hn_chan_attach(sc, subchans[i]);
627871e8ac56SSepherosa Ziehau 		if (error1) {
627971e8ac56SSepherosa Ziehau 			error = error1;
628071e8ac56SSepherosa Ziehau 			/* Move on; all channels will be detached later. */
628171e8ac56SSepherosa Ziehau 		}
628215516c77SSepherosa Ziehau 	}
628315516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
628415516c77SSepherosa Ziehau 
628515516c77SSepherosa Ziehau 	if (error) {
628615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error);
628715516c77SSepherosa Ziehau 	} else {
628815516c77SSepherosa Ziehau 		if (bootverbose) {
628915516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "%d sub-channels attached\n",
629015516c77SSepherosa Ziehau 			    subchan_cnt);
629115516c77SSepherosa Ziehau 		}
629215516c77SSepherosa Ziehau 	}
629315516c77SSepherosa Ziehau 	return (error);
629415516c77SSepherosa Ziehau }
629515516c77SSepherosa Ziehau 
629615516c77SSepherosa Ziehau static void
629715516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc)
629815516c77SSepherosa Ziehau {
629915516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
630015516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
630115516c77SSepherosa Ziehau 	int i;
630215516c77SSepherosa Ziehau 
630315516c77SSepherosa Ziehau 	if (subchan_cnt == 0)
630415516c77SSepherosa Ziehau 		goto back;
630515516c77SSepherosa Ziehau 
630615516c77SSepherosa Ziehau 	/* Detach the sub-channels. */
630715516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
630815516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i)
630915516c77SSepherosa Ziehau 		hn_chan_detach(sc, subchans[i]);
631015516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
631115516c77SSepherosa Ziehau 
631215516c77SSepherosa Ziehau back:
631315516c77SSepherosa Ziehau 	/*
631415516c77SSepherosa Ziehau 	 * Detach the primary channel, _after_ all sub-channels
631515516c77SSepherosa Ziehau 	 * are detached.
631615516c77SSepherosa Ziehau 	 */
631715516c77SSepherosa Ziehau 	hn_chan_detach(sc, sc->hn_prichan);
631815516c77SSepherosa Ziehau 
631915516c77SSepherosa Ziehau 	/* Wait for sub-channels to be destroyed, if any. */
632015516c77SSepherosa Ziehau 	vmbus_subchan_drain(sc->hn_prichan);
632115516c77SSepherosa Ziehau 
632215516c77SSepherosa Ziehau #ifdef INVARIANTS
632315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
632415516c77SSepherosa Ziehau 		KASSERT((sc->hn_rx_ring[i].hn_rx_flags &
632515516c77SSepherosa Ziehau 		    HN_RX_FLAG_ATTACHED) == 0,
632615516c77SSepherosa Ziehau 		    ("%dth RX ring is still attached", i));
632715516c77SSepherosa Ziehau 	}
632815516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
632915516c77SSepherosa Ziehau 		KASSERT((sc->hn_tx_ring[i].hn_tx_flags &
633015516c77SSepherosa Ziehau 		    HN_TX_FLAG_ATTACHED) == 0,
633115516c77SSepherosa Ziehau 		    ("%dth TX ring is still attached", i));
633215516c77SSepherosa Ziehau 	}
633315516c77SSepherosa Ziehau #endif
633415516c77SSepherosa Ziehau }
633515516c77SSepherosa Ziehau 
633615516c77SSepherosa Ziehau static int
633715516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch)
633815516c77SSepherosa Ziehau {
633915516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
634015516c77SSepherosa Ziehau 	int nchan, rxr_cnt, error;
634115516c77SSepherosa Ziehau 
634215516c77SSepherosa Ziehau 	nchan = *nsubch + 1;
634315516c77SSepherosa Ziehau 	if (nchan == 1) {
634415516c77SSepherosa Ziehau 		/*
634515516c77SSepherosa Ziehau 		 * Multiple RX/TX rings are not requested.
634615516c77SSepherosa Ziehau 		 */
634715516c77SSepherosa Ziehau 		*nsubch = 0;
634815516c77SSepherosa Ziehau 		return (0);
634915516c77SSepherosa Ziehau 	}
635015516c77SSepherosa Ziehau 
635115516c77SSepherosa Ziehau 	/*
635215516c77SSepherosa Ziehau 	 * Query RSS capabilities, e.g. # of RX rings, and # of indirect
635315516c77SSepherosa Ziehau 	 * table entries.
635415516c77SSepherosa Ziehau 	 */
635515516c77SSepherosa Ziehau 	error = hn_rndis_query_rsscaps(sc, &rxr_cnt);
635615516c77SSepherosa Ziehau 	if (error) {
635715516c77SSepherosa Ziehau 		/* No RSS; this is benign. */
635815516c77SSepherosa Ziehau 		*nsubch = 0;
635915516c77SSepherosa Ziehau 		return (0);
636015516c77SSepherosa Ziehau 	}
636115516c77SSepherosa Ziehau 	if (bootverbose) {
636215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
636315516c77SSepherosa Ziehau 		    rxr_cnt, nchan);
636415516c77SSepherosa Ziehau 	}
636515516c77SSepherosa Ziehau 
636615516c77SSepherosa Ziehau 	if (nchan > rxr_cnt)
636715516c77SSepherosa Ziehau 		nchan = rxr_cnt;
636815516c77SSepherosa Ziehau 	if (nchan == 1) {
636915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n");
637015516c77SSepherosa Ziehau 		*nsubch = 0;
637115516c77SSepherosa Ziehau 		return (0);
637215516c77SSepherosa Ziehau 	}
637315516c77SSepherosa Ziehau 
637415516c77SSepherosa Ziehau 	/*
637515516c77SSepherosa Ziehau 	 * Allocate sub-channels from NVS.
637615516c77SSepherosa Ziehau 	 */
637715516c77SSepherosa Ziehau 	*nsubch = nchan - 1;
637815516c77SSepherosa Ziehau 	error = hn_nvs_alloc_subchans(sc, nsubch);
637915516c77SSepherosa Ziehau 	if (error || *nsubch == 0) {
638015516c77SSepherosa Ziehau 		/* Failed to allocate sub-channels. */
638115516c77SSepherosa Ziehau 		*nsubch = 0;
638215516c77SSepherosa Ziehau 		return (0);
638315516c77SSepherosa Ziehau 	}
638415516c77SSepherosa Ziehau 
638515516c77SSepherosa Ziehau 	/*
638615516c77SSepherosa Ziehau 	 * Wait for all sub-channels to become ready before moving on.
638715516c77SSepherosa Ziehau 	 */
638815516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch);
638915516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, *nsubch);
639015516c77SSepherosa Ziehau 	return (0);
639115516c77SSepherosa Ziehau }
639215516c77SSepherosa Ziehau 
63932494d735SSepherosa Ziehau static bool
63942494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc)
63952494d735SSepherosa Ziehau {
63962494d735SSepherosa Ziehau 	int i;
63972494d735SSepherosa Ziehau 
63982494d735SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_ERRORS)
63992494d735SSepherosa Ziehau 		return (false);
64002494d735SSepherosa Ziehau 
64012494d735SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
64022494d735SSepherosa Ziehau 		const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
64032494d735SSepherosa Ziehau 
64042494d735SSepherosa Ziehau 		if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF)
64052494d735SSepherosa Ziehau 			return (false);
64062494d735SSepherosa Ziehau 	}
64072494d735SSepherosa Ziehau 	return (true);
64082494d735SSepherosa Ziehau }
64092494d735SSepherosa Ziehau 
6410b3b75d9cSSepherosa Ziehau /*
6411b3b75d9cSSepherosa Ziehau  * Make sure that the RX filter is zero after the successful
6412b3b75d9cSSepherosa Ziehau  * RNDIS initialization.
6413b3b75d9cSSepherosa Ziehau  *
6414b3b75d9cSSepherosa Ziehau  * NOTE:
6415b3b75d9cSSepherosa Ziehau  * Under certain conditions on certain versions of Hyper-V,
6416b3b75d9cSSepherosa Ziehau  * the RNDIS rxfilter is _not_ zero on the hypervisor side
6417b3b75d9cSSepherosa Ziehau  * after the successful RNDIS initialization, which breaks
6418b3b75d9cSSepherosa Ziehau  * the assumption of any following code (well, it breaks the
6419b3b75d9cSSepherosa Ziehau  * RNDIS API contract actually).  Clear the RNDIS rxfilter
6420b3b75d9cSSepherosa Ziehau  * explicitly, drain packets sneaking through, and drain the
6421b3b75d9cSSepherosa Ziehau  * interrupt taskqueues scheduled due to the stealth packets.
6422b3b75d9cSSepherosa Ziehau  */
6423b3b75d9cSSepherosa Ziehau static void
6424b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(struct hn_softc *sc, int nchan)
6425b3b75d9cSSepherosa Ziehau {
6426b3b75d9cSSepherosa Ziehau 
6427b3b75d9cSSepherosa Ziehau 	hn_disable_rx(sc);
6428b3b75d9cSSepherosa Ziehau 	hn_drain_rxtx(sc, nchan);
6429b3b75d9cSSepherosa Ziehau }
6430b3b75d9cSSepherosa Ziehau 
643115516c77SSepherosa Ziehau static int
643215516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu)
643315516c77SSepherosa Ziehau {
643471e8ac56SSepherosa Ziehau #define ATTACHED_NVS		0x0002
643571e8ac56SSepherosa Ziehau #define ATTACHED_RNDIS		0x0004
643671e8ac56SSepherosa Ziehau 
643715516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
6438b3b75d9cSSepherosa Ziehau 	int error, nsubch, nchan = 1, i, rndis_inited;
643971e8ac56SSepherosa Ziehau 	uint32_t old_caps, attached = 0;
644015516c77SSepherosa Ziehau 
644115516c77SSepherosa Ziehau 	KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0,
644215516c77SSepherosa Ziehau 	    ("synthetic parts were attached"));
644315516c77SSepherosa Ziehau 
64442494d735SSepherosa Ziehau 	if (!hn_synth_attachable(sc))
64452494d735SSepherosa Ziehau 		return (ENXIO);
64462494d735SSepherosa Ziehau 
644715516c77SSepherosa Ziehau 	/* Save capabilities for later verification. */
644815516c77SSepherosa Ziehau 	old_caps = sc->hn_caps;
644915516c77SSepherosa Ziehau 	sc->hn_caps = 0;
645015516c77SSepherosa Ziehau 
645115516c77SSepherosa Ziehau 	/* Clear RSS stuffs. */
645215516c77SSepherosa Ziehau 	sc->hn_rss_ind_size = 0;
645315516c77SSepherosa Ziehau 	sc->hn_rss_hash = 0;
6454642ec226SSepherosa Ziehau 	sc->hn_rss_hcap = 0;
645515516c77SSepherosa Ziehau 
645615516c77SSepherosa Ziehau 	/*
645715516c77SSepherosa Ziehau 	 * Attach the primary channel _before_ attaching NVS and RNDIS.
645815516c77SSepherosa Ziehau 	 */
645915516c77SSepherosa Ziehau 	error = hn_chan_attach(sc, sc->hn_prichan);
646015516c77SSepherosa Ziehau 	if (error)
646171e8ac56SSepherosa Ziehau 		goto failed;
646215516c77SSepherosa Ziehau 
646315516c77SSepherosa Ziehau 	/*
646415516c77SSepherosa Ziehau 	 * Attach NVS.
646515516c77SSepherosa Ziehau 	 */
646615516c77SSepherosa Ziehau 	error = hn_nvs_attach(sc, mtu);
646715516c77SSepherosa Ziehau 	if (error)
646871e8ac56SSepherosa Ziehau 		goto failed;
646971e8ac56SSepherosa Ziehau 	attached |= ATTACHED_NVS;
647015516c77SSepherosa Ziehau 
647115516c77SSepherosa Ziehau 	/*
647215516c77SSepherosa Ziehau 	 * Attach RNDIS _after_ NVS is attached.
647315516c77SSepherosa Ziehau 	 */
6474b3b75d9cSSepherosa Ziehau 	error = hn_rndis_attach(sc, mtu, &rndis_inited);
6475b3b75d9cSSepherosa Ziehau 	if (rndis_inited)
6476b3b75d9cSSepherosa Ziehau 		attached |= ATTACHED_RNDIS;
647715516c77SSepherosa Ziehau 	if (error)
647871e8ac56SSepherosa Ziehau 		goto failed;
647915516c77SSepherosa Ziehau 
648015516c77SSepherosa Ziehau 	/*
648115516c77SSepherosa Ziehau 	 * Make sure capabilities are not changed.
648215516c77SSepherosa Ziehau 	 */
648315516c77SSepherosa Ziehau 	if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) {
648415516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n",
648515516c77SSepherosa Ziehau 		    old_caps, sc->hn_caps);
648671e8ac56SSepherosa Ziehau 		error = ENXIO;
648771e8ac56SSepherosa Ziehau 		goto failed;
648815516c77SSepherosa Ziehau 	}
648915516c77SSepherosa Ziehau 
649015516c77SSepherosa Ziehau 	/*
649115516c77SSepherosa Ziehau 	 * Allocate sub-channels for multi-TX/RX rings.
649215516c77SSepherosa Ziehau 	 *
649315516c77SSepherosa Ziehau 	 * NOTE:
649415516c77SSepherosa Ziehau 	 * The # of RX rings that can be used is equivalent to the # of
649515516c77SSepherosa Ziehau 	 * channels to be requested.
649615516c77SSepherosa Ziehau 	 */
649715516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_cnt - 1;
649815516c77SSepherosa Ziehau 	error = hn_synth_alloc_subchans(sc, &nsubch);
649915516c77SSepherosa Ziehau 	if (error)
650071e8ac56SSepherosa Ziehau 		goto failed;
650171e8ac56SSepherosa Ziehau 	/* NOTE: _Full_ synthetic parts detach is required now. */
650271e8ac56SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED;
650315516c77SSepherosa Ziehau 
650471e8ac56SSepherosa Ziehau 	/*
650571e8ac56SSepherosa Ziehau 	 * Set the # of TX/RX rings that could be used according to
650671e8ac56SSepherosa Ziehau 	 * the # of channels that NVS offered.
650771e8ac56SSepherosa Ziehau 	 */
650815516c77SSepherosa Ziehau 	nchan = nsubch + 1;
650971e8ac56SSepherosa Ziehau 	hn_set_ring_inuse(sc, nchan);
651015516c77SSepherosa Ziehau 	if (nchan == 1) {
651115516c77SSepherosa Ziehau 		/* Only the primary channel can be used; done */
651215516c77SSepherosa Ziehau 		goto back;
651315516c77SSepherosa Ziehau 	}
651415516c77SSepherosa Ziehau 
651515516c77SSepherosa Ziehau 	/*
651671e8ac56SSepherosa Ziehau 	 * Attach the sub-channels.
6517afd4971bSSepherosa Ziehau 	 *
6518afd4971bSSepherosa Ziehau 	 * NOTE: hn_set_ring_inuse() _must_ have been called.
651915516c77SSepherosa Ziehau 	 */
652071e8ac56SSepherosa Ziehau 	error = hn_attach_subchans(sc);
652171e8ac56SSepherosa Ziehau 	if (error)
652271e8ac56SSepherosa Ziehau 		goto failed;
652315516c77SSepherosa Ziehau 
652471e8ac56SSepherosa Ziehau 	/*
652571e8ac56SSepherosa Ziehau 	 * Configure RSS key and indirect table _after_ all sub-channels
652671e8ac56SSepherosa Ziehau 	 * are attached.
652771e8ac56SSepherosa Ziehau 	 */
652815516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) {
652915516c77SSepherosa Ziehau 		/*
653015516c77SSepherosa Ziehau 		 * RSS key is not set yet; set it to the default RSS key.
653115516c77SSepherosa Ziehau 		 */
653215516c77SSepherosa Ziehau 		if (bootverbose)
653315516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS key\n");
653434d68912SSepherosa Ziehau #ifdef RSS
653534d68912SSepherosa Ziehau 		rss_getkey(rss->rss_key);
653634d68912SSepherosa Ziehau #else
653715516c77SSepherosa Ziehau 		memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key));
653834d68912SSepherosa Ziehau #endif
653915516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
654015516c77SSepherosa Ziehau 	}
654115516c77SSepherosa Ziehau 
654215516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) {
654315516c77SSepherosa Ziehau 		/*
654415516c77SSepherosa Ziehau 		 * RSS indirect table is not set yet; set it up in round-
654515516c77SSepherosa Ziehau 		 * robin fashion.
654615516c77SSepherosa Ziehau 		 */
654715516c77SSepherosa Ziehau 		if (bootverbose) {
654815516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS indirect "
654915516c77SSepherosa Ziehau 			    "table\n");
655015516c77SSepherosa Ziehau 		}
655134d68912SSepherosa Ziehau 		for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
655234d68912SSepherosa Ziehau 			uint32_t subidx;
655334d68912SSepherosa Ziehau 
655434d68912SSepherosa Ziehau #ifdef RSS
655534d68912SSepherosa Ziehau 			subidx = rss_get_indirection_to_bucket(i);
655634d68912SSepherosa Ziehau #else
655734d68912SSepherosa Ziehau 			subidx = i;
655834d68912SSepherosa Ziehau #endif
655934d68912SSepherosa Ziehau 			rss->rss_ind[i] = subidx % nchan;
656034d68912SSepherosa Ziehau 		}
656115516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSIND;
656215516c77SSepherosa Ziehau 	} else {
656315516c77SSepherosa Ziehau 		/*
656415516c77SSepherosa Ziehau 		 * # of usable channels may be changed, so we have to
656515516c77SSepherosa Ziehau 		 * make sure that all entries in RSS indirect table
656615516c77SSepherosa Ziehau 		 * are valid.
6567afd4971bSSepherosa Ziehau 		 *
6568afd4971bSSepherosa Ziehau 		 * NOTE: hn_set_ring_inuse() _must_ have been called.
656915516c77SSepherosa Ziehau 		 */
6570afd4971bSSepherosa Ziehau 		hn_rss_ind_fixup(sc);
657115516c77SSepherosa Ziehau 	}
657215516c77SSepherosa Ziehau 
6573642ec226SSepherosa Ziehau 	sc->hn_rss_hash = sc->hn_rss_hcap;
6574642ec226SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) ||
6575642ec226SSepherosa Ziehau 	    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
6576642ec226SSepherosa Ziehau 		/* NOTE: Don't reconfigure RSS; will do immediately. */
6577642ec226SSepherosa Ziehau 		hn_vf_rss_fixup(sc, false);
6578642ec226SSepherosa Ziehau 	}
657915516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
658015516c77SSepherosa Ziehau 	if (error)
658171e8ac56SSepherosa Ziehau 		goto failed;
658271e8ac56SSepherosa Ziehau back:
6583dc13fee6SSepherosa Ziehau 	/*
6584dc13fee6SSepherosa Ziehau 	 * Fixup transmission aggregation setup.
6585dc13fee6SSepherosa Ziehau 	 */
6586dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
6587b3b75d9cSSepherosa Ziehau 	hn_rndis_init_fixat(sc, nchan);
658815516c77SSepherosa Ziehau 	return (0);
658971e8ac56SSepherosa Ziehau 
659071e8ac56SSepherosa Ziehau failed:
659171e8ac56SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
6592b3b75d9cSSepherosa Ziehau 		hn_rndis_init_fixat(sc, nchan);
659371e8ac56SSepherosa Ziehau 		hn_synth_detach(sc);
659471e8ac56SSepherosa Ziehau 	} else {
6595b3b75d9cSSepherosa Ziehau 		if (attached & ATTACHED_RNDIS) {
6596b3b75d9cSSepherosa Ziehau 			hn_rndis_init_fixat(sc, nchan);
659771e8ac56SSepherosa Ziehau 			hn_rndis_detach(sc);
6598b3b75d9cSSepherosa Ziehau 		}
659971e8ac56SSepherosa Ziehau 		if (attached & ATTACHED_NVS)
660071e8ac56SSepherosa Ziehau 			hn_nvs_detach(sc);
660171e8ac56SSepherosa Ziehau 		hn_chan_detach(sc, sc->hn_prichan);
660271e8ac56SSepherosa Ziehau 		/* Restore old capabilities. */
660371e8ac56SSepherosa Ziehau 		sc->hn_caps = old_caps;
660471e8ac56SSepherosa Ziehau 	}
660571e8ac56SSepherosa Ziehau 	return (error);
660671e8ac56SSepherosa Ziehau 
660771e8ac56SSepherosa Ziehau #undef ATTACHED_RNDIS
660871e8ac56SSepherosa Ziehau #undef ATTACHED_NVS
660915516c77SSepherosa Ziehau }
661015516c77SSepherosa Ziehau 
661115516c77SSepherosa Ziehau /*
661215516c77SSepherosa Ziehau  * NOTE:
661315516c77SSepherosa Ziehau  * The interface must have been suspended though hn_suspend(), before
661415516c77SSepherosa Ziehau  * this function get called.
661515516c77SSepherosa Ziehau  */
661615516c77SSepherosa Ziehau static void
661715516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc)
661815516c77SSepherosa Ziehau {
661915516c77SSepherosa Ziehau 
662015516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
662115516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
662215516c77SSepherosa Ziehau 
662315516c77SSepherosa Ziehau 	/* Detach the RNDIS first. */
662415516c77SSepherosa Ziehau 	hn_rndis_detach(sc);
662515516c77SSepherosa Ziehau 
662615516c77SSepherosa Ziehau 	/* Detach NVS. */
662715516c77SSepherosa Ziehau 	hn_nvs_detach(sc);
662815516c77SSepherosa Ziehau 
662915516c77SSepherosa Ziehau 	/* Detach all of the channels. */
663015516c77SSepherosa Ziehau 	hn_detach_allchans(sc);
663115516c77SSepherosa Ziehau 
663215516c77SSepherosa Ziehau 	sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED;
663315516c77SSepherosa Ziehau }
663415516c77SSepherosa Ziehau 
663515516c77SSepherosa Ziehau static void
663615516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt)
663715516c77SSepherosa Ziehau {
663815516c77SSepherosa Ziehau 	KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt,
663915516c77SSepherosa Ziehau 	    ("invalid ring count %d", ring_cnt));
664015516c77SSepherosa Ziehau 
664115516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt > ring_cnt)
664215516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = ring_cnt;
664315516c77SSepherosa Ziehau 	else
664415516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
664515516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = ring_cnt;
664615516c77SSepherosa Ziehau 
664734d68912SSepherosa Ziehau #ifdef RSS
664834d68912SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse != rss_getnumbuckets()) {
664934d68912SSepherosa Ziehau 		if_printf(sc->hn_ifp, "# of RX rings (%d) does not match "
665034d68912SSepherosa Ziehau 		    "# of RSS buckets (%d)\n", sc->hn_rx_ring_inuse,
665134d68912SSepherosa Ziehau 		    rss_getnumbuckets());
665234d68912SSepherosa Ziehau 	}
665334d68912SSepherosa Ziehau #endif
665434d68912SSepherosa Ziehau 
665515516c77SSepherosa Ziehau 	if (bootverbose) {
665615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n",
665715516c77SSepherosa Ziehau 		    sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
665815516c77SSepherosa Ziehau 	}
665915516c77SSepherosa Ziehau }
666015516c77SSepherosa Ziehau 
666115516c77SSepherosa Ziehau static void
666225641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan)
666315516c77SSepherosa Ziehau {
666415516c77SSepherosa Ziehau 
666525641fc7SSepherosa Ziehau 	/*
666625641fc7SSepherosa Ziehau 	 * NOTE:
666725641fc7SSepherosa Ziehau 	 * The TX bufring will not be drained by the hypervisor,
666825641fc7SSepherosa Ziehau 	 * if the primary channel is revoked.
666925641fc7SSepherosa Ziehau 	 */
667025641fc7SSepherosa Ziehau 	while (!vmbus_chan_rx_empty(chan) ||
667125641fc7SSepherosa Ziehau 	    (!vmbus_chan_is_revoked(sc->hn_prichan) &&
667225641fc7SSepherosa Ziehau 	     !vmbus_chan_tx_empty(chan)))
667315516c77SSepherosa Ziehau 		pause("waitch", 1);
667415516c77SSepherosa Ziehau 	vmbus_chan_intr_drain(chan);
667515516c77SSepherosa Ziehau }
667615516c77SSepherosa Ziehau 
667715516c77SSepherosa Ziehau static void
6678b3b75d9cSSepherosa Ziehau hn_disable_rx(struct hn_softc *sc)
6679b3b75d9cSSepherosa Ziehau {
6680b3b75d9cSSepherosa Ziehau 
6681b3b75d9cSSepherosa Ziehau 	/*
6682b3b75d9cSSepherosa Ziehau 	 * Disable RX by clearing RX filter forcefully.
6683b3b75d9cSSepherosa Ziehau 	 */
6684b3b75d9cSSepherosa Ziehau 	sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE;
6685b3b75d9cSSepherosa Ziehau 	hn_rndis_set_rxfilter(sc, sc->hn_rx_filter); /* ignore error */
6686b3b75d9cSSepherosa Ziehau 
6687b3b75d9cSSepherosa Ziehau 	/*
6688b3b75d9cSSepherosa Ziehau 	 * Give RNDIS enough time to flush all pending data packets.
6689b3b75d9cSSepherosa Ziehau 	 */
6690b3b75d9cSSepherosa Ziehau 	pause("waitrx", (200 * hz) / 1000);
6691b3b75d9cSSepherosa Ziehau }
6692b3b75d9cSSepherosa Ziehau 
6693b3b75d9cSSepherosa Ziehau /*
6694b3b75d9cSSepherosa Ziehau  * NOTE:
6695b3b75d9cSSepherosa Ziehau  * RX/TX _must_ have been suspended/disabled, before this function
6696b3b75d9cSSepherosa Ziehau  * is called.
6697b3b75d9cSSepherosa Ziehau  */
6698b3b75d9cSSepherosa Ziehau static void
6699b3b75d9cSSepherosa Ziehau hn_drain_rxtx(struct hn_softc *sc, int nchan)
670015516c77SSepherosa Ziehau {
670115516c77SSepherosa Ziehau 	struct vmbus_channel **subch = NULL;
6702b3b75d9cSSepherosa Ziehau 	int nsubch;
6703b3b75d9cSSepherosa Ziehau 
6704b3b75d9cSSepherosa Ziehau 	/*
6705b3b75d9cSSepherosa Ziehau 	 * Drain RX/TX bufrings and interrupts.
6706b3b75d9cSSepherosa Ziehau 	 */
6707b3b75d9cSSepherosa Ziehau 	nsubch = nchan - 1;
6708b3b75d9cSSepherosa Ziehau 	if (nsubch > 0)
6709b3b75d9cSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
6710b3b75d9cSSepherosa Ziehau 
6711b3b75d9cSSepherosa Ziehau 	if (subch != NULL) {
6712b3b75d9cSSepherosa Ziehau 		int i;
6713b3b75d9cSSepherosa Ziehau 
6714b3b75d9cSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
6715b3b75d9cSSepherosa Ziehau 			hn_chan_drain(sc, subch[i]);
6716b3b75d9cSSepherosa Ziehau 	}
6717b3b75d9cSSepherosa Ziehau 	hn_chan_drain(sc, sc->hn_prichan);
6718b3b75d9cSSepherosa Ziehau 
6719b3b75d9cSSepherosa Ziehau 	if (subch != NULL)
6720b3b75d9cSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
6721b3b75d9cSSepherosa Ziehau }
6722b3b75d9cSSepherosa Ziehau 
6723b3b75d9cSSepherosa Ziehau static void
6724b3b75d9cSSepherosa Ziehau hn_suspend_data(struct hn_softc *sc)
6725b3b75d9cSSepherosa Ziehau {
672625641fc7SSepherosa Ziehau 	struct hn_tx_ring *txr;
6727b3b75d9cSSepherosa Ziehau 	int i;
672815516c77SSepherosa Ziehau 
672915516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
673015516c77SSepherosa Ziehau 
673115516c77SSepherosa Ziehau 	/*
673215516c77SSepherosa Ziehau 	 * Suspend TX.
673315516c77SSepherosa Ziehau 	 */
673415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
673525641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
673615516c77SSepherosa Ziehau 
673715516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
673815516c77SSepherosa Ziehau 		txr->hn_suspended = 1;
673915516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
674015516c77SSepherosa Ziehau 		/* No one is able send more packets now. */
674115516c77SSepherosa Ziehau 
674225641fc7SSepherosa Ziehau 		/*
674325641fc7SSepherosa Ziehau 		 * Wait for all pending sends to finish.
674425641fc7SSepherosa Ziehau 		 *
674525641fc7SSepherosa Ziehau 		 * NOTE:
674625641fc7SSepherosa Ziehau 		 * We will _not_ receive all pending send-done, if the
674725641fc7SSepherosa Ziehau 		 * primary channel is revoked.
674825641fc7SSepherosa Ziehau 		 */
674925641fc7SSepherosa Ziehau 		while (hn_tx_ring_pending(txr) &&
675025641fc7SSepherosa Ziehau 		    !vmbus_chan_is_revoked(sc->hn_prichan))
675115516c77SSepherosa Ziehau 			pause("hnwtx", 1 /* 1 tick */);
675215516c77SSepherosa Ziehau 	}
675315516c77SSepherosa Ziehau 
675415516c77SSepherosa Ziehau 	/*
6755b3b75d9cSSepherosa Ziehau 	 * Disable RX.
675615516c77SSepherosa Ziehau 	 */
6757b3b75d9cSSepherosa Ziehau 	hn_disable_rx(sc);
675815516c77SSepherosa Ziehau 
675915516c77SSepherosa Ziehau 	/*
6760b3b75d9cSSepherosa Ziehau 	 * Drain RX/TX.
676115516c77SSepherosa Ziehau 	 */
6762b3b75d9cSSepherosa Ziehau 	hn_drain_rxtx(sc, sc->hn_rx_ring_inuse);
676325641fc7SSepherosa Ziehau 
676425641fc7SSepherosa Ziehau 	/*
676525641fc7SSepherosa Ziehau 	 * Drain any pending TX tasks.
676625641fc7SSepherosa Ziehau 	 *
676725641fc7SSepherosa Ziehau 	 * NOTE:
6768b3b75d9cSSepherosa Ziehau 	 * The above hn_drain_rxtx() can dispatch TX tasks, so the TX
6769b3b75d9cSSepherosa Ziehau 	 * tasks will have to be drained _after_ the above hn_drain_rxtx().
677025641fc7SSepherosa Ziehau 	 */
677125641fc7SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
677225641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
677325641fc7SSepherosa Ziehau 
677425641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task);
677525641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task);
677625641fc7SSepherosa Ziehau 	}
677715516c77SSepherosa Ziehau }
677815516c77SSepherosa Ziehau 
677915516c77SSepherosa Ziehau static void
678015516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused)
678115516c77SSepherosa Ziehau {
678215516c77SSepherosa Ziehau 
678315516c77SSepherosa Ziehau 	((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL;
678415516c77SSepherosa Ziehau }
678515516c77SSepherosa Ziehau 
678615516c77SSepherosa Ziehau static void
678715516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc)
678815516c77SSepherosa Ziehau {
678915516c77SSepherosa Ziehau 	struct task task;
679015516c77SSepherosa Ziehau 
679115516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
679215516c77SSepherosa Ziehau 
679315516c77SSepherosa Ziehau 	/*
679415516c77SSepherosa Ziehau 	 * Make sure that hn_mgmt_taskq0 can nolonger be accessed
679515516c77SSepherosa Ziehau 	 * through hn_mgmt_taskq.
679615516c77SSepherosa Ziehau 	 */
679715516c77SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc);
679815516c77SSepherosa Ziehau 	vmbus_chan_run_task(sc->hn_prichan, &task);
679915516c77SSepherosa Ziehau 
680015516c77SSepherosa Ziehau 	/*
680115516c77SSepherosa Ziehau 	 * Make sure that all pending management tasks are completed.
680215516c77SSepherosa Ziehau 	 */
680315516c77SSepherosa Ziehau 	taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init);
680415516c77SSepherosa Ziehau 	taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status);
680515516c77SSepherosa Ziehau 	taskqueue_drain_all(sc->hn_mgmt_taskq0);
680615516c77SSepherosa Ziehau }
680715516c77SSepherosa Ziehau 
680815516c77SSepherosa Ziehau static void
680915516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc)
681015516c77SSepherosa Ziehau {
681115516c77SSepherosa Ziehau 
681287f8129dSSepherosa Ziehau 	/* Disable polling. */
681387f8129dSSepherosa Ziehau 	hn_polling(sc, 0);
681487f8129dSSepherosa Ziehau 
68159c6cae24SSepherosa Ziehau 	/*
68169c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, the synthetic
68179c6cae24SSepherosa Ziehau 	 * device is receiving packets, so the data path of the
68189c6cae24SSepherosa Ziehau 	 * synthetic device must be suspended.
68199c6cae24SSepherosa Ziehau 	 */
68205bdfd3fdSDexuan Cui 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
6821962f0357SSepherosa Ziehau 	    (sc->hn_flags & HN_FLAG_RXVF))
682215516c77SSepherosa Ziehau 		hn_suspend_data(sc);
682315516c77SSepherosa Ziehau 	hn_suspend_mgmt(sc);
682415516c77SSepherosa Ziehau }
682515516c77SSepherosa Ziehau 
682615516c77SSepherosa Ziehau static void
682715516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt)
682815516c77SSepherosa Ziehau {
682915516c77SSepherosa Ziehau 	int i;
683015516c77SSepherosa Ziehau 
683115516c77SSepherosa Ziehau 	KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt,
683215516c77SSepherosa Ziehau 	    ("invalid TX ring count %d", tx_ring_cnt));
683315516c77SSepherosa Ziehau 
683415516c77SSepherosa Ziehau 	for (i = 0; i < tx_ring_cnt; ++i) {
683515516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
683615516c77SSepherosa Ziehau 
683715516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
683815516c77SSepherosa Ziehau 		txr->hn_suspended = 0;
683915516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
684015516c77SSepherosa Ziehau 	}
684115516c77SSepherosa Ziehau }
684215516c77SSepherosa Ziehau 
684315516c77SSepherosa Ziehau static void
684415516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc)
684515516c77SSepherosa Ziehau {
684615516c77SSepherosa Ziehau 	int i;
684715516c77SSepherosa Ziehau 
684815516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
684915516c77SSepherosa Ziehau 
685015516c77SSepherosa Ziehau 	/*
685115516c77SSepherosa Ziehau 	 * Re-enable RX.
685215516c77SSepherosa Ziehau 	 */
6853c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
685415516c77SSepherosa Ziehau 
685515516c77SSepherosa Ziehau 	/*
685615516c77SSepherosa Ziehau 	 * Make sure to clear suspend status on "all" TX rings,
685715516c77SSepherosa Ziehau 	 * since hn_tx_ring_inuse can be changed after
685815516c77SSepherosa Ziehau 	 * hn_suspend_data().
685915516c77SSepherosa Ziehau 	 */
686015516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_cnt);
686115516c77SSepherosa Ziehau 
686223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
686323bf9e15SSepherosa Ziehau 	if (!hn_use_if_start)
686423bf9e15SSepherosa Ziehau #endif
686523bf9e15SSepherosa Ziehau 	{
686615516c77SSepherosa Ziehau 		/*
686715516c77SSepherosa Ziehau 		 * Flush unused drbrs, since hn_tx_ring_inuse may be
686815516c77SSepherosa Ziehau 		 * reduced.
686915516c77SSepherosa Ziehau 		 */
687015516c77SSepherosa Ziehau 		for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i)
687115516c77SSepherosa Ziehau 			hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
687215516c77SSepherosa Ziehau 	}
687315516c77SSepherosa Ziehau 
687415516c77SSepherosa Ziehau 	/*
687515516c77SSepherosa Ziehau 	 * Kick start TX.
687615516c77SSepherosa Ziehau 	 */
687715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
687815516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
687915516c77SSepherosa Ziehau 
688015516c77SSepherosa Ziehau 		/*
688115516c77SSepherosa Ziehau 		 * Use txeof task, so that any pending oactive can be
688215516c77SSepherosa Ziehau 		 * cleared properly.
688315516c77SSepherosa Ziehau 		 */
688415516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
688515516c77SSepherosa Ziehau 	}
688615516c77SSepherosa Ziehau }
688715516c77SSepherosa Ziehau 
688815516c77SSepherosa Ziehau static void
688915516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc)
689015516c77SSepherosa Ziehau {
689115516c77SSepherosa Ziehau 
689215516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
689315516c77SSepherosa Ziehau 
689415516c77SSepherosa Ziehau 	/*
689515516c77SSepherosa Ziehau 	 * Kick off network change detection, if it was pending.
689615516c77SSepherosa Ziehau 	 * If no network change was pending, start link status
689715516c77SSepherosa Ziehau 	 * checks, which is more lightweight than network change
689815516c77SSepherosa Ziehau 	 * detection.
689915516c77SSepherosa Ziehau 	 */
690015516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
690115516c77SSepherosa Ziehau 		hn_change_network(sc);
690215516c77SSepherosa Ziehau 	else
690315516c77SSepherosa Ziehau 		hn_update_link_status(sc);
690415516c77SSepherosa Ziehau }
690515516c77SSepherosa Ziehau 
690615516c77SSepherosa Ziehau static void
690715516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc)
690815516c77SSepherosa Ziehau {
690915516c77SSepherosa Ziehau 
69109c6cae24SSepherosa Ziehau 	/*
69119c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, the synthetic
69129c6cae24SSepherosa Ziehau 	 * device have to receive packets, so the data path of the
69139c6cae24SSepherosa Ziehau 	 * synthetic device must be resumed.
69149c6cae24SSepherosa Ziehau 	 */
69155bdfd3fdSDexuan Cui 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
6916962f0357SSepherosa Ziehau 	    (sc->hn_flags & HN_FLAG_RXVF))
691715516c77SSepherosa Ziehau 		hn_resume_data(sc);
69185bdfd3fdSDexuan Cui 
69195bdfd3fdSDexuan Cui 	/*
69209c6cae24SSepherosa Ziehau 	 * Don't resume link status change if VF is attached/activated.
69219c6cae24SSepherosa Ziehau 	 * - In the non-transparent VF mode, the synthetic device marks
69229c6cae24SSepherosa Ziehau 	 *   link down until the VF is deactivated; i.e. VF is down.
69239c6cae24SSepherosa Ziehau 	 * - In transparent VF mode, VF's media status is used until
69249c6cae24SSepherosa Ziehau 	 *   the VF is detached.
69255bdfd3fdSDexuan Cui 	 */
69269c6cae24SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) == 0 &&
69279c6cae24SSepherosa Ziehau 	    !(hn_xpnt_vf && sc->hn_vf_ifp != NULL))
692815516c77SSepherosa Ziehau 		hn_resume_mgmt(sc);
692987f8129dSSepherosa Ziehau 
693087f8129dSSepherosa Ziehau 	/*
693187f8129dSSepherosa Ziehau 	 * Re-enable polling if this interface is running and
693287f8129dSSepherosa Ziehau 	 * the polling is requested.
693387f8129dSSepherosa Ziehau 	 */
693487f8129dSSepherosa Ziehau 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->hn_pollhz > 0)
693587f8129dSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
693615516c77SSepherosa Ziehau }
693715516c77SSepherosa Ziehau 
693815516c77SSepherosa Ziehau static void
693915516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen)
694015516c77SSepherosa Ziehau {
694115516c77SSepherosa Ziehau 	const struct rndis_status_msg *msg;
694215516c77SSepherosa Ziehau 	int ofs;
694315516c77SSepherosa Ziehau 
694415516c77SSepherosa Ziehau 	if (dlen < sizeof(*msg)) {
694515516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid RNDIS status\n");
694615516c77SSepherosa Ziehau 		return;
694715516c77SSepherosa Ziehau 	}
694815516c77SSepherosa Ziehau 	msg = data;
694915516c77SSepherosa Ziehau 
695015516c77SSepherosa Ziehau 	switch (msg->rm_status) {
695115516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_CONNECT:
695215516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_DISCONNECT:
695315516c77SSepherosa Ziehau 		hn_update_link_status(sc);
695415516c77SSepherosa Ziehau 		break;
695515516c77SSepherosa Ziehau 
695615516c77SSepherosa Ziehau 	case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
695740905afaSSepherosa Ziehau 	case RNDIS_STATUS_LINK_SPEED_CHANGE:
695815516c77SSepherosa Ziehau 		/* Not really useful; ignore. */
695915516c77SSepherosa Ziehau 		break;
696015516c77SSepherosa Ziehau 
696115516c77SSepherosa Ziehau 	case RNDIS_STATUS_NETWORK_CHANGE:
696215516c77SSepherosa Ziehau 		ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
696315516c77SSepherosa Ziehau 		if (dlen < ofs + msg->rm_stbuflen ||
696415516c77SSepherosa Ziehau 		    msg->rm_stbuflen < sizeof(uint32_t)) {
696515516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed\n");
696615516c77SSepherosa Ziehau 		} else {
696715516c77SSepherosa Ziehau 			uint32_t change;
696815516c77SSepherosa Ziehau 
696915516c77SSepherosa Ziehau 			memcpy(&change, ((const uint8_t *)msg) + ofs,
697015516c77SSepherosa Ziehau 			    sizeof(change));
697115516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed, change %u\n",
697215516c77SSepherosa Ziehau 			    change);
697315516c77SSepherosa Ziehau 		}
697415516c77SSepherosa Ziehau 		hn_change_network(sc);
697515516c77SSepherosa Ziehau 		break;
697615516c77SSepherosa Ziehau 
697715516c77SSepherosa Ziehau 	default:
697815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
697915516c77SSepherosa Ziehau 		    msg->rm_status);
698015516c77SSepherosa Ziehau 		break;
698115516c77SSepherosa Ziehau 	}
698215516c77SSepherosa Ziehau }
698315516c77SSepherosa Ziehau 
698415516c77SSepherosa Ziehau static int
698515516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info)
698615516c77SSepherosa Ziehau {
698715516c77SSepherosa Ziehau 	const struct rndis_pktinfo *pi = info_data;
698815516c77SSepherosa Ziehau 	uint32_t mask = 0;
698915516c77SSepherosa Ziehau 
699015516c77SSepherosa Ziehau 	while (info_dlen != 0) {
699115516c77SSepherosa Ziehau 		const void *data;
699215516c77SSepherosa Ziehau 		uint32_t dlen;
699315516c77SSepherosa Ziehau 
699415516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < sizeof(*pi)))
699515516c77SSepherosa Ziehau 			return (EINVAL);
699615516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < pi->rm_size))
699715516c77SSepherosa Ziehau 			return (EINVAL);
699815516c77SSepherosa Ziehau 		info_dlen -= pi->rm_size;
699915516c77SSepherosa Ziehau 
700015516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
700115516c77SSepherosa Ziehau 			return (EINVAL);
700215516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
700315516c77SSepherosa Ziehau 			return (EINVAL);
700415516c77SSepherosa Ziehau 		dlen = pi->rm_size - pi->rm_pktinfooffset;
700515516c77SSepherosa Ziehau 		data = pi->rm_data;
700615516c77SSepherosa Ziehau 
700715516c77SSepherosa Ziehau 		switch (pi->rm_type) {
700815516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_VLAN:
700915516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
701015516c77SSepherosa Ziehau 				return (EINVAL);
701115516c77SSepherosa Ziehau 			info->vlan_info = *((const uint32_t *)data);
701215516c77SSepherosa Ziehau 			mask |= HN_RXINFO_VLAN;
701315516c77SSepherosa Ziehau 			break;
701415516c77SSepherosa Ziehau 
701515516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_CSUM:
701615516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
701715516c77SSepherosa Ziehau 				return (EINVAL);
701815516c77SSepherosa Ziehau 			info->csum_info = *((const uint32_t *)data);
701915516c77SSepherosa Ziehau 			mask |= HN_RXINFO_CSUM;
702015516c77SSepherosa Ziehau 			break;
702115516c77SSepherosa Ziehau 
702215516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHVAL:
702315516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
702415516c77SSepherosa Ziehau 				return (EINVAL);
702515516c77SSepherosa Ziehau 			info->hash_value = *((const uint32_t *)data);
702615516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHVAL;
702715516c77SSepherosa Ziehau 			break;
702815516c77SSepherosa Ziehau 
702915516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHINF:
703015516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
703115516c77SSepherosa Ziehau 				return (EINVAL);
703215516c77SSepherosa Ziehau 			info->hash_info = *((const uint32_t *)data);
703315516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHINF;
703415516c77SSepherosa Ziehau 			break;
703515516c77SSepherosa Ziehau 
703615516c77SSepherosa Ziehau 		default:
703715516c77SSepherosa Ziehau 			goto next;
703815516c77SSepherosa Ziehau 		}
703915516c77SSepherosa Ziehau 
704015516c77SSepherosa Ziehau 		if (mask == HN_RXINFO_ALL) {
704115516c77SSepherosa Ziehau 			/* All found; done */
704215516c77SSepherosa Ziehau 			break;
704315516c77SSepherosa Ziehau 		}
704415516c77SSepherosa Ziehau next:
704515516c77SSepherosa Ziehau 		pi = (const struct rndis_pktinfo *)
704615516c77SSepherosa Ziehau 		    ((const uint8_t *)pi + pi->rm_size);
704715516c77SSepherosa Ziehau 	}
704815516c77SSepherosa Ziehau 
704915516c77SSepherosa Ziehau 	/*
705015516c77SSepherosa Ziehau 	 * Final fixup.
705115516c77SSepherosa Ziehau 	 * - If there is no hash value, invalidate the hash info.
705215516c77SSepherosa Ziehau 	 */
705315516c77SSepherosa Ziehau 	if ((mask & HN_RXINFO_HASHVAL) == 0)
705415516c77SSepherosa Ziehau 		info->hash_info = HN_NDIS_HASH_INFO_INVALID;
705515516c77SSepherosa Ziehau 	return (0);
705615516c77SSepherosa Ziehau }
705715516c77SSepherosa Ziehau 
705815516c77SSepherosa Ziehau static __inline bool
705915516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
706015516c77SSepherosa Ziehau {
706115516c77SSepherosa Ziehau 
706215516c77SSepherosa Ziehau 	if (off < check_off) {
706315516c77SSepherosa Ziehau 		if (__predict_true(off + len <= check_off))
706415516c77SSepherosa Ziehau 			return (false);
706515516c77SSepherosa Ziehau 	} else if (off > check_off) {
706615516c77SSepherosa Ziehau 		if (__predict_true(check_off + check_len <= off))
706715516c77SSepherosa Ziehau 			return (false);
706815516c77SSepherosa Ziehau 	}
706915516c77SSepherosa Ziehau 	return (true);
707015516c77SSepherosa Ziehau }
707115516c77SSepherosa Ziehau 
707215516c77SSepherosa Ziehau static void
707315516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen)
707415516c77SSepherosa Ziehau {
707515516c77SSepherosa Ziehau 	const struct rndis_packet_msg *pkt;
707615516c77SSepherosa Ziehau 	struct hn_rxinfo info;
707715516c77SSepherosa Ziehau 	int data_off, pktinfo_off, data_len, pktinfo_len;
707815516c77SSepherosa Ziehau 
707915516c77SSepherosa Ziehau 	/*
708015516c77SSepherosa Ziehau 	 * Check length.
708115516c77SSepherosa Ziehau 	 */
708215516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*pkt))) {
708315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
708415516c77SSepherosa Ziehau 		return;
708515516c77SSepherosa Ziehau 	}
708615516c77SSepherosa Ziehau 	pkt = data;
708715516c77SSepherosa Ziehau 
708815516c77SSepherosa Ziehau 	if (__predict_false(dlen < pkt->rm_len)) {
708915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
709015516c77SSepherosa Ziehau 		    "dlen %d, msglen %u\n", dlen, pkt->rm_len);
709115516c77SSepherosa Ziehau 		return;
709215516c77SSepherosa Ziehau 	}
709315516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_len <
709415516c77SSepherosa Ziehau 	    pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
709515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
709615516c77SSepherosa Ziehau 		    "msglen %u, data %u, oob %u, pktinfo %u\n",
709715516c77SSepherosa Ziehau 		    pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
709815516c77SSepherosa Ziehau 		    pkt->rm_pktinfolen);
709915516c77SSepherosa Ziehau 		return;
710015516c77SSepherosa Ziehau 	}
710115516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_datalen == 0)) {
710215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
710315516c77SSepherosa Ziehau 		return;
710415516c77SSepherosa Ziehau 	}
710515516c77SSepherosa Ziehau 
710615516c77SSepherosa Ziehau 	/*
710715516c77SSepherosa Ziehau 	 * Check offests.
710815516c77SSepherosa Ziehau 	 */
710915516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs)			\
711015516c77SSepherosa Ziehau 	((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN ||	\
711115516c77SSepherosa Ziehau 	 ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
711215516c77SSepherosa Ziehau 
711315516c77SSepherosa Ziehau 	/* XXX Hyper-V does not meet data offset alignment requirement */
711415516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
711515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
711615516c77SSepherosa Ziehau 		    "data offset %u\n", pkt->rm_dataoffset);
711715516c77SSepherosa Ziehau 		return;
711815516c77SSepherosa Ziehau 	}
711915516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdataoffset > 0 &&
712015516c77SSepherosa Ziehau 	    IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
712115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
712215516c77SSepherosa Ziehau 		    "oob offset %u\n", pkt->rm_oobdataoffset);
712315516c77SSepherosa Ziehau 		return;
712415516c77SSepherosa Ziehau 	}
712515516c77SSepherosa Ziehau 	if (__predict_true(pkt->rm_pktinfooffset > 0) &&
712615516c77SSepherosa Ziehau 	    __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
712715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
712815516c77SSepherosa Ziehau 		    "pktinfo offset %u\n", pkt->rm_pktinfooffset);
712915516c77SSepherosa Ziehau 		return;
713015516c77SSepherosa Ziehau 	}
713115516c77SSepherosa Ziehau 
713215516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID
713315516c77SSepherosa Ziehau 
713415516c77SSepherosa Ziehau 	data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
713515516c77SSepherosa Ziehau 	data_len = pkt->rm_datalen;
713615516c77SSepherosa Ziehau 	pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
713715516c77SSepherosa Ziehau 	pktinfo_len = pkt->rm_pktinfolen;
713815516c77SSepherosa Ziehau 
713915516c77SSepherosa Ziehau 	/*
714015516c77SSepherosa Ziehau 	 * Check OOB coverage.
714115516c77SSepherosa Ziehau 	 */
714215516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdatalen != 0)) {
714315516c77SSepherosa Ziehau 		int oob_off, oob_len;
714415516c77SSepherosa Ziehau 
714515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "got oobdata\n");
714615516c77SSepherosa Ziehau 		oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
714715516c77SSepherosa Ziehau 		oob_len = pkt->rm_oobdatalen;
714815516c77SSepherosa Ziehau 
714915516c77SSepherosa Ziehau 		if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
715015516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
715115516c77SSepherosa Ziehau 			    "oob overflow, msglen %u, oob abs %d len %d\n",
715215516c77SSepherosa Ziehau 			    pkt->rm_len, oob_off, oob_len);
715315516c77SSepherosa Ziehau 			return;
715415516c77SSepherosa Ziehau 		}
715515516c77SSepherosa Ziehau 
715615516c77SSepherosa Ziehau 		/*
715715516c77SSepherosa Ziehau 		 * Check against data.
715815516c77SSepherosa Ziehau 		 */
715915516c77SSepherosa Ziehau 		if (hn_rndis_check_overlap(oob_off, oob_len,
716015516c77SSepherosa Ziehau 		    data_off, data_len)) {
716115516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
716215516c77SSepherosa Ziehau 			    "oob overlaps data, oob abs %d len %d, "
716315516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
716415516c77SSepherosa Ziehau 			    oob_off, oob_len, data_off, data_len);
716515516c77SSepherosa Ziehau 			return;
716615516c77SSepherosa Ziehau 		}
716715516c77SSepherosa Ziehau 
716815516c77SSepherosa Ziehau 		/*
716915516c77SSepherosa Ziehau 		 * Check against pktinfo.
717015516c77SSepherosa Ziehau 		 */
717115516c77SSepherosa Ziehau 		if (pktinfo_len != 0 &&
717215516c77SSepherosa Ziehau 		    hn_rndis_check_overlap(oob_off, oob_len,
717315516c77SSepherosa Ziehau 		    pktinfo_off, pktinfo_len)) {
717415516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
717515516c77SSepherosa Ziehau 			    "oob overlaps pktinfo, oob abs %d len %d, "
717615516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
717715516c77SSepherosa Ziehau 			    oob_off, oob_len, pktinfo_off, pktinfo_len);
717815516c77SSepherosa Ziehau 			return;
717915516c77SSepherosa Ziehau 		}
718015516c77SSepherosa Ziehau 	}
718115516c77SSepherosa Ziehau 
718215516c77SSepherosa Ziehau 	/*
718315516c77SSepherosa Ziehau 	 * Check per-packet-info coverage and find useful per-packet-info.
718415516c77SSepherosa Ziehau 	 */
718515516c77SSepherosa Ziehau 	info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
718615516c77SSepherosa Ziehau 	info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
718715516c77SSepherosa Ziehau 	info.hash_info = HN_NDIS_HASH_INFO_INVALID;
718815516c77SSepherosa Ziehau 	if (__predict_true(pktinfo_len != 0)) {
718915516c77SSepherosa Ziehau 		bool overlap;
719015516c77SSepherosa Ziehau 		int error;
719115516c77SSepherosa Ziehau 
719215516c77SSepherosa Ziehau 		if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
719315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
719415516c77SSepherosa Ziehau 			    "pktinfo overflow, msglen %u, "
719515516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
719615516c77SSepherosa Ziehau 			    pkt->rm_len, pktinfo_off, pktinfo_len);
719715516c77SSepherosa Ziehau 			return;
719815516c77SSepherosa Ziehau 		}
719915516c77SSepherosa Ziehau 
720015516c77SSepherosa Ziehau 		/*
720115516c77SSepherosa Ziehau 		 * Check packet info coverage.
720215516c77SSepherosa Ziehau 		 */
720315516c77SSepherosa Ziehau 		overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
720415516c77SSepherosa Ziehau 		    data_off, data_len);
720515516c77SSepherosa Ziehau 		if (__predict_false(overlap)) {
720615516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
720715516c77SSepherosa Ziehau 			    "pktinfo overlap data, pktinfo abs %d len %d, "
720815516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
720915516c77SSepherosa Ziehau 			    pktinfo_off, pktinfo_len, data_off, data_len);
721015516c77SSepherosa Ziehau 			return;
721115516c77SSepherosa Ziehau 		}
721215516c77SSepherosa Ziehau 
721315516c77SSepherosa Ziehau 		/*
721415516c77SSepherosa Ziehau 		 * Find useful per-packet-info.
721515516c77SSepherosa Ziehau 		 */
721615516c77SSepherosa Ziehau 		error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
721715516c77SSepherosa Ziehau 		    pktinfo_len, &info);
721815516c77SSepherosa Ziehau 		if (__predict_false(error)) {
721915516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
722015516c77SSepherosa Ziehau 			    "pktinfo\n");
722115516c77SSepherosa Ziehau 			return;
722215516c77SSepherosa Ziehau 		}
722315516c77SSepherosa Ziehau 	}
722415516c77SSepherosa Ziehau 
722515516c77SSepherosa Ziehau 	if (__predict_false(data_off + data_len > pkt->rm_len)) {
722615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
722715516c77SSepherosa Ziehau 		    "data overflow, msglen %u, data abs %d len %d\n",
722815516c77SSepherosa Ziehau 		    pkt->rm_len, data_off, data_len);
722915516c77SSepherosa Ziehau 		return;
723015516c77SSepherosa Ziehau 	}
723115516c77SSepherosa Ziehau 	hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
723215516c77SSepherosa Ziehau }
723315516c77SSepherosa Ziehau 
723415516c77SSepherosa Ziehau static __inline void
723515516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen)
723615516c77SSepherosa Ziehau {
723715516c77SSepherosa Ziehau 	const struct rndis_msghdr *hdr;
723815516c77SSepherosa Ziehau 
723915516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*hdr))) {
724015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
724115516c77SSepherosa Ziehau 		return;
724215516c77SSepherosa Ziehau 	}
724315516c77SSepherosa Ziehau 	hdr = data;
724415516c77SSepherosa Ziehau 
724515516c77SSepherosa Ziehau 	if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) {
724615516c77SSepherosa Ziehau 		/* Hot data path. */
724715516c77SSepherosa Ziehau 		hn_rndis_rx_data(rxr, data, dlen);
724815516c77SSepherosa Ziehau 		/* Done! */
724915516c77SSepherosa Ziehau 		return;
725015516c77SSepherosa Ziehau 	}
725115516c77SSepherosa Ziehau 
725215516c77SSepherosa Ziehau 	if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG)
725315516c77SSepherosa Ziehau 		hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen);
725415516c77SSepherosa Ziehau 	else
725515516c77SSepherosa Ziehau 		hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen);
725615516c77SSepherosa Ziehau }
725715516c77SSepherosa Ziehau 
725815516c77SSepherosa Ziehau static void
725915516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
726015516c77SSepherosa Ziehau {
726115516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *hdr;
726215516c77SSepherosa Ziehau 
726315516c77SSepherosa Ziehau 	if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) {
726415516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid nvs notify\n");
726515516c77SSepherosa Ziehau 		return;
726615516c77SSepherosa Ziehau 	}
726715516c77SSepherosa Ziehau 	hdr = VMBUS_CHANPKT_CONST_DATA(pkt);
726815516c77SSepherosa Ziehau 
726915516c77SSepherosa Ziehau 	if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) {
727015516c77SSepherosa Ziehau 		/* Useless; ignore */
727115516c77SSepherosa Ziehau 		return;
727215516c77SSepherosa Ziehau 	}
727315516c77SSepherosa Ziehau 	if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type);
727415516c77SSepherosa Ziehau }
727515516c77SSepherosa Ziehau 
727615516c77SSepherosa Ziehau static void
727715516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan,
727815516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkt)
727915516c77SSepherosa Ziehau {
728015516c77SSepherosa Ziehau 	struct hn_nvs_sendctx *sndc;
728115516c77SSepherosa Ziehau 
728215516c77SSepherosa Ziehau 	sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid;
728315516c77SSepherosa Ziehau 	sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt),
728415516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_DATALEN(pkt));
728515516c77SSepherosa Ziehau 	/*
728615516c77SSepherosa Ziehau 	 * NOTE:
728715516c77SSepherosa Ziehau 	 * 'sndc' CAN NOT be accessed anymore, since it can be freed by
728815516c77SSepherosa Ziehau 	 * its callback.
728915516c77SSepherosa Ziehau 	 */
729015516c77SSepherosa Ziehau }
729115516c77SSepherosa Ziehau 
729215516c77SSepherosa Ziehau static void
729315516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
729415516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkthdr)
729515516c77SSepherosa Ziehau {
729615516c77SSepherosa Ziehau 	const struct vmbus_chanpkt_rxbuf *pkt;
729715516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *nvs_hdr;
729815516c77SSepherosa Ziehau 	int count, i, hlen;
729915516c77SSepherosa Ziehau 
730015516c77SSepherosa Ziehau 	if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) {
730115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n");
730215516c77SSepherosa Ziehau 		return;
730315516c77SSepherosa Ziehau 	}
730415516c77SSepherosa Ziehau 	nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr);
730515516c77SSepherosa Ziehau 
730615516c77SSepherosa Ziehau 	/* Make sure that this is a RNDIS message. */
730715516c77SSepherosa Ziehau 	if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) {
730815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n",
730915516c77SSepherosa Ziehau 		    nvs_hdr->nvs_type);
731015516c77SSepherosa Ziehau 		return;
731115516c77SSepherosa Ziehau 	}
731215516c77SSepherosa Ziehau 
731315516c77SSepherosa Ziehau 	hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen);
731415516c77SSepherosa Ziehau 	if (__predict_false(hlen < sizeof(*pkt))) {
731515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n");
731615516c77SSepherosa Ziehau 		return;
731715516c77SSepherosa Ziehau 	}
731815516c77SSepherosa Ziehau 	pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
731915516c77SSepherosa Ziehau 
732015516c77SSepherosa Ziehau 	if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) {
732115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n",
732215516c77SSepherosa Ziehau 		    pkt->cp_rxbuf_id);
732315516c77SSepherosa Ziehau 		return;
732415516c77SSepherosa Ziehau 	}
732515516c77SSepherosa Ziehau 
732615516c77SSepherosa Ziehau 	count = pkt->cp_rxbuf_cnt;
732715516c77SSepherosa Ziehau 	if (__predict_false(hlen <
732815516c77SSepherosa Ziehau 	    __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) {
732915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count);
733015516c77SSepherosa Ziehau 		return;
733115516c77SSepherosa Ziehau 	}
733215516c77SSepherosa Ziehau 
733315516c77SSepherosa Ziehau 	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
733415516c77SSepherosa Ziehau 	for (i = 0; i < count; ++i) {
733515516c77SSepherosa Ziehau 		int ofs, len;
733615516c77SSepherosa Ziehau 
733715516c77SSepherosa Ziehau 		ofs = pkt->cp_rxbuf[i].rb_ofs;
733815516c77SSepherosa Ziehau 		len = pkt->cp_rxbuf[i].rb_len;
733915516c77SSepherosa Ziehau 		if (__predict_false(ofs + len > HN_RXBUF_SIZE)) {
734015516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, "
734115516c77SSepherosa Ziehau 			    "ofs %d, len %d\n", i, ofs, len);
734215516c77SSepherosa Ziehau 			continue;
734315516c77SSepherosa Ziehau 		}
734415516c77SSepherosa Ziehau 		hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len);
734515516c77SSepherosa Ziehau 	}
734615516c77SSepherosa Ziehau 
734715516c77SSepherosa Ziehau 	/*
734815516c77SSepherosa Ziehau 	 * Ack the consumed RXBUF associated w/ this channel packet,
734915516c77SSepherosa Ziehau 	 * so that this RXBUF can be recycled by the hypervisor.
735015516c77SSepherosa Ziehau 	 */
735115516c77SSepherosa Ziehau 	hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid);
735215516c77SSepherosa Ziehau }
735315516c77SSepherosa Ziehau 
735415516c77SSepherosa Ziehau static void
735515516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
735615516c77SSepherosa Ziehau     uint64_t tid)
735715516c77SSepherosa Ziehau {
735815516c77SSepherosa Ziehau 	struct hn_nvs_rndis_ack ack;
735915516c77SSepherosa Ziehau 	int retries, error;
736015516c77SSepherosa Ziehau 
736115516c77SSepherosa Ziehau 	ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK;
736215516c77SSepherosa Ziehau 	ack.nvs_status = HN_NVS_STATUS_OK;
736315516c77SSepherosa Ziehau 
736415516c77SSepherosa Ziehau 	retries = 0;
736515516c77SSepherosa Ziehau again:
736615516c77SSepherosa Ziehau 	error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP,
736715516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid);
736815516c77SSepherosa Ziehau 	if (__predict_false(error == EAGAIN)) {
736915516c77SSepherosa Ziehau 		/*
737015516c77SSepherosa Ziehau 		 * NOTE:
737115516c77SSepherosa Ziehau 		 * This should _not_ happen in real world, since the
737215516c77SSepherosa Ziehau 		 * consumption of the TX bufring from the TX path is
737315516c77SSepherosa Ziehau 		 * controlled.
737415516c77SSepherosa Ziehau 		 */
737515516c77SSepherosa Ziehau 		if (rxr->hn_ack_failed == 0)
737615516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "RXBUF ack retry\n");
737715516c77SSepherosa Ziehau 		rxr->hn_ack_failed++;
737815516c77SSepherosa Ziehau 		retries++;
737915516c77SSepherosa Ziehau 		if (retries < 10) {
738015516c77SSepherosa Ziehau 			DELAY(100);
738115516c77SSepherosa Ziehau 			goto again;
738215516c77SSepherosa Ziehau 		}
738315516c77SSepherosa Ziehau 		/* RXBUF leaks! */
738415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "RXBUF ack failed\n");
738515516c77SSepherosa Ziehau 	}
738615516c77SSepherosa Ziehau }
738715516c77SSepherosa Ziehau 
738815516c77SSepherosa Ziehau static void
738915516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr)
739015516c77SSepherosa Ziehau {
739115516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr = xrxr;
739215516c77SSepherosa Ziehau 	struct hn_softc *sc = rxr->hn_ifp->if_softc;
739315516c77SSepherosa Ziehau 
739415516c77SSepherosa Ziehau 	for (;;) {
739515516c77SSepherosa Ziehau 		struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf;
739615516c77SSepherosa Ziehau 		int error, pktlen;
739715516c77SSepherosa Ziehau 
739815516c77SSepherosa Ziehau 		pktlen = rxr->hn_pktbuf_len;
739915516c77SSepherosa Ziehau 		error = vmbus_chan_recv_pkt(chan, pkt, &pktlen);
740015516c77SSepherosa Ziehau 		if (__predict_false(error == ENOBUFS)) {
740115516c77SSepherosa Ziehau 			void *nbuf;
740215516c77SSepherosa Ziehau 			int nlen;
740315516c77SSepherosa Ziehau 
740415516c77SSepherosa Ziehau 			/*
740515516c77SSepherosa Ziehau 			 * Expand channel packet buffer.
740615516c77SSepherosa Ziehau 			 *
740715516c77SSepherosa Ziehau 			 * XXX
740815516c77SSepherosa Ziehau 			 * Use M_WAITOK here, since allocation failure
740915516c77SSepherosa Ziehau 			 * is fatal.
741015516c77SSepherosa Ziehau 			 */
741115516c77SSepherosa Ziehau 			nlen = rxr->hn_pktbuf_len * 2;
741215516c77SSepherosa Ziehau 			while (nlen < pktlen)
741315516c77SSepherosa Ziehau 				nlen *= 2;
741415516c77SSepherosa Ziehau 			nbuf = malloc(nlen, M_DEVBUF, M_WAITOK);
741515516c77SSepherosa Ziehau 
741615516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n",
741715516c77SSepherosa Ziehau 			    rxr->hn_pktbuf_len, nlen);
741815516c77SSepherosa Ziehau 
741915516c77SSepherosa Ziehau 			free(rxr->hn_pktbuf, M_DEVBUF);
742015516c77SSepherosa Ziehau 			rxr->hn_pktbuf = nbuf;
742115516c77SSepherosa Ziehau 			rxr->hn_pktbuf_len = nlen;
742215516c77SSepherosa Ziehau 			/* Retry! */
742315516c77SSepherosa Ziehau 			continue;
742415516c77SSepherosa Ziehau 		} else if (__predict_false(error == EAGAIN)) {
742515516c77SSepherosa Ziehau 			/* No more channel packets; done! */
742615516c77SSepherosa Ziehau 			break;
742715516c77SSepherosa Ziehau 		}
742815516c77SSepherosa Ziehau 		KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error));
742915516c77SSepherosa Ziehau 
743015516c77SSepherosa Ziehau 		switch (pkt->cph_type) {
743115516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_COMP:
743215516c77SSepherosa Ziehau 			hn_nvs_handle_comp(sc, chan, pkt);
743315516c77SSepherosa Ziehau 			break;
743415516c77SSepherosa Ziehau 
743515516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_RXBUF:
743615516c77SSepherosa Ziehau 			hn_nvs_handle_rxbuf(rxr, chan, pkt);
743715516c77SSepherosa Ziehau 			break;
743815516c77SSepherosa Ziehau 
743915516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_INBAND:
744015516c77SSepherosa Ziehau 			hn_nvs_handle_notify(sc, pkt);
744115516c77SSepherosa Ziehau 			break;
744215516c77SSepherosa Ziehau 
744315516c77SSepherosa Ziehau 		default:
744415516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "unknown chan pkt %u\n",
744515516c77SSepherosa Ziehau 			    pkt->cph_type);
744615516c77SSepherosa Ziehau 			break;
744715516c77SSepherosa Ziehau 		}
744815516c77SSepherosa Ziehau 	}
744915516c77SSepherosa Ziehau 	hn_chan_rollup(rxr, rxr->hn_txr);
745015516c77SSepherosa Ziehau }
745115516c77SSepherosa Ziehau 
745215516c77SSepherosa Ziehau static void
7453499c3e17SSepherosa Ziehau hn_sysinit(void *arg __unused)
745415516c77SSepherosa Ziehau {
7455fdd0222aSSepherosa Ziehau 	int i;
7456fdd0222aSSepherosa Ziehau 
74572be266caSSepherosa Ziehau 	hn_udpcs_fixup = counter_u64_alloc(M_WAITOK);
74582be266caSSepherosa Ziehau 
74599c6cae24SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
74609c6cae24SSepherosa Ziehau 	/*
74619c6cae24SSepherosa Ziehau 	 * Don't use ifnet.if_start if transparent VF mode is requested;
74629c6cae24SSepherosa Ziehau 	 * mainly due to the IFF_DRV_OACTIVE flag.
74639c6cae24SSepherosa Ziehau 	 */
74649c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && hn_use_if_start) {
74659c6cae24SSepherosa Ziehau 		hn_use_if_start = 0;
74669c6cae24SSepherosa Ziehau 		printf("hn: tranparent VF mode, if_transmit will be used, "
74679c6cae24SSepherosa Ziehau 		    "instead of if_start\n");
74689c6cae24SSepherosa Ziehau 	}
74699c6cae24SSepherosa Ziehau #endif
74709c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_attwait < HN_XPNT_VF_ATTWAIT_MIN) {
74719c6cae24SSepherosa Ziehau 		printf("hn: invalid transparent VF attach routing "
74729c6cae24SSepherosa Ziehau 		    "wait timeout %d, reset to %d\n",
74739c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_attwait, HN_XPNT_VF_ATTWAIT_MIN);
74749c6cae24SSepherosa Ziehau 		hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN;
74759c6cae24SSepherosa Ziehau 	}
74769c6cae24SSepherosa Ziehau 
7477fdd0222aSSepherosa Ziehau 	/*
7478499c3e17SSepherosa Ziehau 	 * Initialize VF map.
7479499c3e17SSepherosa Ziehau 	 */
7480499c3e17SSepherosa Ziehau 	rm_init_flags(&hn_vfmap_lock, "hn_vfmap", RM_SLEEPABLE);
7481499c3e17SSepherosa Ziehau 	hn_vfmap_size = HN_VFMAP_SIZE_DEF;
7482499c3e17SSepherosa Ziehau 	hn_vfmap = malloc(sizeof(struct ifnet *) * hn_vfmap_size, M_DEVBUF,
7483499c3e17SSepherosa Ziehau 	    M_WAITOK | M_ZERO);
7484499c3e17SSepherosa Ziehau 
7485499c3e17SSepherosa Ziehau 	/*
7486fdd0222aSSepherosa Ziehau 	 * Fix the # of TX taskqueues.
7487fdd0222aSSepherosa Ziehau 	 */
7488fdd0222aSSepherosa Ziehau 	if (hn_tx_taskq_cnt <= 0)
7489fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = 1;
7490fdd0222aSSepherosa Ziehau 	else if (hn_tx_taskq_cnt > mp_ncpus)
7491fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = mp_ncpus;
749215516c77SSepherosa Ziehau 
74930e11868dSSepherosa Ziehau 	/*
74940e11868dSSepherosa Ziehau 	 * Fix the TX taskqueue mode.
74950e11868dSSepherosa Ziehau 	 */
74960e11868dSSepherosa Ziehau 	switch (hn_tx_taskq_mode) {
74970e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_INDEP:
74980e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_GLOBAL:
74990e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_EVTTQ:
75000e11868dSSepherosa Ziehau 		break;
75010e11868dSSepherosa Ziehau 	default:
75020e11868dSSepherosa Ziehau 		hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
75030e11868dSSepherosa Ziehau 		break;
75040e11868dSSepherosa Ziehau 	}
75050e11868dSSepherosa Ziehau 
750615516c77SSepherosa Ziehau 	if (vm_guest != VM_GUEST_HV)
750715516c77SSepherosa Ziehau 		return;
750815516c77SSepherosa Ziehau 
75090e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode != HN_TX_TASKQ_M_GLOBAL)
751015516c77SSepherosa Ziehau 		return;
751115516c77SSepherosa Ziehau 
7512fdd0222aSSepherosa Ziehau 	hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
7513fdd0222aSSepherosa Ziehau 	    M_DEVBUF, M_WAITOK);
7514fdd0222aSSepherosa Ziehau 	for (i = 0; i < hn_tx_taskq_cnt; ++i) {
7515fdd0222aSSepherosa Ziehau 		hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK,
7516fdd0222aSSepherosa Ziehau 		    taskqueue_thread_enqueue, &hn_tx_taskque[i]);
7517fdd0222aSSepherosa Ziehau 		taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET,
7518fdd0222aSSepherosa Ziehau 		    "hn tx%d", i);
7519fdd0222aSSepherosa Ziehau 	}
752015516c77SSepherosa Ziehau }
7521499c3e17SSepherosa Ziehau SYSINIT(hn_sysinit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysinit, NULL);
752215516c77SSepherosa Ziehau 
752315516c77SSepherosa Ziehau static void
7524499c3e17SSepherosa Ziehau hn_sysuninit(void *arg __unused)
752515516c77SSepherosa Ziehau {
752615516c77SSepherosa Ziehau 
7527fdd0222aSSepherosa Ziehau 	if (hn_tx_taskque != NULL) {
7528fdd0222aSSepherosa Ziehau 		int i;
7529fdd0222aSSepherosa Ziehau 
7530fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
7531fdd0222aSSepherosa Ziehau 			taskqueue_free(hn_tx_taskque[i]);
7532fdd0222aSSepherosa Ziehau 		free(hn_tx_taskque, M_DEVBUF);
7533fdd0222aSSepherosa Ziehau 	}
7534499c3e17SSepherosa Ziehau 
7535499c3e17SSepherosa Ziehau 	if (hn_vfmap != NULL)
7536499c3e17SSepherosa Ziehau 		free(hn_vfmap, M_DEVBUF);
7537499c3e17SSepherosa Ziehau 	rm_destroy(&hn_vfmap_lock);
75382be266caSSepherosa Ziehau 
75392be266caSSepherosa Ziehau 	counter_u64_free(hn_udpcs_fixup);
754015516c77SSepherosa Ziehau }
7541499c3e17SSepherosa Ziehau SYSUNINIT(hn_sysuninit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysuninit, NULL);
7542