xref: /freebsd/sys/dev/hyperv/netvsc/if_hn.c (revision a491581f3f8df07cdff0236bd556895205929af4)
115516c77SSepherosa Ziehau /*-
215516c77SSepherosa Ziehau  * Copyright (c) 2010-2012 Citrix Inc.
393b4e111SSepherosa Ziehau  * Copyright (c) 2009-2012,2016-2017 Microsoft Corp.
415516c77SSepherosa Ziehau  * Copyright (c) 2012 NetApp Inc.
515516c77SSepherosa Ziehau  * All rights reserved.
615516c77SSepherosa Ziehau  *
715516c77SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
815516c77SSepherosa Ziehau  * modification, are permitted provided that the following conditions
915516c77SSepherosa Ziehau  * are met:
1015516c77SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
1115516c77SSepherosa Ziehau  *    notice unmodified, this list of conditions, and the following
1215516c77SSepherosa Ziehau  *    disclaimer.
1315516c77SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
1415516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
1515516c77SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
1615516c77SSepherosa Ziehau  *
1715516c77SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1815516c77SSepherosa Ziehau  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1915516c77SSepherosa Ziehau  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2015516c77SSepherosa Ziehau  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2115516c77SSepherosa Ziehau  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2215516c77SSepherosa Ziehau  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2315516c77SSepherosa Ziehau  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2415516c77SSepherosa Ziehau  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2515516c77SSepherosa Ziehau  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2615516c77SSepherosa Ziehau  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2715516c77SSepherosa Ziehau  */
2815516c77SSepherosa Ziehau 
2915516c77SSepherosa Ziehau /*-
3015516c77SSepherosa Ziehau  * Copyright (c) 2004-2006 Kip Macy
3115516c77SSepherosa Ziehau  * All rights reserved.
3215516c77SSepherosa Ziehau  *
3315516c77SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
3415516c77SSepherosa Ziehau  * modification, are permitted provided that the following conditions
3515516c77SSepherosa Ziehau  * are met:
3615516c77SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
3715516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer.
3815516c77SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
3915516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
4015516c77SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
4115516c77SSepherosa Ziehau  *
4215516c77SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
4315516c77SSepherosa Ziehau  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4415516c77SSepherosa Ziehau  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4515516c77SSepherosa Ziehau  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4615516c77SSepherosa Ziehau  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4715516c77SSepherosa Ziehau  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4815516c77SSepherosa Ziehau  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4915516c77SSepherosa Ziehau  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5015516c77SSepherosa Ziehau  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5115516c77SSepherosa Ziehau  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5215516c77SSepherosa Ziehau  * SUCH DAMAGE.
5315516c77SSepherosa Ziehau  */
5415516c77SSepherosa Ziehau 
5515516c77SSepherosa Ziehau #include <sys/cdefs.h>
5615516c77SSepherosa Ziehau __FBSDID("$FreeBSD$");
5715516c77SSepherosa Ziehau 
5834d68912SSepherosa Ziehau #include "opt_hn.h"
5915516c77SSepherosa Ziehau #include "opt_inet6.h"
6015516c77SSepherosa Ziehau #include "opt_inet.h"
6134d68912SSepherosa Ziehau #include "opt_rss.h"
6215516c77SSepherosa Ziehau 
6315516c77SSepherosa Ziehau #include <sys/param.h>
6435203574SSepherosa Ziehau #include <sys/systm.h>
6515516c77SSepherosa Ziehau #include <sys/bus.h>
662be266caSSepherosa Ziehau #include <sys/counter.h>
6715516c77SSepherosa Ziehau #include <sys/kernel.h>
6815516c77SSepherosa Ziehau #include <sys/limits.h>
6915516c77SSepherosa Ziehau #include <sys/malloc.h>
7015516c77SSepherosa Ziehau #include <sys/mbuf.h>
7115516c77SSepherosa Ziehau #include <sys/module.h>
7215516c77SSepherosa Ziehau #include <sys/queue.h>
7315516c77SSepherosa Ziehau #include <sys/lock.h>
74b3460f44SWei Hu #include <sys/proc.h>
75499c3e17SSepherosa Ziehau #include <sys/rmlock.h>
76499c3e17SSepherosa Ziehau #include <sys/sbuf.h>
77b3460f44SWei Hu #include <sys/sched.h>
7815516c77SSepherosa Ziehau #include <sys/smp.h>
7915516c77SSepherosa Ziehau #include <sys/socket.h>
8015516c77SSepherosa Ziehau #include <sys/sockio.h>
8115516c77SSepherosa Ziehau #include <sys/sx.h>
8215516c77SSepherosa Ziehau #include <sys/sysctl.h>
8315516c77SSepherosa Ziehau #include <sys/taskqueue.h>
8415516c77SSepherosa Ziehau #include <sys/buf_ring.h>
855bdfd3fdSDexuan Cui #include <sys/eventhandler.h>
8615516c77SSepherosa Ziehau 
8715516c77SSepherosa Ziehau #include <machine/atomic.h>
8815516c77SSepherosa Ziehau #include <machine/in_cksum.h>
8915516c77SSepherosa Ziehau 
9015516c77SSepherosa Ziehau #include <net/bpf.h>
9115516c77SSepherosa Ziehau #include <net/ethernet.h>
9215516c77SSepherosa Ziehau #include <net/if.h>
935bdfd3fdSDexuan Cui #include <net/if_dl.h>
9415516c77SSepherosa Ziehau #include <net/if_media.h>
9515516c77SSepherosa Ziehau #include <net/if_types.h>
9615516c77SSepherosa Ziehau #include <net/if_var.h>
9715516c77SSepherosa Ziehau #include <net/rndis.h>
9834d68912SSepherosa Ziehau #ifdef RSS
9934d68912SSepherosa Ziehau #include <net/rss_config.h>
10034d68912SSepherosa Ziehau #endif
10115516c77SSepherosa Ziehau 
10215516c77SSepherosa Ziehau #include <netinet/in_systm.h>
10315516c77SSepherosa Ziehau #include <netinet/in.h>
10415516c77SSepherosa Ziehau #include <netinet/ip.h>
10515516c77SSepherosa Ziehau #include <netinet/ip6.h>
10615516c77SSepherosa Ziehau #include <netinet/tcp.h>
10715516c77SSepherosa Ziehau #include <netinet/tcp_lro.h>
10815516c77SSepherosa Ziehau #include <netinet/udp.h>
10915516c77SSepherosa Ziehau 
11015516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h>
11115516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv_busdma.h>
11215516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus.h>
11315516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus_xact.h>
11415516c77SSepherosa Ziehau 
11515516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/ndis.h>
11615516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnreg.h>
11715516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnvar.h>
11815516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_nvs.h>
11915516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_rndis.h>
12015516c77SSepherosa Ziehau 
12115516c77SSepherosa Ziehau #include "vmbus_if.h"
12215516c77SSepherosa Ziehau 
12323bf9e15SSepherosa Ziehau #define HN_IFSTART_SUPPORT
12423bf9e15SSepherosa Ziehau 
12515516c77SSepherosa Ziehau #define HN_RING_CNT_DEF_MAX		8
12615516c77SSepherosa Ziehau 
127499c3e17SSepherosa Ziehau #define HN_VFMAP_SIZE_DEF		8
128499c3e17SSepherosa Ziehau 
1299c6cae24SSepherosa Ziehau #define HN_XPNT_VF_ATTWAIT_MIN		2	/* seconds */
1309c6cae24SSepherosa Ziehau 
13115516c77SSepherosa Ziehau /* YYY should get it from the underlying channel */
13215516c77SSepherosa Ziehau #define HN_TX_DESC_CNT			512
13315516c77SSepherosa Ziehau 
13415516c77SSepherosa Ziehau #define HN_RNDIS_PKT_LEN					\
13515516c77SSepherosa Ziehau 	(sizeof(struct rndis_packet_msg) +			\
13615516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) +	\
13715516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) +		\
13815516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) +		\
13915516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_TXCSUM_INFO_SIZE))
14015516c77SSepherosa Ziehau #define HN_RNDIS_PKT_BOUNDARY		PAGE_SIZE
14115516c77SSepherosa Ziehau #define HN_RNDIS_PKT_ALIGN		CACHE_LINE_SIZE
14215516c77SSepherosa Ziehau 
14315516c77SSepherosa Ziehau #define HN_TX_DATA_BOUNDARY		PAGE_SIZE
14415516c77SSepherosa Ziehau #define HN_TX_DATA_MAXSIZE		IP_MAXPACKET
14515516c77SSepherosa Ziehau #define HN_TX_DATA_SEGSIZE		PAGE_SIZE
14615516c77SSepherosa Ziehau /* -1 for RNDIS packet message */
14715516c77SSepherosa Ziehau #define HN_TX_DATA_SEGCNT_MAX		(HN_GPACNT_MAX - 1)
14815516c77SSepherosa Ziehau 
14915516c77SSepherosa Ziehau #define HN_DIRECT_TX_SIZE_DEF		128
15015516c77SSepherosa Ziehau 
15115516c77SSepherosa Ziehau #define HN_EARLY_TXEOF_THRESH		8
15215516c77SSepherosa Ziehau 
15315516c77SSepherosa Ziehau #define HN_PKTBUF_LEN_DEF		(16 * 1024)
15415516c77SSepherosa Ziehau 
15515516c77SSepherosa Ziehau #define HN_LROENT_CNT_DEF		128
15615516c77SSepherosa Ziehau 
15715516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MULTIRX_DEF	(12 * ETHERMTU)
15815516c77SSepherosa Ziehau #define HN_LRO_LENLIM_DEF		(25 * ETHERMTU)
15915516c77SSepherosa Ziehau /* YYY 2*MTU is a bit rough, but should be good enough. */
16015516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MIN(ifp)		(2 * (ifp)->if_mtu)
16115516c77SSepherosa Ziehau 
16215516c77SSepherosa Ziehau #define HN_LRO_ACKCNT_DEF		1
16315516c77SSepherosa Ziehau 
16415516c77SSepherosa Ziehau #define HN_LOCK_INIT(sc)		\
16515516c77SSepherosa Ziehau 	sx_init(&(sc)->hn_lock, device_get_nameunit((sc)->hn_dev))
16615516c77SSepherosa Ziehau #define HN_LOCK_DESTROY(sc)		sx_destroy(&(sc)->hn_lock)
16715516c77SSepherosa Ziehau #define HN_LOCK_ASSERT(sc)		sx_assert(&(sc)->hn_lock, SA_XLOCKED)
168fdc4f478SSepherosa Ziehau #define HN_LOCK(sc)					\
169fdc4f478SSepherosa Ziehau do {							\
170b3460f44SWei Hu 	while (sx_try_xlock(&(sc)->hn_lock) == 0) {	\
171b3460f44SWei Hu 		/* Relinquish cpu to avoid deadlock */	\
172b3460f44SWei Hu 		sched_relinquish(curthread);		\
173fdc4f478SSepherosa Ziehau 		DELAY(1000);				\
174b3460f44SWei Hu 	}						\
175fdc4f478SSepherosa Ziehau } while (0)
17615516c77SSepherosa Ziehau #define HN_UNLOCK(sc)			sx_xunlock(&(sc)->hn_lock)
17715516c77SSepherosa Ziehau 
17815516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK			(CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP)
17915516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK		(CSUM_IP6_TCP | CSUM_IP6_UDP)
18015516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc)		\
18115516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK)
18215516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc)	\
18315516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK)
18415516c77SSepherosa Ziehau 
185dc13fee6SSepherosa Ziehau #define HN_PKTSIZE_MIN(align)		\
186dc13fee6SSepherosa Ziehau 	roundup2(ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN + \
187dc13fee6SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN, (align))
188dc13fee6SSepherosa Ziehau #define HN_PKTSIZE(m, align)		\
189dc13fee6SSepherosa Ziehau 	roundup2((m)->m_pkthdr.len + HN_RNDIS_PKT_LEN, (align))
190dc13fee6SSepherosa Ziehau 
19134d68912SSepherosa Ziehau #ifdef RSS
19234d68912SSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx)	rss_getcpu((idx) % rss_getnumbuckets())
19334d68912SSepherosa Ziehau #else
1940e11868dSSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx)	(((sc)->hn_cpu + (idx)) % mp_ncpus)
19534d68912SSepherosa Ziehau #endif
1960e11868dSSepherosa Ziehau 
19715516c77SSepherosa Ziehau struct hn_txdesc {
19815516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
19915516c77SSepherosa Ziehau 	SLIST_ENTRY(hn_txdesc)		link;
20015516c77SSepherosa Ziehau #endif
201dc13fee6SSepherosa Ziehau 	STAILQ_ENTRY(hn_txdesc)		agg_link;
202dc13fee6SSepherosa Ziehau 
203dc13fee6SSepherosa Ziehau 	/* Aggregated txdescs, in sending order. */
204dc13fee6SSepherosa Ziehau 	STAILQ_HEAD(, hn_txdesc)	agg_list;
205dc13fee6SSepherosa Ziehau 
206dc13fee6SSepherosa Ziehau 	/* The oldest packet, if transmission aggregation happens. */
20715516c77SSepherosa Ziehau 	struct mbuf			*m;
20815516c77SSepherosa Ziehau 	struct hn_tx_ring		*txr;
20915516c77SSepherosa Ziehau 	int				refs;
21015516c77SSepherosa Ziehau 	uint32_t			flags;	/* HN_TXD_FLAG_ */
21115516c77SSepherosa Ziehau 	struct hn_nvs_sendctx		send_ctx;
21215516c77SSepherosa Ziehau 	uint32_t			chim_index;
21315516c77SSepherosa Ziehau 	int				chim_size;
21415516c77SSepherosa Ziehau 
21515516c77SSepherosa Ziehau 	bus_dmamap_t			data_dmap;
21615516c77SSepherosa Ziehau 
21715516c77SSepherosa Ziehau 	bus_addr_t			rndis_pkt_paddr;
21815516c77SSepherosa Ziehau 	struct rndis_packet_msg		*rndis_pkt;
21915516c77SSepherosa Ziehau 	bus_dmamap_t			rndis_pkt_dmap;
22015516c77SSepherosa Ziehau };
22115516c77SSepherosa Ziehau 
22215516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST		0x0001
22315516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP		0x0002
224dc13fee6SSepherosa Ziehau #define HN_TXD_FLAG_ONAGG		0x0004
22515516c77SSepherosa Ziehau 
226*a491581fSWei Hu #define	HN_NDIS_PKTINFO_SUBALLOC	0x01
227*a491581fSWei Hu #define	HN_NDIS_PKTINFO_1ST_FRAG	0x02
228*a491581fSWei Hu #define	HN_NDIS_PKTINFO_LAST_FRAG	0x04
229*a491581fSWei Hu 
230*a491581fSWei Hu struct packet_info_id {
231*a491581fSWei Hu 	uint8_t				ver;
232*a491581fSWei Hu 	uint8_t				flag;
233*a491581fSWei Hu 	uint16_t			pkt_id;
234*a491581fSWei Hu };
235*a491581fSWei Hu 
236*a491581fSWei Hu #define NDIS_PKTINFOID_SZ		sizeof(struct packet_info_id)
237*a491581fSWei Hu 
238*a491581fSWei Hu 
23915516c77SSepherosa Ziehau struct hn_rxinfo {
240*a491581fSWei Hu 	const uint32_t			*vlan_info;
241*a491581fSWei Hu 	const uint32_t			*csum_info;
242*a491581fSWei Hu 	const uint32_t			*hash_info;
243*a491581fSWei Hu 	const uint32_t			*hash_value;
244*a491581fSWei Hu 	const struct packet_info_id	*pktinfo_id;
24515516c77SSepherosa Ziehau };
24615516c77SSepherosa Ziehau 
247962f0357SSepherosa Ziehau struct hn_rxvf_setarg {
2485bdfd3fdSDexuan Cui 	struct hn_rx_ring	*rxr;
249962f0357SSepherosa Ziehau 	struct ifnet		*vf_ifp;
2505bdfd3fdSDexuan Cui };
2515bdfd3fdSDexuan Cui 
25215516c77SSepherosa Ziehau #define HN_RXINFO_VLAN			0x0001
25315516c77SSepherosa Ziehau #define HN_RXINFO_CSUM			0x0002
25415516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF		0x0004
25515516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL		0x0008
256*a491581fSWei Hu #define HN_RXINFO_PKTINFO_ID		0x0010
25715516c77SSepherosa Ziehau #define HN_RXINFO_ALL			\
25815516c77SSepherosa Ziehau 	(HN_RXINFO_VLAN |		\
25915516c77SSepherosa Ziehau 	 HN_RXINFO_CSUM |		\
26015516c77SSepherosa Ziehau 	 HN_RXINFO_HASHINF |		\
261*a491581fSWei Hu 	 HN_RXINFO_HASHVAL |		\
262*a491581fSWei Hu 	 HN_RXINFO_PKTINFO_ID)
26315516c77SSepherosa Ziehau 
26415516c77SSepherosa Ziehau static int			hn_probe(device_t);
26515516c77SSepherosa Ziehau static int			hn_attach(device_t);
26615516c77SSepherosa Ziehau static int			hn_detach(device_t);
26715516c77SSepherosa Ziehau static int			hn_shutdown(device_t);
26815516c77SSepherosa Ziehau static void			hn_chan_callback(struct vmbus_channel *,
26915516c77SSepherosa Ziehau 				    void *);
27015516c77SSepherosa Ziehau 
27115516c77SSepherosa Ziehau static void			hn_init(void *);
27215516c77SSepherosa Ziehau static int			hn_ioctl(struct ifnet *, u_long, caddr_t);
27323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
27415516c77SSepherosa Ziehau static void			hn_start(struct ifnet *);
27523bf9e15SSepherosa Ziehau #endif
27615516c77SSepherosa Ziehau static int			hn_transmit(struct ifnet *, struct mbuf *);
27715516c77SSepherosa Ziehau static void			hn_xmit_qflush(struct ifnet *);
27815516c77SSepherosa Ziehau static int			hn_ifmedia_upd(struct ifnet *);
27915516c77SSepherosa Ziehau static void			hn_ifmedia_sts(struct ifnet *,
28015516c77SSepherosa Ziehau 				    struct ifmediareq *);
28115516c77SSepherosa Ziehau 
282499c3e17SSepherosa Ziehau static void			hn_ifnet_event(void *, struct ifnet *, int);
283499c3e17SSepherosa Ziehau static void			hn_ifaddr_event(void *, struct ifnet *);
284499c3e17SSepherosa Ziehau static void			hn_ifnet_attevent(void *, struct ifnet *);
285499c3e17SSepherosa Ziehau static void			hn_ifnet_detevent(void *, struct ifnet *);
2869c6cae24SSepherosa Ziehau static void			hn_ifnet_lnkevent(void *, struct ifnet *, int);
287499c3e17SSepherosa Ziehau 
288962f0357SSepherosa Ziehau static bool			hn_ismyvf(const struct hn_softc *,
289962f0357SSepherosa Ziehau 				    const struct ifnet *);
290962f0357SSepherosa Ziehau static void			hn_rxvf_change(struct hn_softc *,
291962f0357SSepherosa Ziehau 				    struct ifnet *, bool);
292962f0357SSepherosa Ziehau static void			hn_rxvf_set(struct hn_softc *, struct ifnet *);
293962f0357SSepherosa Ziehau static void			hn_rxvf_set_task(void *, int);
2949c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_input(struct ifnet *, struct mbuf *);
2959c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_iocsetflags(struct hn_softc *);
2969c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_iocsetcaps(struct hn_softc *,
2979c6cae24SSepherosa Ziehau 				    struct ifreq *);
2989c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_saveifflags(struct hn_softc *);
2999c6cae24SSepherosa Ziehau static bool			hn_xpnt_vf_isready(struct hn_softc *);
3009c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_setready(struct hn_softc *);
3019c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_init_taskfunc(void *, int);
3029c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_init(struct hn_softc *);
303a97fff19SSepherosa Ziehau static void			hn_xpnt_vf_setenable(struct hn_softc *);
304a97fff19SSepherosa Ziehau static void			hn_xpnt_vf_setdisable(struct hn_softc *, bool);
305642ec226SSepherosa Ziehau static void			hn_vf_rss_fixup(struct hn_softc *, bool);
306642ec226SSepherosa Ziehau static void			hn_vf_rss_restore(struct hn_softc *);
307962f0357SSepherosa Ziehau 
30815516c77SSepherosa Ziehau static int			hn_rndis_rxinfo(const void *, int,
30915516c77SSepherosa Ziehau 				    struct hn_rxinfo *);
31015516c77SSepherosa Ziehau static void			hn_rndis_rx_data(struct hn_rx_ring *,
31115516c77SSepherosa Ziehau 				    const void *, int);
31215516c77SSepherosa Ziehau static void			hn_rndis_rx_status(struct hn_softc *,
31315516c77SSepherosa Ziehau 				    const void *, int);
314b3b75d9cSSepherosa Ziehau static void			hn_rndis_init_fixat(struct hn_softc *, int);
31515516c77SSepherosa Ziehau 
31615516c77SSepherosa Ziehau static void			hn_nvs_handle_notify(struct hn_softc *,
31715516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
31815516c77SSepherosa Ziehau static void			hn_nvs_handle_comp(struct hn_softc *,
31915516c77SSepherosa Ziehau 				    struct vmbus_channel *,
32015516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
32115516c77SSepherosa Ziehau static void			hn_nvs_handle_rxbuf(struct hn_rx_ring *,
32215516c77SSepherosa Ziehau 				    struct vmbus_channel *,
32315516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
32415516c77SSepherosa Ziehau static void			hn_nvs_ack_rxbuf(struct hn_rx_ring *,
32515516c77SSepherosa Ziehau 				    struct vmbus_channel *, uint64_t);
32615516c77SSepherosa Ziehau 
32715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
32815516c77SSepherosa Ziehau static int			hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS);
32915516c77SSepherosa Ziehau static int			hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS);
33015516c77SSepherosa Ziehau #endif
33115516c77SSepherosa Ziehau static int			hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS);
33215516c77SSepherosa Ziehau static int			hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS);
33315516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
33415516c77SSepherosa Ziehau static int			hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS);
33515516c77SSepherosa Ziehau #else
33615516c77SSepherosa Ziehau static int			hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS);
33715516c77SSepherosa Ziehau #endif
33815516c77SSepherosa Ziehau static int			hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
33915516c77SSepherosa Ziehau static int			hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
34015516c77SSepherosa Ziehau static int			hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS);
34115516c77SSepherosa Ziehau static int			hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS);
34215516c77SSepherosa Ziehau static int			hn_caps_sysctl(SYSCTL_HANDLER_ARGS);
34315516c77SSepherosa Ziehau static int			hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS);
34415516c77SSepherosa Ziehau static int			hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS);
34534d68912SSepherosa Ziehau #ifndef RSS
34615516c77SSepherosa Ziehau static int			hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS);
34715516c77SSepherosa Ziehau static int			hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS);
34834d68912SSepherosa Ziehau #endif
34915516c77SSepherosa Ziehau static int			hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS);
350642ec226SSepherosa Ziehau static int			hn_rss_hcap_sysctl(SYSCTL_HANDLER_ARGS);
351642ec226SSepherosa Ziehau static int			hn_rss_mbuf_sysctl(SYSCTL_HANDLER_ARGS);
352dc13fee6SSepherosa Ziehau static int			hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS);
353dc13fee6SSepherosa Ziehau static int			hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS);
354dc13fee6SSepherosa Ziehau static int			hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS);
355dc13fee6SSepherosa Ziehau static int			hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS);
3566c1204dfSSepherosa Ziehau static int			hn_polling_sysctl(SYSCTL_HANDLER_ARGS);
35740d60d6eSDexuan Cui static int			hn_vf_sysctl(SYSCTL_HANDLER_ARGS);
358499c3e17SSepherosa Ziehau static int			hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS);
359499c3e17SSepherosa Ziehau static int			hn_vflist_sysctl(SYSCTL_HANDLER_ARGS);
360499c3e17SSepherosa Ziehau static int			hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS);
3619c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS);
3629c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS);
36315516c77SSepherosa Ziehau 
3645bdfd3fdSDexuan Cui static void			hn_stop(struct hn_softc *, bool);
36515516c77SSepherosa Ziehau static void			hn_init_locked(struct hn_softc *);
36615516c77SSepherosa Ziehau static int			hn_chan_attach(struct hn_softc *,
36715516c77SSepherosa Ziehau 				    struct vmbus_channel *);
36815516c77SSepherosa Ziehau static void			hn_chan_detach(struct hn_softc *,
36915516c77SSepherosa Ziehau 				    struct vmbus_channel *);
37015516c77SSepherosa Ziehau static int			hn_attach_subchans(struct hn_softc *);
37115516c77SSepherosa Ziehau static void			hn_detach_allchans(struct hn_softc *);
37215516c77SSepherosa Ziehau static void			hn_chan_rollup(struct hn_rx_ring *,
37315516c77SSepherosa Ziehau 				    struct hn_tx_ring *);
37415516c77SSepherosa Ziehau static void			hn_set_ring_inuse(struct hn_softc *, int);
37515516c77SSepherosa Ziehau static int			hn_synth_attach(struct hn_softc *, int);
37615516c77SSepherosa Ziehau static void			hn_synth_detach(struct hn_softc *);
37715516c77SSepherosa Ziehau static int			hn_synth_alloc_subchans(struct hn_softc *,
37815516c77SSepherosa Ziehau 				    int *);
3792494d735SSepherosa Ziehau static bool			hn_synth_attachable(const struct hn_softc *);
38015516c77SSepherosa Ziehau static void			hn_suspend(struct hn_softc *);
38115516c77SSepherosa Ziehau static void			hn_suspend_data(struct hn_softc *);
38215516c77SSepherosa Ziehau static void			hn_suspend_mgmt(struct hn_softc *);
38315516c77SSepherosa Ziehau static void			hn_resume(struct hn_softc *);
38415516c77SSepherosa Ziehau static void			hn_resume_data(struct hn_softc *);
38515516c77SSepherosa Ziehau static void			hn_resume_mgmt(struct hn_softc *);
38615516c77SSepherosa Ziehau static void			hn_suspend_mgmt_taskfunc(void *, int);
38725641fc7SSepherosa Ziehau static void			hn_chan_drain(struct hn_softc *,
38825641fc7SSepherosa Ziehau 				    struct vmbus_channel *);
389b3b75d9cSSepherosa Ziehau static void			hn_disable_rx(struct hn_softc *);
390b3b75d9cSSepherosa Ziehau static void			hn_drain_rxtx(struct hn_softc *, int);
3916c1204dfSSepherosa Ziehau static void			hn_polling(struct hn_softc *, u_int);
3926c1204dfSSepherosa Ziehau static void			hn_chan_polling(struct vmbus_channel *, u_int);
3939c6cae24SSepherosa Ziehau static void			hn_mtu_change_fixup(struct hn_softc *);
39415516c77SSepherosa Ziehau 
39515516c77SSepherosa Ziehau static void			hn_update_link_status(struct hn_softc *);
39615516c77SSepherosa Ziehau static void			hn_change_network(struct hn_softc *);
39715516c77SSepherosa Ziehau static void			hn_link_taskfunc(void *, int);
39815516c77SSepherosa Ziehau static void			hn_netchg_init_taskfunc(void *, int);
39915516c77SSepherosa Ziehau static void			hn_netchg_status_taskfunc(void *, int);
40015516c77SSepherosa Ziehau static void			hn_link_status(struct hn_softc *);
40115516c77SSepherosa Ziehau 
40215516c77SSepherosa Ziehau static int			hn_create_rx_data(struct hn_softc *, int);
40315516c77SSepherosa Ziehau static void			hn_destroy_rx_data(struct hn_softc *);
40415516c77SSepherosa Ziehau static int			hn_check_iplen(const struct mbuf *, int);
405db76829bSSepherosa Ziehau static void			hn_rxpkt_proto(const struct mbuf *, int *, int *);
406f1b0a43fSSepherosa Ziehau static int			hn_set_rxfilter(struct hn_softc *, uint32_t);
407c08f7b2cSSepherosa Ziehau static int			hn_rxfilter_config(struct hn_softc *);
40815516c77SSepherosa Ziehau static int			hn_rss_reconfig(struct hn_softc *);
409afd4971bSSepherosa Ziehau static void			hn_rss_ind_fixup(struct hn_softc *);
410642ec226SSepherosa Ziehau static void			hn_rss_mbuf_hash(struct hn_softc *, uint32_t);
411*a491581fSWei Hu static int			hn_rxpkt(struct hn_rx_ring *);
412642ec226SSepherosa Ziehau static uint32_t			hn_rss_type_fromndis(uint32_t);
413642ec226SSepherosa Ziehau static uint32_t			hn_rss_type_tondis(uint32_t);
41415516c77SSepherosa Ziehau 
41515516c77SSepherosa Ziehau static int			hn_tx_ring_create(struct hn_softc *, int);
41615516c77SSepherosa Ziehau static void			hn_tx_ring_destroy(struct hn_tx_ring *);
41715516c77SSepherosa Ziehau static int			hn_create_tx_data(struct hn_softc *, int);
41815516c77SSepherosa Ziehau static void			hn_fixup_tx_data(struct hn_softc *);
419db76829bSSepherosa Ziehau static void			hn_fixup_rx_data(struct hn_softc *);
42015516c77SSepherosa Ziehau static void			hn_destroy_tx_data(struct hn_softc *);
42115516c77SSepherosa Ziehau static void			hn_txdesc_dmamap_destroy(struct hn_txdesc *);
42225641fc7SSepherosa Ziehau static void			hn_txdesc_gc(struct hn_tx_ring *,
42325641fc7SSepherosa Ziehau 				    struct hn_txdesc *);
424dc13fee6SSepherosa Ziehau static int			hn_encap(struct ifnet *, struct hn_tx_ring *,
42515516c77SSepherosa Ziehau 				    struct hn_txdesc *, struct mbuf **);
42615516c77SSepherosa Ziehau static int			hn_txpkt(struct ifnet *, struct hn_tx_ring *,
42715516c77SSepherosa Ziehau 				    struct hn_txdesc *);
42815516c77SSepherosa Ziehau static void			hn_set_chim_size(struct hn_softc *, int);
42915516c77SSepherosa Ziehau static void			hn_set_tso_maxsize(struct hn_softc *, int, int);
43015516c77SSepherosa Ziehau static bool			hn_tx_ring_pending(struct hn_tx_ring *);
43115516c77SSepherosa Ziehau static void			hn_tx_ring_qflush(struct hn_tx_ring *);
43215516c77SSepherosa Ziehau static void			hn_resume_tx(struct hn_softc *, int);
433dc13fee6SSepherosa Ziehau static void			hn_set_txagg(struct hn_softc *);
434dc13fee6SSepherosa Ziehau static void			*hn_try_txagg(struct ifnet *,
435dc13fee6SSepherosa Ziehau 				    struct hn_tx_ring *, struct hn_txdesc *,
436dc13fee6SSepherosa Ziehau 				    int);
43715516c77SSepherosa Ziehau static int			hn_get_txswq_depth(const struct hn_tx_ring *);
43815516c77SSepherosa Ziehau static void			hn_txpkt_done(struct hn_nvs_sendctx *,
43915516c77SSepherosa Ziehau 				    struct hn_softc *, struct vmbus_channel *,
44015516c77SSepherosa Ziehau 				    const void *, int);
44115516c77SSepherosa Ziehau static int			hn_txpkt_sglist(struct hn_tx_ring *,
44215516c77SSepherosa Ziehau 				    struct hn_txdesc *);
44315516c77SSepherosa Ziehau static int			hn_txpkt_chim(struct hn_tx_ring *,
44415516c77SSepherosa Ziehau 				    struct hn_txdesc *);
44515516c77SSepherosa Ziehau static int			hn_xmit(struct hn_tx_ring *, int);
44615516c77SSepherosa Ziehau static void			hn_xmit_taskfunc(void *, int);
44715516c77SSepherosa Ziehau static void			hn_xmit_txeof(struct hn_tx_ring *);
44815516c77SSepherosa Ziehau static void			hn_xmit_txeof_taskfunc(void *, int);
44923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
45015516c77SSepherosa Ziehau static int			hn_start_locked(struct hn_tx_ring *, int);
45115516c77SSepherosa Ziehau static void			hn_start_taskfunc(void *, int);
45215516c77SSepherosa Ziehau static void			hn_start_txeof(struct hn_tx_ring *);
45315516c77SSepherosa Ziehau static void			hn_start_txeof_taskfunc(void *, int);
45423bf9e15SSepherosa Ziehau #endif
45515516c77SSepherosa Ziehau 
45615516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
45715516c77SSepherosa Ziehau     "Hyper-V network interface");
45815516c77SSepherosa Ziehau 
45915516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */
46015516c77SSepherosa Ziehau static int			hn_trust_hosttcp = 1;
46115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN,
46215516c77SSepherosa Ziehau     &hn_trust_hosttcp, 0,
46315516c77SSepherosa Ziehau     "Trust tcp segement verification on host side, "
46415516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
46515516c77SSepherosa Ziehau 
46615516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */
46715516c77SSepherosa Ziehau static int			hn_trust_hostudp = 1;
46815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN,
46915516c77SSepherosa Ziehau     &hn_trust_hostudp, 0,
47015516c77SSepherosa Ziehau     "Trust udp datagram verification on host side, "
47115516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
47215516c77SSepherosa Ziehau 
47315516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */
47415516c77SSepherosa Ziehau static int			hn_trust_hostip = 1;
47515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN,
47615516c77SSepherosa Ziehau     &hn_trust_hostip, 0,
47715516c77SSepherosa Ziehau     "Trust ip packet verification on host side, "
47815516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
47915516c77SSepherosa Ziehau 
4802be266caSSepherosa Ziehau /*
4812be266caSSepherosa Ziehau  * Offload UDP/IPv4 checksum.
4822be266caSSepherosa Ziehau  */
4832be266caSSepherosa Ziehau static int			hn_enable_udp4cs = 1;
4842be266caSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, enable_udp4cs, CTLFLAG_RDTUN,
4852be266caSSepherosa Ziehau     &hn_enable_udp4cs, 0, "Offload UDP/IPv4 checksum");
4862be266caSSepherosa Ziehau 
4872be266caSSepherosa Ziehau /*
4882be266caSSepherosa Ziehau  * Offload UDP/IPv6 checksum.
4892be266caSSepherosa Ziehau  */
4902be266caSSepherosa Ziehau static int			hn_enable_udp6cs = 1;
4912be266caSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, enable_udp6cs, CTLFLAG_RDTUN,
4922be266caSSepherosa Ziehau     &hn_enable_udp6cs, 0, "Offload UDP/IPv6 checksum");
4932be266caSSepherosa Ziehau 
4942be266caSSepherosa Ziehau /* Stats. */
4952be266caSSepherosa Ziehau static counter_u64_t		hn_udpcs_fixup;
4962be266caSSepherosa Ziehau SYSCTL_COUNTER_U64(_hw_hn, OID_AUTO, udpcs_fixup, CTLFLAG_RW,
4972be266caSSepherosa Ziehau     &hn_udpcs_fixup, "# of UDP checksum fixup");
4982be266caSSepherosa Ziehau 
4992be266caSSepherosa Ziehau /*
5002be266caSSepherosa Ziehau  * See hn_set_hlen().
5012be266caSSepherosa Ziehau  *
5022be266caSSepherosa Ziehau  * This value is for Azure.  For Hyper-V, set this above
5032be266caSSepherosa Ziehau  * 65536 to disable UDP datagram checksum fixup.
5042be266caSSepherosa Ziehau  */
5052be266caSSepherosa Ziehau static int			hn_udpcs_fixup_mtu = 1420;
5062be266caSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, udpcs_fixup_mtu, CTLFLAG_RWTUN,
5072be266caSSepherosa Ziehau     &hn_udpcs_fixup_mtu, 0, "UDP checksum fixup MTU threshold");
5082be266caSSepherosa Ziehau 
50915516c77SSepherosa Ziehau /* Limit TSO burst size */
51015516c77SSepherosa Ziehau static int			hn_tso_maxlen = IP_MAXPACKET;
51115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN,
51215516c77SSepherosa Ziehau     &hn_tso_maxlen, 0, "TSO burst limit");
51315516c77SSepherosa Ziehau 
51415516c77SSepherosa Ziehau /* Limit chimney send size */
51515516c77SSepherosa Ziehau static int			hn_tx_chimney_size = 0;
51615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN,
51715516c77SSepherosa Ziehau     &hn_tx_chimney_size, 0, "Chimney send packet size limit");
51815516c77SSepherosa Ziehau 
51915516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */
52015516c77SSepherosa Ziehau static int			hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF;
52115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN,
52215516c77SSepherosa Ziehau     &hn_direct_tx_size, 0, "Size of the packet for direct transmission");
52315516c77SSepherosa Ziehau 
52415516c77SSepherosa Ziehau /* # of LRO entries per RX ring */
52515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
52615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
52715516c77SSepherosa Ziehau static int			hn_lro_entry_count = HN_LROENT_CNT_DEF;
52815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN,
52915516c77SSepherosa Ziehau     &hn_lro_entry_count, 0, "LRO entry count");
53015516c77SSepherosa Ziehau #endif
53115516c77SSepherosa Ziehau #endif
53215516c77SSepherosa Ziehau 
533fdd0222aSSepherosa Ziehau static int			hn_tx_taskq_cnt = 1;
534fdd0222aSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_cnt, CTLFLAG_RDTUN,
535fdd0222aSSepherosa Ziehau     &hn_tx_taskq_cnt, 0, "# of TX taskqueues");
536fdd0222aSSepherosa Ziehau 
5370e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_INDEP	0
5380e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_GLOBAL	1
5390e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_EVTTQ	2
5400e11868dSSepherosa Ziehau 
5410e11868dSSepherosa Ziehau static int			hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
5420e11868dSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_mode, CTLFLAG_RDTUN,
5430e11868dSSepherosa Ziehau     &hn_tx_taskq_mode, 0, "TX taskqueue modes: "
5440e11868dSSepherosa Ziehau     "0 - independent, 1 - share global tx taskqs, 2 - share event taskqs");
5450e11868dSSepherosa Ziehau 
54615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
54715516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 0;
54815516c77SSepherosa Ziehau #else
54915516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 1;
55015516c77SSepherosa Ziehau #endif
55115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD,
55215516c77SSepherosa Ziehau     &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors");
55315516c77SSepherosa Ziehau 
55423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
55515516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */
55615516c77SSepherosa Ziehau static int			hn_use_if_start = 0;
55715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN,
55815516c77SSepherosa Ziehau     &hn_use_if_start, 0, "Use if_start TX method");
55923bf9e15SSepherosa Ziehau #endif
56015516c77SSepherosa Ziehau 
56115516c77SSepherosa Ziehau /* # of channels to use */
56215516c77SSepherosa Ziehau static int			hn_chan_cnt = 0;
56315516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN,
56415516c77SSepherosa Ziehau     &hn_chan_cnt, 0,
56515516c77SSepherosa Ziehau     "# of channels to use; each channel has one RX ring and one TX ring");
56615516c77SSepherosa Ziehau 
56715516c77SSepherosa Ziehau /* # of transmit rings to use */
56815516c77SSepherosa Ziehau static int			hn_tx_ring_cnt = 0;
56915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN,
57015516c77SSepherosa Ziehau     &hn_tx_ring_cnt, 0, "# of TX rings to use");
57115516c77SSepherosa Ziehau 
57215516c77SSepherosa Ziehau /* Software TX ring deptch */
57315516c77SSepherosa Ziehau static int			hn_tx_swq_depth = 0;
57415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN,
57515516c77SSepherosa Ziehau     &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING");
57615516c77SSepherosa Ziehau 
57715516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */
57815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
57915516c77SSepherosa Ziehau static u_int			hn_lro_mbufq_depth = 0;
58015516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN,
58115516c77SSepherosa Ziehau     &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue");
58215516c77SSepherosa Ziehau #endif
58315516c77SSepherosa Ziehau 
584dc13fee6SSepherosa Ziehau /* Packet transmission aggregation size limit */
585dc13fee6SSepherosa Ziehau static int			hn_tx_agg_size = -1;
586dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN,
587dc13fee6SSepherosa Ziehau     &hn_tx_agg_size, 0, "Packet transmission aggregation size limit");
588dc13fee6SSepherosa Ziehau 
589dc13fee6SSepherosa Ziehau /* Packet transmission aggregation count limit */
590fa915c4dSSepherosa Ziehau static int			hn_tx_agg_pkts = -1;
591dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN,
592dc13fee6SSepherosa Ziehau     &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit");
593dc13fee6SSepherosa Ziehau 
594499c3e17SSepherosa Ziehau /* VF list */
5957029da5cSPawel Biernacki SYSCTL_PROC(_hw_hn, OID_AUTO, vflist,
5967029da5cSPawel Biernacki     CTLFLAG_RD | CTLTYPE_STRING | CTLFLAG_NEEDGIANT, 0, 0,
5977029da5cSPawel Biernacki     hn_vflist_sysctl, "A",
5987029da5cSPawel Biernacki     "VF list");
599499c3e17SSepherosa Ziehau 
600499c3e17SSepherosa Ziehau /* VF mapping */
6017029da5cSPawel Biernacki SYSCTL_PROC(_hw_hn, OID_AUTO, vfmap,
6027029da5cSPawel Biernacki     CTLFLAG_RD | CTLTYPE_STRING | CTLFLAG_NEEDGIANT, 0, 0,
6037029da5cSPawel Biernacki     hn_vfmap_sysctl, "A",
6047029da5cSPawel Biernacki     "VF mapping");
605499c3e17SSepherosa Ziehau 
6069c6cae24SSepherosa Ziehau /* Transparent VF */
60778e46963SSepherosa Ziehau static int			hn_xpnt_vf = 1;
6089c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_transparent, CTLFLAG_RDTUN,
6099c6cae24SSepherosa Ziehau     &hn_xpnt_vf, 0, "Transparent VF mod");
6109c6cae24SSepherosa Ziehau 
6119c6cae24SSepherosa Ziehau /* Accurate BPF support for Transparent VF */
6129c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_accbpf = 0;
6139c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_xpnt_accbpf, CTLFLAG_RDTUN,
6149c6cae24SSepherosa Ziehau     &hn_xpnt_vf_accbpf, 0, "Accurate BPF for transparent VF");
6159c6cae24SSepherosa Ziehau 
6169c6cae24SSepherosa Ziehau /* Extra wait for transparent VF attach routing; unit seconds. */
6179c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN;
6189c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_xpnt_attwait, CTLFLAG_RWTUN,
6199c6cae24SSepherosa Ziehau     &hn_xpnt_vf_attwait, 0,
6209c6cae24SSepherosa Ziehau     "Extra wait for transparent VF attach routing; unit: seconds");
6219c6cae24SSepherosa Ziehau 
62215516c77SSepherosa Ziehau static u_int			hn_cpu_index;	/* next CPU for channel */
623fdd0222aSSepherosa Ziehau static struct taskqueue		**hn_tx_taskque;/* shared TX taskqueues */
62415516c77SSepherosa Ziehau 
625499c3e17SSepherosa Ziehau static struct rmlock		hn_vfmap_lock;
626499c3e17SSepherosa Ziehau static int			hn_vfmap_size;
627499c3e17SSepherosa Ziehau static struct ifnet		**hn_vfmap;
628499c3e17SSepherosa Ziehau 
62934d68912SSepherosa Ziehau #ifndef RSS
63015516c77SSepherosa Ziehau static const uint8_t
63115516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
63215516c77SSepherosa Ziehau 	0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
63315516c77SSepherosa Ziehau 	0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
63415516c77SSepherosa Ziehau 	0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
63515516c77SSepherosa Ziehau 	0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
63615516c77SSepherosa Ziehau 	0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
63715516c77SSepherosa Ziehau };
63834d68912SSepherosa Ziehau #endif	/* !RSS */
63915516c77SSepherosa Ziehau 
640c2d50b26SSepherosa Ziehau static const struct hyperv_guid	hn_guid = {
641c2d50b26SSepherosa Ziehau 	.hv_guid = {
642c2d50b26SSepherosa Ziehau 	    0x63, 0x51, 0x61, 0xf8, 0x3e, 0xdf, 0xc5, 0x46,
643c2d50b26SSepherosa Ziehau 	    0x91, 0x3f, 0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e }
644c2d50b26SSepherosa Ziehau };
645c2d50b26SSepherosa Ziehau 
64615516c77SSepherosa Ziehau static device_method_t hn_methods[] = {
64715516c77SSepherosa Ziehau 	/* Device interface */
64815516c77SSepherosa Ziehau 	DEVMETHOD(device_probe,		hn_probe),
64915516c77SSepherosa Ziehau 	DEVMETHOD(device_attach,	hn_attach),
65015516c77SSepherosa Ziehau 	DEVMETHOD(device_detach,	hn_detach),
65115516c77SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	hn_shutdown),
65215516c77SSepherosa Ziehau 	DEVMETHOD_END
65315516c77SSepherosa Ziehau };
65415516c77SSepherosa Ziehau 
65515516c77SSepherosa Ziehau static driver_t hn_driver = {
65615516c77SSepherosa Ziehau 	"hn",
65715516c77SSepherosa Ziehau 	hn_methods,
65815516c77SSepherosa Ziehau 	sizeof(struct hn_softc)
65915516c77SSepherosa Ziehau };
66015516c77SSepherosa Ziehau 
66115516c77SSepherosa Ziehau static devclass_t hn_devclass;
66215516c77SSepherosa Ziehau 
66315516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0);
66415516c77SSepherosa Ziehau MODULE_VERSION(hn, 1);
66515516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1);
66615516c77SSepherosa Ziehau 
66715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
66815516c77SSepherosa Ziehau static void
66915516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim)
67015516c77SSepherosa Ziehau {
67115516c77SSepherosa Ziehau 	int i;
67215516c77SSepherosa Ziehau 
673a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
67415516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim;
67515516c77SSepherosa Ziehau }
67615516c77SSepherosa Ziehau #endif
67715516c77SSepherosa Ziehau 
67815516c77SSepherosa Ziehau static int
67915516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd)
68015516c77SSepherosa Ziehau {
68115516c77SSepherosa Ziehau 
68215516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
68315516c77SSepherosa Ziehau 	    txd->chim_size == 0, ("invalid rndis sglist txd"));
68415516c77SSepherosa Ziehau 	return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA,
68515516c77SSepherosa Ziehau 	    &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt));
68615516c77SSepherosa Ziehau }
68715516c77SSepherosa Ziehau 
68815516c77SSepherosa Ziehau static int
68915516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd)
69015516c77SSepherosa Ziehau {
69115516c77SSepherosa Ziehau 	struct hn_nvs_rndis rndis;
69215516c77SSepherosa Ziehau 
69315516c77SSepherosa Ziehau 	KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID &&
69415516c77SSepherosa Ziehau 	    txd->chim_size > 0, ("invalid rndis chim txd"));
69515516c77SSepherosa Ziehau 
69615516c77SSepherosa Ziehau 	rndis.nvs_type = HN_NVS_TYPE_RNDIS;
69715516c77SSepherosa Ziehau 	rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA;
69815516c77SSepherosa Ziehau 	rndis.nvs_chim_idx = txd->chim_index;
69915516c77SSepherosa Ziehau 	rndis.nvs_chim_sz = txd->chim_size;
70015516c77SSepherosa Ziehau 
70115516c77SSepherosa Ziehau 	return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC,
70215516c77SSepherosa Ziehau 	    &rndis, sizeof(rndis), &txd->send_ctx));
70315516c77SSepherosa Ziehau }
70415516c77SSepherosa Ziehau 
70515516c77SSepherosa Ziehau static __inline uint32_t
70615516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc)
70715516c77SSepherosa Ziehau {
70815516c77SSepherosa Ziehau 	int i, bmap_cnt = sc->hn_chim_bmap_cnt;
70915516c77SSepherosa Ziehau 	u_long *bmap = sc->hn_chim_bmap;
71015516c77SSepherosa Ziehau 	uint32_t ret = HN_NVS_CHIM_IDX_INVALID;
71115516c77SSepherosa Ziehau 
71215516c77SSepherosa Ziehau 	for (i = 0; i < bmap_cnt; ++i) {
71315516c77SSepherosa Ziehau 		int idx;
71415516c77SSepherosa Ziehau 
71515516c77SSepherosa Ziehau 		idx = ffsl(~bmap[i]);
71615516c77SSepherosa Ziehau 		if (idx == 0)
71715516c77SSepherosa Ziehau 			continue;
71815516c77SSepherosa Ziehau 
71915516c77SSepherosa Ziehau 		--idx; /* ffsl is 1-based */
72015516c77SSepherosa Ziehau 		KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt,
72115516c77SSepherosa Ziehau 		    ("invalid i %d and idx %d", i, idx));
72215516c77SSepherosa Ziehau 
72315516c77SSepherosa Ziehau 		if (atomic_testandset_long(&bmap[i], idx))
72415516c77SSepherosa Ziehau 			continue;
72515516c77SSepherosa Ziehau 
72615516c77SSepherosa Ziehau 		ret = i * LONG_BIT + idx;
72715516c77SSepherosa Ziehau 		break;
72815516c77SSepherosa Ziehau 	}
72915516c77SSepherosa Ziehau 	return (ret);
73015516c77SSepherosa Ziehau }
73115516c77SSepherosa Ziehau 
73215516c77SSepherosa Ziehau static __inline void
73315516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx)
73415516c77SSepherosa Ziehau {
73515516c77SSepherosa Ziehau 	u_long mask;
73615516c77SSepherosa Ziehau 	uint32_t idx;
73715516c77SSepherosa Ziehau 
73815516c77SSepherosa Ziehau 	idx = chim_idx / LONG_BIT;
73915516c77SSepherosa Ziehau 	KASSERT(idx < sc->hn_chim_bmap_cnt,
74015516c77SSepherosa Ziehau 	    ("invalid chimney index 0x%x", chim_idx));
74115516c77SSepherosa Ziehau 
74215516c77SSepherosa Ziehau 	mask = 1UL << (chim_idx % LONG_BIT);
74315516c77SSepherosa Ziehau 	KASSERT(sc->hn_chim_bmap[idx] & mask,
74415516c77SSepherosa Ziehau 	    ("index bitmap 0x%lx, chimney index %u, "
74515516c77SSepherosa Ziehau 	     "bitmap idx %d, bitmask 0x%lx",
74615516c77SSepherosa Ziehau 	     sc->hn_chim_bmap[idx], chim_idx, idx, mask));
74715516c77SSepherosa Ziehau 
74815516c77SSepherosa Ziehau 	atomic_clear_long(&sc->hn_chim_bmap[idx], mask);
74915516c77SSepherosa Ziehau }
75015516c77SSepherosa Ziehau 
751edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
752cc0c6ebcSSepherosa Ziehau 
753cc0c6ebcSSepherosa Ziehau #define PULLUP_HDR(m, len)				\
754cc0c6ebcSSepherosa Ziehau do {							\
755cc0c6ebcSSepherosa Ziehau 	if (__predict_false((m)->m_len < (len))) {	\
756cc0c6ebcSSepherosa Ziehau 		(m) = m_pullup((m), (len));		\
757cc0c6ebcSSepherosa Ziehau 		if ((m) == NULL)			\
758cc0c6ebcSSepherosa Ziehau 			return (NULL);			\
759cc0c6ebcSSepherosa Ziehau 	}						\
760cc0c6ebcSSepherosa Ziehau } while (0)
761cc0c6ebcSSepherosa Ziehau 
762edd3f315SSepherosa Ziehau /*
763edd3f315SSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
764edd3f315SSepherosa Ziehau  */
765edd3f315SSepherosa Ziehau static __inline struct mbuf *
766edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head)
767edd3f315SSepherosa Ziehau {
768edd3f315SSepherosa Ziehau 	struct ether_vlan_header *evl;
769edd3f315SSepherosa Ziehau 	struct tcphdr *th;
770edd3f315SSepherosa Ziehau 	int ehlen;
771edd3f315SSepherosa Ziehau 
772edd3f315SSepherosa Ziehau 	KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable"));
773edd3f315SSepherosa Ziehau 
774edd3f315SSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
775edd3f315SSepherosa Ziehau 	evl = mtod(m_head, struct ether_vlan_header *);
776edd3f315SSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
777edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
778edd3f315SSepherosa Ziehau 	else
779edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
780c49d47daSSepherosa Ziehau 	m_head->m_pkthdr.l2hlen = ehlen;
781edd3f315SSepherosa Ziehau 
782edd3f315SSepherosa Ziehau #ifdef INET
783edd3f315SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
784edd3f315SSepherosa Ziehau 		struct ip *ip;
785edd3f315SSepherosa Ziehau 		int iphlen;
786edd3f315SSepherosa Ziehau 
787edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
788edd3f315SSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
789edd3f315SSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
790c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = iphlen;
791edd3f315SSepherosa Ziehau 
792edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
793edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + iphlen);
794edd3f315SSepherosa Ziehau 
795edd3f315SSepherosa Ziehau 		ip->ip_len = 0;
796edd3f315SSepherosa Ziehau 		ip->ip_sum = 0;
797edd3f315SSepherosa Ziehau 		th->th_sum = in_pseudo(ip->ip_src.s_addr,
798edd3f315SSepherosa Ziehau 		    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
799edd3f315SSepherosa Ziehau 	}
800edd3f315SSepherosa Ziehau #endif
801edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET)
802edd3f315SSepherosa Ziehau 	else
803edd3f315SSepherosa Ziehau #endif
804edd3f315SSepherosa Ziehau #ifdef INET6
805edd3f315SSepherosa Ziehau 	{
806edd3f315SSepherosa Ziehau 		struct ip6_hdr *ip6;
807edd3f315SSepherosa Ziehau 
808edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
809edd3f315SSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
810edd3f315SSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP) {
811edd3f315SSepherosa Ziehau 			m_freem(m_head);
812edd3f315SSepherosa Ziehau 			return (NULL);
813edd3f315SSepherosa Ziehau 		}
814c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = sizeof(*ip6);
815edd3f315SSepherosa Ziehau 
816edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
817edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + sizeof(*ip6));
818edd3f315SSepherosa Ziehau 
819edd3f315SSepherosa Ziehau 		ip6->ip6_plen = 0;
820edd3f315SSepherosa Ziehau 		th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
821edd3f315SSepherosa Ziehau 	}
822edd3f315SSepherosa Ziehau #endif
823edd3f315SSepherosa Ziehau 	return (m_head);
824edd3f315SSepherosa Ziehau }
825cc0c6ebcSSepherosa Ziehau 
826cc0c6ebcSSepherosa Ziehau /*
827cc0c6ebcSSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
828cc0c6ebcSSepherosa Ziehau  */
829cc0c6ebcSSepherosa Ziehau static __inline struct mbuf *
830c49d47daSSepherosa Ziehau hn_set_hlen(struct mbuf *m_head)
831cc0c6ebcSSepherosa Ziehau {
832cc0c6ebcSSepherosa Ziehau 	const struct ether_vlan_header *evl;
833cc0c6ebcSSepherosa Ziehau 	int ehlen;
834cc0c6ebcSSepherosa Ziehau 
835cc0c6ebcSSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
836cc0c6ebcSSepherosa Ziehau 	evl = mtod(m_head, const struct ether_vlan_header *);
837cc0c6ebcSSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
838cc0c6ebcSSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
839cc0c6ebcSSepherosa Ziehau 	else
840cc0c6ebcSSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
841c49d47daSSepherosa Ziehau 	m_head->m_pkthdr.l2hlen = ehlen;
842cc0c6ebcSSepherosa Ziehau 
843cc0c6ebcSSepherosa Ziehau #ifdef INET
844c49d47daSSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP_UDP)) {
845cc0c6ebcSSepherosa Ziehau 		const struct ip *ip;
846cc0c6ebcSSepherosa Ziehau 		int iphlen;
847cc0c6ebcSSepherosa Ziehau 
848cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
849cc0c6ebcSSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
850cc0c6ebcSSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
851c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = iphlen;
8522be266caSSepherosa Ziehau 
8532be266caSSepherosa Ziehau 		/*
8542be266caSSepherosa Ziehau 		 * UDP checksum offload does not work in Azure, if the
8552be266caSSepherosa Ziehau 		 * following conditions meet:
8562be266caSSepherosa Ziehau 		 * - sizeof(IP hdr + UDP hdr + payload) > 1420.
8572be266caSSepherosa Ziehau 		 * - IP_DF is not set in the IP hdr.
8582be266caSSepherosa Ziehau 		 *
8592be266caSSepherosa Ziehau 		 * Fallback to software checksum for these UDP datagrams.
8602be266caSSepherosa Ziehau 		 */
8612be266caSSepherosa Ziehau 		if ((m_head->m_pkthdr.csum_flags & CSUM_IP_UDP) &&
8622be266caSSepherosa Ziehau 		    m_head->m_pkthdr.len > hn_udpcs_fixup_mtu + ehlen &&
8632be266caSSepherosa Ziehau 		    (ntohs(ip->ip_off) & IP_DF) == 0) {
8642be266caSSepherosa Ziehau 			uint16_t off = ehlen + iphlen;
8652be266caSSepherosa Ziehau 
8662be266caSSepherosa Ziehau 			counter_u64_add(hn_udpcs_fixup, 1);
8672be266caSSepherosa Ziehau 			PULLUP_HDR(m_head, off + sizeof(struct udphdr));
8682be266caSSepherosa Ziehau 			*(uint16_t *)(m_head->m_data + off +
8692be266caSSepherosa Ziehau                             m_head->m_pkthdr.csum_data) = in_cksum_skip(
8702be266caSSepherosa Ziehau 			    m_head, m_head->m_pkthdr.len, off);
8712be266caSSepherosa Ziehau 			m_head->m_pkthdr.csum_flags &= ~CSUM_IP_UDP;
8722be266caSSepherosa Ziehau 		}
873cc0c6ebcSSepherosa Ziehau 	}
874cc0c6ebcSSepherosa Ziehau #endif
875cc0c6ebcSSepherosa Ziehau #if defined(INET6) && defined(INET)
876cc0c6ebcSSepherosa Ziehau 	else
877cc0c6ebcSSepherosa Ziehau #endif
878cc0c6ebcSSepherosa Ziehau #ifdef INET6
879cc0c6ebcSSepherosa Ziehau 	{
880cc0c6ebcSSepherosa Ziehau 		const struct ip6_hdr *ip6;
881cc0c6ebcSSepherosa Ziehau 
882cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
883cc0c6ebcSSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
884f0319886SWei Hu 		if (ip6->ip6_nxt != IPPROTO_TCP &&
885f0319886SWei Hu 		    ip6->ip6_nxt != IPPROTO_UDP) {
886c49d47daSSepherosa Ziehau 			m_freem(m_head);
887c49d47daSSepherosa Ziehau 			return (NULL);
888c49d47daSSepherosa Ziehau 		}
889c49d47daSSepherosa Ziehau 		m_head->m_pkthdr.l3hlen = sizeof(*ip6);
890cc0c6ebcSSepherosa Ziehau 	}
891cc0c6ebcSSepherosa Ziehau #endif
892cc0c6ebcSSepherosa Ziehau 	return (m_head);
893cc0c6ebcSSepherosa Ziehau }
894cc0c6ebcSSepherosa Ziehau 
895c49d47daSSepherosa Ziehau /*
896c49d47daSSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
897c49d47daSSepherosa Ziehau  */
898c49d47daSSepherosa Ziehau static __inline struct mbuf *
899c49d47daSSepherosa Ziehau hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn)
900c49d47daSSepherosa Ziehau {
901c49d47daSSepherosa Ziehau 	const struct tcphdr *th;
902c49d47daSSepherosa Ziehau 	int ehlen, iphlen;
903c49d47daSSepherosa Ziehau 
904c49d47daSSepherosa Ziehau 	*tcpsyn = 0;
905c49d47daSSepherosa Ziehau 	ehlen = m_head->m_pkthdr.l2hlen;
906c49d47daSSepherosa Ziehau 	iphlen = m_head->m_pkthdr.l3hlen;
907c49d47daSSepherosa Ziehau 
908c49d47daSSepherosa Ziehau 	PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
909c49d47daSSepherosa Ziehau 	th = mtodo(m_head, ehlen + iphlen);
910c49d47daSSepherosa Ziehau 	if (th->th_flags & TH_SYN)
911c49d47daSSepherosa Ziehau 		*tcpsyn = 1;
912c49d47daSSepherosa Ziehau 	return (m_head);
913c49d47daSSepherosa Ziehau }
914c49d47daSSepherosa Ziehau 
915cc0c6ebcSSepherosa Ziehau #undef PULLUP_HDR
916cc0c6ebcSSepherosa Ziehau 
917edd3f315SSepherosa Ziehau #endif	/* INET6 || INET */
918edd3f315SSepherosa Ziehau 
91915516c77SSepherosa Ziehau static int
920f1b0a43fSSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc, uint32_t filter)
921f1b0a43fSSepherosa Ziehau {
922f1b0a43fSSepherosa Ziehau 	int error = 0;
923f1b0a43fSSepherosa Ziehau 
924f1b0a43fSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
925f1b0a43fSSepherosa Ziehau 
926f1b0a43fSSepherosa Ziehau 	if (sc->hn_rx_filter != filter) {
927f1b0a43fSSepherosa Ziehau 		error = hn_rndis_set_rxfilter(sc, filter);
928f1b0a43fSSepherosa Ziehau 		if (!error)
929f1b0a43fSSepherosa Ziehau 			sc->hn_rx_filter = filter;
930f1b0a43fSSepherosa Ziehau 	}
931f1b0a43fSSepherosa Ziehau 	return (error);
932f1b0a43fSSepherosa Ziehau }
933f1b0a43fSSepherosa Ziehau 
934f1b0a43fSSepherosa Ziehau static int
935c08f7b2cSSepherosa Ziehau hn_rxfilter_config(struct hn_softc *sc)
93615516c77SSepherosa Ziehau {
93715516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
93815516c77SSepherosa Ziehau 	uint32_t filter;
93915516c77SSepherosa Ziehau 
94015516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
94115516c77SSepherosa Ziehau 
9429c6cae24SSepherosa Ziehau 	/*
9439c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, we don't know how
9449c6cae24SSepherosa Ziehau 	 * its RX filter is configured, so stick the synthetic device in
9459c6cae24SSepherosa Ziehau 	 * the promiscous mode.
9469c6cae24SSepherosa Ziehau 	 */
9479c6cae24SSepherosa Ziehau 	if ((ifp->if_flags & IFF_PROMISC) || (sc->hn_flags & HN_FLAG_RXVF)) {
94815516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_PROMISCUOUS;
94915516c77SSepherosa Ziehau 	} else {
95015516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_DIRECTED;
95115516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_BROADCAST)
95215516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_BROADCAST;
95315516c77SSepherosa Ziehau 		/* TODO: support multicast list */
95415516c77SSepherosa Ziehau 		if ((ifp->if_flags & IFF_ALLMULTI) ||
955d7c5a620SMatt Macy 		    !CK_STAILQ_EMPTY(&ifp->if_multiaddrs))
95615516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
95715516c77SSepherosa Ziehau 	}
958f1b0a43fSSepherosa Ziehau 	return (hn_set_rxfilter(sc, filter));
95915516c77SSepherosa Ziehau }
96015516c77SSepherosa Ziehau 
961dc13fee6SSepherosa Ziehau static void
962dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc)
963dc13fee6SSepherosa Ziehau {
964dc13fee6SSepherosa Ziehau 	uint32_t size, pkts;
965dc13fee6SSepherosa Ziehau 	int i;
966dc13fee6SSepherosa Ziehau 
967dc13fee6SSepherosa Ziehau 	/*
968dc13fee6SSepherosa Ziehau 	 * Setup aggregation size.
969dc13fee6SSepherosa Ziehau 	 */
970dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_size < 0)
971dc13fee6SSepherosa Ziehau 		size = UINT32_MAX;
972dc13fee6SSepherosa Ziehau 	else
973dc13fee6SSepherosa Ziehau 		size = sc->hn_agg_size;
974dc13fee6SSepherosa Ziehau 
975dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_size < size)
976dc13fee6SSepherosa Ziehau 		size = sc->hn_rndis_agg_size;
977dc13fee6SSepherosa Ziehau 
978a4364cfeSSepherosa Ziehau 	/* NOTE: We only aggregate packets using chimney sending buffers. */
979a4364cfeSSepherosa Ziehau 	if (size > (uint32_t)sc->hn_chim_szmax)
980a4364cfeSSepherosa Ziehau 		size = sc->hn_chim_szmax;
981a4364cfeSSepherosa Ziehau 
982dc13fee6SSepherosa Ziehau 	if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) {
983dc13fee6SSepherosa Ziehau 		/* Disable */
984dc13fee6SSepherosa Ziehau 		size = 0;
985dc13fee6SSepherosa Ziehau 		pkts = 0;
986dc13fee6SSepherosa Ziehau 		goto done;
987dc13fee6SSepherosa Ziehau 	}
988dc13fee6SSepherosa Ziehau 
989dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'int'. */
990dc13fee6SSepherosa Ziehau 	if (size > INT_MAX)
991dc13fee6SSepherosa Ziehau 		size = INT_MAX;
992dc13fee6SSepherosa Ziehau 
993dc13fee6SSepherosa Ziehau 	/*
994dc13fee6SSepherosa Ziehau 	 * Setup aggregation packet count.
995dc13fee6SSepherosa Ziehau 	 */
996dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_pkts < 0)
997dc13fee6SSepherosa Ziehau 		pkts = UINT32_MAX;
998dc13fee6SSepherosa Ziehau 	else
999dc13fee6SSepherosa Ziehau 		pkts = sc->hn_agg_pkts;
1000dc13fee6SSepherosa Ziehau 
1001dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_pkts < pkts)
1002dc13fee6SSepherosa Ziehau 		pkts = sc->hn_rndis_agg_pkts;
1003dc13fee6SSepherosa Ziehau 
1004dc13fee6SSepherosa Ziehau 	if (pkts <= 1) {
1005dc13fee6SSepherosa Ziehau 		/* Disable */
1006dc13fee6SSepherosa Ziehau 		size = 0;
1007dc13fee6SSepherosa Ziehau 		pkts = 0;
1008dc13fee6SSepherosa Ziehau 		goto done;
1009dc13fee6SSepherosa Ziehau 	}
1010dc13fee6SSepherosa Ziehau 
1011dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
1012dc13fee6SSepherosa Ziehau 	if (pkts > SHRT_MAX)
1013dc13fee6SSepherosa Ziehau 		pkts = SHRT_MAX;
1014dc13fee6SSepherosa Ziehau 
1015dc13fee6SSepherosa Ziehau done:
1016dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
1017dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_align > SHRT_MAX) {
1018dc13fee6SSepherosa Ziehau 		/* Disable */
1019dc13fee6SSepherosa Ziehau 		size = 0;
1020dc13fee6SSepherosa Ziehau 		pkts = 0;
1021dc13fee6SSepherosa Ziehau 	}
1022dc13fee6SSepherosa Ziehau 
1023dc13fee6SSepherosa Ziehau 	if (bootverbose) {
1024dc13fee6SSepherosa Ziehau 		if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n",
1025dc13fee6SSepherosa Ziehau 		    size, pkts, sc->hn_rndis_agg_align);
1026dc13fee6SSepherosa Ziehau 	}
1027dc13fee6SSepherosa Ziehau 
1028dc13fee6SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
1029dc13fee6SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
1030dc13fee6SSepherosa Ziehau 
1031dc13fee6SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
1032dc13fee6SSepherosa Ziehau 		txr->hn_agg_szmax = size;
1033dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktmax = pkts;
1034dc13fee6SSepherosa Ziehau 		txr->hn_agg_align = sc->hn_rndis_agg_align;
1035dc13fee6SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
1036dc13fee6SSepherosa Ziehau 	}
1037dc13fee6SSepherosa Ziehau }
1038dc13fee6SSepherosa Ziehau 
103915516c77SSepherosa Ziehau static int
104015516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr)
104115516c77SSepherosa Ziehau {
104215516c77SSepherosa Ziehau 
104315516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet"));
104415516c77SSepherosa Ziehau 	if (hn_tx_swq_depth < txr->hn_txdesc_cnt)
104515516c77SSepherosa Ziehau 		return txr->hn_txdesc_cnt;
104615516c77SSepherosa Ziehau 	return hn_tx_swq_depth;
104715516c77SSepherosa Ziehau }
104815516c77SSepherosa Ziehau 
104915516c77SSepherosa Ziehau static int
105015516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc)
105115516c77SSepherosa Ziehau {
105215516c77SSepherosa Ziehau 	int error;
105315516c77SSepherosa Ziehau 
105415516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
105515516c77SSepherosa Ziehau 
105615516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
105715516c77SSepherosa Ziehau 		return (ENXIO);
105815516c77SSepherosa Ziehau 
105915516c77SSepherosa Ziehau 	/*
106015516c77SSepherosa Ziehau 	 * Disable RSS first.
106115516c77SSepherosa Ziehau 	 *
106215516c77SSepherosa Ziehau 	 * NOTE:
106315516c77SSepherosa Ziehau 	 * Direct reconfiguration by setting the UNCHG flags does
106415516c77SSepherosa Ziehau 	 * _not_ work properly.
106515516c77SSepherosa Ziehau 	 */
106615516c77SSepherosa Ziehau 	if (bootverbose)
106715516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "disable RSS\n");
106815516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE);
106915516c77SSepherosa Ziehau 	if (error) {
107015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS disable failed\n");
107115516c77SSepherosa Ziehau 		return (error);
107215516c77SSepherosa Ziehau 	}
107315516c77SSepherosa Ziehau 
107415516c77SSepherosa Ziehau 	/*
107515516c77SSepherosa Ziehau 	 * Reenable the RSS w/ the updated RSS key or indirect
107615516c77SSepherosa Ziehau 	 * table.
107715516c77SSepherosa Ziehau 	 */
107815516c77SSepherosa Ziehau 	if (bootverbose)
107915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "reconfig RSS\n");
108015516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
108115516c77SSepherosa Ziehau 	if (error) {
108215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS reconfig failed\n");
108315516c77SSepherosa Ziehau 		return (error);
108415516c77SSepherosa Ziehau 	}
108515516c77SSepherosa Ziehau 	return (0);
108615516c77SSepherosa Ziehau }
108715516c77SSepherosa Ziehau 
108815516c77SSepherosa Ziehau static void
1089afd4971bSSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc)
109015516c77SSepherosa Ziehau {
109115516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
1092afd4971bSSepherosa Ziehau 	int i, nchan;
109315516c77SSepherosa Ziehau 
1094afd4971bSSepherosa Ziehau 	nchan = sc->hn_rx_ring_inuse;
109515516c77SSepherosa Ziehau 	KASSERT(nchan > 1, ("invalid # of channels %d", nchan));
109615516c77SSepherosa Ziehau 
109715516c77SSepherosa Ziehau 	/*
109815516c77SSepherosa Ziehau 	 * Check indirect table to make sure that all channels in it
109915516c77SSepherosa Ziehau 	 * can be used.
110015516c77SSepherosa Ziehau 	 */
110115516c77SSepherosa Ziehau 	for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
110215516c77SSepherosa Ziehau 		if (rss->rss_ind[i] >= nchan) {
110315516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp,
110415516c77SSepherosa Ziehau 			    "RSS indirect table %d fixup: %u -> %d\n",
110515516c77SSepherosa Ziehau 			    i, rss->rss_ind[i], nchan - 1);
110615516c77SSepherosa Ziehau 			rss->rss_ind[i] = nchan - 1;
110715516c77SSepherosa Ziehau 		}
110815516c77SSepherosa Ziehau 	}
110915516c77SSepherosa Ziehau }
111015516c77SSepherosa Ziehau 
111115516c77SSepherosa Ziehau static int
111215516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused)
111315516c77SSepherosa Ziehau {
111415516c77SSepherosa Ziehau 
111515516c77SSepherosa Ziehau 	return EOPNOTSUPP;
111615516c77SSepherosa Ziehau }
111715516c77SSepherosa Ziehau 
111815516c77SSepherosa Ziehau static void
111915516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
112015516c77SSepherosa Ziehau {
112115516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
112215516c77SSepherosa Ziehau 
112315516c77SSepherosa Ziehau 	ifmr->ifm_status = IFM_AVALID;
112415516c77SSepherosa Ziehau 	ifmr->ifm_active = IFM_ETHER;
112515516c77SSepherosa Ziehau 
112615516c77SSepherosa Ziehau 	if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) {
112715516c77SSepherosa Ziehau 		ifmr->ifm_active |= IFM_NONE;
112815516c77SSepherosa Ziehau 		return;
112915516c77SSepherosa Ziehau 	}
113015516c77SSepherosa Ziehau 	ifmr->ifm_status |= IFM_ACTIVE;
113115516c77SSepherosa Ziehau 	ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
113215516c77SSepherosa Ziehau }
113315516c77SSepherosa Ziehau 
11345bdfd3fdSDexuan Cui static void
1135962f0357SSepherosa Ziehau hn_rxvf_set_task(void *xarg, int pending __unused)
11365bdfd3fdSDexuan Cui {
1137962f0357SSepherosa Ziehau 	struct hn_rxvf_setarg *arg = xarg;
11385bdfd3fdSDexuan Cui 
1139962f0357SSepherosa Ziehau 	arg->rxr->hn_rxvf_ifp = arg->vf_ifp;
11405bdfd3fdSDexuan Cui }
11415bdfd3fdSDexuan Cui 
11425bdfd3fdSDexuan Cui static void
1143962f0357SSepherosa Ziehau hn_rxvf_set(struct hn_softc *sc, struct ifnet *vf_ifp)
11445bdfd3fdSDexuan Cui {
11455bdfd3fdSDexuan Cui 	struct hn_rx_ring *rxr;
1146962f0357SSepherosa Ziehau 	struct hn_rxvf_setarg arg;
11475bdfd3fdSDexuan Cui 	struct task task;
11485bdfd3fdSDexuan Cui 	int i;
11495bdfd3fdSDexuan Cui 
11505bdfd3fdSDexuan Cui 	HN_LOCK_ASSERT(sc);
11515bdfd3fdSDexuan Cui 
1152962f0357SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_rxvf_set_task, &arg);
11535bdfd3fdSDexuan Cui 
11545bdfd3fdSDexuan Cui 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
11555bdfd3fdSDexuan Cui 		rxr = &sc->hn_rx_ring[i];
11565bdfd3fdSDexuan Cui 
11575bdfd3fdSDexuan Cui 		if (i < sc->hn_rx_ring_inuse) {
1158962f0357SSepherosa Ziehau 			arg.rxr = rxr;
1159962f0357SSepherosa Ziehau 			arg.vf_ifp = vf_ifp;
11605bdfd3fdSDexuan Cui 			vmbus_chan_run_task(rxr->hn_chan, &task);
11615bdfd3fdSDexuan Cui 		} else {
1162962f0357SSepherosa Ziehau 			rxr->hn_rxvf_ifp = vf_ifp;
11635bdfd3fdSDexuan Cui 		}
11645bdfd3fdSDexuan Cui 	}
11655bdfd3fdSDexuan Cui }
11665bdfd3fdSDexuan Cui 
1167962f0357SSepherosa Ziehau static bool
1168499c3e17SSepherosa Ziehau hn_ismyvf(const struct hn_softc *sc, const struct ifnet *ifp)
1169499c3e17SSepherosa Ziehau {
1170499c3e17SSepherosa Ziehau 	const struct ifnet *hn_ifp;
1171499c3e17SSepherosa Ziehau 
1172499c3e17SSepherosa Ziehau 	hn_ifp = sc->hn_ifp;
1173499c3e17SSepherosa Ziehau 
1174499c3e17SSepherosa Ziehau 	if (ifp == hn_ifp)
1175499c3e17SSepherosa Ziehau 		return (false);
1176499c3e17SSepherosa Ziehau 
1177499c3e17SSepherosa Ziehau 	if (ifp->if_alloctype != IFT_ETHER)
1178499c3e17SSepherosa Ziehau 		return (false);
1179499c3e17SSepherosa Ziehau 
1180499c3e17SSepherosa Ziehau 	/* Ignore lagg/vlan interfaces */
1181499c3e17SSepherosa Ziehau 	if (strcmp(ifp->if_dname, "lagg") == 0 ||
1182499c3e17SSepherosa Ziehau 	    strcmp(ifp->if_dname, "vlan") == 0)
1183499c3e17SSepherosa Ziehau 		return (false);
1184499c3e17SSepherosa Ziehau 
1185d76fb49fSDexuan Cui 	/*
1186d76fb49fSDexuan Cui 	 * During detach events ifp->if_addr might be NULL.
1187d76fb49fSDexuan Cui 	 * Make sure the bcmp() below doesn't panic on that:
1188d76fb49fSDexuan Cui 	 */
1189d76fb49fSDexuan Cui 	if (ifp->if_addr == NULL || hn_ifp->if_addr == NULL)
1190d76fb49fSDexuan Cui 		return (false);
1191d76fb49fSDexuan Cui 
1192499c3e17SSepherosa Ziehau 	if (bcmp(IF_LLADDR(ifp), IF_LLADDR(hn_ifp), ETHER_ADDR_LEN) != 0)
1193499c3e17SSepherosa Ziehau 		return (false);
1194499c3e17SSepherosa Ziehau 
1195499c3e17SSepherosa Ziehau 	return (true);
1196499c3e17SSepherosa Ziehau }
1197499c3e17SSepherosa Ziehau 
11985bdfd3fdSDexuan Cui static void
1199962f0357SSepherosa Ziehau hn_rxvf_change(struct hn_softc *sc, struct ifnet *ifp, bool rxvf)
12005bdfd3fdSDexuan Cui {
12015bdfd3fdSDexuan Cui 	struct ifnet *hn_ifp;
12025bdfd3fdSDexuan Cui 
12035bdfd3fdSDexuan Cui 	HN_LOCK(sc);
12045bdfd3fdSDexuan Cui 
12055bdfd3fdSDexuan Cui 	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
12065bdfd3fdSDexuan Cui 		goto out;
12075bdfd3fdSDexuan Cui 
1208499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1209499c3e17SSepherosa Ziehau 		goto out;
12105bdfd3fdSDexuan Cui 	hn_ifp = sc->hn_ifp;
12115bdfd3fdSDexuan Cui 
1212962f0357SSepherosa Ziehau 	if (rxvf) {
1213962f0357SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_RXVF)
12145bdfd3fdSDexuan Cui 			goto out;
12155bdfd3fdSDexuan Cui 
1216962f0357SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_RXVF;
12175bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
12185bdfd3fdSDexuan Cui 	} else {
1219962f0357SSepherosa Ziehau 		if (!(sc->hn_flags & HN_FLAG_RXVF))
12205bdfd3fdSDexuan Cui 			goto out;
12215bdfd3fdSDexuan Cui 
1222962f0357SSepherosa Ziehau 		sc->hn_flags &= ~HN_FLAG_RXVF;
1223499c3e17SSepherosa Ziehau 		if (hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
12245bdfd3fdSDexuan Cui 			hn_rxfilter_config(sc);
12255bdfd3fdSDexuan Cui 		else
12265bdfd3fdSDexuan Cui 			hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE);
12275bdfd3fdSDexuan Cui 	}
12285bdfd3fdSDexuan Cui 
12295bdfd3fdSDexuan Cui 	hn_nvs_set_datapath(sc,
12309c6cae24SSepherosa Ziehau 	    rxvf ? HN_NVS_DATAPATH_VF : HN_NVS_DATAPATH_SYNTH);
12315bdfd3fdSDexuan Cui 
1232962f0357SSepherosa Ziehau 	hn_rxvf_set(sc, rxvf ? ifp : NULL);
12335bdfd3fdSDexuan Cui 
1234962f0357SSepherosa Ziehau 	if (rxvf) {
1235642ec226SSepherosa Ziehau 		hn_vf_rss_fixup(sc, true);
12365bdfd3fdSDexuan Cui 		hn_suspend_mgmt(sc);
12375bdfd3fdSDexuan Cui 		sc->hn_link_flags &=
12385bdfd3fdSDexuan Cui 		    ~(HN_LINK_FLAG_LINKUP | HN_LINK_FLAG_NETCHG);
1239499c3e17SSepherosa Ziehau 		if_link_state_change(hn_ifp, LINK_STATE_DOWN);
12405bdfd3fdSDexuan Cui 	} else {
1241642ec226SSepherosa Ziehau 		hn_vf_rss_restore(sc);
12425bdfd3fdSDexuan Cui 		hn_resume_mgmt(sc);
12435bdfd3fdSDexuan Cui 	}
12445bdfd3fdSDexuan Cui 
1245962f0357SSepherosa Ziehau 	devctl_notify("HYPERV_NIC_VF", hn_ifp->if_xname,
1246962f0357SSepherosa Ziehau 	    rxvf ? "VF_UP" : "VF_DOWN", NULL);
124733408a34SDexuan Cui 
1248962f0357SSepherosa Ziehau 	if (bootverbose) {
1249962f0357SSepherosa Ziehau 		if_printf(hn_ifp, "datapath is switched %s %s\n",
1250962f0357SSepherosa Ziehau 		    rxvf ? "to" : "from", ifp->if_xname);
1251962f0357SSepherosa Ziehau 	}
12525bdfd3fdSDexuan Cui out:
12535bdfd3fdSDexuan Cui 	HN_UNLOCK(sc);
12545bdfd3fdSDexuan Cui }
12555bdfd3fdSDexuan Cui 
12565bdfd3fdSDexuan Cui static void
12575bdfd3fdSDexuan Cui hn_ifnet_event(void *arg, struct ifnet *ifp, int event)
12585bdfd3fdSDexuan Cui {
1259962f0357SSepherosa Ziehau 
12605bdfd3fdSDexuan Cui 	if (event != IFNET_EVENT_UP && event != IFNET_EVENT_DOWN)
12615bdfd3fdSDexuan Cui 		return;
1262962f0357SSepherosa Ziehau 	hn_rxvf_change(arg, ifp, event == IFNET_EVENT_UP);
12635bdfd3fdSDexuan Cui }
12645bdfd3fdSDexuan Cui 
12655bdfd3fdSDexuan Cui static void
12665bdfd3fdSDexuan Cui hn_ifaddr_event(void *arg, struct ifnet *ifp)
12675bdfd3fdSDexuan Cui {
1268962f0357SSepherosa Ziehau 
1269962f0357SSepherosa Ziehau 	hn_rxvf_change(arg, ifp, ifp->if_flags & IFF_UP);
12705bdfd3fdSDexuan Cui }
12715bdfd3fdSDexuan Cui 
12729c6cae24SSepherosa Ziehau static int
12739c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetcaps(struct hn_softc *sc, struct ifreq *ifr)
12749c6cae24SSepherosa Ziehau {
12759c6cae24SSepherosa Ziehau 	struct ifnet *ifp, *vf_ifp;
12769c6cae24SSepherosa Ziehau 	uint64_t tmp;
12779c6cae24SSepherosa Ziehau 	int error;
12789c6cae24SSepherosa Ziehau 
12799c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
12809c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
12819c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
12829c6cae24SSepherosa Ziehau 
12839c6cae24SSepherosa Ziehau 	/*
12849c6cae24SSepherosa Ziehau 	 * Fix up requested capabilities w/ supported capabilities,
12859c6cae24SSepherosa Ziehau 	 * since the supported capabilities could have been changed.
12869c6cae24SSepherosa Ziehau 	 */
12879c6cae24SSepherosa Ziehau 	ifr->ifr_reqcap &= ifp->if_capabilities;
12889c6cae24SSepherosa Ziehau 	/* Pass SIOCSIFCAP to VF. */
12899c6cae24SSepherosa Ziehau 	error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFCAP, (caddr_t)ifr);
12909c6cae24SSepherosa Ziehau 
12919c6cae24SSepherosa Ziehau 	/*
12929c6cae24SSepherosa Ziehau 	 * NOTE:
12939c6cae24SSepherosa Ziehau 	 * The error will be propagated to the callers, however, it
12949c6cae24SSepherosa Ziehau 	 * is _not_ useful here.
12959c6cae24SSepherosa Ziehau 	 */
12969c6cae24SSepherosa Ziehau 
12979c6cae24SSepherosa Ziehau 	/*
12989c6cae24SSepherosa Ziehau 	 * Merge VF's enabled capabilities.
12999c6cae24SSepherosa Ziehau 	 */
13009c6cae24SSepherosa Ziehau 	ifp->if_capenable = vf_ifp->if_capenable & ifp->if_capabilities;
13019c6cae24SSepherosa Ziehau 
13029c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & HN_CSUM_IP_HWASSIST(sc);
13039c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TXCSUM)
13049c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
13059c6cae24SSepherosa Ziehau 	else
13069c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
13079c6cae24SSepherosa Ziehau 
13089c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & HN_CSUM_IP6_HWASSIST(sc);
13099c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
13109c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
13119c6cae24SSepherosa Ziehau 	else
13129c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
13139c6cae24SSepherosa Ziehau 
13149c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & CSUM_IP_TSO;
13159c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TSO4)
13169c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
13179c6cae24SSepherosa Ziehau 	else
13189c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
13199c6cae24SSepherosa Ziehau 
13209c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & CSUM_IP6_TSO;
13219c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TSO6)
13229c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
13239c6cae24SSepherosa Ziehau 	else
13249c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
13259c6cae24SSepherosa Ziehau 
13269c6cae24SSepherosa Ziehau 	return (error);
13279c6cae24SSepherosa Ziehau }
13289c6cae24SSepherosa Ziehau 
13299c6cae24SSepherosa Ziehau static int
13309c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetflags(struct hn_softc *sc)
13319c6cae24SSepherosa Ziehau {
13329c6cae24SSepherosa Ziehau 	struct ifnet *vf_ifp;
13339c6cae24SSepherosa Ziehau 	struct ifreq ifr;
13349c6cae24SSepherosa Ziehau 
13359c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
13369c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
13379c6cae24SSepherosa Ziehau 
13389c6cae24SSepherosa Ziehau 	memset(&ifr, 0, sizeof(ifr));
13399c6cae24SSepherosa Ziehau 	strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
13409c6cae24SSepherosa Ziehau 	ifr.ifr_flags = vf_ifp->if_flags & 0xffff;
13419c6cae24SSepherosa Ziehau 	ifr.ifr_flagshigh = vf_ifp->if_flags >> 16;
13429c6cae24SSepherosa Ziehau 	return (vf_ifp->if_ioctl(vf_ifp, SIOCSIFFLAGS, (caddr_t)&ifr));
13439c6cae24SSepherosa Ziehau }
13449c6cae24SSepherosa Ziehau 
13459c6cae24SSepherosa Ziehau static void
13469c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(struct hn_softc *sc)
13479c6cae24SSepherosa Ziehau {
13489c6cae24SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
13499c6cae24SSepherosa Ziehau 	int allmulti = 0;
13509c6cae24SSepherosa Ziehau 
13519c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
13529c6cae24SSepherosa Ziehau 
13539c6cae24SSepherosa Ziehau 	/* XXX vlan(4) style mcast addr maintenance */
1354d7c5a620SMatt Macy 	if (!CK_STAILQ_EMPTY(&ifp->if_multiaddrs))
13559c6cae24SSepherosa Ziehau 		allmulti = IFF_ALLMULTI;
13569c6cae24SSepherosa Ziehau 
13579c6cae24SSepherosa Ziehau 	/* Always set the VF's if_flags */
13589c6cae24SSepherosa Ziehau 	sc->hn_vf_ifp->if_flags = ifp->if_flags | allmulti;
13599c6cae24SSepherosa Ziehau }
13609c6cae24SSepherosa Ziehau 
13619c6cae24SSepherosa Ziehau static void
13629c6cae24SSepherosa Ziehau hn_xpnt_vf_input(struct ifnet *vf_ifp, struct mbuf *m)
13639c6cae24SSepherosa Ziehau {
13649c6cae24SSepherosa Ziehau 	struct rm_priotracker pt;
13659c6cae24SSepherosa Ziehau 	struct ifnet *hn_ifp = NULL;
13669c6cae24SSepherosa Ziehau 	struct mbuf *mn;
13679c6cae24SSepherosa Ziehau 
13689c6cae24SSepherosa Ziehau 	/*
13699c6cae24SSepherosa Ziehau 	 * XXX racy, if hn(4) ever detached.
13709c6cae24SSepherosa Ziehau 	 */
13719c6cae24SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
13729c6cae24SSepherosa Ziehau 	if (vf_ifp->if_index < hn_vfmap_size)
13739c6cae24SSepherosa Ziehau 		hn_ifp = hn_vfmap[vf_ifp->if_index];
13749c6cae24SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
13759c6cae24SSepherosa Ziehau 
13769c6cae24SSepherosa Ziehau 	if (hn_ifp != NULL) {
13779c6cae24SSepherosa Ziehau 		for (mn = m; mn != NULL; mn = mn->m_nextpkt) {
13783bed4e54SSepherosa Ziehau 			/*
13793bed4e54SSepherosa Ziehau 			 * Allow tapping on the VF.
13803bed4e54SSepherosa Ziehau 			 */
13819c6cae24SSepherosa Ziehau 			ETHER_BPF_MTAP(vf_ifp, mn);
13823bed4e54SSepherosa Ziehau 
13833bed4e54SSepherosa Ziehau 			/*
13843bed4e54SSepherosa Ziehau 			 * Update VF stats.
13853bed4e54SSepherosa Ziehau 			 */
13863bed4e54SSepherosa Ziehau 			if ((vf_ifp->if_capenable & IFCAP_HWSTATS) == 0) {
13873bed4e54SSepherosa Ziehau 				if_inc_counter(vf_ifp, IFCOUNTER_IBYTES,
13883bed4e54SSepherosa Ziehau 				    mn->m_pkthdr.len);
13893bed4e54SSepherosa Ziehau 			}
13903bed4e54SSepherosa Ziehau 			/*
13913bed4e54SSepherosa Ziehau 			 * XXX IFCOUNTER_IMCAST
13923bed4e54SSepherosa Ziehau 			 * This stat updating is kinda invasive, since it
13933bed4e54SSepherosa Ziehau 			 * requires two checks on the mbuf: the length check
13943bed4e54SSepherosa Ziehau 			 * and the ethernet header check.  As of this write,
13953bed4e54SSepherosa Ziehau 			 * all multicast packets go directly to hn(4), which
13963bed4e54SSepherosa Ziehau 			 * makes imcast stat updating in the VF a try in vian.
13973bed4e54SSepherosa Ziehau 			 */
13983bed4e54SSepherosa Ziehau 
13993bed4e54SSepherosa Ziehau 			/*
14003bed4e54SSepherosa Ziehau 			 * Fix up rcvif and increase hn(4)'s ipackets.
14013bed4e54SSepherosa Ziehau 			 */
14029c6cae24SSepherosa Ziehau 			mn->m_pkthdr.rcvif = hn_ifp;
14039c6cae24SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1);
14049c6cae24SSepherosa Ziehau 		}
14053bed4e54SSepherosa Ziehau 		/*
14063bed4e54SSepherosa Ziehau 		 * Go through hn(4)'s if_input.
14073bed4e54SSepherosa Ziehau 		 */
14089c6cae24SSepherosa Ziehau 		hn_ifp->if_input(hn_ifp, m);
14099c6cae24SSepherosa Ziehau 	} else {
14109c6cae24SSepherosa Ziehau 		/*
14119c6cae24SSepherosa Ziehau 		 * In the middle of the transition; free this
14129c6cae24SSepherosa Ziehau 		 * mbuf chain.
14139c6cae24SSepherosa Ziehau 		 */
14149c6cae24SSepherosa Ziehau 		while (m != NULL) {
14159c6cae24SSepherosa Ziehau 			mn = m->m_nextpkt;
14169c6cae24SSepherosa Ziehau 			m->m_nextpkt = NULL;
14179c6cae24SSepherosa Ziehau 			m_freem(m);
14189c6cae24SSepherosa Ziehau 			m = mn;
14199c6cae24SSepherosa Ziehau 		}
14209c6cae24SSepherosa Ziehau 	}
14219c6cae24SSepherosa Ziehau }
14229c6cae24SSepherosa Ziehau 
14239c6cae24SSepherosa Ziehau static void
14249c6cae24SSepherosa Ziehau hn_mtu_change_fixup(struct hn_softc *sc)
14259c6cae24SSepherosa Ziehau {
14269c6cae24SSepherosa Ziehau 	struct ifnet *ifp;
14279c6cae24SSepherosa Ziehau 
14289c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
14299c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
14309c6cae24SSepherosa Ziehau 
14319c6cae24SSepherosa Ziehau 	hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu);
14329c6cae24SSepherosa Ziehau #if __FreeBSD_version >= 1100099
14339c6cae24SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_lro.lro_length_lim < HN_LRO_LENLIM_MIN(ifp))
14349c6cae24SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
14359c6cae24SSepherosa Ziehau #endif
14369c6cae24SSepherosa Ziehau }
14379c6cae24SSepherosa Ziehau 
1438642ec226SSepherosa Ziehau static uint32_t
1439642ec226SSepherosa Ziehau hn_rss_type_fromndis(uint32_t rss_hash)
1440642ec226SSepherosa Ziehau {
1441642ec226SSepherosa Ziehau 	uint32_t types = 0;
1442642ec226SSepherosa Ziehau 
1443642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_IPV4)
1444642ec226SSepherosa Ziehau 		types |= RSS_TYPE_IPV4;
1445642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_TCP_IPV4)
1446642ec226SSepherosa Ziehau 		types |= RSS_TYPE_TCP_IPV4;
1447642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_IPV6)
1448642ec226SSepherosa Ziehau 		types |= RSS_TYPE_IPV6;
1449642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_IPV6_EX)
1450642ec226SSepherosa Ziehau 		types |= RSS_TYPE_IPV6_EX;
1451642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_TCP_IPV6)
1452642ec226SSepherosa Ziehau 		types |= RSS_TYPE_TCP_IPV6;
1453642ec226SSepherosa Ziehau 	if (rss_hash & NDIS_HASH_TCP_IPV6_EX)
1454642ec226SSepherosa Ziehau 		types |= RSS_TYPE_TCP_IPV6_EX;
14556f12c42eSSepherosa Ziehau 	if (rss_hash & NDIS_HASH_UDP_IPV4_X)
14566f12c42eSSepherosa Ziehau 		types |= RSS_TYPE_UDP_IPV4;
1457642ec226SSepherosa Ziehau 	return (types);
1458642ec226SSepherosa Ziehau }
1459642ec226SSepherosa Ziehau 
1460642ec226SSepherosa Ziehau static uint32_t
1461642ec226SSepherosa Ziehau hn_rss_type_tondis(uint32_t types)
1462642ec226SSepherosa Ziehau {
1463642ec226SSepherosa Ziehau 	uint32_t rss_hash = 0;
1464642ec226SSepherosa Ziehau 
14656f12c42eSSepherosa Ziehau 	KASSERT((types & (RSS_TYPE_UDP_IPV6 | RSS_TYPE_UDP_IPV6_EX)) == 0,
14666f12c42eSSepherosa Ziehau 	    ("UDP6 and UDP6EX are not supported"));
1467642ec226SSepherosa Ziehau 
1468642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_IPV4)
1469642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_IPV4;
1470642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_TCP_IPV4)
1471642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_TCP_IPV4;
1472642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_IPV6)
1473642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_IPV6;
1474642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_IPV6_EX)
1475642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_IPV6_EX;
1476642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_TCP_IPV6)
1477642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_TCP_IPV6;
1478642ec226SSepherosa Ziehau 	if (types & RSS_TYPE_TCP_IPV6_EX)
1479642ec226SSepherosa Ziehau 		rss_hash |= NDIS_HASH_TCP_IPV6_EX;
14806f12c42eSSepherosa Ziehau 	if (types & RSS_TYPE_UDP_IPV4)
14816f12c42eSSepherosa Ziehau 		rss_hash |= NDIS_HASH_UDP_IPV4_X;
1482642ec226SSepherosa Ziehau 	return (rss_hash);
1483642ec226SSepherosa Ziehau }
1484642ec226SSepherosa Ziehau 
1485642ec226SSepherosa Ziehau static void
1486642ec226SSepherosa Ziehau hn_rss_mbuf_hash(struct hn_softc *sc, uint32_t mbuf_hash)
1487642ec226SSepherosa Ziehau {
1488642ec226SSepherosa Ziehau 	int i;
1489642ec226SSepherosa Ziehau 
1490642ec226SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1491642ec226SSepherosa Ziehau 
1492642ec226SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1493642ec226SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_mbuf_hash = mbuf_hash;
1494642ec226SSepherosa Ziehau }
1495642ec226SSepherosa Ziehau 
1496642ec226SSepherosa Ziehau static void
1497642ec226SSepherosa Ziehau hn_vf_rss_fixup(struct hn_softc *sc, bool reconf)
1498642ec226SSepherosa Ziehau {
1499642ec226SSepherosa Ziehau 	struct ifnet *ifp, *vf_ifp;
1500642ec226SSepherosa Ziehau 	struct ifrsshash ifrh;
1501642ec226SSepherosa Ziehau 	struct ifrsskey ifrk;
1502642ec226SSepherosa Ziehau 	int error;
1503642ec226SSepherosa Ziehau 	uint32_t my_types, diff_types, mbuf_types = 0;
1504642ec226SSepherosa Ziehau 
1505642ec226SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1506642ec226SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
1507642ec226SSepherosa Ziehau 	    ("%s: synthetic parts are not attached", sc->hn_ifp->if_xname));
1508642ec226SSepherosa Ziehau 
1509642ec226SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
1510642ec226SSepherosa Ziehau 		/* No RSS on synthetic parts; done. */
1511642ec226SSepherosa Ziehau 		return;
1512642ec226SSepherosa Ziehau 	}
1513642ec226SSepherosa Ziehau 	if ((sc->hn_rss_hcap & NDIS_HASH_FUNCTION_TOEPLITZ) == 0) {
1514642ec226SSepherosa Ziehau 		/* Synthetic parts do not support Toeplitz; done. */
1515642ec226SSepherosa Ziehau 		return;
1516642ec226SSepherosa Ziehau 	}
1517642ec226SSepherosa Ziehau 
1518642ec226SSepherosa Ziehau 	ifp = sc->hn_ifp;
1519642ec226SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
1520642ec226SSepherosa Ziehau 
1521642ec226SSepherosa Ziehau 	/*
1522642ec226SSepherosa Ziehau 	 * Extract VF's RSS key.  Only 40 bytes key for Toeplitz is
1523642ec226SSepherosa Ziehau 	 * supported.
1524642ec226SSepherosa Ziehau 	 */
1525642ec226SSepherosa Ziehau 	memset(&ifrk, 0, sizeof(ifrk));
1526642ec226SSepherosa Ziehau 	strlcpy(ifrk.ifrk_name, vf_ifp->if_xname, sizeof(ifrk.ifrk_name));
1527642ec226SSepherosa Ziehau 	error = vf_ifp->if_ioctl(vf_ifp, SIOCGIFRSSKEY, (caddr_t)&ifrk);
1528642ec226SSepherosa Ziehau 	if (error) {
1529a3b413afSHans Petter Selasky 		if_printf(ifp, "%s SIOCGIFRSSKEY failed: %d\n",
1530642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, error);
1531642ec226SSepherosa Ziehau 		goto done;
1532642ec226SSepherosa Ziehau 	}
1533642ec226SSepherosa Ziehau 	if (ifrk.ifrk_func != RSS_FUNC_TOEPLITZ) {
1534642ec226SSepherosa Ziehau 		if_printf(ifp, "%s RSS function %u is not Toeplitz\n",
1535642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, ifrk.ifrk_func);
1536642ec226SSepherosa Ziehau 		goto done;
1537642ec226SSepherosa Ziehau 	}
1538642ec226SSepherosa Ziehau 	if (ifrk.ifrk_keylen != NDIS_HASH_KEYSIZE_TOEPLITZ) {
1539642ec226SSepherosa Ziehau 		if_printf(ifp, "%s invalid RSS Toeplitz key length %d\n",
1540642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, ifrk.ifrk_keylen);
1541642ec226SSepherosa Ziehau 		goto done;
1542642ec226SSepherosa Ziehau 	}
1543642ec226SSepherosa Ziehau 
1544642ec226SSepherosa Ziehau 	/*
1545642ec226SSepherosa Ziehau 	 * Extract VF's RSS hash.  Only Toeplitz is supported.
1546642ec226SSepherosa Ziehau 	 */
1547642ec226SSepherosa Ziehau 	memset(&ifrh, 0, sizeof(ifrh));
1548642ec226SSepherosa Ziehau 	strlcpy(ifrh.ifrh_name, vf_ifp->if_xname, sizeof(ifrh.ifrh_name));
1549642ec226SSepherosa Ziehau 	error = vf_ifp->if_ioctl(vf_ifp, SIOCGIFRSSHASH, (caddr_t)&ifrh);
1550642ec226SSepherosa Ziehau 	if (error) {
1551642ec226SSepherosa Ziehau 		if_printf(ifp, "%s SIOCGRSSHASH failed: %d\n",
1552642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, error);
1553642ec226SSepherosa Ziehau 		goto done;
1554642ec226SSepherosa Ziehau 	}
1555642ec226SSepherosa Ziehau 	if (ifrh.ifrh_func != RSS_FUNC_TOEPLITZ) {
1556642ec226SSepherosa Ziehau 		if_printf(ifp, "%s RSS function %u is not Toeplitz\n",
1557642ec226SSepherosa Ziehau 		    vf_ifp->if_xname, ifrh.ifrh_func);
1558642ec226SSepherosa Ziehau 		goto done;
1559642ec226SSepherosa Ziehau 	}
1560642ec226SSepherosa Ziehau 
1561642ec226SSepherosa Ziehau 	my_types = hn_rss_type_fromndis(sc->hn_rss_hcap);
1562642ec226SSepherosa Ziehau 	if ((ifrh.ifrh_types & my_types) == 0) {
1563642ec226SSepherosa Ziehau 		/* This disables RSS; ignore it then */
1564642ec226SSepherosa Ziehau 		if_printf(ifp, "%s intersection of RSS types failed.  "
1565642ec226SSepherosa Ziehau 		    "VF %#x, mine %#x\n", vf_ifp->if_xname,
1566642ec226SSepherosa Ziehau 		    ifrh.ifrh_types, my_types);
1567642ec226SSepherosa Ziehau 		goto done;
1568642ec226SSepherosa Ziehau 	}
1569642ec226SSepherosa Ziehau 
1570642ec226SSepherosa Ziehau 	diff_types = my_types ^ ifrh.ifrh_types;
1571642ec226SSepherosa Ziehau 	my_types &= ifrh.ifrh_types;
1572642ec226SSepherosa Ziehau 	mbuf_types = my_types;
1573642ec226SSepherosa Ziehau 
1574642ec226SSepherosa Ziehau 	/*
1575642ec226SSepherosa Ziehau 	 * Detect RSS hash value/type confliction.
1576642ec226SSepherosa Ziehau 	 *
1577642ec226SSepherosa Ziehau 	 * NOTE:
1578642ec226SSepherosa Ziehau 	 * We don't disable the hash type, but stop delivery the hash
1579642ec226SSepherosa Ziehau 	 * value/type through mbufs on RX path.
15806f12c42eSSepherosa Ziehau 	 *
15816f12c42eSSepherosa Ziehau 	 * XXX If HN_CAP_UDPHASH is set in hn_caps, then UDP 4-tuple
15826f12c42eSSepherosa Ziehau 	 * hash is delivered with type of TCP_IPV4.  This means if
15836f12c42eSSepherosa Ziehau 	 * UDP_IPV4 is enabled, then TCP_IPV4 should be forced, at
15846f12c42eSSepherosa Ziehau 	 * least to hn_mbuf_hash.  However, given that _all_ of the
15856f12c42eSSepherosa Ziehau 	 * NICs implement TCP_IPV4, this will _not_ impose any issues
15866f12c42eSSepherosa Ziehau 	 * here.
1587642ec226SSepherosa Ziehau 	 */
1588642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_IPV4) &&
1589642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types &
1590642ec226SSepherosa Ziehau 	     (RSS_TYPE_TCP_IPV4 | RSS_TYPE_UDP_IPV4))) {
1591642ec226SSepherosa Ziehau 		/* Conflict; disable IPV4 hash type/value delivery. */
1592642ec226SSepherosa Ziehau 		if_printf(ifp, "disable IPV4 mbuf hash delivery\n");
1593642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_IPV4;
1594642ec226SSepherosa Ziehau 	}
1595642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_IPV6) &&
1596642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types &
1597642ec226SSepherosa Ziehau 	     (RSS_TYPE_TCP_IPV6 | RSS_TYPE_UDP_IPV6 |
1598642ec226SSepherosa Ziehau 	      RSS_TYPE_TCP_IPV6_EX | RSS_TYPE_UDP_IPV6_EX |
1599642ec226SSepherosa Ziehau 	      RSS_TYPE_IPV6_EX))) {
1600642ec226SSepherosa Ziehau 		/* Conflict; disable IPV6 hash type/value delivery. */
1601642ec226SSepherosa Ziehau 		if_printf(ifp, "disable IPV6 mbuf hash delivery\n");
1602642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_IPV6;
1603642ec226SSepherosa Ziehau 	}
1604642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_IPV6_EX) &&
1605642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types &
1606642ec226SSepherosa Ziehau 	     (RSS_TYPE_TCP_IPV6 | RSS_TYPE_UDP_IPV6 |
1607642ec226SSepherosa Ziehau 	      RSS_TYPE_TCP_IPV6_EX | RSS_TYPE_UDP_IPV6_EX |
1608642ec226SSepherosa Ziehau 	      RSS_TYPE_IPV6))) {
1609642ec226SSepherosa Ziehau 		/* Conflict; disable IPV6_EX hash type/value delivery. */
1610642ec226SSepherosa Ziehau 		if_printf(ifp, "disable IPV6_EX mbuf hash delivery\n");
1611642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_IPV6_EX;
1612642ec226SSepherosa Ziehau 	}
1613642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_TCP_IPV6) &&
1614642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_TCP_IPV6_EX)) {
1615642ec226SSepherosa Ziehau 		/* Conflict; disable TCP_IPV6 hash type/value delivery. */
1616642ec226SSepherosa Ziehau 		if_printf(ifp, "disable TCP_IPV6 mbuf hash delivery\n");
1617642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_TCP_IPV6;
1618642ec226SSepherosa Ziehau 	}
1619642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_TCP_IPV6_EX) &&
1620642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_TCP_IPV6)) {
1621642ec226SSepherosa Ziehau 		/* Conflict; disable TCP_IPV6_EX hash type/value delivery. */
1622642ec226SSepherosa Ziehau 		if_printf(ifp, "disable TCP_IPV6_EX mbuf hash delivery\n");
1623642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_TCP_IPV6_EX;
1624642ec226SSepherosa Ziehau 	}
1625642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_UDP_IPV6) &&
1626642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_UDP_IPV6_EX)) {
1627642ec226SSepherosa Ziehau 		/* Conflict; disable UDP_IPV6 hash type/value delivery. */
1628642ec226SSepherosa Ziehau 		if_printf(ifp, "disable UDP_IPV6 mbuf hash delivery\n");
1629642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_UDP_IPV6;
1630642ec226SSepherosa Ziehau 	}
1631642ec226SSepherosa Ziehau 	if ((my_types & RSS_TYPE_UDP_IPV6_EX) &&
1632642ec226SSepherosa Ziehau 	    (diff_types & ifrh.ifrh_types & RSS_TYPE_UDP_IPV6)) {
1633642ec226SSepherosa Ziehau 		/* Conflict; disable UDP_IPV6_EX hash type/value delivery. */
1634642ec226SSepherosa Ziehau 		if_printf(ifp, "disable UDP_IPV6_EX mbuf hash delivery\n");
1635642ec226SSepherosa Ziehau 		mbuf_types &= ~RSS_TYPE_UDP_IPV6_EX;
1636642ec226SSepherosa Ziehau 	}
1637642ec226SSepherosa Ziehau 
1638642ec226SSepherosa Ziehau 	/*
1639642ec226SSepherosa Ziehau 	 * Indirect table does not matter.
1640642ec226SSepherosa Ziehau 	 */
1641642ec226SSepherosa Ziehau 
1642642ec226SSepherosa Ziehau 	sc->hn_rss_hash = (sc->hn_rss_hcap & NDIS_HASH_FUNCTION_MASK) |
1643642ec226SSepherosa Ziehau 	    hn_rss_type_tondis(my_types);
1644642ec226SSepherosa Ziehau 	memcpy(sc->hn_rss.rss_key, ifrk.ifrk_key, sizeof(sc->hn_rss.rss_key));
1645642ec226SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
1646642ec226SSepherosa Ziehau 
1647642ec226SSepherosa Ziehau 	if (reconf) {
1648642ec226SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
1649642ec226SSepherosa Ziehau 		if (error) {
1650642ec226SSepherosa Ziehau 			/* XXX roll-back? */
1651642ec226SSepherosa Ziehau 			if_printf(ifp, "hn_rss_reconfig failed: %d\n", error);
1652642ec226SSepherosa Ziehau 			/* XXX keep going. */
1653642ec226SSepherosa Ziehau 		}
1654642ec226SSepherosa Ziehau 	}
1655642ec226SSepherosa Ziehau done:
1656642ec226SSepherosa Ziehau 	/* Hash deliverability for mbufs. */
1657642ec226SSepherosa Ziehau 	hn_rss_mbuf_hash(sc, hn_rss_type_tondis(mbuf_types));
1658642ec226SSepherosa Ziehau }
1659642ec226SSepherosa Ziehau 
1660642ec226SSepherosa Ziehau static void
1661642ec226SSepherosa Ziehau hn_vf_rss_restore(struct hn_softc *sc)
1662642ec226SSepherosa Ziehau {
1663642ec226SSepherosa Ziehau 
1664642ec226SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1665642ec226SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
1666642ec226SSepherosa Ziehau 	    ("%s: synthetic parts are not attached", sc->hn_ifp->if_xname));
1667642ec226SSepherosa Ziehau 
1668642ec226SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1)
1669642ec226SSepherosa Ziehau 		goto done;
1670642ec226SSepherosa Ziehau 
1671642ec226SSepherosa Ziehau 	/*
1672642ec226SSepherosa Ziehau 	 * Restore hash types.  Key does _not_ matter.
1673642ec226SSepherosa Ziehau 	 */
1674642ec226SSepherosa Ziehau 	if (sc->hn_rss_hash != sc->hn_rss_hcap) {
1675642ec226SSepherosa Ziehau 		int error;
1676642ec226SSepherosa Ziehau 
1677642ec226SSepherosa Ziehau 		sc->hn_rss_hash = sc->hn_rss_hcap;
1678642ec226SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
1679642ec226SSepherosa Ziehau 		if (error) {
1680642ec226SSepherosa Ziehau 			if_printf(sc->hn_ifp, "hn_rss_reconfig failed: %d\n",
1681642ec226SSepherosa Ziehau 			    error);
1682642ec226SSepherosa Ziehau 			/* XXX keep going. */
1683642ec226SSepherosa Ziehau 		}
1684642ec226SSepherosa Ziehau 	}
1685642ec226SSepherosa Ziehau done:
1686642ec226SSepherosa Ziehau 	/* Hash deliverability for mbufs. */
1687642ec226SSepherosa Ziehau 	hn_rss_mbuf_hash(sc, NDIS_HASH_ALL);
1688642ec226SSepherosa Ziehau }
1689642ec226SSepherosa Ziehau 
16909c6cae24SSepherosa Ziehau static void
16919c6cae24SSepherosa Ziehau hn_xpnt_vf_setready(struct hn_softc *sc)
16929c6cae24SSepherosa Ziehau {
16939c6cae24SSepherosa Ziehau 	struct ifnet *ifp, *vf_ifp;
16949c6cae24SSepherosa Ziehau 	struct ifreq ifr;
16959c6cae24SSepherosa Ziehau 
16969c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
16979c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
16989c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
16999c6cae24SSepherosa Ziehau 
17009c6cae24SSepherosa Ziehau 	/*
17019c6cae24SSepherosa Ziehau 	 * Mark the VF ready.
17029c6cae24SSepherosa Ziehau 	 */
17039c6cae24SSepherosa Ziehau 	sc->hn_vf_rdytick = 0;
17049c6cae24SSepherosa Ziehau 
17059c6cae24SSepherosa Ziehau 	/*
17069c6cae24SSepherosa Ziehau 	 * Save information for restoration.
17079c6cae24SSepherosa Ziehau 	 */
17089c6cae24SSepherosa Ziehau 	sc->hn_saved_caps = ifp->if_capabilities;
17099c6cae24SSepherosa Ziehau 	sc->hn_saved_tsomax = ifp->if_hw_tsomax;
17109c6cae24SSepherosa Ziehau 	sc->hn_saved_tsosegcnt = ifp->if_hw_tsomaxsegcount;
17119c6cae24SSepherosa Ziehau 	sc->hn_saved_tsosegsz = ifp->if_hw_tsomaxsegsize;
17129c6cae24SSepherosa Ziehau 
17139c6cae24SSepherosa Ziehau 	/*
17149c6cae24SSepherosa Ziehau 	 * Intersect supported/enabled capabilities.
17159c6cae24SSepherosa Ziehau 	 *
17169c6cae24SSepherosa Ziehau 	 * NOTE:
17179c6cae24SSepherosa Ziehau 	 * if_hwassist is not changed here.
17189c6cae24SSepherosa Ziehau 	 */
17199c6cae24SSepherosa Ziehau 	ifp->if_capabilities &= vf_ifp->if_capabilities;
17209c6cae24SSepherosa Ziehau 	ifp->if_capenable &= ifp->if_capabilities;
17219c6cae24SSepherosa Ziehau 
17229c6cae24SSepherosa Ziehau 	/*
17239c6cae24SSepherosa Ziehau 	 * Fix TSO settings.
17249c6cae24SSepherosa Ziehau 	 */
17259c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomax > vf_ifp->if_hw_tsomax)
17269c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomax = vf_ifp->if_hw_tsomax;
17279c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomaxsegcount > vf_ifp->if_hw_tsomaxsegcount)
17289c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = vf_ifp->if_hw_tsomaxsegcount;
17299c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomaxsegsize > vf_ifp->if_hw_tsomaxsegsize)
17309c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = vf_ifp->if_hw_tsomaxsegsize;
17319c6cae24SSepherosa Ziehau 
17329c6cae24SSepherosa Ziehau 	/*
17339c6cae24SSepherosa Ziehau 	 * Change VF's enabled capabilities.
17349c6cae24SSepherosa Ziehau 	 */
17359c6cae24SSepherosa Ziehau 	memset(&ifr, 0, sizeof(ifr));
17369c6cae24SSepherosa Ziehau 	strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
17379c6cae24SSepherosa Ziehau 	ifr.ifr_reqcap = ifp->if_capenable;
17389c6cae24SSepherosa Ziehau 	hn_xpnt_vf_iocsetcaps(sc, &ifr);
17399c6cae24SSepherosa Ziehau 
17409c6cae24SSepherosa Ziehau 	if (ifp->if_mtu != ETHERMTU) {
17419c6cae24SSepherosa Ziehau 		int error;
17429c6cae24SSepherosa Ziehau 
17439c6cae24SSepherosa Ziehau 		/*
17449c6cae24SSepherosa Ziehau 		 * Change VF's MTU.
17459c6cae24SSepherosa Ziehau 		 */
17469c6cae24SSepherosa Ziehau 		memset(&ifr, 0, sizeof(ifr));
17479c6cae24SSepherosa Ziehau 		strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
17489c6cae24SSepherosa Ziehau 		ifr.ifr_mtu = ifp->if_mtu;
17499c6cae24SSepherosa Ziehau 		error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU, (caddr_t)&ifr);
17509c6cae24SSepherosa Ziehau 		if (error) {
17519c6cae24SSepherosa Ziehau 			if_printf(ifp, "%s SIOCSIFMTU %u failed\n",
17529c6cae24SSepherosa Ziehau 			    vf_ifp->if_xname, ifp->if_mtu);
17539c6cae24SSepherosa Ziehau 			if (ifp->if_mtu > ETHERMTU) {
17549c6cae24SSepherosa Ziehau 				if_printf(ifp, "change MTU to %d\n", ETHERMTU);
17559c6cae24SSepherosa Ziehau 
17569c6cae24SSepherosa Ziehau 				/*
17579c6cae24SSepherosa Ziehau 				 * XXX
17589c6cae24SSepherosa Ziehau 				 * No need to adjust the synthetic parts' MTU;
17599c6cae24SSepherosa Ziehau 				 * failure of the adjustment will cause us
17609c6cae24SSepherosa Ziehau 				 * infinite headache.
17619c6cae24SSepherosa Ziehau 				 */
17629c6cae24SSepherosa Ziehau 				ifp->if_mtu = ETHERMTU;
17639c6cae24SSepherosa Ziehau 				hn_mtu_change_fixup(sc);
17649c6cae24SSepherosa Ziehau 			}
17659c6cae24SSepherosa Ziehau 		}
17669c6cae24SSepherosa Ziehau 	}
17679c6cae24SSepherosa Ziehau }
17689c6cae24SSepherosa Ziehau 
17699c6cae24SSepherosa Ziehau static bool
17709c6cae24SSepherosa Ziehau hn_xpnt_vf_isready(struct hn_softc *sc)
17719c6cae24SSepherosa Ziehau {
17729c6cae24SSepherosa Ziehau 
17739c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
17749c6cae24SSepherosa Ziehau 
17759c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf || sc->hn_vf_ifp == NULL)
17769c6cae24SSepherosa Ziehau 		return (false);
17779c6cae24SSepherosa Ziehau 
17789c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick == 0)
17799c6cae24SSepherosa Ziehau 		return (true);
17809c6cae24SSepherosa Ziehau 
17819c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick > ticks)
17829c6cae24SSepherosa Ziehau 		return (false);
17839c6cae24SSepherosa Ziehau 
17849c6cae24SSepherosa Ziehau 	/* Mark VF as ready. */
17859c6cae24SSepherosa Ziehau 	hn_xpnt_vf_setready(sc);
17869c6cae24SSepherosa Ziehau 	return (true);
17879c6cae24SSepherosa Ziehau }
17889c6cae24SSepherosa Ziehau 
17899c6cae24SSepherosa Ziehau static void
1790a97fff19SSepherosa Ziehau hn_xpnt_vf_setenable(struct hn_softc *sc)
1791a97fff19SSepherosa Ziehau {
1792a97fff19SSepherosa Ziehau 	int i;
1793a97fff19SSepherosa Ziehau 
1794a97fff19SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1795a97fff19SSepherosa Ziehau 
1796a97fff19SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
1797a97fff19SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
1798a97fff19SSepherosa Ziehau 	sc->hn_xvf_flags |= HN_XVFFLAG_ENABLED;
1799a97fff19SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
1800a97fff19SSepherosa Ziehau 
1801a97fff19SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1802a97fff19SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_rx_flags |= HN_RX_FLAG_XPNT_VF;
1803a97fff19SSepherosa Ziehau }
1804a97fff19SSepherosa Ziehau 
1805a97fff19SSepherosa Ziehau static void
1806a97fff19SSepherosa Ziehau hn_xpnt_vf_setdisable(struct hn_softc *sc, bool clear_vf)
1807a97fff19SSepherosa Ziehau {
1808a97fff19SSepherosa Ziehau 	int i;
1809a97fff19SSepherosa Ziehau 
1810a97fff19SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1811a97fff19SSepherosa Ziehau 
1812a97fff19SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
1813a97fff19SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
1814a97fff19SSepherosa Ziehau 	sc->hn_xvf_flags &= ~HN_XVFFLAG_ENABLED;
1815a97fff19SSepherosa Ziehau 	if (clear_vf)
1816a97fff19SSepherosa Ziehau 		sc->hn_vf_ifp = NULL;
1817a97fff19SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
1818a97fff19SSepherosa Ziehau 
1819a97fff19SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1820a97fff19SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_rx_flags &= ~HN_RX_FLAG_XPNT_VF;
1821a97fff19SSepherosa Ziehau }
1822a97fff19SSepherosa Ziehau 
1823a97fff19SSepherosa Ziehau static void
18249c6cae24SSepherosa Ziehau hn_xpnt_vf_init(struct hn_softc *sc)
18259c6cae24SSepherosa Ziehau {
18269c6cae24SSepherosa Ziehau 	int error;
18279c6cae24SSepherosa Ziehau 
18289c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
18299c6cae24SSepherosa Ziehau 
18309c6cae24SSepherosa Ziehau 	KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0,
18319c6cae24SSepherosa Ziehau 	    ("%s: transparent VF was enabled", sc->hn_ifp->if_xname));
18329c6cae24SSepherosa Ziehau 
18339c6cae24SSepherosa Ziehau 	if (bootverbose) {
18349c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "try bringing up %s\n",
18359c6cae24SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname);
18369c6cae24SSepherosa Ziehau 	}
18379c6cae24SSepherosa Ziehau 
18389c6cae24SSepherosa Ziehau 	/*
18399c6cae24SSepherosa Ziehau 	 * Bring the VF up.
18409c6cae24SSepherosa Ziehau 	 */
18419c6cae24SSepherosa Ziehau 	hn_xpnt_vf_saveifflags(sc);
18429c6cae24SSepherosa Ziehau 	sc->hn_vf_ifp->if_flags |= IFF_UP;
18439c6cae24SSepherosa Ziehau 	error = hn_xpnt_vf_iocsetflags(sc);
18449c6cae24SSepherosa Ziehau 	if (error) {
18459c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "bringing up %s failed: %d\n",
18469c6cae24SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname, error);
18479c6cae24SSepherosa Ziehau 		return;
18489c6cae24SSepherosa Ziehau 	}
18499c6cae24SSepherosa Ziehau 
18509c6cae24SSepherosa Ziehau 	/*
18519c6cae24SSepherosa Ziehau 	 * NOTE:
18529c6cae24SSepherosa Ziehau 	 * Datapath setting must happen _after_ bringing the VF up.
18539c6cae24SSepherosa Ziehau 	 */
18549c6cae24SSepherosa Ziehau 	hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF);
18559c6cae24SSepherosa Ziehau 
1856642ec226SSepherosa Ziehau 	/*
1857642ec226SSepherosa Ziehau 	 * NOTE:
1858642ec226SSepherosa Ziehau 	 * Fixup RSS related bits _after_ the VF is brought up, since
1859642ec226SSepherosa Ziehau 	 * many VFs generate RSS key during it's initialization.
1860642ec226SSepherosa Ziehau 	 */
1861642ec226SSepherosa Ziehau 	hn_vf_rss_fixup(sc, true);
1862642ec226SSepherosa Ziehau 
1863a97fff19SSepherosa Ziehau 	/* Mark transparent mode VF as enabled. */
1864a97fff19SSepherosa Ziehau 	hn_xpnt_vf_setenable(sc);
18659c6cae24SSepherosa Ziehau }
18669c6cae24SSepherosa Ziehau 
18679c6cae24SSepherosa Ziehau static void
18689c6cae24SSepherosa Ziehau hn_xpnt_vf_init_taskfunc(void *xsc, int pending __unused)
18699c6cae24SSepherosa Ziehau {
18709c6cae24SSepherosa Ziehau 	struct hn_softc *sc = xsc;
18719c6cae24SSepherosa Ziehau 
18729c6cae24SSepherosa Ziehau 	HN_LOCK(sc);
18739c6cae24SSepherosa Ziehau 
18749c6cae24SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
18759c6cae24SSepherosa Ziehau 		goto done;
18769c6cae24SSepherosa Ziehau 	if (sc->hn_vf_ifp == NULL)
18779c6cae24SSepherosa Ziehau 		goto done;
18789c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
18799c6cae24SSepherosa Ziehau 		goto done;
18809c6cae24SSepherosa Ziehau 
18819c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick != 0) {
18829c6cae24SSepherosa Ziehau 		/* Mark VF as ready. */
18839c6cae24SSepherosa Ziehau 		hn_xpnt_vf_setready(sc);
18849c6cae24SSepherosa Ziehau 	}
18859c6cae24SSepherosa Ziehau 
18869c6cae24SSepherosa Ziehau 	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) {
18879c6cae24SSepherosa Ziehau 		/*
18889c6cae24SSepherosa Ziehau 		 * Delayed VF initialization.
18899c6cae24SSepherosa Ziehau 		 */
18909c6cae24SSepherosa Ziehau 		if (bootverbose) {
18919c6cae24SSepherosa Ziehau 			if_printf(sc->hn_ifp, "delayed initialize %s\n",
18929c6cae24SSepherosa Ziehau 			    sc->hn_vf_ifp->if_xname);
18939c6cae24SSepherosa Ziehau 		}
18949c6cae24SSepherosa Ziehau 		hn_xpnt_vf_init(sc);
18959c6cae24SSepherosa Ziehau 	}
18969c6cae24SSepherosa Ziehau done:
18979c6cae24SSepherosa Ziehau 	HN_UNLOCK(sc);
18989c6cae24SSepherosa Ziehau }
18999c6cae24SSepherosa Ziehau 
1900499c3e17SSepherosa Ziehau static void
1901499c3e17SSepherosa Ziehau hn_ifnet_attevent(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_flags & HN_FLAG_SYNTH_ATTACHED))
1908499c3e17SSepherosa Ziehau 		goto done;
1909499c3e17SSepherosa Ziehau 
1910499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1911499c3e17SSepherosa Ziehau 		goto done;
1912499c3e17SSepherosa Ziehau 
1913499c3e17SSepherosa Ziehau 	if (sc->hn_vf_ifp != NULL) {
1914499c3e17SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%s was attached as VF\n",
1915499c3e17SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname);
1916499c3e17SSepherosa Ziehau 		goto done;
1917499c3e17SSepherosa Ziehau 	}
1918499c3e17SSepherosa Ziehau 
19199c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && ifp->if_start != NULL) {
19209c6cae24SSepherosa Ziehau 		/*
19219c6cae24SSepherosa Ziehau 		 * ifnet.if_start is _not_ supported by transparent
19229c6cae24SSepherosa Ziehau 		 * mode VF; mainly due to the IFF_DRV_OACTIVE flag.
19239c6cae24SSepherosa Ziehau 		 */
19249c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%s uses if_start, which is unsupported "
19259c6cae24SSepherosa Ziehau 		    "in transparent VF mode.\n", ifp->if_xname);
19269c6cae24SSepherosa Ziehau 		goto done;
19279c6cae24SSepherosa Ziehau 	}
19289c6cae24SSepherosa Ziehau 
1929499c3e17SSepherosa Ziehau 	rm_wlock(&hn_vfmap_lock);
1930499c3e17SSepherosa Ziehau 
1931499c3e17SSepherosa Ziehau 	if (ifp->if_index >= hn_vfmap_size) {
1932499c3e17SSepherosa Ziehau 		struct ifnet **newmap;
1933499c3e17SSepherosa Ziehau 		int newsize;
1934499c3e17SSepherosa Ziehau 
1935499c3e17SSepherosa Ziehau 		newsize = ifp->if_index + HN_VFMAP_SIZE_DEF;
1936499c3e17SSepherosa Ziehau 		newmap = malloc(sizeof(struct ifnet *) * newsize, M_DEVBUF,
1937499c3e17SSepherosa Ziehau 		    M_WAITOK | M_ZERO);
1938499c3e17SSepherosa Ziehau 
1939499c3e17SSepherosa Ziehau 		memcpy(newmap, hn_vfmap,
1940499c3e17SSepherosa Ziehau 		    sizeof(struct ifnet *) * hn_vfmap_size);
1941499c3e17SSepherosa Ziehau 		free(hn_vfmap, M_DEVBUF);
1942499c3e17SSepherosa Ziehau 		hn_vfmap = newmap;
1943499c3e17SSepherosa Ziehau 		hn_vfmap_size = newsize;
1944499c3e17SSepherosa Ziehau 	}
1945499c3e17SSepherosa Ziehau 	KASSERT(hn_vfmap[ifp->if_index] == NULL,
1946499c3e17SSepherosa Ziehau 	    ("%s: ifindex %d was mapped to %s",
1947499c3e17SSepherosa Ziehau 	     ifp->if_xname, ifp->if_index, hn_vfmap[ifp->if_index]->if_xname));
1948499c3e17SSepherosa Ziehau 	hn_vfmap[ifp->if_index] = sc->hn_ifp;
1949499c3e17SSepherosa Ziehau 
1950499c3e17SSepherosa Ziehau 	rm_wunlock(&hn_vfmap_lock);
1951499c3e17SSepherosa Ziehau 
19529c6cae24SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
19539c6cae24SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
19549c6cae24SSepherosa Ziehau 	KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0,
19559c6cae24SSepherosa Ziehau 	    ("%s: transparent VF was enabled", sc->hn_ifp->if_xname));
1956499c3e17SSepherosa Ziehau 	sc->hn_vf_ifp = ifp;
19579c6cae24SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
19589c6cae24SSepherosa Ziehau 
19599c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
19609c6cae24SSepherosa Ziehau 		int wait_ticks;
19619c6cae24SSepherosa Ziehau 
19629c6cae24SSepherosa Ziehau 		/*
19639c6cae24SSepherosa Ziehau 		 * Install if_input for vf_ifp, which does vf_ifp -> hn_ifp.
19649c6cae24SSepherosa Ziehau 		 * Save vf_ifp's current if_input for later restoration.
19659c6cae24SSepherosa Ziehau 		 */
19669c6cae24SSepherosa Ziehau 		sc->hn_vf_input = ifp->if_input;
19679c6cae24SSepherosa Ziehau 		ifp->if_input = hn_xpnt_vf_input;
19689c6cae24SSepherosa Ziehau 
19699c6cae24SSepherosa Ziehau 		/*
19709c6cae24SSepherosa Ziehau 		 * Stop link status management; use the VF's.
19719c6cae24SSepherosa Ziehau 		 */
19729c6cae24SSepherosa Ziehau 		hn_suspend_mgmt(sc);
19739c6cae24SSepherosa Ziehau 
19749c6cae24SSepherosa Ziehau 		/*
19759c6cae24SSepherosa Ziehau 		 * Give VF sometime to complete its attach routing.
19769c6cae24SSepherosa Ziehau 		 */
19779c6cae24SSepherosa Ziehau 		wait_ticks = hn_xpnt_vf_attwait * hz;
19789c6cae24SSepherosa Ziehau 		sc->hn_vf_rdytick = ticks + wait_ticks;
19799c6cae24SSepherosa Ziehau 
19809c6cae24SSepherosa Ziehau 		taskqueue_enqueue_timeout(sc->hn_vf_taskq, &sc->hn_vf_init,
19819c6cae24SSepherosa Ziehau 		    wait_ticks);
19829c6cae24SSepherosa Ziehau 	}
1983499c3e17SSepherosa Ziehau done:
1984499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
1985499c3e17SSepherosa Ziehau }
1986499c3e17SSepherosa Ziehau 
1987499c3e17SSepherosa Ziehau static void
1988499c3e17SSepherosa Ziehau hn_ifnet_detevent(void *xsc, struct ifnet *ifp)
1989499c3e17SSepherosa Ziehau {
1990499c3e17SSepherosa Ziehau 	struct hn_softc *sc = xsc;
1991499c3e17SSepherosa Ziehau 
1992499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
1993499c3e17SSepherosa Ziehau 
1994499c3e17SSepherosa Ziehau 	if (sc->hn_vf_ifp == NULL)
1995499c3e17SSepherosa Ziehau 		goto done;
1996499c3e17SSepherosa Ziehau 
1997499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1998499c3e17SSepherosa Ziehau 		goto done;
1999499c3e17SSepherosa Ziehau 
20009c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
20019c6cae24SSepherosa Ziehau 		/*
20029c6cae24SSepherosa Ziehau 		 * Make sure that the delayed initialization is not running.
20039c6cae24SSepherosa Ziehau 		 *
20049c6cae24SSepherosa Ziehau 		 * NOTE:
20059c6cae24SSepherosa Ziehau 		 * - This lock _must_ be released, since the hn_vf_init task
20069c6cae24SSepherosa Ziehau 		 *   will try holding this lock.
20079c6cae24SSepherosa Ziehau 		 * - It is safe to release this lock here, since the
20089c6cae24SSepherosa Ziehau 		 *   hn_ifnet_attevent() is interlocked by the hn_vf_ifp.
20099c6cae24SSepherosa Ziehau 		 *
20109c6cae24SSepherosa Ziehau 		 * XXX racy, if hn(4) ever detached.
20119c6cae24SSepherosa Ziehau 		 */
20129c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
20139c6cae24SSepherosa Ziehau 		taskqueue_drain_timeout(sc->hn_vf_taskq, &sc->hn_vf_init);
20149c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
20159c6cae24SSepherosa Ziehau 
20169c6cae24SSepherosa Ziehau 		KASSERT(sc->hn_vf_input != NULL, ("%s VF input is not saved",
20179c6cae24SSepherosa Ziehau 		    sc->hn_ifp->if_xname));
20189c6cae24SSepherosa Ziehau 		ifp->if_input = sc->hn_vf_input;
20199c6cae24SSepherosa Ziehau 		sc->hn_vf_input = NULL;
20209c6cae24SSepherosa Ziehau 
2021642ec226SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) &&
2022642ec226SSepherosa Ziehau 		    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED))
20239c6cae24SSepherosa Ziehau 			hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH);
20249c6cae24SSepherosa Ziehau 
20259c6cae24SSepherosa Ziehau 		if (sc->hn_vf_rdytick == 0) {
20269c6cae24SSepherosa Ziehau 			/*
20279c6cae24SSepherosa Ziehau 			 * The VF was ready; restore some settings.
20289c6cae24SSepherosa Ziehau 			 */
20299c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_capabilities = sc->hn_saved_caps;
20309c6cae24SSepherosa Ziehau 			/*
20319c6cae24SSepherosa Ziehau 			 * NOTE:
20329c6cae24SSepherosa Ziehau 			 * There is _no_ need to fixup if_capenable and
20339c6cae24SSepherosa Ziehau 			 * if_hwassist, since the if_capabilities before
20349c6cae24SSepherosa Ziehau 			 * restoration was an intersection of the VF's
20359c6cae24SSepherosa Ziehau 			 * if_capabilites and the synthetic device's
20369c6cae24SSepherosa Ziehau 			 * if_capabilites.
20379c6cae24SSepherosa Ziehau 			 */
20389c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomax = sc->hn_saved_tsomax;
20399c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomaxsegcount =
20409c6cae24SSepherosa Ziehau 			    sc->hn_saved_tsosegcnt;
20419c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomaxsegsize = sc->hn_saved_tsosegsz;
20429c6cae24SSepherosa Ziehau 		}
20439c6cae24SSepherosa Ziehau 
2044642ec226SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
2045642ec226SSepherosa Ziehau 			/*
2046642ec226SSepherosa Ziehau 			 * Restore RSS settings.
2047642ec226SSepherosa Ziehau 			 */
2048642ec226SSepherosa Ziehau 			hn_vf_rss_restore(sc);
2049642ec226SSepherosa Ziehau 
20509c6cae24SSepherosa Ziehau 			/*
20519c6cae24SSepherosa Ziehau 			 * Resume link status management, which was suspended
20529c6cae24SSepherosa Ziehau 			 * by hn_ifnet_attevent().
20539c6cae24SSepherosa Ziehau 			 */
20549c6cae24SSepherosa Ziehau 			hn_resume_mgmt(sc);
20559c6cae24SSepherosa Ziehau 		}
2056642ec226SSepherosa Ziehau 	}
20579c6cae24SSepherosa Ziehau 
2058a97fff19SSepherosa Ziehau 	/* Mark transparent mode VF as disabled. */
2059a97fff19SSepherosa Ziehau 	hn_xpnt_vf_setdisable(sc, true /* clear hn_vf_ifp */);
2060499c3e17SSepherosa Ziehau 
2061499c3e17SSepherosa Ziehau 	rm_wlock(&hn_vfmap_lock);
2062499c3e17SSepherosa Ziehau 
2063499c3e17SSepherosa Ziehau 	KASSERT(ifp->if_index < hn_vfmap_size,
2064499c3e17SSepherosa Ziehau 	    ("ifindex %d, vfmapsize %d", ifp->if_index, hn_vfmap_size));
2065499c3e17SSepherosa Ziehau 	if (hn_vfmap[ifp->if_index] != NULL) {
2066499c3e17SSepherosa Ziehau 		KASSERT(hn_vfmap[ifp->if_index] == sc->hn_ifp,
2067499c3e17SSepherosa Ziehau 		    ("%s: ifindex %d was mapped to %s",
2068499c3e17SSepherosa Ziehau 		     ifp->if_xname, ifp->if_index,
2069499c3e17SSepherosa Ziehau 		     hn_vfmap[ifp->if_index]->if_xname));
2070499c3e17SSepherosa Ziehau 		hn_vfmap[ifp->if_index] = NULL;
2071499c3e17SSepherosa Ziehau 	}
2072499c3e17SSepherosa Ziehau 
2073499c3e17SSepherosa Ziehau 	rm_wunlock(&hn_vfmap_lock);
2074499c3e17SSepherosa Ziehau done:
2075499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
2076499c3e17SSepherosa Ziehau }
2077499c3e17SSepherosa Ziehau 
20789c6cae24SSepherosa Ziehau static void
20799c6cae24SSepherosa Ziehau hn_ifnet_lnkevent(void *xsc, struct ifnet *ifp, int link_state)
20809c6cae24SSepherosa Ziehau {
20819c6cae24SSepherosa Ziehau 	struct hn_softc *sc = xsc;
20829c6cae24SSepherosa Ziehau 
20839c6cae24SSepherosa Ziehau 	if (sc->hn_vf_ifp == ifp)
20849c6cae24SSepherosa Ziehau 		if_link_state_change(sc->hn_ifp, link_state);
20859c6cae24SSepherosa Ziehau }
20869c6cae24SSepherosa Ziehau 
208715516c77SSepherosa Ziehau static int
208815516c77SSepherosa Ziehau hn_probe(device_t dev)
208915516c77SSepherosa Ziehau {
209015516c77SSepherosa Ziehau 
2091c2d50b26SSepherosa Ziehau 	if (VMBUS_PROBE_GUID(device_get_parent(dev), dev, &hn_guid) == 0) {
209215516c77SSepherosa Ziehau 		device_set_desc(dev, "Hyper-V Network Interface");
209315516c77SSepherosa Ziehau 		return BUS_PROBE_DEFAULT;
209415516c77SSepherosa Ziehau 	}
209515516c77SSepherosa Ziehau 	return ENXIO;
209615516c77SSepherosa Ziehau }
209715516c77SSepherosa Ziehau 
209815516c77SSepherosa Ziehau static int
209915516c77SSepherosa Ziehau hn_attach(device_t dev)
210015516c77SSepherosa Ziehau {
210115516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
210215516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
210315516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
210415516c77SSepherosa Ziehau 	uint8_t eaddr[ETHER_ADDR_LEN];
210515516c77SSepherosa Ziehau 	struct ifnet *ifp = NULL;
210615516c77SSepherosa Ziehau 	int error, ring_cnt, tx_ring_cnt;
2107eb2fe044SSepherosa Ziehau 	uint32_t mtu;
210815516c77SSepherosa Ziehau 
210915516c77SSepherosa Ziehau 	sc->hn_dev = dev;
211015516c77SSepherosa Ziehau 	sc->hn_prichan = vmbus_get_channel(dev);
211115516c77SSepherosa Ziehau 	HN_LOCK_INIT(sc);
21129c6cae24SSepherosa Ziehau 	rm_init(&sc->hn_vf_lock, "hnvf");
21139c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && hn_xpnt_vf_accbpf)
21149c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF;
211515516c77SSepherosa Ziehau 
211615516c77SSepherosa Ziehau 	/*
2117dc13fee6SSepherosa Ziehau 	 * Initialize these tunables once.
2118dc13fee6SSepherosa Ziehau 	 */
2119dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = hn_tx_agg_size;
2120dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = hn_tx_agg_pkts;
2121dc13fee6SSepherosa Ziehau 
2122dc13fee6SSepherosa Ziehau 	/*
212315516c77SSepherosa Ziehau 	 * Setup taskqueue for transmission.
212415516c77SSepherosa Ziehau 	 */
21250e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_INDEP) {
2126fdd0222aSSepherosa Ziehau 		int i;
2127fdd0222aSSepherosa Ziehau 
2128fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs =
2129fdd0222aSSepherosa Ziehau 		    malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
2130fdd0222aSSepherosa Ziehau 		    M_DEVBUF, M_WAITOK);
2131fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i) {
2132fdd0222aSSepherosa Ziehau 			sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx",
2133fdd0222aSSepherosa Ziehau 			    M_WAITOK, taskqueue_thread_enqueue,
2134fdd0222aSSepherosa Ziehau 			    &sc->hn_tx_taskqs[i]);
2135fdd0222aSSepherosa Ziehau 			taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET,
2136fdd0222aSSepherosa Ziehau 			    "%s tx%d", device_get_nameunit(dev), i);
2137fdd0222aSSepherosa Ziehau 		}
21380e11868dSSepherosa Ziehau 	} else if (hn_tx_taskq_mode == HN_TX_TASKQ_M_GLOBAL) {
2139fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs = hn_tx_taskque;
214015516c77SSepherosa Ziehau 	}
214115516c77SSepherosa Ziehau 
214215516c77SSepherosa Ziehau 	/*
214315516c77SSepherosa Ziehau 	 * Setup taskqueue for mangement tasks, e.g. link status.
214415516c77SSepherosa Ziehau 	 */
214515516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK,
214615516c77SSepherosa Ziehau 	    taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0);
214715516c77SSepherosa Ziehau 	taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
214815516c77SSepherosa Ziehau 	    device_get_nameunit(dev));
214915516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
215015516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc);
215115516c77SSepherosa Ziehau 	TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0,
215215516c77SSepherosa Ziehau 	    hn_netchg_status_taskfunc, sc);
215315516c77SSepherosa Ziehau 
21549c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
21559c6cae24SSepherosa Ziehau 		/*
21569c6cae24SSepherosa Ziehau 		 * Setup taskqueue for VF tasks, e.g. delayed VF bringing up.
21579c6cae24SSepherosa Ziehau 		 */
21589c6cae24SSepherosa Ziehau 		sc->hn_vf_taskq = taskqueue_create("hn_vf", M_WAITOK,
21599c6cae24SSepherosa Ziehau 		    taskqueue_thread_enqueue, &sc->hn_vf_taskq);
21609c6cae24SSepherosa Ziehau 		taskqueue_start_threads(&sc->hn_vf_taskq, 1, PI_NET, "%s vf",
21619c6cae24SSepherosa Ziehau 		    device_get_nameunit(dev));
21629c6cae24SSepherosa Ziehau 		TIMEOUT_TASK_INIT(sc->hn_vf_taskq, &sc->hn_vf_init, 0,
21639c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_init_taskfunc, sc);
21649c6cae24SSepherosa Ziehau 	}
21659c6cae24SSepherosa Ziehau 
216615516c77SSepherosa Ziehau 	/*
216715516c77SSepherosa Ziehau 	 * Allocate ifnet and setup its name earlier, so that if_printf
216815516c77SSepherosa Ziehau 	 * can be used by functions, which will be called after
216915516c77SSepherosa Ziehau 	 * ether_ifattach().
217015516c77SSepherosa Ziehau 	 */
217115516c77SSepherosa Ziehau 	ifp = sc->hn_ifp = if_alloc(IFT_ETHER);
217215516c77SSepherosa Ziehau 	ifp->if_softc = sc;
217315516c77SSepherosa Ziehau 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
217415516c77SSepherosa Ziehau 
217515516c77SSepherosa Ziehau 	/*
217615516c77SSepherosa Ziehau 	 * Initialize ifmedia earlier so that it can be unconditionally
217715516c77SSepherosa Ziehau 	 * destroyed, if error happened later on.
217815516c77SSepherosa Ziehau 	 */
217915516c77SSepherosa Ziehau 	ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts);
218015516c77SSepherosa Ziehau 
218115516c77SSepherosa Ziehau 	/*
218215516c77SSepherosa Ziehau 	 * Figure out the # of RX rings (ring_cnt) and the # of TX rings
218315516c77SSepherosa Ziehau 	 * to use (tx_ring_cnt).
218415516c77SSepherosa Ziehau 	 *
218515516c77SSepherosa Ziehau 	 * NOTE:
218615516c77SSepherosa Ziehau 	 * The # of RX rings to use is same as the # of channels to use.
218715516c77SSepherosa Ziehau 	 */
218815516c77SSepherosa Ziehau 	ring_cnt = hn_chan_cnt;
218915516c77SSepherosa Ziehau 	if (ring_cnt <= 0) {
219015516c77SSepherosa Ziehau 		/* Default */
219115516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
219215516c77SSepherosa Ziehau 		if (ring_cnt > HN_RING_CNT_DEF_MAX)
219315516c77SSepherosa Ziehau 			ring_cnt = HN_RING_CNT_DEF_MAX;
219415516c77SSepherosa Ziehau 	} else if (ring_cnt > mp_ncpus) {
219515516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
219615516c77SSepherosa Ziehau 	}
219734d68912SSepherosa Ziehau #ifdef RSS
219834d68912SSepherosa Ziehau 	if (ring_cnt > rss_getnumbuckets())
219934d68912SSepherosa Ziehau 		ring_cnt = rss_getnumbuckets();
220034d68912SSepherosa Ziehau #endif
220115516c77SSepherosa Ziehau 
220215516c77SSepherosa Ziehau 	tx_ring_cnt = hn_tx_ring_cnt;
220315516c77SSepherosa Ziehau 	if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt)
220415516c77SSepherosa Ziehau 		tx_ring_cnt = ring_cnt;
220523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
220615516c77SSepherosa Ziehau 	if (hn_use_if_start) {
220715516c77SSepherosa Ziehau 		/* ifnet.if_start only needs one TX ring. */
220815516c77SSepherosa Ziehau 		tx_ring_cnt = 1;
220915516c77SSepherosa Ziehau 	}
221023bf9e15SSepherosa Ziehau #endif
221115516c77SSepherosa Ziehau 
221215516c77SSepherosa Ziehau 	/*
221315516c77SSepherosa Ziehau 	 * Set the leader CPU for channels.
221415516c77SSepherosa Ziehau 	 */
221515516c77SSepherosa Ziehau 	sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus;
221615516c77SSepherosa Ziehau 
221715516c77SSepherosa Ziehau 	/*
221815516c77SSepherosa Ziehau 	 * Create enough TX/RX rings, even if only limited number of
221915516c77SSepherosa Ziehau 	 * channels can be allocated.
222015516c77SSepherosa Ziehau 	 */
222115516c77SSepherosa Ziehau 	error = hn_create_tx_data(sc, tx_ring_cnt);
222215516c77SSepherosa Ziehau 	if (error)
222315516c77SSepherosa Ziehau 		goto failed;
222415516c77SSepherosa Ziehau 	error = hn_create_rx_data(sc, ring_cnt);
222515516c77SSepherosa Ziehau 	if (error)
222615516c77SSepherosa Ziehau 		goto failed;
222715516c77SSepherosa Ziehau 
222815516c77SSepherosa Ziehau 	/*
222915516c77SSepherosa Ziehau 	 * Create transaction context for NVS and RNDIS transactions.
223015516c77SSepherosa Ziehau 	 */
223115516c77SSepherosa Ziehau 	sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
223215516c77SSepherosa Ziehau 	    HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
223325641fc7SSepherosa Ziehau 	if (sc->hn_xact == NULL) {
223425641fc7SSepherosa Ziehau 		error = ENXIO;
223515516c77SSepherosa Ziehau 		goto failed;
223625641fc7SSepherosa Ziehau 	}
223725641fc7SSepherosa Ziehau 
223825641fc7SSepherosa Ziehau 	/*
223925641fc7SSepherosa Ziehau 	 * Install orphan handler for the revocation of this device's
224025641fc7SSepherosa Ziehau 	 * primary channel.
224125641fc7SSepherosa Ziehau 	 *
224225641fc7SSepherosa Ziehau 	 * NOTE:
224325641fc7SSepherosa Ziehau 	 * The processing order is critical here:
224425641fc7SSepherosa Ziehau 	 * Install the orphan handler, _before_ testing whether this
224525641fc7SSepherosa Ziehau 	 * device's primary channel has been revoked or not.
224625641fc7SSepherosa Ziehau 	 */
224725641fc7SSepherosa Ziehau 	vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact);
224825641fc7SSepherosa Ziehau 	if (vmbus_chan_is_revoked(sc->hn_prichan)) {
224925641fc7SSepherosa Ziehau 		error = ENXIO;
225025641fc7SSepherosa Ziehau 		goto failed;
225125641fc7SSepherosa Ziehau 	}
225215516c77SSepherosa Ziehau 
225315516c77SSepherosa Ziehau 	/*
225415516c77SSepherosa Ziehau 	 * Attach the synthetic parts, i.e. NVS and RNDIS.
225515516c77SSepherosa Ziehau 	 */
225615516c77SSepherosa Ziehau 	error = hn_synth_attach(sc, ETHERMTU);
225715516c77SSepherosa Ziehau 	if (error)
225815516c77SSepherosa Ziehau 		goto failed;
225915516c77SSepherosa Ziehau 
226015516c77SSepherosa Ziehau 	error = hn_rndis_get_eaddr(sc, eaddr);
226115516c77SSepherosa Ziehau 	if (error)
226215516c77SSepherosa Ziehau 		goto failed;
226315516c77SSepherosa Ziehau 
2264eb2fe044SSepherosa Ziehau 	error = hn_rndis_get_mtu(sc, &mtu);
2265eb2fe044SSepherosa Ziehau 	if (error)
2266eb2fe044SSepherosa Ziehau 		mtu = ETHERMTU;
2267eb2fe044SSepherosa Ziehau 	else if (bootverbose)
2268eb2fe044SSepherosa Ziehau 		device_printf(dev, "RNDIS mtu %u\n", mtu);
2269eb2fe044SSepherosa Ziehau 
227015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
227115516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
227215516c77SSepherosa Ziehau 		/*
227315516c77SSepherosa Ziehau 		 * Reduce TCP segment aggregation limit for multiple
227415516c77SSepherosa Ziehau 		 * RX rings to increase ACK timeliness.
227515516c77SSepherosa Ziehau 		 */
227615516c77SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF);
227715516c77SSepherosa Ziehau 	}
227815516c77SSepherosa Ziehau #endif
227915516c77SSepherosa Ziehau 
228015516c77SSepherosa Ziehau 	/*
2281db76829bSSepherosa Ziehau 	 * Fixup TX/RX stuffs after synthetic parts are attached.
228215516c77SSepherosa Ziehau 	 */
228315516c77SSepherosa Ziehau 	hn_fixup_tx_data(sc);
2284db76829bSSepherosa Ziehau 	hn_fixup_rx_data(sc);
228515516c77SSepherosa Ziehau 
228615516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
228715516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
228815516c77SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD,
228915516c77SSepherosa Ziehau 	    &sc->hn_nvs_ver, 0, "NVS version");
229015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version",
229115516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
229215516c77SSepherosa Ziehau 	    hn_ndis_version_sysctl, "A", "NDIS version");
229315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps",
229415516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
229515516c77SSepherosa Ziehau 	    hn_caps_sysctl, "A", "capabilities");
229615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist",
229715516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
229815516c77SSepherosa Ziehau 	    hn_hwassist_sysctl, "A", "hwassist");
22999c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_max",
23009c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomax, 0, "max TSO size");
23019c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegcnt",
23029c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomaxsegcount, 0,
23039c6cae24SSepherosa Ziehau 	    "max # of TSO segments");
23049c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegsz",
23059c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomaxsegsize, 0,
23069c6cae24SSepherosa Ziehau 	    "max size of TSO segment");
230715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter",
230815516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
230915516c77SSepherosa Ziehau 	    hn_rxfilter_sysctl, "A", "rxfilter");
231015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash",
231115516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
231215516c77SSepherosa Ziehau 	    hn_rss_hash_sysctl, "A", "RSS hash");
2313642ec226SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hashcap",
2314642ec226SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2315642ec226SSepherosa Ziehau 	    hn_rss_hcap_sysctl, "A", "RSS hash capabilities");
2316642ec226SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "mbuf_hash",
2317642ec226SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2318642ec226SSepherosa Ziehau 	    hn_rss_mbuf_sysctl, "A", "RSS hash for mbufs");
231915516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size",
232015516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count");
232134d68912SSepherosa Ziehau #ifndef RSS
232234d68912SSepherosa Ziehau 	/*
232334d68912SSepherosa Ziehau 	 * Don't allow RSS key/indirect table changes, if RSS is defined.
232434d68912SSepherosa Ziehau 	 */
232515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key",
232615516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
232715516c77SSepherosa Ziehau 	    hn_rss_key_sysctl, "IU", "RSS key");
232815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind",
232915516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
233015516c77SSepherosa Ziehau 	    hn_rss_ind_sysctl, "IU", "RSS indirect table");
233134d68912SSepherosa Ziehau #endif
2332dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size",
2333dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_size, 0,
2334dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation size limit");
2335dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts",
2336dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0,
2337dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation count limit");
2338dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align",
2339dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_align, 0,
2340dc13fee6SSepherosa Ziehau 	    "RNDIS packet transmission aggregation alignment");
2341dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size",
2342dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
2343dc13fee6SSepherosa Ziehau 	    hn_txagg_size_sysctl, "I",
2344dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation size, 0 -- disable, -1 -- auto");
2345dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts",
2346dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
2347dc13fee6SSepherosa Ziehau 	    hn_txagg_pkts_sysctl, "I",
2348dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation packets, "
2349dc13fee6SSepherosa Ziehau 	    "0 -- disable, -1 -- auto");
23506c1204dfSSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "polling",
23516c1204dfSSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
23526c1204dfSSepherosa Ziehau 	    hn_polling_sysctl, "I",
23536c1204dfSSepherosa Ziehau 	    "Polling frequency: [100,1000000], 0 disable polling");
235440d60d6eSDexuan Cui 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf",
235540d60d6eSDexuan Cui 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
235640d60d6eSDexuan Cui 	    hn_vf_sysctl, "A", "Virtual Function's name");
23579c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf) {
2358499c3e17SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxvf",
2359499c3e17SSepherosa Ziehau 		    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2360499c3e17SSepherosa Ziehau 		    hn_rxvf_sysctl, "A", "activated Virtual Function's name");
23619c6cae24SSepherosa Ziehau 	} else {
23629c6cae24SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_enabled",
23639c6cae24SSepherosa Ziehau 		    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
23649c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_enabled_sysctl, "I",
23659c6cae24SSepherosa Ziehau 		    "Transparent VF enabled");
23669c6cae24SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_accbpf",
23679c6cae24SSepherosa Ziehau 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
23689c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_accbpf_sysctl, "I",
23699c6cae24SSepherosa Ziehau 		    "Accurate BPF for transparent VF");
23709c6cae24SSepherosa Ziehau 	}
237115516c77SSepherosa Ziehau 
237215516c77SSepherosa Ziehau 	/*
237315516c77SSepherosa Ziehau 	 * Setup the ifmedia, which has been initialized earlier.
237415516c77SSepherosa Ziehau 	 */
237515516c77SSepherosa Ziehau 	ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL);
237615516c77SSepherosa Ziehau 	ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO);
237715516c77SSepherosa Ziehau 	/* XXX ifmedia_set really should do this for us */
237815516c77SSepherosa Ziehau 	sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media;
237915516c77SSepherosa Ziehau 
238015516c77SSepherosa Ziehau 	/*
238115516c77SSepherosa Ziehau 	 * Setup the ifnet for this interface.
238215516c77SSepherosa Ziehau 	 */
238315516c77SSepherosa Ziehau 
238415516c77SSepherosa Ziehau 	ifp->if_baudrate = IF_Gbps(10);
2385e87c4940SGleb Smirnoff 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
238615516c77SSepherosa Ziehau 	ifp->if_ioctl = hn_ioctl;
238715516c77SSepherosa Ziehau 	ifp->if_init = hn_init;
238823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
238915516c77SSepherosa Ziehau 	if (hn_use_if_start) {
239015516c77SSepherosa Ziehau 		int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]);
239115516c77SSepherosa Ziehau 
239215516c77SSepherosa Ziehau 		ifp->if_start = hn_start;
239315516c77SSepherosa Ziehau 		IFQ_SET_MAXLEN(&ifp->if_snd, qdepth);
239415516c77SSepherosa Ziehau 		ifp->if_snd.ifq_drv_maxlen = qdepth - 1;
239515516c77SSepherosa Ziehau 		IFQ_SET_READY(&ifp->if_snd);
239623bf9e15SSepherosa Ziehau 	} else
239723bf9e15SSepherosa Ziehau #endif
239823bf9e15SSepherosa Ziehau 	{
239915516c77SSepherosa Ziehau 		ifp->if_transmit = hn_transmit;
240015516c77SSepherosa Ziehau 		ifp->if_qflush = hn_xmit_qflush;
240115516c77SSepherosa Ziehau 	}
240215516c77SSepherosa Ziehau 
24039c6cae24SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO | IFCAP_LINKSTATE;
240415516c77SSepherosa Ziehau #ifdef foo
240515516c77SSepherosa Ziehau 	/* We can't diff IPv6 packets from IPv4 packets on RX path. */
240615516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM_IPV6;
240715516c77SSepherosa Ziehau #endif
240815516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_VLAN) {
240915516c77SSepherosa Ziehau 		/* XXX not sure about VLAN_MTU. */
241015516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
241115516c77SSepherosa Ziehau 	}
241215516c77SSepherosa Ziehau 
241315516c77SSepherosa Ziehau 	ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist;
241415516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP_MASK)
241515516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM;
241615516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP6_MASK)
241715516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM_IPV6;
241815516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO4) {
241915516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO4;
242015516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP_TSO;
242115516c77SSepherosa Ziehau 	}
242215516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO6) {
242315516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO6;
242415516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP6_TSO;
242515516c77SSepherosa Ziehau 	}
242615516c77SSepherosa Ziehau 
242715516c77SSepherosa Ziehau 	/* Enable all available capabilities by default. */
242815516c77SSepherosa Ziehau 	ifp->if_capenable = ifp->if_capabilities;
242915516c77SSepherosa Ziehau 
24307960e6baSSepherosa Ziehau 	/*
24317960e6baSSepherosa Ziehau 	 * Disable IPv6 TSO and TXCSUM by default, they still can
24327960e6baSSepherosa Ziehau 	 * be enabled through SIOCSIFCAP.
24337960e6baSSepherosa Ziehau 	 */
24347960e6baSSepherosa Ziehau 	ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
24357960e6baSSepherosa Ziehau 	ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO);
24367960e6baSSepherosa Ziehau 
243715516c77SSepherosa Ziehau 	if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) {
24389c6cae24SSepherosa Ziehau 		/*
24399c6cae24SSepherosa Ziehau 		 * Lock hn_set_tso_maxsize() to simplify its
24409c6cae24SSepherosa Ziehau 		 * internal logic.
24419c6cae24SSepherosa Ziehau 		 */
24429c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
244315516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU);
24449c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
244515516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX;
244615516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = PAGE_SIZE;
244715516c77SSepherosa Ziehau 	}
244815516c77SSepherosa Ziehau 
244915516c77SSepherosa Ziehau 	ether_ifattach(ifp, eaddr);
245015516c77SSepherosa Ziehau 
245115516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) {
245215516c77SSepherosa Ziehau 		if_printf(ifp, "TSO segcnt %u segsz %u\n",
245315516c77SSepherosa Ziehau 		    ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize);
245415516c77SSepherosa Ziehau 	}
2455eb2fe044SSepherosa Ziehau 	if (mtu < ETHERMTU) {
2456eb2fe044SSepherosa Ziehau 		if_printf(ifp, "fixup mtu %u -> %u\n", ifp->if_mtu, mtu);
2457eb2fe044SSepherosa Ziehau 		ifp->if_mtu = mtu;
2458eb2fe044SSepherosa Ziehau 	}
245915516c77SSepherosa Ziehau 
246015516c77SSepherosa Ziehau 	/* Inform the upper layer about the long frame support. */
246115516c77SSepherosa Ziehau 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
246215516c77SSepherosa Ziehau 
246315516c77SSepherosa Ziehau 	/*
246415516c77SSepherosa Ziehau 	 * Kick off link status check.
246515516c77SSepherosa Ziehau 	 */
246615516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
246715516c77SSepherosa Ziehau 	hn_update_link_status(sc);
246815516c77SSepherosa Ziehau 
24699c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf) {
24705bdfd3fdSDexuan Cui 		sc->hn_ifnet_evthand = EVENTHANDLER_REGISTER(ifnet_event,
24715bdfd3fdSDexuan Cui 		    hn_ifnet_event, sc, EVENTHANDLER_PRI_ANY);
24725bdfd3fdSDexuan Cui 		sc->hn_ifaddr_evthand = EVENTHANDLER_REGISTER(ifaddr_event,
24735bdfd3fdSDexuan Cui 		    hn_ifaddr_event, sc, EVENTHANDLER_PRI_ANY);
24749c6cae24SSepherosa Ziehau 	} else {
24759c6cae24SSepherosa Ziehau 		sc->hn_ifnet_lnkhand = EVENTHANDLER_REGISTER(ifnet_link_event,
24769c6cae24SSepherosa Ziehau 		    hn_ifnet_lnkevent, sc, EVENTHANDLER_PRI_ANY);
24779c6cae24SSepherosa Ziehau 	}
24785bdfd3fdSDexuan Cui 
2479f41e0df4SSepherosa Ziehau 	/*
2480f41e0df4SSepherosa Ziehau 	 * NOTE:
2481f41e0df4SSepherosa Ziehau 	 * Subscribe ether_ifattach event, instead of ifnet_arrival event,
2482f41e0df4SSepherosa Ziehau 	 * since interface's LLADDR is needed; interface LLADDR is not
2483f41e0df4SSepherosa Ziehau 	 * available when ifnet_arrival event is triggered.
2484f41e0df4SSepherosa Ziehau 	 */
2485499c3e17SSepherosa Ziehau 	sc->hn_ifnet_atthand = EVENTHANDLER_REGISTER(ether_ifattach_event,
2486499c3e17SSepherosa Ziehau 	    hn_ifnet_attevent, sc, EVENTHANDLER_PRI_ANY);
2487499c3e17SSepherosa Ziehau 	sc->hn_ifnet_dethand = EVENTHANDLER_REGISTER(ifnet_departure_event,
2488499c3e17SSepherosa Ziehau 	    hn_ifnet_detevent, sc, EVENTHANDLER_PRI_ANY);
2489499c3e17SSepherosa Ziehau 
249015516c77SSepherosa Ziehau 	return (0);
249115516c77SSepherosa Ziehau failed:
249215516c77SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)
249315516c77SSepherosa Ziehau 		hn_synth_detach(sc);
249415516c77SSepherosa Ziehau 	hn_detach(dev);
249515516c77SSepherosa Ziehau 	return (error);
249615516c77SSepherosa Ziehau }
249715516c77SSepherosa Ziehau 
249815516c77SSepherosa Ziehau static int
249915516c77SSepherosa Ziehau hn_detach(device_t dev)
250015516c77SSepherosa Ziehau {
250115516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
2502499c3e17SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp, *vf_ifp;
250315516c77SSepherosa Ziehau 
25049c6cae24SSepherosa Ziehau 	if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) {
25059c6cae24SSepherosa Ziehau 		/*
25069c6cae24SSepherosa Ziehau 		 * In case that the vmbus missed the orphan handler
25079c6cae24SSepherosa Ziehau 		 * installation.
25089c6cae24SSepherosa Ziehau 		 */
25099c6cae24SSepherosa Ziehau 		vmbus_xact_ctx_orphan(sc->hn_xact);
25109c6cae24SSepherosa Ziehau 	}
25119c6cae24SSepherosa Ziehau 
25125bdfd3fdSDexuan Cui 	if (sc->hn_ifaddr_evthand != NULL)
25135bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifaddr_event, sc->hn_ifaddr_evthand);
25145bdfd3fdSDexuan Cui 	if (sc->hn_ifnet_evthand != NULL)
25155bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifnet_event, sc->hn_ifnet_evthand);
2516499c3e17SSepherosa Ziehau 	if (sc->hn_ifnet_atthand != NULL) {
2517499c3e17SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ether_ifattach_event,
2518499c3e17SSepherosa Ziehau 		    sc->hn_ifnet_atthand);
2519499c3e17SSepherosa Ziehau 	}
2520499c3e17SSepherosa Ziehau 	if (sc->hn_ifnet_dethand != NULL) {
2521499c3e17SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ifnet_departure_event,
2522499c3e17SSepherosa Ziehau 		    sc->hn_ifnet_dethand);
2523499c3e17SSepherosa Ziehau 	}
25249c6cae24SSepherosa Ziehau 	if (sc->hn_ifnet_lnkhand != NULL)
25259c6cae24SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ifnet_link_event, sc->hn_ifnet_lnkhand);
2526499c3e17SSepherosa Ziehau 
2527499c3e17SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
2528499c3e17SSepherosa Ziehau 	__compiler_membar();
2529499c3e17SSepherosa Ziehau 	if (vf_ifp != NULL)
2530499c3e17SSepherosa Ziehau 		hn_ifnet_detevent(sc, vf_ifp);
25315bdfd3fdSDexuan Cui 
253215516c77SSepherosa Ziehau 	if (device_is_attached(dev)) {
253315516c77SSepherosa Ziehau 		HN_LOCK(sc);
253415516c77SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
253515516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
25365bdfd3fdSDexuan Cui 				hn_stop(sc, true);
253715516c77SSepherosa Ziehau 			/*
253815516c77SSepherosa Ziehau 			 * NOTE:
253915516c77SSepherosa Ziehau 			 * hn_stop() only suspends data, so managment
254015516c77SSepherosa Ziehau 			 * stuffs have to be suspended manually here.
254115516c77SSepherosa Ziehau 			 */
254215516c77SSepherosa Ziehau 			hn_suspend_mgmt(sc);
254315516c77SSepherosa Ziehau 			hn_synth_detach(sc);
254415516c77SSepherosa Ziehau 		}
254515516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
254615516c77SSepherosa Ziehau 		ether_ifdetach(ifp);
254715516c77SSepherosa Ziehau 	}
254815516c77SSepherosa Ziehau 
254915516c77SSepherosa Ziehau 	ifmedia_removeall(&sc->hn_media);
255015516c77SSepherosa Ziehau 	hn_destroy_rx_data(sc);
255115516c77SSepherosa Ziehau 	hn_destroy_tx_data(sc);
255215516c77SSepherosa Ziehau 
25530e11868dSSepherosa Ziehau 	if (sc->hn_tx_taskqs != NULL && sc->hn_tx_taskqs != hn_tx_taskque) {
2554fdd0222aSSepherosa Ziehau 		int i;
2555fdd0222aSSepherosa Ziehau 
2556fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
2557fdd0222aSSepherosa Ziehau 			taskqueue_free(sc->hn_tx_taskqs[i]);
2558fdd0222aSSepherosa Ziehau 		free(sc->hn_tx_taskqs, M_DEVBUF);
2559fdd0222aSSepherosa Ziehau 	}
256015516c77SSepherosa Ziehau 	taskqueue_free(sc->hn_mgmt_taskq0);
25619c6cae24SSepherosa Ziehau 	if (sc->hn_vf_taskq != NULL)
25629c6cae24SSepherosa Ziehau 		taskqueue_free(sc->hn_vf_taskq);
256315516c77SSepherosa Ziehau 
256425641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL) {
256525641fc7SSepherosa Ziehau 		/*
256625641fc7SSepherosa Ziehau 		 * Uninstall the orphan handler _before_ the xact is
256725641fc7SSepherosa Ziehau 		 * destructed.
256825641fc7SSepherosa Ziehau 		 */
256925641fc7SSepherosa Ziehau 		vmbus_chan_unset_orphan(sc->hn_prichan);
257015516c77SSepherosa Ziehau 		vmbus_xact_ctx_destroy(sc->hn_xact);
257125641fc7SSepherosa Ziehau 	}
257215516c77SSepherosa Ziehau 
257315516c77SSepherosa Ziehau 	if_free(ifp);
257415516c77SSepherosa Ziehau 
257515516c77SSepherosa Ziehau 	HN_LOCK_DESTROY(sc);
25769c6cae24SSepherosa Ziehau 	rm_destroy(&sc->hn_vf_lock);
257715516c77SSepherosa Ziehau 	return (0);
257815516c77SSepherosa Ziehau }
257915516c77SSepherosa Ziehau 
258015516c77SSepherosa Ziehau static int
258115516c77SSepherosa Ziehau hn_shutdown(device_t dev)
258215516c77SSepherosa Ziehau {
258315516c77SSepherosa Ziehau 
258415516c77SSepherosa Ziehau 	return (0);
258515516c77SSepherosa Ziehau }
258615516c77SSepherosa Ziehau 
258715516c77SSepherosa Ziehau static void
258815516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc)
258915516c77SSepherosa Ziehau {
259015516c77SSepherosa Ziehau 	uint32_t link_status;
259115516c77SSepherosa Ziehau 	int error;
259215516c77SSepherosa Ziehau 
259315516c77SSepherosa Ziehau 	error = hn_rndis_get_linkstatus(sc, &link_status);
259415516c77SSepherosa Ziehau 	if (error) {
259515516c77SSepherosa Ziehau 		/* XXX what to do? */
259615516c77SSepherosa Ziehau 		return;
259715516c77SSepherosa Ziehau 	}
259815516c77SSepherosa Ziehau 
259915516c77SSepherosa Ziehau 	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
260015516c77SSepherosa Ziehau 		sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
260115516c77SSepherosa Ziehau 	else
260215516c77SSepherosa Ziehau 		sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
260315516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp,
260415516c77SSepherosa Ziehau 	    (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ?
260515516c77SSepherosa Ziehau 	    LINK_STATE_UP : LINK_STATE_DOWN);
260615516c77SSepherosa Ziehau }
260715516c77SSepherosa Ziehau 
260815516c77SSepherosa Ziehau static void
260915516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused)
261015516c77SSepherosa Ziehau {
261115516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
261215516c77SSepherosa Ziehau 
261315516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
261415516c77SSepherosa Ziehau 		return;
261515516c77SSepherosa Ziehau 	hn_link_status(sc);
261615516c77SSepherosa Ziehau }
261715516c77SSepherosa Ziehau 
261815516c77SSepherosa Ziehau static void
261915516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused)
262015516c77SSepherosa Ziehau {
262115516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
262215516c77SSepherosa Ziehau 
262315516c77SSepherosa Ziehau 	/* Prevent any link status checks from running. */
262415516c77SSepherosa Ziehau 	sc->hn_link_flags |= HN_LINK_FLAG_NETCHG;
262515516c77SSepherosa Ziehau 
262615516c77SSepherosa Ziehau 	/*
262715516c77SSepherosa Ziehau 	 * Fake up a [link down --> link up] state change; 5 seconds
262815516c77SSepherosa Ziehau 	 * delay is used, which closely simulates miibus reaction
262915516c77SSepherosa Ziehau 	 * upon link down event.
263015516c77SSepherosa Ziehau 	 */
263115516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
263215516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
263315516c77SSepherosa Ziehau 	taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0,
263415516c77SSepherosa Ziehau 	    &sc->hn_netchg_status, 5 * hz);
263515516c77SSepherosa Ziehau }
263615516c77SSepherosa Ziehau 
263715516c77SSepherosa Ziehau static void
263815516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused)
263915516c77SSepherosa Ziehau {
264015516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
264115516c77SSepherosa Ziehau 
264215516c77SSepherosa Ziehau 	/* Re-allow link status checks. */
264315516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG;
264415516c77SSepherosa Ziehau 	hn_link_status(sc);
264515516c77SSepherosa Ziehau }
264615516c77SSepherosa Ziehau 
264715516c77SSepherosa Ziehau static void
264815516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc)
264915516c77SSepherosa Ziehau {
265015516c77SSepherosa Ziehau 
265115516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
265215516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
265315516c77SSepherosa Ziehau }
265415516c77SSepherosa Ziehau 
265515516c77SSepherosa Ziehau static void
265615516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc)
265715516c77SSepherosa Ziehau {
265815516c77SSepherosa Ziehau 
265915516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
266015516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init);
266115516c77SSepherosa Ziehau }
266215516c77SSepherosa Ziehau 
266315516c77SSepherosa Ziehau static __inline int
266415516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
266515516c77SSepherosa Ziehau     struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
266615516c77SSepherosa Ziehau {
266715516c77SSepherosa Ziehau 	struct mbuf *m = *m_head;
266815516c77SSepherosa Ziehau 	int error;
266915516c77SSepherosa Ziehau 
267015516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim"));
267115516c77SSepherosa Ziehau 
267215516c77SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap,
267315516c77SSepherosa Ziehau 	    m, segs, nsegs, BUS_DMA_NOWAIT);
267415516c77SSepherosa Ziehau 	if (error == EFBIG) {
267515516c77SSepherosa Ziehau 		struct mbuf *m_new;
267615516c77SSepherosa Ziehau 
267715516c77SSepherosa Ziehau 		m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX);
267815516c77SSepherosa Ziehau 		if (m_new == NULL)
267915516c77SSepherosa Ziehau 			return ENOBUFS;
268015516c77SSepherosa Ziehau 		else
268115516c77SSepherosa Ziehau 			*m_head = m = m_new;
268215516c77SSepherosa Ziehau 		txr->hn_tx_collapsed++;
268315516c77SSepherosa Ziehau 
268415516c77SSepherosa Ziehau 		error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag,
268515516c77SSepherosa Ziehau 		    txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT);
268615516c77SSepherosa Ziehau 	}
268715516c77SSepherosa Ziehau 	if (!error) {
268815516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap,
268915516c77SSepherosa Ziehau 		    BUS_DMASYNC_PREWRITE);
269015516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_DMAMAP;
269115516c77SSepherosa Ziehau 	}
269215516c77SSepherosa Ziehau 	return error;
269315516c77SSepherosa Ziehau }
269415516c77SSepherosa Ziehau 
269515516c77SSepherosa Ziehau static __inline int
269615516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd)
269715516c77SSepherosa Ziehau {
269815516c77SSepherosa Ziehau 
269915516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0,
270015516c77SSepherosa Ziehau 	    ("put an onlist txd %#x", txd->flags));
2701dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2702dc13fee6SSepherosa Ziehau 	    ("put an onagg txd %#x", txd->flags));
270315516c77SSepherosa Ziehau 
270415516c77SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
270515516c77SSepherosa Ziehau 	if (atomic_fetchadd_int(&txd->refs, -1) != 1)
270615516c77SSepherosa Ziehau 		return 0;
270715516c77SSepherosa Ziehau 
2708dc13fee6SSepherosa Ziehau 	if (!STAILQ_EMPTY(&txd->agg_list)) {
2709dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tmp_txd;
2710dc13fee6SSepherosa Ziehau 
2711dc13fee6SSepherosa Ziehau 		while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) {
2712dc13fee6SSepherosa Ziehau 			int freed;
2713dc13fee6SSepherosa Ziehau 
2714dc13fee6SSepherosa Ziehau 			KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list),
2715dc13fee6SSepherosa Ziehau 			    ("resursive aggregation on aggregated txdesc"));
2716dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG),
2717dc13fee6SSepherosa Ziehau 			    ("not aggregated txdesc"));
2718dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
2719dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc uses dmamap"));
2720dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
2721dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc consumes "
2722dc13fee6SSepherosa Ziehau 			     "chimney sending buffer"));
2723dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_size == 0,
2724dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc has non-zero "
2725dc13fee6SSepherosa Ziehau 			     "chimney sending size"));
2726dc13fee6SSepherosa Ziehau 
2727dc13fee6SSepherosa Ziehau 			STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link);
2728dc13fee6SSepherosa Ziehau 			tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG;
2729dc13fee6SSepherosa Ziehau 			freed = hn_txdesc_put(txr, tmp_txd);
2730dc13fee6SSepherosa Ziehau 			KASSERT(freed, ("failed to free aggregated txdesc"));
2731dc13fee6SSepherosa Ziehau 		}
2732dc13fee6SSepherosa Ziehau 	}
2733dc13fee6SSepherosa Ziehau 
273415516c77SSepherosa Ziehau 	if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) {
273515516c77SSepherosa Ziehau 		KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
273615516c77SSepherosa Ziehau 		    ("chim txd uses dmamap"));
273715516c77SSepherosa Ziehau 		hn_chim_free(txr->hn_sc, txd->chim_index);
273815516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
2739dc13fee6SSepherosa Ziehau 		txd->chim_size = 0;
274015516c77SSepherosa Ziehau 	} else if (txd->flags & HN_TXD_FLAG_DMAMAP) {
274115516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag,
274215516c77SSepherosa Ziehau 		    txd->data_dmap, BUS_DMASYNC_POSTWRITE);
274315516c77SSepherosa Ziehau 		bus_dmamap_unload(txr->hn_tx_data_dtag,
274415516c77SSepherosa Ziehau 		    txd->data_dmap);
274515516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_DMAMAP;
274615516c77SSepherosa Ziehau 	}
274715516c77SSepherosa Ziehau 
274815516c77SSepherosa Ziehau 	if (txd->m != NULL) {
274915516c77SSepherosa Ziehau 		m_freem(txd->m);
275015516c77SSepherosa Ziehau 		txd->m = NULL;
275115516c77SSepherosa Ziehau 	}
275215516c77SSepherosa Ziehau 
275315516c77SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONLIST;
275415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
275515516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
275615516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_avail >= 0 &&
275715516c77SSepherosa Ziehau 	    txr->hn_txdesc_avail < txr->hn_txdesc_cnt,
275815516c77SSepherosa Ziehau 	    ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail));
275915516c77SSepherosa Ziehau 	txr->hn_txdesc_avail++;
276015516c77SSepherosa Ziehau 	SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
276115516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
276285e4ae1eSSepherosa Ziehau #else	/* HN_USE_TXDESC_BUFRING */
276385e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
276415516c77SSepherosa Ziehau 	atomic_add_int(&txr->hn_txdesc_avail, 1);
276515516c77SSepherosa Ziehau #endif
276685e4ae1eSSepherosa Ziehau 	buf_ring_enqueue(txr->hn_txdesc_br, txd);
276785e4ae1eSSepherosa Ziehau #endif	/* !HN_USE_TXDESC_BUFRING */
276815516c77SSepherosa Ziehau 
276915516c77SSepherosa Ziehau 	return 1;
277015516c77SSepherosa Ziehau }
277115516c77SSepherosa Ziehau 
277215516c77SSepherosa Ziehau static __inline struct hn_txdesc *
277315516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr)
277415516c77SSepherosa Ziehau {
277515516c77SSepherosa Ziehau 	struct hn_txdesc *txd;
277615516c77SSepherosa Ziehau 
277715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
277815516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
277915516c77SSepherosa Ziehau 	txd = SLIST_FIRST(&txr->hn_txlist);
278015516c77SSepherosa Ziehau 	if (txd != NULL) {
278115516c77SSepherosa Ziehau 		KASSERT(txr->hn_txdesc_avail > 0,
278215516c77SSepherosa Ziehau 		    ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail));
278315516c77SSepherosa Ziehau 		txr->hn_txdesc_avail--;
278415516c77SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&txr->hn_txlist, link);
278515516c77SSepherosa Ziehau 	}
278615516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
278715516c77SSepherosa Ziehau #else
278815516c77SSepherosa Ziehau 	txd = buf_ring_dequeue_sc(txr->hn_txdesc_br);
278915516c77SSepherosa Ziehau #endif
279015516c77SSepherosa Ziehau 
279115516c77SSepherosa Ziehau 	if (txd != NULL) {
279215516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
279385e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
279415516c77SSepherosa Ziehau 		atomic_subtract_int(&txr->hn_txdesc_avail, 1);
279515516c77SSepherosa Ziehau #endif
279685e4ae1eSSepherosa Ziehau #endif	/* HN_USE_TXDESC_BUFRING */
279715516c77SSepherosa Ziehau 		KASSERT(txd->m == NULL && txd->refs == 0 &&
2798dc13fee6SSepherosa Ziehau 		    STAILQ_EMPTY(&txd->agg_list) &&
279915516c77SSepherosa Ziehau 		    txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
2800dc13fee6SSepherosa Ziehau 		    txd->chim_size == 0 &&
280115516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONLIST) &&
2802dc13fee6SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONAGG) == 0 &&
280315516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd"));
280415516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_ONLIST;
280515516c77SSepherosa Ziehau 		txd->refs = 1;
280615516c77SSepherosa Ziehau 	}
280715516c77SSepherosa Ziehau 	return txd;
280815516c77SSepherosa Ziehau }
280915516c77SSepherosa Ziehau 
281015516c77SSepherosa Ziehau static __inline void
281115516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd)
281215516c77SSepherosa Ziehau {
281315516c77SSepherosa Ziehau 
281415516c77SSepherosa Ziehau 	/* 0->1 transition will never work */
281525641fc7SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
281615516c77SSepherosa Ziehau 	atomic_add_int(&txd->refs, 1);
281715516c77SSepherosa Ziehau }
281815516c77SSepherosa Ziehau 
2819dc13fee6SSepherosa Ziehau static __inline void
2820dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd)
2821dc13fee6SSepherosa Ziehau {
2822dc13fee6SSepherosa Ziehau 
2823dc13fee6SSepherosa Ziehau 	KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2824dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on aggregating txdesc"));
2825dc13fee6SSepherosa Ziehau 
2826dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2827dc13fee6SSepherosa Ziehau 	    ("already aggregated"));
2828dc13fee6SSepherosa Ziehau 	KASSERT(STAILQ_EMPTY(&txd->agg_list),
2829dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on to-be-aggregated txdesc"));
2830dc13fee6SSepherosa Ziehau 
2831dc13fee6SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONAGG;
2832dc13fee6SSepherosa Ziehau 	STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link);
2833dc13fee6SSepherosa Ziehau }
2834dc13fee6SSepherosa Ziehau 
283515516c77SSepherosa Ziehau static bool
283615516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr)
283715516c77SSepherosa Ziehau {
283815516c77SSepherosa Ziehau 	bool pending = false;
283915516c77SSepherosa Ziehau 
284015516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
284115516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
284215516c77SSepherosa Ziehau 	if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt)
284315516c77SSepherosa Ziehau 		pending = true;
284415516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
284515516c77SSepherosa Ziehau #else
284615516c77SSepherosa Ziehau 	if (!buf_ring_full(txr->hn_txdesc_br))
284715516c77SSepherosa Ziehau 		pending = true;
284815516c77SSepherosa Ziehau #endif
284915516c77SSepherosa Ziehau 	return (pending);
285015516c77SSepherosa Ziehau }
285115516c77SSepherosa Ziehau 
285215516c77SSepherosa Ziehau static __inline void
285315516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr)
285415516c77SSepherosa Ziehau {
285515516c77SSepherosa Ziehau 	txr->hn_has_txeof = 0;
285615516c77SSepherosa Ziehau 	txr->hn_txeof(txr);
285715516c77SSepherosa Ziehau }
285815516c77SSepherosa Ziehau 
285915516c77SSepherosa Ziehau static void
286015516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc,
286115516c77SSepherosa Ziehau     struct vmbus_channel *chan, const void *data __unused, int dlen __unused)
286215516c77SSepherosa Ziehau {
286315516c77SSepherosa Ziehau 	struct hn_txdesc *txd = sndc->hn_cbarg;
286415516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
286515516c77SSepherosa Ziehau 
286615516c77SSepherosa Ziehau 	txr = txd->txr;
286715516c77SSepherosa Ziehau 	KASSERT(txr->hn_chan == chan,
286815516c77SSepherosa Ziehau 	    ("channel mismatch, on chan%u, should be chan%u",
2869aa1a2adcSSepherosa Ziehau 	     vmbus_chan_id(chan), vmbus_chan_id(txr->hn_chan)));
287015516c77SSepherosa Ziehau 
287115516c77SSepherosa Ziehau 	txr->hn_has_txeof = 1;
287215516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
287315516c77SSepherosa Ziehau 
287415516c77SSepherosa Ziehau 	++txr->hn_txdone_cnt;
287515516c77SSepherosa Ziehau 	if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) {
287615516c77SSepherosa Ziehau 		txr->hn_txdone_cnt = 0;
287715516c77SSepherosa Ziehau 		if (txr->hn_oactive)
287815516c77SSepherosa Ziehau 			hn_txeof(txr);
287915516c77SSepherosa Ziehau 	}
288015516c77SSepherosa Ziehau }
288115516c77SSepherosa Ziehau 
288215516c77SSepherosa Ziehau static void
288315516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
288415516c77SSepherosa Ziehau {
288515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
288615516c77SSepherosa Ziehau 	tcp_lro_flush_all(&rxr->hn_lro);
288715516c77SSepherosa Ziehau #endif
288815516c77SSepherosa Ziehau 
288915516c77SSepherosa Ziehau 	/*
289015516c77SSepherosa Ziehau 	 * NOTE:
289115516c77SSepherosa Ziehau 	 * 'txr' could be NULL, if multiple channels and
289215516c77SSepherosa Ziehau 	 * ifnet.if_start method are enabled.
289315516c77SSepherosa Ziehau 	 */
289415516c77SSepherosa Ziehau 	if (txr == NULL || !txr->hn_has_txeof)
289515516c77SSepherosa Ziehau 		return;
289615516c77SSepherosa Ziehau 
289715516c77SSepherosa Ziehau 	txr->hn_txdone_cnt = 0;
289815516c77SSepherosa Ziehau 	hn_txeof(txr);
289915516c77SSepherosa Ziehau }
290015516c77SSepherosa Ziehau 
290115516c77SSepherosa Ziehau static __inline uint32_t
290215516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs)
290315516c77SSepherosa Ziehau {
290415516c77SSepherosa Ziehau 
290515516c77SSepherosa Ziehau 	KASSERT(ofs >= sizeof(struct rndis_packet_msg),
290615516c77SSepherosa Ziehau 	    ("invalid RNDIS packet msg offset %u", ofs));
290715516c77SSepherosa Ziehau 	return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset));
290815516c77SSepherosa Ziehau }
290915516c77SSepherosa Ziehau 
291015516c77SSepherosa Ziehau static __inline void *
291115516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
291215516c77SSepherosa Ziehau     size_t pi_dlen, uint32_t pi_type)
291315516c77SSepherosa Ziehau {
291415516c77SSepherosa Ziehau 	const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
291515516c77SSepherosa Ziehau 	struct rndis_pktinfo *pi;
291615516c77SSepherosa Ziehau 
291715516c77SSepherosa Ziehau 	KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
291815516c77SSepherosa Ziehau 	    ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
291915516c77SSepherosa Ziehau 
292015516c77SSepherosa Ziehau 	/*
292115516c77SSepherosa Ziehau 	 * Per-packet-info does not move; it only grows.
292215516c77SSepherosa Ziehau 	 *
292315516c77SSepherosa Ziehau 	 * NOTE:
292415516c77SSepherosa Ziehau 	 * rm_pktinfooffset in this phase counts from the beginning
292515516c77SSepherosa Ziehau 	 * of rndis_packet_msg.
292615516c77SSepherosa Ziehau 	 */
292715516c77SSepherosa Ziehau 	KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
292815516c77SSepherosa Ziehau 	    ("%u pktinfo overflows RNDIS packet msg", pi_type));
292915516c77SSepherosa Ziehau 	pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
293015516c77SSepherosa Ziehau 	    pkt->rm_pktinfolen);
293115516c77SSepherosa Ziehau 	pkt->rm_pktinfolen += pi_size;
293215516c77SSepherosa Ziehau 
293315516c77SSepherosa Ziehau 	pi->rm_size = pi_size;
293415516c77SSepherosa Ziehau 	pi->rm_type = pi_type;
293515516c77SSepherosa Ziehau 	pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
293615516c77SSepherosa Ziehau 
293715516c77SSepherosa Ziehau 	return (pi->rm_data);
293815516c77SSepherosa Ziehau }
293915516c77SSepherosa Ziehau 
2940dc13fee6SSepherosa Ziehau static __inline int
2941dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr)
2942dc13fee6SSepherosa Ziehau {
2943dc13fee6SSepherosa Ziehau 	struct hn_txdesc *txd;
2944dc13fee6SSepherosa Ziehau 	struct mbuf *m;
2945dc13fee6SSepherosa Ziehau 	int error, pkts;
2946dc13fee6SSepherosa Ziehau 
2947dc13fee6SSepherosa Ziehau 	txd = txr->hn_agg_txd;
2948dc13fee6SSepherosa Ziehau 	KASSERT(txd != NULL, ("no aggregate txdesc"));
2949dc13fee6SSepherosa Ziehau 
2950dc13fee6SSepherosa Ziehau 	/*
2951dc13fee6SSepherosa Ziehau 	 * Since hn_txpkt() will reset this temporary stat, save
2952dc13fee6SSepherosa Ziehau 	 * it now, so that oerrors can be updated properly, if
2953dc13fee6SSepherosa Ziehau 	 * hn_txpkt() ever fails.
2954dc13fee6SSepherosa Ziehau 	 */
2955dc13fee6SSepherosa Ziehau 	pkts = txr->hn_stat_pkts;
2956dc13fee6SSepherosa Ziehau 
2957dc13fee6SSepherosa Ziehau 	/*
2958dc13fee6SSepherosa Ziehau 	 * Since txd's mbuf will _not_ be freed upon hn_txpkt()
2959dc13fee6SSepherosa Ziehau 	 * failure, save it for later freeing, if hn_txpkt() ever
2960dc13fee6SSepherosa Ziehau 	 * fails.
2961dc13fee6SSepherosa Ziehau 	 */
2962dc13fee6SSepherosa Ziehau 	m = txd->m;
2963dc13fee6SSepherosa Ziehau 	error = hn_txpkt(ifp, txr, txd);
2964dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
2965dc13fee6SSepherosa Ziehau 		/* txd is freed, but m is not. */
2966dc13fee6SSepherosa Ziehau 		m_freem(m);
2967dc13fee6SSepherosa Ziehau 
2968dc13fee6SSepherosa Ziehau 		txr->hn_flush_failed++;
2969dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts);
2970dc13fee6SSepherosa Ziehau 	}
2971dc13fee6SSepherosa Ziehau 
2972dc13fee6SSepherosa Ziehau 	/* Reset all aggregation states. */
2973dc13fee6SSepherosa Ziehau 	txr->hn_agg_txd = NULL;
2974dc13fee6SSepherosa Ziehau 	txr->hn_agg_szleft = 0;
2975dc13fee6SSepherosa Ziehau 	txr->hn_agg_pktleft = 0;
2976dc13fee6SSepherosa Ziehau 	txr->hn_agg_prevpkt = NULL;
2977dc13fee6SSepherosa Ziehau 
2978dc13fee6SSepherosa Ziehau 	return (error);
2979dc13fee6SSepherosa Ziehau }
2980dc13fee6SSepherosa Ziehau 
2981dc13fee6SSepherosa Ziehau static void *
2982dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
2983dc13fee6SSepherosa Ziehau     int pktsize)
2984dc13fee6SSepherosa Ziehau {
2985dc13fee6SSepherosa Ziehau 	void *chim;
2986dc13fee6SSepherosa Ziehau 
2987dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL) {
2988dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) {
2989dc13fee6SSepherosa Ziehau 			struct hn_txdesc *agg_txd = txr->hn_agg_txd;
2990dc13fee6SSepherosa Ziehau 			struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt;
2991dc13fee6SSepherosa Ziehau 			int olen;
2992dc13fee6SSepherosa Ziehau 
2993dc13fee6SSepherosa Ziehau 			/*
2994dc13fee6SSepherosa Ziehau 			 * Update the previous RNDIS packet's total length,
2995dc13fee6SSepherosa Ziehau 			 * it can be increased due to the mandatory alignment
2996dc13fee6SSepherosa Ziehau 			 * padding for this RNDIS packet.  And update the
2997dc13fee6SSepherosa Ziehau 			 * aggregating txdesc's chimney sending buffer size
2998dc13fee6SSepherosa Ziehau 			 * accordingly.
2999dc13fee6SSepherosa Ziehau 			 *
3000dc13fee6SSepherosa Ziehau 			 * XXX
3001dc13fee6SSepherosa Ziehau 			 * Zero-out the padding, as required by the RNDIS spec.
3002dc13fee6SSepherosa Ziehau 			 */
3003dc13fee6SSepherosa Ziehau 			olen = pkt->rm_len;
3004dc13fee6SSepherosa Ziehau 			pkt->rm_len = roundup2(olen, txr->hn_agg_align);
3005dc13fee6SSepherosa Ziehau 			agg_txd->chim_size += pkt->rm_len - olen;
3006dc13fee6SSepherosa Ziehau 
3007dc13fee6SSepherosa Ziehau 			/* Link this txdesc to the parent. */
3008dc13fee6SSepherosa Ziehau 			hn_txdesc_agg(agg_txd, txd);
3009dc13fee6SSepherosa Ziehau 
3010dc13fee6SSepherosa Ziehau 			chim = (uint8_t *)pkt + pkt->rm_len;
3011dc13fee6SSepherosa Ziehau 			/* Save the current packet for later fixup. */
3012dc13fee6SSepherosa Ziehau 			txr->hn_agg_prevpkt = chim;
3013dc13fee6SSepherosa Ziehau 
3014dc13fee6SSepherosa Ziehau 			txr->hn_agg_pktleft--;
3015dc13fee6SSepherosa Ziehau 			txr->hn_agg_szleft -= pktsize;
3016dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_szleft <=
3017dc13fee6SSepherosa Ziehau 			    HN_PKTSIZE_MIN(txr->hn_agg_align)) {
3018dc13fee6SSepherosa Ziehau 				/*
3019dc13fee6SSepherosa Ziehau 				 * Probably can't aggregate more packets,
3020dc13fee6SSepherosa Ziehau 				 * flush this aggregating txdesc proactively.
3021dc13fee6SSepherosa Ziehau 				 */
3022dc13fee6SSepherosa Ziehau 				txr->hn_agg_pktleft = 0;
3023dc13fee6SSepherosa Ziehau 			}
3024dc13fee6SSepherosa Ziehau 			/* Done! */
3025dc13fee6SSepherosa Ziehau 			return (chim);
3026dc13fee6SSepherosa Ziehau 		}
3027dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
3028dc13fee6SSepherosa Ziehau 	}
3029dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
3030dc13fee6SSepherosa Ziehau 
3031dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney_tried++;
3032dc13fee6SSepherosa Ziehau 	txd->chim_index = hn_chim_alloc(txr->hn_sc);
3033dc13fee6SSepherosa Ziehau 	if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID)
3034dc13fee6SSepherosa Ziehau 		return (NULL);
3035dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney++;
3036dc13fee6SSepherosa Ziehau 
3037dc13fee6SSepherosa Ziehau 	chim = txr->hn_sc->hn_chim +
3038dc13fee6SSepherosa Ziehau 	    (txd->chim_index * txr->hn_sc->hn_chim_szmax);
3039dc13fee6SSepherosa Ziehau 
3040dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_pktmax > 1 &&
3041dc13fee6SSepherosa Ziehau 	    txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) {
3042dc13fee6SSepherosa Ziehau 		txr->hn_agg_txd = txd;
3043dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1;
3044dc13fee6SSepherosa Ziehau 		txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize;
3045dc13fee6SSepherosa Ziehau 		txr->hn_agg_prevpkt = chim;
3046dc13fee6SSepherosa Ziehau 	}
3047dc13fee6SSepherosa Ziehau 	return (chim);
3048dc13fee6SSepherosa Ziehau }
3049dc13fee6SSepherosa Ziehau 
305015516c77SSepherosa Ziehau /*
305115516c77SSepherosa Ziehau  * NOTE:
305215516c77SSepherosa Ziehau  * If this function fails, then both txd and m_head0 will be freed.
305315516c77SSepherosa Ziehau  */
305415516c77SSepherosa Ziehau static int
3055dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
3056dc13fee6SSepherosa Ziehau     struct mbuf **m_head0)
305715516c77SSepherosa Ziehau {
305815516c77SSepherosa Ziehau 	bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX];
305915516c77SSepherosa Ziehau 	int error, nsegs, i;
306015516c77SSepherosa Ziehau 	struct mbuf *m_head = *m_head0;
306115516c77SSepherosa Ziehau 	struct rndis_packet_msg *pkt;
306215516c77SSepherosa Ziehau 	uint32_t *pi_data;
30638966e5d5SSepherosa Ziehau 	void *chim = NULL;
3064dc13fee6SSepherosa Ziehau 	int pkt_hlen, pkt_size;
306515516c77SSepherosa Ziehau 
306615516c77SSepherosa Ziehau 	pkt = txd->rndis_pkt;
3067dc13fee6SSepherosa Ziehau 	pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align);
3068dc13fee6SSepherosa Ziehau 	if (pkt_size < txr->hn_chim_size) {
3069dc13fee6SSepherosa Ziehau 		chim = hn_try_txagg(ifp, txr, txd, pkt_size);
3070dc13fee6SSepherosa Ziehau 		if (chim != NULL)
30718966e5d5SSepherosa Ziehau 			pkt = chim;
3072dc13fee6SSepherosa Ziehau 	} else {
3073dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL)
3074dc13fee6SSepherosa Ziehau 			hn_flush_txagg(ifp, txr);
30758966e5d5SSepherosa Ziehau 	}
30768966e5d5SSepherosa Ziehau 
307715516c77SSepherosa Ziehau 	pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
30788fe90f73SSepherosa Ziehau 	pkt->rm_len = m_head->m_pkthdr.len;
30799130c4f7SSepherosa Ziehau 	pkt->rm_dataoffset = 0;
308015516c77SSepherosa Ziehau 	pkt->rm_datalen = m_head->m_pkthdr.len;
3081dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataoffset = 0;
3082dc13fee6SSepherosa Ziehau 	pkt->rm_oobdatalen = 0;
3083dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataelements = 0;
308415516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = sizeof(*pkt);
308515516c77SSepherosa Ziehau 	pkt->rm_pktinfolen = 0;
3086dc13fee6SSepherosa Ziehau 	pkt->rm_vchandle = 0;
3087dc13fee6SSepherosa Ziehau 	pkt->rm_reserved = 0;
308815516c77SSepherosa Ziehau 
308915516c77SSepherosa Ziehau 	if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) {
309015516c77SSepherosa Ziehau 		/*
309180f39bd9SWei Hu 		 * Set the hash value for this packet.
309215516c77SSepherosa Ziehau 		 */
309315516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
309415516c77SSepherosa Ziehau 		    HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL);
309580f39bd9SWei Hu 
309680f39bd9SWei Hu 		if (M_HASHTYPE_ISHASH(m_head))
309780f39bd9SWei Hu 			/*
309880f39bd9SWei Hu 			 * The flowid field contains the hash value host
309980f39bd9SWei Hu 			 * set in the rx queue if it is a ip forwarding pkt.
310080f39bd9SWei Hu 			 * Set the same hash value so host can send on the
310180f39bd9SWei Hu 			 * cpu it was received.
310280f39bd9SWei Hu 			 */
310380f39bd9SWei Hu 			*pi_data = m_head->m_pkthdr.flowid;
310480f39bd9SWei Hu 		else
310580f39bd9SWei Hu 			/*
310680f39bd9SWei Hu 			 * Otherwise just put the tx queue index.
310780f39bd9SWei Hu 			 */
310815516c77SSepherosa Ziehau 			*pi_data = txr->hn_tx_idx;
310915516c77SSepherosa Ziehau 	}
311015516c77SSepherosa Ziehau 
311115516c77SSepherosa Ziehau 	if (m_head->m_flags & M_VLANTAG) {
311215516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
311315516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
311415516c77SSepherosa Ziehau 		*pi_data = NDIS_VLAN_INFO_MAKE(
311515516c77SSepherosa Ziehau 		    EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag),
311615516c77SSepherosa Ziehau 		    EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag),
311715516c77SSepherosa Ziehau 		    EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag));
311815516c77SSepherosa Ziehau 	}
311915516c77SSepherosa Ziehau 
312015516c77SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
312115516c77SSepherosa Ziehau #if defined(INET6) || defined(INET)
312215516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
312315516c77SSepherosa Ziehau 		    NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO);
312415516c77SSepherosa Ziehau #ifdef INET
312515516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
3126c49d47daSSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV4(
3127c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen,
312815516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
312915516c77SSepherosa Ziehau 		}
313015516c77SSepherosa Ziehau #endif
313115516c77SSepherosa Ziehau #if defined(INET6) && defined(INET)
313215516c77SSepherosa Ziehau 		else
313315516c77SSepherosa Ziehau #endif
313415516c77SSepherosa Ziehau #ifdef INET6
313515516c77SSepherosa Ziehau 		{
3136c49d47daSSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV6(
3137c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen,
313815516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
313915516c77SSepherosa Ziehau 		}
314015516c77SSepherosa Ziehau #endif
314115516c77SSepherosa Ziehau #endif	/* INET6 || INET */
314215516c77SSepherosa Ziehau 	} else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) {
314315516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
314415516c77SSepherosa Ziehau 		    NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
314515516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
314615516c77SSepherosa Ziehau 		    (CSUM_IP6_TCP | CSUM_IP6_UDP)) {
314715516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV6;
314815516c77SSepherosa Ziehau 		} else {
314915516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV4;
315015516c77SSepherosa Ziehau 			if (m_head->m_pkthdr.csum_flags & CSUM_IP)
315115516c77SSepherosa Ziehau 				*pi_data |= NDIS_TXCSUM_INFO_IPCS;
315215516c77SSepherosa Ziehau 		}
315315516c77SSepherosa Ziehau 
3154c49d47daSSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
3155c49d47daSSepherosa Ziehau 		    (CSUM_IP_TCP | CSUM_IP6_TCP)) {
3156c49d47daSSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_MKTCPCS(
3157c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen);
3158c49d47daSSepherosa Ziehau 		} else if (m_head->m_pkthdr.csum_flags &
3159c49d47daSSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP6_UDP)) {
3160c49d47daSSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_MKUDPCS(
3161c49d47daSSepherosa Ziehau 			    m_head->m_pkthdr.l2hlen + m_head->m_pkthdr.l3hlen);
3162c49d47daSSepherosa Ziehau 		}
316315516c77SSepherosa Ziehau 	}
316415516c77SSepherosa Ziehau 
3165dc13fee6SSepherosa Ziehau 	pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
31668fe90f73SSepherosa Ziehau 	/* Fixup RNDIS packet message total length */
31678fe90f73SSepherosa Ziehau 	pkt->rm_len += pkt_hlen;
316815516c77SSepherosa Ziehau 	/* Convert RNDIS packet message offsets */
31699130c4f7SSepherosa Ziehau 	pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt_hlen);
317015516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset);
317115516c77SSepherosa Ziehau 
317215516c77SSepherosa Ziehau 	/*
31738966e5d5SSepherosa Ziehau 	 * Fast path: Chimney sending.
317415516c77SSepherosa Ziehau 	 */
31758966e5d5SSepherosa Ziehau 	if (chim != NULL) {
3176dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tgt_txd = txd;
3177dc13fee6SSepherosa Ziehau 
3178dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL) {
3179dc13fee6SSepherosa Ziehau 			tgt_txd = txr->hn_agg_txd;
3180dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
3181dc13fee6SSepherosa Ziehau 			*m_head0 = NULL;
3182dc13fee6SSepherosa Ziehau #endif
3183dc13fee6SSepherosa Ziehau 		}
3184dc13fee6SSepherosa Ziehau 
3185dc13fee6SSepherosa Ziehau 		KASSERT(pkt == chim,
3186dc13fee6SSepherosa Ziehau 		    ("RNDIS pkt not in chimney sending buffer"));
3187dc13fee6SSepherosa Ziehau 		KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID,
3188dc13fee6SSepherosa Ziehau 		    ("chimney sending buffer is not used"));
3189dc13fee6SSepherosa Ziehau 		tgt_txd->chim_size += pkt->rm_len;
319015516c77SSepherosa Ziehau 
31918966e5d5SSepherosa Ziehau 		m_copydata(m_head, 0, m_head->m_pkthdr.len,
3192dc13fee6SSepherosa Ziehau 		    ((uint8_t *)chim) + pkt_hlen);
319315516c77SSepherosa Ziehau 
319415516c77SSepherosa Ziehau 		txr->hn_gpa_cnt = 0;
319515516c77SSepherosa Ziehau 		txr->hn_sendpkt = hn_txpkt_chim;
319615516c77SSepherosa Ziehau 		goto done;
319715516c77SSepherosa Ziehau 	}
3198dc13fee6SSepherosa Ziehau 
3199dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc"));
32008966e5d5SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
32018966e5d5SSepherosa Ziehau 	    ("chimney buffer is used"));
32028966e5d5SSepherosa Ziehau 	KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc"));
320315516c77SSepherosa Ziehau 
320415516c77SSepherosa Ziehau 	error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs);
3205dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
320615516c77SSepherosa Ziehau 		int freed;
320715516c77SSepherosa Ziehau 
320815516c77SSepherosa Ziehau 		/*
320915516c77SSepherosa Ziehau 		 * This mbuf is not linked w/ the txd yet, so free it now.
321015516c77SSepherosa Ziehau 		 */
321115516c77SSepherosa Ziehau 		m_freem(m_head);
321215516c77SSepherosa Ziehau 		*m_head0 = NULL;
321315516c77SSepherosa Ziehau 
321415516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
321515516c77SSepherosa Ziehau 		KASSERT(freed != 0,
321615516c77SSepherosa Ziehau 		    ("fail to free txd upon txdma error"));
321715516c77SSepherosa Ziehau 
321815516c77SSepherosa Ziehau 		txr->hn_txdma_failed++;
3219dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
322015516c77SSepherosa Ziehau 		return error;
322115516c77SSepherosa Ziehau 	}
322215516c77SSepherosa Ziehau 	*m_head0 = m_head;
322315516c77SSepherosa Ziehau 
322415516c77SSepherosa Ziehau 	/* +1 RNDIS packet message */
322515516c77SSepherosa Ziehau 	txr->hn_gpa_cnt = nsegs + 1;
322615516c77SSepherosa Ziehau 
322715516c77SSepherosa Ziehau 	/* send packet with page buffer */
322815516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr);
322915516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK;
3230dc13fee6SSepherosa Ziehau 	txr->hn_gpa[0].gpa_len = pkt_hlen;
323115516c77SSepherosa Ziehau 
323215516c77SSepherosa Ziehau 	/*
323315516c77SSepherosa Ziehau 	 * Fill the page buffers with mbuf info after the page
323415516c77SSepherosa Ziehau 	 * buffer for RNDIS packet message.
323515516c77SSepherosa Ziehau 	 */
323615516c77SSepherosa Ziehau 	for (i = 0; i < nsegs; ++i) {
323715516c77SSepherosa Ziehau 		struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1];
323815516c77SSepherosa Ziehau 
323915516c77SSepherosa Ziehau 		gpa->gpa_page = atop(segs[i].ds_addr);
324015516c77SSepherosa Ziehau 		gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK;
324115516c77SSepherosa Ziehau 		gpa->gpa_len = segs[i].ds_len;
324215516c77SSepherosa Ziehau 	}
324315516c77SSepherosa Ziehau 
324415516c77SSepherosa Ziehau 	txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
324515516c77SSepherosa Ziehau 	txd->chim_size = 0;
324615516c77SSepherosa Ziehau 	txr->hn_sendpkt = hn_txpkt_sglist;
324715516c77SSepherosa Ziehau done:
324815516c77SSepherosa Ziehau 	txd->m = m_head;
324915516c77SSepherosa Ziehau 
325015516c77SSepherosa Ziehau 	/* Set the completion routine */
325115516c77SSepherosa Ziehau 	hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd);
325215516c77SSepherosa Ziehau 
3253dc13fee6SSepherosa Ziehau 	/* Update temporary stats for later use. */
3254dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts++;
3255dc13fee6SSepherosa Ziehau 	txr->hn_stat_size += m_head->m_pkthdr.len;
3256dc13fee6SSepherosa Ziehau 	if (m_head->m_flags & M_MCAST)
3257dc13fee6SSepherosa Ziehau 		txr->hn_stat_mcasts++;
3258dc13fee6SSepherosa Ziehau 
325915516c77SSepherosa Ziehau 	return 0;
326015516c77SSepherosa Ziehau }
326115516c77SSepherosa Ziehau 
326215516c77SSepherosa Ziehau /*
326315516c77SSepherosa Ziehau  * NOTE:
326415516c77SSepherosa Ziehau  * If this function fails, then txd will be freed, but the mbuf
326515516c77SSepherosa Ziehau  * associated w/ the txd will _not_ be freed.
326615516c77SSepherosa Ziehau  */
326715516c77SSepherosa Ziehau static int
326815516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd)
326915516c77SSepherosa Ziehau {
32708e7d3136SSepherosa Ziehau 	int error, send_failed = 0, has_bpf;
327115516c77SSepherosa Ziehau 
327215516c77SSepherosa Ziehau again:
32738e7d3136SSepherosa Ziehau 	has_bpf = bpf_peers_present(ifp->if_bpf);
32748e7d3136SSepherosa Ziehau 	if (has_bpf) {
327515516c77SSepherosa Ziehau 		/*
32768e7d3136SSepherosa Ziehau 		 * Make sure that this txd and any aggregated txds are not
32778e7d3136SSepherosa Ziehau 		 * freed before ETHER_BPF_MTAP.
327815516c77SSepherosa Ziehau 		 */
327915516c77SSepherosa Ziehau 		hn_txdesc_hold(txd);
32808e7d3136SSepherosa Ziehau 	}
328115516c77SSepherosa Ziehau 	error = txr->hn_sendpkt(txr, txd);
328215516c77SSepherosa Ziehau 	if (!error) {
32838e7d3136SSepherosa Ziehau 		if (has_bpf) {
3284dc13fee6SSepherosa Ziehau 			const struct hn_txdesc *tmp_txd;
3285dc13fee6SSepherosa Ziehau 
328615516c77SSepherosa Ziehau 			ETHER_BPF_MTAP(ifp, txd->m);
3287dc13fee6SSepherosa Ziehau 			STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link)
3288dc13fee6SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, tmp_txd->m);
3289dc13fee6SSepherosa Ziehau 		}
3290dc13fee6SSepherosa Ziehau 
3291dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts);
329223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
329323bf9e15SSepherosa Ziehau 		if (!hn_use_if_start)
329423bf9e15SSepherosa Ziehau #endif
329523bf9e15SSepherosa Ziehau 		{
329615516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OBYTES,
3297dc13fee6SSepherosa Ziehau 			    txr->hn_stat_size);
3298dc13fee6SSepherosa Ziehau 			if (txr->hn_stat_mcasts != 0) {
3299dc13fee6SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OMCASTS,
3300dc13fee6SSepherosa Ziehau 				    txr->hn_stat_mcasts);
330115516c77SSepherosa Ziehau 			}
3302dc13fee6SSepherosa Ziehau 		}
3303dc13fee6SSepherosa Ziehau 		txr->hn_pkts += txr->hn_stat_pkts;
3304dc13fee6SSepherosa Ziehau 		txr->hn_sends++;
330515516c77SSepherosa Ziehau 	}
33068e7d3136SSepherosa Ziehau 	if (has_bpf)
330715516c77SSepherosa Ziehau 		hn_txdesc_put(txr, txd);
330815516c77SSepherosa Ziehau 
330915516c77SSepherosa Ziehau 	if (__predict_false(error)) {
331015516c77SSepherosa Ziehau 		int freed;
331115516c77SSepherosa Ziehau 
331215516c77SSepherosa Ziehau 		/*
331315516c77SSepherosa Ziehau 		 * This should "really rarely" happen.
331415516c77SSepherosa Ziehau 		 *
331515516c77SSepherosa Ziehau 		 * XXX Too many RX to be acked or too many sideband
331615516c77SSepherosa Ziehau 		 * commands to run?  Ask netvsc_channel_rollup()
331715516c77SSepherosa Ziehau 		 * to kick start later.
331815516c77SSepherosa Ziehau 		 */
331915516c77SSepherosa Ziehau 		txr->hn_has_txeof = 1;
332015516c77SSepherosa Ziehau 		if (!send_failed) {
332115516c77SSepherosa Ziehau 			txr->hn_send_failed++;
332215516c77SSepherosa Ziehau 			send_failed = 1;
332315516c77SSepherosa Ziehau 			/*
332415516c77SSepherosa Ziehau 			 * Try sending again after set hn_has_txeof;
332515516c77SSepherosa Ziehau 			 * in case that we missed the last
332615516c77SSepherosa Ziehau 			 * netvsc_channel_rollup().
332715516c77SSepherosa Ziehau 			 */
332815516c77SSepherosa Ziehau 			goto again;
332915516c77SSepherosa Ziehau 		}
333015516c77SSepherosa Ziehau 		if_printf(ifp, "send failed\n");
333115516c77SSepherosa Ziehau 
333215516c77SSepherosa Ziehau 		/*
333315516c77SSepherosa Ziehau 		 * Caller will perform further processing on the
333415516c77SSepherosa Ziehau 		 * associated mbuf, so don't free it in hn_txdesc_put();
333515516c77SSepherosa Ziehau 		 * only unload it from the DMA map in hn_txdesc_put(),
333615516c77SSepherosa Ziehau 		 * if it was loaded.
333715516c77SSepherosa Ziehau 		 */
333815516c77SSepherosa Ziehau 		txd->m = NULL;
333915516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
334015516c77SSepherosa Ziehau 		KASSERT(freed != 0,
334115516c77SSepherosa Ziehau 		    ("fail to free txd upon send error"));
334215516c77SSepherosa Ziehau 
334315516c77SSepherosa Ziehau 		txr->hn_send_failed++;
334415516c77SSepherosa Ziehau 	}
3345dc13fee6SSepherosa Ziehau 
3346dc13fee6SSepherosa Ziehau 	/* Reset temporary stats, after this sending is done. */
3347dc13fee6SSepherosa Ziehau 	txr->hn_stat_size = 0;
3348dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts = 0;
3349dc13fee6SSepherosa Ziehau 	txr->hn_stat_mcasts = 0;
3350dc13fee6SSepherosa Ziehau 
3351dc13fee6SSepherosa Ziehau 	return (error);
335215516c77SSepherosa Ziehau }
335315516c77SSepherosa Ziehau 
335415516c77SSepherosa Ziehau /*
335515516c77SSepherosa Ziehau  * Append the specified data to the indicated mbuf chain,
335615516c77SSepherosa Ziehau  * Extend the mbuf chain if the new data does not fit in
335715516c77SSepherosa Ziehau  * existing space.
335815516c77SSepherosa Ziehau  *
335915516c77SSepherosa Ziehau  * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c.
336015516c77SSepherosa Ziehau  * There should be an equivalent in the kernel mbuf code,
336115516c77SSepherosa Ziehau  * but there does not appear to be one yet.
336215516c77SSepherosa Ziehau  *
336315516c77SSepherosa Ziehau  * Differs from m_append() in that additional mbufs are
336415516c77SSepherosa Ziehau  * allocated with cluster size MJUMPAGESIZE, and filled
336515516c77SSepherosa Ziehau  * accordingly.
336615516c77SSepherosa Ziehau  *
3367*a491581fSWei Hu  * Return the last mbuf in the chain or NULL if failed to
3368*a491581fSWei Hu  * allocate new mbuf.
336915516c77SSepherosa Ziehau  */
3370*a491581fSWei Hu static struct mbuf *
337115516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp)
337215516c77SSepherosa Ziehau {
337315516c77SSepherosa Ziehau 	struct mbuf *m, *n;
337415516c77SSepherosa Ziehau 	int remainder, space;
337515516c77SSepherosa Ziehau 
337615516c77SSepherosa Ziehau 	for (m = m0; m->m_next != NULL; m = m->m_next)
337715516c77SSepherosa Ziehau 		;
337815516c77SSepherosa Ziehau 	remainder = len;
337915516c77SSepherosa Ziehau 	space = M_TRAILINGSPACE(m);
338015516c77SSepherosa Ziehau 	if (space > 0) {
338115516c77SSepherosa Ziehau 		/*
338215516c77SSepherosa Ziehau 		 * Copy into available space.
338315516c77SSepherosa Ziehau 		 */
338415516c77SSepherosa Ziehau 		if (space > remainder)
338515516c77SSepherosa Ziehau 			space = remainder;
338615516c77SSepherosa Ziehau 		bcopy(cp, mtod(m, caddr_t) + m->m_len, space);
338715516c77SSepherosa Ziehau 		m->m_len += space;
338815516c77SSepherosa Ziehau 		cp += space;
338915516c77SSepherosa Ziehau 		remainder -= space;
339015516c77SSepherosa Ziehau 	}
339115516c77SSepherosa Ziehau 	while (remainder > 0) {
339215516c77SSepherosa Ziehau 		/*
339315516c77SSepherosa Ziehau 		 * Allocate a new mbuf; could check space
339415516c77SSepherosa Ziehau 		 * and allocate a cluster instead.
339515516c77SSepherosa Ziehau 		 */
339615516c77SSepherosa Ziehau 		n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE);
339715516c77SSepherosa Ziehau 		if (n == NULL)
3398*a491581fSWei Hu 			return NULL;
339915516c77SSepherosa Ziehau 		n->m_len = min(MJUMPAGESIZE, remainder);
340015516c77SSepherosa Ziehau 		bcopy(cp, mtod(n, caddr_t), n->m_len);
340115516c77SSepherosa Ziehau 		cp += n->m_len;
340215516c77SSepherosa Ziehau 		remainder -= n->m_len;
340315516c77SSepherosa Ziehau 		m->m_next = n;
340415516c77SSepherosa Ziehau 		m = n;
340515516c77SSepherosa Ziehau 	}
340615516c77SSepherosa Ziehau 
3407*a491581fSWei Hu 	return m;
340815516c77SSepherosa Ziehau }
340915516c77SSepherosa Ziehau 
341015516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
341115516c77SSepherosa Ziehau static __inline int
341215516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m)
341315516c77SSepherosa Ziehau {
341415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
341515516c77SSepherosa Ziehau 	if (hn_lro_mbufq_depth) {
341615516c77SSepherosa Ziehau 		tcp_lro_queue_mbuf(lc, m);
341715516c77SSepherosa Ziehau 		return 0;
341815516c77SSepherosa Ziehau 	}
341915516c77SSepherosa Ziehau #endif
342015516c77SSepherosa Ziehau 	return tcp_lro_rx(lc, m, 0);
342115516c77SSepherosa Ziehau }
342215516c77SSepherosa Ziehau #endif
342315516c77SSepherosa Ziehau 
342415516c77SSepherosa Ziehau static int
3425*a491581fSWei Hu hn_rxpkt(struct hn_rx_ring *rxr)
342615516c77SSepherosa Ziehau {
3427a97fff19SSepherosa Ziehau 	struct ifnet *ifp, *hn_ifp = rxr->hn_ifp;
3428*a491581fSWei Hu 	struct mbuf *m_new, *n;
3429642ec226SSepherosa Ziehau 	int size, do_lro = 0, do_csum = 1, is_vf = 0;
3430642ec226SSepherosa Ziehau 	int hash_type = M_HASHTYPE_NONE;
3431db76829bSSepherosa Ziehau 	int l3proto = ETHERTYPE_MAX, l4proto = IPPROTO_DONE;
3432*a491581fSWei Hu 	int i;
343315516c77SSepherosa Ziehau 
3434642ec226SSepherosa Ziehau 	ifp = hn_ifp;
3435642ec226SSepherosa Ziehau 	if (rxr->hn_rxvf_ifp != NULL) {
3436a97fff19SSepherosa Ziehau 		/*
3437642ec226SSepherosa Ziehau 		 * Non-transparent mode VF; pretend this packet is from
3438642ec226SSepherosa Ziehau 		 * the VF.
3439a97fff19SSepherosa Ziehau 		 */
3440642ec226SSepherosa Ziehau 		ifp = rxr->hn_rxvf_ifp;
3441642ec226SSepherosa Ziehau 		is_vf = 1;
3442642ec226SSepherosa Ziehau 	} else if (rxr->hn_rx_flags & HN_RX_FLAG_XPNT_VF) {
3443642ec226SSepherosa Ziehau 		/* Transparent mode VF. */
3444642ec226SSepherosa Ziehau 		is_vf = 1;
3445642ec226SSepherosa Ziehau 	}
34465bdfd3fdSDexuan Cui 
3447b3b75d9cSSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
3448b3b75d9cSSepherosa Ziehau 		/*
3449b3b75d9cSSepherosa Ziehau 		 * NOTE:
3450b3b75d9cSSepherosa Ziehau 		 * See the NOTE of hn_rndis_init_fixat().  This
3451b3b75d9cSSepherosa Ziehau 		 * function can be reached, immediately after the
3452b3b75d9cSSepherosa Ziehau 		 * RNDIS is initialized but before the ifnet is
3453b3b75d9cSSepherosa Ziehau 		 * setup on the hn_attach() path; drop the unexpected
3454b3b75d9cSSepherosa Ziehau 		 * packets.
3455b3b75d9cSSepherosa Ziehau 		 */
3456b3b75d9cSSepherosa Ziehau 		return (0);
3457b3b75d9cSSepherosa Ziehau 	}
3458b3b75d9cSSepherosa Ziehau 
3459*a491581fSWei Hu 	if (__predict_false(rxr->rsc.pktlen < ETHER_HDR_LEN)) {
3460a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IERRORS, 1);
3461a97fff19SSepherosa Ziehau 		return (0);
3462a97fff19SSepherosa Ziehau 	}
3463a97fff19SSepherosa Ziehau 
3464*a491581fSWei Hu 	if (rxr->rsc.cnt == 1 && rxr->rsc.pktlen <= MHLEN) {
346515516c77SSepherosa Ziehau 		m_new = m_gethdr(M_NOWAIT, MT_DATA);
346615516c77SSepherosa Ziehau 		if (m_new == NULL) {
3467a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1);
346815516c77SSepherosa Ziehau 			return (0);
346915516c77SSepherosa Ziehau 		}
3470*a491581fSWei Hu 		memcpy(mtod(m_new, void *), rxr->rsc.frag_data[0],
3471*a491581fSWei Hu 		    rxr->rsc.frag_len[0]);
3472*a491581fSWei Hu 		m_new->m_pkthdr.len = m_new->m_len = rxr->rsc.frag_len[0];
347315516c77SSepherosa Ziehau 	} else {
347415516c77SSepherosa Ziehau 		/*
347515516c77SSepherosa Ziehau 		 * Get an mbuf with a cluster.  For packets 2K or less,
347615516c77SSepherosa Ziehau 		 * get a standard 2K cluster.  For anything larger, get a
347715516c77SSepherosa Ziehau 		 * 4K cluster.  Any buffers larger than 4K can cause problems
347815516c77SSepherosa Ziehau 		 * if looped around to the Hyper-V TX channel, so avoid them.
347915516c77SSepherosa Ziehau 		 */
348015516c77SSepherosa Ziehau 		size = MCLBYTES;
3481*a491581fSWei Hu 		if (rxr->rsc.pktlen > MCLBYTES) {
348215516c77SSepherosa Ziehau 			/* 4096 */
348315516c77SSepherosa Ziehau 			size = MJUMPAGESIZE;
348415516c77SSepherosa Ziehau 		}
348515516c77SSepherosa Ziehau 
348615516c77SSepherosa Ziehau 		m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size);
348715516c77SSepherosa Ziehau 		if (m_new == NULL) {
3488a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1);
348915516c77SSepherosa Ziehau 			return (0);
349015516c77SSepherosa Ziehau 		}
349115516c77SSepherosa Ziehau 
3492*a491581fSWei Hu 		n = m_new;
3493*a491581fSWei Hu 		for (i = 0; i < rxr->rsc.cnt; i++) {
3494*a491581fSWei Hu 			n = hv_m_append(n, rxr->rsc.frag_len[i],
3495*a491581fSWei Hu 			    rxr->rsc.frag_data[i]);
3496*a491581fSWei Hu 			if (n == NULL) {
3497*a491581fSWei Hu 				if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1);
3498*a491581fSWei Hu 				return (0);
3499*a491581fSWei Hu 			} else {
3500*a491581fSWei Hu 				m_new->m_pkthdr.len += rxr->rsc.frag_len[i];
350115516c77SSepherosa Ziehau 			}
3502*a491581fSWei Hu 		}
3503*a491581fSWei Hu 	}
3504*a491581fSWei Hu 	if (rxr->rsc.pktlen <= MHLEN)
3505*a491581fSWei Hu 		rxr->hn_small_pkts++;
3506*a491581fSWei Hu 
350715516c77SSepherosa Ziehau 	m_new->m_pkthdr.rcvif = ifp;
350815516c77SSepherosa Ziehau 
3509a97fff19SSepherosa Ziehau 	if (__predict_false((hn_ifp->if_capenable & IFCAP_RXCSUM) == 0))
351015516c77SSepherosa Ziehau 		do_csum = 0;
351115516c77SSepherosa Ziehau 
351215516c77SSepherosa Ziehau 	/* receive side checksum offload */
3513*a491581fSWei Hu 	if (rxr->rsc.csum_info != NULL) {
351415516c77SSepherosa Ziehau 		/* IP csum offload */
3515*a491581fSWei Hu 		if ((*(rxr->rsc.csum_info) & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) {
351615516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
351715516c77SSepherosa Ziehau 			    (CSUM_IP_CHECKED | CSUM_IP_VALID);
351815516c77SSepherosa Ziehau 			rxr->hn_csum_ip++;
351915516c77SSepherosa Ziehau 		}
352015516c77SSepherosa Ziehau 
352115516c77SSepherosa Ziehau 		/* TCP/UDP csum offload */
3522*a491581fSWei Hu 		if ((*(rxr->rsc.csum_info) & (NDIS_RXCSUM_INFO_UDPCS_OK |
352315516c77SSepherosa Ziehau 		     NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) {
352415516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
352515516c77SSepherosa Ziehau 			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
352615516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_data = 0xffff;
3527*a491581fSWei Hu 			if (*(rxr->rsc.csum_info) & NDIS_RXCSUM_INFO_TCPCS_OK)
352815516c77SSepherosa Ziehau 				rxr->hn_csum_tcp++;
352915516c77SSepherosa Ziehau 			else
353015516c77SSepherosa Ziehau 				rxr->hn_csum_udp++;
353115516c77SSepherosa Ziehau 		}
353215516c77SSepherosa Ziehau 
353315516c77SSepherosa Ziehau 		/*
353415516c77SSepherosa Ziehau 		 * XXX
353515516c77SSepherosa Ziehau 		 * As of this write (Oct 28th, 2016), host side will turn
353615516c77SSepherosa Ziehau 		 * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so
353715516c77SSepherosa Ziehau 		 * the do_lro setting here is actually _not_ accurate.  We
353815516c77SSepherosa Ziehau 		 * depend on the RSS hash type check to reset do_lro.
353915516c77SSepherosa Ziehau 		 */
3540*a491581fSWei Hu 		if ((*(rxr->rsc.csum_info) &
354115516c77SSepherosa Ziehau 		     (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) ==
354215516c77SSepherosa Ziehau 		    (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK))
354315516c77SSepherosa Ziehau 			do_lro = 1;
354415516c77SSepherosa Ziehau 	} else {
3545db76829bSSepherosa Ziehau 		hn_rxpkt_proto(m_new, &l3proto, &l4proto);
3546db76829bSSepherosa Ziehau 		if (l3proto == ETHERTYPE_IP) {
3547db76829bSSepherosa Ziehau 			if (l4proto == IPPROTO_TCP) {
354815516c77SSepherosa Ziehau 				if (do_csum &&
354915516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
355015516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_TCP)) {
355115516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
355215516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
355315516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
355415516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
355515516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
355615516c77SSepherosa Ziehau 				}
355715516c77SSepherosa Ziehau 				do_lro = 1;
3558db76829bSSepherosa Ziehau 			} else if (l4proto == IPPROTO_UDP) {
355915516c77SSepherosa Ziehau 				if (do_csum &&
356015516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
356115516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_UDP)) {
356215516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
356315516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
356415516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
356515516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
356615516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
356715516c77SSepherosa Ziehau 				}
3568db76829bSSepherosa Ziehau 			} else if (l4proto != IPPROTO_DONE && do_csum &&
356915516c77SSepherosa Ziehau 			    (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) {
357015516c77SSepherosa Ziehau 				rxr->hn_csum_trusted++;
357115516c77SSepherosa Ziehau 				m_new->m_pkthdr.csum_flags |=
357215516c77SSepherosa Ziehau 				    (CSUM_IP_CHECKED | CSUM_IP_VALID);
357315516c77SSepherosa Ziehau 			}
357415516c77SSepherosa Ziehau 		}
357515516c77SSepherosa Ziehau 	}
3576db76829bSSepherosa Ziehau 
3577*a491581fSWei Hu 	if (rxr->rsc.vlan_info != NULL) {
357815516c77SSepherosa Ziehau 		m_new->m_pkthdr.ether_vtag = EVL_MAKETAG(
3579*a491581fSWei Hu 		    NDIS_VLAN_INFO_ID(*(rxr->rsc.vlan_info)),
3580*a491581fSWei Hu 		    NDIS_VLAN_INFO_PRI(*(rxr->rsc.vlan_info)),
3581*a491581fSWei Hu 		    NDIS_VLAN_INFO_CFI(*(rxr->rsc.vlan_info)));
358215516c77SSepherosa Ziehau 		m_new->m_flags |= M_VLANTAG;
358315516c77SSepherosa Ziehau 	}
358415516c77SSepherosa Ziehau 
3585a97fff19SSepherosa Ziehau 	/*
3586a97fff19SSepherosa Ziehau 	 * If VF is activated (tranparent/non-transparent mode does not
3587a97fff19SSepherosa Ziehau 	 * matter here).
3588a97fff19SSepherosa Ziehau 	 *
3589a97fff19SSepherosa Ziehau 	 * - Disable LRO
3590a97fff19SSepherosa Ziehau 	 *
3591a97fff19SSepherosa Ziehau 	 *   hn(4) will only receive broadcast packets, multicast packets,
3592a97fff19SSepherosa Ziehau 	 *   TCP SYN and SYN|ACK (in Azure), LRO is useless for these
3593a97fff19SSepherosa Ziehau 	 *   packet types.
3594a97fff19SSepherosa Ziehau 	 *
3595a97fff19SSepherosa Ziehau 	 *   For non-transparent, we definitely _cannot_ enable LRO at
3596a97fff19SSepherosa Ziehau 	 *   all, since the LRO flush will use hn(4) as the receiving
3597a97fff19SSepherosa Ziehau 	 *   interface; i.e. hn_ifp->if_input(hn_ifp, m).
3598a97fff19SSepherosa Ziehau 	 */
3599642ec226SSepherosa Ziehau 	if (is_vf)
3600642ec226SSepherosa Ziehau 		do_lro = 0;
3601a97fff19SSepherosa Ziehau 
3602642ec226SSepherosa Ziehau 	/*
3603642ec226SSepherosa Ziehau 	 * If VF is activated (tranparent/non-transparent mode does not
3604642ec226SSepherosa Ziehau 	 * matter here), do _not_ mess with unsupported hash types or
3605642ec226SSepherosa Ziehau 	 * functions.
3606642ec226SSepherosa Ziehau 	 */
3607*a491581fSWei Hu 	if (rxr->rsc.hash_info != NULL) {
360815516c77SSepherosa Ziehau 		rxr->hn_rss_pkts++;
3609*a491581fSWei Hu 		m_new->m_pkthdr.flowid = *(rxr->rsc.hash_value);
3610642ec226SSepherosa Ziehau 		if (!is_vf)
361115516c77SSepherosa Ziehau 			hash_type = M_HASHTYPE_OPAQUE_HASH;
3612*a491581fSWei Hu 		if ((*(rxr->rsc.hash_info) & NDIS_HASH_FUNCTION_MASK) ==
361315516c77SSepherosa Ziehau 		    NDIS_HASH_FUNCTION_TOEPLITZ) {
3614*a491581fSWei Hu 			uint32_t type = (*(rxr->rsc.hash_info) & NDIS_HASH_TYPE_MASK &
3615642ec226SSepherosa Ziehau 			    rxr->hn_mbuf_hash);
361615516c77SSepherosa Ziehau 
361715516c77SSepherosa Ziehau 			/*
361815516c77SSepherosa Ziehau 			 * NOTE:
361915516c77SSepherosa Ziehau 			 * do_lro is resetted, if the hash types are not TCP
362015516c77SSepherosa Ziehau 			 * related.  See the comment in the above csum_flags
362115516c77SSepherosa Ziehau 			 * setup section.
362215516c77SSepherosa Ziehau 			 */
362315516c77SSepherosa Ziehau 			switch (type) {
362415516c77SSepherosa Ziehau 			case NDIS_HASH_IPV4:
362515516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV4;
362615516c77SSepherosa Ziehau 				do_lro = 0;
362715516c77SSepherosa Ziehau 				break;
362815516c77SSepherosa Ziehau 
362915516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV4:
363015516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV4;
3631db76829bSSepherosa Ziehau 				if (rxr->hn_rx_flags & HN_RX_FLAG_UDP_HASH) {
3632db76829bSSepherosa Ziehau 					int def_htype = M_HASHTYPE_OPAQUE_HASH;
3633db76829bSSepherosa Ziehau 
3634db76829bSSepherosa Ziehau 					if (is_vf)
3635db76829bSSepherosa Ziehau 						def_htype = M_HASHTYPE_NONE;
3636db76829bSSepherosa Ziehau 
3637db76829bSSepherosa Ziehau 					/*
3638db76829bSSepherosa Ziehau 					 * UDP 4-tuple hash is delivered as
3639db76829bSSepherosa Ziehau 					 * TCP 4-tuple hash.
3640db76829bSSepherosa Ziehau 					 */
3641db76829bSSepherosa Ziehau 					if (l3proto == ETHERTYPE_MAX) {
3642db76829bSSepherosa Ziehau 						hn_rxpkt_proto(m_new,
3643db76829bSSepherosa Ziehau 						    &l3proto, &l4proto);
3644db76829bSSepherosa Ziehau 					}
3645db76829bSSepherosa Ziehau 					if (l3proto == ETHERTYPE_IP) {
36466f12c42eSSepherosa Ziehau 						if (l4proto == IPPROTO_UDP &&
36476f12c42eSSepherosa Ziehau 						    (rxr->hn_mbuf_hash &
36486f12c42eSSepherosa Ziehau 						     NDIS_HASH_UDP_IPV4_X)) {
3649db76829bSSepherosa Ziehau 							hash_type =
3650db76829bSSepherosa Ziehau 							M_HASHTYPE_RSS_UDP_IPV4;
3651db76829bSSepherosa Ziehau 							do_lro = 0;
3652db76829bSSepherosa Ziehau 						} else if (l4proto !=
3653db76829bSSepherosa Ziehau 						    IPPROTO_TCP) {
3654db76829bSSepherosa Ziehau 							hash_type = def_htype;
3655db76829bSSepherosa Ziehau 							do_lro = 0;
3656db76829bSSepherosa Ziehau 						}
3657db76829bSSepherosa Ziehau 					} else {
3658db76829bSSepherosa Ziehau 						hash_type = def_htype;
3659db76829bSSepherosa Ziehau 						do_lro = 0;
3660db76829bSSepherosa Ziehau 					}
3661db76829bSSepherosa Ziehau 				}
366215516c77SSepherosa Ziehau 				break;
366315516c77SSepherosa Ziehau 
366415516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6:
366515516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6;
366615516c77SSepherosa Ziehau 				do_lro = 0;
366715516c77SSepherosa Ziehau 				break;
366815516c77SSepherosa Ziehau 
366915516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6_EX:
367015516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6_EX;
367115516c77SSepherosa Ziehau 				do_lro = 0;
367215516c77SSepherosa Ziehau 				break;
367315516c77SSepherosa Ziehau 
367415516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6:
367515516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6;
367615516c77SSepherosa Ziehau 				break;
367715516c77SSepherosa Ziehau 
367815516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6_EX:
367915516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX;
368015516c77SSepherosa Ziehau 				break;
368115516c77SSepherosa Ziehau 			}
368215516c77SSepherosa Ziehau 		}
3683642ec226SSepherosa Ziehau 	} else if (!is_vf) {
368415516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
368515516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE;
368615516c77SSepherosa Ziehau 	}
368715516c77SSepherosa Ziehau 	M_HASHTYPE_SET(m_new, hash_type);
368815516c77SSepherosa Ziehau 
3689a97fff19SSepherosa Ziehau 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
3690a97fff19SSepherosa Ziehau 	if (hn_ifp != ifp) {
3691a97fff19SSepherosa Ziehau 		const struct ether_header *eh;
3692a97fff19SSepherosa Ziehau 
369315516c77SSepherosa Ziehau 		/*
3694a97fff19SSepherosa Ziehau 		 * Non-transparent mode VF is activated.
369515516c77SSepherosa Ziehau 		 */
369615516c77SSepherosa Ziehau 
3697a97fff19SSepherosa Ziehau 		/*
3698a97fff19SSepherosa Ziehau 		 * Allow tapping on hn(4).
3699a97fff19SSepherosa Ziehau 		 */
3700a97fff19SSepherosa Ziehau 		ETHER_BPF_MTAP(hn_ifp, m_new);
3701a97fff19SSepherosa Ziehau 
3702a97fff19SSepherosa Ziehau 		/*
3703a97fff19SSepherosa Ziehau 		 * Update hn(4)'s stats.
3704a97fff19SSepherosa Ziehau 		 */
3705a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1);
3706a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IBYTES, m_new->m_pkthdr.len);
3707a97fff19SSepherosa Ziehau 		/* Checked at the beginning of this function. */
3708a97fff19SSepherosa Ziehau 		KASSERT(m_new->m_len >= ETHER_HDR_LEN, ("not ethernet frame"));
3709a97fff19SSepherosa Ziehau 		eh = mtod(m_new, struct ether_header *);
3710a97fff19SSepherosa Ziehau 		if (ETHER_IS_MULTICAST(eh->ether_dhost))
3711a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IMCASTS, 1);
3712a97fff19SSepherosa Ziehau 	}
371315516c77SSepherosa Ziehau 	rxr->hn_pkts++;
371415516c77SSepherosa Ziehau 
3715a97fff19SSepherosa Ziehau 	if ((hn_ifp->if_capenable & IFCAP_LRO) && do_lro) {
371615516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
371715516c77SSepherosa Ziehau 		struct lro_ctrl *lro = &rxr->hn_lro;
371815516c77SSepherosa Ziehau 
371915516c77SSepherosa Ziehau 		if (lro->lro_cnt) {
372015516c77SSepherosa Ziehau 			rxr->hn_lro_tried++;
372115516c77SSepherosa Ziehau 			if (hn_lro_rx(lro, m_new) == 0) {
372215516c77SSepherosa Ziehau 				/* DONE! */
372315516c77SSepherosa Ziehau 				return 0;
372415516c77SSepherosa Ziehau 			}
372515516c77SSepherosa Ziehau 		}
372615516c77SSepherosa Ziehau #endif
372715516c77SSepherosa Ziehau 	}
3728a97fff19SSepherosa Ziehau 	ifp->if_input(ifp, m_new);
372915516c77SSepherosa Ziehau 
373015516c77SSepherosa Ziehau 	return (0);
373115516c77SSepherosa Ziehau }
373215516c77SSepherosa Ziehau 
373315516c77SSepherosa Ziehau static int
373415516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
373515516c77SSepherosa Ziehau {
373615516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
37379c6cae24SSepherosa Ziehau 	struct ifreq *ifr = (struct ifreq *)data, ifr_vf;
37389c6cae24SSepherosa Ziehau 	struct ifnet *vf_ifp;
373915516c77SSepherosa Ziehau 	int mask, error = 0;
37408c068aa5SSepherosa Ziehau 	struct ifrsskey *ifrk;
37418c068aa5SSepherosa Ziehau 	struct ifrsshash *ifrh;
3742eb2fe044SSepherosa Ziehau 	uint32_t mtu;
374315516c77SSepherosa Ziehau 
374415516c77SSepherosa Ziehau 	switch (cmd) {
374515516c77SSepherosa Ziehau 	case SIOCSIFMTU:
374615516c77SSepherosa Ziehau 		if (ifr->ifr_mtu > HN_MTU_MAX) {
374715516c77SSepherosa Ziehau 			error = EINVAL;
374815516c77SSepherosa Ziehau 			break;
374915516c77SSepherosa Ziehau 		}
375015516c77SSepherosa Ziehau 
375115516c77SSepherosa Ziehau 		HN_LOCK(sc);
375215516c77SSepherosa Ziehau 
375315516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
375415516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
375515516c77SSepherosa Ziehau 			break;
375615516c77SSepherosa Ziehau 		}
375715516c77SSepherosa Ziehau 
375815516c77SSepherosa Ziehau 		if ((sc->hn_caps & HN_CAP_MTU) == 0) {
375915516c77SSepherosa Ziehau 			/* Can't change MTU */
376015516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
376115516c77SSepherosa Ziehau 			error = EOPNOTSUPP;
376215516c77SSepherosa Ziehau 			break;
376315516c77SSepherosa Ziehau 		}
376415516c77SSepherosa Ziehau 
376515516c77SSepherosa Ziehau 		if (ifp->if_mtu == ifr->ifr_mtu) {
376615516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
376715516c77SSepherosa Ziehau 			break;
376815516c77SSepherosa Ziehau 		}
376915516c77SSepherosa Ziehau 
37709c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
37719c6cae24SSepherosa Ziehau 			vf_ifp = sc->hn_vf_ifp;
37729c6cae24SSepherosa Ziehau 			ifr_vf = *ifr;
37739c6cae24SSepherosa Ziehau 			strlcpy(ifr_vf.ifr_name, vf_ifp->if_xname,
37749c6cae24SSepherosa Ziehau 			    sizeof(ifr_vf.ifr_name));
37759c6cae24SSepherosa Ziehau 			error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU,
37769c6cae24SSepherosa Ziehau 			    (caddr_t)&ifr_vf);
37779c6cae24SSepherosa Ziehau 			if (error) {
37789c6cae24SSepherosa Ziehau 				HN_UNLOCK(sc);
37799c6cae24SSepherosa Ziehau 				if_printf(ifp, "%s SIOCSIFMTU %d failed: %d\n",
37809c6cae24SSepherosa Ziehau 				    vf_ifp->if_xname, ifr->ifr_mtu, error);
37819c6cae24SSepherosa Ziehau 				break;
37829c6cae24SSepherosa Ziehau 			}
37839c6cae24SSepherosa Ziehau 		}
37849c6cae24SSepherosa Ziehau 
378515516c77SSepherosa Ziehau 		/*
378615516c77SSepherosa Ziehau 		 * Suspend this interface before the synthetic parts
378715516c77SSepherosa Ziehau 		 * are ripped.
378815516c77SSepherosa Ziehau 		 */
378915516c77SSepherosa Ziehau 		hn_suspend(sc);
379015516c77SSepherosa Ziehau 
379115516c77SSepherosa Ziehau 		/*
379215516c77SSepherosa Ziehau 		 * Detach the synthetics parts, i.e. NVS and RNDIS.
379315516c77SSepherosa Ziehau 		 */
379415516c77SSepherosa Ziehau 		hn_synth_detach(sc);
379515516c77SSepherosa Ziehau 
379615516c77SSepherosa Ziehau 		/*
379715516c77SSepherosa Ziehau 		 * Reattach the synthetic parts, i.e. NVS and RNDIS,
379815516c77SSepherosa Ziehau 		 * with the new MTU setting.
379915516c77SSepherosa Ziehau 		 */
380015516c77SSepherosa Ziehau 		error = hn_synth_attach(sc, ifr->ifr_mtu);
380115516c77SSepherosa Ziehau 		if (error) {
380215516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
380315516c77SSepherosa Ziehau 			break;
380415516c77SSepherosa Ziehau 		}
380515516c77SSepherosa Ziehau 
3806eb2fe044SSepherosa Ziehau 		error = hn_rndis_get_mtu(sc, &mtu);
3807eb2fe044SSepherosa Ziehau 		if (error)
3808eb2fe044SSepherosa Ziehau 			mtu = ifr->ifr_mtu;
3809eb2fe044SSepherosa Ziehau 		else if (bootverbose)
3810eb2fe044SSepherosa Ziehau 			if_printf(ifp, "RNDIS mtu %u\n", mtu);
3811eb2fe044SSepherosa Ziehau 
381215516c77SSepherosa Ziehau 		/*
381315516c77SSepherosa Ziehau 		 * Commit the requested MTU, after the synthetic parts
381415516c77SSepherosa Ziehau 		 * have been successfully attached.
381515516c77SSepherosa Ziehau 		 */
3816eb2fe044SSepherosa Ziehau 		if (mtu >= ifr->ifr_mtu) {
3817eb2fe044SSepherosa Ziehau 			mtu = ifr->ifr_mtu;
3818eb2fe044SSepherosa Ziehau 		} else {
3819eb2fe044SSepherosa Ziehau 			if_printf(ifp, "fixup mtu %d -> %u\n",
3820eb2fe044SSepherosa Ziehau 			    ifr->ifr_mtu, mtu);
3821eb2fe044SSepherosa Ziehau 		}
3822eb2fe044SSepherosa Ziehau 		ifp->if_mtu = mtu;
382315516c77SSepherosa Ziehau 
382415516c77SSepherosa Ziehau 		/*
38259c6cae24SSepherosa Ziehau 		 * Synthetic parts' reattach may change the chimney
38269c6cae24SSepherosa Ziehau 		 * sending size; update it.
382715516c77SSepherosa Ziehau 		 */
382815516c77SSepherosa Ziehau 		if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax)
382915516c77SSepherosa Ziehau 			hn_set_chim_size(sc, sc->hn_chim_szmax);
38309c6cae24SSepherosa Ziehau 
38319c6cae24SSepherosa Ziehau 		/*
38329c6cae24SSepherosa Ziehau 		 * Make sure that various parameters based on MTU are
38339c6cae24SSepherosa Ziehau 		 * still valid, after the MTU change.
38349c6cae24SSepherosa Ziehau 		 */
38359c6cae24SSepherosa Ziehau 		hn_mtu_change_fixup(sc);
383615516c77SSepherosa Ziehau 
383715516c77SSepherosa Ziehau 		/*
383815516c77SSepherosa Ziehau 		 * All done!  Resume the interface now.
383915516c77SSepherosa Ziehau 		 */
384015516c77SSepherosa Ziehau 		hn_resume(sc);
384115516c77SSepherosa Ziehau 
3842d0cd8231SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXVF) ||
3843d0cd8231SSepherosa Ziehau 		    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
38449c6cae24SSepherosa Ziehau 			/*
38459c6cae24SSepherosa Ziehau 			 * Since we have reattached the NVS part,
38469c6cae24SSepherosa Ziehau 			 * change the datapath to VF again; in case
38479c6cae24SSepherosa Ziehau 			 * that it is lost, after the NVS was detached.
38489c6cae24SSepherosa Ziehau 			 */
38499c6cae24SSepherosa Ziehau 			hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF);
38509c6cae24SSepherosa Ziehau 		}
38519c6cae24SSepherosa Ziehau 
385215516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
385315516c77SSepherosa Ziehau 		break;
385415516c77SSepherosa Ziehau 
385515516c77SSepherosa Ziehau 	case SIOCSIFFLAGS:
385615516c77SSepherosa Ziehau 		HN_LOCK(sc);
385715516c77SSepherosa Ziehau 
385815516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
385915516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
386015516c77SSepherosa Ziehau 			break;
386115516c77SSepherosa Ziehau 		}
386215516c77SSepherosa Ziehau 
38639c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc))
38649c6cae24SSepherosa Ziehau 			hn_xpnt_vf_saveifflags(sc);
38659c6cae24SSepherosa Ziehau 
386615516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_UP) {
3867fdc4f478SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
3868fdc4f478SSepherosa Ziehau 				/*
3869fdc4f478SSepherosa Ziehau 				 * Caller meight hold mutex, e.g.
3870fdc4f478SSepherosa Ziehau 				 * bpf; use busy-wait for the RNDIS
3871fdc4f478SSepherosa Ziehau 				 * reply.
3872fdc4f478SSepherosa Ziehau 				 */
3873fdc4f478SSepherosa Ziehau 				HN_NO_SLEEPING(sc);
3874c08f7b2cSSepherosa Ziehau 				hn_rxfilter_config(sc);
3875fdc4f478SSepherosa Ziehau 				HN_SLEEPING_OK(sc);
38769c6cae24SSepherosa Ziehau 
38779c6cae24SSepherosa Ziehau 				if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
38789c6cae24SSepherosa Ziehau 					error = hn_xpnt_vf_iocsetflags(sc);
3879fdc4f478SSepherosa Ziehau 			} else {
388015516c77SSepherosa Ziehau 				hn_init_locked(sc);
3881fdc4f478SSepherosa Ziehau 			}
388215516c77SSepherosa Ziehau 		} else {
388315516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
38845bdfd3fdSDexuan Cui 				hn_stop(sc, false);
388515516c77SSepherosa Ziehau 		}
388615516c77SSepherosa Ziehau 		sc->hn_if_flags = ifp->if_flags;
388715516c77SSepherosa Ziehau 
388815516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
388915516c77SSepherosa Ziehau 		break;
389015516c77SSepherosa Ziehau 
389115516c77SSepherosa Ziehau 	case SIOCSIFCAP:
389215516c77SSepherosa Ziehau 		HN_LOCK(sc);
38939c6cae24SSepherosa Ziehau 
38949c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
38959c6cae24SSepherosa Ziehau 			ifr_vf = *ifr;
38969c6cae24SSepherosa Ziehau 			strlcpy(ifr_vf.ifr_name, sc->hn_vf_ifp->if_xname,
38979c6cae24SSepherosa Ziehau 			    sizeof(ifr_vf.ifr_name));
38989c6cae24SSepherosa Ziehau 			error = hn_xpnt_vf_iocsetcaps(sc, &ifr_vf);
38999c6cae24SSepherosa Ziehau 			HN_UNLOCK(sc);
39009c6cae24SSepherosa Ziehau 			break;
39019c6cae24SSepherosa Ziehau 		}
39029c6cae24SSepherosa Ziehau 
39039c6cae24SSepherosa Ziehau 		/*
39049c6cae24SSepherosa Ziehau 		 * Fix up requested capabilities w/ supported capabilities,
39059c6cae24SSepherosa Ziehau 		 * since the supported capabilities could have been changed.
39069c6cae24SSepherosa Ziehau 		 */
39079c6cae24SSepherosa Ziehau 		mask = (ifr->ifr_reqcap & ifp->if_capabilities) ^
39089c6cae24SSepherosa Ziehau 		    ifp->if_capenable;
390915516c77SSepherosa Ziehau 
391015516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM) {
391115516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM;
391215516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM)
391315516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc);
391415516c77SSepherosa Ziehau 			else
391515516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc);
391615516c77SSepherosa Ziehau 		}
391715516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM_IPV6) {
391815516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
391915516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
392015516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc);
392115516c77SSepherosa Ziehau 			else
392215516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc);
392315516c77SSepherosa Ziehau 		}
392415516c77SSepherosa Ziehau 
392515516c77SSepherosa Ziehau 		/* TODO: flip RNDIS offload parameters for RXCSUM. */
392615516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM)
392715516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM;
392815516c77SSepherosa Ziehau #ifdef foo
392915516c77SSepherosa Ziehau 		/* We can't diff IPv6 packets from IPv4 packets on RX path. */
393015516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM_IPV6)
393115516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
393215516c77SSepherosa Ziehau #endif
393315516c77SSepherosa Ziehau 
393415516c77SSepherosa Ziehau 		if (mask & IFCAP_LRO)
393515516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_LRO;
393615516c77SSepherosa Ziehau 
393715516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO4) {
393815516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO4;
393915516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO4)
394015516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP_TSO;
394115516c77SSepherosa Ziehau 			else
394215516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP_TSO;
394315516c77SSepherosa Ziehau 		}
394415516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO6) {
394515516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO6;
394615516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO6)
394715516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP6_TSO;
394815516c77SSepherosa Ziehau 			else
394915516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP6_TSO;
395015516c77SSepherosa Ziehau 		}
395115516c77SSepherosa Ziehau 
395215516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
395315516c77SSepherosa Ziehau 		break;
395415516c77SSepherosa Ziehau 
395515516c77SSepherosa Ziehau 	case SIOCADDMULTI:
395615516c77SSepherosa Ziehau 	case SIOCDELMULTI:
395715516c77SSepherosa Ziehau 		HN_LOCK(sc);
395815516c77SSepherosa Ziehau 
395915516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
396015516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
396115516c77SSepherosa Ziehau 			break;
396215516c77SSepherosa Ziehau 		}
3963fdc4f478SSepherosa Ziehau 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
3964fdc4f478SSepherosa Ziehau 			/*
3965fdc4f478SSepherosa Ziehau 			 * Multicast uses mutex; use busy-wait for
3966fdc4f478SSepherosa Ziehau 			 * the RNDIS reply.
3967fdc4f478SSepherosa Ziehau 			 */
3968fdc4f478SSepherosa Ziehau 			HN_NO_SLEEPING(sc);
3969c08f7b2cSSepherosa Ziehau 			hn_rxfilter_config(sc);
3970fdc4f478SSepherosa Ziehau 			HN_SLEEPING_OK(sc);
3971fdc4f478SSepherosa Ziehau 		}
397215516c77SSepherosa Ziehau 
39739c6cae24SSepherosa Ziehau 		/* XXX vlan(4) style mcast addr maintenance */
39749c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
39759c6cae24SSepherosa Ziehau 			int old_if_flags;
39769c6cae24SSepherosa Ziehau 
39779c6cae24SSepherosa Ziehau 			old_if_flags = sc->hn_vf_ifp->if_flags;
39789c6cae24SSepherosa Ziehau 			hn_xpnt_vf_saveifflags(sc);
39799c6cae24SSepherosa Ziehau 
39809c6cae24SSepherosa Ziehau 			if ((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) &&
39819c6cae24SSepherosa Ziehau 			    ((old_if_flags ^ sc->hn_vf_ifp->if_flags) &
39829c6cae24SSepherosa Ziehau 			     IFF_ALLMULTI))
39839c6cae24SSepherosa Ziehau 				error = hn_xpnt_vf_iocsetflags(sc);
39849c6cae24SSepherosa Ziehau 		}
39859c6cae24SSepherosa Ziehau 
398615516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
398715516c77SSepherosa Ziehau 		break;
398815516c77SSepherosa Ziehau 
398915516c77SSepherosa Ziehau 	case SIOCSIFMEDIA:
399015516c77SSepherosa Ziehau 	case SIOCGIFMEDIA:
39919c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
39929c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
39939c6cae24SSepherosa Ziehau 			/*
39949c6cae24SSepherosa Ziehau 			 * SIOCGIFMEDIA expects ifmediareq, so don't
39959c6cae24SSepherosa Ziehau 			 * create and pass ifr_vf to the VF here; just
39969c6cae24SSepherosa Ziehau 			 * replace the ifr_name.
39979c6cae24SSepherosa Ziehau 			 */
39989c6cae24SSepherosa Ziehau 			vf_ifp = sc->hn_vf_ifp;
39999c6cae24SSepherosa Ziehau 			strlcpy(ifr->ifr_name, vf_ifp->if_xname,
40009c6cae24SSepherosa Ziehau 			    sizeof(ifr->ifr_name));
40019c6cae24SSepherosa Ziehau 			error = vf_ifp->if_ioctl(vf_ifp, cmd, data);
40029c6cae24SSepherosa Ziehau 			/* Restore the ifr_name. */
40039c6cae24SSepherosa Ziehau 			strlcpy(ifr->ifr_name, ifp->if_xname,
40049c6cae24SSepherosa Ziehau 			    sizeof(ifr->ifr_name));
40059c6cae24SSepherosa Ziehau 			HN_UNLOCK(sc);
40069c6cae24SSepherosa Ziehau 			break;
40079c6cae24SSepherosa Ziehau 		}
40089c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
400915516c77SSepherosa Ziehau 		error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd);
401015516c77SSepherosa Ziehau 		break;
401115516c77SSepherosa Ziehau 
40128c068aa5SSepherosa Ziehau 	case SIOCGIFRSSHASH:
40138c068aa5SSepherosa Ziehau 		ifrh = (struct ifrsshash *)data;
40148c068aa5SSepherosa Ziehau 		HN_LOCK(sc);
40158c068aa5SSepherosa Ziehau 		if (sc->hn_rx_ring_inuse == 1) {
40168c068aa5SSepherosa Ziehau 			HN_UNLOCK(sc);
40178c068aa5SSepherosa Ziehau 			ifrh->ifrh_func = RSS_FUNC_NONE;
40188c068aa5SSepherosa Ziehau 			ifrh->ifrh_types = 0;
40198c068aa5SSepherosa Ziehau 			break;
40208c068aa5SSepherosa Ziehau 		}
40218c068aa5SSepherosa Ziehau 
40228c068aa5SSepherosa Ziehau 		if (sc->hn_rss_hash & NDIS_HASH_FUNCTION_TOEPLITZ)
40238c068aa5SSepherosa Ziehau 			ifrh->ifrh_func = RSS_FUNC_TOEPLITZ;
40248c068aa5SSepherosa Ziehau 		else
40258c068aa5SSepherosa Ziehau 			ifrh->ifrh_func = RSS_FUNC_PRIVATE;
4026642ec226SSepherosa Ziehau 		ifrh->ifrh_types = hn_rss_type_fromndis(sc->hn_rss_hash);
40278c068aa5SSepherosa Ziehau 		HN_UNLOCK(sc);
40288c068aa5SSepherosa Ziehau 		break;
40298c068aa5SSepherosa Ziehau 
40308c068aa5SSepherosa Ziehau 	case SIOCGIFRSSKEY:
40318c068aa5SSepherosa Ziehau 		ifrk = (struct ifrsskey *)data;
40328c068aa5SSepherosa Ziehau 		HN_LOCK(sc);
40338c068aa5SSepherosa Ziehau 		if (sc->hn_rx_ring_inuse == 1) {
40348c068aa5SSepherosa Ziehau 			HN_UNLOCK(sc);
40358c068aa5SSepherosa Ziehau 			ifrk->ifrk_func = RSS_FUNC_NONE;
40368c068aa5SSepherosa Ziehau 			ifrk->ifrk_keylen = 0;
40378c068aa5SSepherosa Ziehau 			break;
40388c068aa5SSepherosa Ziehau 		}
40398c068aa5SSepherosa Ziehau 		if (sc->hn_rss_hash & NDIS_HASH_FUNCTION_TOEPLITZ)
40408c068aa5SSepherosa Ziehau 			ifrk->ifrk_func = RSS_FUNC_TOEPLITZ;
40418c068aa5SSepherosa Ziehau 		else
40428c068aa5SSepherosa Ziehau 			ifrk->ifrk_func = RSS_FUNC_PRIVATE;
40438c068aa5SSepherosa Ziehau 		ifrk->ifrk_keylen = NDIS_HASH_KEYSIZE_TOEPLITZ;
40448c068aa5SSepherosa Ziehau 		memcpy(ifrk->ifrk_key, sc->hn_rss.rss_key,
40458c068aa5SSepherosa Ziehau 		    NDIS_HASH_KEYSIZE_TOEPLITZ);
40468c068aa5SSepherosa Ziehau 		HN_UNLOCK(sc);
40478c068aa5SSepherosa Ziehau 		break;
40488c068aa5SSepherosa Ziehau 
404915516c77SSepherosa Ziehau 	default:
405015516c77SSepherosa Ziehau 		error = ether_ioctl(ifp, cmd, data);
405115516c77SSepherosa Ziehau 		break;
405215516c77SSepherosa Ziehau 	}
405315516c77SSepherosa Ziehau 	return (error);
405415516c77SSepherosa Ziehau }
405515516c77SSepherosa Ziehau 
405615516c77SSepherosa Ziehau static void
40575bdfd3fdSDexuan Cui hn_stop(struct hn_softc *sc, bool detaching)
405815516c77SSepherosa Ziehau {
405915516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
406015516c77SSepherosa Ziehau 	int i;
406115516c77SSepherosa Ziehau 
406215516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
406315516c77SSepherosa Ziehau 
406415516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
406515516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
406615516c77SSepherosa Ziehau 
40679c6cae24SSepherosa Ziehau 	/* Clear RUNNING bit ASAP. */
40689c6cae24SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
40699c6cae24SSepherosa Ziehau 
40706c1204dfSSepherosa Ziehau 	/* Disable polling. */
40716c1204dfSSepherosa Ziehau 	hn_polling(sc, 0);
40726c1204dfSSepherosa Ziehau 
40739c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) {
40749c6cae24SSepherosa Ziehau 		KASSERT(sc->hn_vf_ifp != NULL,
40759c6cae24SSepherosa Ziehau 		    ("%s: VF is not attached", ifp->if_xname));
40769c6cae24SSepherosa Ziehau 
4077a97fff19SSepherosa Ziehau 		/* Mark transparent mode VF as disabled. */
4078a97fff19SSepherosa Ziehau 		hn_xpnt_vf_setdisable(sc, false /* keep hn_vf_ifp */);
40799c6cae24SSepherosa Ziehau 
40809c6cae24SSepherosa Ziehau 		/*
40819c6cae24SSepherosa Ziehau 		 * NOTE:
40829c6cae24SSepherosa Ziehau 		 * Datapath setting must happen _before_ bringing
40839c6cae24SSepherosa Ziehau 		 * the VF down.
40849c6cae24SSepherosa Ziehau 		 */
40859c6cae24SSepherosa Ziehau 		hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH);
40869c6cae24SSepherosa Ziehau 
40879c6cae24SSepherosa Ziehau 		/*
40889c6cae24SSepherosa Ziehau 		 * Bring the VF down.
40899c6cae24SSepherosa Ziehau 		 */
40909c6cae24SSepherosa Ziehau 		hn_xpnt_vf_saveifflags(sc);
40919c6cae24SSepherosa Ziehau 		sc->hn_vf_ifp->if_flags &= ~IFF_UP;
40929c6cae24SSepherosa Ziehau 		hn_xpnt_vf_iocsetflags(sc);
40939c6cae24SSepherosa Ziehau 	}
40949c6cae24SSepherosa Ziehau 
40959c6cae24SSepherosa Ziehau 	/* Suspend data transfers. */
409615516c77SSepherosa Ziehau 	hn_suspend_data(sc);
409715516c77SSepherosa Ziehau 
409815516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
409915516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
410015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
410115516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
41025bdfd3fdSDexuan Cui 
41035bdfd3fdSDexuan Cui 	/*
41049c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is active, make sure
41059c6cae24SSepherosa Ziehau 	 * that the RX filter still allows packet reception.
41065bdfd3fdSDexuan Cui 	 */
4107962f0357SSepherosa Ziehau 	if (!detaching && (sc->hn_flags & HN_FLAG_RXVF))
41085bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
410915516c77SSepherosa Ziehau }
411015516c77SSepherosa Ziehau 
411115516c77SSepherosa Ziehau static void
411215516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc)
411315516c77SSepherosa Ziehau {
411415516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
411515516c77SSepherosa Ziehau 	int i;
411615516c77SSepherosa Ziehau 
411715516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
411815516c77SSepherosa Ziehau 
411915516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
412015516c77SSepherosa Ziehau 		return;
412115516c77SSepherosa Ziehau 
412215516c77SSepherosa Ziehau 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
412315516c77SSepherosa Ziehau 		return;
412415516c77SSepherosa Ziehau 
412515516c77SSepherosa Ziehau 	/* Configure RX filter */
4126c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
412715516c77SSepherosa Ziehau 
412815516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
412915516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
413015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
413115516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
413215516c77SSepherosa Ziehau 
413315516c77SSepherosa Ziehau 	/* Clear TX 'suspended' bit. */
413415516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_inuse);
413515516c77SSepherosa Ziehau 
41369c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_isready(sc)) {
41379c6cae24SSepherosa Ziehau 		/* Initialize transparent VF. */
41389c6cae24SSepherosa Ziehau 		hn_xpnt_vf_init(sc);
41399c6cae24SSepherosa Ziehau 	}
41409c6cae24SSepherosa Ziehau 
414115516c77SSepherosa Ziehau 	/* Everything is ready; unleash! */
414215516c77SSepherosa Ziehau 	atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
41436c1204dfSSepherosa Ziehau 
41446c1204dfSSepherosa Ziehau 	/* Re-enable polling if requested. */
41456c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz > 0)
41466c1204dfSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
414715516c77SSepherosa Ziehau }
414815516c77SSepherosa Ziehau 
414915516c77SSepherosa Ziehau static void
415015516c77SSepherosa Ziehau hn_init(void *xsc)
415115516c77SSepherosa Ziehau {
415215516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
415315516c77SSepherosa Ziehau 
415415516c77SSepherosa Ziehau 	HN_LOCK(sc);
415515516c77SSepherosa Ziehau 	hn_init_locked(sc);
415615516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
415715516c77SSepherosa Ziehau }
415815516c77SSepherosa Ziehau 
415915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
416015516c77SSepherosa Ziehau 
416115516c77SSepherosa Ziehau static int
416215516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
416315516c77SSepherosa Ziehau {
416415516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
416515516c77SSepherosa Ziehau 	unsigned int lenlim;
416615516c77SSepherosa Ziehau 	int error;
416715516c77SSepherosa Ziehau 
416815516c77SSepherosa Ziehau 	lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim;
416915516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &lenlim, 0, req);
417015516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
417115516c77SSepherosa Ziehau 		return error;
417215516c77SSepherosa Ziehau 
417315516c77SSepherosa Ziehau 	HN_LOCK(sc);
417415516c77SSepherosa Ziehau 	if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) ||
417515516c77SSepherosa Ziehau 	    lenlim > TCP_LRO_LENGTH_MAX) {
417615516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
417715516c77SSepherosa Ziehau 		return EINVAL;
417815516c77SSepherosa Ziehau 	}
417915516c77SSepherosa Ziehau 	hn_set_lro_lenlim(sc, lenlim);
418015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
418115516c77SSepherosa Ziehau 
418215516c77SSepherosa Ziehau 	return 0;
418315516c77SSepherosa Ziehau }
418415516c77SSepherosa Ziehau 
418515516c77SSepherosa Ziehau static int
418615516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS)
418715516c77SSepherosa Ziehau {
418815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
418915516c77SSepherosa Ziehau 	int ackcnt, error, i;
419015516c77SSepherosa Ziehau 
419115516c77SSepherosa Ziehau 	/*
419215516c77SSepherosa Ziehau 	 * lro_ackcnt_lim is append count limit,
419315516c77SSepherosa Ziehau 	 * +1 to turn it into aggregation limit.
419415516c77SSepherosa Ziehau 	 */
419515516c77SSepherosa Ziehau 	ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1;
419615516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &ackcnt, 0, req);
419715516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
419815516c77SSepherosa Ziehau 		return error;
419915516c77SSepherosa Ziehau 
420015516c77SSepherosa Ziehau 	if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1))
420115516c77SSepherosa Ziehau 		return EINVAL;
420215516c77SSepherosa Ziehau 
420315516c77SSepherosa Ziehau 	/*
420415516c77SSepherosa Ziehau 	 * Convert aggregation limit back to append
420515516c77SSepherosa Ziehau 	 * count limit.
420615516c77SSepherosa Ziehau 	 */
420715516c77SSepherosa Ziehau 	--ackcnt;
420815516c77SSepherosa Ziehau 	HN_LOCK(sc);
4209a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
421015516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt;
421115516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
421215516c77SSepherosa Ziehau 	return 0;
421315516c77SSepherosa Ziehau }
421415516c77SSepherosa Ziehau 
421515516c77SSepherosa Ziehau #endif
421615516c77SSepherosa Ziehau 
421715516c77SSepherosa Ziehau static int
421815516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS)
421915516c77SSepherosa Ziehau {
422015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
422115516c77SSepherosa Ziehau 	int hcsum = arg2;
422215516c77SSepherosa Ziehau 	int on, error, i;
422315516c77SSepherosa Ziehau 
422415516c77SSepherosa Ziehau 	on = 0;
422515516c77SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum)
422615516c77SSepherosa Ziehau 		on = 1;
422715516c77SSepherosa Ziehau 
422815516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &on, 0, req);
422915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
423015516c77SSepherosa Ziehau 		return error;
423115516c77SSepherosa Ziehau 
423215516c77SSepherosa Ziehau 	HN_LOCK(sc);
4233a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
423415516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
423515516c77SSepherosa Ziehau 
423615516c77SSepherosa Ziehau 		if (on)
423715516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= hcsum;
423815516c77SSepherosa Ziehau 		else
423915516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum &= ~hcsum;
424015516c77SSepherosa Ziehau 	}
424115516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
424215516c77SSepherosa Ziehau 	return 0;
424315516c77SSepherosa Ziehau }
424415516c77SSepherosa Ziehau 
424515516c77SSepherosa Ziehau static int
424615516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS)
424715516c77SSepherosa Ziehau {
424815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
424915516c77SSepherosa Ziehau 	int chim_size, error;
425015516c77SSepherosa Ziehau 
425115516c77SSepherosa Ziehau 	chim_size = sc->hn_tx_ring[0].hn_chim_size;
425215516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &chim_size, 0, req);
425315516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
425415516c77SSepherosa Ziehau 		return error;
425515516c77SSepherosa Ziehau 
425615516c77SSepherosa Ziehau 	if (chim_size > sc->hn_chim_szmax || chim_size <= 0)
425715516c77SSepherosa Ziehau 		return EINVAL;
425815516c77SSepherosa Ziehau 
425915516c77SSepherosa Ziehau 	HN_LOCK(sc);
426015516c77SSepherosa Ziehau 	hn_set_chim_size(sc, chim_size);
426115516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
426215516c77SSepherosa Ziehau 	return 0;
426315516c77SSepherosa Ziehau }
426415516c77SSepherosa Ziehau 
426515516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
426615516c77SSepherosa Ziehau static int
426715516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS)
426815516c77SSepherosa Ziehau {
426915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
427015516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
427115516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
427215516c77SSepherosa Ziehau 	uint64_t stat;
427315516c77SSepherosa Ziehau 
427415516c77SSepherosa Ziehau 	stat = 0;
427515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
427615516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
427715516c77SSepherosa Ziehau 		stat += *((int *)((uint8_t *)rxr + ofs));
427815516c77SSepherosa Ziehau 	}
427915516c77SSepherosa Ziehau 
428015516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
428115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
428215516c77SSepherosa Ziehau 		return error;
428315516c77SSepherosa Ziehau 
428415516c77SSepherosa Ziehau 	/* Zero out this stat. */
428515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
428615516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
428715516c77SSepherosa Ziehau 		*((int *)((uint8_t *)rxr + ofs)) = 0;
428815516c77SSepherosa Ziehau 	}
428915516c77SSepherosa Ziehau 	return 0;
429015516c77SSepherosa Ziehau }
429115516c77SSepherosa Ziehau #else
429215516c77SSepherosa Ziehau static int
429315516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS)
429415516c77SSepherosa Ziehau {
429515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
429615516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
429715516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
429815516c77SSepherosa Ziehau 	uint64_t stat;
429915516c77SSepherosa Ziehau 
430015516c77SSepherosa Ziehau 	stat = 0;
4301a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
430215516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
430315516c77SSepherosa Ziehau 		stat += *((uint64_t *)((uint8_t *)rxr + ofs));
430415516c77SSepherosa Ziehau 	}
430515516c77SSepherosa Ziehau 
430615516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
430715516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
430815516c77SSepherosa Ziehau 		return error;
430915516c77SSepherosa Ziehau 
431015516c77SSepherosa Ziehau 	/* Zero out this stat. */
4311a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
431215516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
431315516c77SSepherosa Ziehau 		*((uint64_t *)((uint8_t *)rxr + ofs)) = 0;
431415516c77SSepherosa Ziehau 	}
431515516c77SSepherosa Ziehau 	return 0;
431615516c77SSepherosa Ziehau }
431715516c77SSepherosa Ziehau 
431815516c77SSepherosa Ziehau #endif
431915516c77SSepherosa Ziehau 
432015516c77SSepherosa Ziehau static int
432115516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
432215516c77SSepherosa Ziehau {
432315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
432415516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
432515516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
432615516c77SSepherosa Ziehau 	u_long stat;
432715516c77SSepherosa Ziehau 
432815516c77SSepherosa Ziehau 	stat = 0;
4329a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
433015516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
433115516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)rxr + ofs));
433215516c77SSepherosa Ziehau 	}
433315516c77SSepherosa Ziehau 
433415516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
433515516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
433615516c77SSepherosa Ziehau 		return error;
433715516c77SSepherosa Ziehau 
433815516c77SSepherosa Ziehau 	/* Zero out this stat. */
4339a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
434015516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
434115516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)rxr + ofs)) = 0;
434215516c77SSepherosa Ziehau 	}
434315516c77SSepherosa Ziehau 	return 0;
434415516c77SSepherosa Ziehau }
434515516c77SSepherosa Ziehau 
434615516c77SSepherosa Ziehau static int
434715516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
434815516c77SSepherosa Ziehau {
434915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
435015516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
435115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
435215516c77SSepherosa Ziehau 	u_long stat;
435315516c77SSepherosa Ziehau 
435415516c77SSepherosa Ziehau 	stat = 0;
4355a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
435615516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
435715516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)txr + ofs));
435815516c77SSepherosa Ziehau 	}
435915516c77SSepherosa Ziehau 
436015516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
436115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
436215516c77SSepherosa Ziehau 		return error;
436315516c77SSepherosa Ziehau 
436415516c77SSepherosa Ziehau 	/* Zero out this stat. */
4365a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
436615516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
436715516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)txr + ofs)) = 0;
436815516c77SSepherosa Ziehau 	}
436915516c77SSepherosa Ziehau 	return 0;
437015516c77SSepherosa Ziehau }
437115516c77SSepherosa Ziehau 
437215516c77SSepherosa Ziehau static int
437315516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS)
437415516c77SSepherosa Ziehau {
437515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
437615516c77SSepherosa Ziehau 	int ofs = arg2, i, error, conf;
437715516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
437815516c77SSepherosa Ziehau 
437915516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[0];
438015516c77SSepherosa Ziehau 	conf = *((int *)((uint8_t *)txr + ofs));
438115516c77SSepherosa Ziehau 
438215516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &conf, 0, req);
438315516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
438415516c77SSepherosa Ziehau 		return error;
438515516c77SSepherosa Ziehau 
438615516c77SSepherosa Ziehau 	HN_LOCK(sc);
4387a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
438815516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
438915516c77SSepherosa Ziehau 		*((int *)((uint8_t *)txr + ofs)) = conf;
439015516c77SSepherosa Ziehau 	}
439115516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
439215516c77SSepherosa Ziehau 
439315516c77SSepherosa Ziehau 	return 0;
439415516c77SSepherosa Ziehau }
439515516c77SSepherosa Ziehau 
439615516c77SSepherosa Ziehau static int
4397dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS)
4398dc13fee6SSepherosa Ziehau {
4399dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4400dc13fee6SSepherosa Ziehau 	int error, size;
4401dc13fee6SSepherosa Ziehau 
4402dc13fee6SSepherosa Ziehau 	size = sc->hn_agg_size;
4403dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &size, 0, req);
4404dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
4405dc13fee6SSepherosa Ziehau 		return (error);
4406dc13fee6SSepherosa Ziehau 
4407dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
4408dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = size;
4409dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
4410dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
4411dc13fee6SSepherosa Ziehau 
4412dc13fee6SSepherosa Ziehau 	return (0);
4413dc13fee6SSepherosa Ziehau }
4414dc13fee6SSepherosa Ziehau 
4415dc13fee6SSepherosa Ziehau static int
4416dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS)
4417dc13fee6SSepherosa Ziehau {
4418dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4419dc13fee6SSepherosa Ziehau 	int error, pkts;
4420dc13fee6SSepherosa Ziehau 
4421dc13fee6SSepherosa Ziehau 	pkts = sc->hn_agg_pkts;
4422dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pkts, 0, req);
4423dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
4424dc13fee6SSepherosa Ziehau 		return (error);
4425dc13fee6SSepherosa Ziehau 
4426dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
4427dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = pkts;
4428dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
4429dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
4430dc13fee6SSepherosa Ziehau 
4431dc13fee6SSepherosa Ziehau 	return (0);
4432dc13fee6SSepherosa Ziehau }
4433dc13fee6SSepherosa Ziehau 
4434dc13fee6SSepherosa Ziehau static int
4435dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS)
4436dc13fee6SSepherosa Ziehau {
4437dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4438dc13fee6SSepherosa Ziehau 	int pkts;
4439dc13fee6SSepherosa Ziehau 
4440dc13fee6SSepherosa Ziehau 	pkts = sc->hn_tx_ring[0].hn_agg_pktmax;
4441dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &pkts, 0, req));
4442dc13fee6SSepherosa Ziehau }
4443dc13fee6SSepherosa Ziehau 
4444dc13fee6SSepherosa Ziehau static int
4445dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS)
4446dc13fee6SSepherosa Ziehau {
4447dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4448dc13fee6SSepherosa Ziehau 	int align;
4449dc13fee6SSepherosa Ziehau 
4450dc13fee6SSepherosa Ziehau 	align = sc->hn_tx_ring[0].hn_agg_align;
4451dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &align, 0, req));
4452dc13fee6SSepherosa Ziehau }
4453dc13fee6SSepherosa Ziehau 
44546c1204dfSSepherosa Ziehau static void
44556c1204dfSSepherosa Ziehau hn_chan_polling(struct vmbus_channel *chan, u_int pollhz)
44566c1204dfSSepherosa Ziehau {
44576c1204dfSSepherosa Ziehau 	if (pollhz == 0)
44586c1204dfSSepherosa Ziehau 		vmbus_chan_poll_disable(chan);
44596c1204dfSSepherosa Ziehau 	else
44606c1204dfSSepherosa Ziehau 		vmbus_chan_poll_enable(chan, pollhz);
44616c1204dfSSepherosa Ziehau }
44626c1204dfSSepherosa Ziehau 
44636c1204dfSSepherosa Ziehau static void
44646c1204dfSSepherosa Ziehau hn_polling(struct hn_softc *sc, u_int pollhz)
44656c1204dfSSepherosa Ziehau {
44666c1204dfSSepherosa Ziehau 	int nsubch = sc->hn_rx_ring_inuse - 1;
44676c1204dfSSepherosa Ziehau 
44686c1204dfSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
44696c1204dfSSepherosa Ziehau 
44706c1204dfSSepherosa Ziehau 	if (nsubch > 0) {
44716c1204dfSSepherosa Ziehau 		struct vmbus_channel **subch;
44726c1204dfSSepherosa Ziehau 		int i;
44736c1204dfSSepherosa Ziehau 
44746c1204dfSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
44756c1204dfSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
44766c1204dfSSepherosa Ziehau 			hn_chan_polling(subch[i], pollhz);
44776c1204dfSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
44786c1204dfSSepherosa Ziehau 	}
44796c1204dfSSepherosa Ziehau 	hn_chan_polling(sc->hn_prichan, pollhz);
44806c1204dfSSepherosa Ziehau }
44816c1204dfSSepherosa Ziehau 
44826c1204dfSSepherosa Ziehau static int
44836c1204dfSSepherosa Ziehau hn_polling_sysctl(SYSCTL_HANDLER_ARGS)
44846c1204dfSSepherosa Ziehau {
44856c1204dfSSepherosa Ziehau 	struct hn_softc *sc = arg1;
44866c1204dfSSepherosa Ziehau 	int pollhz, error;
44876c1204dfSSepherosa Ziehau 
44886c1204dfSSepherosa Ziehau 	pollhz = sc->hn_pollhz;
44896c1204dfSSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pollhz, 0, req);
44906c1204dfSSepherosa Ziehau 	if (error || req->newptr == NULL)
44916c1204dfSSepherosa Ziehau 		return (error);
44926c1204dfSSepherosa Ziehau 
44936c1204dfSSepherosa Ziehau 	if (pollhz != 0 &&
44946c1204dfSSepherosa Ziehau 	    (pollhz < VMBUS_CHAN_POLLHZ_MIN || pollhz > VMBUS_CHAN_POLLHZ_MAX))
44956c1204dfSSepherosa Ziehau 		return (EINVAL);
44966c1204dfSSepherosa Ziehau 
44976c1204dfSSepherosa Ziehau 	HN_LOCK(sc);
44986c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz != pollhz) {
44996c1204dfSSepherosa Ziehau 		sc->hn_pollhz = pollhz;
45006c1204dfSSepherosa Ziehau 		if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) &&
45016c1204dfSSepherosa Ziehau 		    (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
45026c1204dfSSepherosa Ziehau 			hn_polling(sc, sc->hn_pollhz);
45036c1204dfSSepherosa Ziehau 	}
45046c1204dfSSepherosa Ziehau 	HN_UNLOCK(sc);
45056c1204dfSSepherosa Ziehau 
45066c1204dfSSepherosa Ziehau 	return (0);
45076c1204dfSSepherosa Ziehau }
45086c1204dfSSepherosa Ziehau 
4509dc13fee6SSepherosa Ziehau static int
451015516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS)
451115516c77SSepherosa Ziehau {
451215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
451315516c77SSepherosa Ziehau 	char verstr[16];
451415516c77SSepherosa Ziehau 
451515516c77SSepherosa Ziehau 	snprintf(verstr, sizeof(verstr), "%u.%u",
451615516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
451715516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
451815516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
451915516c77SSepherosa Ziehau }
452015516c77SSepherosa Ziehau 
452115516c77SSepherosa Ziehau static int
452215516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS)
452315516c77SSepherosa Ziehau {
452415516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
452515516c77SSepherosa Ziehau 	char caps_str[128];
452615516c77SSepherosa Ziehau 	uint32_t caps;
452715516c77SSepherosa Ziehau 
452815516c77SSepherosa Ziehau 	HN_LOCK(sc);
452915516c77SSepherosa Ziehau 	caps = sc->hn_caps;
453015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
453115516c77SSepherosa Ziehau 	snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS);
453215516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req);
453315516c77SSepherosa Ziehau }
453415516c77SSepherosa Ziehau 
453515516c77SSepherosa Ziehau static int
453615516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS)
453715516c77SSepherosa Ziehau {
453815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
453915516c77SSepherosa Ziehau 	char assist_str[128];
454015516c77SSepherosa Ziehau 	uint32_t hwassist;
454115516c77SSepherosa Ziehau 
454215516c77SSepherosa Ziehau 	HN_LOCK(sc);
454315516c77SSepherosa Ziehau 	hwassist = sc->hn_ifp->if_hwassist;
454415516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
454515516c77SSepherosa Ziehau 	snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS);
454615516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req);
454715516c77SSepherosa Ziehau }
454815516c77SSepherosa Ziehau 
454915516c77SSepherosa Ziehau static int
455015516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS)
455115516c77SSepherosa Ziehau {
455215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
455315516c77SSepherosa Ziehau 	char filter_str[128];
455415516c77SSepherosa Ziehau 	uint32_t filter;
455515516c77SSepherosa Ziehau 
455615516c77SSepherosa Ziehau 	HN_LOCK(sc);
455715516c77SSepherosa Ziehau 	filter = sc->hn_rx_filter;
455815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
455915516c77SSepherosa Ziehau 	snprintf(filter_str, sizeof(filter_str), "%b", filter,
456015516c77SSepherosa Ziehau 	    NDIS_PACKET_TYPES);
456115516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req);
456215516c77SSepherosa Ziehau }
456315516c77SSepherosa Ziehau 
456434d68912SSepherosa Ziehau #ifndef RSS
456534d68912SSepherosa Ziehau 
456615516c77SSepherosa Ziehau static int
456715516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
456815516c77SSepherosa Ziehau {
456915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
457015516c77SSepherosa Ziehau 	int error;
457115516c77SSepherosa Ziehau 
457215516c77SSepherosa Ziehau 	HN_LOCK(sc);
457315516c77SSepherosa Ziehau 
457415516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
457515516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
457615516c77SSepherosa Ziehau 		goto back;
457715516c77SSepherosa Ziehau 
4578642ec226SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) ||
4579642ec226SSepherosa Ziehau 	    (hn_xpnt_vf && sc->hn_vf_ifp != NULL)) {
4580642ec226SSepherosa Ziehau 		/*
4581642ec226SSepherosa Ziehau 		 * RSS key is synchronized w/ VF's, don't allow users
4582642ec226SSepherosa Ziehau 		 * to change it.
4583642ec226SSepherosa Ziehau 		 */
4584642ec226SSepherosa Ziehau 		error = EBUSY;
4585642ec226SSepherosa Ziehau 		goto back;
4586642ec226SSepherosa Ziehau 	}
4587642ec226SSepherosa Ziehau 
458815516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
458915516c77SSepherosa Ziehau 	if (error)
459015516c77SSepherosa Ziehau 		goto back;
459115516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
459215516c77SSepherosa Ziehau 
459315516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
459415516c77SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
459515516c77SSepherosa Ziehau 	} else {
459615516c77SSepherosa Ziehau 		/* Not RSS capable, at least for now; just save the RSS key. */
459715516c77SSepherosa Ziehau 		error = 0;
459815516c77SSepherosa Ziehau 	}
459915516c77SSepherosa Ziehau back:
460015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
460115516c77SSepherosa Ziehau 	return (error);
460215516c77SSepherosa Ziehau }
460315516c77SSepherosa Ziehau 
460415516c77SSepherosa Ziehau static int
460515516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS)
460615516c77SSepherosa Ziehau {
460715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
460815516c77SSepherosa Ziehau 	int error;
460915516c77SSepherosa Ziehau 
461015516c77SSepherosa Ziehau 	HN_LOCK(sc);
461115516c77SSepherosa Ziehau 
461215516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
461315516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
461415516c77SSepherosa Ziehau 		goto back;
461515516c77SSepherosa Ziehau 
461615516c77SSepherosa Ziehau 	/*
461715516c77SSepherosa Ziehau 	 * Don't allow RSS indirect table change, if this interface is not
461815516c77SSepherosa Ziehau 	 * RSS capable currently.
461915516c77SSepherosa Ziehau 	 */
462015516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
462115516c77SSepherosa Ziehau 		error = EOPNOTSUPP;
462215516c77SSepherosa Ziehau 		goto back;
462315516c77SSepherosa Ziehau 	}
462415516c77SSepherosa Ziehau 
462515516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
462615516c77SSepherosa Ziehau 	if (error)
462715516c77SSepherosa Ziehau 		goto back;
462815516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSIND;
462915516c77SSepherosa Ziehau 
4630afd4971bSSepherosa Ziehau 	hn_rss_ind_fixup(sc);
463115516c77SSepherosa Ziehau 	error = hn_rss_reconfig(sc);
463215516c77SSepherosa Ziehau back:
463315516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
463415516c77SSepherosa Ziehau 	return (error);
463515516c77SSepherosa Ziehau }
463615516c77SSepherosa Ziehau 
463734d68912SSepherosa Ziehau #endif	/* !RSS */
463834d68912SSepherosa Ziehau 
463915516c77SSepherosa Ziehau static int
464015516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS)
464115516c77SSepherosa Ziehau {
464215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
464315516c77SSepherosa Ziehau 	char hash_str[128];
464415516c77SSepherosa Ziehau 	uint32_t hash;
464515516c77SSepherosa Ziehau 
464615516c77SSepherosa Ziehau 	HN_LOCK(sc);
464715516c77SSepherosa Ziehau 	hash = sc->hn_rss_hash;
464815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
464915516c77SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
465015516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
465115516c77SSepherosa Ziehau }
465215516c77SSepherosa Ziehau 
465315516c77SSepherosa Ziehau static int
4654642ec226SSepherosa Ziehau hn_rss_hcap_sysctl(SYSCTL_HANDLER_ARGS)
4655642ec226SSepherosa Ziehau {
4656642ec226SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4657642ec226SSepherosa Ziehau 	char hash_str[128];
4658642ec226SSepherosa Ziehau 	uint32_t hash;
4659642ec226SSepherosa Ziehau 
4660642ec226SSepherosa Ziehau 	HN_LOCK(sc);
4661642ec226SSepherosa Ziehau 	hash = sc->hn_rss_hcap;
4662642ec226SSepherosa Ziehau 	HN_UNLOCK(sc);
4663642ec226SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
4664642ec226SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
4665642ec226SSepherosa Ziehau }
4666642ec226SSepherosa Ziehau 
4667642ec226SSepherosa Ziehau static int
4668642ec226SSepherosa Ziehau hn_rss_mbuf_sysctl(SYSCTL_HANDLER_ARGS)
4669642ec226SSepherosa Ziehau {
4670642ec226SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4671642ec226SSepherosa Ziehau 	char hash_str[128];
4672642ec226SSepherosa Ziehau 	uint32_t hash;
4673642ec226SSepherosa Ziehau 
4674642ec226SSepherosa Ziehau 	HN_LOCK(sc);
4675642ec226SSepherosa Ziehau 	hash = sc->hn_rx_ring[0].hn_mbuf_hash;
4676642ec226SSepherosa Ziehau 	HN_UNLOCK(sc);
4677642ec226SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
4678642ec226SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
4679642ec226SSepherosa Ziehau }
4680642ec226SSepherosa Ziehau 
4681642ec226SSepherosa Ziehau static int
468240d60d6eSDexuan Cui hn_vf_sysctl(SYSCTL_HANDLER_ARGS)
468340d60d6eSDexuan Cui {
468440d60d6eSDexuan Cui 	struct hn_softc *sc = arg1;
4685499c3e17SSepherosa Ziehau 	char vf_name[IFNAMSIZ + 1];
4686962f0357SSepherosa Ziehau 	struct ifnet *vf_ifp;
468740d60d6eSDexuan Cui 
468840d60d6eSDexuan Cui 	HN_LOCK(sc);
468940d60d6eSDexuan Cui 	vf_name[0] = '\0';
4690962f0357SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
4691962f0357SSepherosa Ziehau 	if (vf_ifp != NULL)
4692962f0357SSepherosa Ziehau 		snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname);
469340d60d6eSDexuan Cui 	HN_UNLOCK(sc);
469440d60d6eSDexuan Cui 	return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req);
469540d60d6eSDexuan Cui }
469640d60d6eSDexuan Cui 
469740d60d6eSDexuan Cui static int
4698499c3e17SSepherosa Ziehau hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS)
4699499c3e17SSepherosa Ziehau {
4700499c3e17SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4701499c3e17SSepherosa Ziehau 	char vf_name[IFNAMSIZ + 1];
4702962f0357SSepherosa Ziehau 	struct ifnet *vf_ifp;
4703499c3e17SSepherosa Ziehau 
4704499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
4705499c3e17SSepherosa Ziehau 	vf_name[0] = '\0';
4706962f0357SSepherosa Ziehau 	vf_ifp = sc->hn_rx_ring[0].hn_rxvf_ifp;
4707962f0357SSepherosa Ziehau 	if (vf_ifp != NULL)
4708962f0357SSepherosa Ziehau 		snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname);
4709499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
4710499c3e17SSepherosa Ziehau 	return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req);
4711499c3e17SSepherosa Ziehau }
4712499c3e17SSepherosa Ziehau 
4713499c3e17SSepherosa Ziehau static int
4714499c3e17SSepherosa Ziehau hn_vflist_sysctl(SYSCTL_HANDLER_ARGS)
4715499c3e17SSepherosa Ziehau {
4716499c3e17SSepherosa Ziehau 	struct rm_priotracker pt;
4717499c3e17SSepherosa Ziehau 	struct sbuf *sb;
4718499c3e17SSepherosa Ziehau 	int error, i;
4719499c3e17SSepherosa Ziehau 	bool first;
4720499c3e17SSepherosa Ziehau 
4721499c3e17SSepherosa Ziehau 	error = sysctl_wire_old_buffer(req, 0);
4722499c3e17SSepherosa Ziehau 	if (error != 0)
4723499c3e17SSepherosa Ziehau 		return (error);
4724499c3e17SSepherosa Ziehau 
4725499c3e17SSepherosa Ziehau 	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4726499c3e17SSepherosa Ziehau 	if (sb == NULL)
4727499c3e17SSepherosa Ziehau 		return (ENOMEM);
4728499c3e17SSepherosa Ziehau 
4729499c3e17SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
4730499c3e17SSepherosa Ziehau 
4731499c3e17SSepherosa Ziehau 	first = true;
4732499c3e17SSepherosa Ziehau 	for (i = 0; i < hn_vfmap_size; ++i) {
4733499c3e17SSepherosa Ziehau 		struct ifnet *ifp;
4734499c3e17SSepherosa Ziehau 
4735499c3e17SSepherosa Ziehau 		if (hn_vfmap[i] == NULL)
4736499c3e17SSepherosa Ziehau 			continue;
4737499c3e17SSepherosa Ziehau 
4738499c3e17SSepherosa Ziehau 		ifp = ifnet_byindex(i);
4739499c3e17SSepherosa Ziehau 		if (ifp != NULL) {
4740499c3e17SSepherosa Ziehau 			if (first)
4741499c3e17SSepherosa Ziehau 				sbuf_printf(sb, "%s", ifp->if_xname);
4742499c3e17SSepherosa Ziehau 			else
4743499c3e17SSepherosa Ziehau 				sbuf_printf(sb, " %s", ifp->if_xname);
4744499c3e17SSepherosa Ziehau 			first = false;
4745499c3e17SSepherosa Ziehau 		}
4746499c3e17SSepherosa Ziehau 	}
4747499c3e17SSepherosa Ziehau 
4748499c3e17SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
4749499c3e17SSepherosa Ziehau 
4750499c3e17SSepherosa Ziehau 	error = sbuf_finish(sb);
4751499c3e17SSepherosa Ziehau 	sbuf_delete(sb);
4752499c3e17SSepherosa Ziehau 	return (error);
4753499c3e17SSepherosa Ziehau }
4754499c3e17SSepherosa Ziehau 
4755499c3e17SSepherosa Ziehau static int
4756499c3e17SSepherosa Ziehau hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS)
4757499c3e17SSepherosa Ziehau {
4758499c3e17SSepherosa Ziehau 	struct rm_priotracker pt;
4759499c3e17SSepherosa Ziehau 	struct sbuf *sb;
4760499c3e17SSepherosa Ziehau 	int error, i;
4761499c3e17SSepherosa Ziehau 	bool first;
4762499c3e17SSepherosa Ziehau 
4763499c3e17SSepherosa Ziehau 	error = sysctl_wire_old_buffer(req, 0);
4764499c3e17SSepherosa Ziehau 	if (error != 0)
4765499c3e17SSepherosa Ziehau 		return (error);
4766499c3e17SSepherosa Ziehau 
4767499c3e17SSepherosa Ziehau 	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4768499c3e17SSepherosa Ziehau 	if (sb == NULL)
4769499c3e17SSepherosa Ziehau 		return (ENOMEM);
4770499c3e17SSepherosa Ziehau 
4771499c3e17SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
4772499c3e17SSepherosa Ziehau 
4773499c3e17SSepherosa Ziehau 	first = true;
4774499c3e17SSepherosa Ziehau 	for (i = 0; i < hn_vfmap_size; ++i) {
4775499c3e17SSepherosa Ziehau 		struct ifnet *ifp, *hn_ifp;
4776499c3e17SSepherosa Ziehau 
4777499c3e17SSepherosa Ziehau 		hn_ifp = hn_vfmap[i];
4778499c3e17SSepherosa Ziehau 		if (hn_ifp == NULL)
4779499c3e17SSepherosa Ziehau 			continue;
4780499c3e17SSepherosa Ziehau 
4781499c3e17SSepherosa Ziehau 		ifp = ifnet_byindex(i);
4782499c3e17SSepherosa Ziehau 		if (ifp != NULL) {
4783499c3e17SSepherosa Ziehau 			if (first) {
4784499c3e17SSepherosa Ziehau 				sbuf_printf(sb, "%s:%s", ifp->if_xname,
4785499c3e17SSepherosa Ziehau 				    hn_ifp->if_xname);
4786499c3e17SSepherosa Ziehau 			} else {
4787499c3e17SSepherosa Ziehau 				sbuf_printf(sb, " %s:%s", ifp->if_xname,
4788499c3e17SSepherosa Ziehau 				    hn_ifp->if_xname);
4789499c3e17SSepherosa Ziehau 			}
4790499c3e17SSepherosa Ziehau 			first = false;
4791499c3e17SSepherosa Ziehau 		}
4792499c3e17SSepherosa Ziehau 	}
4793499c3e17SSepherosa Ziehau 
4794499c3e17SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
4795499c3e17SSepherosa Ziehau 
4796499c3e17SSepherosa Ziehau 	error = sbuf_finish(sb);
4797499c3e17SSepherosa Ziehau 	sbuf_delete(sb);
4798499c3e17SSepherosa Ziehau 	return (error);
4799499c3e17SSepherosa Ziehau }
4800499c3e17SSepherosa Ziehau 
4801499c3e17SSepherosa Ziehau static int
48029c6cae24SSepherosa Ziehau hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS)
48039c6cae24SSepherosa Ziehau {
48049c6cae24SSepherosa Ziehau 	struct hn_softc *sc = arg1;
48059c6cae24SSepherosa Ziehau 	int error, onoff = 0;
48069c6cae24SSepherosa Ziehau 
48079c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF)
48089c6cae24SSepherosa Ziehau 		onoff = 1;
48099c6cae24SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &onoff, 0, req);
48109c6cae24SSepherosa Ziehau 	if (error || req->newptr == NULL)
48119c6cae24SSepherosa Ziehau 		return (error);
48129c6cae24SSepherosa Ziehau 
48139c6cae24SSepherosa Ziehau 	HN_LOCK(sc);
48149c6cae24SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit() */
48159c6cae24SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
48169c6cae24SSepherosa Ziehau 	if (onoff)
48179c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF;
48189c6cae24SSepherosa Ziehau 	else
48199c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags &= ~HN_XVFFLAG_ACCBPF;
48209c6cae24SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
48219c6cae24SSepherosa Ziehau 	HN_UNLOCK(sc);
48229c6cae24SSepherosa Ziehau 
48239c6cae24SSepherosa Ziehau 	return (0);
48249c6cae24SSepherosa Ziehau }
48259c6cae24SSepherosa Ziehau 
48269c6cae24SSepherosa Ziehau static int
48279c6cae24SSepherosa Ziehau hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS)
48289c6cae24SSepherosa Ziehau {
48299c6cae24SSepherosa Ziehau 	struct hn_softc *sc = arg1;
48309c6cae24SSepherosa Ziehau 	int enabled = 0;
48319c6cae24SSepherosa Ziehau 
48329c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
48339c6cae24SSepherosa Ziehau 		enabled = 1;
48349c6cae24SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &enabled, 0, req));
48359c6cae24SSepherosa Ziehau }
48369c6cae24SSepherosa Ziehau 
48379c6cae24SSepherosa Ziehau static int
483815516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff)
483915516c77SSepherosa Ziehau {
484015516c77SSepherosa Ziehau 	const struct ip *ip;
484115516c77SSepherosa Ziehau 	int len, iphlen, iplen;
484215516c77SSepherosa Ziehau 	const struct tcphdr *th;
484315516c77SSepherosa Ziehau 	int thoff;				/* TCP data offset */
484415516c77SSepherosa Ziehau 
484515516c77SSepherosa Ziehau 	len = hoff + sizeof(struct ip);
484615516c77SSepherosa Ziehau 
484715516c77SSepherosa Ziehau 	/* The packet must be at least the size of an IP header. */
484815516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < len)
484915516c77SSepherosa Ziehau 		return IPPROTO_DONE;
485015516c77SSepherosa Ziehau 
485115516c77SSepherosa Ziehau 	/* The fixed IP header must reside completely in the first mbuf. */
485215516c77SSepherosa Ziehau 	if (m->m_len < len)
485315516c77SSepherosa Ziehau 		return IPPROTO_DONE;
485415516c77SSepherosa Ziehau 
485515516c77SSepherosa Ziehau 	ip = mtodo(m, hoff);
485615516c77SSepherosa Ziehau 
485715516c77SSepherosa Ziehau 	/* Bound check the packet's stated IP header length. */
485815516c77SSepherosa Ziehau 	iphlen = ip->ip_hl << 2;
485915516c77SSepherosa Ziehau 	if (iphlen < sizeof(struct ip))		/* minimum header length */
486015516c77SSepherosa Ziehau 		return IPPROTO_DONE;
486115516c77SSepherosa Ziehau 
486215516c77SSepherosa Ziehau 	/* The full IP header must reside completely in the one mbuf. */
486315516c77SSepherosa Ziehau 	if (m->m_len < hoff + iphlen)
486415516c77SSepherosa Ziehau 		return IPPROTO_DONE;
486515516c77SSepherosa Ziehau 
486615516c77SSepherosa Ziehau 	iplen = ntohs(ip->ip_len);
486715516c77SSepherosa Ziehau 
486815516c77SSepherosa Ziehau 	/*
486915516c77SSepherosa Ziehau 	 * Check that the amount of data in the buffers is as
487015516c77SSepherosa Ziehau 	 * at least much as the IP header would have us expect.
487115516c77SSepherosa Ziehau 	 */
487215516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < hoff + iplen)
487315516c77SSepherosa Ziehau 		return IPPROTO_DONE;
487415516c77SSepherosa Ziehau 
487515516c77SSepherosa Ziehau 	/*
487615516c77SSepherosa Ziehau 	 * Ignore IP fragments.
487715516c77SSepherosa Ziehau 	 */
487815516c77SSepherosa Ziehau 	if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF))
487915516c77SSepherosa Ziehau 		return IPPROTO_DONE;
488015516c77SSepherosa Ziehau 
488115516c77SSepherosa Ziehau 	/*
488215516c77SSepherosa Ziehau 	 * The TCP/IP or UDP/IP header must be entirely contained within
488315516c77SSepherosa Ziehau 	 * the first fragment of a packet.
488415516c77SSepherosa Ziehau 	 */
488515516c77SSepherosa Ziehau 	switch (ip->ip_p) {
488615516c77SSepherosa Ziehau 	case IPPROTO_TCP:
488715516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct tcphdr))
488815516c77SSepherosa Ziehau 			return IPPROTO_DONE;
488915516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct tcphdr))
489015516c77SSepherosa Ziehau 			return IPPROTO_DONE;
489115516c77SSepherosa Ziehau 		th = (const struct tcphdr *)((const uint8_t *)ip + iphlen);
489215516c77SSepherosa Ziehau 		thoff = th->th_off << 2;
489315516c77SSepherosa Ziehau 		if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen)
489415516c77SSepherosa Ziehau 			return IPPROTO_DONE;
489515516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + thoff)
489615516c77SSepherosa Ziehau 			return IPPROTO_DONE;
489715516c77SSepherosa Ziehau 		break;
489815516c77SSepherosa Ziehau 	case IPPROTO_UDP:
489915516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct udphdr))
490015516c77SSepherosa Ziehau 			return IPPROTO_DONE;
490115516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct udphdr))
490215516c77SSepherosa Ziehau 			return IPPROTO_DONE;
490315516c77SSepherosa Ziehau 		break;
490415516c77SSepherosa Ziehau 	default:
490515516c77SSepherosa Ziehau 		if (iplen < iphlen)
490615516c77SSepherosa Ziehau 			return IPPROTO_DONE;
490715516c77SSepherosa Ziehau 		break;
490815516c77SSepherosa Ziehau 	}
490915516c77SSepherosa Ziehau 	return ip->ip_p;
491015516c77SSepherosa Ziehau }
491115516c77SSepherosa Ziehau 
4912db76829bSSepherosa Ziehau static void
4913db76829bSSepherosa Ziehau hn_rxpkt_proto(const struct mbuf *m_new, int *l3proto, int *l4proto)
4914db76829bSSepherosa Ziehau {
4915db76829bSSepherosa Ziehau 	const struct ether_header *eh;
4916db76829bSSepherosa Ziehau 	uint16_t etype;
4917db76829bSSepherosa Ziehau 	int hoff;
4918db76829bSSepherosa Ziehau 
4919db76829bSSepherosa Ziehau 	hoff = sizeof(*eh);
4920db76829bSSepherosa Ziehau 	/* Checked at the beginning of this function. */
4921db76829bSSepherosa Ziehau 	KASSERT(m_new->m_len >= hoff, ("not ethernet frame"));
4922db76829bSSepherosa Ziehau 
4923db76829bSSepherosa Ziehau 	eh = mtod(m_new, const struct ether_header *);
4924db76829bSSepherosa Ziehau 	etype = ntohs(eh->ether_type);
4925db76829bSSepherosa Ziehau 	if (etype == ETHERTYPE_VLAN) {
4926db76829bSSepherosa Ziehau 		const struct ether_vlan_header *evl;
4927db76829bSSepherosa Ziehau 
4928db76829bSSepherosa Ziehau 		hoff = sizeof(*evl);
4929db76829bSSepherosa Ziehau 		if (m_new->m_len < hoff)
4930db76829bSSepherosa Ziehau 			return;
4931db76829bSSepherosa Ziehau 		evl = mtod(m_new, const struct ether_vlan_header *);
4932db76829bSSepherosa Ziehau 		etype = ntohs(evl->evl_proto);
4933db76829bSSepherosa Ziehau 	}
4934db76829bSSepherosa Ziehau 	*l3proto = etype;
4935db76829bSSepherosa Ziehau 
4936db76829bSSepherosa Ziehau 	if (etype == ETHERTYPE_IP)
4937db76829bSSepherosa Ziehau 		*l4proto = hn_check_iplen(m_new, hoff);
4938db76829bSSepherosa Ziehau 	else
4939db76829bSSepherosa Ziehau 		*l4proto = IPPROTO_DONE;
4940db76829bSSepherosa Ziehau }
4941db76829bSSepherosa Ziehau 
494215516c77SSepherosa Ziehau static int
494315516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt)
494415516c77SSepherosa Ziehau {
494515516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
494615516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
494715516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
494815516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
494915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
495015516c77SSepherosa Ziehau 	int lroent_cnt;
495115516c77SSepherosa Ziehau #endif
495215516c77SSepherosa Ziehau #endif
495315516c77SSepherosa Ziehau 	int i;
495415516c77SSepherosa Ziehau 
495515516c77SSepherosa Ziehau 	/*
495615516c77SSepherosa Ziehau 	 * Create RXBUF for reception.
495715516c77SSepherosa Ziehau 	 *
495815516c77SSepherosa Ziehau 	 * NOTE:
495915516c77SSepherosa Ziehau 	 * - It is shared by all channels.
496015516c77SSepherosa Ziehau 	 * - A large enough buffer is allocated, certain version of NVSes
496115516c77SSepherosa Ziehau 	 *   may further limit the usable space.
496215516c77SSepherosa Ziehau 	 */
496315516c77SSepherosa Ziehau 	sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
496415516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma,
496515516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
496615516c77SSepherosa Ziehau 	if (sc->hn_rxbuf == NULL) {
496715516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate rxbuf failed\n");
496815516c77SSepherosa Ziehau 		return (ENOMEM);
496915516c77SSepherosa Ziehau 	}
497015516c77SSepherosa Ziehau 
497115516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = ring_cnt;
497215516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt;
497315516c77SSepherosa Ziehau 
497415516c77SSepherosa Ziehau 	sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt,
497515516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
497615516c77SSepherosa Ziehau 
497715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
497815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
497915516c77SSepherosa Ziehau 	lroent_cnt = hn_lro_entry_count;
498015516c77SSepherosa Ziehau 	if (lroent_cnt < TCP_LRO_ENTRIES)
498115516c77SSepherosa Ziehau 		lroent_cnt = TCP_LRO_ENTRIES;
498215516c77SSepherosa Ziehau 	if (bootverbose)
498315516c77SSepherosa Ziehau 		device_printf(dev, "LRO: entry count %d\n", lroent_cnt);
498415516c77SSepherosa Ziehau #endif
498515516c77SSepherosa Ziehau #endif	/* INET || INET6 */
498615516c77SSepherosa Ziehau 
498715516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
498815516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
498915516c77SSepherosa Ziehau 
499015516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.rx sysctl tree */
499115516c77SSepherosa Ziehau 	sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx",
499215516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
499315516c77SSepherosa Ziehau 
499415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
499515516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
499615516c77SSepherosa Ziehau 
499715516c77SSepherosa Ziehau 		rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
499815516c77SSepherosa Ziehau 		    PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE,
499915516c77SSepherosa Ziehau 		    &rxr->hn_br_dma, BUS_DMA_WAITOK);
500015516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL) {
500115516c77SSepherosa Ziehau 			device_printf(dev, "allocate bufring failed\n");
500215516c77SSepherosa Ziehau 			return (ENOMEM);
500315516c77SSepherosa Ziehau 		}
500415516c77SSepherosa Ziehau 
500515516c77SSepherosa Ziehau 		if (hn_trust_hosttcp)
500615516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP;
500715516c77SSepherosa Ziehau 		if (hn_trust_hostudp)
500815516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP;
500915516c77SSepherosa Ziehau 		if (hn_trust_hostip)
501015516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP;
5011642ec226SSepherosa Ziehau 		rxr->hn_mbuf_hash = NDIS_HASH_ALL;
501215516c77SSepherosa Ziehau 		rxr->hn_ifp = sc->hn_ifp;
501315516c77SSepherosa Ziehau 		if (i < sc->hn_tx_ring_cnt)
501415516c77SSepherosa Ziehau 			rxr->hn_txr = &sc->hn_tx_ring[i];
501515516c77SSepherosa Ziehau 		rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF;
501615516c77SSepherosa Ziehau 		rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK);
501715516c77SSepherosa Ziehau 		rxr->hn_rx_idx = i;
501815516c77SSepherosa Ziehau 		rxr->hn_rxbuf = sc->hn_rxbuf;
501915516c77SSepherosa Ziehau 
502015516c77SSepherosa Ziehau 		/*
502115516c77SSepherosa Ziehau 		 * Initialize LRO.
502215516c77SSepherosa Ziehau 		 */
502315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
502415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
502515516c77SSepherosa Ziehau 		tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt,
502615516c77SSepherosa Ziehau 		    hn_lro_mbufq_depth);
502715516c77SSepherosa Ziehau #else
502815516c77SSepherosa Ziehau 		tcp_lro_init(&rxr->hn_lro);
502915516c77SSepherosa Ziehau 		rxr->hn_lro.ifp = sc->hn_ifp;
503015516c77SSepherosa Ziehau #endif
503115516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
503215516c77SSepherosa Ziehau 		rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF;
503315516c77SSepherosa Ziehau 		rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF;
503415516c77SSepherosa Ziehau #endif
503515516c77SSepherosa Ziehau #endif	/* INET || INET6 */
503615516c77SSepherosa Ziehau 
503715516c77SSepherosa Ziehau 		if (sc->hn_rx_sysctl_tree != NULL) {
503815516c77SSepherosa Ziehau 			char name[16];
503915516c77SSepherosa Ziehau 
504015516c77SSepherosa Ziehau 			/*
504115516c77SSepherosa Ziehau 			 * Create per RX ring sysctl tree:
504215516c77SSepherosa Ziehau 			 * dev.hn.UNIT.rx.RINGID
504315516c77SSepherosa Ziehau 			 */
504415516c77SSepherosa Ziehau 			snprintf(name, sizeof(name), "%d", i);
504515516c77SSepherosa Ziehau 			rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx,
504615516c77SSepherosa Ziehau 			    SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree),
504715516c77SSepherosa Ziehau 			    OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
504815516c77SSepherosa Ziehau 
504915516c77SSepherosa Ziehau 			if (rxr->hn_rx_sysctl_tree != NULL) {
505015516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
505115516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
505215516c77SSepherosa Ziehau 				    OID_AUTO, "packets", CTLFLAG_RW,
505315516c77SSepherosa Ziehau 				    &rxr->hn_pkts, "# of packets received");
505415516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
505515516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
505615516c77SSepherosa Ziehau 				    OID_AUTO, "rss_pkts", CTLFLAG_RW,
505715516c77SSepherosa Ziehau 				    &rxr->hn_rss_pkts,
505815516c77SSepherosa Ziehau 				    "# of packets w/ RSS info received");
5059*a491581fSWei Hu 				SYSCTL_ADD_ULONG(ctx,
5060*a491581fSWei Hu 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
5061*a491581fSWei Hu 				    OID_AUTO, "rsc_pkts", CTLFLAG_RW,
5062*a491581fSWei Hu 				    &rxr->hn_rsc_pkts,
5063*a491581fSWei Hu 				    "# of RSC packets received");
5064*a491581fSWei Hu 				SYSCTL_ADD_ULONG(ctx,
5065*a491581fSWei Hu 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
5066*a491581fSWei Hu 				    OID_AUTO, "rsc_drop", CTLFLAG_RW,
5067*a491581fSWei Hu 				    &rxr->hn_rsc_drop,
5068*a491581fSWei Hu 				    "# of RSC fragments dropped");
506915516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx,
507015516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
507115516c77SSepherosa Ziehau 				    OID_AUTO, "pktbuf_len", CTLFLAG_RD,
507215516c77SSepherosa Ziehau 				    &rxr->hn_pktbuf_len, 0,
507315516c77SSepherosa Ziehau 				    "Temporary channel packet buffer length");
507415516c77SSepherosa Ziehau 			}
507515516c77SSepherosa Ziehau 		}
507615516c77SSepherosa Ziehau 	}
507715516c77SSepherosa Ziehau 
507815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued",
507915516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
508015516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_queued),
508115516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
508215516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
508315516c77SSepherosa Ziehau #else
508415516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
508515516c77SSepherosa Ziehau #endif
508615516c77SSepherosa Ziehau 	    "LU", "LRO queued");
508715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed",
508815516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
508915516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_flushed),
509015516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
509115516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
509215516c77SSepherosa Ziehau #else
509315516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
509415516c77SSepherosa Ziehau #endif
509515516c77SSepherosa Ziehau 	    "LU", "LRO flushed");
509615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried",
509715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
509815516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro_tried),
509915516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries");
510015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
510115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim",
510215516c77SSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
510315516c77SSepherosa Ziehau 	    hn_lro_lenlim_sysctl, "IU",
510415516c77SSepherosa Ziehau 	    "Max # of data bytes to be aggregated by LRO");
510515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim",
510615516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
510715516c77SSepherosa Ziehau 	    hn_lro_ackcnt_sysctl, "I",
510815516c77SSepherosa Ziehau 	    "Max # of ACKs to be aggregated by LRO");
510915516c77SSepherosa Ziehau #endif
511015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp",
511115516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP,
511215516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
511315516c77SSepherosa Ziehau 	    "Trust tcp segement verification on host side, "
511415516c77SSepherosa Ziehau 	    "when csum info is missing");
511515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp",
511615516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP,
511715516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
511815516c77SSepherosa Ziehau 	    "Trust udp datagram verification on host side, "
511915516c77SSepherosa Ziehau 	    "when csum info is missing");
512015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip",
512115516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP,
512215516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
512315516c77SSepherosa Ziehau 	    "Trust ip packet verification on host side, "
512415516c77SSepherosa Ziehau 	    "when csum info is missing");
512515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip",
512615516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
512715516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_ip),
512815516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP");
512915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp",
513015516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
513115516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_tcp),
513215516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP");
513315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp",
513415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
513515516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_udp),
513615516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP");
513715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted",
513815516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
513915516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_trusted),
514015516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU",
514115516c77SSepherosa Ziehau 	    "# of packets that we trust host's csum verification");
514215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts",
514315516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
514415516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_small_pkts),
514515516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of small packets received");
514615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed",
514715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
514815516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_ack_failed),
514915516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures");
515015516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt",
515115516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings");
515215516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse",
515315516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings");
515415516c77SSepherosa Ziehau 
515515516c77SSepherosa Ziehau 	return (0);
515615516c77SSepherosa Ziehau }
515715516c77SSepherosa Ziehau 
515815516c77SSepherosa Ziehau static void
515915516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc)
516015516c77SSepherosa Ziehau {
516115516c77SSepherosa Ziehau 	int i;
516215516c77SSepherosa Ziehau 
516315516c77SSepherosa Ziehau 	if (sc->hn_rxbuf != NULL) {
51642494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0)
516515516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf);
51662494d735SSepherosa Ziehau 		else
51672494d735SSepherosa Ziehau 			device_printf(sc->hn_dev, "RXBUF is referenced\n");
516815516c77SSepherosa Ziehau 		sc->hn_rxbuf = NULL;
516915516c77SSepherosa Ziehau 	}
517015516c77SSepherosa Ziehau 
517115516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_cnt == 0)
517215516c77SSepherosa Ziehau 		return;
517315516c77SSepherosa Ziehau 
517415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
517515516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
517615516c77SSepherosa Ziehau 
517715516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL)
517815516c77SSepherosa Ziehau 			continue;
51792494d735SSepherosa Ziehau 		if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) {
518015516c77SSepherosa Ziehau 			hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br);
51812494d735SSepherosa Ziehau 		} else {
51822494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
51832494d735SSepherosa Ziehau 			    "%dth channel bufring is referenced", i);
51842494d735SSepherosa Ziehau 		}
518515516c77SSepherosa Ziehau 		rxr->hn_br = NULL;
518615516c77SSepherosa Ziehau 
518715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
518815516c77SSepherosa Ziehau 		tcp_lro_free(&rxr->hn_lro);
518915516c77SSepherosa Ziehau #endif
519015516c77SSepherosa Ziehau 		free(rxr->hn_pktbuf, M_DEVBUF);
519115516c77SSepherosa Ziehau 	}
519215516c77SSepherosa Ziehau 	free(sc->hn_rx_ring, M_DEVBUF);
519315516c77SSepherosa Ziehau 	sc->hn_rx_ring = NULL;
519415516c77SSepherosa Ziehau 
519515516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = 0;
519615516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = 0;
519715516c77SSepherosa Ziehau }
519815516c77SSepherosa Ziehau 
519915516c77SSepherosa Ziehau static int
520015516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id)
520115516c77SSepherosa Ziehau {
520215516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[id];
520315516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
520415516c77SSepherosa Ziehau 	bus_dma_tag_t parent_dtag;
520515516c77SSepherosa Ziehau 	int error, i;
520615516c77SSepherosa Ziehau 
520715516c77SSepherosa Ziehau 	txr->hn_sc = sc;
520815516c77SSepherosa Ziehau 	txr->hn_tx_idx = id;
520915516c77SSepherosa Ziehau 
521015516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
521115516c77SSepherosa Ziehau 	mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN);
521215516c77SSepherosa Ziehau #endif
521315516c77SSepherosa Ziehau 	mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF);
521415516c77SSepherosa Ziehau 
521515516c77SSepherosa Ziehau 	txr->hn_txdesc_cnt = HN_TX_DESC_CNT;
521615516c77SSepherosa Ziehau 	txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt,
521715516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
521815516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
521915516c77SSepherosa Ziehau 	SLIST_INIT(&txr->hn_txlist);
522015516c77SSepherosa Ziehau #else
522115516c77SSepherosa Ziehau 	txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF,
522215516c77SSepherosa Ziehau 	    M_WAITOK, &txr->hn_tx_lock);
522315516c77SSepherosa Ziehau #endif
522415516c77SSepherosa Ziehau 
52250e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_EVTTQ) {
52260e11868dSSepherosa Ziehau 		txr->hn_tx_taskq = VMBUS_GET_EVENT_TASKQ(
52270e11868dSSepherosa Ziehau 		    device_get_parent(dev), dev, HN_RING_IDX2CPU(sc, id));
52280e11868dSSepherosa Ziehau 	} else {
5229fdd0222aSSepherosa Ziehau 		txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt];
52300e11868dSSepherosa Ziehau 	}
523115516c77SSepherosa Ziehau 
523223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
523315516c77SSepherosa Ziehau 	if (hn_use_if_start) {
523415516c77SSepherosa Ziehau 		txr->hn_txeof = hn_start_txeof;
523515516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr);
523615516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr);
523723bf9e15SSepherosa Ziehau 	} else
523823bf9e15SSepherosa Ziehau #endif
523923bf9e15SSepherosa Ziehau 	{
524015516c77SSepherosa Ziehau 		int br_depth;
524115516c77SSepherosa Ziehau 
524215516c77SSepherosa Ziehau 		txr->hn_txeof = hn_xmit_txeof;
524315516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr);
524415516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr);
524515516c77SSepherosa Ziehau 
524615516c77SSepherosa Ziehau 		br_depth = hn_get_txswq_depth(txr);
524715516c77SSepherosa Ziehau 		txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF,
524815516c77SSepherosa Ziehau 		    M_WAITOK, &txr->hn_tx_lock);
524915516c77SSepherosa Ziehau 	}
525015516c77SSepherosa Ziehau 
525115516c77SSepherosa Ziehau 	txr->hn_direct_tx_size = hn_direct_tx_size;
525215516c77SSepherosa Ziehau 
525315516c77SSepherosa Ziehau 	/*
525415516c77SSepherosa Ziehau 	 * Always schedule transmission instead of trying to do direct
525515516c77SSepherosa Ziehau 	 * transmission.  This one gives the best performance so far.
525615516c77SSepherosa Ziehau 	 */
525715516c77SSepherosa Ziehau 	txr->hn_sched_tx = 1;
525815516c77SSepherosa Ziehau 
525915516c77SSepherosa Ziehau 	parent_dtag = bus_get_dma_tag(dev);
526015516c77SSepherosa Ziehau 
526115516c77SSepherosa Ziehau 	/* DMA tag for RNDIS packet messages. */
526215516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
526315516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_ALIGN,		/* alignment */
526415516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_BOUNDARY,	/* boundary */
526515516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
526615516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
526715516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
526815516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsize */
526915516c77SSepherosa Ziehau 	    1,				/* nsegments */
527015516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsegsize */
527115516c77SSepherosa Ziehau 	    0,				/* flags */
527215516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
527315516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
527415516c77SSepherosa Ziehau 	    &txr->hn_tx_rndis_dtag);
527515516c77SSepherosa Ziehau 	if (error) {
527615516c77SSepherosa Ziehau 		device_printf(dev, "failed to create rndis dmatag\n");
527715516c77SSepherosa Ziehau 		return error;
527815516c77SSepherosa Ziehau 	}
527915516c77SSepherosa Ziehau 
528015516c77SSepherosa Ziehau 	/* DMA tag for data. */
528115516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
528215516c77SSepherosa Ziehau 	    1,				/* alignment */
528315516c77SSepherosa Ziehau 	    HN_TX_DATA_BOUNDARY,	/* boundary */
528415516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
528515516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
528615516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
528715516c77SSepherosa Ziehau 	    HN_TX_DATA_MAXSIZE,		/* maxsize */
528815516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGCNT_MAX,	/* nsegments */
528915516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGSIZE,		/* maxsegsize */
529015516c77SSepherosa Ziehau 	    0,				/* flags */
529115516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
529215516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
529315516c77SSepherosa Ziehau 	    &txr->hn_tx_data_dtag);
529415516c77SSepherosa Ziehau 	if (error) {
529515516c77SSepherosa Ziehau 		device_printf(dev, "failed to create data dmatag\n");
529615516c77SSepherosa Ziehau 		return error;
529715516c77SSepherosa Ziehau 	}
529815516c77SSepherosa Ziehau 
529915516c77SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i) {
530015516c77SSepherosa Ziehau 		struct hn_txdesc *txd = &txr->hn_txdesc[i];
530115516c77SSepherosa Ziehau 
530215516c77SSepherosa Ziehau 		txd->txr = txr;
530315516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
5304dc13fee6SSepherosa Ziehau 		STAILQ_INIT(&txd->agg_list);
530515516c77SSepherosa Ziehau 
530615516c77SSepherosa Ziehau 		/*
530715516c77SSepherosa Ziehau 		 * Allocate and load RNDIS packet message.
530815516c77SSepherosa Ziehau 		 */
530915516c77SSepherosa Ziehau         	error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag,
531015516c77SSepherosa Ziehau 		    (void **)&txd->rndis_pkt,
531115516c77SSepherosa Ziehau 		    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
531215516c77SSepherosa Ziehau 		    &txd->rndis_pkt_dmap);
531315516c77SSepherosa Ziehau 		if (error) {
531415516c77SSepherosa Ziehau 			device_printf(dev,
531515516c77SSepherosa Ziehau 			    "failed to allocate rndis_packet_msg, %d\n", i);
531615516c77SSepherosa Ziehau 			return error;
531715516c77SSepherosa Ziehau 		}
531815516c77SSepherosa Ziehau 
531915516c77SSepherosa Ziehau 		error = bus_dmamap_load(txr->hn_tx_rndis_dtag,
532015516c77SSepherosa Ziehau 		    txd->rndis_pkt_dmap,
532115516c77SSepherosa Ziehau 		    txd->rndis_pkt, HN_RNDIS_PKT_LEN,
532215516c77SSepherosa Ziehau 		    hyperv_dma_map_paddr, &txd->rndis_pkt_paddr,
532315516c77SSepherosa Ziehau 		    BUS_DMA_NOWAIT);
532415516c77SSepherosa Ziehau 		if (error) {
532515516c77SSepherosa Ziehau 			device_printf(dev,
532615516c77SSepherosa Ziehau 			    "failed to load rndis_packet_msg, %d\n", i);
532715516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
532815516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
532915516c77SSepherosa Ziehau 			return error;
533015516c77SSepherosa Ziehau 		}
533115516c77SSepherosa Ziehau 
533215516c77SSepherosa Ziehau 		/* DMA map for TX data. */
533315516c77SSepherosa Ziehau 		error = bus_dmamap_create(txr->hn_tx_data_dtag, 0,
533415516c77SSepherosa Ziehau 		    &txd->data_dmap);
533515516c77SSepherosa Ziehau 		if (error) {
533615516c77SSepherosa Ziehau 			device_printf(dev,
533715516c77SSepherosa Ziehau 			    "failed to allocate tx data dmamap\n");
533815516c77SSepherosa Ziehau 			bus_dmamap_unload(txr->hn_tx_rndis_dtag,
533915516c77SSepherosa Ziehau 			    txd->rndis_pkt_dmap);
534015516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
534115516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
534215516c77SSepherosa Ziehau 			return error;
534315516c77SSepherosa Ziehau 		}
534415516c77SSepherosa Ziehau 
534515516c77SSepherosa Ziehau 		/* All set, put it to list */
534615516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_ONLIST;
534715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
534815516c77SSepherosa Ziehau 		SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
534915516c77SSepherosa Ziehau #else
535015516c77SSepherosa Ziehau 		buf_ring_enqueue(txr->hn_txdesc_br, txd);
535115516c77SSepherosa Ziehau #endif
535215516c77SSepherosa Ziehau 	}
535315516c77SSepherosa Ziehau 	txr->hn_txdesc_avail = txr->hn_txdesc_cnt;
535415516c77SSepherosa Ziehau 
535515516c77SSepherosa Ziehau 	if (sc->hn_tx_sysctl_tree != NULL) {
535615516c77SSepherosa Ziehau 		struct sysctl_oid_list *child;
535715516c77SSepherosa Ziehau 		struct sysctl_ctx_list *ctx;
535815516c77SSepherosa Ziehau 		char name[16];
535915516c77SSepherosa Ziehau 
536015516c77SSepherosa Ziehau 		/*
536115516c77SSepherosa Ziehau 		 * Create per TX ring sysctl tree:
536215516c77SSepherosa Ziehau 		 * dev.hn.UNIT.tx.RINGID
536315516c77SSepherosa Ziehau 		 */
536415516c77SSepherosa Ziehau 		ctx = device_get_sysctl_ctx(dev);
536515516c77SSepherosa Ziehau 		child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree);
536615516c77SSepherosa Ziehau 
536715516c77SSepherosa Ziehau 		snprintf(name, sizeof(name), "%d", id);
536815516c77SSepherosa Ziehau 		txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
536915516c77SSepherosa Ziehau 		    name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
537015516c77SSepherosa Ziehau 
537115516c77SSepherosa Ziehau 		if (txr->hn_tx_sysctl_tree != NULL) {
537215516c77SSepherosa Ziehau 			child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree);
537315516c77SSepherosa Ziehau 
537485e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
537515516c77SSepherosa Ziehau 			SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail",
537615516c77SSepherosa Ziehau 			    CTLFLAG_RD, &txr->hn_txdesc_avail, 0,
537715516c77SSepherosa Ziehau 			    "# of available TX descs");
537885e4ae1eSSepherosa Ziehau #endif
537923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
538023bf9e15SSepherosa Ziehau 			if (!hn_use_if_start)
538123bf9e15SSepherosa Ziehau #endif
538223bf9e15SSepherosa Ziehau 			{
538315516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive",
538415516c77SSepherosa Ziehau 				    CTLFLAG_RD, &txr->hn_oactive, 0,
538515516c77SSepherosa Ziehau 				    "over active");
538615516c77SSepherosa Ziehau 			}
538715516c77SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets",
538815516c77SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_pkts,
538915516c77SSepherosa Ziehau 			    "# of packets transmitted");
5390dc13fee6SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends",
5391dc13fee6SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_sends, "# of sends");
539215516c77SSepherosa Ziehau 		}
539315516c77SSepherosa Ziehau 	}
539415516c77SSepherosa Ziehau 
539515516c77SSepherosa Ziehau 	return 0;
539615516c77SSepherosa Ziehau }
539715516c77SSepherosa Ziehau 
539815516c77SSepherosa Ziehau static void
539915516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd)
540015516c77SSepherosa Ziehau {
540115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = txd->txr;
540215516c77SSepherosa Ziehau 
540315516c77SSepherosa Ziehau 	KASSERT(txd->m == NULL, ("still has mbuf installed"));
540415516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped"));
540515516c77SSepherosa Ziehau 
540615516c77SSepherosa Ziehau 	bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap);
540715516c77SSepherosa Ziehau 	bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt,
540815516c77SSepherosa Ziehau 	    txd->rndis_pkt_dmap);
540915516c77SSepherosa Ziehau 	bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap);
541015516c77SSepherosa Ziehau }
541115516c77SSepherosa Ziehau 
541215516c77SSepherosa Ziehau static void
541325641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd)
541425641fc7SSepherosa Ziehau {
541525641fc7SSepherosa Ziehau 
541625641fc7SSepherosa Ziehau 	KASSERT(txd->refs == 0 || txd->refs == 1,
541725641fc7SSepherosa Ziehau 	    ("invalid txd refs %d", txd->refs));
541825641fc7SSepherosa Ziehau 
541925641fc7SSepherosa Ziehau 	/* Aggregated txds will be freed by their aggregating txd. */
542025641fc7SSepherosa Ziehau 	if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) {
542125641fc7SSepherosa Ziehau 		int freed;
542225641fc7SSepherosa Ziehau 
542325641fc7SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
542425641fc7SSepherosa Ziehau 		KASSERT(freed, ("can't free txdesc"));
542525641fc7SSepherosa Ziehau 	}
542625641fc7SSepherosa Ziehau }
542725641fc7SSepherosa Ziehau 
542825641fc7SSepherosa Ziehau static void
542915516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr)
543015516c77SSepherosa Ziehau {
543125641fc7SSepherosa Ziehau 	int i;
543215516c77SSepherosa Ziehau 
543315516c77SSepherosa Ziehau 	if (txr->hn_txdesc == NULL)
543415516c77SSepherosa Ziehau 		return;
543515516c77SSepherosa Ziehau 
543625641fc7SSepherosa Ziehau 	/*
543725641fc7SSepherosa Ziehau 	 * NOTE:
543825641fc7SSepherosa Ziehau 	 * Because the freeing of aggregated txds will be deferred
543925641fc7SSepherosa Ziehau 	 * to the aggregating txd, two passes are used here:
544025641fc7SSepherosa Ziehau 	 * - The first pass GCes any pending txds.  This GC is necessary,
544125641fc7SSepherosa Ziehau 	 *   since if the channels are revoked, hypervisor will not
544225641fc7SSepherosa Ziehau 	 *   deliver send-done for all pending txds.
544325641fc7SSepherosa Ziehau 	 * - The second pass frees the busdma stuffs, i.e. after all txds
544425641fc7SSepherosa Ziehau 	 *   were freed.
544525641fc7SSepherosa Ziehau 	 */
544625641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
544725641fc7SSepherosa Ziehau 		hn_txdesc_gc(txr, &txr->hn_txdesc[i]);
544825641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
544925641fc7SSepherosa Ziehau 		hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]);
545015516c77SSepherosa Ziehau 
545115516c77SSepherosa Ziehau 	if (txr->hn_tx_data_dtag != NULL)
545215516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_data_dtag);
545315516c77SSepherosa Ziehau 	if (txr->hn_tx_rndis_dtag != NULL)
545415516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_rndis_dtag);
545515516c77SSepherosa Ziehau 
545615516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
545715516c77SSepherosa Ziehau 	buf_ring_free(txr->hn_txdesc_br, M_DEVBUF);
545815516c77SSepherosa Ziehau #endif
545915516c77SSepherosa Ziehau 
546015516c77SSepherosa Ziehau 	free(txr->hn_txdesc, M_DEVBUF);
546115516c77SSepherosa Ziehau 	txr->hn_txdesc = NULL;
546215516c77SSepherosa Ziehau 
546315516c77SSepherosa Ziehau 	if (txr->hn_mbuf_br != NULL)
546415516c77SSepherosa Ziehau 		buf_ring_free(txr->hn_mbuf_br, M_DEVBUF);
546515516c77SSepherosa Ziehau 
546615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
546715516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_txlist_spin);
546815516c77SSepherosa Ziehau #endif
546915516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_tx_lock);
547015516c77SSepherosa Ziehau }
547115516c77SSepherosa Ziehau 
547215516c77SSepherosa Ziehau static int
547315516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt)
547415516c77SSepherosa Ziehau {
547515516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
547615516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
547715516c77SSepherosa Ziehau 	int i;
547815516c77SSepherosa Ziehau 
547915516c77SSepherosa Ziehau 	/*
548015516c77SSepherosa Ziehau 	 * Create TXBUF for chimney sending.
548115516c77SSepherosa Ziehau 	 *
548215516c77SSepherosa Ziehau 	 * NOTE: It is shared by all channels.
548315516c77SSepherosa Ziehau 	 */
548415516c77SSepherosa Ziehau 	sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev),
548515516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma,
548615516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
548715516c77SSepherosa Ziehau 	if (sc->hn_chim == NULL) {
548815516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate txbuf failed\n");
548915516c77SSepherosa Ziehau 		return (ENOMEM);
549015516c77SSepherosa Ziehau 	}
549115516c77SSepherosa Ziehau 
549215516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = ring_cnt;
549315516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
549415516c77SSepherosa Ziehau 
549515516c77SSepherosa Ziehau 	sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt,
549615516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
549715516c77SSepherosa Ziehau 
549815516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(sc->hn_dev);
549915516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev));
550015516c77SSepherosa Ziehau 
550115516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.tx sysctl tree */
550215516c77SSepherosa Ziehau 	sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx",
550315516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
550415516c77SSepherosa Ziehau 
550515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
550615516c77SSepherosa Ziehau 		int error;
550715516c77SSepherosa Ziehau 
550815516c77SSepherosa Ziehau 		error = hn_tx_ring_create(sc, i);
550915516c77SSepherosa Ziehau 		if (error)
551015516c77SSepherosa Ziehau 			return error;
551115516c77SSepherosa Ziehau 	}
551215516c77SSepherosa Ziehau 
551315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs",
551415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
551515516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_no_txdescs),
551615516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs");
551715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed",
551815516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
551915516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_send_failed),
552015516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure");
552115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed",
552215516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
552315516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_txdma_failed),
552415516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure");
5525dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed",
5526dc13fee6SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
5527dc13fee6SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_flush_failed),
5528dc13fee6SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU",
5529dc13fee6SSepherosa Ziehau 	    "# of packet transmission aggregation flush failure");
553015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed",
553115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
553215516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_collapsed),
553315516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed");
553415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney",
553515516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
553615516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney),
553715516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send");
553815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried",
553915516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
554015516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney_tried),
554115516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries");
554215516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt",
554315516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0,
554415516c77SSepherosa Ziehau 	    "# of total TX descs");
554515516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max",
554615516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_chim_szmax, 0,
554715516c77SSepherosa Ziehau 	    "Chimney send packet size upper boundary");
554815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size",
554915516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
555015516c77SSepherosa Ziehau 	    hn_chim_size_sysctl, "I", "Chimney send packet size limit");
555115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size",
555215516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
555315516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_direct_tx_size),
555415516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
555515516c77SSepherosa Ziehau 	    "Size of the packet for direct transmission");
555615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx",
555715516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
555815516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_sched_tx),
555915516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
556015516c77SSepherosa Ziehau 	    "Always schedule transmission "
556115516c77SSepherosa Ziehau 	    "instead of doing direct transmission");
556215516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt",
556315516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings");
556415516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse",
556515516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings");
5566dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax",
5567dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0,
5568dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation size");
5569dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax",
5570dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
5571dc13fee6SSepherosa Ziehau 	    hn_txagg_pktmax_sysctl, "I",
5572dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation packets");
5573dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align",
5574dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
5575dc13fee6SSepherosa Ziehau 	    hn_txagg_align_sysctl, "I",
5576dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation alignment");
557715516c77SSepherosa Ziehau 
557815516c77SSepherosa Ziehau 	return 0;
557915516c77SSepherosa Ziehau }
558015516c77SSepherosa Ziehau 
558115516c77SSepherosa Ziehau static void
558215516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size)
558315516c77SSepherosa Ziehau {
558415516c77SSepherosa Ziehau 	int i;
558515516c77SSepherosa Ziehau 
5586a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
558715516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_chim_size = chim_size;
558815516c77SSepherosa Ziehau }
558915516c77SSepherosa Ziehau 
559015516c77SSepherosa Ziehau static void
559115516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu)
559215516c77SSepherosa Ziehau {
559315516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
55949c6cae24SSepherosa Ziehau 	u_int hw_tsomax;
559515516c77SSepherosa Ziehau 	int tso_minlen;
559615516c77SSepherosa Ziehau 
55979c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
55989c6cae24SSepherosa Ziehau 
559915516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0)
560015516c77SSepherosa Ziehau 		return;
560115516c77SSepherosa Ziehau 
560215516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_sgmin >= 2,
560315516c77SSepherosa Ziehau 	    ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin));
560415516c77SSepherosa Ziehau 	tso_minlen = sc->hn_ndis_tso_sgmin * mtu;
560515516c77SSepherosa Ziehau 
560615516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen &&
560715516c77SSepherosa Ziehau 	    sc->hn_ndis_tso_szmax <= IP_MAXPACKET,
560815516c77SSepherosa Ziehau 	    ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax));
560915516c77SSepherosa Ziehau 
561015516c77SSepherosa Ziehau 	if (tso_maxlen < tso_minlen)
561115516c77SSepherosa Ziehau 		tso_maxlen = tso_minlen;
561215516c77SSepherosa Ziehau 	else if (tso_maxlen > IP_MAXPACKET)
561315516c77SSepherosa Ziehau 		tso_maxlen = IP_MAXPACKET;
561415516c77SSepherosa Ziehau 	if (tso_maxlen > sc->hn_ndis_tso_szmax)
561515516c77SSepherosa Ziehau 		tso_maxlen = sc->hn_ndis_tso_szmax;
56169c6cae24SSepherosa Ziehau 	hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
56179c6cae24SSepherosa Ziehau 
56189c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_isready(sc)) {
56199c6cae24SSepherosa Ziehau 		if (hw_tsomax > sc->hn_vf_ifp->if_hw_tsomax)
56209c6cae24SSepherosa Ziehau 			hw_tsomax = sc->hn_vf_ifp->if_hw_tsomax;
56219c6cae24SSepherosa Ziehau 	}
56229c6cae24SSepherosa Ziehau 	ifp->if_hw_tsomax = hw_tsomax;
562315516c77SSepherosa Ziehau 	if (bootverbose)
562415516c77SSepherosa Ziehau 		if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax);
562515516c77SSepherosa Ziehau }
562615516c77SSepherosa Ziehau 
562715516c77SSepherosa Ziehau static void
562815516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc)
562915516c77SSepherosa Ziehau {
563015516c77SSepherosa Ziehau 	uint64_t csum_assist;
563115516c77SSepherosa Ziehau 	int i;
563215516c77SSepherosa Ziehau 
563315516c77SSepherosa Ziehau 	hn_set_chim_size(sc, sc->hn_chim_szmax);
563415516c77SSepherosa Ziehau 	if (hn_tx_chimney_size > 0 &&
563515516c77SSepherosa Ziehau 	    hn_tx_chimney_size < sc->hn_chim_szmax)
563615516c77SSepherosa Ziehau 		hn_set_chim_size(sc, hn_tx_chimney_size);
563715516c77SSepherosa Ziehau 
563815516c77SSepherosa Ziehau 	csum_assist = 0;
563915516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_IPCS)
564015516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP;
564115516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP4CS)
564215516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_TCP;
56432be266caSSepherosa Ziehau 	if ((sc->hn_caps & HN_CAP_UDP4CS) && hn_enable_udp4cs)
564415516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_UDP;
564515516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP6CS)
564615516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_TCP;
56472be266caSSepherosa Ziehau 	if ((sc->hn_caps & HN_CAP_UDP6CS) && hn_enable_udp6cs)
564815516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_UDP;
564915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
565015516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_csum_assist = csum_assist;
565115516c77SSepherosa Ziehau 
565215516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_HASHVAL) {
565315516c77SSepherosa Ziehau 		/*
565415516c77SSepherosa Ziehau 		 * Support HASHVAL pktinfo on TX path.
565515516c77SSepherosa Ziehau 		 */
565615516c77SSepherosa Ziehau 		if (bootverbose)
565715516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n");
565815516c77SSepherosa Ziehau 		for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
565915516c77SSepherosa Ziehau 			sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL;
566015516c77SSepherosa Ziehau 	}
566115516c77SSepherosa Ziehau }
566215516c77SSepherosa Ziehau 
566315516c77SSepherosa Ziehau static void
5664db76829bSSepherosa Ziehau hn_fixup_rx_data(struct hn_softc *sc)
5665db76829bSSepherosa Ziehau {
5666db76829bSSepherosa Ziehau 
5667db76829bSSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDPHASH) {
5668db76829bSSepherosa Ziehau 		int i;
5669db76829bSSepherosa Ziehau 
5670db76829bSSepherosa Ziehau 		for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
5671db76829bSSepherosa Ziehau 			sc->hn_rx_ring[i].hn_rx_flags |= HN_RX_FLAG_UDP_HASH;
5672db76829bSSepherosa Ziehau 	}
5673db76829bSSepherosa Ziehau }
5674db76829bSSepherosa Ziehau 
5675db76829bSSepherosa Ziehau static void
567615516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc)
567715516c77SSepherosa Ziehau {
567815516c77SSepherosa Ziehau 	int i;
567915516c77SSepherosa Ziehau 
568015516c77SSepherosa Ziehau 	if (sc->hn_chim != NULL) {
56812494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) {
568215516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim);
56832494d735SSepherosa Ziehau 		} else {
56842494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
56852494d735SSepherosa Ziehau 			    "chimney sending buffer is referenced");
56862494d735SSepherosa Ziehau 		}
568715516c77SSepherosa Ziehau 		sc->hn_chim = NULL;
568815516c77SSepherosa Ziehau 	}
568915516c77SSepherosa Ziehau 
569015516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt == 0)
569115516c77SSepherosa Ziehau 		return;
569215516c77SSepherosa Ziehau 
569315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
569415516c77SSepherosa Ziehau 		hn_tx_ring_destroy(&sc->hn_tx_ring[i]);
569515516c77SSepherosa Ziehau 
569615516c77SSepherosa Ziehau 	free(sc->hn_tx_ring, M_DEVBUF);
569715516c77SSepherosa Ziehau 	sc->hn_tx_ring = NULL;
569815516c77SSepherosa Ziehau 
569915516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = 0;
570015516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = 0;
570115516c77SSepherosa Ziehau }
570215516c77SSepherosa Ziehau 
570323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
570423bf9e15SSepherosa Ziehau 
570515516c77SSepherosa Ziehau static void
570615516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused)
570715516c77SSepherosa Ziehau {
570815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
570915516c77SSepherosa Ziehau 
571015516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
571115516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
571215516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
571315516c77SSepherosa Ziehau }
571415516c77SSepherosa Ziehau 
571523bf9e15SSepherosa Ziehau static int
571623bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len)
571723bf9e15SSepherosa Ziehau {
571823bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
571923bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
5720dc13fee6SSepherosa Ziehau 	int sched = 0;
572123bf9e15SSepherosa Ziehau 
572223bf9e15SSepherosa Ziehau 	KASSERT(hn_use_if_start,
572323bf9e15SSepherosa Ziehau 	    ("hn_start_locked is called, when if_start is disabled"));
572423bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
572523bf9e15SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
5726dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
572723bf9e15SSepherosa Ziehau 
572823bf9e15SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
5729dc13fee6SSepherosa Ziehau 		return (0);
573023bf9e15SSepherosa Ziehau 
573123bf9e15SSepherosa Ziehau 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
573223bf9e15SSepherosa Ziehau 	    IFF_DRV_RUNNING)
5733dc13fee6SSepherosa Ziehau 		return (0);
573423bf9e15SSepherosa Ziehau 
573523bf9e15SSepherosa Ziehau 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
573623bf9e15SSepherosa Ziehau 		struct hn_txdesc *txd;
573723bf9e15SSepherosa Ziehau 		struct mbuf *m_head;
573823bf9e15SSepherosa Ziehau 		int error;
573923bf9e15SSepherosa Ziehau 
574023bf9e15SSepherosa Ziehau 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
574123bf9e15SSepherosa Ziehau 		if (m_head == NULL)
574223bf9e15SSepherosa Ziehau 			break;
574323bf9e15SSepherosa Ziehau 
574423bf9e15SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
574523bf9e15SSepherosa Ziehau 			/*
574623bf9e15SSepherosa Ziehau 			 * This sending could be time consuming; let callers
574723bf9e15SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
574823bf9e15SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
574923bf9e15SSepherosa Ziehau 			 */
575023bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
5751dc13fee6SSepherosa Ziehau 			sched = 1;
5752dc13fee6SSepherosa Ziehau 			break;
575323bf9e15SSepherosa Ziehau 		}
575423bf9e15SSepherosa Ziehau 
5755edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
5756edd3f315SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
5757edd3f315SSepherosa Ziehau 			m_head = hn_tso_fixup(m_head);
5758edd3f315SSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
5759edd3f315SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5760edd3f315SSepherosa Ziehau 				continue;
5761edd3f315SSepherosa Ziehau 			}
5762c49d47daSSepherosa Ziehau 		} else if (m_head->m_pkthdr.csum_flags &
5763c49d47daSSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) {
5764c49d47daSSepherosa Ziehau 			m_head = hn_set_hlen(m_head);
5765c49d47daSSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
5766c49d47daSSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5767c49d47daSSepherosa Ziehau 				continue;
5768c49d47daSSepherosa Ziehau 			}
5769edd3f315SSepherosa Ziehau 		}
5770edd3f315SSepherosa Ziehau #endif
5771edd3f315SSepherosa Ziehau 
577223bf9e15SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
577323bf9e15SSepherosa Ziehau 		if (txd == NULL) {
577423bf9e15SSepherosa Ziehau 			txr->hn_no_txdescs++;
577523bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
577623bf9e15SSepherosa Ziehau 			atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
577723bf9e15SSepherosa Ziehau 			break;
577823bf9e15SSepherosa Ziehau 		}
577923bf9e15SSepherosa Ziehau 
5780dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
578123bf9e15SSepherosa Ziehau 		if (error) {
578223bf9e15SSepherosa Ziehau 			/* Both txd and m_head are freed */
5783dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
5784dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
578523bf9e15SSepherosa Ziehau 			continue;
578623bf9e15SSepherosa Ziehau 		}
578723bf9e15SSepherosa Ziehau 
5788dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
5789dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
5790dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
5791dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
5792dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
5793dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
5794dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
5795dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
5796dc13fee6SSepherosa Ziehau 					break;
5797dc13fee6SSepherosa Ziehau 				}
5798dc13fee6SSepherosa Ziehau 			} else {
5799dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
580023bf9e15SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
580123bf9e15SSepherosa Ziehau 				if (__predict_false(error)) {
580223bf9e15SSepherosa Ziehau 					/* txd is freed, but m_head is not */
580323bf9e15SSepherosa Ziehau 					IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
5804dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
5805dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
580623bf9e15SSepherosa Ziehau 					break;
580723bf9e15SSepherosa Ziehau 				}
580823bf9e15SSepherosa Ziehau 			}
5809dc13fee6SSepherosa Ziehau 		}
5810dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
5811dc13fee6SSepherosa Ziehau 		else {
5812dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
5813dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
5814dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
5815dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
5816dc13fee6SSepherosa Ziehau 		}
5817dc13fee6SSepherosa Ziehau #endif
5818dc13fee6SSepherosa Ziehau 	}
5819dc13fee6SSepherosa Ziehau 
5820dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
5821dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
5822dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
5823dc13fee6SSepherosa Ziehau 	return (sched);
582423bf9e15SSepherosa Ziehau }
582523bf9e15SSepherosa Ziehau 
582623bf9e15SSepherosa Ziehau static void
582723bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp)
582823bf9e15SSepherosa Ziehau {
582923bf9e15SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
583023bf9e15SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[0];
583123bf9e15SSepherosa Ziehau 
583223bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
583323bf9e15SSepherosa Ziehau 		goto do_sched;
583423bf9e15SSepherosa Ziehau 
583523bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
583623bf9e15SSepherosa Ziehau 		int sched;
583723bf9e15SSepherosa Ziehau 
583823bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
583923bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
584023bf9e15SSepherosa Ziehau 		if (!sched)
584123bf9e15SSepherosa Ziehau 			return;
584223bf9e15SSepherosa Ziehau 	}
584323bf9e15SSepherosa Ziehau do_sched:
584423bf9e15SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
584523bf9e15SSepherosa Ziehau }
584623bf9e15SSepherosa Ziehau 
584715516c77SSepherosa Ziehau static void
584815516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused)
584915516c77SSepherosa Ziehau {
585015516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
585115516c77SSepherosa Ziehau 
585215516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
585315516c77SSepherosa Ziehau 	atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE);
585415516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
585515516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
585615516c77SSepherosa Ziehau }
585715516c77SSepherosa Ziehau 
585823bf9e15SSepherosa Ziehau static void
585923bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr)
586023bf9e15SSepherosa Ziehau {
586123bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
586223bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
586323bf9e15SSepherosa Ziehau 
586423bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
586523bf9e15SSepherosa Ziehau 
586623bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
586723bf9e15SSepherosa Ziehau 		goto do_sched;
586823bf9e15SSepherosa Ziehau 
586923bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
587023bf9e15SSepherosa Ziehau 		int sched;
587123bf9e15SSepherosa Ziehau 
587223bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
587323bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
587423bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
587523bf9e15SSepherosa Ziehau 		if (sched) {
587623bf9e15SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
587723bf9e15SSepherosa Ziehau 			    &txr->hn_tx_task);
587823bf9e15SSepherosa Ziehau 		}
587923bf9e15SSepherosa Ziehau 	} else {
588023bf9e15SSepherosa Ziehau do_sched:
588123bf9e15SSepherosa Ziehau 		/*
588223bf9e15SSepherosa Ziehau 		 * Release the OACTIVE earlier, with the hope, that
588323bf9e15SSepherosa Ziehau 		 * others could catch up.  The task will clear the
588423bf9e15SSepherosa Ziehau 		 * flag again with the hn_tx_lock to avoid possible
588523bf9e15SSepherosa Ziehau 		 * races.
588623bf9e15SSepherosa Ziehau 		 */
588723bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
588823bf9e15SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
588923bf9e15SSepherosa Ziehau 	}
589023bf9e15SSepherosa Ziehau }
589123bf9e15SSepherosa Ziehau 
589223bf9e15SSepherosa Ziehau #endif	/* HN_IFSTART_SUPPORT */
589323bf9e15SSepherosa Ziehau 
589415516c77SSepherosa Ziehau static int
589515516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len)
589615516c77SSepherosa Ziehau {
589715516c77SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
589815516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
589915516c77SSepherosa Ziehau 	struct mbuf *m_head;
5900dc13fee6SSepherosa Ziehau 	int sched = 0;
590115516c77SSepherosa Ziehau 
590215516c77SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
590323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
590415516c77SSepherosa Ziehau 	KASSERT(hn_use_if_start == 0,
590515516c77SSepherosa Ziehau 	    ("hn_xmit is called, when if_start is enabled"));
590623bf9e15SSepherosa Ziehau #endif
5907dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
590815516c77SSepherosa Ziehau 
590915516c77SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
5910dc13fee6SSepherosa Ziehau 		return (0);
591115516c77SSepherosa Ziehau 
591215516c77SSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive)
5913dc13fee6SSepherosa Ziehau 		return (0);
591415516c77SSepherosa Ziehau 
591515516c77SSepherosa Ziehau 	while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) {
591615516c77SSepherosa Ziehau 		struct hn_txdesc *txd;
591715516c77SSepherosa Ziehau 		int error;
591815516c77SSepherosa Ziehau 
591915516c77SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
592015516c77SSepherosa Ziehau 			/*
592115516c77SSepherosa Ziehau 			 * This sending could be time consuming; let callers
592215516c77SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
592315516c77SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
592415516c77SSepherosa Ziehau 			 */
592515516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
5926dc13fee6SSepherosa Ziehau 			sched = 1;
5927dc13fee6SSepherosa Ziehau 			break;
592815516c77SSepherosa Ziehau 		}
592915516c77SSepherosa Ziehau 
593015516c77SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
593115516c77SSepherosa Ziehau 		if (txd == NULL) {
593215516c77SSepherosa Ziehau 			txr->hn_no_txdescs++;
593315516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
593415516c77SSepherosa Ziehau 			txr->hn_oactive = 1;
593515516c77SSepherosa Ziehau 			break;
593615516c77SSepherosa Ziehau 		}
593715516c77SSepherosa Ziehau 
5938dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
593915516c77SSepherosa Ziehau 		if (error) {
594015516c77SSepherosa Ziehau 			/* Both txd and m_head are freed; discard */
5941dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
5942dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
594315516c77SSepherosa Ziehau 			drbr_advance(ifp, txr->hn_mbuf_br);
594415516c77SSepherosa Ziehau 			continue;
594515516c77SSepherosa Ziehau 		}
594615516c77SSepherosa Ziehau 
5947dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
5948dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
5949dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
5950dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
5951dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
595215516c77SSepherosa Ziehau 				if (__predict_false(error)) {
595315516c77SSepherosa Ziehau 					txr->hn_oactive = 1;
595415516c77SSepherosa Ziehau 					break;
595515516c77SSepherosa Ziehau 				}
5956dc13fee6SSepherosa Ziehau 			} else {
5957dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
5958dc13fee6SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
5959dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
5960dc13fee6SSepherosa Ziehau 					/* txd is freed, but m_head is not */
5961dc13fee6SSepherosa Ziehau 					drbr_putback(ifp, txr->hn_mbuf_br,
5962dc13fee6SSepherosa Ziehau 					    m_head);
5963dc13fee6SSepherosa Ziehau 					txr->hn_oactive = 1;
5964dc13fee6SSepherosa Ziehau 					break;
5965dc13fee6SSepherosa Ziehau 				}
5966dc13fee6SSepherosa Ziehau 			}
5967dc13fee6SSepherosa Ziehau 		}
5968dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
5969dc13fee6SSepherosa Ziehau 		else {
5970dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
5971dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
5972dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
5973dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
5974dc13fee6SSepherosa Ziehau 		}
5975dc13fee6SSepherosa Ziehau #endif
597615516c77SSepherosa Ziehau 
597715516c77SSepherosa Ziehau 		/* Sent */
597815516c77SSepherosa Ziehau 		drbr_advance(ifp, txr->hn_mbuf_br);
597915516c77SSepherosa Ziehau 	}
5980dc13fee6SSepherosa Ziehau 
5981dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
5982dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
5983dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
5984dc13fee6SSepherosa Ziehau 	return (sched);
598515516c77SSepherosa Ziehau }
598615516c77SSepherosa Ziehau 
598715516c77SSepherosa Ziehau static int
598815516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m)
598915516c77SSepherosa Ziehau {
599015516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
599115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
599215516c77SSepherosa Ziehau 	int error, idx = 0;
599315516c77SSepherosa Ziehau 
59949c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) {
59959c6cae24SSepherosa Ziehau 		struct rm_priotracker pt;
59969c6cae24SSepherosa Ziehau 
59979c6cae24SSepherosa Ziehau 		rm_rlock(&sc->hn_vf_lock, &pt);
59989c6cae24SSepherosa Ziehau 		if (__predict_true(sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
59999c6cae24SSepherosa Ziehau 			struct mbuf *m_bpf = NULL;
60009c6cae24SSepherosa Ziehau 			int obytes, omcast;
60019c6cae24SSepherosa Ziehau 
60029c6cae24SSepherosa Ziehau 			obytes = m->m_pkthdr.len;
60037898a1f4SEric van Gyzen 			omcast = (m->m_flags & M_MCAST) != 0;
60049c6cae24SSepherosa Ziehau 
60059c6cae24SSepherosa Ziehau 			if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF) {
60069c6cae24SSepherosa Ziehau 				if (bpf_peers_present(ifp->if_bpf)) {
60079c6cae24SSepherosa Ziehau 					m_bpf = m_copypacket(m, M_NOWAIT);
60089c6cae24SSepherosa Ziehau 					if (m_bpf == NULL) {
60099c6cae24SSepherosa Ziehau 						/*
60109c6cae24SSepherosa Ziehau 						 * Failed to grab a shallow
60119c6cae24SSepherosa Ziehau 						 * copy; tap now.
60129c6cae24SSepherosa Ziehau 						 */
60139c6cae24SSepherosa Ziehau 						ETHER_BPF_MTAP(ifp, m);
60149c6cae24SSepherosa Ziehau 					}
60159c6cae24SSepherosa Ziehau 				}
60169c6cae24SSepherosa Ziehau 			} else {
60179c6cae24SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, m);
60189c6cae24SSepherosa Ziehau 			}
60199c6cae24SSepherosa Ziehau 
60209c6cae24SSepherosa Ziehau 			error = sc->hn_vf_ifp->if_transmit(sc->hn_vf_ifp, m);
60219c6cae24SSepherosa Ziehau 			rm_runlock(&sc->hn_vf_lock, &pt);
60229c6cae24SSepherosa Ziehau 
60239c6cae24SSepherosa Ziehau 			if (m_bpf != NULL) {
60249c6cae24SSepherosa Ziehau 				if (!error)
60259c6cae24SSepherosa Ziehau 					ETHER_BPF_MTAP(ifp, m_bpf);
60269c6cae24SSepherosa Ziehau 				m_freem(m_bpf);
60279c6cae24SSepherosa Ziehau 			}
60289c6cae24SSepherosa Ziehau 
60299c6cae24SSepherosa Ziehau 			if (error == ENOBUFS) {
60309c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
60319c6cae24SSepherosa Ziehau 			} else if (error) {
60329c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
60339c6cae24SSepherosa Ziehau 			} else {
60349c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
60359c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OBYTES, obytes);
60369c6cae24SSepherosa Ziehau 				if (omcast) {
60379c6cae24SSepherosa Ziehau 					if_inc_counter(ifp, IFCOUNTER_OMCASTS,
60389c6cae24SSepherosa Ziehau 					    omcast);
60399c6cae24SSepherosa Ziehau 				}
60409c6cae24SSepherosa Ziehau 			}
60419c6cae24SSepherosa Ziehau 			return (error);
60429c6cae24SSepherosa Ziehau 		}
60439c6cae24SSepherosa Ziehau 		rm_runlock(&sc->hn_vf_lock, &pt);
60449c6cae24SSepherosa Ziehau 	}
60459c6cae24SSepherosa Ziehau 
6046edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
6047edd3f315SSepherosa Ziehau 	/*
6048c49d47daSSepherosa Ziehau 	 * Perform TSO packet header fixup or get l2/l3 header length now,
6049c49d47daSSepherosa Ziehau 	 * since packet headers should be cache-hot.
6050edd3f315SSepherosa Ziehau 	 */
6051edd3f315SSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
6052edd3f315SSepherosa Ziehau 		m = hn_tso_fixup(m);
6053edd3f315SSepherosa Ziehau 		if (__predict_false(m == NULL)) {
6054edd3f315SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
6055edd3f315SSepherosa Ziehau 			return EIO;
6056edd3f315SSepherosa Ziehau 		}
6057c49d47daSSepherosa Ziehau 	} else if (m->m_pkthdr.csum_flags &
6058c49d47daSSepherosa Ziehau 	    (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) {
6059c49d47daSSepherosa Ziehau 		m = hn_set_hlen(m);
6060c49d47daSSepherosa Ziehau 		if (__predict_false(m == NULL)) {
6061c49d47daSSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
6062c49d47daSSepherosa Ziehau 			return EIO;
6063c49d47daSSepherosa Ziehau 		}
6064edd3f315SSepherosa Ziehau 	}
6065edd3f315SSepherosa Ziehau #endif
6066edd3f315SSepherosa Ziehau 
606715516c77SSepherosa Ziehau 	/*
606815516c77SSepherosa Ziehau 	 * Select the TX ring based on flowid
606915516c77SSepherosa Ziehau 	 */
607034d68912SSepherosa Ziehau 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
607134d68912SSepherosa Ziehau #ifdef RSS
607234d68912SSepherosa Ziehau 		uint32_t bid;
607334d68912SSepherosa Ziehau 
607434d68912SSepherosa Ziehau 		if (rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m),
607534d68912SSepherosa Ziehau 		    &bid) == 0)
607634d68912SSepherosa Ziehau 			idx = bid % sc->hn_tx_ring_inuse;
607734d68912SSepherosa Ziehau 		else
607834d68912SSepherosa Ziehau #endif
6079cc0c6ebcSSepherosa Ziehau 		{
6080cc0c6ebcSSepherosa Ziehau #if defined(INET6) || defined(INET)
6081cc0c6ebcSSepherosa Ziehau 			int tcpsyn = 0;
6082cc0c6ebcSSepherosa Ziehau 
6083cc0c6ebcSSepherosa Ziehau 			if (m->m_pkthdr.len < 128 &&
6084cc0c6ebcSSepherosa Ziehau 			    (m->m_pkthdr.csum_flags &
6085cc0c6ebcSSepherosa Ziehau 			     (CSUM_IP_TCP | CSUM_IP6_TCP)) &&
6086cc0c6ebcSSepherosa Ziehau 			    (m->m_pkthdr.csum_flags & CSUM_TSO) == 0) {
6087cc0c6ebcSSepherosa Ziehau 				m = hn_check_tcpsyn(m, &tcpsyn);
6088cc0c6ebcSSepherosa Ziehau 				if (__predict_false(m == NULL)) {
6089cc0c6ebcSSepherosa Ziehau 					if_inc_counter(ifp,
6090cc0c6ebcSSepherosa Ziehau 					    IFCOUNTER_OERRORS, 1);
6091cc0c6ebcSSepherosa Ziehau 					return (EIO);
6092cc0c6ebcSSepherosa Ziehau 				}
6093cc0c6ebcSSepherosa Ziehau 			}
6094cc0c6ebcSSepherosa Ziehau #else
6095cc0c6ebcSSepherosa Ziehau 			const int tcpsyn = 0;
6096cc0c6ebcSSepherosa Ziehau #endif
6097cc0c6ebcSSepherosa Ziehau 			if (tcpsyn)
6098cc0c6ebcSSepherosa Ziehau 				idx = 0;
6099cc0c6ebcSSepherosa Ziehau 			else
610015516c77SSepherosa Ziehau 				idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse;
610134d68912SSepherosa Ziehau 		}
6102cc0c6ebcSSepherosa Ziehau 	}
610315516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[idx];
610415516c77SSepherosa Ziehau 
610515516c77SSepherosa Ziehau 	error = drbr_enqueue(ifp, txr->hn_mbuf_br, m);
610615516c77SSepherosa Ziehau 	if (error) {
610715516c77SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
610815516c77SSepherosa Ziehau 		return error;
610915516c77SSepherosa Ziehau 	}
611015516c77SSepherosa Ziehau 
611115516c77SSepherosa Ziehau 	if (txr->hn_oactive)
611215516c77SSepherosa Ziehau 		return 0;
611315516c77SSepherosa Ziehau 
611415516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
611515516c77SSepherosa Ziehau 		goto do_sched;
611615516c77SSepherosa Ziehau 
611715516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
611815516c77SSepherosa Ziehau 		int sched;
611915516c77SSepherosa Ziehau 
612015516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
612115516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
612215516c77SSepherosa Ziehau 		if (!sched)
612315516c77SSepherosa Ziehau 			return 0;
612415516c77SSepherosa Ziehau 	}
612515516c77SSepherosa Ziehau do_sched:
612615516c77SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
612715516c77SSepherosa Ziehau 	return 0;
612815516c77SSepherosa Ziehau }
612915516c77SSepherosa Ziehau 
613015516c77SSepherosa Ziehau static void
613115516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr)
613215516c77SSepherosa Ziehau {
613315516c77SSepherosa Ziehau 	struct mbuf *m;
613415516c77SSepherosa Ziehau 
613515516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
613615516c77SSepherosa Ziehau 	while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL)
613715516c77SSepherosa Ziehau 		m_freem(m);
613815516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
613915516c77SSepherosa Ziehau }
614015516c77SSepherosa Ziehau 
614115516c77SSepherosa Ziehau static void
614215516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp)
614315516c77SSepherosa Ziehau {
614415516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
61459c6cae24SSepherosa Ziehau 	struct rm_priotracker pt;
614615516c77SSepherosa Ziehau 	int i;
614715516c77SSepherosa Ziehau 
614815516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
614915516c77SSepherosa Ziehau 		hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
615015516c77SSepherosa Ziehau 	if_qflush(ifp);
61519c6cae24SSepherosa Ziehau 
61529c6cae24SSepherosa Ziehau 	rm_rlock(&sc->hn_vf_lock, &pt);
61539c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
61549c6cae24SSepherosa Ziehau 		sc->hn_vf_ifp->if_qflush(sc->hn_vf_ifp);
61559c6cae24SSepherosa Ziehau 	rm_runlock(&sc->hn_vf_lock, &pt);
615615516c77SSepherosa Ziehau }
615715516c77SSepherosa Ziehau 
615815516c77SSepherosa Ziehau static void
615915516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr)
616015516c77SSepherosa Ziehau {
616115516c77SSepherosa Ziehau 
616215516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
616315516c77SSepherosa Ziehau 		goto do_sched;
616415516c77SSepherosa Ziehau 
616515516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
616615516c77SSepherosa Ziehau 		int sched;
616715516c77SSepherosa Ziehau 
616815516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
616915516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
617015516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
617115516c77SSepherosa Ziehau 		if (sched) {
617215516c77SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
617315516c77SSepherosa Ziehau 			    &txr->hn_tx_task);
617415516c77SSepherosa Ziehau 		}
617515516c77SSepherosa Ziehau 	} else {
617615516c77SSepherosa Ziehau do_sched:
617715516c77SSepherosa Ziehau 		/*
617815516c77SSepherosa Ziehau 		 * Release the oactive earlier, with the hope, that
617915516c77SSepherosa Ziehau 		 * others could catch up.  The task will clear the
618015516c77SSepherosa Ziehau 		 * oactive again with the hn_tx_lock to avoid possible
618115516c77SSepherosa Ziehau 		 * races.
618215516c77SSepherosa Ziehau 		 */
618315516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
618415516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
618515516c77SSepherosa Ziehau 	}
618615516c77SSepherosa Ziehau }
618715516c77SSepherosa Ziehau 
618815516c77SSepherosa Ziehau static void
618915516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused)
619015516c77SSepherosa Ziehau {
619115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
619215516c77SSepherosa Ziehau 
619315516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
619415516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
619515516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
619615516c77SSepherosa Ziehau }
619715516c77SSepherosa Ziehau 
619815516c77SSepherosa Ziehau static void
619915516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused)
620015516c77SSepherosa Ziehau {
620115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
620215516c77SSepherosa Ziehau 
620315516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
620415516c77SSepherosa Ziehau 	txr->hn_oactive = 0;
620515516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
620615516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
620715516c77SSepherosa Ziehau }
620815516c77SSepherosa Ziehau 
620915516c77SSepherosa Ziehau static int
621015516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan)
621115516c77SSepherosa Ziehau {
621215516c77SSepherosa Ziehau 	struct vmbus_chan_br cbr;
621315516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
621415516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = NULL;
621515516c77SSepherosa Ziehau 	int idx, error;
621615516c77SSepherosa Ziehau 
621715516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
621815516c77SSepherosa Ziehau 
621915516c77SSepherosa Ziehau 	/*
622015516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
622115516c77SSepherosa Ziehau 	 */
622215516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
622315516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
622415516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
622515516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
622615516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0,
622715516c77SSepherosa Ziehau 	    ("RX ring %d already attached", idx));
622815516c77SSepherosa Ziehau 	rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED;
62293ab0fea1SDexuan Cui 	rxr->hn_chan = chan;
623015516c77SSepherosa Ziehau 
623115516c77SSepherosa Ziehau 	if (bootverbose) {
623215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n",
623315516c77SSepherosa Ziehau 		    idx, vmbus_chan_id(chan));
623415516c77SSepherosa Ziehau 	}
623515516c77SSepherosa Ziehau 
623615516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
623715516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[idx];
623815516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0,
623915516c77SSepherosa Ziehau 		    ("TX ring %d already attached", idx));
624015516c77SSepherosa Ziehau 		txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED;
624115516c77SSepherosa Ziehau 
624215516c77SSepherosa Ziehau 		txr->hn_chan = chan;
624315516c77SSepherosa Ziehau 		if (bootverbose) {
624415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n",
624515516c77SSepherosa Ziehau 			    idx, vmbus_chan_id(chan));
624615516c77SSepherosa Ziehau 		}
624715516c77SSepherosa Ziehau 	}
624815516c77SSepherosa Ziehau 
624915516c77SSepherosa Ziehau 	/* Bind this channel to a proper CPU. */
62500e11868dSSepherosa Ziehau 	vmbus_chan_cpu_set(chan, HN_RING_IDX2CPU(sc, idx));
625115516c77SSepherosa Ziehau 
625215516c77SSepherosa Ziehau 	/*
625315516c77SSepherosa Ziehau 	 * Open this channel
625415516c77SSepherosa Ziehau 	 */
625515516c77SSepherosa Ziehau 	cbr.cbr = rxr->hn_br;
625615516c77SSepherosa Ziehau 	cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr;
625715516c77SSepherosa Ziehau 	cbr.cbr_txsz = HN_TXBR_SIZE;
625815516c77SSepherosa Ziehau 	cbr.cbr_rxsz = HN_RXBR_SIZE;
625915516c77SSepherosa Ziehau 	error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr);
626015516c77SSepherosa Ziehau 	if (error) {
626171e8ac56SSepherosa Ziehau 		if (error == EISCONN) {
626271e8ac56SSepherosa Ziehau 			if_printf(sc->hn_ifp, "bufring is connected after "
626371e8ac56SSepherosa Ziehau 			    "chan%u open failure\n", vmbus_chan_id(chan));
626471e8ac56SSepherosa Ziehau 			rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
626571e8ac56SSepherosa Ziehau 		} else {
626615516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "open chan%u failed: %d\n",
626715516c77SSepherosa Ziehau 			    vmbus_chan_id(chan), error);
626871e8ac56SSepherosa Ziehau 		}
626915516c77SSepherosa Ziehau 	}
627015516c77SSepherosa Ziehau 	return (error);
627115516c77SSepherosa Ziehau }
627215516c77SSepherosa Ziehau 
627315516c77SSepherosa Ziehau static void
627415516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan)
627515516c77SSepherosa Ziehau {
627615516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
62772494d735SSepherosa Ziehau 	int idx, error;
627815516c77SSepherosa Ziehau 
627915516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
628015516c77SSepherosa Ziehau 
628115516c77SSepherosa Ziehau 	/*
628215516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
628315516c77SSepherosa Ziehau 	 */
628415516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
628515516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
628615516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
628715516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
628815516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED),
628915516c77SSepherosa Ziehau 	    ("RX ring %d is not attached", idx));
629015516c77SSepherosa Ziehau 	rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
629115516c77SSepherosa Ziehau 
629215516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
629315516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[idx];
629415516c77SSepherosa Ziehau 
629515516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED),
629615516c77SSepherosa Ziehau 		    ("TX ring %d is not attached attached", idx));
629715516c77SSepherosa Ziehau 		txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
629815516c77SSepherosa Ziehau 	}
629915516c77SSepherosa Ziehau 
630015516c77SSepherosa Ziehau 	/*
630115516c77SSepherosa Ziehau 	 * Close this channel.
630215516c77SSepherosa Ziehau 	 *
630315516c77SSepherosa Ziehau 	 * NOTE:
630415516c77SSepherosa Ziehau 	 * Channel closing does _not_ destroy the target channel.
630515516c77SSepherosa Ziehau 	 */
63062494d735SSepherosa Ziehau 	error = vmbus_chan_close_direct(chan);
63072494d735SSepherosa Ziehau 	if (error == EISCONN) {
6308aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u bufring is connected "
6309aa1a2adcSSepherosa Ziehau 		    "after being closed\n", vmbus_chan_id(chan));
63102494d735SSepherosa Ziehau 		rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
63112494d735SSepherosa Ziehau 	} else if (error) {
6312aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u close failed: %d\n",
6313aa1a2adcSSepherosa Ziehau 		    vmbus_chan_id(chan), error);
63142494d735SSepherosa Ziehau 	}
631515516c77SSepherosa Ziehau }
631615516c77SSepherosa Ziehau 
631715516c77SSepherosa Ziehau static int
631815516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc)
631915516c77SSepherosa Ziehau {
632015516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
632115516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
632215516c77SSepherosa Ziehau 	int i, error = 0;
632315516c77SSepherosa Ziehau 
632471e8ac56SSepherosa Ziehau 	KASSERT(subchan_cnt > 0, ("no sub-channels"));
632515516c77SSepherosa Ziehau 
632615516c77SSepherosa Ziehau 	/* Attach the sub-channels. */
632715516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
632815516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i) {
632971e8ac56SSepherosa Ziehau 		int error1;
633071e8ac56SSepherosa Ziehau 
633171e8ac56SSepherosa Ziehau 		error1 = hn_chan_attach(sc, subchans[i]);
633271e8ac56SSepherosa Ziehau 		if (error1) {
633371e8ac56SSepherosa Ziehau 			error = error1;
633471e8ac56SSepherosa Ziehau 			/* Move on; all channels will be detached later. */
633571e8ac56SSepherosa Ziehau 		}
633615516c77SSepherosa Ziehau 	}
633715516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
633815516c77SSepherosa Ziehau 
633915516c77SSepherosa Ziehau 	if (error) {
634015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error);
634115516c77SSepherosa Ziehau 	} else {
634215516c77SSepherosa Ziehau 		if (bootverbose) {
634315516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "%d sub-channels attached\n",
634415516c77SSepherosa Ziehau 			    subchan_cnt);
634515516c77SSepherosa Ziehau 		}
634615516c77SSepherosa Ziehau 	}
634715516c77SSepherosa Ziehau 	return (error);
634815516c77SSepherosa Ziehau }
634915516c77SSepherosa Ziehau 
635015516c77SSepherosa Ziehau static void
635115516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc)
635215516c77SSepherosa Ziehau {
635315516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
635415516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
635515516c77SSepherosa Ziehau 	int i;
635615516c77SSepherosa Ziehau 
635715516c77SSepherosa Ziehau 	if (subchan_cnt == 0)
635815516c77SSepherosa Ziehau 		goto back;
635915516c77SSepherosa Ziehau 
636015516c77SSepherosa Ziehau 	/* Detach the sub-channels. */
636115516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
636215516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i)
636315516c77SSepherosa Ziehau 		hn_chan_detach(sc, subchans[i]);
636415516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
636515516c77SSepherosa Ziehau 
636615516c77SSepherosa Ziehau back:
636715516c77SSepherosa Ziehau 	/*
636815516c77SSepherosa Ziehau 	 * Detach the primary channel, _after_ all sub-channels
636915516c77SSepherosa Ziehau 	 * are detached.
637015516c77SSepherosa Ziehau 	 */
637115516c77SSepherosa Ziehau 	hn_chan_detach(sc, sc->hn_prichan);
637215516c77SSepherosa Ziehau 
637315516c77SSepherosa Ziehau 	/* Wait for sub-channels to be destroyed, if any. */
637415516c77SSepherosa Ziehau 	vmbus_subchan_drain(sc->hn_prichan);
637515516c77SSepherosa Ziehau 
637615516c77SSepherosa Ziehau #ifdef INVARIANTS
637715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
637815516c77SSepherosa Ziehau 		KASSERT((sc->hn_rx_ring[i].hn_rx_flags &
637915516c77SSepherosa Ziehau 		    HN_RX_FLAG_ATTACHED) == 0,
638015516c77SSepherosa Ziehau 		    ("%dth RX ring is still attached", i));
638115516c77SSepherosa Ziehau 	}
638215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
638315516c77SSepherosa Ziehau 		KASSERT((sc->hn_tx_ring[i].hn_tx_flags &
638415516c77SSepherosa Ziehau 		    HN_TX_FLAG_ATTACHED) == 0,
638515516c77SSepherosa Ziehau 		    ("%dth TX ring is still attached", i));
638615516c77SSepherosa Ziehau 	}
638715516c77SSepherosa Ziehau #endif
638815516c77SSepherosa Ziehau }
638915516c77SSepherosa Ziehau 
639015516c77SSepherosa Ziehau static int
639115516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch)
639215516c77SSepherosa Ziehau {
639315516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
639415516c77SSepherosa Ziehau 	int nchan, rxr_cnt, error;
639515516c77SSepherosa Ziehau 
639615516c77SSepherosa Ziehau 	nchan = *nsubch + 1;
639715516c77SSepherosa Ziehau 	if (nchan == 1) {
639815516c77SSepherosa Ziehau 		/*
639915516c77SSepherosa Ziehau 		 * Multiple RX/TX rings are not requested.
640015516c77SSepherosa Ziehau 		 */
640115516c77SSepherosa Ziehau 		*nsubch = 0;
640215516c77SSepherosa Ziehau 		return (0);
640315516c77SSepherosa Ziehau 	}
640415516c77SSepherosa Ziehau 
640515516c77SSepherosa Ziehau 	/*
640615516c77SSepherosa Ziehau 	 * Query RSS capabilities, e.g. # of RX rings, and # of indirect
640715516c77SSepherosa Ziehau 	 * table entries.
640815516c77SSepherosa Ziehau 	 */
640915516c77SSepherosa Ziehau 	error = hn_rndis_query_rsscaps(sc, &rxr_cnt);
641015516c77SSepherosa Ziehau 	if (error) {
641115516c77SSepherosa Ziehau 		/* No RSS; this is benign. */
641215516c77SSepherosa Ziehau 		*nsubch = 0;
641315516c77SSepherosa Ziehau 		return (0);
641415516c77SSepherosa Ziehau 	}
641515516c77SSepherosa Ziehau 	if (bootverbose) {
641615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
641715516c77SSepherosa Ziehau 		    rxr_cnt, nchan);
641815516c77SSepherosa Ziehau 	}
641915516c77SSepherosa Ziehau 
642015516c77SSepherosa Ziehau 	if (nchan > rxr_cnt)
642115516c77SSepherosa Ziehau 		nchan = rxr_cnt;
642215516c77SSepherosa Ziehau 	if (nchan == 1) {
642315516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n");
642415516c77SSepherosa Ziehau 		*nsubch = 0;
642515516c77SSepherosa Ziehau 		return (0);
642615516c77SSepherosa Ziehau 	}
642715516c77SSepherosa Ziehau 
642815516c77SSepherosa Ziehau 	/*
642915516c77SSepherosa Ziehau 	 * Allocate sub-channels from NVS.
643015516c77SSepherosa Ziehau 	 */
643115516c77SSepherosa Ziehau 	*nsubch = nchan - 1;
643215516c77SSepherosa Ziehau 	error = hn_nvs_alloc_subchans(sc, nsubch);
643315516c77SSepherosa Ziehau 	if (error || *nsubch == 0) {
643415516c77SSepherosa Ziehau 		/* Failed to allocate sub-channels. */
643515516c77SSepherosa Ziehau 		*nsubch = 0;
643615516c77SSepherosa Ziehau 		return (0);
643715516c77SSepherosa Ziehau 	}
643815516c77SSepherosa Ziehau 
643915516c77SSepherosa Ziehau 	/*
644015516c77SSepherosa Ziehau 	 * Wait for all sub-channels to become ready before moving on.
644115516c77SSepherosa Ziehau 	 */
644215516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch);
644315516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, *nsubch);
644415516c77SSepherosa Ziehau 	return (0);
644515516c77SSepherosa Ziehau }
644615516c77SSepherosa Ziehau 
64472494d735SSepherosa Ziehau static bool
64482494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc)
64492494d735SSepherosa Ziehau {
64502494d735SSepherosa Ziehau 	int i;
64512494d735SSepherosa Ziehau 
64522494d735SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_ERRORS)
64532494d735SSepherosa Ziehau 		return (false);
64542494d735SSepherosa Ziehau 
64552494d735SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
64562494d735SSepherosa Ziehau 		const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
64572494d735SSepherosa Ziehau 
64582494d735SSepherosa Ziehau 		if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF)
64592494d735SSepherosa Ziehau 			return (false);
64602494d735SSepherosa Ziehau 	}
64612494d735SSepherosa Ziehau 	return (true);
64622494d735SSepherosa Ziehau }
64632494d735SSepherosa Ziehau 
6464b3b75d9cSSepherosa Ziehau /*
6465b3b75d9cSSepherosa Ziehau  * Make sure that the RX filter is zero after the successful
6466b3b75d9cSSepherosa Ziehau  * RNDIS initialization.
6467b3b75d9cSSepherosa Ziehau  *
6468b3b75d9cSSepherosa Ziehau  * NOTE:
6469b3b75d9cSSepherosa Ziehau  * Under certain conditions on certain versions of Hyper-V,
6470b3b75d9cSSepherosa Ziehau  * the RNDIS rxfilter is _not_ zero on the hypervisor side
6471b3b75d9cSSepherosa Ziehau  * after the successful RNDIS initialization, which breaks
6472b3b75d9cSSepherosa Ziehau  * the assumption of any following code (well, it breaks the
6473b3b75d9cSSepherosa Ziehau  * RNDIS API contract actually).  Clear the RNDIS rxfilter
6474b3b75d9cSSepherosa Ziehau  * explicitly, drain packets sneaking through, and drain the
6475b3b75d9cSSepherosa Ziehau  * interrupt taskqueues scheduled due to the stealth packets.
6476b3b75d9cSSepherosa Ziehau  */
6477b3b75d9cSSepherosa Ziehau static void
6478b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(struct hn_softc *sc, int nchan)
6479b3b75d9cSSepherosa Ziehau {
6480b3b75d9cSSepherosa Ziehau 
6481b3b75d9cSSepherosa Ziehau 	hn_disable_rx(sc);
6482b3b75d9cSSepherosa Ziehau 	hn_drain_rxtx(sc, nchan);
6483b3b75d9cSSepherosa Ziehau }
6484b3b75d9cSSepherosa Ziehau 
648515516c77SSepherosa Ziehau static int
648615516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu)
648715516c77SSepherosa Ziehau {
648871e8ac56SSepherosa Ziehau #define ATTACHED_NVS		0x0002
648971e8ac56SSepherosa Ziehau #define ATTACHED_RNDIS		0x0004
649071e8ac56SSepherosa Ziehau 
649115516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
6492b3b75d9cSSepherosa Ziehau 	int error, nsubch, nchan = 1, i, rndis_inited;
649371e8ac56SSepherosa Ziehau 	uint32_t old_caps, attached = 0;
649415516c77SSepherosa Ziehau 
649515516c77SSepherosa Ziehau 	KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0,
649615516c77SSepherosa Ziehau 	    ("synthetic parts were attached"));
649715516c77SSepherosa Ziehau 
64982494d735SSepherosa Ziehau 	if (!hn_synth_attachable(sc))
64992494d735SSepherosa Ziehau 		return (ENXIO);
65002494d735SSepherosa Ziehau 
650115516c77SSepherosa Ziehau 	/* Save capabilities for later verification. */
650215516c77SSepherosa Ziehau 	old_caps = sc->hn_caps;
650315516c77SSepherosa Ziehau 	sc->hn_caps = 0;
650415516c77SSepherosa Ziehau 
650515516c77SSepherosa Ziehau 	/* Clear RSS stuffs. */
650615516c77SSepherosa Ziehau 	sc->hn_rss_ind_size = 0;
650715516c77SSepherosa Ziehau 	sc->hn_rss_hash = 0;
6508642ec226SSepherosa Ziehau 	sc->hn_rss_hcap = 0;
650915516c77SSepherosa Ziehau 
651015516c77SSepherosa Ziehau 	/*
651115516c77SSepherosa Ziehau 	 * Attach the primary channel _before_ attaching NVS and RNDIS.
651215516c77SSepherosa Ziehau 	 */
651315516c77SSepherosa Ziehau 	error = hn_chan_attach(sc, sc->hn_prichan);
651415516c77SSepherosa Ziehau 	if (error)
651571e8ac56SSepherosa Ziehau 		goto failed;
651615516c77SSepherosa Ziehau 
651715516c77SSepherosa Ziehau 	/*
651815516c77SSepherosa Ziehau 	 * Attach NVS.
651915516c77SSepherosa Ziehau 	 */
652015516c77SSepherosa Ziehau 	error = hn_nvs_attach(sc, mtu);
652115516c77SSepherosa Ziehau 	if (error)
652271e8ac56SSepherosa Ziehau 		goto failed;
652371e8ac56SSepherosa Ziehau 	attached |= ATTACHED_NVS;
652415516c77SSepherosa Ziehau 
652515516c77SSepherosa Ziehau 	/*
652615516c77SSepherosa Ziehau 	 * Attach RNDIS _after_ NVS is attached.
652715516c77SSepherosa Ziehau 	 */
6528b3b75d9cSSepherosa Ziehau 	error = hn_rndis_attach(sc, mtu, &rndis_inited);
6529b3b75d9cSSepherosa Ziehau 	if (rndis_inited)
6530b3b75d9cSSepherosa Ziehau 		attached |= ATTACHED_RNDIS;
653115516c77SSepherosa Ziehau 	if (error)
653271e8ac56SSepherosa Ziehau 		goto failed;
653315516c77SSepherosa Ziehau 
653415516c77SSepherosa Ziehau 	/*
653515516c77SSepherosa Ziehau 	 * Make sure capabilities are not changed.
653615516c77SSepherosa Ziehau 	 */
653715516c77SSepherosa Ziehau 	if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) {
653815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n",
653915516c77SSepherosa Ziehau 		    old_caps, sc->hn_caps);
654071e8ac56SSepherosa Ziehau 		error = ENXIO;
654171e8ac56SSepherosa Ziehau 		goto failed;
654215516c77SSepherosa Ziehau 	}
654315516c77SSepherosa Ziehau 
654415516c77SSepherosa Ziehau 	/*
654515516c77SSepherosa Ziehau 	 * Allocate sub-channels for multi-TX/RX rings.
654615516c77SSepherosa Ziehau 	 *
654715516c77SSepherosa Ziehau 	 * NOTE:
654815516c77SSepherosa Ziehau 	 * The # of RX rings that can be used is equivalent to the # of
654915516c77SSepherosa Ziehau 	 * channels to be requested.
655015516c77SSepherosa Ziehau 	 */
655115516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_cnt - 1;
655215516c77SSepherosa Ziehau 	error = hn_synth_alloc_subchans(sc, &nsubch);
655315516c77SSepherosa Ziehau 	if (error)
655471e8ac56SSepherosa Ziehau 		goto failed;
655571e8ac56SSepherosa Ziehau 	/* NOTE: _Full_ synthetic parts detach is required now. */
655671e8ac56SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED;
655715516c77SSepherosa Ziehau 
655871e8ac56SSepherosa Ziehau 	/*
655971e8ac56SSepherosa Ziehau 	 * Set the # of TX/RX rings that could be used according to
656071e8ac56SSepherosa Ziehau 	 * the # of channels that NVS offered.
656171e8ac56SSepherosa Ziehau 	 */
656215516c77SSepherosa Ziehau 	nchan = nsubch + 1;
656371e8ac56SSepherosa Ziehau 	hn_set_ring_inuse(sc, nchan);
656415516c77SSepherosa Ziehau 	if (nchan == 1) {
656515516c77SSepherosa Ziehau 		/* Only the primary channel can be used; done */
656615516c77SSepherosa Ziehau 		goto back;
656715516c77SSepherosa Ziehau 	}
656815516c77SSepherosa Ziehau 
656915516c77SSepherosa Ziehau 	/*
657071e8ac56SSepherosa Ziehau 	 * Attach the sub-channels.
6571afd4971bSSepherosa Ziehau 	 *
6572afd4971bSSepherosa Ziehau 	 * NOTE: hn_set_ring_inuse() _must_ have been called.
657315516c77SSepherosa Ziehau 	 */
657471e8ac56SSepherosa Ziehau 	error = hn_attach_subchans(sc);
657571e8ac56SSepherosa Ziehau 	if (error)
657671e8ac56SSepherosa Ziehau 		goto failed;
657715516c77SSepherosa Ziehau 
657871e8ac56SSepherosa Ziehau 	/*
657971e8ac56SSepherosa Ziehau 	 * Configure RSS key and indirect table _after_ all sub-channels
658071e8ac56SSepherosa Ziehau 	 * are attached.
658171e8ac56SSepherosa Ziehau 	 */
658215516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) {
658315516c77SSepherosa Ziehau 		/*
658415516c77SSepherosa Ziehau 		 * RSS key is not set yet; set it to the default RSS key.
658515516c77SSepherosa Ziehau 		 */
658615516c77SSepherosa Ziehau 		if (bootverbose)
658715516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS key\n");
658834d68912SSepherosa Ziehau #ifdef RSS
658934d68912SSepherosa Ziehau 		rss_getkey(rss->rss_key);
659034d68912SSepherosa Ziehau #else
659115516c77SSepherosa Ziehau 		memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key));
659234d68912SSepherosa Ziehau #endif
659315516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
659415516c77SSepherosa Ziehau 	}
659515516c77SSepherosa Ziehau 
659615516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) {
659715516c77SSepherosa Ziehau 		/*
659815516c77SSepherosa Ziehau 		 * RSS indirect table is not set yet; set it up in round-
659915516c77SSepherosa Ziehau 		 * robin fashion.
660015516c77SSepherosa Ziehau 		 */
660115516c77SSepherosa Ziehau 		if (bootverbose) {
660215516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS indirect "
660315516c77SSepherosa Ziehau 			    "table\n");
660415516c77SSepherosa Ziehau 		}
660534d68912SSepherosa Ziehau 		for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
660634d68912SSepherosa Ziehau 			uint32_t subidx;
660734d68912SSepherosa Ziehau 
660834d68912SSepherosa Ziehau #ifdef RSS
660934d68912SSepherosa Ziehau 			subidx = rss_get_indirection_to_bucket(i);
661034d68912SSepherosa Ziehau #else
661134d68912SSepherosa Ziehau 			subidx = i;
661234d68912SSepherosa Ziehau #endif
661334d68912SSepherosa Ziehau 			rss->rss_ind[i] = subidx % nchan;
661434d68912SSepherosa Ziehau 		}
661515516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSIND;
661615516c77SSepherosa Ziehau 	} else {
661715516c77SSepherosa Ziehau 		/*
661815516c77SSepherosa Ziehau 		 * # of usable channels may be changed, so we have to
661915516c77SSepherosa Ziehau 		 * make sure that all entries in RSS indirect table
662015516c77SSepherosa Ziehau 		 * are valid.
6621afd4971bSSepherosa Ziehau 		 *
6622afd4971bSSepherosa Ziehau 		 * NOTE: hn_set_ring_inuse() _must_ have been called.
662315516c77SSepherosa Ziehau 		 */
6624afd4971bSSepherosa Ziehau 		hn_rss_ind_fixup(sc);
662515516c77SSepherosa Ziehau 	}
662615516c77SSepherosa Ziehau 
6627642ec226SSepherosa Ziehau 	sc->hn_rss_hash = sc->hn_rss_hcap;
6628642ec226SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) ||
6629642ec226SSepherosa Ziehau 	    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
6630642ec226SSepherosa Ziehau 		/* NOTE: Don't reconfigure RSS; will do immediately. */
6631642ec226SSepherosa Ziehau 		hn_vf_rss_fixup(sc, false);
6632642ec226SSepherosa Ziehau 	}
663315516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
663415516c77SSepherosa Ziehau 	if (error)
663571e8ac56SSepherosa Ziehau 		goto failed;
663671e8ac56SSepherosa Ziehau back:
6637dc13fee6SSepherosa Ziehau 	/*
6638dc13fee6SSepherosa Ziehau 	 * Fixup transmission aggregation setup.
6639dc13fee6SSepherosa Ziehau 	 */
6640dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
6641b3b75d9cSSepherosa Ziehau 	hn_rndis_init_fixat(sc, nchan);
664215516c77SSepherosa Ziehau 	return (0);
664371e8ac56SSepherosa Ziehau 
664471e8ac56SSepherosa Ziehau failed:
664571e8ac56SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
6646b3b75d9cSSepherosa Ziehau 		hn_rndis_init_fixat(sc, nchan);
664771e8ac56SSepherosa Ziehau 		hn_synth_detach(sc);
664871e8ac56SSepherosa Ziehau 	} else {
6649b3b75d9cSSepherosa Ziehau 		if (attached & ATTACHED_RNDIS) {
6650b3b75d9cSSepherosa Ziehau 			hn_rndis_init_fixat(sc, nchan);
665171e8ac56SSepherosa Ziehau 			hn_rndis_detach(sc);
6652b3b75d9cSSepherosa Ziehau 		}
665371e8ac56SSepherosa Ziehau 		if (attached & ATTACHED_NVS)
665471e8ac56SSepherosa Ziehau 			hn_nvs_detach(sc);
665571e8ac56SSepherosa Ziehau 		hn_chan_detach(sc, sc->hn_prichan);
665671e8ac56SSepherosa Ziehau 		/* Restore old capabilities. */
665771e8ac56SSepherosa Ziehau 		sc->hn_caps = old_caps;
665871e8ac56SSepherosa Ziehau 	}
665971e8ac56SSepherosa Ziehau 	return (error);
666071e8ac56SSepherosa Ziehau 
666171e8ac56SSepherosa Ziehau #undef ATTACHED_RNDIS
666271e8ac56SSepherosa Ziehau #undef ATTACHED_NVS
666315516c77SSepherosa Ziehau }
666415516c77SSepherosa Ziehau 
666515516c77SSepherosa Ziehau /*
666615516c77SSepherosa Ziehau  * NOTE:
666715516c77SSepherosa Ziehau  * The interface must have been suspended though hn_suspend(), before
666815516c77SSepherosa Ziehau  * this function get called.
666915516c77SSepherosa Ziehau  */
667015516c77SSepherosa Ziehau static void
667115516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc)
667215516c77SSepherosa Ziehau {
667315516c77SSepherosa Ziehau 
667415516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
667515516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
667615516c77SSepherosa Ziehau 
667715516c77SSepherosa Ziehau 	/* Detach the RNDIS first. */
667815516c77SSepherosa Ziehau 	hn_rndis_detach(sc);
667915516c77SSepherosa Ziehau 
668015516c77SSepherosa Ziehau 	/* Detach NVS. */
668115516c77SSepherosa Ziehau 	hn_nvs_detach(sc);
668215516c77SSepherosa Ziehau 
668315516c77SSepherosa Ziehau 	/* Detach all of the channels. */
668415516c77SSepherosa Ziehau 	hn_detach_allchans(sc);
668515516c77SSepherosa Ziehau 
6686ace5ce7eSWei Hu 	if (vmbus_current_version >= VMBUS_VERSION_WIN10 && sc->hn_rxbuf_gpadl != 0) {
6687ace5ce7eSWei Hu 		/*
6688ace5ce7eSWei Hu 		 * Host is post-Win2016, disconnect RXBUF from primary channel here.
6689ace5ce7eSWei Hu 		 */
6690ace5ce7eSWei Hu 		int error;
6691ace5ce7eSWei Hu 
6692ace5ce7eSWei Hu 		error = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
6693ace5ce7eSWei Hu 		    sc->hn_rxbuf_gpadl);
6694ace5ce7eSWei Hu 		if (error) {
6695ace5ce7eSWei Hu 			if_printf(sc->hn_ifp,
6696ace5ce7eSWei Hu 			    "rxbuf gpadl disconn failed: %d\n", error);
6697ace5ce7eSWei Hu 			sc->hn_flags |= HN_FLAG_RXBUF_REF;
6698ace5ce7eSWei Hu 		}
6699ace5ce7eSWei Hu 		sc->hn_rxbuf_gpadl = 0;
6700ace5ce7eSWei Hu 	}
6701ace5ce7eSWei Hu 
6702ace5ce7eSWei Hu 	if (vmbus_current_version >= VMBUS_VERSION_WIN10 && sc->hn_chim_gpadl != 0) {
6703ace5ce7eSWei Hu 		/*
6704ace5ce7eSWei Hu 		 * Host is post-Win2016, disconnect chimney sending buffer from
6705ace5ce7eSWei Hu 		 * primary channel here.
6706ace5ce7eSWei Hu 		 */
6707ace5ce7eSWei Hu 		int error;
6708ace5ce7eSWei Hu 
6709ace5ce7eSWei Hu 		error = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
6710ace5ce7eSWei Hu 		    sc->hn_chim_gpadl);
6711ace5ce7eSWei Hu 		if (error) {
6712ace5ce7eSWei Hu 			if_printf(sc->hn_ifp,
6713ace5ce7eSWei Hu 			    "chim gpadl disconn failed: %d\n", error);
6714ace5ce7eSWei Hu 			sc->hn_flags |= HN_FLAG_CHIM_REF;
6715ace5ce7eSWei Hu 		}
6716ace5ce7eSWei Hu 		sc->hn_chim_gpadl = 0;
6717ace5ce7eSWei Hu 	}
671815516c77SSepherosa Ziehau 	sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED;
671915516c77SSepherosa Ziehau }
672015516c77SSepherosa Ziehau 
672115516c77SSepherosa Ziehau static void
672215516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt)
672315516c77SSepherosa Ziehau {
672415516c77SSepherosa Ziehau 	KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt,
672515516c77SSepherosa Ziehau 	    ("invalid ring count %d", ring_cnt));
672615516c77SSepherosa Ziehau 
672715516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt > ring_cnt)
672815516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = ring_cnt;
672915516c77SSepherosa Ziehau 	else
673015516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
673115516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = ring_cnt;
673215516c77SSepherosa Ziehau 
673334d68912SSepherosa Ziehau #ifdef RSS
673434d68912SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse != rss_getnumbuckets()) {
673534d68912SSepherosa Ziehau 		if_printf(sc->hn_ifp, "# of RX rings (%d) does not match "
673634d68912SSepherosa Ziehau 		    "# of RSS buckets (%d)\n", sc->hn_rx_ring_inuse,
673734d68912SSepherosa Ziehau 		    rss_getnumbuckets());
673834d68912SSepherosa Ziehau 	}
673934d68912SSepherosa Ziehau #endif
674034d68912SSepherosa Ziehau 
674115516c77SSepherosa Ziehau 	if (bootverbose) {
674215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n",
674315516c77SSepherosa Ziehau 		    sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
674415516c77SSepherosa Ziehau 	}
674515516c77SSepherosa Ziehau }
674615516c77SSepherosa Ziehau 
674715516c77SSepherosa Ziehau static void
674825641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan)
674915516c77SSepherosa Ziehau {
675015516c77SSepherosa Ziehau 
675125641fc7SSepherosa Ziehau 	/*
675225641fc7SSepherosa Ziehau 	 * NOTE:
675325641fc7SSepherosa Ziehau 	 * The TX bufring will not be drained by the hypervisor,
675425641fc7SSepherosa Ziehau 	 * if the primary channel is revoked.
675525641fc7SSepherosa Ziehau 	 */
675625641fc7SSepherosa Ziehau 	while (!vmbus_chan_rx_empty(chan) ||
675725641fc7SSepherosa Ziehau 	    (!vmbus_chan_is_revoked(sc->hn_prichan) &&
675825641fc7SSepherosa Ziehau 	     !vmbus_chan_tx_empty(chan)))
675915516c77SSepherosa Ziehau 		pause("waitch", 1);
676015516c77SSepherosa Ziehau 	vmbus_chan_intr_drain(chan);
676115516c77SSepherosa Ziehau }
676215516c77SSepherosa Ziehau 
676315516c77SSepherosa Ziehau static void
6764b3b75d9cSSepherosa Ziehau hn_disable_rx(struct hn_softc *sc)
6765b3b75d9cSSepherosa Ziehau {
6766b3b75d9cSSepherosa Ziehau 
6767b3b75d9cSSepherosa Ziehau 	/*
6768b3b75d9cSSepherosa Ziehau 	 * Disable RX by clearing RX filter forcefully.
6769b3b75d9cSSepherosa Ziehau 	 */
6770b3b75d9cSSepherosa Ziehau 	sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE;
6771b3b75d9cSSepherosa Ziehau 	hn_rndis_set_rxfilter(sc, sc->hn_rx_filter); /* ignore error */
6772b3b75d9cSSepherosa Ziehau 
6773b3b75d9cSSepherosa Ziehau 	/*
6774b3b75d9cSSepherosa Ziehau 	 * Give RNDIS enough time to flush all pending data packets.
6775b3b75d9cSSepherosa Ziehau 	 */
6776b3b75d9cSSepherosa Ziehau 	pause("waitrx", (200 * hz) / 1000);
6777b3b75d9cSSepherosa Ziehau }
6778b3b75d9cSSepherosa Ziehau 
6779b3b75d9cSSepherosa Ziehau /*
6780b3b75d9cSSepherosa Ziehau  * NOTE:
6781b3b75d9cSSepherosa Ziehau  * RX/TX _must_ have been suspended/disabled, before this function
6782b3b75d9cSSepherosa Ziehau  * is called.
6783b3b75d9cSSepherosa Ziehau  */
6784b3b75d9cSSepherosa Ziehau static void
6785b3b75d9cSSepherosa Ziehau hn_drain_rxtx(struct hn_softc *sc, int nchan)
678615516c77SSepherosa Ziehau {
678715516c77SSepherosa Ziehau 	struct vmbus_channel **subch = NULL;
6788b3b75d9cSSepherosa Ziehau 	int nsubch;
6789b3b75d9cSSepherosa Ziehau 
6790b3b75d9cSSepherosa Ziehau 	/*
6791b3b75d9cSSepherosa Ziehau 	 * Drain RX/TX bufrings and interrupts.
6792b3b75d9cSSepherosa Ziehau 	 */
6793b3b75d9cSSepherosa Ziehau 	nsubch = nchan - 1;
6794b3b75d9cSSepherosa Ziehau 	if (nsubch > 0)
6795b3b75d9cSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
6796b3b75d9cSSepherosa Ziehau 
6797b3b75d9cSSepherosa Ziehau 	if (subch != NULL) {
6798b3b75d9cSSepherosa Ziehau 		int i;
6799b3b75d9cSSepherosa Ziehau 
6800b3b75d9cSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
6801b3b75d9cSSepherosa Ziehau 			hn_chan_drain(sc, subch[i]);
6802b3b75d9cSSepherosa Ziehau 	}
6803b3b75d9cSSepherosa Ziehau 	hn_chan_drain(sc, sc->hn_prichan);
6804b3b75d9cSSepherosa Ziehau 
6805b3b75d9cSSepherosa Ziehau 	if (subch != NULL)
6806b3b75d9cSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
6807b3b75d9cSSepherosa Ziehau }
6808b3b75d9cSSepherosa Ziehau 
6809b3b75d9cSSepherosa Ziehau static void
6810b3b75d9cSSepherosa Ziehau hn_suspend_data(struct hn_softc *sc)
6811b3b75d9cSSepherosa Ziehau {
681225641fc7SSepherosa Ziehau 	struct hn_tx_ring *txr;
6813b3b75d9cSSepherosa Ziehau 	int i;
681415516c77SSepherosa Ziehau 
681515516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
681615516c77SSepherosa Ziehau 
681715516c77SSepherosa Ziehau 	/*
681815516c77SSepherosa Ziehau 	 * Suspend TX.
681915516c77SSepherosa Ziehau 	 */
682015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
682125641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
682215516c77SSepherosa Ziehau 
682315516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
682415516c77SSepherosa Ziehau 		txr->hn_suspended = 1;
682515516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
682615516c77SSepherosa Ziehau 		/* No one is able send more packets now. */
682715516c77SSepherosa Ziehau 
682825641fc7SSepherosa Ziehau 		/*
682925641fc7SSepherosa Ziehau 		 * Wait for all pending sends to finish.
683025641fc7SSepherosa Ziehau 		 *
683125641fc7SSepherosa Ziehau 		 * NOTE:
683225641fc7SSepherosa Ziehau 		 * We will _not_ receive all pending send-done, if the
683325641fc7SSepherosa Ziehau 		 * primary channel is revoked.
683425641fc7SSepherosa Ziehau 		 */
683525641fc7SSepherosa Ziehau 		while (hn_tx_ring_pending(txr) &&
683625641fc7SSepherosa Ziehau 		    !vmbus_chan_is_revoked(sc->hn_prichan))
683715516c77SSepherosa Ziehau 			pause("hnwtx", 1 /* 1 tick */);
683815516c77SSepherosa Ziehau 	}
683915516c77SSepherosa Ziehau 
684015516c77SSepherosa Ziehau 	/*
6841b3b75d9cSSepherosa Ziehau 	 * Disable RX.
684215516c77SSepherosa Ziehau 	 */
6843b3b75d9cSSepherosa Ziehau 	hn_disable_rx(sc);
684415516c77SSepherosa Ziehau 
684515516c77SSepherosa Ziehau 	/*
6846b3b75d9cSSepherosa Ziehau 	 * Drain RX/TX.
684715516c77SSepherosa Ziehau 	 */
6848b3b75d9cSSepherosa Ziehau 	hn_drain_rxtx(sc, sc->hn_rx_ring_inuse);
684925641fc7SSepherosa Ziehau 
685025641fc7SSepherosa Ziehau 	/*
685125641fc7SSepherosa Ziehau 	 * Drain any pending TX tasks.
685225641fc7SSepherosa Ziehau 	 *
685325641fc7SSepherosa Ziehau 	 * NOTE:
6854b3b75d9cSSepherosa Ziehau 	 * The above hn_drain_rxtx() can dispatch TX tasks, so the TX
6855b3b75d9cSSepherosa Ziehau 	 * tasks will have to be drained _after_ the above hn_drain_rxtx().
685625641fc7SSepherosa Ziehau 	 */
685725641fc7SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
685825641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
685925641fc7SSepherosa Ziehau 
686025641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task);
686125641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task);
686225641fc7SSepherosa Ziehau 	}
686315516c77SSepherosa Ziehau }
686415516c77SSepherosa Ziehau 
686515516c77SSepherosa Ziehau static void
686615516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused)
686715516c77SSepherosa Ziehau {
686815516c77SSepherosa Ziehau 
686915516c77SSepherosa Ziehau 	((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL;
687015516c77SSepherosa Ziehau }
687115516c77SSepherosa Ziehau 
687215516c77SSepherosa Ziehau static void
687315516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc)
687415516c77SSepherosa Ziehau {
687515516c77SSepherosa Ziehau 	struct task task;
687615516c77SSepherosa Ziehau 
687715516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
687815516c77SSepherosa Ziehau 
687915516c77SSepherosa Ziehau 	/*
688015516c77SSepherosa Ziehau 	 * Make sure that hn_mgmt_taskq0 can nolonger be accessed
688115516c77SSepherosa Ziehau 	 * through hn_mgmt_taskq.
688215516c77SSepherosa Ziehau 	 */
688315516c77SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc);
688415516c77SSepherosa Ziehau 	vmbus_chan_run_task(sc->hn_prichan, &task);
688515516c77SSepherosa Ziehau 
688615516c77SSepherosa Ziehau 	/*
688715516c77SSepherosa Ziehau 	 * Make sure that all pending management tasks are completed.
688815516c77SSepherosa Ziehau 	 */
688915516c77SSepherosa Ziehau 	taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init);
689015516c77SSepherosa Ziehau 	taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status);
689115516c77SSepherosa Ziehau 	taskqueue_drain_all(sc->hn_mgmt_taskq0);
689215516c77SSepherosa Ziehau }
689315516c77SSepherosa Ziehau 
689415516c77SSepherosa Ziehau static void
689515516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc)
689615516c77SSepherosa Ziehau {
689715516c77SSepherosa Ziehau 
689887f8129dSSepherosa Ziehau 	/* Disable polling. */
689987f8129dSSepherosa Ziehau 	hn_polling(sc, 0);
690087f8129dSSepherosa Ziehau 
69019c6cae24SSepherosa Ziehau 	/*
69029c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, the synthetic
69039c6cae24SSepherosa Ziehau 	 * device is receiving packets, so the data path of the
69049c6cae24SSepherosa Ziehau 	 * synthetic device must be suspended.
69059c6cae24SSepherosa Ziehau 	 */
69065bdfd3fdSDexuan Cui 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
6907962f0357SSepherosa Ziehau 	    (sc->hn_flags & HN_FLAG_RXVF))
690815516c77SSepherosa Ziehau 		hn_suspend_data(sc);
690915516c77SSepherosa Ziehau 	hn_suspend_mgmt(sc);
691015516c77SSepherosa Ziehau }
691115516c77SSepherosa Ziehau 
691215516c77SSepherosa Ziehau static void
691315516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt)
691415516c77SSepherosa Ziehau {
691515516c77SSepherosa Ziehau 	int i;
691615516c77SSepherosa Ziehau 
691715516c77SSepherosa Ziehau 	KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt,
691815516c77SSepherosa Ziehau 	    ("invalid TX ring count %d", tx_ring_cnt));
691915516c77SSepherosa Ziehau 
692015516c77SSepherosa Ziehau 	for (i = 0; i < tx_ring_cnt; ++i) {
692115516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
692215516c77SSepherosa Ziehau 
692315516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
692415516c77SSepherosa Ziehau 		txr->hn_suspended = 0;
692515516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
692615516c77SSepherosa Ziehau 	}
692715516c77SSepherosa Ziehau }
692815516c77SSepherosa Ziehau 
692915516c77SSepherosa Ziehau static void
693015516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc)
693115516c77SSepherosa Ziehau {
693215516c77SSepherosa Ziehau 	int i;
693315516c77SSepherosa Ziehau 
693415516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
693515516c77SSepherosa Ziehau 
693615516c77SSepherosa Ziehau 	/*
693715516c77SSepherosa Ziehau 	 * Re-enable RX.
693815516c77SSepherosa Ziehau 	 */
6939c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
694015516c77SSepherosa Ziehau 
694115516c77SSepherosa Ziehau 	/*
694215516c77SSepherosa Ziehau 	 * Make sure to clear suspend status on "all" TX rings,
694315516c77SSepherosa Ziehau 	 * since hn_tx_ring_inuse can be changed after
694415516c77SSepherosa Ziehau 	 * hn_suspend_data().
694515516c77SSepherosa Ziehau 	 */
694615516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_cnt);
694715516c77SSepherosa Ziehau 
694823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
694923bf9e15SSepherosa Ziehau 	if (!hn_use_if_start)
695023bf9e15SSepherosa Ziehau #endif
695123bf9e15SSepherosa Ziehau 	{
695215516c77SSepherosa Ziehau 		/*
695315516c77SSepherosa Ziehau 		 * Flush unused drbrs, since hn_tx_ring_inuse may be
695415516c77SSepherosa Ziehau 		 * reduced.
695515516c77SSepherosa Ziehau 		 */
695615516c77SSepherosa Ziehau 		for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i)
695715516c77SSepherosa Ziehau 			hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
695815516c77SSepherosa Ziehau 	}
695915516c77SSepherosa Ziehau 
696015516c77SSepherosa Ziehau 	/*
696115516c77SSepherosa Ziehau 	 * Kick start TX.
696215516c77SSepherosa Ziehau 	 */
696315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
696415516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
696515516c77SSepherosa Ziehau 
696615516c77SSepherosa Ziehau 		/*
696715516c77SSepherosa Ziehau 		 * Use txeof task, so that any pending oactive can be
696815516c77SSepherosa Ziehau 		 * cleared properly.
696915516c77SSepherosa Ziehau 		 */
697015516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
697115516c77SSepherosa Ziehau 	}
697215516c77SSepherosa Ziehau }
697315516c77SSepherosa Ziehau 
697415516c77SSepherosa Ziehau static void
697515516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc)
697615516c77SSepherosa Ziehau {
697715516c77SSepherosa Ziehau 
697815516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
697915516c77SSepherosa Ziehau 
698015516c77SSepherosa Ziehau 	/*
698115516c77SSepherosa Ziehau 	 * Kick off network change detection, if it was pending.
698215516c77SSepherosa Ziehau 	 * If no network change was pending, start link status
698315516c77SSepherosa Ziehau 	 * checks, which is more lightweight than network change
698415516c77SSepherosa Ziehau 	 * detection.
698515516c77SSepherosa Ziehau 	 */
698615516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
698715516c77SSepherosa Ziehau 		hn_change_network(sc);
698815516c77SSepherosa Ziehau 	else
698915516c77SSepherosa Ziehau 		hn_update_link_status(sc);
699015516c77SSepherosa Ziehau }
699115516c77SSepherosa Ziehau 
699215516c77SSepherosa Ziehau static void
699315516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc)
699415516c77SSepherosa Ziehau {
699515516c77SSepherosa Ziehau 
69969c6cae24SSepherosa Ziehau 	/*
69979c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, the synthetic
69989c6cae24SSepherosa Ziehau 	 * device have to receive packets, so the data path of the
69999c6cae24SSepherosa Ziehau 	 * synthetic device must be resumed.
70009c6cae24SSepherosa Ziehau 	 */
70015bdfd3fdSDexuan Cui 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
7002962f0357SSepherosa Ziehau 	    (sc->hn_flags & HN_FLAG_RXVF))
700315516c77SSepherosa Ziehau 		hn_resume_data(sc);
70045bdfd3fdSDexuan Cui 
70055bdfd3fdSDexuan Cui 	/*
70069c6cae24SSepherosa Ziehau 	 * Don't resume link status change if VF is attached/activated.
70079c6cae24SSepherosa Ziehau 	 * - In the non-transparent VF mode, the synthetic device marks
70089c6cae24SSepherosa Ziehau 	 *   link down until the VF is deactivated; i.e. VF is down.
70099c6cae24SSepherosa Ziehau 	 * - In transparent VF mode, VF's media status is used until
70109c6cae24SSepherosa Ziehau 	 *   the VF is detached.
70115bdfd3fdSDexuan Cui 	 */
70129c6cae24SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) == 0 &&
70139c6cae24SSepherosa Ziehau 	    !(hn_xpnt_vf && sc->hn_vf_ifp != NULL))
701415516c77SSepherosa Ziehau 		hn_resume_mgmt(sc);
701587f8129dSSepherosa Ziehau 
701687f8129dSSepherosa Ziehau 	/*
701787f8129dSSepherosa Ziehau 	 * Re-enable polling if this interface is running and
701887f8129dSSepherosa Ziehau 	 * the polling is requested.
701987f8129dSSepherosa Ziehau 	 */
702087f8129dSSepherosa Ziehau 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->hn_pollhz > 0)
702187f8129dSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
702215516c77SSepherosa Ziehau }
702315516c77SSepherosa Ziehau 
702415516c77SSepherosa Ziehau static void
702515516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen)
702615516c77SSepherosa Ziehau {
702715516c77SSepherosa Ziehau 	const struct rndis_status_msg *msg;
702815516c77SSepherosa Ziehau 	int ofs;
702915516c77SSepherosa Ziehau 
703015516c77SSepherosa Ziehau 	if (dlen < sizeof(*msg)) {
703115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid RNDIS status\n");
703215516c77SSepherosa Ziehau 		return;
703315516c77SSepherosa Ziehau 	}
703415516c77SSepherosa Ziehau 	msg = data;
703515516c77SSepherosa Ziehau 
703615516c77SSepherosa Ziehau 	switch (msg->rm_status) {
703715516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_CONNECT:
703815516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_DISCONNECT:
703915516c77SSepherosa Ziehau 		hn_update_link_status(sc);
704015516c77SSepherosa Ziehau 		break;
704115516c77SSepherosa Ziehau 
704215516c77SSepherosa Ziehau 	case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
704340905afaSSepherosa Ziehau 	case RNDIS_STATUS_LINK_SPEED_CHANGE:
704415516c77SSepherosa Ziehau 		/* Not really useful; ignore. */
704515516c77SSepherosa Ziehau 		break;
704615516c77SSepherosa Ziehau 
704715516c77SSepherosa Ziehau 	case RNDIS_STATUS_NETWORK_CHANGE:
704815516c77SSepherosa Ziehau 		ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
704915516c77SSepherosa Ziehau 		if (dlen < ofs + msg->rm_stbuflen ||
705015516c77SSepherosa Ziehau 		    msg->rm_stbuflen < sizeof(uint32_t)) {
705115516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed\n");
705215516c77SSepherosa Ziehau 		} else {
705315516c77SSepherosa Ziehau 			uint32_t change;
705415516c77SSepherosa Ziehau 
705515516c77SSepherosa Ziehau 			memcpy(&change, ((const uint8_t *)msg) + ofs,
705615516c77SSepherosa Ziehau 			    sizeof(change));
705715516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed, change %u\n",
705815516c77SSepherosa Ziehau 			    change);
705915516c77SSepherosa Ziehau 		}
706015516c77SSepherosa Ziehau 		hn_change_network(sc);
706115516c77SSepherosa Ziehau 		break;
706215516c77SSepherosa Ziehau 
706315516c77SSepherosa Ziehau 	default:
706415516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
706515516c77SSepherosa Ziehau 		    msg->rm_status);
706615516c77SSepherosa Ziehau 		break;
706715516c77SSepherosa Ziehau 	}
706815516c77SSepherosa Ziehau }
706915516c77SSepherosa Ziehau 
707015516c77SSepherosa Ziehau static int
707115516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info)
707215516c77SSepherosa Ziehau {
707315516c77SSepherosa Ziehau 	const struct rndis_pktinfo *pi = info_data;
707415516c77SSepherosa Ziehau 	uint32_t mask = 0;
707515516c77SSepherosa Ziehau 
707615516c77SSepherosa Ziehau 	while (info_dlen != 0) {
707715516c77SSepherosa Ziehau 		const void *data;
707815516c77SSepherosa Ziehau 		uint32_t dlen;
707915516c77SSepherosa Ziehau 
708015516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < sizeof(*pi)))
708115516c77SSepherosa Ziehau 			return (EINVAL);
708215516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < pi->rm_size))
708315516c77SSepherosa Ziehau 			return (EINVAL);
708415516c77SSepherosa Ziehau 		info_dlen -= pi->rm_size;
708515516c77SSepherosa Ziehau 
708615516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
708715516c77SSepherosa Ziehau 			return (EINVAL);
708815516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
708915516c77SSepherosa Ziehau 			return (EINVAL);
709015516c77SSepherosa Ziehau 		dlen = pi->rm_size - pi->rm_pktinfooffset;
709115516c77SSepherosa Ziehau 		data = pi->rm_data;
709215516c77SSepherosa Ziehau 
7093*a491581fSWei Hu 		if (pi->rm_internal == 1) {
7094*a491581fSWei Hu 			switch (pi->rm_type) {
7095*a491581fSWei Hu 			case NDIS_PKTINFO_IT_PKTINFO_ID:
7096*a491581fSWei Hu 				if (__predict_false(dlen < NDIS_PKTINFOID_SZ))
7097*a491581fSWei Hu 					return (EINVAL);
7098*a491581fSWei Hu 				info->pktinfo_id =
7099*a491581fSWei Hu 				    (const struct packet_info_id *)data;
7100*a491581fSWei Hu 				mask |= HN_RXINFO_PKTINFO_ID;
7101*a491581fSWei Hu 				break;
7102*a491581fSWei Hu 
7103*a491581fSWei Hu 			default:
7104*a491581fSWei Hu 				goto next;
7105*a491581fSWei Hu 			}
7106*a491581fSWei Hu 		} else {
710715516c77SSepherosa Ziehau 			switch (pi->rm_type) {
710815516c77SSepherosa Ziehau 			case NDIS_PKTINFO_TYPE_VLAN:
7109*a491581fSWei Hu 				if (__predict_false(dlen
7110*a491581fSWei Hu 				    < NDIS_VLAN_INFO_SIZE))
711115516c77SSepherosa Ziehau 					return (EINVAL);
7112*a491581fSWei Hu 				info->vlan_info = (const uint32_t *)data;
711315516c77SSepherosa Ziehau 				mask |= HN_RXINFO_VLAN;
711415516c77SSepherosa Ziehau 				break;
711515516c77SSepherosa Ziehau 
711615516c77SSepherosa Ziehau 			case NDIS_PKTINFO_TYPE_CSUM:
7117*a491581fSWei Hu 				if (__predict_false(dlen
7118*a491581fSWei Hu 				    < NDIS_RXCSUM_INFO_SIZE))
711915516c77SSepherosa Ziehau 					return (EINVAL);
7120*a491581fSWei Hu 				info->csum_info = (const uint32_t *)data;
712115516c77SSepherosa Ziehau 				mask |= HN_RXINFO_CSUM;
712215516c77SSepherosa Ziehau 				break;
712315516c77SSepherosa Ziehau 
712415516c77SSepherosa Ziehau 			case HN_NDIS_PKTINFO_TYPE_HASHVAL:
7125*a491581fSWei Hu 				if (__predict_false(dlen
7126*a491581fSWei Hu 				    < HN_NDIS_HASH_VALUE_SIZE))
712715516c77SSepherosa Ziehau 					return (EINVAL);
7128*a491581fSWei Hu 				info->hash_value = (const uint32_t *)data;
712915516c77SSepherosa Ziehau 				mask |= HN_RXINFO_HASHVAL;
713015516c77SSepherosa Ziehau 				break;
713115516c77SSepherosa Ziehau 
713215516c77SSepherosa Ziehau 			case HN_NDIS_PKTINFO_TYPE_HASHINF:
7133*a491581fSWei Hu 				if (__predict_false(dlen
7134*a491581fSWei Hu 				    < HN_NDIS_HASH_INFO_SIZE))
713515516c77SSepherosa Ziehau 					return (EINVAL);
7136*a491581fSWei Hu 				info->hash_info = (const uint32_t *)data;
713715516c77SSepherosa Ziehau 				mask |= HN_RXINFO_HASHINF;
713815516c77SSepherosa Ziehau 				break;
713915516c77SSepherosa Ziehau 
714015516c77SSepherosa Ziehau 			default:
714115516c77SSepherosa Ziehau 				goto next;
714215516c77SSepherosa Ziehau 			}
7143*a491581fSWei Hu 		}
714415516c77SSepherosa Ziehau 
714515516c77SSepherosa Ziehau 		if (mask == HN_RXINFO_ALL) {
714615516c77SSepherosa Ziehau 			/* All found; done */
714715516c77SSepherosa Ziehau 			break;
714815516c77SSepherosa Ziehau 		}
714915516c77SSepherosa Ziehau next:
715015516c77SSepherosa Ziehau 		pi = (const struct rndis_pktinfo *)
715115516c77SSepherosa Ziehau 		    ((const uint8_t *)pi + pi->rm_size);
715215516c77SSepherosa Ziehau 	}
715315516c77SSepherosa Ziehau 
715415516c77SSepherosa Ziehau 	/*
715515516c77SSepherosa Ziehau 	 * Final fixup.
715615516c77SSepherosa Ziehau 	 * - If there is no hash value, invalidate the hash info.
715715516c77SSepherosa Ziehau 	 */
715815516c77SSepherosa Ziehau 	if ((mask & HN_RXINFO_HASHVAL) == 0)
7159*a491581fSWei Hu 		info->hash_info = NULL;
716015516c77SSepherosa Ziehau 	return (0);
716115516c77SSepherosa Ziehau }
716215516c77SSepherosa Ziehau 
716315516c77SSepherosa Ziehau static __inline bool
716415516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
716515516c77SSepherosa Ziehau {
716615516c77SSepherosa Ziehau 
716715516c77SSepherosa Ziehau 	if (off < check_off) {
716815516c77SSepherosa Ziehau 		if (__predict_true(off + len <= check_off))
716915516c77SSepherosa Ziehau 			return (false);
717015516c77SSepherosa Ziehau 	} else if (off > check_off) {
717115516c77SSepherosa Ziehau 		if (__predict_true(check_off + check_len <= off))
717215516c77SSepherosa Ziehau 			return (false);
717315516c77SSepherosa Ziehau 	}
717415516c77SSepherosa Ziehau 	return (true);
717515516c77SSepherosa Ziehau }
717615516c77SSepherosa Ziehau 
7177*a491581fSWei Hu static __inline void
7178*a491581fSWei Hu hn_rsc_add_data(struct hn_rx_ring *rxr, const void *data,
7179*a491581fSWei Hu 		uint32_t len, struct hn_rxinfo *info)
7180*a491581fSWei Hu {
7181*a491581fSWei Hu 	uint32_t cnt = rxr->rsc.cnt;
7182*a491581fSWei Hu 
7183*a491581fSWei Hu 	if (cnt) {
7184*a491581fSWei Hu 		rxr->rsc.pktlen += len;
7185*a491581fSWei Hu 	} else {
7186*a491581fSWei Hu 		rxr->rsc.vlan_info = info->vlan_info;
7187*a491581fSWei Hu 		rxr->rsc.csum_info = info->csum_info;
7188*a491581fSWei Hu 		rxr->rsc.hash_info = info->hash_info;
7189*a491581fSWei Hu 		rxr->rsc.hash_value = info->hash_value;
7190*a491581fSWei Hu 		rxr->rsc.pktlen = len;
7191*a491581fSWei Hu 	}
7192*a491581fSWei Hu 
7193*a491581fSWei Hu 	rxr->rsc.frag_data[cnt] = data;
7194*a491581fSWei Hu 	rxr->rsc.frag_len[cnt] = len;
7195*a491581fSWei Hu 	rxr->rsc.cnt++;
7196*a491581fSWei Hu }
7197*a491581fSWei Hu 
719815516c77SSepherosa Ziehau static void
719915516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen)
720015516c77SSepherosa Ziehau {
720115516c77SSepherosa Ziehau 	const struct rndis_packet_msg *pkt;
720215516c77SSepherosa Ziehau 	struct hn_rxinfo info;
720315516c77SSepherosa Ziehau 	int data_off, pktinfo_off, data_len, pktinfo_len;
7204*a491581fSWei Hu 	bool rsc_more= false;
720515516c77SSepherosa Ziehau 
720615516c77SSepherosa Ziehau 	/*
720715516c77SSepherosa Ziehau 	 * Check length.
720815516c77SSepherosa Ziehau 	 */
720915516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*pkt))) {
721015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
721115516c77SSepherosa Ziehau 		return;
721215516c77SSepherosa Ziehau 	}
721315516c77SSepherosa Ziehau 	pkt = data;
721415516c77SSepherosa Ziehau 
721515516c77SSepherosa Ziehau 	if (__predict_false(dlen < pkt->rm_len)) {
721615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
721715516c77SSepherosa Ziehau 		    "dlen %d, msglen %u\n", dlen, pkt->rm_len);
721815516c77SSepherosa Ziehau 		return;
721915516c77SSepherosa Ziehau 	}
722015516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_len <
722115516c77SSepherosa Ziehau 	    pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
722215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
722315516c77SSepherosa Ziehau 		    "msglen %u, data %u, oob %u, pktinfo %u\n",
722415516c77SSepherosa Ziehau 		    pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
722515516c77SSepherosa Ziehau 		    pkt->rm_pktinfolen);
722615516c77SSepherosa Ziehau 		return;
722715516c77SSepherosa Ziehau 	}
722815516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_datalen == 0)) {
722915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
723015516c77SSepherosa Ziehau 		return;
723115516c77SSepherosa Ziehau 	}
723215516c77SSepherosa Ziehau 
723315516c77SSepherosa Ziehau 	/*
723415516c77SSepherosa Ziehau 	 * Check offests.
723515516c77SSepherosa Ziehau 	 */
723615516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs)			\
723715516c77SSepherosa Ziehau 	((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN ||	\
723815516c77SSepherosa Ziehau 	 ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
723915516c77SSepherosa Ziehau 
724015516c77SSepherosa Ziehau 	/* XXX Hyper-V does not meet data offset alignment requirement */
724115516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
724215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
724315516c77SSepherosa Ziehau 		    "data offset %u\n", pkt->rm_dataoffset);
724415516c77SSepherosa Ziehau 		return;
724515516c77SSepherosa Ziehau 	}
724615516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdataoffset > 0 &&
724715516c77SSepherosa Ziehau 	    IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
724815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
724915516c77SSepherosa Ziehau 		    "oob offset %u\n", pkt->rm_oobdataoffset);
725015516c77SSepherosa Ziehau 		return;
725115516c77SSepherosa Ziehau 	}
725215516c77SSepherosa Ziehau 	if (__predict_true(pkt->rm_pktinfooffset > 0) &&
725315516c77SSepherosa Ziehau 	    __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
725415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
725515516c77SSepherosa Ziehau 		    "pktinfo offset %u\n", pkt->rm_pktinfooffset);
725615516c77SSepherosa Ziehau 		return;
725715516c77SSepherosa Ziehau 	}
725815516c77SSepherosa Ziehau 
725915516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID
726015516c77SSepherosa Ziehau 
726115516c77SSepherosa Ziehau 	data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
726215516c77SSepherosa Ziehau 	data_len = pkt->rm_datalen;
726315516c77SSepherosa Ziehau 	pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
726415516c77SSepherosa Ziehau 	pktinfo_len = pkt->rm_pktinfolen;
726515516c77SSepherosa Ziehau 
726615516c77SSepherosa Ziehau 	/*
726715516c77SSepherosa Ziehau 	 * Check OOB coverage.
726815516c77SSepherosa Ziehau 	 */
726915516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdatalen != 0)) {
727015516c77SSepherosa Ziehau 		int oob_off, oob_len;
727115516c77SSepherosa Ziehau 
727215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "got oobdata\n");
727315516c77SSepherosa Ziehau 		oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
727415516c77SSepherosa Ziehau 		oob_len = pkt->rm_oobdatalen;
727515516c77SSepherosa Ziehau 
727615516c77SSepherosa Ziehau 		if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
727715516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
727815516c77SSepherosa Ziehau 			    "oob overflow, msglen %u, oob abs %d len %d\n",
727915516c77SSepherosa Ziehau 			    pkt->rm_len, oob_off, oob_len);
728015516c77SSepherosa Ziehau 			return;
728115516c77SSepherosa Ziehau 		}
728215516c77SSepherosa Ziehau 
728315516c77SSepherosa Ziehau 		/*
728415516c77SSepherosa Ziehau 		 * Check against data.
728515516c77SSepherosa Ziehau 		 */
728615516c77SSepherosa Ziehau 		if (hn_rndis_check_overlap(oob_off, oob_len,
728715516c77SSepherosa Ziehau 		    data_off, data_len)) {
728815516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
728915516c77SSepherosa Ziehau 			    "oob overlaps data, oob abs %d len %d, "
729015516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
729115516c77SSepherosa Ziehau 			    oob_off, oob_len, data_off, data_len);
729215516c77SSepherosa Ziehau 			return;
729315516c77SSepherosa Ziehau 		}
729415516c77SSepherosa Ziehau 
729515516c77SSepherosa Ziehau 		/*
729615516c77SSepherosa Ziehau 		 * Check against pktinfo.
729715516c77SSepherosa Ziehau 		 */
729815516c77SSepherosa Ziehau 		if (pktinfo_len != 0 &&
729915516c77SSepherosa Ziehau 		    hn_rndis_check_overlap(oob_off, oob_len,
730015516c77SSepherosa Ziehau 		    pktinfo_off, pktinfo_len)) {
730115516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
730215516c77SSepherosa Ziehau 			    "oob overlaps pktinfo, oob abs %d len %d, "
730315516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
730415516c77SSepherosa Ziehau 			    oob_off, oob_len, pktinfo_off, pktinfo_len);
730515516c77SSepherosa Ziehau 			return;
730615516c77SSepherosa Ziehau 		}
730715516c77SSepherosa Ziehau 	}
730815516c77SSepherosa Ziehau 
730915516c77SSepherosa Ziehau 	/*
731015516c77SSepherosa Ziehau 	 * Check per-packet-info coverage and find useful per-packet-info.
731115516c77SSepherosa Ziehau 	 */
7312*a491581fSWei Hu 	info.vlan_info = NULL;
7313*a491581fSWei Hu 	info.csum_info = NULL;
7314*a491581fSWei Hu 	info.hash_info = NULL;
7315*a491581fSWei Hu 	info.pktinfo_id = NULL;
7316*a491581fSWei Hu 
731715516c77SSepherosa Ziehau 	if (__predict_true(pktinfo_len != 0)) {
731815516c77SSepherosa Ziehau 		bool overlap;
731915516c77SSepherosa Ziehau 		int error;
732015516c77SSepherosa Ziehau 
732115516c77SSepherosa Ziehau 		if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
732215516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
732315516c77SSepherosa Ziehau 			    "pktinfo overflow, msglen %u, "
732415516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
732515516c77SSepherosa Ziehau 			    pkt->rm_len, pktinfo_off, pktinfo_len);
732615516c77SSepherosa Ziehau 			return;
732715516c77SSepherosa Ziehau 		}
732815516c77SSepherosa Ziehau 
732915516c77SSepherosa Ziehau 		/*
733015516c77SSepherosa Ziehau 		 * Check packet info coverage.
733115516c77SSepherosa Ziehau 		 */
733215516c77SSepherosa Ziehau 		overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
733315516c77SSepherosa Ziehau 		    data_off, data_len);
733415516c77SSepherosa Ziehau 		if (__predict_false(overlap)) {
733515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
733615516c77SSepherosa Ziehau 			    "pktinfo overlap data, pktinfo abs %d len %d, "
733715516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
733815516c77SSepherosa Ziehau 			    pktinfo_off, pktinfo_len, data_off, data_len);
733915516c77SSepherosa Ziehau 			return;
734015516c77SSepherosa Ziehau 		}
734115516c77SSepherosa Ziehau 
734215516c77SSepherosa Ziehau 		/*
734315516c77SSepherosa Ziehau 		 * Find useful per-packet-info.
734415516c77SSepherosa Ziehau 		 */
734515516c77SSepherosa Ziehau 		error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
734615516c77SSepherosa Ziehau 		    pktinfo_len, &info);
734715516c77SSepherosa Ziehau 		if (__predict_false(error)) {
734815516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
734915516c77SSepherosa Ziehau 			    "pktinfo\n");
735015516c77SSepherosa Ziehau 			return;
735115516c77SSepherosa Ziehau 		}
735215516c77SSepherosa Ziehau 	}
735315516c77SSepherosa Ziehau 
735415516c77SSepherosa Ziehau 	if (__predict_false(data_off + data_len > pkt->rm_len)) {
735515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
735615516c77SSepherosa Ziehau 		    "data overflow, msglen %u, data abs %d len %d\n",
735715516c77SSepherosa Ziehau 		    pkt->rm_len, data_off, data_len);
735815516c77SSepherosa Ziehau 		return;
735915516c77SSepherosa Ziehau 	}
7360*a491581fSWei Hu 
7361*a491581fSWei Hu 	/* Identify RSC fragments, drop invalid packets */
7362*a491581fSWei Hu 	if ((info.pktinfo_id != NULL) &&
7363*a491581fSWei Hu 	    (info.pktinfo_id->flag & HN_NDIS_PKTINFO_SUBALLOC)) {
7364*a491581fSWei Hu 		if (info.pktinfo_id->flag & HN_NDIS_PKTINFO_1ST_FRAG) {
7365*a491581fSWei Hu 			rxr->rsc.cnt = 0;
7366*a491581fSWei Hu 			rxr->hn_rsc_pkts++;
7367*a491581fSWei Hu 		} else if (rxr->rsc.cnt == 0)
7368*a491581fSWei Hu 			goto drop;
7369*a491581fSWei Hu 
7370*a491581fSWei Hu 		rsc_more = true;
7371*a491581fSWei Hu 
7372*a491581fSWei Hu 		if (info.pktinfo_id->flag & HN_NDIS_PKTINFO_LAST_FRAG)
7373*a491581fSWei Hu 			rsc_more = false;
7374*a491581fSWei Hu 
7375*a491581fSWei Hu 		if (rsc_more && rxr->rsc.is_last)
7376*a491581fSWei Hu 			goto drop;
7377*a491581fSWei Hu 	} else {
7378*a491581fSWei Hu 		rxr->rsc.cnt = 0;
7379*a491581fSWei Hu 	}
7380*a491581fSWei Hu 
7381*a491581fSWei Hu 	if (__predict_false(rxr->rsc.cnt >= HN_NVS_RSC_MAX))
7382*a491581fSWei Hu 		goto drop;
7383*a491581fSWei Hu 
7384*a491581fSWei Hu 	/* Store data in per rx ring structure */
7385*a491581fSWei Hu 	hn_rsc_add_data(rxr,((const uint8_t *)pkt) + data_off,
7386*a491581fSWei Hu 	    data_len, &info);
7387*a491581fSWei Hu 
7388*a491581fSWei Hu 	if (rsc_more)
7389*a491581fSWei Hu 		return;
7390*a491581fSWei Hu 
7391*a491581fSWei Hu 	hn_rxpkt(rxr);
7392*a491581fSWei Hu 	rxr->rsc.cnt = 0;
7393*a491581fSWei Hu 	return;
7394*a491581fSWei Hu drop:
7395*a491581fSWei Hu 	rxr->hn_rsc_drop++;
7396*a491581fSWei Hu 	return;
739715516c77SSepherosa Ziehau }
739815516c77SSepherosa Ziehau 
739915516c77SSepherosa Ziehau static __inline void
740015516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen)
740115516c77SSepherosa Ziehau {
740215516c77SSepherosa Ziehau 	const struct rndis_msghdr *hdr;
740315516c77SSepherosa Ziehau 
740415516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*hdr))) {
740515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
740615516c77SSepherosa Ziehau 		return;
740715516c77SSepherosa Ziehau 	}
740815516c77SSepherosa Ziehau 	hdr = data;
740915516c77SSepherosa Ziehau 
741015516c77SSepherosa Ziehau 	if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) {
741115516c77SSepherosa Ziehau 		/* Hot data path. */
741215516c77SSepherosa Ziehau 		hn_rndis_rx_data(rxr, data, dlen);
741315516c77SSepherosa Ziehau 		/* Done! */
741415516c77SSepherosa Ziehau 		return;
741515516c77SSepherosa Ziehau 	}
741615516c77SSepherosa Ziehau 
741715516c77SSepherosa Ziehau 	if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG)
741815516c77SSepherosa Ziehau 		hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen);
741915516c77SSepherosa Ziehau 	else
742015516c77SSepherosa Ziehau 		hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen);
742115516c77SSepherosa Ziehau }
742215516c77SSepherosa Ziehau 
742315516c77SSepherosa Ziehau static void
742415516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
742515516c77SSepherosa Ziehau {
742615516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *hdr;
742715516c77SSepherosa Ziehau 
742815516c77SSepherosa Ziehau 	if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) {
742915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid nvs notify\n");
743015516c77SSepherosa Ziehau 		return;
743115516c77SSepherosa Ziehau 	}
743215516c77SSepherosa Ziehau 	hdr = VMBUS_CHANPKT_CONST_DATA(pkt);
743315516c77SSepherosa Ziehau 
743415516c77SSepherosa Ziehau 	if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) {
743515516c77SSepherosa Ziehau 		/* Useless; ignore */
743615516c77SSepherosa Ziehau 		return;
743715516c77SSepherosa Ziehau 	}
743815516c77SSepherosa Ziehau 	if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type);
743915516c77SSepherosa Ziehau }
744015516c77SSepherosa Ziehau 
744115516c77SSepherosa Ziehau static void
744215516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan,
744315516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkt)
744415516c77SSepherosa Ziehau {
744515516c77SSepherosa Ziehau 	struct hn_nvs_sendctx *sndc;
744615516c77SSepherosa Ziehau 
744715516c77SSepherosa Ziehau 	sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid;
744815516c77SSepherosa Ziehau 	sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt),
744915516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_DATALEN(pkt));
745015516c77SSepherosa Ziehau 	/*
745115516c77SSepherosa Ziehau 	 * NOTE:
745215516c77SSepherosa Ziehau 	 * 'sndc' CAN NOT be accessed anymore, since it can be freed by
745315516c77SSepherosa Ziehau 	 * its callback.
745415516c77SSepherosa Ziehau 	 */
745515516c77SSepherosa Ziehau }
745615516c77SSepherosa Ziehau 
745715516c77SSepherosa Ziehau static void
745815516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
745915516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkthdr)
746015516c77SSepherosa Ziehau {
746115516c77SSepherosa Ziehau 	const struct vmbus_chanpkt_rxbuf *pkt;
746215516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *nvs_hdr;
746315516c77SSepherosa Ziehau 	int count, i, hlen;
746415516c77SSepherosa Ziehau 
746515516c77SSepherosa Ziehau 	if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) {
746615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n");
746715516c77SSepherosa Ziehau 		return;
746815516c77SSepherosa Ziehau 	}
746915516c77SSepherosa Ziehau 	nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr);
747015516c77SSepherosa Ziehau 
747115516c77SSepherosa Ziehau 	/* Make sure that this is a RNDIS message. */
747215516c77SSepherosa Ziehau 	if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) {
747315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n",
747415516c77SSepherosa Ziehau 		    nvs_hdr->nvs_type);
747515516c77SSepherosa Ziehau 		return;
747615516c77SSepherosa Ziehau 	}
747715516c77SSepherosa Ziehau 
747815516c77SSepherosa Ziehau 	hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen);
747915516c77SSepherosa Ziehau 	if (__predict_false(hlen < sizeof(*pkt))) {
748015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n");
748115516c77SSepherosa Ziehau 		return;
748215516c77SSepherosa Ziehau 	}
748315516c77SSepherosa Ziehau 	pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
748415516c77SSepherosa Ziehau 
748515516c77SSepherosa Ziehau 	if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) {
748615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n",
748715516c77SSepherosa Ziehau 		    pkt->cp_rxbuf_id);
748815516c77SSepherosa Ziehau 		return;
748915516c77SSepherosa Ziehau 	}
749015516c77SSepherosa Ziehau 
749115516c77SSepherosa Ziehau 	count = pkt->cp_rxbuf_cnt;
749215516c77SSepherosa Ziehau 	if (__predict_false(hlen <
749315516c77SSepherosa Ziehau 	    __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) {
749415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count);
749515516c77SSepherosa Ziehau 		return;
749615516c77SSepherosa Ziehau 	}
749715516c77SSepherosa Ziehau 
749815516c77SSepherosa Ziehau 	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
749915516c77SSepherosa Ziehau 	for (i = 0; i < count; ++i) {
750015516c77SSepherosa Ziehau 		int ofs, len;
750115516c77SSepherosa Ziehau 
750215516c77SSepherosa Ziehau 		ofs = pkt->cp_rxbuf[i].rb_ofs;
750315516c77SSepherosa Ziehau 		len = pkt->cp_rxbuf[i].rb_len;
750415516c77SSepherosa Ziehau 		if (__predict_false(ofs + len > HN_RXBUF_SIZE)) {
750515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, "
750615516c77SSepherosa Ziehau 			    "ofs %d, len %d\n", i, ofs, len);
750715516c77SSepherosa Ziehau 			continue;
750815516c77SSepherosa Ziehau 		}
7509*a491581fSWei Hu 
7510*a491581fSWei Hu 		rxr->rsc.is_last = (i == (count - 1));
751115516c77SSepherosa Ziehau 		hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len);
751215516c77SSepherosa Ziehau 	}
751315516c77SSepherosa Ziehau 
751415516c77SSepherosa Ziehau 	/*
751515516c77SSepherosa Ziehau 	 * Ack the consumed RXBUF associated w/ this channel packet,
751615516c77SSepherosa Ziehau 	 * so that this RXBUF can be recycled by the hypervisor.
751715516c77SSepherosa Ziehau 	 */
751815516c77SSepherosa Ziehau 	hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid);
751915516c77SSepherosa Ziehau }
752015516c77SSepherosa Ziehau 
752115516c77SSepherosa Ziehau static void
752215516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
752315516c77SSepherosa Ziehau     uint64_t tid)
752415516c77SSepherosa Ziehau {
752515516c77SSepherosa Ziehau 	struct hn_nvs_rndis_ack ack;
752615516c77SSepherosa Ziehau 	int retries, error;
752715516c77SSepherosa Ziehau 
752815516c77SSepherosa Ziehau 	ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK;
752915516c77SSepherosa Ziehau 	ack.nvs_status = HN_NVS_STATUS_OK;
753015516c77SSepherosa Ziehau 
753115516c77SSepherosa Ziehau 	retries = 0;
753215516c77SSepherosa Ziehau again:
753315516c77SSepherosa Ziehau 	error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP,
753415516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid);
753515516c77SSepherosa Ziehau 	if (__predict_false(error == EAGAIN)) {
753615516c77SSepherosa Ziehau 		/*
753715516c77SSepherosa Ziehau 		 * NOTE:
753815516c77SSepherosa Ziehau 		 * This should _not_ happen in real world, since the
753915516c77SSepherosa Ziehau 		 * consumption of the TX bufring from the TX path is
754015516c77SSepherosa Ziehau 		 * controlled.
754115516c77SSepherosa Ziehau 		 */
754215516c77SSepherosa Ziehau 		if (rxr->hn_ack_failed == 0)
754315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "RXBUF ack retry\n");
754415516c77SSepherosa Ziehau 		rxr->hn_ack_failed++;
754515516c77SSepherosa Ziehau 		retries++;
754615516c77SSepherosa Ziehau 		if (retries < 10) {
754715516c77SSepherosa Ziehau 			DELAY(100);
754815516c77SSepherosa Ziehau 			goto again;
754915516c77SSepherosa Ziehau 		}
755015516c77SSepherosa Ziehau 		/* RXBUF leaks! */
755115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "RXBUF ack failed\n");
755215516c77SSepherosa Ziehau 	}
755315516c77SSepherosa Ziehau }
755415516c77SSepherosa Ziehau 
755515516c77SSepherosa Ziehau static void
755615516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr)
755715516c77SSepherosa Ziehau {
755815516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr = xrxr;
755915516c77SSepherosa Ziehau 	struct hn_softc *sc = rxr->hn_ifp->if_softc;
756015516c77SSepherosa Ziehau 
756115516c77SSepherosa Ziehau 	for (;;) {
756215516c77SSepherosa Ziehau 		struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf;
756315516c77SSepherosa Ziehau 		int error, pktlen;
756415516c77SSepherosa Ziehau 
756515516c77SSepherosa Ziehau 		pktlen = rxr->hn_pktbuf_len;
756615516c77SSepherosa Ziehau 		error = vmbus_chan_recv_pkt(chan, pkt, &pktlen);
756715516c77SSepherosa Ziehau 		if (__predict_false(error == ENOBUFS)) {
756815516c77SSepherosa Ziehau 			void *nbuf;
756915516c77SSepherosa Ziehau 			int nlen;
757015516c77SSepherosa Ziehau 
757115516c77SSepherosa Ziehau 			/*
757215516c77SSepherosa Ziehau 			 * Expand channel packet buffer.
757315516c77SSepherosa Ziehau 			 *
757415516c77SSepherosa Ziehau 			 * XXX
757515516c77SSepherosa Ziehau 			 * Use M_WAITOK here, since allocation failure
757615516c77SSepherosa Ziehau 			 * is fatal.
757715516c77SSepherosa Ziehau 			 */
757815516c77SSepherosa Ziehau 			nlen = rxr->hn_pktbuf_len * 2;
757915516c77SSepherosa Ziehau 			while (nlen < pktlen)
758015516c77SSepherosa Ziehau 				nlen *= 2;
758115516c77SSepherosa Ziehau 			nbuf = malloc(nlen, M_DEVBUF, M_WAITOK);
758215516c77SSepherosa Ziehau 
758315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n",
758415516c77SSepherosa Ziehau 			    rxr->hn_pktbuf_len, nlen);
758515516c77SSepherosa Ziehau 
758615516c77SSepherosa Ziehau 			free(rxr->hn_pktbuf, M_DEVBUF);
758715516c77SSepherosa Ziehau 			rxr->hn_pktbuf = nbuf;
758815516c77SSepherosa Ziehau 			rxr->hn_pktbuf_len = nlen;
758915516c77SSepherosa Ziehau 			/* Retry! */
759015516c77SSepherosa Ziehau 			continue;
759115516c77SSepherosa Ziehau 		} else if (__predict_false(error == EAGAIN)) {
759215516c77SSepherosa Ziehau 			/* No more channel packets; done! */
759315516c77SSepherosa Ziehau 			break;
759415516c77SSepherosa Ziehau 		}
759515516c77SSepherosa Ziehau 		KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error));
759615516c77SSepherosa Ziehau 
759715516c77SSepherosa Ziehau 		switch (pkt->cph_type) {
759815516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_COMP:
759915516c77SSepherosa Ziehau 			hn_nvs_handle_comp(sc, chan, pkt);
760015516c77SSepherosa Ziehau 			break;
760115516c77SSepherosa Ziehau 
760215516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_RXBUF:
760315516c77SSepherosa Ziehau 			hn_nvs_handle_rxbuf(rxr, chan, pkt);
760415516c77SSepherosa Ziehau 			break;
760515516c77SSepherosa Ziehau 
760615516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_INBAND:
760715516c77SSepherosa Ziehau 			hn_nvs_handle_notify(sc, pkt);
760815516c77SSepherosa Ziehau 			break;
760915516c77SSepherosa Ziehau 
761015516c77SSepherosa Ziehau 		default:
761115516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "unknown chan pkt %u\n",
761215516c77SSepherosa Ziehau 			    pkt->cph_type);
761315516c77SSepherosa Ziehau 			break;
761415516c77SSepherosa Ziehau 		}
761515516c77SSepherosa Ziehau 	}
761615516c77SSepherosa Ziehau 	hn_chan_rollup(rxr, rxr->hn_txr);
761715516c77SSepherosa Ziehau }
761815516c77SSepherosa Ziehau 
761915516c77SSepherosa Ziehau static void
7620499c3e17SSepherosa Ziehau hn_sysinit(void *arg __unused)
762115516c77SSepherosa Ziehau {
7622fdd0222aSSepherosa Ziehau 	int i;
7623fdd0222aSSepherosa Ziehau 
76242be266caSSepherosa Ziehau 	hn_udpcs_fixup = counter_u64_alloc(M_WAITOK);
76252be266caSSepherosa Ziehau 
76269c6cae24SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
76279c6cae24SSepherosa Ziehau 	/*
76289c6cae24SSepherosa Ziehau 	 * Don't use ifnet.if_start if transparent VF mode is requested;
76299c6cae24SSepherosa Ziehau 	 * mainly due to the IFF_DRV_OACTIVE flag.
76309c6cae24SSepherosa Ziehau 	 */
76319c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && hn_use_if_start) {
76329c6cae24SSepherosa Ziehau 		hn_use_if_start = 0;
76339c6cae24SSepherosa Ziehau 		printf("hn: tranparent VF mode, if_transmit will be used, "
76349c6cae24SSepherosa Ziehau 		    "instead of if_start\n");
76359c6cae24SSepherosa Ziehau 	}
76369c6cae24SSepherosa Ziehau #endif
76379c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_attwait < HN_XPNT_VF_ATTWAIT_MIN) {
76389c6cae24SSepherosa Ziehau 		printf("hn: invalid transparent VF attach routing "
76399c6cae24SSepherosa Ziehau 		    "wait timeout %d, reset to %d\n",
76409c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_attwait, HN_XPNT_VF_ATTWAIT_MIN);
76419c6cae24SSepherosa Ziehau 		hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN;
76429c6cae24SSepherosa Ziehau 	}
76439c6cae24SSepherosa Ziehau 
7644fdd0222aSSepherosa Ziehau 	/*
7645499c3e17SSepherosa Ziehau 	 * Initialize VF map.
7646499c3e17SSepherosa Ziehau 	 */
7647499c3e17SSepherosa Ziehau 	rm_init_flags(&hn_vfmap_lock, "hn_vfmap", RM_SLEEPABLE);
7648499c3e17SSepherosa Ziehau 	hn_vfmap_size = HN_VFMAP_SIZE_DEF;
7649499c3e17SSepherosa Ziehau 	hn_vfmap = malloc(sizeof(struct ifnet *) * hn_vfmap_size, M_DEVBUF,
7650499c3e17SSepherosa Ziehau 	    M_WAITOK | M_ZERO);
7651499c3e17SSepherosa Ziehau 
7652499c3e17SSepherosa Ziehau 	/*
7653fdd0222aSSepherosa Ziehau 	 * Fix the # of TX taskqueues.
7654fdd0222aSSepherosa Ziehau 	 */
7655fdd0222aSSepherosa Ziehau 	if (hn_tx_taskq_cnt <= 0)
7656fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = 1;
7657fdd0222aSSepherosa Ziehau 	else if (hn_tx_taskq_cnt > mp_ncpus)
7658fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = mp_ncpus;
765915516c77SSepherosa Ziehau 
76600e11868dSSepherosa Ziehau 	/*
76610e11868dSSepherosa Ziehau 	 * Fix the TX taskqueue mode.
76620e11868dSSepherosa Ziehau 	 */
76630e11868dSSepherosa Ziehau 	switch (hn_tx_taskq_mode) {
76640e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_INDEP:
76650e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_GLOBAL:
76660e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_EVTTQ:
76670e11868dSSepherosa Ziehau 		break;
76680e11868dSSepherosa Ziehau 	default:
76690e11868dSSepherosa Ziehau 		hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
76700e11868dSSepherosa Ziehau 		break;
76710e11868dSSepherosa Ziehau 	}
76720e11868dSSepherosa Ziehau 
767315516c77SSepherosa Ziehau 	if (vm_guest != VM_GUEST_HV)
767415516c77SSepherosa Ziehau 		return;
767515516c77SSepherosa Ziehau 
76760e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode != HN_TX_TASKQ_M_GLOBAL)
767715516c77SSepherosa Ziehau 		return;
767815516c77SSepherosa Ziehau 
7679fdd0222aSSepherosa Ziehau 	hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
7680fdd0222aSSepherosa Ziehau 	    M_DEVBUF, M_WAITOK);
7681fdd0222aSSepherosa Ziehau 	for (i = 0; i < hn_tx_taskq_cnt; ++i) {
7682fdd0222aSSepherosa Ziehau 		hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK,
7683fdd0222aSSepherosa Ziehau 		    taskqueue_thread_enqueue, &hn_tx_taskque[i]);
7684fdd0222aSSepherosa Ziehau 		taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET,
7685fdd0222aSSepherosa Ziehau 		    "hn tx%d", i);
7686fdd0222aSSepherosa Ziehau 	}
768715516c77SSepherosa Ziehau }
7688499c3e17SSepherosa Ziehau SYSINIT(hn_sysinit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysinit, NULL);
768915516c77SSepherosa Ziehau 
769015516c77SSepherosa Ziehau static void
7691499c3e17SSepherosa Ziehau hn_sysuninit(void *arg __unused)
769215516c77SSepherosa Ziehau {
769315516c77SSepherosa Ziehau 
7694fdd0222aSSepherosa Ziehau 	if (hn_tx_taskque != NULL) {
7695fdd0222aSSepherosa Ziehau 		int i;
7696fdd0222aSSepherosa Ziehau 
7697fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
7698fdd0222aSSepherosa Ziehau 			taskqueue_free(hn_tx_taskque[i]);
7699fdd0222aSSepherosa Ziehau 		free(hn_tx_taskque, M_DEVBUF);
7700fdd0222aSSepherosa Ziehau 	}
7701499c3e17SSepherosa Ziehau 
7702499c3e17SSepherosa Ziehau 	if (hn_vfmap != NULL)
7703499c3e17SSepherosa Ziehau 		free(hn_vfmap, M_DEVBUF);
7704499c3e17SSepherosa Ziehau 	rm_destroy(&hn_vfmap_lock);
77052be266caSSepherosa Ziehau 
77062be266caSSepherosa Ziehau 	counter_u64_free(hn_udpcs_fixup);
770715516c77SSepherosa Ziehau }
7708499c3e17SSepherosa Ziehau SYSUNINIT(hn_sysuninit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysuninit, NULL);
7709