xref: /freebsd/sys/dev/hyperv/netvsc/if_hn.c (revision db76829b2bf17e4ef3f0e81904a6f98aefa4ab06)
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);
388*db76829bSSepherosa 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 *);
403*db76829bSSepherosa 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 */
5879c6cae24SSepherosa Ziehau static int			hn_xpnt_vf = 0;
5889c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_transparent, CTLFLAG_RDTUN,
5899c6cae24SSepherosa Ziehau     &hn_xpnt_vf, 0, "Transparent VF mod");
5909c6cae24SSepherosa Ziehau 
5919c6cae24SSepherosa Ziehau /* Accurate BPF support for Transparent VF */
5929c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_accbpf = 0;
5939c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_xpnt_accbpf, CTLFLAG_RDTUN,
5949c6cae24SSepherosa Ziehau     &hn_xpnt_vf_accbpf, 0, "Accurate BPF for transparent VF");
5959c6cae24SSepherosa Ziehau 
5969c6cae24SSepherosa Ziehau /* Extra wait for transparent VF attach routing; unit seconds. */
5979c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN;
5989c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_xpnt_attwait, CTLFLAG_RWTUN,
5999c6cae24SSepherosa Ziehau     &hn_xpnt_vf_attwait, 0,
6009c6cae24SSepherosa Ziehau     "Extra wait for transparent VF attach routing; unit: seconds");
6019c6cae24SSepherosa Ziehau 
60215516c77SSepherosa Ziehau static u_int			hn_cpu_index;	/* next CPU for channel */
603fdd0222aSSepherosa Ziehau static struct taskqueue		**hn_tx_taskque;/* shared TX taskqueues */
60415516c77SSepherosa Ziehau 
605499c3e17SSepherosa Ziehau static struct rmlock		hn_vfmap_lock;
606499c3e17SSepherosa Ziehau static int			hn_vfmap_size;
607499c3e17SSepherosa Ziehau static struct ifnet		**hn_vfmap;
608499c3e17SSepherosa Ziehau 
60934d68912SSepherosa Ziehau #ifndef RSS
61015516c77SSepherosa Ziehau static const uint8_t
61115516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
61215516c77SSepherosa Ziehau 	0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
61315516c77SSepherosa Ziehau 	0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
61415516c77SSepherosa Ziehau 	0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
61515516c77SSepherosa Ziehau 	0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
61615516c77SSepherosa Ziehau 	0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
61715516c77SSepherosa Ziehau };
61834d68912SSepherosa Ziehau #endif	/* !RSS */
61915516c77SSepherosa Ziehau 
620c2d50b26SSepherosa Ziehau static const struct hyperv_guid	hn_guid = {
621c2d50b26SSepherosa Ziehau 	.hv_guid = {
622c2d50b26SSepherosa Ziehau 	    0x63, 0x51, 0x61, 0xf8, 0x3e, 0xdf, 0xc5, 0x46,
623c2d50b26SSepherosa Ziehau 	    0x91, 0x3f, 0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e }
624c2d50b26SSepherosa Ziehau };
625c2d50b26SSepherosa Ziehau 
62615516c77SSepherosa Ziehau static device_method_t hn_methods[] = {
62715516c77SSepherosa Ziehau 	/* Device interface */
62815516c77SSepherosa Ziehau 	DEVMETHOD(device_probe,		hn_probe),
62915516c77SSepherosa Ziehau 	DEVMETHOD(device_attach,	hn_attach),
63015516c77SSepherosa Ziehau 	DEVMETHOD(device_detach,	hn_detach),
63115516c77SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	hn_shutdown),
63215516c77SSepherosa Ziehau 	DEVMETHOD_END
63315516c77SSepherosa Ziehau };
63415516c77SSepherosa Ziehau 
63515516c77SSepherosa Ziehau static driver_t hn_driver = {
63615516c77SSepherosa Ziehau 	"hn",
63715516c77SSepherosa Ziehau 	hn_methods,
63815516c77SSepherosa Ziehau 	sizeof(struct hn_softc)
63915516c77SSepherosa Ziehau };
64015516c77SSepherosa Ziehau 
64115516c77SSepherosa Ziehau static devclass_t hn_devclass;
64215516c77SSepherosa Ziehau 
64315516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0);
64415516c77SSepherosa Ziehau MODULE_VERSION(hn, 1);
64515516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1);
64615516c77SSepherosa Ziehau 
64715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
64815516c77SSepherosa Ziehau static void
64915516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim)
65015516c77SSepherosa Ziehau {
65115516c77SSepherosa Ziehau 	int i;
65215516c77SSepherosa Ziehau 
653a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
65415516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim;
65515516c77SSepherosa Ziehau }
65615516c77SSepherosa Ziehau #endif
65715516c77SSepherosa Ziehau 
65815516c77SSepherosa Ziehau static int
65915516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd)
66015516c77SSepherosa Ziehau {
66115516c77SSepherosa Ziehau 
66215516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
66315516c77SSepherosa Ziehau 	    txd->chim_size == 0, ("invalid rndis sglist txd"));
66415516c77SSepherosa Ziehau 	return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA,
66515516c77SSepherosa Ziehau 	    &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt));
66615516c77SSepherosa Ziehau }
66715516c77SSepherosa Ziehau 
66815516c77SSepherosa Ziehau static int
66915516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd)
67015516c77SSepherosa Ziehau {
67115516c77SSepherosa Ziehau 	struct hn_nvs_rndis rndis;
67215516c77SSepherosa Ziehau 
67315516c77SSepherosa Ziehau 	KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID &&
67415516c77SSepherosa Ziehau 	    txd->chim_size > 0, ("invalid rndis chim txd"));
67515516c77SSepherosa Ziehau 
67615516c77SSepherosa Ziehau 	rndis.nvs_type = HN_NVS_TYPE_RNDIS;
67715516c77SSepherosa Ziehau 	rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA;
67815516c77SSepherosa Ziehau 	rndis.nvs_chim_idx = txd->chim_index;
67915516c77SSepherosa Ziehau 	rndis.nvs_chim_sz = txd->chim_size;
68015516c77SSepherosa Ziehau 
68115516c77SSepherosa Ziehau 	return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC,
68215516c77SSepherosa Ziehau 	    &rndis, sizeof(rndis), &txd->send_ctx));
68315516c77SSepherosa Ziehau }
68415516c77SSepherosa Ziehau 
68515516c77SSepherosa Ziehau static __inline uint32_t
68615516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc)
68715516c77SSepherosa Ziehau {
68815516c77SSepherosa Ziehau 	int i, bmap_cnt = sc->hn_chim_bmap_cnt;
68915516c77SSepherosa Ziehau 	u_long *bmap = sc->hn_chim_bmap;
69015516c77SSepherosa Ziehau 	uint32_t ret = HN_NVS_CHIM_IDX_INVALID;
69115516c77SSepherosa Ziehau 
69215516c77SSepherosa Ziehau 	for (i = 0; i < bmap_cnt; ++i) {
69315516c77SSepherosa Ziehau 		int idx;
69415516c77SSepherosa Ziehau 
69515516c77SSepherosa Ziehau 		idx = ffsl(~bmap[i]);
69615516c77SSepherosa Ziehau 		if (idx == 0)
69715516c77SSepherosa Ziehau 			continue;
69815516c77SSepherosa Ziehau 
69915516c77SSepherosa Ziehau 		--idx; /* ffsl is 1-based */
70015516c77SSepherosa Ziehau 		KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt,
70115516c77SSepherosa Ziehau 		    ("invalid i %d and idx %d", i, idx));
70215516c77SSepherosa Ziehau 
70315516c77SSepherosa Ziehau 		if (atomic_testandset_long(&bmap[i], idx))
70415516c77SSepherosa Ziehau 			continue;
70515516c77SSepherosa Ziehau 
70615516c77SSepherosa Ziehau 		ret = i * LONG_BIT + idx;
70715516c77SSepherosa Ziehau 		break;
70815516c77SSepherosa Ziehau 	}
70915516c77SSepherosa Ziehau 	return (ret);
71015516c77SSepherosa Ziehau }
71115516c77SSepherosa Ziehau 
71215516c77SSepherosa Ziehau static __inline void
71315516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx)
71415516c77SSepherosa Ziehau {
71515516c77SSepherosa Ziehau 	u_long mask;
71615516c77SSepherosa Ziehau 	uint32_t idx;
71715516c77SSepherosa Ziehau 
71815516c77SSepherosa Ziehau 	idx = chim_idx / LONG_BIT;
71915516c77SSepherosa Ziehau 	KASSERT(idx < sc->hn_chim_bmap_cnt,
72015516c77SSepherosa Ziehau 	    ("invalid chimney index 0x%x", chim_idx));
72115516c77SSepherosa Ziehau 
72215516c77SSepherosa Ziehau 	mask = 1UL << (chim_idx % LONG_BIT);
72315516c77SSepherosa Ziehau 	KASSERT(sc->hn_chim_bmap[idx] & mask,
72415516c77SSepherosa Ziehau 	    ("index bitmap 0x%lx, chimney index %u, "
72515516c77SSepherosa Ziehau 	     "bitmap idx %d, bitmask 0x%lx",
72615516c77SSepherosa Ziehau 	     sc->hn_chim_bmap[idx], chim_idx, idx, mask));
72715516c77SSepherosa Ziehau 
72815516c77SSepherosa Ziehau 	atomic_clear_long(&sc->hn_chim_bmap[idx], mask);
72915516c77SSepherosa Ziehau }
73015516c77SSepherosa Ziehau 
731edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
732cc0c6ebcSSepherosa Ziehau 
733cc0c6ebcSSepherosa Ziehau #define PULLUP_HDR(m, len)				\
734cc0c6ebcSSepherosa Ziehau do {							\
735cc0c6ebcSSepherosa Ziehau 	if (__predict_false((m)->m_len < (len))) {	\
736cc0c6ebcSSepherosa Ziehau 		(m) = m_pullup((m), (len));		\
737cc0c6ebcSSepherosa Ziehau 		if ((m) == NULL)			\
738cc0c6ebcSSepherosa Ziehau 			return (NULL);			\
739cc0c6ebcSSepherosa Ziehau 	}						\
740cc0c6ebcSSepherosa Ziehau } while (0)
741cc0c6ebcSSepherosa Ziehau 
742edd3f315SSepherosa Ziehau /*
743edd3f315SSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
744edd3f315SSepherosa Ziehau  */
745edd3f315SSepherosa Ziehau static __inline struct mbuf *
746edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head)
747edd3f315SSepherosa Ziehau {
748edd3f315SSepherosa Ziehau 	struct ether_vlan_header *evl;
749edd3f315SSepherosa Ziehau 	struct tcphdr *th;
750edd3f315SSepherosa Ziehau 	int ehlen;
751edd3f315SSepherosa Ziehau 
752edd3f315SSepherosa Ziehau 	KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable"));
753edd3f315SSepherosa Ziehau 
754edd3f315SSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
755edd3f315SSepherosa Ziehau 	evl = mtod(m_head, struct ether_vlan_header *);
756edd3f315SSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
757edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
758edd3f315SSepherosa Ziehau 	else
759edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
760c49d47daSSepherosa Ziehau 	m_head->m_pkthdr.l2hlen = ehlen;
761edd3f315SSepherosa Ziehau 
762edd3f315SSepherosa Ziehau #ifdef INET
763edd3f315SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
764edd3f315SSepherosa Ziehau 		struct ip *ip;
765edd3f315SSepherosa Ziehau 		int iphlen;
766edd3f315SSepherosa Ziehau 
767edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
768edd3f315SSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
769edd3f315SSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
770c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = iphlen;
771edd3f315SSepherosa Ziehau 
772edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
773edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + iphlen);
774edd3f315SSepherosa Ziehau 
775edd3f315SSepherosa Ziehau 		ip->ip_len = 0;
776edd3f315SSepherosa Ziehau 		ip->ip_sum = 0;
777edd3f315SSepherosa Ziehau 		th->th_sum = in_pseudo(ip->ip_src.s_addr,
778edd3f315SSepherosa Ziehau 		    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
779edd3f315SSepherosa Ziehau 	}
780edd3f315SSepherosa Ziehau #endif
781edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET)
782edd3f315SSepherosa Ziehau 	else
783edd3f315SSepherosa Ziehau #endif
784edd3f315SSepherosa Ziehau #ifdef INET6
785edd3f315SSepherosa Ziehau 	{
786edd3f315SSepherosa Ziehau 		struct ip6_hdr *ip6;
787edd3f315SSepherosa Ziehau 
788edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
789edd3f315SSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
790edd3f315SSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP) {
791edd3f315SSepherosa Ziehau 			m_freem(m_head);
792edd3f315SSepherosa Ziehau 			return (NULL);
793edd3f315SSepherosa Ziehau 		}
794c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = sizeof(*ip6);
795edd3f315SSepherosa Ziehau 
796edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
797edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + sizeof(*ip6));
798edd3f315SSepherosa Ziehau 
799edd3f315SSepherosa Ziehau 		ip6->ip6_plen = 0;
800edd3f315SSepherosa Ziehau 		th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
801edd3f315SSepherosa Ziehau 	}
802edd3f315SSepherosa Ziehau #endif
803edd3f315SSepherosa Ziehau 	return (m_head);
804edd3f315SSepherosa Ziehau }
805cc0c6ebcSSepherosa Ziehau 
806cc0c6ebcSSepherosa Ziehau /*
807cc0c6ebcSSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
808cc0c6ebcSSepherosa Ziehau  */
809cc0c6ebcSSepherosa Ziehau static __inline struct mbuf *
810c49d47daSSepherosa Ziehau hn_set_hlen(struct mbuf *m_head)
811cc0c6ebcSSepherosa Ziehau {
812cc0c6ebcSSepherosa Ziehau 	const struct ether_vlan_header *evl;
813cc0c6ebcSSepherosa Ziehau 	int ehlen;
814cc0c6ebcSSepherosa Ziehau 
815cc0c6ebcSSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
816cc0c6ebcSSepherosa Ziehau 	evl = mtod(m_head, const struct ether_vlan_header *);
817cc0c6ebcSSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
818cc0c6ebcSSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
819cc0c6ebcSSepherosa Ziehau 	else
820cc0c6ebcSSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
821c49d47daSSepherosa Ziehau 	m_head->m_pkthdr.l2hlen = ehlen;
822cc0c6ebcSSepherosa Ziehau 
823cc0c6ebcSSepherosa Ziehau #ifdef INET
824c49d47daSSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP_UDP)) {
825cc0c6ebcSSepherosa Ziehau 		const struct ip *ip;
826cc0c6ebcSSepherosa Ziehau 		int iphlen;
827cc0c6ebcSSepherosa Ziehau 
828cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
829cc0c6ebcSSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
830cc0c6ebcSSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
831c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = iphlen;
8322be266caSSepherosa Ziehau 
8332be266caSSepherosa Ziehau 		/*
8342be266caSSepherosa Ziehau 		 * UDP checksum offload does not work in Azure, if the
8352be266caSSepherosa Ziehau 		 * following conditions meet:
8362be266caSSepherosa Ziehau 		 * - sizeof(IP hdr + UDP hdr + payload) > 1420.
8372be266caSSepherosa Ziehau 		 * - IP_DF is not set in the IP hdr.
8382be266caSSepherosa Ziehau 		 *
8392be266caSSepherosa Ziehau 		 * Fallback to software checksum for these UDP datagrams.
8402be266caSSepherosa Ziehau 		 */
8412be266caSSepherosa Ziehau 		if ((m_head->m_pkthdr.csum_flags & CSUM_IP_UDP) &&
8422be266caSSepherosa Ziehau 		    m_head->m_pkthdr.len > hn_udpcs_fixup_mtu + ehlen &&
8432be266caSSepherosa Ziehau 		    (ntohs(ip->ip_off) & IP_DF) == 0) {
8442be266caSSepherosa Ziehau 			uint16_t off = ehlen + iphlen;
8452be266caSSepherosa Ziehau 
8462be266caSSepherosa Ziehau 			counter_u64_add(hn_udpcs_fixup, 1);
8472be266caSSepherosa Ziehau 			PULLUP_HDR(m_head, off + sizeof(struct udphdr));
8482be266caSSepherosa Ziehau 			*(uint16_t *)(m_head->m_data + off +
8492be266caSSepherosa Ziehau                             m_head->m_pkthdr.csum_data) = in_cksum_skip(
8502be266caSSepherosa Ziehau 			    m_head, m_head->m_pkthdr.len, off);
8512be266caSSepherosa Ziehau 			m_head->m_pkthdr.csum_flags &= ~CSUM_IP_UDP;
8522be266caSSepherosa Ziehau 		}
853cc0c6ebcSSepherosa Ziehau 	}
854cc0c6ebcSSepherosa Ziehau #endif
855cc0c6ebcSSepherosa Ziehau #if defined(INET6) && defined(INET)
856cc0c6ebcSSepherosa Ziehau 	else
857cc0c6ebcSSepherosa Ziehau #endif
858cc0c6ebcSSepherosa Ziehau #ifdef INET6
859cc0c6ebcSSepherosa Ziehau 	{
860cc0c6ebcSSepherosa Ziehau 		const struct ip6_hdr *ip6;
861cc0c6ebcSSepherosa Ziehau 
862cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
863cc0c6ebcSSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
864c49d47daSSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP) {
865c49d47daSSepherosa Ziehau 			m_freem(m_head);
866c49d47daSSepherosa Ziehau 			return (NULL);
867c49d47daSSepherosa Ziehau 		}
868c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = sizeof(*ip6);
869cc0c6ebcSSepherosa Ziehau 	}
870cc0c6ebcSSepherosa Ziehau #endif
871cc0c6ebcSSepherosa Ziehau 	return (m_head);
872cc0c6ebcSSepherosa Ziehau }
873cc0c6ebcSSepherosa Ziehau 
874c49d47daSSepherosa Ziehau /*
875c49d47daSSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
876c49d47daSSepherosa Ziehau  */
877c49d47daSSepherosa Ziehau static __inline struct mbuf *
878c49d47daSSepherosa Ziehau hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn)
879c49d47daSSepherosa Ziehau {
880c49d47daSSepherosa Ziehau 	const struct tcphdr *th;
881c49d47daSSepherosa Ziehau 	int ehlen, iphlen;
882c49d47daSSepherosa Ziehau 
883c49d47daSSepherosa Ziehau 	*tcpsyn = 0;
884c49d47daSSepherosa Ziehau 	ehlen = m_head->m_pkthdr.l2hlen;
885c49d47daSSepherosa Ziehau 	iphlen = m_head->m_pkthdr.l3hlen;
886c49d47daSSepherosa Ziehau 
887c49d47daSSepherosa Ziehau 	PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
888c49d47daSSepherosa Ziehau 	th = mtodo(m_head, ehlen + iphlen);
889c49d47daSSepherosa Ziehau 	if (th->th_flags & TH_SYN)
890c49d47daSSepherosa Ziehau 		*tcpsyn = 1;
891c49d47daSSepherosa Ziehau 	return (m_head);
892c49d47daSSepherosa Ziehau }
893c49d47daSSepherosa Ziehau 
894cc0c6ebcSSepherosa Ziehau #undef PULLUP_HDR
895cc0c6ebcSSepherosa Ziehau 
896edd3f315SSepherosa Ziehau #endif	/* INET6 || INET */
897edd3f315SSepherosa Ziehau 
89815516c77SSepherosa Ziehau static int
899f1b0a43fSSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc, uint32_t filter)
900f1b0a43fSSepherosa Ziehau {
901f1b0a43fSSepherosa Ziehau 	int error = 0;
902f1b0a43fSSepherosa Ziehau 
903f1b0a43fSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
904f1b0a43fSSepherosa Ziehau 
905f1b0a43fSSepherosa Ziehau 	if (sc->hn_rx_filter != filter) {
906f1b0a43fSSepherosa Ziehau 		error = hn_rndis_set_rxfilter(sc, filter);
907f1b0a43fSSepherosa Ziehau 		if (!error)
908f1b0a43fSSepherosa Ziehau 			sc->hn_rx_filter = filter;
909f1b0a43fSSepherosa Ziehau 	}
910f1b0a43fSSepherosa Ziehau 	return (error);
911f1b0a43fSSepherosa Ziehau }
912f1b0a43fSSepherosa Ziehau 
913f1b0a43fSSepherosa Ziehau static int
914c08f7b2cSSepherosa Ziehau hn_rxfilter_config(struct hn_softc *sc)
91515516c77SSepherosa Ziehau {
91615516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
91715516c77SSepherosa Ziehau 	uint32_t filter;
91815516c77SSepherosa Ziehau 
91915516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
92015516c77SSepherosa Ziehau 
9219c6cae24SSepherosa Ziehau 	/*
9229c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, we don't know how
9239c6cae24SSepherosa Ziehau 	 * its RX filter is configured, so stick the synthetic device in
9249c6cae24SSepherosa Ziehau 	 * the promiscous mode.
9259c6cae24SSepherosa Ziehau 	 */
9269c6cae24SSepherosa Ziehau 	if ((ifp->if_flags & IFF_PROMISC) || (sc->hn_flags & HN_FLAG_RXVF)) {
92715516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_PROMISCUOUS;
92815516c77SSepherosa Ziehau 	} else {
92915516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_DIRECTED;
93015516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_BROADCAST)
93115516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_BROADCAST;
93215516c77SSepherosa Ziehau 		/* TODO: support multicast list */
93315516c77SSepherosa Ziehau 		if ((ifp->if_flags & IFF_ALLMULTI) ||
93415516c77SSepherosa Ziehau 		    !TAILQ_EMPTY(&ifp->if_multiaddrs))
93515516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
93615516c77SSepherosa Ziehau 	}
937f1b0a43fSSepherosa Ziehau 	return (hn_set_rxfilter(sc, filter));
93815516c77SSepherosa Ziehau }
93915516c77SSepherosa Ziehau 
940dc13fee6SSepherosa Ziehau static void
941dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc)
942dc13fee6SSepherosa Ziehau {
943dc13fee6SSepherosa Ziehau 	uint32_t size, pkts;
944dc13fee6SSepherosa Ziehau 	int i;
945dc13fee6SSepherosa Ziehau 
946dc13fee6SSepherosa Ziehau 	/*
947dc13fee6SSepherosa Ziehau 	 * Setup aggregation size.
948dc13fee6SSepherosa Ziehau 	 */
949dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_size < 0)
950dc13fee6SSepherosa Ziehau 		size = UINT32_MAX;
951dc13fee6SSepherosa Ziehau 	else
952dc13fee6SSepherosa Ziehau 		size = sc->hn_agg_size;
953dc13fee6SSepherosa Ziehau 
954dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_size < size)
955dc13fee6SSepherosa Ziehau 		size = sc->hn_rndis_agg_size;
956dc13fee6SSepherosa Ziehau 
957a4364cfeSSepherosa Ziehau 	/* NOTE: We only aggregate packets using chimney sending buffers. */
958a4364cfeSSepherosa Ziehau 	if (size > (uint32_t)sc->hn_chim_szmax)
959a4364cfeSSepherosa Ziehau 		size = sc->hn_chim_szmax;
960a4364cfeSSepherosa Ziehau 
961dc13fee6SSepherosa Ziehau 	if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) {
962dc13fee6SSepherosa Ziehau 		/* Disable */
963dc13fee6SSepherosa Ziehau 		size = 0;
964dc13fee6SSepherosa Ziehau 		pkts = 0;
965dc13fee6SSepherosa Ziehau 		goto done;
966dc13fee6SSepherosa Ziehau 	}
967dc13fee6SSepherosa Ziehau 
968dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'int'. */
969dc13fee6SSepherosa Ziehau 	if (size > INT_MAX)
970dc13fee6SSepherosa Ziehau 		size = INT_MAX;
971dc13fee6SSepherosa Ziehau 
972dc13fee6SSepherosa Ziehau 	/*
973dc13fee6SSepherosa Ziehau 	 * Setup aggregation packet count.
974dc13fee6SSepherosa Ziehau 	 */
975dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_pkts < 0)
976dc13fee6SSepherosa Ziehau 		pkts = UINT32_MAX;
977dc13fee6SSepherosa Ziehau 	else
978dc13fee6SSepherosa Ziehau 		pkts = sc->hn_agg_pkts;
979dc13fee6SSepherosa Ziehau 
980dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_pkts < pkts)
981dc13fee6SSepherosa Ziehau 		pkts = sc->hn_rndis_agg_pkts;
982dc13fee6SSepherosa Ziehau 
983dc13fee6SSepherosa Ziehau 	if (pkts <= 1) {
984dc13fee6SSepherosa Ziehau 		/* Disable */
985dc13fee6SSepherosa Ziehau 		size = 0;
986dc13fee6SSepherosa Ziehau 		pkts = 0;
987dc13fee6SSepherosa Ziehau 		goto done;
988dc13fee6SSepherosa Ziehau 	}
989dc13fee6SSepherosa Ziehau 
990dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
991dc13fee6SSepherosa Ziehau 	if (pkts > SHRT_MAX)
992dc13fee6SSepherosa Ziehau 		pkts = SHRT_MAX;
993dc13fee6SSepherosa Ziehau 
994dc13fee6SSepherosa Ziehau done:
995dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
996dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_align > SHRT_MAX) {
997dc13fee6SSepherosa Ziehau 		/* Disable */
998dc13fee6SSepherosa Ziehau 		size = 0;
999dc13fee6SSepherosa Ziehau 		pkts = 0;
1000dc13fee6SSepherosa Ziehau 	}
1001dc13fee6SSepherosa Ziehau 
1002dc13fee6SSepherosa Ziehau 	if (bootverbose) {
1003dc13fee6SSepherosa Ziehau 		if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n",
1004dc13fee6SSepherosa Ziehau 		    size, pkts, sc->hn_rndis_agg_align);
1005dc13fee6SSepherosa Ziehau 	}
1006dc13fee6SSepherosa Ziehau 
1007dc13fee6SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
1008dc13fee6SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
1009dc13fee6SSepherosa Ziehau 
1010dc13fee6SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
1011dc13fee6SSepherosa Ziehau 		txr->hn_agg_szmax = size;
1012dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktmax = pkts;
1013dc13fee6SSepherosa Ziehau 		txr->hn_agg_align = sc->hn_rndis_agg_align;
1014dc13fee6SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
1015dc13fee6SSepherosa Ziehau 	}
1016dc13fee6SSepherosa Ziehau }
1017dc13fee6SSepherosa Ziehau 
101815516c77SSepherosa Ziehau static int
101915516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr)
102015516c77SSepherosa Ziehau {
102115516c77SSepherosa Ziehau 
102215516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet"));
102315516c77SSepherosa Ziehau 	if (hn_tx_swq_depth < txr->hn_txdesc_cnt)
102415516c77SSepherosa Ziehau 		return txr->hn_txdesc_cnt;
102515516c77SSepherosa Ziehau 	return hn_tx_swq_depth;
102615516c77SSepherosa Ziehau }
102715516c77SSepherosa Ziehau 
102815516c77SSepherosa Ziehau static int
102915516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc)
103015516c77SSepherosa Ziehau {
103115516c77SSepherosa Ziehau 	int error;
103215516c77SSepherosa Ziehau 
103315516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
103415516c77SSepherosa Ziehau 
103515516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
103615516c77SSepherosa Ziehau 		return (ENXIO);
103715516c77SSepherosa Ziehau 
103815516c77SSepherosa Ziehau 	/*
103915516c77SSepherosa Ziehau 	 * Disable RSS first.
104015516c77SSepherosa Ziehau 	 *
104115516c77SSepherosa Ziehau 	 * NOTE:
104215516c77SSepherosa Ziehau 	 * Direct reconfiguration by setting the UNCHG flags does
104315516c77SSepherosa Ziehau 	 * _not_ work properly.
104415516c77SSepherosa Ziehau 	 */
104515516c77SSepherosa Ziehau 	if (bootverbose)
104615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "disable RSS\n");
104715516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE);
104815516c77SSepherosa Ziehau 	if (error) {
104915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS disable failed\n");
105015516c77SSepherosa Ziehau 		return (error);
105115516c77SSepherosa Ziehau 	}
105215516c77SSepherosa Ziehau 
105315516c77SSepherosa Ziehau 	/*
105415516c77SSepherosa Ziehau 	 * Reenable the RSS w/ the updated RSS key or indirect
105515516c77SSepherosa Ziehau 	 * table.
105615516c77SSepherosa Ziehau 	 */
105715516c77SSepherosa Ziehau 	if (bootverbose)
105815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "reconfig RSS\n");
105915516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
106015516c77SSepherosa Ziehau 	if (error) {
106115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS reconfig failed\n");
106215516c77SSepherosa Ziehau 		return (error);
106315516c77SSepherosa Ziehau 	}
106415516c77SSepherosa Ziehau 	return (0);
106515516c77SSepherosa Ziehau }
106615516c77SSepherosa Ziehau 
106715516c77SSepherosa Ziehau static void
1068afd4971bSSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc)
106915516c77SSepherosa Ziehau {
107015516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
1071afd4971bSSepherosa Ziehau 	int i, nchan;
107215516c77SSepherosa Ziehau 
1073afd4971bSSepherosa Ziehau 	nchan = sc->hn_rx_ring_inuse;
107415516c77SSepherosa Ziehau 	KASSERT(nchan > 1, ("invalid # of channels %d", nchan));
107515516c77SSepherosa Ziehau 
107615516c77SSepherosa Ziehau 	/*
107715516c77SSepherosa Ziehau 	 * Check indirect table to make sure that all channels in it
107815516c77SSepherosa Ziehau 	 * can be used.
107915516c77SSepherosa Ziehau 	 */
108015516c77SSepherosa Ziehau 	for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
108115516c77SSepherosa Ziehau 		if (rss->rss_ind[i] >= nchan) {
108215516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp,
108315516c77SSepherosa Ziehau 			    "RSS indirect table %d fixup: %u -> %d\n",
108415516c77SSepherosa Ziehau 			    i, rss->rss_ind[i], nchan - 1);
108515516c77SSepherosa Ziehau 			rss->rss_ind[i] = nchan - 1;
108615516c77SSepherosa Ziehau 		}
108715516c77SSepherosa Ziehau 	}
108815516c77SSepherosa Ziehau }
108915516c77SSepherosa Ziehau 
109015516c77SSepherosa Ziehau static int
109115516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused)
109215516c77SSepherosa Ziehau {
109315516c77SSepherosa Ziehau 
109415516c77SSepherosa Ziehau 	return EOPNOTSUPP;
109515516c77SSepherosa Ziehau }
109615516c77SSepherosa Ziehau 
109715516c77SSepherosa Ziehau static void
109815516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
109915516c77SSepherosa Ziehau {
110015516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
110115516c77SSepherosa Ziehau 
110215516c77SSepherosa Ziehau 	ifmr->ifm_status = IFM_AVALID;
110315516c77SSepherosa Ziehau 	ifmr->ifm_active = IFM_ETHER;
110415516c77SSepherosa Ziehau 
110515516c77SSepherosa Ziehau 	if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) {
110615516c77SSepherosa Ziehau 		ifmr->ifm_active |= IFM_NONE;
110715516c77SSepherosa Ziehau 		return;
110815516c77SSepherosa Ziehau 	}
110915516c77SSepherosa Ziehau 	ifmr->ifm_status |= IFM_ACTIVE;
111015516c77SSepherosa Ziehau 	ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
111115516c77SSepherosa Ziehau }
111215516c77SSepherosa Ziehau 
11135bdfd3fdSDexuan Cui static void
1114962f0357SSepherosa Ziehau hn_rxvf_set_task(void *xarg, int pending __unused)
11155bdfd3fdSDexuan Cui {
1116962f0357SSepherosa Ziehau 	struct hn_rxvf_setarg *arg = xarg;
11175bdfd3fdSDexuan Cui 
1118962f0357SSepherosa Ziehau 	arg->rxr->hn_rxvf_ifp = arg->vf_ifp;
11195bdfd3fdSDexuan Cui }
11205bdfd3fdSDexuan Cui 
11215bdfd3fdSDexuan Cui static void
1122962f0357SSepherosa Ziehau hn_rxvf_set(struct hn_softc *sc, struct ifnet *vf_ifp)
11235bdfd3fdSDexuan Cui {
11245bdfd3fdSDexuan Cui 	struct hn_rx_ring *rxr;
1125962f0357SSepherosa Ziehau 	struct hn_rxvf_setarg arg;
11265bdfd3fdSDexuan Cui 	struct task task;
11275bdfd3fdSDexuan Cui 	int i;
11285bdfd3fdSDexuan Cui 
11295bdfd3fdSDexuan Cui 	HN_LOCK_ASSERT(sc);
11305bdfd3fdSDexuan Cui 
1131962f0357SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_rxvf_set_task, &arg);
11325bdfd3fdSDexuan Cui 
11335bdfd3fdSDexuan Cui 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
11345bdfd3fdSDexuan Cui 		rxr = &sc->hn_rx_ring[i];
11355bdfd3fdSDexuan Cui 
11365bdfd3fdSDexuan Cui 		if (i < sc->hn_rx_ring_inuse) {
1137962f0357SSepherosa Ziehau 			arg.rxr = rxr;
1138962f0357SSepherosa Ziehau 			arg.vf_ifp = vf_ifp;
11395bdfd3fdSDexuan Cui 			vmbus_chan_run_task(rxr->hn_chan, &task);
11405bdfd3fdSDexuan Cui 		} else {
1141962f0357SSepherosa Ziehau 			rxr->hn_rxvf_ifp = vf_ifp;
11425bdfd3fdSDexuan Cui 		}
11435bdfd3fdSDexuan Cui 	}
11445bdfd3fdSDexuan Cui }
11455bdfd3fdSDexuan Cui 
1146962f0357SSepherosa Ziehau static bool
1147499c3e17SSepherosa Ziehau hn_ismyvf(const struct hn_softc *sc, const struct ifnet *ifp)
1148499c3e17SSepherosa Ziehau {
1149499c3e17SSepherosa Ziehau 	const struct ifnet *hn_ifp;
1150499c3e17SSepherosa Ziehau 
1151499c3e17SSepherosa Ziehau 	hn_ifp = sc->hn_ifp;
1152499c3e17SSepherosa Ziehau 
1153499c3e17SSepherosa Ziehau 	if (ifp == hn_ifp)
1154499c3e17SSepherosa Ziehau 		return (false);
1155499c3e17SSepherosa Ziehau 
1156499c3e17SSepherosa Ziehau 	if (ifp->if_alloctype != IFT_ETHER)
1157499c3e17SSepherosa Ziehau 		return (false);
1158499c3e17SSepherosa Ziehau 
1159499c3e17SSepherosa Ziehau 	/* Ignore lagg/vlan interfaces */
1160499c3e17SSepherosa Ziehau 	if (strcmp(ifp->if_dname, "lagg") == 0 ||
1161499c3e17SSepherosa Ziehau 	    strcmp(ifp->if_dname, "vlan") == 0)
1162499c3e17SSepherosa Ziehau 		return (false);
1163499c3e17SSepherosa Ziehau 
1164499c3e17SSepherosa Ziehau 	if (bcmp(IF_LLADDR(ifp), IF_LLADDR(hn_ifp), ETHER_ADDR_LEN) != 0)
1165499c3e17SSepherosa Ziehau 		return (false);
1166499c3e17SSepherosa Ziehau 
1167499c3e17SSepherosa Ziehau 	return (true);
1168499c3e17SSepherosa Ziehau }
1169499c3e17SSepherosa Ziehau 
11705bdfd3fdSDexuan Cui static void
1171962f0357SSepherosa Ziehau hn_rxvf_change(struct hn_softc *sc, struct ifnet *ifp, bool rxvf)
11725bdfd3fdSDexuan Cui {
11735bdfd3fdSDexuan Cui 	struct ifnet *hn_ifp;
11745bdfd3fdSDexuan Cui 
11755bdfd3fdSDexuan Cui 	HN_LOCK(sc);
11765bdfd3fdSDexuan Cui 
11775bdfd3fdSDexuan Cui 	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
11785bdfd3fdSDexuan Cui 		goto out;
11795bdfd3fdSDexuan Cui 
1180499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1181499c3e17SSepherosa Ziehau 		goto out;
11825bdfd3fdSDexuan Cui 	hn_ifp = sc->hn_ifp;
11835bdfd3fdSDexuan Cui 
1184962f0357SSepherosa Ziehau 	if (rxvf) {
1185962f0357SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_RXVF)
11865bdfd3fdSDexuan Cui 			goto out;
11875bdfd3fdSDexuan Cui 
1188962f0357SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_RXVF;
11895bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
11905bdfd3fdSDexuan Cui 	} else {
1191962f0357SSepherosa Ziehau 		if (!(sc->hn_flags & HN_FLAG_RXVF))
11925bdfd3fdSDexuan Cui 			goto out;
11935bdfd3fdSDexuan Cui 
1194962f0357SSepherosa Ziehau 		sc->hn_flags &= ~HN_FLAG_RXVF;
1195499c3e17SSepherosa Ziehau 		if (hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
11965bdfd3fdSDexuan Cui 			hn_rxfilter_config(sc);
11975bdfd3fdSDexuan Cui 		else
11985bdfd3fdSDexuan Cui 			hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE);
11995bdfd3fdSDexuan Cui 	}
12005bdfd3fdSDexuan Cui 
12015bdfd3fdSDexuan Cui 	hn_nvs_set_datapath(sc,
12029c6cae24SSepherosa Ziehau 	    rxvf ? HN_NVS_DATAPATH_VF : HN_NVS_DATAPATH_SYNTH);
12035bdfd3fdSDexuan Cui 
1204962f0357SSepherosa Ziehau 	hn_rxvf_set(sc, rxvf ? ifp : NULL);
12055bdfd3fdSDexuan Cui 
1206962f0357SSepherosa Ziehau 	if (rxvf) {
1207642ec226SSepherosa Ziehau 		hn_vf_rss_fixup(sc, true);
12085bdfd3fdSDexuan Cui 		hn_suspend_mgmt(sc);
12095bdfd3fdSDexuan Cui 		sc->hn_link_flags &=
12105bdfd3fdSDexuan Cui 		    ~(HN_LINK_FLAG_LINKUP | HN_LINK_FLAG_NETCHG);
1211499c3e17SSepherosa Ziehau 		if_link_state_change(hn_ifp, LINK_STATE_DOWN);
12125bdfd3fdSDexuan Cui 	} else {
1213642ec226SSepherosa Ziehau 		hn_vf_rss_restore(sc);
12145bdfd3fdSDexuan Cui 		hn_resume_mgmt(sc);
12155bdfd3fdSDexuan Cui 	}
12165bdfd3fdSDexuan Cui 
1217962f0357SSepherosa Ziehau 	devctl_notify("HYPERV_NIC_VF", hn_ifp->if_xname,
1218962f0357SSepherosa Ziehau 	    rxvf ? "VF_UP" : "VF_DOWN", NULL);
121933408a34SDexuan Cui 
1220962f0357SSepherosa Ziehau 	if (bootverbose) {
1221962f0357SSepherosa Ziehau 		if_printf(hn_ifp, "datapath is switched %s %s\n",
1222962f0357SSepherosa Ziehau 		    rxvf ? "to" : "from", ifp->if_xname);
1223962f0357SSepherosa Ziehau 	}
12245bdfd3fdSDexuan Cui out:
12255bdfd3fdSDexuan Cui 	HN_UNLOCK(sc);
12265bdfd3fdSDexuan Cui }
12275bdfd3fdSDexuan Cui 
12285bdfd3fdSDexuan Cui static void
12295bdfd3fdSDexuan Cui hn_ifnet_event(void *arg, struct ifnet *ifp, int event)
12305bdfd3fdSDexuan Cui {
1231962f0357SSepherosa Ziehau 
12325bdfd3fdSDexuan Cui 	if (event != IFNET_EVENT_UP && event != IFNET_EVENT_DOWN)
12335bdfd3fdSDexuan Cui 		return;
1234962f0357SSepherosa Ziehau 	hn_rxvf_change(arg, ifp, event == IFNET_EVENT_UP);
12355bdfd3fdSDexuan Cui }
12365bdfd3fdSDexuan Cui 
12375bdfd3fdSDexuan Cui static void
12385bdfd3fdSDexuan Cui hn_ifaddr_event(void *arg, struct ifnet *ifp)
12395bdfd3fdSDexuan Cui {
1240962f0357SSepherosa Ziehau 
1241962f0357SSepherosa Ziehau 	hn_rxvf_change(arg, ifp, ifp->if_flags & IFF_UP);
12425bdfd3fdSDexuan Cui }
12435bdfd3fdSDexuan Cui 
12449c6cae24SSepherosa Ziehau static int
12459c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetcaps(struct hn_softc *sc, struct ifreq *ifr)
12469c6cae24SSepherosa Ziehau {
12479c6cae24SSepherosa Ziehau 	struct ifnet *ifp, *vf_ifp;
12489c6cae24SSepherosa Ziehau 	uint64_t tmp;
12499c6cae24SSepherosa Ziehau 	int error;
12509c6cae24SSepherosa Ziehau 
12519c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
12529c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
12539c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
12549c6cae24SSepherosa Ziehau 
12559c6cae24SSepherosa Ziehau 	/*
12569c6cae24SSepherosa Ziehau 	 * Fix up requested capabilities w/ supported capabilities,
12579c6cae24SSepherosa Ziehau 	 * since the supported capabilities could have been changed.
12589c6cae24SSepherosa Ziehau 	 */
12599c6cae24SSepherosa Ziehau 	ifr->ifr_reqcap &= ifp->if_capabilities;
12609c6cae24SSepherosa Ziehau 	/* Pass SIOCSIFCAP to VF. */
12619c6cae24SSepherosa Ziehau 	error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFCAP, (caddr_t)ifr);
12629c6cae24SSepherosa Ziehau 
12639c6cae24SSepherosa Ziehau 	/*
12649c6cae24SSepherosa Ziehau 	 * NOTE:
12659c6cae24SSepherosa Ziehau 	 * The error will be propagated to the callers, however, it
12669c6cae24SSepherosa Ziehau 	 * is _not_ useful here.
12679c6cae24SSepherosa Ziehau 	 */
12689c6cae24SSepherosa Ziehau 
12699c6cae24SSepherosa Ziehau 	/*
12709c6cae24SSepherosa Ziehau 	 * Merge VF's enabled capabilities.
12719c6cae24SSepherosa Ziehau 	 */
12729c6cae24SSepherosa Ziehau 	ifp->if_capenable = vf_ifp->if_capenable & ifp->if_capabilities;
12739c6cae24SSepherosa Ziehau 
12749c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & HN_CSUM_IP_HWASSIST(sc);
12759c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TXCSUM)
12769c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
12779c6cae24SSepherosa Ziehau 	else
12789c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
12799c6cae24SSepherosa Ziehau 
12809c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & HN_CSUM_IP6_HWASSIST(sc);
12819c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
12829c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
12839c6cae24SSepherosa Ziehau 	else
12849c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
12859c6cae24SSepherosa Ziehau 
12869c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & CSUM_IP_TSO;
12879c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TSO4)
12889c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
12899c6cae24SSepherosa Ziehau 	else
12909c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
12919c6cae24SSepherosa Ziehau 
12929c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & CSUM_IP6_TSO;
12939c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TSO6)
12949c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
12959c6cae24SSepherosa Ziehau 	else
12969c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
12979c6cae24SSepherosa Ziehau 
12989c6cae24SSepherosa Ziehau 	return (error);
12999c6cae24SSepherosa Ziehau }
13009c6cae24SSepherosa Ziehau 
13019c6cae24SSepherosa Ziehau static int
13029c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetflags(struct hn_softc *sc)
13039c6cae24SSepherosa Ziehau {
13049c6cae24SSepherosa Ziehau 	struct ifnet *vf_ifp;
13059c6cae24SSepherosa Ziehau 	struct ifreq ifr;
13069c6cae24SSepherosa Ziehau 
13079c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
13089c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
13099c6cae24SSepherosa Ziehau 
13109c6cae24SSepherosa Ziehau 	memset(&ifr, 0, sizeof(ifr));
13119c6cae24SSepherosa Ziehau 	strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
13129c6cae24SSepherosa Ziehau 	ifr.ifr_flags = vf_ifp->if_flags & 0xffff;
13139c6cae24SSepherosa Ziehau 	ifr.ifr_flagshigh = vf_ifp->if_flags >> 16;
13149c6cae24SSepherosa Ziehau 	return (vf_ifp->if_ioctl(vf_ifp, SIOCSIFFLAGS, (caddr_t)&ifr));
13159c6cae24SSepherosa Ziehau }
13169c6cae24SSepherosa Ziehau 
13179c6cae24SSepherosa Ziehau static void
13189c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(struct hn_softc *sc)
13199c6cae24SSepherosa Ziehau {
13209c6cae24SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
13219c6cae24SSepherosa Ziehau 	int allmulti = 0;
13229c6cae24SSepherosa Ziehau 
13239c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
13249c6cae24SSepherosa Ziehau 
13259c6cae24SSepherosa Ziehau 	/* XXX vlan(4) style mcast addr maintenance */
13269c6cae24SSepherosa Ziehau 	if (!TAILQ_EMPTY(&ifp->if_multiaddrs))
13279c6cae24SSepherosa Ziehau 		allmulti = IFF_ALLMULTI;
13289c6cae24SSepherosa Ziehau 
13299c6cae24SSepherosa Ziehau 	/* Always set the VF's if_flags */
13309c6cae24SSepherosa Ziehau 	sc->hn_vf_ifp->if_flags = ifp->if_flags | allmulti;
13319c6cae24SSepherosa Ziehau }
13329c6cae24SSepherosa Ziehau 
13339c6cae24SSepherosa Ziehau static void
13349c6cae24SSepherosa Ziehau hn_xpnt_vf_input(struct ifnet *vf_ifp, struct mbuf *m)
13359c6cae24SSepherosa Ziehau {
13369c6cae24SSepherosa Ziehau 	struct rm_priotracker pt;
13379c6cae24SSepherosa Ziehau 	struct ifnet *hn_ifp = NULL;
13389c6cae24SSepherosa Ziehau 	struct mbuf *mn;
13399c6cae24SSepherosa Ziehau 
13409c6cae24SSepherosa Ziehau 	/*
13419c6cae24SSepherosa Ziehau 	 * XXX racy, if hn(4) ever detached.
13429c6cae24SSepherosa Ziehau 	 */
13439c6cae24SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
13449c6cae24SSepherosa Ziehau 	if (vf_ifp->if_index < hn_vfmap_size)
13459c6cae24SSepherosa Ziehau 		hn_ifp = hn_vfmap[vf_ifp->if_index];
13469c6cae24SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
13479c6cae24SSepherosa Ziehau 
13489c6cae24SSepherosa Ziehau 	if (hn_ifp != NULL) {
13499c6cae24SSepherosa Ziehau 		for (mn = m; mn != NULL; mn = mn->m_nextpkt) {
13503bed4e54SSepherosa Ziehau 			/*
13513bed4e54SSepherosa Ziehau 			 * Allow tapping on the VF.
13523bed4e54SSepherosa Ziehau 			 */
13539c6cae24SSepherosa Ziehau 			ETHER_BPF_MTAP(vf_ifp, mn);
13543bed4e54SSepherosa Ziehau 
13553bed4e54SSepherosa Ziehau 			/*
13563bed4e54SSepherosa Ziehau 			 * Update VF stats.
13573bed4e54SSepherosa Ziehau 			 */
13583bed4e54SSepherosa Ziehau 			if ((vf_ifp->if_capenable & IFCAP_HWSTATS) == 0) {
13593bed4e54SSepherosa Ziehau 				if_inc_counter(vf_ifp, IFCOUNTER_IBYTES,
13603bed4e54SSepherosa Ziehau 				    mn->m_pkthdr.len);
13613bed4e54SSepherosa Ziehau 			}
13623bed4e54SSepherosa Ziehau 			/*
13633bed4e54SSepherosa Ziehau 			 * XXX IFCOUNTER_IMCAST
13643bed4e54SSepherosa Ziehau 			 * This stat updating is kinda invasive, since it
13653bed4e54SSepherosa Ziehau 			 * requires two checks on the mbuf: the length check
13663bed4e54SSepherosa Ziehau 			 * and the ethernet header check.  As of this write,
13673bed4e54SSepherosa Ziehau 			 * all multicast packets go directly to hn(4), which
13683bed4e54SSepherosa Ziehau 			 * makes imcast stat updating in the VF a try in vian.
13693bed4e54SSepherosa Ziehau 			 */
13703bed4e54SSepherosa Ziehau 
13713bed4e54SSepherosa Ziehau 			/*
13723bed4e54SSepherosa Ziehau 			 * Fix up rcvif and increase hn(4)'s ipackets.
13733bed4e54SSepherosa Ziehau 			 */
13749c6cae24SSepherosa Ziehau 			mn->m_pkthdr.rcvif = hn_ifp;
13759c6cae24SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1);
13769c6cae24SSepherosa Ziehau 		}
13773bed4e54SSepherosa Ziehau 		/*
13783bed4e54SSepherosa Ziehau 		 * Go through hn(4)'s if_input.
13793bed4e54SSepherosa Ziehau 		 */
13809c6cae24SSepherosa Ziehau 		hn_ifp->if_input(hn_ifp, m);
13819c6cae24SSepherosa Ziehau 	} else {
13829c6cae24SSepherosa Ziehau 		/*
13839c6cae24SSepherosa Ziehau 		 * In the middle of the transition; free this
13849c6cae24SSepherosa Ziehau 		 * mbuf chain.
13859c6cae24SSepherosa Ziehau 		 */
13869c6cae24SSepherosa Ziehau 		while (m != NULL) {
13879c6cae24SSepherosa Ziehau 			mn = m->m_nextpkt;
13889c6cae24SSepherosa Ziehau 			m->m_nextpkt = NULL;
13899c6cae24SSepherosa Ziehau 			m_freem(m);
13909c6cae24SSepherosa Ziehau 			m = mn;
13919c6cae24SSepherosa Ziehau 		}
13929c6cae24SSepherosa Ziehau 	}
13939c6cae24SSepherosa Ziehau }
13949c6cae24SSepherosa Ziehau 
13959c6cae24SSepherosa Ziehau static void
13969c6cae24SSepherosa Ziehau hn_mtu_change_fixup(struct hn_softc *sc)
13979c6cae24SSepherosa Ziehau {
13989c6cae24SSepherosa Ziehau 	struct ifnet *ifp;
13999c6cae24SSepherosa Ziehau 
14009c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
14019c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
14029c6cae24SSepherosa Ziehau 
14039c6cae24SSepherosa Ziehau 	hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu);
14049c6cae24SSepherosa Ziehau #if __FreeBSD_version >= 1100099
14059c6cae24SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_lro.lro_length_lim < HN_LRO_LENLIM_MIN(ifp))
14069c6cae24SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
14079c6cae24SSepherosa Ziehau #endif
14089c6cae24SSepherosa Ziehau }
14099c6cae24SSepherosa Ziehau 
1410642ec226SSepherosa Ziehau static uint32_t
1411642ec226SSepherosa Ziehau hn_rss_type_fromndis(uint32_t rss_hash)
1412642ec226SSepherosa Ziehau {
1413642ec226SSepherosa Ziehau 	uint32_t types = 0;
1414642ec226SSepherosa Ziehau 
1415642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_IPV4)
1416642ec226SSepherosa Ziehau 		types |= RSS_TYPE_IPV4;
1417642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_TCP_IPV4)
1418642ec226SSepherosa Ziehau 		types |= RSS_TYPE_TCP_IPV4;
1419642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_IPV6)
1420642ec226SSepherosa Ziehau 		types |= RSS_TYPE_IPV6;
1421642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_IPV6_EX)
1422642ec226SSepherosa Ziehau 		types |= RSS_TYPE_IPV6_EX;
1423642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_TCP_IPV6)
1424642ec226SSepherosa Ziehau 		types |= RSS_TYPE_TCP_IPV6;
1425642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_TCP_IPV6_EX)
1426642ec226SSepherosa Ziehau 		types |= RSS_TYPE_TCP_IPV6_EX;
1427642ec226SSepherosa Ziehau 	return (types);
1428642ec226SSepherosa Ziehau }
1429642ec226SSepherosa Ziehau 
1430642ec226SSepherosa Ziehau static uint32_t
1431642ec226SSepherosa Ziehau hn_rss_type_tondis(uint32_t types)
1432642ec226SSepherosa Ziehau {
1433642ec226SSepherosa Ziehau 	uint32_t rss_hash = 0;
1434642ec226SSepherosa Ziehau 
1435642ec226SSepherosa Ziehau 	KASSERT((types &
1436642ec226SSepherosa Ziehau 	(RSS_TYPE_UDP_IPV4 | RSS_TYPE_UDP_IPV6 | RSS_TYPE_UDP_IPV6_EX)) == 0,
1437642ec226SSepherosa Ziehau 	("UDP4, UDP6 and UDP6EX are not supported"));
1438642ec226SSepherosa Ziehau 
1439642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_IPV4)
1440642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_IPV4;
1441642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_TCP_IPV4)
1442642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_TCP_IPV4;
1443642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_IPV6)
1444642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_IPV6;
1445642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_IPV6_EX)
1446642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_IPV6_EX;
1447642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_TCP_IPV6)
1448642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_TCP_IPV6;
1449642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_TCP_IPV6_EX)
1450642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_TCP_IPV6_EX;
1451642ec226SSepherosa Ziehau 	return (rss_hash);
1452642ec226SSepherosa Ziehau }
1453642ec226SSepherosa Ziehau 
1454642ec226SSepherosa Ziehau static void
1455642ec226SSepherosa Ziehau hn_rss_mbuf_hash(struct hn_softc *sc, uint32_t mbuf_hash)
1456642ec226SSepherosa Ziehau {
1457642ec226SSepherosa Ziehau 	int i;
1458642ec226SSepherosa Ziehau 
1459642ec226SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1460642ec226SSepherosa Ziehau 
1461642ec226SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1462642ec226SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_mbuf_hash = mbuf_hash;
1463642ec226SSepherosa Ziehau }
1464642ec226SSepherosa Ziehau 
1465642ec226SSepherosa Ziehau static void
1466642ec226SSepherosa Ziehau hn_vf_rss_fixup(struct hn_softc *sc, bool reconf)
1467642ec226SSepherosa Ziehau {
1468642ec226SSepherosa Ziehau 	struct ifnet *ifp, *vf_ifp;
1469642ec226SSepherosa Ziehau 	struct ifrsshash ifrh;
1470642ec226SSepherosa Ziehau 	struct ifrsskey ifrk;
1471642ec226SSepherosa Ziehau 	int error;
1472642ec226SSepherosa Ziehau 	uint32_t my_types, diff_types, mbuf_types = 0;
1473642ec226SSepherosa Ziehau 
1474642ec226SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1475642ec226SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
1476642ec226SSepherosa Ziehau 	    ("%s: synthetic parts are not attached", sc->hn_ifp->if_xname));
1477642ec226SSepherosa Ziehau 
1478642ec226SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
1479642ec226SSepherosa Ziehau 		/* No RSS on synthetic parts; done. */
1480642ec226SSepherosa Ziehau 		return;
1481642ec226SSepherosa Ziehau 	}
1482642ec226SSepherosa Ziehau 	if ((sc->hn_rss_hcap & NDIS_HASH_FUNCTION_TOEPLITZ) == 0) {
1483642ec226SSepherosa Ziehau 		/* Synthetic parts do not support Toeplitz; done. */
1484642ec226SSepherosa Ziehau 		return;
1485642ec226SSepherosa Ziehau 	}
1486642ec226SSepherosa Ziehau 
1487642ec226SSepherosa Ziehau 	ifp = sc->hn_ifp;
1488642ec226SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
1489642ec226SSepherosa Ziehau 
1490642ec226SSepherosa Ziehau 	/*
1491642ec226SSepherosa Ziehau 	 * Extract VF's RSS key.  Only 40 bytes key for Toeplitz is
1492642ec226SSepherosa Ziehau 	 * supported.
1493642ec226SSepherosa Ziehau 	 */
1494642ec226SSepherosa Ziehau 	memset(&ifrk, 0, sizeof(ifrk));
1495642ec226SSepherosa Ziehau 	strlcpy(ifrk.ifrk_name, vf_ifp->if_xname, sizeof(ifrk.ifrk_name));
1496642ec226SSepherosa Ziehau 	error = vf_ifp->if_ioctl(vf_ifp, SIOCGIFRSSKEY, (caddr_t)&ifrk);
1497642ec226SSepherosa Ziehau 	if (error) {
1498642ec226SSepherosa Ziehau 		if_printf(ifp, "%s SIOCGRSSKEY failed: %d\n",
1499642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, error);
1500642ec226SSepherosa Ziehau 		goto done;
1501642ec226SSepherosa Ziehau 	}
1502642ec226SSepherosa Ziehau 	if (ifrk.ifrk_func != RSS_FUNC_TOEPLITZ) {
1503642ec226SSepherosa Ziehau 		if_printf(ifp, "%s RSS function %u is not Toeplitz\n",
1504642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, ifrk.ifrk_func);
1505642ec226SSepherosa Ziehau 		goto done;
1506642ec226SSepherosa Ziehau 	}
1507642ec226SSepherosa Ziehau 	if (ifrk.ifrk_keylen != NDIS_HASH_KEYSIZE_TOEPLITZ) {
1508642ec226SSepherosa Ziehau 		if_printf(ifp, "%s invalid RSS Toeplitz key length %d\n",
1509642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, ifrk.ifrk_keylen);
1510642ec226SSepherosa Ziehau 		goto done;
1511642ec226SSepherosa Ziehau 	}
1512642ec226SSepherosa Ziehau 
1513642ec226SSepherosa Ziehau 	/*
1514642ec226SSepherosa Ziehau 	 * Extract VF's RSS hash.  Only Toeplitz is supported.
1515642ec226SSepherosa Ziehau 	 */
1516642ec226SSepherosa Ziehau 	memset(&ifrh, 0, sizeof(ifrh));
1517642ec226SSepherosa Ziehau 	strlcpy(ifrh.ifrh_name, vf_ifp->if_xname, sizeof(ifrh.ifrh_name));
1518642ec226SSepherosa Ziehau 	error = vf_ifp->if_ioctl(vf_ifp, SIOCGIFRSSHASH, (caddr_t)&ifrh);
1519642ec226SSepherosa Ziehau 	if (error) {
1520642ec226SSepherosa Ziehau 		if_printf(ifp, "%s SIOCGRSSHASH failed: %d\n",
1521642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, error);
1522642ec226SSepherosa Ziehau 		goto done;
1523642ec226SSepherosa Ziehau 	}
1524642ec226SSepherosa Ziehau 	if (ifrh.ifrh_func != RSS_FUNC_TOEPLITZ) {
1525642ec226SSepherosa Ziehau 		if_printf(ifp, "%s RSS function %u is not Toeplitz\n",
1526642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, ifrh.ifrh_func);
1527642ec226SSepherosa Ziehau 		goto done;
1528642ec226SSepherosa Ziehau 	}
1529642ec226SSepherosa Ziehau 
1530642ec226SSepherosa Ziehau 	my_types = hn_rss_type_fromndis(sc->hn_rss_hcap);
1531642ec226SSepherosa Ziehau 	if ((ifrh.ifrh_types & my_types) == 0) {
1532642ec226SSepherosa Ziehau 		/* This disables RSS; ignore it then */
1533642ec226SSepherosa Ziehau 		if_printf(ifp, "%s intersection of RSS types failed.  "
1534642ec226SSepherosa Ziehau 		    "VF %#x, mine %#x\n", vf_ifp->if_xname,
1535642ec226SSepherosa Ziehau 		    ifrh.ifrh_types, my_types);
1536642ec226SSepherosa Ziehau 		goto done;
1537642ec226SSepherosa Ziehau 	}
1538642ec226SSepherosa Ziehau 
1539642ec226SSepherosa Ziehau 	diff_types = my_types ^ ifrh.ifrh_types;
1540642ec226SSepherosa Ziehau 	my_types &= ifrh.ifrh_types;
1541642ec226SSepherosa Ziehau 	mbuf_types = my_types;
1542642ec226SSepherosa Ziehau 
1543642ec226SSepherosa Ziehau 	/*
1544642ec226SSepherosa Ziehau 	 * Detect RSS hash value/type confliction.
1545642ec226SSepherosa Ziehau 	 *
1546642ec226SSepherosa Ziehau 	 * NOTE:
1547642ec226SSepherosa Ziehau 	 * We don't disable the hash type, but stop delivery the hash
1548642ec226SSepherosa Ziehau 	 * value/type through mbufs on RX path.
1549642ec226SSepherosa Ziehau 	 */
1550642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_IPV4) &&
1551642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types &
1552642ec226SSepherosa Ziehau 	     (RSS_TYPE_TCP_IPV4 | RSS_TYPE_UDP_IPV4))) {
1553642ec226SSepherosa Ziehau 		/* Conflict; disable IPV4 hash type/value delivery. */
1554642ec226SSepherosa Ziehau 		if_printf(ifp, "disable IPV4 mbuf hash delivery\n");
1555642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_IPV4;
1556642ec226SSepherosa Ziehau 	}
1557642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_IPV6) &&
1558642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types &
1559642ec226SSepherosa Ziehau 	     (RSS_TYPE_TCP_IPV6 | RSS_TYPE_UDP_IPV6 |
1560642ec226SSepherosa Ziehau 	      RSS_TYPE_TCP_IPV6_EX | RSS_TYPE_UDP_IPV6_EX |
1561642ec226SSepherosa Ziehau 	      RSS_TYPE_IPV6_EX))) {
1562642ec226SSepherosa Ziehau 		/* Conflict; disable IPV6 hash type/value delivery. */
1563642ec226SSepherosa Ziehau 		if_printf(ifp, "disable IPV6 mbuf hash delivery\n");
1564642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_IPV6;
1565642ec226SSepherosa Ziehau 	}
1566642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_IPV6_EX) &&
1567642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types &
1568642ec226SSepherosa Ziehau 	     (RSS_TYPE_TCP_IPV6 | RSS_TYPE_UDP_IPV6 |
1569642ec226SSepherosa Ziehau 	      RSS_TYPE_TCP_IPV6_EX | RSS_TYPE_UDP_IPV6_EX |
1570642ec226SSepherosa Ziehau 	      RSS_TYPE_IPV6))) {
1571642ec226SSepherosa Ziehau 		/* Conflict; disable IPV6_EX hash type/value delivery. */
1572642ec226SSepherosa Ziehau 		if_printf(ifp, "disable IPV6_EX mbuf hash delivery\n");
1573642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_IPV6_EX;
1574642ec226SSepherosa Ziehau 	}
1575642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_TCP_IPV6) &&
1576642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_TCP_IPV6_EX)) {
1577642ec226SSepherosa Ziehau 		/* Conflict; disable TCP_IPV6 hash type/value delivery. */
1578642ec226SSepherosa Ziehau 		if_printf(ifp, "disable TCP_IPV6 mbuf hash delivery\n");
1579642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_TCP_IPV6;
1580642ec226SSepherosa Ziehau 	}
1581642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_TCP_IPV6_EX) &&
1582642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_TCP_IPV6)) {
1583642ec226SSepherosa Ziehau 		/* Conflict; disable TCP_IPV6_EX hash type/value delivery. */
1584642ec226SSepherosa Ziehau 		if_printf(ifp, "disable TCP_IPV6_EX mbuf hash delivery\n");
1585642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_TCP_IPV6_EX;
1586642ec226SSepherosa Ziehau 	}
1587642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_UDP_IPV6) &&
1588642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_UDP_IPV6_EX)) {
1589642ec226SSepherosa Ziehau 		/* Conflict; disable UDP_IPV6 hash type/value delivery. */
1590642ec226SSepherosa Ziehau 		if_printf(ifp, "disable UDP_IPV6 mbuf hash delivery\n");
1591642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_UDP_IPV6;
1592642ec226SSepherosa Ziehau 	}
1593642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_UDP_IPV6_EX) &&
1594642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_UDP_IPV6)) {
1595642ec226SSepherosa Ziehau 		/* Conflict; disable UDP_IPV6_EX hash type/value delivery. */
1596642ec226SSepherosa Ziehau 		if_printf(ifp, "disable UDP_IPV6_EX mbuf hash delivery\n");
1597642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_UDP_IPV6_EX;
1598642ec226SSepherosa Ziehau 	}
1599642ec226SSepherosa Ziehau 
1600642ec226SSepherosa Ziehau 	/*
1601642ec226SSepherosa Ziehau 	 * Indirect table does not matter.
1602642ec226SSepherosa Ziehau 	 */
1603642ec226SSepherosa Ziehau 
1604642ec226SSepherosa Ziehau 	sc->hn_rss_hash = (sc->hn_rss_hcap & NDIS_HASH_FUNCTION_MASK) |
1605642ec226SSepherosa Ziehau 	    hn_rss_type_tondis(my_types);
1606642ec226SSepherosa Ziehau 	memcpy(sc->hn_rss.rss_key, ifrk.ifrk_key, sizeof(sc->hn_rss.rss_key));
1607642ec226SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
1608642ec226SSepherosa Ziehau 
1609642ec226SSepherosa Ziehau 	if (reconf) {
1610642ec226SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
1611642ec226SSepherosa Ziehau 		if (error) {
1612642ec226SSepherosa Ziehau 			/* XXX roll-back? */
1613642ec226SSepherosa Ziehau 			if_printf(ifp, "hn_rss_reconfig failed: %d\n", error);
1614642ec226SSepherosa Ziehau 			/* XXX keep going. */
1615642ec226SSepherosa Ziehau 		}
1616642ec226SSepherosa Ziehau 	}
1617642ec226SSepherosa Ziehau done:
1618642ec226SSepherosa Ziehau 	/* Hash deliverability for mbufs. */
1619642ec226SSepherosa Ziehau 	hn_rss_mbuf_hash(sc, hn_rss_type_tondis(mbuf_types));
1620642ec226SSepherosa Ziehau }
1621642ec226SSepherosa Ziehau 
1622642ec226SSepherosa Ziehau static void
1623642ec226SSepherosa Ziehau hn_vf_rss_restore(struct hn_softc *sc)
1624642ec226SSepherosa Ziehau {
1625642ec226SSepherosa Ziehau 
1626642ec226SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1627642ec226SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
1628642ec226SSepherosa Ziehau 	    ("%s: synthetic parts are not attached", sc->hn_ifp->if_xname));
1629642ec226SSepherosa Ziehau 
1630642ec226SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1)
1631642ec226SSepherosa Ziehau 		goto done;
1632642ec226SSepherosa Ziehau 
1633642ec226SSepherosa Ziehau 	/*
1634642ec226SSepherosa Ziehau 	 * Restore hash types.  Key does _not_ matter.
1635642ec226SSepherosa Ziehau 	 */
1636642ec226SSepherosa Ziehau 	if (sc->hn_rss_hash != sc->hn_rss_hcap) {
1637642ec226SSepherosa Ziehau 		int error;
1638642ec226SSepherosa Ziehau 
1639642ec226SSepherosa Ziehau 		sc->hn_rss_hash = sc->hn_rss_hcap;
1640642ec226SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
1641642ec226SSepherosa Ziehau 		if (error) {
1642642ec226SSepherosa Ziehau 			if_printf(sc->hn_ifp, "hn_rss_reconfig failed: %d\n",
1643642ec226SSepherosa Ziehau 			    error);
1644642ec226SSepherosa Ziehau 			/* XXX keep going. */
1645642ec226SSepherosa Ziehau 		}
1646642ec226SSepherosa Ziehau 	}
1647642ec226SSepherosa Ziehau done:
1648642ec226SSepherosa Ziehau 	/* Hash deliverability for mbufs. */
1649642ec226SSepherosa Ziehau 	hn_rss_mbuf_hash(sc, NDIS_HASH_ALL);
1650642ec226SSepherosa Ziehau }
1651642ec226SSepherosa Ziehau 
16529c6cae24SSepherosa Ziehau static void
16539c6cae24SSepherosa Ziehau hn_xpnt_vf_setready(struct hn_softc *sc)
16549c6cae24SSepherosa Ziehau {
16559c6cae24SSepherosa Ziehau 	struct ifnet *ifp, *vf_ifp;
16569c6cae24SSepherosa Ziehau 	struct ifreq ifr;
16579c6cae24SSepherosa Ziehau 
16589c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
16599c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
16609c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
16619c6cae24SSepherosa Ziehau 
16629c6cae24SSepherosa Ziehau 	/*
16639c6cae24SSepherosa Ziehau 	 * Mark the VF ready.
16649c6cae24SSepherosa Ziehau 	 */
16659c6cae24SSepherosa Ziehau 	sc->hn_vf_rdytick = 0;
16669c6cae24SSepherosa Ziehau 
16679c6cae24SSepherosa Ziehau 	/*
16689c6cae24SSepherosa Ziehau 	 * Save information for restoration.
16699c6cae24SSepherosa Ziehau 	 */
16709c6cae24SSepherosa Ziehau 	sc->hn_saved_caps = ifp->if_capabilities;
16719c6cae24SSepherosa Ziehau 	sc->hn_saved_tsomax = ifp->if_hw_tsomax;
16729c6cae24SSepherosa Ziehau 	sc->hn_saved_tsosegcnt = ifp->if_hw_tsomaxsegcount;
16739c6cae24SSepherosa Ziehau 	sc->hn_saved_tsosegsz = ifp->if_hw_tsomaxsegsize;
16749c6cae24SSepherosa Ziehau 
16759c6cae24SSepherosa Ziehau 	/*
16769c6cae24SSepherosa Ziehau 	 * Intersect supported/enabled capabilities.
16779c6cae24SSepherosa Ziehau 	 *
16789c6cae24SSepherosa Ziehau 	 * NOTE:
16799c6cae24SSepherosa Ziehau 	 * if_hwassist is not changed here.
16809c6cae24SSepherosa Ziehau 	 */
16819c6cae24SSepherosa Ziehau 	ifp->if_capabilities &= vf_ifp->if_capabilities;
16829c6cae24SSepherosa Ziehau 	ifp->if_capenable &= ifp->if_capabilities;
16839c6cae24SSepherosa Ziehau 
16849c6cae24SSepherosa Ziehau 	/*
16859c6cae24SSepherosa Ziehau 	 * Fix TSO settings.
16869c6cae24SSepherosa Ziehau 	 */
16879c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomax > vf_ifp->if_hw_tsomax)
16889c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomax = vf_ifp->if_hw_tsomax;
16899c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomaxsegcount > vf_ifp->if_hw_tsomaxsegcount)
16909c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = vf_ifp->if_hw_tsomaxsegcount;
16919c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomaxsegsize > vf_ifp->if_hw_tsomaxsegsize)
16929c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = vf_ifp->if_hw_tsomaxsegsize;
16939c6cae24SSepherosa Ziehau 
16949c6cae24SSepherosa Ziehau 	/*
16959c6cae24SSepherosa Ziehau 	 * Change VF's enabled capabilities.
16969c6cae24SSepherosa Ziehau 	 */
16979c6cae24SSepherosa Ziehau 	memset(&ifr, 0, sizeof(ifr));
16989c6cae24SSepherosa Ziehau 	strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
16999c6cae24SSepherosa Ziehau 	ifr.ifr_reqcap = ifp->if_capenable;
17009c6cae24SSepherosa Ziehau 	hn_xpnt_vf_iocsetcaps(sc, &ifr);
17019c6cae24SSepherosa Ziehau 
17029c6cae24SSepherosa Ziehau 	if (ifp->if_mtu != ETHERMTU) {
17039c6cae24SSepherosa Ziehau 		int error;
17049c6cae24SSepherosa Ziehau 
17059c6cae24SSepherosa Ziehau 		/*
17069c6cae24SSepherosa Ziehau 		 * Change VF's MTU.
17079c6cae24SSepherosa Ziehau 		 */
17089c6cae24SSepherosa Ziehau 		memset(&ifr, 0, sizeof(ifr));
17099c6cae24SSepherosa Ziehau 		strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
17109c6cae24SSepherosa Ziehau 		ifr.ifr_mtu = ifp->if_mtu;
17119c6cae24SSepherosa Ziehau 		error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU, (caddr_t)&ifr);
17129c6cae24SSepherosa Ziehau 		if (error) {
17139c6cae24SSepherosa Ziehau 			if_printf(ifp, "%s SIOCSIFMTU %u failed\n",
17149c6cae24SSepherosa Ziehau 			    vf_ifp->if_xname, ifp->if_mtu);
17159c6cae24SSepherosa Ziehau 			if (ifp->if_mtu > ETHERMTU) {
17169c6cae24SSepherosa Ziehau 				if_printf(ifp, "change MTU to %d\n", ETHERMTU);
17179c6cae24SSepherosa Ziehau 
17189c6cae24SSepherosa Ziehau 				/*
17199c6cae24SSepherosa Ziehau 				 * XXX
17209c6cae24SSepherosa Ziehau 				 * No need to adjust the synthetic parts' MTU;
17219c6cae24SSepherosa Ziehau 				 * failure of the adjustment will cause us
17229c6cae24SSepherosa Ziehau 				 * infinite headache.
17239c6cae24SSepherosa Ziehau 				 */
17249c6cae24SSepherosa Ziehau 				ifp->if_mtu = ETHERMTU;
17259c6cae24SSepherosa Ziehau 				hn_mtu_change_fixup(sc);
17269c6cae24SSepherosa Ziehau 			}
17279c6cae24SSepherosa Ziehau 		}
17289c6cae24SSepherosa Ziehau 	}
17299c6cae24SSepherosa Ziehau }
17309c6cae24SSepherosa Ziehau 
17319c6cae24SSepherosa Ziehau static bool
17329c6cae24SSepherosa Ziehau hn_xpnt_vf_isready(struct hn_softc *sc)
17339c6cae24SSepherosa Ziehau {
17349c6cae24SSepherosa Ziehau 
17359c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
17369c6cae24SSepherosa Ziehau 
17379c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf || sc->hn_vf_ifp == NULL)
17389c6cae24SSepherosa Ziehau 		return (false);
17399c6cae24SSepherosa Ziehau 
17409c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick == 0)
17419c6cae24SSepherosa Ziehau 		return (true);
17429c6cae24SSepherosa Ziehau 
17439c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick > ticks)
17449c6cae24SSepherosa Ziehau 		return (false);
17459c6cae24SSepherosa Ziehau 
17469c6cae24SSepherosa Ziehau 	/* Mark VF as ready. */
17479c6cae24SSepherosa Ziehau 	hn_xpnt_vf_setready(sc);
17489c6cae24SSepherosa Ziehau 	return (true);
17499c6cae24SSepherosa Ziehau }
17509c6cae24SSepherosa Ziehau 
17519c6cae24SSepherosa Ziehau static void
1752a97fff19SSepherosa Ziehau hn_xpnt_vf_setenable(struct hn_softc *sc)
1753a97fff19SSepherosa Ziehau {
1754a97fff19SSepherosa Ziehau 	int i;
1755a97fff19SSepherosa Ziehau 
1756a97fff19SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1757a97fff19SSepherosa Ziehau 
1758a97fff19SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
1759a97fff19SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
1760a97fff19SSepherosa Ziehau 	sc->hn_xvf_flags |= HN_XVFFLAG_ENABLED;
1761a97fff19SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
1762a97fff19SSepherosa Ziehau 
1763a97fff19SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1764a97fff19SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_rx_flags |= HN_RX_FLAG_XPNT_VF;
1765a97fff19SSepherosa Ziehau }
1766a97fff19SSepherosa Ziehau 
1767a97fff19SSepherosa Ziehau static void
1768a97fff19SSepherosa Ziehau hn_xpnt_vf_setdisable(struct hn_softc *sc, bool clear_vf)
1769a97fff19SSepherosa Ziehau {
1770a97fff19SSepherosa Ziehau 	int i;
1771a97fff19SSepherosa Ziehau 
1772a97fff19SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1773a97fff19SSepherosa Ziehau 
1774a97fff19SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
1775a97fff19SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
1776a97fff19SSepherosa Ziehau 	sc->hn_xvf_flags &= ~HN_XVFFLAG_ENABLED;
1777a97fff19SSepherosa Ziehau 	if (clear_vf)
1778a97fff19SSepherosa Ziehau 		sc->hn_vf_ifp = NULL;
1779a97fff19SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
1780a97fff19SSepherosa Ziehau 
1781a97fff19SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1782a97fff19SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_rx_flags &= ~HN_RX_FLAG_XPNT_VF;
1783a97fff19SSepherosa Ziehau }
1784a97fff19SSepherosa Ziehau 
1785a97fff19SSepherosa Ziehau static void
17869c6cae24SSepherosa Ziehau hn_xpnt_vf_init(struct hn_softc *sc)
17879c6cae24SSepherosa Ziehau {
17889c6cae24SSepherosa Ziehau 	int error;
17899c6cae24SSepherosa Ziehau 
17909c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
17919c6cae24SSepherosa Ziehau 
17929c6cae24SSepherosa Ziehau 	KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0,
17939c6cae24SSepherosa Ziehau 	    ("%s: transparent VF was enabled", sc->hn_ifp->if_xname));
17949c6cae24SSepherosa Ziehau 
17959c6cae24SSepherosa Ziehau 	if (bootverbose) {
17969c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "try bringing up %s\n",
17979c6cae24SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname);
17989c6cae24SSepherosa Ziehau 	}
17999c6cae24SSepherosa Ziehau 
18009c6cae24SSepherosa Ziehau 	/*
18019c6cae24SSepherosa Ziehau 	 * Bring the VF up.
18029c6cae24SSepherosa Ziehau 	 */
18039c6cae24SSepherosa Ziehau 	hn_xpnt_vf_saveifflags(sc);
18049c6cae24SSepherosa Ziehau 	sc->hn_vf_ifp->if_flags |= IFF_UP;
18059c6cae24SSepherosa Ziehau 	error = hn_xpnt_vf_iocsetflags(sc);
18069c6cae24SSepherosa Ziehau 	if (error) {
18079c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "bringing up %s failed: %d\n",
18089c6cae24SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname, error);
18099c6cae24SSepherosa Ziehau 		return;
18109c6cae24SSepherosa Ziehau 	}
18119c6cae24SSepherosa Ziehau 
18129c6cae24SSepherosa Ziehau 	/*
18139c6cae24SSepherosa Ziehau 	 * NOTE:
18149c6cae24SSepherosa Ziehau 	 * Datapath setting must happen _after_ bringing the VF up.
18159c6cae24SSepherosa Ziehau 	 */
18169c6cae24SSepherosa Ziehau 	hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF);
18179c6cae24SSepherosa Ziehau 
1818642ec226SSepherosa Ziehau 	/*
1819642ec226SSepherosa Ziehau 	 * NOTE:
1820642ec226SSepherosa Ziehau 	 * Fixup RSS related bits _after_ the VF is brought up, since
1821642ec226SSepherosa Ziehau 	 * many VFs generate RSS key during it's initialization.
1822642ec226SSepherosa Ziehau 	 */
1823642ec226SSepherosa Ziehau 	hn_vf_rss_fixup(sc, true);
1824642ec226SSepherosa Ziehau 
1825a97fff19SSepherosa Ziehau 	/* Mark transparent mode VF as enabled. */
1826a97fff19SSepherosa Ziehau 	hn_xpnt_vf_setenable(sc);
18279c6cae24SSepherosa Ziehau }
18289c6cae24SSepherosa Ziehau 
18299c6cae24SSepherosa Ziehau static void
18309c6cae24SSepherosa Ziehau hn_xpnt_vf_init_taskfunc(void *xsc, int pending __unused)
18319c6cae24SSepherosa Ziehau {
18329c6cae24SSepherosa Ziehau 	struct hn_softc *sc = xsc;
18339c6cae24SSepherosa Ziehau 
18349c6cae24SSepherosa Ziehau 	HN_LOCK(sc);
18359c6cae24SSepherosa Ziehau 
18369c6cae24SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
18379c6cae24SSepherosa Ziehau 		goto done;
18389c6cae24SSepherosa Ziehau 	if (sc->hn_vf_ifp == NULL)
18399c6cae24SSepherosa Ziehau 		goto done;
18409c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
18419c6cae24SSepherosa Ziehau 		goto done;
18429c6cae24SSepherosa Ziehau 
18439c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick != 0) {
18449c6cae24SSepherosa Ziehau 		/* Mark VF as ready. */
18459c6cae24SSepherosa Ziehau 		hn_xpnt_vf_setready(sc);
18469c6cae24SSepherosa Ziehau 	}
18479c6cae24SSepherosa Ziehau 
18489c6cae24SSepherosa Ziehau 	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) {
18499c6cae24SSepherosa Ziehau 		/*
18509c6cae24SSepherosa Ziehau 		 * Delayed VF initialization.
18519c6cae24SSepherosa Ziehau 		 */
18529c6cae24SSepherosa Ziehau 		if (bootverbose) {
18539c6cae24SSepherosa Ziehau 			if_printf(sc->hn_ifp, "delayed initialize %s\n",
18549c6cae24SSepherosa Ziehau 			    sc->hn_vf_ifp->if_xname);
18559c6cae24SSepherosa Ziehau 		}
18569c6cae24SSepherosa Ziehau 		hn_xpnt_vf_init(sc);
18579c6cae24SSepherosa Ziehau 	}
18589c6cae24SSepherosa Ziehau done:
18599c6cae24SSepherosa Ziehau 	HN_UNLOCK(sc);
18609c6cae24SSepherosa Ziehau }
18619c6cae24SSepherosa Ziehau 
1862499c3e17SSepherosa Ziehau static void
1863499c3e17SSepherosa Ziehau hn_ifnet_attevent(void *xsc, struct ifnet *ifp)
1864499c3e17SSepherosa Ziehau {
1865499c3e17SSepherosa Ziehau 	struct hn_softc *sc = xsc;
1866499c3e17SSepherosa Ziehau 
1867499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
1868499c3e17SSepherosa Ziehau 
1869499c3e17SSepherosa Ziehau 	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
1870499c3e17SSepherosa Ziehau 		goto done;
1871499c3e17SSepherosa Ziehau 
1872499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1873499c3e17SSepherosa Ziehau 		goto done;
1874499c3e17SSepherosa Ziehau 
1875499c3e17SSepherosa Ziehau 	if (sc->hn_vf_ifp != NULL) {
1876499c3e17SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%s was attached as VF\n",
1877499c3e17SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname);
1878499c3e17SSepherosa Ziehau 		goto done;
1879499c3e17SSepherosa Ziehau 	}
1880499c3e17SSepherosa Ziehau 
18819c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && ifp->if_start != NULL) {
18829c6cae24SSepherosa Ziehau 		/*
18839c6cae24SSepherosa Ziehau 		 * ifnet.if_start is _not_ supported by transparent
18849c6cae24SSepherosa Ziehau 		 * mode VF; mainly due to the IFF_DRV_OACTIVE flag.
18859c6cae24SSepherosa Ziehau 		 */
18869c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%s uses if_start, which is unsupported "
18879c6cae24SSepherosa Ziehau 		    "in transparent VF mode.\n", ifp->if_xname);
18889c6cae24SSepherosa Ziehau 		goto done;
18899c6cae24SSepherosa Ziehau 	}
18909c6cae24SSepherosa Ziehau 
1891499c3e17SSepherosa Ziehau 	rm_wlock(&hn_vfmap_lock);
1892499c3e17SSepherosa Ziehau 
1893499c3e17SSepherosa Ziehau 	if (ifp->if_index >= hn_vfmap_size) {
1894499c3e17SSepherosa Ziehau 		struct ifnet **newmap;
1895499c3e17SSepherosa Ziehau 		int newsize;
1896499c3e17SSepherosa Ziehau 
1897499c3e17SSepherosa Ziehau 		newsize = ifp->if_index + HN_VFMAP_SIZE_DEF;
1898499c3e17SSepherosa Ziehau 		newmap = malloc(sizeof(struct ifnet *) * newsize, M_DEVBUF,
1899499c3e17SSepherosa Ziehau 		    M_WAITOK | M_ZERO);
1900499c3e17SSepherosa Ziehau 
1901499c3e17SSepherosa Ziehau 		memcpy(newmap, hn_vfmap,
1902499c3e17SSepherosa Ziehau 		    sizeof(struct ifnet *) * hn_vfmap_size);
1903499c3e17SSepherosa Ziehau 		free(hn_vfmap, M_DEVBUF);
1904499c3e17SSepherosa Ziehau 		hn_vfmap = newmap;
1905499c3e17SSepherosa Ziehau 		hn_vfmap_size = newsize;
1906499c3e17SSepherosa Ziehau 	}
1907499c3e17SSepherosa Ziehau 	KASSERT(hn_vfmap[ifp->if_index] == NULL,
1908499c3e17SSepherosa Ziehau 	    ("%s: ifindex %d was mapped to %s",
1909499c3e17SSepherosa Ziehau 	     ifp->if_xname, ifp->if_index, hn_vfmap[ifp->if_index]->if_xname));
1910499c3e17SSepherosa Ziehau 	hn_vfmap[ifp->if_index] = sc->hn_ifp;
1911499c3e17SSepherosa Ziehau 
1912499c3e17SSepherosa Ziehau 	rm_wunlock(&hn_vfmap_lock);
1913499c3e17SSepherosa Ziehau 
19149c6cae24SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
19159c6cae24SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
19169c6cae24SSepherosa Ziehau 	KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0,
19179c6cae24SSepherosa Ziehau 	    ("%s: transparent VF was enabled", sc->hn_ifp->if_xname));
1918499c3e17SSepherosa Ziehau 	sc->hn_vf_ifp = ifp;
19199c6cae24SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
19209c6cae24SSepherosa Ziehau 
19219c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
19229c6cae24SSepherosa Ziehau 		int wait_ticks;
19239c6cae24SSepherosa Ziehau 
19249c6cae24SSepherosa Ziehau 		/*
19259c6cae24SSepherosa Ziehau 		 * Install if_input for vf_ifp, which does vf_ifp -> hn_ifp.
19269c6cae24SSepherosa Ziehau 		 * Save vf_ifp's current if_input for later restoration.
19279c6cae24SSepherosa Ziehau 		 */
19289c6cae24SSepherosa Ziehau 		sc->hn_vf_input = ifp->if_input;
19299c6cae24SSepherosa Ziehau 		ifp->if_input = hn_xpnt_vf_input;
19309c6cae24SSepherosa Ziehau 
19319c6cae24SSepherosa Ziehau 		/*
19329c6cae24SSepherosa Ziehau 		 * Stop link status management; use the VF's.
19339c6cae24SSepherosa Ziehau 		 */
19349c6cae24SSepherosa Ziehau 		hn_suspend_mgmt(sc);
19359c6cae24SSepherosa Ziehau 
19369c6cae24SSepherosa Ziehau 		/*
19379c6cae24SSepherosa Ziehau 		 * Give VF sometime to complete its attach routing.
19389c6cae24SSepherosa Ziehau 		 */
19399c6cae24SSepherosa Ziehau 		wait_ticks = hn_xpnt_vf_attwait * hz;
19409c6cae24SSepherosa Ziehau 		sc->hn_vf_rdytick = ticks + wait_ticks;
19419c6cae24SSepherosa Ziehau 
19429c6cae24SSepherosa Ziehau 		taskqueue_enqueue_timeout(sc->hn_vf_taskq, &sc->hn_vf_init,
19439c6cae24SSepherosa Ziehau 		    wait_ticks);
19449c6cae24SSepherosa Ziehau 	}
1945499c3e17SSepherosa Ziehau done:
1946499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
1947499c3e17SSepherosa Ziehau }
1948499c3e17SSepherosa Ziehau 
1949499c3e17SSepherosa Ziehau static void
1950499c3e17SSepherosa Ziehau hn_ifnet_detevent(void *xsc, struct ifnet *ifp)
1951499c3e17SSepherosa Ziehau {
1952499c3e17SSepherosa Ziehau 	struct hn_softc *sc = xsc;
1953499c3e17SSepherosa Ziehau 
1954499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
1955499c3e17SSepherosa Ziehau 
1956499c3e17SSepherosa Ziehau 	if (sc->hn_vf_ifp == NULL)
1957499c3e17SSepherosa Ziehau 		goto done;
1958499c3e17SSepherosa Ziehau 
1959499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1960499c3e17SSepherosa Ziehau 		goto done;
1961499c3e17SSepherosa Ziehau 
19629c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
19639c6cae24SSepherosa Ziehau 		/*
19649c6cae24SSepherosa Ziehau 		 * Make sure that the delayed initialization is not running.
19659c6cae24SSepherosa Ziehau 		 *
19669c6cae24SSepherosa Ziehau 		 * NOTE:
19679c6cae24SSepherosa Ziehau 		 * - This lock _must_ be released, since the hn_vf_init task
19689c6cae24SSepherosa Ziehau 		 *   will try holding this lock.
19699c6cae24SSepherosa Ziehau 		 * - It is safe to release this lock here, since the
19709c6cae24SSepherosa Ziehau 		 *   hn_ifnet_attevent() is interlocked by the hn_vf_ifp.
19719c6cae24SSepherosa Ziehau 		 *
19729c6cae24SSepherosa Ziehau 		 * XXX racy, if hn(4) ever detached.
19739c6cae24SSepherosa Ziehau 		 */
19749c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
19759c6cae24SSepherosa Ziehau 		taskqueue_drain_timeout(sc->hn_vf_taskq, &sc->hn_vf_init);
19769c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
19779c6cae24SSepherosa Ziehau 
19789c6cae24SSepherosa Ziehau 		KASSERT(sc->hn_vf_input != NULL, ("%s VF input is not saved",
19799c6cae24SSepherosa Ziehau 		    sc->hn_ifp->if_xname));
19809c6cae24SSepherosa Ziehau 		ifp->if_input = sc->hn_vf_input;
19819c6cae24SSepherosa Ziehau 		sc->hn_vf_input = NULL;
19829c6cae24SSepherosa Ziehau 
1983642ec226SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) &&
1984642ec226SSepherosa Ziehau 		    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED))
19859c6cae24SSepherosa Ziehau 			hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH);
19869c6cae24SSepherosa Ziehau 
19879c6cae24SSepherosa Ziehau 		if (sc->hn_vf_rdytick == 0) {
19889c6cae24SSepherosa Ziehau 			/*
19899c6cae24SSepherosa Ziehau 			 * The VF was ready; restore some settings.
19909c6cae24SSepherosa Ziehau 			 */
19919c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_capabilities = sc->hn_saved_caps;
19929c6cae24SSepherosa Ziehau 			/*
19939c6cae24SSepherosa Ziehau 			 * NOTE:
19949c6cae24SSepherosa Ziehau 			 * There is _no_ need to fixup if_capenable and
19959c6cae24SSepherosa Ziehau 			 * if_hwassist, since the if_capabilities before
19969c6cae24SSepherosa Ziehau 			 * restoration was an intersection of the VF's
19979c6cae24SSepherosa Ziehau 			 * if_capabilites and the synthetic device's
19989c6cae24SSepherosa Ziehau 			 * if_capabilites.
19999c6cae24SSepherosa Ziehau 			 */
20009c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomax = sc->hn_saved_tsomax;
20019c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomaxsegcount =
20029c6cae24SSepherosa Ziehau 			    sc->hn_saved_tsosegcnt;
20039c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomaxsegsize = sc->hn_saved_tsosegsz;
20049c6cae24SSepherosa Ziehau 		}
20059c6cae24SSepherosa Ziehau 
2006642ec226SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
2007642ec226SSepherosa Ziehau 			/*
2008642ec226SSepherosa Ziehau 			 * Restore RSS settings.
2009642ec226SSepherosa Ziehau 			 */
2010642ec226SSepherosa Ziehau 			hn_vf_rss_restore(sc);
2011642ec226SSepherosa Ziehau 
20129c6cae24SSepherosa Ziehau 			/*
20139c6cae24SSepherosa Ziehau 			 * Resume link status management, which was suspended
20149c6cae24SSepherosa Ziehau 			 * by hn_ifnet_attevent().
20159c6cae24SSepherosa Ziehau 			 */
20169c6cae24SSepherosa Ziehau 			hn_resume_mgmt(sc);
20179c6cae24SSepherosa Ziehau 		}
2018642ec226SSepherosa Ziehau 	}
20199c6cae24SSepherosa Ziehau 
2020a97fff19SSepherosa Ziehau 	/* Mark transparent mode VF as disabled. */
2021a97fff19SSepherosa Ziehau 	hn_xpnt_vf_setdisable(sc, true /* clear hn_vf_ifp */);
2022499c3e17SSepherosa Ziehau 
2023499c3e17SSepherosa Ziehau 	rm_wlock(&hn_vfmap_lock);
2024499c3e17SSepherosa Ziehau 
2025499c3e17SSepherosa Ziehau 	KASSERT(ifp->if_index < hn_vfmap_size,
2026499c3e17SSepherosa Ziehau 	    ("ifindex %d, vfmapsize %d", ifp->if_index, hn_vfmap_size));
2027499c3e17SSepherosa Ziehau 	if (hn_vfmap[ifp->if_index] != NULL) {
2028499c3e17SSepherosa Ziehau 		KASSERT(hn_vfmap[ifp->if_index] == sc->hn_ifp,
2029499c3e17SSepherosa Ziehau 		    ("%s: ifindex %d was mapped to %s",
2030499c3e17SSepherosa Ziehau 		     ifp->if_xname, ifp->if_index,
2031499c3e17SSepherosa Ziehau 		     hn_vfmap[ifp->if_index]->if_xname));
2032499c3e17SSepherosa Ziehau 		hn_vfmap[ifp->if_index] = NULL;
2033499c3e17SSepherosa Ziehau 	}
2034499c3e17SSepherosa Ziehau 
2035499c3e17SSepherosa Ziehau 	rm_wunlock(&hn_vfmap_lock);
2036499c3e17SSepherosa Ziehau done:
2037499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
2038499c3e17SSepherosa Ziehau }
2039499c3e17SSepherosa Ziehau 
20409c6cae24SSepherosa Ziehau static void
20419c6cae24SSepherosa Ziehau hn_ifnet_lnkevent(void *xsc, struct ifnet *ifp, int link_state)
20429c6cae24SSepherosa Ziehau {
20439c6cae24SSepherosa Ziehau 	struct hn_softc *sc = xsc;
20449c6cae24SSepherosa Ziehau 
20459c6cae24SSepherosa Ziehau 	if (sc->hn_vf_ifp == ifp)
20469c6cae24SSepherosa Ziehau 		if_link_state_change(sc->hn_ifp, link_state);
20479c6cae24SSepherosa Ziehau }
20489c6cae24SSepherosa Ziehau 
204915516c77SSepherosa Ziehau static int
205015516c77SSepherosa Ziehau hn_probe(device_t dev)
205115516c77SSepherosa Ziehau {
205215516c77SSepherosa Ziehau 
2053c2d50b26SSepherosa Ziehau 	if (VMBUS_PROBE_GUID(device_get_parent(dev), dev, &hn_guid) == 0) {
205415516c77SSepherosa Ziehau 		device_set_desc(dev, "Hyper-V Network Interface");
205515516c77SSepherosa Ziehau 		return BUS_PROBE_DEFAULT;
205615516c77SSepherosa Ziehau 	}
205715516c77SSepherosa Ziehau 	return ENXIO;
205815516c77SSepherosa Ziehau }
205915516c77SSepherosa Ziehau 
206015516c77SSepherosa Ziehau static int
206115516c77SSepherosa Ziehau hn_attach(device_t dev)
206215516c77SSepherosa Ziehau {
206315516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
206415516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
206515516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
206615516c77SSepherosa Ziehau 	uint8_t eaddr[ETHER_ADDR_LEN];
206715516c77SSepherosa Ziehau 	struct ifnet *ifp = NULL;
206815516c77SSepherosa Ziehau 	int error, ring_cnt, tx_ring_cnt;
2069eb2fe044SSepherosa Ziehau 	uint32_t mtu;
207015516c77SSepherosa Ziehau 
207115516c77SSepherosa Ziehau 	sc->hn_dev = dev;
207215516c77SSepherosa Ziehau 	sc->hn_prichan = vmbus_get_channel(dev);
207315516c77SSepherosa Ziehau 	HN_LOCK_INIT(sc);
20749c6cae24SSepherosa Ziehau 	rm_init(&sc->hn_vf_lock, "hnvf");
20759c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && hn_xpnt_vf_accbpf)
20769c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF;
207715516c77SSepherosa Ziehau 
207815516c77SSepherosa Ziehau 	/*
2079dc13fee6SSepherosa Ziehau 	 * Initialize these tunables once.
2080dc13fee6SSepherosa Ziehau 	 */
2081dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = hn_tx_agg_size;
2082dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = hn_tx_agg_pkts;
2083dc13fee6SSepherosa Ziehau 
2084dc13fee6SSepherosa Ziehau 	/*
208515516c77SSepherosa Ziehau 	 * Setup taskqueue for transmission.
208615516c77SSepherosa Ziehau 	 */
20870e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_INDEP) {
2088fdd0222aSSepherosa Ziehau 		int i;
2089fdd0222aSSepherosa Ziehau 
2090fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs =
2091fdd0222aSSepherosa Ziehau 		    malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
2092fdd0222aSSepherosa Ziehau 		    M_DEVBUF, M_WAITOK);
2093fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i) {
2094fdd0222aSSepherosa Ziehau 			sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx",
2095fdd0222aSSepherosa Ziehau 			    M_WAITOK, taskqueue_thread_enqueue,
2096fdd0222aSSepherosa Ziehau 			    &sc->hn_tx_taskqs[i]);
2097fdd0222aSSepherosa Ziehau 			taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET,
2098fdd0222aSSepherosa Ziehau 			    "%s tx%d", device_get_nameunit(dev), i);
2099fdd0222aSSepherosa Ziehau 		}
21000e11868dSSepherosa Ziehau 	} else if (hn_tx_taskq_mode == HN_TX_TASKQ_M_GLOBAL) {
2101fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs = hn_tx_taskque;
210215516c77SSepherosa Ziehau 	}
210315516c77SSepherosa Ziehau 
210415516c77SSepherosa Ziehau 	/*
210515516c77SSepherosa Ziehau 	 * Setup taskqueue for mangement tasks, e.g. link status.
210615516c77SSepherosa Ziehau 	 */
210715516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK,
210815516c77SSepherosa Ziehau 	    taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0);
210915516c77SSepherosa Ziehau 	taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
211015516c77SSepherosa Ziehau 	    device_get_nameunit(dev));
211115516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
211215516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc);
211315516c77SSepherosa Ziehau 	TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0,
211415516c77SSepherosa Ziehau 	    hn_netchg_status_taskfunc, sc);
211515516c77SSepherosa Ziehau 
21169c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
21179c6cae24SSepherosa Ziehau 		/*
21189c6cae24SSepherosa Ziehau 		 * Setup taskqueue for VF tasks, e.g. delayed VF bringing up.
21199c6cae24SSepherosa Ziehau 		 */
21209c6cae24SSepherosa Ziehau 		sc->hn_vf_taskq = taskqueue_create("hn_vf", M_WAITOK,
21219c6cae24SSepherosa Ziehau 		    taskqueue_thread_enqueue, &sc->hn_vf_taskq);
21229c6cae24SSepherosa Ziehau 		taskqueue_start_threads(&sc->hn_vf_taskq, 1, PI_NET, "%s vf",
21239c6cae24SSepherosa Ziehau 		    device_get_nameunit(dev));
21249c6cae24SSepherosa Ziehau 		TIMEOUT_TASK_INIT(sc->hn_vf_taskq, &sc->hn_vf_init, 0,
21259c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_init_taskfunc, sc);
21269c6cae24SSepherosa Ziehau 	}
21279c6cae24SSepherosa Ziehau 
212815516c77SSepherosa Ziehau 	/*
212915516c77SSepherosa Ziehau 	 * Allocate ifnet and setup its name earlier, so that if_printf
213015516c77SSepherosa Ziehau 	 * can be used by functions, which will be called after
213115516c77SSepherosa Ziehau 	 * ether_ifattach().
213215516c77SSepherosa Ziehau 	 */
213315516c77SSepherosa Ziehau 	ifp = sc->hn_ifp = if_alloc(IFT_ETHER);
213415516c77SSepherosa Ziehau 	ifp->if_softc = sc;
213515516c77SSepherosa Ziehau 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
213615516c77SSepherosa Ziehau 
213715516c77SSepherosa Ziehau 	/*
213815516c77SSepherosa Ziehau 	 * Initialize ifmedia earlier so that it can be unconditionally
213915516c77SSepherosa Ziehau 	 * destroyed, if error happened later on.
214015516c77SSepherosa Ziehau 	 */
214115516c77SSepherosa Ziehau 	ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts);
214215516c77SSepherosa Ziehau 
214315516c77SSepherosa Ziehau 	/*
214415516c77SSepherosa Ziehau 	 * Figure out the # of RX rings (ring_cnt) and the # of TX rings
214515516c77SSepherosa Ziehau 	 * to use (tx_ring_cnt).
214615516c77SSepherosa Ziehau 	 *
214715516c77SSepherosa Ziehau 	 * NOTE:
214815516c77SSepherosa Ziehau 	 * The # of RX rings to use is same as the # of channels to use.
214915516c77SSepherosa Ziehau 	 */
215015516c77SSepherosa Ziehau 	ring_cnt = hn_chan_cnt;
215115516c77SSepherosa Ziehau 	if (ring_cnt <= 0) {
215215516c77SSepherosa Ziehau 		/* Default */
215315516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
215415516c77SSepherosa Ziehau 		if (ring_cnt > HN_RING_CNT_DEF_MAX)
215515516c77SSepherosa Ziehau 			ring_cnt = HN_RING_CNT_DEF_MAX;
215615516c77SSepherosa Ziehau 	} else if (ring_cnt > mp_ncpus) {
215715516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
215815516c77SSepherosa Ziehau 	}
215934d68912SSepherosa Ziehau #ifdef RSS
216034d68912SSepherosa Ziehau 	if (ring_cnt > rss_getnumbuckets())
216134d68912SSepherosa Ziehau 		ring_cnt = rss_getnumbuckets();
216234d68912SSepherosa Ziehau #endif
216315516c77SSepherosa Ziehau 
216415516c77SSepherosa Ziehau 	tx_ring_cnt = hn_tx_ring_cnt;
216515516c77SSepherosa Ziehau 	if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt)
216615516c77SSepherosa Ziehau 		tx_ring_cnt = ring_cnt;
216723bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
216815516c77SSepherosa Ziehau 	if (hn_use_if_start) {
216915516c77SSepherosa Ziehau 		/* ifnet.if_start only needs one TX ring. */
217015516c77SSepherosa Ziehau 		tx_ring_cnt = 1;
217115516c77SSepherosa Ziehau 	}
217223bf9e15SSepherosa Ziehau #endif
217315516c77SSepherosa Ziehau 
217415516c77SSepherosa Ziehau 	/*
217515516c77SSepherosa Ziehau 	 * Set the leader CPU for channels.
217615516c77SSepherosa Ziehau 	 */
217715516c77SSepherosa Ziehau 	sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus;
217815516c77SSepherosa Ziehau 
217915516c77SSepherosa Ziehau 	/*
218015516c77SSepherosa Ziehau 	 * Create enough TX/RX rings, even if only limited number of
218115516c77SSepherosa Ziehau 	 * channels can be allocated.
218215516c77SSepherosa Ziehau 	 */
218315516c77SSepherosa Ziehau 	error = hn_create_tx_data(sc, tx_ring_cnt);
218415516c77SSepherosa Ziehau 	if (error)
218515516c77SSepherosa Ziehau 		goto failed;
218615516c77SSepherosa Ziehau 	error = hn_create_rx_data(sc, ring_cnt);
218715516c77SSepherosa Ziehau 	if (error)
218815516c77SSepherosa Ziehau 		goto failed;
218915516c77SSepherosa Ziehau 
219015516c77SSepherosa Ziehau 	/*
219115516c77SSepherosa Ziehau 	 * Create transaction context for NVS and RNDIS transactions.
219215516c77SSepherosa Ziehau 	 */
219315516c77SSepherosa Ziehau 	sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
219415516c77SSepherosa Ziehau 	    HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
219525641fc7SSepherosa Ziehau 	if (sc->hn_xact == NULL) {
219625641fc7SSepherosa Ziehau 		error = ENXIO;
219715516c77SSepherosa Ziehau 		goto failed;
219825641fc7SSepherosa Ziehau 	}
219925641fc7SSepherosa Ziehau 
220025641fc7SSepherosa Ziehau 	/*
220125641fc7SSepherosa Ziehau 	 * Install orphan handler for the revocation of this device's
220225641fc7SSepherosa Ziehau 	 * primary channel.
220325641fc7SSepherosa Ziehau 	 *
220425641fc7SSepherosa Ziehau 	 * NOTE:
220525641fc7SSepherosa Ziehau 	 * The processing order is critical here:
220625641fc7SSepherosa Ziehau 	 * Install the orphan handler, _before_ testing whether this
220725641fc7SSepherosa Ziehau 	 * device's primary channel has been revoked or not.
220825641fc7SSepherosa Ziehau 	 */
220925641fc7SSepherosa Ziehau 	vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact);
221025641fc7SSepherosa Ziehau 	if (vmbus_chan_is_revoked(sc->hn_prichan)) {
221125641fc7SSepherosa Ziehau 		error = ENXIO;
221225641fc7SSepherosa Ziehau 		goto failed;
221325641fc7SSepherosa Ziehau 	}
221415516c77SSepherosa Ziehau 
221515516c77SSepherosa Ziehau 	/*
221615516c77SSepherosa Ziehau 	 * Attach the synthetic parts, i.e. NVS and RNDIS.
221715516c77SSepherosa Ziehau 	 */
221815516c77SSepherosa Ziehau 	error = hn_synth_attach(sc, ETHERMTU);
221915516c77SSepherosa Ziehau 	if (error)
222015516c77SSepherosa Ziehau 		goto failed;
222115516c77SSepherosa Ziehau 
222215516c77SSepherosa Ziehau 	error = hn_rndis_get_eaddr(sc, eaddr);
222315516c77SSepherosa Ziehau 	if (error)
222415516c77SSepherosa Ziehau 		goto failed;
222515516c77SSepherosa Ziehau 
2226eb2fe044SSepherosa Ziehau 	error = hn_rndis_get_mtu(sc, &mtu);
2227eb2fe044SSepherosa Ziehau 	if (error)
2228eb2fe044SSepherosa Ziehau 		mtu = ETHERMTU;
2229eb2fe044SSepherosa Ziehau 	else if (bootverbose)
2230eb2fe044SSepherosa Ziehau 		device_printf(dev, "RNDIS mtu %u\n", mtu);
2231eb2fe044SSepherosa Ziehau 
223215516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
223315516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
223415516c77SSepherosa Ziehau 		/*
223515516c77SSepherosa Ziehau 		 * Reduce TCP segment aggregation limit for multiple
223615516c77SSepherosa Ziehau 		 * RX rings to increase ACK timeliness.
223715516c77SSepherosa Ziehau 		 */
223815516c77SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF);
223915516c77SSepherosa Ziehau 	}
224015516c77SSepherosa Ziehau #endif
224115516c77SSepherosa Ziehau 
224215516c77SSepherosa Ziehau 	/*
2243*db76829bSSepherosa Ziehau 	 * Fixup TX/RX stuffs after synthetic parts are attached.
224415516c77SSepherosa Ziehau 	 */
224515516c77SSepherosa Ziehau 	hn_fixup_tx_data(sc);
2246*db76829bSSepherosa Ziehau 	hn_fixup_rx_data(sc);
224715516c77SSepherosa Ziehau 
224815516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
224915516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
225015516c77SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD,
225115516c77SSepherosa Ziehau 	    &sc->hn_nvs_ver, 0, "NVS version");
225215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version",
225315516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
225415516c77SSepherosa Ziehau 	    hn_ndis_version_sysctl, "A", "NDIS version");
225515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps",
225615516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
225715516c77SSepherosa Ziehau 	    hn_caps_sysctl, "A", "capabilities");
225815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist",
225915516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
226015516c77SSepherosa Ziehau 	    hn_hwassist_sysctl, "A", "hwassist");
22619c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_max",
22629c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomax, 0, "max TSO size");
22639c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegcnt",
22649c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomaxsegcount, 0,
22659c6cae24SSepherosa Ziehau 	    "max # of TSO segments");
22669c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegsz",
22679c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomaxsegsize, 0,
22689c6cae24SSepherosa Ziehau 	    "max size of TSO segment");
226915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter",
227015516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
227115516c77SSepherosa Ziehau 	    hn_rxfilter_sysctl, "A", "rxfilter");
227215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash",
227315516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
227415516c77SSepherosa Ziehau 	    hn_rss_hash_sysctl, "A", "RSS hash");
2275642ec226SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hashcap",
2276642ec226SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2277642ec226SSepherosa Ziehau 	    hn_rss_hcap_sysctl, "A", "RSS hash capabilities");
2278642ec226SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "mbuf_hash",
2279642ec226SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2280642ec226SSepherosa Ziehau 	    hn_rss_mbuf_sysctl, "A", "RSS hash for mbufs");
228115516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size",
228215516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count");
228334d68912SSepherosa Ziehau #ifndef RSS
228434d68912SSepherosa Ziehau 	/*
228534d68912SSepherosa Ziehau 	 * Don't allow RSS key/indirect table changes, if RSS is defined.
228634d68912SSepherosa Ziehau 	 */
228715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key",
228815516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
228915516c77SSepherosa Ziehau 	    hn_rss_key_sysctl, "IU", "RSS key");
229015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind",
229115516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
229215516c77SSepherosa Ziehau 	    hn_rss_ind_sysctl, "IU", "RSS indirect table");
229334d68912SSepherosa Ziehau #endif
2294dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size",
2295dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_size, 0,
2296dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation size limit");
2297dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts",
2298dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0,
2299dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation count limit");
2300dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align",
2301dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_align, 0,
2302dc13fee6SSepherosa Ziehau 	    "RNDIS packet transmission aggregation alignment");
2303dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size",
2304dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
2305dc13fee6SSepherosa Ziehau 	    hn_txagg_size_sysctl, "I",
2306dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation size, 0 -- disable, -1 -- auto");
2307dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts",
2308dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
2309dc13fee6SSepherosa Ziehau 	    hn_txagg_pkts_sysctl, "I",
2310dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation packets, "
2311dc13fee6SSepherosa Ziehau 	    "0 -- disable, -1 -- auto");
23126c1204dfSSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "polling",
23136c1204dfSSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
23146c1204dfSSepherosa Ziehau 	    hn_polling_sysctl, "I",
23156c1204dfSSepherosa Ziehau 	    "Polling frequency: [100,1000000], 0 disable polling");
231640d60d6eSDexuan Cui 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf",
231740d60d6eSDexuan Cui 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
231840d60d6eSDexuan Cui 	    hn_vf_sysctl, "A", "Virtual Function's name");
23199c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf) {
2320499c3e17SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxvf",
2321499c3e17SSepherosa Ziehau 		    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2322499c3e17SSepherosa Ziehau 		    hn_rxvf_sysctl, "A", "activated Virtual Function's name");
23239c6cae24SSepherosa Ziehau 	} else {
23249c6cae24SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_enabled",
23259c6cae24SSepherosa Ziehau 		    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
23269c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_enabled_sysctl, "I",
23279c6cae24SSepherosa Ziehau 		    "Transparent VF enabled");
23289c6cae24SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_accbpf",
23299c6cae24SSepherosa Ziehau 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
23309c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_accbpf_sysctl, "I",
23319c6cae24SSepherosa Ziehau 		    "Accurate BPF for transparent VF");
23329c6cae24SSepherosa Ziehau 	}
233315516c77SSepherosa Ziehau 
233415516c77SSepherosa Ziehau 	/*
233515516c77SSepherosa Ziehau 	 * Setup the ifmedia, which has been initialized earlier.
233615516c77SSepherosa Ziehau 	 */
233715516c77SSepherosa Ziehau 	ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL);
233815516c77SSepherosa Ziehau 	ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO);
233915516c77SSepherosa Ziehau 	/* XXX ifmedia_set really should do this for us */
234015516c77SSepherosa Ziehau 	sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media;
234115516c77SSepherosa Ziehau 
234215516c77SSepherosa Ziehau 	/*
234315516c77SSepherosa Ziehau 	 * Setup the ifnet for this interface.
234415516c77SSepherosa Ziehau 	 */
234515516c77SSepherosa Ziehau 
234615516c77SSepherosa Ziehau 	ifp->if_baudrate = IF_Gbps(10);
234715516c77SSepherosa Ziehau 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
234815516c77SSepherosa Ziehau 	ifp->if_ioctl = hn_ioctl;
234915516c77SSepherosa Ziehau 	ifp->if_init = hn_init;
235023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
235115516c77SSepherosa Ziehau 	if (hn_use_if_start) {
235215516c77SSepherosa Ziehau 		int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]);
235315516c77SSepherosa Ziehau 
235415516c77SSepherosa Ziehau 		ifp->if_start = hn_start;
235515516c77SSepherosa Ziehau 		IFQ_SET_MAXLEN(&ifp->if_snd, qdepth);
235615516c77SSepherosa Ziehau 		ifp->if_snd.ifq_drv_maxlen = qdepth - 1;
235715516c77SSepherosa Ziehau 		IFQ_SET_READY(&ifp->if_snd);
235823bf9e15SSepherosa Ziehau 	} else
235923bf9e15SSepherosa Ziehau #endif
236023bf9e15SSepherosa Ziehau 	{
236115516c77SSepherosa Ziehau 		ifp->if_transmit = hn_transmit;
236215516c77SSepherosa Ziehau 		ifp->if_qflush = hn_xmit_qflush;
236315516c77SSepherosa Ziehau 	}
236415516c77SSepherosa Ziehau 
23659c6cae24SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO | IFCAP_LINKSTATE;
236615516c77SSepherosa Ziehau #ifdef foo
236715516c77SSepherosa Ziehau 	/* We can't diff IPv6 packets from IPv4 packets on RX path. */
236815516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM_IPV6;
236915516c77SSepherosa Ziehau #endif
237015516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_VLAN) {
237115516c77SSepherosa Ziehau 		/* XXX not sure about VLAN_MTU. */
237215516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
237315516c77SSepherosa Ziehau 	}
237415516c77SSepherosa Ziehau 
237515516c77SSepherosa Ziehau 	ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist;
237615516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP_MASK)
237715516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM;
237815516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP6_MASK)
237915516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM_IPV6;
238015516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO4) {
238115516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO4;
238215516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP_TSO;
238315516c77SSepherosa Ziehau 	}
238415516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO6) {
238515516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO6;
238615516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP6_TSO;
238715516c77SSepherosa Ziehau 	}
238815516c77SSepherosa Ziehau 
238915516c77SSepherosa Ziehau 	/* Enable all available capabilities by default. */
239015516c77SSepherosa Ziehau 	ifp->if_capenable = ifp->if_capabilities;
239115516c77SSepherosa Ziehau 
23927960e6baSSepherosa Ziehau 	/*
23937960e6baSSepherosa Ziehau 	 * Disable IPv6 TSO and TXCSUM by default, they still can
23947960e6baSSepherosa Ziehau 	 * be enabled through SIOCSIFCAP.
23957960e6baSSepherosa Ziehau 	 */
23967960e6baSSepherosa Ziehau 	ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
23977960e6baSSepherosa Ziehau 	ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO);
23987960e6baSSepherosa Ziehau 
239915516c77SSepherosa Ziehau 	if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) {
24009c6cae24SSepherosa Ziehau 		/*
24019c6cae24SSepherosa Ziehau 		 * Lock hn_set_tso_maxsize() to simplify its
24029c6cae24SSepherosa Ziehau 		 * internal logic.
24039c6cae24SSepherosa Ziehau 		 */
24049c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
240515516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU);
24069c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
240715516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX;
240815516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = PAGE_SIZE;
240915516c77SSepherosa Ziehau 	}
241015516c77SSepherosa Ziehau 
241115516c77SSepherosa Ziehau 	ether_ifattach(ifp, eaddr);
241215516c77SSepherosa Ziehau 
241315516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) {
241415516c77SSepherosa Ziehau 		if_printf(ifp, "TSO segcnt %u segsz %u\n",
241515516c77SSepherosa Ziehau 		    ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize);
241615516c77SSepherosa Ziehau 	}
2417eb2fe044SSepherosa Ziehau 	if (mtu < ETHERMTU) {
2418eb2fe044SSepherosa Ziehau 		if_printf(ifp, "fixup mtu %u -> %u\n", ifp->if_mtu, mtu);
2419eb2fe044SSepherosa Ziehau 		ifp->if_mtu = mtu;
2420eb2fe044SSepherosa Ziehau 	}
242115516c77SSepherosa Ziehau 
242215516c77SSepherosa Ziehau 	/* Inform the upper layer about the long frame support. */
242315516c77SSepherosa Ziehau 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
242415516c77SSepherosa Ziehau 
242515516c77SSepherosa Ziehau 	/*
242615516c77SSepherosa Ziehau 	 * Kick off link status check.
242715516c77SSepherosa Ziehau 	 */
242815516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
242915516c77SSepherosa Ziehau 	hn_update_link_status(sc);
243015516c77SSepherosa Ziehau 
24319c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf) {
24325bdfd3fdSDexuan Cui 		sc->hn_ifnet_evthand = EVENTHANDLER_REGISTER(ifnet_event,
24335bdfd3fdSDexuan Cui 		    hn_ifnet_event, sc, EVENTHANDLER_PRI_ANY);
24345bdfd3fdSDexuan Cui 		sc->hn_ifaddr_evthand = EVENTHANDLER_REGISTER(ifaddr_event,
24355bdfd3fdSDexuan Cui 		    hn_ifaddr_event, sc, EVENTHANDLER_PRI_ANY);
24369c6cae24SSepherosa Ziehau 	} else {
24379c6cae24SSepherosa Ziehau 		sc->hn_ifnet_lnkhand = EVENTHANDLER_REGISTER(ifnet_link_event,
24389c6cae24SSepherosa Ziehau 		    hn_ifnet_lnkevent, sc, EVENTHANDLER_PRI_ANY);
24399c6cae24SSepherosa Ziehau 	}
24405bdfd3fdSDexuan Cui 
2441f41e0df4SSepherosa Ziehau 	/*
2442f41e0df4SSepherosa Ziehau 	 * NOTE:
2443f41e0df4SSepherosa Ziehau 	 * Subscribe ether_ifattach event, instead of ifnet_arrival event,
2444f41e0df4SSepherosa Ziehau 	 * since interface's LLADDR is needed; interface LLADDR is not
2445f41e0df4SSepherosa Ziehau 	 * available when ifnet_arrival event is triggered.
2446f41e0df4SSepherosa Ziehau 	 */
2447499c3e17SSepherosa Ziehau 	sc->hn_ifnet_atthand = EVENTHANDLER_REGISTER(ether_ifattach_event,
2448499c3e17SSepherosa Ziehau 	    hn_ifnet_attevent, sc, EVENTHANDLER_PRI_ANY);
2449499c3e17SSepherosa Ziehau 	sc->hn_ifnet_dethand = EVENTHANDLER_REGISTER(ifnet_departure_event,
2450499c3e17SSepherosa Ziehau 	    hn_ifnet_detevent, sc, EVENTHANDLER_PRI_ANY);
2451499c3e17SSepherosa Ziehau 
245215516c77SSepherosa Ziehau 	return (0);
245315516c77SSepherosa Ziehau failed:
245415516c77SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)
245515516c77SSepherosa Ziehau 		hn_synth_detach(sc);
245615516c77SSepherosa Ziehau 	hn_detach(dev);
245715516c77SSepherosa Ziehau 	return (error);
245815516c77SSepherosa Ziehau }
245915516c77SSepherosa Ziehau 
246015516c77SSepherosa Ziehau static int
246115516c77SSepherosa Ziehau hn_detach(device_t dev)
246215516c77SSepherosa Ziehau {
246315516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
2464499c3e17SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp, *vf_ifp;
246515516c77SSepherosa Ziehau 
24669c6cae24SSepherosa Ziehau 	if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) {
24679c6cae24SSepherosa Ziehau 		/*
24689c6cae24SSepherosa Ziehau 		 * In case that the vmbus missed the orphan handler
24699c6cae24SSepherosa Ziehau 		 * installation.
24709c6cae24SSepherosa Ziehau 		 */
24719c6cae24SSepherosa Ziehau 		vmbus_xact_ctx_orphan(sc->hn_xact);
24729c6cae24SSepherosa Ziehau 	}
24739c6cae24SSepherosa Ziehau 
24745bdfd3fdSDexuan Cui 	if (sc->hn_ifaddr_evthand != NULL)
24755bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifaddr_event, sc->hn_ifaddr_evthand);
24765bdfd3fdSDexuan Cui 	if (sc->hn_ifnet_evthand != NULL)
24775bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifnet_event, sc->hn_ifnet_evthand);
2478499c3e17SSepherosa Ziehau 	if (sc->hn_ifnet_atthand != NULL) {
2479499c3e17SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ether_ifattach_event,
2480499c3e17SSepherosa Ziehau 		    sc->hn_ifnet_atthand);
2481499c3e17SSepherosa Ziehau 	}
2482499c3e17SSepherosa Ziehau 	if (sc->hn_ifnet_dethand != NULL) {
2483499c3e17SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ifnet_departure_event,
2484499c3e17SSepherosa Ziehau 		    sc->hn_ifnet_dethand);
2485499c3e17SSepherosa Ziehau 	}
24869c6cae24SSepherosa Ziehau 	if (sc->hn_ifnet_lnkhand != NULL)
24879c6cae24SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ifnet_link_event, sc->hn_ifnet_lnkhand);
2488499c3e17SSepherosa Ziehau 
2489499c3e17SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
2490499c3e17SSepherosa Ziehau 	__compiler_membar();
2491499c3e17SSepherosa Ziehau 	if (vf_ifp != NULL)
2492499c3e17SSepherosa Ziehau 		hn_ifnet_detevent(sc, vf_ifp);
24935bdfd3fdSDexuan Cui 
249415516c77SSepherosa Ziehau 	if (device_is_attached(dev)) {
249515516c77SSepherosa Ziehau 		HN_LOCK(sc);
249615516c77SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
249715516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
24985bdfd3fdSDexuan Cui 				hn_stop(sc, true);
249915516c77SSepherosa Ziehau 			/*
250015516c77SSepherosa Ziehau 			 * NOTE:
250115516c77SSepherosa Ziehau 			 * hn_stop() only suspends data, so managment
250215516c77SSepherosa Ziehau 			 * stuffs have to be suspended manually here.
250315516c77SSepherosa Ziehau 			 */
250415516c77SSepherosa Ziehau 			hn_suspend_mgmt(sc);
250515516c77SSepherosa Ziehau 			hn_synth_detach(sc);
250615516c77SSepherosa Ziehau 		}
250715516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
250815516c77SSepherosa Ziehau 		ether_ifdetach(ifp);
250915516c77SSepherosa Ziehau 	}
251015516c77SSepherosa Ziehau 
251115516c77SSepherosa Ziehau 	ifmedia_removeall(&sc->hn_media);
251215516c77SSepherosa Ziehau 	hn_destroy_rx_data(sc);
251315516c77SSepherosa Ziehau 	hn_destroy_tx_data(sc);
251415516c77SSepherosa Ziehau 
25150e11868dSSepherosa Ziehau 	if (sc->hn_tx_taskqs != NULL && sc->hn_tx_taskqs != hn_tx_taskque) {
2516fdd0222aSSepherosa Ziehau 		int i;
2517fdd0222aSSepherosa Ziehau 
2518fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
2519fdd0222aSSepherosa Ziehau 			taskqueue_free(sc->hn_tx_taskqs[i]);
2520fdd0222aSSepherosa Ziehau 		free(sc->hn_tx_taskqs, M_DEVBUF);
2521fdd0222aSSepherosa Ziehau 	}
252215516c77SSepherosa Ziehau 	taskqueue_free(sc->hn_mgmt_taskq0);
25239c6cae24SSepherosa Ziehau 	if (sc->hn_vf_taskq != NULL)
25249c6cae24SSepherosa Ziehau 		taskqueue_free(sc->hn_vf_taskq);
252515516c77SSepherosa Ziehau 
252625641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL) {
252725641fc7SSepherosa Ziehau 		/*
252825641fc7SSepherosa Ziehau 		 * Uninstall the orphan handler _before_ the xact is
252925641fc7SSepherosa Ziehau 		 * destructed.
253025641fc7SSepherosa Ziehau 		 */
253125641fc7SSepherosa Ziehau 		vmbus_chan_unset_orphan(sc->hn_prichan);
253215516c77SSepherosa Ziehau 		vmbus_xact_ctx_destroy(sc->hn_xact);
253325641fc7SSepherosa Ziehau 	}
253415516c77SSepherosa Ziehau 
253515516c77SSepherosa Ziehau 	if_free(ifp);
253615516c77SSepherosa Ziehau 
253715516c77SSepherosa Ziehau 	HN_LOCK_DESTROY(sc);
25389c6cae24SSepherosa Ziehau 	rm_destroy(&sc->hn_vf_lock);
253915516c77SSepherosa Ziehau 	return (0);
254015516c77SSepherosa Ziehau }
254115516c77SSepherosa Ziehau 
254215516c77SSepherosa Ziehau static int
254315516c77SSepherosa Ziehau hn_shutdown(device_t dev)
254415516c77SSepherosa Ziehau {
254515516c77SSepherosa Ziehau 
254615516c77SSepherosa Ziehau 	return (0);
254715516c77SSepherosa Ziehau }
254815516c77SSepherosa Ziehau 
254915516c77SSepherosa Ziehau static void
255015516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc)
255115516c77SSepherosa Ziehau {
255215516c77SSepherosa Ziehau 	uint32_t link_status;
255315516c77SSepherosa Ziehau 	int error;
255415516c77SSepherosa Ziehau 
255515516c77SSepherosa Ziehau 	error = hn_rndis_get_linkstatus(sc, &link_status);
255615516c77SSepherosa Ziehau 	if (error) {
255715516c77SSepherosa Ziehau 		/* XXX what to do? */
255815516c77SSepherosa Ziehau 		return;
255915516c77SSepherosa Ziehau 	}
256015516c77SSepherosa Ziehau 
256115516c77SSepherosa Ziehau 	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
256215516c77SSepherosa Ziehau 		sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
256315516c77SSepherosa Ziehau 	else
256415516c77SSepherosa Ziehau 		sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
256515516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp,
256615516c77SSepherosa Ziehau 	    (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ?
256715516c77SSepherosa Ziehau 	    LINK_STATE_UP : LINK_STATE_DOWN);
256815516c77SSepherosa Ziehau }
256915516c77SSepherosa Ziehau 
257015516c77SSepherosa Ziehau static void
257115516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused)
257215516c77SSepherosa Ziehau {
257315516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
257415516c77SSepherosa Ziehau 
257515516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
257615516c77SSepherosa Ziehau 		return;
257715516c77SSepherosa Ziehau 	hn_link_status(sc);
257815516c77SSepherosa Ziehau }
257915516c77SSepherosa Ziehau 
258015516c77SSepherosa Ziehau static void
258115516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused)
258215516c77SSepherosa Ziehau {
258315516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
258415516c77SSepherosa Ziehau 
258515516c77SSepherosa Ziehau 	/* Prevent any link status checks from running. */
258615516c77SSepherosa Ziehau 	sc->hn_link_flags |= HN_LINK_FLAG_NETCHG;
258715516c77SSepherosa Ziehau 
258815516c77SSepherosa Ziehau 	/*
258915516c77SSepherosa Ziehau 	 * Fake up a [link down --> link up] state change; 5 seconds
259015516c77SSepherosa Ziehau 	 * delay is used, which closely simulates miibus reaction
259115516c77SSepherosa Ziehau 	 * upon link down event.
259215516c77SSepherosa Ziehau 	 */
259315516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
259415516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
259515516c77SSepherosa Ziehau 	taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0,
259615516c77SSepherosa Ziehau 	    &sc->hn_netchg_status, 5 * hz);
259715516c77SSepherosa Ziehau }
259815516c77SSepherosa Ziehau 
259915516c77SSepherosa Ziehau static void
260015516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused)
260115516c77SSepherosa Ziehau {
260215516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
260315516c77SSepherosa Ziehau 
260415516c77SSepherosa Ziehau 	/* Re-allow link status checks. */
260515516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG;
260615516c77SSepherosa Ziehau 	hn_link_status(sc);
260715516c77SSepherosa Ziehau }
260815516c77SSepherosa Ziehau 
260915516c77SSepherosa Ziehau static void
261015516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc)
261115516c77SSepherosa Ziehau {
261215516c77SSepherosa Ziehau 
261315516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
261415516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
261515516c77SSepherosa Ziehau }
261615516c77SSepherosa Ziehau 
261715516c77SSepherosa Ziehau static void
261815516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc)
261915516c77SSepherosa Ziehau {
262015516c77SSepherosa Ziehau 
262115516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
262215516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init);
262315516c77SSepherosa Ziehau }
262415516c77SSepherosa Ziehau 
262515516c77SSepherosa Ziehau static __inline int
262615516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
262715516c77SSepherosa Ziehau     struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
262815516c77SSepherosa Ziehau {
262915516c77SSepherosa Ziehau 	struct mbuf *m = *m_head;
263015516c77SSepherosa Ziehau 	int error;
263115516c77SSepherosa Ziehau 
263215516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim"));
263315516c77SSepherosa Ziehau 
263415516c77SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap,
263515516c77SSepherosa Ziehau 	    m, segs, nsegs, BUS_DMA_NOWAIT);
263615516c77SSepherosa Ziehau 	if (error == EFBIG) {
263715516c77SSepherosa Ziehau 		struct mbuf *m_new;
263815516c77SSepherosa Ziehau 
263915516c77SSepherosa Ziehau 		m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX);
264015516c77SSepherosa Ziehau 		if (m_new == NULL)
264115516c77SSepherosa Ziehau 			return ENOBUFS;
264215516c77SSepherosa Ziehau 		else
264315516c77SSepherosa Ziehau 			*m_head = m = m_new;
264415516c77SSepherosa Ziehau 		txr->hn_tx_collapsed++;
264515516c77SSepherosa Ziehau 
264615516c77SSepherosa Ziehau 		error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag,
264715516c77SSepherosa Ziehau 		    txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT);
264815516c77SSepherosa Ziehau 	}
264915516c77SSepherosa Ziehau 	if (!error) {
265015516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap,
265115516c77SSepherosa Ziehau 		    BUS_DMASYNC_PREWRITE);
265215516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_DMAMAP;
265315516c77SSepherosa Ziehau 	}
265415516c77SSepherosa Ziehau 	return error;
265515516c77SSepherosa Ziehau }
265615516c77SSepherosa Ziehau 
265715516c77SSepherosa Ziehau static __inline int
265815516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd)
265915516c77SSepherosa Ziehau {
266015516c77SSepherosa Ziehau 
266115516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0,
266215516c77SSepherosa Ziehau 	    ("put an onlist txd %#x", txd->flags));
2663dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2664dc13fee6SSepherosa Ziehau 	    ("put an onagg txd %#x", txd->flags));
266515516c77SSepherosa Ziehau 
266615516c77SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
266715516c77SSepherosa Ziehau 	if (atomic_fetchadd_int(&txd->refs, -1) != 1)
266815516c77SSepherosa Ziehau 		return 0;
266915516c77SSepherosa Ziehau 
2670dc13fee6SSepherosa Ziehau 	if (!STAILQ_EMPTY(&txd->agg_list)) {
2671dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tmp_txd;
2672dc13fee6SSepherosa Ziehau 
2673dc13fee6SSepherosa Ziehau 		while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) {
2674dc13fee6SSepherosa Ziehau 			int freed;
2675dc13fee6SSepherosa Ziehau 
2676dc13fee6SSepherosa Ziehau 			KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list),
2677dc13fee6SSepherosa Ziehau 			    ("resursive aggregation on aggregated txdesc"));
2678dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG),
2679dc13fee6SSepherosa Ziehau 			    ("not aggregated txdesc"));
2680dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
2681dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc uses dmamap"));
2682dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
2683dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc consumes "
2684dc13fee6SSepherosa Ziehau 			     "chimney sending buffer"));
2685dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_size == 0,
2686dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc has non-zero "
2687dc13fee6SSepherosa Ziehau 			     "chimney sending size"));
2688dc13fee6SSepherosa Ziehau 
2689dc13fee6SSepherosa Ziehau 			STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link);
2690dc13fee6SSepherosa Ziehau 			tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG;
2691dc13fee6SSepherosa Ziehau 			freed = hn_txdesc_put(txr, tmp_txd);
2692dc13fee6SSepherosa Ziehau 			KASSERT(freed, ("failed to free aggregated txdesc"));
2693dc13fee6SSepherosa Ziehau 		}
2694dc13fee6SSepherosa Ziehau 	}
2695dc13fee6SSepherosa Ziehau 
269615516c77SSepherosa Ziehau 	if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) {
269715516c77SSepherosa Ziehau 		KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
269815516c77SSepherosa Ziehau 		    ("chim txd uses dmamap"));
269915516c77SSepherosa Ziehau 		hn_chim_free(txr->hn_sc, txd->chim_index);
270015516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
2701dc13fee6SSepherosa Ziehau 		txd->chim_size = 0;
270215516c77SSepherosa Ziehau 	} else if (txd->flags & HN_TXD_FLAG_DMAMAP) {
270315516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag,
270415516c77SSepherosa Ziehau 		    txd->data_dmap, BUS_DMASYNC_POSTWRITE);
270515516c77SSepherosa Ziehau 		bus_dmamap_unload(txr->hn_tx_data_dtag,
270615516c77SSepherosa Ziehau 		    txd->data_dmap);
270715516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_DMAMAP;
270815516c77SSepherosa Ziehau 	}
270915516c77SSepherosa Ziehau 
271015516c77SSepherosa Ziehau 	if (txd->m != NULL) {
271115516c77SSepherosa Ziehau 		m_freem(txd->m);
271215516c77SSepherosa Ziehau 		txd->m = NULL;
271315516c77SSepherosa Ziehau 	}
271415516c77SSepherosa Ziehau 
271515516c77SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONLIST;
271615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
271715516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
271815516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_avail >= 0 &&
271915516c77SSepherosa Ziehau 	    txr->hn_txdesc_avail < txr->hn_txdesc_cnt,
272015516c77SSepherosa Ziehau 	    ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail));
272115516c77SSepherosa Ziehau 	txr->hn_txdesc_avail++;
272215516c77SSepherosa Ziehau 	SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
272315516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
272485e4ae1eSSepherosa Ziehau #else	/* HN_USE_TXDESC_BUFRING */
272585e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
272615516c77SSepherosa Ziehau 	atomic_add_int(&txr->hn_txdesc_avail, 1);
272715516c77SSepherosa Ziehau #endif
272885e4ae1eSSepherosa Ziehau 	buf_ring_enqueue(txr->hn_txdesc_br, txd);
272985e4ae1eSSepherosa Ziehau #endif	/* !HN_USE_TXDESC_BUFRING */
273015516c77SSepherosa Ziehau 
273115516c77SSepherosa Ziehau 	return 1;
273215516c77SSepherosa Ziehau }
273315516c77SSepherosa Ziehau 
273415516c77SSepherosa Ziehau static __inline struct hn_txdesc *
273515516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr)
273615516c77SSepherosa Ziehau {
273715516c77SSepherosa Ziehau 	struct hn_txdesc *txd;
273815516c77SSepherosa Ziehau 
273915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
274015516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
274115516c77SSepherosa Ziehau 	txd = SLIST_FIRST(&txr->hn_txlist);
274215516c77SSepherosa Ziehau 	if (txd != NULL) {
274315516c77SSepherosa Ziehau 		KASSERT(txr->hn_txdesc_avail > 0,
274415516c77SSepherosa Ziehau 		    ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail));
274515516c77SSepherosa Ziehau 		txr->hn_txdesc_avail--;
274615516c77SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&txr->hn_txlist, link);
274715516c77SSepherosa Ziehau 	}
274815516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
274915516c77SSepherosa Ziehau #else
275015516c77SSepherosa Ziehau 	txd = buf_ring_dequeue_sc(txr->hn_txdesc_br);
275115516c77SSepherosa Ziehau #endif
275215516c77SSepherosa Ziehau 
275315516c77SSepherosa Ziehau 	if (txd != NULL) {
275415516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
275585e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
275615516c77SSepherosa Ziehau 		atomic_subtract_int(&txr->hn_txdesc_avail, 1);
275715516c77SSepherosa Ziehau #endif
275885e4ae1eSSepherosa Ziehau #endif	/* HN_USE_TXDESC_BUFRING */
275915516c77SSepherosa Ziehau 		KASSERT(txd->m == NULL && txd->refs == 0 &&
2760dc13fee6SSepherosa Ziehau 		    STAILQ_EMPTY(&txd->agg_list) &&
276115516c77SSepherosa Ziehau 		    txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
2762dc13fee6SSepherosa Ziehau 		    txd->chim_size == 0 &&
276315516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONLIST) &&
2764dc13fee6SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONAGG) == 0 &&
276515516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd"));
276615516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_ONLIST;
276715516c77SSepherosa Ziehau 		txd->refs = 1;
276815516c77SSepherosa Ziehau 	}
276915516c77SSepherosa Ziehau 	return txd;
277015516c77SSepherosa Ziehau }
277115516c77SSepherosa Ziehau 
277215516c77SSepherosa Ziehau static __inline void
277315516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd)
277415516c77SSepherosa Ziehau {
277515516c77SSepherosa Ziehau 
277615516c77SSepherosa Ziehau 	/* 0->1 transition will never work */
277725641fc7SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
277815516c77SSepherosa Ziehau 	atomic_add_int(&txd->refs, 1);
277915516c77SSepherosa Ziehau }
278015516c77SSepherosa Ziehau 
2781dc13fee6SSepherosa Ziehau static __inline void
2782dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd)
2783dc13fee6SSepherosa Ziehau {
2784dc13fee6SSepherosa Ziehau 
2785dc13fee6SSepherosa Ziehau 	KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2786dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on aggregating txdesc"));
2787dc13fee6SSepherosa Ziehau 
2788dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2789dc13fee6SSepherosa Ziehau 	    ("already aggregated"));
2790dc13fee6SSepherosa Ziehau 	KASSERT(STAILQ_EMPTY(&txd->agg_list),
2791dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on to-be-aggregated txdesc"));
2792dc13fee6SSepherosa Ziehau 
2793dc13fee6SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONAGG;
2794dc13fee6SSepherosa Ziehau 	STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link);
2795dc13fee6SSepherosa Ziehau }
2796dc13fee6SSepherosa Ziehau 
279715516c77SSepherosa Ziehau static bool
279815516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr)
279915516c77SSepherosa Ziehau {
280015516c77SSepherosa Ziehau 	bool pending = false;
280115516c77SSepherosa Ziehau 
280215516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
280315516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
280415516c77SSepherosa Ziehau 	if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt)
280515516c77SSepherosa Ziehau 		pending = true;
280615516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
280715516c77SSepherosa Ziehau #else
280815516c77SSepherosa Ziehau 	if (!buf_ring_full(txr->hn_txdesc_br))
280915516c77SSepherosa Ziehau 		pending = true;
281015516c77SSepherosa Ziehau #endif
281115516c77SSepherosa Ziehau 	return (pending);
281215516c77SSepherosa Ziehau }
281315516c77SSepherosa Ziehau 
281415516c77SSepherosa Ziehau static __inline void
281515516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr)
281615516c77SSepherosa Ziehau {
281715516c77SSepherosa Ziehau 	txr->hn_has_txeof = 0;
281815516c77SSepherosa Ziehau 	txr->hn_txeof(txr);
281915516c77SSepherosa Ziehau }
282015516c77SSepherosa Ziehau 
282115516c77SSepherosa Ziehau static void
282215516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc,
282315516c77SSepherosa Ziehau     struct vmbus_channel *chan, const void *data __unused, int dlen __unused)
282415516c77SSepherosa Ziehau {
282515516c77SSepherosa Ziehau 	struct hn_txdesc *txd = sndc->hn_cbarg;
282615516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
282715516c77SSepherosa Ziehau 
282815516c77SSepherosa Ziehau 	txr = txd->txr;
282915516c77SSepherosa Ziehau 	KASSERT(txr->hn_chan == chan,
283015516c77SSepherosa Ziehau 	    ("channel mismatch, on chan%u, should be chan%u",
2831aa1a2adcSSepherosa Ziehau 	     vmbus_chan_id(chan), vmbus_chan_id(txr->hn_chan)));
283215516c77SSepherosa Ziehau 
283315516c77SSepherosa Ziehau 	txr->hn_has_txeof = 1;
283415516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
283515516c77SSepherosa Ziehau 
283615516c77SSepherosa Ziehau 	++txr->hn_txdone_cnt;
283715516c77SSepherosa Ziehau 	if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) {
283815516c77SSepherosa Ziehau 		txr->hn_txdone_cnt = 0;
283915516c77SSepherosa Ziehau 		if (txr->hn_oactive)
284015516c77SSepherosa Ziehau 			hn_txeof(txr);
284115516c77SSepherosa Ziehau 	}
284215516c77SSepherosa Ziehau }
284315516c77SSepherosa Ziehau 
284415516c77SSepherosa Ziehau static void
284515516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
284615516c77SSepherosa Ziehau {
284715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
284815516c77SSepherosa Ziehau 	tcp_lro_flush_all(&rxr->hn_lro);
284915516c77SSepherosa Ziehau #endif
285015516c77SSepherosa Ziehau 
285115516c77SSepherosa Ziehau 	/*
285215516c77SSepherosa Ziehau 	 * NOTE:
285315516c77SSepherosa Ziehau 	 * 'txr' could be NULL, if multiple channels and
285415516c77SSepherosa Ziehau 	 * ifnet.if_start method are enabled.
285515516c77SSepherosa Ziehau 	 */
285615516c77SSepherosa Ziehau 	if (txr == NULL || !txr->hn_has_txeof)
285715516c77SSepherosa Ziehau 		return;
285815516c77SSepherosa Ziehau 
285915516c77SSepherosa Ziehau 	txr->hn_txdone_cnt = 0;
286015516c77SSepherosa Ziehau 	hn_txeof(txr);
286115516c77SSepherosa Ziehau }
286215516c77SSepherosa Ziehau 
286315516c77SSepherosa Ziehau static __inline uint32_t
286415516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs)
286515516c77SSepherosa Ziehau {
286615516c77SSepherosa Ziehau 
286715516c77SSepherosa Ziehau 	KASSERT(ofs >= sizeof(struct rndis_packet_msg),
286815516c77SSepherosa Ziehau 	    ("invalid RNDIS packet msg offset %u", ofs));
286915516c77SSepherosa Ziehau 	return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset));
287015516c77SSepherosa Ziehau }
287115516c77SSepherosa Ziehau 
287215516c77SSepherosa Ziehau static __inline void *
287315516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
287415516c77SSepherosa Ziehau     size_t pi_dlen, uint32_t pi_type)
287515516c77SSepherosa Ziehau {
287615516c77SSepherosa Ziehau 	const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
287715516c77SSepherosa Ziehau 	struct rndis_pktinfo *pi;
287815516c77SSepherosa Ziehau 
287915516c77SSepherosa Ziehau 	KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
288015516c77SSepherosa Ziehau 	    ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
288115516c77SSepherosa Ziehau 
288215516c77SSepherosa Ziehau 	/*
288315516c77SSepherosa Ziehau 	 * Per-packet-info does not move; it only grows.
288415516c77SSepherosa Ziehau 	 *
288515516c77SSepherosa Ziehau 	 * NOTE:
288615516c77SSepherosa Ziehau 	 * rm_pktinfooffset in this phase counts from the beginning
288715516c77SSepherosa Ziehau 	 * of rndis_packet_msg.
288815516c77SSepherosa Ziehau 	 */
288915516c77SSepherosa Ziehau 	KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
289015516c77SSepherosa Ziehau 	    ("%u pktinfo overflows RNDIS packet msg", pi_type));
289115516c77SSepherosa Ziehau 	pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
289215516c77SSepherosa Ziehau 	    pkt->rm_pktinfolen);
289315516c77SSepherosa Ziehau 	pkt->rm_pktinfolen += pi_size;
289415516c77SSepherosa Ziehau 
289515516c77SSepherosa Ziehau 	pi->rm_size = pi_size;
289615516c77SSepherosa Ziehau 	pi->rm_type = pi_type;
289715516c77SSepherosa Ziehau 	pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
289815516c77SSepherosa Ziehau 
289915516c77SSepherosa Ziehau 	return (pi->rm_data);
290015516c77SSepherosa Ziehau }
290115516c77SSepherosa Ziehau 
2902dc13fee6SSepherosa Ziehau static __inline int
2903dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr)
2904dc13fee6SSepherosa Ziehau {
2905dc13fee6SSepherosa Ziehau 	struct hn_txdesc *txd;
2906dc13fee6SSepherosa Ziehau 	struct mbuf *m;
2907dc13fee6SSepherosa Ziehau 	int error, pkts;
2908dc13fee6SSepherosa Ziehau 
2909dc13fee6SSepherosa Ziehau 	txd = txr->hn_agg_txd;
2910dc13fee6SSepherosa Ziehau 	KASSERT(txd != NULL, ("no aggregate txdesc"));
2911dc13fee6SSepherosa Ziehau 
2912dc13fee6SSepherosa Ziehau 	/*
2913dc13fee6SSepherosa Ziehau 	 * Since hn_txpkt() will reset this temporary stat, save
2914dc13fee6SSepherosa Ziehau 	 * it now, so that oerrors can be updated properly, if
2915dc13fee6SSepherosa Ziehau 	 * hn_txpkt() ever fails.
2916dc13fee6SSepherosa Ziehau 	 */
2917dc13fee6SSepherosa Ziehau 	pkts = txr->hn_stat_pkts;
2918dc13fee6SSepherosa Ziehau 
2919dc13fee6SSepherosa Ziehau 	/*
2920dc13fee6SSepherosa Ziehau 	 * Since txd's mbuf will _not_ be freed upon hn_txpkt()
2921dc13fee6SSepherosa Ziehau 	 * failure, save it for later freeing, if hn_txpkt() ever
2922dc13fee6SSepherosa Ziehau 	 * fails.
2923dc13fee6SSepherosa Ziehau 	 */
2924dc13fee6SSepherosa Ziehau 	m = txd->m;
2925dc13fee6SSepherosa Ziehau 	error = hn_txpkt(ifp, txr, txd);
2926dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
2927dc13fee6SSepherosa Ziehau 		/* txd is freed, but m is not. */
2928dc13fee6SSepherosa Ziehau 		m_freem(m);
2929dc13fee6SSepherosa Ziehau 
2930dc13fee6SSepherosa Ziehau 		txr->hn_flush_failed++;
2931dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts);
2932dc13fee6SSepherosa Ziehau 	}
2933dc13fee6SSepherosa Ziehau 
2934dc13fee6SSepherosa Ziehau 	/* Reset all aggregation states. */
2935dc13fee6SSepherosa Ziehau 	txr->hn_agg_txd = NULL;
2936dc13fee6SSepherosa Ziehau 	txr->hn_agg_szleft = 0;
2937dc13fee6SSepherosa Ziehau 	txr->hn_agg_pktleft = 0;
2938dc13fee6SSepherosa Ziehau 	txr->hn_agg_prevpkt = NULL;
2939dc13fee6SSepherosa Ziehau 
2940dc13fee6SSepherosa Ziehau 	return (error);
2941dc13fee6SSepherosa Ziehau }
2942dc13fee6SSepherosa Ziehau 
2943dc13fee6SSepherosa Ziehau static void *
2944dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
2945dc13fee6SSepherosa Ziehau     int pktsize)
2946dc13fee6SSepherosa Ziehau {
2947dc13fee6SSepherosa Ziehau 	void *chim;
2948dc13fee6SSepherosa Ziehau 
2949dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL) {
2950dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) {
2951dc13fee6SSepherosa Ziehau 			struct hn_txdesc *agg_txd = txr->hn_agg_txd;
2952dc13fee6SSepherosa Ziehau 			struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt;
2953dc13fee6SSepherosa Ziehau 			int olen;
2954dc13fee6SSepherosa Ziehau 
2955dc13fee6SSepherosa Ziehau 			/*
2956dc13fee6SSepherosa Ziehau 			 * Update the previous RNDIS packet's total length,
2957dc13fee6SSepherosa Ziehau 			 * it can be increased due to the mandatory alignment
2958dc13fee6SSepherosa Ziehau 			 * padding for this RNDIS packet.  And update the
2959dc13fee6SSepherosa Ziehau 			 * aggregating txdesc's chimney sending buffer size
2960dc13fee6SSepherosa Ziehau 			 * accordingly.
2961dc13fee6SSepherosa Ziehau 			 *
2962dc13fee6SSepherosa Ziehau 			 * XXX
2963dc13fee6SSepherosa Ziehau 			 * Zero-out the padding, as required by the RNDIS spec.
2964dc13fee6SSepherosa Ziehau 			 */
2965dc13fee6SSepherosa Ziehau 			olen = pkt->rm_len;
2966dc13fee6SSepherosa Ziehau 			pkt->rm_len = roundup2(olen, txr->hn_agg_align);
2967dc13fee6SSepherosa Ziehau 			agg_txd->chim_size += pkt->rm_len - olen;
2968dc13fee6SSepherosa Ziehau 
2969dc13fee6SSepherosa Ziehau 			/* Link this txdesc to the parent. */
2970dc13fee6SSepherosa Ziehau 			hn_txdesc_agg(agg_txd, txd);
2971dc13fee6SSepherosa Ziehau 
2972dc13fee6SSepherosa Ziehau 			chim = (uint8_t *)pkt + pkt->rm_len;
2973dc13fee6SSepherosa Ziehau 			/* Save the current packet for later fixup. */
2974dc13fee6SSepherosa Ziehau 			txr->hn_agg_prevpkt = chim;
2975dc13fee6SSepherosa Ziehau 
2976dc13fee6SSepherosa Ziehau 			txr->hn_agg_pktleft--;
2977dc13fee6SSepherosa Ziehau 			txr->hn_agg_szleft -= pktsize;
2978dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_szleft <=
2979dc13fee6SSepherosa Ziehau 			    HN_PKTSIZE_MIN(txr->hn_agg_align)) {
2980dc13fee6SSepherosa Ziehau 				/*
2981dc13fee6SSepherosa Ziehau 				 * Probably can't aggregate more packets,
2982dc13fee6SSepherosa Ziehau 				 * flush this aggregating txdesc proactively.
2983dc13fee6SSepherosa Ziehau 				 */
2984dc13fee6SSepherosa Ziehau 				txr->hn_agg_pktleft = 0;
2985dc13fee6SSepherosa Ziehau 			}
2986dc13fee6SSepherosa Ziehau 			/* Done! */
2987dc13fee6SSepherosa Ziehau 			return (chim);
2988dc13fee6SSepherosa Ziehau 		}
2989dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
2990dc13fee6SSepherosa Ziehau 	}
2991dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
2992dc13fee6SSepherosa Ziehau 
2993dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney_tried++;
2994dc13fee6SSepherosa Ziehau 	txd->chim_index = hn_chim_alloc(txr->hn_sc);
2995dc13fee6SSepherosa Ziehau 	if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID)
2996dc13fee6SSepherosa Ziehau 		return (NULL);
2997dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney++;
2998dc13fee6SSepherosa Ziehau 
2999dc13fee6SSepherosa Ziehau 	chim = txr->hn_sc->hn_chim +
3000dc13fee6SSepherosa Ziehau 	    (txd->chim_index * txr->hn_sc->hn_chim_szmax);
3001dc13fee6SSepherosa Ziehau 
3002dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_pktmax > 1 &&
3003dc13fee6SSepherosa Ziehau 	    txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) {
3004dc13fee6SSepherosa Ziehau 		txr->hn_agg_txd = txd;
3005dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1;
3006dc13fee6SSepherosa Ziehau 		txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize;
3007dc13fee6SSepherosa Ziehau 		txr->hn_agg_prevpkt = chim;
3008dc13fee6SSepherosa Ziehau 	}
3009dc13fee6SSepherosa Ziehau 	return (chim);
3010dc13fee6SSepherosa Ziehau }
3011dc13fee6SSepherosa Ziehau 
301215516c77SSepherosa Ziehau /*
301315516c77SSepherosa Ziehau  * NOTE:
301415516c77SSepherosa Ziehau  * If this function fails, then both txd and m_head0 will be freed.
301515516c77SSepherosa Ziehau  */
301615516c77SSepherosa Ziehau static int
3017dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
3018dc13fee6SSepherosa Ziehau     struct mbuf **m_head0)
301915516c77SSepherosa Ziehau {
302015516c77SSepherosa Ziehau 	bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX];
302115516c77SSepherosa Ziehau 	int error, nsegs, i;
302215516c77SSepherosa Ziehau 	struct mbuf *m_head = *m_head0;
302315516c77SSepherosa Ziehau 	struct rndis_packet_msg *pkt;
302415516c77SSepherosa Ziehau 	uint32_t *pi_data;
30258966e5d5SSepherosa Ziehau 	void *chim = NULL;
3026dc13fee6SSepherosa Ziehau 	int pkt_hlen, pkt_size;
302715516c77SSepherosa Ziehau 
302815516c77SSepherosa Ziehau 	pkt = txd->rndis_pkt;
3029dc13fee6SSepherosa Ziehau 	pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align);
3030dc13fee6SSepherosa Ziehau 	if (pkt_size < txr->hn_chim_size) {
3031dc13fee6SSepherosa Ziehau 		chim = hn_try_txagg(ifp, txr, txd, pkt_size);
3032dc13fee6SSepherosa Ziehau 		if (chim != NULL)
30338966e5d5SSepherosa Ziehau 			pkt = chim;
3034dc13fee6SSepherosa Ziehau 	} else {
3035dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL)
3036dc13fee6SSepherosa Ziehau 			hn_flush_txagg(ifp, txr);
30378966e5d5SSepherosa Ziehau 	}
30388966e5d5SSepherosa Ziehau 
303915516c77SSepherosa Ziehau 	pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
30408fe90f73SSepherosa Ziehau 	pkt->rm_len = m_head->m_pkthdr.len;
30419130c4f7SSepherosa Ziehau 	pkt->rm_dataoffset = 0;
304215516c77SSepherosa Ziehau 	pkt->rm_datalen = m_head->m_pkthdr.len;
3043dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataoffset = 0;
3044dc13fee6SSepherosa Ziehau 	pkt->rm_oobdatalen = 0;
3045dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataelements = 0;
304615516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = sizeof(*pkt);
304715516c77SSepherosa Ziehau 	pkt->rm_pktinfolen = 0;
3048dc13fee6SSepherosa Ziehau 	pkt->rm_vchandle = 0;
3049dc13fee6SSepherosa Ziehau 	pkt->rm_reserved = 0;
305015516c77SSepherosa Ziehau 
305115516c77SSepherosa Ziehau 	if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) {
305215516c77SSepherosa Ziehau 		/*
305315516c77SSepherosa Ziehau 		 * Set the hash value for this packet, so that the host could
305415516c77SSepherosa Ziehau 		 * dispatch the TX done event for this packet back to this TX
305515516c77SSepherosa Ziehau 		 * ring's channel.
305615516c77SSepherosa Ziehau 		 */
305715516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
305815516c77SSepherosa Ziehau 		    HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL);
305915516c77SSepherosa Ziehau 		*pi_data = txr->hn_tx_idx;
306015516c77SSepherosa Ziehau 	}
306115516c77SSepherosa Ziehau 
306215516c77SSepherosa Ziehau 	if (m_head->m_flags & M_VLANTAG) {
306315516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
306415516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
306515516c77SSepherosa Ziehau 		*pi_data = NDIS_VLAN_INFO_MAKE(
306615516c77SSepherosa Ziehau 		    EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag),
306715516c77SSepherosa Ziehau 		    EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag),
306815516c77SSepherosa Ziehau 		    EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag));
306915516c77SSepherosa Ziehau 	}
307015516c77SSepherosa Ziehau 
307115516c77SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
307215516c77SSepherosa Ziehau #if defined(INET6) || defined(INET)
307315516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
307415516c77SSepherosa Ziehau 		    NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO);
307515516c77SSepherosa Ziehau #ifdef INET
307615516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
3077c49d47daSSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV4(
3078c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen,
307915516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
308015516c77SSepherosa Ziehau 		}
308115516c77SSepherosa Ziehau #endif
308215516c77SSepherosa Ziehau #if defined(INET6) && defined(INET)
308315516c77SSepherosa Ziehau 		else
308415516c77SSepherosa Ziehau #endif
308515516c77SSepherosa Ziehau #ifdef INET6
308615516c77SSepherosa Ziehau 		{
3087c49d47daSSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV6(
3088c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen,
308915516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
309015516c77SSepherosa Ziehau 		}
309115516c77SSepherosa Ziehau #endif
309215516c77SSepherosa Ziehau #endif	/* INET6 || INET */
309315516c77SSepherosa Ziehau 	} else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) {
309415516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
309515516c77SSepherosa Ziehau 		    NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
309615516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
309715516c77SSepherosa Ziehau 		    (CSUM_IP6_TCP | CSUM_IP6_UDP)) {
309815516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV6;
309915516c77SSepherosa Ziehau 		} else {
310015516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV4;
310115516c77SSepherosa Ziehau 			if (m_head->m_pkthdr.csum_flags & CSUM_IP)
310215516c77SSepherosa Ziehau 				*pi_data |= NDIS_TXCSUM_INFO_IPCS;
310315516c77SSepherosa Ziehau 		}
310415516c77SSepherosa Ziehau 
3105c49d47daSSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
3106c49d47daSSepherosa Ziehau 		    (CSUM_IP_TCP | CSUM_IP6_TCP)) {
3107c49d47daSSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_MKTCPCS(
3108c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen);
3109c49d47daSSepherosa Ziehau 		} else if (m_head->m_pkthdr.csum_flags &
3110c49d47daSSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP6_UDP)) {
3111c49d47daSSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_MKUDPCS(
3112c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen);
3113c49d47daSSepherosa Ziehau 		}
311415516c77SSepherosa Ziehau 	}
311515516c77SSepherosa Ziehau 
3116dc13fee6SSepherosa Ziehau 	pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
31178fe90f73SSepherosa Ziehau 	/* Fixup RNDIS packet message total length */
31188fe90f73SSepherosa Ziehau 	pkt->rm_len += pkt_hlen;
311915516c77SSepherosa Ziehau 	/* Convert RNDIS packet message offsets */
31209130c4f7SSepherosa Ziehau 	pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt_hlen);
312115516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset);
312215516c77SSepherosa Ziehau 
312315516c77SSepherosa Ziehau 	/*
31248966e5d5SSepherosa Ziehau 	 * Fast path: Chimney sending.
312515516c77SSepherosa Ziehau 	 */
31268966e5d5SSepherosa Ziehau 	if (chim != NULL) {
3127dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tgt_txd = txd;
3128dc13fee6SSepherosa Ziehau 
3129dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL) {
3130dc13fee6SSepherosa Ziehau 			tgt_txd = txr->hn_agg_txd;
3131dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
3132dc13fee6SSepherosa Ziehau 			*m_head0 = NULL;
3133dc13fee6SSepherosa Ziehau #endif
3134dc13fee6SSepherosa Ziehau 		}
3135dc13fee6SSepherosa Ziehau 
3136dc13fee6SSepherosa Ziehau 		KASSERT(pkt == chim,
3137dc13fee6SSepherosa Ziehau 		    ("RNDIS pkt not in chimney sending buffer"));
3138dc13fee6SSepherosa Ziehau 		KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID,
3139dc13fee6SSepherosa Ziehau 		    ("chimney sending buffer is not used"));
3140dc13fee6SSepherosa Ziehau 		tgt_txd->chim_size += pkt->rm_len;
314115516c77SSepherosa Ziehau 
31428966e5d5SSepherosa Ziehau 		m_copydata(m_head, 0, m_head->m_pkthdr.len,
3143dc13fee6SSepherosa Ziehau 		    ((uint8_t *)chim) + pkt_hlen);
314415516c77SSepherosa Ziehau 
314515516c77SSepherosa Ziehau 		txr->hn_gpa_cnt = 0;
314615516c77SSepherosa Ziehau 		txr->hn_sendpkt = hn_txpkt_chim;
314715516c77SSepherosa Ziehau 		goto done;
314815516c77SSepherosa Ziehau 	}
3149dc13fee6SSepherosa Ziehau 
3150dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc"));
31518966e5d5SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
31528966e5d5SSepherosa Ziehau 	    ("chimney buffer is used"));
31538966e5d5SSepherosa Ziehau 	KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc"));
315415516c77SSepherosa Ziehau 
315515516c77SSepherosa Ziehau 	error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs);
3156dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
315715516c77SSepherosa Ziehau 		int freed;
315815516c77SSepherosa Ziehau 
315915516c77SSepherosa Ziehau 		/*
316015516c77SSepherosa Ziehau 		 * This mbuf is not linked w/ the txd yet, so free it now.
316115516c77SSepherosa Ziehau 		 */
316215516c77SSepherosa Ziehau 		m_freem(m_head);
316315516c77SSepherosa Ziehau 		*m_head0 = NULL;
316415516c77SSepherosa Ziehau 
316515516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
316615516c77SSepherosa Ziehau 		KASSERT(freed != 0,
316715516c77SSepherosa Ziehau 		    ("fail to free txd upon txdma error"));
316815516c77SSepherosa Ziehau 
316915516c77SSepherosa Ziehau 		txr->hn_txdma_failed++;
3170dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
317115516c77SSepherosa Ziehau 		return error;
317215516c77SSepherosa Ziehau 	}
317315516c77SSepherosa Ziehau 	*m_head0 = m_head;
317415516c77SSepherosa Ziehau 
317515516c77SSepherosa Ziehau 	/* +1 RNDIS packet message */
317615516c77SSepherosa Ziehau 	txr->hn_gpa_cnt = nsegs + 1;
317715516c77SSepherosa Ziehau 
317815516c77SSepherosa Ziehau 	/* send packet with page buffer */
317915516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr);
318015516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK;
3181dc13fee6SSepherosa Ziehau 	txr->hn_gpa[0].gpa_len = pkt_hlen;
318215516c77SSepherosa Ziehau 
318315516c77SSepherosa Ziehau 	/*
318415516c77SSepherosa Ziehau 	 * Fill the page buffers with mbuf info after the page
318515516c77SSepherosa Ziehau 	 * buffer for RNDIS packet message.
318615516c77SSepherosa Ziehau 	 */
318715516c77SSepherosa Ziehau 	for (i = 0; i < nsegs; ++i) {
318815516c77SSepherosa Ziehau 		struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1];
318915516c77SSepherosa Ziehau 
319015516c77SSepherosa Ziehau 		gpa->gpa_page = atop(segs[i].ds_addr);
319115516c77SSepherosa Ziehau 		gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK;
319215516c77SSepherosa Ziehau 		gpa->gpa_len = segs[i].ds_len;
319315516c77SSepherosa Ziehau 	}
319415516c77SSepherosa Ziehau 
319515516c77SSepherosa Ziehau 	txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
319615516c77SSepherosa Ziehau 	txd->chim_size = 0;
319715516c77SSepherosa Ziehau 	txr->hn_sendpkt = hn_txpkt_sglist;
319815516c77SSepherosa Ziehau done:
319915516c77SSepherosa Ziehau 	txd->m = m_head;
320015516c77SSepherosa Ziehau 
320115516c77SSepherosa Ziehau 	/* Set the completion routine */
320215516c77SSepherosa Ziehau 	hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd);
320315516c77SSepherosa Ziehau 
3204dc13fee6SSepherosa Ziehau 	/* Update temporary stats for later use. */
3205dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts++;
3206dc13fee6SSepherosa Ziehau 	txr->hn_stat_size += m_head->m_pkthdr.len;
3207dc13fee6SSepherosa Ziehau 	if (m_head->m_flags & M_MCAST)
3208dc13fee6SSepherosa Ziehau 		txr->hn_stat_mcasts++;
3209dc13fee6SSepherosa Ziehau 
321015516c77SSepherosa Ziehau 	return 0;
321115516c77SSepherosa Ziehau }
321215516c77SSepherosa Ziehau 
321315516c77SSepherosa Ziehau /*
321415516c77SSepherosa Ziehau  * NOTE:
321515516c77SSepherosa Ziehau  * If this function fails, then txd will be freed, but the mbuf
321615516c77SSepherosa Ziehau  * associated w/ the txd will _not_ be freed.
321715516c77SSepherosa Ziehau  */
321815516c77SSepherosa Ziehau static int
321915516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd)
322015516c77SSepherosa Ziehau {
32218e7d3136SSepherosa Ziehau 	int error, send_failed = 0, has_bpf;
322215516c77SSepherosa Ziehau 
322315516c77SSepherosa Ziehau again:
32248e7d3136SSepherosa Ziehau 	has_bpf = bpf_peers_present(ifp->if_bpf);
32258e7d3136SSepherosa Ziehau 	if (has_bpf) {
322615516c77SSepherosa Ziehau 		/*
32278e7d3136SSepherosa Ziehau 		 * Make sure that this txd and any aggregated txds are not
32288e7d3136SSepherosa Ziehau 		 * freed before ETHER_BPF_MTAP.
322915516c77SSepherosa Ziehau 		 */
323015516c77SSepherosa Ziehau 		hn_txdesc_hold(txd);
32318e7d3136SSepherosa Ziehau 	}
323215516c77SSepherosa Ziehau 	error = txr->hn_sendpkt(txr, txd);
323315516c77SSepherosa Ziehau 	if (!error) {
32348e7d3136SSepherosa Ziehau 		if (has_bpf) {
3235dc13fee6SSepherosa Ziehau 			const struct hn_txdesc *tmp_txd;
3236dc13fee6SSepherosa Ziehau 
323715516c77SSepherosa Ziehau 			ETHER_BPF_MTAP(ifp, txd->m);
3238dc13fee6SSepherosa Ziehau 			STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link)
3239dc13fee6SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, tmp_txd->m);
3240dc13fee6SSepherosa Ziehau 		}
3241dc13fee6SSepherosa Ziehau 
3242dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts);
324323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
324423bf9e15SSepherosa Ziehau 		if (!hn_use_if_start)
324523bf9e15SSepherosa Ziehau #endif
324623bf9e15SSepherosa Ziehau 		{
324715516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OBYTES,
3248dc13fee6SSepherosa Ziehau 			    txr->hn_stat_size);
3249dc13fee6SSepherosa Ziehau 			if (txr->hn_stat_mcasts != 0) {
3250dc13fee6SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OMCASTS,
3251dc13fee6SSepherosa Ziehau 				    txr->hn_stat_mcasts);
325215516c77SSepherosa Ziehau 			}
3253dc13fee6SSepherosa Ziehau 		}
3254dc13fee6SSepherosa Ziehau 		txr->hn_pkts += txr->hn_stat_pkts;
3255dc13fee6SSepherosa Ziehau 		txr->hn_sends++;
325615516c77SSepherosa Ziehau 	}
32578e7d3136SSepherosa Ziehau 	if (has_bpf)
325815516c77SSepherosa Ziehau 		hn_txdesc_put(txr, txd);
325915516c77SSepherosa Ziehau 
326015516c77SSepherosa Ziehau 	if (__predict_false(error)) {
326115516c77SSepherosa Ziehau 		int freed;
326215516c77SSepherosa Ziehau 
326315516c77SSepherosa Ziehau 		/*
326415516c77SSepherosa Ziehau 		 * This should "really rarely" happen.
326515516c77SSepherosa Ziehau 		 *
326615516c77SSepherosa Ziehau 		 * XXX Too many RX to be acked or too many sideband
326715516c77SSepherosa Ziehau 		 * commands to run?  Ask netvsc_channel_rollup()
326815516c77SSepherosa Ziehau 		 * to kick start later.
326915516c77SSepherosa Ziehau 		 */
327015516c77SSepherosa Ziehau 		txr->hn_has_txeof = 1;
327115516c77SSepherosa Ziehau 		if (!send_failed) {
327215516c77SSepherosa Ziehau 			txr->hn_send_failed++;
327315516c77SSepherosa Ziehau 			send_failed = 1;
327415516c77SSepherosa Ziehau 			/*
327515516c77SSepherosa Ziehau 			 * Try sending again after set hn_has_txeof;
327615516c77SSepherosa Ziehau 			 * in case that we missed the last
327715516c77SSepherosa Ziehau 			 * netvsc_channel_rollup().
327815516c77SSepherosa Ziehau 			 */
327915516c77SSepherosa Ziehau 			goto again;
328015516c77SSepherosa Ziehau 		}
328115516c77SSepherosa Ziehau 		if_printf(ifp, "send failed\n");
328215516c77SSepherosa Ziehau 
328315516c77SSepherosa Ziehau 		/*
328415516c77SSepherosa Ziehau 		 * Caller will perform further processing on the
328515516c77SSepherosa Ziehau 		 * associated mbuf, so don't free it in hn_txdesc_put();
328615516c77SSepherosa Ziehau 		 * only unload it from the DMA map in hn_txdesc_put(),
328715516c77SSepherosa Ziehau 		 * if it was loaded.
328815516c77SSepherosa Ziehau 		 */
328915516c77SSepherosa Ziehau 		txd->m = NULL;
329015516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
329115516c77SSepherosa Ziehau 		KASSERT(freed != 0,
329215516c77SSepherosa Ziehau 		    ("fail to free txd upon send error"));
329315516c77SSepherosa Ziehau 
329415516c77SSepherosa Ziehau 		txr->hn_send_failed++;
329515516c77SSepherosa Ziehau 	}
3296dc13fee6SSepherosa Ziehau 
3297dc13fee6SSepherosa Ziehau 	/* Reset temporary stats, after this sending is done. */
3298dc13fee6SSepherosa Ziehau 	txr->hn_stat_size = 0;
3299dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts = 0;
3300dc13fee6SSepherosa Ziehau 	txr->hn_stat_mcasts = 0;
3301dc13fee6SSepherosa Ziehau 
3302dc13fee6SSepherosa Ziehau 	return (error);
330315516c77SSepherosa Ziehau }
330415516c77SSepherosa Ziehau 
330515516c77SSepherosa Ziehau /*
330615516c77SSepherosa Ziehau  * Append the specified data to the indicated mbuf chain,
330715516c77SSepherosa Ziehau  * Extend the mbuf chain if the new data does not fit in
330815516c77SSepherosa Ziehau  * existing space.
330915516c77SSepherosa Ziehau  *
331015516c77SSepherosa Ziehau  * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c.
331115516c77SSepherosa Ziehau  * There should be an equivalent in the kernel mbuf code,
331215516c77SSepherosa Ziehau  * but there does not appear to be one yet.
331315516c77SSepherosa Ziehau  *
331415516c77SSepherosa Ziehau  * Differs from m_append() in that additional mbufs are
331515516c77SSepherosa Ziehau  * allocated with cluster size MJUMPAGESIZE, and filled
331615516c77SSepherosa Ziehau  * accordingly.
331715516c77SSepherosa Ziehau  *
331815516c77SSepherosa Ziehau  * Return 1 if able to complete the job; otherwise 0.
331915516c77SSepherosa Ziehau  */
332015516c77SSepherosa Ziehau static int
332115516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp)
332215516c77SSepherosa Ziehau {
332315516c77SSepherosa Ziehau 	struct mbuf *m, *n;
332415516c77SSepherosa Ziehau 	int remainder, space;
332515516c77SSepherosa Ziehau 
332615516c77SSepherosa Ziehau 	for (m = m0; m->m_next != NULL; m = m->m_next)
332715516c77SSepherosa Ziehau 		;
332815516c77SSepherosa Ziehau 	remainder = len;
332915516c77SSepherosa Ziehau 	space = M_TRAILINGSPACE(m);
333015516c77SSepherosa Ziehau 	if (space > 0) {
333115516c77SSepherosa Ziehau 		/*
333215516c77SSepherosa Ziehau 		 * Copy into available space.
333315516c77SSepherosa Ziehau 		 */
333415516c77SSepherosa Ziehau 		if (space > remainder)
333515516c77SSepherosa Ziehau 			space = remainder;
333615516c77SSepherosa Ziehau 		bcopy(cp, mtod(m, caddr_t) + m->m_len, space);
333715516c77SSepherosa Ziehau 		m->m_len += space;
333815516c77SSepherosa Ziehau 		cp += space;
333915516c77SSepherosa Ziehau 		remainder -= space;
334015516c77SSepherosa Ziehau 	}
334115516c77SSepherosa Ziehau 	while (remainder > 0) {
334215516c77SSepherosa Ziehau 		/*
334315516c77SSepherosa Ziehau 		 * Allocate a new mbuf; could check space
334415516c77SSepherosa Ziehau 		 * and allocate a cluster instead.
334515516c77SSepherosa Ziehau 		 */
334615516c77SSepherosa Ziehau 		n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE);
334715516c77SSepherosa Ziehau 		if (n == NULL)
334815516c77SSepherosa Ziehau 			break;
334915516c77SSepherosa Ziehau 		n->m_len = min(MJUMPAGESIZE, remainder);
335015516c77SSepherosa Ziehau 		bcopy(cp, mtod(n, caddr_t), n->m_len);
335115516c77SSepherosa Ziehau 		cp += n->m_len;
335215516c77SSepherosa Ziehau 		remainder -= n->m_len;
335315516c77SSepherosa Ziehau 		m->m_next = n;
335415516c77SSepherosa Ziehau 		m = n;
335515516c77SSepherosa Ziehau 	}
335615516c77SSepherosa Ziehau 	if (m0->m_flags & M_PKTHDR)
335715516c77SSepherosa Ziehau 		m0->m_pkthdr.len += len - remainder;
335815516c77SSepherosa Ziehau 
335915516c77SSepherosa Ziehau 	return (remainder == 0);
336015516c77SSepherosa Ziehau }
336115516c77SSepherosa Ziehau 
336215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
336315516c77SSepherosa Ziehau static __inline int
336415516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m)
336515516c77SSepherosa Ziehau {
336615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
336715516c77SSepherosa Ziehau 	if (hn_lro_mbufq_depth) {
336815516c77SSepherosa Ziehau 		tcp_lro_queue_mbuf(lc, m);
336915516c77SSepherosa Ziehau 		return 0;
337015516c77SSepherosa Ziehau 	}
337115516c77SSepherosa Ziehau #endif
337215516c77SSepherosa Ziehau 	return tcp_lro_rx(lc, m, 0);
337315516c77SSepherosa Ziehau }
337415516c77SSepherosa Ziehau #endif
337515516c77SSepherosa Ziehau 
337615516c77SSepherosa Ziehau static int
337715516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
337815516c77SSepherosa Ziehau     const struct hn_rxinfo *info)
337915516c77SSepherosa Ziehau {
3380a97fff19SSepherosa Ziehau 	struct ifnet *ifp, *hn_ifp = rxr->hn_ifp;
338115516c77SSepherosa Ziehau 	struct mbuf *m_new;
3382642ec226SSepherosa Ziehau 	int size, do_lro = 0, do_csum = 1, is_vf = 0;
3383642ec226SSepherosa Ziehau 	int hash_type = M_HASHTYPE_NONE;
3384*db76829bSSepherosa Ziehau 	int l3proto = ETHERTYPE_MAX, l4proto = IPPROTO_DONE;
338515516c77SSepherosa Ziehau 
3386642ec226SSepherosa Ziehau 	ifp = hn_ifp;
3387642ec226SSepherosa Ziehau 	if (rxr->hn_rxvf_ifp != NULL) {
3388a97fff19SSepherosa Ziehau 		/*
3389642ec226SSepherosa Ziehau 		 * Non-transparent mode VF; pretend this packet is from
3390642ec226SSepherosa Ziehau 		 * the VF.
3391a97fff19SSepherosa Ziehau 		 */
3392642ec226SSepherosa Ziehau 		ifp = rxr->hn_rxvf_ifp;
3393642ec226SSepherosa Ziehau 		is_vf = 1;
3394642ec226SSepherosa Ziehau 	} else if (rxr->hn_rx_flags & HN_RX_FLAG_XPNT_VF) {
3395642ec226SSepherosa Ziehau 		/* Transparent mode VF. */
3396642ec226SSepherosa Ziehau 		is_vf = 1;
3397642ec226SSepherosa Ziehau 	}
33985bdfd3fdSDexuan Cui 
3399b3b75d9cSSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
3400b3b75d9cSSepherosa Ziehau 		/*
3401b3b75d9cSSepherosa Ziehau 		 * NOTE:
3402b3b75d9cSSepherosa Ziehau 		 * See the NOTE of hn_rndis_init_fixat().  This
3403b3b75d9cSSepherosa Ziehau 		 * function can be reached, immediately after the
3404b3b75d9cSSepherosa Ziehau 		 * RNDIS is initialized but before the ifnet is
3405b3b75d9cSSepherosa Ziehau 		 * setup on the hn_attach() path; drop the unexpected
3406b3b75d9cSSepherosa Ziehau 		 * packets.
3407b3b75d9cSSepherosa Ziehau 		 */
3408b3b75d9cSSepherosa Ziehau 		return (0);
3409b3b75d9cSSepherosa Ziehau 	}
3410b3b75d9cSSepherosa Ziehau 
3411a97fff19SSepherosa Ziehau 	if (__predict_false(dlen < ETHER_HDR_LEN)) {
3412a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IERRORS, 1);
3413a97fff19SSepherosa Ziehau 		return (0);
3414a97fff19SSepherosa Ziehau 	}
3415a97fff19SSepherosa Ziehau 
3416c927d681SDexuan Cui 	if (dlen <= MHLEN) {
341715516c77SSepherosa Ziehau 		m_new = m_gethdr(M_NOWAIT, MT_DATA);
341815516c77SSepherosa Ziehau 		if (m_new == NULL) {
3419a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1);
342015516c77SSepherosa Ziehau 			return (0);
342115516c77SSepherosa Ziehau 		}
342215516c77SSepherosa Ziehau 		memcpy(mtod(m_new, void *), data, dlen);
342315516c77SSepherosa Ziehau 		m_new->m_pkthdr.len = m_new->m_len = dlen;
342415516c77SSepherosa Ziehau 		rxr->hn_small_pkts++;
342515516c77SSepherosa Ziehau 	} else {
342615516c77SSepherosa Ziehau 		/*
342715516c77SSepherosa Ziehau 		 * Get an mbuf with a cluster.  For packets 2K or less,
342815516c77SSepherosa Ziehau 		 * get a standard 2K cluster.  For anything larger, get a
342915516c77SSepherosa Ziehau 		 * 4K cluster.  Any buffers larger than 4K can cause problems
343015516c77SSepherosa Ziehau 		 * if looped around to the Hyper-V TX channel, so avoid them.
343115516c77SSepherosa Ziehau 		 */
343215516c77SSepherosa Ziehau 		size = MCLBYTES;
343315516c77SSepherosa Ziehau 		if (dlen > MCLBYTES) {
343415516c77SSepherosa Ziehau 			/* 4096 */
343515516c77SSepherosa Ziehau 			size = MJUMPAGESIZE;
343615516c77SSepherosa Ziehau 		}
343715516c77SSepherosa Ziehau 
343815516c77SSepherosa Ziehau 		m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size);
343915516c77SSepherosa Ziehau 		if (m_new == NULL) {
3440a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1);
344115516c77SSepherosa Ziehau 			return (0);
344215516c77SSepherosa Ziehau 		}
344315516c77SSepherosa Ziehau 
344415516c77SSepherosa Ziehau 		hv_m_append(m_new, dlen, data);
344515516c77SSepherosa Ziehau 	}
344615516c77SSepherosa Ziehau 	m_new->m_pkthdr.rcvif = ifp;
344715516c77SSepherosa Ziehau 
3448a97fff19SSepherosa Ziehau 	if (__predict_false((hn_ifp->if_capenable & IFCAP_RXCSUM) == 0))
344915516c77SSepherosa Ziehau 		do_csum = 0;
345015516c77SSepherosa Ziehau 
345115516c77SSepherosa Ziehau 	/* receive side checksum offload */
345215516c77SSepherosa Ziehau 	if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) {
345315516c77SSepherosa Ziehau 		/* IP csum offload */
345415516c77SSepherosa Ziehau 		if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) {
345515516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
345615516c77SSepherosa Ziehau 			    (CSUM_IP_CHECKED | CSUM_IP_VALID);
345715516c77SSepherosa Ziehau 			rxr->hn_csum_ip++;
345815516c77SSepherosa Ziehau 		}
345915516c77SSepherosa Ziehau 
346015516c77SSepherosa Ziehau 		/* TCP/UDP csum offload */
346115516c77SSepherosa Ziehau 		if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK |
346215516c77SSepherosa Ziehau 		     NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) {
346315516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
346415516c77SSepherosa Ziehau 			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
346515516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_data = 0xffff;
346615516c77SSepherosa Ziehau 			if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK)
346715516c77SSepherosa Ziehau 				rxr->hn_csum_tcp++;
346815516c77SSepherosa Ziehau 			else
346915516c77SSepherosa Ziehau 				rxr->hn_csum_udp++;
347015516c77SSepherosa Ziehau 		}
347115516c77SSepherosa Ziehau 
347215516c77SSepherosa Ziehau 		/*
347315516c77SSepherosa Ziehau 		 * XXX
347415516c77SSepherosa Ziehau 		 * As of this write (Oct 28th, 2016), host side will turn
347515516c77SSepherosa Ziehau 		 * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so
347615516c77SSepherosa Ziehau 		 * the do_lro setting here is actually _not_ accurate.  We
347715516c77SSepherosa Ziehau 		 * depend on the RSS hash type check to reset do_lro.
347815516c77SSepherosa Ziehau 		 */
347915516c77SSepherosa Ziehau 		if ((info->csum_info &
348015516c77SSepherosa Ziehau 		     (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) ==
348115516c77SSepherosa Ziehau 		    (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK))
348215516c77SSepherosa Ziehau 			do_lro = 1;
348315516c77SSepherosa Ziehau 	} else {
3484*db76829bSSepherosa Ziehau 		hn_rxpkt_proto(m_new, &l3proto, &l4proto);
3485*db76829bSSepherosa Ziehau 		if (l3proto == ETHERTYPE_IP) {
3486*db76829bSSepherosa Ziehau 			if (l4proto == IPPROTO_TCP) {
348715516c77SSepherosa Ziehau 				if (do_csum &&
348815516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
348915516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_TCP)) {
349015516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
349115516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
349215516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
349315516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
349415516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
349515516c77SSepherosa Ziehau 				}
349615516c77SSepherosa Ziehau 				do_lro = 1;
3497*db76829bSSepherosa Ziehau 			} else if (l4proto == IPPROTO_UDP) {
349815516c77SSepherosa Ziehau 				if (do_csum &&
349915516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
350015516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_UDP)) {
350115516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
350215516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
350315516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
350415516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
350515516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
350615516c77SSepherosa Ziehau 				}
3507*db76829bSSepherosa Ziehau 			} else if (l4proto != IPPROTO_DONE && do_csum &&
350815516c77SSepherosa Ziehau 			    (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) {
350915516c77SSepherosa Ziehau 				rxr->hn_csum_trusted++;
351015516c77SSepherosa Ziehau 				m_new->m_pkthdr.csum_flags |=
351115516c77SSepherosa Ziehau 				    (CSUM_IP_CHECKED | CSUM_IP_VALID);
351215516c77SSepherosa Ziehau 			}
351315516c77SSepherosa Ziehau 		}
351415516c77SSepherosa Ziehau 	}
3515*db76829bSSepherosa Ziehau 
351615516c77SSepherosa Ziehau 	if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) {
351715516c77SSepherosa Ziehau 		m_new->m_pkthdr.ether_vtag = EVL_MAKETAG(
351815516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_ID(info->vlan_info),
351915516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_PRI(info->vlan_info),
352015516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_CFI(info->vlan_info));
352115516c77SSepherosa Ziehau 		m_new->m_flags |= M_VLANTAG;
352215516c77SSepherosa Ziehau 	}
352315516c77SSepherosa Ziehau 
3524a97fff19SSepherosa Ziehau 	/*
3525a97fff19SSepherosa Ziehau 	 * If VF is activated (tranparent/non-transparent mode does not
3526a97fff19SSepherosa Ziehau 	 * matter here).
3527a97fff19SSepherosa Ziehau 	 *
3528a97fff19SSepherosa Ziehau 	 * - Disable LRO
3529a97fff19SSepherosa Ziehau 	 *
3530a97fff19SSepherosa Ziehau 	 *   hn(4) will only receive broadcast packets, multicast packets,
3531a97fff19SSepherosa Ziehau 	 *   TCP SYN and SYN|ACK (in Azure), LRO is useless for these
3532a97fff19SSepherosa Ziehau 	 *   packet types.
3533a97fff19SSepherosa Ziehau 	 *
3534a97fff19SSepherosa Ziehau 	 *   For non-transparent, we definitely _cannot_ enable LRO at
3535a97fff19SSepherosa Ziehau 	 *   all, since the LRO flush will use hn(4) as the receiving
3536a97fff19SSepherosa Ziehau 	 *   interface; i.e. hn_ifp->if_input(hn_ifp, m).
3537a97fff19SSepherosa Ziehau 	 */
3538642ec226SSepherosa Ziehau 	if (is_vf)
3539642ec226SSepherosa Ziehau 		do_lro = 0;
3540a97fff19SSepherosa Ziehau 
3541642ec226SSepherosa Ziehau 	/*
3542642ec226SSepherosa Ziehau 	 * If VF is activated (tranparent/non-transparent mode does not
3543642ec226SSepherosa Ziehau 	 * matter here), do _not_ mess with unsupported hash types or
3544642ec226SSepherosa Ziehau 	 * functions.
3545642ec226SSepherosa Ziehau 	 */
354615516c77SSepherosa Ziehau 	if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) {
354715516c77SSepherosa Ziehau 		rxr->hn_rss_pkts++;
354815516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = info->hash_value;
3549642ec226SSepherosa Ziehau 		if (!is_vf)
355015516c77SSepherosa Ziehau 			hash_type = M_HASHTYPE_OPAQUE_HASH;
355115516c77SSepherosa Ziehau 		if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) ==
355215516c77SSepherosa Ziehau 		    NDIS_HASH_FUNCTION_TOEPLITZ) {
3553642ec226SSepherosa Ziehau 			uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK &
3554642ec226SSepherosa Ziehau 			    rxr->hn_mbuf_hash);
355515516c77SSepherosa Ziehau 
355615516c77SSepherosa Ziehau 			/*
355715516c77SSepherosa Ziehau 			 * NOTE:
355815516c77SSepherosa Ziehau 			 * do_lro is resetted, if the hash types are not TCP
355915516c77SSepherosa Ziehau 			 * related.  See the comment in the above csum_flags
356015516c77SSepherosa Ziehau 			 * setup section.
356115516c77SSepherosa Ziehau 			 */
356215516c77SSepherosa Ziehau 			switch (type) {
356315516c77SSepherosa Ziehau 			case NDIS_HASH_IPV4:
356415516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV4;
356515516c77SSepherosa Ziehau 				do_lro = 0;
356615516c77SSepherosa Ziehau 				break;
356715516c77SSepherosa Ziehau 
356815516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV4:
356915516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV4;
3570*db76829bSSepherosa Ziehau 				if (rxr->hn_rx_flags & HN_RX_FLAG_UDP_HASH) {
3571*db76829bSSepherosa Ziehau 					int def_htype = M_HASHTYPE_OPAQUE_HASH;
3572*db76829bSSepherosa Ziehau 
3573*db76829bSSepherosa Ziehau 					if (is_vf)
3574*db76829bSSepherosa Ziehau 						def_htype = M_HASHTYPE_NONE;
3575*db76829bSSepherosa Ziehau 
3576*db76829bSSepherosa Ziehau 					/*
3577*db76829bSSepherosa Ziehau 					 * UDP 4-tuple hash is delivered as
3578*db76829bSSepherosa Ziehau 					 * TCP 4-tuple hash.
3579*db76829bSSepherosa Ziehau 					 */
3580*db76829bSSepherosa Ziehau 					if (l3proto == ETHERTYPE_MAX) {
3581*db76829bSSepherosa Ziehau 						hn_rxpkt_proto(m_new,
3582*db76829bSSepherosa Ziehau 						    &l3proto, &l4proto);
3583*db76829bSSepherosa Ziehau 					}
3584*db76829bSSepherosa Ziehau 					if (l3proto == ETHERTYPE_IP) {
3585*db76829bSSepherosa Ziehau 						if (l4proto == IPPROTO_UDP) {
3586*db76829bSSepherosa Ziehau 							hash_type =
3587*db76829bSSepherosa Ziehau 							M_HASHTYPE_RSS_UDP_IPV4;
3588*db76829bSSepherosa Ziehau 							do_lro = 0;
3589*db76829bSSepherosa Ziehau 						} else if (l4proto !=
3590*db76829bSSepherosa Ziehau 						    IPPROTO_TCP) {
3591*db76829bSSepherosa Ziehau 							hash_type = def_htype;
3592*db76829bSSepherosa Ziehau 							do_lro = 0;
3593*db76829bSSepherosa Ziehau 						}
3594*db76829bSSepherosa Ziehau 					} else {
3595*db76829bSSepherosa Ziehau 						hash_type = def_htype;
3596*db76829bSSepherosa Ziehau 						do_lro = 0;
3597*db76829bSSepherosa Ziehau 					}
3598*db76829bSSepherosa Ziehau 				}
359915516c77SSepherosa Ziehau 				break;
360015516c77SSepherosa Ziehau 
360115516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6:
360215516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6;
360315516c77SSepherosa Ziehau 				do_lro = 0;
360415516c77SSepherosa Ziehau 				break;
360515516c77SSepherosa Ziehau 
360615516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6_EX:
360715516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6_EX;
360815516c77SSepherosa Ziehau 				do_lro = 0;
360915516c77SSepherosa Ziehau 				break;
361015516c77SSepherosa Ziehau 
361115516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6:
361215516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6;
361315516c77SSepherosa Ziehau 				break;
361415516c77SSepherosa Ziehau 
361515516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6_EX:
361615516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX;
361715516c77SSepherosa Ziehau 				break;
361815516c77SSepherosa Ziehau 			}
361915516c77SSepherosa Ziehau 		}
3620642ec226SSepherosa Ziehau 	} else if (!is_vf) {
362115516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
362215516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE;
362315516c77SSepherosa Ziehau 	}
362415516c77SSepherosa Ziehau 	M_HASHTYPE_SET(m_new, hash_type);
362515516c77SSepherosa Ziehau 
3626a97fff19SSepherosa Ziehau 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
3627a97fff19SSepherosa Ziehau 	if (hn_ifp != ifp) {
3628a97fff19SSepherosa Ziehau 		const struct ether_header *eh;
3629a97fff19SSepherosa Ziehau 
363015516c77SSepherosa Ziehau 		/*
3631a97fff19SSepherosa Ziehau 		 * Non-transparent mode VF is activated.
363215516c77SSepherosa Ziehau 		 */
363315516c77SSepherosa Ziehau 
3634a97fff19SSepherosa Ziehau 		/*
3635a97fff19SSepherosa Ziehau 		 * Allow tapping on hn(4).
3636a97fff19SSepherosa Ziehau 		 */
3637a97fff19SSepherosa Ziehau 		ETHER_BPF_MTAP(hn_ifp, m_new);
3638a97fff19SSepherosa Ziehau 
3639a97fff19SSepherosa Ziehau 		/*
3640a97fff19SSepherosa Ziehau 		 * Update hn(4)'s stats.
3641a97fff19SSepherosa Ziehau 		 */
3642a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1);
3643a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IBYTES, m_new->m_pkthdr.len);
3644a97fff19SSepherosa Ziehau 		/* Checked at the beginning of this function. */
3645a97fff19SSepherosa Ziehau 		KASSERT(m_new->m_len >= ETHER_HDR_LEN, ("not ethernet frame"));
3646a97fff19SSepherosa Ziehau 		eh = mtod(m_new, struct ether_header *);
3647a97fff19SSepherosa Ziehau 		if (ETHER_IS_MULTICAST(eh->ether_dhost))
3648a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IMCASTS, 1);
3649a97fff19SSepherosa Ziehau 	}
365015516c77SSepherosa Ziehau 	rxr->hn_pkts++;
365115516c77SSepherosa Ziehau 
3652a97fff19SSepherosa Ziehau 	if ((hn_ifp->if_capenable & IFCAP_LRO) && do_lro) {
365315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
365415516c77SSepherosa Ziehau 		struct lro_ctrl *lro = &rxr->hn_lro;
365515516c77SSepherosa Ziehau 
365615516c77SSepherosa Ziehau 		if (lro->lro_cnt) {
365715516c77SSepherosa Ziehau 			rxr->hn_lro_tried++;
365815516c77SSepherosa Ziehau 			if (hn_lro_rx(lro, m_new) == 0) {
365915516c77SSepherosa Ziehau 				/* DONE! */
366015516c77SSepherosa Ziehau 				return 0;
366115516c77SSepherosa Ziehau 			}
366215516c77SSepherosa Ziehau 		}
366315516c77SSepherosa Ziehau #endif
366415516c77SSepherosa Ziehau 	}
3665a97fff19SSepherosa Ziehau 	ifp->if_input(ifp, m_new);
366615516c77SSepherosa Ziehau 
366715516c77SSepherosa Ziehau 	return (0);
366815516c77SSepherosa Ziehau }
366915516c77SSepherosa Ziehau 
367015516c77SSepherosa Ziehau static int
367115516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
367215516c77SSepherosa Ziehau {
367315516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
36749c6cae24SSepherosa Ziehau 	struct ifreq *ifr = (struct ifreq *)data, ifr_vf;
36759c6cae24SSepherosa Ziehau 	struct ifnet *vf_ifp;
367615516c77SSepherosa Ziehau 	int mask, error = 0;
36778c068aa5SSepherosa Ziehau 	struct ifrsskey *ifrk;
36788c068aa5SSepherosa Ziehau 	struct ifrsshash *ifrh;
3679eb2fe044SSepherosa Ziehau 	uint32_t mtu;
368015516c77SSepherosa Ziehau 
368115516c77SSepherosa Ziehau 	switch (cmd) {
368215516c77SSepherosa Ziehau 	case SIOCSIFMTU:
368315516c77SSepherosa Ziehau 		if (ifr->ifr_mtu > HN_MTU_MAX) {
368415516c77SSepherosa Ziehau 			error = EINVAL;
368515516c77SSepherosa Ziehau 			break;
368615516c77SSepherosa Ziehau 		}
368715516c77SSepherosa Ziehau 
368815516c77SSepherosa Ziehau 		HN_LOCK(sc);
368915516c77SSepherosa Ziehau 
369015516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
369115516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
369215516c77SSepherosa Ziehau 			break;
369315516c77SSepherosa Ziehau 		}
369415516c77SSepherosa Ziehau 
369515516c77SSepherosa Ziehau 		if ((sc->hn_caps & HN_CAP_MTU) == 0) {
369615516c77SSepherosa Ziehau 			/* Can't change MTU */
369715516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
369815516c77SSepherosa Ziehau 			error = EOPNOTSUPP;
369915516c77SSepherosa Ziehau 			break;
370015516c77SSepherosa Ziehau 		}
370115516c77SSepherosa Ziehau 
370215516c77SSepherosa Ziehau 		if (ifp->if_mtu == ifr->ifr_mtu) {
370315516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
370415516c77SSepherosa Ziehau 			break;
370515516c77SSepherosa Ziehau 		}
370615516c77SSepherosa Ziehau 
37079c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
37089c6cae24SSepherosa Ziehau 			vf_ifp = sc->hn_vf_ifp;
37099c6cae24SSepherosa Ziehau 			ifr_vf = *ifr;
37109c6cae24SSepherosa Ziehau 			strlcpy(ifr_vf.ifr_name, vf_ifp->if_xname,
37119c6cae24SSepherosa Ziehau 			    sizeof(ifr_vf.ifr_name));
37129c6cae24SSepherosa Ziehau 			error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU,
37139c6cae24SSepherosa Ziehau 			    (caddr_t)&ifr_vf);
37149c6cae24SSepherosa Ziehau 			if (error) {
37159c6cae24SSepherosa Ziehau 				HN_UNLOCK(sc);
37169c6cae24SSepherosa Ziehau 				if_printf(ifp, "%s SIOCSIFMTU %d failed: %d\n",
37179c6cae24SSepherosa Ziehau 				    vf_ifp->if_xname, ifr->ifr_mtu, error);
37189c6cae24SSepherosa Ziehau 				break;
37199c6cae24SSepherosa Ziehau 			}
37209c6cae24SSepherosa Ziehau 		}
37219c6cae24SSepherosa Ziehau 
372215516c77SSepherosa Ziehau 		/*
372315516c77SSepherosa Ziehau 		 * Suspend this interface before the synthetic parts
372415516c77SSepherosa Ziehau 		 * are ripped.
372515516c77SSepherosa Ziehau 		 */
372615516c77SSepherosa Ziehau 		hn_suspend(sc);
372715516c77SSepherosa Ziehau 
372815516c77SSepherosa Ziehau 		/*
372915516c77SSepherosa Ziehau 		 * Detach the synthetics parts, i.e. NVS and RNDIS.
373015516c77SSepherosa Ziehau 		 */
373115516c77SSepherosa Ziehau 		hn_synth_detach(sc);
373215516c77SSepherosa Ziehau 
373315516c77SSepherosa Ziehau 		/*
373415516c77SSepherosa Ziehau 		 * Reattach the synthetic parts, i.e. NVS and RNDIS,
373515516c77SSepherosa Ziehau 		 * with the new MTU setting.
373615516c77SSepherosa Ziehau 		 */
373715516c77SSepherosa Ziehau 		error = hn_synth_attach(sc, ifr->ifr_mtu);
373815516c77SSepherosa Ziehau 		if (error) {
373915516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
374015516c77SSepherosa Ziehau 			break;
374115516c77SSepherosa Ziehau 		}
374215516c77SSepherosa Ziehau 
3743eb2fe044SSepherosa Ziehau 		error = hn_rndis_get_mtu(sc, &mtu);
3744eb2fe044SSepherosa Ziehau 		if (error)
3745eb2fe044SSepherosa Ziehau 			mtu = ifr->ifr_mtu;
3746eb2fe044SSepherosa Ziehau 		else if (bootverbose)
3747eb2fe044SSepherosa Ziehau 			if_printf(ifp, "RNDIS mtu %u\n", mtu);
3748eb2fe044SSepherosa Ziehau 
374915516c77SSepherosa Ziehau 		/*
375015516c77SSepherosa Ziehau 		 * Commit the requested MTU, after the synthetic parts
375115516c77SSepherosa Ziehau 		 * have been successfully attached.
375215516c77SSepherosa Ziehau 		 */
3753eb2fe044SSepherosa Ziehau 		if (mtu >= ifr->ifr_mtu) {
3754eb2fe044SSepherosa Ziehau 			mtu = ifr->ifr_mtu;
3755eb2fe044SSepherosa Ziehau 		} else {
3756eb2fe044SSepherosa Ziehau 			if_printf(ifp, "fixup mtu %d -> %u\n",
3757eb2fe044SSepherosa Ziehau 			    ifr->ifr_mtu, mtu);
3758eb2fe044SSepherosa Ziehau 		}
3759eb2fe044SSepherosa Ziehau 		ifp->if_mtu = mtu;
376015516c77SSepherosa Ziehau 
376115516c77SSepherosa Ziehau 		/*
37629c6cae24SSepherosa Ziehau 		 * Synthetic parts' reattach may change the chimney
37639c6cae24SSepherosa Ziehau 		 * sending size; update it.
376415516c77SSepherosa Ziehau 		 */
376515516c77SSepherosa Ziehau 		if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax)
376615516c77SSepherosa Ziehau 			hn_set_chim_size(sc, sc->hn_chim_szmax);
37679c6cae24SSepherosa Ziehau 
37689c6cae24SSepherosa Ziehau 		/*
37699c6cae24SSepherosa Ziehau 		 * Make sure that various parameters based on MTU are
37709c6cae24SSepherosa Ziehau 		 * still valid, after the MTU change.
37719c6cae24SSepherosa Ziehau 		 */
37729c6cae24SSepherosa Ziehau 		hn_mtu_change_fixup(sc);
377315516c77SSepherosa Ziehau 
377415516c77SSepherosa Ziehau 		/*
377515516c77SSepherosa Ziehau 		 * All done!  Resume the interface now.
377615516c77SSepherosa Ziehau 		 */
377715516c77SSepherosa Ziehau 		hn_resume(sc);
377815516c77SSepherosa Ziehau 
3779d0cd8231SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXVF) ||
3780d0cd8231SSepherosa Ziehau 		    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
37819c6cae24SSepherosa Ziehau 			/*
37829c6cae24SSepherosa Ziehau 			 * Since we have reattached the NVS part,
37839c6cae24SSepherosa Ziehau 			 * change the datapath to VF again; in case
37849c6cae24SSepherosa Ziehau 			 * that it is lost, after the NVS was detached.
37859c6cae24SSepherosa Ziehau 			 */
37869c6cae24SSepherosa Ziehau 			hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF);
37879c6cae24SSepherosa Ziehau 		}
37889c6cae24SSepherosa Ziehau 
378915516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
379015516c77SSepherosa Ziehau 		break;
379115516c77SSepherosa Ziehau 
379215516c77SSepherosa Ziehau 	case SIOCSIFFLAGS:
379315516c77SSepherosa Ziehau 		HN_LOCK(sc);
379415516c77SSepherosa Ziehau 
379515516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
379615516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
379715516c77SSepherosa Ziehau 			break;
379815516c77SSepherosa Ziehau 		}
379915516c77SSepherosa Ziehau 
38009c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc))
38019c6cae24SSepherosa Ziehau 			hn_xpnt_vf_saveifflags(sc);
38029c6cae24SSepherosa Ziehau 
380315516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_UP) {
3804fdc4f478SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
3805fdc4f478SSepherosa Ziehau 				/*
3806fdc4f478SSepherosa Ziehau 				 * Caller meight hold mutex, e.g.
3807fdc4f478SSepherosa Ziehau 				 * bpf; use busy-wait for the RNDIS
3808fdc4f478SSepherosa Ziehau 				 * reply.
3809fdc4f478SSepherosa Ziehau 				 */
3810fdc4f478SSepherosa Ziehau 				HN_NO_SLEEPING(sc);
3811c08f7b2cSSepherosa Ziehau 				hn_rxfilter_config(sc);
3812fdc4f478SSepherosa Ziehau 				HN_SLEEPING_OK(sc);
38139c6cae24SSepherosa Ziehau 
38149c6cae24SSepherosa Ziehau 				if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
38159c6cae24SSepherosa Ziehau 					error = hn_xpnt_vf_iocsetflags(sc);
3816fdc4f478SSepherosa Ziehau 			} else {
381715516c77SSepherosa Ziehau 				hn_init_locked(sc);
3818fdc4f478SSepherosa Ziehau 			}
381915516c77SSepherosa Ziehau 		} else {
382015516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
38215bdfd3fdSDexuan Cui 				hn_stop(sc, false);
382215516c77SSepherosa Ziehau 		}
382315516c77SSepherosa Ziehau 		sc->hn_if_flags = ifp->if_flags;
382415516c77SSepherosa Ziehau 
382515516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
382615516c77SSepherosa Ziehau 		break;
382715516c77SSepherosa Ziehau 
382815516c77SSepherosa Ziehau 	case SIOCSIFCAP:
382915516c77SSepherosa Ziehau 		HN_LOCK(sc);
38309c6cae24SSepherosa Ziehau 
38319c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
38329c6cae24SSepherosa Ziehau 			ifr_vf = *ifr;
38339c6cae24SSepherosa Ziehau 			strlcpy(ifr_vf.ifr_name, sc->hn_vf_ifp->if_xname,
38349c6cae24SSepherosa Ziehau 			    sizeof(ifr_vf.ifr_name));
38359c6cae24SSepherosa Ziehau 			error = hn_xpnt_vf_iocsetcaps(sc, &ifr_vf);
38369c6cae24SSepherosa Ziehau 			HN_UNLOCK(sc);
38379c6cae24SSepherosa Ziehau 			break;
38389c6cae24SSepherosa Ziehau 		}
38399c6cae24SSepherosa Ziehau 
38409c6cae24SSepherosa Ziehau 		/*
38419c6cae24SSepherosa Ziehau 		 * Fix up requested capabilities w/ supported capabilities,
38429c6cae24SSepherosa Ziehau 		 * since the supported capabilities could have been changed.
38439c6cae24SSepherosa Ziehau 		 */
38449c6cae24SSepherosa Ziehau 		mask = (ifr->ifr_reqcap & ifp->if_capabilities) ^
38459c6cae24SSepherosa Ziehau 		    ifp->if_capenable;
384615516c77SSepherosa Ziehau 
384715516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM) {
384815516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM;
384915516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM)
385015516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc);
385115516c77SSepherosa Ziehau 			else
385215516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc);
385315516c77SSepherosa Ziehau 		}
385415516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM_IPV6) {
385515516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
385615516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
385715516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc);
385815516c77SSepherosa Ziehau 			else
385915516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc);
386015516c77SSepherosa Ziehau 		}
386115516c77SSepherosa Ziehau 
386215516c77SSepherosa Ziehau 		/* TODO: flip RNDIS offload parameters for RXCSUM. */
386315516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM)
386415516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM;
386515516c77SSepherosa Ziehau #ifdef foo
386615516c77SSepherosa Ziehau 		/* We can't diff IPv6 packets from IPv4 packets on RX path. */
386715516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM_IPV6)
386815516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
386915516c77SSepherosa Ziehau #endif
387015516c77SSepherosa Ziehau 
387115516c77SSepherosa Ziehau 		if (mask & IFCAP_LRO)
387215516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_LRO;
387315516c77SSepherosa Ziehau 
387415516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO4) {
387515516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO4;
387615516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO4)
387715516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP_TSO;
387815516c77SSepherosa Ziehau 			else
387915516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP_TSO;
388015516c77SSepherosa Ziehau 		}
388115516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO6) {
388215516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO6;
388315516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO6)
388415516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP6_TSO;
388515516c77SSepherosa Ziehau 			else
388615516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP6_TSO;
388715516c77SSepherosa Ziehau 		}
388815516c77SSepherosa Ziehau 
388915516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
389015516c77SSepherosa Ziehau 		break;
389115516c77SSepherosa Ziehau 
389215516c77SSepherosa Ziehau 	case SIOCADDMULTI:
389315516c77SSepherosa Ziehau 	case SIOCDELMULTI:
389415516c77SSepherosa Ziehau 		HN_LOCK(sc);
389515516c77SSepherosa Ziehau 
389615516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
389715516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
389815516c77SSepherosa Ziehau 			break;
389915516c77SSepherosa Ziehau 		}
3900fdc4f478SSepherosa Ziehau 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
3901fdc4f478SSepherosa Ziehau 			/*
3902fdc4f478SSepherosa Ziehau 			 * Multicast uses mutex; use busy-wait for
3903fdc4f478SSepherosa Ziehau 			 * the RNDIS reply.
3904fdc4f478SSepherosa Ziehau 			 */
3905fdc4f478SSepherosa Ziehau 			HN_NO_SLEEPING(sc);
3906c08f7b2cSSepherosa Ziehau 			hn_rxfilter_config(sc);
3907fdc4f478SSepherosa Ziehau 			HN_SLEEPING_OK(sc);
3908fdc4f478SSepherosa Ziehau 		}
390915516c77SSepherosa Ziehau 
39109c6cae24SSepherosa Ziehau 		/* XXX vlan(4) style mcast addr maintenance */
39119c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
39129c6cae24SSepherosa Ziehau 			int old_if_flags;
39139c6cae24SSepherosa Ziehau 
39149c6cae24SSepherosa Ziehau 			old_if_flags = sc->hn_vf_ifp->if_flags;
39159c6cae24SSepherosa Ziehau 			hn_xpnt_vf_saveifflags(sc);
39169c6cae24SSepherosa Ziehau 
39179c6cae24SSepherosa Ziehau 			if ((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) &&
39189c6cae24SSepherosa Ziehau 			    ((old_if_flags ^ sc->hn_vf_ifp->if_flags) &
39199c6cae24SSepherosa Ziehau 			     IFF_ALLMULTI))
39209c6cae24SSepherosa Ziehau 				error = hn_xpnt_vf_iocsetflags(sc);
39219c6cae24SSepherosa Ziehau 		}
39229c6cae24SSepherosa Ziehau 
392315516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
392415516c77SSepherosa Ziehau 		break;
392515516c77SSepherosa Ziehau 
392615516c77SSepherosa Ziehau 	case SIOCSIFMEDIA:
392715516c77SSepherosa Ziehau 	case SIOCGIFMEDIA:
39289c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
39299c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
39309c6cae24SSepherosa Ziehau 			/*
39319c6cae24SSepherosa Ziehau 			 * SIOCGIFMEDIA expects ifmediareq, so don't
39329c6cae24SSepherosa Ziehau 			 * create and pass ifr_vf to the VF here; just
39339c6cae24SSepherosa Ziehau 			 * replace the ifr_name.
39349c6cae24SSepherosa Ziehau 			 */
39359c6cae24SSepherosa Ziehau 			vf_ifp = sc->hn_vf_ifp;
39369c6cae24SSepherosa Ziehau 			strlcpy(ifr->ifr_name, vf_ifp->if_xname,
39379c6cae24SSepherosa Ziehau 			    sizeof(ifr->ifr_name));
39389c6cae24SSepherosa Ziehau 			error = vf_ifp->if_ioctl(vf_ifp, cmd, data);
39399c6cae24SSepherosa Ziehau 			/* Restore the ifr_name. */
39409c6cae24SSepherosa Ziehau 			strlcpy(ifr->ifr_name, ifp->if_xname,
39419c6cae24SSepherosa Ziehau 			    sizeof(ifr->ifr_name));
39429c6cae24SSepherosa Ziehau 			HN_UNLOCK(sc);
39439c6cae24SSepherosa Ziehau 			break;
39449c6cae24SSepherosa Ziehau 		}
39459c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
394615516c77SSepherosa Ziehau 		error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd);
394715516c77SSepherosa Ziehau 		break;
394815516c77SSepherosa Ziehau 
39498c068aa5SSepherosa Ziehau 	case SIOCGIFRSSHASH:
39508c068aa5SSepherosa Ziehau 		ifrh = (struct ifrsshash *)data;
39518c068aa5SSepherosa Ziehau 		HN_LOCK(sc);
39528c068aa5SSepherosa Ziehau 		if (sc->hn_rx_ring_inuse == 1) {
39538c068aa5SSepherosa Ziehau 			HN_UNLOCK(sc);
39548c068aa5SSepherosa Ziehau 			ifrh->ifrh_func = RSS_FUNC_NONE;
39558c068aa5SSepherosa Ziehau 			ifrh->ifrh_types = 0;
39568c068aa5SSepherosa Ziehau 			break;
39578c068aa5SSepherosa Ziehau 		}
39588c068aa5SSepherosa Ziehau 
39598c068aa5SSepherosa Ziehau 		if (sc->hn_rss_hash & NDIS_HASH_FUNCTION_TOEPLITZ)
39608c068aa5SSepherosa Ziehau 			ifrh->ifrh_func = RSS_FUNC_TOEPLITZ;
39618c068aa5SSepherosa Ziehau 		else
39628c068aa5SSepherosa Ziehau 			ifrh->ifrh_func = RSS_FUNC_PRIVATE;
3963642ec226SSepherosa Ziehau 		ifrh->ifrh_types = hn_rss_type_fromndis(sc->hn_rss_hash);
39648c068aa5SSepherosa Ziehau 		HN_UNLOCK(sc);
39658c068aa5SSepherosa Ziehau 		break;
39668c068aa5SSepherosa Ziehau 
39678c068aa5SSepherosa Ziehau 	case SIOCGIFRSSKEY:
39688c068aa5SSepherosa Ziehau 		ifrk = (struct ifrsskey *)data;
39698c068aa5SSepherosa Ziehau 		HN_LOCK(sc);
39708c068aa5SSepherosa Ziehau 		if (sc->hn_rx_ring_inuse == 1) {
39718c068aa5SSepherosa Ziehau 			HN_UNLOCK(sc);
39728c068aa5SSepherosa Ziehau 			ifrk->ifrk_func = RSS_FUNC_NONE;
39738c068aa5SSepherosa Ziehau 			ifrk->ifrk_keylen = 0;
39748c068aa5SSepherosa Ziehau 			break;
39758c068aa5SSepherosa Ziehau 		}
39768c068aa5SSepherosa Ziehau 		if (sc->hn_rss_hash & NDIS_HASH_FUNCTION_TOEPLITZ)
39778c068aa5SSepherosa Ziehau 			ifrk->ifrk_func = RSS_FUNC_TOEPLITZ;
39788c068aa5SSepherosa Ziehau 		else
39798c068aa5SSepherosa Ziehau 			ifrk->ifrk_func = RSS_FUNC_PRIVATE;
39808c068aa5SSepherosa Ziehau 		ifrk->ifrk_keylen = NDIS_HASH_KEYSIZE_TOEPLITZ;
39818c068aa5SSepherosa Ziehau 		memcpy(ifrk->ifrk_key, sc->hn_rss.rss_key,
39828c068aa5SSepherosa Ziehau 		    NDIS_HASH_KEYSIZE_TOEPLITZ);
39838c068aa5SSepherosa Ziehau 		HN_UNLOCK(sc);
39848c068aa5SSepherosa Ziehau 		break;
39858c068aa5SSepherosa Ziehau 
398615516c77SSepherosa Ziehau 	default:
398715516c77SSepherosa Ziehau 		error = ether_ioctl(ifp, cmd, data);
398815516c77SSepherosa Ziehau 		break;
398915516c77SSepherosa Ziehau 	}
399015516c77SSepherosa Ziehau 	return (error);
399115516c77SSepherosa Ziehau }
399215516c77SSepherosa Ziehau 
399315516c77SSepherosa Ziehau static void
39945bdfd3fdSDexuan Cui hn_stop(struct hn_softc *sc, bool detaching)
399515516c77SSepherosa Ziehau {
399615516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
399715516c77SSepherosa Ziehau 	int i;
399815516c77SSepherosa Ziehau 
399915516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
400015516c77SSepherosa Ziehau 
400115516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
400215516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
400315516c77SSepherosa Ziehau 
40049c6cae24SSepherosa Ziehau 	/* Clear RUNNING bit ASAP. */
40059c6cae24SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
40069c6cae24SSepherosa Ziehau 
40076c1204dfSSepherosa Ziehau 	/* Disable polling. */
40086c1204dfSSepherosa Ziehau 	hn_polling(sc, 0);
40096c1204dfSSepherosa Ziehau 
40109c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) {
40119c6cae24SSepherosa Ziehau 		KASSERT(sc->hn_vf_ifp != NULL,
40129c6cae24SSepherosa Ziehau 		    ("%s: VF is not attached", ifp->if_xname));
40139c6cae24SSepherosa Ziehau 
4014a97fff19SSepherosa Ziehau 		/* Mark transparent mode VF as disabled. */
4015a97fff19SSepherosa Ziehau 		hn_xpnt_vf_setdisable(sc, false /* keep hn_vf_ifp */);
40169c6cae24SSepherosa Ziehau 
40179c6cae24SSepherosa Ziehau 		/*
40189c6cae24SSepherosa Ziehau 		 * NOTE:
40199c6cae24SSepherosa Ziehau 		 * Datapath setting must happen _before_ bringing
40209c6cae24SSepherosa Ziehau 		 * the VF down.
40219c6cae24SSepherosa Ziehau 		 */
40229c6cae24SSepherosa Ziehau 		hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH);
40239c6cae24SSepherosa Ziehau 
40249c6cae24SSepherosa Ziehau 		/*
40259c6cae24SSepherosa Ziehau 		 * Bring the VF down.
40269c6cae24SSepherosa Ziehau 		 */
40279c6cae24SSepherosa Ziehau 		hn_xpnt_vf_saveifflags(sc);
40289c6cae24SSepherosa Ziehau 		sc->hn_vf_ifp->if_flags &= ~IFF_UP;
40299c6cae24SSepherosa Ziehau 		hn_xpnt_vf_iocsetflags(sc);
40309c6cae24SSepherosa Ziehau 	}
40319c6cae24SSepherosa Ziehau 
40329c6cae24SSepherosa Ziehau 	/* Suspend data transfers. */
403315516c77SSepherosa Ziehau 	hn_suspend_data(sc);
403415516c77SSepherosa Ziehau 
403515516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
403615516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
403715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
403815516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
40395bdfd3fdSDexuan Cui 
40405bdfd3fdSDexuan Cui 	/*
40419c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is active, make sure
40429c6cae24SSepherosa Ziehau 	 * that the RX filter still allows packet reception.
40435bdfd3fdSDexuan Cui 	 */
4044962f0357SSepherosa Ziehau 	if (!detaching && (sc->hn_flags & HN_FLAG_RXVF))
40455bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
404615516c77SSepherosa Ziehau }
404715516c77SSepherosa Ziehau 
404815516c77SSepherosa Ziehau static void
404915516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc)
405015516c77SSepherosa Ziehau {
405115516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
405215516c77SSepherosa Ziehau 	int i;
405315516c77SSepherosa Ziehau 
405415516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
405515516c77SSepherosa Ziehau 
405615516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
405715516c77SSepherosa Ziehau 		return;
405815516c77SSepherosa Ziehau 
405915516c77SSepherosa Ziehau 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
406015516c77SSepherosa Ziehau 		return;
406115516c77SSepherosa Ziehau 
406215516c77SSepherosa Ziehau 	/* Configure RX filter */
4063c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
406415516c77SSepherosa Ziehau 
406515516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
406615516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
406715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
406815516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
406915516c77SSepherosa Ziehau 
407015516c77SSepherosa Ziehau 	/* Clear TX 'suspended' bit. */
407115516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_inuse);
407215516c77SSepherosa Ziehau 
40739c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_isready(sc)) {
40749c6cae24SSepherosa Ziehau 		/* Initialize transparent VF. */
40759c6cae24SSepherosa Ziehau 		hn_xpnt_vf_init(sc);
40769c6cae24SSepherosa Ziehau 	}
40779c6cae24SSepherosa Ziehau 
407815516c77SSepherosa Ziehau 	/* Everything is ready; unleash! */
407915516c77SSepherosa Ziehau 	atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
40806c1204dfSSepherosa Ziehau 
40816c1204dfSSepherosa Ziehau 	/* Re-enable polling if requested. */
40826c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz > 0)
40836c1204dfSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
408415516c77SSepherosa Ziehau }
408515516c77SSepherosa Ziehau 
408615516c77SSepherosa Ziehau static void
408715516c77SSepherosa Ziehau hn_init(void *xsc)
408815516c77SSepherosa Ziehau {
408915516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
409015516c77SSepherosa Ziehau 
409115516c77SSepherosa Ziehau 	HN_LOCK(sc);
409215516c77SSepherosa Ziehau 	hn_init_locked(sc);
409315516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
409415516c77SSepherosa Ziehau }
409515516c77SSepherosa Ziehau 
409615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
409715516c77SSepherosa Ziehau 
409815516c77SSepherosa Ziehau static int
409915516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
410015516c77SSepherosa Ziehau {
410115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
410215516c77SSepherosa Ziehau 	unsigned int lenlim;
410315516c77SSepherosa Ziehau 	int error;
410415516c77SSepherosa Ziehau 
410515516c77SSepherosa Ziehau 	lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim;
410615516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &lenlim, 0, req);
410715516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
410815516c77SSepherosa Ziehau 		return error;
410915516c77SSepherosa Ziehau 
411015516c77SSepherosa Ziehau 	HN_LOCK(sc);
411115516c77SSepherosa Ziehau 	if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) ||
411215516c77SSepherosa Ziehau 	    lenlim > TCP_LRO_LENGTH_MAX) {
411315516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
411415516c77SSepherosa Ziehau 		return EINVAL;
411515516c77SSepherosa Ziehau 	}
411615516c77SSepherosa Ziehau 	hn_set_lro_lenlim(sc, lenlim);
411715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
411815516c77SSepherosa Ziehau 
411915516c77SSepherosa Ziehau 	return 0;
412015516c77SSepherosa Ziehau }
412115516c77SSepherosa Ziehau 
412215516c77SSepherosa Ziehau static int
412315516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS)
412415516c77SSepherosa Ziehau {
412515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
412615516c77SSepherosa Ziehau 	int ackcnt, error, i;
412715516c77SSepherosa Ziehau 
412815516c77SSepherosa Ziehau 	/*
412915516c77SSepherosa Ziehau 	 * lro_ackcnt_lim is append count limit,
413015516c77SSepherosa Ziehau 	 * +1 to turn it into aggregation limit.
413115516c77SSepherosa Ziehau 	 */
413215516c77SSepherosa Ziehau 	ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1;
413315516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &ackcnt, 0, req);
413415516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
413515516c77SSepherosa Ziehau 		return error;
413615516c77SSepherosa Ziehau 
413715516c77SSepherosa Ziehau 	if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1))
413815516c77SSepherosa Ziehau 		return EINVAL;
413915516c77SSepherosa Ziehau 
414015516c77SSepherosa Ziehau 	/*
414115516c77SSepherosa Ziehau 	 * Convert aggregation limit back to append
414215516c77SSepherosa Ziehau 	 * count limit.
414315516c77SSepherosa Ziehau 	 */
414415516c77SSepherosa Ziehau 	--ackcnt;
414515516c77SSepherosa Ziehau 	HN_LOCK(sc);
4146a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
414715516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt;
414815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
414915516c77SSepherosa Ziehau 	return 0;
415015516c77SSepherosa Ziehau }
415115516c77SSepherosa Ziehau 
415215516c77SSepherosa Ziehau #endif
415315516c77SSepherosa Ziehau 
415415516c77SSepherosa Ziehau static int
415515516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS)
415615516c77SSepherosa Ziehau {
415715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
415815516c77SSepherosa Ziehau 	int hcsum = arg2;
415915516c77SSepherosa Ziehau 	int on, error, i;
416015516c77SSepherosa Ziehau 
416115516c77SSepherosa Ziehau 	on = 0;
416215516c77SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum)
416315516c77SSepherosa Ziehau 		on = 1;
416415516c77SSepherosa Ziehau 
416515516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &on, 0, req);
416615516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
416715516c77SSepherosa Ziehau 		return error;
416815516c77SSepherosa Ziehau 
416915516c77SSepherosa Ziehau 	HN_LOCK(sc);
4170a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
417115516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
417215516c77SSepherosa Ziehau 
417315516c77SSepherosa Ziehau 		if (on)
417415516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= hcsum;
417515516c77SSepherosa Ziehau 		else
417615516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum &= ~hcsum;
417715516c77SSepherosa Ziehau 	}
417815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
417915516c77SSepherosa Ziehau 	return 0;
418015516c77SSepherosa Ziehau }
418115516c77SSepherosa Ziehau 
418215516c77SSepherosa Ziehau static int
418315516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS)
418415516c77SSepherosa Ziehau {
418515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
418615516c77SSepherosa Ziehau 	int chim_size, error;
418715516c77SSepherosa Ziehau 
418815516c77SSepherosa Ziehau 	chim_size = sc->hn_tx_ring[0].hn_chim_size;
418915516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &chim_size, 0, req);
419015516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
419115516c77SSepherosa Ziehau 		return error;
419215516c77SSepherosa Ziehau 
419315516c77SSepherosa Ziehau 	if (chim_size > sc->hn_chim_szmax || chim_size <= 0)
419415516c77SSepherosa Ziehau 		return EINVAL;
419515516c77SSepherosa Ziehau 
419615516c77SSepherosa Ziehau 	HN_LOCK(sc);
419715516c77SSepherosa Ziehau 	hn_set_chim_size(sc, chim_size);
419815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
419915516c77SSepherosa Ziehau 	return 0;
420015516c77SSepherosa Ziehau }
420115516c77SSepherosa Ziehau 
420215516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
420315516c77SSepherosa Ziehau static int
420415516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS)
420515516c77SSepherosa Ziehau {
420615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
420715516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
420815516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
420915516c77SSepherosa Ziehau 	uint64_t stat;
421015516c77SSepherosa Ziehau 
421115516c77SSepherosa Ziehau 	stat = 0;
421215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
421315516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
421415516c77SSepherosa Ziehau 		stat += *((int *)((uint8_t *)rxr + ofs));
421515516c77SSepherosa Ziehau 	}
421615516c77SSepherosa Ziehau 
421715516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
421815516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
421915516c77SSepherosa Ziehau 		return error;
422015516c77SSepherosa Ziehau 
422115516c77SSepherosa Ziehau 	/* Zero out this stat. */
422215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
422315516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
422415516c77SSepherosa Ziehau 		*((int *)((uint8_t *)rxr + ofs)) = 0;
422515516c77SSepherosa Ziehau 	}
422615516c77SSepherosa Ziehau 	return 0;
422715516c77SSepherosa Ziehau }
422815516c77SSepherosa Ziehau #else
422915516c77SSepherosa Ziehau static int
423015516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS)
423115516c77SSepherosa Ziehau {
423215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
423315516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
423415516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
423515516c77SSepherosa Ziehau 	uint64_t stat;
423615516c77SSepherosa Ziehau 
423715516c77SSepherosa Ziehau 	stat = 0;
4238a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
423915516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
424015516c77SSepherosa Ziehau 		stat += *((uint64_t *)((uint8_t *)rxr + ofs));
424115516c77SSepherosa Ziehau 	}
424215516c77SSepherosa Ziehau 
424315516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
424415516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
424515516c77SSepherosa Ziehau 		return error;
424615516c77SSepherosa Ziehau 
424715516c77SSepherosa Ziehau 	/* Zero out this stat. */
4248a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
424915516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
425015516c77SSepherosa Ziehau 		*((uint64_t *)((uint8_t *)rxr + ofs)) = 0;
425115516c77SSepherosa Ziehau 	}
425215516c77SSepherosa Ziehau 	return 0;
425315516c77SSepherosa Ziehau }
425415516c77SSepherosa Ziehau 
425515516c77SSepherosa Ziehau #endif
425615516c77SSepherosa Ziehau 
425715516c77SSepherosa Ziehau static int
425815516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
425915516c77SSepherosa Ziehau {
426015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
426115516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
426215516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
426315516c77SSepherosa Ziehau 	u_long stat;
426415516c77SSepherosa Ziehau 
426515516c77SSepherosa Ziehau 	stat = 0;
4266a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
426715516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
426815516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)rxr + ofs));
426915516c77SSepherosa Ziehau 	}
427015516c77SSepherosa Ziehau 
427115516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
427215516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
427315516c77SSepherosa Ziehau 		return error;
427415516c77SSepherosa Ziehau 
427515516c77SSepherosa Ziehau 	/* Zero out this stat. */
4276a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
427715516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
427815516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)rxr + ofs)) = 0;
427915516c77SSepherosa Ziehau 	}
428015516c77SSepherosa Ziehau 	return 0;
428115516c77SSepherosa Ziehau }
428215516c77SSepherosa Ziehau 
428315516c77SSepherosa Ziehau static int
428415516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
428515516c77SSepherosa Ziehau {
428615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
428715516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
428815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
428915516c77SSepherosa Ziehau 	u_long stat;
429015516c77SSepherosa Ziehau 
429115516c77SSepherosa Ziehau 	stat = 0;
4292a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
429315516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
429415516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)txr + ofs));
429515516c77SSepherosa Ziehau 	}
429615516c77SSepherosa Ziehau 
429715516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
429815516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
429915516c77SSepherosa Ziehau 		return error;
430015516c77SSepherosa Ziehau 
430115516c77SSepherosa Ziehau 	/* Zero out this stat. */
4302a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
430315516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
430415516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)txr + ofs)) = 0;
430515516c77SSepherosa Ziehau 	}
430615516c77SSepherosa Ziehau 	return 0;
430715516c77SSepherosa Ziehau }
430815516c77SSepherosa Ziehau 
430915516c77SSepherosa Ziehau static int
431015516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS)
431115516c77SSepherosa Ziehau {
431215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
431315516c77SSepherosa Ziehau 	int ofs = arg2, i, error, conf;
431415516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
431515516c77SSepherosa Ziehau 
431615516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[0];
431715516c77SSepherosa Ziehau 	conf = *((int *)((uint8_t *)txr + ofs));
431815516c77SSepherosa Ziehau 
431915516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &conf, 0, req);
432015516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
432115516c77SSepherosa Ziehau 		return error;
432215516c77SSepherosa Ziehau 
432315516c77SSepherosa Ziehau 	HN_LOCK(sc);
4324a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
432515516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
432615516c77SSepherosa Ziehau 		*((int *)((uint8_t *)txr + ofs)) = conf;
432715516c77SSepherosa Ziehau 	}
432815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
432915516c77SSepherosa Ziehau 
433015516c77SSepherosa Ziehau 	return 0;
433115516c77SSepherosa Ziehau }
433215516c77SSepherosa Ziehau 
433315516c77SSepherosa Ziehau static int
4334dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS)
4335dc13fee6SSepherosa Ziehau {
4336dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4337dc13fee6SSepherosa Ziehau 	int error, size;
4338dc13fee6SSepherosa Ziehau 
4339dc13fee6SSepherosa Ziehau 	size = sc->hn_agg_size;
4340dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &size, 0, req);
4341dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
4342dc13fee6SSepherosa Ziehau 		return (error);
4343dc13fee6SSepherosa Ziehau 
4344dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
4345dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = size;
4346dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
4347dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
4348dc13fee6SSepherosa Ziehau 
4349dc13fee6SSepherosa Ziehau 	return (0);
4350dc13fee6SSepherosa Ziehau }
4351dc13fee6SSepherosa Ziehau 
4352dc13fee6SSepherosa Ziehau static int
4353dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS)
4354dc13fee6SSepherosa Ziehau {
4355dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4356dc13fee6SSepherosa Ziehau 	int error, pkts;
4357dc13fee6SSepherosa Ziehau 
4358dc13fee6SSepherosa Ziehau 	pkts = sc->hn_agg_pkts;
4359dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pkts, 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_pkts = pkts;
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_pktmax_sysctl(SYSCTL_HANDLER_ARGS)
4373dc13fee6SSepherosa Ziehau {
4374dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4375dc13fee6SSepherosa Ziehau 	int pkts;
4376dc13fee6SSepherosa Ziehau 
4377dc13fee6SSepherosa Ziehau 	pkts = sc->hn_tx_ring[0].hn_agg_pktmax;
4378dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &pkts, 0, req));
4379dc13fee6SSepherosa Ziehau }
4380dc13fee6SSepherosa Ziehau 
4381dc13fee6SSepherosa Ziehau static int
4382dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS)
4383dc13fee6SSepherosa Ziehau {
4384dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4385dc13fee6SSepherosa Ziehau 	int align;
4386dc13fee6SSepherosa Ziehau 
4387dc13fee6SSepherosa Ziehau 	align = sc->hn_tx_ring[0].hn_agg_align;
4388dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &align, 0, req));
4389dc13fee6SSepherosa Ziehau }
4390dc13fee6SSepherosa Ziehau 
43916c1204dfSSepherosa Ziehau static void
43926c1204dfSSepherosa Ziehau hn_chan_polling(struct vmbus_channel *chan, u_int pollhz)
43936c1204dfSSepherosa Ziehau {
43946c1204dfSSepherosa Ziehau 	if (pollhz == 0)
43956c1204dfSSepherosa Ziehau 		vmbus_chan_poll_disable(chan);
43966c1204dfSSepherosa Ziehau 	else
43976c1204dfSSepherosa Ziehau 		vmbus_chan_poll_enable(chan, pollhz);
43986c1204dfSSepherosa Ziehau }
43996c1204dfSSepherosa Ziehau 
44006c1204dfSSepherosa Ziehau static void
44016c1204dfSSepherosa Ziehau hn_polling(struct hn_softc *sc, u_int pollhz)
44026c1204dfSSepherosa Ziehau {
44036c1204dfSSepherosa Ziehau 	int nsubch = sc->hn_rx_ring_inuse - 1;
44046c1204dfSSepherosa Ziehau 
44056c1204dfSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
44066c1204dfSSepherosa Ziehau 
44076c1204dfSSepherosa Ziehau 	if (nsubch > 0) {
44086c1204dfSSepherosa Ziehau 		struct vmbus_channel **subch;
44096c1204dfSSepherosa Ziehau 		int i;
44106c1204dfSSepherosa Ziehau 
44116c1204dfSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
44126c1204dfSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
44136c1204dfSSepherosa Ziehau 			hn_chan_polling(subch[i], pollhz);
44146c1204dfSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
44156c1204dfSSepherosa Ziehau 	}
44166c1204dfSSepherosa Ziehau 	hn_chan_polling(sc->hn_prichan, pollhz);
44176c1204dfSSepherosa Ziehau }
44186c1204dfSSepherosa Ziehau 
44196c1204dfSSepherosa Ziehau static int
44206c1204dfSSepherosa Ziehau hn_polling_sysctl(SYSCTL_HANDLER_ARGS)
44216c1204dfSSepherosa Ziehau {
44226c1204dfSSepherosa Ziehau 	struct hn_softc *sc = arg1;
44236c1204dfSSepherosa Ziehau 	int pollhz, error;
44246c1204dfSSepherosa Ziehau 
44256c1204dfSSepherosa Ziehau 	pollhz = sc->hn_pollhz;
44266c1204dfSSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pollhz, 0, req);
44276c1204dfSSepherosa Ziehau 	if (error || req->newptr == NULL)
44286c1204dfSSepherosa Ziehau 		return (error);
44296c1204dfSSepherosa Ziehau 
44306c1204dfSSepherosa Ziehau 	if (pollhz != 0 &&
44316c1204dfSSepherosa Ziehau 	    (pollhz < VMBUS_CHAN_POLLHZ_MIN || pollhz > VMBUS_CHAN_POLLHZ_MAX))
44326c1204dfSSepherosa Ziehau 		return (EINVAL);
44336c1204dfSSepherosa Ziehau 
44346c1204dfSSepherosa Ziehau 	HN_LOCK(sc);
44356c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz != pollhz) {
44366c1204dfSSepherosa Ziehau 		sc->hn_pollhz = pollhz;
44376c1204dfSSepherosa Ziehau 		if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) &&
44386c1204dfSSepherosa Ziehau 		    (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
44396c1204dfSSepherosa Ziehau 			hn_polling(sc, sc->hn_pollhz);
44406c1204dfSSepherosa Ziehau 	}
44416c1204dfSSepherosa Ziehau 	HN_UNLOCK(sc);
44426c1204dfSSepherosa Ziehau 
44436c1204dfSSepherosa Ziehau 	return (0);
44446c1204dfSSepherosa Ziehau }
44456c1204dfSSepherosa Ziehau 
4446dc13fee6SSepherosa Ziehau static int
444715516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS)
444815516c77SSepherosa Ziehau {
444915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
445015516c77SSepherosa Ziehau 	char verstr[16];
445115516c77SSepherosa Ziehau 
445215516c77SSepherosa Ziehau 	snprintf(verstr, sizeof(verstr), "%u.%u",
445315516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
445415516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
445515516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
445615516c77SSepherosa Ziehau }
445715516c77SSepherosa Ziehau 
445815516c77SSepherosa Ziehau static int
445915516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS)
446015516c77SSepherosa Ziehau {
446115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
446215516c77SSepherosa Ziehau 	char caps_str[128];
446315516c77SSepherosa Ziehau 	uint32_t caps;
446415516c77SSepherosa Ziehau 
446515516c77SSepherosa Ziehau 	HN_LOCK(sc);
446615516c77SSepherosa Ziehau 	caps = sc->hn_caps;
446715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
446815516c77SSepherosa Ziehau 	snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS);
446915516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req);
447015516c77SSepherosa Ziehau }
447115516c77SSepherosa Ziehau 
447215516c77SSepherosa Ziehau static int
447315516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS)
447415516c77SSepherosa Ziehau {
447515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
447615516c77SSepherosa Ziehau 	char assist_str[128];
447715516c77SSepherosa Ziehau 	uint32_t hwassist;
447815516c77SSepherosa Ziehau 
447915516c77SSepherosa Ziehau 	HN_LOCK(sc);
448015516c77SSepherosa Ziehau 	hwassist = sc->hn_ifp->if_hwassist;
448115516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
448215516c77SSepherosa Ziehau 	snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS);
448315516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req);
448415516c77SSepherosa Ziehau }
448515516c77SSepherosa Ziehau 
448615516c77SSepherosa Ziehau static int
448715516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS)
448815516c77SSepherosa Ziehau {
448915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
449015516c77SSepherosa Ziehau 	char filter_str[128];
449115516c77SSepherosa Ziehau 	uint32_t filter;
449215516c77SSepherosa Ziehau 
449315516c77SSepherosa Ziehau 	HN_LOCK(sc);
449415516c77SSepherosa Ziehau 	filter = sc->hn_rx_filter;
449515516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
449615516c77SSepherosa Ziehau 	snprintf(filter_str, sizeof(filter_str), "%b", filter,
449715516c77SSepherosa Ziehau 	    NDIS_PACKET_TYPES);
449815516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req);
449915516c77SSepherosa Ziehau }
450015516c77SSepherosa Ziehau 
450134d68912SSepherosa Ziehau #ifndef RSS
450234d68912SSepherosa Ziehau 
450315516c77SSepherosa Ziehau static int
450415516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
450515516c77SSepherosa Ziehau {
450615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
450715516c77SSepherosa Ziehau 	int error;
450815516c77SSepherosa Ziehau 
450915516c77SSepherosa Ziehau 	HN_LOCK(sc);
451015516c77SSepherosa Ziehau 
451115516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
451215516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
451315516c77SSepherosa Ziehau 		goto back;
451415516c77SSepherosa Ziehau 
4515642ec226SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) ||
4516642ec226SSepherosa Ziehau 	    (hn_xpnt_vf && sc->hn_vf_ifp != NULL)) {
4517642ec226SSepherosa Ziehau 		/*
4518642ec226SSepherosa Ziehau 		 * RSS key is synchronized w/ VF's, don't allow users
4519642ec226SSepherosa Ziehau 		 * to change it.
4520642ec226SSepherosa Ziehau 		 */
4521642ec226SSepherosa Ziehau 		error = EBUSY;
4522642ec226SSepherosa Ziehau 		goto back;
4523642ec226SSepherosa Ziehau 	}
4524642ec226SSepherosa Ziehau 
452515516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
452615516c77SSepherosa Ziehau 	if (error)
452715516c77SSepherosa Ziehau 		goto back;
452815516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
452915516c77SSepherosa Ziehau 
453015516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
453115516c77SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
453215516c77SSepherosa Ziehau 	} else {
453315516c77SSepherosa Ziehau 		/* Not RSS capable, at least for now; just save the RSS key. */
453415516c77SSepherosa Ziehau 		error = 0;
453515516c77SSepherosa Ziehau 	}
453615516c77SSepherosa Ziehau back:
453715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
453815516c77SSepherosa Ziehau 	return (error);
453915516c77SSepherosa Ziehau }
454015516c77SSepherosa Ziehau 
454115516c77SSepherosa Ziehau static int
454215516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS)
454315516c77SSepherosa Ziehau {
454415516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
454515516c77SSepherosa Ziehau 	int error;
454615516c77SSepherosa Ziehau 
454715516c77SSepherosa Ziehau 	HN_LOCK(sc);
454815516c77SSepherosa Ziehau 
454915516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
455015516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
455115516c77SSepherosa Ziehau 		goto back;
455215516c77SSepherosa Ziehau 
455315516c77SSepherosa Ziehau 	/*
455415516c77SSepherosa Ziehau 	 * Don't allow RSS indirect table change, if this interface is not
455515516c77SSepherosa Ziehau 	 * RSS capable currently.
455615516c77SSepherosa Ziehau 	 */
455715516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
455815516c77SSepherosa Ziehau 		error = EOPNOTSUPP;
455915516c77SSepherosa Ziehau 		goto back;
456015516c77SSepherosa Ziehau 	}
456115516c77SSepherosa Ziehau 
456215516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
456315516c77SSepherosa Ziehau 	if (error)
456415516c77SSepherosa Ziehau 		goto back;
456515516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSIND;
456615516c77SSepherosa Ziehau 
4567afd4971bSSepherosa Ziehau 	hn_rss_ind_fixup(sc);
456815516c77SSepherosa Ziehau 	error = hn_rss_reconfig(sc);
456915516c77SSepherosa Ziehau back:
457015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
457115516c77SSepherosa Ziehau 	return (error);
457215516c77SSepherosa Ziehau }
457315516c77SSepherosa Ziehau 
457434d68912SSepherosa Ziehau #endif	/* !RSS */
457534d68912SSepherosa Ziehau 
457615516c77SSepherosa Ziehau static int
457715516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS)
457815516c77SSepherosa Ziehau {
457915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
458015516c77SSepherosa Ziehau 	char hash_str[128];
458115516c77SSepherosa Ziehau 	uint32_t hash;
458215516c77SSepherosa Ziehau 
458315516c77SSepherosa Ziehau 	HN_LOCK(sc);
458415516c77SSepherosa Ziehau 	hash = sc->hn_rss_hash;
458515516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
458615516c77SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
458715516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
458815516c77SSepherosa Ziehau }
458915516c77SSepherosa Ziehau 
459015516c77SSepherosa Ziehau static int
4591642ec226SSepherosa Ziehau hn_rss_hcap_sysctl(SYSCTL_HANDLER_ARGS)
4592642ec226SSepherosa Ziehau {
4593642ec226SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4594642ec226SSepherosa Ziehau 	char hash_str[128];
4595642ec226SSepherosa Ziehau 	uint32_t hash;
4596642ec226SSepherosa Ziehau 
4597642ec226SSepherosa Ziehau 	HN_LOCK(sc);
4598642ec226SSepherosa Ziehau 	hash = sc->hn_rss_hcap;
4599642ec226SSepherosa Ziehau 	HN_UNLOCK(sc);
4600642ec226SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
4601642ec226SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
4602642ec226SSepherosa Ziehau }
4603642ec226SSepherosa Ziehau 
4604642ec226SSepherosa Ziehau static int
4605642ec226SSepherosa Ziehau hn_rss_mbuf_sysctl(SYSCTL_HANDLER_ARGS)
4606642ec226SSepherosa Ziehau {
4607642ec226SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4608642ec226SSepherosa Ziehau 	char hash_str[128];
4609642ec226SSepherosa Ziehau 	uint32_t hash;
4610642ec226SSepherosa Ziehau 
4611642ec226SSepherosa Ziehau 	HN_LOCK(sc);
4612642ec226SSepherosa Ziehau 	hash = sc->hn_rx_ring[0].hn_mbuf_hash;
4613642ec226SSepherosa Ziehau 	HN_UNLOCK(sc);
4614642ec226SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
4615642ec226SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
4616642ec226SSepherosa Ziehau }
4617642ec226SSepherosa Ziehau 
4618642ec226SSepherosa Ziehau static int
461940d60d6eSDexuan Cui hn_vf_sysctl(SYSCTL_HANDLER_ARGS)
462040d60d6eSDexuan Cui {
462140d60d6eSDexuan Cui 	struct hn_softc *sc = arg1;
4622499c3e17SSepherosa Ziehau 	char vf_name[IFNAMSIZ + 1];
4623962f0357SSepherosa Ziehau 	struct ifnet *vf_ifp;
462440d60d6eSDexuan Cui 
462540d60d6eSDexuan Cui 	HN_LOCK(sc);
462640d60d6eSDexuan Cui 	vf_name[0] = '\0';
4627962f0357SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
4628962f0357SSepherosa Ziehau 	if (vf_ifp != NULL)
4629962f0357SSepherosa Ziehau 		snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname);
463040d60d6eSDexuan Cui 	HN_UNLOCK(sc);
463140d60d6eSDexuan Cui 	return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req);
463240d60d6eSDexuan Cui }
463340d60d6eSDexuan Cui 
463440d60d6eSDexuan Cui static int
4635499c3e17SSepherosa Ziehau hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS)
4636499c3e17SSepherosa Ziehau {
4637499c3e17SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4638499c3e17SSepherosa Ziehau 	char vf_name[IFNAMSIZ + 1];
4639962f0357SSepherosa Ziehau 	struct ifnet *vf_ifp;
4640499c3e17SSepherosa Ziehau 
4641499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
4642499c3e17SSepherosa Ziehau 	vf_name[0] = '\0';
4643962f0357SSepherosa Ziehau 	vf_ifp = sc->hn_rx_ring[0].hn_rxvf_ifp;
4644962f0357SSepherosa Ziehau 	if (vf_ifp != NULL)
4645962f0357SSepherosa Ziehau 		snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname);
4646499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
4647499c3e17SSepherosa Ziehau 	return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req);
4648499c3e17SSepherosa Ziehau }
4649499c3e17SSepherosa Ziehau 
4650499c3e17SSepherosa Ziehau static int
4651499c3e17SSepherosa Ziehau hn_vflist_sysctl(SYSCTL_HANDLER_ARGS)
4652499c3e17SSepherosa Ziehau {
4653499c3e17SSepherosa Ziehau 	struct rm_priotracker pt;
4654499c3e17SSepherosa Ziehau 	struct sbuf *sb;
4655499c3e17SSepherosa Ziehau 	int error, i;
4656499c3e17SSepherosa Ziehau 	bool first;
4657499c3e17SSepherosa Ziehau 
4658499c3e17SSepherosa Ziehau 	error = sysctl_wire_old_buffer(req, 0);
4659499c3e17SSepherosa Ziehau 	if (error != 0)
4660499c3e17SSepherosa Ziehau 		return (error);
4661499c3e17SSepherosa Ziehau 
4662499c3e17SSepherosa Ziehau 	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4663499c3e17SSepherosa Ziehau 	if (sb == NULL)
4664499c3e17SSepherosa Ziehau 		return (ENOMEM);
4665499c3e17SSepherosa Ziehau 
4666499c3e17SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
4667499c3e17SSepherosa Ziehau 
4668499c3e17SSepherosa Ziehau 	first = true;
4669499c3e17SSepherosa Ziehau 	for (i = 0; i < hn_vfmap_size; ++i) {
4670499c3e17SSepherosa Ziehau 		struct ifnet *ifp;
4671499c3e17SSepherosa Ziehau 
4672499c3e17SSepherosa Ziehau 		if (hn_vfmap[i] == NULL)
4673499c3e17SSepherosa Ziehau 			continue;
4674499c3e17SSepherosa Ziehau 
4675499c3e17SSepherosa Ziehau 		ifp = ifnet_byindex(i);
4676499c3e17SSepherosa Ziehau 		if (ifp != NULL) {
4677499c3e17SSepherosa Ziehau 			if (first)
4678499c3e17SSepherosa Ziehau 				sbuf_printf(sb, "%s", ifp->if_xname);
4679499c3e17SSepherosa Ziehau 			else
4680499c3e17SSepherosa Ziehau 				sbuf_printf(sb, " %s", ifp->if_xname);
4681499c3e17SSepherosa Ziehau 			first = false;
4682499c3e17SSepherosa Ziehau 		}
4683499c3e17SSepherosa Ziehau 	}
4684499c3e17SSepherosa Ziehau 
4685499c3e17SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
4686499c3e17SSepherosa Ziehau 
4687499c3e17SSepherosa Ziehau 	error = sbuf_finish(sb);
4688499c3e17SSepherosa Ziehau 	sbuf_delete(sb);
4689499c3e17SSepherosa Ziehau 	return (error);
4690499c3e17SSepherosa Ziehau }
4691499c3e17SSepherosa Ziehau 
4692499c3e17SSepherosa Ziehau static int
4693499c3e17SSepherosa Ziehau hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS)
4694499c3e17SSepherosa Ziehau {
4695499c3e17SSepherosa Ziehau 	struct rm_priotracker pt;
4696499c3e17SSepherosa Ziehau 	struct sbuf *sb;
4697499c3e17SSepherosa Ziehau 	int error, i;
4698499c3e17SSepherosa Ziehau 	bool first;
4699499c3e17SSepherosa Ziehau 
4700499c3e17SSepherosa Ziehau 	error = sysctl_wire_old_buffer(req, 0);
4701499c3e17SSepherosa Ziehau 	if (error != 0)
4702499c3e17SSepherosa Ziehau 		return (error);
4703499c3e17SSepherosa Ziehau 
4704499c3e17SSepherosa Ziehau 	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4705499c3e17SSepherosa Ziehau 	if (sb == NULL)
4706499c3e17SSepherosa Ziehau 		return (ENOMEM);
4707499c3e17SSepherosa Ziehau 
4708499c3e17SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
4709499c3e17SSepherosa Ziehau 
4710499c3e17SSepherosa Ziehau 	first = true;
4711499c3e17SSepherosa Ziehau 	for (i = 0; i < hn_vfmap_size; ++i) {
4712499c3e17SSepherosa Ziehau 		struct ifnet *ifp, *hn_ifp;
4713499c3e17SSepherosa Ziehau 
4714499c3e17SSepherosa Ziehau 		hn_ifp = hn_vfmap[i];
4715499c3e17SSepherosa Ziehau 		if (hn_ifp == NULL)
4716499c3e17SSepherosa Ziehau 			continue;
4717499c3e17SSepherosa Ziehau 
4718499c3e17SSepherosa Ziehau 		ifp = ifnet_byindex(i);
4719499c3e17SSepherosa Ziehau 		if (ifp != NULL) {
4720499c3e17SSepherosa Ziehau 			if (first) {
4721499c3e17SSepherosa Ziehau 				sbuf_printf(sb, "%s:%s", ifp->if_xname,
4722499c3e17SSepherosa Ziehau 				    hn_ifp->if_xname);
4723499c3e17SSepherosa Ziehau 			} else {
4724499c3e17SSepherosa Ziehau 				sbuf_printf(sb, " %s:%s", ifp->if_xname,
4725499c3e17SSepherosa Ziehau 				    hn_ifp->if_xname);
4726499c3e17SSepherosa Ziehau 			}
4727499c3e17SSepherosa Ziehau 			first = false;
4728499c3e17SSepherosa Ziehau 		}
4729499c3e17SSepherosa Ziehau 	}
4730499c3e17SSepherosa Ziehau 
4731499c3e17SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
4732499c3e17SSepherosa Ziehau 
4733499c3e17SSepherosa Ziehau 	error = sbuf_finish(sb);
4734499c3e17SSepherosa Ziehau 	sbuf_delete(sb);
4735499c3e17SSepherosa Ziehau 	return (error);
4736499c3e17SSepherosa Ziehau }
4737499c3e17SSepherosa Ziehau 
4738499c3e17SSepherosa Ziehau static int
47399c6cae24SSepherosa Ziehau hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS)
47409c6cae24SSepherosa Ziehau {
47419c6cae24SSepherosa Ziehau 	struct hn_softc *sc = arg1;
47429c6cae24SSepherosa Ziehau 	int error, onoff = 0;
47439c6cae24SSepherosa Ziehau 
47449c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF)
47459c6cae24SSepherosa Ziehau 		onoff = 1;
47469c6cae24SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &onoff, 0, req);
47479c6cae24SSepherosa Ziehau 	if (error || req->newptr == NULL)
47489c6cae24SSepherosa Ziehau 		return (error);
47499c6cae24SSepherosa Ziehau 
47509c6cae24SSepherosa Ziehau 	HN_LOCK(sc);
47519c6cae24SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit() */
47529c6cae24SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
47539c6cae24SSepherosa Ziehau 	if (onoff)
47549c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF;
47559c6cae24SSepherosa Ziehau 	else
47569c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags &= ~HN_XVFFLAG_ACCBPF;
47579c6cae24SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
47589c6cae24SSepherosa Ziehau 	HN_UNLOCK(sc);
47599c6cae24SSepherosa Ziehau 
47609c6cae24SSepherosa Ziehau 	return (0);
47619c6cae24SSepherosa Ziehau }
47629c6cae24SSepherosa Ziehau 
47639c6cae24SSepherosa Ziehau static int
47649c6cae24SSepherosa Ziehau hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS)
47659c6cae24SSepherosa Ziehau {
47669c6cae24SSepherosa Ziehau 	struct hn_softc *sc = arg1;
47679c6cae24SSepherosa Ziehau 	int enabled = 0;
47689c6cae24SSepherosa Ziehau 
47699c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
47709c6cae24SSepherosa Ziehau 		enabled = 1;
47719c6cae24SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &enabled, 0, req));
47729c6cae24SSepherosa Ziehau }
47739c6cae24SSepherosa Ziehau 
47749c6cae24SSepherosa Ziehau static int
477515516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff)
477615516c77SSepherosa Ziehau {
477715516c77SSepherosa Ziehau 	const struct ip *ip;
477815516c77SSepherosa Ziehau 	int len, iphlen, iplen;
477915516c77SSepherosa Ziehau 	const struct tcphdr *th;
478015516c77SSepherosa Ziehau 	int thoff;				/* TCP data offset */
478115516c77SSepherosa Ziehau 
478215516c77SSepherosa Ziehau 	len = hoff + sizeof(struct ip);
478315516c77SSepherosa Ziehau 
478415516c77SSepherosa Ziehau 	/* The packet must be at least the size of an IP header. */
478515516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < len)
478615516c77SSepherosa Ziehau 		return IPPROTO_DONE;
478715516c77SSepherosa Ziehau 
478815516c77SSepherosa Ziehau 	/* The fixed IP header must reside completely in the first mbuf. */
478915516c77SSepherosa Ziehau 	if (m->m_len < len)
479015516c77SSepherosa Ziehau 		return IPPROTO_DONE;
479115516c77SSepherosa Ziehau 
479215516c77SSepherosa Ziehau 	ip = mtodo(m, hoff);
479315516c77SSepherosa Ziehau 
479415516c77SSepherosa Ziehau 	/* Bound check the packet's stated IP header length. */
479515516c77SSepherosa Ziehau 	iphlen = ip->ip_hl << 2;
479615516c77SSepherosa Ziehau 	if (iphlen < sizeof(struct ip))		/* minimum header length */
479715516c77SSepherosa Ziehau 		return IPPROTO_DONE;
479815516c77SSepherosa Ziehau 
479915516c77SSepherosa Ziehau 	/* The full IP header must reside completely in the one mbuf. */
480015516c77SSepherosa Ziehau 	if (m->m_len < hoff + iphlen)
480115516c77SSepherosa Ziehau 		return IPPROTO_DONE;
480215516c77SSepherosa Ziehau 
480315516c77SSepherosa Ziehau 	iplen = ntohs(ip->ip_len);
480415516c77SSepherosa Ziehau 
480515516c77SSepherosa Ziehau 	/*
480615516c77SSepherosa Ziehau 	 * Check that the amount of data in the buffers is as
480715516c77SSepherosa Ziehau 	 * at least much as the IP header would have us expect.
480815516c77SSepherosa Ziehau 	 */
480915516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < hoff + iplen)
481015516c77SSepherosa Ziehau 		return IPPROTO_DONE;
481115516c77SSepherosa Ziehau 
481215516c77SSepherosa Ziehau 	/*
481315516c77SSepherosa Ziehau 	 * Ignore IP fragments.
481415516c77SSepherosa Ziehau 	 */
481515516c77SSepherosa Ziehau 	if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF))
481615516c77SSepherosa Ziehau 		return IPPROTO_DONE;
481715516c77SSepherosa Ziehau 
481815516c77SSepherosa Ziehau 	/*
481915516c77SSepherosa Ziehau 	 * The TCP/IP or UDP/IP header must be entirely contained within
482015516c77SSepherosa Ziehau 	 * the first fragment of a packet.
482115516c77SSepherosa Ziehau 	 */
482215516c77SSepherosa Ziehau 	switch (ip->ip_p) {
482315516c77SSepherosa Ziehau 	case IPPROTO_TCP:
482415516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct tcphdr))
482515516c77SSepherosa Ziehau 			return IPPROTO_DONE;
482615516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct tcphdr))
482715516c77SSepherosa Ziehau 			return IPPROTO_DONE;
482815516c77SSepherosa Ziehau 		th = (const struct tcphdr *)((const uint8_t *)ip + iphlen);
482915516c77SSepherosa Ziehau 		thoff = th->th_off << 2;
483015516c77SSepherosa Ziehau 		if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen)
483115516c77SSepherosa Ziehau 			return IPPROTO_DONE;
483215516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + thoff)
483315516c77SSepherosa Ziehau 			return IPPROTO_DONE;
483415516c77SSepherosa Ziehau 		break;
483515516c77SSepherosa Ziehau 	case IPPROTO_UDP:
483615516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct udphdr))
483715516c77SSepherosa Ziehau 			return IPPROTO_DONE;
483815516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct udphdr))
483915516c77SSepherosa Ziehau 			return IPPROTO_DONE;
484015516c77SSepherosa Ziehau 		break;
484115516c77SSepherosa Ziehau 	default:
484215516c77SSepherosa Ziehau 		if (iplen < iphlen)
484315516c77SSepherosa Ziehau 			return IPPROTO_DONE;
484415516c77SSepherosa Ziehau 		break;
484515516c77SSepherosa Ziehau 	}
484615516c77SSepherosa Ziehau 	return ip->ip_p;
484715516c77SSepherosa Ziehau }
484815516c77SSepherosa Ziehau 
4849*db76829bSSepherosa Ziehau static void
4850*db76829bSSepherosa Ziehau hn_rxpkt_proto(const struct mbuf *m_new, int *l3proto, int *l4proto)
4851*db76829bSSepherosa Ziehau {
4852*db76829bSSepherosa Ziehau 	const struct ether_header *eh;
4853*db76829bSSepherosa Ziehau 	uint16_t etype;
4854*db76829bSSepherosa Ziehau 	int hoff;
4855*db76829bSSepherosa Ziehau 
4856*db76829bSSepherosa Ziehau 	hoff = sizeof(*eh);
4857*db76829bSSepherosa Ziehau 	/* Checked at the beginning of this function. */
4858*db76829bSSepherosa Ziehau 	KASSERT(m_new->m_len >= hoff, ("not ethernet frame"));
4859*db76829bSSepherosa Ziehau 
4860*db76829bSSepherosa Ziehau 	eh = mtod(m_new, const struct ether_header *);
4861*db76829bSSepherosa Ziehau 	etype = ntohs(eh->ether_type);
4862*db76829bSSepherosa Ziehau 	if (etype == ETHERTYPE_VLAN) {
4863*db76829bSSepherosa Ziehau 		const struct ether_vlan_header *evl;
4864*db76829bSSepherosa Ziehau 
4865*db76829bSSepherosa Ziehau 		hoff = sizeof(*evl);
4866*db76829bSSepherosa Ziehau 		if (m_new->m_len < hoff)
4867*db76829bSSepherosa Ziehau 			return;
4868*db76829bSSepherosa Ziehau 		evl = mtod(m_new, const struct ether_vlan_header *);
4869*db76829bSSepherosa Ziehau 		etype = ntohs(evl->evl_proto);
4870*db76829bSSepherosa Ziehau 	}
4871*db76829bSSepherosa Ziehau 	*l3proto = etype;
4872*db76829bSSepherosa Ziehau 
4873*db76829bSSepherosa Ziehau 	if (etype == ETHERTYPE_IP)
4874*db76829bSSepherosa Ziehau 		*l4proto = hn_check_iplen(m_new, hoff);
4875*db76829bSSepherosa Ziehau 	else
4876*db76829bSSepherosa Ziehau 		*l4proto = IPPROTO_DONE;
4877*db76829bSSepherosa Ziehau }
4878*db76829bSSepherosa Ziehau 
487915516c77SSepherosa Ziehau static int
488015516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt)
488115516c77SSepherosa Ziehau {
488215516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
488315516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
488415516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
488515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
488615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
488715516c77SSepherosa Ziehau 	int lroent_cnt;
488815516c77SSepherosa Ziehau #endif
488915516c77SSepherosa Ziehau #endif
489015516c77SSepherosa Ziehau 	int i;
489115516c77SSepherosa Ziehau 
489215516c77SSepherosa Ziehau 	/*
489315516c77SSepherosa Ziehau 	 * Create RXBUF for reception.
489415516c77SSepherosa Ziehau 	 *
489515516c77SSepherosa Ziehau 	 * NOTE:
489615516c77SSepherosa Ziehau 	 * - It is shared by all channels.
489715516c77SSepherosa Ziehau 	 * - A large enough buffer is allocated, certain version of NVSes
489815516c77SSepherosa Ziehau 	 *   may further limit the usable space.
489915516c77SSepherosa Ziehau 	 */
490015516c77SSepherosa Ziehau 	sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
490115516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma,
490215516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
490315516c77SSepherosa Ziehau 	if (sc->hn_rxbuf == NULL) {
490415516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate rxbuf failed\n");
490515516c77SSepherosa Ziehau 		return (ENOMEM);
490615516c77SSepherosa Ziehau 	}
490715516c77SSepherosa Ziehau 
490815516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = ring_cnt;
490915516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt;
491015516c77SSepherosa Ziehau 
491115516c77SSepherosa Ziehau 	sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt,
491215516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
491315516c77SSepherosa Ziehau 
491415516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
491515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
491615516c77SSepherosa Ziehau 	lroent_cnt = hn_lro_entry_count;
491715516c77SSepherosa Ziehau 	if (lroent_cnt < TCP_LRO_ENTRIES)
491815516c77SSepherosa Ziehau 		lroent_cnt = TCP_LRO_ENTRIES;
491915516c77SSepherosa Ziehau 	if (bootverbose)
492015516c77SSepherosa Ziehau 		device_printf(dev, "LRO: entry count %d\n", lroent_cnt);
492115516c77SSepherosa Ziehau #endif
492215516c77SSepherosa Ziehau #endif	/* INET || INET6 */
492315516c77SSepherosa Ziehau 
492415516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
492515516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
492615516c77SSepherosa Ziehau 
492715516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.rx sysctl tree */
492815516c77SSepherosa Ziehau 	sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx",
492915516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
493015516c77SSepherosa Ziehau 
493115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
493215516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
493315516c77SSepherosa Ziehau 
493415516c77SSepherosa Ziehau 		rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
493515516c77SSepherosa Ziehau 		    PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE,
493615516c77SSepherosa Ziehau 		    &rxr->hn_br_dma, BUS_DMA_WAITOK);
493715516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL) {
493815516c77SSepherosa Ziehau 			device_printf(dev, "allocate bufring failed\n");
493915516c77SSepherosa Ziehau 			return (ENOMEM);
494015516c77SSepherosa Ziehau 		}
494115516c77SSepherosa Ziehau 
494215516c77SSepherosa Ziehau 		if (hn_trust_hosttcp)
494315516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP;
494415516c77SSepherosa Ziehau 		if (hn_trust_hostudp)
494515516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP;
494615516c77SSepherosa Ziehau 		if (hn_trust_hostip)
494715516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP;
4948642ec226SSepherosa Ziehau 		rxr->hn_mbuf_hash = NDIS_HASH_ALL;
494915516c77SSepherosa Ziehau 		rxr->hn_ifp = sc->hn_ifp;
495015516c77SSepherosa Ziehau 		if (i < sc->hn_tx_ring_cnt)
495115516c77SSepherosa Ziehau 			rxr->hn_txr = &sc->hn_tx_ring[i];
495215516c77SSepherosa Ziehau 		rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF;
495315516c77SSepherosa Ziehau 		rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK);
495415516c77SSepherosa Ziehau 		rxr->hn_rx_idx = i;
495515516c77SSepherosa Ziehau 		rxr->hn_rxbuf = sc->hn_rxbuf;
495615516c77SSepherosa Ziehau 
495715516c77SSepherosa Ziehau 		/*
495815516c77SSepherosa Ziehau 		 * Initialize LRO.
495915516c77SSepherosa Ziehau 		 */
496015516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
496115516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
496215516c77SSepherosa Ziehau 		tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt,
496315516c77SSepherosa Ziehau 		    hn_lro_mbufq_depth);
496415516c77SSepherosa Ziehau #else
496515516c77SSepherosa Ziehau 		tcp_lro_init(&rxr->hn_lro);
496615516c77SSepherosa Ziehau 		rxr->hn_lro.ifp = sc->hn_ifp;
496715516c77SSepherosa Ziehau #endif
496815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
496915516c77SSepherosa Ziehau 		rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF;
497015516c77SSepherosa Ziehau 		rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF;
497115516c77SSepherosa Ziehau #endif
497215516c77SSepherosa Ziehau #endif	/* INET || INET6 */
497315516c77SSepherosa Ziehau 
497415516c77SSepherosa Ziehau 		if (sc->hn_rx_sysctl_tree != NULL) {
497515516c77SSepherosa Ziehau 			char name[16];
497615516c77SSepherosa Ziehau 
497715516c77SSepherosa Ziehau 			/*
497815516c77SSepherosa Ziehau 			 * Create per RX ring sysctl tree:
497915516c77SSepherosa Ziehau 			 * dev.hn.UNIT.rx.RINGID
498015516c77SSepherosa Ziehau 			 */
498115516c77SSepherosa Ziehau 			snprintf(name, sizeof(name), "%d", i);
498215516c77SSepherosa Ziehau 			rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx,
498315516c77SSepherosa Ziehau 			    SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree),
498415516c77SSepherosa Ziehau 			    OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
498515516c77SSepherosa Ziehau 
498615516c77SSepherosa Ziehau 			if (rxr->hn_rx_sysctl_tree != NULL) {
498715516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
498815516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
498915516c77SSepherosa Ziehau 				    OID_AUTO, "packets", CTLFLAG_RW,
499015516c77SSepherosa Ziehau 				    &rxr->hn_pkts, "# of packets received");
499115516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
499215516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
499315516c77SSepherosa Ziehau 				    OID_AUTO, "rss_pkts", CTLFLAG_RW,
499415516c77SSepherosa Ziehau 				    &rxr->hn_rss_pkts,
499515516c77SSepherosa Ziehau 				    "# of packets w/ RSS info received");
499615516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx,
499715516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
499815516c77SSepherosa Ziehau 				    OID_AUTO, "pktbuf_len", CTLFLAG_RD,
499915516c77SSepherosa Ziehau 				    &rxr->hn_pktbuf_len, 0,
500015516c77SSepherosa Ziehau 				    "Temporary channel packet buffer length");
500115516c77SSepherosa Ziehau 			}
500215516c77SSepherosa Ziehau 		}
500315516c77SSepherosa Ziehau 	}
500415516c77SSepherosa Ziehau 
500515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued",
500615516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
500715516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_queued),
500815516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
500915516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
501015516c77SSepherosa Ziehau #else
501115516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
501215516c77SSepherosa Ziehau #endif
501315516c77SSepherosa Ziehau 	    "LU", "LRO queued");
501415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed",
501515516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
501615516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_flushed),
501715516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
501815516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
501915516c77SSepherosa Ziehau #else
502015516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
502115516c77SSepherosa Ziehau #endif
502215516c77SSepherosa Ziehau 	    "LU", "LRO flushed");
502315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried",
502415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
502515516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro_tried),
502615516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries");
502715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
502815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim",
502915516c77SSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
503015516c77SSepherosa Ziehau 	    hn_lro_lenlim_sysctl, "IU",
503115516c77SSepherosa Ziehau 	    "Max # of data bytes to be aggregated by LRO");
503215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim",
503315516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
503415516c77SSepherosa Ziehau 	    hn_lro_ackcnt_sysctl, "I",
503515516c77SSepherosa Ziehau 	    "Max # of ACKs to be aggregated by LRO");
503615516c77SSepherosa Ziehau #endif
503715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp",
503815516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP,
503915516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
504015516c77SSepherosa Ziehau 	    "Trust tcp segement verification on host side, "
504115516c77SSepherosa Ziehau 	    "when csum info is missing");
504215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp",
504315516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP,
504415516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
504515516c77SSepherosa Ziehau 	    "Trust udp datagram verification on host side, "
504615516c77SSepherosa Ziehau 	    "when csum info is missing");
504715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip",
504815516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP,
504915516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
505015516c77SSepherosa Ziehau 	    "Trust ip packet verification on host side, "
505115516c77SSepherosa Ziehau 	    "when csum info is missing");
505215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip",
505315516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
505415516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_ip),
505515516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP");
505615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp",
505715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
505815516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_tcp),
505915516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP");
506015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp",
506115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
506215516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_udp),
506315516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP");
506415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted",
506515516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
506615516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_trusted),
506715516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU",
506815516c77SSepherosa Ziehau 	    "# of packets that we trust host's csum verification");
506915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts",
507015516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
507115516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_small_pkts),
507215516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of small packets received");
507315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed",
507415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
507515516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_ack_failed),
507615516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures");
507715516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt",
507815516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings");
507915516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse",
508015516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings");
508115516c77SSepherosa Ziehau 
508215516c77SSepherosa Ziehau 	return (0);
508315516c77SSepherosa Ziehau }
508415516c77SSepherosa Ziehau 
508515516c77SSepherosa Ziehau static void
508615516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc)
508715516c77SSepherosa Ziehau {
508815516c77SSepherosa Ziehau 	int i;
508915516c77SSepherosa Ziehau 
509015516c77SSepherosa Ziehau 	if (sc->hn_rxbuf != NULL) {
50912494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0)
509215516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf);
50932494d735SSepherosa Ziehau 		else
50942494d735SSepherosa Ziehau 			device_printf(sc->hn_dev, "RXBUF is referenced\n");
509515516c77SSepherosa Ziehau 		sc->hn_rxbuf = NULL;
509615516c77SSepherosa Ziehau 	}
509715516c77SSepherosa Ziehau 
509815516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_cnt == 0)
509915516c77SSepherosa Ziehau 		return;
510015516c77SSepherosa Ziehau 
510115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
510215516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
510315516c77SSepherosa Ziehau 
510415516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL)
510515516c77SSepherosa Ziehau 			continue;
51062494d735SSepherosa Ziehau 		if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) {
510715516c77SSepherosa Ziehau 			hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br);
51082494d735SSepherosa Ziehau 		} else {
51092494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
51102494d735SSepherosa Ziehau 			    "%dth channel bufring is referenced", i);
51112494d735SSepherosa Ziehau 		}
511215516c77SSepherosa Ziehau 		rxr->hn_br = NULL;
511315516c77SSepherosa Ziehau 
511415516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
511515516c77SSepherosa Ziehau 		tcp_lro_free(&rxr->hn_lro);
511615516c77SSepherosa Ziehau #endif
511715516c77SSepherosa Ziehau 		free(rxr->hn_pktbuf, M_DEVBUF);
511815516c77SSepherosa Ziehau 	}
511915516c77SSepherosa Ziehau 	free(sc->hn_rx_ring, M_DEVBUF);
512015516c77SSepherosa Ziehau 	sc->hn_rx_ring = NULL;
512115516c77SSepherosa Ziehau 
512215516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = 0;
512315516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = 0;
512415516c77SSepherosa Ziehau }
512515516c77SSepherosa Ziehau 
512615516c77SSepherosa Ziehau static int
512715516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id)
512815516c77SSepherosa Ziehau {
512915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[id];
513015516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
513115516c77SSepherosa Ziehau 	bus_dma_tag_t parent_dtag;
513215516c77SSepherosa Ziehau 	int error, i;
513315516c77SSepherosa Ziehau 
513415516c77SSepherosa Ziehau 	txr->hn_sc = sc;
513515516c77SSepherosa Ziehau 	txr->hn_tx_idx = id;
513615516c77SSepherosa Ziehau 
513715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
513815516c77SSepherosa Ziehau 	mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN);
513915516c77SSepherosa Ziehau #endif
514015516c77SSepherosa Ziehau 	mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF);
514115516c77SSepherosa Ziehau 
514215516c77SSepherosa Ziehau 	txr->hn_txdesc_cnt = HN_TX_DESC_CNT;
514315516c77SSepherosa Ziehau 	txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt,
514415516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
514515516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
514615516c77SSepherosa Ziehau 	SLIST_INIT(&txr->hn_txlist);
514715516c77SSepherosa Ziehau #else
514815516c77SSepherosa Ziehau 	txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF,
514915516c77SSepherosa Ziehau 	    M_WAITOK, &txr->hn_tx_lock);
515015516c77SSepherosa Ziehau #endif
515115516c77SSepherosa Ziehau 
51520e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_EVTTQ) {
51530e11868dSSepherosa Ziehau 		txr->hn_tx_taskq = VMBUS_GET_EVENT_TASKQ(
51540e11868dSSepherosa Ziehau 		    device_get_parent(dev), dev, HN_RING_IDX2CPU(sc, id));
51550e11868dSSepherosa Ziehau 	} else {
5156fdd0222aSSepherosa Ziehau 		txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt];
51570e11868dSSepherosa Ziehau 	}
515815516c77SSepherosa Ziehau 
515923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
516015516c77SSepherosa Ziehau 	if (hn_use_if_start) {
516115516c77SSepherosa Ziehau 		txr->hn_txeof = hn_start_txeof;
516215516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr);
516315516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr);
516423bf9e15SSepherosa Ziehau 	} else
516523bf9e15SSepherosa Ziehau #endif
516623bf9e15SSepherosa Ziehau 	{
516715516c77SSepherosa Ziehau 		int br_depth;
516815516c77SSepherosa Ziehau 
516915516c77SSepherosa Ziehau 		txr->hn_txeof = hn_xmit_txeof;
517015516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr);
517115516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr);
517215516c77SSepherosa Ziehau 
517315516c77SSepherosa Ziehau 		br_depth = hn_get_txswq_depth(txr);
517415516c77SSepherosa Ziehau 		txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF,
517515516c77SSepherosa Ziehau 		    M_WAITOK, &txr->hn_tx_lock);
517615516c77SSepherosa Ziehau 	}
517715516c77SSepherosa Ziehau 
517815516c77SSepherosa Ziehau 	txr->hn_direct_tx_size = hn_direct_tx_size;
517915516c77SSepherosa Ziehau 
518015516c77SSepherosa Ziehau 	/*
518115516c77SSepherosa Ziehau 	 * Always schedule transmission instead of trying to do direct
518215516c77SSepherosa Ziehau 	 * transmission.  This one gives the best performance so far.
518315516c77SSepherosa Ziehau 	 */
518415516c77SSepherosa Ziehau 	txr->hn_sched_tx = 1;
518515516c77SSepherosa Ziehau 
518615516c77SSepherosa Ziehau 	parent_dtag = bus_get_dma_tag(dev);
518715516c77SSepherosa Ziehau 
518815516c77SSepherosa Ziehau 	/* DMA tag for RNDIS packet messages. */
518915516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
519015516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_ALIGN,		/* alignment */
519115516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_BOUNDARY,	/* boundary */
519215516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
519315516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
519415516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
519515516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsize */
519615516c77SSepherosa Ziehau 	    1,				/* nsegments */
519715516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsegsize */
519815516c77SSepherosa Ziehau 	    0,				/* flags */
519915516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
520015516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
520115516c77SSepherosa Ziehau 	    &txr->hn_tx_rndis_dtag);
520215516c77SSepherosa Ziehau 	if (error) {
520315516c77SSepherosa Ziehau 		device_printf(dev, "failed to create rndis dmatag\n");
520415516c77SSepherosa Ziehau 		return error;
520515516c77SSepherosa Ziehau 	}
520615516c77SSepherosa Ziehau 
520715516c77SSepherosa Ziehau 	/* DMA tag for data. */
520815516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
520915516c77SSepherosa Ziehau 	    1,				/* alignment */
521015516c77SSepherosa Ziehau 	    HN_TX_DATA_BOUNDARY,	/* boundary */
521115516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
521215516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
521315516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
521415516c77SSepherosa Ziehau 	    HN_TX_DATA_MAXSIZE,		/* maxsize */
521515516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGCNT_MAX,	/* nsegments */
521615516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGSIZE,		/* maxsegsize */
521715516c77SSepherosa Ziehau 	    0,				/* flags */
521815516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
521915516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
522015516c77SSepherosa Ziehau 	    &txr->hn_tx_data_dtag);
522115516c77SSepherosa Ziehau 	if (error) {
522215516c77SSepherosa Ziehau 		device_printf(dev, "failed to create data dmatag\n");
522315516c77SSepherosa Ziehau 		return error;
522415516c77SSepherosa Ziehau 	}
522515516c77SSepherosa Ziehau 
522615516c77SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i) {
522715516c77SSepherosa Ziehau 		struct hn_txdesc *txd = &txr->hn_txdesc[i];
522815516c77SSepherosa Ziehau 
522915516c77SSepherosa Ziehau 		txd->txr = txr;
523015516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
5231dc13fee6SSepherosa Ziehau 		STAILQ_INIT(&txd->agg_list);
523215516c77SSepherosa Ziehau 
523315516c77SSepherosa Ziehau 		/*
523415516c77SSepherosa Ziehau 		 * Allocate and load RNDIS packet message.
523515516c77SSepherosa Ziehau 		 */
523615516c77SSepherosa Ziehau         	error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag,
523715516c77SSepherosa Ziehau 		    (void **)&txd->rndis_pkt,
523815516c77SSepherosa Ziehau 		    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
523915516c77SSepherosa Ziehau 		    &txd->rndis_pkt_dmap);
524015516c77SSepherosa Ziehau 		if (error) {
524115516c77SSepherosa Ziehau 			device_printf(dev,
524215516c77SSepherosa Ziehau 			    "failed to allocate rndis_packet_msg, %d\n", i);
524315516c77SSepherosa Ziehau 			return error;
524415516c77SSepherosa Ziehau 		}
524515516c77SSepherosa Ziehau 
524615516c77SSepherosa Ziehau 		error = bus_dmamap_load(txr->hn_tx_rndis_dtag,
524715516c77SSepherosa Ziehau 		    txd->rndis_pkt_dmap,
524815516c77SSepherosa Ziehau 		    txd->rndis_pkt, HN_RNDIS_PKT_LEN,
524915516c77SSepherosa Ziehau 		    hyperv_dma_map_paddr, &txd->rndis_pkt_paddr,
525015516c77SSepherosa Ziehau 		    BUS_DMA_NOWAIT);
525115516c77SSepherosa Ziehau 		if (error) {
525215516c77SSepherosa Ziehau 			device_printf(dev,
525315516c77SSepherosa Ziehau 			    "failed to load rndis_packet_msg, %d\n", i);
525415516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
525515516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
525615516c77SSepherosa Ziehau 			return error;
525715516c77SSepherosa Ziehau 		}
525815516c77SSepherosa Ziehau 
525915516c77SSepherosa Ziehau 		/* DMA map for TX data. */
526015516c77SSepherosa Ziehau 		error = bus_dmamap_create(txr->hn_tx_data_dtag, 0,
526115516c77SSepherosa Ziehau 		    &txd->data_dmap);
526215516c77SSepherosa Ziehau 		if (error) {
526315516c77SSepherosa Ziehau 			device_printf(dev,
526415516c77SSepherosa Ziehau 			    "failed to allocate tx data dmamap\n");
526515516c77SSepherosa Ziehau 			bus_dmamap_unload(txr->hn_tx_rndis_dtag,
526615516c77SSepherosa Ziehau 			    txd->rndis_pkt_dmap);
526715516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
526815516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
526915516c77SSepherosa Ziehau 			return error;
527015516c77SSepherosa Ziehau 		}
527115516c77SSepherosa Ziehau 
527215516c77SSepherosa Ziehau 		/* All set, put it to list */
527315516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_ONLIST;
527415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
527515516c77SSepherosa Ziehau 		SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
527615516c77SSepherosa Ziehau #else
527715516c77SSepherosa Ziehau 		buf_ring_enqueue(txr->hn_txdesc_br, txd);
527815516c77SSepherosa Ziehau #endif
527915516c77SSepherosa Ziehau 	}
528015516c77SSepherosa Ziehau 	txr->hn_txdesc_avail = txr->hn_txdesc_cnt;
528115516c77SSepherosa Ziehau 
528215516c77SSepherosa Ziehau 	if (sc->hn_tx_sysctl_tree != NULL) {
528315516c77SSepherosa Ziehau 		struct sysctl_oid_list *child;
528415516c77SSepherosa Ziehau 		struct sysctl_ctx_list *ctx;
528515516c77SSepherosa Ziehau 		char name[16];
528615516c77SSepherosa Ziehau 
528715516c77SSepherosa Ziehau 		/*
528815516c77SSepherosa Ziehau 		 * Create per TX ring sysctl tree:
528915516c77SSepherosa Ziehau 		 * dev.hn.UNIT.tx.RINGID
529015516c77SSepherosa Ziehau 		 */
529115516c77SSepherosa Ziehau 		ctx = device_get_sysctl_ctx(dev);
529215516c77SSepherosa Ziehau 		child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree);
529315516c77SSepherosa Ziehau 
529415516c77SSepherosa Ziehau 		snprintf(name, sizeof(name), "%d", id);
529515516c77SSepherosa Ziehau 		txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
529615516c77SSepherosa Ziehau 		    name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
529715516c77SSepherosa Ziehau 
529815516c77SSepherosa Ziehau 		if (txr->hn_tx_sysctl_tree != NULL) {
529915516c77SSepherosa Ziehau 			child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree);
530015516c77SSepherosa Ziehau 
530185e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
530215516c77SSepherosa Ziehau 			SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail",
530315516c77SSepherosa Ziehau 			    CTLFLAG_RD, &txr->hn_txdesc_avail, 0,
530415516c77SSepherosa Ziehau 			    "# of available TX descs");
530585e4ae1eSSepherosa Ziehau #endif
530623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
530723bf9e15SSepherosa Ziehau 			if (!hn_use_if_start)
530823bf9e15SSepherosa Ziehau #endif
530923bf9e15SSepherosa Ziehau 			{
531015516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive",
531115516c77SSepherosa Ziehau 				    CTLFLAG_RD, &txr->hn_oactive, 0,
531215516c77SSepherosa Ziehau 				    "over active");
531315516c77SSepherosa Ziehau 			}
531415516c77SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets",
531515516c77SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_pkts,
531615516c77SSepherosa Ziehau 			    "# of packets transmitted");
5317dc13fee6SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends",
5318dc13fee6SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_sends, "# of sends");
531915516c77SSepherosa Ziehau 		}
532015516c77SSepherosa Ziehau 	}
532115516c77SSepherosa Ziehau 
532215516c77SSepherosa Ziehau 	return 0;
532315516c77SSepherosa Ziehau }
532415516c77SSepherosa Ziehau 
532515516c77SSepherosa Ziehau static void
532615516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd)
532715516c77SSepherosa Ziehau {
532815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = txd->txr;
532915516c77SSepherosa Ziehau 
533015516c77SSepherosa Ziehau 	KASSERT(txd->m == NULL, ("still has mbuf installed"));
533115516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped"));
533215516c77SSepherosa Ziehau 
533315516c77SSepherosa Ziehau 	bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap);
533415516c77SSepherosa Ziehau 	bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt,
533515516c77SSepherosa Ziehau 	    txd->rndis_pkt_dmap);
533615516c77SSepherosa Ziehau 	bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap);
533715516c77SSepherosa Ziehau }
533815516c77SSepherosa Ziehau 
533915516c77SSepherosa Ziehau static void
534025641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd)
534125641fc7SSepherosa Ziehau {
534225641fc7SSepherosa Ziehau 
534325641fc7SSepherosa Ziehau 	KASSERT(txd->refs == 0 || txd->refs == 1,
534425641fc7SSepherosa Ziehau 	    ("invalid txd refs %d", txd->refs));
534525641fc7SSepherosa Ziehau 
534625641fc7SSepherosa Ziehau 	/* Aggregated txds will be freed by their aggregating txd. */
534725641fc7SSepherosa Ziehau 	if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) {
534825641fc7SSepherosa Ziehau 		int freed;
534925641fc7SSepherosa Ziehau 
535025641fc7SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
535125641fc7SSepherosa Ziehau 		KASSERT(freed, ("can't free txdesc"));
535225641fc7SSepherosa Ziehau 	}
535325641fc7SSepherosa Ziehau }
535425641fc7SSepherosa Ziehau 
535525641fc7SSepherosa Ziehau static void
535615516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr)
535715516c77SSepherosa Ziehau {
535825641fc7SSepherosa Ziehau 	int i;
535915516c77SSepherosa Ziehau 
536015516c77SSepherosa Ziehau 	if (txr->hn_txdesc == NULL)
536115516c77SSepherosa Ziehau 		return;
536215516c77SSepherosa Ziehau 
536325641fc7SSepherosa Ziehau 	/*
536425641fc7SSepherosa Ziehau 	 * NOTE:
536525641fc7SSepherosa Ziehau 	 * Because the freeing of aggregated txds will be deferred
536625641fc7SSepherosa Ziehau 	 * to the aggregating txd, two passes are used here:
536725641fc7SSepherosa Ziehau 	 * - The first pass GCes any pending txds.  This GC is necessary,
536825641fc7SSepherosa Ziehau 	 *   since if the channels are revoked, hypervisor will not
536925641fc7SSepherosa Ziehau 	 *   deliver send-done for all pending txds.
537025641fc7SSepherosa Ziehau 	 * - The second pass frees the busdma stuffs, i.e. after all txds
537125641fc7SSepherosa Ziehau 	 *   were freed.
537225641fc7SSepherosa Ziehau 	 */
537325641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
537425641fc7SSepherosa Ziehau 		hn_txdesc_gc(txr, &txr->hn_txdesc[i]);
537525641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
537625641fc7SSepherosa Ziehau 		hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]);
537715516c77SSepherosa Ziehau 
537815516c77SSepherosa Ziehau 	if (txr->hn_tx_data_dtag != NULL)
537915516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_data_dtag);
538015516c77SSepherosa Ziehau 	if (txr->hn_tx_rndis_dtag != NULL)
538115516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_rndis_dtag);
538215516c77SSepherosa Ziehau 
538315516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
538415516c77SSepherosa Ziehau 	buf_ring_free(txr->hn_txdesc_br, M_DEVBUF);
538515516c77SSepherosa Ziehau #endif
538615516c77SSepherosa Ziehau 
538715516c77SSepherosa Ziehau 	free(txr->hn_txdesc, M_DEVBUF);
538815516c77SSepherosa Ziehau 	txr->hn_txdesc = NULL;
538915516c77SSepherosa Ziehau 
539015516c77SSepherosa Ziehau 	if (txr->hn_mbuf_br != NULL)
539115516c77SSepherosa Ziehau 		buf_ring_free(txr->hn_mbuf_br, M_DEVBUF);
539215516c77SSepherosa Ziehau 
539315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
539415516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_txlist_spin);
539515516c77SSepherosa Ziehau #endif
539615516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_tx_lock);
539715516c77SSepherosa Ziehau }
539815516c77SSepherosa Ziehau 
539915516c77SSepherosa Ziehau static int
540015516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt)
540115516c77SSepherosa Ziehau {
540215516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
540315516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
540415516c77SSepherosa Ziehau 	int i;
540515516c77SSepherosa Ziehau 
540615516c77SSepherosa Ziehau 	/*
540715516c77SSepherosa Ziehau 	 * Create TXBUF for chimney sending.
540815516c77SSepherosa Ziehau 	 *
540915516c77SSepherosa Ziehau 	 * NOTE: It is shared by all channels.
541015516c77SSepherosa Ziehau 	 */
541115516c77SSepherosa Ziehau 	sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev),
541215516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma,
541315516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
541415516c77SSepherosa Ziehau 	if (sc->hn_chim == NULL) {
541515516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate txbuf failed\n");
541615516c77SSepherosa Ziehau 		return (ENOMEM);
541715516c77SSepherosa Ziehau 	}
541815516c77SSepherosa Ziehau 
541915516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = ring_cnt;
542015516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
542115516c77SSepherosa Ziehau 
542215516c77SSepherosa Ziehau 	sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt,
542315516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
542415516c77SSepherosa Ziehau 
542515516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(sc->hn_dev);
542615516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev));
542715516c77SSepherosa Ziehau 
542815516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.tx sysctl tree */
542915516c77SSepherosa Ziehau 	sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx",
543015516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
543115516c77SSepherosa Ziehau 
543215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
543315516c77SSepherosa Ziehau 		int error;
543415516c77SSepherosa Ziehau 
543515516c77SSepherosa Ziehau 		error = hn_tx_ring_create(sc, i);
543615516c77SSepherosa Ziehau 		if (error)
543715516c77SSepherosa Ziehau 			return error;
543815516c77SSepherosa Ziehau 	}
543915516c77SSepherosa Ziehau 
544015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs",
544115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
544215516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_no_txdescs),
544315516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs");
544415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed",
544515516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
544615516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_send_failed),
544715516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure");
544815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed",
544915516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
545015516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_txdma_failed),
545115516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure");
5452dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed",
5453dc13fee6SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
5454dc13fee6SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_flush_failed),
5455dc13fee6SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU",
5456dc13fee6SSepherosa Ziehau 	    "# of packet transmission aggregation flush failure");
545715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed",
545815516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
545915516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_collapsed),
546015516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed");
546115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney",
546215516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
546315516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney),
546415516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send");
546515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried",
546615516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
546715516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney_tried),
546815516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries");
546915516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt",
547015516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0,
547115516c77SSepherosa Ziehau 	    "# of total TX descs");
547215516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max",
547315516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_chim_szmax, 0,
547415516c77SSepherosa Ziehau 	    "Chimney send packet size upper boundary");
547515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size",
547615516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
547715516c77SSepherosa Ziehau 	    hn_chim_size_sysctl, "I", "Chimney send packet size limit");
547815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size",
547915516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
548015516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_direct_tx_size),
548115516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
548215516c77SSepherosa Ziehau 	    "Size of the packet for direct transmission");
548315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx",
548415516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
548515516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_sched_tx),
548615516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
548715516c77SSepherosa Ziehau 	    "Always schedule transmission "
548815516c77SSepherosa Ziehau 	    "instead of doing direct transmission");
548915516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt",
549015516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings");
549115516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse",
549215516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings");
5493dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax",
5494dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0,
5495dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation size");
5496dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax",
5497dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
5498dc13fee6SSepherosa Ziehau 	    hn_txagg_pktmax_sysctl, "I",
5499dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation packets");
5500dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align",
5501dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
5502dc13fee6SSepherosa Ziehau 	    hn_txagg_align_sysctl, "I",
5503dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation alignment");
550415516c77SSepherosa Ziehau 
550515516c77SSepherosa Ziehau 	return 0;
550615516c77SSepherosa Ziehau }
550715516c77SSepherosa Ziehau 
550815516c77SSepherosa Ziehau static void
550915516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size)
551015516c77SSepherosa Ziehau {
551115516c77SSepherosa Ziehau 	int i;
551215516c77SSepherosa Ziehau 
5513a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
551415516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_chim_size = chim_size;
551515516c77SSepherosa Ziehau }
551615516c77SSepherosa Ziehau 
551715516c77SSepherosa Ziehau static void
551815516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu)
551915516c77SSepherosa Ziehau {
552015516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
55219c6cae24SSepherosa Ziehau 	u_int hw_tsomax;
552215516c77SSepherosa Ziehau 	int tso_minlen;
552315516c77SSepherosa Ziehau 
55249c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
55259c6cae24SSepherosa Ziehau 
552615516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0)
552715516c77SSepherosa Ziehau 		return;
552815516c77SSepherosa Ziehau 
552915516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_sgmin >= 2,
553015516c77SSepherosa Ziehau 	    ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin));
553115516c77SSepherosa Ziehau 	tso_minlen = sc->hn_ndis_tso_sgmin * mtu;
553215516c77SSepherosa Ziehau 
553315516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen &&
553415516c77SSepherosa Ziehau 	    sc->hn_ndis_tso_szmax <= IP_MAXPACKET,
553515516c77SSepherosa Ziehau 	    ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax));
553615516c77SSepherosa Ziehau 
553715516c77SSepherosa Ziehau 	if (tso_maxlen < tso_minlen)
553815516c77SSepherosa Ziehau 		tso_maxlen = tso_minlen;
553915516c77SSepherosa Ziehau 	else if (tso_maxlen > IP_MAXPACKET)
554015516c77SSepherosa Ziehau 		tso_maxlen = IP_MAXPACKET;
554115516c77SSepherosa Ziehau 	if (tso_maxlen > sc->hn_ndis_tso_szmax)
554215516c77SSepherosa Ziehau 		tso_maxlen = sc->hn_ndis_tso_szmax;
55439c6cae24SSepherosa Ziehau 	hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
55449c6cae24SSepherosa Ziehau 
55459c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_isready(sc)) {
55469c6cae24SSepherosa Ziehau 		if (hw_tsomax > sc->hn_vf_ifp->if_hw_tsomax)
55479c6cae24SSepherosa Ziehau 			hw_tsomax = sc->hn_vf_ifp->if_hw_tsomax;
55489c6cae24SSepherosa Ziehau 	}
55499c6cae24SSepherosa Ziehau 	ifp->if_hw_tsomax = hw_tsomax;
555015516c77SSepherosa Ziehau 	if (bootverbose)
555115516c77SSepherosa Ziehau 		if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax);
555215516c77SSepherosa Ziehau }
555315516c77SSepherosa Ziehau 
555415516c77SSepherosa Ziehau static void
555515516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc)
555615516c77SSepherosa Ziehau {
555715516c77SSepherosa Ziehau 	uint64_t csum_assist;
555815516c77SSepherosa Ziehau 	int i;
555915516c77SSepherosa Ziehau 
556015516c77SSepherosa Ziehau 	hn_set_chim_size(sc, sc->hn_chim_szmax);
556115516c77SSepherosa Ziehau 	if (hn_tx_chimney_size > 0 &&
556215516c77SSepherosa Ziehau 	    hn_tx_chimney_size < sc->hn_chim_szmax)
556315516c77SSepherosa Ziehau 		hn_set_chim_size(sc, hn_tx_chimney_size);
556415516c77SSepherosa Ziehau 
556515516c77SSepherosa Ziehau 	csum_assist = 0;
556615516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_IPCS)
556715516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP;
556815516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP4CS)
556915516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_TCP;
55702be266caSSepherosa Ziehau 	if ((sc->hn_caps & HN_CAP_UDP4CS) && hn_enable_udp4cs)
557115516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_UDP;
557215516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP6CS)
557315516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_TCP;
55742be266caSSepherosa Ziehau 	if ((sc->hn_caps & HN_CAP_UDP6CS) && hn_enable_udp6cs)
557515516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_UDP;
557615516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
557715516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_csum_assist = csum_assist;
557815516c77SSepherosa Ziehau 
557915516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_HASHVAL) {
558015516c77SSepherosa Ziehau 		/*
558115516c77SSepherosa Ziehau 		 * Support HASHVAL pktinfo on TX path.
558215516c77SSepherosa Ziehau 		 */
558315516c77SSepherosa Ziehau 		if (bootverbose)
558415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n");
558515516c77SSepherosa Ziehau 		for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
558615516c77SSepherosa Ziehau 			sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL;
558715516c77SSepherosa Ziehau 	}
558815516c77SSepherosa Ziehau }
558915516c77SSepherosa Ziehau 
559015516c77SSepherosa Ziehau static void
5591*db76829bSSepherosa Ziehau hn_fixup_rx_data(struct hn_softc *sc)
5592*db76829bSSepherosa Ziehau {
5593*db76829bSSepherosa Ziehau 
5594*db76829bSSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDPHASH) {
5595*db76829bSSepherosa Ziehau 		int i;
5596*db76829bSSepherosa Ziehau 
5597*db76829bSSepherosa Ziehau 		for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
5598*db76829bSSepherosa Ziehau 			sc->hn_rx_ring[i].hn_rx_flags |= HN_RX_FLAG_UDP_HASH;
5599*db76829bSSepherosa Ziehau 	}
5600*db76829bSSepherosa Ziehau }
5601*db76829bSSepherosa Ziehau 
5602*db76829bSSepherosa Ziehau static void
560315516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc)
560415516c77SSepherosa Ziehau {
560515516c77SSepherosa Ziehau 	int i;
560615516c77SSepherosa Ziehau 
560715516c77SSepherosa Ziehau 	if (sc->hn_chim != NULL) {
56082494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) {
560915516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim);
56102494d735SSepherosa Ziehau 		} else {
56112494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
56122494d735SSepherosa Ziehau 			    "chimney sending buffer is referenced");
56132494d735SSepherosa Ziehau 		}
561415516c77SSepherosa Ziehau 		sc->hn_chim = NULL;
561515516c77SSepherosa Ziehau 	}
561615516c77SSepherosa Ziehau 
561715516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt == 0)
561815516c77SSepherosa Ziehau 		return;
561915516c77SSepherosa Ziehau 
562015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
562115516c77SSepherosa Ziehau 		hn_tx_ring_destroy(&sc->hn_tx_ring[i]);
562215516c77SSepherosa Ziehau 
562315516c77SSepherosa Ziehau 	free(sc->hn_tx_ring, M_DEVBUF);
562415516c77SSepherosa Ziehau 	sc->hn_tx_ring = NULL;
562515516c77SSepherosa Ziehau 
562615516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = 0;
562715516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = 0;
562815516c77SSepherosa Ziehau }
562915516c77SSepherosa Ziehau 
563023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
563123bf9e15SSepherosa Ziehau 
563215516c77SSepherosa Ziehau static void
563315516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused)
563415516c77SSepherosa Ziehau {
563515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
563615516c77SSepherosa Ziehau 
563715516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
563815516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
563915516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
564015516c77SSepherosa Ziehau }
564115516c77SSepherosa Ziehau 
564223bf9e15SSepherosa Ziehau static int
564323bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len)
564423bf9e15SSepherosa Ziehau {
564523bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
564623bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
5647dc13fee6SSepherosa Ziehau 	int sched = 0;
564823bf9e15SSepherosa Ziehau 
564923bf9e15SSepherosa Ziehau 	KASSERT(hn_use_if_start,
565023bf9e15SSepherosa Ziehau 	    ("hn_start_locked is called, when if_start is disabled"));
565123bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
565223bf9e15SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
5653dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
565423bf9e15SSepherosa Ziehau 
565523bf9e15SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
5656dc13fee6SSepherosa Ziehau 		return (0);
565723bf9e15SSepherosa Ziehau 
565823bf9e15SSepherosa Ziehau 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
565923bf9e15SSepherosa Ziehau 	    IFF_DRV_RUNNING)
5660dc13fee6SSepherosa Ziehau 		return (0);
566123bf9e15SSepherosa Ziehau 
566223bf9e15SSepherosa Ziehau 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
566323bf9e15SSepherosa Ziehau 		struct hn_txdesc *txd;
566423bf9e15SSepherosa Ziehau 		struct mbuf *m_head;
566523bf9e15SSepherosa Ziehau 		int error;
566623bf9e15SSepherosa Ziehau 
566723bf9e15SSepherosa Ziehau 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
566823bf9e15SSepherosa Ziehau 		if (m_head == NULL)
566923bf9e15SSepherosa Ziehau 			break;
567023bf9e15SSepherosa Ziehau 
567123bf9e15SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
567223bf9e15SSepherosa Ziehau 			/*
567323bf9e15SSepherosa Ziehau 			 * This sending could be time consuming; let callers
567423bf9e15SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
567523bf9e15SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
567623bf9e15SSepherosa Ziehau 			 */
567723bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
5678dc13fee6SSepherosa Ziehau 			sched = 1;
5679dc13fee6SSepherosa Ziehau 			break;
568023bf9e15SSepherosa Ziehau 		}
568123bf9e15SSepherosa Ziehau 
5682edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
5683edd3f315SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
5684edd3f315SSepherosa Ziehau 			m_head = hn_tso_fixup(m_head);
5685edd3f315SSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
5686edd3f315SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5687edd3f315SSepherosa Ziehau 				continue;
5688edd3f315SSepherosa Ziehau 			}
5689c49d47daSSepherosa Ziehau 		} else if (m_head->m_pkthdr.csum_flags &
5690c49d47daSSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) {
5691c49d47daSSepherosa Ziehau 			m_head = hn_set_hlen(m_head);
5692c49d47daSSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
5693c49d47daSSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5694c49d47daSSepherosa Ziehau 				continue;
5695c49d47daSSepherosa Ziehau 			}
5696edd3f315SSepherosa Ziehau 		}
5697edd3f315SSepherosa Ziehau #endif
5698edd3f315SSepherosa Ziehau 
569923bf9e15SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
570023bf9e15SSepherosa Ziehau 		if (txd == NULL) {
570123bf9e15SSepherosa Ziehau 			txr->hn_no_txdescs++;
570223bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
570323bf9e15SSepherosa Ziehau 			atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
570423bf9e15SSepherosa Ziehau 			break;
570523bf9e15SSepherosa Ziehau 		}
570623bf9e15SSepherosa Ziehau 
5707dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
570823bf9e15SSepherosa Ziehau 		if (error) {
570923bf9e15SSepherosa Ziehau 			/* Both txd and m_head are freed */
5710dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
5711dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
571223bf9e15SSepherosa Ziehau 			continue;
571323bf9e15SSepherosa Ziehau 		}
571423bf9e15SSepherosa Ziehau 
5715dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
5716dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
5717dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
5718dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
5719dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
5720dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
5721dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
5722dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
5723dc13fee6SSepherosa Ziehau 					break;
5724dc13fee6SSepherosa Ziehau 				}
5725dc13fee6SSepherosa Ziehau 			} else {
5726dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
572723bf9e15SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
572823bf9e15SSepherosa Ziehau 				if (__predict_false(error)) {
572923bf9e15SSepherosa Ziehau 					/* txd is freed, but m_head is not */
573023bf9e15SSepherosa Ziehau 					IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
5731dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
5732dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
573323bf9e15SSepherosa Ziehau 					break;
573423bf9e15SSepherosa Ziehau 				}
573523bf9e15SSepherosa Ziehau 			}
5736dc13fee6SSepherosa Ziehau 		}
5737dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
5738dc13fee6SSepherosa Ziehau 		else {
5739dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
5740dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
5741dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
5742dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
5743dc13fee6SSepherosa Ziehau 		}
5744dc13fee6SSepherosa Ziehau #endif
5745dc13fee6SSepherosa Ziehau 	}
5746dc13fee6SSepherosa Ziehau 
5747dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
5748dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
5749dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
5750dc13fee6SSepherosa Ziehau 	return (sched);
575123bf9e15SSepherosa Ziehau }
575223bf9e15SSepherosa Ziehau 
575323bf9e15SSepherosa Ziehau static void
575423bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp)
575523bf9e15SSepherosa Ziehau {
575623bf9e15SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
575723bf9e15SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[0];
575823bf9e15SSepherosa Ziehau 
575923bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
576023bf9e15SSepherosa Ziehau 		goto do_sched;
576123bf9e15SSepherosa Ziehau 
576223bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
576323bf9e15SSepherosa Ziehau 		int sched;
576423bf9e15SSepherosa Ziehau 
576523bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
576623bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
576723bf9e15SSepherosa Ziehau 		if (!sched)
576823bf9e15SSepherosa Ziehau 			return;
576923bf9e15SSepherosa Ziehau 	}
577023bf9e15SSepherosa Ziehau do_sched:
577123bf9e15SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
577223bf9e15SSepherosa Ziehau }
577323bf9e15SSepherosa Ziehau 
577415516c77SSepherosa Ziehau static void
577515516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused)
577615516c77SSepherosa Ziehau {
577715516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
577815516c77SSepherosa Ziehau 
577915516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
578015516c77SSepherosa Ziehau 	atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE);
578115516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
578215516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
578315516c77SSepherosa Ziehau }
578415516c77SSepherosa Ziehau 
578523bf9e15SSepherosa Ziehau static void
578623bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr)
578723bf9e15SSepherosa Ziehau {
578823bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
578923bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
579023bf9e15SSepherosa Ziehau 
579123bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
579223bf9e15SSepherosa Ziehau 
579323bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
579423bf9e15SSepherosa Ziehau 		goto do_sched;
579523bf9e15SSepherosa Ziehau 
579623bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
579723bf9e15SSepherosa Ziehau 		int sched;
579823bf9e15SSepherosa Ziehau 
579923bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
580023bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
580123bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
580223bf9e15SSepherosa Ziehau 		if (sched) {
580323bf9e15SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
580423bf9e15SSepherosa Ziehau 			    &txr->hn_tx_task);
580523bf9e15SSepherosa Ziehau 		}
580623bf9e15SSepherosa Ziehau 	} else {
580723bf9e15SSepherosa Ziehau do_sched:
580823bf9e15SSepherosa Ziehau 		/*
580923bf9e15SSepherosa Ziehau 		 * Release the OACTIVE earlier, with the hope, that
581023bf9e15SSepherosa Ziehau 		 * others could catch up.  The task will clear the
581123bf9e15SSepherosa Ziehau 		 * flag again with the hn_tx_lock to avoid possible
581223bf9e15SSepherosa Ziehau 		 * races.
581323bf9e15SSepherosa Ziehau 		 */
581423bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
581523bf9e15SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
581623bf9e15SSepherosa Ziehau 	}
581723bf9e15SSepherosa Ziehau }
581823bf9e15SSepherosa Ziehau 
581923bf9e15SSepherosa Ziehau #endif	/* HN_IFSTART_SUPPORT */
582023bf9e15SSepherosa Ziehau 
582115516c77SSepherosa Ziehau static int
582215516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len)
582315516c77SSepherosa Ziehau {
582415516c77SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
582515516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
582615516c77SSepherosa Ziehau 	struct mbuf *m_head;
5827dc13fee6SSepherosa Ziehau 	int sched = 0;
582815516c77SSepherosa Ziehau 
582915516c77SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
583023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
583115516c77SSepherosa Ziehau 	KASSERT(hn_use_if_start == 0,
583215516c77SSepherosa Ziehau 	    ("hn_xmit is called, when if_start is enabled"));
583323bf9e15SSepherosa Ziehau #endif
5834dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
583515516c77SSepherosa Ziehau 
583615516c77SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
5837dc13fee6SSepherosa Ziehau 		return (0);
583815516c77SSepherosa Ziehau 
583915516c77SSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive)
5840dc13fee6SSepherosa Ziehau 		return (0);
584115516c77SSepherosa Ziehau 
584215516c77SSepherosa Ziehau 	while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) {
584315516c77SSepherosa Ziehau 		struct hn_txdesc *txd;
584415516c77SSepherosa Ziehau 		int error;
584515516c77SSepherosa Ziehau 
584615516c77SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
584715516c77SSepherosa Ziehau 			/*
584815516c77SSepherosa Ziehau 			 * This sending could be time consuming; let callers
584915516c77SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
585015516c77SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
585115516c77SSepherosa Ziehau 			 */
585215516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
5853dc13fee6SSepherosa Ziehau 			sched = 1;
5854dc13fee6SSepherosa Ziehau 			break;
585515516c77SSepherosa Ziehau 		}
585615516c77SSepherosa Ziehau 
585715516c77SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
585815516c77SSepherosa Ziehau 		if (txd == NULL) {
585915516c77SSepherosa Ziehau 			txr->hn_no_txdescs++;
586015516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
586115516c77SSepherosa Ziehau 			txr->hn_oactive = 1;
586215516c77SSepherosa Ziehau 			break;
586315516c77SSepherosa Ziehau 		}
586415516c77SSepherosa Ziehau 
5865dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
586615516c77SSepherosa Ziehau 		if (error) {
586715516c77SSepherosa Ziehau 			/* Both txd and m_head are freed; discard */
5868dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
5869dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
587015516c77SSepherosa Ziehau 			drbr_advance(ifp, txr->hn_mbuf_br);
587115516c77SSepherosa Ziehau 			continue;
587215516c77SSepherosa Ziehau 		}
587315516c77SSepherosa Ziehau 
5874dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
5875dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
5876dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
5877dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
5878dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
587915516c77SSepherosa Ziehau 				if (__predict_false(error)) {
588015516c77SSepherosa Ziehau 					txr->hn_oactive = 1;
588115516c77SSepherosa Ziehau 					break;
588215516c77SSepherosa Ziehau 				}
5883dc13fee6SSepherosa Ziehau 			} else {
5884dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
5885dc13fee6SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
5886dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
5887dc13fee6SSepherosa Ziehau 					/* txd is freed, but m_head is not */
5888dc13fee6SSepherosa Ziehau 					drbr_putback(ifp, txr->hn_mbuf_br,
5889dc13fee6SSepherosa Ziehau 					    m_head);
5890dc13fee6SSepherosa Ziehau 					txr->hn_oactive = 1;
5891dc13fee6SSepherosa Ziehau 					break;
5892dc13fee6SSepherosa Ziehau 				}
5893dc13fee6SSepherosa Ziehau 			}
5894dc13fee6SSepherosa Ziehau 		}
5895dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
5896dc13fee6SSepherosa Ziehau 		else {
5897dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
5898dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
5899dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
5900dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
5901dc13fee6SSepherosa Ziehau 		}
5902dc13fee6SSepherosa Ziehau #endif
590315516c77SSepherosa Ziehau 
590415516c77SSepherosa Ziehau 		/* Sent */
590515516c77SSepherosa Ziehau 		drbr_advance(ifp, txr->hn_mbuf_br);
590615516c77SSepherosa Ziehau 	}
5907dc13fee6SSepherosa Ziehau 
5908dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
5909dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
5910dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
5911dc13fee6SSepherosa Ziehau 	return (sched);
591215516c77SSepherosa Ziehau }
591315516c77SSepherosa Ziehau 
591415516c77SSepherosa Ziehau static int
591515516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m)
591615516c77SSepherosa Ziehau {
591715516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
591815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
591915516c77SSepherosa Ziehau 	int error, idx = 0;
592015516c77SSepherosa Ziehau 
59219c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) {
59229c6cae24SSepherosa Ziehau 		struct rm_priotracker pt;
59239c6cae24SSepherosa Ziehau 
59249c6cae24SSepherosa Ziehau 		rm_rlock(&sc->hn_vf_lock, &pt);
59259c6cae24SSepherosa Ziehau 		if (__predict_true(sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
59269c6cae24SSepherosa Ziehau 			struct mbuf *m_bpf = NULL;
59279c6cae24SSepherosa Ziehau 			int obytes, omcast;
59289c6cae24SSepherosa Ziehau 
59299c6cae24SSepherosa Ziehau 			obytes = m->m_pkthdr.len;
59309c6cae24SSepherosa Ziehau 			if (m->m_flags & M_MCAST)
59319c6cae24SSepherosa Ziehau 				omcast = 1;
59329c6cae24SSepherosa Ziehau 
59339c6cae24SSepherosa Ziehau 			if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF) {
59349c6cae24SSepherosa Ziehau 				if (bpf_peers_present(ifp->if_bpf)) {
59359c6cae24SSepherosa Ziehau 					m_bpf = m_copypacket(m, M_NOWAIT);
59369c6cae24SSepherosa Ziehau 					if (m_bpf == NULL) {
59379c6cae24SSepherosa Ziehau 						/*
59389c6cae24SSepherosa Ziehau 						 * Failed to grab a shallow
59399c6cae24SSepherosa Ziehau 						 * copy; tap now.
59409c6cae24SSepherosa Ziehau 						 */
59419c6cae24SSepherosa Ziehau 						ETHER_BPF_MTAP(ifp, m);
59429c6cae24SSepherosa Ziehau 					}
59439c6cae24SSepherosa Ziehau 				}
59449c6cae24SSepherosa Ziehau 			} else {
59459c6cae24SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, m);
59469c6cae24SSepherosa Ziehau 			}
59479c6cae24SSepherosa Ziehau 
59489c6cae24SSepherosa Ziehau 			error = sc->hn_vf_ifp->if_transmit(sc->hn_vf_ifp, m);
59499c6cae24SSepherosa Ziehau 			rm_runlock(&sc->hn_vf_lock, &pt);
59509c6cae24SSepherosa Ziehau 
59519c6cae24SSepherosa Ziehau 			if (m_bpf != NULL) {
59529c6cae24SSepherosa Ziehau 				if (!error)
59539c6cae24SSepherosa Ziehau 					ETHER_BPF_MTAP(ifp, m_bpf);
59549c6cae24SSepherosa Ziehau 				m_freem(m_bpf);
59559c6cae24SSepherosa Ziehau 			}
59569c6cae24SSepherosa Ziehau 
59579c6cae24SSepherosa Ziehau 			if (error == ENOBUFS) {
59589c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
59599c6cae24SSepherosa Ziehau 			} else if (error) {
59609c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
59619c6cae24SSepherosa Ziehau 			} else {
59629c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
59639c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OBYTES, obytes);
59649c6cae24SSepherosa Ziehau 				if (omcast) {
59659c6cae24SSepherosa Ziehau 					if_inc_counter(ifp, IFCOUNTER_OMCASTS,
59669c6cae24SSepherosa Ziehau 					    omcast);
59679c6cae24SSepherosa Ziehau 				}
59689c6cae24SSepherosa Ziehau 			}
59699c6cae24SSepherosa Ziehau 			return (error);
59709c6cae24SSepherosa Ziehau 		}
59719c6cae24SSepherosa Ziehau 		rm_runlock(&sc->hn_vf_lock, &pt);
59729c6cae24SSepherosa Ziehau 	}
59739c6cae24SSepherosa Ziehau 
5974edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
5975edd3f315SSepherosa Ziehau 	/*
5976c49d47daSSepherosa Ziehau 	 * Perform TSO packet header fixup or get l2/l3 header length now,
5977c49d47daSSepherosa Ziehau 	 * since packet headers should be cache-hot.
5978edd3f315SSepherosa Ziehau 	 */
5979edd3f315SSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
5980edd3f315SSepherosa Ziehau 		m = hn_tso_fixup(m);
5981edd3f315SSepherosa Ziehau 		if (__predict_false(m == NULL)) {
5982edd3f315SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5983edd3f315SSepherosa Ziehau 			return EIO;
5984edd3f315SSepherosa Ziehau 		}
5985c49d47daSSepherosa Ziehau 	} else if (m->m_pkthdr.csum_flags &
5986c49d47daSSepherosa Ziehau 	    (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) {
5987c49d47daSSepherosa Ziehau 		m = hn_set_hlen(m);
5988c49d47daSSepherosa Ziehau 		if (__predict_false(m == NULL)) {
5989c49d47daSSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5990c49d47daSSepherosa Ziehau 			return EIO;
5991c49d47daSSepherosa Ziehau 		}
5992edd3f315SSepherosa Ziehau 	}
5993edd3f315SSepherosa Ziehau #endif
5994edd3f315SSepherosa Ziehau 
599515516c77SSepherosa Ziehau 	/*
599615516c77SSepherosa Ziehau 	 * Select the TX ring based on flowid
599715516c77SSepherosa Ziehau 	 */
599834d68912SSepherosa Ziehau 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
599934d68912SSepherosa Ziehau #ifdef RSS
600034d68912SSepherosa Ziehau 		uint32_t bid;
600134d68912SSepherosa Ziehau 
600234d68912SSepherosa Ziehau 		if (rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m),
600334d68912SSepherosa Ziehau 		    &bid) == 0)
600434d68912SSepherosa Ziehau 			idx = bid % sc->hn_tx_ring_inuse;
600534d68912SSepherosa Ziehau 		else
600634d68912SSepherosa Ziehau #endif
6007cc0c6ebcSSepherosa Ziehau 		{
6008cc0c6ebcSSepherosa Ziehau #if defined(INET6) || defined(INET)
6009cc0c6ebcSSepherosa Ziehau 			int tcpsyn = 0;
6010cc0c6ebcSSepherosa Ziehau 
6011cc0c6ebcSSepherosa Ziehau 			if (m->m_pkthdr.len < 128 &&
6012cc0c6ebcSSepherosa Ziehau 			    (m->m_pkthdr.csum_flags &
6013cc0c6ebcSSepherosa Ziehau 			     (CSUM_IP_TCP | CSUM_IP6_TCP)) &&
6014cc0c6ebcSSepherosa Ziehau 			    (m->m_pkthdr.csum_flags & CSUM_TSO) == 0) {
6015cc0c6ebcSSepherosa Ziehau 				m = hn_check_tcpsyn(m, &tcpsyn);
6016cc0c6ebcSSepherosa Ziehau 				if (__predict_false(m == NULL)) {
6017cc0c6ebcSSepherosa Ziehau 					if_inc_counter(ifp,
6018cc0c6ebcSSepherosa Ziehau 					    IFCOUNTER_OERRORS, 1);
6019cc0c6ebcSSepherosa Ziehau 					return (EIO);
6020cc0c6ebcSSepherosa Ziehau 				}
6021cc0c6ebcSSepherosa Ziehau 			}
6022cc0c6ebcSSepherosa Ziehau #else
6023cc0c6ebcSSepherosa Ziehau 			const int tcpsyn = 0;
6024cc0c6ebcSSepherosa Ziehau #endif
6025cc0c6ebcSSepherosa Ziehau 			if (tcpsyn)
6026cc0c6ebcSSepherosa Ziehau 				idx = 0;
6027cc0c6ebcSSepherosa Ziehau 			else
602815516c77SSepherosa Ziehau 				idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse;
602934d68912SSepherosa Ziehau 		}
6030cc0c6ebcSSepherosa Ziehau 	}
603115516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[idx];
603215516c77SSepherosa Ziehau 
603315516c77SSepherosa Ziehau 	error = drbr_enqueue(ifp, txr->hn_mbuf_br, m);
603415516c77SSepherosa Ziehau 	if (error) {
603515516c77SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
603615516c77SSepherosa Ziehau 		return error;
603715516c77SSepherosa Ziehau 	}
603815516c77SSepherosa Ziehau 
603915516c77SSepherosa Ziehau 	if (txr->hn_oactive)
604015516c77SSepherosa Ziehau 		return 0;
604115516c77SSepherosa Ziehau 
604215516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
604315516c77SSepherosa Ziehau 		goto do_sched;
604415516c77SSepherosa Ziehau 
604515516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
604615516c77SSepherosa Ziehau 		int sched;
604715516c77SSepherosa Ziehau 
604815516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
604915516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
605015516c77SSepherosa Ziehau 		if (!sched)
605115516c77SSepherosa Ziehau 			return 0;
605215516c77SSepherosa Ziehau 	}
605315516c77SSepherosa Ziehau do_sched:
605415516c77SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
605515516c77SSepherosa Ziehau 	return 0;
605615516c77SSepherosa Ziehau }
605715516c77SSepherosa Ziehau 
605815516c77SSepherosa Ziehau static void
605915516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr)
606015516c77SSepherosa Ziehau {
606115516c77SSepherosa Ziehau 	struct mbuf *m;
606215516c77SSepherosa Ziehau 
606315516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
606415516c77SSepherosa Ziehau 	while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL)
606515516c77SSepherosa Ziehau 		m_freem(m);
606615516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
606715516c77SSepherosa Ziehau }
606815516c77SSepherosa Ziehau 
606915516c77SSepherosa Ziehau static void
607015516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp)
607115516c77SSepherosa Ziehau {
607215516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
60739c6cae24SSepherosa Ziehau 	struct rm_priotracker pt;
607415516c77SSepherosa Ziehau 	int i;
607515516c77SSepherosa Ziehau 
607615516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
607715516c77SSepherosa Ziehau 		hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
607815516c77SSepherosa Ziehau 	if_qflush(ifp);
60799c6cae24SSepherosa Ziehau 
60809c6cae24SSepherosa Ziehau 	rm_rlock(&sc->hn_vf_lock, &pt);
60819c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
60829c6cae24SSepherosa Ziehau 		sc->hn_vf_ifp->if_qflush(sc->hn_vf_ifp);
60839c6cae24SSepherosa Ziehau 	rm_runlock(&sc->hn_vf_lock, &pt);
608415516c77SSepherosa Ziehau }
608515516c77SSepherosa Ziehau 
608615516c77SSepherosa Ziehau static void
608715516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr)
608815516c77SSepherosa Ziehau {
608915516c77SSepherosa Ziehau 
609015516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
609115516c77SSepherosa Ziehau 		goto do_sched;
609215516c77SSepherosa Ziehau 
609315516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
609415516c77SSepherosa Ziehau 		int sched;
609515516c77SSepherosa Ziehau 
609615516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
609715516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
609815516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
609915516c77SSepherosa Ziehau 		if (sched) {
610015516c77SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
610115516c77SSepherosa Ziehau 			    &txr->hn_tx_task);
610215516c77SSepherosa Ziehau 		}
610315516c77SSepherosa Ziehau 	} else {
610415516c77SSepherosa Ziehau do_sched:
610515516c77SSepherosa Ziehau 		/*
610615516c77SSepherosa Ziehau 		 * Release the oactive earlier, with the hope, that
610715516c77SSepherosa Ziehau 		 * others could catch up.  The task will clear the
610815516c77SSepherosa Ziehau 		 * oactive again with the hn_tx_lock to avoid possible
610915516c77SSepherosa Ziehau 		 * races.
611015516c77SSepherosa Ziehau 		 */
611115516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
611215516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
611315516c77SSepherosa Ziehau 	}
611415516c77SSepherosa Ziehau }
611515516c77SSepherosa Ziehau 
611615516c77SSepherosa Ziehau static void
611715516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused)
611815516c77SSepherosa Ziehau {
611915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
612015516c77SSepherosa Ziehau 
612115516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
612215516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
612315516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
612415516c77SSepherosa Ziehau }
612515516c77SSepherosa Ziehau 
612615516c77SSepherosa Ziehau static void
612715516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused)
612815516c77SSepherosa Ziehau {
612915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
613015516c77SSepherosa Ziehau 
613115516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
613215516c77SSepherosa Ziehau 	txr->hn_oactive = 0;
613315516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
613415516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
613515516c77SSepherosa Ziehau }
613615516c77SSepherosa Ziehau 
613715516c77SSepherosa Ziehau static int
613815516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan)
613915516c77SSepherosa Ziehau {
614015516c77SSepherosa Ziehau 	struct vmbus_chan_br cbr;
614115516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
614215516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = NULL;
614315516c77SSepherosa Ziehau 	int idx, error;
614415516c77SSepherosa Ziehau 
614515516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
614615516c77SSepherosa Ziehau 
614715516c77SSepherosa Ziehau 	/*
614815516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
614915516c77SSepherosa Ziehau 	 */
615015516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
615115516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
615215516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
615315516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
615415516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0,
615515516c77SSepherosa Ziehau 	    ("RX ring %d already attached", idx));
615615516c77SSepherosa Ziehau 	rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED;
61573ab0fea1SDexuan Cui 	rxr->hn_chan = chan;
615815516c77SSepherosa Ziehau 
615915516c77SSepherosa Ziehau 	if (bootverbose) {
616015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n",
616115516c77SSepherosa Ziehau 		    idx, vmbus_chan_id(chan));
616215516c77SSepherosa Ziehau 	}
616315516c77SSepherosa Ziehau 
616415516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
616515516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[idx];
616615516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0,
616715516c77SSepherosa Ziehau 		    ("TX ring %d already attached", idx));
616815516c77SSepherosa Ziehau 		txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED;
616915516c77SSepherosa Ziehau 
617015516c77SSepherosa Ziehau 		txr->hn_chan = chan;
617115516c77SSepherosa Ziehau 		if (bootverbose) {
617215516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n",
617315516c77SSepherosa Ziehau 			    idx, vmbus_chan_id(chan));
617415516c77SSepherosa Ziehau 		}
617515516c77SSepherosa Ziehau 	}
617615516c77SSepherosa Ziehau 
617715516c77SSepherosa Ziehau 	/* Bind this channel to a proper CPU. */
61780e11868dSSepherosa Ziehau 	vmbus_chan_cpu_set(chan, HN_RING_IDX2CPU(sc, idx));
617915516c77SSepherosa Ziehau 
618015516c77SSepherosa Ziehau 	/*
618115516c77SSepherosa Ziehau 	 * Open this channel
618215516c77SSepherosa Ziehau 	 */
618315516c77SSepherosa Ziehau 	cbr.cbr = rxr->hn_br;
618415516c77SSepherosa Ziehau 	cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr;
618515516c77SSepherosa Ziehau 	cbr.cbr_txsz = HN_TXBR_SIZE;
618615516c77SSepherosa Ziehau 	cbr.cbr_rxsz = HN_RXBR_SIZE;
618715516c77SSepherosa Ziehau 	error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr);
618815516c77SSepherosa Ziehau 	if (error) {
618971e8ac56SSepherosa Ziehau 		if (error == EISCONN) {
619071e8ac56SSepherosa Ziehau 			if_printf(sc->hn_ifp, "bufring is connected after "
619171e8ac56SSepherosa Ziehau 			    "chan%u open failure\n", vmbus_chan_id(chan));
619271e8ac56SSepherosa Ziehau 			rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
619371e8ac56SSepherosa Ziehau 		} else {
619415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "open chan%u failed: %d\n",
619515516c77SSepherosa Ziehau 			    vmbus_chan_id(chan), error);
619671e8ac56SSepherosa Ziehau 		}
619715516c77SSepherosa Ziehau 	}
619815516c77SSepherosa Ziehau 	return (error);
619915516c77SSepherosa Ziehau }
620015516c77SSepherosa Ziehau 
620115516c77SSepherosa Ziehau static void
620215516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan)
620315516c77SSepherosa Ziehau {
620415516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
62052494d735SSepherosa Ziehau 	int idx, error;
620615516c77SSepherosa Ziehau 
620715516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
620815516c77SSepherosa Ziehau 
620915516c77SSepherosa Ziehau 	/*
621015516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
621115516c77SSepherosa Ziehau 	 */
621215516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
621315516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
621415516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
621515516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
621615516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED),
621715516c77SSepherosa Ziehau 	    ("RX ring %d is not attached", idx));
621815516c77SSepherosa Ziehau 	rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
621915516c77SSepherosa Ziehau 
622015516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
622115516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[idx];
622215516c77SSepherosa Ziehau 
622315516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED),
622415516c77SSepherosa Ziehau 		    ("TX ring %d is not attached attached", idx));
622515516c77SSepherosa Ziehau 		txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
622615516c77SSepherosa Ziehau 	}
622715516c77SSepherosa Ziehau 
622815516c77SSepherosa Ziehau 	/*
622915516c77SSepherosa Ziehau 	 * Close this channel.
623015516c77SSepherosa Ziehau 	 *
623115516c77SSepherosa Ziehau 	 * NOTE:
623215516c77SSepherosa Ziehau 	 * Channel closing does _not_ destroy the target channel.
623315516c77SSepherosa Ziehau 	 */
62342494d735SSepherosa Ziehau 	error = vmbus_chan_close_direct(chan);
62352494d735SSepherosa Ziehau 	if (error == EISCONN) {
6236aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u bufring is connected "
6237aa1a2adcSSepherosa Ziehau 		    "after being closed\n", vmbus_chan_id(chan));
62382494d735SSepherosa Ziehau 		rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
62392494d735SSepherosa Ziehau 	} else if (error) {
6240aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u close failed: %d\n",
6241aa1a2adcSSepherosa Ziehau 		    vmbus_chan_id(chan), error);
62422494d735SSepherosa Ziehau 	}
624315516c77SSepherosa Ziehau }
624415516c77SSepherosa Ziehau 
624515516c77SSepherosa Ziehau static int
624615516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc)
624715516c77SSepherosa Ziehau {
624815516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
624915516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
625015516c77SSepherosa Ziehau 	int i, error = 0;
625115516c77SSepherosa Ziehau 
625271e8ac56SSepherosa Ziehau 	KASSERT(subchan_cnt > 0, ("no sub-channels"));
625315516c77SSepherosa Ziehau 
625415516c77SSepherosa Ziehau 	/* Attach the sub-channels. */
625515516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
625615516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i) {
625771e8ac56SSepherosa Ziehau 		int error1;
625871e8ac56SSepherosa Ziehau 
625971e8ac56SSepherosa Ziehau 		error1 = hn_chan_attach(sc, subchans[i]);
626071e8ac56SSepherosa Ziehau 		if (error1) {
626171e8ac56SSepherosa Ziehau 			error = error1;
626271e8ac56SSepherosa Ziehau 			/* Move on; all channels will be detached later. */
626371e8ac56SSepherosa Ziehau 		}
626415516c77SSepherosa Ziehau 	}
626515516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
626615516c77SSepherosa Ziehau 
626715516c77SSepherosa Ziehau 	if (error) {
626815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error);
626915516c77SSepherosa Ziehau 	} else {
627015516c77SSepherosa Ziehau 		if (bootverbose) {
627115516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "%d sub-channels attached\n",
627215516c77SSepherosa Ziehau 			    subchan_cnt);
627315516c77SSepherosa Ziehau 		}
627415516c77SSepherosa Ziehau 	}
627515516c77SSepherosa Ziehau 	return (error);
627615516c77SSepherosa Ziehau }
627715516c77SSepherosa Ziehau 
627815516c77SSepherosa Ziehau static void
627915516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc)
628015516c77SSepherosa Ziehau {
628115516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
628215516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
628315516c77SSepherosa Ziehau 	int i;
628415516c77SSepherosa Ziehau 
628515516c77SSepherosa Ziehau 	if (subchan_cnt == 0)
628615516c77SSepherosa Ziehau 		goto back;
628715516c77SSepherosa Ziehau 
628815516c77SSepherosa Ziehau 	/* Detach the sub-channels. */
628915516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
629015516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i)
629115516c77SSepherosa Ziehau 		hn_chan_detach(sc, subchans[i]);
629215516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
629315516c77SSepherosa Ziehau 
629415516c77SSepherosa Ziehau back:
629515516c77SSepherosa Ziehau 	/*
629615516c77SSepherosa Ziehau 	 * Detach the primary channel, _after_ all sub-channels
629715516c77SSepherosa Ziehau 	 * are detached.
629815516c77SSepherosa Ziehau 	 */
629915516c77SSepherosa Ziehau 	hn_chan_detach(sc, sc->hn_prichan);
630015516c77SSepherosa Ziehau 
630115516c77SSepherosa Ziehau 	/* Wait for sub-channels to be destroyed, if any. */
630215516c77SSepherosa Ziehau 	vmbus_subchan_drain(sc->hn_prichan);
630315516c77SSepherosa Ziehau 
630415516c77SSepherosa Ziehau #ifdef INVARIANTS
630515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
630615516c77SSepherosa Ziehau 		KASSERT((sc->hn_rx_ring[i].hn_rx_flags &
630715516c77SSepherosa Ziehau 		    HN_RX_FLAG_ATTACHED) == 0,
630815516c77SSepherosa Ziehau 		    ("%dth RX ring is still attached", i));
630915516c77SSepherosa Ziehau 	}
631015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
631115516c77SSepherosa Ziehau 		KASSERT((sc->hn_tx_ring[i].hn_tx_flags &
631215516c77SSepherosa Ziehau 		    HN_TX_FLAG_ATTACHED) == 0,
631315516c77SSepherosa Ziehau 		    ("%dth TX ring is still attached", i));
631415516c77SSepherosa Ziehau 	}
631515516c77SSepherosa Ziehau #endif
631615516c77SSepherosa Ziehau }
631715516c77SSepherosa Ziehau 
631815516c77SSepherosa Ziehau static int
631915516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch)
632015516c77SSepherosa Ziehau {
632115516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
632215516c77SSepherosa Ziehau 	int nchan, rxr_cnt, error;
632315516c77SSepherosa Ziehau 
632415516c77SSepherosa Ziehau 	nchan = *nsubch + 1;
632515516c77SSepherosa Ziehau 	if (nchan == 1) {
632615516c77SSepherosa Ziehau 		/*
632715516c77SSepherosa Ziehau 		 * Multiple RX/TX rings are not requested.
632815516c77SSepherosa Ziehau 		 */
632915516c77SSepherosa Ziehau 		*nsubch = 0;
633015516c77SSepherosa Ziehau 		return (0);
633115516c77SSepherosa Ziehau 	}
633215516c77SSepherosa Ziehau 
633315516c77SSepherosa Ziehau 	/*
633415516c77SSepherosa Ziehau 	 * Query RSS capabilities, e.g. # of RX rings, and # of indirect
633515516c77SSepherosa Ziehau 	 * table entries.
633615516c77SSepherosa Ziehau 	 */
633715516c77SSepherosa Ziehau 	error = hn_rndis_query_rsscaps(sc, &rxr_cnt);
633815516c77SSepherosa Ziehau 	if (error) {
633915516c77SSepherosa Ziehau 		/* No RSS; this is benign. */
634015516c77SSepherosa Ziehau 		*nsubch = 0;
634115516c77SSepherosa Ziehau 		return (0);
634215516c77SSepherosa Ziehau 	}
634315516c77SSepherosa Ziehau 	if (bootverbose) {
634415516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
634515516c77SSepherosa Ziehau 		    rxr_cnt, nchan);
634615516c77SSepherosa Ziehau 	}
634715516c77SSepherosa Ziehau 
634815516c77SSepherosa Ziehau 	if (nchan > rxr_cnt)
634915516c77SSepherosa Ziehau 		nchan = rxr_cnt;
635015516c77SSepherosa Ziehau 	if (nchan == 1) {
635115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n");
635215516c77SSepherosa Ziehau 		*nsubch = 0;
635315516c77SSepherosa Ziehau 		return (0);
635415516c77SSepherosa Ziehau 	}
635515516c77SSepherosa Ziehau 
635615516c77SSepherosa Ziehau 	/*
635715516c77SSepherosa Ziehau 	 * Allocate sub-channels from NVS.
635815516c77SSepherosa Ziehau 	 */
635915516c77SSepherosa Ziehau 	*nsubch = nchan - 1;
636015516c77SSepherosa Ziehau 	error = hn_nvs_alloc_subchans(sc, nsubch);
636115516c77SSepherosa Ziehau 	if (error || *nsubch == 0) {
636215516c77SSepherosa Ziehau 		/* Failed to allocate sub-channels. */
636315516c77SSepherosa Ziehau 		*nsubch = 0;
636415516c77SSepherosa Ziehau 		return (0);
636515516c77SSepherosa Ziehau 	}
636615516c77SSepherosa Ziehau 
636715516c77SSepherosa Ziehau 	/*
636815516c77SSepherosa Ziehau 	 * Wait for all sub-channels to become ready before moving on.
636915516c77SSepherosa Ziehau 	 */
637015516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch);
637115516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, *nsubch);
637215516c77SSepherosa Ziehau 	return (0);
637315516c77SSepherosa Ziehau }
637415516c77SSepherosa Ziehau 
63752494d735SSepherosa Ziehau static bool
63762494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc)
63772494d735SSepherosa Ziehau {
63782494d735SSepherosa Ziehau 	int i;
63792494d735SSepherosa Ziehau 
63802494d735SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_ERRORS)
63812494d735SSepherosa Ziehau 		return (false);
63822494d735SSepherosa Ziehau 
63832494d735SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
63842494d735SSepherosa Ziehau 		const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
63852494d735SSepherosa Ziehau 
63862494d735SSepherosa Ziehau 		if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF)
63872494d735SSepherosa Ziehau 			return (false);
63882494d735SSepherosa Ziehau 	}
63892494d735SSepherosa Ziehau 	return (true);
63902494d735SSepherosa Ziehau }
63912494d735SSepherosa Ziehau 
6392b3b75d9cSSepherosa Ziehau /*
6393b3b75d9cSSepherosa Ziehau  * Make sure that the RX filter is zero after the successful
6394b3b75d9cSSepherosa Ziehau  * RNDIS initialization.
6395b3b75d9cSSepherosa Ziehau  *
6396b3b75d9cSSepherosa Ziehau  * NOTE:
6397b3b75d9cSSepherosa Ziehau  * Under certain conditions on certain versions of Hyper-V,
6398b3b75d9cSSepherosa Ziehau  * the RNDIS rxfilter is _not_ zero on the hypervisor side
6399b3b75d9cSSepherosa Ziehau  * after the successful RNDIS initialization, which breaks
6400b3b75d9cSSepherosa Ziehau  * the assumption of any following code (well, it breaks the
6401b3b75d9cSSepherosa Ziehau  * RNDIS API contract actually).  Clear the RNDIS rxfilter
6402b3b75d9cSSepherosa Ziehau  * explicitly, drain packets sneaking through, and drain the
6403b3b75d9cSSepherosa Ziehau  * interrupt taskqueues scheduled due to the stealth packets.
6404b3b75d9cSSepherosa Ziehau  */
6405b3b75d9cSSepherosa Ziehau static void
6406b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(struct hn_softc *sc, int nchan)
6407b3b75d9cSSepherosa Ziehau {
6408b3b75d9cSSepherosa Ziehau 
6409b3b75d9cSSepherosa Ziehau 	hn_disable_rx(sc);
6410b3b75d9cSSepherosa Ziehau 	hn_drain_rxtx(sc, nchan);
6411b3b75d9cSSepherosa Ziehau }
6412b3b75d9cSSepherosa Ziehau 
641315516c77SSepherosa Ziehau static int
641415516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu)
641515516c77SSepherosa Ziehau {
641671e8ac56SSepherosa Ziehau #define ATTACHED_NVS		0x0002
641771e8ac56SSepherosa Ziehau #define ATTACHED_RNDIS		0x0004
641871e8ac56SSepherosa Ziehau 
641915516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
6420b3b75d9cSSepherosa Ziehau 	int error, nsubch, nchan = 1, i, rndis_inited;
642171e8ac56SSepherosa Ziehau 	uint32_t old_caps, attached = 0;
642215516c77SSepherosa Ziehau 
642315516c77SSepherosa Ziehau 	KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0,
642415516c77SSepherosa Ziehau 	    ("synthetic parts were attached"));
642515516c77SSepherosa Ziehau 
64262494d735SSepherosa Ziehau 	if (!hn_synth_attachable(sc))
64272494d735SSepherosa Ziehau 		return (ENXIO);
64282494d735SSepherosa Ziehau 
642915516c77SSepherosa Ziehau 	/* Save capabilities for later verification. */
643015516c77SSepherosa Ziehau 	old_caps = sc->hn_caps;
643115516c77SSepherosa Ziehau 	sc->hn_caps = 0;
643215516c77SSepherosa Ziehau 
643315516c77SSepherosa Ziehau 	/* Clear RSS stuffs. */
643415516c77SSepherosa Ziehau 	sc->hn_rss_ind_size = 0;
643515516c77SSepherosa Ziehau 	sc->hn_rss_hash = 0;
6436642ec226SSepherosa Ziehau 	sc->hn_rss_hcap = 0;
643715516c77SSepherosa Ziehau 
643815516c77SSepherosa Ziehau 	/*
643915516c77SSepherosa Ziehau 	 * Attach the primary channel _before_ attaching NVS and RNDIS.
644015516c77SSepherosa Ziehau 	 */
644115516c77SSepherosa Ziehau 	error = hn_chan_attach(sc, sc->hn_prichan);
644215516c77SSepherosa Ziehau 	if (error)
644371e8ac56SSepherosa Ziehau 		goto failed;
644415516c77SSepherosa Ziehau 
644515516c77SSepherosa Ziehau 	/*
644615516c77SSepherosa Ziehau 	 * Attach NVS.
644715516c77SSepherosa Ziehau 	 */
644815516c77SSepherosa Ziehau 	error = hn_nvs_attach(sc, mtu);
644915516c77SSepherosa Ziehau 	if (error)
645071e8ac56SSepherosa Ziehau 		goto failed;
645171e8ac56SSepherosa Ziehau 	attached |= ATTACHED_NVS;
645215516c77SSepherosa Ziehau 
645315516c77SSepherosa Ziehau 	/*
645415516c77SSepherosa Ziehau 	 * Attach RNDIS _after_ NVS is attached.
645515516c77SSepherosa Ziehau 	 */
6456b3b75d9cSSepherosa Ziehau 	error = hn_rndis_attach(sc, mtu, &rndis_inited);
6457b3b75d9cSSepherosa Ziehau 	if (rndis_inited)
6458b3b75d9cSSepherosa Ziehau 		attached |= ATTACHED_RNDIS;
645915516c77SSepherosa Ziehau 	if (error)
646071e8ac56SSepherosa Ziehau 		goto failed;
646115516c77SSepherosa Ziehau 
646215516c77SSepherosa Ziehau 	/*
646315516c77SSepherosa Ziehau 	 * Make sure capabilities are not changed.
646415516c77SSepherosa Ziehau 	 */
646515516c77SSepherosa Ziehau 	if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) {
646615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n",
646715516c77SSepherosa Ziehau 		    old_caps, sc->hn_caps);
646871e8ac56SSepherosa Ziehau 		error = ENXIO;
646971e8ac56SSepherosa Ziehau 		goto failed;
647015516c77SSepherosa Ziehau 	}
647115516c77SSepherosa Ziehau 
647215516c77SSepherosa Ziehau 	/*
647315516c77SSepherosa Ziehau 	 * Allocate sub-channels for multi-TX/RX rings.
647415516c77SSepherosa Ziehau 	 *
647515516c77SSepherosa Ziehau 	 * NOTE:
647615516c77SSepherosa Ziehau 	 * The # of RX rings that can be used is equivalent to the # of
647715516c77SSepherosa Ziehau 	 * channels to be requested.
647815516c77SSepherosa Ziehau 	 */
647915516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_cnt - 1;
648015516c77SSepherosa Ziehau 	error = hn_synth_alloc_subchans(sc, &nsubch);
648115516c77SSepherosa Ziehau 	if (error)
648271e8ac56SSepherosa Ziehau 		goto failed;
648371e8ac56SSepherosa Ziehau 	/* NOTE: _Full_ synthetic parts detach is required now. */
648471e8ac56SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED;
648515516c77SSepherosa Ziehau 
648671e8ac56SSepherosa Ziehau 	/*
648771e8ac56SSepherosa Ziehau 	 * Set the # of TX/RX rings that could be used according to
648871e8ac56SSepherosa Ziehau 	 * the # of channels that NVS offered.
648971e8ac56SSepherosa Ziehau 	 */
649015516c77SSepherosa Ziehau 	nchan = nsubch + 1;
649171e8ac56SSepherosa Ziehau 	hn_set_ring_inuse(sc, nchan);
649215516c77SSepherosa Ziehau 	if (nchan == 1) {
649315516c77SSepherosa Ziehau 		/* Only the primary channel can be used; done */
649415516c77SSepherosa Ziehau 		goto back;
649515516c77SSepherosa Ziehau 	}
649615516c77SSepherosa Ziehau 
649715516c77SSepherosa Ziehau 	/*
649871e8ac56SSepherosa Ziehau 	 * Attach the sub-channels.
6499afd4971bSSepherosa Ziehau 	 *
6500afd4971bSSepherosa Ziehau 	 * NOTE: hn_set_ring_inuse() _must_ have been called.
650115516c77SSepherosa Ziehau 	 */
650271e8ac56SSepherosa Ziehau 	error = hn_attach_subchans(sc);
650371e8ac56SSepherosa Ziehau 	if (error)
650471e8ac56SSepherosa Ziehau 		goto failed;
650515516c77SSepherosa Ziehau 
650671e8ac56SSepherosa Ziehau 	/*
650771e8ac56SSepherosa Ziehau 	 * Configure RSS key and indirect table _after_ all sub-channels
650871e8ac56SSepherosa Ziehau 	 * are attached.
650971e8ac56SSepherosa Ziehau 	 */
651015516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) {
651115516c77SSepherosa Ziehau 		/*
651215516c77SSepherosa Ziehau 		 * RSS key is not set yet; set it to the default RSS key.
651315516c77SSepherosa Ziehau 		 */
651415516c77SSepherosa Ziehau 		if (bootverbose)
651515516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS key\n");
651634d68912SSepherosa Ziehau #ifdef RSS
651734d68912SSepherosa Ziehau 		rss_getkey(rss->rss_key);
651834d68912SSepherosa Ziehau #else
651915516c77SSepherosa Ziehau 		memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key));
652034d68912SSepherosa Ziehau #endif
652115516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
652215516c77SSepherosa Ziehau 	}
652315516c77SSepherosa Ziehau 
652415516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) {
652515516c77SSepherosa Ziehau 		/*
652615516c77SSepherosa Ziehau 		 * RSS indirect table is not set yet; set it up in round-
652715516c77SSepherosa Ziehau 		 * robin fashion.
652815516c77SSepherosa Ziehau 		 */
652915516c77SSepherosa Ziehau 		if (bootverbose) {
653015516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS indirect "
653115516c77SSepherosa Ziehau 			    "table\n");
653215516c77SSepherosa Ziehau 		}
653334d68912SSepherosa Ziehau 		for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
653434d68912SSepherosa Ziehau 			uint32_t subidx;
653534d68912SSepherosa Ziehau 
653634d68912SSepherosa Ziehau #ifdef RSS
653734d68912SSepherosa Ziehau 			subidx = rss_get_indirection_to_bucket(i);
653834d68912SSepherosa Ziehau #else
653934d68912SSepherosa Ziehau 			subidx = i;
654034d68912SSepherosa Ziehau #endif
654134d68912SSepherosa Ziehau 			rss->rss_ind[i] = subidx % nchan;
654234d68912SSepherosa Ziehau 		}
654315516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSIND;
654415516c77SSepherosa Ziehau 	} else {
654515516c77SSepherosa Ziehau 		/*
654615516c77SSepherosa Ziehau 		 * # of usable channels may be changed, so we have to
654715516c77SSepherosa Ziehau 		 * make sure that all entries in RSS indirect table
654815516c77SSepherosa Ziehau 		 * are valid.
6549afd4971bSSepherosa Ziehau 		 *
6550afd4971bSSepherosa Ziehau 		 * NOTE: hn_set_ring_inuse() _must_ have been called.
655115516c77SSepherosa Ziehau 		 */
6552afd4971bSSepherosa Ziehau 		hn_rss_ind_fixup(sc);
655315516c77SSepherosa Ziehau 	}
655415516c77SSepherosa Ziehau 
6555642ec226SSepherosa Ziehau 	sc->hn_rss_hash = sc->hn_rss_hcap;
6556642ec226SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) ||
6557642ec226SSepherosa Ziehau 	    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
6558642ec226SSepherosa Ziehau 		/* NOTE: Don't reconfigure RSS; will do immediately. */
6559642ec226SSepherosa Ziehau 		hn_vf_rss_fixup(sc, false);
6560642ec226SSepherosa Ziehau 	}
656115516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
656215516c77SSepherosa Ziehau 	if (error)
656371e8ac56SSepherosa Ziehau 		goto failed;
656471e8ac56SSepherosa Ziehau back:
6565dc13fee6SSepherosa Ziehau 	/*
6566dc13fee6SSepherosa Ziehau 	 * Fixup transmission aggregation setup.
6567dc13fee6SSepherosa Ziehau 	 */
6568dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
6569b3b75d9cSSepherosa Ziehau 	hn_rndis_init_fixat(sc, nchan);
657015516c77SSepherosa Ziehau 	return (0);
657171e8ac56SSepherosa Ziehau 
657271e8ac56SSepherosa Ziehau failed:
657371e8ac56SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
6574b3b75d9cSSepherosa Ziehau 		hn_rndis_init_fixat(sc, nchan);
657571e8ac56SSepherosa Ziehau 		hn_synth_detach(sc);
657671e8ac56SSepherosa Ziehau 	} else {
6577b3b75d9cSSepherosa Ziehau 		if (attached & ATTACHED_RNDIS) {
6578b3b75d9cSSepherosa Ziehau 			hn_rndis_init_fixat(sc, nchan);
657971e8ac56SSepherosa Ziehau 			hn_rndis_detach(sc);
6580b3b75d9cSSepherosa Ziehau 		}
658171e8ac56SSepherosa Ziehau 		if (attached & ATTACHED_NVS)
658271e8ac56SSepherosa Ziehau 			hn_nvs_detach(sc);
658371e8ac56SSepherosa Ziehau 		hn_chan_detach(sc, sc->hn_prichan);
658471e8ac56SSepherosa Ziehau 		/* Restore old capabilities. */
658571e8ac56SSepherosa Ziehau 		sc->hn_caps = old_caps;
658671e8ac56SSepherosa Ziehau 	}
658771e8ac56SSepherosa Ziehau 	return (error);
658871e8ac56SSepherosa Ziehau 
658971e8ac56SSepherosa Ziehau #undef ATTACHED_RNDIS
659071e8ac56SSepherosa Ziehau #undef ATTACHED_NVS
659115516c77SSepherosa Ziehau }
659215516c77SSepherosa Ziehau 
659315516c77SSepherosa Ziehau /*
659415516c77SSepherosa Ziehau  * NOTE:
659515516c77SSepherosa Ziehau  * The interface must have been suspended though hn_suspend(), before
659615516c77SSepherosa Ziehau  * this function get called.
659715516c77SSepherosa Ziehau  */
659815516c77SSepherosa Ziehau static void
659915516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc)
660015516c77SSepherosa Ziehau {
660115516c77SSepherosa Ziehau 
660215516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
660315516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
660415516c77SSepherosa Ziehau 
660515516c77SSepherosa Ziehau 	/* Detach the RNDIS first. */
660615516c77SSepherosa Ziehau 	hn_rndis_detach(sc);
660715516c77SSepherosa Ziehau 
660815516c77SSepherosa Ziehau 	/* Detach NVS. */
660915516c77SSepherosa Ziehau 	hn_nvs_detach(sc);
661015516c77SSepherosa Ziehau 
661115516c77SSepherosa Ziehau 	/* Detach all of the channels. */
661215516c77SSepherosa Ziehau 	hn_detach_allchans(sc);
661315516c77SSepherosa Ziehau 
661415516c77SSepherosa Ziehau 	sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED;
661515516c77SSepherosa Ziehau }
661615516c77SSepherosa Ziehau 
661715516c77SSepherosa Ziehau static void
661815516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt)
661915516c77SSepherosa Ziehau {
662015516c77SSepherosa Ziehau 	KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt,
662115516c77SSepherosa Ziehau 	    ("invalid ring count %d", ring_cnt));
662215516c77SSepherosa Ziehau 
662315516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt > ring_cnt)
662415516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = ring_cnt;
662515516c77SSepherosa Ziehau 	else
662615516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
662715516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = ring_cnt;
662815516c77SSepherosa Ziehau 
662934d68912SSepherosa Ziehau #ifdef RSS
663034d68912SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse != rss_getnumbuckets()) {
663134d68912SSepherosa Ziehau 		if_printf(sc->hn_ifp, "# of RX rings (%d) does not match "
663234d68912SSepherosa Ziehau 		    "# of RSS buckets (%d)\n", sc->hn_rx_ring_inuse,
663334d68912SSepherosa Ziehau 		    rss_getnumbuckets());
663434d68912SSepherosa Ziehau 	}
663534d68912SSepherosa Ziehau #endif
663634d68912SSepherosa Ziehau 
663715516c77SSepherosa Ziehau 	if (bootverbose) {
663815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n",
663915516c77SSepherosa Ziehau 		    sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
664015516c77SSepherosa Ziehau 	}
664115516c77SSepherosa Ziehau }
664215516c77SSepherosa Ziehau 
664315516c77SSepherosa Ziehau static void
664425641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan)
664515516c77SSepherosa Ziehau {
664615516c77SSepherosa Ziehau 
664725641fc7SSepherosa Ziehau 	/*
664825641fc7SSepherosa Ziehau 	 * NOTE:
664925641fc7SSepherosa Ziehau 	 * The TX bufring will not be drained by the hypervisor,
665025641fc7SSepherosa Ziehau 	 * if the primary channel is revoked.
665125641fc7SSepherosa Ziehau 	 */
665225641fc7SSepherosa Ziehau 	while (!vmbus_chan_rx_empty(chan) ||
665325641fc7SSepherosa Ziehau 	    (!vmbus_chan_is_revoked(sc->hn_prichan) &&
665425641fc7SSepherosa Ziehau 	     !vmbus_chan_tx_empty(chan)))
665515516c77SSepherosa Ziehau 		pause("waitch", 1);
665615516c77SSepherosa Ziehau 	vmbus_chan_intr_drain(chan);
665715516c77SSepherosa Ziehau }
665815516c77SSepherosa Ziehau 
665915516c77SSepherosa Ziehau static void
6660b3b75d9cSSepherosa Ziehau hn_disable_rx(struct hn_softc *sc)
6661b3b75d9cSSepherosa Ziehau {
6662b3b75d9cSSepherosa Ziehau 
6663b3b75d9cSSepherosa Ziehau 	/*
6664b3b75d9cSSepherosa Ziehau 	 * Disable RX by clearing RX filter forcefully.
6665b3b75d9cSSepherosa Ziehau 	 */
6666b3b75d9cSSepherosa Ziehau 	sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE;
6667b3b75d9cSSepherosa Ziehau 	hn_rndis_set_rxfilter(sc, sc->hn_rx_filter); /* ignore error */
6668b3b75d9cSSepherosa Ziehau 
6669b3b75d9cSSepherosa Ziehau 	/*
6670b3b75d9cSSepherosa Ziehau 	 * Give RNDIS enough time to flush all pending data packets.
6671b3b75d9cSSepherosa Ziehau 	 */
6672b3b75d9cSSepherosa Ziehau 	pause("waitrx", (200 * hz) / 1000);
6673b3b75d9cSSepherosa Ziehau }
6674b3b75d9cSSepherosa Ziehau 
6675b3b75d9cSSepherosa Ziehau /*
6676b3b75d9cSSepherosa Ziehau  * NOTE:
6677b3b75d9cSSepherosa Ziehau  * RX/TX _must_ have been suspended/disabled, before this function
6678b3b75d9cSSepherosa Ziehau  * is called.
6679b3b75d9cSSepherosa Ziehau  */
6680b3b75d9cSSepherosa Ziehau static void
6681b3b75d9cSSepherosa Ziehau hn_drain_rxtx(struct hn_softc *sc, int nchan)
668215516c77SSepherosa Ziehau {
668315516c77SSepherosa Ziehau 	struct vmbus_channel **subch = NULL;
6684b3b75d9cSSepherosa Ziehau 	int nsubch;
6685b3b75d9cSSepherosa Ziehau 
6686b3b75d9cSSepherosa Ziehau 	/*
6687b3b75d9cSSepherosa Ziehau 	 * Drain RX/TX bufrings and interrupts.
6688b3b75d9cSSepherosa Ziehau 	 */
6689b3b75d9cSSepherosa Ziehau 	nsubch = nchan - 1;
6690b3b75d9cSSepherosa Ziehau 	if (nsubch > 0)
6691b3b75d9cSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
6692b3b75d9cSSepherosa Ziehau 
6693b3b75d9cSSepherosa Ziehau 	if (subch != NULL) {
6694b3b75d9cSSepherosa Ziehau 		int i;
6695b3b75d9cSSepherosa Ziehau 
6696b3b75d9cSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
6697b3b75d9cSSepherosa Ziehau 			hn_chan_drain(sc, subch[i]);
6698b3b75d9cSSepherosa Ziehau 	}
6699b3b75d9cSSepherosa Ziehau 	hn_chan_drain(sc, sc->hn_prichan);
6700b3b75d9cSSepherosa Ziehau 
6701b3b75d9cSSepherosa Ziehau 	if (subch != NULL)
6702b3b75d9cSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
6703b3b75d9cSSepherosa Ziehau }
6704b3b75d9cSSepherosa Ziehau 
6705b3b75d9cSSepherosa Ziehau static void
6706b3b75d9cSSepherosa Ziehau hn_suspend_data(struct hn_softc *sc)
6707b3b75d9cSSepherosa Ziehau {
670825641fc7SSepherosa Ziehau 	struct hn_tx_ring *txr;
6709b3b75d9cSSepherosa Ziehau 	int i;
671015516c77SSepherosa Ziehau 
671115516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
671215516c77SSepherosa Ziehau 
671315516c77SSepherosa Ziehau 	/*
671415516c77SSepherosa Ziehau 	 * Suspend TX.
671515516c77SSepherosa Ziehau 	 */
671615516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
671725641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
671815516c77SSepherosa Ziehau 
671915516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
672015516c77SSepherosa Ziehau 		txr->hn_suspended = 1;
672115516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
672215516c77SSepherosa Ziehau 		/* No one is able send more packets now. */
672315516c77SSepherosa Ziehau 
672425641fc7SSepherosa Ziehau 		/*
672525641fc7SSepherosa Ziehau 		 * Wait for all pending sends to finish.
672625641fc7SSepherosa Ziehau 		 *
672725641fc7SSepherosa Ziehau 		 * NOTE:
672825641fc7SSepherosa Ziehau 		 * We will _not_ receive all pending send-done, if the
672925641fc7SSepherosa Ziehau 		 * primary channel is revoked.
673025641fc7SSepherosa Ziehau 		 */
673125641fc7SSepherosa Ziehau 		while (hn_tx_ring_pending(txr) &&
673225641fc7SSepherosa Ziehau 		    !vmbus_chan_is_revoked(sc->hn_prichan))
673315516c77SSepherosa Ziehau 			pause("hnwtx", 1 /* 1 tick */);
673415516c77SSepherosa Ziehau 	}
673515516c77SSepherosa Ziehau 
673615516c77SSepherosa Ziehau 	/*
6737b3b75d9cSSepherosa Ziehau 	 * Disable RX.
673815516c77SSepherosa Ziehau 	 */
6739b3b75d9cSSepherosa Ziehau 	hn_disable_rx(sc);
674015516c77SSepherosa Ziehau 
674115516c77SSepherosa Ziehau 	/*
6742b3b75d9cSSepherosa Ziehau 	 * Drain RX/TX.
674315516c77SSepherosa Ziehau 	 */
6744b3b75d9cSSepherosa Ziehau 	hn_drain_rxtx(sc, sc->hn_rx_ring_inuse);
674525641fc7SSepherosa Ziehau 
674625641fc7SSepherosa Ziehau 	/*
674725641fc7SSepherosa Ziehau 	 * Drain any pending TX tasks.
674825641fc7SSepherosa Ziehau 	 *
674925641fc7SSepherosa Ziehau 	 * NOTE:
6750b3b75d9cSSepherosa Ziehau 	 * The above hn_drain_rxtx() can dispatch TX tasks, so the TX
6751b3b75d9cSSepherosa Ziehau 	 * tasks will have to be drained _after_ the above hn_drain_rxtx().
675225641fc7SSepherosa Ziehau 	 */
675325641fc7SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
675425641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
675525641fc7SSepherosa Ziehau 
675625641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task);
675725641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task);
675825641fc7SSepherosa Ziehau 	}
675915516c77SSepherosa Ziehau }
676015516c77SSepherosa Ziehau 
676115516c77SSepherosa Ziehau static void
676215516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused)
676315516c77SSepherosa Ziehau {
676415516c77SSepherosa Ziehau 
676515516c77SSepherosa Ziehau 	((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL;
676615516c77SSepherosa Ziehau }
676715516c77SSepherosa Ziehau 
676815516c77SSepherosa Ziehau static void
676915516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc)
677015516c77SSepherosa Ziehau {
677115516c77SSepherosa Ziehau 	struct task task;
677215516c77SSepherosa Ziehau 
677315516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
677415516c77SSepherosa Ziehau 
677515516c77SSepherosa Ziehau 	/*
677615516c77SSepherosa Ziehau 	 * Make sure that hn_mgmt_taskq0 can nolonger be accessed
677715516c77SSepherosa Ziehau 	 * through hn_mgmt_taskq.
677815516c77SSepherosa Ziehau 	 */
677915516c77SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc);
678015516c77SSepherosa Ziehau 	vmbus_chan_run_task(sc->hn_prichan, &task);
678115516c77SSepherosa Ziehau 
678215516c77SSepherosa Ziehau 	/*
678315516c77SSepherosa Ziehau 	 * Make sure that all pending management tasks are completed.
678415516c77SSepherosa Ziehau 	 */
678515516c77SSepherosa Ziehau 	taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init);
678615516c77SSepherosa Ziehau 	taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status);
678715516c77SSepherosa Ziehau 	taskqueue_drain_all(sc->hn_mgmt_taskq0);
678815516c77SSepherosa Ziehau }
678915516c77SSepherosa Ziehau 
679015516c77SSepherosa Ziehau static void
679115516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc)
679215516c77SSepherosa Ziehau {
679315516c77SSepherosa Ziehau 
679487f8129dSSepherosa Ziehau 	/* Disable polling. */
679587f8129dSSepherosa Ziehau 	hn_polling(sc, 0);
679687f8129dSSepherosa Ziehau 
67979c6cae24SSepherosa Ziehau 	/*
67989c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, the synthetic
67999c6cae24SSepherosa Ziehau 	 * device is receiving packets, so the data path of the
68009c6cae24SSepherosa Ziehau 	 * synthetic device must be suspended.
68019c6cae24SSepherosa Ziehau 	 */
68025bdfd3fdSDexuan Cui 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
6803962f0357SSepherosa Ziehau 	    (sc->hn_flags & HN_FLAG_RXVF))
680415516c77SSepherosa Ziehau 		hn_suspend_data(sc);
680515516c77SSepherosa Ziehau 	hn_suspend_mgmt(sc);
680615516c77SSepherosa Ziehau }
680715516c77SSepherosa Ziehau 
680815516c77SSepherosa Ziehau static void
680915516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt)
681015516c77SSepherosa Ziehau {
681115516c77SSepherosa Ziehau 	int i;
681215516c77SSepherosa Ziehau 
681315516c77SSepherosa Ziehau 	KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt,
681415516c77SSepherosa Ziehau 	    ("invalid TX ring count %d", tx_ring_cnt));
681515516c77SSepherosa Ziehau 
681615516c77SSepherosa Ziehau 	for (i = 0; i < tx_ring_cnt; ++i) {
681715516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
681815516c77SSepherosa Ziehau 
681915516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
682015516c77SSepherosa Ziehau 		txr->hn_suspended = 0;
682115516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
682215516c77SSepherosa Ziehau 	}
682315516c77SSepherosa Ziehau }
682415516c77SSepherosa Ziehau 
682515516c77SSepherosa Ziehau static void
682615516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc)
682715516c77SSepherosa Ziehau {
682815516c77SSepherosa Ziehau 	int i;
682915516c77SSepherosa Ziehau 
683015516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
683115516c77SSepherosa Ziehau 
683215516c77SSepherosa Ziehau 	/*
683315516c77SSepherosa Ziehau 	 * Re-enable RX.
683415516c77SSepherosa Ziehau 	 */
6835c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
683615516c77SSepherosa Ziehau 
683715516c77SSepherosa Ziehau 	/*
683815516c77SSepherosa Ziehau 	 * Make sure to clear suspend status on "all" TX rings,
683915516c77SSepherosa Ziehau 	 * since hn_tx_ring_inuse can be changed after
684015516c77SSepherosa Ziehau 	 * hn_suspend_data().
684115516c77SSepherosa Ziehau 	 */
684215516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_cnt);
684315516c77SSepherosa Ziehau 
684423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
684523bf9e15SSepherosa Ziehau 	if (!hn_use_if_start)
684623bf9e15SSepherosa Ziehau #endif
684723bf9e15SSepherosa Ziehau 	{
684815516c77SSepherosa Ziehau 		/*
684915516c77SSepherosa Ziehau 		 * Flush unused drbrs, since hn_tx_ring_inuse may be
685015516c77SSepherosa Ziehau 		 * reduced.
685115516c77SSepherosa Ziehau 		 */
685215516c77SSepherosa Ziehau 		for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i)
685315516c77SSepherosa Ziehau 			hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
685415516c77SSepherosa Ziehau 	}
685515516c77SSepherosa Ziehau 
685615516c77SSepherosa Ziehau 	/*
685715516c77SSepherosa Ziehau 	 * Kick start TX.
685815516c77SSepherosa Ziehau 	 */
685915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
686015516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
686115516c77SSepherosa Ziehau 
686215516c77SSepherosa Ziehau 		/*
686315516c77SSepherosa Ziehau 		 * Use txeof task, so that any pending oactive can be
686415516c77SSepherosa Ziehau 		 * cleared properly.
686515516c77SSepherosa Ziehau 		 */
686615516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
686715516c77SSepherosa Ziehau 	}
686815516c77SSepherosa Ziehau }
686915516c77SSepherosa Ziehau 
687015516c77SSepherosa Ziehau static void
687115516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc)
687215516c77SSepherosa Ziehau {
687315516c77SSepherosa Ziehau 
687415516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
687515516c77SSepherosa Ziehau 
687615516c77SSepherosa Ziehau 	/*
687715516c77SSepherosa Ziehau 	 * Kick off network change detection, if it was pending.
687815516c77SSepherosa Ziehau 	 * If no network change was pending, start link status
687915516c77SSepherosa Ziehau 	 * checks, which is more lightweight than network change
688015516c77SSepherosa Ziehau 	 * detection.
688115516c77SSepherosa Ziehau 	 */
688215516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
688315516c77SSepherosa Ziehau 		hn_change_network(sc);
688415516c77SSepherosa Ziehau 	else
688515516c77SSepherosa Ziehau 		hn_update_link_status(sc);
688615516c77SSepherosa Ziehau }
688715516c77SSepherosa Ziehau 
688815516c77SSepherosa Ziehau static void
688915516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc)
689015516c77SSepherosa Ziehau {
689115516c77SSepherosa Ziehau 
68929c6cae24SSepherosa Ziehau 	/*
68939c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, the synthetic
68949c6cae24SSepherosa Ziehau 	 * device have to receive packets, so the data path of the
68959c6cae24SSepherosa Ziehau 	 * synthetic device must be resumed.
68969c6cae24SSepherosa Ziehau 	 */
68975bdfd3fdSDexuan Cui 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
6898962f0357SSepherosa Ziehau 	    (sc->hn_flags & HN_FLAG_RXVF))
689915516c77SSepherosa Ziehau 		hn_resume_data(sc);
69005bdfd3fdSDexuan Cui 
69015bdfd3fdSDexuan Cui 	/*
69029c6cae24SSepherosa Ziehau 	 * Don't resume link status change if VF is attached/activated.
69039c6cae24SSepherosa Ziehau 	 * - In the non-transparent VF mode, the synthetic device marks
69049c6cae24SSepherosa Ziehau 	 *   link down until the VF is deactivated; i.e. VF is down.
69059c6cae24SSepherosa Ziehau 	 * - In transparent VF mode, VF's media status is used until
69069c6cae24SSepherosa Ziehau 	 *   the VF is detached.
69075bdfd3fdSDexuan Cui 	 */
69089c6cae24SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) == 0 &&
69099c6cae24SSepherosa Ziehau 	    !(hn_xpnt_vf && sc->hn_vf_ifp != NULL))
691015516c77SSepherosa Ziehau 		hn_resume_mgmt(sc);
691187f8129dSSepherosa Ziehau 
691287f8129dSSepherosa Ziehau 	/*
691387f8129dSSepherosa Ziehau 	 * Re-enable polling if this interface is running and
691487f8129dSSepherosa Ziehau 	 * the polling is requested.
691587f8129dSSepherosa Ziehau 	 */
691687f8129dSSepherosa Ziehau 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->hn_pollhz > 0)
691787f8129dSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
691815516c77SSepherosa Ziehau }
691915516c77SSepherosa Ziehau 
692015516c77SSepherosa Ziehau static void
692115516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen)
692215516c77SSepherosa Ziehau {
692315516c77SSepherosa Ziehau 	const struct rndis_status_msg *msg;
692415516c77SSepherosa Ziehau 	int ofs;
692515516c77SSepherosa Ziehau 
692615516c77SSepherosa Ziehau 	if (dlen < sizeof(*msg)) {
692715516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid RNDIS status\n");
692815516c77SSepherosa Ziehau 		return;
692915516c77SSepherosa Ziehau 	}
693015516c77SSepherosa Ziehau 	msg = data;
693115516c77SSepherosa Ziehau 
693215516c77SSepherosa Ziehau 	switch (msg->rm_status) {
693315516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_CONNECT:
693415516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_DISCONNECT:
693515516c77SSepherosa Ziehau 		hn_update_link_status(sc);
693615516c77SSepherosa Ziehau 		break;
693715516c77SSepherosa Ziehau 
693815516c77SSepherosa Ziehau 	case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
693940905afaSSepherosa Ziehau 	case RNDIS_STATUS_LINK_SPEED_CHANGE:
694015516c77SSepherosa Ziehau 		/* Not really useful; ignore. */
694115516c77SSepherosa Ziehau 		break;
694215516c77SSepherosa Ziehau 
694315516c77SSepherosa Ziehau 	case RNDIS_STATUS_NETWORK_CHANGE:
694415516c77SSepherosa Ziehau 		ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
694515516c77SSepherosa Ziehau 		if (dlen < ofs + msg->rm_stbuflen ||
694615516c77SSepherosa Ziehau 		    msg->rm_stbuflen < sizeof(uint32_t)) {
694715516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed\n");
694815516c77SSepherosa Ziehau 		} else {
694915516c77SSepherosa Ziehau 			uint32_t change;
695015516c77SSepherosa Ziehau 
695115516c77SSepherosa Ziehau 			memcpy(&change, ((const uint8_t *)msg) + ofs,
695215516c77SSepherosa Ziehau 			    sizeof(change));
695315516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed, change %u\n",
695415516c77SSepherosa Ziehau 			    change);
695515516c77SSepherosa Ziehau 		}
695615516c77SSepherosa Ziehau 		hn_change_network(sc);
695715516c77SSepherosa Ziehau 		break;
695815516c77SSepherosa Ziehau 
695915516c77SSepherosa Ziehau 	default:
696015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
696115516c77SSepherosa Ziehau 		    msg->rm_status);
696215516c77SSepherosa Ziehau 		break;
696315516c77SSepherosa Ziehau 	}
696415516c77SSepherosa Ziehau }
696515516c77SSepherosa Ziehau 
696615516c77SSepherosa Ziehau static int
696715516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info)
696815516c77SSepherosa Ziehau {
696915516c77SSepherosa Ziehau 	const struct rndis_pktinfo *pi = info_data;
697015516c77SSepherosa Ziehau 	uint32_t mask = 0;
697115516c77SSepherosa Ziehau 
697215516c77SSepherosa Ziehau 	while (info_dlen != 0) {
697315516c77SSepherosa Ziehau 		const void *data;
697415516c77SSepherosa Ziehau 		uint32_t dlen;
697515516c77SSepherosa Ziehau 
697615516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < sizeof(*pi)))
697715516c77SSepherosa Ziehau 			return (EINVAL);
697815516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < pi->rm_size))
697915516c77SSepherosa Ziehau 			return (EINVAL);
698015516c77SSepherosa Ziehau 		info_dlen -= pi->rm_size;
698115516c77SSepherosa Ziehau 
698215516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
698315516c77SSepherosa Ziehau 			return (EINVAL);
698415516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
698515516c77SSepherosa Ziehau 			return (EINVAL);
698615516c77SSepherosa Ziehau 		dlen = pi->rm_size - pi->rm_pktinfooffset;
698715516c77SSepherosa Ziehau 		data = pi->rm_data;
698815516c77SSepherosa Ziehau 
698915516c77SSepherosa Ziehau 		switch (pi->rm_type) {
699015516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_VLAN:
699115516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
699215516c77SSepherosa Ziehau 				return (EINVAL);
699315516c77SSepherosa Ziehau 			info->vlan_info = *((const uint32_t *)data);
699415516c77SSepherosa Ziehau 			mask |= HN_RXINFO_VLAN;
699515516c77SSepherosa Ziehau 			break;
699615516c77SSepherosa Ziehau 
699715516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_CSUM:
699815516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
699915516c77SSepherosa Ziehau 				return (EINVAL);
700015516c77SSepherosa Ziehau 			info->csum_info = *((const uint32_t *)data);
700115516c77SSepherosa Ziehau 			mask |= HN_RXINFO_CSUM;
700215516c77SSepherosa Ziehau 			break;
700315516c77SSepherosa Ziehau 
700415516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHVAL:
700515516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
700615516c77SSepherosa Ziehau 				return (EINVAL);
700715516c77SSepherosa Ziehau 			info->hash_value = *((const uint32_t *)data);
700815516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHVAL;
700915516c77SSepherosa Ziehau 			break;
701015516c77SSepherosa Ziehau 
701115516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHINF:
701215516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
701315516c77SSepherosa Ziehau 				return (EINVAL);
701415516c77SSepherosa Ziehau 			info->hash_info = *((const uint32_t *)data);
701515516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHINF;
701615516c77SSepherosa Ziehau 			break;
701715516c77SSepherosa Ziehau 
701815516c77SSepherosa Ziehau 		default:
701915516c77SSepherosa Ziehau 			goto next;
702015516c77SSepherosa Ziehau 		}
702115516c77SSepherosa Ziehau 
702215516c77SSepherosa Ziehau 		if (mask == HN_RXINFO_ALL) {
702315516c77SSepherosa Ziehau 			/* All found; done */
702415516c77SSepherosa Ziehau 			break;
702515516c77SSepherosa Ziehau 		}
702615516c77SSepherosa Ziehau next:
702715516c77SSepherosa Ziehau 		pi = (const struct rndis_pktinfo *)
702815516c77SSepherosa Ziehau 		    ((const uint8_t *)pi + pi->rm_size);
702915516c77SSepherosa Ziehau 	}
703015516c77SSepherosa Ziehau 
703115516c77SSepherosa Ziehau 	/*
703215516c77SSepherosa Ziehau 	 * Final fixup.
703315516c77SSepherosa Ziehau 	 * - If there is no hash value, invalidate the hash info.
703415516c77SSepherosa Ziehau 	 */
703515516c77SSepherosa Ziehau 	if ((mask & HN_RXINFO_HASHVAL) == 0)
703615516c77SSepherosa Ziehau 		info->hash_info = HN_NDIS_HASH_INFO_INVALID;
703715516c77SSepherosa Ziehau 	return (0);
703815516c77SSepherosa Ziehau }
703915516c77SSepherosa Ziehau 
704015516c77SSepherosa Ziehau static __inline bool
704115516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
704215516c77SSepherosa Ziehau {
704315516c77SSepherosa Ziehau 
704415516c77SSepherosa Ziehau 	if (off < check_off) {
704515516c77SSepherosa Ziehau 		if (__predict_true(off + len <= check_off))
704615516c77SSepherosa Ziehau 			return (false);
704715516c77SSepherosa Ziehau 	} else if (off > check_off) {
704815516c77SSepherosa Ziehau 		if (__predict_true(check_off + check_len <= off))
704915516c77SSepherosa Ziehau 			return (false);
705015516c77SSepherosa Ziehau 	}
705115516c77SSepherosa Ziehau 	return (true);
705215516c77SSepherosa Ziehau }
705315516c77SSepherosa Ziehau 
705415516c77SSepherosa Ziehau static void
705515516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen)
705615516c77SSepherosa Ziehau {
705715516c77SSepherosa Ziehau 	const struct rndis_packet_msg *pkt;
705815516c77SSepherosa Ziehau 	struct hn_rxinfo info;
705915516c77SSepherosa Ziehau 	int data_off, pktinfo_off, data_len, pktinfo_len;
706015516c77SSepherosa Ziehau 
706115516c77SSepherosa Ziehau 	/*
706215516c77SSepherosa Ziehau 	 * Check length.
706315516c77SSepherosa Ziehau 	 */
706415516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*pkt))) {
706515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
706615516c77SSepherosa Ziehau 		return;
706715516c77SSepherosa Ziehau 	}
706815516c77SSepherosa Ziehau 	pkt = data;
706915516c77SSepherosa Ziehau 
707015516c77SSepherosa Ziehau 	if (__predict_false(dlen < pkt->rm_len)) {
707115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
707215516c77SSepherosa Ziehau 		    "dlen %d, msglen %u\n", dlen, pkt->rm_len);
707315516c77SSepherosa Ziehau 		return;
707415516c77SSepherosa Ziehau 	}
707515516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_len <
707615516c77SSepherosa Ziehau 	    pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
707715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
707815516c77SSepherosa Ziehau 		    "msglen %u, data %u, oob %u, pktinfo %u\n",
707915516c77SSepherosa Ziehau 		    pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
708015516c77SSepherosa Ziehau 		    pkt->rm_pktinfolen);
708115516c77SSepherosa Ziehau 		return;
708215516c77SSepherosa Ziehau 	}
708315516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_datalen == 0)) {
708415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
708515516c77SSepherosa Ziehau 		return;
708615516c77SSepherosa Ziehau 	}
708715516c77SSepherosa Ziehau 
708815516c77SSepherosa Ziehau 	/*
708915516c77SSepherosa Ziehau 	 * Check offests.
709015516c77SSepherosa Ziehau 	 */
709115516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs)			\
709215516c77SSepherosa Ziehau 	((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN ||	\
709315516c77SSepherosa Ziehau 	 ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
709415516c77SSepherosa Ziehau 
709515516c77SSepherosa Ziehau 	/* XXX Hyper-V does not meet data offset alignment requirement */
709615516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
709715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
709815516c77SSepherosa Ziehau 		    "data offset %u\n", pkt->rm_dataoffset);
709915516c77SSepherosa Ziehau 		return;
710015516c77SSepherosa Ziehau 	}
710115516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdataoffset > 0 &&
710215516c77SSepherosa Ziehau 	    IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
710315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
710415516c77SSepherosa Ziehau 		    "oob offset %u\n", pkt->rm_oobdataoffset);
710515516c77SSepherosa Ziehau 		return;
710615516c77SSepherosa Ziehau 	}
710715516c77SSepherosa Ziehau 	if (__predict_true(pkt->rm_pktinfooffset > 0) &&
710815516c77SSepherosa Ziehau 	    __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
710915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
711015516c77SSepherosa Ziehau 		    "pktinfo offset %u\n", pkt->rm_pktinfooffset);
711115516c77SSepherosa Ziehau 		return;
711215516c77SSepherosa Ziehau 	}
711315516c77SSepherosa Ziehau 
711415516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID
711515516c77SSepherosa Ziehau 
711615516c77SSepherosa Ziehau 	data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
711715516c77SSepherosa Ziehau 	data_len = pkt->rm_datalen;
711815516c77SSepherosa Ziehau 	pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
711915516c77SSepherosa Ziehau 	pktinfo_len = pkt->rm_pktinfolen;
712015516c77SSepherosa Ziehau 
712115516c77SSepherosa Ziehau 	/*
712215516c77SSepherosa Ziehau 	 * Check OOB coverage.
712315516c77SSepherosa Ziehau 	 */
712415516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdatalen != 0)) {
712515516c77SSepherosa Ziehau 		int oob_off, oob_len;
712615516c77SSepherosa Ziehau 
712715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "got oobdata\n");
712815516c77SSepherosa Ziehau 		oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
712915516c77SSepherosa Ziehau 		oob_len = pkt->rm_oobdatalen;
713015516c77SSepherosa Ziehau 
713115516c77SSepherosa Ziehau 		if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
713215516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
713315516c77SSepherosa Ziehau 			    "oob overflow, msglen %u, oob abs %d len %d\n",
713415516c77SSepherosa Ziehau 			    pkt->rm_len, oob_off, oob_len);
713515516c77SSepherosa Ziehau 			return;
713615516c77SSepherosa Ziehau 		}
713715516c77SSepherosa Ziehau 
713815516c77SSepherosa Ziehau 		/*
713915516c77SSepherosa Ziehau 		 * Check against data.
714015516c77SSepherosa Ziehau 		 */
714115516c77SSepherosa Ziehau 		if (hn_rndis_check_overlap(oob_off, oob_len,
714215516c77SSepherosa Ziehau 		    data_off, data_len)) {
714315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
714415516c77SSepherosa Ziehau 			    "oob overlaps data, oob abs %d len %d, "
714515516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
714615516c77SSepherosa Ziehau 			    oob_off, oob_len, data_off, data_len);
714715516c77SSepherosa Ziehau 			return;
714815516c77SSepherosa Ziehau 		}
714915516c77SSepherosa Ziehau 
715015516c77SSepherosa Ziehau 		/*
715115516c77SSepherosa Ziehau 		 * Check against pktinfo.
715215516c77SSepherosa Ziehau 		 */
715315516c77SSepherosa Ziehau 		if (pktinfo_len != 0 &&
715415516c77SSepherosa Ziehau 		    hn_rndis_check_overlap(oob_off, oob_len,
715515516c77SSepherosa Ziehau 		    pktinfo_off, pktinfo_len)) {
715615516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
715715516c77SSepherosa Ziehau 			    "oob overlaps pktinfo, oob abs %d len %d, "
715815516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
715915516c77SSepherosa Ziehau 			    oob_off, oob_len, pktinfo_off, pktinfo_len);
716015516c77SSepherosa Ziehau 			return;
716115516c77SSepherosa Ziehau 		}
716215516c77SSepherosa Ziehau 	}
716315516c77SSepherosa Ziehau 
716415516c77SSepherosa Ziehau 	/*
716515516c77SSepherosa Ziehau 	 * Check per-packet-info coverage and find useful per-packet-info.
716615516c77SSepherosa Ziehau 	 */
716715516c77SSepherosa Ziehau 	info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
716815516c77SSepherosa Ziehau 	info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
716915516c77SSepherosa Ziehau 	info.hash_info = HN_NDIS_HASH_INFO_INVALID;
717015516c77SSepherosa Ziehau 	if (__predict_true(pktinfo_len != 0)) {
717115516c77SSepherosa Ziehau 		bool overlap;
717215516c77SSepherosa Ziehau 		int error;
717315516c77SSepherosa Ziehau 
717415516c77SSepherosa Ziehau 		if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
717515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
717615516c77SSepherosa Ziehau 			    "pktinfo overflow, msglen %u, "
717715516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
717815516c77SSepherosa Ziehau 			    pkt->rm_len, pktinfo_off, pktinfo_len);
717915516c77SSepherosa Ziehau 			return;
718015516c77SSepherosa Ziehau 		}
718115516c77SSepherosa Ziehau 
718215516c77SSepherosa Ziehau 		/*
718315516c77SSepherosa Ziehau 		 * Check packet info coverage.
718415516c77SSepherosa Ziehau 		 */
718515516c77SSepherosa Ziehau 		overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
718615516c77SSepherosa Ziehau 		    data_off, data_len);
718715516c77SSepherosa Ziehau 		if (__predict_false(overlap)) {
718815516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
718915516c77SSepherosa Ziehau 			    "pktinfo overlap data, pktinfo abs %d len %d, "
719015516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
719115516c77SSepherosa Ziehau 			    pktinfo_off, pktinfo_len, data_off, data_len);
719215516c77SSepherosa Ziehau 			return;
719315516c77SSepherosa Ziehau 		}
719415516c77SSepherosa Ziehau 
719515516c77SSepherosa Ziehau 		/*
719615516c77SSepherosa Ziehau 		 * Find useful per-packet-info.
719715516c77SSepherosa Ziehau 		 */
719815516c77SSepherosa Ziehau 		error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
719915516c77SSepherosa Ziehau 		    pktinfo_len, &info);
720015516c77SSepherosa Ziehau 		if (__predict_false(error)) {
720115516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
720215516c77SSepherosa Ziehau 			    "pktinfo\n");
720315516c77SSepherosa Ziehau 			return;
720415516c77SSepherosa Ziehau 		}
720515516c77SSepherosa Ziehau 	}
720615516c77SSepherosa Ziehau 
720715516c77SSepherosa Ziehau 	if (__predict_false(data_off + data_len > pkt->rm_len)) {
720815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
720915516c77SSepherosa Ziehau 		    "data overflow, msglen %u, data abs %d len %d\n",
721015516c77SSepherosa Ziehau 		    pkt->rm_len, data_off, data_len);
721115516c77SSepherosa Ziehau 		return;
721215516c77SSepherosa Ziehau 	}
721315516c77SSepherosa Ziehau 	hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
721415516c77SSepherosa Ziehau }
721515516c77SSepherosa Ziehau 
721615516c77SSepherosa Ziehau static __inline void
721715516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen)
721815516c77SSepherosa Ziehau {
721915516c77SSepherosa Ziehau 	const struct rndis_msghdr *hdr;
722015516c77SSepherosa Ziehau 
722115516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*hdr))) {
722215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
722315516c77SSepherosa Ziehau 		return;
722415516c77SSepherosa Ziehau 	}
722515516c77SSepherosa Ziehau 	hdr = data;
722615516c77SSepherosa Ziehau 
722715516c77SSepherosa Ziehau 	if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) {
722815516c77SSepherosa Ziehau 		/* Hot data path. */
722915516c77SSepherosa Ziehau 		hn_rndis_rx_data(rxr, data, dlen);
723015516c77SSepherosa Ziehau 		/* Done! */
723115516c77SSepherosa Ziehau 		return;
723215516c77SSepherosa Ziehau 	}
723315516c77SSepherosa Ziehau 
723415516c77SSepherosa Ziehau 	if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG)
723515516c77SSepherosa Ziehau 		hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen);
723615516c77SSepherosa Ziehau 	else
723715516c77SSepherosa Ziehau 		hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen);
723815516c77SSepherosa Ziehau }
723915516c77SSepherosa Ziehau 
724015516c77SSepherosa Ziehau static void
724115516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
724215516c77SSepherosa Ziehau {
724315516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *hdr;
724415516c77SSepherosa Ziehau 
724515516c77SSepherosa Ziehau 	if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) {
724615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid nvs notify\n");
724715516c77SSepherosa Ziehau 		return;
724815516c77SSepherosa Ziehau 	}
724915516c77SSepherosa Ziehau 	hdr = VMBUS_CHANPKT_CONST_DATA(pkt);
725015516c77SSepherosa Ziehau 
725115516c77SSepherosa Ziehau 	if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) {
725215516c77SSepherosa Ziehau 		/* Useless; ignore */
725315516c77SSepherosa Ziehau 		return;
725415516c77SSepherosa Ziehau 	}
725515516c77SSepherosa Ziehau 	if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type);
725615516c77SSepherosa Ziehau }
725715516c77SSepherosa Ziehau 
725815516c77SSepherosa Ziehau static void
725915516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan,
726015516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkt)
726115516c77SSepherosa Ziehau {
726215516c77SSepherosa Ziehau 	struct hn_nvs_sendctx *sndc;
726315516c77SSepherosa Ziehau 
726415516c77SSepherosa Ziehau 	sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid;
726515516c77SSepherosa Ziehau 	sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt),
726615516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_DATALEN(pkt));
726715516c77SSepherosa Ziehau 	/*
726815516c77SSepherosa Ziehau 	 * NOTE:
726915516c77SSepherosa Ziehau 	 * 'sndc' CAN NOT be accessed anymore, since it can be freed by
727015516c77SSepherosa Ziehau 	 * its callback.
727115516c77SSepherosa Ziehau 	 */
727215516c77SSepherosa Ziehau }
727315516c77SSepherosa Ziehau 
727415516c77SSepherosa Ziehau static void
727515516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
727615516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkthdr)
727715516c77SSepherosa Ziehau {
727815516c77SSepherosa Ziehau 	const struct vmbus_chanpkt_rxbuf *pkt;
727915516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *nvs_hdr;
728015516c77SSepherosa Ziehau 	int count, i, hlen;
728115516c77SSepherosa Ziehau 
728215516c77SSepherosa Ziehau 	if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) {
728315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n");
728415516c77SSepherosa Ziehau 		return;
728515516c77SSepherosa Ziehau 	}
728615516c77SSepherosa Ziehau 	nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr);
728715516c77SSepherosa Ziehau 
728815516c77SSepherosa Ziehau 	/* Make sure that this is a RNDIS message. */
728915516c77SSepherosa Ziehau 	if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) {
729015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n",
729115516c77SSepherosa Ziehau 		    nvs_hdr->nvs_type);
729215516c77SSepherosa Ziehau 		return;
729315516c77SSepherosa Ziehau 	}
729415516c77SSepherosa Ziehau 
729515516c77SSepherosa Ziehau 	hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen);
729615516c77SSepherosa Ziehau 	if (__predict_false(hlen < sizeof(*pkt))) {
729715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n");
729815516c77SSepherosa Ziehau 		return;
729915516c77SSepherosa Ziehau 	}
730015516c77SSepherosa Ziehau 	pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
730115516c77SSepherosa Ziehau 
730215516c77SSepherosa Ziehau 	if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) {
730315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n",
730415516c77SSepherosa Ziehau 		    pkt->cp_rxbuf_id);
730515516c77SSepherosa Ziehau 		return;
730615516c77SSepherosa Ziehau 	}
730715516c77SSepherosa Ziehau 
730815516c77SSepherosa Ziehau 	count = pkt->cp_rxbuf_cnt;
730915516c77SSepherosa Ziehau 	if (__predict_false(hlen <
731015516c77SSepherosa Ziehau 	    __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) {
731115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count);
731215516c77SSepherosa Ziehau 		return;
731315516c77SSepherosa Ziehau 	}
731415516c77SSepherosa Ziehau 
731515516c77SSepherosa Ziehau 	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
731615516c77SSepherosa Ziehau 	for (i = 0; i < count; ++i) {
731715516c77SSepherosa Ziehau 		int ofs, len;
731815516c77SSepherosa Ziehau 
731915516c77SSepherosa Ziehau 		ofs = pkt->cp_rxbuf[i].rb_ofs;
732015516c77SSepherosa Ziehau 		len = pkt->cp_rxbuf[i].rb_len;
732115516c77SSepherosa Ziehau 		if (__predict_false(ofs + len > HN_RXBUF_SIZE)) {
732215516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, "
732315516c77SSepherosa Ziehau 			    "ofs %d, len %d\n", i, ofs, len);
732415516c77SSepherosa Ziehau 			continue;
732515516c77SSepherosa Ziehau 		}
732615516c77SSepherosa Ziehau 		hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len);
732715516c77SSepherosa Ziehau 	}
732815516c77SSepherosa Ziehau 
732915516c77SSepherosa Ziehau 	/*
733015516c77SSepherosa Ziehau 	 * Ack the consumed RXBUF associated w/ this channel packet,
733115516c77SSepherosa Ziehau 	 * so that this RXBUF can be recycled by the hypervisor.
733215516c77SSepherosa Ziehau 	 */
733315516c77SSepherosa Ziehau 	hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid);
733415516c77SSepherosa Ziehau }
733515516c77SSepherosa Ziehau 
733615516c77SSepherosa Ziehau static void
733715516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
733815516c77SSepherosa Ziehau     uint64_t tid)
733915516c77SSepherosa Ziehau {
734015516c77SSepherosa Ziehau 	struct hn_nvs_rndis_ack ack;
734115516c77SSepherosa Ziehau 	int retries, error;
734215516c77SSepherosa Ziehau 
734315516c77SSepherosa Ziehau 	ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK;
734415516c77SSepherosa Ziehau 	ack.nvs_status = HN_NVS_STATUS_OK;
734515516c77SSepherosa Ziehau 
734615516c77SSepherosa Ziehau 	retries = 0;
734715516c77SSepherosa Ziehau again:
734815516c77SSepherosa Ziehau 	error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP,
734915516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid);
735015516c77SSepherosa Ziehau 	if (__predict_false(error == EAGAIN)) {
735115516c77SSepherosa Ziehau 		/*
735215516c77SSepherosa Ziehau 		 * NOTE:
735315516c77SSepherosa Ziehau 		 * This should _not_ happen in real world, since the
735415516c77SSepherosa Ziehau 		 * consumption of the TX bufring from the TX path is
735515516c77SSepherosa Ziehau 		 * controlled.
735615516c77SSepherosa Ziehau 		 */
735715516c77SSepherosa Ziehau 		if (rxr->hn_ack_failed == 0)
735815516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "RXBUF ack retry\n");
735915516c77SSepherosa Ziehau 		rxr->hn_ack_failed++;
736015516c77SSepherosa Ziehau 		retries++;
736115516c77SSepherosa Ziehau 		if (retries < 10) {
736215516c77SSepherosa Ziehau 			DELAY(100);
736315516c77SSepherosa Ziehau 			goto again;
736415516c77SSepherosa Ziehau 		}
736515516c77SSepherosa Ziehau 		/* RXBUF leaks! */
736615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "RXBUF ack failed\n");
736715516c77SSepherosa Ziehau 	}
736815516c77SSepherosa Ziehau }
736915516c77SSepherosa Ziehau 
737015516c77SSepherosa Ziehau static void
737115516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr)
737215516c77SSepherosa Ziehau {
737315516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr = xrxr;
737415516c77SSepherosa Ziehau 	struct hn_softc *sc = rxr->hn_ifp->if_softc;
737515516c77SSepherosa Ziehau 
737615516c77SSepherosa Ziehau 	for (;;) {
737715516c77SSepherosa Ziehau 		struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf;
737815516c77SSepherosa Ziehau 		int error, pktlen;
737915516c77SSepherosa Ziehau 
738015516c77SSepherosa Ziehau 		pktlen = rxr->hn_pktbuf_len;
738115516c77SSepherosa Ziehau 		error = vmbus_chan_recv_pkt(chan, pkt, &pktlen);
738215516c77SSepherosa Ziehau 		if (__predict_false(error == ENOBUFS)) {
738315516c77SSepherosa Ziehau 			void *nbuf;
738415516c77SSepherosa Ziehau 			int nlen;
738515516c77SSepherosa Ziehau 
738615516c77SSepherosa Ziehau 			/*
738715516c77SSepherosa Ziehau 			 * Expand channel packet buffer.
738815516c77SSepherosa Ziehau 			 *
738915516c77SSepherosa Ziehau 			 * XXX
739015516c77SSepherosa Ziehau 			 * Use M_WAITOK here, since allocation failure
739115516c77SSepherosa Ziehau 			 * is fatal.
739215516c77SSepherosa Ziehau 			 */
739315516c77SSepherosa Ziehau 			nlen = rxr->hn_pktbuf_len * 2;
739415516c77SSepherosa Ziehau 			while (nlen < pktlen)
739515516c77SSepherosa Ziehau 				nlen *= 2;
739615516c77SSepherosa Ziehau 			nbuf = malloc(nlen, M_DEVBUF, M_WAITOK);
739715516c77SSepherosa Ziehau 
739815516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n",
739915516c77SSepherosa Ziehau 			    rxr->hn_pktbuf_len, nlen);
740015516c77SSepherosa Ziehau 
740115516c77SSepherosa Ziehau 			free(rxr->hn_pktbuf, M_DEVBUF);
740215516c77SSepherosa Ziehau 			rxr->hn_pktbuf = nbuf;
740315516c77SSepherosa Ziehau 			rxr->hn_pktbuf_len = nlen;
740415516c77SSepherosa Ziehau 			/* Retry! */
740515516c77SSepherosa Ziehau 			continue;
740615516c77SSepherosa Ziehau 		} else if (__predict_false(error == EAGAIN)) {
740715516c77SSepherosa Ziehau 			/* No more channel packets; done! */
740815516c77SSepherosa Ziehau 			break;
740915516c77SSepherosa Ziehau 		}
741015516c77SSepherosa Ziehau 		KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error));
741115516c77SSepherosa Ziehau 
741215516c77SSepherosa Ziehau 		switch (pkt->cph_type) {
741315516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_COMP:
741415516c77SSepherosa Ziehau 			hn_nvs_handle_comp(sc, chan, pkt);
741515516c77SSepherosa Ziehau 			break;
741615516c77SSepherosa Ziehau 
741715516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_RXBUF:
741815516c77SSepherosa Ziehau 			hn_nvs_handle_rxbuf(rxr, chan, pkt);
741915516c77SSepherosa Ziehau 			break;
742015516c77SSepherosa Ziehau 
742115516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_INBAND:
742215516c77SSepherosa Ziehau 			hn_nvs_handle_notify(sc, pkt);
742315516c77SSepherosa Ziehau 			break;
742415516c77SSepherosa Ziehau 
742515516c77SSepherosa Ziehau 		default:
742615516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "unknown chan pkt %u\n",
742715516c77SSepherosa Ziehau 			    pkt->cph_type);
742815516c77SSepherosa Ziehau 			break;
742915516c77SSepherosa Ziehau 		}
743015516c77SSepherosa Ziehau 	}
743115516c77SSepherosa Ziehau 	hn_chan_rollup(rxr, rxr->hn_txr);
743215516c77SSepherosa Ziehau }
743315516c77SSepherosa Ziehau 
743415516c77SSepherosa Ziehau static void
7435499c3e17SSepherosa Ziehau hn_sysinit(void *arg __unused)
743615516c77SSepherosa Ziehau {
7437fdd0222aSSepherosa Ziehau 	int i;
7438fdd0222aSSepherosa Ziehau 
74392be266caSSepherosa Ziehau 	hn_udpcs_fixup = counter_u64_alloc(M_WAITOK);
74402be266caSSepherosa Ziehau 
74419c6cae24SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
74429c6cae24SSepherosa Ziehau 	/*
74439c6cae24SSepherosa Ziehau 	 * Don't use ifnet.if_start if transparent VF mode is requested;
74449c6cae24SSepherosa Ziehau 	 * mainly due to the IFF_DRV_OACTIVE flag.
74459c6cae24SSepherosa Ziehau 	 */
74469c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && hn_use_if_start) {
74479c6cae24SSepherosa Ziehau 		hn_use_if_start = 0;
74489c6cae24SSepherosa Ziehau 		printf("hn: tranparent VF mode, if_transmit will be used, "
74499c6cae24SSepherosa Ziehau 		    "instead of if_start\n");
74509c6cae24SSepherosa Ziehau 	}
74519c6cae24SSepherosa Ziehau #endif
74529c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_attwait < HN_XPNT_VF_ATTWAIT_MIN) {
74539c6cae24SSepherosa Ziehau 		printf("hn: invalid transparent VF attach routing "
74549c6cae24SSepherosa Ziehau 		    "wait timeout %d, reset to %d\n",
74559c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_attwait, HN_XPNT_VF_ATTWAIT_MIN);
74569c6cae24SSepherosa Ziehau 		hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN;
74579c6cae24SSepherosa Ziehau 	}
74589c6cae24SSepherosa Ziehau 
7459fdd0222aSSepherosa Ziehau 	/*
7460499c3e17SSepherosa Ziehau 	 * Initialize VF map.
7461499c3e17SSepherosa Ziehau 	 */
7462499c3e17SSepherosa Ziehau 	rm_init_flags(&hn_vfmap_lock, "hn_vfmap", RM_SLEEPABLE);
7463499c3e17SSepherosa Ziehau 	hn_vfmap_size = HN_VFMAP_SIZE_DEF;
7464499c3e17SSepherosa Ziehau 	hn_vfmap = malloc(sizeof(struct ifnet *) * hn_vfmap_size, M_DEVBUF,
7465499c3e17SSepherosa Ziehau 	    M_WAITOK | M_ZERO);
7466499c3e17SSepherosa Ziehau 
7467499c3e17SSepherosa Ziehau 	/*
7468fdd0222aSSepherosa Ziehau 	 * Fix the # of TX taskqueues.
7469fdd0222aSSepherosa Ziehau 	 */
7470fdd0222aSSepherosa Ziehau 	if (hn_tx_taskq_cnt <= 0)
7471fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = 1;
7472fdd0222aSSepherosa Ziehau 	else if (hn_tx_taskq_cnt > mp_ncpus)
7473fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = mp_ncpus;
747415516c77SSepherosa Ziehau 
74750e11868dSSepherosa Ziehau 	/*
74760e11868dSSepherosa Ziehau 	 * Fix the TX taskqueue mode.
74770e11868dSSepherosa Ziehau 	 */
74780e11868dSSepherosa Ziehau 	switch (hn_tx_taskq_mode) {
74790e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_INDEP:
74800e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_GLOBAL:
74810e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_EVTTQ:
74820e11868dSSepherosa Ziehau 		break;
74830e11868dSSepherosa Ziehau 	default:
74840e11868dSSepherosa Ziehau 		hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
74850e11868dSSepherosa Ziehau 		break;
74860e11868dSSepherosa Ziehau 	}
74870e11868dSSepherosa Ziehau 
748815516c77SSepherosa Ziehau 	if (vm_guest != VM_GUEST_HV)
748915516c77SSepherosa Ziehau 		return;
749015516c77SSepherosa Ziehau 
74910e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode != HN_TX_TASKQ_M_GLOBAL)
749215516c77SSepherosa Ziehau 		return;
749315516c77SSepherosa Ziehau 
7494fdd0222aSSepherosa Ziehau 	hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
7495fdd0222aSSepherosa Ziehau 	    M_DEVBUF, M_WAITOK);
7496fdd0222aSSepherosa Ziehau 	for (i = 0; i < hn_tx_taskq_cnt; ++i) {
7497fdd0222aSSepherosa Ziehau 		hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK,
7498fdd0222aSSepherosa Ziehau 		    taskqueue_thread_enqueue, &hn_tx_taskque[i]);
7499fdd0222aSSepherosa Ziehau 		taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET,
7500fdd0222aSSepherosa Ziehau 		    "hn tx%d", i);
7501fdd0222aSSepherosa Ziehau 	}
750215516c77SSepherosa Ziehau }
7503499c3e17SSepherosa Ziehau SYSINIT(hn_sysinit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysinit, NULL);
750415516c77SSepherosa Ziehau 
750515516c77SSepherosa Ziehau static void
7506499c3e17SSepherosa Ziehau hn_sysuninit(void *arg __unused)
750715516c77SSepherosa Ziehau {
750815516c77SSepherosa Ziehau 
7509fdd0222aSSepherosa Ziehau 	if (hn_tx_taskque != NULL) {
7510fdd0222aSSepherosa Ziehau 		int i;
7511fdd0222aSSepherosa Ziehau 
7512fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
7513fdd0222aSSepherosa Ziehau 			taskqueue_free(hn_tx_taskque[i]);
7514fdd0222aSSepherosa Ziehau 		free(hn_tx_taskque, M_DEVBUF);
7515fdd0222aSSepherosa Ziehau 	}
7516499c3e17SSepherosa Ziehau 
7517499c3e17SSepherosa Ziehau 	if (hn_vfmap != NULL)
7518499c3e17SSepherosa Ziehau 		free(hn_vfmap, M_DEVBUF);
7519499c3e17SSepherosa Ziehau 	rm_destroy(&hn_vfmap_lock);
75202be266caSSepherosa Ziehau 
75212be266caSSepherosa Ziehau 	counter_u64_free(hn_udpcs_fixup);
752215516c77SSepherosa Ziehau }
7523499c3e17SSepherosa Ziehau SYSUNINIT(hn_sysuninit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysuninit, NULL);
7524