xref: /freebsd/sys/dev/hyperv/netvsc/if_hn.c (revision c49d47daf37f7cddef07e456565ad6f2270de773)
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>
6415516c77SSepherosa Ziehau #include <sys/bus.h>
6515516c77SSepherosa Ziehau #include <sys/kernel.h>
6615516c77SSepherosa Ziehau #include <sys/limits.h>
6715516c77SSepherosa Ziehau #include <sys/malloc.h>
6815516c77SSepherosa Ziehau #include <sys/mbuf.h>
6915516c77SSepherosa Ziehau #include <sys/module.h>
7015516c77SSepherosa Ziehau #include <sys/queue.h>
7115516c77SSepherosa Ziehau #include <sys/lock.h>
72499c3e17SSepherosa Ziehau #include <sys/rmlock.h>
73499c3e17SSepherosa Ziehau #include <sys/sbuf.h>
7415516c77SSepherosa Ziehau #include <sys/smp.h>
7515516c77SSepherosa Ziehau #include <sys/socket.h>
7615516c77SSepherosa Ziehau #include <sys/sockio.h>
7715516c77SSepherosa Ziehau #include <sys/sx.h>
7815516c77SSepherosa Ziehau #include <sys/sysctl.h>
7915516c77SSepherosa Ziehau #include <sys/systm.h>
8015516c77SSepherosa Ziehau #include <sys/taskqueue.h>
8115516c77SSepherosa Ziehau #include <sys/buf_ring.h>
825bdfd3fdSDexuan Cui #include <sys/eventhandler.h>
8315516c77SSepherosa Ziehau 
8415516c77SSepherosa Ziehau #include <machine/atomic.h>
8515516c77SSepherosa Ziehau #include <machine/in_cksum.h>
8615516c77SSepherosa Ziehau 
8715516c77SSepherosa Ziehau #include <net/bpf.h>
8815516c77SSepherosa Ziehau #include <net/ethernet.h>
8915516c77SSepherosa Ziehau #include <net/if.h>
905bdfd3fdSDexuan Cui #include <net/if_dl.h>
9115516c77SSepherosa Ziehau #include <net/if_media.h>
9215516c77SSepherosa Ziehau #include <net/if_types.h>
9315516c77SSepherosa Ziehau #include <net/if_var.h>
9415516c77SSepherosa Ziehau #include <net/rndis.h>
9534d68912SSepherosa Ziehau #ifdef RSS
9634d68912SSepherosa Ziehau #include <net/rss_config.h>
9734d68912SSepherosa Ziehau #endif
9815516c77SSepherosa Ziehau 
9915516c77SSepherosa Ziehau #include <netinet/in_systm.h>
10015516c77SSepherosa Ziehau #include <netinet/in.h>
10115516c77SSepherosa Ziehau #include <netinet/ip.h>
10215516c77SSepherosa Ziehau #include <netinet/ip6.h>
10315516c77SSepherosa Ziehau #include <netinet/tcp.h>
10415516c77SSepherosa Ziehau #include <netinet/tcp_lro.h>
10515516c77SSepherosa Ziehau #include <netinet/udp.h>
10615516c77SSepherosa Ziehau 
10715516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h>
10815516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv_busdma.h>
10915516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus.h>
11015516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus_xact.h>
11115516c77SSepherosa Ziehau 
11215516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/ndis.h>
11315516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnreg.h>
11415516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnvar.h>
11515516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_nvs.h>
11615516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_rndis.h>
11715516c77SSepherosa Ziehau 
11815516c77SSepherosa Ziehau #include "vmbus_if.h"
11915516c77SSepherosa Ziehau 
12023bf9e15SSepherosa Ziehau #define HN_IFSTART_SUPPORT
12123bf9e15SSepherosa Ziehau 
12215516c77SSepherosa Ziehau #define HN_RING_CNT_DEF_MAX		8
12315516c77SSepherosa Ziehau 
124499c3e17SSepherosa Ziehau #define HN_VFMAP_SIZE_DEF		8
125499c3e17SSepherosa Ziehau 
1269c6cae24SSepherosa Ziehau #define HN_XPNT_VF_ATTWAIT_MIN		2	/* seconds */
1279c6cae24SSepherosa Ziehau 
12815516c77SSepherosa Ziehau /* YYY should get it from the underlying channel */
12915516c77SSepherosa Ziehau #define HN_TX_DESC_CNT			512
13015516c77SSepherosa Ziehau 
13115516c77SSepherosa Ziehau #define HN_RNDIS_PKT_LEN					\
13215516c77SSepherosa Ziehau 	(sizeof(struct rndis_packet_msg) +			\
13315516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) +	\
13415516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) +		\
13515516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) +		\
13615516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_TXCSUM_INFO_SIZE))
13715516c77SSepherosa Ziehau #define HN_RNDIS_PKT_BOUNDARY		PAGE_SIZE
13815516c77SSepherosa Ziehau #define HN_RNDIS_PKT_ALIGN		CACHE_LINE_SIZE
13915516c77SSepherosa Ziehau 
14015516c77SSepherosa Ziehau #define HN_TX_DATA_BOUNDARY		PAGE_SIZE
14115516c77SSepherosa Ziehau #define HN_TX_DATA_MAXSIZE		IP_MAXPACKET
14215516c77SSepherosa Ziehau #define HN_TX_DATA_SEGSIZE		PAGE_SIZE
14315516c77SSepherosa Ziehau /* -1 for RNDIS packet message */
14415516c77SSepherosa Ziehau #define HN_TX_DATA_SEGCNT_MAX		(HN_GPACNT_MAX - 1)
14515516c77SSepherosa Ziehau 
14615516c77SSepherosa Ziehau #define HN_DIRECT_TX_SIZE_DEF		128
14715516c77SSepherosa Ziehau 
14815516c77SSepherosa Ziehau #define HN_EARLY_TXEOF_THRESH		8
14915516c77SSepherosa Ziehau 
15015516c77SSepherosa Ziehau #define HN_PKTBUF_LEN_DEF		(16 * 1024)
15115516c77SSepherosa Ziehau 
15215516c77SSepherosa Ziehau #define HN_LROENT_CNT_DEF		128
15315516c77SSepherosa Ziehau 
15415516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MULTIRX_DEF	(12 * ETHERMTU)
15515516c77SSepherosa Ziehau #define HN_LRO_LENLIM_DEF		(25 * ETHERMTU)
15615516c77SSepherosa Ziehau /* YYY 2*MTU is a bit rough, but should be good enough. */
15715516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MIN(ifp)		(2 * (ifp)->if_mtu)
15815516c77SSepherosa Ziehau 
15915516c77SSepherosa Ziehau #define HN_LRO_ACKCNT_DEF		1
16015516c77SSepherosa Ziehau 
16115516c77SSepherosa Ziehau #define HN_LOCK_INIT(sc)		\
16215516c77SSepherosa Ziehau 	sx_init(&(sc)->hn_lock, device_get_nameunit((sc)->hn_dev))
16315516c77SSepherosa Ziehau #define HN_LOCK_DESTROY(sc)		sx_destroy(&(sc)->hn_lock)
16415516c77SSepherosa Ziehau #define HN_LOCK_ASSERT(sc)		sx_assert(&(sc)->hn_lock, SA_XLOCKED)
165fdc4f478SSepherosa Ziehau #define HN_LOCK(sc)					\
166fdc4f478SSepherosa Ziehau do {							\
167fdc4f478SSepherosa Ziehau 	while (sx_try_xlock(&(sc)->hn_lock) == 0)	\
168fdc4f478SSepherosa Ziehau 		DELAY(1000);				\
169fdc4f478SSepherosa Ziehau } while (0)
17015516c77SSepherosa Ziehau #define HN_UNLOCK(sc)			sx_xunlock(&(sc)->hn_lock)
17115516c77SSepherosa Ziehau 
17215516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK			(CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP)
17315516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK		(CSUM_IP6_TCP | CSUM_IP6_UDP)
17415516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc)		\
17515516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK)
17615516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc)	\
17715516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK)
17815516c77SSepherosa Ziehau 
179dc13fee6SSepherosa Ziehau #define HN_PKTSIZE_MIN(align)		\
180dc13fee6SSepherosa Ziehau 	roundup2(ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN + \
181dc13fee6SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN, (align))
182dc13fee6SSepherosa Ziehau #define HN_PKTSIZE(m, align)		\
183dc13fee6SSepherosa Ziehau 	roundup2((m)->m_pkthdr.len + HN_RNDIS_PKT_LEN, (align))
184dc13fee6SSepherosa Ziehau 
18534d68912SSepherosa Ziehau #ifdef RSS
18634d68912SSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx)	rss_getcpu((idx) % rss_getnumbuckets())
18734d68912SSepherosa Ziehau #else
1880e11868dSSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx)	(((sc)->hn_cpu + (idx)) % mp_ncpus)
18934d68912SSepherosa Ziehau #endif
1900e11868dSSepherosa Ziehau 
19115516c77SSepherosa Ziehau struct hn_txdesc {
19215516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
19315516c77SSepherosa Ziehau 	SLIST_ENTRY(hn_txdesc)		link;
19415516c77SSepherosa Ziehau #endif
195dc13fee6SSepherosa Ziehau 	STAILQ_ENTRY(hn_txdesc)		agg_link;
196dc13fee6SSepherosa Ziehau 
197dc13fee6SSepherosa Ziehau 	/* Aggregated txdescs, in sending order. */
198dc13fee6SSepherosa Ziehau 	STAILQ_HEAD(, hn_txdesc)	agg_list;
199dc13fee6SSepherosa Ziehau 
200dc13fee6SSepherosa Ziehau 	/* The oldest packet, if transmission aggregation happens. */
20115516c77SSepherosa Ziehau 	struct mbuf			*m;
20215516c77SSepherosa Ziehau 	struct hn_tx_ring		*txr;
20315516c77SSepherosa Ziehau 	int				refs;
20415516c77SSepherosa Ziehau 	uint32_t			flags;	/* HN_TXD_FLAG_ */
20515516c77SSepherosa Ziehau 	struct hn_nvs_sendctx		send_ctx;
20615516c77SSepherosa Ziehau 	uint32_t			chim_index;
20715516c77SSepherosa Ziehau 	int				chim_size;
20815516c77SSepherosa Ziehau 
20915516c77SSepherosa Ziehau 	bus_dmamap_t			data_dmap;
21015516c77SSepherosa Ziehau 
21115516c77SSepherosa Ziehau 	bus_addr_t			rndis_pkt_paddr;
21215516c77SSepherosa Ziehau 	struct rndis_packet_msg		*rndis_pkt;
21315516c77SSepherosa Ziehau 	bus_dmamap_t			rndis_pkt_dmap;
21415516c77SSepherosa Ziehau };
21515516c77SSepherosa Ziehau 
21615516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST		0x0001
21715516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP		0x0002
218dc13fee6SSepherosa Ziehau #define HN_TXD_FLAG_ONAGG		0x0004
21915516c77SSepherosa Ziehau 
22015516c77SSepherosa Ziehau struct hn_rxinfo {
22115516c77SSepherosa Ziehau 	uint32_t			vlan_info;
22215516c77SSepherosa Ziehau 	uint32_t			csum_info;
22315516c77SSepherosa Ziehau 	uint32_t			hash_info;
22415516c77SSepherosa Ziehau 	uint32_t			hash_value;
22515516c77SSepherosa Ziehau };
22615516c77SSepherosa Ziehau 
227962f0357SSepherosa Ziehau struct hn_rxvf_setarg {
2285bdfd3fdSDexuan Cui 	struct hn_rx_ring	*rxr;
229962f0357SSepherosa Ziehau 	struct ifnet		*vf_ifp;
2305bdfd3fdSDexuan Cui };
2315bdfd3fdSDexuan Cui 
23215516c77SSepherosa Ziehau #define HN_RXINFO_VLAN			0x0001
23315516c77SSepherosa Ziehau #define HN_RXINFO_CSUM			0x0002
23415516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF		0x0004
23515516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL		0x0008
23615516c77SSepherosa Ziehau #define HN_RXINFO_ALL			\
23715516c77SSepherosa Ziehau 	(HN_RXINFO_VLAN |		\
23815516c77SSepherosa Ziehau 	 HN_RXINFO_CSUM |		\
23915516c77SSepherosa Ziehau 	 HN_RXINFO_HASHINF |		\
24015516c77SSepherosa Ziehau 	 HN_RXINFO_HASHVAL)
24115516c77SSepherosa Ziehau 
24215516c77SSepherosa Ziehau #define HN_NDIS_VLAN_INFO_INVALID	0xffffffff
24315516c77SSepherosa Ziehau #define HN_NDIS_RXCSUM_INFO_INVALID	0
24415516c77SSepherosa Ziehau #define HN_NDIS_HASH_INFO_INVALID	0
24515516c77SSepherosa Ziehau 
24615516c77SSepherosa Ziehau static int			hn_probe(device_t);
24715516c77SSepherosa Ziehau static int			hn_attach(device_t);
24815516c77SSepherosa Ziehau static int			hn_detach(device_t);
24915516c77SSepherosa Ziehau static int			hn_shutdown(device_t);
25015516c77SSepherosa Ziehau static void			hn_chan_callback(struct vmbus_channel *,
25115516c77SSepherosa Ziehau 				    void *);
25215516c77SSepherosa Ziehau 
25315516c77SSepherosa Ziehau static void			hn_init(void *);
25415516c77SSepherosa Ziehau static int			hn_ioctl(struct ifnet *, u_long, caddr_t);
25523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
25615516c77SSepherosa Ziehau static void			hn_start(struct ifnet *);
25723bf9e15SSepherosa Ziehau #endif
25815516c77SSepherosa Ziehau static int			hn_transmit(struct ifnet *, struct mbuf *);
25915516c77SSepherosa Ziehau static void			hn_xmit_qflush(struct ifnet *);
26015516c77SSepherosa Ziehau static int			hn_ifmedia_upd(struct ifnet *);
26115516c77SSepherosa Ziehau static void			hn_ifmedia_sts(struct ifnet *,
26215516c77SSepherosa Ziehau 				    struct ifmediareq *);
26315516c77SSepherosa Ziehau 
264499c3e17SSepherosa Ziehau static void			hn_ifnet_event(void *, struct ifnet *, int);
265499c3e17SSepherosa Ziehau static void			hn_ifaddr_event(void *, struct ifnet *);
266499c3e17SSepherosa Ziehau static void			hn_ifnet_attevent(void *, struct ifnet *);
267499c3e17SSepherosa Ziehau static void			hn_ifnet_detevent(void *, struct ifnet *);
2689c6cae24SSepherosa Ziehau static void			hn_ifnet_lnkevent(void *, struct ifnet *, int);
269499c3e17SSepherosa Ziehau 
270962f0357SSepherosa Ziehau static bool			hn_ismyvf(const struct hn_softc *,
271962f0357SSepherosa Ziehau 				    const struct ifnet *);
272962f0357SSepherosa Ziehau static void			hn_rxvf_change(struct hn_softc *,
273962f0357SSepherosa Ziehau 				    struct ifnet *, bool);
274962f0357SSepherosa Ziehau static void			hn_rxvf_set(struct hn_softc *, struct ifnet *);
275962f0357SSepherosa Ziehau static void			hn_rxvf_set_task(void *, int);
2769c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_input(struct ifnet *, struct mbuf *);
2779c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_iocsetflags(struct hn_softc *);
2789c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_iocsetcaps(struct hn_softc *,
2799c6cae24SSepherosa Ziehau 				    struct ifreq *);
2809c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_saveifflags(struct hn_softc *);
2819c6cae24SSepherosa Ziehau static bool			hn_xpnt_vf_isready(struct hn_softc *);
2829c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_setready(struct hn_softc *);
2839c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_init_taskfunc(void *, int);
2849c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_init(struct hn_softc *);
285a97fff19SSepherosa Ziehau static void			hn_xpnt_vf_setenable(struct hn_softc *);
286a97fff19SSepherosa Ziehau static void			hn_xpnt_vf_setdisable(struct hn_softc *, bool);
287642ec226SSepherosa Ziehau static void			hn_vf_rss_fixup(struct hn_softc *, bool);
288642ec226SSepherosa Ziehau static void			hn_vf_rss_restore(struct hn_softc *);
289962f0357SSepherosa Ziehau 
29015516c77SSepherosa Ziehau static int			hn_rndis_rxinfo(const void *, int,
29115516c77SSepherosa Ziehau 				    struct hn_rxinfo *);
29215516c77SSepherosa Ziehau static void			hn_rndis_rx_data(struct hn_rx_ring *,
29315516c77SSepherosa Ziehau 				    const void *, int);
29415516c77SSepherosa Ziehau static void			hn_rndis_rx_status(struct hn_softc *,
29515516c77SSepherosa Ziehau 				    const void *, int);
296b3b75d9cSSepherosa Ziehau static void			hn_rndis_init_fixat(struct hn_softc *, int);
29715516c77SSepherosa Ziehau 
29815516c77SSepherosa Ziehau static void			hn_nvs_handle_notify(struct hn_softc *,
29915516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
30015516c77SSepherosa Ziehau static void			hn_nvs_handle_comp(struct hn_softc *,
30115516c77SSepherosa Ziehau 				    struct vmbus_channel *,
30215516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
30315516c77SSepherosa Ziehau static void			hn_nvs_handle_rxbuf(struct hn_rx_ring *,
30415516c77SSepherosa Ziehau 				    struct vmbus_channel *,
30515516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
30615516c77SSepherosa Ziehau static void			hn_nvs_ack_rxbuf(struct hn_rx_ring *,
30715516c77SSepherosa Ziehau 				    struct vmbus_channel *, uint64_t);
30815516c77SSepherosa Ziehau 
30915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
31015516c77SSepherosa Ziehau static int			hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS);
31115516c77SSepherosa Ziehau static int			hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS);
31215516c77SSepherosa Ziehau #endif
31315516c77SSepherosa Ziehau static int			hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS);
31415516c77SSepherosa Ziehau static int			hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS);
31515516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
31615516c77SSepherosa Ziehau static int			hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS);
31715516c77SSepherosa Ziehau #else
31815516c77SSepherosa Ziehau static int			hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS);
31915516c77SSepherosa Ziehau #endif
32015516c77SSepherosa Ziehau static int			hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
32115516c77SSepherosa Ziehau static int			hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
32215516c77SSepherosa Ziehau static int			hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS);
32315516c77SSepherosa Ziehau static int			hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS);
32415516c77SSepherosa Ziehau static int			hn_caps_sysctl(SYSCTL_HANDLER_ARGS);
32515516c77SSepherosa Ziehau static int			hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS);
32615516c77SSepherosa Ziehau static int			hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS);
32734d68912SSepherosa Ziehau #ifndef RSS
32815516c77SSepherosa Ziehau static int			hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS);
32915516c77SSepherosa Ziehau static int			hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS);
33034d68912SSepherosa Ziehau #endif
33115516c77SSepherosa Ziehau static int			hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS);
332642ec226SSepherosa Ziehau static int			hn_rss_hcap_sysctl(SYSCTL_HANDLER_ARGS);
333642ec226SSepherosa Ziehau static int			hn_rss_mbuf_sysctl(SYSCTL_HANDLER_ARGS);
334dc13fee6SSepherosa Ziehau static int			hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS);
335dc13fee6SSepherosa Ziehau static int			hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS);
336dc13fee6SSepherosa Ziehau static int			hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS);
337dc13fee6SSepherosa Ziehau static int			hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS);
3386c1204dfSSepherosa Ziehau static int			hn_polling_sysctl(SYSCTL_HANDLER_ARGS);
33940d60d6eSDexuan Cui static int			hn_vf_sysctl(SYSCTL_HANDLER_ARGS);
340499c3e17SSepherosa Ziehau static int			hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS);
341499c3e17SSepherosa Ziehau static int			hn_vflist_sysctl(SYSCTL_HANDLER_ARGS);
342499c3e17SSepherosa Ziehau static int			hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS);
3439c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS);
3449c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS);
34515516c77SSepherosa Ziehau 
3465bdfd3fdSDexuan Cui static void			hn_stop(struct hn_softc *, bool);
34715516c77SSepherosa Ziehau static void			hn_init_locked(struct hn_softc *);
34815516c77SSepherosa Ziehau static int			hn_chan_attach(struct hn_softc *,
34915516c77SSepherosa Ziehau 				    struct vmbus_channel *);
35015516c77SSepherosa Ziehau static void			hn_chan_detach(struct hn_softc *,
35115516c77SSepherosa Ziehau 				    struct vmbus_channel *);
35215516c77SSepherosa Ziehau static int			hn_attach_subchans(struct hn_softc *);
35315516c77SSepherosa Ziehau static void			hn_detach_allchans(struct hn_softc *);
35415516c77SSepherosa Ziehau static void			hn_chan_rollup(struct hn_rx_ring *,
35515516c77SSepherosa Ziehau 				    struct hn_tx_ring *);
35615516c77SSepherosa Ziehau static void			hn_set_ring_inuse(struct hn_softc *, int);
35715516c77SSepherosa Ziehau static int			hn_synth_attach(struct hn_softc *, int);
35815516c77SSepherosa Ziehau static void			hn_synth_detach(struct hn_softc *);
35915516c77SSepherosa Ziehau static int			hn_synth_alloc_subchans(struct hn_softc *,
36015516c77SSepherosa Ziehau 				    int *);
3612494d735SSepherosa Ziehau static bool			hn_synth_attachable(const struct hn_softc *);
36215516c77SSepherosa Ziehau static void			hn_suspend(struct hn_softc *);
36315516c77SSepherosa Ziehau static void			hn_suspend_data(struct hn_softc *);
36415516c77SSepherosa Ziehau static void			hn_suspend_mgmt(struct hn_softc *);
36515516c77SSepherosa Ziehau static void			hn_resume(struct hn_softc *);
36615516c77SSepherosa Ziehau static void			hn_resume_data(struct hn_softc *);
36715516c77SSepherosa Ziehau static void			hn_resume_mgmt(struct hn_softc *);
36815516c77SSepherosa Ziehau static void			hn_suspend_mgmt_taskfunc(void *, int);
36925641fc7SSepherosa Ziehau static void			hn_chan_drain(struct hn_softc *,
37025641fc7SSepherosa Ziehau 				    struct vmbus_channel *);
371b3b75d9cSSepherosa Ziehau static void			hn_disable_rx(struct hn_softc *);
372b3b75d9cSSepherosa Ziehau static void			hn_drain_rxtx(struct hn_softc *, int);
3736c1204dfSSepherosa Ziehau static void			hn_polling(struct hn_softc *, u_int);
3746c1204dfSSepherosa Ziehau static void			hn_chan_polling(struct vmbus_channel *, u_int);
3759c6cae24SSepherosa Ziehau static void			hn_mtu_change_fixup(struct hn_softc *);
37615516c77SSepherosa Ziehau 
37715516c77SSepherosa Ziehau static void			hn_update_link_status(struct hn_softc *);
37815516c77SSepherosa Ziehau static void			hn_change_network(struct hn_softc *);
37915516c77SSepherosa Ziehau static void			hn_link_taskfunc(void *, int);
38015516c77SSepherosa Ziehau static void			hn_netchg_init_taskfunc(void *, int);
38115516c77SSepherosa Ziehau static void			hn_netchg_status_taskfunc(void *, int);
38215516c77SSepherosa Ziehau static void			hn_link_status(struct hn_softc *);
38315516c77SSepherosa Ziehau 
38415516c77SSepherosa Ziehau static int			hn_create_rx_data(struct hn_softc *, int);
38515516c77SSepherosa Ziehau static void			hn_destroy_rx_data(struct hn_softc *);
38615516c77SSepherosa Ziehau static int			hn_check_iplen(const struct mbuf *, int);
387f1b0a43fSSepherosa Ziehau static int			hn_set_rxfilter(struct hn_softc *, uint32_t);
388c08f7b2cSSepherosa Ziehau static int			hn_rxfilter_config(struct hn_softc *);
38934d68912SSepherosa Ziehau #ifndef RSS
39015516c77SSepherosa Ziehau static int			hn_rss_reconfig(struct hn_softc *);
39134d68912SSepherosa Ziehau #endif
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 *);
40315516c77SSepherosa Ziehau static void			hn_destroy_tx_data(struct hn_softc *);
40415516c77SSepherosa Ziehau static void			hn_txdesc_dmamap_destroy(struct hn_txdesc *);
40525641fc7SSepherosa Ziehau static void			hn_txdesc_gc(struct hn_tx_ring *,
40625641fc7SSepherosa Ziehau 				    struct hn_txdesc *);
407dc13fee6SSepherosa Ziehau static int			hn_encap(struct ifnet *, struct hn_tx_ring *,
40815516c77SSepherosa Ziehau 				    struct hn_txdesc *, struct mbuf **);
40915516c77SSepherosa Ziehau static int			hn_txpkt(struct ifnet *, struct hn_tx_ring *,
41015516c77SSepherosa Ziehau 				    struct hn_txdesc *);
41115516c77SSepherosa Ziehau static void			hn_set_chim_size(struct hn_softc *, int);
41215516c77SSepherosa Ziehau static void			hn_set_tso_maxsize(struct hn_softc *, int, int);
41315516c77SSepherosa Ziehau static bool			hn_tx_ring_pending(struct hn_tx_ring *);
41415516c77SSepherosa Ziehau static void			hn_tx_ring_qflush(struct hn_tx_ring *);
41515516c77SSepherosa Ziehau static void			hn_resume_tx(struct hn_softc *, int);
416dc13fee6SSepherosa Ziehau static void			hn_set_txagg(struct hn_softc *);
417dc13fee6SSepherosa Ziehau static void			*hn_try_txagg(struct ifnet *,
418dc13fee6SSepherosa Ziehau 				    struct hn_tx_ring *, struct hn_txdesc *,
419dc13fee6SSepherosa Ziehau 				    int);
42015516c77SSepherosa Ziehau static int			hn_get_txswq_depth(const struct hn_tx_ring *);
42115516c77SSepherosa Ziehau static void			hn_txpkt_done(struct hn_nvs_sendctx *,
42215516c77SSepherosa Ziehau 				    struct hn_softc *, struct vmbus_channel *,
42315516c77SSepherosa Ziehau 				    const void *, int);
42415516c77SSepherosa Ziehau static int			hn_txpkt_sglist(struct hn_tx_ring *,
42515516c77SSepherosa Ziehau 				    struct hn_txdesc *);
42615516c77SSepherosa Ziehau static int			hn_txpkt_chim(struct hn_tx_ring *,
42715516c77SSepherosa Ziehau 				    struct hn_txdesc *);
42815516c77SSepherosa Ziehau static int			hn_xmit(struct hn_tx_ring *, int);
42915516c77SSepherosa Ziehau static void			hn_xmit_taskfunc(void *, int);
43015516c77SSepherosa Ziehau static void			hn_xmit_txeof(struct hn_tx_ring *);
43115516c77SSepherosa Ziehau static void			hn_xmit_txeof_taskfunc(void *, int);
43223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
43315516c77SSepherosa Ziehau static int			hn_start_locked(struct hn_tx_ring *, int);
43415516c77SSepherosa Ziehau static void			hn_start_taskfunc(void *, int);
43515516c77SSepherosa Ziehau static void			hn_start_txeof(struct hn_tx_ring *);
43615516c77SSepherosa Ziehau static void			hn_start_txeof_taskfunc(void *, int);
43723bf9e15SSepherosa Ziehau #endif
43815516c77SSepherosa Ziehau 
43915516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
44015516c77SSepherosa Ziehau     "Hyper-V network interface");
44115516c77SSepherosa Ziehau 
44215516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */
44315516c77SSepherosa Ziehau static int			hn_trust_hosttcp = 1;
44415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN,
44515516c77SSepherosa Ziehau     &hn_trust_hosttcp, 0,
44615516c77SSepherosa Ziehau     "Trust tcp segement verification on host side, "
44715516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
44815516c77SSepherosa Ziehau 
44915516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */
45015516c77SSepherosa Ziehau static int			hn_trust_hostudp = 1;
45115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN,
45215516c77SSepherosa Ziehau     &hn_trust_hostudp, 0,
45315516c77SSepherosa Ziehau     "Trust udp datagram verification on host side, "
45415516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
45515516c77SSepherosa Ziehau 
45615516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */
45715516c77SSepherosa Ziehau static int			hn_trust_hostip = 1;
45815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN,
45915516c77SSepherosa Ziehau     &hn_trust_hostip, 0,
46015516c77SSepherosa Ziehau     "Trust ip packet verification on host side, "
46115516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
46215516c77SSepherosa Ziehau 
46315516c77SSepherosa Ziehau /* Limit TSO burst size */
46415516c77SSepherosa Ziehau static int			hn_tso_maxlen = IP_MAXPACKET;
46515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN,
46615516c77SSepherosa Ziehau     &hn_tso_maxlen, 0, "TSO burst limit");
46715516c77SSepherosa Ziehau 
46815516c77SSepherosa Ziehau /* Limit chimney send size */
46915516c77SSepherosa Ziehau static int			hn_tx_chimney_size = 0;
47015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN,
47115516c77SSepherosa Ziehau     &hn_tx_chimney_size, 0, "Chimney send packet size limit");
47215516c77SSepherosa Ziehau 
47315516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */
47415516c77SSepherosa Ziehau static int			hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF;
47515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN,
47615516c77SSepherosa Ziehau     &hn_direct_tx_size, 0, "Size of the packet for direct transmission");
47715516c77SSepherosa Ziehau 
47815516c77SSepherosa Ziehau /* # of LRO entries per RX ring */
47915516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
48015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
48115516c77SSepherosa Ziehau static int			hn_lro_entry_count = HN_LROENT_CNT_DEF;
48215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN,
48315516c77SSepherosa Ziehau     &hn_lro_entry_count, 0, "LRO entry count");
48415516c77SSepherosa Ziehau #endif
48515516c77SSepherosa Ziehau #endif
48615516c77SSepherosa Ziehau 
487fdd0222aSSepherosa Ziehau static int			hn_tx_taskq_cnt = 1;
488fdd0222aSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_cnt, CTLFLAG_RDTUN,
489fdd0222aSSepherosa Ziehau     &hn_tx_taskq_cnt, 0, "# of TX taskqueues");
490fdd0222aSSepherosa Ziehau 
4910e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_INDEP	0
4920e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_GLOBAL	1
4930e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_EVTTQ	2
4940e11868dSSepherosa Ziehau 
4950e11868dSSepherosa Ziehau static int			hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
4960e11868dSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_mode, CTLFLAG_RDTUN,
4970e11868dSSepherosa Ziehau     &hn_tx_taskq_mode, 0, "TX taskqueue modes: "
4980e11868dSSepherosa Ziehau     "0 - independent, 1 - share global tx taskqs, 2 - share event taskqs");
4990e11868dSSepherosa Ziehau 
50015516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
50115516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 0;
50215516c77SSepherosa Ziehau #else
50315516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 1;
50415516c77SSepherosa Ziehau #endif
50515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD,
50615516c77SSepherosa Ziehau     &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors");
50715516c77SSepherosa Ziehau 
50823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
50915516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */
51015516c77SSepherosa Ziehau static int			hn_use_if_start = 0;
51115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN,
51215516c77SSepherosa Ziehau     &hn_use_if_start, 0, "Use if_start TX method");
51323bf9e15SSepherosa Ziehau #endif
51415516c77SSepherosa Ziehau 
51515516c77SSepherosa Ziehau /* # of channels to use */
51615516c77SSepherosa Ziehau static int			hn_chan_cnt = 0;
51715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN,
51815516c77SSepherosa Ziehau     &hn_chan_cnt, 0,
51915516c77SSepherosa Ziehau     "# of channels to use; each channel has one RX ring and one TX ring");
52015516c77SSepherosa Ziehau 
52115516c77SSepherosa Ziehau /* # of transmit rings to use */
52215516c77SSepherosa Ziehau static int			hn_tx_ring_cnt = 0;
52315516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN,
52415516c77SSepherosa Ziehau     &hn_tx_ring_cnt, 0, "# of TX rings to use");
52515516c77SSepherosa Ziehau 
52615516c77SSepherosa Ziehau /* Software TX ring deptch */
52715516c77SSepherosa Ziehau static int			hn_tx_swq_depth = 0;
52815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN,
52915516c77SSepherosa Ziehau     &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING");
53015516c77SSepherosa Ziehau 
53115516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */
53215516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
53315516c77SSepherosa Ziehau static u_int			hn_lro_mbufq_depth = 0;
53415516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN,
53515516c77SSepherosa Ziehau     &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue");
53615516c77SSepherosa Ziehau #endif
53715516c77SSepherosa Ziehau 
538dc13fee6SSepherosa Ziehau /* Packet transmission aggregation size limit */
539dc13fee6SSepherosa Ziehau static int			hn_tx_agg_size = -1;
540dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN,
541dc13fee6SSepherosa Ziehau     &hn_tx_agg_size, 0, "Packet transmission aggregation size limit");
542dc13fee6SSepherosa Ziehau 
543dc13fee6SSepherosa Ziehau /* Packet transmission aggregation count limit */
544fa915c4dSSepherosa Ziehau static int			hn_tx_agg_pkts = -1;
545dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN,
546dc13fee6SSepherosa Ziehau     &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit");
547dc13fee6SSepherosa Ziehau 
548499c3e17SSepherosa Ziehau /* VF list */
549499c3e17SSepherosa Ziehau SYSCTL_PROC(_hw_hn, OID_AUTO, vflist, CTLFLAG_RD | CTLTYPE_STRING,
550499c3e17SSepherosa Ziehau     0, 0, hn_vflist_sysctl, "A", "VF list");
551499c3e17SSepherosa Ziehau 
552499c3e17SSepherosa Ziehau /* VF mapping */
553499c3e17SSepherosa Ziehau SYSCTL_PROC(_hw_hn, OID_AUTO, vfmap, CTLFLAG_RD | CTLTYPE_STRING,
554499c3e17SSepherosa Ziehau     0, 0, hn_vfmap_sysctl, "A", "VF mapping");
555499c3e17SSepherosa Ziehau 
5569c6cae24SSepherosa Ziehau /* Transparent VF */
5579c6cae24SSepherosa Ziehau static int			hn_xpnt_vf = 0;
5589c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_transparent, CTLFLAG_RDTUN,
5599c6cae24SSepherosa Ziehau     &hn_xpnt_vf, 0, "Transparent VF mod");
5609c6cae24SSepherosa Ziehau 
5619c6cae24SSepherosa Ziehau /* Accurate BPF support for Transparent VF */
5629c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_accbpf = 0;
5639c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_xpnt_accbpf, CTLFLAG_RDTUN,
5649c6cae24SSepherosa Ziehau     &hn_xpnt_vf_accbpf, 0, "Accurate BPF for transparent VF");
5659c6cae24SSepherosa Ziehau 
5669c6cae24SSepherosa Ziehau /* Extra wait for transparent VF attach routing; unit seconds. */
5679c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN;
5689c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_xpnt_attwait, CTLFLAG_RWTUN,
5699c6cae24SSepherosa Ziehau     &hn_xpnt_vf_attwait, 0,
5709c6cae24SSepherosa Ziehau     "Extra wait for transparent VF attach routing; unit: seconds");
5719c6cae24SSepherosa Ziehau 
57215516c77SSepherosa Ziehau static u_int			hn_cpu_index;	/* next CPU for channel */
573fdd0222aSSepherosa Ziehau static struct taskqueue		**hn_tx_taskque;/* shared TX taskqueues */
57415516c77SSepherosa Ziehau 
575499c3e17SSepherosa Ziehau static struct rmlock		hn_vfmap_lock;
576499c3e17SSepherosa Ziehau static int			hn_vfmap_size;
577499c3e17SSepherosa Ziehau static struct ifnet		**hn_vfmap;
578499c3e17SSepherosa Ziehau 
57934d68912SSepherosa Ziehau #ifndef RSS
58015516c77SSepherosa Ziehau static const uint8_t
58115516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
58215516c77SSepherosa Ziehau 	0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
58315516c77SSepherosa Ziehau 	0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
58415516c77SSepherosa Ziehau 	0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
58515516c77SSepherosa Ziehau 	0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
58615516c77SSepherosa Ziehau 	0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
58715516c77SSepherosa Ziehau };
58834d68912SSepherosa Ziehau #endif	/* !RSS */
58915516c77SSepherosa Ziehau 
590c2d50b26SSepherosa Ziehau static const struct hyperv_guid	hn_guid = {
591c2d50b26SSepherosa Ziehau 	.hv_guid = {
592c2d50b26SSepherosa Ziehau 	    0x63, 0x51, 0x61, 0xf8, 0x3e, 0xdf, 0xc5, 0x46,
593c2d50b26SSepherosa Ziehau 	    0x91, 0x3f, 0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e }
594c2d50b26SSepherosa Ziehau };
595c2d50b26SSepherosa Ziehau 
59615516c77SSepherosa Ziehau static device_method_t hn_methods[] = {
59715516c77SSepherosa Ziehau 	/* Device interface */
59815516c77SSepherosa Ziehau 	DEVMETHOD(device_probe,		hn_probe),
59915516c77SSepherosa Ziehau 	DEVMETHOD(device_attach,	hn_attach),
60015516c77SSepherosa Ziehau 	DEVMETHOD(device_detach,	hn_detach),
60115516c77SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	hn_shutdown),
60215516c77SSepherosa Ziehau 	DEVMETHOD_END
60315516c77SSepherosa Ziehau };
60415516c77SSepherosa Ziehau 
60515516c77SSepherosa Ziehau static driver_t hn_driver = {
60615516c77SSepherosa Ziehau 	"hn",
60715516c77SSepherosa Ziehau 	hn_methods,
60815516c77SSepherosa Ziehau 	sizeof(struct hn_softc)
60915516c77SSepherosa Ziehau };
61015516c77SSepherosa Ziehau 
61115516c77SSepherosa Ziehau static devclass_t hn_devclass;
61215516c77SSepherosa Ziehau 
61315516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0);
61415516c77SSepherosa Ziehau MODULE_VERSION(hn, 1);
61515516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1);
61615516c77SSepherosa Ziehau 
61715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
61815516c77SSepherosa Ziehau static void
61915516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim)
62015516c77SSepherosa Ziehau {
62115516c77SSepherosa Ziehau 	int i;
62215516c77SSepherosa Ziehau 
623a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
62415516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim;
62515516c77SSepherosa Ziehau }
62615516c77SSepherosa Ziehau #endif
62715516c77SSepherosa Ziehau 
62815516c77SSepherosa Ziehau static int
62915516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd)
63015516c77SSepherosa Ziehau {
63115516c77SSepherosa Ziehau 
63215516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
63315516c77SSepherosa Ziehau 	    txd->chim_size == 0, ("invalid rndis sglist txd"));
63415516c77SSepherosa Ziehau 	return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA,
63515516c77SSepherosa Ziehau 	    &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt));
63615516c77SSepherosa Ziehau }
63715516c77SSepherosa Ziehau 
63815516c77SSepherosa Ziehau static int
63915516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd)
64015516c77SSepherosa Ziehau {
64115516c77SSepherosa Ziehau 	struct hn_nvs_rndis rndis;
64215516c77SSepherosa Ziehau 
64315516c77SSepherosa Ziehau 	KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID &&
64415516c77SSepherosa Ziehau 	    txd->chim_size > 0, ("invalid rndis chim txd"));
64515516c77SSepherosa Ziehau 
64615516c77SSepherosa Ziehau 	rndis.nvs_type = HN_NVS_TYPE_RNDIS;
64715516c77SSepherosa Ziehau 	rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA;
64815516c77SSepherosa Ziehau 	rndis.nvs_chim_idx = txd->chim_index;
64915516c77SSepherosa Ziehau 	rndis.nvs_chim_sz = txd->chim_size;
65015516c77SSepherosa Ziehau 
65115516c77SSepherosa Ziehau 	return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC,
65215516c77SSepherosa Ziehau 	    &rndis, sizeof(rndis), &txd->send_ctx));
65315516c77SSepherosa Ziehau }
65415516c77SSepherosa Ziehau 
65515516c77SSepherosa Ziehau static __inline uint32_t
65615516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc)
65715516c77SSepherosa Ziehau {
65815516c77SSepherosa Ziehau 	int i, bmap_cnt = sc->hn_chim_bmap_cnt;
65915516c77SSepherosa Ziehau 	u_long *bmap = sc->hn_chim_bmap;
66015516c77SSepherosa Ziehau 	uint32_t ret = HN_NVS_CHIM_IDX_INVALID;
66115516c77SSepherosa Ziehau 
66215516c77SSepherosa Ziehau 	for (i = 0; i < bmap_cnt; ++i) {
66315516c77SSepherosa Ziehau 		int idx;
66415516c77SSepherosa Ziehau 
66515516c77SSepherosa Ziehau 		idx = ffsl(~bmap[i]);
66615516c77SSepherosa Ziehau 		if (idx == 0)
66715516c77SSepherosa Ziehau 			continue;
66815516c77SSepherosa Ziehau 
66915516c77SSepherosa Ziehau 		--idx; /* ffsl is 1-based */
67015516c77SSepherosa Ziehau 		KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt,
67115516c77SSepherosa Ziehau 		    ("invalid i %d and idx %d", i, idx));
67215516c77SSepherosa Ziehau 
67315516c77SSepherosa Ziehau 		if (atomic_testandset_long(&bmap[i], idx))
67415516c77SSepherosa Ziehau 			continue;
67515516c77SSepherosa Ziehau 
67615516c77SSepherosa Ziehau 		ret = i * LONG_BIT + idx;
67715516c77SSepherosa Ziehau 		break;
67815516c77SSepherosa Ziehau 	}
67915516c77SSepherosa Ziehau 	return (ret);
68015516c77SSepherosa Ziehau }
68115516c77SSepherosa Ziehau 
68215516c77SSepherosa Ziehau static __inline void
68315516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx)
68415516c77SSepherosa Ziehau {
68515516c77SSepherosa Ziehau 	u_long mask;
68615516c77SSepherosa Ziehau 	uint32_t idx;
68715516c77SSepherosa Ziehau 
68815516c77SSepherosa Ziehau 	idx = chim_idx / LONG_BIT;
68915516c77SSepherosa Ziehau 	KASSERT(idx < sc->hn_chim_bmap_cnt,
69015516c77SSepherosa Ziehau 	    ("invalid chimney index 0x%x", chim_idx));
69115516c77SSepherosa Ziehau 
69215516c77SSepherosa Ziehau 	mask = 1UL << (chim_idx % LONG_BIT);
69315516c77SSepherosa Ziehau 	KASSERT(sc->hn_chim_bmap[idx] & mask,
69415516c77SSepherosa Ziehau 	    ("index bitmap 0x%lx, chimney index %u, "
69515516c77SSepherosa Ziehau 	     "bitmap idx %d, bitmask 0x%lx",
69615516c77SSepherosa Ziehau 	     sc->hn_chim_bmap[idx], chim_idx, idx, mask));
69715516c77SSepherosa Ziehau 
69815516c77SSepherosa Ziehau 	atomic_clear_long(&sc->hn_chim_bmap[idx], mask);
69915516c77SSepherosa Ziehau }
70015516c77SSepherosa Ziehau 
701edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
702cc0c6ebcSSepherosa Ziehau 
703cc0c6ebcSSepherosa Ziehau #define PULLUP_HDR(m, len)				\
704cc0c6ebcSSepherosa Ziehau do {							\
705cc0c6ebcSSepherosa Ziehau 	if (__predict_false((m)->m_len < (len))) {	\
706cc0c6ebcSSepherosa Ziehau 		(m) = m_pullup((m), (len));		\
707cc0c6ebcSSepherosa Ziehau 		if ((m) == NULL)			\
708cc0c6ebcSSepherosa Ziehau 			return (NULL);			\
709cc0c6ebcSSepherosa Ziehau 	}						\
710cc0c6ebcSSepherosa Ziehau } while (0)
711cc0c6ebcSSepherosa Ziehau 
712edd3f315SSepherosa Ziehau /*
713edd3f315SSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
714edd3f315SSepherosa Ziehau  */
715edd3f315SSepherosa Ziehau static __inline struct mbuf *
716edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head)
717edd3f315SSepherosa Ziehau {
718edd3f315SSepherosa Ziehau 	struct ether_vlan_header *evl;
719edd3f315SSepherosa Ziehau 	struct tcphdr *th;
720edd3f315SSepherosa Ziehau 	int ehlen;
721edd3f315SSepherosa Ziehau 
722edd3f315SSepherosa Ziehau 	KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable"));
723edd3f315SSepherosa Ziehau 
724edd3f315SSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
725edd3f315SSepherosa Ziehau 	evl = mtod(m_head, struct ether_vlan_header *);
726edd3f315SSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
727edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
728edd3f315SSepherosa Ziehau 	else
729edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
730*c49d47daSSepherosa Ziehau 	m_head->m_pkthdr.l2hlen = ehlen;
731edd3f315SSepherosa Ziehau 
732edd3f315SSepherosa Ziehau #ifdef INET
733edd3f315SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
734edd3f315SSepherosa Ziehau 		struct ip *ip;
735edd3f315SSepherosa Ziehau 		int iphlen;
736edd3f315SSepherosa Ziehau 
737edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
738edd3f315SSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
739edd3f315SSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
740*c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = iphlen;
741edd3f315SSepherosa Ziehau 
742edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
743edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + iphlen);
744edd3f315SSepherosa Ziehau 
745edd3f315SSepherosa Ziehau 		ip->ip_len = 0;
746edd3f315SSepherosa Ziehau 		ip->ip_sum = 0;
747edd3f315SSepherosa Ziehau 		th->th_sum = in_pseudo(ip->ip_src.s_addr,
748edd3f315SSepherosa Ziehau 		    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
749edd3f315SSepherosa Ziehau 	}
750edd3f315SSepherosa Ziehau #endif
751edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET)
752edd3f315SSepherosa Ziehau 	else
753edd3f315SSepherosa Ziehau #endif
754edd3f315SSepherosa Ziehau #ifdef INET6
755edd3f315SSepherosa Ziehau 	{
756edd3f315SSepherosa Ziehau 		struct ip6_hdr *ip6;
757edd3f315SSepherosa Ziehau 
758edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
759edd3f315SSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
760edd3f315SSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP) {
761edd3f315SSepherosa Ziehau 			m_freem(m_head);
762edd3f315SSepherosa Ziehau 			return (NULL);
763edd3f315SSepherosa Ziehau 		}
764*c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = sizeof(*ip6);
765edd3f315SSepherosa Ziehau 
766edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
767edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + sizeof(*ip6));
768edd3f315SSepherosa Ziehau 
769edd3f315SSepherosa Ziehau 		ip6->ip6_plen = 0;
770edd3f315SSepherosa Ziehau 		th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
771edd3f315SSepherosa Ziehau 	}
772edd3f315SSepherosa Ziehau #endif
773edd3f315SSepherosa Ziehau 	return (m_head);
774edd3f315SSepherosa Ziehau }
775cc0c6ebcSSepherosa Ziehau 
776cc0c6ebcSSepherosa Ziehau /*
777cc0c6ebcSSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
778cc0c6ebcSSepherosa Ziehau  */
779cc0c6ebcSSepherosa Ziehau static __inline struct mbuf *
780*c49d47daSSepherosa Ziehau hn_set_hlen(struct mbuf *m_head)
781cc0c6ebcSSepherosa Ziehau {
782cc0c6ebcSSepherosa Ziehau 	const struct ether_vlan_header *evl;
783cc0c6ebcSSepherosa Ziehau 	int ehlen;
784cc0c6ebcSSepherosa Ziehau 
785cc0c6ebcSSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
786cc0c6ebcSSepherosa Ziehau 	evl = mtod(m_head, const struct ether_vlan_header *);
787cc0c6ebcSSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
788cc0c6ebcSSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
789cc0c6ebcSSepherosa Ziehau 	else
790cc0c6ebcSSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
791*c49d47daSSepherosa Ziehau 	m_head->m_pkthdr.l2hlen = ehlen;
792cc0c6ebcSSepherosa Ziehau 
793cc0c6ebcSSepherosa Ziehau #ifdef INET
794*c49d47daSSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP_UDP)) {
795cc0c6ebcSSepherosa Ziehau 		const struct ip *ip;
796cc0c6ebcSSepherosa Ziehau 		int iphlen;
797cc0c6ebcSSepherosa Ziehau 
798cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
799cc0c6ebcSSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
800cc0c6ebcSSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
801*c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = iphlen;
802cc0c6ebcSSepherosa Ziehau 	}
803cc0c6ebcSSepherosa Ziehau #endif
804cc0c6ebcSSepherosa Ziehau #if defined(INET6) && defined(INET)
805cc0c6ebcSSepherosa Ziehau 	else
806cc0c6ebcSSepherosa Ziehau #endif
807cc0c6ebcSSepherosa Ziehau #ifdef INET6
808cc0c6ebcSSepherosa Ziehau 	{
809cc0c6ebcSSepherosa Ziehau 		const struct ip6_hdr *ip6;
810cc0c6ebcSSepherosa Ziehau 
811cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
812cc0c6ebcSSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
813*c49d47daSSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP) {
814*c49d47daSSepherosa Ziehau 			m_freem(m_head);
815*c49d47daSSepherosa Ziehau 			return (NULL);
816*c49d47daSSepherosa Ziehau 		}
817*c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = sizeof(*ip6);
818cc0c6ebcSSepherosa Ziehau 	}
819cc0c6ebcSSepherosa Ziehau #endif
820cc0c6ebcSSepherosa Ziehau 	return (m_head);
821cc0c6ebcSSepherosa Ziehau }
822cc0c6ebcSSepherosa Ziehau 
823*c49d47daSSepherosa Ziehau /*
824*c49d47daSSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
825*c49d47daSSepherosa Ziehau  */
826*c49d47daSSepherosa Ziehau static __inline struct mbuf *
827*c49d47daSSepherosa Ziehau hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn)
828*c49d47daSSepherosa Ziehau {
829*c49d47daSSepherosa Ziehau 	const struct tcphdr *th;
830*c49d47daSSepherosa Ziehau 	int ehlen, iphlen;
831*c49d47daSSepherosa Ziehau 
832*c49d47daSSepherosa Ziehau 	*tcpsyn = 0;
833*c49d47daSSepherosa Ziehau 	ehlen = m_head->m_pkthdr.l2hlen;
834*c49d47daSSepherosa Ziehau 	iphlen = m_head->m_pkthdr.l3hlen;
835*c49d47daSSepherosa Ziehau 
836*c49d47daSSepherosa Ziehau 	PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
837*c49d47daSSepherosa Ziehau 	th = mtodo(m_head, ehlen + iphlen);
838*c49d47daSSepherosa Ziehau 	if (th->th_flags & TH_SYN)
839*c49d47daSSepherosa Ziehau 		*tcpsyn = 1;
840*c49d47daSSepherosa Ziehau 	return (m_head);
841*c49d47daSSepherosa Ziehau }
842*c49d47daSSepherosa Ziehau 
843cc0c6ebcSSepherosa Ziehau #undef PULLUP_HDR
844cc0c6ebcSSepherosa Ziehau 
845edd3f315SSepherosa Ziehau #endif	/* INET6 || INET */
846edd3f315SSepherosa Ziehau 
84715516c77SSepherosa Ziehau static int
848f1b0a43fSSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc, uint32_t filter)
849f1b0a43fSSepherosa Ziehau {
850f1b0a43fSSepherosa Ziehau 	int error = 0;
851f1b0a43fSSepherosa Ziehau 
852f1b0a43fSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
853f1b0a43fSSepherosa Ziehau 
854f1b0a43fSSepherosa Ziehau 	if (sc->hn_rx_filter != filter) {
855f1b0a43fSSepherosa Ziehau 		error = hn_rndis_set_rxfilter(sc, filter);
856f1b0a43fSSepherosa Ziehau 		if (!error)
857f1b0a43fSSepherosa Ziehau 			sc->hn_rx_filter = filter;
858f1b0a43fSSepherosa Ziehau 	}
859f1b0a43fSSepherosa Ziehau 	return (error);
860f1b0a43fSSepherosa Ziehau }
861f1b0a43fSSepherosa Ziehau 
862f1b0a43fSSepherosa Ziehau static int
863c08f7b2cSSepherosa Ziehau hn_rxfilter_config(struct hn_softc *sc)
86415516c77SSepherosa Ziehau {
86515516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
86615516c77SSepherosa Ziehau 	uint32_t filter;
86715516c77SSepherosa Ziehau 
86815516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
86915516c77SSepherosa Ziehau 
8709c6cae24SSepherosa Ziehau 	/*
8719c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, we don't know how
8729c6cae24SSepherosa Ziehau 	 * its RX filter is configured, so stick the synthetic device in
8739c6cae24SSepherosa Ziehau 	 * the promiscous mode.
8749c6cae24SSepherosa Ziehau 	 */
8759c6cae24SSepherosa Ziehau 	if ((ifp->if_flags & IFF_PROMISC) || (sc->hn_flags & HN_FLAG_RXVF)) {
87615516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_PROMISCUOUS;
87715516c77SSepherosa Ziehau 	} else {
87815516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_DIRECTED;
87915516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_BROADCAST)
88015516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_BROADCAST;
88115516c77SSepherosa Ziehau 		/* TODO: support multicast list */
88215516c77SSepherosa Ziehau 		if ((ifp->if_flags & IFF_ALLMULTI) ||
88315516c77SSepherosa Ziehau 		    !TAILQ_EMPTY(&ifp->if_multiaddrs))
88415516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
88515516c77SSepherosa Ziehau 	}
886f1b0a43fSSepherosa Ziehau 	return (hn_set_rxfilter(sc, filter));
88715516c77SSepherosa Ziehau }
88815516c77SSepherosa Ziehau 
889dc13fee6SSepherosa Ziehau static void
890dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc)
891dc13fee6SSepherosa Ziehau {
892dc13fee6SSepherosa Ziehau 	uint32_t size, pkts;
893dc13fee6SSepherosa Ziehau 	int i;
894dc13fee6SSepherosa Ziehau 
895dc13fee6SSepherosa Ziehau 	/*
896dc13fee6SSepherosa Ziehau 	 * Setup aggregation size.
897dc13fee6SSepherosa Ziehau 	 */
898dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_size < 0)
899dc13fee6SSepherosa Ziehau 		size = UINT32_MAX;
900dc13fee6SSepherosa Ziehau 	else
901dc13fee6SSepherosa Ziehau 		size = sc->hn_agg_size;
902dc13fee6SSepherosa Ziehau 
903dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_size < size)
904dc13fee6SSepherosa Ziehau 		size = sc->hn_rndis_agg_size;
905dc13fee6SSepherosa Ziehau 
906a4364cfeSSepherosa Ziehau 	/* NOTE: We only aggregate packets using chimney sending buffers. */
907a4364cfeSSepherosa Ziehau 	if (size > (uint32_t)sc->hn_chim_szmax)
908a4364cfeSSepherosa Ziehau 		size = sc->hn_chim_szmax;
909a4364cfeSSepherosa Ziehau 
910dc13fee6SSepherosa Ziehau 	if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) {
911dc13fee6SSepherosa Ziehau 		/* Disable */
912dc13fee6SSepherosa Ziehau 		size = 0;
913dc13fee6SSepherosa Ziehau 		pkts = 0;
914dc13fee6SSepherosa Ziehau 		goto done;
915dc13fee6SSepherosa Ziehau 	}
916dc13fee6SSepherosa Ziehau 
917dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'int'. */
918dc13fee6SSepherosa Ziehau 	if (size > INT_MAX)
919dc13fee6SSepherosa Ziehau 		size = INT_MAX;
920dc13fee6SSepherosa Ziehau 
921dc13fee6SSepherosa Ziehau 	/*
922dc13fee6SSepherosa Ziehau 	 * Setup aggregation packet count.
923dc13fee6SSepherosa Ziehau 	 */
924dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_pkts < 0)
925dc13fee6SSepherosa Ziehau 		pkts = UINT32_MAX;
926dc13fee6SSepherosa Ziehau 	else
927dc13fee6SSepherosa Ziehau 		pkts = sc->hn_agg_pkts;
928dc13fee6SSepherosa Ziehau 
929dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_pkts < pkts)
930dc13fee6SSepherosa Ziehau 		pkts = sc->hn_rndis_agg_pkts;
931dc13fee6SSepherosa Ziehau 
932dc13fee6SSepherosa Ziehau 	if (pkts <= 1) {
933dc13fee6SSepherosa Ziehau 		/* Disable */
934dc13fee6SSepherosa Ziehau 		size = 0;
935dc13fee6SSepherosa Ziehau 		pkts = 0;
936dc13fee6SSepherosa Ziehau 		goto done;
937dc13fee6SSepherosa Ziehau 	}
938dc13fee6SSepherosa Ziehau 
939dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
940dc13fee6SSepherosa Ziehau 	if (pkts > SHRT_MAX)
941dc13fee6SSepherosa Ziehau 		pkts = SHRT_MAX;
942dc13fee6SSepherosa Ziehau 
943dc13fee6SSepherosa Ziehau done:
944dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
945dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_align > SHRT_MAX) {
946dc13fee6SSepherosa Ziehau 		/* Disable */
947dc13fee6SSepherosa Ziehau 		size = 0;
948dc13fee6SSepherosa Ziehau 		pkts = 0;
949dc13fee6SSepherosa Ziehau 	}
950dc13fee6SSepherosa Ziehau 
951dc13fee6SSepherosa Ziehau 	if (bootverbose) {
952dc13fee6SSepherosa Ziehau 		if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n",
953dc13fee6SSepherosa Ziehau 		    size, pkts, sc->hn_rndis_agg_align);
954dc13fee6SSepherosa Ziehau 	}
955dc13fee6SSepherosa Ziehau 
956dc13fee6SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
957dc13fee6SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
958dc13fee6SSepherosa Ziehau 
959dc13fee6SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
960dc13fee6SSepherosa Ziehau 		txr->hn_agg_szmax = size;
961dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktmax = pkts;
962dc13fee6SSepherosa Ziehau 		txr->hn_agg_align = sc->hn_rndis_agg_align;
963dc13fee6SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
964dc13fee6SSepherosa Ziehau 	}
965dc13fee6SSepherosa Ziehau }
966dc13fee6SSepherosa Ziehau 
96715516c77SSepherosa Ziehau static int
96815516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr)
96915516c77SSepherosa Ziehau {
97015516c77SSepherosa Ziehau 
97115516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet"));
97215516c77SSepherosa Ziehau 	if (hn_tx_swq_depth < txr->hn_txdesc_cnt)
97315516c77SSepherosa Ziehau 		return txr->hn_txdesc_cnt;
97415516c77SSepherosa Ziehau 	return hn_tx_swq_depth;
97515516c77SSepherosa Ziehau }
97615516c77SSepherosa Ziehau 
97734d68912SSepherosa Ziehau #ifndef RSS
97815516c77SSepherosa Ziehau static int
97915516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc)
98015516c77SSepherosa Ziehau {
98115516c77SSepherosa Ziehau 	int error;
98215516c77SSepherosa Ziehau 
98315516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
98415516c77SSepherosa Ziehau 
98515516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
98615516c77SSepherosa Ziehau 		return (ENXIO);
98715516c77SSepherosa Ziehau 
98815516c77SSepherosa Ziehau 	/*
98915516c77SSepherosa Ziehau 	 * Disable RSS first.
99015516c77SSepherosa Ziehau 	 *
99115516c77SSepherosa Ziehau 	 * NOTE:
99215516c77SSepherosa Ziehau 	 * Direct reconfiguration by setting the UNCHG flags does
99315516c77SSepherosa Ziehau 	 * _not_ work properly.
99415516c77SSepherosa Ziehau 	 */
99515516c77SSepherosa Ziehau 	if (bootverbose)
99615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "disable RSS\n");
99715516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE);
99815516c77SSepherosa Ziehau 	if (error) {
99915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS disable failed\n");
100015516c77SSepherosa Ziehau 		return (error);
100115516c77SSepherosa Ziehau 	}
100215516c77SSepherosa Ziehau 
100315516c77SSepherosa Ziehau 	/*
100415516c77SSepherosa Ziehau 	 * Reenable the RSS w/ the updated RSS key or indirect
100515516c77SSepherosa Ziehau 	 * table.
100615516c77SSepherosa Ziehau 	 */
100715516c77SSepherosa Ziehau 	if (bootverbose)
100815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "reconfig RSS\n");
100915516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
101015516c77SSepherosa Ziehau 	if (error) {
101115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS reconfig failed\n");
101215516c77SSepherosa Ziehau 		return (error);
101315516c77SSepherosa Ziehau 	}
101415516c77SSepherosa Ziehau 	return (0);
101515516c77SSepherosa Ziehau }
101634d68912SSepherosa Ziehau #endif	/* !RSS */
101715516c77SSepherosa Ziehau 
101815516c77SSepherosa Ziehau static void
1019afd4971bSSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc)
102015516c77SSepherosa Ziehau {
102115516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
1022afd4971bSSepherosa Ziehau 	int i, nchan;
102315516c77SSepherosa Ziehau 
1024afd4971bSSepherosa Ziehau 	nchan = sc->hn_rx_ring_inuse;
102515516c77SSepherosa Ziehau 	KASSERT(nchan > 1, ("invalid # of channels %d", nchan));
102615516c77SSepherosa Ziehau 
102715516c77SSepherosa Ziehau 	/*
102815516c77SSepherosa Ziehau 	 * Check indirect table to make sure that all channels in it
102915516c77SSepherosa Ziehau 	 * can be used.
103015516c77SSepherosa Ziehau 	 */
103115516c77SSepherosa Ziehau 	for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
103215516c77SSepherosa Ziehau 		if (rss->rss_ind[i] >= nchan) {
103315516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp,
103415516c77SSepherosa Ziehau 			    "RSS indirect table %d fixup: %u -> %d\n",
103515516c77SSepherosa Ziehau 			    i, rss->rss_ind[i], nchan - 1);
103615516c77SSepherosa Ziehau 			rss->rss_ind[i] = nchan - 1;
103715516c77SSepherosa Ziehau 		}
103815516c77SSepherosa Ziehau 	}
103915516c77SSepherosa Ziehau }
104015516c77SSepherosa Ziehau 
104115516c77SSepherosa Ziehau static int
104215516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused)
104315516c77SSepherosa Ziehau {
104415516c77SSepherosa Ziehau 
104515516c77SSepherosa Ziehau 	return EOPNOTSUPP;
104615516c77SSepherosa Ziehau }
104715516c77SSepherosa Ziehau 
104815516c77SSepherosa Ziehau static void
104915516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
105015516c77SSepherosa Ziehau {
105115516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
105215516c77SSepherosa Ziehau 
105315516c77SSepherosa Ziehau 	ifmr->ifm_status = IFM_AVALID;
105415516c77SSepherosa Ziehau 	ifmr->ifm_active = IFM_ETHER;
105515516c77SSepherosa Ziehau 
105615516c77SSepherosa Ziehau 	if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) {
105715516c77SSepherosa Ziehau 		ifmr->ifm_active |= IFM_NONE;
105815516c77SSepherosa Ziehau 		return;
105915516c77SSepherosa Ziehau 	}
106015516c77SSepherosa Ziehau 	ifmr->ifm_status |= IFM_ACTIVE;
106115516c77SSepherosa Ziehau 	ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
106215516c77SSepherosa Ziehau }
106315516c77SSepherosa Ziehau 
10645bdfd3fdSDexuan Cui static void
1065962f0357SSepherosa Ziehau hn_rxvf_set_task(void *xarg, int pending __unused)
10665bdfd3fdSDexuan Cui {
1067962f0357SSepherosa Ziehau 	struct hn_rxvf_setarg *arg = xarg;
10685bdfd3fdSDexuan Cui 
1069962f0357SSepherosa Ziehau 	arg->rxr->hn_rxvf_ifp = arg->vf_ifp;
10705bdfd3fdSDexuan Cui }
10715bdfd3fdSDexuan Cui 
10725bdfd3fdSDexuan Cui static void
1073962f0357SSepherosa Ziehau hn_rxvf_set(struct hn_softc *sc, struct ifnet *vf_ifp)
10745bdfd3fdSDexuan Cui {
10755bdfd3fdSDexuan Cui 	struct hn_rx_ring *rxr;
1076962f0357SSepherosa Ziehau 	struct hn_rxvf_setarg arg;
10775bdfd3fdSDexuan Cui 	struct task task;
10785bdfd3fdSDexuan Cui 	int i;
10795bdfd3fdSDexuan Cui 
10805bdfd3fdSDexuan Cui 	HN_LOCK_ASSERT(sc);
10815bdfd3fdSDexuan Cui 
1082962f0357SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_rxvf_set_task, &arg);
10835bdfd3fdSDexuan Cui 
10845bdfd3fdSDexuan Cui 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
10855bdfd3fdSDexuan Cui 		rxr = &sc->hn_rx_ring[i];
10865bdfd3fdSDexuan Cui 
10875bdfd3fdSDexuan Cui 		if (i < sc->hn_rx_ring_inuse) {
1088962f0357SSepherosa Ziehau 			arg.rxr = rxr;
1089962f0357SSepherosa Ziehau 			arg.vf_ifp = vf_ifp;
10905bdfd3fdSDexuan Cui 			vmbus_chan_run_task(rxr->hn_chan, &task);
10915bdfd3fdSDexuan Cui 		} else {
1092962f0357SSepherosa Ziehau 			rxr->hn_rxvf_ifp = vf_ifp;
10935bdfd3fdSDexuan Cui 		}
10945bdfd3fdSDexuan Cui 	}
10955bdfd3fdSDexuan Cui }
10965bdfd3fdSDexuan Cui 
1097962f0357SSepherosa Ziehau static bool
1098499c3e17SSepherosa Ziehau hn_ismyvf(const struct hn_softc *sc, const struct ifnet *ifp)
1099499c3e17SSepherosa Ziehau {
1100499c3e17SSepherosa Ziehau 	const struct ifnet *hn_ifp;
1101499c3e17SSepherosa Ziehau 
1102499c3e17SSepherosa Ziehau 	hn_ifp = sc->hn_ifp;
1103499c3e17SSepherosa Ziehau 
1104499c3e17SSepherosa Ziehau 	if (ifp == hn_ifp)
1105499c3e17SSepherosa Ziehau 		return (false);
1106499c3e17SSepherosa Ziehau 
1107499c3e17SSepherosa Ziehau 	if (ifp->if_alloctype != IFT_ETHER)
1108499c3e17SSepherosa Ziehau 		return (false);
1109499c3e17SSepherosa Ziehau 
1110499c3e17SSepherosa Ziehau 	/* Ignore lagg/vlan interfaces */
1111499c3e17SSepherosa Ziehau 	if (strcmp(ifp->if_dname, "lagg") == 0 ||
1112499c3e17SSepherosa Ziehau 	    strcmp(ifp->if_dname, "vlan") == 0)
1113499c3e17SSepherosa Ziehau 		return (false);
1114499c3e17SSepherosa Ziehau 
1115499c3e17SSepherosa Ziehau 	if (bcmp(IF_LLADDR(ifp), IF_LLADDR(hn_ifp), ETHER_ADDR_LEN) != 0)
1116499c3e17SSepherosa Ziehau 		return (false);
1117499c3e17SSepherosa Ziehau 
1118499c3e17SSepherosa Ziehau 	return (true);
1119499c3e17SSepherosa Ziehau }
1120499c3e17SSepherosa Ziehau 
11215bdfd3fdSDexuan Cui static void
1122962f0357SSepherosa Ziehau hn_rxvf_change(struct hn_softc *sc, struct ifnet *ifp, bool rxvf)
11235bdfd3fdSDexuan Cui {
11245bdfd3fdSDexuan Cui 	struct ifnet *hn_ifp;
11255bdfd3fdSDexuan Cui 
11265bdfd3fdSDexuan Cui 	HN_LOCK(sc);
11275bdfd3fdSDexuan Cui 
11285bdfd3fdSDexuan Cui 	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
11295bdfd3fdSDexuan Cui 		goto out;
11305bdfd3fdSDexuan Cui 
1131499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1132499c3e17SSepherosa Ziehau 		goto out;
11335bdfd3fdSDexuan Cui 	hn_ifp = sc->hn_ifp;
11345bdfd3fdSDexuan Cui 
1135962f0357SSepherosa Ziehau 	if (rxvf) {
1136962f0357SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_RXVF)
11375bdfd3fdSDexuan Cui 			goto out;
11385bdfd3fdSDexuan Cui 
1139962f0357SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_RXVF;
11405bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
11415bdfd3fdSDexuan Cui 	} else {
1142962f0357SSepherosa Ziehau 		if (!(sc->hn_flags & HN_FLAG_RXVF))
11435bdfd3fdSDexuan Cui 			goto out;
11445bdfd3fdSDexuan Cui 
1145962f0357SSepherosa Ziehau 		sc->hn_flags &= ~HN_FLAG_RXVF;
1146499c3e17SSepherosa Ziehau 		if (hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
11475bdfd3fdSDexuan Cui 			hn_rxfilter_config(sc);
11485bdfd3fdSDexuan Cui 		else
11495bdfd3fdSDexuan Cui 			hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE);
11505bdfd3fdSDexuan Cui 	}
11515bdfd3fdSDexuan Cui 
11525bdfd3fdSDexuan Cui 	hn_nvs_set_datapath(sc,
11539c6cae24SSepherosa Ziehau 	    rxvf ? HN_NVS_DATAPATH_VF : HN_NVS_DATAPATH_SYNTH);
11545bdfd3fdSDexuan Cui 
1155962f0357SSepherosa Ziehau 	hn_rxvf_set(sc, rxvf ? ifp : NULL);
11565bdfd3fdSDexuan Cui 
1157962f0357SSepherosa Ziehau 	if (rxvf) {
1158642ec226SSepherosa Ziehau 		hn_vf_rss_fixup(sc, true);
11595bdfd3fdSDexuan Cui 		hn_suspend_mgmt(sc);
11605bdfd3fdSDexuan Cui 		sc->hn_link_flags &=
11615bdfd3fdSDexuan Cui 		    ~(HN_LINK_FLAG_LINKUP | HN_LINK_FLAG_NETCHG);
1162499c3e17SSepherosa Ziehau 		if_link_state_change(hn_ifp, LINK_STATE_DOWN);
11635bdfd3fdSDexuan Cui 	} else {
1164642ec226SSepherosa Ziehau 		hn_vf_rss_restore(sc);
11655bdfd3fdSDexuan Cui 		hn_resume_mgmt(sc);
11665bdfd3fdSDexuan Cui 	}
11675bdfd3fdSDexuan Cui 
1168962f0357SSepherosa Ziehau 	devctl_notify("HYPERV_NIC_VF", hn_ifp->if_xname,
1169962f0357SSepherosa Ziehau 	    rxvf ? "VF_UP" : "VF_DOWN", NULL);
117033408a34SDexuan Cui 
1171962f0357SSepherosa Ziehau 	if (bootverbose) {
1172962f0357SSepherosa Ziehau 		if_printf(hn_ifp, "datapath is switched %s %s\n",
1173962f0357SSepherosa Ziehau 		    rxvf ? "to" : "from", ifp->if_xname);
1174962f0357SSepherosa Ziehau 	}
11755bdfd3fdSDexuan Cui out:
11765bdfd3fdSDexuan Cui 	HN_UNLOCK(sc);
11775bdfd3fdSDexuan Cui }
11785bdfd3fdSDexuan Cui 
11795bdfd3fdSDexuan Cui static void
11805bdfd3fdSDexuan Cui hn_ifnet_event(void *arg, struct ifnet *ifp, int event)
11815bdfd3fdSDexuan Cui {
1182962f0357SSepherosa Ziehau 
11835bdfd3fdSDexuan Cui 	if (event != IFNET_EVENT_UP && event != IFNET_EVENT_DOWN)
11845bdfd3fdSDexuan Cui 		return;
1185962f0357SSepherosa Ziehau 	hn_rxvf_change(arg, ifp, event == IFNET_EVENT_UP);
11865bdfd3fdSDexuan Cui }
11875bdfd3fdSDexuan Cui 
11885bdfd3fdSDexuan Cui static void
11895bdfd3fdSDexuan Cui hn_ifaddr_event(void *arg, struct ifnet *ifp)
11905bdfd3fdSDexuan Cui {
1191962f0357SSepherosa Ziehau 
1192962f0357SSepherosa Ziehau 	hn_rxvf_change(arg, ifp, ifp->if_flags & IFF_UP);
11935bdfd3fdSDexuan Cui }
11945bdfd3fdSDexuan Cui 
11959c6cae24SSepherosa Ziehau static int
11969c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetcaps(struct hn_softc *sc, struct ifreq *ifr)
11979c6cae24SSepherosa Ziehau {
11989c6cae24SSepherosa Ziehau 	struct ifnet *ifp, *vf_ifp;
11999c6cae24SSepherosa Ziehau 	uint64_t tmp;
12009c6cae24SSepherosa Ziehau 	int error;
12019c6cae24SSepherosa Ziehau 
12029c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
12039c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
12049c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
12059c6cae24SSepherosa Ziehau 
12069c6cae24SSepherosa Ziehau 	/*
12079c6cae24SSepherosa Ziehau 	 * Fix up requested capabilities w/ supported capabilities,
12089c6cae24SSepherosa Ziehau 	 * since the supported capabilities could have been changed.
12099c6cae24SSepherosa Ziehau 	 */
12109c6cae24SSepherosa Ziehau 	ifr->ifr_reqcap &= ifp->if_capabilities;
12119c6cae24SSepherosa Ziehau 	/* Pass SIOCSIFCAP to VF. */
12129c6cae24SSepherosa Ziehau 	error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFCAP, (caddr_t)ifr);
12139c6cae24SSepherosa Ziehau 
12149c6cae24SSepherosa Ziehau 	/*
12159c6cae24SSepherosa Ziehau 	 * NOTE:
12169c6cae24SSepherosa Ziehau 	 * The error will be propagated to the callers, however, it
12179c6cae24SSepherosa Ziehau 	 * is _not_ useful here.
12189c6cae24SSepherosa Ziehau 	 */
12199c6cae24SSepherosa Ziehau 
12209c6cae24SSepherosa Ziehau 	/*
12219c6cae24SSepherosa Ziehau 	 * Merge VF's enabled capabilities.
12229c6cae24SSepherosa Ziehau 	 */
12239c6cae24SSepherosa Ziehau 	ifp->if_capenable = vf_ifp->if_capenable & ifp->if_capabilities;
12249c6cae24SSepherosa Ziehau 
12259c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & HN_CSUM_IP_HWASSIST(sc);
12269c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TXCSUM)
12279c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
12289c6cae24SSepherosa Ziehau 	else
12299c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
12309c6cae24SSepherosa Ziehau 
12319c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & HN_CSUM_IP6_HWASSIST(sc);
12329c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
12339c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
12349c6cae24SSepherosa Ziehau 	else
12359c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
12369c6cae24SSepherosa Ziehau 
12379c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & CSUM_IP_TSO;
12389c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TSO4)
12399c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
12409c6cae24SSepherosa Ziehau 	else
12419c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
12429c6cae24SSepherosa Ziehau 
12439c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & CSUM_IP6_TSO;
12449c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TSO6)
12459c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
12469c6cae24SSepherosa Ziehau 	else
12479c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
12489c6cae24SSepherosa Ziehau 
12499c6cae24SSepherosa Ziehau 	return (error);
12509c6cae24SSepherosa Ziehau }
12519c6cae24SSepherosa Ziehau 
12529c6cae24SSepherosa Ziehau static int
12539c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetflags(struct hn_softc *sc)
12549c6cae24SSepherosa Ziehau {
12559c6cae24SSepherosa Ziehau 	struct ifnet *vf_ifp;
12569c6cae24SSepherosa Ziehau 	struct ifreq ifr;
12579c6cae24SSepherosa Ziehau 
12589c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
12599c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
12609c6cae24SSepherosa Ziehau 
12619c6cae24SSepherosa Ziehau 	memset(&ifr, 0, sizeof(ifr));
12629c6cae24SSepherosa Ziehau 	strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
12639c6cae24SSepherosa Ziehau 	ifr.ifr_flags = vf_ifp->if_flags & 0xffff;
12649c6cae24SSepherosa Ziehau 	ifr.ifr_flagshigh = vf_ifp->if_flags >> 16;
12659c6cae24SSepherosa Ziehau 	return (vf_ifp->if_ioctl(vf_ifp, SIOCSIFFLAGS, (caddr_t)&ifr));
12669c6cae24SSepherosa Ziehau }
12679c6cae24SSepherosa Ziehau 
12689c6cae24SSepherosa Ziehau static void
12699c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(struct hn_softc *sc)
12709c6cae24SSepherosa Ziehau {
12719c6cae24SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
12729c6cae24SSepherosa Ziehau 	int allmulti = 0;
12739c6cae24SSepherosa Ziehau 
12749c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
12759c6cae24SSepherosa Ziehau 
12769c6cae24SSepherosa Ziehau 	/* XXX vlan(4) style mcast addr maintenance */
12779c6cae24SSepherosa Ziehau 	if (!TAILQ_EMPTY(&ifp->if_multiaddrs))
12789c6cae24SSepherosa Ziehau 		allmulti = IFF_ALLMULTI;
12799c6cae24SSepherosa Ziehau 
12809c6cae24SSepherosa Ziehau 	/* Always set the VF's if_flags */
12819c6cae24SSepherosa Ziehau 	sc->hn_vf_ifp->if_flags = ifp->if_flags | allmulti;
12829c6cae24SSepherosa Ziehau }
12839c6cae24SSepherosa Ziehau 
12849c6cae24SSepherosa Ziehau static void
12859c6cae24SSepherosa Ziehau hn_xpnt_vf_input(struct ifnet *vf_ifp, struct mbuf *m)
12869c6cae24SSepherosa Ziehau {
12879c6cae24SSepherosa Ziehau 	struct rm_priotracker pt;
12889c6cae24SSepherosa Ziehau 	struct ifnet *hn_ifp = NULL;
12899c6cae24SSepherosa Ziehau 	struct mbuf *mn;
12909c6cae24SSepherosa Ziehau 
12919c6cae24SSepherosa Ziehau 	/*
12929c6cae24SSepherosa Ziehau 	 * XXX racy, if hn(4) ever detached.
12939c6cae24SSepherosa Ziehau 	 */
12949c6cae24SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
12959c6cae24SSepherosa Ziehau 	if (vf_ifp->if_index < hn_vfmap_size)
12969c6cae24SSepherosa Ziehau 		hn_ifp = hn_vfmap[vf_ifp->if_index];
12979c6cae24SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
12989c6cae24SSepherosa Ziehau 
12999c6cae24SSepherosa Ziehau 	if (hn_ifp != NULL) {
13009c6cae24SSepherosa Ziehau 		for (mn = m; mn != NULL; mn = mn->m_nextpkt) {
13013bed4e54SSepherosa Ziehau 			/*
13023bed4e54SSepherosa Ziehau 			 * Allow tapping on the VF.
13033bed4e54SSepherosa Ziehau 			 */
13049c6cae24SSepherosa Ziehau 			ETHER_BPF_MTAP(vf_ifp, mn);
13053bed4e54SSepherosa Ziehau 
13063bed4e54SSepherosa Ziehau 			/*
13073bed4e54SSepherosa Ziehau 			 * Update VF stats.
13083bed4e54SSepherosa Ziehau 			 */
13093bed4e54SSepherosa Ziehau 			if ((vf_ifp->if_capenable & IFCAP_HWSTATS) == 0) {
13103bed4e54SSepherosa Ziehau 				if_inc_counter(vf_ifp, IFCOUNTER_IBYTES,
13113bed4e54SSepherosa Ziehau 				    mn->m_pkthdr.len);
13123bed4e54SSepherosa Ziehau 			}
13133bed4e54SSepherosa Ziehau 			/*
13143bed4e54SSepherosa Ziehau 			 * XXX IFCOUNTER_IMCAST
13153bed4e54SSepherosa Ziehau 			 * This stat updating is kinda invasive, since it
13163bed4e54SSepherosa Ziehau 			 * requires two checks on the mbuf: the length check
13173bed4e54SSepherosa Ziehau 			 * and the ethernet header check.  As of this write,
13183bed4e54SSepherosa Ziehau 			 * all multicast packets go directly to hn(4), which
13193bed4e54SSepherosa Ziehau 			 * makes imcast stat updating in the VF a try in vian.
13203bed4e54SSepherosa Ziehau 			 */
13213bed4e54SSepherosa Ziehau 
13223bed4e54SSepherosa Ziehau 			/*
13233bed4e54SSepherosa Ziehau 			 * Fix up rcvif and increase hn(4)'s ipackets.
13243bed4e54SSepherosa Ziehau 			 */
13259c6cae24SSepherosa Ziehau 			mn->m_pkthdr.rcvif = hn_ifp;
13269c6cae24SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1);
13279c6cae24SSepherosa Ziehau 		}
13283bed4e54SSepherosa Ziehau 		/*
13293bed4e54SSepherosa Ziehau 		 * Go through hn(4)'s if_input.
13303bed4e54SSepherosa Ziehau 		 */
13319c6cae24SSepherosa Ziehau 		hn_ifp->if_input(hn_ifp, m);
13329c6cae24SSepherosa Ziehau 	} else {
13339c6cae24SSepherosa Ziehau 		/*
13349c6cae24SSepherosa Ziehau 		 * In the middle of the transition; free this
13359c6cae24SSepherosa Ziehau 		 * mbuf chain.
13369c6cae24SSepherosa Ziehau 		 */
13379c6cae24SSepherosa Ziehau 		while (m != NULL) {
13389c6cae24SSepherosa Ziehau 			mn = m->m_nextpkt;
13399c6cae24SSepherosa Ziehau 			m->m_nextpkt = NULL;
13409c6cae24SSepherosa Ziehau 			m_freem(m);
13419c6cae24SSepherosa Ziehau 			m = mn;
13429c6cae24SSepherosa Ziehau 		}
13439c6cae24SSepherosa Ziehau 	}
13449c6cae24SSepherosa Ziehau }
13459c6cae24SSepherosa Ziehau 
13469c6cae24SSepherosa Ziehau static void
13479c6cae24SSepherosa Ziehau hn_mtu_change_fixup(struct hn_softc *sc)
13489c6cae24SSepherosa Ziehau {
13499c6cae24SSepherosa Ziehau 	struct ifnet *ifp;
13509c6cae24SSepherosa Ziehau 
13519c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
13529c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
13539c6cae24SSepherosa Ziehau 
13549c6cae24SSepherosa Ziehau 	hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu);
13559c6cae24SSepherosa Ziehau #if __FreeBSD_version >= 1100099
13569c6cae24SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_lro.lro_length_lim < HN_LRO_LENLIM_MIN(ifp))
13579c6cae24SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
13589c6cae24SSepherosa Ziehau #endif
13599c6cae24SSepherosa Ziehau }
13609c6cae24SSepherosa Ziehau 
1361642ec226SSepherosa Ziehau static uint32_t
1362642ec226SSepherosa Ziehau hn_rss_type_fromndis(uint32_t rss_hash)
1363642ec226SSepherosa Ziehau {
1364642ec226SSepherosa Ziehau 	uint32_t types = 0;
1365642ec226SSepherosa Ziehau 
1366642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_IPV4)
1367642ec226SSepherosa Ziehau 		types |= RSS_TYPE_IPV4;
1368642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_TCP_IPV4)
1369642ec226SSepherosa Ziehau 		types |= RSS_TYPE_TCP_IPV4;
1370642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_IPV6)
1371642ec226SSepherosa Ziehau 		types |= RSS_TYPE_IPV6;
1372642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_IPV6_EX)
1373642ec226SSepherosa Ziehau 		types |= RSS_TYPE_IPV6_EX;
1374642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_TCP_IPV6)
1375642ec226SSepherosa Ziehau 		types |= RSS_TYPE_TCP_IPV6;
1376642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_TCP_IPV6_EX)
1377642ec226SSepherosa Ziehau 		types |= RSS_TYPE_TCP_IPV6_EX;
1378642ec226SSepherosa Ziehau 	return (types);
1379642ec226SSepherosa Ziehau }
1380642ec226SSepherosa Ziehau 
1381642ec226SSepherosa Ziehau static uint32_t
1382642ec226SSepherosa Ziehau hn_rss_type_tondis(uint32_t types)
1383642ec226SSepherosa Ziehau {
1384642ec226SSepherosa Ziehau 	uint32_t rss_hash = 0;
1385642ec226SSepherosa Ziehau 
1386642ec226SSepherosa Ziehau 	KASSERT((types &
1387642ec226SSepherosa Ziehau 	(RSS_TYPE_UDP_IPV4 | RSS_TYPE_UDP_IPV6 | RSS_TYPE_UDP_IPV6_EX)) == 0,
1388642ec226SSepherosa Ziehau 	("UDP4, UDP6 and UDP6EX are not supported"));
1389642ec226SSepherosa Ziehau 
1390642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_IPV4)
1391642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_IPV4;
1392642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_TCP_IPV4)
1393642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_TCP_IPV4;
1394642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_IPV6)
1395642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_IPV6;
1396642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_IPV6_EX)
1397642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_IPV6_EX;
1398642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_TCP_IPV6)
1399642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_TCP_IPV6;
1400642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_TCP_IPV6_EX)
1401642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_TCP_IPV6_EX;
1402642ec226SSepherosa Ziehau 	return (rss_hash);
1403642ec226SSepherosa Ziehau }
1404642ec226SSepherosa Ziehau 
1405642ec226SSepherosa Ziehau static void
1406642ec226SSepherosa Ziehau hn_rss_mbuf_hash(struct hn_softc *sc, uint32_t mbuf_hash)
1407642ec226SSepherosa Ziehau {
1408642ec226SSepherosa Ziehau 	int i;
1409642ec226SSepherosa Ziehau 
1410642ec226SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1411642ec226SSepherosa Ziehau 
1412642ec226SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1413642ec226SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_mbuf_hash = mbuf_hash;
1414642ec226SSepherosa Ziehau }
1415642ec226SSepherosa Ziehau 
1416642ec226SSepherosa Ziehau static void
1417642ec226SSepherosa Ziehau hn_vf_rss_fixup(struct hn_softc *sc, bool reconf)
1418642ec226SSepherosa Ziehau {
1419642ec226SSepherosa Ziehau 	struct ifnet *ifp, *vf_ifp;
1420642ec226SSepherosa Ziehau 	struct ifrsshash ifrh;
1421642ec226SSepherosa Ziehau 	struct ifrsskey ifrk;
1422642ec226SSepherosa Ziehau 	int error;
1423642ec226SSepherosa Ziehau 	uint32_t my_types, diff_types, mbuf_types = 0;
1424642ec226SSepherosa Ziehau 
1425642ec226SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1426642ec226SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
1427642ec226SSepherosa Ziehau 	    ("%s: synthetic parts are not attached", sc->hn_ifp->if_xname));
1428642ec226SSepherosa Ziehau 
1429642ec226SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
1430642ec226SSepherosa Ziehau 		/* No RSS on synthetic parts; done. */
1431642ec226SSepherosa Ziehau 		return;
1432642ec226SSepherosa Ziehau 	}
1433642ec226SSepherosa Ziehau 	if ((sc->hn_rss_hcap & NDIS_HASH_FUNCTION_TOEPLITZ) == 0) {
1434642ec226SSepherosa Ziehau 		/* Synthetic parts do not support Toeplitz; done. */
1435642ec226SSepherosa Ziehau 		return;
1436642ec226SSepherosa Ziehau 	}
1437642ec226SSepherosa Ziehau 
1438642ec226SSepherosa Ziehau 	ifp = sc->hn_ifp;
1439642ec226SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
1440642ec226SSepherosa Ziehau 
1441642ec226SSepherosa Ziehau 	/*
1442642ec226SSepherosa Ziehau 	 * Extract VF's RSS key.  Only 40 bytes key for Toeplitz is
1443642ec226SSepherosa Ziehau 	 * supported.
1444642ec226SSepherosa Ziehau 	 */
1445642ec226SSepherosa Ziehau 	memset(&ifrk, 0, sizeof(ifrk));
1446642ec226SSepherosa Ziehau 	strlcpy(ifrk.ifrk_name, vf_ifp->if_xname, sizeof(ifrk.ifrk_name));
1447642ec226SSepherosa Ziehau 	error = vf_ifp->if_ioctl(vf_ifp, SIOCGIFRSSKEY, (caddr_t)&ifrk);
1448642ec226SSepherosa Ziehau 	if (error) {
1449642ec226SSepherosa Ziehau 		if_printf(ifp, "%s SIOCGRSSKEY failed: %d\n",
1450642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, error);
1451642ec226SSepherosa Ziehau 		goto done;
1452642ec226SSepherosa Ziehau 	}
1453642ec226SSepherosa Ziehau 	if (ifrk.ifrk_func != RSS_FUNC_TOEPLITZ) {
1454642ec226SSepherosa Ziehau 		if_printf(ifp, "%s RSS function %u is not Toeplitz\n",
1455642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, ifrk.ifrk_func);
1456642ec226SSepherosa Ziehau 		goto done;
1457642ec226SSepherosa Ziehau 	}
1458642ec226SSepherosa Ziehau 	if (ifrk.ifrk_keylen != NDIS_HASH_KEYSIZE_TOEPLITZ) {
1459642ec226SSepherosa Ziehau 		if_printf(ifp, "%s invalid RSS Toeplitz key length %d\n",
1460642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, ifrk.ifrk_keylen);
1461642ec226SSepherosa Ziehau 		goto done;
1462642ec226SSepherosa Ziehau 	}
1463642ec226SSepherosa Ziehau 
1464642ec226SSepherosa Ziehau 	/*
1465642ec226SSepherosa Ziehau 	 * Extract VF's RSS hash.  Only Toeplitz is supported.
1466642ec226SSepherosa Ziehau 	 */
1467642ec226SSepherosa Ziehau 	memset(&ifrh, 0, sizeof(ifrh));
1468642ec226SSepherosa Ziehau 	strlcpy(ifrh.ifrh_name, vf_ifp->if_xname, sizeof(ifrh.ifrh_name));
1469642ec226SSepherosa Ziehau 	error = vf_ifp->if_ioctl(vf_ifp, SIOCGIFRSSHASH, (caddr_t)&ifrh);
1470642ec226SSepherosa Ziehau 	if (error) {
1471642ec226SSepherosa Ziehau 		if_printf(ifp, "%s SIOCGRSSHASH failed: %d\n",
1472642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, error);
1473642ec226SSepherosa Ziehau 		goto done;
1474642ec226SSepherosa Ziehau 	}
1475642ec226SSepherosa Ziehau 	if (ifrh.ifrh_func != RSS_FUNC_TOEPLITZ) {
1476642ec226SSepherosa Ziehau 		if_printf(ifp, "%s RSS function %u is not Toeplitz\n",
1477642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, ifrh.ifrh_func);
1478642ec226SSepherosa Ziehau 		goto done;
1479642ec226SSepherosa Ziehau 	}
1480642ec226SSepherosa Ziehau 
1481642ec226SSepherosa Ziehau 	my_types = hn_rss_type_fromndis(sc->hn_rss_hcap);
1482642ec226SSepherosa Ziehau 	if ((ifrh.ifrh_types & my_types) == 0) {
1483642ec226SSepherosa Ziehau 		/* This disables RSS; ignore it then */
1484642ec226SSepherosa Ziehau 		if_printf(ifp, "%s intersection of RSS types failed.  "
1485642ec226SSepherosa Ziehau 		    "VF %#x, mine %#x\n", vf_ifp->if_xname,
1486642ec226SSepherosa Ziehau 		    ifrh.ifrh_types, my_types);
1487642ec226SSepherosa Ziehau 		goto done;
1488642ec226SSepherosa Ziehau 	}
1489642ec226SSepherosa Ziehau 
1490642ec226SSepherosa Ziehau 	diff_types = my_types ^ ifrh.ifrh_types;
1491642ec226SSepherosa Ziehau 	my_types &= ifrh.ifrh_types;
1492642ec226SSepherosa Ziehau 	mbuf_types = my_types;
1493642ec226SSepherosa Ziehau 
1494642ec226SSepherosa Ziehau 	/*
1495642ec226SSepherosa Ziehau 	 * Detect RSS hash value/type confliction.
1496642ec226SSepherosa Ziehau 	 *
1497642ec226SSepherosa Ziehau 	 * NOTE:
1498642ec226SSepherosa Ziehau 	 * We don't disable the hash type, but stop delivery the hash
1499642ec226SSepherosa Ziehau 	 * value/type through mbufs on RX path.
1500642ec226SSepherosa Ziehau 	 */
1501642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_IPV4) &&
1502642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types &
1503642ec226SSepherosa Ziehau 	     (RSS_TYPE_TCP_IPV4 | RSS_TYPE_UDP_IPV4))) {
1504642ec226SSepherosa Ziehau 		/* Conflict; disable IPV4 hash type/value delivery. */
1505642ec226SSepherosa Ziehau 		if_printf(ifp, "disable IPV4 mbuf hash delivery\n");
1506642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_IPV4;
1507642ec226SSepherosa Ziehau 	}
1508642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_IPV6) &&
1509642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types &
1510642ec226SSepherosa Ziehau 	     (RSS_TYPE_TCP_IPV6 | RSS_TYPE_UDP_IPV6 |
1511642ec226SSepherosa Ziehau 	      RSS_TYPE_TCP_IPV6_EX | RSS_TYPE_UDP_IPV6_EX |
1512642ec226SSepherosa Ziehau 	      RSS_TYPE_IPV6_EX))) {
1513642ec226SSepherosa Ziehau 		/* Conflict; disable IPV6 hash type/value delivery. */
1514642ec226SSepherosa Ziehau 		if_printf(ifp, "disable IPV6 mbuf hash delivery\n");
1515642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_IPV6;
1516642ec226SSepherosa Ziehau 	}
1517642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_IPV6_EX) &&
1518642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types &
1519642ec226SSepherosa Ziehau 	     (RSS_TYPE_TCP_IPV6 | RSS_TYPE_UDP_IPV6 |
1520642ec226SSepherosa Ziehau 	      RSS_TYPE_TCP_IPV6_EX | RSS_TYPE_UDP_IPV6_EX |
1521642ec226SSepherosa Ziehau 	      RSS_TYPE_IPV6))) {
1522642ec226SSepherosa Ziehau 		/* Conflict; disable IPV6_EX hash type/value delivery. */
1523642ec226SSepherosa Ziehau 		if_printf(ifp, "disable IPV6_EX mbuf hash delivery\n");
1524642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_IPV6_EX;
1525642ec226SSepherosa Ziehau 	}
1526642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_TCP_IPV6) &&
1527642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_TCP_IPV6_EX)) {
1528642ec226SSepherosa Ziehau 		/* Conflict; disable TCP_IPV6 hash type/value delivery. */
1529642ec226SSepherosa Ziehau 		if_printf(ifp, "disable TCP_IPV6 mbuf hash delivery\n");
1530642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_TCP_IPV6;
1531642ec226SSepherosa Ziehau 	}
1532642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_TCP_IPV6_EX) &&
1533642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_TCP_IPV6)) {
1534642ec226SSepherosa Ziehau 		/* Conflict; disable TCP_IPV6_EX hash type/value delivery. */
1535642ec226SSepherosa Ziehau 		if_printf(ifp, "disable TCP_IPV6_EX mbuf hash delivery\n");
1536642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_TCP_IPV6_EX;
1537642ec226SSepherosa Ziehau 	}
1538642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_UDP_IPV6) &&
1539642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_UDP_IPV6_EX)) {
1540642ec226SSepherosa Ziehau 		/* Conflict; disable UDP_IPV6 hash type/value delivery. */
1541642ec226SSepherosa Ziehau 		if_printf(ifp, "disable UDP_IPV6 mbuf hash delivery\n");
1542642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_UDP_IPV6;
1543642ec226SSepherosa Ziehau 	}
1544642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_UDP_IPV6_EX) &&
1545642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_UDP_IPV6)) {
1546642ec226SSepherosa Ziehau 		/* Conflict; disable UDP_IPV6_EX hash type/value delivery. */
1547642ec226SSepherosa Ziehau 		if_printf(ifp, "disable UDP_IPV6_EX mbuf hash delivery\n");
1548642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_UDP_IPV6_EX;
1549642ec226SSepherosa Ziehau 	}
1550642ec226SSepherosa Ziehau 
1551642ec226SSepherosa Ziehau 	/*
1552642ec226SSepherosa Ziehau 	 * Indirect table does not matter.
1553642ec226SSepherosa Ziehau 	 */
1554642ec226SSepherosa Ziehau 
1555642ec226SSepherosa Ziehau 	sc->hn_rss_hash = (sc->hn_rss_hcap & NDIS_HASH_FUNCTION_MASK) |
1556642ec226SSepherosa Ziehau 	    hn_rss_type_tondis(my_types);
1557642ec226SSepherosa Ziehau 	memcpy(sc->hn_rss.rss_key, ifrk.ifrk_key, sizeof(sc->hn_rss.rss_key));
1558642ec226SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
1559642ec226SSepherosa Ziehau 
1560642ec226SSepherosa Ziehau 	if (reconf) {
1561642ec226SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
1562642ec226SSepherosa Ziehau 		if (error) {
1563642ec226SSepherosa Ziehau 			/* XXX roll-back? */
1564642ec226SSepherosa Ziehau 			if_printf(ifp, "hn_rss_reconfig failed: %d\n", error);
1565642ec226SSepherosa Ziehau 			/* XXX keep going. */
1566642ec226SSepherosa Ziehau 		}
1567642ec226SSepherosa Ziehau 	}
1568642ec226SSepherosa Ziehau done:
1569642ec226SSepherosa Ziehau 	/* Hash deliverability for mbufs. */
1570642ec226SSepherosa Ziehau 	hn_rss_mbuf_hash(sc, hn_rss_type_tondis(mbuf_types));
1571642ec226SSepherosa Ziehau }
1572642ec226SSepherosa Ziehau 
1573642ec226SSepherosa Ziehau static void
1574642ec226SSepherosa Ziehau hn_vf_rss_restore(struct hn_softc *sc)
1575642ec226SSepherosa Ziehau {
1576642ec226SSepherosa Ziehau 
1577642ec226SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1578642ec226SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
1579642ec226SSepherosa Ziehau 	    ("%s: synthetic parts are not attached", sc->hn_ifp->if_xname));
1580642ec226SSepherosa Ziehau 
1581642ec226SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1)
1582642ec226SSepherosa Ziehau 		goto done;
1583642ec226SSepherosa Ziehau 
1584642ec226SSepherosa Ziehau 	/*
1585642ec226SSepherosa Ziehau 	 * Restore hash types.  Key does _not_ matter.
1586642ec226SSepherosa Ziehau 	 */
1587642ec226SSepherosa Ziehau 	if (sc->hn_rss_hash != sc->hn_rss_hcap) {
1588642ec226SSepherosa Ziehau 		int error;
1589642ec226SSepherosa Ziehau 
1590642ec226SSepherosa Ziehau 		sc->hn_rss_hash = sc->hn_rss_hcap;
1591642ec226SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
1592642ec226SSepherosa Ziehau 		if (error) {
1593642ec226SSepherosa Ziehau 			if_printf(sc->hn_ifp, "hn_rss_reconfig failed: %d\n",
1594642ec226SSepherosa Ziehau 			    error);
1595642ec226SSepherosa Ziehau 			/* XXX keep going. */
1596642ec226SSepherosa Ziehau 		}
1597642ec226SSepherosa Ziehau 	}
1598642ec226SSepherosa Ziehau done:
1599642ec226SSepherosa Ziehau 	/* Hash deliverability for mbufs. */
1600642ec226SSepherosa Ziehau 	hn_rss_mbuf_hash(sc, NDIS_HASH_ALL);
1601642ec226SSepherosa Ziehau }
1602642ec226SSepherosa Ziehau 
16039c6cae24SSepherosa Ziehau static void
16049c6cae24SSepherosa Ziehau hn_xpnt_vf_setready(struct hn_softc *sc)
16059c6cae24SSepherosa Ziehau {
16069c6cae24SSepherosa Ziehau 	struct ifnet *ifp, *vf_ifp;
16079c6cae24SSepherosa Ziehau 	struct ifreq ifr;
16089c6cae24SSepherosa Ziehau 
16099c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
16109c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
16119c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
16129c6cae24SSepherosa Ziehau 
16139c6cae24SSepherosa Ziehau 	/*
16149c6cae24SSepherosa Ziehau 	 * Mark the VF ready.
16159c6cae24SSepherosa Ziehau 	 */
16169c6cae24SSepherosa Ziehau 	sc->hn_vf_rdytick = 0;
16179c6cae24SSepherosa Ziehau 
16189c6cae24SSepherosa Ziehau 	/*
16199c6cae24SSepherosa Ziehau 	 * Save information for restoration.
16209c6cae24SSepherosa Ziehau 	 */
16219c6cae24SSepherosa Ziehau 	sc->hn_saved_caps = ifp->if_capabilities;
16229c6cae24SSepherosa Ziehau 	sc->hn_saved_tsomax = ifp->if_hw_tsomax;
16239c6cae24SSepherosa Ziehau 	sc->hn_saved_tsosegcnt = ifp->if_hw_tsomaxsegcount;
16249c6cae24SSepherosa Ziehau 	sc->hn_saved_tsosegsz = ifp->if_hw_tsomaxsegsize;
16259c6cae24SSepherosa Ziehau 
16269c6cae24SSepherosa Ziehau 	/*
16279c6cae24SSepherosa Ziehau 	 * Intersect supported/enabled capabilities.
16289c6cae24SSepherosa Ziehau 	 *
16299c6cae24SSepherosa Ziehau 	 * NOTE:
16309c6cae24SSepherosa Ziehau 	 * if_hwassist is not changed here.
16319c6cae24SSepherosa Ziehau 	 */
16329c6cae24SSepherosa Ziehau 	ifp->if_capabilities &= vf_ifp->if_capabilities;
16339c6cae24SSepherosa Ziehau 	ifp->if_capenable &= ifp->if_capabilities;
16349c6cae24SSepherosa Ziehau 
16359c6cae24SSepherosa Ziehau 	/*
16369c6cae24SSepherosa Ziehau 	 * Fix TSO settings.
16379c6cae24SSepherosa Ziehau 	 */
16389c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomax > vf_ifp->if_hw_tsomax)
16399c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomax = vf_ifp->if_hw_tsomax;
16409c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomaxsegcount > vf_ifp->if_hw_tsomaxsegcount)
16419c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = vf_ifp->if_hw_tsomaxsegcount;
16429c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomaxsegsize > vf_ifp->if_hw_tsomaxsegsize)
16439c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = vf_ifp->if_hw_tsomaxsegsize;
16449c6cae24SSepherosa Ziehau 
16459c6cae24SSepherosa Ziehau 	/*
16469c6cae24SSepherosa Ziehau 	 * Change VF's enabled capabilities.
16479c6cae24SSepherosa Ziehau 	 */
16489c6cae24SSepherosa Ziehau 	memset(&ifr, 0, sizeof(ifr));
16499c6cae24SSepherosa Ziehau 	strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
16509c6cae24SSepherosa Ziehau 	ifr.ifr_reqcap = ifp->if_capenable;
16519c6cae24SSepherosa Ziehau 	hn_xpnt_vf_iocsetcaps(sc, &ifr);
16529c6cae24SSepherosa Ziehau 
16539c6cae24SSepherosa Ziehau 	if (ifp->if_mtu != ETHERMTU) {
16549c6cae24SSepherosa Ziehau 		int error;
16559c6cae24SSepherosa Ziehau 
16569c6cae24SSepherosa Ziehau 		/*
16579c6cae24SSepherosa Ziehau 		 * Change VF's MTU.
16589c6cae24SSepherosa Ziehau 		 */
16599c6cae24SSepherosa Ziehau 		memset(&ifr, 0, sizeof(ifr));
16609c6cae24SSepherosa Ziehau 		strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
16619c6cae24SSepherosa Ziehau 		ifr.ifr_mtu = ifp->if_mtu;
16629c6cae24SSepherosa Ziehau 		error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU, (caddr_t)&ifr);
16639c6cae24SSepherosa Ziehau 		if (error) {
16649c6cae24SSepherosa Ziehau 			if_printf(ifp, "%s SIOCSIFMTU %u failed\n",
16659c6cae24SSepherosa Ziehau 			    vf_ifp->if_xname, ifp->if_mtu);
16669c6cae24SSepherosa Ziehau 			if (ifp->if_mtu > ETHERMTU) {
16679c6cae24SSepherosa Ziehau 				if_printf(ifp, "change MTU to %d\n", ETHERMTU);
16689c6cae24SSepherosa Ziehau 
16699c6cae24SSepherosa Ziehau 				/*
16709c6cae24SSepherosa Ziehau 				 * XXX
16719c6cae24SSepherosa Ziehau 				 * No need to adjust the synthetic parts' MTU;
16729c6cae24SSepherosa Ziehau 				 * failure of the adjustment will cause us
16739c6cae24SSepherosa Ziehau 				 * infinite headache.
16749c6cae24SSepherosa Ziehau 				 */
16759c6cae24SSepherosa Ziehau 				ifp->if_mtu = ETHERMTU;
16769c6cae24SSepherosa Ziehau 				hn_mtu_change_fixup(sc);
16779c6cae24SSepherosa Ziehau 			}
16789c6cae24SSepherosa Ziehau 		}
16799c6cae24SSepherosa Ziehau 	}
16809c6cae24SSepherosa Ziehau }
16819c6cae24SSepherosa Ziehau 
16829c6cae24SSepherosa Ziehau static bool
16839c6cae24SSepherosa Ziehau hn_xpnt_vf_isready(struct hn_softc *sc)
16849c6cae24SSepherosa Ziehau {
16859c6cae24SSepherosa Ziehau 
16869c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
16879c6cae24SSepherosa Ziehau 
16889c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf || sc->hn_vf_ifp == NULL)
16899c6cae24SSepherosa Ziehau 		return (false);
16909c6cae24SSepherosa Ziehau 
16919c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick == 0)
16929c6cae24SSepherosa Ziehau 		return (true);
16939c6cae24SSepherosa Ziehau 
16949c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick > ticks)
16959c6cae24SSepherosa Ziehau 		return (false);
16969c6cae24SSepherosa Ziehau 
16979c6cae24SSepherosa Ziehau 	/* Mark VF as ready. */
16989c6cae24SSepherosa Ziehau 	hn_xpnt_vf_setready(sc);
16999c6cae24SSepherosa Ziehau 	return (true);
17009c6cae24SSepherosa Ziehau }
17019c6cae24SSepherosa Ziehau 
17029c6cae24SSepherosa Ziehau static void
1703a97fff19SSepherosa Ziehau hn_xpnt_vf_setenable(struct hn_softc *sc)
1704a97fff19SSepherosa Ziehau {
1705a97fff19SSepherosa Ziehau 	int i;
1706a97fff19SSepherosa Ziehau 
1707a97fff19SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1708a97fff19SSepherosa Ziehau 
1709a97fff19SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
1710a97fff19SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
1711a97fff19SSepherosa Ziehau 	sc->hn_xvf_flags |= HN_XVFFLAG_ENABLED;
1712a97fff19SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
1713a97fff19SSepherosa Ziehau 
1714a97fff19SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1715a97fff19SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_rx_flags |= HN_RX_FLAG_XPNT_VF;
1716a97fff19SSepherosa Ziehau }
1717a97fff19SSepherosa Ziehau 
1718a97fff19SSepherosa Ziehau static void
1719a97fff19SSepherosa Ziehau hn_xpnt_vf_setdisable(struct hn_softc *sc, bool clear_vf)
1720a97fff19SSepherosa Ziehau {
1721a97fff19SSepherosa Ziehau 	int i;
1722a97fff19SSepherosa Ziehau 
1723a97fff19SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1724a97fff19SSepherosa Ziehau 
1725a97fff19SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
1726a97fff19SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
1727a97fff19SSepherosa Ziehau 	sc->hn_xvf_flags &= ~HN_XVFFLAG_ENABLED;
1728a97fff19SSepherosa Ziehau 	if (clear_vf)
1729a97fff19SSepherosa Ziehau 		sc->hn_vf_ifp = NULL;
1730a97fff19SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
1731a97fff19SSepherosa Ziehau 
1732a97fff19SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1733a97fff19SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_rx_flags &= ~HN_RX_FLAG_XPNT_VF;
1734a97fff19SSepherosa Ziehau }
1735a97fff19SSepherosa Ziehau 
1736a97fff19SSepherosa Ziehau static void
17379c6cae24SSepherosa Ziehau hn_xpnt_vf_init(struct hn_softc *sc)
17389c6cae24SSepherosa Ziehau {
17399c6cae24SSepherosa Ziehau 	int error;
17409c6cae24SSepherosa Ziehau 
17419c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
17429c6cae24SSepherosa Ziehau 
17439c6cae24SSepherosa Ziehau 	KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0,
17449c6cae24SSepherosa Ziehau 	    ("%s: transparent VF was enabled", sc->hn_ifp->if_xname));
17459c6cae24SSepherosa Ziehau 
17469c6cae24SSepherosa Ziehau 	if (bootverbose) {
17479c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "try bringing up %s\n",
17489c6cae24SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname);
17499c6cae24SSepherosa Ziehau 	}
17509c6cae24SSepherosa Ziehau 
17519c6cae24SSepherosa Ziehau 	/*
17529c6cae24SSepherosa Ziehau 	 * Bring the VF up.
17539c6cae24SSepherosa Ziehau 	 */
17549c6cae24SSepherosa Ziehau 	hn_xpnt_vf_saveifflags(sc);
17559c6cae24SSepherosa Ziehau 	sc->hn_vf_ifp->if_flags |= IFF_UP;
17569c6cae24SSepherosa Ziehau 	error = hn_xpnt_vf_iocsetflags(sc);
17579c6cae24SSepherosa Ziehau 	if (error) {
17589c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "bringing up %s failed: %d\n",
17599c6cae24SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname, error);
17609c6cae24SSepherosa Ziehau 		return;
17619c6cae24SSepherosa Ziehau 	}
17629c6cae24SSepherosa Ziehau 
17639c6cae24SSepherosa Ziehau 	/*
17649c6cae24SSepherosa Ziehau 	 * NOTE:
17659c6cae24SSepherosa Ziehau 	 * Datapath setting must happen _after_ bringing the VF up.
17669c6cae24SSepherosa Ziehau 	 */
17679c6cae24SSepherosa Ziehau 	hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF);
17689c6cae24SSepherosa Ziehau 
1769642ec226SSepherosa Ziehau 	/*
1770642ec226SSepherosa Ziehau 	 * NOTE:
1771642ec226SSepherosa Ziehau 	 * Fixup RSS related bits _after_ the VF is brought up, since
1772642ec226SSepherosa Ziehau 	 * many VFs generate RSS key during it's initialization.
1773642ec226SSepherosa Ziehau 	 */
1774642ec226SSepherosa Ziehau 	hn_vf_rss_fixup(sc, true);
1775642ec226SSepherosa Ziehau 
1776a97fff19SSepherosa Ziehau 	/* Mark transparent mode VF as enabled. */
1777a97fff19SSepherosa Ziehau 	hn_xpnt_vf_setenable(sc);
17789c6cae24SSepherosa Ziehau }
17799c6cae24SSepherosa Ziehau 
17809c6cae24SSepherosa Ziehau static void
17819c6cae24SSepherosa Ziehau hn_xpnt_vf_init_taskfunc(void *xsc, int pending __unused)
17829c6cae24SSepherosa Ziehau {
17839c6cae24SSepherosa Ziehau 	struct hn_softc *sc = xsc;
17849c6cae24SSepherosa Ziehau 
17859c6cae24SSepherosa Ziehau 	HN_LOCK(sc);
17869c6cae24SSepherosa Ziehau 
17879c6cae24SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
17889c6cae24SSepherosa Ziehau 		goto done;
17899c6cae24SSepherosa Ziehau 	if (sc->hn_vf_ifp == NULL)
17909c6cae24SSepherosa Ziehau 		goto done;
17919c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
17929c6cae24SSepherosa Ziehau 		goto done;
17939c6cae24SSepherosa Ziehau 
17949c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick != 0) {
17959c6cae24SSepherosa Ziehau 		/* Mark VF as ready. */
17969c6cae24SSepherosa Ziehau 		hn_xpnt_vf_setready(sc);
17979c6cae24SSepherosa Ziehau 	}
17989c6cae24SSepherosa Ziehau 
17999c6cae24SSepherosa Ziehau 	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) {
18009c6cae24SSepherosa Ziehau 		/*
18019c6cae24SSepherosa Ziehau 		 * Delayed VF initialization.
18029c6cae24SSepherosa Ziehau 		 */
18039c6cae24SSepherosa Ziehau 		if (bootverbose) {
18049c6cae24SSepherosa Ziehau 			if_printf(sc->hn_ifp, "delayed initialize %s\n",
18059c6cae24SSepherosa Ziehau 			    sc->hn_vf_ifp->if_xname);
18069c6cae24SSepherosa Ziehau 		}
18079c6cae24SSepherosa Ziehau 		hn_xpnt_vf_init(sc);
18089c6cae24SSepherosa Ziehau 	}
18099c6cae24SSepherosa Ziehau done:
18109c6cae24SSepherosa Ziehau 	HN_UNLOCK(sc);
18119c6cae24SSepherosa Ziehau }
18129c6cae24SSepherosa Ziehau 
1813499c3e17SSepherosa Ziehau static void
1814499c3e17SSepherosa Ziehau hn_ifnet_attevent(void *xsc, struct ifnet *ifp)
1815499c3e17SSepherosa Ziehau {
1816499c3e17SSepherosa Ziehau 	struct hn_softc *sc = xsc;
1817499c3e17SSepherosa Ziehau 
1818499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
1819499c3e17SSepherosa Ziehau 
1820499c3e17SSepherosa Ziehau 	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
1821499c3e17SSepherosa Ziehau 		goto done;
1822499c3e17SSepherosa Ziehau 
1823499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1824499c3e17SSepherosa Ziehau 		goto done;
1825499c3e17SSepherosa Ziehau 
1826499c3e17SSepherosa Ziehau 	if (sc->hn_vf_ifp != NULL) {
1827499c3e17SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%s was attached as VF\n",
1828499c3e17SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname);
1829499c3e17SSepherosa Ziehau 		goto done;
1830499c3e17SSepherosa Ziehau 	}
1831499c3e17SSepherosa Ziehau 
18329c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && ifp->if_start != NULL) {
18339c6cae24SSepherosa Ziehau 		/*
18349c6cae24SSepherosa Ziehau 		 * ifnet.if_start is _not_ supported by transparent
18359c6cae24SSepherosa Ziehau 		 * mode VF; mainly due to the IFF_DRV_OACTIVE flag.
18369c6cae24SSepherosa Ziehau 		 */
18379c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%s uses if_start, which is unsupported "
18389c6cae24SSepherosa Ziehau 		    "in transparent VF mode.\n", ifp->if_xname);
18399c6cae24SSepherosa Ziehau 		goto done;
18409c6cae24SSepherosa Ziehau 	}
18419c6cae24SSepherosa Ziehau 
1842499c3e17SSepherosa Ziehau 	rm_wlock(&hn_vfmap_lock);
1843499c3e17SSepherosa Ziehau 
1844499c3e17SSepherosa Ziehau 	if (ifp->if_index >= hn_vfmap_size) {
1845499c3e17SSepherosa Ziehau 		struct ifnet **newmap;
1846499c3e17SSepherosa Ziehau 		int newsize;
1847499c3e17SSepherosa Ziehau 
1848499c3e17SSepherosa Ziehau 		newsize = ifp->if_index + HN_VFMAP_SIZE_DEF;
1849499c3e17SSepherosa Ziehau 		newmap = malloc(sizeof(struct ifnet *) * newsize, M_DEVBUF,
1850499c3e17SSepherosa Ziehau 		    M_WAITOK | M_ZERO);
1851499c3e17SSepherosa Ziehau 
1852499c3e17SSepherosa Ziehau 		memcpy(newmap, hn_vfmap,
1853499c3e17SSepherosa Ziehau 		    sizeof(struct ifnet *) * hn_vfmap_size);
1854499c3e17SSepherosa Ziehau 		free(hn_vfmap, M_DEVBUF);
1855499c3e17SSepherosa Ziehau 		hn_vfmap = newmap;
1856499c3e17SSepherosa Ziehau 		hn_vfmap_size = newsize;
1857499c3e17SSepherosa Ziehau 	}
1858499c3e17SSepherosa Ziehau 	KASSERT(hn_vfmap[ifp->if_index] == NULL,
1859499c3e17SSepherosa Ziehau 	    ("%s: ifindex %d was mapped to %s",
1860499c3e17SSepherosa Ziehau 	     ifp->if_xname, ifp->if_index, hn_vfmap[ifp->if_index]->if_xname));
1861499c3e17SSepherosa Ziehau 	hn_vfmap[ifp->if_index] = sc->hn_ifp;
1862499c3e17SSepherosa Ziehau 
1863499c3e17SSepherosa Ziehau 	rm_wunlock(&hn_vfmap_lock);
1864499c3e17SSepherosa Ziehau 
18659c6cae24SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
18669c6cae24SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
18679c6cae24SSepherosa Ziehau 	KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0,
18689c6cae24SSepherosa Ziehau 	    ("%s: transparent VF was enabled", sc->hn_ifp->if_xname));
1869499c3e17SSepherosa Ziehau 	sc->hn_vf_ifp = ifp;
18709c6cae24SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
18719c6cae24SSepherosa Ziehau 
18729c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
18739c6cae24SSepherosa Ziehau 		int wait_ticks;
18749c6cae24SSepherosa Ziehau 
18759c6cae24SSepherosa Ziehau 		/*
18769c6cae24SSepherosa Ziehau 		 * Install if_input for vf_ifp, which does vf_ifp -> hn_ifp.
18779c6cae24SSepherosa Ziehau 		 * Save vf_ifp's current if_input for later restoration.
18789c6cae24SSepherosa Ziehau 		 */
18799c6cae24SSepherosa Ziehau 		sc->hn_vf_input = ifp->if_input;
18809c6cae24SSepherosa Ziehau 		ifp->if_input = hn_xpnt_vf_input;
18819c6cae24SSepherosa Ziehau 
18829c6cae24SSepherosa Ziehau 		/*
18839c6cae24SSepherosa Ziehau 		 * Stop link status management; use the VF's.
18849c6cae24SSepherosa Ziehau 		 */
18859c6cae24SSepherosa Ziehau 		hn_suspend_mgmt(sc);
18869c6cae24SSepherosa Ziehau 
18879c6cae24SSepherosa Ziehau 		/*
18889c6cae24SSepherosa Ziehau 		 * Give VF sometime to complete its attach routing.
18899c6cae24SSepherosa Ziehau 		 */
18909c6cae24SSepherosa Ziehau 		wait_ticks = hn_xpnt_vf_attwait * hz;
18919c6cae24SSepherosa Ziehau 		sc->hn_vf_rdytick = ticks + wait_ticks;
18929c6cae24SSepherosa Ziehau 
18939c6cae24SSepherosa Ziehau 		taskqueue_enqueue_timeout(sc->hn_vf_taskq, &sc->hn_vf_init,
18949c6cae24SSepherosa Ziehau 		    wait_ticks);
18959c6cae24SSepherosa Ziehau 	}
1896499c3e17SSepherosa Ziehau done:
1897499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
1898499c3e17SSepherosa Ziehau }
1899499c3e17SSepherosa Ziehau 
1900499c3e17SSepherosa Ziehau static void
1901499c3e17SSepherosa Ziehau hn_ifnet_detevent(void *xsc, struct ifnet *ifp)
1902499c3e17SSepherosa Ziehau {
1903499c3e17SSepherosa Ziehau 	struct hn_softc *sc = xsc;
1904499c3e17SSepherosa Ziehau 
1905499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
1906499c3e17SSepherosa Ziehau 
1907499c3e17SSepherosa Ziehau 	if (sc->hn_vf_ifp == NULL)
1908499c3e17SSepherosa Ziehau 		goto done;
1909499c3e17SSepherosa Ziehau 
1910499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1911499c3e17SSepherosa Ziehau 		goto done;
1912499c3e17SSepherosa Ziehau 
19139c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
19149c6cae24SSepherosa Ziehau 		/*
19159c6cae24SSepherosa Ziehau 		 * Make sure that the delayed initialization is not running.
19169c6cae24SSepherosa Ziehau 		 *
19179c6cae24SSepherosa Ziehau 		 * NOTE:
19189c6cae24SSepherosa Ziehau 		 * - This lock _must_ be released, since the hn_vf_init task
19199c6cae24SSepherosa Ziehau 		 *   will try holding this lock.
19209c6cae24SSepherosa Ziehau 		 * - It is safe to release this lock here, since the
19219c6cae24SSepherosa Ziehau 		 *   hn_ifnet_attevent() is interlocked by the hn_vf_ifp.
19229c6cae24SSepherosa Ziehau 		 *
19239c6cae24SSepherosa Ziehau 		 * XXX racy, if hn(4) ever detached.
19249c6cae24SSepherosa Ziehau 		 */
19259c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
19269c6cae24SSepherosa Ziehau 		taskqueue_drain_timeout(sc->hn_vf_taskq, &sc->hn_vf_init);
19279c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
19289c6cae24SSepherosa Ziehau 
19299c6cae24SSepherosa Ziehau 		KASSERT(sc->hn_vf_input != NULL, ("%s VF input is not saved",
19309c6cae24SSepherosa Ziehau 		    sc->hn_ifp->if_xname));
19319c6cae24SSepherosa Ziehau 		ifp->if_input = sc->hn_vf_input;
19329c6cae24SSepherosa Ziehau 		sc->hn_vf_input = NULL;
19339c6cae24SSepherosa Ziehau 
1934642ec226SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) &&
1935642ec226SSepherosa Ziehau 		    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED))
19369c6cae24SSepherosa Ziehau 			hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH);
19379c6cae24SSepherosa Ziehau 
19389c6cae24SSepherosa Ziehau 		if (sc->hn_vf_rdytick == 0) {
19399c6cae24SSepherosa Ziehau 			/*
19409c6cae24SSepherosa Ziehau 			 * The VF was ready; restore some settings.
19419c6cae24SSepherosa Ziehau 			 */
19429c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_capabilities = sc->hn_saved_caps;
19439c6cae24SSepherosa Ziehau 			/*
19449c6cae24SSepherosa Ziehau 			 * NOTE:
19459c6cae24SSepherosa Ziehau 			 * There is _no_ need to fixup if_capenable and
19469c6cae24SSepherosa Ziehau 			 * if_hwassist, since the if_capabilities before
19479c6cae24SSepherosa Ziehau 			 * restoration was an intersection of the VF's
19489c6cae24SSepherosa Ziehau 			 * if_capabilites and the synthetic device's
19499c6cae24SSepherosa Ziehau 			 * if_capabilites.
19509c6cae24SSepherosa Ziehau 			 */
19519c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomax = sc->hn_saved_tsomax;
19529c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomaxsegcount =
19539c6cae24SSepherosa Ziehau 			    sc->hn_saved_tsosegcnt;
19549c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomaxsegsize = sc->hn_saved_tsosegsz;
19559c6cae24SSepherosa Ziehau 		}
19569c6cae24SSepherosa Ziehau 
1957642ec226SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
1958642ec226SSepherosa Ziehau 			/*
1959642ec226SSepherosa Ziehau 			 * Restore RSS settings.
1960642ec226SSepherosa Ziehau 			 */
1961642ec226SSepherosa Ziehau 			hn_vf_rss_restore(sc);
1962642ec226SSepherosa Ziehau 
19639c6cae24SSepherosa Ziehau 			/*
19649c6cae24SSepherosa Ziehau 			 * Resume link status management, which was suspended
19659c6cae24SSepherosa Ziehau 			 * by hn_ifnet_attevent().
19669c6cae24SSepherosa Ziehau 			 */
19679c6cae24SSepherosa Ziehau 			hn_resume_mgmt(sc);
19689c6cae24SSepherosa Ziehau 		}
1969642ec226SSepherosa Ziehau 	}
19709c6cae24SSepherosa Ziehau 
1971a97fff19SSepherosa Ziehau 	/* Mark transparent mode VF as disabled. */
1972a97fff19SSepherosa Ziehau 	hn_xpnt_vf_setdisable(sc, true /* clear hn_vf_ifp */);
1973499c3e17SSepherosa Ziehau 
1974499c3e17SSepherosa Ziehau 	rm_wlock(&hn_vfmap_lock);
1975499c3e17SSepherosa Ziehau 
1976499c3e17SSepherosa Ziehau 	KASSERT(ifp->if_index < hn_vfmap_size,
1977499c3e17SSepherosa Ziehau 	    ("ifindex %d, vfmapsize %d", ifp->if_index, hn_vfmap_size));
1978499c3e17SSepherosa Ziehau 	if (hn_vfmap[ifp->if_index] != NULL) {
1979499c3e17SSepherosa Ziehau 		KASSERT(hn_vfmap[ifp->if_index] == sc->hn_ifp,
1980499c3e17SSepherosa Ziehau 		    ("%s: ifindex %d was mapped to %s",
1981499c3e17SSepherosa Ziehau 		     ifp->if_xname, ifp->if_index,
1982499c3e17SSepherosa Ziehau 		     hn_vfmap[ifp->if_index]->if_xname));
1983499c3e17SSepherosa Ziehau 		hn_vfmap[ifp->if_index] = NULL;
1984499c3e17SSepherosa Ziehau 	}
1985499c3e17SSepherosa Ziehau 
1986499c3e17SSepherosa Ziehau 	rm_wunlock(&hn_vfmap_lock);
1987499c3e17SSepherosa Ziehau done:
1988499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
1989499c3e17SSepherosa Ziehau }
1990499c3e17SSepherosa Ziehau 
19919c6cae24SSepherosa Ziehau static void
19929c6cae24SSepherosa Ziehau hn_ifnet_lnkevent(void *xsc, struct ifnet *ifp, int link_state)
19939c6cae24SSepherosa Ziehau {
19949c6cae24SSepherosa Ziehau 	struct hn_softc *sc = xsc;
19959c6cae24SSepherosa Ziehau 
19969c6cae24SSepherosa Ziehau 	if (sc->hn_vf_ifp == ifp)
19979c6cae24SSepherosa Ziehau 		if_link_state_change(sc->hn_ifp, link_state);
19989c6cae24SSepherosa Ziehau }
19999c6cae24SSepherosa Ziehau 
200015516c77SSepherosa Ziehau static int
200115516c77SSepherosa Ziehau hn_probe(device_t dev)
200215516c77SSepherosa Ziehau {
200315516c77SSepherosa Ziehau 
2004c2d50b26SSepherosa Ziehau 	if (VMBUS_PROBE_GUID(device_get_parent(dev), dev, &hn_guid) == 0) {
200515516c77SSepherosa Ziehau 		device_set_desc(dev, "Hyper-V Network Interface");
200615516c77SSepherosa Ziehau 		return BUS_PROBE_DEFAULT;
200715516c77SSepherosa Ziehau 	}
200815516c77SSepherosa Ziehau 	return ENXIO;
200915516c77SSepherosa Ziehau }
201015516c77SSepherosa Ziehau 
201115516c77SSepherosa Ziehau static int
201215516c77SSepherosa Ziehau hn_attach(device_t dev)
201315516c77SSepherosa Ziehau {
201415516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
201515516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
201615516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
201715516c77SSepherosa Ziehau 	uint8_t eaddr[ETHER_ADDR_LEN];
201815516c77SSepherosa Ziehau 	struct ifnet *ifp = NULL;
201915516c77SSepherosa Ziehau 	int error, ring_cnt, tx_ring_cnt;
2020eb2fe044SSepherosa Ziehau 	uint32_t mtu;
202115516c77SSepherosa Ziehau 
202215516c77SSepherosa Ziehau 	sc->hn_dev = dev;
202315516c77SSepherosa Ziehau 	sc->hn_prichan = vmbus_get_channel(dev);
202415516c77SSepherosa Ziehau 	HN_LOCK_INIT(sc);
20259c6cae24SSepherosa Ziehau 	rm_init(&sc->hn_vf_lock, "hnvf");
20269c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && hn_xpnt_vf_accbpf)
20279c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF;
202815516c77SSepherosa Ziehau 
202915516c77SSepherosa Ziehau 	/*
2030dc13fee6SSepherosa Ziehau 	 * Initialize these tunables once.
2031dc13fee6SSepherosa Ziehau 	 */
2032dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = hn_tx_agg_size;
2033dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = hn_tx_agg_pkts;
2034dc13fee6SSepherosa Ziehau 
2035dc13fee6SSepherosa Ziehau 	/*
203615516c77SSepherosa Ziehau 	 * Setup taskqueue for transmission.
203715516c77SSepherosa Ziehau 	 */
20380e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_INDEP) {
2039fdd0222aSSepherosa Ziehau 		int i;
2040fdd0222aSSepherosa Ziehau 
2041fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs =
2042fdd0222aSSepherosa Ziehau 		    malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
2043fdd0222aSSepherosa Ziehau 		    M_DEVBUF, M_WAITOK);
2044fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i) {
2045fdd0222aSSepherosa Ziehau 			sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx",
2046fdd0222aSSepherosa Ziehau 			    M_WAITOK, taskqueue_thread_enqueue,
2047fdd0222aSSepherosa Ziehau 			    &sc->hn_tx_taskqs[i]);
2048fdd0222aSSepherosa Ziehau 			taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET,
2049fdd0222aSSepherosa Ziehau 			    "%s tx%d", device_get_nameunit(dev), i);
2050fdd0222aSSepherosa Ziehau 		}
20510e11868dSSepherosa Ziehau 	} else if (hn_tx_taskq_mode == HN_TX_TASKQ_M_GLOBAL) {
2052fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs = hn_tx_taskque;
205315516c77SSepherosa Ziehau 	}
205415516c77SSepherosa Ziehau 
205515516c77SSepherosa Ziehau 	/*
205615516c77SSepherosa Ziehau 	 * Setup taskqueue for mangement tasks, e.g. link status.
205715516c77SSepherosa Ziehau 	 */
205815516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK,
205915516c77SSepherosa Ziehau 	    taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0);
206015516c77SSepherosa Ziehau 	taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
206115516c77SSepherosa Ziehau 	    device_get_nameunit(dev));
206215516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
206315516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc);
206415516c77SSepherosa Ziehau 	TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0,
206515516c77SSepherosa Ziehau 	    hn_netchg_status_taskfunc, sc);
206615516c77SSepherosa Ziehau 
20679c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
20689c6cae24SSepherosa Ziehau 		/*
20699c6cae24SSepherosa Ziehau 		 * Setup taskqueue for VF tasks, e.g. delayed VF bringing up.
20709c6cae24SSepherosa Ziehau 		 */
20719c6cae24SSepherosa Ziehau 		sc->hn_vf_taskq = taskqueue_create("hn_vf", M_WAITOK,
20729c6cae24SSepherosa Ziehau 		    taskqueue_thread_enqueue, &sc->hn_vf_taskq);
20739c6cae24SSepherosa Ziehau 		taskqueue_start_threads(&sc->hn_vf_taskq, 1, PI_NET, "%s vf",
20749c6cae24SSepherosa Ziehau 		    device_get_nameunit(dev));
20759c6cae24SSepherosa Ziehau 		TIMEOUT_TASK_INIT(sc->hn_vf_taskq, &sc->hn_vf_init, 0,
20769c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_init_taskfunc, sc);
20779c6cae24SSepherosa Ziehau 	}
20789c6cae24SSepherosa Ziehau 
207915516c77SSepherosa Ziehau 	/*
208015516c77SSepherosa Ziehau 	 * Allocate ifnet and setup its name earlier, so that if_printf
208115516c77SSepherosa Ziehau 	 * can be used by functions, which will be called after
208215516c77SSepherosa Ziehau 	 * ether_ifattach().
208315516c77SSepherosa Ziehau 	 */
208415516c77SSepherosa Ziehau 	ifp = sc->hn_ifp = if_alloc(IFT_ETHER);
208515516c77SSepherosa Ziehau 	ifp->if_softc = sc;
208615516c77SSepherosa Ziehau 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
208715516c77SSepherosa Ziehau 
208815516c77SSepherosa Ziehau 	/*
208915516c77SSepherosa Ziehau 	 * Initialize ifmedia earlier so that it can be unconditionally
209015516c77SSepherosa Ziehau 	 * destroyed, if error happened later on.
209115516c77SSepherosa Ziehau 	 */
209215516c77SSepherosa Ziehau 	ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts);
209315516c77SSepherosa Ziehau 
209415516c77SSepherosa Ziehau 	/*
209515516c77SSepherosa Ziehau 	 * Figure out the # of RX rings (ring_cnt) and the # of TX rings
209615516c77SSepherosa Ziehau 	 * to use (tx_ring_cnt).
209715516c77SSepherosa Ziehau 	 *
209815516c77SSepherosa Ziehau 	 * NOTE:
209915516c77SSepherosa Ziehau 	 * The # of RX rings to use is same as the # of channels to use.
210015516c77SSepherosa Ziehau 	 */
210115516c77SSepherosa Ziehau 	ring_cnt = hn_chan_cnt;
210215516c77SSepherosa Ziehau 	if (ring_cnt <= 0) {
210315516c77SSepherosa Ziehau 		/* Default */
210415516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
210515516c77SSepherosa Ziehau 		if (ring_cnt > HN_RING_CNT_DEF_MAX)
210615516c77SSepherosa Ziehau 			ring_cnt = HN_RING_CNT_DEF_MAX;
210715516c77SSepherosa Ziehau 	} else if (ring_cnt > mp_ncpus) {
210815516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
210915516c77SSepherosa Ziehau 	}
211034d68912SSepherosa Ziehau #ifdef RSS
211134d68912SSepherosa Ziehau 	if (ring_cnt > rss_getnumbuckets())
211234d68912SSepherosa Ziehau 		ring_cnt = rss_getnumbuckets();
211334d68912SSepherosa Ziehau #endif
211415516c77SSepherosa Ziehau 
211515516c77SSepherosa Ziehau 	tx_ring_cnt = hn_tx_ring_cnt;
211615516c77SSepherosa Ziehau 	if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt)
211715516c77SSepherosa Ziehau 		tx_ring_cnt = ring_cnt;
211823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
211915516c77SSepherosa Ziehau 	if (hn_use_if_start) {
212015516c77SSepherosa Ziehau 		/* ifnet.if_start only needs one TX ring. */
212115516c77SSepherosa Ziehau 		tx_ring_cnt = 1;
212215516c77SSepherosa Ziehau 	}
212323bf9e15SSepherosa Ziehau #endif
212415516c77SSepherosa Ziehau 
212515516c77SSepherosa Ziehau 	/*
212615516c77SSepherosa Ziehau 	 * Set the leader CPU for channels.
212715516c77SSepherosa Ziehau 	 */
212815516c77SSepherosa Ziehau 	sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus;
212915516c77SSepherosa Ziehau 
213015516c77SSepherosa Ziehau 	/*
213115516c77SSepherosa Ziehau 	 * Create enough TX/RX rings, even if only limited number of
213215516c77SSepherosa Ziehau 	 * channels can be allocated.
213315516c77SSepherosa Ziehau 	 */
213415516c77SSepherosa Ziehau 	error = hn_create_tx_data(sc, tx_ring_cnt);
213515516c77SSepherosa Ziehau 	if (error)
213615516c77SSepherosa Ziehau 		goto failed;
213715516c77SSepherosa Ziehau 	error = hn_create_rx_data(sc, ring_cnt);
213815516c77SSepherosa Ziehau 	if (error)
213915516c77SSepherosa Ziehau 		goto failed;
214015516c77SSepherosa Ziehau 
214115516c77SSepherosa Ziehau 	/*
214215516c77SSepherosa Ziehau 	 * Create transaction context for NVS and RNDIS transactions.
214315516c77SSepherosa Ziehau 	 */
214415516c77SSepherosa Ziehau 	sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
214515516c77SSepherosa Ziehau 	    HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
214625641fc7SSepherosa Ziehau 	if (sc->hn_xact == NULL) {
214725641fc7SSepherosa Ziehau 		error = ENXIO;
214815516c77SSepherosa Ziehau 		goto failed;
214925641fc7SSepherosa Ziehau 	}
215025641fc7SSepherosa Ziehau 
215125641fc7SSepherosa Ziehau 	/*
215225641fc7SSepherosa Ziehau 	 * Install orphan handler for the revocation of this device's
215325641fc7SSepherosa Ziehau 	 * primary channel.
215425641fc7SSepherosa Ziehau 	 *
215525641fc7SSepherosa Ziehau 	 * NOTE:
215625641fc7SSepherosa Ziehau 	 * The processing order is critical here:
215725641fc7SSepherosa Ziehau 	 * Install the orphan handler, _before_ testing whether this
215825641fc7SSepherosa Ziehau 	 * device's primary channel has been revoked or not.
215925641fc7SSepherosa Ziehau 	 */
216025641fc7SSepherosa Ziehau 	vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact);
216125641fc7SSepherosa Ziehau 	if (vmbus_chan_is_revoked(sc->hn_prichan)) {
216225641fc7SSepherosa Ziehau 		error = ENXIO;
216325641fc7SSepherosa Ziehau 		goto failed;
216425641fc7SSepherosa Ziehau 	}
216515516c77SSepherosa Ziehau 
216615516c77SSepherosa Ziehau 	/*
216715516c77SSepherosa Ziehau 	 * Attach the synthetic parts, i.e. NVS and RNDIS.
216815516c77SSepherosa Ziehau 	 */
216915516c77SSepherosa Ziehau 	error = hn_synth_attach(sc, ETHERMTU);
217015516c77SSepherosa Ziehau 	if (error)
217115516c77SSepherosa Ziehau 		goto failed;
217215516c77SSepherosa Ziehau 
217315516c77SSepherosa Ziehau 	error = hn_rndis_get_eaddr(sc, eaddr);
217415516c77SSepherosa Ziehau 	if (error)
217515516c77SSepherosa Ziehau 		goto failed;
217615516c77SSepherosa Ziehau 
2177eb2fe044SSepherosa Ziehau 	error = hn_rndis_get_mtu(sc, &mtu);
2178eb2fe044SSepherosa Ziehau 	if (error)
2179eb2fe044SSepherosa Ziehau 		mtu = ETHERMTU;
2180eb2fe044SSepherosa Ziehau 	else if (bootverbose)
2181eb2fe044SSepherosa Ziehau 		device_printf(dev, "RNDIS mtu %u\n", mtu);
2182eb2fe044SSepherosa Ziehau 
218315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
218415516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
218515516c77SSepherosa Ziehau 		/*
218615516c77SSepherosa Ziehau 		 * Reduce TCP segment aggregation limit for multiple
218715516c77SSepherosa Ziehau 		 * RX rings to increase ACK timeliness.
218815516c77SSepherosa Ziehau 		 */
218915516c77SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF);
219015516c77SSepherosa Ziehau 	}
219115516c77SSepherosa Ziehau #endif
219215516c77SSepherosa Ziehau 
219315516c77SSepherosa Ziehau 	/*
219415516c77SSepherosa Ziehau 	 * Fixup TX stuffs after synthetic parts are attached.
219515516c77SSepherosa Ziehau 	 */
219615516c77SSepherosa Ziehau 	hn_fixup_tx_data(sc);
219715516c77SSepherosa Ziehau 
219815516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
219915516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
220015516c77SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD,
220115516c77SSepherosa Ziehau 	    &sc->hn_nvs_ver, 0, "NVS version");
220215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version",
220315516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
220415516c77SSepherosa Ziehau 	    hn_ndis_version_sysctl, "A", "NDIS version");
220515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps",
220615516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
220715516c77SSepherosa Ziehau 	    hn_caps_sysctl, "A", "capabilities");
220815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist",
220915516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
221015516c77SSepherosa Ziehau 	    hn_hwassist_sysctl, "A", "hwassist");
22119c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_max",
22129c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomax, 0, "max TSO size");
22139c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegcnt",
22149c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomaxsegcount, 0,
22159c6cae24SSepherosa Ziehau 	    "max # of TSO segments");
22169c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegsz",
22179c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomaxsegsize, 0,
22189c6cae24SSepherosa Ziehau 	    "max size of TSO segment");
221915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter",
222015516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
222115516c77SSepherosa Ziehau 	    hn_rxfilter_sysctl, "A", "rxfilter");
222215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash",
222315516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
222415516c77SSepherosa Ziehau 	    hn_rss_hash_sysctl, "A", "RSS hash");
2225642ec226SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hashcap",
2226642ec226SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2227642ec226SSepherosa Ziehau 	    hn_rss_hcap_sysctl, "A", "RSS hash capabilities");
2228642ec226SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "mbuf_hash",
2229642ec226SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2230642ec226SSepherosa Ziehau 	    hn_rss_mbuf_sysctl, "A", "RSS hash for mbufs");
223115516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size",
223215516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count");
223334d68912SSepherosa Ziehau #ifndef RSS
223434d68912SSepherosa Ziehau 	/*
223534d68912SSepherosa Ziehau 	 * Don't allow RSS key/indirect table changes, if RSS is defined.
223634d68912SSepherosa Ziehau 	 */
223715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key",
223815516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
223915516c77SSepherosa Ziehau 	    hn_rss_key_sysctl, "IU", "RSS key");
224015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind",
224115516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
224215516c77SSepherosa Ziehau 	    hn_rss_ind_sysctl, "IU", "RSS indirect table");
224334d68912SSepherosa Ziehau #endif
2244dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size",
2245dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_size, 0,
2246dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation size limit");
2247dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts",
2248dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0,
2249dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation count limit");
2250dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align",
2251dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_align, 0,
2252dc13fee6SSepherosa Ziehau 	    "RNDIS packet transmission aggregation alignment");
2253dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size",
2254dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
2255dc13fee6SSepherosa Ziehau 	    hn_txagg_size_sysctl, "I",
2256dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation size, 0 -- disable, -1 -- auto");
2257dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts",
2258dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
2259dc13fee6SSepherosa Ziehau 	    hn_txagg_pkts_sysctl, "I",
2260dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation packets, "
2261dc13fee6SSepherosa Ziehau 	    "0 -- disable, -1 -- auto");
22626c1204dfSSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "polling",
22636c1204dfSSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
22646c1204dfSSepherosa Ziehau 	    hn_polling_sysctl, "I",
22656c1204dfSSepherosa Ziehau 	    "Polling frequency: [100,1000000], 0 disable polling");
226640d60d6eSDexuan Cui 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf",
226740d60d6eSDexuan Cui 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
226840d60d6eSDexuan Cui 	    hn_vf_sysctl, "A", "Virtual Function's name");
22699c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf) {
2270499c3e17SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxvf",
2271499c3e17SSepherosa Ziehau 		    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2272499c3e17SSepherosa Ziehau 		    hn_rxvf_sysctl, "A", "activated Virtual Function's name");
22739c6cae24SSepherosa Ziehau 	} else {
22749c6cae24SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_enabled",
22759c6cae24SSepherosa Ziehau 		    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
22769c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_enabled_sysctl, "I",
22779c6cae24SSepherosa Ziehau 		    "Transparent VF enabled");
22789c6cae24SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_accbpf",
22799c6cae24SSepherosa Ziehau 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
22809c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_accbpf_sysctl, "I",
22819c6cae24SSepherosa Ziehau 		    "Accurate BPF for transparent VF");
22829c6cae24SSepherosa Ziehau 	}
228315516c77SSepherosa Ziehau 
228415516c77SSepherosa Ziehau 	/*
228515516c77SSepherosa Ziehau 	 * Setup the ifmedia, which has been initialized earlier.
228615516c77SSepherosa Ziehau 	 */
228715516c77SSepherosa Ziehau 	ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL);
228815516c77SSepherosa Ziehau 	ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO);
228915516c77SSepherosa Ziehau 	/* XXX ifmedia_set really should do this for us */
229015516c77SSepherosa Ziehau 	sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media;
229115516c77SSepherosa Ziehau 
229215516c77SSepherosa Ziehau 	/*
229315516c77SSepherosa Ziehau 	 * Setup the ifnet for this interface.
229415516c77SSepherosa Ziehau 	 */
229515516c77SSepherosa Ziehau 
229615516c77SSepherosa Ziehau 	ifp->if_baudrate = IF_Gbps(10);
229715516c77SSepherosa Ziehau 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
229815516c77SSepherosa Ziehau 	ifp->if_ioctl = hn_ioctl;
229915516c77SSepherosa Ziehau 	ifp->if_init = hn_init;
230023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
230115516c77SSepherosa Ziehau 	if (hn_use_if_start) {
230215516c77SSepherosa Ziehau 		int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]);
230315516c77SSepherosa Ziehau 
230415516c77SSepherosa Ziehau 		ifp->if_start = hn_start;
230515516c77SSepherosa Ziehau 		IFQ_SET_MAXLEN(&ifp->if_snd, qdepth);
230615516c77SSepherosa Ziehau 		ifp->if_snd.ifq_drv_maxlen = qdepth - 1;
230715516c77SSepherosa Ziehau 		IFQ_SET_READY(&ifp->if_snd);
230823bf9e15SSepherosa Ziehau 	} else
230923bf9e15SSepherosa Ziehau #endif
231023bf9e15SSepherosa Ziehau 	{
231115516c77SSepherosa Ziehau 		ifp->if_transmit = hn_transmit;
231215516c77SSepherosa Ziehau 		ifp->if_qflush = hn_xmit_qflush;
231315516c77SSepherosa Ziehau 	}
231415516c77SSepherosa Ziehau 
23159c6cae24SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO | IFCAP_LINKSTATE;
231615516c77SSepherosa Ziehau #ifdef foo
231715516c77SSepherosa Ziehau 	/* We can't diff IPv6 packets from IPv4 packets on RX path. */
231815516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM_IPV6;
231915516c77SSepherosa Ziehau #endif
232015516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_VLAN) {
232115516c77SSepherosa Ziehau 		/* XXX not sure about VLAN_MTU. */
232215516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
232315516c77SSepherosa Ziehau 	}
232415516c77SSepherosa Ziehau 
232515516c77SSepherosa Ziehau 	ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist;
232615516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP_MASK)
232715516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM;
232815516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP6_MASK)
232915516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM_IPV6;
233015516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO4) {
233115516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO4;
233215516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP_TSO;
233315516c77SSepherosa Ziehau 	}
233415516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO6) {
233515516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO6;
233615516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP6_TSO;
233715516c77SSepherosa Ziehau 	}
233815516c77SSepherosa Ziehau 
233915516c77SSepherosa Ziehau 	/* Enable all available capabilities by default. */
234015516c77SSepherosa Ziehau 	ifp->if_capenable = ifp->if_capabilities;
234115516c77SSepherosa Ziehau 
23427960e6baSSepherosa Ziehau 	/*
23437960e6baSSepherosa Ziehau 	 * Disable IPv6 TSO and TXCSUM by default, they still can
23447960e6baSSepherosa Ziehau 	 * be enabled through SIOCSIFCAP.
23457960e6baSSepherosa Ziehau 	 */
23467960e6baSSepherosa Ziehau 	ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
23477960e6baSSepherosa Ziehau 	ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO);
23487960e6baSSepherosa Ziehau 
234915516c77SSepherosa Ziehau 	if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) {
23509c6cae24SSepherosa Ziehau 		/*
23519c6cae24SSepherosa Ziehau 		 * Lock hn_set_tso_maxsize() to simplify its
23529c6cae24SSepherosa Ziehau 		 * internal logic.
23539c6cae24SSepherosa Ziehau 		 */
23549c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
235515516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU);
23569c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
235715516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX;
235815516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = PAGE_SIZE;
235915516c77SSepherosa Ziehau 	}
236015516c77SSepherosa Ziehau 
236115516c77SSepherosa Ziehau 	ether_ifattach(ifp, eaddr);
236215516c77SSepherosa Ziehau 
236315516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) {
236415516c77SSepherosa Ziehau 		if_printf(ifp, "TSO segcnt %u segsz %u\n",
236515516c77SSepherosa Ziehau 		    ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize);
236615516c77SSepherosa Ziehau 	}
2367eb2fe044SSepherosa Ziehau 	if (mtu < ETHERMTU) {
2368eb2fe044SSepherosa Ziehau 		if_printf(ifp, "fixup mtu %u -> %u\n", ifp->if_mtu, mtu);
2369eb2fe044SSepherosa Ziehau 		ifp->if_mtu = mtu;
2370eb2fe044SSepherosa Ziehau 	}
237115516c77SSepherosa Ziehau 
237215516c77SSepherosa Ziehau 	/* Inform the upper layer about the long frame support. */
237315516c77SSepherosa Ziehau 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
237415516c77SSepherosa Ziehau 
237515516c77SSepherosa Ziehau 	/*
237615516c77SSepherosa Ziehau 	 * Kick off link status check.
237715516c77SSepherosa Ziehau 	 */
237815516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
237915516c77SSepherosa Ziehau 	hn_update_link_status(sc);
238015516c77SSepherosa Ziehau 
23819c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf) {
23825bdfd3fdSDexuan Cui 		sc->hn_ifnet_evthand = EVENTHANDLER_REGISTER(ifnet_event,
23835bdfd3fdSDexuan Cui 		    hn_ifnet_event, sc, EVENTHANDLER_PRI_ANY);
23845bdfd3fdSDexuan Cui 		sc->hn_ifaddr_evthand = EVENTHANDLER_REGISTER(ifaddr_event,
23855bdfd3fdSDexuan Cui 		    hn_ifaddr_event, sc, EVENTHANDLER_PRI_ANY);
23869c6cae24SSepherosa Ziehau 	} else {
23879c6cae24SSepherosa Ziehau 		sc->hn_ifnet_lnkhand = EVENTHANDLER_REGISTER(ifnet_link_event,
23889c6cae24SSepherosa Ziehau 		    hn_ifnet_lnkevent, sc, EVENTHANDLER_PRI_ANY);
23899c6cae24SSepherosa Ziehau 	}
23905bdfd3fdSDexuan Cui 
2391f41e0df4SSepherosa Ziehau 	/*
2392f41e0df4SSepherosa Ziehau 	 * NOTE:
2393f41e0df4SSepherosa Ziehau 	 * Subscribe ether_ifattach event, instead of ifnet_arrival event,
2394f41e0df4SSepherosa Ziehau 	 * since interface's LLADDR is needed; interface LLADDR is not
2395f41e0df4SSepherosa Ziehau 	 * available when ifnet_arrival event is triggered.
2396f41e0df4SSepherosa Ziehau 	 */
2397499c3e17SSepherosa Ziehau 	sc->hn_ifnet_atthand = EVENTHANDLER_REGISTER(ether_ifattach_event,
2398499c3e17SSepherosa Ziehau 	    hn_ifnet_attevent, sc, EVENTHANDLER_PRI_ANY);
2399499c3e17SSepherosa Ziehau 	sc->hn_ifnet_dethand = EVENTHANDLER_REGISTER(ifnet_departure_event,
2400499c3e17SSepherosa Ziehau 	    hn_ifnet_detevent, sc, EVENTHANDLER_PRI_ANY);
2401499c3e17SSepherosa Ziehau 
240215516c77SSepherosa Ziehau 	return (0);
240315516c77SSepherosa Ziehau failed:
240415516c77SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)
240515516c77SSepherosa Ziehau 		hn_synth_detach(sc);
240615516c77SSepherosa Ziehau 	hn_detach(dev);
240715516c77SSepherosa Ziehau 	return (error);
240815516c77SSepherosa Ziehau }
240915516c77SSepherosa Ziehau 
241015516c77SSepherosa Ziehau static int
241115516c77SSepherosa Ziehau hn_detach(device_t dev)
241215516c77SSepherosa Ziehau {
241315516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
2414499c3e17SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp, *vf_ifp;
241515516c77SSepherosa Ziehau 
24169c6cae24SSepherosa Ziehau 	if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) {
24179c6cae24SSepherosa Ziehau 		/*
24189c6cae24SSepherosa Ziehau 		 * In case that the vmbus missed the orphan handler
24199c6cae24SSepherosa Ziehau 		 * installation.
24209c6cae24SSepherosa Ziehau 		 */
24219c6cae24SSepherosa Ziehau 		vmbus_xact_ctx_orphan(sc->hn_xact);
24229c6cae24SSepherosa Ziehau 	}
24239c6cae24SSepherosa Ziehau 
24245bdfd3fdSDexuan Cui 	if (sc->hn_ifaddr_evthand != NULL)
24255bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifaddr_event, sc->hn_ifaddr_evthand);
24265bdfd3fdSDexuan Cui 	if (sc->hn_ifnet_evthand != NULL)
24275bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifnet_event, sc->hn_ifnet_evthand);
2428499c3e17SSepherosa Ziehau 	if (sc->hn_ifnet_atthand != NULL) {
2429499c3e17SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ether_ifattach_event,
2430499c3e17SSepherosa Ziehau 		    sc->hn_ifnet_atthand);
2431499c3e17SSepherosa Ziehau 	}
2432499c3e17SSepherosa Ziehau 	if (sc->hn_ifnet_dethand != NULL) {
2433499c3e17SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ifnet_departure_event,
2434499c3e17SSepherosa Ziehau 		    sc->hn_ifnet_dethand);
2435499c3e17SSepherosa Ziehau 	}
24369c6cae24SSepherosa Ziehau 	if (sc->hn_ifnet_lnkhand != NULL)
24379c6cae24SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ifnet_link_event, sc->hn_ifnet_lnkhand);
2438499c3e17SSepherosa Ziehau 
2439499c3e17SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
2440499c3e17SSepherosa Ziehau 	__compiler_membar();
2441499c3e17SSepherosa Ziehau 	if (vf_ifp != NULL)
2442499c3e17SSepherosa Ziehau 		hn_ifnet_detevent(sc, vf_ifp);
24435bdfd3fdSDexuan Cui 
244415516c77SSepherosa Ziehau 	if (device_is_attached(dev)) {
244515516c77SSepherosa Ziehau 		HN_LOCK(sc);
244615516c77SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
244715516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
24485bdfd3fdSDexuan Cui 				hn_stop(sc, true);
244915516c77SSepherosa Ziehau 			/*
245015516c77SSepherosa Ziehau 			 * NOTE:
245115516c77SSepherosa Ziehau 			 * hn_stop() only suspends data, so managment
245215516c77SSepherosa Ziehau 			 * stuffs have to be suspended manually here.
245315516c77SSepherosa Ziehau 			 */
245415516c77SSepherosa Ziehau 			hn_suspend_mgmt(sc);
245515516c77SSepherosa Ziehau 			hn_synth_detach(sc);
245615516c77SSepherosa Ziehau 		}
245715516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
245815516c77SSepherosa Ziehau 		ether_ifdetach(ifp);
245915516c77SSepherosa Ziehau 	}
246015516c77SSepherosa Ziehau 
246115516c77SSepherosa Ziehau 	ifmedia_removeall(&sc->hn_media);
246215516c77SSepherosa Ziehau 	hn_destroy_rx_data(sc);
246315516c77SSepherosa Ziehau 	hn_destroy_tx_data(sc);
246415516c77SSepherosa Ziehau 
24650e11868dSSepherosa Ziehau 	if (sc->hn_tx_taskqs != NULL && sc->hn_tx_taskqs != hn_tx_taskque) {
2466fdd0222aSSepherosa Ziehau 		int i;
2467fdd0222aSSepherosa Ziehau 
2468fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
2469fdd0222aSSepherosa Ziehau 			taskqueue_free(sc->hn_tx_taskqs[i]);
2470fdd0222aSSepherosa Ziehau 		free(sc->hn_tx_taskqs, M_DEVBUF);
2471fdd0222aSSepherosa Ziehau 	}
247215516c77SSepherosa Ziehau 	taskqueue_free(sc->hn_mgmt_taskq0);
24739c6cae24SSepherosa Ziehau 	if (sc->hn_vf_taskq != NULL)
24749c6cae24SSepherosa Ziehau 		taskqueue_free(sc->hn_vf_taskq);
247515516c77SSepherosa Ziehau 
247625641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL) {
247725641fc7SSepherosa Ziehau 		/*
247825641fc7SSepherosa Ziehau 		 * Uninstall the orphan handler _before_ the xact is
247925641fc7SSepherosa Ziehau 		 * destructed.
248025641fc7SSepherosa Ziehau 		 */
248125641fc7SSepherosa Ziehau 		vmbus_chan_unset_orphan(sc->hn_prichan);
248215516c77SSepherosa Ziehau 		vmbus_xact_ctx_destroy(sc->hn_xact);
248325641fc7SSepherosa Ziehau 	}
248415516c77SSepherosa Ziehau 
248515516c77SSepherosa Ziehau 	if_free(ifp);
248615516c77SSepherosa Ziehau 
248715516c77SSepherosa Ziehau 	HN_LOCK_DESTROY(sc);
24889c6cae24SSepherosa Ziehau 	rm_destroy(&sc->hn_vf_lock);
248915516c77SSepherosa Ziehau 	return (0);
249015516c77SSepherosa Ziehau }
249115516c77SSepherosa Ziehau 
249215516c77SSepherosa Ziehau static int
249315516c77SSepherosa Ziehau hn_shutdown(device_t dev)
249415516c77SSepherosa Ziehau {
249515516c77SSepherosa Ziehau 
249615516c77SSepherosa Ziehau 	return (0);
249715516c77SSepherosa Ziehau }
249815516c77SSepherosa Ziehau 
249915516c77SSepherosa Ziehau static void
250015516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc)
250115516c77SSepherosa Ziehau {
250215516c77SSepherosa Ziehau 	uint32_t link_status;
250315516c77SSepherosa Ziehau 	int error;
250415516c77SSepherosa Ziehau 
250515516c77SSepherosa Ziehau 	error = hn_rndis_get_linkstatus(sc, &link_status);
250615516c77SSepherosa Ziehau 	if (error) {
250715516c77SSepherosa Ziehau 		/* XXX what to do? */
250815516c77SSepherosa Ziehau 		return;
250915516c77SSepherosa Ziehau 	}
251015516c77SSepherosa Ziehau 
251115516c77SSepherosa Ziehau 	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
251215516c77SSepherosa Ziehau 		sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
251315516c77SSepherosa Ziehau 	else
251415516c77SSepherosa Ziehau 		sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
251515516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp,
251615516c77SSepherosa Ziehau 	    (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ?
251715516c77SSepherosa Ziehau 	    LINK_STATE_UP : LINK_STATE_DOWN);
251815516c77SSepherosa Ziehau }
251915516c77SSepherosa Ziehau 
252015516c77SSepherosa Ziehau static void
252115516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused)
252215516c77SSepherosa Ziehau {
252315516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
252415516c77SSepherosa Ziehau 
252515516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
252615516c77SSepherosa Ziehau 		return;
252715516c77SSepherosa Ziehau 	hn_link_status(sc);
252815516c77SSepherosa Ziehau }
252915516c77SSepherosa Ziehau 
253015516c77SSepherosa Ziehau static void
253115516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused)
253215516c77SSepherosa Ziehau {
253315516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
253415516c77SSepherosa Ziehau 
253515516c77SSepherosa Ziehau 	/* Prevent any link status checks from running. */
253615516c77SSepherosa Ziehau 	sc->hn_link_flags |= HN_LINK_FLAG_NETCHG;
253715516c77SSepherosa Ziehau 
253815516c77SSepherosa Ziehau 	/*
253915516c77SSepherosa Ziehau 	 * Fake up a [link down --> link up] state change; 5 seconds
254015516c77SSepherosa Ziehau 	 * delay is used, which closely simulates miibus reaction
254115516c77SSepherosa Ziehau 	 * upon link down event.
254215516c77SSepherosa Ziehau 	 */
254315516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
254415516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
254515516c77SSepherosa Ziehau 	taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0,
254615516c77SSepherosa Ziehau 	    &sc->hn_netchg_status, 5 * hz);
254715516c77SSepherosa Ziehau }
254815516c77SSepherosa Ziehau 
254915516c77SSepherosa Ziehau static void
255015516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused)
255115516c77SSepherosa Ziehau {
255215516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
255315516c77SSepherosa Ziehau 
255415516c77SSepherosa Ziehau 	/* Re-allow link status checks. */
255515516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG;
255615516c77SSepherosa Ziehau 	hn_link_status(sc);
255715516c77SSepherosa Ziehau }
255815516c77SSepherosa Ziehau 
255915516c77SSepherosa Ziehau static void
256015516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc)
256115516c77SSepherosa Ziehau {
256215516c77SSepherosa Ziehau 
256315516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
256415516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
256515516c77SSepherosa Ziehau }
256615516c77SSepherosa Ziehau 
256715516c77SSepherosa Ziehau static void
256815516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc)
256915516c77SSepherosa Ziehau {
257015516c77SSepherosa Ziehau 
257115516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
257215516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init);
257315516c77SSepherosa Ziehau }
257415516c77SSepherosa Ziehau 
257515516c77SSepherosa Ziehau static __inline int
257615516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
257715516c77SSepherosa Ziehau     struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
257815516c77SSepherosa Ziehau {
257915516c77SSepherosa Ziehau 	struct mbuf *m = *m_head;
258015516c77SSepherosa Ziehau 	int error;
258115516c77SSepherosa Ziehau 
258215516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim"));
258315516c77SSepherosa Ziehau 
258415516c77SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap,
258515516c77SSepherosa Ziehau 	    m, segs, nsegs, BUS_DMA_NOWAIT);
258615516c77SSepherosa Ziehau 	if (error == EFBIG) {
258715516c77SSepherosa Ziehau 		struct mbuf *m_new;
258815516c77SSepherosa Ziehau 
258915516c77SSepherosa Ziehau 		m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX);
259015516c77SSepherosa Ziehau 		if (m_new == NULL)
259115516c77SSepherosa Ziehau 			return ENOBUFS;
259215516c77SSepherosa Ziehau 		else
259315516c77SSepherosa Ziehau 			*m_head = m = m_new;
259415516c77SSepherosa Ziehau 		txr->hn_tx_collapsed++;
259515516c77SSepherosa Ziehau 
259615516c77SSepherosa Ziehau 		error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag,
259715516c77SSepherosa Ziehau 		    txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT);
259815516c77SSepherosa Ziehau 	}
259915516c77SSepherosa Ziehau 	if (!error) {
260015516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap,
260115516c77SSepherosa Ziehau 		    BUS_DMASYNC_PREWRITE);
260215516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_DMAMAP;
260315516c77SSepherosa Ziehau 	}
260415516c77SSepherosa Ziehau 	return error;
260515516c77SSepherosa Ziehau }
260615516c77SSepherosa Ziehau 
260715516c77SSepherosa Ziehau static __inline int
260815516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd)
260915516c77SSepherosa Ziehau {
261015516c77SSepherosa Ziehau 
261115516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0,
261215516c77SSepherosa Ziehau 	    ("put an onlist txd %#x", txd->flags));
2613dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2614dc13fee6SSepherosa Ziehau 	    ("put an onagg txd %#x", txd->flags));
261515516c77SSepherosa Ziehau 
261615516c77SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
261715516c77SSepherosa Ziehau 	if (atomic_fetchadd_int(&txd->refs, -1) != 1)
261815516c77SSepherosa Ziehau 		return 0;
261915516c77SSepherosa Ziehau 
2620dc13fee6SSepherosa Ziehau 	if (!STAILQ_EMPTY(&txd->agg_list)) {
2621dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tmp_txd;
2622dc13fee6SSepherosa Ziehau 
2623dc13fee6SSepherosa Ziehau 		while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) {
2624dc13fee6SSepherosa Ziehau 			int freed;
2625dc13fee6SSepherosa Ziehau 
2626dc13fee6SSepherosa Ziehau 			KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list),
2627dc13fee6SSepherosa Ziehau 			    ("resursive aggregation on aggregated txdesc"));
2628dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG),
2629dc13fee6SSepherosa Ziehau 			    ("not aggregated txdesc"));
2630dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
2631dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc uses dmamap"));
2632dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
2633dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc consumes "
2634dc13fee6SSepherosa Ziehau 			     "chimney sending buffer"));
2635dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_size == 0,
2636dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc has non-zero "
2637dc13fee6SSepherosa Ziehau 			     "chimney sending size"));
2638dc13fee6SSepherosa Ziehau 
2639dc13fee6SSepherosa Ziehau 			STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link);
2640dc13fee6SSepherosa Ziehau 			tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG;
2641dc13fee6SSepherosa Ziehau 			freed = hn_txdesc_put(txr, tmp_txd);
2642dc13fee6SSepherosa Ziehau 			KASSERT(freed, ("failed to free aggregated txdesc"));
2643dc13fee6SSepherosa Ziehau 		}
2644dc13fee6SSepherosa Ziehau 	}
2645dc13fee6SSepherosa Ziehau 
264615516c77SSepherosa Ziehau 	if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) {
264715516c77SSepherosa Ziehau 		KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
264815516c77SSepherosa Ziehau 		    ("chim txd uses dmamap"));
264915516c77SSepherosa Ziehau 		hn_chim_free(txr->hn_sc, txd->chim_index);
265015516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
2651dc13fee6SSepherosa Ziehau 		txd->chim_size = 0;
265215516c77SSepherosa Ziehau 	} else if (txd->flags & HN_TXD_FLAG_DMAMAP) {
265315516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag,
265415516c77SSepherosa Ziehau 		    txd->data_dmap, BUS_DMASYNC_POSTWRITE);
265515516c77SSepherosa Ziehau 		bus_dmamap_unload(txr->hn_tx_data_dtag,
265615516c77SSepherosa Ziehau 		    txd->data_dmap);
265715516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_DMAMAP;
265815516c77SSepherosa Ziehau 	}
265915516c77SSepherosa Ziehau 
266015516c77SSepherosa Ziehau 	if (txd->m != NULL) {
266115516c77SSepherosa Ziehau 		m_freem(txd->m);
266215516c77SSepherosa Ziehau 		txd->m = NULL;
266315516c77SSepherosa Ziehau 	}
266415516c77SSepherosa Ziehau 
266515516c77SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONLIST;
266615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
266715516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
266815516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_avail >= 0 &&
266915516c77SSepherosa Ziehau 	    txr->hn_txdesc_avail < txr->hn_txdesc_cnt,
267015516c77SSepherosa Ziehau 	    ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail));
267115516c77SSepherosa Ziehau 	txr->hn_txdesc_avail++;
267215516c77SSepherosa Ziehau 	SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
267315516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
267485e4ae1eSSepherosa Ziehau #else	/* HN_USE_TXDESC_BUFRING */
267585e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
267615516c77SSepherosa Ziehau 	atomic_add_int(&txr->hn_txdesc_avail, 1);
267715516c77SSepherosa Ziehau #endif
267885e4ae1eSSepherosa Ziehau 	buf_ring_enqueue(txr->hn_txdesc_br, txd);
267985e4ae1eSSepherosa Ziehau #endif	/* !HN_USE_TXDESC_BUFRING */
268015516c77SSepherosa Ziehau 
268115516c77SSepherosa Ziehau 	return 1;
268215516c77SSepherosa Ziehau }
268315516c77SSepherosa Ziehau 
268415516c77SSepherosa Ziehau static __inline struct hn_txdesc *
268515516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr)
268615516c77SSepherosa Ziehau {
268715516c77SSepherosa Ziehau 	struct hn_txdesc *txd;
268815516c77SSepherosa Ziehau 
268915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
269015516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
269115516c77SSepherosa Ziehau 	txd = SLIST_FIRST(&txr->hn_txlist);
269215516c77SSepherosa Ziehau 	if (txd != NULL) {
269315516c77SSepherosa Ziehau 		KASSERT(txr->hn_txdesc_avail > 0,
269415516c77SSepherosa Ziehau 		    ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail));
269515516c77SSepherosa Ziehau 		txr->hn_txdesc_avail--;
269615516c77SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&txr->hn_txlist, link);
269715516c77SSepherosa Ziehau 	}
269815516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
269915516c77SSepherosa Ziehau #else
270015516c77SSepherosa Ziehau 	txd = buf_ring_dequeue_sc(txr->hn_txdesc_br);
270115516c77SSepherosa Ziehau #endif
270215516c77SSepherosa Ziehau 
270315516c77SSepherosa Ziehau 	if (txd != NULL) {
270415516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
270585e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
270615516c77SSepherosa Ziehau 		atomic_subtract_int(&txr->hn_txdesc_avail, 1);
270715516c77SSepherosa Ziehau #endif
270885e4ae1eSSepherosa Ziehau #endif	/* HN_USE_TXDESC_BUFRING */
270915516c77SSepherosa Ziehau 		KASSERT(txd->m == NULL && txd->refs == 0 &&
2710dc13fee6SSepherosa Ziehau 		    STAILQ_EMPTY(&txd->agg_list) &&
271115516c77SSepherosa Ziehau 		    txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
2712dc13fee6SSepherosa Ziehau 		    txd->chim_size == 0 &&
271315516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONLIST) &&
2714dc13fee6SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONAGG) == 0 &&
271515516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd"));
271615516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_ONLIST;
271715516c77SSepherosa Ziehau 		txd->refs = 1;
271815516c77SSepherosa Ziehau 	}
271915516c77SSepherosa Ziehau 	return txd;
272015516c77SSepherosa Ziehau }
272115516c77SSepherosa Ziehau 
272215516c77SSepherosa Ziehau static __inline void
272315516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd)
272415516c77SSepherosa Ziehau {
272515516c77SSepherosa Ziehau 
272615516c77SSepherosa Ziehau 	/* 0->1 transition will never work */
272725641fc7SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
272815516c77SSepherosa Ziehau 	atomic_add_int(&txd->refs, 1);
272915516c77SSepherosa Ziehau }
273015516c77SSepherosa Ziehau 
2731dc13fee6SSepherosa Ziehau static __inline void
2732dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd)
2733dc13fee6SSepherosa Ziehau {
2734dc13fee6SSepherosa Ziehau 
2735dc13fee6SSepherosa Ziehau 	KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2736dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on aggregating txdesc"));
2737dc13fee6SSepherosa Ziehau 
2738dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2739dc13fee6SSepherosa Ziehau 	    ("already aggregated"));
2740dc13fee6SSepherosa Ziehau 	KASSERT(STAILQ_EMPTY(&txd->agg_list),
2741dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on to-be-aggregated txdesc"));
2742dc13fee6SSepherosa Ziehau 
2743dc13fee6SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONAGG;
2744dc13fee6SSepherosa Ziehau 	STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link);
2745dc13fee6SSepherosa Ziehau }
2746dc13fee6SSepherosa Ziehau 
274715516c77SSepherosa Ziehau static bool
274815516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr)
274915516c77SSepherosa Ziehau {
275015516c77SSepherosa Ziehau 	bool pending = false;
275115516c77SSepherosa Ziehau 
275215516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
275315516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
275415516c77SSepherosa Ziehau 	if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt)
275515516c77SSepherosa Ziehau 		pending = true;
275615516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
275715516c77SSepherosa Ziehau #else
275815516c77SSepherosa Ziehau 	if (!buf_ring_full(txr->hn_txdesc_br))
275915516c77SSepherosa Ziehau 		pending = true;
276015516c77SSepherosa Ziehau #endif
276115516c77SSepherosa Ziehau 	return (pending);
276215516c77SSepherosa Ziehau }
276315516c77SSepherosa Ziehau 
276415516c77SSepherosa Ziehau static __inline void
276515516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr)
276615516c77SSepherosa Ziehau {
276715516c77SSepherosa Ziehau 	txr->hn_has_txeof = 0;
276815516c77SSepherosa Ziehau 	txr->hn_txeof(txr);
276915516c77SSepherosa Ziehau }
277015516c77SSepherosa Ziehau 
277115516c77SSepherosa Ziehau static void
277215516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc,
277315516c77SSepherosa Ziehau     struct vmbus_channel *chan, const void *data __unused, int dlen __unused)
277415516c77SSepherosa Ziehau {
277515516c77SSepherosa Ziehau 	struct hn_txdesc *txd = sndc->hn_cbarg;
277615516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
277715516c77SSepherosa Ziehau 
277815516c77SSepherosa Ziehau 	txr = txd->txr;
277915516c77SSepherosa Ziehau 	KASSERT(txr->hn_chan == chan,
278015516c77SSepherosa Ziehau 	    ("channel mismatch, on chan%u, should be chan%u",
2781aa1a2adcSSepherosa Ziehau 	     vmbus_chan_id(chan), vmbus_chan_id(txr->hn_chan)));
278215516c77SSepherosa Ziehau 
278315516c77SSepherosa Ziehau 	txr->hn_has_txeof = 1;
278415516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
278515516c77SSepherosa Ziehau 
278615516c77SSepherosa Ziehau 	++txr->hn_txdone_cnt;
278715516c77SSepherosa Ziehau 	if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) {
278815516c77SSepherosa Ziehau 		txr->hn_txdone_cnt = 0;
278915516c77SSepherosa Ziehau 		if (txr->hn_oactive)
279015516c77SSepherosa Ziehau 			hn_txeof(txr);
279115516c77SSepherosa Ziehau 	}
279215516c77SSepherosa Ziehau }
279315516c77SSepherosa Ziehau 
279415516c77SSepherosa Ziehau static void
279515516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
279615516c77SSepherosa Ziehau {
279715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
279815516c77SSepherosa Ziehau 	tcp_lro_flush_all(&rxr->hn_lro);
279915516c77SSepherosa Ziehau #endif
280015516c77SSepherosa Ziehau 
280115516c77SSepherosa Ziehau 	/*
280215516c77SSepherosa Ziehau 	 * NOTE:
280315516c77SSepherosa Ziehau 	 * 'txr' could be NULL, if multiple channels and
280415516c77SSepherosa Ziehau 	 * ifnet.if_start method are enabled.
280515516c77SSepherosa Ziehau 	 */
280615516c77SSepherosa Ziehau 	if (txr == NULL || !txr->hn_has_txeof)
280715516c77SSepherosa Ziehau 		return;
280815516c77SSepherosa Ziehau 
280915516c77SSepherosa Ziehau 	txr->hn_txdone_cnt = 0;
281015516c77SSepherosa Ziehau 	hn_txeof(txr);
281115516c77SSepherosa Ziehau }
281215516c77SSepherosa Ziehau 
281315516c77SSepherosa Ziehau static __inline uint32_t
281415516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs)
281515516c77SSepherosa Ziehau {
281615516c77SSepherosa Ziehau 
281715516c77SSepherosa Ziehau 	KASSERT(ofs >= sizeof(struct rndis_packet_msg),
281815516c77SSepherosa Ziehau 	    ("invalid RNDIS packet msg offset %u", ofs));
281915516c77SSepherosa Ziehau 	return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset));
282015516c77SSepherosa Ziehau }
282115516c77SSepherosa Ziehau 
282215516c77SSepherosa Ziehau static __inline void *
282315516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
282415516c77SSepherosa Ziehau     size_t pi_dlen, uint32_t pi_type)
282515516c77SSepherosa Ziehau {
282615516c77SSepherosa Ziehau 	const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
282715516c77SSepherosa Ziehau 	struct rndis_pktinfo *pi;
282815516c77SSepherosa Ziehau 
282915516c77SSepherosa Ziehau 	KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
283015516c77SSepherosa Ziehau 	    ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
283115516c77SSepherosa Ziehau 
283215516c77SSepherosa Ziehau 	/*
283315516c77SSepherosa Ziehau 	 * Per-packet-info does not move; it only grows.
283415516c77SSepherosa Ziehau 	 *
283515516c77SSepherosa Ziehau 	 * NOTE:
283615516c77SSepherosa Ziehau 	 * rm_pktinfooffset in this phase counts from the beginning
283715516c77SSepherosa Ziehau 	 * of rndis_packet_msg.
283815516c77SSepherosa Ziehau 	 */
283915516c77SSepherosa Ziehau 	KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
284015516c77SSepherosa Ziehau 	    ("%u pktinfo overflows RNDIS packet msg", pi_type));
284115516c77SSepherosa Ziehau 	pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
284215516c77SSepherosa Ziehau 	    pkt->rm_pktinfolen);
284315516c77SSepherosa Ziehau 	pkt->rm_pktinfolen += pi_size;
284415516c77SSepherosa Ziehau 
284515516c77SSepherosa Ziehau 	pi->rm_size = pi_size;
284615516c77SSepherosa Ziehau 	pi->rm_type = pi_type;
284715516c77SSepherosa Ziehau 	pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
284815516c77SSepherosa Ziehau 
284915516c77SSepherosa Ziehau 	return (pi->rm_data);
285015516c77SSepherosa Ziehau }
285115516c77SSepherosa Ziehau 
2852dc13fee6SSepherosa Ziehau static __inline int
2853dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr)
2854dc13fee6SSepherosa Ziehau {
2855dc13fee6SSepherosa Ziehau 	struct hn_txdesc *txd;
2856dc13fee6SSepherosa Ziehau 	struct mbuf *m;
2857dc13fee6SSepherosa Ziehau 	int error, pkts;
2858dc13fee6SSepherosa Ziehau 
2859dc13fee6SSepherosa Ziehau 	txd = txr->hn_agg_txd;
2860dc13fee6SSepherosa Ziehau 	KASSERT(txd != NULL, ("no aggregate txdesc"));
2861dc13fee6SSepherosa Ziehau 
2862dc13fee6SSepherosa Ziehau 	/*
2863dc13fee6SSepherosa Ziehau 	 * Since hn_txpkt() will reset this temporary stat, save
2864dc13fee6SSepherosa Ziehau 	 * it now, so that oerrors can be updated properly, if
2865dc13fee6SSepherosa Ziehau 	 * hn_txpkt() ever fails.
2866dc13fee6SSepherosa Ziehau 	 */
2867dc13fee6SSepherosa Ziehau 	pkts = txr->hn_stat_pkts;
2868dc13fee6SSepherosa Ziehau 
2869dc13fee6SSepherosa Ziehau 	/*
2870dc13fee6SSepherosa Ziehau 	 * Since txd's mbuf will _not_ be freed upon hn_txpkt()
2871dc13fee6SSepherosa Ziehau 	 * failure, save it for later freeing, if hn_txpkt() ever
2872dc13fee6SSepherosa Ziehau 	 * fails.
2873dc13fee6SSepherosa Ziehau 	 */
2874dc13fee6SSepherosa Ziehau 	m = txd->m;
2875dc13fee6SSepherosa Ziehau 	error = hn_txpkt(ifp, txr, txd);
2876dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
2877dc13fee6SSepherosa Ziehau 		/* txd is freed, but m is not. */
2878dc13fee6SSepherosa Ziehau 		m_freem(m);
2879dc13fee6SSepherosa Ziehau 
2880dc13fee6SSepherosa Ziehau 		txr->hn_flush_failed++;
2881dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts);
2882dc13fee6SSepherosa Ziehau 	}
2883dc13fee6SSepherosa Ziehau 
2884dc13fee6SSepherosa Ziehau 	/* Reset all aggregation states. */
2885dc13fee6SSepherosa Ziehau 	txr->hn_agg_txd = NULL;
2886dc13fee6SSepherosa Ziehau 	txr->hn_agg_szleft = 0;
2887dc13fee6SSepherosa Ziehau 	txr->hn_agg_pktleft = 0;
2888dc13fee6SSepherosa Ziehau 	txr->hn_agg_prevpkt = NULL;
2889dc13fee6SSepherosa Ziehau 
2890dc13fee6SSepherosa Ziehau 	return (error);
2891dc13fee6SSepherosa Ziehau }
2892dc13fee6SSepherosa Ziehau 
2893dc13fee6SSepherosa Ziehau static void *
2894dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
2895dc13fee6SSepherosa Ziehau     int pktsize)
2896dc13fee6SSepherosa Ziehau {
2897dc13fee6SSepherosa Ziehau 	void *chim;
2898dc13fee6SSepherosa Ziehau 
2899dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL) {
2900dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) {
2901dc13fee6SSepherosa Ziehau 			struct hn_txdesc *agg_txd = txr->hn_agg_txd;
2902dc13fee6SSepherosa Ziehau 			struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt;
2903dc13fee6SSepherosa Ziehau 			int olen;
2904dc13fee6SSepherosa Ziehau 
2905dc13fee6SSepherosa Ziehau 			/*
2906dc13fee6SSepherosa Ziehau 			 * Update the previous RNDIS packet's total length,
2907dc13fee6SSepherosa Ziehau 			 * it can be increased due to the mandatory alignment
2908dc13fee6SSepherosa Ziehau 			 * padding for this RNDIS packet.  And update the
2909dc13fee6SSepherosa Ziehau 			 * aggregating txdesc's chimney sending buffer size
2910dc13fee6SSepherosa Ziehau 			 * accordingly.
2911dc13fee6SSepherosa Ziehau 			 *
2912dc13fee6SSepherosa Ziehau 			 * XXX
2913dc13fee6SSepherosa Ziehau 			 * Zero-out the padding, as required by the RNDIS spec.
2914dc13fee6SSepherosa Ziehau 			 */
2915dc13fee6SSepherosa Ziehau 			olen = pkt->rm_len;
2916dc13fee6SSepherosa Ziehau 			pkt->rm_len = roundup2(olen, txr->hn_agg_align);
2917dc13fee6SSepherosa Ziehau 			agg_txd->chim_size += pkt->rm_len - olen;
2918dc13fee6SSepherosa Ziehau 
2919dc13fee6SSepherosa Ziehau 			/* Link this txdesc to the parent. */
2920dc13fee6SSepherosa Ziehau 			hn_txdesc_agg(agg_txd, txd);
2921dc13fee6SSepherosa Ziehau 
2922dc13fee6SSepherosa Ziehau 			chim = (uint8_t *)pkt + pkt->rm_len;
2923dc13fee6SSepherosa Ziehau 			/* Save the current packet for later fixup. */
2924dc13fee6SSepherosa Ziehau 			txr->hn_agg_prevpkt = chim;
2925dc13fee6SSepherosa Ziehau 
2926dc13fee6SSepherosa Ziehau 			txr->hn_agg_pktleft--;
2927dc13fee6SSepherosa Ziehau 			txr->hn_agg_szleft -= pktsize;
2928dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_szleft <=
2929dc13fee6SSepherosa Ziehau 			    HN_PKTSIZE_MIN(txr->hn_agg_align)) {
2930dc13fee6SSepherosa Ziehau 				/*
2931dc13fee6SSepherosa Ziehau 				 * Probably can't aggregate more packets,
2932dc13fee6SSepherosa Ziehau 				 * flush this aggregating txdesc proactively.
2933dc13fee6SSepherosa Ziehau 				 */
2934dc13fee6SSepherosa Ziehau 				txr->hn_agg_pktleft = 0;
2935dc13fee6SSepherosa Ziehau 			}
2936dc13fee6SSepherosa Ziehau 			/* Done! */
2937dc13fee6SSepherosa Ziehau 			return (chim);
2938dc13fee6SSepherosa Ziehau 		}
2939dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
2940dc13fee6SSepherosa Ziehau 	}
2941dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
2942dc13fee6SSepherosa Ziehau 
2943dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney_tried++;
2944dc13fee6SSepherosa Ziehau 	txd->chim_index = hn_chim_alloc(txr->hn_sc);
2945dc13fee6SSepherosa Ziehau 	if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID)
2946dc13fee6SSepherosa Ziehau 		return (NULL);
2947dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney++;
2948dc13fee6SSepherosa Ziehau 
2949dc13fee6SSepherosa Ziehau 	chim = txr->hn_sc->hn_chim +
2950dc13fee6SSepherosa Ziehau 	    (txd->chim_index * txr->hn_sc->hn_chim_szmax);
2951dc13fee6SSepherosa Ziehau 
2952dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_pktmax > 1 &&
2953dc13fee6SSepherosa Ziehau 	    txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) {
2954dc13fee6SSepherosa Ziehau 		txr->hn_agg_txd = txd;
2955dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1;
2956dc13fee6SSepherosa Ziehau 		txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize;
2957dc13fee6SSepherosa Ziehau 		txr->hn_agg_prevpkt = chim;
2958dc13fee6SSepherosa Ziehau 	}
2959dc13fee6SSepherosa Ziehau 	return (chim);
2960dc13fee6SSepherosa Ziehau }
2961dc13fee6SSepherosa Ziehau 
296215516c77SSepherosa Ziehau /*
296315516c77SSepherosa Ziehau  * NOTE:
296415516c77SSepherosa Ziehau  * If this function fails, then both txd and m_head0 will be freed.
296515516c77SSepherosa Ziehau  */
296615516c77SSepherosa Ziehau static int
2967dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
2968dc13fee6SSepherosa Ziehau     struct mbuf **m_head0)
296915516c77SSepherosa Ziehau {
297015516c77SSepherosa Ziehau 	bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX];
297115516c77SSepherosa Ziehau 	int error, nsegs, i;
297215516c77SSepherosa Ziehau 	struct mbuf *m_head = *m_head0;
297315516c77SSepherosa Ziehau 	struct rndis_packet_msg *pkt;
297415516c77SSepherosa Ziehau 	uint32_t *pi_data;
29758966e5d5SSepherosa Ziehau 	void *chim = NULL;
2976dc13fee6SSepherosa Ziehau 	int pkt_hlen, pkt_size;
297715516c77SSepherosa Ziehau 
297815516c77SSepherosa Ziehau 	pkt = txd->rndis_pkt;
2979dc13fee6SSepherosa Ziehau 	pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align);
2980dc13fee6SSepherosa Ziehau 	if (pkt_size < txr->hn_chim_size) {
2981dc13fee6SSepherosa Ziehau 		chim = hn_try_txagg(ifp, txr, txd, pkt_size);
2982dc13fee6SSepherosa Ziehau 		if (chim != NULL)
29838966e5d5SSepherosa Ziehau 			pkt = chim;
2984dc13fee6SSepherosa Ziehau 	} else {
2985dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL)
2986dc13fee6SSepherosa Ziehau 			hn_flush_txagg(ifp, txr);
29878966e5d5SSepherosa Ziehau 	}
29888966e5d5SSepherosa Ziehau 
298915516c77SSepherosa Ziehau 	pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
29908fe90f73SSepherosa Ziehau 	pkt->rm_len = m_head->m_pkthdr.len;
29919130c4f7SSepherosa Ziehau 	pkt->rm_dataoffset = 0;
299215516c77SSepherosa Ziehau 	pkt->rm_datalen = m_head->m_pkthdr.len;
2993dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataoffset = 0;
2994dc13fee6SSepherosa Ziehau 	pkt->rm_oobdatalen = 0;
2995dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataelements = 0;
299615516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = sizeof(*pkt);
299715516c77SSepherosa Ziehau 	pkt->rm_pktinfolen = 0;
2998dc13fee6SSepherosa Ziehau 	pkt->rm_vchandle = 0;
2999dc13fee6SSepherosa Ziehau 	pkt->rm_reserved = 0;
300015516c77SSepherosa Ziehau 
300115516c77SSepherosa Ziehau 	if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) {
300215516c77SSepherosa Ziehau 		/*
300315516c77SSepherosa Ziehau 		 * Set the hash value for this packet, so that the host could
300415516c77SSepherosa Ziehau 		 * dispatch the TX done event for this packet back to this TX
300515516c77SSepherosa Ziehau 		 * ring's channel.
300615516c77SSepherosa Ziehau 		 */
300715516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
300815516c77SSepherosa Ziehau 		    HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL);
300915516c77SSepherosa Ziehau 		*pi_data = txr->hn_tx_idx;
301015516c77SSepherosa Ziehau 	}
301115516c77SSepherosa Ziehau 
301215516c77SSepherosa Ziehau 	if (m_head->m_flags & M_VLANTAG) {
301315516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
301415516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
301515516c77SSepherosa Ziehau 		*pi_data = NDIS_VLAN_INFO_MAKE(
301615516c77SSepherosa Ziehau 		    EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag),
301715516c77SSepherosa Ziehau 		    EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag),
301815516c77SSepherosa Ziehau 		    EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag));
301915516c77SSepherosa Ziehau 	}
302015516c77SSepherosa Ziehau 
302115516c77SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
302215516c77SSepherosa Ziehau #if defined(INET6) || defined(INET)
302315516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
302415516c77SSepherosa Ziehau 		    NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO);
302515516c77SSepherosa Ziehau #ifdef INET
302615516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
3027*c49d47daSSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV4(
3028*c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen,
302915516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
303015516c77SSepherosa Ziehau 		}
303115516c77SSepherosa Ziehau #endif
303215516c77SSepherosa Ziehau #if defined(INET6) && defined(INET)
303315516c77SSepherosa Ziehau 		else
303415516c77SSepherosa Ziehau #endif
303515516c77SSepherosa Ziehau #ifdef INET6
303615516c77SSepherosa Ziehau 		{
3037*c49d47daSSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV6(
3038*c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen,
303915516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
304015516c77SSepherosa Ziehau 		}
304115516c77SSepherosa Ziehau #endif
304215516c77SSepherosa Ziehau #endif	/* INET6 || INET */
304315516c77SSepherosa Ziehau 	} else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) {
304415516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
304515516c77SSepherosa Ziehau 		    NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
304615516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
304715516c77SSepherosa Ziehau 		    (CSUM_IP6_TCP | CSUM_IP6_UDP)) {
304815516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV6;
304915516c77SSepherosa Ziehau 		} else {
305015516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV4;
305115516c77SSepherosa Ziehau 			if (m_head->m_pkthdr.csum_flags & CSUM_IP)
305215516c77SSepherosa Ziehau 				*pi_data |= NDIS_TXCSUM_INFO_IPCS;
305315516c77SSepherosa Ziehau 		}
305415516c77SSepherosa Ziehau 
3055*c49d47daSSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
3056*c49d47daSSepherosa Ziehau 		    (CSUM_IP_TCP | CSUM_IP6_TCP)) {
3057*c49d47daSSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_MKTCPCS(
3058*c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen);
3059*c49d47daSSepherosa Ziehau 		} else if (m_head->m_pkthdr.csum_flags &
3060*c49d47daSSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP6_UDP)) {
3061*c49d47daSSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_MKUDPCS(
3062*c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen);
3063*c49d47daSSepherosa Ziehau 		}
306415516c77SSepherosa Ziehau 	}
306515516c77SSepherosa Ziehau 
3066dc13fee6SSepherosa Ziehau 	pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
30678fe90f73SSepherosa Ziehau 	/* Fixup RNDIS packet message total length */
30688fe90f73SSepherosa Ziehau 	pkt->rm_len += pkt_hlen;
306915516c77SSepherosa Ziehau 	/* Convert RNDIS packet message offsets */
30709130c4f7SSepherosa Ziehau 	pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt_hlen);
307115516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset);
307215516c77SSepherosa Ziehau 
307315516c77SSepherosa Ziehau 	/*
30748966e5d5SSepherosa Ziehau 	 * Fast path: Chimney sending.
307515516c77SSepherosa Ziehau 	 */
30768966e5d5SSepherosa Ziehau 	if (chim != NULL) {
3077dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tgt_txd = txd;
3078dc13fee6SSepherosa Ziehau 
3079dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL) {
3080dc13fee6SSepherosa Ziehau 			tgt_txd = txr->hn_agg_txd;
3081dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
3082dc13fee6SSepherosa Ziehau 			*m_head0 = NULL;
3083dc13fee6SSepherosa Ziehau #endif
3084dc13fee6SSepherosa Ziehau 		}
3085dc13fee6SSepherosa Ziehau 
3086dc13fee6SSepherosa Ziehau 		KASSERT(pkt == chim,
3087dc13fee6SSepherosa Ziehau 		    ("RNDIS pkt not in chimney sending buffer"));
3088dc13fee6SSepherosa Ziehau 		KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID,
3089dc13fee6SSepherosa Ziehau 		    ("chimney sending buffer is not used"));
3090dc13fee6SSepherosa Ziehau 		tgt_txd->chim_size += pkt->rm_len;
309115516c77SSepherosa Ziehau 
30928966e5d5SSepherosa Ziehau 		m_copydata(m_head, 0, m_head->m_pkthdr.len,
3093dc13fee6SSepherosa Ziehau 		    ((uint8_t *)chim) + pkt_hlen);
309415516c77SSepherosa Ziehau 
309515516c77SSepherosa Ziehau 		txr->hn_gpa_cnt = 0;
309615516c77SSepherosa Ziehau 		txr->hn_sendpkt = hn_txpkt_chim;
309715516c77SSepherosa Ziehau 		goto done;
309815516c77SSepherosa Ziehau 	}
3099dc13fee6SSepherosa Ziehau 
3100dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc"));
31018966e5d5SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
31028966e5d5SSepherosa Ziehau 	    ("chimney buffer is used"));
31038966e5d5SSepherosa Ziehau 	KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc"));
310415516c77SSepherosa Ziehau 
310515516c77SSepherosa Ziehau 	error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs);
3106dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
310715516c77SSepherosa Ziehau 		int freed;
310815516c77SSepherosa Ziehau 
310915516c77SSepherosa Ziehau 		/*
311015516c77SSepherosa Ziehau 		 * This mbuf is not linked w/ the txd yet, so free it now.
311115516c77SSepherosa Ziehau 		 */
311215516c77SSepherosa Ziehau 		m_freem(m_head);
311315516c77SSepherosa Ziehau 		*m_head0 = NULL;
311415516c77SSepherosa Ziehau 
311515516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
311615516c77SSepherosa Ziehau 		KASSERT(freed != 0,
311715516c77SSepherosa Ziehau 		    ("fail to free txd upon txdma error"));
311815516c77SSepherosa Ziehau 
311915516c77SSepherosa Ziehau 		txr->hn_txdma_failed++;
3120dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
312115516c77SSepherosa Ziehau 		return error;
312215516c77SSepherosa Ziehau 	}
312315516c77SSepherosa Ziehau 	*m_head0 = m_head;
312415516c77SSepherosa Ziehau 
312515516c77SSepherosa Ziehau 	/* +1 RNDIS packet message */
312615516c77SSepherosa Ziehau 	txr->hn_gpa_cnt = nsegs + 1;
312715516c77SSepherosa Ziehau 
312815516c77SSepherosa Ziehau 	/* send packet with page buffer */
312915516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr);
313015516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK;
3131dc13fee6SSepherosa Ziehau 	txr->hn_gpa[0].gpa_len = pkt_hlen;
313215516c77SSepherosa Ziehau 
313315516c77SSepherosa Ziehau 	/*
313415516c77SSepherosa Ziehau 	 * Fill the page buffers with mbuf info after the page
313515516c77SSepherosa Ziehau 	 * buffer for RNDIS packet message.
313615516c77SSepherosa Ziehau 	 */
313715516c77SSepherosa Ziehau 	for (i = 0; i < nsegs; ++i) {
313815516c77SSepherosa Ziehau 		struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1];
313915516c77SSepherosa Ziehau 
314015516c77SSepherosa Ziehau 		gpa->gpa_page = atop(segs[i].ds_addr);
314115516c77SSepherosa Ziehau 		gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK;
314215516c77SSepherosa Ziehau 		gpa->gpa_len = segs[i].ds_len;
314315516c77SSepherosa Ziehau 	}
314415516c77SSepherosa Ziehau 
314515516c77SSepherosa Ziehau 	txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
314615516c77SSepherosa Ziehau 	txd->chim_size = 0;
314715516c77SSepherosa Ziehau 	txr->hn_sendpkt = hn_txpkt_sglist;
314815516c77SSepherosa Ziehau done:
314915516c77SSepherosa Ziehau 	txd->m = m_head;
315015516c77SSepherosa Ziehau 
315115516c77SSepherosa Ziehau 	/* Set the completion routine */
315215516c77SSepherosa Ziehau 	hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd);
315315516c77SSepherosa Ziehau 
3154dc13fee6SSepherosa Ziehau 	/* Update temporary stats for later use. */
3155dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts++;
3156dc13fee6SSepherosa Ziehau 	txr->hn_stat_size += m_head->m_pkthdr.len;
3157dc13fee6SSepherosa Ziehau 	if (m_head->m_flags & M_MCAST)
3158dc13fee6SSepherosa Ziehau 		txr->hn_stat_mcasts++;
3159dc13fee6SSepherosa Ziehau 
316015516c77SSepherosa Ziehau 	return 0;
316115516c77SSepherosa Ziehau }
316215516c77SSepherosa Ziehau 
316315516c77SSepherosa Ziehau /*
316415516c77SSepherosa Ziehau  * NOTE:
316515516c77SSepherosa Ziehau  * If this function fails, then txd will be freed, but the mbuf
316615516c77SSepherosa Ziehau  * associated w/ the txd will _not_ be freed.
316715516c77SSepherosa Ziehau  */
316815516c77SSepherosa Ziehau static int
316915516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd)
317015516c77SSepherosa Ziehau {
31718e7d3136SSepherosa Ziehau 	int error, send_failed = 0, has_bpf;
317215516c77SSepherosa Ziehau 
317315516c77SSepherosa Ziehau again:
31748e7d3136SSepherosa Ziehau 	has_bpf = bpf_peers_present(ifp->if_bpf);
31758e7d3136SSepherosa Ziehau 	if (has_bpf) {
317615516c77SSepherosa Ziehau 		/*
31778e7d3136SSepherosa Ziehau 		 * Make sure that this txd and any aggregated txds are not
31788e7d3136SSepherosa Ziehau 		 * freed before ETHER_BPF_MTAP.
317915516c77SSepherosa Ziehau 		 */
318015516c77SSepherosa Ziehau 		hn_txdesc_hold(txd);
31818e7d3136SSepherosa Ziehau 	}
318215516c77SSepherosa Ziehau 	error = txr->hn_sendpkt(txr, txd);
318315516c77SSepherosa Ziehau 	if (!error) {
31848e7d3136SSepherosa Ziehau 		if (has_bpf) {
3185dc13fee6SSepherosa Ziehau 			const struct hn_txdesc *tmp_txd;
3186dc13fee6SSepherosa Ziehau 
318715516c77SSepherosa Ziehau 			ETHER_BPF_MTAP(ifp, txd->m);
3188dc13fee6SSepherosa Ziehau 			STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link)
3189dc13fee6SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, tmp_txd->m);
3190dc13fee6SSepherosa Ziehau 		}
3191dc13fee6SSepherosa Ziehau 
3192dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts);
319323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
319423bf9e15SSepherosa Ziehau 		if (!hn_use_if_start)
319523bf9e15SSepherosa Ziehau #endif
319623bf9e15SSepherosa Ziehau 		{
319715516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OBYTES,
3198dc13fee6SSepherosa Ziehau 			    txr->hn_stat_size);
3199dc13fee6SSepherosa Ziehau 			if (txr->hn_stat_mcasts != 0) {
3200dc13fee6SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OMCASTS,
3201dc13fee6SSepherosa Ziehau 				    txr->hn_stat_mcasts);
320215516c77SSepherosa Ziehau 			}
3203dc13fee6SSepherosa Ziehau 		}
3204dc13fee6SSepherosa Ziehau 		txr->hn_pkts += txr->hn_stat_pkts;
3205dc13fee6SSepherosa Ziehau 		txr->hn_sends++;
320615516c77SSepherosa Ziehau 	}
32078e7d3136SSepherosa Ziehau 	if (has_bpf)
320815516c77SSepherosa Ziehau 		hn_txdesc_put(txr, txd);
320915516c77SSepherosa Ziehau 
321015516c77SSepherosa Ziehau 	if (__predict_false(error)) {
321115516c77SSepherosa Ziehau 		int freed;
321215516c77SSepherosa Ziehau 
321315516c77SSepherosa Ziehau 		/*
321415516c77SSepherosa Ziehau 		 * This should "really rarely" happen.
321515516c77SSepherosa Ziehau 		 *
321615516c77SSepherosa Ziehau 		 * XXX Too many RX to be acked or too many sideband
321715516c77SSepherosa Ziehau 		 * commands to run?  Ask netvsc_channel_rollup()
321815516c77SSepherosa Ziehau 		 * to kick start later.
321915516c77SSepherosa Ziehau 		 */
322015516c77SSepherosa Ziehau 		txr->hn_has_txeof = 1;
322115516c77SSepherosa Ziehau 		if (!send_failed) {
322215516c77SSepherosa Ziehau 			txr->hn_send_failed++;
322315516c77SSepherosa Ziehau 			send_failed = 1;
322415516c77SSepherosa Ziehau 			/*
322515516c77SSepherosa Ziehau 			 * Try sending again after set hn_has_txeof;
322615516c77SSepherosa Ziehau 			 * in case that we missed the last
322715516c77SSepherosa Ziehau 			 * netvsc_channel_rollup().
322815516c77SSepherosa Ziehau 			 */
322915516c77SSepherosa Ziehau 			goto again;
323015516c77SSepherosa Ziehau 		}
323115516c77SSepherosa Ziehau 		if_printf(ifp, "send failed\n");
323215516c77SSepherosa Ziehau 
323315516c77SSepherosa Ziehau 		/*
323415516c77SSepherosa Ziehau 		 * Caller will perform further processing on the
323515516c77SSepherosa Ziehau 		 * associated mbuf, so don't free it in hn_txdesc_put();
323615516c77SSepherosa Ziehau 		 * only unload it from the DMA map in hn_txdesc_put(),
323715516c77SSepherosa Ziehau 		 * if it was loaded.
323815516c77SSepherosa Ziehau 		 */
323915516c77SSepherosa Ziehau 		txd->m = NULL;
324015516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
324115516c77SSepherosa Ziehau 		KASSERT(freed != 0,
324215516c77SSepherosa Ziehau 		    ("fail to free txd upon send error"));
324315516c77SSepherosa Ziehau 
324415516c77SSepherosa Ziehau 		txr->hn_send_failed++;
324515516c77SSepherosa Ziehau 	}
3246dc13fee6SSepherosa Ziehau 
3247dc13fee6SSepherosa Ziehau 	/* Reset temporary stats, after this sending is done. */
3248dc13fee6SSepherosa Ziehau 	txr->hn_stat_size = 0;
3249dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts = 0;
3250dc13fee6SSepherosa Ziehau 	txr->hn_stat_mcasts = 0;
3251dc13fee6SSepherosa Ziehau 
3252dc13fee6SSepherosa Ziehau 	return (error);
325315516c77SSepherosa Ziehau }
325415516c77SSepherosa Ziehau 
325515516c77SSepherosa Ziehau /*
325615516c77SSepherosa Ziehau  * Append the specified data to the indicated mbuf chain,
325715516c77SSepherosa Ziehau  * Extend the mbuf chain if the new data does not fit in
325815516c77SSepherosa Ziehau  * existing space.
325915516c77SSepherosa Ziehau  *
326015516c77SSepherosa Ziehau  * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c.
326115516c77SSepherosa Ziehau  * There should be an equivalent in the kernel mbuf code,
326215516c77SSepherosa Ziehau  * but there does not appear to be one yet.
326315516c77SSepherosa Ziehau  *
326415516c77SSepherosa Ziehau  * Differs from m_append() in that additional mbufs are
326515516c77SSepherosa Ziehau  * allocated with cluster size MJUMPAGESIZE, and filled
326615516c77SSepherosa Ziehau  * accordingly.
326715516c77SSepherosa Ziehau  *
326815516c77SSepherosa Ziehau  * Return 1 if able to complete the job; otherwise 0.
326915516c77SSepherosa Ziehau  */
327015516c77SSepherosa Ziehau static int
327115516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp)
327215516c77SSepherosa Ziehau {
327315516c77SSepherosa Ziehau 	struct mbuf *m, *n;
327415516c77SSepherosa Ziehau 	int remainder, space;
327515516c77SSepherosa Ziehau 
327615516c77SSepherosa Ziehau 	for (m = m0; m->m_next != NULL; m = m->m_next)
327715516c77SSepherosa Ziehau 		;
327815516c77SSepherosa Ziehau 	remainder = len;
327915516c77SSepherosa Ziehau 	space = M_TRAILINGSPACE(m);
328015516c77SSepherosa Ziehau 	if (space > 0) {
328115516c77SSepherosa Ziehau 		/*
328215516c77SSepherosa Ziehau 		 * Copy into available space.
328315516c77SSepherosa Ziehau 		 */
328415516c77SSepherosa Ziehau 		if (space > remainder)
328515516c77SSepherosa Ziehau 			space = remainder;
328615516c77SSepherosa Ziehau 		bcopy(cp, mtod(m, caddr_t) + m->m_len, space);
328715516c77SSepherosa Ziehau 		m->m_len += space;
328815516c77SSepherosa Ziehau 		cp += space;
328915516c77SSepherosa Ziehau 		remainder -= space;
329015516c77SSepherosa Ziehau 	}
329115516c77SSepherosa Ziehau 	while (remainder > 0) {
329215516c77SSepherosa Ziehau 		/*
329315516c77SSepherosa Ziehau 		 * Allocate a new mbuf; could check space
329415516c77SSepherosa Ziehau 		 * and allocate a cluster instead.
329515516c77SSepherosa Ziehau 		 */
329615516c77SSepherosa Ziehau 		n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE);
329715516c77SSepherosa Ziehau 		if (n == NULL)
329815516c77SSepherosa Ziehau 			break;
329915516c77SSepherosa Ziehau 		n->m_len = min(MJUMPAGESIZE, remainder);
330015516c77SSepherosa Ziehau 		bcopy(cp, mtod(n, caddr_t), n->m_len);
330115516c77SSepherosa Ziehau 		cp += n->m_len;
330215516c77SSepherosa Ziehau 		remainder -= n->m_len;
330315516c77SSepherosa Ziehau 		m->m_next = n;
330415516c77SSepherosa Ziehau 		m = n;
330515516c77SSepherosa Ziehau 	}
330615516c77SSepherosa Ziehau 	if (m0->m_flags & M_PKTHDR)
330715516c77SSepherosa Ziehau 		m0->m_pkthdr.len += len - remainder;
330815516c77SSepherosa Ziehau 
330915516c77SSepherosa Ziehau 	return (remainder == 0);
331015516c77SSepherosa Ziehau }
331115516c77SSepherosa Ziehau 
331215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
331315516c77SSepherosa Ziehau static __inline int
331415516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m)
331515516c77SSepherosa Ziehau {
331615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
331715516c77SSepherosa Ziehau 	if (hn_lro_mbufq_depth) {
331815516c77SSepherosa Ziehau 		tcp_lro_queue_mbuf(lc, m);
331915516c77SSepherosa Ziehau 		return 0;
332015516c77SSepherosa Ziehau 	}
332115516c77SSepherosa Ziehau #endif
332215516c77SSepherosa Ziehau 	return tcp_lro_rx(lc, m, 0);
332315516c77SSepherosa Ziehau }
332415516c77SSepherosa Ziehau #endif
332515516c77SSepherosa Ziehau 
332615516c77SSepherosa Ziehau static int
332715516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
332815516c77SSepherosa Ziehau     const struct hn_rxinfo *info)
332915516c77SSepherosa Ziehau {
3330a97fff19SSepherosa Ziehau 	struct ifnet *ifp, *hn_ifp = rxr->hn_ifp;
333115516c77SSepherosa Ziehau 	struct mbuf *m_new;
3332642ec226SSepherosa Ziehau 	int size, do_lro = 0, do_csum = 1, is_vf = 0;
3333642ec226SSepherosa Ziehau 	int hash_type = M_HASHTYPE_NONE;
333415516c77SSepherosa Ziehau 
3335642ec226SSepherosa Ziehau 	ifp = hn_ifp;
3336642ec226SSepherosa Ziehau 	if (rxr->hn_rxvf_ifp != NULL) {
3337a97fff19SSepherosa Ziehau 		/*
3338642ec226SSepherosa Ziehau 		 * Non-transparent mode VF; pretend this packet is from
3339642ec226SSepherosa Ziehau 		 * the VF.
3340a97fff19SSepherosa Ziehau 		 */
3341642ec226SSepherosa Ziehau 		ifp = rxr->hn_rxvf_ifp;
3342642ec226SSepherosa Ziehau 		is_vf = 1;
3343642ec226SSepherosa Ziehau 	} else if (rxr->hn_rx_flags & HN_RX_FLAG_XPNT_VF) {
3344642ec226SSepherosa Ziehau 		/* Transparent mode VF. */
3345642ec226SSepherosa Ziehau 		is_vf = 1;
3346642ec226SSepherosa Ziehau 	}
33475bdfd3fdSDexuan Cui 
3348b3b75d9cSSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
3349b3b75d9cSSepherosa Ziehau 		/*
3350b3b75d9cSSepherosa Ziehau 		 * NOTE:
3351b3b75d9cSSepherosa Ziehau 		 * See the NOTE of hn_rndis_init_fixat().  This
3352b3b75d9cSSepherosa Ziehau 		 * function can be reached, immediately after the
3353b3b75d9cSSepherosa Ziehau 		 * RNDIS is initialized but before the ifnet is
3354b3b75d9cSSepherosa Ziehau 		 * setup on the hn_attach() path; drop the unexpected
3355b3b75d9cSSepherosa Ziehau 		 * packets.
3356b3b75d9cSSepherosa Ziehau 		 */
3357b3b75d9cSSepherosa Ziehau 		return (0);
3358b3b75d9cSSepherosa Ziehau 	}
3359b3b75d9cSSepherosa Ziehau 
3360a97fff19SSepherosa Ziehau 	if (__predict_false(dlen < ETHER_HDR_LEN)) {
3361a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IERRORS, 1);
3362a97fff19SSepherosa Ziehau 		return (0);
3363a97fff19SSepherosa Ziehau 	}
3364a97fff19SSepherosa Ziehau 
3365c927d681SDexuan Cui 	if (dlen <= MHLEN) {
336615516c77SSepherosa Ziehau 		m_new = m_gethdr(M_NOWAIT, MT_DATA);
336715516c77SSepherosa Ziehau 		if (m_new == NULL) {
3368a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1);
336915516c77SSepherosa Ziehau 			return (0);
337015516c77SSepherosa Ziehau 		}
337115516c77SSepherosa Ziehau 		memcpy(mtod(m_new, void *), data, dlen);
337215516c77SSepherosa Ziehau 		m_new->m_pkthdr.len = m_new->m_len = dlen;
337315516c77SSepherosa Ziehau 		rxr->hn_small_pkts++;
337415516c77SSepherosa Ziehau 	} else {
337515516c77SSepherosa Ziehau 		/*
337615516c77SSepherosa Ziehau 		 * Get an mbuf with a cluster.  For packets 2K or less,
337715516c77SSepherosa Ziehau 		 * get a standard 2K cluster.  For anything larger, get a
337815516c77SSepherosa Ziehau 		 * 4K cluster.  Any buffers larger than 4K can cause problems
337915516c77SSepherosa Ziehau 		 * if looped around to the Hyper-V TX channel, so avoid them.
338015516c77SSepherosa Ziehau 		 */
338115516c77SSepherosa Ziehau 		size = MCLBYTES;
338215516c77SSepherosa Ziehau 		if (dlen > MCLBYTES) {
338315516c77SSepherosa Ziehau 			/* 4096 */
338415516c77SSepherosa Ziehau 			size = MJUMPAGESIZE;
338515516c77SSepherosa Ziehau 		}
338615516c77SSepherosa Ziehau 
338715516c77SSepherosa Ziehau 		m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size);
338815516c77SSepherosa Ziehau 		if (m_new == NULL) {
3389a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1);
339015516c77SSepherosa Ziehau 			return (0);
339115516c77SSepherosa Ziehau 		}
339215516c77SSepherosa Ziehau 
339315516c77SSepherosa Ziehau 		hv_m_append(m_new, dlen, data);
339415516c77SSepherosa Ziehau 	}
339515516c77SSepherosa Ziehau 	m_new->m_pkthdr.rcvif = ifp;
339615516c77SSepherosa Ziehau 
3397a97fff19SSepherosa Ziehau 	if (__predict_false((hn_ifp->if_capenable & IFCAP_RXCSUM) == 0))
339815516c77SSepherosa Ziehau 		do_csum = 0;
339915516c77SSepherosa Ziehau 
340015516c77SSepherosa Ziehau 	/* receive side checksum offload */
340115516c77SSepherosa Ziehau 	if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) {
340215516c77SSepherosa Ziehau 		/* IP csum offload */
340315516c77SSepherosa Ziehau 		if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) {
340415516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
340515516c77SSepherosa Ziehau 			    (CSUM_IP_CHECKED | CSUM_IP_VALID);
340615516c77SSepherosa Ziehau 			rxr->hn_csum_ip++;
340715516c77SSepherosa Ziehau 		}
340815516c77SSepherosa Ziehau 
340915516c77SSepherosa Ziehau 		/* TCP/UDP csum offload */
341015516c77SSepherosa Ziehau 		if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK |
341115516c77SSepherosa Ziehau 		     NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) {
341215516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
341315516c77SSepherosa Ziehau 			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
341415516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_data = 0xffff;
341515516c77SSepherosa Ziehau 			if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK)
341615516c77SSepherosa Ziehau 				rxr->hn_csum_tcp++;
341715516c77SSepherosa Ziehau 			else
341815516c77SSepherosa Ziehau 				rxr->hn_csum_udp++;
341915516c77SSepherosa Ziehau 		}
342015516c77SSepherosa Ziehau 
342115516c77SSepherosa Ziehau 		/*
342215516c77SSepherosa Ziehau 		 * XXX
342315516c77SSepherosa Ziehau 		 * As of this write (Oct 28th, 2016), host side will turn
342415516c77SSepherosa Ziehau 		 * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so
342515516c77SSepherosa Ziehau 		 * the do_lro setting here is actually _not_ accurate.  We
342615516c77SSepherosa Ziehau 		 * depend on the RSS hash type check to reset do_lro.
342715516c77SSepherosa Ziehau 		 */
342815516c77SSepherosa Ziehau 		if ((info->csum_info &
342915516c77SSepherosa Ziehau 		     (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) ==
343015516c77SSepherosa Ziehau 		    (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK))
343115516c77SSepherosa Ziehau 			do_lro = 1;
343215516c77SSepherosa Ziehau 	} else {
343315516c77SSepherosa Ziehau 		const struct ether_header *eh;
343415516c77SSepherosa Ziehau 		uint16_t etype;
343515516c77SSepherosa Ziehau 		int hoff;
343615516c77SSepherosa Ziehau 
343715516c77SSepherosa Ziehau 		hoff = sizeof(*eh);
3438a97fff19SSepherosa Ziehau 		/* Checked at the beginning of this function. */
3439a97fff19SSepherosa Ziehau 		KASSERT(m_new->m_len >= hoff, ("not ethernet frame"));
3440a97fff19SSepherosa Ziehau 
344115516c77SSepherosa Ziehau 		eh = mtod(m_new, struct ether_header *);
344215516c77SSepherosa Ziehau 		etype = ntohs(eh->ether_type);
344315516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_VLAN) {
344415516c77SSepherosa Ziehau 			const struct ether_vlan_header *evl;
344515516c77SSepherosa Ziehau 
344615516c77SSepherosa Ziehau 			hoff = sizeof(*evl);
344715516c77SSepherosa Ziehau 			if (m_new->m_len < hoff)
344815516c77SSepherosa Ziehau 				goto skip;
344915516c77SSepherosa Ziehau 			evl = mtod(m_new, struct ether_vlan_header *);
345015516c77SSepherosa Ziehau 			etype = ntohs(evl->evl_proto);
345115516c77SSepherosa Ziehau 		}
345215516c77SSepherosa Ziehau 
345315516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_IP) {
345415516c77SSepherosa Ziehau 			int pr;
345515516c77SSepherosa Ziehau 
345615516c77SSepherosa Ziehau 			pr = hn_check_iplen(m_new, hoff);
345715516c77SSepherosa Ziehau 			if (pr == IPPROTO_TCP) {
345815516c77SSepherosa Ziehau 				if (do_csum &&
345915516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
346015516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_TCP)) {
346115516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
346215516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
346315516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
346415516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
346515516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
346615516c77SSepherosa Ziehau 				}
346715516c77SSepherosa Ziehau 				do_lro = 1;
346815516c77SSepherosa Ziehau 			} else if (pr == IPPROTO_UDP) {
346915516c77SSepherosa Ziehau 				if (do_csum &&
347015516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
347115516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_UDP)) {
347215516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
347315516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
347415516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
347515516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
347615516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
347715516c77SSepherosa Ziehau 				}
347815516c77SSepherosa Ziehau 			} else if (pr != IPPROTO_DONE && do_csum &&
347915516c77SSepherosa Ziehau 			    (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) {
348015516c77SSepherosa Ziehau 				rxr->hn_csum_trusted++;
348115516c77SSepherosa Ziehau 				m_new->m_pkthdr.csum_flags |=
348215516c77SSepherosa Ziehau 				    (CSUM_IP_CHECKED | CSUM_IP_VALID);
348315516c77SSepherosa Ziehau 			}
348415516c77SSepherosa Ziehau 		}
348515516c77SSepherosa Ziehau 	}
348615516c77SSepherosa Ziehau skip:
348715516c77SSepherosa Ziehau 	if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) {
348815516c77SSepherosa Ziehau 		m_new->m_pkthdr.ether_vtag = EVL_MAKETAG(
348915516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_ID(info->vlan_info),
349015516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_PRI(info->vlan_info),
349115516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_CFI(info->vlan_info));
349215516c77SSepherosa Ziehau 		m_new->m_flags |= M_VLANTAG;
349315516c77SSepherosa Ziehau 	}
349415516c77SSepherosa Ziehau 
3495a97fff19SSepherosa Ziehau 	/*
3496a97fff19SSepherosa Ziehau 	 * If VF is activated (tranparent/non-transparent mode does not
3497a97fff19SSepherosa Ziehau 	 * matter here).
3498a97fff19SSepherosa Ziehau 	 *
3499a97fff19SSepherosa Ziehau 	 * - Disable LRO
3500a97fff19SSepherosa Ziehau 	 *
3501a97fff19SSepherosa Ziehau 	 *   hn(4) will only receive broadcast packets, multicast packets,
3502a97fff19SSepherosa Ziehau 	 *   TCP SYN and SYN|ACK (in Azure), LRO is useless for these
3503a97fff19SSepherosa Ziehau 	 *   packet types.
3504a97fff19SSepherosa Ziehau 	 *
3505a97fff19SSepherosa Ziehau 	 *   For non-transparent, we definitely _cannot_ enable LRO at
3506a97fff19SSepherosa Ziehau 	 *   all, since the LRO flush will use hn(4) as the receiving
3507a97fff19SSepherosa Ziehau 	 *   interface; i.e. hn_ifp->if_input(hn_ifp, m).
3508a97fff19SSepherosa Ziehau 	 */
3509642ec226SSepherosa Ziehau 	if (is_vf)
3510642ec226SSepherosa Ziehau 		do_lro = 0;
3511a97fff19SSepherosa Ziehau 
3512642ec226SSepherosa Ziehau 	/*
3513642ec226SSepherosa Ziehau 	 * If VF is activated (tranparent/non-transparent mode does not
3514642ec226SSepherosa Ziehau 	 * matter here), do _not_ mess with unsupported hash types or
3515642ec226SSepherosa Ziehau 	 * functions.
3516642ec226SSepherosa Ziehau 	 */
351715516c77SSepherosa Ziehau 	if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) {
351815516c77SSepherosa Ziehau 		rxr->hn_rss_pkts++;
351915516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = info->hash_value;
3520642ec226SSepherosa Ziehau 		if (!is_vf)
352115516c77SSepherosa Ziehau 			hash_type = M_HASHTYPE_OPAQUE_HASH;
352215516c77SSepherosa Ziehau 		if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) ==
352315516c77SSepherosa Ziehau 		    NDIS_HASH_FUNCTION_TOEPLITZ) {
3524642ec226SSepherosa Ziehau 			uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK &
3525642ec226SSepherosa Ziehau 			    rxr->hn_mbuf_hash);
352615516c77SSepherosa Ziehau 
352715516c77SSepherosa Ziehau 			/*
352815516c77SSepherosa Ziehau 			 * NOTE:
352915516c77SSepherosa Ziehau 			 * do_lro is resetted, if the hash types are not TCP
353015516c77SSepherosa Ziehau 			 * related.  See the comment in the above csum_flags
353115516c77SSepherosa Ziehau 			 * setup section.
353215516c77SSepherosa Ziehau 			 */
353315516c77SSepherosa Ziehau 			switch (type) {
353415516c77SSepherosa Ziehau 			case NDIS_HASH_IPV4:
353515516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV4;
353615516c77SSepherosa Ziehau 				do_lro = 0;
353715516c77SSepherosa Ziehau 				break;
353815516c77SSepherosa Ziehau 
353915516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV4:
354015516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV4;
354115516c77SSepherosa Ziehau 				break;
354215516c77SSepherosa Ziehau 
354315516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6:
354415516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6;
354515516c77SSepherosa Ziehau 				do_lro = 0;
354615516c77SSepherosa Ziehau 				break;
354715516c77SSepherosa Ziehau 
354815516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6_EX:
354915516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6_EX;
355015516c77SSepherosa Ziehau 				do_lro = 0;
355115516c77SSepherosa Ziehau 				break;
355215516c77SSepherosa Ziehau 
355315516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6:
355415516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6;
355515516c77SSepherosa Ziehau 				break;
355615516c77SSepherosa Ziehau 
355715516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6_EX:
355815516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX;
355915516c77SSepherosa Ziehau 				break;
356015516c77SSepherosa Ziehau 			}
356115516c77SSepherosa Ziehau 		}
3562642ec226SSepherosa Ziehau 	} else if (!is_vf) {
356315516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
356415516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE;
356515516c77SSepherosa Ziehau 	}
356615516c77SSepherosa Ziehau 	M_HASHTYPE_SET(m_new, hash_type);
356715516c77SSepherosa Ziehau 
3568a97fff19SSepherosa Ziehau 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
3569a97fff19SSepherosa Ziehau 	if (hn_ifp != ifp) {
3570a97fff19SSepherosa Ziehau 		const struct ether_header *eh;
3571a97fff19SSepherosa Ziehau 
357215516c77SSepherosa Ziehau 		/*
3573a97fff19SSepherosa Ziehau 		 * Non-transparent mode VF is activated.
357415516c77SSepherosa Ziehau 		 */
357515516c77SSepherosa Ziehau 
3576a97fff19SSepherosa Ziehau 		/*
3577a97fff19SSepherosa Ziehau 		 * Allow tapping on hn(4).
3578a97fff19SSepherosa Ziehau 		 */
3579a97fff19SSepherosa Ziehau 		ETHER_BPF_MTAP(hn_ifp, m_new);
3580a97fff19SSepherosa Ziehau 
3581a97fff19SSepherosa Ziehau 		/*
3582a97fff19SSepherosa Ziehau 		 * Update hn(4)'s stats.
3583a97fff19SSepherosa Ziehau 		 */
3584a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1);
3585a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IBYTES, m_new->m_pkthdr.len);
3586a97fff19SSepherosa Ziehau 		/* Checked at the beginning of this function. */
3587a97fff19SSepherosa Ziehau 		KASSERT(m_new->m_len >= ETHER_HDR_LEN, ("not ethernet frame"));
3588a97fff19SSepherosa Ziehau 		eh = mtod(m_new, struct ether_header *);
3589a97fff19SSepherosa Ziehau 		if (ETHER_IS_MULTICAST(eh->ether_dhost))
3590a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IMCASTS, 1);
3591a97fff19SSepherosa Ziehau 	}
359215516c77SSepherosa Ziehau 	rxr->hn_pkts++;
359315516c77SSepherosa Ziehau 
3594a97fff19SSepherosa Ziehau 	if ((hn_ifp->if_capenable & IFCAP_LRO) && do_lro) {
359515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
359615516c77SSepherosa Ziehau 		struct lro_ctrl *lro = &rxr->hn_lro;
359715516c77SSepherosa Ziehau 
359815516c77SSepherosa Ziehau 		if (lro->lro_cnt) {
359915516c77SSepherosa Ziehau 			rxr->hn_lro_tried++;
360015516c77SSepherosa Ziehau 			if (hn_lro_rx(lro, m_new) == 0) {
360115516c77SSepherosa Ziehau 				/* DONE! */
360215516c77SSepherosa Ziehau 				return 0;
360315516c77SSepherosa Ziehau 			}
360415516c77SSepherosa Ziehau 		}
360515516c77SSepherosa Ziehau #endif
360615516c77SSepherosa Ziehau 	}
3607a97fff19SSepherosa Ziehau 	ifp->if_input(ifp, m_new);
360815516c77SSepherosa Ziehau 
360915516c77SSepherosa Ziehau 	return (0);
361015516c77SSepherosa Ziehau }
361115516c77SSepherosa Ziehau 
361215516c77SSepherosa Ziehau static int
361315516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
361415516c77SSepherosa Ziehau {
361515516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
36169c6cae24SSepherosa Ziehau 	struct ifreq *ifr = (struct ifreq *)data, ifr_vf;
36179c6cae24SSepherosa Ziehau 	struct ifnet *vf_ifp;
361815516c77SSepherosa Ziehau 	int mask, error = 0;
36198c068aa5SSepherosa Ziehau 	struct ifrsskey *ifrk;
36208c068aa5SSepherosa Ziehau 	struct ifrsshash *ifrh;
3621eb2fe044SSepherosa Ziehau 	uint32_t mtu;
362215516c77SSepherosa Ziehau 
362315516c77SSepherosa Ziehau 	switch (cmd) {
362415516c77SSepherosa Ziehau 	case SIOCSIFMTU:
362515516c77SSepherosa Ziehau 		if (ifr->ifr_mtu > HN_MTU_MAX) {
362615516c77SSepherosa Ziehau 			error = EINVAL;
362715516c77SSepherosa Ziehau 			break;
362815516c77SSepherosa Ziehau 		}
362915516c77SSepherosa Ziehau 
363015516c77SSepherosa Ziehau 		HN_LOCK(sc);
363115516c77SSepherosa Ziehau 
363215516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
363315516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
363415516c77SSepherosa Ziehau 			break;
363515516c77SSepherosa Ziehau 		}
363615516c77SSepherosa Ziehau 
363715516c77SSepherosa Ziehau 		if ((sc->hn_caps & HN_CAP_MTU) == 0) {
363815516c77SSepherosa Ziehau 			/* Can't change MTU */
363915516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
364015516c77SSepherosa Ziehau 			error = EOPNOTSUPP;
364115516c77SSepherosa Ziehau 			break;
364215516c77SSepherosa Ziehau 		}
364315516c77SSepherosa Ziehau 
364415516c77SSepherosa Ziehau 		if (ifp->if_mtu == ifr->ifr_mtu) {
364515516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
364615516c77SSepherosa Ziehau 			break;
364715516c77SSepherosa Ziehau 		}
364815516c77SSepherosa Ziehau 
36499c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
36509c6cae24SSepherosa Ziehau 			vf_ifp = sc->hn_vf_ifp;
36519c6cae24SSepherosa Ziehau 			ifr_vf = *ifr;
36529c6cae24SSepherosa Ziehau 			strlcpy(ifr_vf.ifr_name, vf_ifp->if_xname,
36539c6cae24SSepherosa Ziehau 			    sizeof(ifr_vf.ifr_name));
36549c6cae24SSepherosa Ziehau 			error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU,
36559c6cae24SSepherosa Ziehau 			    (caddr_t)&ifr_vf);
36569c6cae24SSepherosa Ziehau 			if (error) {
36579c6cae24SSepherosa Ziehau 				HN_UNLOCK(sc);
36589c6cae24SSepherosa Ziehau 				if_printf(ifp, "%s SIOCSIFMTU %d failed: %d\n",
36599c6cae24SSepherosa Ziehau 				    vf_ifp->if_xname, ifr->ifr_mtu, error);
36609c6cae24SSepherosa Ziehau 				break;
36619c6cae24SSepherosa Ziehau 			}
36629c6cae24SSepherosa Ziehau 		}
36639c6cae24SSepherosa Ziehau 
366415516c77SSepherosa Ziehau 		/*
366515516c77SSepherosa Ziehau 		 * Suspend this interface before the synthetic parts
366615516c77SSepherosa Ziehau 		 * are ripped.
366715516c77SSepherosa Ziehau 		 */
366815516c77SSepherosa Ziehau 		hn_suspend(sc);
366915516c77SSepherosa Ziehau 
367015516c77SSepherosa Ziehau 		/*
367115516c77SSepherosa Ziehau 		 * Detach the synthetics parts, i.e. NVS and RNDIS.
367215516c77SSepherosa Ziehau 		 */
367315516c77SSepherosa Ziehau 		hn_synth_detach(sc);
367415516c77SSepherosa Ziehau 
367515516c77SSepherosa Ziehau 		/*
367615516c77SSepherosa Ziehau 		 * Reattach the synthetic parts, i.e. NVS and RNDIS,
367715516c77SSepherosa Ziehau 		 * with the new MTU setting.
367815516c77SSepherosa Ziehau 		 */
367915516c77SSepherosa Ziehau 		error = hn_synth_attach(sc, ifr->ifr_mtu);
368015516c77SSepherosa Ziehau 		if (error) {
368115516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
368215516c77SSepherosa Ziehau 			break;
368315516c77SSepherosa Ziehau 		}
368415516c77SSepherosa Ziehau 
3685eb2fe044SSepherosa Ziehau 		error = hn_rndis_get_mtu(sc, &mtu);
3686eb2fe044SSepherosa Ziehau 		if (error)
3687eb2fe044SSepherosa Ziehau 			mtu = ifr->ifr_mtu;
3688eb2fe044SSepherosa Ziehau 		else if (bootverbose)
3689eb2fe044SSepherosa Ziehau 			if_printf(ifp, "RNDIS mtu %u\n", mtu);
3690eb2fe044SSepherosa Ziehau 
369115516c77SSepherosa Ziehau 		/*
369215516c77SSepherosa Ziehau 		 * Commit the requested MTU, after the synthetic parts
369315516c77SSepherosa Ziehau 		 * have been successfully attached.
369415516c77SSepherosa Ziehau 		 */
3695eb2fe044SSepherosa Ziehau 		if (mtu >= ifr->ifr_mtu) {
3696eb2fe044SSepherosa Ziehau 			mtu = ifr->ifr_mtu;
3697eb2fe044SSepherosa Ziehau 		} else {
3698eb2fe044SSepherosa Ziehau 			if_printf(ifp, "fixup mtu %d -> %u\n",
3699eb2fe044SSepherosa Ziehau 			    ifr->ifr_mtu, mtu);
3700eb2fe044SSepherosa Ziehau 		}
3701eb2fe044SSepherosa Ziehau 		ifp->if_mtu = mtu;
370215516c77SSepherosa Ziehau 
370315516c77SSepherosa Ziehau 		/*
37049c6cae24SSepherosa Ziehau 		 * Synthetic parts' reattach may change the chimney
37059c6cae24SSepherosa Ziehau 		 * sending size; update it.
370615516c77SSepherosa Ziehau 		 */
370715516c77SSepherosa Ziehau 		if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax)
370815516c77SSepherosa Ziehau 			hn_set_chim_size(sc, sc->hn_chim_szmax);
37099c6cae24SSepherosa Ziehau 
37109c6cae24SSepherosa Ziehau 		/*
37119c6cae24SSepherosa Ziehau 		 * Make sure that various parameters based on MTU are
37129c6cae24SSepherosa Ziehau 		 * still valid, after the MTU change.
37139c6cae24SSepherosa Ziehau 		 */
37149c6cae24SSepherosa Ziehau 		hn_mtu_change_fixup(sc);
371515516c77SSepherosa Ziehau 
371615516c77SSepherosa Ziehau 		/*
371715516c77SSepherosa Ziehau 		 * All done!  Resume the interface now.
371815516c77SSepherosa Ziehau 		 */
371915516c77SSepherosa Ziehau 		hn_resume(sc);
372015516c77SSepherosa Ziehau 
3721d0cd8231SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXVF) ||
3722d0cd8231SSepherosa Ziehau 		    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
37239c6cae24SSepherosa Ziehau 			/*
37249c6cae24SSepherosa Ziehau 			 * Since we have reattached the NVS part,
37259c6cae24SSepherosa Ziehau 			 * change the datapath to VF again; in case
37269c6cae24SSepherosa Ziehau 			 * that it is lost, after the NVS was detached.
37279c6cae24SSepherosa Ziehau 			 */
37289c6cae24SSepherosa Ziehau 			hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF);
37299c6cae24SSepherosa Ziehau 		}
37309c6cae24SSepherosa Ziehau 
373115516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
373215516c77SSepherosa Ziehau 		break;
373315516c77SSepherosa Ziehau 
373415516c77SSepherosa Ziehau 	case SIOCSIFFLAGS:
373515516c77SSepherosa Ziehau 		HN_LOCK(sc);
373615516c77SSepherosa Ziehau 
373715516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
373815516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
373915516c77SSepherosa Ziehau 			break;
374015516c77SSepherosa Ziehau 		}
374115516c77SSepherosa Ziehau 
37429c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc))
37439c6cae24SSepherosa Ziehau 			hn_xpnt_vf_saveifflags(sc);
37449c6cae24SSepherosa Ziehau 
374515516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_UP) {
3746fdc4f478SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
3747fdc4f478SSepherosa Ziehau 				/*
3748fdc4f478SSepherosa Ziehau 				 * Caller meight hold mutex, e.g.
3749fdc4f478SSepherosa Ziehau 				 * bpf; use busy-wait for the RNDIS
3750fdc4f478SSepherosa Ziehau 				 * reply.
3751fdc4f478SSepherosa Ziehau 				 */
3752fdc4f478SSepherosa Ziehau 				HN_NO_SLEEPING(sc);
3753c08f7b2cSSepherosa Ziehau 				hn_rxfilter_config(sc);
3754fdc4f478SSepherosa Ziehau 				HN_SLEEPING_OK(sc);
37559c6cae24SSepherosa Ziehau 
37569c6cae24SSepherosa Ziehau 				if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
37579c6cae24SSepherosa Ziehau 					error = hn_xpnt_vf_iocsetflags(sc);
3758fdc4f478SSepherosa Ziehau 			} else {
375915516c77SSepherosa Ziehau 				hn_init_locked(sc);
3760fdc4f478SSepherosa Ziehau 			}
376115516c77SSepherosa Ziehau 		} else {
376215516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
37635bdfd3fdSDexuan Cui 				hn_stop(sc, false);
376415516c77SSepherosa Ziehau 		}
376515516c77SSepherosa Ziehau 		sc->hn_if_flags = ifp->if_flags;
376615516c77SSepherosa Ziehau 
376715516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
376815516c77SSepherosa Ziehau 		break;
376915516c77SSepherosa Ziehau 
377015516c77SSepherosa Ziehau 	case SIOCSIFCAP:
377115516c77SSepherosa Ziehau 		HN_LOCK(sc);
37729c6cae24SSepherosa Ziehau 
37739c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
37749c6cae24SSepherosa Ziehau 			ifr_vf = *ifr;
37759c6cae24SSepherosa Ziehau 			strlcpy(ifr_vf.ifr_name, sc->hn_vf_ifp->if_xname,
37769c6cae24SSepherosa Ziehau 			    sizeof(ifr_vf.ifr_name));
37779c6cae24SSepherosa Ziehau 			error = hn_xpnt_vf_iocsetcaps(sc, &ifr_vf);
37789c6cae24SSepherosa Ziehau 			HN_UNLOCK(sc);
37799c6cae24SSepherosa Ziehau 			break;
37809c6cae24SSepherosa Ziehau 		}
37819c6cae24SSepherosa Ziehau 
37829c6cae24SSepherosa Ziehau 		/*
37839c6cae24SSepherosa Ziehau 		 * Fix up requested capabilities w/ supported capabilities,
37849c6cae24SSepherosa Ziehau 		 * since the supported capabilities could have been changed.
37859c6cae24SSepherosa Ziehau 		 */
37869c6cae24SSepherosa Ziehau 		mask = (ifr->ifr_reqcap & ifp->if_capabilities) ^
37879c6cae24SSepherosa Ziehau 		    ifp->if_capenable;
378815516c77SSepherosa Ziehau 
378915516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM) {
379015516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM;
379115516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM)
379215516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc);
379315516c77SSepherosa Ziehau 			else
379415516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc);
379515516c77SSepherosa Ziehau 		}
379615516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM_IPV6) {
379715516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
379815516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
379915516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc);
380015516c77SSepherosa Ziehau 			else
380115516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc);
380215516c77SSepherosa Ziehau 		}
380315516c77SSepherosa Ziehau 
380415516c77SSepherosa Ziehau 		/* TODO: flip RNDIS offload parameters for RXCSUM. */
380515516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM)
380615516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM;
380715516c77SSepherosa Ziehau #ifdef foo
380815516c77SSepherosa Ziehau 		/* We can't diff IPv6 packets from IPv4 packets on RX path. */
380915516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM_IPV6)
381015516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
381115516c77SSepherosa Ziehau #endif
381215516c77SSepherosa Ziehau 
381315516c77SSepherosa Ziehau 		if (mask & IFCAP_LRO)
381415516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_LRO;
381515516c77SSepherosa Ziehau 
381615516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO4) {
381715516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO4;
381815516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO4)
381915516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP_TSO;
382015516c77SSepherosa Ziehau 			else
382115516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP_TSO;
382215516c77SSepherosa Ziehau 		}
382315516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO6) {
382415516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO6;
382515516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO6)
382615516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP6_TSO;
382715516c77SSepherosa Ziehau 			else
382815516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP6_TSO;
382915516c77SSepherosa Ziehau 		}
383015516c77SSepherosa Ziehau 
383115516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
383215516c77SSepherosa Ziehau 		break;
383315516c77SSepherosa Ziehau 
383415516c77SSepherosa Ziehau 	case SIOCADDMULTI:
383515516c77SSepherosa Ziehau 	case SIOCDELMULTI:
383615516c77SSepherosa Ziehau 		HN_LOCK(sc);
383715516c77SSepherosa Ziehau 
383815516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
383915516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
384015516c77SSepherosa Ziehau 			break;
384115516c77SSepherosa Ziehau 		}
3842fdc4f478SSepherosa Ziehau 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
3843fdc4f478SSepherosa Ziehau 			/*
3844fdc4f478SSepherosa Ziehau 			 * Multicast uses mutex; use busy-wait for
3845fdc4f478SSepherosa Ziehau 			 * the RNDIS reply.
3846fdc4f478SSepherosa Ziehau 			 */
3847fdc4f478SSepherosa Ziehau 			HN_NO_SLEEPING(sc);
3848c08f7b2cSSepherosa Ziehau 			hn_rxfilter_config(sc);
3849fdc4f478SSepherosa Ziehau 			HN_SLEEPING_OK(sc);
3850fdc4f478SSepherosa Ziehau 		}
385115516c77SSepherosa Ziehau 
38529c6cae24SSepherosa Ziehau 		/* XXX vlan(4) style mcast addr maintenance */
38539c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
38549c6cae24SSepherosa Ziehau 			int old_if_flags;
38559c6cae24SSepherosa Ziehau 
38569c6cae24SSepherosa Ziehau 			old_if_flags = sc->hn_vf_ifp->if_flags;
38579c6cae24SSepherosa Ziehau 			hn_xpnt_vf_saveifflags(sc);
38589c6cae24SSepherosa Ziehau 
38599c6cae24SSepherosa Ziehau 			if ((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) &&
38609c6cae24SSepherosa Ziehau 			    ((old_if_flags ^ sc->hn_vf_ifp->if_flags) &
38619c6cae24SSepherosa Ziehau 			     IFF_ALLMULTI))
38629c6cae24SSepherosa Ziehau 				error = hn_xpnt_vf_iocsetflags(sc);
38639c6cae24SSepherosa Ziehau 		}
38649c6cae24SSepherosa Ziehau 
386515516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
386615516c77SSepherosa Ziehau 		break;
386715516c77SSepherosa Ziehau 
386815516c77SSepherosa Ziehau 	case SIOCSIFMEDIA:
386915516c77SSepherosa Ziehau 	case SIOCGIFMEDIA:
38709c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
38719c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
38729c6cae24SSepherosa Ziehau 			/*
38739c6cae24SSepherosa Ziehau 			 * SIOCGIFMEDIA expects ifmediareq, so don't
38749c6cae24SSepherosa Ziehau 			 * create and pass ifr_vf to the VF here; just
38759c6cae24SSepherosa Ziehau 			 * replace the ifr_name.
38769c6cae24SSepherosa Ziehau 			 */
38779c6cae24SSepherosa Ziehau 			vf_ifp = sc->hn_vf_ifp;
38789c6cae24SSepherosa Ziehau 			strlcpy(ifr->ifr_name, vf_ifp->if_xname,
38799c6cae24SSepherosa Ziehau 			    sizeof(ifr->ifr_name));
38809c6cae24SSepherosa Ziehau 			error = vf_ifp->if_ioctl(vf_ifp, cmd, data);
38819c6cae24SSepherosa Ziehau 			/* Restore the ifr_name. */
38829c6cae24SSepherosa Ziehau 			strlcpy(ifr->ifr_name, ifp->if_xname,
38839c6cae24SSepherosa Ziehau 			    sizeof(ifr->ifr_name));
38849c6cae24SSepherosa Ziehau 			HN_UNLOCK(sc);
38859c6cae24SSepherosa Ziehau 			break;
38869c6cae24SSepherosa Ziehau 		}
38879c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
388815516c77SSepherosa Ziehau 		error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd);
388915516c77SSepherosa Ziehau 		break;
389015516c77SSepherosa Ziehau 
38918c068aa5SSepherosa Ziehau 	case SIOCGIFRSSHASH:
38928c068aa5SSepherosa Ziehau 		ifrh = (struct ifrsshash *)data;
38938c068aa5SSepherosa Ziehau 		HN_LOCK(sc);
38948c068aa5SSepherosa Ziehau 		if (sc->hn_rx_ring_inuse == 1) {
38958c068aa5SSepherosa Ziehau 			HN_UNLOCK(sc);
38968c068aa5SSepherosa Ziehau 			ifrh->ifrh_func = RSS_FUNC_NONE;
38978c068aa5SSepherosa Ziehau 			ifrh->ifrh_types = 0;
38988c068aa5SSepherosa Ziehau 			break;
38998c068aa5SSepherosa Ziehau 		}
39008c068aa5SSepherosa Ziehau 
39018c068aa5SSepherosa Ziehau 		if (sc->hn_rss_hash & NDIS_HASH_FUNCTION_TOEPLITZ)
39028c068aa5SSepherosa Ziehau 			ifrh->ifrh_func = RSS_FUNC_TOEPLITZ;
39038c068aa5SSepherosa Ziehau 		else
39048c068aa5SSepherosa Ziehau 			ifrh->ifrh_func = RSS_FUNC_PRIVATE;
3905642ec226SSepherosa Ziehau 		ifrh->ifrh_types = hn_rss_type_fromndis(sc->hn_rss_hash);
39068c068aa5SSepherosa Ziehau 		HN_UNLOCK(sc);
39078c068aa5SSepherosa Ziehau 		break;
39088c068aa5SSepherosa Ziehau 
39098c068aa5SSepherosa Ziehau 	case SIOCGIFRSSKEY:
39108c068aa5SSepherosa Ziehau 		ifrk = (struct ifrsskey *)data;
39118c068aa5SSepherosa Ziehau 		HN_LOCK(sc);
39128c068aa5SSepherosa Ziehau 		if (sc->hn_rx_ring_inuse == 1) {
39138c068aa5SSepherosa Ziehau 			HN_UNLOCK(sc);
39148c068aa5SSepherosa Ziehau 			ifrk->ifrk_func = RSS_FUNC_NONE;
39158c068aa5SSepherosa Ziehau 			ifrk->ifrk_keylen = 0;
39168c068aa5SSepherosa Ziehau 			break;
39178c068aa5SSepherosa Ziehau 		}
39188c068aa5SSepherosa Ziehau 		if (sc->hn_rss_hash & NDIS_HASH_FUNCTION_TOEPLITZ)
39198c068aa5SSepherosa Ziehau 			ifrk->ifrk_func = RSS_FUNC_TOEPLITZ;
39208c068aa5SSepherosa Ziehau 		else
39218c068aa5SSepherosa Ziehau 			ifrk->ifrk_func = RSS_FUNC_PRIVATE;
39228c068aa5SSepherosa Ziehau 		ifrk->ifrk_keylen = NDIS_HASH_KEYSIZE_TOEPLITZ;
39238c068aa5SSepherosa Ziehau 		memcpy(ifrk->ifrk_key, sc->hn_rss.rss_key,
39248c068aa5SSepherosa Ziehau 		    NDIS_HASH_KEYSIZE_TOEPLITZ);
39258c068aa5SSepherosa Ziehau 		HN_UNLOCK(sc);
39268c068aa5SSepherosa Ziehau 		break;
39278c068aa5SSepherosa Ziehau 
392815516c77SSepherosa Ziehau 	default:
392915516c77SSepherosa Ziehau 		error = ether_ioctl(ifp, cmd, data);
393015516c77SSepherosa Ziehau 		break;
393115516c77SSepherosa Ziehau 	}
393215516c77SSepherosa Ziehau 	return (error);
393315516c77SSepherosa Ziehau }
393415516c77SSepherosa Ziehau 
393515516c77SSepherosa Ziehau static void
39365bdfd3fdSDexuan Cui hn_stop(struct hn_softc *sc, bool detaching)
393715516c77SSepherosa Ziehau {
393815516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
393915516c77SSepherosa Ziehau 	int i;
394015516c77SSepherosa Ziehau 
394115516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
394215516c77SSepherosa Ziehau 
394315516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
394415516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
394515516c77SSepherosa Ziehau 
39469c6cae24SSepherosa Ziehau 	/* Clear RUNNING bit ASAP. */
39479c6cae24SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
39489c6cae24SSepherosa Ziehau 
39496c1204dfSSepherosa Ziehau 	/* Disable polling. */
39506c1204dfSSepherosa Ziehau 	hn_polling(sc, 0);
39516c1204dfSSepherosa Ziehau 
39529c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) {
39539c6cae24SSepherosa Ziehau 		KASSERT(sc->hn_vf_ifp != NULL,
39549c6cae24SSepherosa Ziehau 		    ("%s: VF is not attached", ifp->if_xname));
39559c6cae24SSepherosa Ziehau 
3956a97fff19SSepherosa Ziehau 		/* Mark transparent mode VF as disabled. */
3957a97fff19SSepherosa Ziehau 		hn_xpnt_vf_setdisable(sc, false /* keep hn_vf_ifp */);
39589c6cae24SSepherosa Ziehau 
39599c6cae24SSepherosa Ziehau 		/*
39609c6cae24SSepherosa Ziehau 		 * NOTE:
39619c6cae24SSepherosa Ziehau 		 * Datapath setting must happen _before_ bringing
39629c6cae24SSepherosa Ziehau 		 * the VF down.
39639c6cae24SSepherosa Ziehau 		 */
39649c6cae24SSepherosa Ziehau 		hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH);
39659c6cae24SSepherosa Ziehau 
39669c6cae24SSepherosa Ziehau 		/*
39679c6cae24SSepherosa Ziehau 		 * Bring the VF down.
39689c6cae24SSepherosa Ziehau 		 */
39699c6cae24SSepherosa Ziehau 		hn_xpnt_vf_saveifflags(sc);
39709c6cae24SSepherosa Ziehau 		sc->hn_vf_ifp->if_flags &= ~IFF_UP;
39719c6cae24SSepherosa Ziehau 		hn_xpnt_vf_iocsetflags(sc);
39729c6cae24SSepherosa Ziehau 	}
39739c6cae24SSepherosa Ziehau 
39749c6cae24SSepherosa Ziehau 	/* Suspend data transfers. */
397515516c77SSepherosa Ziehau 	hn_suspend_data(sc);
397615516c77SSepherosa Ziehau 
397715516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
397815516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
397915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
398015516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
39815bdfd3fdSDexuan Cui 
39825bdfd3fdSDexuan Cui 	/*
39839c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is active, make sure
39849c6cae24SSepherosa Ziehau 	 * that the RX filter still allows packet reception.
39855bdfd3fdSDexuan Cui 	 */
3986962f0357SSepherosa Ziehau 	if (!detaching && (sc->hn_flags & HN_FLAG_RXVF))
39875bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
398815516c77SSepherosa Ziehau }
398915516c77SSepherosa Ziehau 
399015516c77SSepherosa Ziehau static void
399115516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc)
399215516c77SSepherosa Ziehau {
399315516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
399415516c77SSepherosa Ziehau 	int i;
399515516c77SSepherosa Ziehau 
399615516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
399715516c77SSepherosa Ziehau 
399815516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
399915516c77SSepherosa Ziehau 		return;
400015516c77SSepherosa Ziehau 
400115516c77SSepherosa Ziehau 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
400215516c77SSepherosa Ziehau 		return;
400315516c77SSepherosa Ziehau 
400415516c77SSepherosa Ziehau 	/* Configure RX filter */
4005c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
400615516c77SSepherosa Ziehau 
400715516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
400815516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
400915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
401015516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
401115516c77SSepherosa Ziehau 
401215516c77SSepherosa Ziehau 	/* Clear TX 'suspended' bit. */
401315516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_inuse);
401415516c77SSepherosa Ziehau 
40159c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_isready(sc)) {
40169c6cae24SSepherosa Ziehau 		/* Initialize transparent VF. */
40179c6cae24SSepherosa Ziehau 		hn_xpnt_vf_init(sc);
40189c6cae24SSepherosa Ziehau 	}
40199c6cae24SSepherosa Ziehau 
402015516c77SSepherosa Ziehau 	/* Everything is ready; unleash! */
402115516c77SSepherosa Ziehau 	atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
40226c1204dfSSepherosa Ziehau 
40236c1204dfSSepherosa Ziehau 	/* Re-enable polling if requested. */
40246c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz > 0)
40256c1204dfSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
402615516c77SSepherosa Ziehau }
402715516c77SSepherosa Ziehau 
402815516c77SSepherosa Ziehau static void
402915516c77SSepherosa Ziehau hn_init(void *xsc)
403015516c77SSepherosa Ziehau {
403115516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
403215516c77SSepherosa Ziehau 
403315516c77SSepherosa Ziehau 	HN_LOCK(sc);
403415516c77SSepherosa Ziehau 	hn_init_locked(sc);
403515516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
403615516c77SSepherosa Ziehau }
403715516c77SSepherosa Ziehau 
403815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
403915516c77SSepherosa Ziehau 
404015516c77SSepherosa Ziehau static int
404115516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
404215516c77SSepherosa Ziehau {
404315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
404415516c77SSepherosa Ziehau 	unsigned int lenlim;
404515516c77SSepherosa Ziehau 	int error;
404615516c77SSepherosa Ziehau 
404715516c77SSepherosa Ziehau 	lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim;
404815516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &lenlim, 0, req);
404915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
405015516c77SSepherosa Ziehau 		return error;
405115516c77SSepherosa Ziehau 
405215516c77SSepherosa Ziehau 	HN_LOCK(sc);
405315516c77SSepherosa Ziehau 	if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) ||
405415516c77SSepherosa Ziehau 	    lenlim > TCP_LRO_LENGTH_MAX) {
405515516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
405615516c77SSepherosa Ziehau 		return EINVAL;
405715516c77SSepherosa Ziehau 	}
405815516c77SSepherosa Ziehau 	hn_set_lro_lenlim(sc, lenlim);
405915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
406015516c77SSepherosa Ziehau 
406115516c77SSepherosa Ziehau 	return 0;
406215516c77SSepherosa Ziehau }
406315516c77SSepherosa Ziehau 
406415516c77SSepherosa Ziehau static int
406515516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS)
406615516c77SSepherosa Ziehau {
406715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
406815516c77SSepherosa Ziehau 	int ackcnt, error, i;
406915516c77SSepherosa Ziehau 
407015516c77SSepherosa Ziehau 	/*
407115516c77SSepherosa Ziehau 	 * lro_ackcnt_lim is append count limit,
407215516c77SSepherosa Ziehau 	 * +1 to turn it into aggregation limit.
407315516c77SSepherosa Ziehau 	 */
407415516c77SSepherosa Ziehau 	ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1;
407515516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &ackcnt, 0, req);
407615516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
407715516c77SSepherosa Ziehau 		return error;
407815516c77SSepherosa Ziehau 
407915516c77SSepherosa Ziehau 	if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1))
408015516c77SSepherosa Ziehau 		return EINVAL;
408115516c77SSepherosa Ziehau 
408215516c77SSepherosa Ziehau 	/*
408315516c77SSepherosa Ziehau 	 * Convert aggregation limit back to append
408415516c77SSepherosa Ziehau 	 * count limit.
408515516c77SSepherosa Ziehau 	 */
408615516c77SSepherosa Ziehau 	--ackcnt;
408715516c77SSepherosa Ziehau 	HN_LOCK(sc);
4088a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
408915516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt;
409015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
409115516c77SSepherosa Ziehau 	return 0;
409215516c77SSepherosa Ziehau }
409315516c77SSepherosa Ziehau 
409415516c77SSepherosa Ziehau #endif
409515516c77SSepherosa Ziehau 
409615516c77SSepherosa Ziehau static int
409715516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS)
409815516c77SSepherosa Ziehau {
409915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
410015516c77SSepherosa Ziehau 	int hcsum = arg2;
410115516c77SSepherosa Ziehau 	int on, error, i;
410215516c77SSepherosa Ziehau 
410315516c77SSepherosa Ziehau 	on = 0;
410415516c77SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum)
410515516c77SSepherosa Ziehau 		on = 1;
410615516c77SSepherosa Ziehau 
410715516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &on, 0, req);
410815516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
410915516c77SSepherosa Ziehau 		return error;
411015516c77SSepherosa Ziehau 
411115516c77SSepherosa Ziehau 	HN_LOCK(sc);
4112a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
411315516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
411415516c77SSepherosa Ziehau 
411515516c77SSepherosa Ziehau 		if (on)
411615516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= hcsum;
411715516c77SSepherosa Ziehau 		else
411815516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum &= ~hcsum;
411915516c77SSepherosa Ziehau 	}
412015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
412115516c77SSepherosa Ziehau 	return 0;
412215516c77SSepherosa Ziehau }
412315516c77SSepherosa Ziehau 
412415516c77SSepherosa Ziehau static int
412515516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS)
412615516c77SSepherosa Ziehau {
412715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
412815516c77SSepherosa Ziehau 	int chim_size, error;
412915516c77SSepherosa Ziehau 
413015516c77SSepherosa Ziehau 	chim_size = sc->hn_tx_ring[0].hn_chim_size;
413115516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &chim_size, 0, req);
413215516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
413315516c77SSepherosa Ziehau 		return error;
413415516c77SSepherosa Ziehau 
413515516c77SSepherosa Ziehau 	if (chim_size > sc->hn_chim_szmax || chim_size <= 0)
413615516c77SSepherosa Ziehau 		return EINVAL;
413715516c77SSepherosa Ziehau 
413815516c77SSepherosa Ziehau 	HN_LOCK(sc);
413915516c77SSepherosa Ziehau 	hn_set_chim_size(sc, chim_size);
414015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
414115516c77SSepherosa Ziehau 	return 0;
414215516c77SSepherosa Ziehau }
414315516c77SSepherosa Ziehau 
414415516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
414515516c77SSepherosa Ziehau static int
414615516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS)
414715516c77SSepherosa Ziehau {
414815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
414915516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
415015516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
415115516c77SSepherosa Ziehau 	uint64_t stat;
415215516c77SSepherosa Ziehau 
415315516c77SSepherosa Ziehau 	stat = 0;
415415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
415515516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
415615516c77SSepherosa Ziehau 		stat += *((int *)((uint8_t *)rxr + ofs));
415715516c77SSepherosa Ziehau 	}
415815516c77SSepherosa Ziehau 
415915516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
416015516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
416115516c77SSepherosa Ziehau 		return error;
416215516c77SSepherosa Ziehau 
416315516c77SSepherosa Ziehau 	/* Zero out this stat. */
416415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
416515516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
416615516c77SSepherosa Ziehau 		*((int *)((uint8_t *)rxr + ofs)) = 0;
416715516c77SSepherosa Ziehau 	}
416815516c77SSepherosa Ziehau 	return 0;
416915516c77SSepherosa Ziehau }
417015516c77SSepherosa Ziehau #else
417115516c77SSepherosa Ziehau static int
417215516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS)
417315516c77SSepherosa Ziehau {
417415516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
417515516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
417615516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
417715516c77SSepherosa Ziehau 	uint64_t stat;
417815516c77SSepherosa Ziehau 
417915516c77SSepherosa Ziehau 	stat = 0;
4180a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
418115516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
418215516c77SSepherosa Ziehau 		stat += *((uint64_t *)((uint8_t *)rxr + ofs));
418315516c77SSepherosa Ziehau 	}
418415516c77SSepherosa Ziehau 
418515516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
418615516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
418715516c77SSepherosa Ziehau 		return error;
418815516c77SSepherosa Ziehau 
418915516c77SSepherosa Ziehau 	/* Zero out this stat. */
4190a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
419115516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
419215516c77SSepherosa Ziehau 		*((uint64_t *)((uint8_t *)rxr + ofs)) = 0;
419315516c77SSepherosa Ziehau 	}
419415516c77SSepherosa Ziehau 	return 0;
419515516c77SSepherosa Ziehau }
419615516c77SSepherosa Ziehau 
419715516c77SSepherosa Ziehau #endif
419815516c77SSepherosa Ziehau 
419915516c77SSepherosa Ziehau static int
420015516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
420115516c77SSepherosa Ziehau {
420215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
420315516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
420415516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
420515516c77SSepherosa Ziehau 	u_long stat;
420615516c77SSepherosa Ziehau 
420715516c77SSepherosa Ziehau 	stat = 0;
4208a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
420915516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
421015516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)rxr + ofs));
421115516c77SSepherosa Ziehau 	}
421215516c77SSepherosa Ziehau 
421315516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
421415516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
421515516c77SSepherosa Ziehau 		return error;
421615516c77SSepherosa Ziehau 
421715516c77SSepherosa Ziehau 	/* Zero out this stat. */
4218a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
421915516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
422015516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)rxr + ofs)) = 0;
422115516c77SSepherosa Ziehau 	}
422215516c77SSepherosa Ziehau 	return 0;
422315516c77SSepherosa Ziehau }
422415516c77SSepherosa Ziehau 
422515516c77SSepherosa Ziehau static int
422615516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
422715516c77SSepherosa Ziehau {
422815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
422915516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
423015516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
423115516c77SSepherosa Ziehau 	u_long stat;
423215516c77SSepherosa Ziehau 
423315516c77SSepherosa Ziehau 	stat = 0;
4234a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
423515516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
423615516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)txr + ofs));
423715516c77SSepherosa Ziehau 	}
423815516c77SSepherosa Ziehau 
423915516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
424015516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
424115516c77SSepherosa Ziehau 		return error;
424215516c77SSepherosa Ziehau 
424315516c77SSepherosa Ziehau 	/* Zero out this stat. */
4244a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
424515516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
424615516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)txr + ofs)) = 0;
424715516c77SSepherosa Ziehau 	}
424815516c77SSepherosa Ziehau 	return 0;
424915516c77SSepherosa Ziehau }
425015516c77SSepherosa Ziehau 
425115516c77SSepherosa Ziehau static int
425215516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS)
425315516c77SSepherosa Ziehau {
425415516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
425515516c77SSepherosa Ziehau 	int ofs = arg2, i, error, conf;
425615516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
425715516c77SSepherosa Ziehau 
425815516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[0];
425915516c77SSepherosa Ziehau 	conf = *((int *)((uint8_t *)txr + ofs));
426015516c77SSepherosa Ziehau 
426115516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &conf, 0, req);
426215516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
426315516c77SSepherosa Ziehau 		return error;
426415516c77SSepherosa Ziehau 
426515516c77SSepherosa Ziehau 	HN_LOCK(sc);
4266a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
426715516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
426815516c77SSepherosa Ziehau 		*((int *)((uint8_t *)txr + ofs)) = conf;
426915516c77SSepherosa Ziehau 	}
427015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
427115516c77SSepherosa Ziehau 
427215516c77SSepherosa Ziehau 	return 0;
427315516c77SSepherosa Ziehau }
427415516c77SSepherosa Ziehau 
427515516c77SSepherosa Ziehau static int
4276dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS)
4277dc13fee6SSepherosa Ziehau {
4278dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4279dc13fee6SSepherosa Ziehau 	int error, size;
4280dc13fee6SSepherosa Ziehau 
4281dc13fee6SSepherosa Ziehau 	size = sc->hn_agg_size;
4282dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &size, 0, req);
4283dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
4284dc13fee6SSepherosa Ziehau 		return (error);
4285dc13fee6SSepherosa Ziehau 
4286dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
4287dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = size;
4288dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
4289dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
4290dc13fee6SSepherosa Ziehau 
4291dc13fee6SSepherosa Ziehau 	return (0);
4292dc13fee6SSepherosa Ziehau }
4293dc13fee6SSepherosa Ziehau 
4294dc13fee6SSepherosa Ziehau static int
4295dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS)
4296dc13fee6SSepherosa Ziehau {
4297dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4298dc13fee6SSepherosa Ziehau 	int error, pkts;
4299dc13fee6SSepherosa Ziehau 
4300dc13fee6SSepherosa Ziehau 	pkts = sc->hn_agg_pkts;
4301dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pkts, 0, req);
4302dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
4303dc13fee6SSepherosa Ziehau 		return (error);
4304dc13fee6SSepherosa Ziehau 
4305dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
4306dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = pkts;
4307dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
4308dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
4309dc13fee6SSepherosa Ziehau 
4310dc13fee6SSepherosa Ziehau 	return (0);
4311dc13fee6SSepherosa Ziehau }
4312dc13fee6SSepherosa Ziehau 
4313dc13fee6SSepherosa Ziehau static int
4314dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS)
4315dc13fee6SSepherosa Ziehau {
4316dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4317dc13fee6SSepherosa Ziehau 	int pkts;
4318dc13fee6SSepherosa Ziehau 
4319dc13fee6SSepherosa Ziehau 	pkts = sc->hn_tx_ring[0].hn_agg_pktmax;
4320dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &pkts, 0, req));
4321dc13fee6SSepherosa Ziehau }
4322dc13fee6SSepherosa Ziehau 
4323dc13fee6SSepherosa Ziehau static int
4324dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS)
4325dc13fee6SSepherosa Ziehau {
4326dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4327dc13fee6SSepherosa Ziehau 	int align;
4328dc13fee6SSepherosa Ziehau 
4329dc13fee6SSepherosa Ziehau 	align = sc->hn_tx_ring[0].hn_agg_align;
4330dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &align, 0, req));
4331dc13fee6SSepherosa Ziehau }
4332dc13fee6SSepherosa Ziehau 
43336c1204dfSSepherosa Ziehau static void
43346c1204dfSSepherosa Ziehau hn_chan_polling(struct vmbus_channel *chan, u_int pollhz)
43356c1204dfSSepherosa Ziehau {
43366c1204dfSSepherosa Ziehau 	if (pollhz == 0)
43376c1204dfSSepherosa Ziehau 		vmbus_chan_poll_disable(chan);
43386c1204dfSSepherosa Ziehau 	else
43396c1204dfSSepherosa Ziehau 		vmbus_chan_poll_enable(chan, pollhz);
43406c1204dfSSepherosa Ziehau }
43416c1204dfSSepherosa Ziehau 
43426c1204dfSSepherosa Ziehau static void
43436c1204dfSSepherosa Ziehau hn_polling(struct hn_softc *sc, u_int pollhz)
43446c1204dfSSepherosa Ziehau {
43456c1204dfSSepherosa Ziehau 	int nsubch = sc->hn_rx_ring_inuse - 1;
43466c1204dfSSepherosa Ziehau 
43476c1204dfSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
43486c1204dfSSepherosa Ziehau 
43496c1204dfSSepherosa Ziehau 	if (nsubch > 0) {
43506c1204dfSSepherosa Ziehau 		struct vmbus_channel **subch;
43516c1204dfSSepherosa Ziehau 		int i;
43526c1204dfSSepherosa Ziehau 
43536c1204dfSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
43546c1204dfSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
43556c1204dfSSepherosa Ziehau 			hn_chan_polling(subch[i], pollhz);
43566c1204dfSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
43576c1204dfSSepherosa Ziehau 	}
43586c1204dfSSepherosa Ziehau 	hn_chan_polling(sc->hn_prichan, pollhz);
43596c1204dfSSepherosa Ziehau }
43606c1204dfSSepherosa Ziehau 
43616c1204dfSSepherosa Ziehau static int
43626c1204dfSSepherosa Ziehau hn_polling_sysctl(SYSCTL_HANDLER_ARGS)
43636c1204dfSSepherosa Ziehau {
43646c1204dfSSepherosa Ziehau 	struct hn_softc *sc = arg1;
43656c1204dfSSepherosa Ziehau 	int pollhz, error;
43666c1204dfSSepherosa Ziehau 
43676c1204dfSSepherosa Ziehau 	pollhz = sc->hn_pollhz;
43686c1204dfSSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pollhz, 0, req);
43696c1204dfSSepherosa Ziehau 	if (error || req->newptr == NULL)
43706c1204dfSSepherosa Ziehau 		return (error);
43716c1204dfSSepherosa Ziehau 
43726c1204dfSSepherosa Ziehau 	if (pollhz != 0 &&
43736c1204dfSSepherosa Ziehau 	    (pollhz < VMBUS_CHAN_POLLHZ_MIN || pollhz > VMBUS_CHAN_POLLHZ_MAX))
43746c1204dfSSepherosa Ziehau 		return (EINVAL);
43756c1204dfSSepherosa Ziehau 
43766c1204dfSSepherosa Ziehau 	HN_LOCK(sc);
43776c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz != pollhz) {
43786c1204dfSSepherosa Ziehau 		sc->hn_pollhz = pollhz;
43796c1204dfSSepherosa Ziehau 		if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) &&
43806c1204dfSSepherosa Ziehau 		    (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
43816c1204dfSSepherosa Ziehau 			hn_polling(sc, sc->hn_pollhz);
43826c1204dfSSepherosa Ziehau 	}
43836c1204dfSSepherosa Ziehau 	HN_UNLOCK(sc);
43846c1204dfSSepherosa Ziehau 
43856c1204dfSSepherosa Ziehau 	return (0);
43866c1204dfSSepherosa Ziehau }
43876c1204dfSSepherosa Ziehau 
4388dc13fee6SSepherosa Ziehau static int
438915516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS)
439015516c77SSepherosa Ziehau {
439115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
439215516c77SSepherosa Ziehau 	char verstr[16];
439315516c77SSepherosa Ziehau 
439415516c77SSepherosa Ziehau 	snprintf(verstr, sizeof(verstr), "%u.%u",
439515516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
439615516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
439715516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
439815516c77SSepherosa Ziehau }
439915516c77SSepherosa Ziehau 
440015516c77SSepherosa Ziehau static int
440115516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS)
440215516c77SSepherosa Ziehau {
440315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
440415516c77SSepherosa Ziehau 	char caps_str[128];
440515516c77SSepherosa Ziehau 	uint32_t caps;
440615516c77SSepherosa Ziehau 
440715516c77SSepherosa Ziehau 	HN_LOCK(sc);
440815516c77SSepherosa Ziehau 	caps = sc->hn_caps;
440915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
441015516c77SSepherosa Ziehau 	snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS);
441115516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req);
441215516c77SSepherosa Ziehau }
441315516c77SSepherosa Ziehau 
441415516c77SSepherosa Ziehau static int
441515516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS)
441615516c77SSepherosa Ziehau {
441715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
441815516c77SSepherosa Ziehau 	char assist_str[128];
441915516c77SSepherosa Ziehau 	uint32_t hwassist;
442015516c77SSepherosa Ziehau 
442115516c77SSepherosa Ziehau 	HN_LOCK(sc);
442215516c77SSepherosa Ziehau 	hwassist = sc->hn_ifp->if_hwassist;
442315516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
442415516c77SSepherosa Ziehau 	snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS);
442515516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req);
442615516c77SSepherosa Ziehau }
442715516c77SSepherosa Ziehau 
442815516c77SSepherosa Ziehau static int
442915516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS)
443015516c77SSepherosa Ziehau {
443115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
443215516c77SSepherosa Ziehau 	char filter_str[128];
443315516c77SSepherosa Ziehau 	uint32_t filter;
443415516c77SSepherosa Ziehau 
443515516c77SSepherosa Ziehau 	HN_LOCK(sc);
443615516c77SSepherosa Ziehau 	filter = sc->hn_rx_filter;
443715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
443815516c77SSepherosa Ziehau 	snprintf(filter_str, sizeof(filter_str), "%b", filter,
443915516c77SSepherosa Ziehau 	    NDIS_PACKET_TYPES);
444015516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req);
444115516c77SSepherosa Ziehau }
444215516c77SSepherosa Ziehau 
444334d68912SSepherosa Ziehau #ifndef RSS
444434d68912SSepherosa Ziehau 
444515516c77SSepherosa Ziehau static int
444615516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
444715516c77SSepherosa Ziehau {
444815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
444915516c77SSepherosa Ziehau 	int error;
445015516c77SSepherosa Ziehau 
445115516c77SSepherosa Ziehau 	HN_LOCK(sc);
445215516c77SSepherosa Ziehau 
445315516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
445415516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
445515516c77SSepherosa Ziehau 		goto back;
445615516c77SSepherosa Ziehau 
4457642ec226SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) ||
4458642ec226SSepherosa Ziehau 	    (hn_xpnt_vf && sc->hn_vf_ifp != NULL)) {
4459642ec226SSepherosa Ziehau 		/*
4460642ec226SSepherosa Ziehau 		 * RSS key is synchronized w/ VF's, don't allow users
4461642ec226SSepherosa Ziehau 		 * to change it.
4462642ec226SSepherosa Ziehau 		 */
4463642ec226SSepherosa Ziehau 		error = EBUSY;
4464642ec226SSepherosa Ziehau 		goto back;
4465642ec226SSepherosa Ziehau 	}
4466642ec226SSepherosa Ziehau 
446715516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
446815516c77SSepherosa Ziehau 	if (error)
446915516c77SSepherosa Ziehau 		goto back;
447015516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
447115516c77SSepherosa Ziehau 
447215516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
447315516c77SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
447415516c77SSepherosa Ziehau 	} else {
447515516c77SSepherosa Ziehau 		/* Not RSS capable, at least for now; just save the RSS key. */
447615516c77SSepherosa Ziehau 		error = 0;
447715516c77SSepherosa Ziehau 	}
447815516c77SSepherosa Ziehau back:
447915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
448015516c77SSepherosa Ziehau 	return (error);
448115516c77SSepherosa Ziehau }
448215516c77SSepherosa Ziehau 
448315516c77SSepherosa Ziehau static int
448415516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS)
448515516c77SSepherosa Ziehau {
448615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
448715516c77SSepherosa Ziehau 	int error;
448815516c77SSepherosa Ziehau 
448915516c77SSepherosa Ziehau 	HN_LOCK(sc);
449015516c77SSepherosa Ziehau 
449115516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
449215516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
449315516c77SSepherosa Ziehau 		goto back;
449415516c77SSepherosa Ziehau 
449515516c77SSepherosa Ziehau 	/*
449615516c77SSepherosa Ziehau 	 * Don't allow RSS indirect table change, if this interface is not
449715516c77SSepherosa Ziehau 	 * RSS capable currently.
449815516c77SSepherosa Ziehau 	 */
449915516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
450015516c77SSepherosa Ziehau 		error = EOPNOTSUPP;
450115516c77SSepherosa Ziehau 		goto back;
450215516c77SSepherosa Ziehau 	}
450315516c77SSepherosa Ziehau 
450415516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
450515516c77SSepherosa Ziehau 	if (error)
450615516c77SSepherosa Ziehau 		goto back;
450715516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSIND;
450815516c77SSepherosa Ziehau 
4509afd4971bSSepherosa Ziehau 	hn_rss_ind_fixup(sc);
451015516c77SSepherosa Ziehau 	error = hn_rss_reconfig(sc);
451115516c77SSepherosa Ziehau back:
451215516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
451315516c77SSepherosa Ziehau 	return (error);
451415516c77SSepherosa Ziehau }
451515516c77SSepherosa Ziehau 
451634d68912SSepherosa Ziehau #endif	/* !RSS */
451734d68912SSepherosa Ziehau 
451815516c77SSepherosa Ziehau static int
451915516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS)
452015516c77SSepherosa Ziehau {
452115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
452215516c77SSepherosa Ziehau 	char hash_str[128];
452315516c77SSepherosa Ziehau 	uint32_t hash;
452415516c77SSepherosa Ziehau 
452515516c77SSepherosa Ziehau 	HN_LOCK(sc);
452615516c77SSepherosa Ziehau 	hash = sc->hn_rss_hash;
452715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
452815516c77SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
452915516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
453015516c77SSepherosa Ziehau }
453115516c77SSepherosa Ziehau 
453215516c77SSepherosa Ziehau static int
4533642ec226SSepherosa Ziehau hn_rss_hcap_sysctl(SYSCTL_HANDLER_ARGS)
4534642ec226SSepherosa Ziehau {
4535642ec226SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4536642ec226SSepherosa Ziehau 	char hash_str[128];
4537642ec226SSepherosa Ziehau 	uint32_t hash;
4538642ec226SSepherosa Ziehau 
4539642ec226SSepherosa Ziehau 	HN_LOCK(sc);
4540642ec226SSepherosa Ziehau 	hash = sc->hn_rss_hcap;
4541642ec226SSepherosa Ziehau 	HN_UNLOCK(sc);
4542642ec226SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
4543642ec226SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
4544642ec226SSepherosa Ziehau }
4545642ec226SSepherosa Ziehau 
4546642ec226SSepherosa Ziehau static int
4547642ec226SSepherosa Ziehau hn_rss_mbuf_sysctl(SYSCTL_HANDLER_ARGS)
4548642ec226SSepherosa Ziehau {
4549642ec226SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4550642ec226SSepherosa Ziehau 	char hash_str[128];
4551642ec226SSepherosa Ziehau 	uint32_t hash;
4552642ec226SSepherosa Ziehau 
4553642ec226SSepherosa Ziehau 	HN_LOCK(sc);
4554642ec226SSepherosa Ziehau 	hash = sc->hn_rx_ring[0].hn_mbuf_hash;
4555642ec226SSepherosa Ziehau 	HN_UNLOCK(sc);
4556642ec226SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
4557642ec226SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
4558642ec226SSepherosa Ziehau }
4559642ec226SSepherosa Ziehau 
4560642ec226SSepherosa Ziehau static int
456140d60d6eSDexuan Cui hn_vf_sysctl(SYSCTL_HANDLER_ARGS)
456240d60d6eSDexuan Cui {
456340d60d6eSDexuan Cui 	struct hn_softc *sc = arg1;
4564499c3e17SSepherosa Ziehau 	char vf_name[IFNAMSIZ + 1];
4565962f0357SSepherosa Ziehau 	struct ifnet *vf_ifp;
456640d60d6eSDexuan Cui 
456740d60d6eSDexuan Cui 	HN_LOCK(sc);
456840d60d6eSDexuan Cui 	vf_name[0] = '\0';
4569962f0357SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
4570962f0357SSepherosa Ziehau 	if (vf_ifp != NULL)
4571962f0357SSepherosa Ziehau 		snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname);
457240d60d6eSDexuan Cui 	HN_UNLOCK(sc);
457340d60d6eSDexuan Cui 	return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req);
457440d60d6eSDexuan Cui }
457540d60d6eSDexuan Cui 
457640d60d6eSDexuan Cui static int
4577499c3e17SSepherosa Ziehau hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS)
4578499c3e17SSepherosa Ziehau {
4579499c3e17SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4580499c3e17SSepherosa Ziehau 	char vf_name[IFNAMSIZ + 1];
4581962f0357SSepherosa Ziehau 	struct ifnet *vf_ifp;
4582499c3e17SSepherosa Ziehau 
4583499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
4584499c3e17SSepherosa Ziehau 	vf_name[0] = '\0';
4585962f0357SSepherosa Ziehau 	vf_ifp = sc->hn_rx_ring[0].hn_rxvf_ifp;
4586962f0357SSepherosa Ziehau 	if (vf_ifp != NULL)
4587962f0357SSepherosa Ziehau 		snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname);
4588499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
4589499c3e17SSepherosa Ziehau 	return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req);
4590499c3e17SSepherosa Ziehau }
4591499c3e17SSepherosa Ziehau 
4592499c3e17SSepherosa Ziehau static int
4593499c3e17SSepherosa Ziehau hn_vflist_sysctl(SYSCTL_HANDLER_ARGS)
4594499c3e17SSepherosa Ziehau {
4595499c3e17SSepherosa Ziehau 	struct rm_priotracker pt;
4596499c3e17SSepherosa Ziehau 	struct sbuf *sb;
4597499c3e17SSepherosa Ziehau 	int error, i;
4598499c3e17SSepherosa Ziehau 	bool first;
4599499c3e17SSepherosa Ziehau 
4600499c3e17SSepherosa Ziehau 	error = sysctl_wire_old_buffer(req, 0);
4601499c3e17SSepherosa Ziehau 	if (error != 0)
4602499c3e17SSepherosa Ziehau 		return (error);
4603499c3e17SSepherosa Ziehau 
4604499c3e17SSepherosa Ziehau 	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4605499c3e17SSepherosa Ziehau 	if (sb == NULL)
4606499c3e17SSepherosa Ziehau 		return (ENOMEM);
4607499c3e17SSepherosa Ziehau 
4608499c3e17SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
4609499c3e17SSepherosa Ziehau 
4610499c3e17SSepherosa Ziehau 	first = true;
4611499c3e17SSepherosa Ziehau 	for (i = 0; i < hn_vfmap_size; ++i) {
4612499c3e17SSepherosa Ziehau 		struct ifnet *ifp;
4613499c3e17SSepherosa Ziehau 
4614499c3e17SSepherosa Ziehau 		if (hn_vfmap[i] == NULL)
4615499c3e17SSepherosa Ziehau 			continue;
4616499c3e17SSepherosa Ziehau 
4617499c3e17SSepherosa Ziehau 		ifp = ifnet_byindex(i);
4618499c3e17SSepherosa Ziehau 		if (ifp != NULL) {
4619499c3e17SSepherosa Ziehau 			if (first)
4620499c3e17SSepherosa Ziehau 				sbuf_printf(sb, "%s", ifp->if_xname);
4621499c3e17SSepherosa Ziehau 			else
4622499c3e17SSepherosa Ziehau 				sbuf_printf(sb, " %s", ifp->if_xname);
4623499c3e17SSepherosa Ziehau 			first = false;
4624499c3e17SSepherosa Ziehau 		}
4625499c3e17SSepherosa Ziehau 	}
4626499c3e17SSepherosa Ziehau 
4627499c3e17SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
4628499c3e17SSepherosa Ziehau 
4629499c3e17SSepherosa Ziehau 	error = sbuf_finish(sb);
4630499c3e17SSepherosa Ziehau 	sbuf_delete(sb);
4631499c3e17SSepherosa Ziehau 	return (error);
4632499c3e17SSepherosa Ziehau }
4633499c3e17SSepherosa Ziehau 
4634499c3e17SSepherosa Ziehau static int
4635499c3e17SSepherosa Ziehau hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS)
4636499c3e17SSepherosa Ziehau {
4637499c3e17SSepherosa Ziehau 	struct rm_priotracker pt;
4638499c3e17SSepherosa Ziehau 	struct sbuf *sb;
4639499c3e17SSepherosa Ziehau 	int error, i;
4640499c3e17SSepherosa Ziehau 	bool first;
4641499c3e17SSepherosa Ziehau 
4642499c3e17SSepherosa Ziehau 	error = sysctl_wire_old_buffer(req, 0);
4643499c3e17SSepherosa Ziehau 	if (error != 0)
4644499c3e17SSepherosa Ziehau 		return (error);
4645499c3e17SSepherosa Ziehau 
4646499c3e17SSepherosa Ziehau 	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4647499c3e17SSepherosa Ziehau 	if (sb == NULL)
4648499c3e17SSepherosa Ziehau 		return (ENOMEM);
4649499c3e17SSepherosa Ziehau 
4650499c3e17SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
4651499c3e17SSepherosa Ziehau 
4652499c3e17SSepherosa Ziehau 	first = true;
4653499c3e17SSepherosa Ziehau 	for (i = 0; i < hn_vfmap_size; ++i) {
4654499c3e17SSepherosa Ziehau 		struct ifnet *ifp, *hn_ifp;
4655499c3e17SSepherosa Ziehau 
4656499c3e17SSepherosa Ziehau 		hn_ifp = hn_vfmap[i];
4657499c3e17SSepherosa Ziehau 		if (hn_ifp == NULL)
4658499c3e17SSepherosa Ziehau 			continue;
4659499c3e17SSepherosa Ziehau 
4660499c3e17SSepherosa Ziehau 		ifp = ifnet_byindex(i);
4661499c3e17SSepherosa Ziehau 		if (ifp != NULL) {
4662499c3e17SSepherosa Ziehau 			if (first) {
4663499c3e17SSepherosa Ziehau 				sbuf_printf(sb, "%s:%s", ifp->if_xname,
4664499c3e17SSepherosa Ziehau 				    hn_ifp->if_xname);
4665499c3e17SSepherosa Ziehau 			} else {
4666499c3e17SSepherosa Ziehau 				sbuf_printf(sb, " %s:%s", ifp->if_xname,
4667499c3e17SSepherosa Ziehau 				    hn_ifp->if_xname);
4668499c3e17SSepherosa Ziehau 			}
4669499c3e17SSepherosa Ziehau 			first = false;
4670499c3e17SSepherosa Ziehau 		}
4671499c3e17SSepherosa Ziehau 	}
4672499c3e17SSepherosa Ziehau 
4673499c3e17SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
4674499c3e17SSepherosa Ziehau 
4675499c3e17SSepherosa Ziehau 	error = sbuf_finish(sb);
4676499c3e17SSepherosa Ziehau 	sbuf_delete(sb);
4677499c3e17SSepherosa Ziehau 	return (error);
4678499c3e17SSepherosa Ziehau }
4679499c3e17SSepherosa Ziehau 
4680499c3e17SSepherosa Ziehau static int
46819c6cae24SSepherosa Ziehau hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS)
46829c6cae24SSepherosa Ziehau {
46839c6cae24SSepherosa Ziehau 	struct hn_softc *sc = arg1;
46849c6cae24SSepherosa Ziehau 	int error, onoff = 0;
46859c6cae24SSepherosa Ziehau 
46869c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF)
46879c6cae24SSepherosa Ziehau 		onoff = 1;
46889c6cae24SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &onoff, 0, req);
46899c6cae24SSepherosa Ziehau 	if (error || req->newptr == NULL)
46909c6cae24SSepherosa Ziehau 		return (error);
46919c6cae24SSepherosa Ziehau 
46929c6cae24SSepherosa Ziehau 	HN_LOCK(sc);
46939c6cae24SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit() */
46949c6cae24SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
46959c6cae24SSepherosa Ziehau 	if (onoff)
46969c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF;
46979c6cae24SSepherosa Ziehau 	else
46989c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags &= ~HN_XVFFLAG_ACCBPF;
46999c6cae24SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
47009c6cae24SSepherosa Ziehau 	HN_UNLOCK(sc);
47019c6cae24SSepherosa Ziehau 
47029c6cae24SSepherosa Ziehau 	return (0);
47039c6cae24SSepherosa Ziehau }
47049c6cae24SSepherosa Ziehau 
47059c6cae24SSepherosa Ziehau static int
47069c6cae24SSepherosa Ziehau hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS)
47079c6cae24SSepherosa Ziehau {
47089c6cae24SSepherosa Ziehau 	struct hn_softc *sc = arg1;
47099c6cae24SSepherosa Ziehau 	int enabled = 0;
47109c6cae24SSepherosa Ziehau 
47119c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
47129c6cae24SSepherosa Ziehau 		enabled = 1;
47139c6cae24SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &enabled, 0, req));
47149c6cae24SSepherosa Ziehau }
47159c6cae24SSepherosa Ziehau 
47169c6cae24SSepherosa Ziehau static int
471715516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff)
471815516c77SSepherosa Ziehau {
471915516c77SSepherosa Ziehau 	const struct ip *ip;
472015516c77SSepherosa Ziehau 	int len, iphlen, iplen;
472115516c77SSepherosa Ziehau 	const struct tcphdr *th;
472215516c77SSepherosa Ziehau 	int thoff;				/* TCP data offset */
472315516c77SSepherosa Ziehau 
472415516c77SSepherosa Ziehau 	len = hoff + sizeof(struct ip);
472515516c77SSepherosa Ziehau 
472615516c77SSepherosa Ziehau 	/* The packet must be at least the size of an IP header. */
472715516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < len)
472815516c77SSepherosa Ziehau 		return IPPROTO_DONE;
472915516c77SSepherosa Ziehau 
473015516c77SSepherosa Ziehau 	/* The fixed IP header must reside completely in the first mbuf. */
473115516c77SSepherosa Ziehau 	if (m->m_len < len)
473215516c77SSepherosa Ziehau 		return IPPROTO_DONE;
473315516c77SSepherosa Ziehau 
473415516c77SSepherosa Ziehau 	ip = mtodo(m, hoff);
473515516c77SSepherosa Ziehau 
473615516c77SSepherosa Ziehau 	/* Bound check the packet's stated IP header length. */
473715516c77SSepherosa Ziehau 	iphlen = ip->ip_hl << 2;
473815516c77SSepherosa Ziehau 	if (iphlen < sizeof(struct ip))		/* minimum header length */
473915516c77SSepherosa Ziehau 		return IPPROTO_DONE;
474015516c77SSepherosa Ziehau 
474115516c77SSepherosa Ziehau 	/* The full IP header must reside completely in the one mbuf. */
474215516c77SSepherosa Ziehau 	if (m->m_len < hoff + iphlen)
474315516c77SSepherosa Ziehau 		return IPPROTO_DONE;
474415516c77SSepherosa Ziehau 
474515516c77SSepherosa Ziehau 	iplen = ntohs(ip->ip_len);
474615516c77SSepherosa Ziehau 
474715516c77SSepherosa Ziehau 	/*
474815516c77SSepherosa Ziehau 	 * Check that the amount of data in the buffers is as
474915516c77SSepherosa Ziehau 	 * at least much as the IP header would have us expect.
475015516c77SSepherosa Ziehau 	 */
475115516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < hoff + iplen)
475215516c77SSepherosa Ziehau 		return IPPROTO_DONE;
475315516c77SSepherosa Ziehau 
475415516c77SSepherosa Ziehau 	/*
475515516c77SSepherosa Ziehau 	 * Ignore IP fragments.
475615516c77SSepherosa Ziehau 	 */
475715516c77SSepherosa Ziehau 	if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF))
475815516c77SSepherosa Ziehau 		return IPPROTO_DONE;
475915516c77SSepherosa Ziehau 
476015516c77SSepherosa Ziehau 	/*
476115516c77SSepherosa Ziehau 	 * The TCP/IP or UDP/IP header must be entirely contained within
476215516c77SSepherosa Ziehau 	 * the first fragment of a packet.
476315516c77SSepherosa Ziehau 	 */
476415516c77SSepherosa Ziehau 	switch (ip->ip_p) {
476515516c77SSepherosa Ziehau 	case IPPROTO_TCP:
476615516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct tcphdr))
476715516c77SSepherosa Ziehau 			return IPPROTO_DONE;
476815516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct tcphdr))
476915516c77SSepherosa Ziehau 			return IPPROTO_DONE;
477015516c77SSepherosa Ziehau 		th = (const struct tcphdr *)((const uint8_t *)ip + iphlen);
477115516c77SSepherosa Ziehau 		thoff = th->th_off << 2;
477215516c77SSepherosa Ziehau 		if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen)
477315516c77SSepherosa Ziehau 			return IPPROTO_DONE;
477415516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + thoff)
477515516c77SSepherosa Ziehau 			return IPPROTO_DONE;
477615516c77SSepherosa Ziehau 		break;
477715516c77SSepherosa Ziehau 	case IPPROTO_UDP:
477815516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct udphdr))
477915516c77SSepherosa Ziehau 			return IPPROTO_DONE;
478015516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct udphdr))
478115516c77SSepherosa Ziehau 			return IPPROTO_DONE;
478215516c77SSepherosa Ziehau 		break;
478315516c77SSepherosa Ziehau 	default:
478415516c77SSepherosa Ziehau 		if (iplen < iphlen)
478515516c77SSepherosa Ziehau 			return IPPROTO_DONE;
478615516c77SSepherosa Ziehau 		break;
478715516c77SSepherosa Ziehau 	}
478815516c77SSepherosa Ziehau 	return ip->ip_p;
478915516c77SSepherosa Ziehau }
479015516c77SSepherosa Ziehau 
479115516c77SSepherosa Ziehau static int
479215516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt)
479315516c77SSepherosa Ziehau {
479415516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
479515516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
479615516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
479715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
479815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
479915516c77SSepherosa Ziehau 	int lroent_cnt;
480015516c77SSepherosa Ziehau #endif
480115516c77SSepherosa Ziehau #endif
480215516c77SSepherosa Ziehau 	int i;
480315516c77SSepherosa Ziehau 
480415516c77SSepherosa Ziehau 	/*
480515516c77SSepherosa Ziehau 	 * Create RXBUF for reception.
480615516c77SSepherosa Ziehau 	 *
480715516c77SSepherosa Ziehau 	 * NOTE:
480815516c77SSepherosa Ziehau 	 * - It is shared by all channels.
480915516c77SSepherosa Ziehau 	 * - A large enough buffer is allocated, certain version of NVSes
481015516c77SSepherosa Ziehau 	 *   may further limit the usable space.
481115516c77SSepherosa Ziehau 	 */
481215516c77SSepherosa Ziehau 	sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
481315516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma,
481415516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
481515516c77SSepherosa Ziehau 	if (sc->hn_rxbuf == NULL) {
481615516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate rxbuf failed\n");
481715516c77SSepherosa Ziehau 		return (ENOMEM);
481815516c77SSepherosa Ziehau 	}
481915516c77SSepherosa Ziehau 
482015516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = ring_cnt;
482115516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt;
482215516c77SSepherosa Ziehau 
482315516c77SSepherosa Ziehau 	sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt,
482415516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
482515516c77SSepherosa Ziehau 
482615516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
482715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
482815516c77SSepherosa Ziehau 	lroent_cnt = hn_lro_entry_count;
482915516c77SSepherosa Ziehau 	if (lroent_cnt < TCP_LRO_ENTRIES)
483015516c77SSepherosa Ziehau 		lroent_cnt = TCP_LRO_ENTRIES;
483115516c77SSepherosa Ziehau 	if (bootverbose)
483215516c77SSepherosa Ziehau 		device_printf(dev, "LRO: entry count %d\n", lroent_cnt);
483315516c77SSepherosa Ziehau #endif
483415516c77SSepherosa Ziehau #endif	/* INET || INET6 */
483515516c77SSepherosa Ziehau 
483615516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
483715516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
483815516c77SSepherosa Ziehau 
483915516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.rx sysctl tree */
484015516c77SSepherosa Ziehau 	sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx",
484115516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
484215516c77SSepherosa Ziehau 
484315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
484415516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
484515516c77SSepherosa Ziehau 
484615516c77SSepherosa Ziehau 		rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
484715516c77SSepherosa Ziehau 		    PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE,
484815516c77SSepherosa Ziehau 		    &rxr->hn_br_dma, BUS_DMA_WAITOK);
484915516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL) {
485015516c77SSepherosa Ziehau 			device_printf(dev, "allocate bufring failed\n");
485115516c77SSepherosa Ziehau 			return (ENOMEM);
485215516c77SSepherosa Ziehau 		}
485315516c77SSepherosa Ziehau 
485415516c77SSepherosa Ziehau 		if (hn_trust_hosttcp)
485515516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP;
485615516c77SSepherosa Ziehau 		if (hn_trust_hostudp)
485715516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP;
485815516c77SSepherosa Ziehau 		if (hn_trust_hostip)
485915516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP;
4860642ec226SSepherosa Ziehau 		rxr->hn_mbuf_hash = NDIS_HASH_ALL;
486115516c77SSepherosa Ziehau 		rxr->hn_ifp = sc->hn_ifp;
486215516c77SSepherosa Ziehau 		if (i < sc->hn_tx_ring_cnt)
486315516c77SSepherosa Ziehau 			rxr->hn_txr = &sc->hn_tx_ring[i];
486415516c77SSepherosa Ziehau 		rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF;
486515516c77SSepherosa Ziehau 		rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK);
486615516c77SSepherosa Ziehau 		rxr->hn_rx_idx = i;
486715516c77SSepherosa Ziehau 		rxr->hn_rxbuf = sc->hn_rxbuf;
486815516c77SSepherosa Ziehau 
486915516c77SSepherosa Ziehau 		/*
487015516c77SSepherosa Ziehau 		 * Initialize LRO.
487115516c77SSepherosa Ziehau 		 */
487215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
487315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
487415516c77SSepherosa Ziehau 		tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt,
487515516c77SSepherosa Ziehau 		    hn_lro_mbufq_depth);
487615516c77SSepherosa Ziehau #else
487715516c77SSepherosa Ziehau 		tcp_lro_init(&rxr->hn_lro);
487815516c77SSepherosa Ziehau 		rxr->hn_lro.ifp = sc->hn_ifp;
487915516c77SSepherosa Ziehau #endif
488015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
488115516c77SSepherosa Ziehau 		rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF;
488215516c77SSepherosa Ziehau 		rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF;
488315516c77SSepherosa Ziehau #endif
488415516c77SSepherosa Ziehau #endif	/* INET || INET6 */
488515516c77SSepherosa Ziehau 
488615516c77SSepherosa Ziehau 		if (sc->hn_rx_sysctl_tree != NULL) {
488715516c77SSepherosa Ziehau 			char name[16];
488815516c77SSepherosa Ziehau 
488915516c77SSepherosa Ziehau 			/*
489015516c77SSepherosa Ziehau 			 * Create per RX ring sysctl tree:
489115516c77SSepherosa Ziehau 			 * dev.hn.UNIT.rx.RINGID
489215516c77SSepherosa Ziehau 			 */
489315516c77SSepherosa Ziehau 			snprintf(name, sizeof(name), "%d", i);
489415516c77SSepherosa Ziehau 			rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx,
489515516c77SSepherosa Ziehau 			    SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree),
489615516c77SSepherosa Ziehau 			    OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
489715516c77SSepherosa Ziehau 
489815516c77SSepherosa Ziehau 			if (rxr->hn_rx_sysctl_tree != NULL) {
489915516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
490015516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
490115516c77SSepherosa Ziehau 				    OID_AUTO, "packets", CTLFLAG_RW,
490215516c77SSepherosa Ziehau 				    &rxr->hn_pkts, "# of packets received");
490315516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
490415516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
490515516c77SSepherosa Ziehau 				    OID_AUTO, "rss_pkts", CTLFLAG_RW,
490615516c77SSepherosa Ziehau 				    &rxr->hn_rss_pkts,
490715516c77SSepherosa Ziehau 				    "# of packets w/ RSS info received");
490815516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx,
490915516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
491015516c77SSepherosa Ziehau 				    OID_AUTO, "pktbuf_len", CTLFLAG_RD,
491115516c77SSepherosa Ziehau 				    &rxr->hn_pktbuf_len, 0,
491215516c77SSepherosa Ziehau 				    "Temporary channel packet buffer length");
491315516c77SSepherosa Ziehau 			}
491415516c77SSepherosa Ziehau 		}
491515516c77SSepherosa Ziehau 	}
491615516c77SSepherosa Ziehau 
491715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued",
491815516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
491915516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_queued),
492015516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
492115516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
492215516c77SSepherosa Ziehau #else
492315516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
492415516c77SSepherosa Ziehau #endif
492515516c77SSepherosa Ziehau 	    "LU", "LRO queued");
492615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed",
492715516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
492815516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_flushed),
492915516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
493015516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
493115516c77SSepherosa Ziehau #else
493215516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
493315516c77SSepherosa Ziehau #endif
493415516c77SSepherosa Ziehau 	    "LU", "LRO flushed");
493515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried",
493615516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
493715516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro_tried),
493815516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries");
493915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
494015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim",
494115516c77SSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
494215516c77SSepherosa Ziehau 	    hn_lro_lenlim_sysctl, "IU",
494315516c77SSepherosa Ziehau 	    "Max # of data bytes to be aggregated by LRO");
494415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim",
494515516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
494615516c77SSepherosa Ziehau 	    hn_lro_ackcnt_sysctl, "I",
494715516c77SSepherosa Ziehau 	    "Max # of ACKs to be aggregated by LRO");
494815516c77SSepherosa Ziehau #endif
494915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp",
495015516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP,
495115516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
495215516c77SSepherosa Ziehau 	    "Trust tcp segement verification on host side, "
495315516c77SSepherosa Ziehau 	    "when csum info is missing");
495415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp",
495515516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP,
495615516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
495715516c77SSepherosa Ziehau 	    "Trust udp datagram verification on host side, "
495815516c77SSepherosa Ziehau 	    "when csum info is missing");
495915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip",
496015516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP,
496115516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
496215516c77SSepherosa Ziehau 	    "Trust ip packet verification on host side, "
496315516c77SSepherosa Ziehau 	    "when csum info is missing");
496415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip",
496515516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
496615516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_ip),
496715516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP");
496815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp",
496915516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
497015516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_tcp),
497115516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP");
497215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp",
497315516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
497415516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_udp),
497515516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP");
497615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted",
497715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
497815516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_trusted),
497915516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU",
498015516c77SSepherosa Ziehau 	    "# of packets that we trust host's csum verification");
498115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts",
498215516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
498315516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_small_pkts),
498415516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of small packets received");
498515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed",
498615516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
498715516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_ack_failed),
498815516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures");
498915516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt",
499015516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings");
499115516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse",
499215516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings");
499315516c77SSepherosa Ziehau 
499415516c77SSepherosa Ziehau 	return (0);
499515516c77SSepherosa Ziehau }
499615516c77SSepherosa Ziehau 
499715516c77SSepherosa Ziehau static void
499815516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc)
499915516c77SSepherosa Ziehau {
500015516c77SSepherosa Ziehau 	int i;
500115516c77SSepherosa Ziehau 
500215516c77SSepherosa Ziehau 	if (sc->hn_rxbuf != NULL) {
50032494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0)
500415516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf);
50052494d735SSepherosa Ziehau 		else
50062494d735SSepherosa Ziehau 			device_printf(sc->hn_dev, "RXBUF is referenced\n");
500715516c77SSepherosa Ziehau 		sc->hn_rxbuf = NULL;
500815516c77SSepherosa Ziehau 	}
500915516c77SSepherosa Ziehau 
501015516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_cnt == 0)
501115516c77SSepherosa Ziehau 		return;
501215516c77SSepherosa Ziehau 
501315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
501415516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
501515516c77SSepherosa Ziehau 
501615516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL)
501715516c77SSepherosa Ziehau 			continue;
50182494d735SSepherosa Ziehau 		if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) {
501915516c77SSepherosa Ziehau 			hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br);
50202494d735SSepherosa Ziehau 		} else {
50212494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
50222494d735SSepherosa Ziehau 			    "%dth channel bufring is referenced", i);
50232494d735SSepherosa Ziehau 		}
502415516c77SSepherosa Ziehau 		rxr->hn_br = NULL;
502515516c77SSepherosa Ziehau 
502615516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
502715516c77SSepherosa Ziehau 		tcp_lro_free(&rxr->hn_lro);
502815516c77SSepherosa Ziehau #endif
502915516c77SSepherosa Ziehau 		free(rxr->hn_pktbuf, M_DEVBUF);
503015516c77SSepherosa Ziehau 	}
503115516c77SSepherosa Ziehau 	free(sc->hn_rx_ring, M_DEVBUF);
503215516c77SSepherosa Ziehau 	sc->hn_rx_ring = NULL;
503315516c77SSepherosa Ziehau 
503415516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = 0;
503515516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = 0;
503615516c77SSepherosa Ziehau }
503715516c77SSepherosa Ziehau 
503815516c77SSepherosa Ziehau static int
503915516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id)
504015516c77SSepherosa Ziehau {
504115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[id];
504215516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
504315516c77SSepherosa Ziehau 	bus_dma_tag_t parent_dtag;
504415516c77SSepherosa Ziehau 	int error, i;
504515516c77SSepherosa Ziehau 
504615516c77SSepherosa Ziehau 	txr->hn_sc = sc;
504715516c77SSepherosa Ziehau 	txr->hn_tx_idx = id;
504815516c77SSepherosa Ziehau 
504915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
505015516c77SSepherosa Ziehau 	mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN);
505115516c77SSepherosa Ziehau #endif
505215516c77SSepherosa Ziehau 	mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF);
505315516c77SSepherosa Ziehau 
505415516c77SSepherosa Ziehau 	txr->hn_txdesc_cnt = HN_TX_DESC_CNT;
505515516c77SSepherosa Ziehau 	txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt,
505615516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
505715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
505815516c77SSepherosa Ziehau 	SLIST_INIT(&txr->hn_txlist);
505915516c77SSepherosa Ziehau #else
506015516c77SSepherosa Ziehau 	txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF,
506115516c77SSepherosa Ziehau 	    M_WAITOK, &txr->hn_tx_lock);
506215516c77SSepherosa Ziehau #endif
506315516c77SSepherosa Ziehau 
50640e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_EVTTQ) {
50650e11868dSSepherosa Ziehau 		txr->hn_tx_taskq = VMBUS_GET_EVENT_TASKQ(
50660e11868dSSepherosa Ziehau 		    device_get_parent(dev), dev, HN_RING_IDX2CPU(sc, id));
50670e11868dSSepherosa Ziehau 	} else {
5068fdd0222aSSepherosa Ziehau 		txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt];
50690e11868dSSepherosa Ziehau 	}
507015516c77SSepherosa Ziehau 
507123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
507215516c77SSepherosa Ziehau 	if (hn_use_if_start) {
507315516c77SSepherosa Ziehau 		txr->hn_txeof = hn_start_txeof;
507415516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr);
507515516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr);
507623bf9e15SSepherosa Ziehau 	} else
507723bf9e15SSepherosa Ziehau #endif
507823bf9e15SSepherosa Ziehau 	{
507915516c77SSepherosa Ziehau 		int br_depth;
508015516c77SSepherosa Ziehau 
508115516c77SSepherosa Ziehau 		txr->hn_txeof = hn_xmit_txeof;
508215516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr);
508315516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr);
508415516c77SSepherosa Ziehau 
508515516c77SSepherosa Ziehau 		br_depth = hn_get_txswq_depth(txr);
508615516c77SSepherosa Ziehau 		txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF,
508715516c77SSepherosa Ziehau 		    M_WAITOK, &txr->hn_tx_lock);
508815516c77SSepherosa Ziehau 	}
508915516c77SSepherosa Ziehau 
509015516c77SSepherosa Ziehau 	txr->hn_direct_tx_size = hn_direct_tx_size;
509115516c77SSepherosa Ziehau 
509215516c77SSepherosa Ziehau 	/*
509315516c77SSepherosa Ziehau 	 * Always schedule transmission instead of trying to do direct
509415516c77SSepherosa Ziehau 	 * transmission.  This one gives the best performance so far.
509515516c77SSepherosa Ziehau 	 */
509615516c77SSepherosa Ziehau 	txr->hn_sched_tx = 1;
509715516c77SSepherosa Ziehau 
509815516c77SSepherosa Ziehau 	parent_dtag = bus_get_dma_tag(dev);
509915516c77SSepherosa Ziehau 
510015516c77SSepherosa Ziehau 	/* DMA tag for RNDIS packet messages. */
510115516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
510215516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_ALIGN,		/* alignment */
510315516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_BOUNDARY,	/* boundary */
510415516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
510515516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
510615516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
510715516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsize */
510815516c77SSepherosa Ziehau 	    1,				/* nsegments */
510915516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsegsize */
511015516c77SSepherosa Ziehau 	    0,				/* flags */
511115516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
511215516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
511315516c77SSepherosa Ziehau 	    &txr->hn_tx_rndis_dtag);
511415516c77SSepherosa Ziehau 	if (error) {
511515516c77SSepherosa Ziehau 		device_printf(dev, "failed to create rndis dmatag\n");
511615516c77SSepherosa Ziehau 		return error;
511715516c77SSepherosa Ziehau 	}
511815516c77SSepherosa Ziehau 
511915516c77SSepherosa Ziehau 	/* DMA tag for data. */
512015516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
512115516c77SSepherosa Ziehau 	    1,				/* alignment */
512215516c77SSepherosa Ziehau 	    HN_TX_DATA_BOUNDARY,	/* boundary */
512315516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
512415516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
512515516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
512615516c77SSepherosa Ziehau 	    HN_TX_DATA_MAXSIZE,		/* maxsize */
512715516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGCNT_MAX,	/* nsegments */
512815516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGSIZE,		/* maxsegsize */
512915516c77SSepherosa Ziehau 	    0,				/* flags */
513015516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
513115516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
513215516c77SSepherosa Ziehau 	    &txr->hn_tx_data_dtag);
513315516c77SSepherosa Ziehau 	if (error) {
513415516c77SSepherosa Ziehau 		device_printf(dev, "failed to create data dmatag\n");
513515516c77SSepherosa Ziehau 		return error;
513615516c77SSepherosa Ziehau 	}
513715516c77SSepherosa Ziehau 
513815516c77SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i) {
513915516c77SSepherosa Ziehau 		struct hn_txdesc *txd = &txr->hn_txdesc[i];
514015516c77SSepherosa Ziehau 
514115516c77SSepherosa Ziehau 		txd->txr = txr;
514215516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
5143dc13fee6SSepherosa Ziehau 		STAILQ_INIT(&txd->agg_list);
514415516c77SSepherosa Ziehau 
514515516c77SSepherosa Ziehau 		/*
514615516c77SSepherosa Ziehau 		 * Allocate and load RNDIS packet message.
514715516c77SSepherosa Ziehau 		 */
514815516c77SSepherosa Ziehau         	error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag,
514915516c77SSepherosa Ziehau 		    (void **)&txd->rndis_pkt,
515015516c77SSepherosa Ziehau 		    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
515115516c77SSepherosa Ziehau 		    &txd->rndis_pkt_dmap);
515215516c77SSepherosa Ziehau 		if (error) {
515315516c77SSepherosa Ziehau 			device_printf(dev,
515415516c77SSepherosa Ziehau 			    "failed to allocate rndis_packet_msg, %d\n", i);
515515516c77SSepherosa Ziehau 			return error;
515615516c77SSepherosa Ziehau 		}
515715516c77SSepherosa Ziehau 
515815516c77SSepherosa Ziehau 		error = bus_dmamap_load(txr->hn_tx_rndis_dtag,
515915516c77SSepherosa Ziehau 		    txd->rndis_pkt_dmap,
516015516c77SSepherosa Ziehau 		    txd->rndis_pkt, HN_RNDIS_PKT_LEN,
516115516c77SSepherosa Ziehau 		    hyperv_dma_map_paddr, &txd->rndis_pkt_paddr,
516215516c77SSepherosa Ziehau 		    BUS_DMA_NOWAIT);
516315516c77SSepherosa Ziehau 		if (error) {
516415516c77SSepherosa Ziehau 			device_printf(dev,
516515516c77SSepherosa Ziehau 			    "failed to load rndis_packet_msg, %d\n", i);
516615516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
516715516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
516815516c77SSepherosa Ziehau 			return error;
516915516c77SSepherosa Ziehau 		}
517015516c77SSepherosa Ziehau 
517115516c77SSepherosa Ziehau 		/* DMA map for TX data. */
517215516c77SSepherosa Ziehau 		error = bus_dmamap_create(txr->hn_tx_data_dtag, 0,
517315516c77SSepherosa Ziehau 		    &txd->data_dmap);
517415516c77SSepherosa Ziehau 		if (error) {
517515516c77SSepherosa Ziehau 			device_printf(dev,
517615516c77SSepherosa Ziehau 			    "failed to allocate tx data dmamap\n");
517715516c77SSepherosa Ziehau 			bus_dmamap_unload(txr->hn_tx_rndis_dtag,
517815516c77SSepherosa Ziehau 			    txd->rndis_pkt_dmap);
517915516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
518015516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
518115516c77SSepherosa Ziehau 			return error;
518215516c77SSepherosa Ziehau 		}
518315516c77SSepherosa Ziehau 
518415516c77SSepherosa Ziehau 		/* All set, put it to list */
518515516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_ONLIST;
518615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
518715516c77SSepherosa Ziehau 		SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
518815516c77SSepherosa Ziehau #else
518915516c77SSepherosa Ziehau 		buf_ring_enqueue(txr->hn_txdesc_br, txd);
519015516c77SSepherosa Ziehau #endif
519115516c77SSepherosa Ziehau 	}
519215516c77SSepherosa Ziehau 	txr->hn_txdesc_avail = txr->hn_txdesc_cnt;
519315516c77SSepherosa Ziehau 
519415516c77SSepherosa Ziehau 	if (sc->hn_tx_sysctl_tree != NULL) {
519515516c77SSepherosa Ziehau 		struct sysctl_oid_list *child;
519615516c77SSepherosa Ziehau 		struct sysctl_ctx_list *ctx;
519715516c77SSepherosa Ziehau 		char name[16];
519815516c77SSepherosa Ziehau 
519915516c77SSepherosa Ziehau 		/*
520015516c77SSepherosa Ziehau 		 * Create per TX ring sysctl tree:
520115516c77SSepherosa Ziehau 		 * dev.hn.UNIT.tx.RINGID
520215516c77SSepherosa Ziehau 		 */
520315516c77SSepherosa Ziehau 		ctx = device_get_sysctl_ctx(dev);
520415516c77SSepherosa Ziehau 		child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree);
520515516c77SSepherosa Ziehau 
520615516c77SSepherosa Ziehau 		snprintf(name, sizeof(name), "%d", id);
520715516c77SSepherosa Ziehau 		txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
520815516c77SSepherosa Ziehau 		    name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
520915516c77SSepherosa Ziehau 
521015516c77SSepherosa Ziehau 		if (txr->hn_tx_sysctl_tree != NULL) {
521115516c77SSepherosa Ziehau 			child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree);
521215516c77SSepherosa Ziehau 
521385e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
521415516c77SSepherosa Ziehau 			SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail",
521515516c77SSepherosa Ziehau 			    CTLFLAG_RD, &txr->hn_txdesc_avail, 0,
521615516c77SSepherosa Ziehau 			    "# of available TX descs");
521785e4ae1eSSepherosa Ziehau #endif
521823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
521923bf9e15SSepherosa Ziehau 			if (!hn_use_if_start)
522023bf9e15SSepherosa Ziehau #endif
522123bf9e15SSepherosa Ziehau 			{
522215516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive",
522315516c77SSepherosa Ziehau 				    CTLFLAG_RD, &txr->hn_oactive, 0,
522415516c77SSepherosa Ziehau 				    "over active");
522515516c77SSepherosa Ziehau 			}
522615516c77SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets",
522715516c77SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_pkts,
522815516c77SSepherosa Ziehau 			    "# of packets transmitted");
5229dc13fee6SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends",
5230dc13fee6SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_sends, "# of sends");
523115516c77SSepherosa Ziehau 		}
523215516c77SSepherosa Ziehau 	}
523315516c77SSepherosa Ziehau 
523415516c77SSepherosa Ziehau 	return 0;
523515516c77SSepherosa Ziehau }
523615516c77SSepherosa Ziehau 
523715516c77SSepherosa Ziehau static void
523815516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd)
523915516c77SSepherosa Ziehau {
524015516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = txd->txr;
524115516c77SSepherosa Ziehau 
524215516c77SSepherosa Ziehau 	KASSERT(txd->m == NULL, ("still has mbuf installed"));
524315516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped"));
524415516c77SSepherosa Ziehau 
524515516c77SSepherosa Ziehau 	bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap);
524615516c77SSepherosa Ziehau 	bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt,
524715516c77SSepherosa Ziehau 	    txd->rndis_pkt_dmap);
524815516c77SSepherosa Ziehau 	bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap);
524915516c77SSepherosa Ziehau }
525015516c77SSepherosa Ziehau 
525115516c77SSepherosa Ziehau static void
525225641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd)
525325641fc7SSepherosa Ziehau {
525425641fc7SSepherosa Ziehau 
525525641fc7SSepherosa Ziehau 	KASSERT(txd->refs == 0 || txd->refs == 1,
525625641fc7SSepherosa Ziehau 	    ("invalid txd refs %d", txd->refs));
525725641fc7SSepherosa Ziehau 
525825641fc7SSepherosa Ziehau 	/* Aggregated txds will be freed by their aggregating txd. */
525925641fc7SSepherosa Ziehau 	if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) {
526025641fc7SSepherosa Ziehau 		int freed;
526125641fc7SSepherosa Ziehau 
526225641fc7SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
526325641fc7SSepherosa Ziehau 		KASSERT(freed, ("can't free txdesc"));
526425641fc7SSepherosa Ziehau 	}
526525641fc7SSepherosa Ziehau }
526625641fc7SSepherosa Ziehau 
526725641fc7SSepherosa Ziehau static void
526815516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr)
526915516c77SSepherosa Ziehau {
527025641fc7SSepherosa Ziehau 	int i;
527115516c77SSepherosa Ziehau 
527215516c77SSepherosa Ziehau 	if (txr->hn_txdesc == NULL)
527315516c77SSepherosa Ziehau 		return;
527415516c77SSepherosa Ziehau 
527525641fc7SSepherosa Ziehau 	/*
527625641fc7SSepherosa Ziehau 	 * NOTE:
527725641fc7SSepherosa Ziehau 	 * Because the freeing of aggregated txds will be deferred
527825641fc7SSepherosa Ziehau 	 * to the aggregating txd, two passes are used here:
527925641fc7SSepherosa Ziehau 	 * - The first pass GCes any pending txds.  This GC is necessary,
528025641fc7SSepherosa Ziehau 	 *   since if the channels are revoked, hypervisor will not
528125641fc7SSepherosa Ziehau 	 *   deliver send-done for all pending txds.
528225641fc7SSepherosa Ziehau 	 * - The second pass frees the busdma stuffs, i.e. after all txds
528325641fc7SSepherosa Ziehau 	 *   were freed.
528425641fc7SSepherosa Ziehau 	 */
528525641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
528625641fc7SSepherosa Ziehau 		hn_txdesc_gc(txr, &txr->hn_txdesc[i]);
528725641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
528825641fc7SSepherosa Ziehau 		hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]);
528915516c77SSepherosa Ziehau 
529015516c77SSepherosa Ziehau 	if (txr->hn_tx_data_dtag != NULL)
529115516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_data_dtag);
529215516c77SSepherosa Ziehau 	if (txr->hn_tx_rndis_dtag != NULL)
529315516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_rndis_dtag);
529415516c77SSepherosa Ziehau 
529515516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
529615516c77SSepherosa Ziehau 	buf_ring_free(txr->hn_txdesc_br, M_DEVBUF);
529715516c77SSepherosa Ziehau #endif
529815516c77SSepherosa Ziehau 
529915516c77SSepherosa Ziehau 	free(txr->hn_txdesc, M_DEVBUF);
530015516c77SSepherosa Ziehau 	txr->hn_txdesc = NULL;
530115516c77SSepherosa Ziehau 
530215516c77SSepherosa Ziehau 	if (txr->hn_mbuf_br != NULL)
530315516c77SSepherosa Ziehau 		buf_ring_free(txr->hn_mbuf_br, M_DEVBUF);
530415516c77SSepherosa Ziehau 
530515516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
530615516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_txlist_spin);
530715516c77SSepherosa Ziehau #endif
530815516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_tx_lock);
530915516c77SSepherosa Ziehau }
531015516c77SSepherosa Ziehau 
531115516c77SSepherosa Ziehau static int
531215516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt)
531315516c77SSepherosa Ziehau {
531415516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
531515516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
531615516c77SSepherosa Ziehau 	int i;
531715516c77SSepherosa Ziehau 
531815516c77SSepherosa Ziehau 	/*
531915516c77SSepherosa Ziehau 	 * Create TXBUF for chimney sending.
532015516c77SSepherosa Ziehau 	 *
532115516c77SSepherosa Ziehau 	 * NOTE: It is shared by all channels.
532215516c77SSepherosa Ziehau 	 */
532315516c77SSepherosa Ziehau 	sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev),
532415516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma,
532515516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
532615516c77SSepherosa Ziehau 	if (sc->hn_chim == NULL) {
532715516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate txbuf failed\n");
532815516c77SSepherosa Ziehau 		return (ENOMEM);
532915516c77SSepherosa Ziehau 	}
533015516c77SSepherosa Ziehau 
533115516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = ring_cnt;
533215516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
533315516c77SSepherosa Ziehau 
533415516c77SSepherosa Ziehau 	sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt,
533515516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
533615516c77SSepherosa Ziehau 
533715516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(sc->hn_dev);
533815516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev));
533915516c77SSepherosa Ziehau 
534015516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.tx sysctl tree */
534115516c77SSepherosa Ziehau 	sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx",
534215516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
534315516c77SSepherosa Ziehau 
534415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
534515516c77SSepherosa Ziehau 		int error;
534615516c77SSepherosa Ziehau 
534715516c77SSepherosa Ziehau 		error = hn_tx_ring_create(sc, i);
534815516c77SSepherosa Ziehau 		if (error)
534915516c77SSepherosa Ziehau 			return error;
535015516c77SSepherosa Ziehau 	}
535115516c77SSepherosa Ziehau 
535215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs",
535315516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
535415516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_no_txdescs),
535515516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs");
535615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed",
535715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
535815516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_send_failed),
535915516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure");
536015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed",
536115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
536215516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_txdma_failed),
536315516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure");
5364dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed",
5365dc13fee6SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
5366dc13fee6SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_flush_failed),
5367dc13fee6SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU",
5368dc13fee6SSepherosa Ziehau 	    "# of packet transmission aggregation flush failure");
536915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed",
537015516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
537115516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_collapsed),
537215516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed");
537315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney",
537415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
537515516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney),
537615516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send");
537715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried",
537815516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
537915516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney_tried),
538015516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries");
538115516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt",
538215516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0,
538315516c77SSepherosa Ziehau 	    "# of total TX descs");
538415516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max",
538515516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_chim_szmax, 0,
538615516c77SSepherosa Ziehau 	    "Chimney send packet size upper boundary");
538715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size",
538815516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
538915516c77SSepherosa Ziehau 	    hn_chim_size_sysctl, "I", "Chimney send packet size limit");
539015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size",
539115516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
539215516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_direct_tx_size),
539315516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
539415516c77SSepherosa Ziehau 	    "Size of the packet for direct transmission");
539515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx",
539615516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
539715516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_sched_tx),
539815516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
539915516c77SSepherosa Ziehau 	    "Always schedule transmission "
540015516c77SSepherosa Ziehau 	    "instead of doing direct transmission");
540115516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt",
540215516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings");
540315516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse",
540415516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings");
5405dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax",
5406dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0,
5407dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation size");
5408dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax",
5409dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
5410dc13fee6SSepherosa Ziehau 	    hn_txagg_pktmax_sysctl, "I",
5411dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation packets");
5412dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align",
5413dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
5414dc13fee6SSepherosa Ziehau 	    hn_txagg_align_sysctl, "I",
5415dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation alignment");
541615516c77SSepherosa Ziehau 
541715516c77SSepherosa Ziehau 	return 0;
541815516c77SSepherosa Ziehau }
541915516c77SSepherosa Ziehau 
542015516c77SSepherosa Ziehau static void
542115516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size)
542215516c77SSepherosa Ziehau {
542315516c77SSepherosa Ziehau 	int i;
542415516c77SSepherosa Ziehau 
5425a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
542615516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_chim_size = chim_size;
542715516c77SSepherosa Ziehau }
542815516c77SSepherosa Ziehau 
542915516c77SSepherosa Ziehau static void
543015516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu)
543115516c77SSepherosa Ziehau {
543215516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
54339c6cae24SSepherosa Ziehau 	u_int hw_tsomax;
543415516c77SSepherosa Ziehau 	int tso_minlen;
543515516c77SSepherosa Ziehau 
54369c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
54379c6cae24SSepherosa Ziehau 
543815516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0)
543915516c77SSepherosa Ziehau 		return;
544015516c77SSepherosa Ziehau 
544115516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_sgmin >= 2,
544215516c77SSepherosa Ziehau 	    ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin));
544315516c77SSepherosa Ziehau 	tso_minlen = sc->hn_ndis_tso_sgmin * mtu;
544415516c77SSepherosa Ziehau 
544515516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen &&
544615516c77SSepherosa Ziehau 	    sc->hn_ndis_tso_szmax <= IP_MAXPACKET,
544715516c77SSepherosa Ziehau 	    ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax));
544815516c77SSepherosa Ziehau 
544915516c77SSepherosa Ziehau 	if (tso_maxlen < tso_minlen)
545015516c77SSepherosa Ziehau 		tso_maxlen = tso_minlen;
545115516c77SSepherosa Ziehau 	else if (tso_maxlen > IP_MAXPACKET)
545215516c77SSepherosa Ziehau 		tso_maxlen = IP_MAXPACKET;
545315516c77SSepherosa Ziehau 	if (tso_maxlen > sc->hn_ndis_tso_szmax)
545415516c77SSepherosa Ziehau 		tso_maxlen = sc->hn_ndis_tso_szmax;
54559c6cae24SSepherosa Ziehau 	hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
54569c6cae24SSepherosa Ziehau 
54579c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_isready(sc)) {
54589c6cae24SSepherosa Ziehau 		if (hw_tsomax > sc->hn_vf_ifp->if_hw_tsomax)
54599c6cae24SSepherosa Ziehau 			hw_tsomax = sc->hn_vf_ifp->if_hw_tsomax;
54609c6cae24SSepherosa Ziehau 	}
54619c6cae24SSepherosa Ziehau 	ifp->if_hw_tsomax = hw_tsomax;
546215516c77SSepherosa Ziehau 	if (bootverbose)
546315516c77SSepherosa Ziehau 		if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax);
546415516c77SSepherosa Ziehau }
546515516c77SSepherosa Ziehau 
546615516c77SSepherosa Ziehau static void
546715516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc)
546815516c77SSepherosa Ziehau {
546915516c77SSepherosa Ziehau 	uint64_t csum_assist;
547015516c77SSepherosa Ziehau 	int i;
547115516c77SSepherosa Ziehau 
547215516c77SSepherosa Ziehau 	hn_set_chim_size(sc, sc->hn_chim_szmax);
547315516c77SSepherosa Ziehau 	if (hn_tx_chimney_size > 0 &&
547415516c77SSepherosa Ziehau 	    hn_tx_chimney_size < sc->hn_chim_szmax)
547515516c77SSepherosa Ziehau 		hn_set_chim_size(sc, hn_tx_chimney_size);
547615516c77SSepherosa Ziehau 
547715516c77SSepherosa Ziehau 	csum_assist = 0;
547815516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_IPCS)
547915516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP;
548015516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP4CS)
548115516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_TCP;
548215516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP4CS)
548315516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_UDP;
548415516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP6CS)
548515516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_TCP;
548615516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP6CS)
548715516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_UDP;
548815516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
548915516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_csum_assist = csum_assist;
549015516c77SSepherosa Ziehau 
549115516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_HASHVAL) {
549215516c77SSepherosa Ziehau 		/*
549315516c77SSepherosa Ziehau 		 * Support HASHVAL pktinfo on TX path.
549415516c77SSepherosa Ziehau 		 */
549515516c77SSepherosa Ziehau 		if (bootverbose)
549615516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n");
549715516c77SSepherosa Ziehau 		for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
549815516c77SSepherosa Ziehau 			sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL;
549915516c77SSepherosa Ziehau 	}
550015516c77SSepherosa Ziehau }
550115516c77SSepherosa Ziehau 
550215516c77SSepherosa Ziehau static void
550315516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc)
550415516c77SSepherosa Ziehau {
550515516c77SSepherosa Ziehau 	int i;
550615516c77SSepherosa Ziehau 
550715516c77SSepherosa Ziehau 	if (sc->hn_chim != NULL) {
55082494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) {
550915516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim);
55102494d735SSepherosa Ziehau 		} else {
55112494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
55122494d735SSepherosa Ziehau 			    "chimney sending buffer is referenced");
55132494d735SSepherosa Ziehau 		}
551415516c77SSepherosa Ziehau 		sc->hn_chim = NULL;
551515516c77SSepherosa Ziehau 	}
551615516c77SSepherosa Ziehau 
551715516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt == 0)
551815516c77SSepherosa Ziehau 		return;
551915516c77SSepherosa Ziehau 
552015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
552115516c77SSepherosa Ziehau 		hn_tx_ring_destroy(&sc->hn_tx_ring[i]);
552215516c77SSepherosa Ziehau 
552315516c77SSepherosa Ziehau 	free(sc->hn_tx_ring, M_DEVBUF);
552415516c77SSepherosa Ziehau 	sc->hn_tx_ring = NULL;
552515516c77SSepherosa Ziehau 
552615516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = 0;
552715516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = 0;
552815516c77SSepherosa Ziehau }
552915516c77SSepherosa Ziehau 
553023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
553123bf9e15SSepherosa Ziehau 
553215516c77SSepherosa Ziehau static void
553315516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused)
553415516c77SSepherosa Ziehau {
553515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
553615516c77SSepherosa Ziehau 
553715516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
553815516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
553915516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
554015516c77SSepherosa Ziehau }
554115516c77SSepherosa Ziehau 
554223bf9e15SSepherosa Ziehau static int
554323bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len)
554423bf9e15SSepherosa Ziehau {
554523bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
554623bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
5547dc13fee6SSepherosa Ziehau 	int sched = 0;
554823bf9e15SSepherosa Ziehau 
554923bf9e15SSepherosa Ziehau 	KASSERT(hn_use_if_start,
555023bf9e15SSepherosa Ziehau 	    ("hn_start_locked is called, when if_start is disabled"));
555123bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
555223bf9e15SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
5553dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
555423bf9e15SSepherosa Ziehau 
555523bf9e15SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
5556dc13fee6SSepherosa Ziehau 		return (0);
555723bf9e15SSepherosa Ziehau 
555823bf9e15SSepherosa Ziehau 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
555923bf9e15SSepherosa Ziehau 	    IFF_DRV_RUNNING)
5560dc13fee6SSepherosa Ziehau 		return (0);
556123bf9e15SSepherosa Ziehau 
556223bf9e15SSepherosa Ziehau 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
556323bf9e15SSepherosa Ziehau 		struct hn_txdesc *txd;
556423bf9e15SSepherosa Ziehau 		struct mbuf *m_head;
556523bf9e15SSepherosa Ziehau 		int error;
556623bf9e15SSepherosa Ziehau 
556723bf9e15SSepherosa Ziehau 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
556823bf9e15SSepherosa Ziehau 		if (m_head == NULL)
556923bf9e15SSepherosa Ziehau 			break;
557023bf9e15SSepherosa Ziehau 
557123bf9e15SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
557223bf9e15SSepherosa Ziehau 			/*
557323bf9e15SSepherosa Ziehau 			 * This sending could be time consuming; let callers
557423bf9e15SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
557523bf9e15SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
557623bf9e15SSepherosa Ziehau 			 */
557723bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
5578dc13fee6SSepherosa Ziehau 			sched = 1;
5579dc13fee6SSepherosa Ziehau 			break;
558023bf9e15SSepherosa Ziehau 		}
558123bf9e15SSepherosa Ziehau 
5582edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
5583edd3f315SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
5584edd3f315SSepherosa Ziehau 			m_head = hn_tso_fixup(m_head);
5585edd3f315SSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
5586edd3f315SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5587edd3f315SSepherosa Ziehau 				continue;
5588edd3f315SSepherosa Ziehau 			}
5589*c49d47daSSepherosa Ziehau 		} else if (m_head->m_pkthdr.csum_flags &
5590*c49d47daSSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) {
5591*c49d47daSSepherosa Ziehau 			m_head = hn_set_hlen(m_head);
5592*c49d47daSSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
5593*c49d47daSSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5594*c49d47daSSepherosa Ziehau 				continue;
5595*c49d47daSSepherosa Ziehau 			}
5596edd3f315SSepherosa Ziehau 		}
5597edd3f315SSepherosa Ziehau #endif
5598edd3f315SSepherosa Ziehau 
559923bf9e15SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
560023bf9e15SSepherosa Ziehau 		if (txd == NULL) {
560123bf9e15SSepherosa Ziehau 			txr->hn_no_txdescs++;
560223bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
560323bf9e15SSepherosa Ziehau 			atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
560423bf9e15SSepherosa Ziehau 			break;
560523bf9e15SSepherosa Ziehau 		}
560623bf9e15SSepherosa Ziehau 
5607dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
560823bf9e15SSepherosa Ziehau 		if (error) {
560923bf9e15SSepherosa Ziehau 			/* Both txd and m_head are freed */
5610dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
5611dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
561223bf9e15SSepherosa Ziehau 			continue;
561323bf9e15SSepherosa Ziehau 		}
561423bf9e15SSepherosa Ziehau 
5615dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
5616dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
5617dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
5618dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
5619dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
5620dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
5621dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
5622dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
5623dc13fee6SSepherosa Ziehau 					break;
5624dc13fee6SSepherosa Ziehau 				}
5625dc13fee6SSepherosa Ziehau 			} else {
5626dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
562723bf9e15SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
562823bf9e15SSepherosa Ziehau 				if (__predict_false(error)) {
562923bf9e15SSepherosa Ziehau 					/* txd is freed, but m_head is not */
563023bf9e15SSepherosa Ziehau 					IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
5631dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
5632dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
563323bf9e15SSepherosa Ziehau 					break;
563423bf9e15SSepherosa Ziehau 				}
563523bf9e15SSepherosa Ziehau 			}
5636dc13fee6SSepherosa Ziehau 		}
5637dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
5638dc13fee6SSepherosa Ziehau 		else {
5639dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
5640dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
5641dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
5642dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
5643dc13fee6SSepherosa Ziehau 		}
5644dc13fee6SSepherosa Ziehau #endif
5645dc13fee6SSepherosa Ziehau 	}
5646dc13fee6SSepherosa Ziehau 
5647dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
5648dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
5649dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
5650dc13fee6SSepherosa Ziehau 	return (sched);
565123bf9e15SSepherosa Ziehau }
565223bf9e15SSepherosa Ziehau 
565323bf9e15SSepherosa Ziehau static void
565423bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp)
565523bf9e15SSepherosa Ziehau {
565623bf9e15SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
565723bf9e15SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[0];
565823bf9e15SSepherosa Ziehau 
565923bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
566023bf9e15SSepherosa Ziehau 		goto do_sched;
566123bf9e15SSepherosa Ziehau 
566223bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
566323bf9e15SSepherosa Ziehau 		int sched;
566423bf9e15SSepherosa Ziehau 
566523bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
566623bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
566723bf9e15SSepherosa Ziehau 		if (!sched)
566823bf9e15SSepherosa Ziehau 			return;
566923bf9e15SSepherosa Ziehau 	}
567023bf9e15SSepherosa Ziehau do_sched:
567123bf9e15SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
567223bf9e15SSepherosa Ziehau }
567323bf9e15SSepherosa Ziehau 
567415516c77SSepherosa Ziehau static void
567515516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused)
567615516c77SSepherosa Ziehau {
567715516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
567815516c77SSepherosa Ziehau 
567915516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
568015516c77SSepherosa Ziehau 	atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE);
568115516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
568215516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
568315516c77SSepherosa Ziehau }
568415516c77SSepherosa Ziehau 
568523bf9e15SSepherosa Ziehau static void
568623bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr)
568723bf9e15SSepherosa Ziehau {
568823bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
568923bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
569023bf9e15SSepherosa Ziehau 
569123bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
569223bf9e15SSepherosa Ziehau 
569323bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
569423bf9e15SSepherosa Ziehau 		goto do_sched;
569523bf9e15SSepherosa Ziehau 
569623bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
569723bf9e15SSepherosa Ziehau 		int sched;
569823bf9e15SSepherosa Ziehau 
569923bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
570023bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
570123bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
570223bf9e15SSepherosa Ziehau 		if (sched) {
570323bf9e15SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
570423bf9e15SSepherosa Ziehau 			    &txr->hn_tx_task);
570523bf9e15SSepherosa Ziehau 		}
570623bf9e15SSepherosa Ziehau 	} else {
570723bf9e15SSepherosa Ziehau do_sched:
570823bf9e15SSepherosa Ziehau 		/*
570923bf9e15SSepherosa Ziehau 		 * Release the OACTIVE earlier, with the hope, that
571023bf9e15SSepherosa Ziehau 		 * others could catch up.  The task will clear the
571123bf9e15SSepherosa Ziehau 		 * flag again with the hn_tx_lock to avoid possible
571223bf9e15SSepherosa Ziehau 		 * races.
571323bf9e15SSepherosa Ziehau 		 */
571423bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
571523bf9e15SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
571623bf9e15SSepherosa Ziehau 	}
571723bf9e15SSepherosa Ziehau }
571823bf9e15SSepherosa Ziehau 
571923bf9e15SSepherosa Ziehau #endif	/* HN_IFSTART_SUPPORT */
572023bf9e15SSepherosa Ziehau 
572115516c77SSepherosa Ziehau static int
572215516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len)
572315516c77SSepherosa Ziehau {
572415516c77SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
572515516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
572615516c77SSepherosa Ziehau 	struct mbuf *m_head;
5727dc13fee6SSepherosa Ziehau 	int sched = 0;
572815516c77SSepherosa Ziehau 
572915516c77SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
573023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
573115516c77SSepherosa Ziehau 	KASSERT(hn_use_if_start == 0,
573215516c77SSepherosa Ziehau 	    ("hn_xmit is called, when if_start is enabled"));
573323bf9e15SSepherosa Ziehau #endif
5734dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
573515516c77SSepherosa Ziehau 
573615516c77SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
5737dc13fee6SSepherosa Ziehau 		return (0);
573815516c77SSepherosa Ziehau 
573915516c77SSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive)
5740dc13fee6SSepherosa Ziehau 		return (0);
574115516c77SSepherosa Ziehau 
574215516c77SSepherosa Ziehau 	while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) {
574315516c77SSepherosa Ziehau 		struct hn_txdesc *txd;
574415516c77SSepherosa Ziehau 		int error;
574515516c77SSepherosa Ziehau 
574615516c77SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
574715516c77SSepherosa Ziehau 			/*
574815516c77SSepherosa Ziehau 			 * This sending could be time consuming; let callers
574915516c77SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
575015516c77SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
575115516c77SSepherosa Ziehau 			 */
575215516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
5753dc13fee6SSepherosa Ziehau 			sched = 1;
5754dc13fee6SSepherosa Ziehau 			break;
575515516c77SSepherosa Ziehau 		}
575615516c77SSepherosa Ziehau 
575715516c77SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
575815516c77SSepherosa Ziehau 		if (txd == NULL) {
575915516c77SSepherosa Ziehau 			txr->hn_no_txdescs++;
576015516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
576115516c77SSepherosa Ziehau 			txr->hn_oactive = 1;
576215516c77SSepherosa Ziehau 			break;
576315516c77SSepherosa Ziehau 		}
576415516c77SSepherosa Ziehau 
5765dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
576615516c77SSepherosa Ziehau 		if (error) {
576715516c77SSepherosa Ziehau 			/* Both txd and m_head are freed; discard */
5768dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
5769dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
577015516c77SSepherosa Ziehau 			drbr_advance(ifp, txr->hn_mbuf_br);
577115516c77SSepherosa Ziehau 			continue;
577215516c77SSepherosa Ziehau 		}
577315516c77SSepherosa Ziehau 
5774dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
5775dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
5776dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
5777dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
5778dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
577915516c77SSepherosa Ziehau 				if (__predict_false(error)) {
578015516c77SSepherosa Ziehau 					txr->hn_oactive = 1;
578115516c77SSepherosa Ziehau 					break;
578215516c77SSepherosa Ziehau 				}
5783dc13fee6SSepherosa Ziehau 			} else {
5784dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
5785dc13fee6SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
5786dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
5787dc13fee6SSepherosa Ziehau 					/* txd is freed, but m_head is not */
5788dc13fee6SSepherosa Ziehau 					drbr_putback(ifp, txr->hn_mbuf_br,
5789dc13fee6SSepherosa Ziehau 					    m_head);
5790dc13fee6SSepherosa Ziehau 					txr->hn_oactive = 1;
5791dc13fee6SSepherosa Ziehau 					break;
5792dc13fee6SSepherosa Ziehau 				}
5793dc13fee6SSepherosa Ziehau 			}
5794dc13fee6SSepherosa Ziehau 		}
5795dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
5796dc13fee6SSepherosa Ziehau 		else {
5797dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
5798dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
5799dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
5800dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
5801dc13fee6SSepherosa Ziehau 		}
5802dc13fee6SSepherosa Ziehau #endif
580315516c77SSepherosa Ziehau 
580415516c77SSepherosa Ziehau 		/* Sent */
580515516c77SSepherosa Ziehau 		drbr_advance(ifp, txr->hn_mbuf_br);
580615516c77SSepherosa Ziehau 	}
5807dc13fee6SSepherosa Ziehau 
5808dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
5809dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
5810dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
5811dc13fee6SSepherosa Ziehau 	return (sched);
581215516c77SSepherosa Ziehau }
581315516c77SSepherosa Ziehau 
581415516c77SSepherosa Ziehau static int
581515516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m)
581615516c77SSepherosa Ziehau {
581715516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
581815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
581915516c77SSepherosa Ziehau 	int error, idx = 0;
582015516c77SSepherosa Ziehau 
58219c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) {
58229c6cae24SSepherosa Ziehau 		struct rm_priotracker pt;
58239c6cae24SSepherosa Ziehau 
58249c6cae24SSepherosa Ziehau 		rm_rlock(&sc->hn_vf_lock, &pt);
58259c6cae24SSepherosa Ziehau 		if (__predict_true(sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
58269c6cae24SSepherosa Ziehau 			struct mbuf *m_bpf = NULL;
58279c6cae24SSepherosa Ziehau 			int obytes, omcast;
58289c6cae24SSepherosa Ziehau 
58299c6cae24SSepherosa Ziehau 			obytes = m->m_pkthdr.len;
58309c6cae24SSepherosa Ziehau 			if (m->m_flags & M_MCAST)
58319c6cae24SSepherosa Ziehau 				omcast = 1;
58329c6cae24SSepherosa Ziehau 
58339c6cae24SSepherosa Ziehau 			if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF) {
58349c6cae24SSepherosa Ziehau 				if (bpf_peers_present(ifp->if_bpf)) {
58359c6cae24SSepherosa Ziehau 					m_bpf = m_copypacket(m, M_NOWAIT);
58369c6cae24SSepherosa Ziehau 					if (m_bpf == NULL) {
58379c6cae24SSepherosa Ziehau 						/*
58389c6cae24SSepherosa Ziehau 						 * Failed to grab a shallow
58399c6cae24SSepherosa Ziehau 						 * copy; tap now.
58409c6cae24SSepherosa Ziehau 						 */
58419c6cae24SSepherosa Ziehau 						ETHER_BPF_MTAP(ifp, m);
58429c6cae24SSepherosa Ziehau 					}
58439c6cae24SSepherosa Ziehau 				}
58449c6cae24SSepherosa Ziehau 			} else {
58459c6cae24SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, m);
58469c6cae24SSepherosa Ziehau 			}
58479c6cae24SSepherosa Ziehau 
58489c6cae24SSepherosa Ziehau 			error = sc->hn_vf_ifp->if_transmit(sc->hn_vf_ifp, m);
58499c6cae24SSepherosa Ziehau 			rm_runlock(&sc->hn_vf_lock, &pt);
58509c6cae24SSepherosa Ziehau 
58519c6cae24SSepherosa Ziehau 			if (m_bpf != NULL) {
58529c6cae24SSepherosa Ziehau 				if (!error)
58539c6cae24SSepherosa Ziehau 					ETHER_BPF_MTAP(ifp, m_bpf);
58549c6cae24SSepherosa Ziehau 				m_freem(m_bpf);
58559c6cae24SSepherosa Ziehau 			}
58569c6cae24SSepherosa Ziehau 
58579c6cae24SSepherosa Ziehau 			if (error == ENOBUFS) {
58589c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
58599c6cae24SSepherosa Ziehau 			} else if (error) {
58609c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
58619c6cae24SSepherosa Ziehau 			} else {
58629c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
58639c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OBYTES, obytes);
58649c6cae24SSepherosa Ziehau 				if (omcast) {
58659c6cae24SSepherosa Ziehau 					if_inc_counter(ifp, IFCOUNTER_OMCASTS,
58669c6cae24SSepherosa Ziehau 					    omcast);
58679c6cae24SSepherosa Ziehau 				}
58689c6cae24SSepherosa Ziehau 			}
58699c6cae24SSepherosa Ziehau 			return (error);
58709c6cae24SSepherosa Ziehau 		}
58719c6cae24SSepherosa Ziehau 		rm_runlock(&sc->hn_vf_lock, &pt);
58729c6cae24SSepherosa Ziehau 	}
58739c6cae24SSepherosa Ziehau 
5874edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
5875edd3f315SSepherosa Ziehau 	/*
5876*c49d47daSSepherosa Ziehau 	 * Perform TSO packet header fixup or get l2/l3 header length now,
5877*c49d47daSSepherosa Ziehau 	 * since packet headers should be cache-hot.
5878edd3f315SSepherosa Ziehau 	 */
5879edd3f315SSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
5880edd3f315SSepherosa Ziehau 		m = hn_tso_fixup(m);
5881edd3f315SSepherosa Ziehau 		if (__predict_false(m == NULL)) {
5882edd3f315SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5883edd3f315SSepherosa Ziehau 			return EIO;
5884edd3f315SSepherosa Ziehau 		}
5885*c49d47daSSepherosa Ziehau 	} else if (m->m_pkthdr.csum_flags &
5886*c49d47daSSepherosa Ziehau 	    (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) {
5887*c49d47daSSepherosa Ziehau 		m = hn_set_hlen(m);
5888*c49d47daSSepherosa Ziehau 		if (__predict_false(m == NULL)) {
5889*c49d47daSSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5890*c49d47daSSepherosa Ziehau 			return EIO;
5891*c49d47daSSepherosa Ziehau 		}
5892edd3f315SSepherosa Ziehau 	}
5893edd3f315SSepherosa Ziehau #endif
5894edd3f315SSepherosa Ziehau 
589515516c77SSepherosa Ziehau 	/*
589615516c77SSepherosa Ziehau 	 * Select the TX ring based on flowid
589715516c77SSepherosa Ziehau 	 */
589834d68912SSepherosa Ziehau 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
589934d68912SSepherosa Ziehau #ifdef RSS
590034d68912SSepherosa Ziehau 		uint32_t bid;
590134d68912SSepherosa Ziehau 
590234d68912SSepherosa Ziehau 		if (rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m),
590334d68912SSepherosa Ziehau 		    &bid) == 0)
590434d68912SSepherosa Ziehau 			idx = bid % sc->hn_tx_ring_inuse;
590534d68912SSepherosa Ziehau 		else
590634d68912SSepherosa Ziehau #endif
5907cc0c6ebcSSepherosa Ziehau 		{
5908cc0c6ebcSSepherosa Ziehau #if defined(INET6) || defined(INET)
5909cc0c6ebcSSepherosa Ziehau 			int tcpsyn = 0;
5910cc0c6ebcSSepherosa Ziehau 
5911cc0c6ebcSSepherosa Ziehau 			if (m->m_pkthdr.len < 128 &&
5912cc0c6ebcSSepherosa Ziehau 			    (m->m_pkthdr.csum_flags &
5913cc0c6ebcSSepherosa Ziehau 			     (CSUM_IP_TCP | CSUM_IP6_TCP)) &&
5914cc0c6ebcSSepherosa Ziehau 			    (m->m_pkthdr.csum_flags & CSUM_TSO) == 0) {
5915cc0c6ebcSSepherosa Ziehau 				m = hn_check_tcpsyn(m, &tcpsyn);
5916cc0c6ebcSSepherosa Ziehau 				if (__predict_false(m == NULL)) {
5917cc0c6ebcSSepherosa Ziehau 					if_inc_counter(ifp,
5918cc0c6ebcSSepherosa Ziehau 					    IFCOUNTER_OERRORS, 1);
5919cc0c6ebcSSepherosa Ziehau 					return (EIO);
5920cc0c6ebcSSepherosa Ziehau 				}
5921cc0c6ebcSSepherosa Ziehau 			}
5922cc0c6ebcSSepherosa Ziehau #else
5923cc0c6ebcSSepherosa Ziehau 			const int tcpsyn = 0;
5924cc0c6ebcSSepherosa Ziehau #endif
5925cc0c6ebcSSepherosa Ziehau 			if (tcpsyn)
5926cc0c6ebcSSepherosa Ziehau 				idx = 0;
5927cc0c6ebcSSepherosa Ziehau 			else
592815516c77SSepherosa Ziehau 				idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse;
592934d68912SSepherosa Ziehau 		}
5930cc0c6ebcSSepherosa Ziehau 	}
593115516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[idx];
593215516c77SSepherosa Ziehau 
593315516c77SSepherosa Ziehau 	error = drbr_enqueue(ifp, txr->hn_mbuf_br, m);
593415516c77SSepherosa Ziehau 	if (error) {
593515516c77SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
593615516c77SSepherosa Ziehau 		return error;
593715516c77SSepherosa Ziehau 	}
593815516c77SSepherosa Ziehau 
593915516c77SSepherosa Ziehau 	if (txr->hn_oactive)
594015516c77SSepherosa Ziehau 		return 0;
594115516c77SSepherosa Ziehau 
594215516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
594315516c77SSepherosa Ziehau 		goto do_sched;
594415516c77SSepherosa Ziehau 
594515516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
594615516c77SSepherosa Ziehau 		int sched;
594715516c77SSepherosa Ziehau 
594815516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
594915516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
595015516c77SSepherosa Ziehau 		if (!sched)
595115516c77SSepherosa Ziehau 			return 0;
595215516c77SSepherosa Ziehau 	}
595315516c77SSepherosa Ziehau do_sched:
595415516c77SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
595515516c77SSepherosa Ziehau 	return 0;
595615516c77SSepherosa Ziehau }
595715516c77SSepherosa Ziehau 
595815516c77SSepherosa Ziehau static void
595915516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr)
596015516c77SSepherosa Ziehau {
596115516c77SSepherosa Ziehau 	struct mbuf *m;
596215516c77SSepherosa Ziehau 
596315516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
596415516c77SSepherosa Ziehau 	while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL)
596515516c77SSepherosa Ziehau 		m_freem(m);
596615516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
596715516c77SSepherosa Ziehau }
596815516c77SSepherosa Ziehau 
596915516c77SSepherosa Ziehau static void
597015516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp)
597115516c77SSepherosa Ziehau {
597215516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
59739c6cae24SSepherosa Ziehau 	struct rm_priotracker pt;
597415516c77SSepherosa Ziehau 	int i;
597515516c77SSepherosa Ziehau 
597615516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
597715516c77SSepherosa Ziehau 		hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
597815516c77SSepherosa Ziehau 	if_qflush(ifp);
59799c6cae24SSepherosa Ziehau 
59809c6cae24SSepherosa Ziehau 	rm_rlock(&sc->hn_vf_lock, &pt);
59819c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
59829c6cae24SSepherosa Ziehau 		sc->hn_vf_ifp->if_qflush(sc->hn_vf_ifp);
59839c6cae24SSepherosa Ziehau 	rm_runlock(&sc->hn_vf_lock, &pt);
598415516c77SSepherosa Ziehau }
598515516c77SSepherosa Ziehau 
598615516c77SSepherosa Ziehau static void
598715516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr)
598815516c77SSepherosa Ziehau {
598915516c77SSepherosa Ziehau 
599015516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
599115516c77SSepherosa Ziehau 		goto do_sched;
599215516c77SSepherosa Ziehau 
599315516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
599415516c77SSepherosa Ziehau 		int sched;
599515516c77SSepherosa Ziehau 
599615516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
599715516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
599815516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
599915516c77SSepherosa Ziehau 		if (sched) {
600015516c77SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
600115516c77SSepherosa Ziehau 			    &txr->hn_tx_task);
600215516c77SSepherosa Ziehau 		}
600315516c77SSepherosa Ziehau 	} else {
600415516c77SSepherosa Ziehau do_sched:
600515516c77SSepherosa Ziehau 		/*
600615516c77SSepherosa Ziehau 		 * Release the oactive earlier, with the hope, that
600715516c77SSepherosa Ziehau 		 * others could catch up.  The task will clear the
600815516c77SSepherosa Ziehau 		 * oactive again with the hn_tx_lock to avoid possible
600915516c77SSepherosa Ziehau 		 * races.
601015516c77SSepherosa Ziehau 		 */
601115516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
601215516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
601315516c77SSepherosa Ziehau 	}
601415516c77SSepherosa Ziehau }
601515516c77SSepherosa Ziehau 
601615516c77SSepherosa Ziehau static void
601715516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused)
601815516c77SSepherosa Ziehau {
601915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
602015516c77SSepherosa Ziehau 
602115516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
602215516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
602315516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
602415516c77SSepherosa Ziehau }
602515516c77SSepherosa Ziehau 
602615516c77SSepherosa Ziehau static void
602715516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused)
602815516c77SSepherosa Ziehau {
602915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
603015516c77SSepherosa Ziehau 
603115516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
603215516c77SSepherosa Ziehau 	txr->hn_oactive = 0;
603315516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
603415516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
603515516c77SSepherosa Ziehau }
603615516c77SSepherosa Ziehau 
603715516c77SSepherosa Ziehau static int
603815516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan)
603915516c77SSepherosa Ziehau {
604015516c77SSepherosa Ziehau 	struct vmbus_chan_br cbr;
604115516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
604215516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = NULL;
604315516c77SSepherosa Ziehau 	int idx, error;
604415516c77SSepherosa Ziehau 
604515516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
604615516c77SSepherosa Ziehau 
604715516c77SSepherosa Ziehau 	/*
604815516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
604915516c77SSepherosa Ziehau 	 */
605015516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
605115516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
605215516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
605315516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
605415516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0,
605515516c77SSepherosa Ziehau 	    ("RX ring %d already attached", idx));
605615516c77SSepherosa Ziehau 	rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED;
60573ab0fea1SDexuan Cui 	rxr->hn_chan = chan;
605815516c77SSepherosa Ziehau 
605915516c77SSepherosa Ziehau 	if (bootverbose) {
606015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n",
606115516c77SSepherosa Ziehau 		    idx, vmbus_chan_id(chan));
606215516c77SSepherosa Ziehau 	}
606315516c77SSepherosa Ziehau 
606415516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
606515516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[idx];
606615516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0,
606715516c77SSepherosa Ziehau 		    ("TX ring %d already attached", idx));
606815516c77SSepherosa Ziehau 		txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED;
606915516c77SSepherosa Ziehau 
607015516c77SSepherosa Ziehau 		txr->hn_chan = chan;
607115516c77SSepherosa Ziehau 		if (bootverbose) {
607215516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n",
607315516c77SSepherosa Ziehau 			    idx, vmbus_chan_id(chan));
607415516c77SSepherosa Ziehau 		}
607515516c77SSepherosa Ziehau 	}
607615516c77SSepherosa Ziehau 
607715516c77SSepherosa Ziehau 	/* Bind this channel to a proper CPU. */
60780e11868dSSepherosa Ziehau 	vmbus_chan_cpu_set(chan, HN_RING_IDX2CPU(sc, idx));
607915516c77SSepherosa Ziehau 
608015516c77SSepherosa Ziehau 	/*
608115516c77SSepherosa Ziehau 	 * Open this channel
608215516c77SSepherosa Ziehau 	 */
608315516c77SSepherosa Ziehau 	cbr.cbr = rxr->hn_br;
608415516c77SSepherosa Ziehau 	cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr;
608515516c77SSepherosa Ziehau 	cbr.cbr_txsz = HN_TXBR_SIZE;
608615516c77SSepherosa Ziehau 	cbr.cbr_rxsz = HN_RXBR_SIZE;
608715516c77SSepherosa Ziehau 	error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr);
608815516c77SSepherosa Ziehau 	if (error) {
608971e8ac56SSepherosa Ziehau 		if (error == EISCONN) {
609071e8ac56SSepherosa Ziehau 			if_printf(sc->hn_ifp, "bufring is connected after "
609171e8ac56SSepherosa Ziehau 			    "chan%u open failure\n", vmbus_chan_id(chan));
609271e8ac56SSepherosa Ziehau 			rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
609371e8ac56SSepherosa Ziehau 		} else {
609415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "open chan%u failed: %d\n",
609515516c77SSepherosa Ziehau 			    vmbus_chan_id(chan), error);
609671e8ac56SSepherosa Ziehau 		}
609715516c77SSepherosa Ziehau 	}
609815516c77SSepherosa Ziehau 	return (error);
609915516c77SSepherosa Ziehau }
610015516c77SSepherosa Ziehau 
610115516c77SSepherosa Ziehau static void
610215516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan)
610315516c77SSepherosa Ziehau {
610415516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
61052494d735SSepherosa Ziehau 	int idx, error;
610615516c77SSepherosa Ziehau 
610715516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
610815516c77SSepherosa Ziehau 
610915516c77SSepherosa Ziehau 	/*
611015516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
611115516c77SSepherosa Ziehau 	 */
611215516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
611315516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
611415516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
611515516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
611615516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED),
611715516c77SSepherosa Ziehau 	    ("RX ring %d is not attached", idx));
611815516c77SSepherosa Ziehau 	rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
611915516c77SSepherosa Ziehau 
612015516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
612115516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[idx];
612215516c77SSepherosa Ziehau 
612315516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED),
612415516c77SSepherosa Ziehau 		    ("TX ring %d is not attached attached", idx));
612515516c77SSepherosa Ziehau 		txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
612615516c77SSepherosa Ziehau 	}
612715516c77SSepherosa Ziehau 
612815516c77SSepherosa Ziehau 	/*
612915516c77SSepherosa Ziehau 	 * Close this channel.
613015516c77SSepherosa Ziehau 	 *
613115516c77SSepherosa Ziehau 	 * NOTE:
613215516c77SSepherosa Ziehau 	 * Channel closing does _not_ destroy the target channel.
613315516c77SSepherosa Ziehau 	 */
61342494d735SSepherosa Ziehau 	error = vmbus_chan_close_direct(chan);
61352494d735SSepherosa Ziehau 	if (error == EISCONN) {
6136aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u bufring is connected "
6137aa1a2adcSSepherosa Ziehau 		    "after being closed\n", vmbus_chan_id(chan));
61382494d735SSepherosa Ziehau 		rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
61392494d735SSepherosa Ziehau 	} else if (error) {
6140aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u close failed: %d\n",
6141aa1a2adcSSepherosa Ziehau 		    vmbus_chan_id(chan), error);
61422494d735SSepherosa Ziehau 	}
614315516c77SSepherosa Ziehau }
614415516c77SSepherosa Ziehau 
614515516c77SSepherosa Ziehau static int
614615516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc)
614715516c77SSepherosa Ziehau {
614815516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
614915516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
615015516c77SSepherosa Ziehau 	int i, error = 0;
615115516c77SSepherosa Ziehau 
615271e8ac56SSepherosa Ziehau 	KASSERT(subchan_cnt > 0, ("no sub-channels"));
615315516c77SSepherosa Ziehau 
615415516c77SSepherosa Ziehau 	/* Attach the sub-channels. */
615515516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
615615516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i) {
615771e8ac56SSepherosa Ziehau 		int error1;
615871e8ac56SSepherosa Ziehau 
615971e8ac56SSepherosa Ziehau 		error1 = hn_chan_attach(sc, subchans[i]);
616071e8ac56SSepherosa Ziehau 		if (error1) {
616171e8ac56SSepherosa Ziehau 			error = error1;
616271e8ac56SSepherosa Ziehau 			/* Move on; all channels will be detached later. */
616371e8ac56SSepherosa Ziehau 		}
616415516c77SSepherosa Ziehau 	}
616515516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
616615516c77SSepherosa Ziehau 
616715516c77SSepherosa Ziehau 	if (error) {
616815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error);
616915516c77SSepherosa Ziehau 	} else {
617015516c77SSepherosa Ziehau 		if (bootverbose) {
617115516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "%d sub-channels attached\n",
617215516c77SSepherosa Ziehau 			    subchan_cnt);
617315516c77SSepherosa Ziehau 		}
617415516c77SSepherosa Ziehau 	}
617515516c77SSepherosa Ziehau 	return (error);
617615516c77SSepherosa Ziehau }
617715516c77SSepherosa Ziehau 
617815516c77SSepherosa Ziehau static void
617915516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc)
618015516c77SSepherosa Ziehau {
618115516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
618215516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
618315516c77SSepherosa Ziehau 	int i;
618415516c77SSepherosa Ziehau 
618515516c77SSepherosa Ziehau 	if (subchan_cnt == 0)
618615516c77SSepherosa Ziehau 		goto back;
618715516c77SSepherosa Ziehau 
618815516c77SSepherosa Ziehau 	/* Detach the sub-channels. */
618915516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
619015516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i)
619115516c77SSepherosa Ziehau 		hn_chan_detach(sc, subchans[i]);
619215516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
619315516c77SSepherosa Ziehau 
619415516c77SSepherosa Ziehau back:
619515516c77SSepherosa Ziehau 	/*
619615516c77SSepherosa Ziehau 	 * Detach the primary channel, _after_ all sub-channels
619715516c77SSepherosa Ziehau 	 * are detached.
619815516c77SSepherosa Ziehau 	 */
619915516c77SSepherosa Ziehau 	hn_chan_detach(sc, sc->hn_prichan);
620015516c77SSepherosa Ziehau 
620115516c77SSepherosa Ziehau 	/* Wait for sub-channels to be destroyed, if any. */
620215516c77SSepherosa Ziehau 	vmbus_subchan_drain(sc->hn_prichan);
620315516c77SSepherosa Ziehau 
620415516c77SSepherosa Ziehau #ifdef INVARIANTS
620515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
620615516c77SSepherosa Ziehau 		KASSERT((sc->hn_rx_ring[i].hn_rx_flags &
620715516c77SSepherosa Ziehau 		    HN_RX_FLAG_ATTACHED) == 0,
620815516c77SSepherosa Ziehau 		    ("%dth RX ring is still attached", i));
620915516c77SSepherosa Ziehau 	}
621015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
621115516c77SSepherosa Ziehau 		KASSERT((sc->hn_tx_ring[i].hn_tx_flags &
621215516c77SSepherosa Ziehau 		    HN_TX_FLAG_ATTACHED) == 0,
621315516c77SSepherosa Ziehau 		    ("%dth TX ring is still attached", i));
621415516c77SSepherosa Ziehau 	}
621515516c77SSepherosa Ziehau #endif
621615516c77SSepherosa Ziehau }
621715516c77SSepherosa Ziehau 
621815516c77SSepherosa Ziehau static int
621915516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch)
622015516c77SSepherosa Ziehau {
622115516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
622215516c77SSepherosa Ziehau 	int nchan, rxr_cnt, error;
622315516c77SSepherosa Ziehau 
622415516c77SSepherosa Ziehau 	nchan = *nsubch + 1;
622515516c77SSepherosa Ziehau 	if (nchan == 1) {
622615516c77SSepherosa Ziehau 		/*
622715516c77SSepherosa Ziehau 		 * Multiple RX/TX rings are not requested.
622815516c77SSepherosa Ziehau 		 */
622915516c77SSepherosa Ziehau 		*nsubch = 0;
623015516c77SSepherosa Ziehau 		return (0);
623115516c77SSepherosa Ziehau 	}
623215516c77SSepherosa Ziehau 
623315516c77SSepherosa Ziehau 	/*
623415516c77SSepherosa Ziehau 	 * Query RSS capabilities, e.g. # of RX rings, and # of indirect
623515516c77SSepherosa Ziehau 	 * table entries.
623615516c77SSepherosa Ziehau 	 */
623715516c77SSepherosa Ziehau 	error = hn_rndis_query_rsscaps(sc, &rxr_cnt);
623815516c77SSepherosa Ziehau 	if (error) {
623915516c77SSepherosa Ziehau 		/* No RSS; this is benign. */
624015516c77SSepherosa Ziehau 		*nsubch = 0;
624115516c77SSepherosa Ziehau 		return (0);
624215516c77SSepherosa Ziehau 	}
624315516c77SSepherosa Ziehau 	if (bootverbose) {
624415516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
624515516c77SSepherosa Ziehau 		    rxr_cnt, nchan);
624615516c77SSepherosa Ziehau 	}
624715516c77SSepherosa Ziehau 
624815516c77SSepherosa Ziehau 	if (nchan > rxr_cnt)
624915516c77SSepherosa Ziehau 		nchan = rxr_cnt;
625015516c77SSepherosa Ziehau 	if (nchan == 1) {
625115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n");
625215516c77SSepherosa Ziehau 		*nsubch = 0;
625315516c77SSepherosa Ziehau 		return (0);
625415516c77SSepherosa Ziehau 	}
625515516c77SSepherosa Ziehau 
625615516c77SSepherosa Ziehau 	/*
625715516c77SSepherosa Ziehau 	 * Allocate sub-channels from NVS.
625815516c77SSepherosa Ziehau 	 */
625915516c77SSepherosa Ziehau 	*nsubch = nchan - 1;
626015516c77SSepherosa Ziehau 	error = hn_nvs_alloc_subchans(sc, nsubch);
626115516c77SSepherosa Ziehau 	if (error || *nsubch == 0) {
626215516c77SSepherosa Ziehau 		/* Failed to allocate sub-channels. */
626315516c77SSepherosa Ziehau 		*nsubch = 0;
626415516c77SSepherosa Ziehau 		return (0);
626515516c77SSepherosa Ziehau 	}
626615516c77SSepherosa Ziehau 
626715516c77SSepherosa Ziehau 	/*
626815516c77SSepherosa Ziehau 	 * Wait for all sub-channels to become ready before moving on.
626915516c77SSepherosa Ziehau 	 */
627015516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch);
627115516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, *nsubch);
627215516c77SSepherosa Ziehau 	return (0);
627315516c77SSepherosa Ziehau }
627415516c77SSepherosa Ziehau 
62752494d735SSepherosa Ziehau static bool
62762494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc)
62772494d735SSepherosa Ziehau {
62782494d735SSepherosa Ziehau 	int i;
62792494d735SSepherosa Ziehau 
62802494d735SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_ERRORS)
62812494d735SSepherosa Ziehau 		return (false);
62822494d735SSepherosa Ziehau 
62832494d735SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
62842494d735SSepherosa Ziehau 		const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
62852494d735SSepherosa Ziehau 
62862494d735SSepherosa Ziehau 		if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF)
62872494d735SSepherosa Ziehau 			return (false);
62882494d735SSepherosa Ziehau 	}
62892494d735SSepherosa Ziehau 	return (true);
62902494d735SSepherosa Ziehau }
62912494d735SSepherosa Ziehau 
6292b3b75d9cSSepherosa Ziehau /*
6293b3b75d9cSSepherosa Ziehau  * Make sure that the RX filter is zero after the successful
6294b3b75d9cSSepherosa Ziehau  * RNDIS initialization.
6295b3b75d9cSSepherosa Ziehau  *
6296b3b75d9cSSepherosa Ziehau  * NOTE:
6297b3b75d9cSSepherosa Ziehau  * Under certain conditions on certain versions of Hyper-V,
6298b3b75d9cSSepherosa Ziehau  * the RNDIS rxfilter is _not_ zero on the hypervisor side
6299b3b75d9cSSepherosa Ziehau  * after the successful RNDIS initialization, which breaks
6300b3b75d9cSSepherosa Ziehau  * the assumption of any following code (well, it breaks the
6301b3b75d9cSSepherosa Ziehau  * RNDIS API contract actually).  Clear the RNDIS rxfilter
6302b3b75d9cSSepherosa Ziehau  * explicitly, drain packets sneaking through, and drain the
6303b3b75d9cSSepherosa Ziehau  * interrupt taskqueues scheduled due to the stealth packets.
6304b3b75d9cSSepherosa Ziehau  */
6305b3b75d9cSSepherosa Ziehau static void
6306b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(struct hn_softc *sc, int nchan)
6307b3b75d9cSSepherosa Ziehau {
6308b3b75d9cSSepherosa Ziehau 
6309b3b75d9cSSepherosa Ziehau 	hn_disable_rx(sc);
6310b3b75d9cSSepherosa Ziehau 	hn_drain_rxtx(sc, nchan);
6311b3b75d9cSSepherosa Ziehau }
6312b3b75d9cSSepherosa Ziehau 
631315516c77SSepherosa Ziehau static int
631415516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu)
631515516c77SSepherosa Ziehau {
631671e8ac56SSepherosa Ziehau #define ATTACHED_NVS		0x0002
631771e8ac56SSepherosa Ziehau #define ATTACHED_RNDIS		0x0004
631871e8ac56SSepherosa Ziehau 
631915516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
6320b3b75d9cSSepherosa Ziehau 	int error, nsubch, nchan = 1, i, rndis_inited;
632171e8ac56SSepherosa Ziehau 	uint32_t old_caps, attached = 0;
632215516c77SSepherosa Ziehau 
632315516c77SSepherosa Ziehau 	KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0,
632415516c77SSepherosa Ziehau 	    ("synthetic parts were attached"));
632515516c77SSepherosa Ziehau 
63262494d735SSepherosa Ziehau 	if (!hn_synth_attachable(sc))
63272494d735SSepherosa Ziehau 		return (ENXIO);
63282494d735SSepherosa Ziehau 
632915516c77SSepherosa Ziehau 	/* Save capabilities for later verification. */
633015516c77SSepherosa Ziehau 	old_caps = sc->hn_caps;
633115516c77SSepherosa Ziehau 	sc->hn_caps = 0;
633215516c77SSepherosa Ziehau 
633315516c77SSepherosa Ziehau 	/* Clear RSS stuffs. */
633415516c77SSepherosa Ziehau 	sc->hn_rss_ind_size = 0;
633515516c77SSepherosa Ziehau 	sc->hn_rss_hash = 0;
6336642ec226SSepherosa Ziehau 	sc->hn_rss_hcap = 0;
633715516c77SSepherosa Ziehau 
633815516c77SSepherosa Ziehau 	/*
633915516c77SSepherosa Ziehau 	 * Attach the primary channel _before_ attaching NVS and RNDIS.
634015516c77SSepherosa Ziehau 	 */
634115516c77SSepherosa Ziehau 	error = hn_chan_attach(sc, sc->hn_prichan);
634215516c77SSepherosa Ziehau 	if (error)
634371e8ac56SSepherosa Ziehau 		goto failed;
634415516c77SSepherosa Ziehau 
634515516c77SSepherosa Ziehau 	/*
634615516c77SSepherosa Ziehau 	 * Attach NVS.
634715516c77SSepherosa Ziehau 	 */
634815516c77SSepherosa Ziehau 	error = hn_nvs_attach(sc, mtu);
634915516c77SSepherosa Ziehau 	if (error)
635071e8ac56SSepherosa Ziehau 		goto failed;
635171e8ac56SSepherosa Ziehau 	attached |= ATTACHED_NVS;
635215516c77SSepherosa Ziehau 
635315516c77SSepherosa Ziehau 	/*
635415516c77SSepherosa Ziehau 	 * Attach RNDIS _after_ NVS is attached.
635515516c77SSepherosa Ziehau 	 */
6356b3b75d9cSSepherosa Ziehau 	error = hn_rndis_attach(sc, mtu, &rndis_inited);
6357b3b75d9cSSepherosa Ziehau 	if (rndis_inited)
6358b3b75d9cSSepherosa Ziehau 		attached |= ATTACHED_RNDIS;
635915516c77SSepherosa Ziehau 	if (error)
636071e8ac56SSepherosa Ziehau 		goto failed;
636115516c77SSepherosa Ziehau 
636215516c77SSepherosa Ziehau 	/*
636315516c77SSepherosa Ziehau 	 * Make sure capabilities are not changed.
636415516c77SSepherosa Ziehau 	 */
636515516c77SSepherosa Ziehau 	if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) {
636615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n",
636715516c77SSepherosa Ziehau 		    old_caps, sc->hn_caps);
636871e8ac56SSepherosa Ziehau 		error = ENXIO;
636971e8ac56SSepherosa Ziehau 		goto failed;
637015516c77SSepherosa Ziehau 	}
637115516c77SSepherosa Ziehau 
637215516c77SSepherosa Ziehau 	/*
637315516c77SSepherosa Ziehau 	 * Allocate sub-channels for multi-TX/RX rings.
637415516c77SSepherosa Ziehau 	 *
637515516c77SSepherosa Ziehau 	 * NOTE:
637615516c77SSepherosa Ziehau 	 * The # of RX rings that can be used is equivalent to the # of
637715516c77SSepherosa Ziehau 	 * channels to be requested.
637815516c77SSepherosa Ziehau 	 */
637915516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_cnt - 1;
638015516c77SSepherosa Ziehau 	error = hn_synth_alloc_subchans(sc, &nsubch);
638115516c77SSepherosa Ziehau 	if (error)
638271e8ac56SSepherosa Ziehau 		goto failed;
638371e8ac56SSepherosa Ziehau 	/* NOTE: _Full_ synthetic parts detach is required now. */
638471e8ac56SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED;
638515516c77SSepherosa Ziehau 
638671e8ac56SSepherosa Ziehau 	/*
638771e8ac56SSepherosa Ziehau 	 * Set the # of TX/RX rings that could be used according to
638871e8ac56SSepherosa Ziehau 	 * the # of channels that NVS offered.
638971e8ac56SSepherosa Ziehau 	 */
639015516c77SSepherosa Ziehau 	nchan = nsubch + 1;
639171e8ac56SSepherosa Ziehau 	hn_set_ring_inuse(sc, nchan);
639215516c77SSepherosa Ziehau 	if (nchan == 1) {
639315516c77SSepherosa Ziehau 		/* Only the primary channel can be used; done */
639415516c77SSepherosa Ziehau 		goto back;
639515516c77SSepherosa Ziehau 	}
639615516c77SSepherosa Ziehau 
639715516c77SSepherosa Ziehau 	/*
639871e8ac56SSepherosa Ziehau 	 * Attach the sub-channels.
6399afd4971bSSepherosa Ziehau 	 *
6400afd4971bSSepherosa Ziehau 	 * NOTE: hn_set_ring_inuse() _must_ have been called.
640115516c77SSepherosa Ziehau 	 */
640271e8ac56SSepherosa Ziehau 	error = hn_attach_subchans(sc);
640371e8ac56SSepherosa Ziehau 	if (error)
640471e8ac56SSepherosa Ziehau 		goto failed;
640515516c77SSepherosa Ziehau 
640671e8ac56SSepherosa Ziehau 	/*
640771e8ac56SSepherosa Ziehau 	 * Configure RSS key and indirect table _after_ all sub-channels
640871e8ac56SSepherosa Ziehau 	 * are attached.
640971e8ac56SSepherosa Ziehau 	 */
641015516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) {
641115516c77SSepherosa Ziehau 		/*
641215516c77SSepherosa Ziehau 		 * RSS key is not set yet; set it to the default RSS key.
641315516c77SSepherosa Ziehau 		 */
641415516c77SSepherosa Ziehau 		if (bootverbose)
641515516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS key\n");
641634d68912SSepherosa Ziehau #ifdef RSS
641734d68912SSepherosa Ziehau 		rss_getkey(rss->rss_key);
641834d68912SSepherosa Ziehau #else
641915516c77SSepherosa Ziehau 		memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key));
642034d68912SSepherosa Ziehau #endif
642115516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
642215516c77SSepherosa Ziehau 	}
642315516c77SSepherosa Ziehau 
642415516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) {
642515516c77SSepherosa Ziehau 		/*
642615516c77SSepherosa Ziehau 		 * RSS indirect table is not set yet; set it up in round-
642715516c77SSepherosa Ziehau 		 * robin fashion.
642815516c77SSepherosa Ziehau 		 */
642915516c77SSepherosa Ziehau 		if (bootverbose) {
643015516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS indirect "
643115516c77SSepherosa Ziehau 			    "table\n");
643215516c77SSepherosa Ziehau 		}
643334d68912SSepherosa Ziehau 		for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
643434d68912SSepherosa Ziehau 			uint32_t subidx;
643534d68912SSepherosa Ziehau 
643634d68912SSepherosa Ziehau #ifdef RSS
643734d68912SSepherosa Ziehau 			subidx = rss_get_indirection_to_bucket(i);
643834d68912SSepherosa Ziehau #else
643934d68912SSepherosa Ziehau 			subidx = i;
644034d68912SSepherosa Ziehau #endif
644134d68912SSepherosa Ziehau 			rss->rss_ind[i] = subidx % nchan;
644234d68912SSepherosa Ziehau 		}
644315516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSIND;
644415516c77SSepherosa Ziehau 	} else {
644515516c77SSepherosa Ziehau 		/*
644615516c77SSepherosa Ziehau 		 * # of usable channels may be changed, so we have to
644715516c77SSepherosa Ziehau 		 * make sure that all entries in RSS indirect table
644815516c77SSepherosa Ziehau 		 * are valid.
6449afd4971bSSepherosa Ziehau 		 *
6450afd4971bSSepherosa Ziehau 		 * NOTE: hn_set_ring_inuse() _must_ have been called.
645115516c77SSepherosa Ziehau 		 */
6452afd4971bSSepherosa Ziehau 		hn_rss_ind_fixup(sc);
645315516c77SSepherosa Ziehau 	}
645415516c77SSepherosa Ziehau 
6455642ec226SSepherosa Ziehau 	sc->hn_rss_hash = sc->hn_rss_hcap;
6456642ec226SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) ||
6457642ec226SSepherosa Ziehau 	    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
6458642ec226SSepherosa Ziehau 		/* NOTE: Don't reconfigure RSS; will do immediately. */
6459642ec226SSepherosa Ziehau 		hn_vf_rss_fixup(sc, false);
6460642ec226SSepherosa Ziehau 	}
646115516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
646215516c77SSepherosa Ziehau 	if (error)
646371e8ac56SSepherosa Ziehau 		goto failed;
646471e8ac56SSepherosa Ziehau back:
6465dc13fee6SSepherosa Ziehau 	/*
6466dc13fee6SSepherosa Ziehau 	 * Fixup transmission aggregation setup.
6467dc13fee6SSepherosa Ziehau 	 */
6468dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
6469b3b75d9cSSepherosa Ziehau 	hn_rndis_init_fixat(sc, nchan);
647015516c77SSepherosa Ziehau 	return (0);
647171e8ac56SSepherosa Ziehau 
647271e8ac56SSepherosa Ziehau failed:
647371e8ac56SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
6474b3b75d9cSSepherosa Ziehau 		hn_rndis_init_fixat(sc, nchan);
647571e8ac56SSepherosa Ziehau 		hn_synth_detach(sc);
647671e8ac56SSepherosa Ziehau 	} else {
6477b3b75d9cSSepherosa Ziehau 		if (attached & ATTACHED_RNDIS) {
6478b3b75d9cSSepherosa Ziehau 			hn_rndis_init_fixat(sc, nchan);
647971e8ac56SSepherosa Ziehau 			hn_rndis_detach(sc);
6480b3b75d9cSSepherosa Ziehau 		}
648171e8ac56SSepherosa Ziehau 		if (attached & ATTACHED_NVS)
648271e8ac56SSepherosa Ziehau 			hn_nvs_detach(sc);
648371e8ac56SSepherosa Ziehau 		hn_chan_detach(sc, sc->hn_prichan);
648471e8ac56SSepherosa Ziehau 		/* Restore old capabilities. */
648571e8ac56SSepherosa Ziehau 		sc->hn_caps = old_caps;
648671e8ac56SSepherosa Ziehau 	}
648771e8ac56SSepherosa Ziehau 	return (error);
648871e8ac56SSepherosa Ziehau 
648971e8ac56SSepherosa Ziehau #undef ATTACHED_RNDIS
649071e8ac56SSepherosa Ziehau #undef ATTACHED_NVS
649115516c77SSepherosa Ziehau }
649215516c77SSepherosa Ziehau 
649315516c77SSepherosa Ziehau /*
649415516c77SSepherosa Ziehau  * NOTE:
649515516c77SSepherosa Ziehau  * The interface must have been suspended though hn_suspend(), before
649615516c77SSepherosa Ziehau  * this function get called.
649715516c77SSepherosa Ziehau  */
649815516c77SSepherosa Ziehau static void
649915516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc)
650015516c77SSepherosa Ziehau {
650115516c77SSepherosa Ziehau 
650215516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
650315516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
650415516c77SSepherosa Ziehau 
650515516c77SSepherosa Ziehau 	/* Detach the RNDIS first. */
650615516c77SSepherosa Ziehau 	hn_rndis_detach(sc);
650715516c77SSepherosa Ziehau 
650815516c77SSepherosa Ziehau 	/* Detach NVS. */
650915516c77SSepherosa Ziehau 	hn_nvs_detach(sc);
651015516c77SSepherosa Ziehau 
651115516c77SSepherosa Ziehau 	/* Detach all of the channels. */
651215516c77SSepherosa Ziehau 	hn_detach_allchans(sc);
651315516c77SSepherosa Ziehau 
651415516c77SSepherosa Ziehau 	sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED;
651515516c77SSepherosa Ziehau }
651615516c77SSepherosa Ziehau 
651715516c77SSepherosa Ziehau static void
651815516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt)
651915516c77SSepherosa Ziehau {
652015516c77SSepherosa Ziehau 	KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt,
652115516c77SSepherosa Ziehau 	    ("invalid ring count %d", ring_cnt));
652215516c77SSepherosa Ziehau 
652315516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt > ring_cnt)
652415516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = ring_cnt;
652515516c77SSepherosa Ziehau 	else
652615516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
652715516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = ring_cnt;
652815516c77SSepherosa Ziehau 
652934d68912SSepherosa Ziehau #ifdef RSS
653034d68912SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse != rss_getnumbuckets()) {
653134d68912SSepherosa Ziehau 		if_printf(sc->hn_ifp, "# of RX rings (%d) does not match "
653234d68912SSepherosa Ziehau 		    "# of RSS buckets (%d)\n", sc->hn_rx_ring_inuse,
653334d68912SSepherosa Ziehau 		    rss_getnumbuckets());
653434d68912SSepherosa Ziehau 	}
653534d68912SSepherosa Ziehau #endif
653634d68912SSepherosa Ziehau 
653715516c77SSepherosa Ziehau 	if (bootverbose) {
653815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n",
653915516c77SSepherosa Ziehau 		    sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
654015516c77SSepherosa Ziehau 	}
654115516c77SSepherosa Ziehau }
654215516c77SSepherosa Ziehau 
654315516c77SSepherosa Ziehau static void
654425641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan)
654515516c77SSepherosa Ziehau {
654615516c77SSepherosa Ziehau 
654725641fc7SSepherosa Ziehau 	/*
654825641fc7SSepherosa Ziehau 	 * NOTE:
654925641fc7SSepherosa Ziehau 	 * The TX bufring will not be drained by the hypervisor,
655025641fc7SSepherosa Ziehau 	 * if the primary channel is revoked.
655125641fc7SSepherosa Ziehau 	 */
655225641fc7SSepherosa Ziehau 	while (!vmbus_chan_rx_empty(chan) ||
655325641fc7SSepherosa Ziehau 	    (!vmbus_chan_is_revoked(sc->hn_prichan) &&
655425641fc7SSepherosa Ziehau 	     !vmbus_chan_tx_empty(chan)))
655515516c77SSepherosa Ziehau 		pause("waitch", 1);
655615516c77SSepherosa Ziehau 	vmbus_chan_intr_drain(chan);
655715516c77SSepherosa Ziehau }
655815516c77SSepherosa Ziehau 
655915516c77SSepherosa Ziehau static void
6560b3b75d9cSSepherosa Ziehau hn_disable_rx(struct hn_softc *sc)
6561b3b75d9cSSepherosa Ziehau {
6562b3b75d9cSSepherosa Ziehau 
6563b3b75d9cSSepherosa Ziehau 	/*
6564b3b75d9cSSepherosa Ziehau 	 * Disable RX by clearing RX filter forcefully.
6565b3b75d9cSSepherosa Ziehau 	 */
6566b3b75d9cSSepherosa Ziehau 	sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE;
6567b3b75d9cSSepherosa Ziehau 	hn_rndis_set_rxfilter(sc, sc->hn_rx_filter); /* ignore error */
6568b3b75d9cSSepherosa Ziehau 
6569b3b75d9cSSepherosa Ziehau 	/*
6570b3b75d9cSSepherosa Ziehau 	 * Give RNDIS enough time to flush all pending data packets.
6571b3b75d9cSSepherosa Ziehau 	 */
6572b3b75d9cSSepherosa Ziehau 	pause("waitrx", (200 * hz) / 1000);
6573b3b75d9cSSepherosa Ziehau }
6574b3b75d9cSSepherosa Ziehau 
6575b3b75d9cSSepherosa Ziehau /*
6576b3b75d9cSSepherosa Ziehau  * NOTE:
6577b3b75d9cSSepherosa Ziehau  * RX/TX _must_ have been suspended/disabled, before this function
6578b3b75d9cSSepherosa Ziehau  * is called.
6579b3b75d9cSSepherosa Ziehau  */
6580b3b75d9cSSepherosa Ziehau static void
6581b3b75d9cSSepherosa Ziehau hn_drain_rxtx(struct hn_softc *sc, int nchan)
658215516c77SSepherosa Ziehau {
658315516c77SSepherosa Ziehau 	struct vmbus_channel **subch = NULL;
6584b3b75d9cSSepherosa Ziehau 	int nsubch;
6585b3b75d9cSSepherosa Ziehau 
6586b3b75d9cSSepherosa Ziehau 	/*
6587b3b75d9cSSepherosa Ziehau 	 * Drain RX/TX bufrings and interrupts.
6588b3b75d9cSSepherosa Ziehau 	 */
6589b3b75d9cSSepherosa Ziehau 	nsubch = nchan - 1;
6590b3b75d9cSSepherosa Ziehau 	if (nsubch > 0)
6591b3b75d9cSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
6592b3b75d9cSSepherosa Ziehau 
6593b3b75d9cSSepherosa Ziehau 	if (subch != NULL) {
6594b3b75d9cSSepherosa Ziehau 		int i;
6595b3b75d9cSSepherosa Ziehau 
6596b3b75d9cSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
6597b3b75d9cSSepherosa Ziehau 			hn_chan_drain(sc, subch[i]);
6598b3b75d9cSSepherosa Ziehau 	}
6599b3b75d9cSSepherosa Ziehau 	hn_chan_drain(sc, sc->hn_prichan);
6600b3b75d9cSSepherosa Ziehau 
6601b3b75d9cSSepherosa Ziehau 	if (subch != NULL)
6602b3b75d9cSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
6603b3b75d9cSSepherosa Ziehau }
6604b3b75d9cSSepherosa Ziehau 
6605b3b75d9cSSepherosa Ziehau static void
6606b3b75d9cSSepherosa Ziehau hn_suspend_data(struct hn_softc *sc)
6607b3b75d9cSSepherosa Ziehau {
660825641fc7SSepherosa Ziehau 	struct hn_tx_ring *txr;
6609b3b75d9cSSepherosa Ziehau 	int i;
661015516c77SSepherosa Ziehau 
661115516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
661215516c77SSepherosa Ziehau 
661315516c77SSepherosa Ziehau 	/*
661415516c77SSepherosa Ziehau 	 * Suspend TX.
661515516c77SSepherosa Ziehau 	 */
661615516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
661725641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
661815516c77SSepherosa Ziehau 
661915516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
662015516c77SSepherosa Ziehau 		txr->hn_suspended = 1;
662115516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
662215516c77SSepherosa Ziehau 		/* No one is able send more packets now. */
662315516c77SSepherosa Ziehau 
662425641fc7SSepherosa Ziehau 		/*
662525641fc7SSepherosa Ziehau 		 * Wait for all pending sends to finish.
662625641fc7SSepherosa Ziehau 		 *
662725641fc7SSepherosa Ziehau 		 * NOTE:
662825641fc7SSepherosa Ziehau 		 * We will _not_ receive all pending send-done, if the
662925641fc7SSepherosa Ziehau 		 * primary channel is revoked.
663025641fc7SSepherosa Ziehau 		 */
663125641fc7SSepherosa Ziehau 		while (hn_tx_ring_pending(txr) &&
663225641fc7SSepherosa Ziehau 		    !vmbus_chan_is_revoked(sc->hn_prichan))
663315516c77SSepherosa Ziehau 			pause("hnwtx", 1 /* 1 tick */);
663415516c77SSepherosa Ziehau 	}
663515516c77SSepherosa Ziehau 
663615516c77SSepherosa Ziehau 	/*
6637b3b75d9cSSepherosa Ziehau 	 * Disable RX.
663815516c77SSepherosa Ziehau 	 */
6639b3b75d9cSSepherosa Ziehau 	hn_disable_rx(sc);
664015516c77SSepherosa Ziehau 
664115516c77SSepherosa Ziehau 	/*
6642b3b75d9cSSepherosa Ziehau 	 * Drain RX/TX.
664315516c77SSepherosa Ziehau 	 */
6644b3b75d9cSSepherosa Ziehau 	hn_drain_rxtx(sc, sc->hn_rx_ring_inuse);
664525641fc7SSepherosa Ziehau 
664625641fc7SSepherosa Ziehau 	/*
664725641fc7SSepherosa Ziehau 	 * Drain any pending TX tasks.
664825641fc7SSepherosa Ziehau 	 *
664925641fc7SSepherosa Ziehau 	 * NOTE:
6650b3b75d9cSSepherosa Ziehau 	 * The above hn_drain_rxtx() can dispatch TX tasks, so the TX
6651b3b75d9cSSepherosa Ziehau 	 * tasks will have to be drained _after_ the above hn_drain_rxtx().
665225641fc7SSepherosa Ziehau 	 */
665325641fc7SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
665425641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
665525641fc7SSepherosa Ziehau 
665625641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task);
665725641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task);
665825641fc7SSepherosa Ziehau 	}
665915516c77SSepherosa Ziehau }
666015516c77SSepherosa Ziehau 
666115516c77SSepherosa Ziehau static void
666215516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused)
666315516c77SSepherosa Ziehau {
666415516c77SSepherosa Ziehau 
666515516c77SSepherosa Ziehau 	((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL;
666615516c77SSepherosa Ziehau }
666715516c77SSepherosa Ziehau 
666815516c77SSepherosa Ziehau static void
666915516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc)
667015516c77SSepherosa Ziehau {
667115516c77SSepherosa Ziehau 	struct task task;
667215516c77SSepherosa Ziehau 
667315516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
667415516c77SSepherosa Ziehau 
667515516c77SSepherosa Ziehau 	/*
667615516c77SSepherosa Ziehau 	 * Make sure that hn_mgmt_taskq0 can nolonger be accessed
667715516c77SSepherosa Ziehau 	 * through hn_mgmt_taskq.
667815516c77SSepherosa Ziehau 	 */
667915516c77SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc);
668015516c77SSepherosa Ziehau 	vmbus_chan_run_task(sc->hn_prichan, &task);
668115516c77SSepherosa Ziehau 
668215516c77SSepherosa Ziehau 	/*
668315516c77SSepherosa Ziehau 	 * Make sure that all pending management tasks are completed.
668415516c77SSepherosa Ziehau 	 */
668515516c77SSepherosa Ziehau 	taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init);
668615516c77SSepherosa Ziehau 	taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status);
668715516c77SSepherosa Ziehau 	taskqueue_drain_all(sc->hn_mgmt_taskq0);
668815516c77SSepherosa Ziehau }
668915516c77SSepherosa Ziehau 
669015516c77SSepherosa Ziehau static void
669115516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc)
669215516c77SSepherosa Ziehau {
669315516c77SSepherosa Ziehau 
669487f8129dSSepherosa Ziehau 	/* Disable polling. */
669587f8129dSSepherosa Ziehau 	hn_polling(sc, 0);
669687f8129dSSepherosa Ziehau 
66979c6cae24SSepherosa Ziehau 	/*
66989c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, the synthetic
66999c6cae24SSepherosa Ziehau 	 * device is receiving packets, so the data path of the
67009c6cae24SSepherosa Ziehau 	 * synthetic device must be suspended.
67019c6cae24SSepherosa Ziehau 	 */
67025bdfd3fdSDexuan Cui 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
6703962f0357SSepherosa Ziehau 	    (sc->hn_flags & HN_FLAG_RXVF))
670415516c77SSepherosa Ziehau 		hn_suspend_data(sc);
670515516c77SSepherosa Ziehau 	hn_suspend_mgmt(sc);
670615516c77SSepherosa Ziehau }
670715516c77SSepherosa Ziehau 
670815516c77SSepherosa Ziehau static void
670915516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt)
671015516c77SSepherosa Ziehau {
671115516c77SSepherosa Ziehau 	int i;
671215516c77SSepherosa Ziehau 
671315516c77SSepherosa Ziehau 	KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt,
671415516c77SSepherosa Ziehau 	    ("invalid TX ring count %d", tx_ring_cnt));
671515516c77SSepherosa Ziehau 
671615516c77SSepherosa Ziehau 	for (i = 0; i < tx_ring_cnt; ++i) {
671715516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
671815516c77SSepherosa Ziehau 
671915516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
672015516c77SSepherosa Ziehau 		txr->hn_suspended = 0;
672115516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
672215516c77SSepherosa Ziehau 	}
672315516c77SSepherosa Ziehau }
672415516c77SSepherosa Ziehau 
672515516c77SSepherosa Ziehau static void
672615516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc)
672715516c77SSepherosa Ziehau {
672815516c77SSepherosa Ziehau 	int i;
672915516c77SSepherosa Ziehau 
673015516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
673115516c77SSepherosa Ziehau 
673215516c77SSepherosa Ziehau 	/*
673315516c77SSepherosa Ziehau 	 * Re-enable RX.
673415516c77SSepherosa Ziehau 	 */
6735c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
673615516c77SSepherosa Ziehau 
673715516c77SSepherosa Ziehau 	/*
673815516c77SSepherosa Ziehau 	 * Make sure to clear suspend status on "all" TX rings,
673915516c77SSepherosa Ziehau 	 * since hn_tx_ring_inuse can be changed after
674015516c77SSepherosa Ziehau 	 * hn_suspend_data().
674115516c77SSepherosa Ziehau 	 */
674215516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_cnt);
674315516c77SSepherosa Ziehau 
674423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
674523bf9e15SSepherosa Ziehau 	if (!hn_use_if_start)
674623bf9e15SSepherosa Ziehau #endif
674723bf9e15SSepherosa Ziehau 	{
674815516c77SSepherosa Ziehau 		/*
674915516c77SSepherosa Ziehau 		 * Flush unused drbrs, since hn_tx_ring_inuse may be
675015516c77SSepherosa Ziehau 		 * reduced.
675115516c77SSepherosa Ziehau 		 */
675215516c77SSepherosa Ziehau 		for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i)
675315516c77SSepherosa Ziehau 			hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
675415516c77SSepherosa Ziehau 	}
675515516c77SSepherosa Ziehau 
675615516c77SSepherosa Ziehau 	/*
675715516c77SSepherosa Ziehau 	 * Kick start TX.
675815516c77SSepherosa Ziehau 	 */
675915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
676015516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
676115516c77SSepherosa Ziehau 
676215516c77SSepherosa Ziehau 		/*
676315516c77SSepherosa Ziehau 		 * Use txeof task, so that any pending oactive can be
676415516c77SSepherosa Ziehau 		 * cleared properly.
676515516c77SSepherosa Ziehau 		 */
676615516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
676715516c77SSepherosa Ziehau 	}
676815516c77SSepherosa Ziehau }
676915516c77SSepherosa Ziehau 
677015516c77SSepherosa Ziehau static void
677115516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc)
677215516c77SSepherosa Ziehau {
677315516c77SSepherosa Ziehau 
677415516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
677515516c77SSepherosa Ziehau 
677615516c77SSepherosa Ziehau 	/*
677715516c77SSepherosa Ziehau 	 * Kick off network change detection, if it was pending.
677815516c77SSepherosa Ziehau 	 * If no network change was pending, start link status
677915516c77SSepherosa Ziehau 	 * checks, which is more lightweight than network change
678015516c77SSepherosa Ziehau 	 * detection.
678115516c77SSepherosa Ziehau 	 */
678215516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
678315516c77SSepherosa Ziehau 		hn_change_network(sc);
678415516c77SSepherosa Ziehau 	else
678515516c77SSepherosa Ziehau 		hn_update_link_status(sc);
678615516c77SSepherosa Ziehau }
678715516c77SSepherosa Ziehau 
678815516c77SSepherosa Ziehau static void
678915516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc)
679015516c77SSepherosa Ziehau {
679115516c77SSepherosa Ziehau 
67929c6cae24SSepherosa Ziehau 	/*
67939c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, the synthetic
67949c6cae24SSepherosa Ziehau 	 * device have to receive packets, so the data path of the
67959c6cae24SSepherosa Ziehau 	 * synthetic device must be resumed.
67969c6cae24SSepherosa Ziehau 	 */
67975bdfd3fdSDexuan Cui 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
6798962f0357SSepherosa Ziehau 	    (sc->hn_flags & HN_FLAG_RXVF))
679915516c77SSepherosa Ziehau 		hn_resume_data(sc);
68005bdfd3fdSDexuan Cui 
68015bdfd3fdSDexuan Cui 	/*
68029c6cae24SSepherosa Ziehau 	 * Don't resume link status change if VF is attached/activated.
68039c6cae24SSepherosa Ziehau 	 * - In the non-transparent VF mode, the synthetic device marks
68049c6cae24SSepherosa Ziehau 	 *   link down until the VF is deactivated; i.e. VF is down.
68059c6cae24SSepherosa Ziehau 	 * - In transparent VF mode, VF's media status is used until
68069c6cae24SSepherosa Ziehau 	 *   the VF is detached.
68075bdfd3fdSDexuan Cui 	 */
68089c6cae24SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) == 0 &&
68099c6cae24SSepherosa Ziehau 	    !(hn_xpnt_vf && sc->hn_vf_ifp != NULL))
681015516c77SSepherosa Ziehau 		hn_resume_mgmt(sc);
681187f8129dSSepherosa Ziehau 
681287f8129dSSepherosa Ziehau 	/*
681387f8129dSSepherosa Ziehau 	 * Re-enable polling if this interface is running and
681487f8129dSSepherosa Ziehau 	 * the polling is requested.
681587f8129dSSepherosa Ziehau 	 */
681687f8129dSSepherosa Ziehau 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->hn_pollhz > 0)
681787f8129dSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
681815516c77SSepherosa Ziehau }
681915516c77SSepherosa Ziehau 
682015516c77SSepherosa Ziehau static void
682115516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen)
682215516c77SSepherosa Ziehau {
682315516c77SSepherosa Ziehau 	const struct rndis_status_msg *msg;
682415516c77SSepherosa Ziehau 	int ofs;
682515516c77SSepherosa Ziehau 
682615516c77SSepherosa Ziehau 	if (dlen < sizeof(*msg)) {
682715516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid RNDIS status\n");
682815516c77SSepherosa Ziehau 		return;
682915516c77SSepherosa Ziehau 	}
683015516c77SSepherosa Ziehau 	msg = data;
683115516c77SSepherosa Ziehau 
683215516c77SSepherosa Ziehau 	switch (msg->rm_status) {
683315516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_CONNECT:
683415516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_DISCONNECT:
683515516c77SSepherosa Ziehau 		hn_update_link_status(sc);
683615516c77SSepherosa Ziehau 		break;
683715516c77SSepherosa Ziehau 
683815516c77SSepherosa Ziehau 	case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
683940905afaSSepherosa Ziehau 	case RNDIS_STATUS_LINK_SPEED_CHANGE:
684015516c77SSepherosa Ziehau 		/* Not really useful; ignore. */
684115516c77SSepherosa Ziehau 		break;
684215516c77SSepherosa Ziehau 
684315516c77SSepherosa Ziehau 	case RNDIS_STATUS_NETWORK_CHANGE:
684415516c77SSepherosa Ziehau 		ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
684515516c77SSepherosa Ziehau 		if (dlen < ofs + msg->rm_stbuflen ||
684615516c77SSepherosa Ziehau 		    msg->rm_stbuflen < sizeof(uint32_t)) {
684715516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed\n");
684815516c77SSepherosa Ziehau 		} else {
684915516c77SSepherosa Ziehau 			uint32_t change;
685015516c77SSepherosa Ziehau 
685115516c77SSepherosa Ziehau 			memcpy(&change, ((const uint8_t *)msg) + ofs,
685215516c77SSepherosa Ziehau 			    sizeof(change));
685315516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed, change %u\n",
685415516c77SSepherosa Ziehau 			    change);
685515516c77SSepherosa Ziehau 		}
685615516c77SSepherosa Ziehau 		hn_change_network(sc);
685715516c77SSepherosa Ziehau 		break;
685815516c77SSepherosa Ziehau 
685915516c77SSepherosa Ziehau 	default:
686015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
686115516c77SSepherosa Ziehau 		    msg->rm_status);
686215516c77SSepherosa Ziehau 		break;
686315516c77SSepherosa Ziehau 	}
686415516c77SSepherosa Ziehau }
686515516c77SSepherosa Ziehau 
686615516c77SSepherosa Ziehau static int
686715516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info)
686815516c77SSepherosa Ziehau {
686915516c77SSepherosa Ziehau 	const struct rndis_pktinfo *pi = info_data;
687015516c77SSepherosa Ziehau 	uint32_t mask = 0;
687115516c77SSepherosa Ziehau 
687215516c77SSepherosa Ziehau 	while (info_dlen != 0) {
687315516c77SSepherosa Ziehau 		const void *data;
687415516c77SSepherosa Ziehau 		uint32_t dlen;
687515516c77SSepherosa Ziehau 
687615516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < sizeof(*pi)))
687715516c77SSepherosa Ziehau 			return (EINVAL);
687815516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < pi->rm_size))
687915516c77SSepherosa Ziehau 			return (EINVAL);
688015516c77SSepherosa Ziehau 		info_dlen -= pi->rm_size;
688115516c77SSepherosa Ziehau 
688215516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
688315516c77SSepherosa Ziehau 			return (EINVAL);
688415516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
688515516c77SSepherosa Ziehau 			return (EINVAL);
688615516c77SSepherosa Ziehau 		dlen = pi->rm_size - pi->rm_pktinfooffset;
688715516c77SSepherosa Ziehau 		data = pi->rm_data;
688815516c77SSepherosa Ziehau 
688915516c77SSepherosa Ziehau 		switch (pi->rm_type) {
689015516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_VLAN:
689115516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
689215516c77SSepherosa Ziehau 				return (EINVAL);
689315516c77SSepherosa Ziehau 			info->vlan_info = *((const uint32_t *)data);
689415516c77SSepherosa Ziehau 			mask |= HN_RXINFO_VLAN;
689515516c77SSepherosa Ziehau 			break;
689615516c77SSepherosa Ziehau 
689715516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_CSUM:
689815516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
689915516c77SSepherosa Ziehau 				return (EINVAL);
690015516c77SSepherosa Ziehau 			info->csum_info = *((const uint32_t *)data);
690115516c77SSepherosa Ziehau 			mask |= HN_RXINFO_CSUM;
690215516c77SSepherosa Ziehau 			break;
690315516c77SSepherosa Ziehau 
690415516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHVAL:
690515516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
690615516c77SSepherosa Ziehau 				return (EINVAL);
690715516c77SSepherosa Ziehau 			info->hash_value = *((const uint32_t *)data);
690815516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHVAL;
690915516c77SSepherosa Ziehau 			break;
691015516c77SSepherosa Ziehau 
691115516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHINF:
691215516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
691315516c77SSepherosa Ziehau 				return (EINVAL);
691415516c77SSepherosa Ziehau 			info->hash_info = *((const uint32_t *)data);
691515516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHINF;
691615516c77SSepherosa Ziehau 			break;
691715516c77SSepherosa Ziehau 
691815516c77SSepherosa Ziehau 		default:
691915516c77SSepherosa Ziehau 			goto next;
692015516c77SSepherosa Ziehau 		}
692115516c77SSepherosa Ziehau 
692215516c77SSepherosa Ziehau 		if (mask == HN_RXINFO_ALL) {
692315516c77SSepherosa Ziehau 			/* All found; done */
692415516c77SSepherosa Ziehau 			break;
692515516c77SSepherosa Ziehau 		}
692615516c77SSepherosa Ziehau next:
692715516c77SSepherosa Ziehau 		pi = (const struct rndis_pktinfo *)
692815516c77SSepherosa Ziehau 		    ((const uint8_t *)pi + pi->rm_size);
692915516c77SSepherosa Ziehau 	}
693015516c77SSepherosa Ziehau 
693115516c77SSepherosa Ziehau 	/*
693215516c77SSepherosa Ziehau 	 * Final fixup.
693315516c77SSepherosa Ziehau 	 * - If there is no hash value, invalidate the hash info.
693415516c77SSepherosa Ziehau 	 */
693515516c77SSepherosa Ziehau 	if ((mask & HN_RXINFO_HASHVAL) == 0)
693615516c77SSepherosa Ziehau 		info->hash_info = HN_NDIS_HASH_INFO_INVALID;
693715516c77SSepherosa Ziehau 	return (0);
693815516c77SSepherosa Ziehau }
693915516c77SSepherosa Ziehau 
694015516c77SSepherosa Ziehau static __inline bool
694115516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
694215516c77SSepherosa Ziehau {
694315516c77SSepherosa Ziehau 
694415516c77SSepherosa Ziehau 	if (off < check_off) {
694515516c77SSepherosa Ziehau 		if (__predict_true(off + len <= check_off))
694615516c77SSepherosa Ziehau 			return (false);
694715516c77SSepherosa Ziehau 	} else if (off > check_off) {
694815516c77SSepherosa Ziehau 		if (__predict_true(check_off + check_len <= off))
694915516c77SSepherosa Ziehau 			return (false);
695015516c77SSepherosa Ziehau 	}
695115516c77SSepherosa Ziehau 	return (true);
695215516c77SSepherosa Ziehau }
695315516c77SSepherosa Ziehau 
695415516c77SSepherosa Ziehau static void
695515516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen)
695615516c77SSepherosa Ziehau {
695715516c77SSepherosa Ziehau 	const struct rndis_packet_msg *pkt;
695815516c77SSepherosa Ziehau 	struct hn_rxinfo info;
695915516c77SSepherosa Ziehau 	int data_off, pktinfo_off, data_len, pktinfo_len;
696015516c77SSepherosa Ziehau 
696115516c77SSepherosa Ziehau 	/*
696215516c77SSepherosa Ziehau 	 * Check length.
696315516c77SSepherosa Ziehau 	 */
696415516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*pkt))) {
696515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
696615516c77SSepherosa Ziehau 		return;
696715516c77SSepherosa Ziehau 	}
696815516c77SSepherosa Ziehau 	pkt = data;
696915516c77SSepherosa Ziehau 
697015516c77SSepherosa Ziehau 	if (__predict_false(dlen < pkt->rm_len)) {
697115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
697215516c77SSepherosa Ziehau 		    "dlen %d, msglen %u\n", dlen, pkt->rm_len);
697315516c77SSepherosa Ziehau 		return;
697415516c77SSepherosa Ziehau 	}
697515516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_len <
697615516c77SSepherosa Ziehau 	    pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
697715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
697815516c77SSepherosa Ziehau 		    "msglen %u, data %u, oob %u, pktinfo %u\n",
697915516c77SSepherosa Ziehau 		    pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
698015516c77SSepherosa Ziehau 		    pkt->rm_pktinfolen);
698115516c77SSepherosa Ziehau 		return;
698215516c77SSepherosa Ziehau 	}
698315516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_datalen == 0)) {
698415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
698515516c77SSepherosa Ziehau 		return;
698615516c77SSepherosa Ziehau 	}
698715516c77SSepherosa Ziehau 
698815516c77SSepherosa Ziehau 	/*
698915516c77SSepherosa Ziehau 	 * Check offests.
699015516c77SSepherosa Ziehau 	 */
699115516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs)			\
699215516c77SSepherosa Ziehau 	((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN ||	\
699315516c77SSepherosa Ziehau 	 ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
699415516c77SSepherosa Ziehau 
699515516c77SSepherosa Ziehau 	/* XXX Hyper-V does not meet data offset alignment requirement */
699615516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
699715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
699815516c77SSepherosa Ziehau 		    "data offset %u\n", pkt->rm_dataoffset);
699915516c77SSepherosa Ziehau 		return;
700015516c77SSepherosa Ziehau 	}
700115516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdataoffset > 0 &&
700215516c77SSepherosa Ziehau 	    IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
700315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
700415516c77SSepherosa Ziehau 		    "oob offset %u\n", pkt->rm_oobdataoffset);
700515516c77SSepherosa Ziehau 		return;
700615516c77SSepherosa Ziehau 	}
700715516c77SSepherosa Ziehau 	if (__predict_true(pkt->rm_pktinfooffset > 0) &&
700815516c77SSepherosa Ziehau 	    __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
700915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
701015516c77SSepherosa Ziehau 		    "pktinfo offset %u\n", pkt->rm_pktinfooffset);
701115516c77SSepherosa Ziehau 		return;
701215516c77SSepherosa Ziehau 	}
701315516c77SSepherosa Ziehau 
701415516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID
701515516c77SSepherosa Ziehau 
701615516c77SSepherosa Ziehau 	data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
701715516c77SSepherosa Ziehau 	data_len = pkt->rm_datalen;
701815516c77SSepherosa Ziehau 	pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
701915516c77SSepherosa Ziehau 	pktinfo_len = pkt->rm_pktinfolen;
702015516c77SSepherosa Ziehau 
702115516c77SSepherosa Ziehau 	/*
702215516c77SSepherosa Ziehau 	 * Check OOB coverage.
702315516c77SSepherosa Ziehau 	 */
702415516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdatalen != 0)) {
702515516c77SSepherosa Ziehau 		int oob_off, oob_len;
702615516c77SSepherosa Ziehau 
702715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "got oobdata\n");
702815516c77SSepherosa Ziehau 		oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
702915516c77SSepherosa Ziehau 		oob_len = pkt->rm_oobdatalen;
703015516c77SSepherosa Ziehau 
703115516c77SSepherosa Ziehau 		if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
703215516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
703315516c77SSepherosa Ziehau 			    "oob overflow, msglen %u, oob abs %d len %d\n",
703415516c77SSepherosa Ziehau 			    pkt->rm_len, oob_off, oob_len);
703515516c77SSepherosa Ziehau 			return;
703615516c77SSepherosa Ziehau 		}
703715516c77SSepherosa Ziehau 
703815516c77SSepherosa Ziehau 		/*
703915516c77SSepherosa Ziehau 		 * Check against data.
704015516c77SSepherosa Ziehau 		 */
704115516c77SSepherosa Ziehau 		if (hn_rndis_check_overlap(oob_off, oob_len,
704215516c77SSepherosa Ziehau 		    data_off, data_len)) {
704315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
704415516c77SSepherosa Ziehau 			    "oob overlaps data, oob abs %d len %d, "
704515516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
704615516c77SSepherosa Ziehau 			    oob_off, oob_len, data_off, data_len);
704715516c77SSepherosa Ziehau 			return;
704815516c77SSepherosa Ziehau 		}
704915516c77SSepherosa Ziehau 
705015516c77SSepherosa Ziehau 		/*
705115516c77SSepherosa Ziehau 		 * Check against pktinfo.
705215516c77SSepherosa Ziehau 		 */
705315516c77SSepherosa Ziehau 		if (pktinfo_len != 0 &&
705415516c77SSepherosa Ziehau 		    hn_rndis_check_overlap(oob_off, oob_len,
705515516c77SSepherosa Ziehau 		    pktinfo_off, pktinfo_len)) {
705615516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
705715516c77SSepherosa Ziehau 			    "oob overlaps pktinfo, oob abs %d len %d, "
705815516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
705915516c77SSepherosa Ziehau 			    oob_off, oob_len, pktinfo_off, pktinfo_len);
706015516c77SSepherosa Ziehau 			return;
706115516c77SSepherosa Ziehau 		}
706215516c77SSepherosa Ziehau 	}
706315516c77SSepherosa Ziehau 
706415516c77SSepherosa Ziehau 	/*
706515516c77SSepherosa Ziehau 	 * Check per-packet-info coverage and find useful per-packet-info.
706615516c77SSepherosa Ziehau 	 */
706715516c77SSepherosa Ziehau 	info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
706815516c77SSepherosa Ziehau 	info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
706915516c77SSepherosa Ziehau 	info.hash_info = HN_NDIS_HASH_INFO_INVALID;
707015516c77SSepherosa Ziehau 	if (__predict_true(pktinfo_len != 0)) {
707115516c77SSepherosa Ziehau 		bool overlap;
707215516c77SSepherosa Ziehau 		int error;
707315516c77SSepherosa Ziehau 
707415516c77SSepherosa Ziehau 		if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
707515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
707615516c77SSepherosa Ziehau 			    "pktinfo overflow, msglen %u, "
707715516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
707815516c77SSepherosa Ziehau 			    pkt->rm_len, pktinfo_off, pktinfo_len);
707915516c77SSepherosa Ziehau 			return;
708015516c77SSepherosa Ziehau 		}
708115516c77SSepherosa Ziehau 
708215516c77SSepherosa Ziehau 		/*
708315516c77SSepherosa Ziehau 		 * Check packet info coverage.
708415516c77SSepherosa Ziehau 		 */
708515516c77SSepherosa Ziehau 		overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
708615516c77SSepherosa Ziehau 		    data_off, data_len);
708715516c77SSepherosa Ziehau 		if (__predict_false(overlap)) {
708815516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
708915516c77SSepherosa Ziehau 			    "pktinfo overlap data, pktinfo abs %d len %d, "
709015516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
709115516c77SSepherosa Ziehau 			    pktinfo_off, pktinfo_len, data_off, data_len);
709215516c77SSepherosa Ziehau 			return;
709315516c77SSepherosa Ziehau 		}
709415516c77SSepherosa Ziehau 
709515516c77SSepherosa Ziehau 		/*
709615516c77SSepherosa Ziehau 		 * Find useful per-packet-info.
709715516c77SSepherosa Ziehau 		 */
709815516c77SSepherosa Ziehau 		error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
709915516c77SSepherosa Ziehau 		    pktinfo_len, &info);
710015516c77SSepherosa Ziehau 		if (__predict_false(error)) {
710115516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
710215516c77SSepherosa Ziehau 			    "pktinfo\n");
710315516c77SSepherosa Ziehau 			return;
710415516c77SSepherosa Ziehau 		}
710515516c77SSepherosa Ziehau 	}
710615516c77SSepherosa Ziehau 
710715516c77SSepherosa Ziehau 	if (__predict_false(data_off + data_len > pkt->rm_len)) {
710815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
710915516c77SSepherosa Ziehau 		    "data overflow, msglen %u, data abs %d len %d\n",
711015516c77SSepherosa Ziehau 		    pkt->rm_len, data_off, data_len);
711115516c77SSepherosa Ziehau 		return;
711215516c77SSepherosa Ziehau 	}
711315516c77SSepherosa Ziehau 	hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
711415516c77SSepherosa Ziehau }
711515516c77SSepherosa Ziehau 
711615516c77SSepherosa Ziehau static __inline void
711715516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen)
711815516c77SSepherosa Ziehau {
711915516c77SSepherosa Ziehau 	const struct rndis_msghdr *hdr;
712015516c77SSepherosa Ziehau 
712115516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*hdr))) {
712215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
712315516c77SSepherosa Ziehau 		return;
712415516c77SSepherosa Ziehau 	}
712515516c77SSepherosa Ziehau 	hdr = data;
712615516c77SSepherosa Ziehau 
712715516c77SSepherosa Ziehau 	if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) {
712815516c77SSepherosa Ziehau 		/* Hot data path. */
712915516c77SSepherosa Ziehau 		hn_rndis_rx_data(rxr, data, dlen);
713015516c77SSepherosa Ziehau 		/* Done! */
713115516c77SSepherosa Ziehau 		return;
713215516c77SSepherosa Ziehau 	}
713315516c77SSepherosa Ziehau 
713415516c77SSepherosa Ziehau 	if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG)
713515516c77SSepherosa Ziehau 		hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen);
713615516c77SSepherosa Ziehau 	else
713715516c77SSepherosa Ziehau 		hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen);
713815516c77SSepherosa Ziehau }
713915516c77SSepherosa Ziehau 
714015516c77SSepherosa Ziehau static void
714115516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
714215516c77SSepherosa Ziehau {
714315516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *hdr;
714415516c77SSepherosa Ziehau 
714515516c77SSepherosa Ziehau 	if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) {
714615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid nvs notify\n");
714715516c77SSepherosa Ziehau 		return;
714815516c77SSepherosa Ziehau 	}
714915516c77SSepherosa Ziehau 	hdr = VMBUS_CHANPKT_CONST_DATA(pkt);
715015516c77SSepherosa Ziehau 
715115516c77SSepherosa Ziehau 	if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) {
715215516c77SSepherosa Ziehau 		/* Useless; ignore */
715315516c77SSepherosa Ziehau 		return;
715415516c77SSepherosa Ziehau 	}
715515516c77SSepherosa Ziehau 	if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type);
715615516c77SSepherosa Ziehau }
715715516c77SSepherosa Ziehau 
715815516c77SSepherosa Ziehau static void
715915516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan,
716015516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkt)
716115516c77SSepherosa Ziehau {
716215516c77SSepherosa Ziehau 	struct hn_nvs_sendctx *sndc;
716315516c77SSepherosa Ziehau 
716415516c77SSepherosa Ziehau 	sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid;
716515516c77SSepherosa Ziehau 	sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt),
716615516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_DATALEN(pkt));
716715516c77SSepherosa Ziehau 	/*
716815516c77SSepherosa Ziehau 	 * NOTE:
716915516c77SSepherosa Ziehau 	 * 'sndc' CAN NOT be accessed anymore, since it can be freed by
717015516c77SSepherosa Ziehau 	 * its callback.
717115516c77SSepherosa Ziehau 	 */
717215516c77SSepherosa Ziehau }
717315516c77SSepherosa Ziehau 
717415516c77SSepherosa Ziehau static void
717515516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
717615516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkthdr)
717715516c77SSepherosa Ziehau {
717815516c77SSepherosa Ziehau 	const struct vmbus_chanpkt_rxbuf *pkt;
717915516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *nvs_hdr;
718015516c77SSepherosa Ziehau 	int count, i, hlen;
718115516c77SSepherosa Ziehau 
718215516c77SSepherosa Ziehau 	if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) {
718315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n");
718415516c77SSepherosa Ziehau 		return;
718515516c77SSepherosa Ziehau 	}
718615516c77SSepherosa Ziehau 	nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr);
718715516c77SSepherosa Ziehau 
718815516c77SSepherosa Ziehau 	/* Make sure that this is a RNDIS message. */
718915516c77SSepherosa Ziehau 	if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) {
719015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n",
719115516c77SSepherosa Ziehau 		    nvs_hdr->nvs_type);
719215516c77SSepherosa Ziehau 		return;
719315516c77SSepherosa Ziehau 	}
719415516c77SSepherosa Ziehau 
719515516c77SSepherosa Ziehau 	hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen);
719615516c77SSepherosa Ziehau 	if (__predict_false(hlen < sizeof(*pkt))) {
719715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n");
719815516c77SSepherosa Ziehau 		return;
719915516c77SSepherosa Ziehau 	}
720015516c77SSepherosa Ziehau 	pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
720115516c77SSepherosa Ziehau 
720215516c77SSepherosa Ziehau 	if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) {
720315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n",
720415516c77SSepherosa Ziehau 		    pkt->cp_rxbuf_id);
720515516c77SSepherosa Ziehau 		return;
720615516c77SSepherosa Ziehau 	}
720715516c77SSepherosa Ziehau 
720815516c77SSepherosa Ziehau 	count = pkt->cp_rxbuf_cnt;
720915516c77SSepherosa Ziehau 	if (__predict_false(hlen <
721015516c77SSepherosa Ziehau 	    __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) {
721115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count);
721215516c77SSepherosa Ziehau 		return;
721315516c77SSepherosa Ziehau 	}
721415516c77SSepherosa Ziehau 
721515516c77SSepherosa Ziehau 	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
721615516c77SSepherosa Ziehau 	for (i = 0; i < count; ++i) {
721715516c77SSepherosa Ziehau 		int ofs, len;
721815516c77SSepherosa Ziehau 
721915516c77SSepherosa Ziehau 		ofs = pkt->cp_rxbuf[i].rb_ofs;
722015516c77SSepherosa Ziehau 		len = pkt->cp_rxbuf[i].rb_len;
722115516c77SSepherosa Ziehau 		if (__predict_false(ofs + len > HN_RXBUF_SIZE)) {
722215516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, "
722315516c77SSepherosa Ziehau 			    "ofs %d, len %d\n", i, ofs, len);
722415516c77SSepherosa Ziehau 			continue;
722515516c77SSepherosa Ziehau 		}
722615516c77SSepherosa Ziehau 		hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len);
722715516c77SSepherosa Ziehau 	}
722815516c77SSepherosa Ziehau 
722915516c77SSepherosa Ziehau 	/*
723015516c77SSepherosa Ziehau 	 * Ack the consumed RXBUF associated w/ this channel packet,
723115516c77SSepherosa Ziehau 	 * so that this RXBUF can be recycled by the hypervisor.
723215516c77SSepherosa Ziehau 	 */
723315516c77SSepherosa Ziehau 	hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid);
723415516c77SSepherosa Ziehau }
723515516c77SSepherosa Ziehau 
723615516c77SSepherosa Ziehau static void
723715516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
723815516c77SSepherosa Ziehau     uint64_t tid)
723915516c77SSepherosa Ziehau {
724015516c77SSepherosa Ziehau 	struct hn_nvs_rndis_ack ack;
724115516c77SSepherosa Ziehau 	int retries, error;
724215516c77SSepherosa Ziehau 
724315516c77SSepherosa Ziehau 	ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK;
724415516c77SSepherosa Ziehau 	ack.nvs_status = HN_NVS_STATUS_OK;
724515516c77SSepherosa Ziehau 
724615516c77SSepherosa Ziehau 	retries = 0;
724715516c77SSepherosa Ziehau again:
724815516c77SSepherosa Ziehau 	error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP,
724915516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid);
725015516c77SSepherosa Ziehau 	if (__predict_false(error == EAGAIN)) {
725115516c77SSepherosa Ziehau 		/*
725215516c77SSepherosa Ziehau 		 * NOTE:
725315516c77SSepherosa Ziehau 		 * This should _not_ happen in real world, since the
725415516c77SSepherosa Ziehau 		 * consumption of the TX bufring from the TX path is
725515516c77SSepherosa Ziehau 		 * controlled.
725615516c77SSepherosa Ziehau 		 */
725715516c77SSepherosa Ziehau 		if (rxr->hn_ack_failed == 0)
725815516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "RXBUF ack retry\n");
725915516c77SSepherosa Ziehau 		rxr->hn_ack_failed++;
726015516c77SSepherosa Ziehau 		retries++;
726115516c77SSepherosa Ziehau 		if (retries < 10) {
726215516c77SSepherosa Ziehau 			DELAY(100);
726315516c77SSepherosa Ziehau 			goto again;
726415516c77SSepherosa Ziehau 		}
726515516c77SSepherosa Ziehau 		/* RXBUF leaks! */
726615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "RXBUF ack failed\n");
726715516c77SSepherosa Ziehau 	}
726815516c77SSepherosa Ziehau }
726915516c77SSepherosa Ziehau 
727015516c77SSepherosa Ziehau static void
727115516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr)
727215516c77SSepherosa Ziehau {
727315516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr = xrxr;
727415516c77SSepherosa Ziehau 	struct hn_softc *sc = rxr->hn_ifp->if_softc;
727515516c77SSepherosa Ziehau 
727615516c77SSepherosa Ziehau 	for (;;) {
727715516c77SSepherosa Ziehau 		struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf;
727815516c77SSepherosa Ziehau 		int error, pktlen;
727915516c77SSepherosa Ziehau 
728015516c77SSepherosa Ziehau 		pktlen = rxr->hn_pktbuf_len;
728115516c77SSepherosa Ziehau 		error = vmbus_chan_recv_pkt(chan, pkt, &pktlen);
728215516c77SSepherosa Ziehau 		if (__predict_false(error == ENOBUFS)) {
728315516c77SSepherosa Ziehau 			void *nbuf;
728415516c77SSepherosa Ziehau 			int nlen;
728515516c77SSepherosa Ziehau 
728615516c77SSepherosa Ziehau 			/*
728715516c77SSepherosa Ziehau 			 * Expand channel packet buffer.
728815516c77SSepherosa Ziehau 			 *
728915516c77SSepherosa Ziehau 			 * XXX
729015516c77SSepherosa Ziehau 			 * Use M_WAITOK here, since allocation failure
729115516c77SSepherosa Ziehau 			 * is fatal.
729215516c77SSepherosa Ziehau 			 */
729315516c77SSepherosa Ziehau 			nlen = rxr->hn_pktbuf_len * 2;
729415516c77SSepherosa Ziehau 			while (nlen < pktlen)
729515516c77SSepherosa Ziehau 				nlen *= 2;
729615516c77SSepherosa Ziehau 			nbuf = malloc(nlen, M_DEVBUF, M_WAITOK);
729715516c77SSepherosa Ziehau 
729815516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n",
729915516c77SSepherosa Ziehau 			    rxr->hn_pktbuf_len, nlen);
730015516c77SSepherosa Ziehau 
730115516c77SSepherosa Ziehau 			free(rxr->hn_pktbuf, M_DEVBUF);
730215516c77SSepherosa Ziehau 			rxr->hn_pktbuf = nbuf;
730315516c77SSepherosa Ziehau 			rxr->hn_pktbuf_len = nlen;
730415516c77SSepherosa Ziehau 			/* Retry! */
730515516c77SSepherosa Ziehau 			continue;
730615516c77SSepherosa Ziehau 		} else if (__predict_false(error == EAGAIN)) {
730715516c77SSepherosa Ziehau 			/* No more channel packets; done! */
730815516c77SSepherosa Ziehau 			break;
730915516c77SSepherosa Ziehau 		}
731015516c77SSepherosa Ziehau 		KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error));
731115516c77SSepherosa Ziehau 
731215516c77SSepherosa Ziehau 		switch (pkt->cph_type) {
731315516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_COMP:
731415516c77SSepherosa Ziehau 			hn_nvs_handle_comp(sc, chan, pkt);
731515516c77SSepherosa Ziehau 			break;
731615516c77SSepherosa Ziehau 
731715516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_RXBUF:
731815516c77SSepherosa Ziehau 			hn_nvs_handle_rxbuf(rxr, chan, pkt);
731915516c77SSepherosa Ziehau 			break;
732015516c77SSepherosa Ziehau 
732115516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_INBAND:
732215516c77SSepherosa Ziehau 			hn_nvs_handle_notify(sc, pkt);
732315516c77SSepherosa Ziehau 			break;
732415516c77SSepherosa Ziehau 
732515516c77SSepherosa Ziehau 		default:
732615516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "unknown chan pkt %u\n",
732715516c77SSepherosa Ziehau 			    pkt->cph_type);
732815516c77SSepherosa Ziehau 			break;
732915516c77SSepherosa Ziehau 		}
733015516c77SSepherosa Ziehau 	}
733115516c77SSepherosa Ziehau 	hn_chan_rollup(rxr, rxr->hn_txr);
733215516c77SSepherosa Ziehau }
733315516c77SSepherosa Ziehau 
733415516c77SSepherosa Ziehau static void
7335499c3e17SSepherosa Ziehau hn_sysinit(void *arg __unused)
733615516c77SSepherosa Ziehau {
7337fdd0222aSSepherosa Ziehau 	int i;
7338fdd0222aSSepherosa Ziehau 
73399c6cae24SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
73409c6cae24SSepherosa Ziehau 	/*
73419c6cae24SSepherosa Ziehau 	 * Don't use ifnet.if_start if transparent VF mode is requested;
73429c6cae24SSepherosa Ziehau 	 * mainly due to the IFF_DRV_OACTIVE flag.
73439c6cae24SSepherosa Ziehau 	 */
73449c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && hn_use_if_start) {
73459c6cae24SSepherosa Ziehau 		hn_use_if_start = 0;
73469c6cae24SSepherosa Ziehau 		printf("hn: tranparent VF mode, if_transmit will be used, "
73479c6cae24SSepherosa Ziehau 		    "instead of if_start\n");
73489c6cae24SSepherosa Ziehau 	}
73499c6cae24SSepherosa Ziehau #endif
73509c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_attwait < HN_XPNT_VF_ATTWAIT_MIN) {
73519c6cae24SSepherosa Ziehau 		printf("hn: invalid transparent VF attach routing "
73529c6cae24SSepherosa Ziehau 		    "wait timeout %d, reset to %d\n",
73539c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_attwait, HN_XPNT_VF_ATTWAIT_MIN);
73549c6cae24SSepherosa Ziehau 		hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN;
73559c6cae24SSepherosa Ziehau 	}
73569c6cae24SSepherosa Ziehau 
7357fdd0222aSSepherosa Ziehau 	/*
7358499c3e17SSepherosa Ziehau 	 * Initialize VF map.
7359499c3e17SSepherosa Ziehau 	 */
7360499c3e17SSepherosa Ziehau 	rm_init_flags(&hn_vfmap_lock, "hn_vfmap", RM_SLEEPABLE);
7361499c3e17SSepherosa Ziehau 	hn_vfmap_size = HN_VFMAP_SIZE_DEF;
7362499c3e17SSepherosa Ziehau 	hn_vfmap = malloc(sizeof(struct ifnet *) * hn_vfmap_size, M_DEVBUF,
7363499c3e17SSepherosa Ziehau 	    M_WAITOK | M_ZERO);
7364499c3e17SSepherosa Ziehau 
7365499c3e17SSepherosa Ziehau 	/*
7366fdd0222aSSepherosa Ziehau 	 * Fix the # of TX taskqueues.
7367fdd0222aSSepherosa Ziehau 	 */
7368fdd0222aSSepherosa Ziehau 	if (hn_tx_taskq_cnt <= 0)
7369fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = 1;
7370fdd0222aSSepherosa Ziehau 	else if (hn_tx_taskq_cnt > mp_ncpus)
7371fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = mp_ncpus;
737215516c77SSepherosa Ziehau 
73730e11868dSSepherosa Ziehau 	/*
73740e11868dSSepherosa Ziehau 	 * Fix the TX taskqueue mode.
73750e11868dSSepherosa Ziehau 	 */
73760e11868dSSepherosa Ziehau 	switch (hn_tx_taskq_mode) {
73770e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_INDEP:
73780e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_GLOBAL:
73790e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_EVTTQ:
73800e11868dSSepherosa Ziehau 		break;
73810e11868dSSepherosa Ziehau 	default:
73820e11868dSSepherosa Ziehau 		hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
73830e11868dSSepherosa Ziehau 		break;
73840e11868dSSepherosa Ziehau 	}
73850e11868dSSepherosa Ziehau 
738615516c77SSepherosa Ziehau 	if (vm_guest != VM_GUEST_HV)
738715516c77SSepherosa Ziehau 		return;
738815516c77SSepherosa Ziehau 
73890e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode != HN_TX_TASKQ_M_GLOBAL)
739015516c77SSepherosa Ziehau 		return;
739115516c77SSepherosa Ziehau 
7392fdd0222aSSepherosa Ziehau 	hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
7393fdd0222aSSepherosa Ziehau 	    M_DEVBUF, M_WAITOK);
7394fdd0222aSSepherosa Ziehau 	for (i = 0; i < hn_tx_taskq_cnt; ++i) {
7395fdd0222aSSepherosa Ziehau 		hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK,
7396fdd0222aSSepherosa Ziehau 		    taskqueue_thread_enqueue, &hn_tx_taskque[i]);
7397fdd0222aSSepherosa Ziehau 		taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET,
7398fdd0222aSSepherosa Ziehau 		    "hn tx%d", i);
7399fdd0222aSSepherosa Ziehau 	}
740015516c77SSepherosa Ziehau }
7401499c3e17SSepherosa Ziehau SYSINIT(hn_sysinit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysinit, NULL);
740215516c77SSepherosa Ziehau 
740315516c77SSepherosa Ziehau static void
7404499c3e17SSepherosa Ziehau hn_sysuninit(void *arg __unused)
740515516c77SSepherosa Ziehau {
740615516c77SSepherosa Ziehau 
7407fdd0222aSSepherosa Ziehau 	if (hn_tx_taskque != NULL) {
7408fdd0222aSSepherosa Ziehau 		int i;
7409fdd0222aSSepherosa Ziehau 
7410fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
7411fdd0222aSSepherosa Ziehau 			taskqueue_free(hn_tx_taskque[i]);
7412fdd0222aSSepherosa Ziehau 		free(hn_tx_taskque, M_DEVBUF);
7413fdd0222aSSepherosa Ziehau 	}
7414499c3e17SSepherosa Ziehau 
7415499c3e17SSepherosa Ziehau 	if (hn_vfmap != NULL)
7416499c3e17SSepherosa Ziehau 		free(hn_vfmap, M_DEVBUF);
7417499c3e17SSepherosa Ziehau 	rm_destroy(&hn_vfmap_lock);
741815516c77SSepherosa Ziehau }
7419499c3e17SSepherosa Ziehau SYSUNINIT(hn_sysuninit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysuninit, NULL);
7420