xref: /freebsd/sys/dev/hyperv/netvsc/if_hn.c (revision 93b4e111bb02ce42ba82e25c9c049e03ded19062)
115516c77SSepherosa Ziehau /*-
215516c77SSepherosa Ziehau  * Copyright (c) 2010-2012 Citrix Inc.
3*93b4e111SSepherosa Ziehau  * Copyright (c) 2009-2012,2016-2017 Microsoft Corp.
415516c77SSepherosa Ziehau  * Copyright (c) 2012 NetApp Inc.
515516c77SSepherosa Ziehau  * All rights reserved.
615516c77SSepherosa Ziehau  *
715516c77SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
815516c77SSepherosa Ziehau  * modification, are permitted provided that the following conditions
915516c77SSepherosa Ziehau  * are met:
1015516c77SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
1115516c77SSepherosa Ziehau  *    notice unmodified, this list of conditions, and the following
1215516c77SSepherosa Ziehau  *    disclaimer.
1315516c77SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
1415516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
1515516c77SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
1615516c77SSepherosa Ziehau  *
1715516c77SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1815516c77SSepherosa Ziehau  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1915516c77SSepherosa Ziehau  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2015516c77SSepherosa Ziehau  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2115516c77SSepherosa Ziehau  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2215516c77SSepherosa Ziehau  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2315516c77SSepherosa Ziehau  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2415516c77SSepherosa Ziehau  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2515516c77SSepherosa Ziehau  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2615516c77SSepherosa Ziehau  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2715516c77SSepherosa Ziehau  */
2815516c77SSepherosa Ziehau 
2915516c77SSepherosa Ziehau /*-
3015516c77SSepherosa Ziehau  * Copyright (c) 2004-2006 Kip Macy
3115516c77SSepherosa Ziehau  * All rights reserved.
3215516c77SSepherosa Ziehau  *
3315516c77SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
3415516c77SSepherosa Ziehau  * modification, are permitted provided that the following conditions
3515516c77SSepherosa Ziehau  * are met:
3615516c77SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
3715516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer.
3815516c77SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
3915516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
4015516c77SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
4115516c77SSepherosa Ziehau  *
4215516c77SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
4315516c77SSepherosa Ziehau  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4415516c77SSepherosa Ziehau  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4515516c77SSepherosa Ziehau  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4615516c77SSepherosa Ziehau  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4715516c77SSepherosa Ziehau  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4815516c77SSepherosa Ziehau  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4915516c77SSepherosa Ziehau  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5015516c77SSepherosa Ziehau  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5115516c77SSepherosa Ziehau  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5215516c77SSepherosa Ziehau  * SUCH DAMAGE.
5315516c77SSepherosa Ziehau  */
5415516c77SSepherosa Ziehau 
5515516c77SSepherosa Ziehau #include <sys/cdefs.h>
5615516c77SSepherosa Ziehau __FBSDID("$FreeBSD$");
5715516c77SSepherosa Ziehau 
5834d68912SSepherosa Ziehau #include "opt_hn.h"
5915516c77SSepherosa Ziehau #include "opt_inet6.h"
6015516c77SSepherosa Ziehau #include "opt_inet.h"
6134d68912SSepherosa Ziehau #include "opt_rss.h"
6215516c77SSepherosa Ziehau 
6315516c77SSepherosa Ziehau #include <sys/param.h>
6415516c77SSepherosa Ziehau #include <sys/bus.h>
6515516c77SSepherosa Ziehau #include <sys/kernel.h>
6615516c77SSepherosa Ziehau #include <sys/limits.h>
6715516c77SSepherosa Ziehau #include <sys/malloc.h>
6815516c77SSepherosa Ziehau #include <sys/mbuf.h>
6915516c77SSepherosa Ziehau #include <sys/module.h>
7015516c77SSepherosa Ziehau #include <sys/queue.h>
7115516c77SSepherosa Ziehau #include <sys/lock.h>
72499c3e17SSepherosa Ziehau #include <sys/rmlock.h>
73499c3e17SSepherosa Ziehau #include <sys/sbuf.h>
7415516c77SSepherosa Ziehau #include <sys/smp.h>
7515516c77SSepherosa Ziehau #include <sys/socket.h>
7615516c77SSepherosa Ziehau #include <sys/sockio.h>
7715516c77SSepherosa Ziehau #include <sys/sx.h>
7815516c77SSepherosa Ziehau #include <sys/sysctl.h>
7915516c77SSepherosa Ziehau #include <sys/systm.h>
8015516c77SSepherosa Ziehau #include <sys/taskqueue.h>
8115516c77SSepherosa Ziehau #include <sys/buf_ring.h>
825bdfd3fdSDexuan Cui #include <sys/eventhandler.h>
8315516c77SSepherosa Ziehau 
8415516c77SSepherosa Ziehau #include <machine/atomic.h>
8515516c77SSepherosa Ziehau #include <machine/in_cksum.h>
8615516c77SSepherosa Ziehau 
8715516c77SSepherosa Ziehau #include <net/bpf.h>
8815516c77SSepherosa Ziehau #include <net/ethernet.h>
8915516c77SSepherosa Ziehau #include <net/if.h>
905bdfd3fdSDexuan Cui #include <net/if_dl.h>
9115516c77SSepherosa Ziehau #include <net/if_media.h>
9215516c77SSepherosa Ziehau #include <net/if_types.h>
9315516c77SSepherosa Ziehau #include <net/if_var.h>
9415516c77SSepherosa Ziehau #include <net/rndis.h>
9534d68912SSepherosa Ziehau #ifdef RSS
9634d68912SSepherosa Ziehau #include <net/rss_config.h>
9734d68912SSepherosa Ziehau #endif
9815516c77SSepherosa Ziehau 
9915516c77SSepherosa Ziehau #include <netinet/in_systm.h>
10015516c77SSepherosa Ziehau #include <netinet/in.h>
10115516c77SSepherosa Ziehau #include <netinet/ip.h>
10215516c77SSepherosa Ziehau #include <netinet/ip6.h>
10315516c77SSepherosa Ziehau #include <netinet/tcp.h>
10415516c77SSepherosa Ziehau #include <netinet/tcp_lro.h>
10515516c77SSepherosa Ziehau #include <netinet/udp.h>
10615516c77SSepherosa Ziehau 
10715516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h>
10815516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv_busdma.h>
10915516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus.h>
11015516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus_xact.h>
11115516c77SSepherosa Ziehau 
11215516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/ndis.h>
11315516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnreg.h>
11415516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnvar.h>
11515516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_nvs.h>
11615516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_rndis.h>
11715516c77SSepherosa Ziehau 
11815516c77SSepherosa Ziehau #include "vmbus_if.h"
11915516c77SSepherosa Ziehau 
12023bf9e15SSepherosa Ziehau #define HN_IFSTART_SUPPORT
12123bf9e15SSepherosa Ziehau 
12215516c77SSepherosa Ziehau #define HN_RING_CNT_DEF_MAX		8
12315516c77SSepherosa Ziehau 
124499c3e17SSepherosa Ziehau #define HN_VFMAP_SIZE_DEF		8
125499c3e17SSepherosa Ziehau 
1269c6cae24SSepherosa Ziehau #define HN_XPNT_VF_ATTWAIT_MIN		2	/* seconds */
1279c6cae24SSepherosa Ziehau 
12815516c77SSepherosa Ziehau /* YYY should get it from the underlying channel */
12915516c77SSepherosa Ziehau #define HN_TX_DESC_CNT			512
13015516c77SSepherosa Ziehau 
13115516c77SSepherosa Ziehau #define HN_RNDIS_PKT_LEN					\
13215516c77SSepherosa Ziehau 	(sizeof(struct rndis_packet_msg) +			\
13315516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) +	\
13415516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) +		\
13515516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) +		\
13615516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_TXCSUM_INFO_SIZE))
13715516c77SSepherosa Ziehau #define HN_RNDIS_PKT_BOUNDARY		PAGE_SIZE
13815516c77SSepherosa Ziehau #define HN_RNDIS_PKT_ALIGN		CACHE_LINE_SIZE
13915516c77SSepherosa Ziehau 
14015516c77SSepherosa Ziehau #define HN_TX_DATA_BOUNDARY		PAGE_SIZE
14115516c77SSepherosa Ziehau #define HN_TX_DATA_MAXSIZE		IP_MAXPACKET
14215516c77SSepherosa Ziehau #define HN_TX_DATA_SEGSIZE		PAGE_SIZE
14315516c77SSepherosa Ziehau /* -1 for RNDIS packet message */
14415516c77SSepherosa Ziehau #define HN_TX_DATA_SEGCNT_MAX		(HN_GPACNT_MAX - 1)
14515516c77SSepherosa Ziehau 
14615516c77SSepherosa Ziehau #define HN_DIRECT_TX_SIZE_DEF		128
14715516c77SSepherosa Ziehau 
14815516c77SSepherosa Ziehau #define HN_EARLY_TXEOF_THRESH		8
14915516c77SSepherosa Ziehau 
15015516c77SSepherosa Ziehau #define HN_PKTBUF_LEN_DEF		(16 * 1024)
15115516c77SSepherosa Ziehau 
15215516c77SSepherosa Ziehau #define HN_LROENT_CNT_DEF		128
15315516c77SSepherosa Ziehau 
15415516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MULTIRX_DEF	(12 * ETHERMTU)
15515516c77SSepherosa Ziehau #define HN_LRO_LENLIM_DEF		(25 * ETHERMTU)
15615516c77SSepherosa Ziehau /* YYY 2*MTU is a bit rough, but should be good enough. */
15715516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MIN(ifp)		(2 * (ifp)->if_mtu)
15815516c77SSepherosa Ziehau 
15915516c77SSepherosa Ziehau #define HN_LRO_ACKCNT_DEF		1
16015516c77SSepherosa Ziehau 
16115516c77SSepherosa Ziehau #define HN_LOCK_INIT(sc)		\
16215516c77SSepherosa Ziehau 	sx_init(&(sc)->hn_lock, device_get_nameunit((sc)->hn_dev))
16315516c77SSepherosa Ziehau #define HN_LOCK_DESTROY(sc)		sx_destroy(&(sc)->hn_lock)
16415516c77SSepherosa Ziehau #define HN_LOCK_ASSERT(sc)		sx_assert(&(sc)->hn_lock, SA_XLOCKED)
165fdc4f478SSepherosa Ziehau #define HN_LOCK(sc)					\
166fdc4f478SSepherosa Ziehau do {							\
167fdc4f478SSepherosa Ziehau 	while (sx_try_xlock(&(sc)->hn_lock) == 0)	\
168fdc4f478SSepherosa Ziehau 		DELAY(1000);				\
169fdc4f478SSepherosa Ziehau } while (0)
17015516c77SSepherosa Ziehau #define HN_UNLOCK(sc)			sx_xunlock(&(sc)->hn_lock)
17115516c77SSepherosa Ziehau 
17215516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK			(CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP)
17315516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK		(CSUM_IP6_TCP | CSUM_IP6_UDP)
17415516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc)		\
17515516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK)
17615516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc)	\
17715516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK)
17815516c77SSepherosa Ziehau 
179dc13fee6SSepherosa Ziehau #define HN_PKTSIZE_MIN(align)		\
180dc13fee6SSepherosa Ziehau 	roundup2(ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN + \
181dc13fee6SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN, (align))
182dc13fee6SSepherosa Ziehau #define HN_PKTSIZE(m, align)		\
183dc13fee6SSepherosa Ziehau 	roundup2((m)->m_pkthdr.len + HN_RNDIS_PKT_LEN, (align))
184dc13fee6SSepherosa Ziehau 
18534d68912SSepherosa Ziehau #ifdef RSS
18634d68912SSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx)	rss_getcpu((idx) % rss_getnumbuckets())
18734d68912SSepherosa Ziehau #else
1880e11868dSSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx)	(((sc)->hn_cpu + (idx)) % mp_ncpus)
18934d68912SSepherosa Ziehau #endif
1900e11868dSSepherosa Ziehau 
19115516c77SSepherosa Ziehau struct hn_txdesc {
19215516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
19315516c77SSepherosa Ziehau 	SLIST_ENTRY(hn_txdesc)		link;
19415516c77SSepherosa Ziehau #endif
195dc13fee6SSepherosa Ziehau 	STAILQ_ENTRY(hn_txdesc)		agg_link;
196dc13fee6SSepherosa Ziehau 
197dc13fee6SSepherosa Ziehau 	/* Aggregated txdescs, in sending order. */
198dc13fee6SSepherosa Ziehau 	STAILQ_HEAD(, hn_txdesc)	agg_list;
199dc13fee6SSepherosa Ziehau 
200dc13fee6SSepherosa Ziehau 	/* The oldest packet, if transmission aggregation happens. */
20115516c77SSepherosa Ziehau 	struct mbuf			*m;
20215516c77SSepherosa Ziehau 	struct hn_tx_ring		*txr;
20315516c77SSepherosa Ziehau 	int				refs;
20415516c77SSepherosa Ziehau 	uint32_t			flags;	/* HN_TXD_FLAG_ */
20515516c77SSepherosa Ziehau 	struct hn_nvs_sendctx		send_ctx;
20615516c77SSepherosa Ziehau 	uint32_t			chim_index;
20715516c77SSepherosa Ziehau 	int				chim_size;
20815516c77SSepherosa Ziehau 
20915516c77SSepherosa Ziehau 	bus_dmamap_t			data_dmap;
21015516c77SSepherosa Ziehau 
21115516c77SSepherosa Ziehau 	bus_addr_t			rndis_pkt_paddr;
21215516c77SSepherosa Ziehau 	struct rndis_packet_msg		*rndis_pkt;
21315516c77SSepherosa Ziehau 	bus_dmamap_t			rndis_pkt_dmap;
21415516c77SSepherosa Ziehau };
21515516c77SSepherosa Ziehau 
21615516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST		0x0001
21715516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP		0x0002
218dc13fee6SSepherosa Ziehau #define HN_TXD_FLAG_ONAGG		0x0004
21915516c77SSepherosa Ziehau 
22015516c77SSepherosa Ziehau struct hn_rxinfo {
22115516c77SSepherosa Ziehau 	uint32_t			vlan_info;
22215516c77SSepherosa Ziehau 	uint32_t			csum_info;
22315516c77SSepherosa Ziehau 	uint32_t			hash_info;
22415516c77SSepherosa Ziehau 	uint32_t			hash_value;
22515516c77SSepherosa Ziehau };
22615516c77SSepherosa Ziehau 
227962f0357SSepherosa Ziehau struct hn_rxvf_setarg {
2285bdfd3fdSDexuan Cui 	struct hn_rx_ring	*rxr;
229962f0357SSepherosa Ziehau 	struct ifnet		*vf_ifp;
2305bdfd3fdSDexuan Cui };
2315bdfd3fdSDexuan Cui 
23215516c77SSepherosa Ziehau #define HN_RXINFO_VLAN			0x0001
23315516c77SSepherosa Ziehau #define HN_RXINFO_CSUM			0x0002
23415516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF		0x0004
23515516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL		0x0008
23615516c77SSepherosa Ziehau #define HN_RXINFO_ALL			\
23715516c77SSepherosa Ziehau 	(HN_RXINFO_VLAN |		\
23815516c77SSepherosa Ziehau 	 HN_RXINFO_CSUM |		\
23915516c77SSepherosa Ziehau 	 HN_RXINFO_HASHINF |		\
24015516c77SSepherosa Ziehau 	 HN_RXINFO_HASHVAL)
24115516c77SSepherosa Ziehau 
24215516c77SSepherosa Ziehau #define HN_NDIS_VLAN_INFO_INVALID	0xffffffff
24315516c77SSepherosa Ziehau #define HN_NDIS_RXCSUM_INFO_INVALID	0
24415516c77SSepherosa Ziehau #define HN_NDIS_HASH_INFO_INVALID	0
24515516c77SSepherosa Ziehau 
24615516c77SSepherosa Ziehau static int			hn_probe(device_t);
24715516c77SSepherosa Ziehau static int			hn_attach(device_t);
24815516c77SSepherosa Ziehau static int			hn_detach(device_t);
24915516c77SSepherosa Ziehau static int			hn_shutdown(device_t);
25015516c77SSepherosa Ziehau static void			hn_chan_callback(struct vmbus_channel *,
25115516c77SSepherosa Ziehau 				    void *);
25215516c77SSepherosa Ziehau 
25315516c77SSepherosa Ziehau static void			hn_init(void *);
25415516c77SSepherosa Ziehau static int			hn_ioctl(struct ifnet *, u_long, caddr_t);
25523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
25615516c77SSepherosa Ziehau static void			hn_start(struct ifnet *);
25723bf9e15SSepherosa Ziehau #endif
25815516c77SSepherosa Ziehau static int			hn_transmit(struct ifnet *, struct mbuf *);
25915516c77SSepherosa Ziehau static void			hn_xmit_qflush(struct ifnet *);
26015516c77SSepherosa Ziehau static int			hn_ifmedia_upd(struct ifnet *);
26115516c77SSepherosa Ziehau static void			hn_ifmedia_sts(struct ifnet *,
26215516c77SSepherosa Ziehau 				    struct ifmediareq *);
26315516c77SSepherosa Ziehau 
264499c3e17SSepherosa Ziehau static void			hn_ifnet_event(void *, struct ifnet *, int);
265499c3e17SSepherosa Ziehau static void			hn_ifaddr_event(void *, struct ifnet *);
266499c3e17SSepherosa Ziehau static void			hn_ifnet_attevent(void *, struct ifnet *);
267499c3e17SSepherosa Ziehau static void			hn_ifnet_detevent(void *, struct ifnet *);
2689c6cae24SSepherosa Ziehau static void			hn_ifnet_lnkevent(void *, struct ifnet *, int);
269499c3e17SSepherosa Ziehau 
270962f0357SSepherosa Ziehau static bool			hn_ismyvf(const struct hn_softc *,
271962f0357SSepherosa Ziehau 				    const struct ifnet *);
272962f0357SSepherosa Ziehau static void			hn_rxvf_change(struct hn_softc *,
273962f0357SSepherosa Ziehau 				    struct ifnet *, bool);
274962f0357SSepherosa Ziehau static void			hn_rxvf_set(struct hn_softc *, struct ifnet *);
275962f0357SSepherosa Ziehau static void			hn_rxvf_set_task(void *, int);
2769c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_input(struct ifnet *, struct mbuf *);
2779c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_iocsetflags(struct hn_softc *);
2789c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_iocsetcaps(struct hn_softc *,
2799c6cae24SSepherosa Ziehau 				    struct ifreq *);
2809c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_saveifflags(struct hn_softc *);
2819c6cae24SSepherosa Ziehau static bool			hn_xpnt_vf_isready(struct hn_softc *);
2829c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_setready(struct hn_softc *);
2839c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_init_taskfunc(void *, int);
2849c6cae24SSepherosa Ziehau static void			hn_xpnt_vf_init(struct hn_softc *);
285a97fff19SSepherosa Ziehau static void			hn_xpnt_vf_setenable(struct hn_softc *);
286a97fff19SSepherosa Ziehau static void			hn_xpnt_vf_setdisable(struct hn_softc *, bool);
287962f0357SSepherosa Ziehau 
28815516c77SSepherosa Ziehau static int			hn_rndis_rxinfo(const void *, int,
28915516c77SSepherosa Ziehau 				    struct hn_rxinfo *);
29015516c77SSepherosa Ziehau static void			hn_rndis_rx_data(struct hn_rx_ring *,
29115516c77SSepherosa Ziehau 				    const void *, int);
29215516c77SSepherosa Ziehau static void			hn_rndis_rx_status(struct hn_softc *,
29315516c77SSepherosa Ziehau 				    const void *, int);
294b3b75d9cSSepherosa Ziehau static void			hn_rndis_init_fixat(struct hn_softc *, int);
29515516c77SSepherosa Ziehau 
29615516c77SSepherosa Ziehau static void			hn_nvs_handle_notify(struct hn_softc *,
29715516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
29815516c77SSepherosa Ziehau static void			hn_nvs_handle_comp(struct hn_softc *,
29915516c77SSepherosa Ziehau 				    struct vmbus_channel *,
30015516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
30115516c77SSepherosa Ziehau static void			hn_nvs_handle_rxbuf(struct hn_rx_ring *,
30215516c77SSepherosa Ziehau 				    struct vmbus_channel *,
30315516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
30415516c77SSepherosa Ziehau static void			hn_nvs_ack_rxbuf(struct hn_rx_ring *,
30515516c77SSepherosa Ziehau 				    struct vmbus_channel *, uint64_t);
30615516c77SSepherosa Ziehau 
30715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
30815516c77SSepherosa Ziehau static int			hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS);
30915516c77SSepherosa Ziehau static int			hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS);
31015516c77SSepherosa Ziehau #endif
31115516c77SSepherosa Ziehau static int			hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS);
31215516c77SSepherosa Ziehau static int			hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS);
31315516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
31415516c77SSepherosa Ziehau static int			hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS);
31515516c77SSepherosa Ziehau #else
31615516c77SSepherosa Ziehau static int			hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS);
31715516c77SSepherosa Ziehau #endif
31815516c77SSepherosa Ziehau static int			hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
31915516c77SSepherosa Ziehau static int			hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
32015516c77SSepherosa Ziehau static int			hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS);
32115516c77SSepherosa Ziehau static int			hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS);
32215516c77SSepherosa Ziehau static int			hn_caps_sysctl(SYSCTL_HANDLER_ARGS);
32315516c77SSepherosa Ziehau static int			hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS);
32415516c77SSepherosa Ziehau static int			hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS);
32534d68912SSepherosa Ziehau #ifndef RSS
32615516c77SSepherosa Ziehau static int			hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS);
32715516c77SSepherosa Ziehau static int			hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS);
32834d68912SSepherosa Ziehau #endif
32915516c77SSepherosa Ziehau static int			hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS);
330dc13fee6SSepherosa Ziehau static int			hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS);
331dc13fee6SSepherosa Ziehau static int			hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS);
332dc13fee6SSepherosa Ziehau static int			hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS);
333dc13fee6SSepherosa Ziehau static int			hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS);
3346c1204dfSSepherosa Ziehau static int			hn_polling_sysctl(SYSCTL_HANDLER_ARGS);
33540d60d6eSDexuan Cui static int			hn_vf_sysctl(SYSCTL_HANDLER_ARGS);
336499c3e17SSepherosa Ziehau static int			hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS);
337499c3e17SSepherosa Ziehau static int			hn_vflist_sysctl(SYSCTL_HANDLER_ARGS);
338499c3e17SSepherosa Ziehau static int			hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS);
3399c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS);
3409c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS);
34115516c77SSepherosa Ziehau 
3425bdfd3fdSDexuan Cui static void			hn_stop(struct hn_softc *, bool);
34315516c77SSepherosa Ziehau static void			hn_init_locked(struct hn_softc *);
34415516c77SSepherosa Ziehau static int			hn_chan_attach(struct hn_softc *,
34515516c77SSepherosa Ziehau 				    struct vmbus_channel *);
34615516c77SSepherosa Ziehau static void			hn_chan_detach(struct hn_softc *,
34715516c77SSepherosa Ziehau 				    struct vmbus_channel *);
34815516c77SSepherosa Ziehau static int			hn_attach_subchans(struct hn_softc *);
34915516c77SSepherosa Ziehau static void			hn_detach_allchans(struct hn_softc *);
35015516c77SSepherosa Ziehau static void			hn_chan_rollup(struct hn_rx_ring *,
35115516c77SSepherosa Ziehau 				    struct hn_tx_ring *);
35215516c77SSepherosa Ziehau static void			hn_set_ring_inuse(struct hn_softc *, int);
35315516c77SSepherosa Ziehau static int			hn_synth_attach(struct hn_softc *, int);
35415516c77SSepherosa Ziehau static void			hn_synth_detach(struct hn_softc *);
35515516c77SSepherosa Ziehau static int			hn_synth_alloc_subchans(struct hn_softc *,
35615516c77SSepherosa Ziehau 				    int *);
3572494d735SSepherosa Ziehau static bool			hn_synth_attachable(const struct hn_softc *);
35815516c77SSepherosa Ziehau static void			hn_suspend(struct hn_softc *);
35915516c77SSepherosa Ziehau static void			hn_suspend_data(struct hn_softc *);
36015516c77SSepherosa Ziehau static void			hn_suspend_mgmt(struct hn_softc *);
36115516c77SSepherosa Ziehau static void			hn_resume(struct hn_softc *);
36215516c77SSepherosa Ziehau static void			hn_resume_data(struct hn_softc *);
36315516c77SSepherosa Ziehau static void			hn_resume_mgmt(struct hn_softc *);
36415516c77SSepherosa Ziehau static void			hn_suspend_mgmt_taskfunc(void *, int);
36525641fc7SSepherosa Ziehau static void			hn_chan_drain(struct hn_softc *,
36625641fc7SSepherosa Ziehau 				    struct vmbus_channel *);
367b3b75d9cSSepherosa Ziehau static void			hn_disable_rx(struct hn_softc *);
368b3b75d9cSSepherosa Ziehau static void			hn_drain_rxtx(struct hn_softc *, int);
3696c1204dfSSepherosa Ziehau static void			hn_polling(struct hn_softc *, u_int);
3706c1204dfSSepherosa Ziehau static void			hn_chan_polling(struct vmbus_channel *, u_int);
3719c6cae24SSepherosa Ziehau static void			hn_mtu_change_fixup(struct hn_softc *);
37215516c77SSepherosa Ziehau 
37315516c77SSepherosa Ziehau static void			hn_update_link_status(struct hn_softc *);
37415516c77SSepherosa Ziehau static void			hn_change_network(struct hn_softc *);
37515516c77SSepherosa Ziehau static void			hn_link_taskfunc(void *, int);
37615516c77SSepherosa Ziehau static void			hn_netchg_init_taskfunc(void *, int);
37715516c77SSepherosa Ziehau static void			hn_netchg_status_taskfunc(void *, int);
37815516c77SSepherosa Ziehau static void			hn_link_status(struct hn_softc *);
37915516c77SSepherosa Ziehau 
38015516c77SSepherosa Ziehau static int			hn_create_rx_data(struct hn_softc *, int);
38115516c77SSepherosa Ziehau static void			hn_destroy_rx_data(struct hn_softc *);
38215516c77SSepherosa Ziehau static int			hn_check_iplen(const struct mbuf *, int);
383f1b0a43fSSepherosa Ziehau static int			hn_set_rxfilter(struct hn_softc *, uint32_t);
384c08f7b2cSSepherosa Ziehau static int			hn_rxfilter_config(struct hn_softc *);
38534d68912SSepherosa Ziehau #ifndef RSS
38615516c77SSepherosa Ziehau static int			hn_rss_reconfig(struct hn_softc *);
38734d68912SSepherosa Ziehau #endif
388afd4971bSSepherosa Ziehau static void			hn_rss_ind_fixup(struct hn_softc *);
38915516c77SSepherosa Ziehau static int			hn_rxpkt(struct hn_rx_ring *, const void *,
39015516c77SSepherosa Ziehau 				    int, const struct hn_rxinfo *);
39115516c77SSepherosa Ziehau 
39215516c77SSepherosa Ziehau static int			hn_tx_ring_create(struct hn_softc *, int);
39315516c77SSepherosa Ziehau static void			hn_tx_ring_destroy(struct hn_tx_ring *);
39415516c77SSepherosa Ziehau static int			hn_create_tx_data(struct hn_softc *, int);
39515516c77SSepherosa Ziehau static void			hn_fixup_tx_data(struct hn_softc *);
39615516c77SSepherosa Ziehau static void			hn_destroy_tx_data(struct hn_softc *);
39715516c77SSepherosa Ziehau static void			hn_txdesc_dmamap_destroy(struct hn_txdesc *);
39825641fc7SSepherosa Ziehau static void			hn_txdesc_gc(struct hn_tx_ring *,
39925641fc7SSepherosa Ziehau 				    struct hn_txdesc *);
400dc13fee6SSepherosa Ziehau static int			hn_encap(struct ifnet *, struct hn_tx_ring *,
40115516c77SSepherosa Ziehau 				    struct hn_txdesc *, struct mbuf **);
40215516c77SSepherosa Ziehau static int			hn_txpkt(struct ifnet *, struct hn_tx_ring *,
40315516c77SSepherosa Ziehau 				    struct hn_txdesc *);
40415516c77SSepherosa Ziehau static void			hn_set_chim_size(struct hn_softc *, int);
40515516c77SSepherosa Ziehau static void			hn_set_tso_maxsize(struct hn_softc *, int, int);
40615516c77SSepherosa Ziehau static bool			hn_tx_ring_pending(struct hn_tx_ring *);
40715516c77SSepherosa Ziehau static void			hn_tx_ring_qflush(struct hn_tx_ring *);
40815516c77SSepherosa Ziehau static void			hn_resume_tx(struct hn_softc *, int);
409dc13fee6SSepherosa Ziehau static void			hn_set_txagg(struct hn_softc *);
410dc13fee6SSepherosa Ziehau static void			*hn_try_txagg(struct ifnet *,
411dc13fee6SSepherosa Ziehau 				    struct hn_tx_ring *, struct hn_txdesc *,
412dc13fee6SSepherosa Ziehau 				    int);
41315516c77SSepherosa Ziehau static int			hn_get_txswq_depth(const struct hn_tx_ring *);
41415516c77SSepherosa Ziehau static void			hn_txpkt_done(struct hn_nvs_sendctx *,
41515516c77SSepherosa Ziehau 				    struct hn_softc *, struct vmbus_channel *,
41615516c77SSepherosa Ziehau 				    const void *, int);
41715516c77SSepherosa Ziehau static int			hn_txpkt_sglist(struct hn_tx_ring *,
41815516c77SSepherosa Ziehau 				    struct hn_txdesc *);
41915516c77SSepherosa Ziehau static int			hn_txpkt_chim(struct hn_tx_ring *,
42015516c77SSepherosa Ziehau 				    struct hn_txdesc *);
42115516c77SSepherosa Ziehau static int			hn_xmit(struct hn_tx_ring *, int);
42215516c77SSepherosa Ziehau static void			hn_xmit_taskfunc(void *, int);
42315516c77SSepherosa Ziehau static void			hn_xmit_txeof(struct hn_tx_ring *);
42415516c77SSepherosa Ziehau static void			hn_xmit_txeof_taskfunc(void *, int);
42523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
42615516c77SSepherosa Ziehau static int			hn_start_locked(struct hn_tx_ring *, int);
42715516c77SSepherosa Ziehau static void			hn_start_taskfunc(void *, int);
42815516c77SSepherosa Ziehau static void			hn_start_txeof(struct hn_tx_ring *);
42915516c77SSepherosa Ziehau static void			hn_start_txeof_taskfunc(void *, int);
43023bf9e15SSepherosa Ziehau #endif
43115516c77SSepherosa Ziehau 
43215516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
43315516c77SSepherosa Ziehau     "Hyper-V network interface");
43415516c77SSepherosa Ziehau 
43515516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */
43615516c77SSepherosa Ziehau static int			hn_trust_hosttcp = 1;
43715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN,
43815516c77SSepherosa Ziehau     &hn_trust_hosttcp, 0,
43915516c77SSepherosa Ziehau     "Trust tcp segement verification on host side, "
44015516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
44115516c77SSepherosa Ziehau 
44215516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */
44315516c77SSepherosa Ziehau static int			hn_trust_hostudp = 1;
44415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN,
44515516c77SSepherosa Ziehau     &hn_trust_hostudp, 0,
44615516c77SSepherosa Ziehau     "Trust udp datagram verification on host side, "
44715516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
44815516c77SSepherosa Ziehau 
44915516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */
45015516c77SSepherosa Ziehau static int			hn_trust_hostip = 1;
45115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN,
45215516c77SSepherosa Ziehau     &hn_trust_hostip, 0,
45315516c77SSepherosa Ziehau     "Trust ip packet verification on host side, "
45415516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
45515516c77SSepherosa Ziehau 
45615516c77SSepherosa Ziehau /* Limit TSO burst size */
45715516c77SSepherosa Ziehau static int			hn_tso_maxlen = IP_MAXPACKET;
45815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN,
45915516c77SSepherosa Ziehau     &hn_tso_maxlen, 0, "TSO burst limit");
46015516c77SSepherosa Ziehau 
46115516c77SSepherosa Ziehau /* Limit chimney send size */
46215516c77SSepherosa Ziehau static int			hn_tx_chimney_size = 0;
46315516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN,
46415516c77SSepherosa Ziehau     &hn_tx_chimney_size, 0, "Chimney send packet size limit");
46515516c77SSepherosa Ziehau 
46615516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */
46715516c77SSepherosa Ziehau static int			hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF;
46815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN,
46915516c77SSepherosa Ziehau     &hn_direct_tx_size, 0, "Size of the packet for direct transmission");
47015516c77SSepherosa Ziehau 
47115516c77SSepherosa Ziehau /* # of LRO entries per RX ring */
47215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
47315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
47415516c77SSepherosa Ziehau static int			hn_lro_entry_count = HN_LROENT_CNT_DEF;
47515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN,
47615516c77SSepherosa Ziehau     &hn_lro_entry_count, 0, "LRO entry count");
47715516c77SSepherosa Ziehau #endif
47815516c77SSepherosa Ziehau #endif
47915516c77SSepherosa Ziehau 
480fdd0222aSSepherosa Ziehau static int			hn_tx_taskq_cnt = 1;
481fdd0222aSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_cnt, CTLFLAG_RDTUN,
482fdd0222aSSepherosa Ziehau     &hn_tx_taskq_cnt, 0, "# of TX taskqueues");
483fdd0222aSSepherosa Ziehau 
4840e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_INDEP	0
4850e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_GLOBAL	1
4860e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_EVTTQ	2
4870e11868dSSepherosa Ziehau 
4880e11868dSSepherosa Ziehau static int			hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
4890e11868dSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_mode, CTLFLAG_RDTUN,
4900e11868dSSepherosa Ziehau     &hn_tx_taskq_mode, 0, "TX taskqueue modes: "
4910e11868dSSepherosa Ziehau     "0 - independent, 1 - share global tx taskqs, 2 - share event taskqs");
4920e11868dSSepherosa Ziehau 
49315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
49415516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 0;
49515516c77SSepherosa Ziehau #else
49615516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 1;
49715516c77SSepherosa Ziehau #endif
49815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD,
49915516c77SSepherosa Ziehau     &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors");
50015516c77SSepherosa Ziehau 
50123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
50215516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */
50315516c77SSepherosa Ziehau static int			hn_use_if_start = 0;
50415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN,
50515516c77SSepherosa Ziehau     &hn_use_if_start, 0, "Use if_start TX method");
50623bf9e15SSepherosa Ziehau #endif
50715516c77SSepherosa Ziehau 
50815516c77SSepherosa Ziehau /* # of channels to use */
50915516c77SSepherosa Ziehau static int			hn_chan_cnt = 0;
51015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN,
51115516c77SSepherosa Ziehau     &hn_chan_cnt, 0,
51215516c77SSepherosa Ziehau     "# of channels to use; each channel has one RX ring and one TX ring");
51315516c77SSepherosa Ziehau 
51415516c77SSepherosa Ziehau /* # of transmit rings to use */
51515516c77SSepherosa Ziehau static int			hn_tx_ring_cnt = 0;
51615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN,
51715516c77SSepherosa Ziehau     &hn_tx_ring_cnt, 0, "# of TX rings to use");
51815516c77SSepherosa Ziehau 
51915516c77SSepherosa Ziehau /* Software TX ring deptch */
52015516c77SSepherosa Ziehau static int			hn_tx_swq_depth = 0;
52115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN,
52215516c77SSepherosa Ziehau     &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING");
52315516c77SSepherosa Ziehau 
52415516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */
52515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
52615516c77SSepherosa Ziehau static u_int			hn_lro_mbufq_depth = 0;
52715516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN,
52815516c77SSepherosa Ziehau     &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue");
52915516c77SSepherosa Ziehau #endif
53015516c77SSepherosa Ziehau 
531dc13fee6SSepherosa Ziehau /* Packet transmission aggregation size limit */
532dc13fee6SSepherosa Ziehau static int			hn_tx_agg_size = -1;
533dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN,
534dc13fee6SSepherosa Ziehau     &hn_tx_agg_size, 0, "Packet transmission aggregation size limit");
535dc13fee6SSepherosa Ziehau 
536dc13fee6SSepherosa Ziehau /* Packet transmission aggregation count limit */
537fa915c4dSSepherosa Ziehau static int			hn_tx_agg_pkts = -1;
538dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN,
539dc13fee6SSepherosa Ziehau     &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit");
540dc13fee6SSepherosa Ziehau 
541499c3e17SSepherosa Ziehau /* VF list */
542499c3e17SSepherosa Ziehau SYSCTL_PROC(_hw_hn, OID_AUTO, vflist, CTLFLAG_RD | CTLTYPE_STRING,
543499c3e17SSepherosa Ziehau     0, 0, hn_vflist_sysctl, "A", "VF list");
544499c3e17SSepherosa Ziehau 
545499c3e17SSepherosa Ziehau /* VF mapping */
546499c3e17SSepherosa Ziehau SYSCTL_PROC(_hw_hn, OID_AUTO, vfmap, CTLFLAG_RD | CTLTYPE_STRING,
547499c3e17SSepherosa Ziehau     0, 0, hn_vfmap_sysctl, "A", "VF mapping");
548499c3e17SSepherosa Ziehau 
5499c6cae24SSepherosa Ziehau /* Transparent VF */
5509c6cae24SSepherosa Ziehau static int			hn_xpnt_vf = 0;
5519c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_transparent, CTLFLAG_RDTUN,
5529c6cae24SSepherosa Ziehau     &hn_xpnt_vf, 0, "Transparent VF mod");
5539c6cae24SSepherosa Ziehau 
5549c6cae24SSepherosa Ziehau /* Accurate BPF support for Transparent VF */
5559c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_accbpf = 0;
5569c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_xpnt_accbpf, CTLFLAG_RDTUN,
5579c6cae24SSepherosa Ziehau     &hn_xpnt_vf_accbpf, 0, "Accurate BPF for transparent VF");
5589c6cae24SSepherosa Ziehau 
5599c6cae24SSepherosa Ziehau /* Extra wait for transparent VF attach routing; unit seconds. */
5609c6cae24SSepherosa Ziehau static int			hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN;
5619c6cae24SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, vf_xpnt_attwait, CTLFLAG_RWTUN,
5629c6cae24SSepherosa Ziehau     &hn_xpnt_vf_attwait, 0,
5639c6cae24SSepherosa Ziehau     "Extra wait for transparent VF attach routing; unit: seconds");
5649c6cae24SSepherosa Ziehau 
56515516c77SSepherosa Ziehau static u_int			hn_cpu_index;	/* next CPU for channel */
566fdd0222aSSepherosa Ziehau static struct taskqueue		**hn_tx_taskque;/* shared TX taskqueues */
56715516c77SSepherosa Ziehau 
568499c3e17SSepherosa Ziehau static struct rmlock		hn_vfmap_lock;
569499c3e17SSepherosa Ziehau static int			hn_vfmap_size;
570499c3e17SSepherosa Ziehau static struct ifnet		**hn_vfmap;
571499c3e17SSepherosa Ziehau 
57234d68912SSepherosa Ziehau #ifndef RSS
57315516c77SSepherosa Ziehau static const uint8_t
57415516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
57515516c77SSepherosa Ziehau 	0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
57615516c77SSepherosa Ziehau 	0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
57715516c77SSepherosa Ziehau 	0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
57815516c77SSepherosa Ziehau 	0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
57915516c77SSepherosa Ziehau 	0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
58015516c77SSepherosa Ziehau };
58134d68912SSepherosa Ziehau #endif	/* !RSS */
58215516c77SSepherosa Ziehau 
583c2d50b26SSepherosa Ziehau static const struct hyperv_guid	hn_guid = {
584c2d50b26SSepherosa Ziehau 	.hv_guid = {
585c2d50b26SSepherosa Ziehau 	    0x63, 0x51, 0x61, 0xf8, 0x3e, 0xdf, 0xc5, 0x46,
586c2d50b26SSepherosa Ziehau 	    0x91, 0x3f, 0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e }
587c2d50b26SSepherosa Ziehau };
588c2d50b26SSepherosa Ziehau 
58915516c77SSepherosa Ziehau static device_method_t hn_methods[] = {
59015516c77SSepherosa Ziehau 	/* Device interface */
59115516c77SSepherosa Ziehau 	DEVMETHOD(device_probe,		hn_probe),
59215516c77SSepherosa Ziehau 	DEVMETHOD(device_attach,	hn_attach),
59315516c77SSepherosa Ziehau 	DEVMETHOD(device_detach,	hn_detach),
59415516c77SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	hn_shutdown),
59515516c77SSepherosa Ziehau 	DEVMETHOD_END
59615516c77SSepherosa Ziehau };
59715516c77SSepherosa Ziehau 
59815516c77SSepherosa Ziehau static driver_t hn_driver = {
59915516c77SSepherosa Ziehau 	"hn",
60015516c77SSepherosa Ziehau 	hn_methods,
60115516c77SSepherosa Ziehau 	sizeof(struct hn_softc)
60215516c77SSepherosa Ziehau };
60315516c77SSepherosa Ziehau 
60415516c77SSepherosa Ziehau static devclass_t hn_devclass;
60515516c77SSepherosa Ziehau 
60615516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0);
60715516c77SSepherosa Ziehau MODULE_VERSION(hn, 1);
60815516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1);
60915516c77SSepherosa Ziehau 
61015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
61115516c77SSepherosa Ziehau static void
61215516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim)
61315516c77SSepherosa Ziehau {
61415516c77SSepherosa Ziehau 	int i;
61515516c77SSepherosa Ziehau 
616a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
61715516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim;
61815516c77SSepherosa Ziehau }
61915516c77SSepherosa Ziehau #endif
62015516c77SSepherosa Ziehau 
62115516c77SSepherosa Ziehau static int
62215516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd)
62315516c77SSepherosa Ziehau {
62415516c77SSepherosa Ziehau 
62515516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
62615516c77SSepherosa Ziehau 	    txd->chim_size == 0, ("invalid rndis sglist txd"));
62715516c77SSepherosa Ziehau 	return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA,
62815516c77SSepherosa Ziehau 	    &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt));
62915516c77SSepherosa Ziehau }
63015516c77SSepherosa Ziehau 
63115516c77SSepherosa Ziehau static int
63215516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd)
63315516c77SSepherosa Ziehau {
63415516c77SSepherosa Ziehau 	struct hn_nvs_rndis rndis;
63515516c77SSepherosa Ziehau 
63615516c77SSepherosa Ziehau 	KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID &&
63715516c77SSepherosa Ziehau 	    txd->chim_size > 0, ("invalid rndis chim txd"));
63815516c77SSepherosa Ziehau 
63915516c77SSepherosa Ziehau 	rndis.nvs_type = HN_NVS_TYPE_RNDIS;
64015516c77SSepherosa Ziehau 	rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA;
64115516c77SSepherosa Ziehau 	rndis.nvs_chim_idx = txd->chim_index;
64215516c77SSepherosa Ziehau 	rndis.nvs_chim_sz = txd->chim_size;
64315516c77SSepherosa Ziehau 
64415516c77SSepherosa Ziehau 	return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC,
64515516c77SSepherosa Ziehau 	    &rndis, sizeof(rndis), &txd->send_ctx));
64615516c77SSepherosa Ziehau }
64715516c77SSepherosa Ziehau 
64815516c77SSepherosa Ziehau static __inline uint32_t
64915516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc)
65015516c77SSepherosa Ziehau {
65115516c77SSepherosa Ziehau 	int i, bmap_cnt = sc->hn_chim_bmap_cnt;
65215516c77SSepherosa Ziehau 	u_long *bmap = sc->hn_chim_bmap;
65315516c77SSepherosa Ziehau 	uint32_t ret = HN_NVS_CHIM_IDX_INVALID;
65415516c77SSepherosa Ziehau 
65515516c77SSepherosa Ziehau 	for (i = 0; i < bmap_cnt; ++i) {
65615516c77SSepherosa Ziehau 		int idx;
65715516c77SSepherosa Ziehau 
65815516c77SSepherosa Ziehau 		idx = ffsl(~bmap[i]);
65915516c77SSepherosa Ziehau 		if (idx == 0)
66015516c77SSepherosa Ziehau 			continue;
66115516c77SSepherosa Ziehau 
66215516c77SSepherosa Ziehau 		--idx; /* ffsl is 1-based */
66315516c77SSepherosa Ziehau 		KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt,
66415516c77SSepherosa Ziehau 		    ("invalid i %d and idx %d", i, idx));
66515516c77SSepherosa Ziehau 
66615516c77SSepherosa Ziehau 		if (atomic_testandset_long(&bmap[i], idx))
66715516c77SSepherosa Ziehau 			continue;
66815516c77SSepherosa Ziehau 
66915516c77SSepherosa Ziehau 		ret = i * LONG_BIT + idx;
67015516c77SSepherosa Ziehau 		break;
67115516c77SSepherosa Ziehau 	}
67215516c77SSepherosa Ziehau 	return (ret);
67315516c77SSepherosa Ziehau }
67415516c77SSepherosa Ziehau 
67515516c77SSepherosa Ziehau static __inline void
67615516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx)
67715516c77SSepherosa Ziehau {
67815516c77SSepherosa Ziehau 	u_long mask;
67915516c77SSepherosa Ziehau 	uint32_t idx;
68015516c77SSepherosa Ziehau 
68115516c77SSepherosa Ziehau 	idx = chim_idx / LONG_BIT;
68215516c77SSepherosa Ziehau 	KASSERT(idx < sc->hn_chim_bmap_cnt,
68315516c77SSepherosa Ziehau 	    ("invalid chimney index 0x%x", chim_idx));
68415516c77SSepherosa Ziehau 
68515516c77SSepherosa Ziehau 	mask = 1UL << (chim_idx % LONG_BIT);
68615516c77SSepherosa Ziehau 	KASSERT(sc->hn_chim_bmap[idx] & mask,
68715516c77SSepherosa Ziehau 	    ("index bitmap 0x%lx, chimney index %u, "
68815516c77SSepherosa Ziehau 	     "bitmap idx %d, bitmask 0x%lx",
68915516c77SSepherosa Ziehau 	     sc->hn_chim_bmap[idx], chim_idx, idx, mask));
69015516c77SSepherosa Ziehau 
69115516c77SSepherosa Ziehau 	atomic_clear_long(&sc->hn_chim_bmap[idx], mask);
69215516c77SSepherosa Ziehau }
69315516c77SSepherosa Ziehau 
694edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
695cc0c6ebcSSepherosa Ziehau 
696cc0c6ebcSSepherosa Ziehau #define PULLUP_HDR(m, len)				\
697cc0c6ebcSSepherosa Ziehau do {							\
698cc0c6ebcSSepherosa Ziehau 	if (__predict_false((m)->m_len < (len))) {	\
699cc0c6ebcSSepherosa Ziehau 		(m) = m_pullup((m), (len));		\
700cc0c6ebcSSepherosa Ziehau 		if ((m) == NULL)			\
701cc0c6ebcSSepherosa Ziehau 			return (NULL);			\
702cc0c6ebcSSepherosa Ziehau 	}						\
703cc0c6ebcSSepherosa Ziehau } while (0)
704cc0c6ebcSSepherosa Ziehau 
705edd3f315SSepherosa Ziehau /*
706edd3f315SSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
707edd3f315SSepherosa Ziehau  */
708edd3f315SSepherosa Ziehau static __inline struct mbuf *
709edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head)
710edd3f315SSepherosa Ziehau {
711edd3f315SSepherosa Ziehau 	struct ether_vlan_header *evl;
712edd3f315SSepherosa Ziehau 	struct tcphdr *th;
713edd3f315SSepherosa Ziehau 	int ehlen;
714edd3f315SSepherosa Ziehau 
715edd3f315SSepherosa Ziehau 	KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable"));
716edd3f315SSepherosa Ziehau 
717edd3f315SSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
718edd3f315SSepherosa Ziehau 	evl = mtod(m_head, struct ether_vlan_header *);
719edd3f315SSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
720edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
721edd3f315SSepherosa Ziehau 	else
722edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
723edd3f315SSepherosa Ziehau 
724edd3f315SSepherosa Ziehau #ifdef INET
725edd3f315SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
726edd3f315SSepherosa Ziehau 		struct ip *ip;
727edd3f315SSepherosa Ziehau 		int iphlen;
728edd3f315SSepherosa Ziehau 
729edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
730edd3f315SSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
731edd3f315SSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
732edd3f315SSepherosa Ziehau 
733edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
734edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + iphlen);
735edd3f315SSepherosa Ziehau 
736edd3f315SSepherosa Ziehau 		ip->ip_len = 0;
737edd3f315SSepherosa Ziehau 		ip->ip_sum = 0;
738edd3f315SSepherosa Ziehau 		th->th_sum = in_pseudo(ip->ip_src.s_addr,
739edd3f315SSepherosa Ziehau 		    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
740edd3f315SSepherosa Ziehau 	}
741edd3f315SSepherosa Ziehau #endif
742edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET)
743edd3f315SSepherosa Ziehau 	else
744edd3f315SSepherosa Ziehau #endif
745edd3f315SSepherosa Ziehau #ifdef INET6
746edd3f315SSepherosa Ziehau 	{
747edd3f315SSepherosa Ziehau 		struct ip6_hdr *ip6;
748edd3f315SSepherosa Ziehau 
749edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
750edd3f315SSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
751edd3f315SSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP) {
752edd3f315SSepherosa Ziehau 			m_freem(m_head);
753edd3f315SSepherosa Ziehau 			return (NULL);
754edd3f315SSepherosa Ziehau 		}
755edd3f315SSepherosa Ziehau 
756edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
757edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + sizeof(*ip6));
758edd3f315SSepherosa Ziehau 
759edd3f315SSepherosa Ziehau 		ip6->ip6_plen = 0;
760edd3f315SSepherosa Ziehau 		th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
761edd3f315SSepherosa Ziehau 	}
762edd3f315SSepherosa Ziehau #endif
763edd3f315SSepherosa Ziehau 	return (m_head);
764edd3f315SSepherosa Ziehau 
765edd3f315SSepherosa Ziehau }
766cc0c6ebcSSepherosa Ziehau 
767cc0c6ebcSSepherosa Ziehau /*
768cc0c6ebcSSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
769cc0c6ebcSSepherosa Ziehau  */
770cc0c6ebcSSepherosa Ziehau static __inline struct mbuf *
771cc0c6ebcSSepherosa Ziehau hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn)
772cc0c6ebcSSepherosa Ziehau {
773cc0c6ebcSSepherosa Ziehau 	const struct ether_vlan_header *evl;
774cc0c6ebcSSepherosa Ziehau 	const struct tcphdr *th;
775cc0c6ebcSSepherosa Ziehau 	int ehlen;
776cc0c6ebcSSepherosa Ziehau 
777cc0c6ebcSSepherosa Ziehau 	*tcpsyn = 0;
778cc0c6ebcSSepherosa Ziehau 
779cc0c6ebcSSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
780cc0c6ebcSSepherosa Ziehau 	evl = mtod(m_head, const struct ether_vlan_header *);
781cc0c6ebcSSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
782cc0c6ebcSSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
783cc0c6ebcSSepherosa Ziehau 	else
784cc0c6ebcSSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
785cc0c6ebcSSepherosa Ziehau 
786cc0c6ebcSSepherosa Ziehau #ifdef INET
787cc0c6ebcSSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_IP_TCP) {
788cc0c6ebcSSepherosa Ziehau 		const struct ip *ip;
789cc0c6ebcSSepherosa Ziehau 		int iphlen;
790cc0c6ebcSSepherosa Ziehau 
791cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
792cc0c6ebcSSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
793cc0c6ebcSSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
794cc0c6ebcSSepherosa Ziehau 
795cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
796cc0c6ebcSSepherosa Ziehau 		th = mtodo(m_head, ehlen + iphlen);
797cc0c6ebcSSepherosa Ziehau 		if (th->th_flags & TH_SYN)
798cc0c6ebcSSepherosa Ziehau 			*tcpsyn = 1;
799cc0c6ebcSSepherosa Ziehau 	}
800cc0c6ebcSSepherosa Ziehau #endif
801cc0c6ebcSSepherosa Ziehau #if defined(INET6) && defined(INET)
802cc0c6ebcSSepherosa Ziehau 	else
803cc0c6ebcSSepherosa Ziehau #endif
804cc0c6ebcSSepherosa Ziehau #ifdef INET6
805cc0c6ebcSSepherosa Ziehau 	{
806cc0c6ebcSSepherosa Ziehau 		const struct ip6_hdr *ip6;
807cc0c6ebcSSepherosa Ziehau 
808cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
809cc0c6ebcSSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
810cc0c6ebcSSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP)
811cc0c6ebcSSepherosa Ziehau 			return (m_head);
812cc0c6ebcSSepherosa Ziehau 
813cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
814cc0c6ebcSSepherosa Ziehau 		th = mtodo(m_head, ehlen + sizeof(*ip6));
815cc0c6ebcSSepherosa Ziehau 		if (th->th_flags & TH_SYN)
816cc0c6ebcSSepherosa Ziehau 			*tcpsyn = 1;
817cc0c6ebcSSepherosa Ziehau 	}
818cc0c6ebcSSepherosa Ziehau #endif
819cc0c6ebcSSepherosa Ziehau 	return (m_head);
820cc0c6ebcSSepherosa Ziehau }
821cc0c6ebcSSepherosa Ziehau 
822cc0c6ebcSSepherosa Ziehau #undef PULLUP_HDR
823cc0c6ebcSSepherosa Ziehau 
824edd3f315SSepherosa Ziehau #endif	/* INET6 || INET */
825edd3f315SSepherosa Ziehau 
82615516c77SSepherosa Ziehau static int
827f1b0a43fSSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc, uint32_t filter)
828f1b0a43fSSepherosa Ziehau {
829f1b0a43fSSepherosa Ziehau 	int error = 0;
830f1b0a43fSSepherosa Ziehau 
831f1b0a43fSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
832f1b0a43fSSepherosa Ziehau 
833f1b0a43fSSepherosa Ziehau 	if (sc->hn_rx_filter != filter) {
834f1b0a43fSSepherosa Ziehau 		error = hn_rndis_set_rxfilter(sc, filter);
835f1b0a43fSSepherosa Ziehau 		if (!error)
836f1b0a43fSSepherosa Ziehau 			sc->hn_rx_filter = filter;
837f1b0a43fSSepherosa Ziehau 	}
838f1b0a43fSSepherosa Ziehau 	return (error);
839f1b0a43fSSepherosa Ziehau }
840f1b0a43fSSepherosa Ziehau 
841f1b0a43fSSepherosa Ziehau static int
842c08f7b2cSSepherosa Ziehau hn_rxfilter_config(struct hn_softc *sc)
84315516c77SSepherosa Ziehau {
84415516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
84515516c77SSepherosa Ziehau 	uint32_t filter;
84615516c77SSepherosa Ziehau 
84715516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
84815516c77SSepherosa Ziehau 
8499c6cae24SSepherosa Ziehau 	/*
8509c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, we don't know how
8519c6cae24SSepherosa Ziehau 	 * its RX filter is configured, so stick the synthetic device in
8529c6cae24SSepherosa Ziehau 	 * the promiscous mode.
8539c6cae24SSepherosa Ziehau 	 */
8549c6cae24SSepherosa Ziehau 	if ((ifp->if_flags & IFF_PROMISC) || (sc->hn_flags & HN_FLAG_RXVF)) {
85515516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_PROMISCUOUS;
85615516c77SSepherosa Ziehau 	} else {
85715516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_DIRECTED;
85815516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_BROADCAST)
85915516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_BROADCAST;
86015516c77SSepherosa Ziehau 		/* TODO: support multicast list */
86115516c77SSepherosa Ziehau 		if ((ifp->if_flags & IFF_ALLMULTI) ||
86215516c77SSepherosa Ziehau 		    !TAILQ_EMPTY(&ifp->if_multiaddrs))
86315516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
86415516c77SSepherosa Ziehau 	}
865f1b0a43fSSepherosa Ziehau 	return (hn_set_rxfilter(sc, filter));
86615516c77SSepherosa Ziehau }
86715516c77SSepherosa Ziehau 
868dc13fee6SSepherosa Ziehau static void
869dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc)
870dc13fee6SSepherosa Ziehau {
871dc13fee6SSepherosa Ziehau 	uint32_t size, pkts;
872dc13fee6SSepherosa Ziehau 	int i;
873dc13fee6SSepherosa Ziehau 
874dc13fee6SSepherosa Ziehau 	/*
875dc13fee6SSepherosa Ziehau 	 * Setup aggregation size.
876dc13fee6SSepherosa Ziehau 	 */
877dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_size < 0)
878dc13fee6SSepherosa Ziehau 		size = UINT32_MAX;
879dc13fee6SSepherosa Ziehau 	else
880dc13fee6SSepherosa Ziehau 		size = sc->hn_agg_size;
881dc13fee6SSepherosa Ziehau 
882dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_size < size)
883dc13fee6SSepherosa Ziehau 		size = sc->hn_rndis_agg_size;
884dc13fee6SSepherosa Ziehau 
885a4364cfeSSepherosa Ziehau 	/* NOTE: We only aggregate packets using chimney sending buffers. */
886a4364cfeSSepherosa Ziehau 	if (size > (uint32_t)sc->hn_chim_szmax)
887a4364cfeSSepherosa Ziehau 		size = sc->hn_chim_szmax;
888a4364cfeSSepherosa Ziehau 
889dc13fee6SSepherosa Ziehau 	if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) {
890dc13fee6SSepherosa Ziehau 		/* Disable */
891dc13fee6SSepherosa Ziehau 		size = 0;
892dc13fee6SSepherosa Ziehau 		pkts = 0;
893dc13fee6SSepherosa Ziehau 		goto done;
894dc13fee6SSepherosa Ziehau 	}
895dc13fee6SSepherosa Ziehau 
896dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'int'. */
897dc13fee6SSepherosa Ziehau 	if (size > INT_MAX)
898dc13fee6SSepherosa Ziehau 		size = INT_MAX;
899dc13fee6SSepherosa Ziehau 
900dc13fee6SSepherosa Ziehau 	/*
901dc13fee6SSepherosa Ziehau 	 * Setup aggregation packet count.
902dc13fee6SSepherosa Ziehau 	 */
903dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_pkts < 0)
904dc13fee6SSepherosa Ziehau 		pkts = UINT32_MAX;
905dc13fee6SSepherosa Ziehau 	else
906dc13fee6SSepherosa Ziehau 		pkts = sc->hn_agg_pkts;
907dc13fee6SSepherosa Ziehau 
908dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_pkts < pkts)
909dc13fee6SSepherosa Ziehau 		pkts = sc->hn_rndis_agg_pkts;
910dc13fee6SSepherosa Ziehau 
911dc13fee6SSepherosa Ziehau 	if (pkts <= 1) {
912dc13fee6SSepherosa Ziehau 		/* Disable */
913dc13fee6SSepherosa Ziehau 		size = 0;
914dc13fee6SSepherosa Ziehau 		pkts = 0;
915dc13fee6SSepherosa Ziehau 		goto done;
916dc13fee6SSepherosa Ziehau 	}
917dc13fee6SSepherosa Ziehau 
918dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
919dc13fee6SSepherosa Ziehau 	if (pkts > SHRT_MAX)
920dc13fee6SSepherosa Ziehau 		pkts = SHRT_MAX;
921dc13fee6SSepherosa Ziehau 
922dc13fee6SSepherosa Ziehau done:
923dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
924dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_align > SHRT_MAX) {
925dc13fee6SSepherosa Ziehau 		/* Disable */
926dc13fee6SSepherosa Ziehau 		size = 0;
927dc13fee6SSepherosa Ziehau 		pkts = 0;
928dc13fee6SSepherosa Ziehau 	}
929dc13fee6SSepherosa Ziehau 
930dc13fee6SSepherosa Ziehau 	if (bootverbose) {
931dc13fee6SSepherosa Ziehau 		if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n",
932dc13fee6SSepherosa Ziehau 		    size, pkts, sc->hn_rndis_agg_align);
933dc13fee6SSepherosa Ziehau 	}
934dc13fee6SSepherosa Ziehau 
935dc13fee6SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
936dc13fee6SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
937dc13fee6SSepherosa Ziehau 
938dc13fee6SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
939dc13fee6SSepherosa Ziehau 		txr->hn_agg_szmax = size;
940dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktmax = pkts;
941dc13fee6SSepherosa Ziehau 		txr->hn_agg_align = sc->hn_rndis_agg_align;
942dc13fee6SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
943dc13fee6SSepherosa Ziehau 	}
944dc13fee6SSepherosa Ziehau }
945dc13fee6SSepherosa Ziehau 
94615516c77SSepherosa Ziehau static int
94715516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr)
94815516c77SSepherosa Ziehau {
94915516c77SSepherosa Ziehau 
95015516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet"));
95115516c77SSepherosa Ziehau 	if (hn_tx_swq_depth < txr->hn_txdesc_cnt)
95215516c77SSepherosa Ziehau 		return txr->hn_txdesc_cnt;
95315516c77SSepherosa Ziehau 	return hn_tx_swq_depth;
95415516c77SSepherosa Ziehau }
95515516c77SSepherosa Ziehau 
95634d68912SSepherosa Ziehau #ifndef RSS
95715516c77SSepherosa Ziehau static int
95815516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc)
95915516c77SSepherosa Ziehau {
96015516c77SSepherosa Ziehau 	int error;
96115516c77SSepherosa Ziehau 
96215516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
96315516c77SSepherosa Ziehau 
96415516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
96515516c77SSepherosa Ziehau 		return (ENXIO);
96615516c77SSepherosa Ziehau 
96715516c77SSepherosa Ziehau 	/*
96815516c77SSepherosa Ziehau 	 * Disable RSS first.
96915516c77SSepherosa Ziehau 	 *
97015516c77SSepherosa Ziehau 	 * NOTE:
97115516c77SSepherosa Ziehau 	 * Direct reconfiguration by setting the UNCHG flags does
97215516c77SSepherosa Ziehau 	 * _not_ work properly.
97315516c77SSepherosa Ziehau 	 */
97415516c77SSepherosa Ziehau 	if (bootverbose)
97515516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "disable RSS\n");
97615516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE);
97715516c77SSepherosa Ziehau 	if (error) {
97815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS disable failed\n");
97915516c77SSepherosa Ziehau 		return (error);
98015516c77SSepherosa Ziehau 	}
98115516c77SSepherosa Ziehau 
98215516c77SSepherosa Ziehau 	/*
98315516c77SSepherosa Ziehau 	 * Reenable the RSS w/ the updated RSS key or indirect
98415516c77SSepherosa Ziehau 	 * table.
98515516c77SSepherosa Ziehau 	 */
98615516c77SSepherosa Ziehau 	if (bootverbose)
98715516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "reconfig RSS\n");
98815516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
98915516c77SSepherosa Ziehau 	if (error) {
99015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS reconfig failed\n");
99115516c77SSepherosa Ziehau 		return (error);
99215516c77SSepherosa Ziehau 	}
99315516c77SSepherosa Ziehau 	return (0);
99415516c77SSepherosa Ziehau }
99534d68912SSepherosa Ziehau #endif	/* !RSS */
99615516c77SSepherosa Ziehau 
99715516c77SSepherosa Ziehau static void
998afd4971bSSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc)
99915516c77SSepherosa Ziehau {
100015516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
1001afd4971bSSepherosa Ziehau 	int i, nchan;
100215516c77SSepherosa Ziehau 
1003afd4971bSSepherosa Ziehau 	nchan = sc->hn_rx_ring_inuse;
100415516c77SSepherosa Ziehau 	KASSERT(nchan > 1, ("invalid # of channels %d", nchan));
100515516c77SSepherosa Ziehau 
100615516c77SSepherosa Ziehau 	/*
100715516c77SSepherosa Ziehau 	 * Check indirect table to make sure that all channels in it
100815516c77SSepherosa Ziehau 	 * can be used.
100915516c77SSepherosa Ziehau 	 */
101015516c77SSepherosa Ziehau 	for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
101115516c77SSepherosa Ziehau 		if (rss->rss_ind[i] >= nchan) {
101215516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp,
101315516c77SSepherosa Ziehau 			    "RSS indirect table %d fixup: %u -> %d\n",
101415516c77SSepherosa Ziehau 			    i, rss->rss_ind[i], nchan - 1);
101515516c77SSepherosa Ziehau 			rss->rss_ind[i] = nchan - 1;
101615516c77SSepherosa Ziehau 		}
101715516c77SSepherosa Ziehau 	}
101815516c77SSepherosa Ziehau }
101915516c77SSepherosa Ziehau 
102015516c77SSepherosa Ziehau static int
102115516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused)
102215516c77SSepherosa Ziehau {
102315516c77SSepherosa Ziehau 
102415516c77SSepherosa Ziehau 	return EOPNOTSUPP;
102515516c77SSepherosa Ziehau }
102615516c77SSepherosa Ziehau 
102715516c77SSepherosa Ziehau static void
102815516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
102915516c77SSepherosa Ziehau {
103015516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
103115516c77SSepherosa Ziehau 
103215516c77SSepherosa Ziehau 	ifmr->ifm_status = IFM_AVALID;
103315516c77SSepherosa Ziehau 	ifmr->ifm_active = IFM_ETHER;
103415516c77SSepherosa Ziehau 
103515516c77SSepherosa Ziehau 	if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) {
103615516c77SSepherosa Ziehau 		ifmr->ifm_active |= IFM_NONE;
103715516c77SSepherosa Ziehau 		return;
103815516c77SSepherosa Ziehau 	}
103915516c77SSepherosa Ziehau 	ifmr->ifm_status |= IFM_ACTIVE;
104015516c77SSepherosa Ziehau 	ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
104115516c77SSepherosa Ziehau }
104215516c77SSepherosa Ziehau 
10435bdfd3fdSDexuan Cui static void
1044962f0357SSepherosa Ziehau hn_rxvf_set_task(void *xarg, int pending __unused)
10455bdfd3fdSDexuan Cui {
1046962f0357SSepherosa Ziehau 	struct hn_rxvf_setarg *arg = xarg;
10475bdfd3fdSDexuan Cui 
1048962f0357SSepherosa Ziehau 	arg->rxr->hn_rxvf_ifp = arg->vf_ifp;
10495bdfd3fdSDexuan Cui }
10505bdfd3fdSDexuan Cui 
10515bdfd3fdSDexuan Cui static void
1052962f0357SSepherosa Ziehau hn_rxvf_set(struct hn_softc *sc, struct ifnet *vf_ifp)
10535bdfd3fdSDexuan Cui {
10545bdfd3fdSDexuan Cui 	struct hn_rx_ring *rxr;
1055962f0357SSepherosa Ziehau 	struct hn_rxvf_setarg arg;
10565bdfd3fdSDexuan Cui 	struct task task;
10575bdfd3fdSDexuan Cui 	int i;
10585bdfd3fdSDexuan Cui 
10595bdfd3fdSDexuan Cui 	HN_LOCK_ASSERT(sc);
10605bdfd3fdSDexuan Cui 
1061962f0357SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_rxvf_set_task, &arg);
10625bdfd3fdSDexuan Cui 
10635bdfd3fdSDexuan Cui 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
10645bdfd3fdSDexuan Cui 		rxr = &sc->hn_rx_ring[i];
10655bdfd3fdSDexuan Cui 
10665bdfd3fdSDexuan Cui 		if (i < sc->hn_rx_ring_inuse) {
1067962f0357SSepherosa Ziehau 			arg.rxr = rxr;
1068962f0357SSepherosa Ziehau 			arg.vf_ifp = vf_ifp;
10695bdfd3fdSDexuan Cui 			vmbus_chan_run_task(rxr->hn_chan, &task);
10705bdfd3fdSDexuan Cui 		} else {
1071962f0357SSepherosa Ziehau 			rxr->hn_rxvf_ifp = vf_ifp;
10725bdfd3fdSDexuan Cui 		}
10735bdfd3fdSDexuan Cui 	}
10745bdfd3fdSDexuan Cui }
10755bdfd3fdSDexuan Cui 
1076962f0357SSepherosa Ziehau static bool
1077499c3e17SSepherosa Ziehau hn_ismyvf(const struct hn_softc *sc, const struct ifnet *ifp)
1078499c3e17SSepherosa Ziehau {
1079499c3e17SSepherosa Ziehau 	const struct ifnet *hn_ifp;
1080499c3e17SSepherosa Ziehau 
1081499c3e17SSepherosa Ziehau 	hn_ifp = sc->hn_ifp;
1082499c3e17SSepherosa Ziehau 
1083499c3e17SSepherosa Ziehau 	if (ifp == hn_ifp)
1084499c3e17SSepherosa Ziehau 		return (false);
1085499c3e17SSepherosa Ziehau 
1086499c3e17SSepherosa Ziehau 	if (ifp->if_alloctype != IFT_ETHER)
1087499c3e17SSepherosa Ziehau 		return (false);
1088499c3e17SSepherosa Ziehau 
1089499c3e17SSepherosa Ziehau 	/* Ignore lagg/vlan interfaces */
1090499c3e17SSepherosa Ziehau 	if (strcmp(ifp->if_dname, "lagg") == 0 ||
1091499c3e17SSepherosa Ziehau 	    strcmp(ifp->if_dname, "vlan") == 0)
1092499c3e17SSepherosa Ziehau 		return (false);
1093499c3e17SSepherosa Ziehau 
1094499c3e17SSepherosa Ziehau 	if (bcmp(IF_LLADDR(ifp), IF_LLADDR(hn_ifp), ETHER_ADDR_LEN) != 0)
1095499c3e17SSepherosa Ziehau 		return (false);
1096499c3e17SSepherosa Ziehau 
1097499c3e17SSepherosa Ziehau 	return (true);
1098499c3e17SSepherosa Ziehau }
1099499c3e17SSepherosa Ziehau 
11005bdfd3fdSDexuan Cui static void
1101962f0357SSepherosa Ziehau hn_rxvf_change(struct hn_softc *sc, struct ifnet *ifp, bool rxvf)
11025bdfd3fdSDexuan Cui {
11035bdfd3fdSDexuan Cui 	struct ifnet *hn_ifp;
11045bdfd3fdSDexuan Cui 
11055bdfd3fdSDexuan Cui 	HN_LOCK(sc);
11065bdfd3fdSDexuan Cui 
11075bdfd3fdSDexuan Cui 	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
11085bdfd3fdSDexuan Cui 		goto out;
11095bdfd3fdSDexuan Cui 
1110499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1111499c3e17SSepherosa Ziehau 		goto out;
11125bdfd3fdSDexuan Cui 	hn_ifp = sc->hn_ifp;
11135bdfd3fdSDexuan Cui 
1114962f0357SSepherosa Ziehau 	if (rxvf) {
1115962f0357SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_RXVF)
11165bdfd3fdSDexuan Cui 			goto out;
11175bdfd3fdSDexuan Cui 
1118962f0357SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_RXVF;
11195bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
11205bdfd3fdSDexuan Cui 	} else {
1121962f0357SSepherosa Ziehau 		if (!(sc->hn_flags & HN_FLAG_RXVF))
11225bdfd3fdSDexuan Cui 			goto out;
11235bdfd3fdSDexuan Cui 
1124962f0357SSepherosa Ziehau 		sc->hn_flags &= ~HN_FLAG_RXVF;
1125499c3e17SSepherosa Ziehau 		if (hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
11265bdfd3fdSDexuan Cui 			hn_rxfilter_config(sc);
11275bdfd3fdSDexuan Cui 		else
11285bdfd3fdSDexuan Cui 			hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE);
11295bdfd3fdSDexuan Cui 	}
11305bdfd3fdSDexuan Cui 
11315bdfd3fdSDexuan Cui 	hn_nvs_set_datapath(sc,
11329c6cae24SSepherosa Ziehau 	    rxvf ? HN_NVS_DATAPATH_VF : HN_NVS_DATAPATH_SYNTH);
11335bdfd3fdSDexuan Cui 
1134962f0357SSepherosa Ziehau 	hn_rxvf_set(sc, rxvf ? ifp : NULL);
11355bdfd3fdSDexuan Cui 
1136962f0357SSepherosa Ziehau 	if (rxvf) {
11375bdfd3fdSDexuan Cui 		hn_suspend_mgmt(sc);
11385bdfd3fdSDexuan Cui 		sc->hn_link_flags &=
11395bdfd3fdSDexuan Cui 		    ~(HN_LINK_FLAG_LINKUP | HN_LINK_FLAG_NETCHG);
1140499c3e17SSepherosa Ziehau 		if_link_state_change(hn_ifp, LINK_STATE_DOWN);
11415bdfd3fdSDexuan Cui 	} else {
11425bdfd3fdSDexuan Cui 		hn_resume_mgmt(sc);
11435bdfd3fdSDexuan Cui 	}
11445bdfd3fdSDexuan Cui 
1145962f0357SSepherosa Ziehau 	devctl_notify("HYPERV_NIC_VF", hn_ifp->if_xname,
1146962f0357SSepherosa Ziehau 	    rxvf ? "VF_UP" : "VF_DOWN", NULL);
114733408a34SDexuan Cui 
1148962f0357SSepherosa Ziehau 	if (bootverbose) {
1149962f0357SSepherosa Ziehau 		if_printf(hn_ifp, "datapath is switched %s %s\n",
1150962f0357SSepherosa Ziehau 		    rxvf ? "to" : "from", ifp->if_xname);
1151962f0357SSepherosa Ziehau 	}
11525bdfd3fdSDexuan Cui out:
11535bdfd3fdSDexuan Cui 	HN_UNLOCK(sc);
11545bdfd3fdSDexuan Cui }
11555bdfd3fdSDexuan Cui 
11565bdfd3fdSDexuan Cui static void
11575bdfd3fdSDexuan Cui hn_ifnet_event(void *arg, struct ifnet *ifp, int event)
11585bdfd3fdSDexuan Cui {
1159962f0357SSepherosa Ziehau 
11605bdfd3fdSDexuan Cui 	if (event != IFNET_EVENT_UP && event != IFNET_EVENT_DOWN)
11615bdfd3fdSDexuan Cui 		return;
1162962f0357SSepherosa Ziehau 	hn_rxvf_change(arg, ifp, event == IFNET_EVENT_UP);
11635bdfd3fdSDexuan Cui }
11645bdfd3fdSDexuan Cui 
11655bdfd3fdSDexuan Cui static void
11665bdfd3fdSDexuan Cui hn_ifaddr_event(void *arg, struct ifnet *ifp)
11675bdfd3fdSDexuan Cui {
1168962f0357SSepherosa Ziehau 
1169962f0357SSepherosa Ziehau 	hn_rxvf_change(arg, ifp, ifp->if_flags & IFF_UP);
11705bdfd3fdSDexuan Cui }
11715bdfd3fdSDexuan Cui 
11729c6cae24SSepherosa Ziehau static int
11739c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetcaps(struct hn_softc *sc, struct ifreq *ifr)
11749c6cae24SSepherosa Ziehau {
11759c6cae24SSepherosa Ziehau 	struct ifnet *ifp, *vf_ifp;
11769c6cae24SSepherosa Ziehau 	uint64_t tmp;
11779c6cae24SSepherosa Ziehau 	int error;
11789c6cae24SSepherosa Ziehau 
11799c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
11809c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
11819c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
11829c6cae24SSepherosa Ziehau 
11839c6cae24SSepherosa Ziehau 	/*
11849c6cae24SSepherosa Ziehau 	 * Fix up requested capabilities w/ supported capabilities,
11859c6cae24SSepherosa Ziehau 	 * since the supported capabilities could have been changed.
11869c6cae24SSepherosa Ziehau 	 */
11879c6cae24SSepherosa Ziehau 	ifr->ifr_reqcap &= ifp->if_capabilities;
11889c6cae24SSepherosa Ziehau 	/* Pass SIOCSIFCAP to VF. */
11899c6cae24SSepherosa Ziehau 	error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFCAP, (caddr_t)ifr);
11909c6cae24SSepherosa Ziehau 
11919c6cae24SSepherosa Ziehau 	/*
11929c6cae24SSepherosa Ziehau 	 * NOTE:
11939c6cae24SSepherosa Ziehau 	 * The error will be propagated to the callers, however, it
11949c6cae24SSepherosa Ziehau 	 * is _not_ useful here.
11959c6cae24SSepherosa Ziehau 	 */
11969c6cae24SSepherosa Ziehau 
11979c6cae24SSepherosa Ziehau 	/*
11989c6cae24SSepherosa Ziehau 	 * Merge VF's enabled capabilities.
11999c6cae24SSepherosa Ziehau 	 */
12009c6cae24SSepherosa Ziehau 	ifp->if_capenable = vf_ifp->if_capenable & ifp->if_capabilities;
12019c6cae24SSepherosa Ziehau 
12029c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & HN_CSUM_IP_HWASSIST(sc);
12039c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TXCSUM)
12049c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
12059c6cae24SSepherosa Ziehau 	else
12069c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
12079c6cae24SSepherosa Ziehau 
12089c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & HN_CSUM_IP6_HWASSIST(sc);
12099c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
12109c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
12119c6cae24SSepherosa Ziehau 	else
12129c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
12139c6cae24SSepherosa Ziehau 
12149c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & CSUM_IP_TSO;
12159c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TSO4)
12169c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
12179c6cae24SSepherosa Ziehau 	else
12189c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
12199c6cae24SSepherosa Ziehau 
12209c6cae24SSepherosa Ziehau 	tmp = vf_ifp->if_hwassist & CSUM_IP6_TSO;
12219c6cae24SSepherosa Ziehau 	if (ifp->if_capenable & IFCAP_TSO6)
12229c6cae24SSepherosa Ziehau 		ifp->if_hwassist |= tmp;
12239c6cae24SSepherosa Ziehau 	else
12249c6cae24SSepherosa Ziehau 		ifp->if_hwassist &= ~tmp;
12259c6cae24SSepherosa Ziehau 
12269c6cae24SSepherosa Ziehau 	return (error);
12279c6cae24SSepherosa Ziehau }
12289c6cae24SSepherosa Ziehau 
12299c6cae24SSepherosa Ziehau static int
12309c6cae24SSepherosa Ziehau hn_xpnt_vf_iocsetflags(struct hn_softc *sc)
12319c6cae24SSepherosa Ziehau {
12329c6cae24SSepherosa Ziehau 	struct ifnet *vf_ifp;
12339c6cae24SSepherosa Ziehau 	struct ifreq ifr;
12349c6cae24SSepherosa Ziehau 
12359c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
12369c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
12379c6cae24SSepherosa Ziehau 
12389c6cae24SSepherosa Ziehau 	memset(&ifr, 0, sizeof(ifr));
12399c6cae24SSepherosa Ziehau 	strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
12409c6cae24SSepherosa Ziehau 	ifr.ifr_flags = vf_ifp->if_flags & 0xffff;
12419c6cae24SSepherosa Ziehau 	ifr.ifr_flagshigh = vf_ifp->if_flags >> 16;
12429c6cae24SSepherosa Ziehau 	return (vf_ifp->if_ioctl(vf_ifp, SIOCSIFFLAGS, (caddr_t)&ifr));
12439c6cae24SSepherosa Ziehau }
12449c6cae24SSepherosa Ziehau 
12459c6cae24SSepherosa Ziehau static void
12469c6cae24SSepherosa Ziehau hn_xpnt_vf_saveifflags(struct hn_softc *sc)
12479c6cae24SSepherosa Ziehau {
12489c6cae24SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
12499c6cae24SSepherosa Ziehau 	int allmulti = 0;
12509c6cae24SSepherosa Ziehau 
12519c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
12529c6cae24SSepherosa Ziehau 
12539c6cae24SSepherosa Ziehau 	/* XXX vlan(4) style mcast addr maintenance */
12549c6cae24SSepherosa Ziehau 	if (!TAILQ_EMPTY(&ifp->if_multiaddrs))
12559c6cae24SSepherosa Ziehau 		allmulti = IFF_ALLMULTI;
12569c6cae24SSepherosa Ziehau 
12579c6cae24SSepherosa Ziehau 	/* Always set the VF's if_flags */
12589c6cae24SSepherosa Ziehau 	sc->hn_vf_ifp->if_flags = ifp->if_flags | allmulti;
12599c6cae24SSepherosa Ziehau }
12609c6cae24SSepherosa Ziehau 
12619c6cae24SSepherosa Ziehau static void
12629c6cae24SSepherosa Ziehau hn_xpnt_vf_input(struct ifnet *vf_ifp, struct mbuf *m)
12639c6cae24SSepherosa Ziehau {
12649c6cae24SSepherosa Ziehau 	struct rm_priotracker pt;
12659c6cae24SSepherosa Ziehau 	struct ifnet *hn_ifp = NULL;
12669c6cae24SSepherosa Ziehau 	struct mbuf *mn;
12679c6cae24SSepherosa Ziehau 
12689c6cae24SSepherosa Ziehau 	/*
12699c6cae24SSepherosa Ziehau 	 * XXX racy, if hn(4) ever detached.
12709c6cae24SSepherosa Ziehau 	 */
12719c6cae24SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
12729c6cae24SSepherosa Ziehau 	if (vf_ifp->if_index < hn_vfmap_size)
12739c6cae24SSepherosa Ziehau 		hn_ifp = hn_vfmap[vf_ifp->if_index];
12749c6cae24SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
12759c6cae24SSepherosa Ziehau 
12769c6cae24SSepherosa Ziehau 	if (hn_ifp != NULL) {
12779c6cae24SSepherosa Ziehau 		for (mn = m; mn != NULL; mn = mn->m_nextpkt) {
12783bed4e54SSepherosa Ziehau 			/*
12793bed4e54SSepherosa Ziehau 			 * Allow tapping on the VF.
12803bed4e54SSepherosa Ziehau 			 */
12819c6cae24SSepherosa Ziehau 			ETHER_BPF_MTAP(vf_ifp, mn);
12823bed4e54SSepherosa Ziehau 
12833bed4e54SSepherosa Ziehau 			/*
12843bed4e54SSepherosa Ziehau 			 * Update VF stats.
12853bed4e54SSepherosa Ziehau 			 */
12863bed4e54SSepherosa Ziehau 			if ((vf_ifp->if_capenable & IFCAP_HWSTATS) == 0) {
12873bed4e54SSepherosa Ziehau 				if_inc_counter(vf_ifp, IFCOUNTER_IBYTES,
12883bed4e54SSepherosa Ziehau 				    mn->m_pkthdr.len);
12893bed4e54SSepherosa Ziehau 			}
12903bed4e54SSepherosa Ziehau 			/*
12913bed4e54SSepherosa Ziehau 			 * XXX IFCOUNTER_IMCAST
12923bed4e54SSepherosa Ziehau 			 * This stat updating is kinda invasive, since it
12933bed4e54SSepherosa Ziehau 			 * requires two checks on the mbuf: the length check
12943bed4e54SSepherosa Ziehau 			 * and the ethernet header check.  As of this write,
12953bed4e54SSepherosa Ziehau 			 * all multicast packets go directly to hn(4), which
12963bed4e54SSepherosa Ziehau 			 * makes imcast stat updating in the VF a try in vian.
12973bed4e54SSepherosa Ziehau 			 */
12983bed4e54SSepherosa Ziehau 
12993bed4e54SSepherosa Ziehau 			/*
13003bed4e54SSepherosa Ziehau 			 * Fix up rcvif and increase hn(4)'s ipackets.
13013bed4e54SSepherosa Ziehau 			 */
13029c6cae24SSepherosa Ziehau 			mn->m_pkthdr.rcvif = hn_ifp;
13039c6cae24SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1);
13049c6cae24SSepherosa Ziehau 		}
13053bed4e54SSepherosa Ziehau 		/*
13063bed4e54SSepherosa Ziehau 		 * Go through hn(4)'s if_input.
13073bed4e54SSepherosa Ziehau 		 */
13089c6cae24SSepherosa Ziehau 		hn_ifp->if_input(hn_ifp, m);
13099c6cae24SSepherosa Ziehau 	} else {
13109c6cae24SSepherosa Ziehau 		/*
13119c6cae24SSepherosa Ziehau 		 * In the middle of the transition; free this
13129c6cae24SSepherosa Ziehau 		 * mbuf chain.
13139c6cae24SSepherosa Ziehau 		 */
13149c6cae24SSepherosa Ziehau 		while (m != NULL) {
13159c6cae24SSepherosa Ziehau 			mn = m->m_nextpkt;
13169c6cae24SSepherosa Ziehau 			m->m_nextpkt = NULL;
13179c6cae24SSepherosa Ziehau 			m_freem(m);
13189c6cae24SSepherosa Ziehau 			m = mn;
13199c6cae24SSepherosa Ziehau 		}
13209c6cae24SSepherosa Ziehau 	}
13219c6cae24SSepherosa Ziehau }
13229c6cae24SSepherosa Ziehau 
13239c6cae24SSepherosa Ziehau static void
13249c6cae24SSepherosa Ziehau hn_mtu_change_fixup(struct hn_softc *sc)
13259c6cae24SSepherosa Ziehau {
13269c6cae24SSepherosa Ziehau 	struct ifnet *ifp;
13279c6cae24SSepherosa Ziehau 
13289c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
13299c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
13309c6cae24SSepherosa Ziehau 
13319c6cae24SSepherosa Ziehau 	hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu);
13329c6cae24SSepherosa Ziehau #if __FreeBSD_version >= 1100099
13339c6cae24SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_lro.lro_length_lim < HN_LRO_LENLIM_MIN(ifp))
13349c6cae24SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
13359c6cae24SSepherosa Ziehau #endif
13369c6cae24SSepherosa Ziehau }
13379c6cae24SSepherosa Ziehau 
13389c6cae24SSepherosa Ziehau static void
13399c6cae24SSepherosa Ziehau hn_xpnt_vf_setready(struct hn_softc *sc)
13409c6cae24SSepherosa Ziehau {
13419c6cae24SSepherosa Ziehau 	struct ifnet *ifp, *vf_ifp;
13429c6cae24SSepherosa Ziehau 	struct ifreq ifr;
13439c6cae24SSepherosa Ziehau 
13449c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
13459c6cae24SSepherosa Ziehau 	ifp = sc->hn_ifp;
13469c6cae24SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
13479c6cae24SSepherosa Ziehau 
13489c6cae24SSepherosa Ziehau 	/*
13499c6cae24SSepherosa Ziehau 	 * Mark the VF ready.
13509c6cae24SSepherosa Ziehau 	 */
13519c6cae24SSepherosa Ziehau 	sc->hn_vf_rdytick = 0;
13529c6cae24SSepherosa Ziehau 
13539c6cae24SSepherosa Ziehau 	/*
13549c6cae24SSepherosa Ziehau 	 * Save information for restoration.
13559c6cae24SSepherosa Ziehau 	 */
13569c6cae24SSepherosa Ziehau 	sc->hn_saved_caps = ifp->if_capabilities;
13579c6cae24SSepherosa Ziehau 	sc->hn_saved_tsomax = ifp->if_hw_tsomax;
13589c6cae24SSepherosa Ziehau 	sc->hn_saved_tsosegcnt = ifp->if_hw_tsomaxsegcount;
13599c6cae24SSepherosa Ziehau 	sc->hn_saved_tsosegsz = ifp->if_hw_tsomaxsegsize;
13609c6cae24SSepherosa Ziehau 
13619c6cae24SSepherosa Ziehau 	/*
13629c6cae24SSepherosa Ziehau 	 * Intersect supported/enabled capabilities.
13639c6cae24SSepherosa Ziehau 	 *
13649c6cae24SSepherosa Ziehau 	 * NOTE:
13659c6cae24SSepherosa Ziehau 	 * if_hwassist is not changed here.
13669c6cae24SSepherosa Ziehau 	 */
13679c6cae24SSepherosa Ziehau 	ifp->if_capabilities &= vf_ifp->if_capabilities;
13689c6cae24SSepherosa Ziehau 	ifp->if_capenable &= ifp->if_capabilities;
13699c6cae24SSepherosa Ziehau 
13709c6cae24SSepherosa Ziehau 	/*
13719c6cae24SSepherosa Ziehau 	 * Fix TSO settings.
13729c6cae24SSepherosa Ziehau 	 */
13739c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomax > vf_ifp->if_hw_tsomax)
13749c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomax = vf_ifp->if_hw_tsomax;
13759c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomaxsegcount > vf_ifp->if_hw_tsomaxsegcount)
13769c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = vf_ifp->if_hw_tsomaxsegcount;
13779c6cae24SSepherosa Ziehau 	if (ifp->if_hw_tsomaxsegsize > vf_ifp->if_hw_tsomaxsegsize)
13789c6cae24SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = vf_ifp->if_hw_tsomaxsegsize;
13799c6cae24SSepherosa Ziehau 
13809c6cae24SSepherosa Ziehau 	/*
13819c6cae24SSepherosa Ziehau 	 * Change VF's enabled capabilities.
13829c6cae24SSepherosa Ziehau 	 */
13839c6cae24SSepherosa Ziehau 	memset(&ifr, 0, sizeof(ifr));
13849c6cae24SSepherosa Ziehau 	strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
13859c6cae24SSepherosa Ziehau 	ifr.ifr_reqcap = ifp->if_capenable;
13869c6cae24SSepherosa Ziehau 	hn_xpnt_vf_iocsetcaps(sc, &ifr);
13879c6cae24SSepherosa Ziehau 
13889c6cae24SSepherosa Ziehau 	if (ifp->if_mtu != ETHERMTU) {
13899c6cae24SSepherosa Ziehau 		int error;
13909c6cae24SSepherosa Ziehau 
13919c6cae24SSepherosa Ziehau 		/*
13929c6cae24SSepherosa Ziehau 		 * Change VF's MTU.
13939c6cae24SSepherosa Ziehau 		 */
13949c6cae24SSepherosa Ziehau 		memset(&ifr, 0, sizeof(ifr));
13959c6cae24SSepherosa Ziehau 		strlcpy(ifr.ifr_name, vf_ifp->if_xname, sizeof(ifr.ifr_name));
13969c6cae24SSepherosa Ziehau 		ifr.ifr_mtu = ifp->if_mtu;
13979c6cae24SSepherosa Ziehau 		error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU, (caddr_t)&ifr);
13989c6cae24SSepherosa Ziehau 		if (error) {
13999c6cae24SSepherosa Ziehau 			if_printf(ifp, "%s SIOCSIFMTU %u failed\n",
14009c6cae24SSepherosa Ziehau 			    vf_ifp->if_xname, ifp->if_mtu);
14019c6cae24SSepherosa Ziehau 			if (ifp->if_mtu > ETHERMTU) {
14029c6cae24SSepherosa Ziehau 				if_printf(ifp, "change MTU to %d\n", ETHERMTU);
14039c6cae24SSepherosa Ziehau 
14049c6cae24SSepherosa Ziehau 				/*
14059c6cae24SSepherosa Ziehau 				 * XXX
14069c6cae24SSepherosa Ziehau 				 * No need to adjust the synthetic parts' MTU;
14079c6cae24SSepherosa Ziehau 				 * failure of the adjustment will cause us
14089c6cae24SSepherosa Ziehau 				 * infinite headache.
14099c6cae24SSepherosa Ziehau 				 */
14109c6cae24SSepherosa Ziehau 				ifp->if_mtu = ETHERMTU;
14119c6cae24SSepherosa Ziehau 				hn_mtu_change_fixup(sc);
14129c6cae24SSepherosa Ziehau 			}
14139c6cae24SSepherosa Ziehau 		}
14149c6cae24SSepherosa Ziehau 	}
14159c6cae24SSepherosa Ziehau }
14169c6cae24SSepherosa Ziehau 
14179c6cae24SSepherosa Ziehau static bool
14189c6cae24SSepherosa Ziehau hn_xpnt_vf_isready(struct hn_softc *sc)
14199c6cae24SSepherosa Ziehau {
14209c6cae24SSepherosa Ziehau 
14219c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
14229c6cae24SSepherosa Ziehau 
14239c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf || sc->hn_vf_ifp == NULL)
14249c6cae24SSepherosa Ziehau 		return (false);
14259c6cae24SSepherosa Ziehau 
14269c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick == 0)
14279c6cae24SSepherosa Ziehau 		return (true);
14289c6cae24SSepherosa Ziehau 
14299c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick > ticks)
14309c6cae24SSepherosa Ziehau 		return (false);
14319c6cae24SSepherosa Ziehau 
14329c6cae24SSepherosa Ziehau 	/* Mark VF as ready. */
14339c6cae24SSepherosa Ziehau 	hn_xpnt_vf_setready(sc);
14349c6cae24SSepherosa Ziehau 	return (true);
14359c6cae24SSepherosa Ziehau }
14369c6cae24SSepherosa Ziehau 
14379c6cae24SSepherosa Ziehau static void
1438a97fff19SSepherosa Ziehau hn_xpnt_vf_setenable(struct hn_softc *sc)
1439a97fff19SSepherosa Ziehau {
1440a97fff19SSepherosa Ziehau 	int i;
1441a97fff19SSepherosa Ziehau 
1442a97fff19SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1443a97fff19SSepherosa Ziehau 
1444a97fff19SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
1445a97fff19SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
1446a97fff19SSepherosa Ziehau 	sc->hn_xvf_flags |= HN_XVFFLAG_ENABLED;
1447a97fff19SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
1448a97fff19SSepherosa Ziehau 
1449a97fff19SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1450a97fff19SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_rx_flags |= HN_RX_FLAG_XPNT_VF;
1451a97fff19SSepherosa Ziehau }
1452a97fff19SSepherosa Ziehau 
1453a97fff19SSepherosa Ziehau static void
1454a97fff19SSepherosa Ziehau hn_xpnt_vf_setdisable(struct hn_softc *sc, bool clear_vf)
1455a97fff19SSepherosa Ziehau {
1456a97fff19SSepherosa Ziehau 	int i;
1457a97fff19SSepherosa Ziehau 
1458a97fff19SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
1459a97fff19SSepherosa Ziehau 
1460a97fff19SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
1461a97fff19SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
1462a97fff19SSepherosa Ziehau 	sc->hn_xvf_flags &= ~HN_XVFFLAG_ENABLED;
1463a97fff19SSepherosa Ziehau 	if (clear_vf)
1464a97fff19SSepherosa Ziehau 		sc->hn_vf_ifp = NULL;
1465a97fff19SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
1466a97fff19SSepherosa Ziehau 
1467a97fff19SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
1468a97fff19SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_rx_flags &= ~HN_RX_FLAG_XPNT_VF;
1469a97fff19SSepherosa Ziehau }
1470a97fff19SSepherosa Ziehau 
1471a97fff19SSepherosa Ziehau static void
14729c6cae24SSepherosa Ziehau hn_xpnt_vf_init(struct hn_softc *sc)
14739c6cae24SSepherosa Ziehau {
14749c6cae24SSepherosa Ziehau 	int error;
14759c6cae24SSepherosa Ziehau 
14769c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
14779c6cae24SSepherosa Ziehau 
14789c6cae24SSepherosa Ziehau 	KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0,
14799c6cae24SSepherosa Ziehau 	    ("%s: transparent VF was enabled", sc->hn_ifp->if_xname));
14809c6cae24SSepherosa Ziehau 
14819c6cae24SSepherosa Ziehau 	if (bootverbose) {
14829c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "try bringing up %s\n",
14839c6cae24SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname);
14849c6cae24SSepherosa Ziehau 	}
14859c6cae24SSepherosa Ziehau 
14869c6cae24SSepherosa Ziehau 	/*
14879c6cae24SSepherosa Ziehau 	 * Bring the VF up.
14889c6cae24SSepherosa Ziehau 	 */
14899c6cae24SSepherosa Ziehau 	hn_xpnt_vf_saveifflags(sc);
14909c6cae24SSepherosa Ziehau 	sc->hn_vf_ifp->if_flags |= IFF_UP;
14919c6cae24SSepherosa Ziehau 	error = hn_xpnt_vf_iocsetflags(sc);
14929c6cae24SSepherosa Ziehau 	if (error) {
14939c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "bringing up %s failed: %d\n",
14949c6cae24SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname, error);
14959c6cae24SSepherosa Ziehau 		return;
14969c6cae24SSepherosa Ziehau 	}
14979c6cae24SSepherosa Ziehau 
14989c6cae24SSepherosa Ziehau 	/*
14999c6cae24SSepherosa Ziehau 	 * NOTE:
15009c6cae24SSepherosa Ziehau 	 * Datapath setting must happen _after_ bringing the VF up.
15019c6cae24SSepherosa Ziehau 	 */
15029c6cae24SSepherosa Ziehau 	hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF);
15039c6cae24SSepherosa Ziehau 
1504a97fff19SSepherosa Ziehau 	/* Mark transparent mode VF as enabled. */
1505a97fff19SSepherosa Ziehau 	hn_xpnt_vf_setenable(sc);
15069c6cae24SSepherosa Ziehau }
15079c6cae24SSepherosa Ziehau 
15089c6cae24SSepherosa Ziehau static void
15099c6cae24SSepherosa Ziehau hn_xpnt_vf_init_taskfunc(void *xsc, int pending __unused)
15109c6cae24SSepherosa Ziehau {
15119c6cae24SSepherosa Ziehau 	struct hn_softc *sc = xsc;
15129c6cae24SSepherosa Ziehau 
15139c6cae24SSepherosa Ziehau 	HN_LOCK(sc);
15149c6cae24SSepherosa Ziehau 
15159c6cae24SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
15169c6cae24SSepherosa Ziehau 		goto done;
15179c6cae24SSepherosa Ziehau 	if (sc->hn_vf_ifp == NULL)
15189c6cae24SSepherosa Ziehau 		goto done;
15199c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
15209c6cae24SSepherosa Ziehau 		goto done;
15219c6cae24SSepherosa Ziehau 
15229c6cae24SSepherosa Ziehau 	if (sc->hn_vf_rdytick != 0) {
15239c6cae24SSepherosa Ziehau 		/* Mark VF as ready. */
15249c6cae24SSepherosa Ziehau 		hn_xpnt_vf_setready(sc);
15259c6cae24SSepherosa Ziehau 	}
15269c6cae24SSepherosa Ziehau 
15279c6cae24SSepherosa Ziehau 	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) {
15289c6cae24SSepherosa Ziehau 		/*
15299c6cae24SSepherosa Ziehau 		 * Delayed VF initialization.
15309c6cae24SSepherosa Ziehau 		 */
15319c6cae24SSepherosa Ziehau 		if (bootverbose) {
15329c6cae24SSepherosa Ziehau 			if_printf(sc->hn_ifp, "delayed initialize %s\n",
15339c6cae24SSepherosa Ziehau 			    sc->hn_vf_ifp->if_xname);
15349c6cae24SSepherosa Ziehau 		}
15359c6cae24SSepherosa Ziehau 		hn_xpnt_vf_init(sc);
15369c6cae24SSepherosa Ziehau 	}
15379c6cae24SSepherosa Ziehau done:
15389c6cae24SSepherosa Ziehau 	HN_UNLOCK(sc);
15399c6cae24SSepherosa Ziehau }
15409c6cae24SSepherosa Ziehau 
1541499c3e17SSepherosa Ziehau static void
1542499c3e17SSepherosa Ziehau hn_ifnet_attevent(void *xsc, struct ifnet *ifp)
1543499c3e17SSepherosa Ziehau {
1544499c3e17SSepherosa Ziehau 	struct hn_softc *sc = xsc;
1545499c3e17SSepherosa Ziehau 
1546499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
1547499c3e17SSepherosa Ziehau 
1548499c3e17SSepherosa Ziehau 	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
1549499c3e17SSepherosa Ziehau 		goto done;
1550499c3e17SSepherosa Ziehau 
1551499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1552499c3e17SSepherosa Ziehau 		goto done;
1553499c3e17SSepherosa Ziehau 
1554499c3e17SSepherosa Ziehau 	if (sc->hn_vf_ifp != NULL) {
1555499c3e17SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%s was attached as VF\n",
1556499c3e17SSepherosa Ziehau 		    sc->hn_vf_ifp->if_xname);
1557499c3e17SSepherosa Ziehau 		goto done;
1558499c3e17SSepherosa Ziehau 	}
1559499c3e17SSepherosa Ziehau 
15609c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && ifp->if_start != NULL) {
15619c6cae24SSepherosa Ziehau 		/*
15629c6cae24SSepherosa Ziehau 		 * ifnet.if_start is _not_ supported by transparent
15639c6cae24SSepherosa Ziehau 		 * mode VF; mainly due to the IFF_DRV_OACTIVE flag.
15649c6cae24SSepherosa Ziehau 		 */
15659c6cae24SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%s uses if_start, which is unsupported "
15669c6cae24SSepherosa Ziehau 		    "in transparent VF mode.\n", ifp->if_xname);
15679c6cae24SSepherosa Ziehau 		goto done;
15689c6cae24SSepherosa Ziehau 	}
15699c6cae24SSepherosa Ziehau 
1570499c3e17SSepherosa Ziehau 	rm_wlock(&hn_vfmap_lock);
1571499c3e17SSepherosa Ziehau 
1572499c3e17SSepherosa Ziehau 	if (ifp->if_index >= hn_vfmap_size) {
1573499c3e17SSepherosa Ziehau 		struct ifnet **newmap;
1574499c3e17SSepherosa Ziehau 		int newsize;
1575499c3e17SSepherosa Ziehau 
1576499c3e17SSepherosa Ziehau 		newsize = ifp->if_index + HN_VFMAP_SIZE_DEF;
1577499c3e17SSepherosa Ziehau 		newmap = malloc(sizeof(struct ifnet *) * newsize, M_DEVBUF,
1578499c3e17SSepherosa Ziehau 		    M_WAITOK | M_ZERO);
1579499c3e17SSepherosa Ziehau 
1580499c3e17SSepherosa Ziehau 		memcpy(newmap, hn_vfmap,
1581499c3e17SSepherosa Ziehau 		    sizeof(struct ifnet *) * hn_vfmap_size);
1582499c3e17SSepherosa Ziehau 		free(hn_vfmap, M_DEVBUF);
1583499c3e17SSepherosa Ziehau 		hn_vfmap = newmap;
1584499c3e17SSepherosa Ziehau 		hn_vfmap_size = newsize;
1585499c3e17SSepherosa Ziehau 	}
1586499c3e17SSepherosa Ziehau 	KASSERT(hn_vfmap[ifp->if_index] == NULL,
1587499c3e17SSepherosa Ziehau 	    ("%s: ifindex %d was mapped to %s",
1588499c3e17SSepherosa Ziehau 	     ifp->if_xname, ifp->if_index, hn_vfmap[ifp->if_index]->if_xname));
1589499c3e17SSepherosa Ziehau 	hn_vfmap[ifp->if_index] = sc->hn_ifp;
1590499c3e17SSepherosa Ziehau 
1591499c3e17SSepherosa Ziehau 	rm_wunlock(&hn_vfmap_lock);
1592499c3e17SSepherosa Ziehau 
15939c6cae24SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit()/hn_qflush() */
15949c6cae24SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
15959c6cae24SSepherosa Ziehau 	KASSERT((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) == 0,
15969c6cae24SSepherosa Ziehau 	    ("%s: transparent VF was enabled", sc->hn_ifp->if_xname));
1597499c3e17SSepherosa Ziehau 	sc->hn_vf_ifp = ifp;
15989c6cae24SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
15999c6cae24SSepherosa Ziehau 
16009c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
16019c6cae24SSepherosa Ziehau 		int wait_ticks;
16029c6cae24SSepherosa Ziehau 
16039c6cae24SSepherosa Ziehau 		/*
16049c6cae24SSepherosa Ziehau 		 * Install if_input for vf_ifp, which does vf_ifp -> hn_ifp.
16059c6cae24SSepherosa Ziehau 		 * Save vf_ifp's current if_input for later restoration.
16069c6cae24SSepherosa Ziehau 		 */
16079c6cae24SSepherosa Ziehau 		sc->hn_vf_input = ifp->if_input;
16089c6cae24SSepherosa Ziehau 		ifp->if_input = hn_xpnt_vf_input;
16099c6cae24SSepherosa Ziehau 
16109c6cae24SSepherosa Ziehau 		/*
16119c6cae24SSepherosa Ziehau 		 * Stop link status management; use the VF's.
16129c6cae24SSepherosa Ziehau 		 */
16139c6cae24SSepherosa Ziehau 		hn_suspend_mgmt(sc);
16149c6cae24SSepherosa Ziehau 
16159c6cae24SSepherosa Ziehau 		/*
16169c6cae24SSepherosa Ziehau 		 * Give VF sometime to complete its attach routing.
16179c6cae24SSepherosa Ziehau 		 */
16189c6cae24SSepherosa Ziehau 		wait_ticks = hn_xpnt_vf_attwait * hz;
16199c6cae24SSepherosa Ziehau 		sc->hn_vf_rdytick = ticks + wait_ticks;
16209c6cae24SSepherosa Ziehau 
16219c6cae24SSepherosa Ziehau 		taskqueue_enqueue_timeout(sc->hn_vf_taskq, &sc->hn_vf_init,
16229c6cae24SSepherosa Ziehau 		    wait_ticks);
16239c6cae24SSepherosa Ziehau 	}
1624499c3e17SSepherosa Ziehau done:
1625499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
1626499c3e17SSepherosa Ziehau }
1627499c3e17SSepherosa Ziehau 
1628499c3e17SSepherosa Ziehau static void
1629499c3e17SSepherosa Ziehau hn_ifnet_detevent(void *xsc, struct ifnet *ifp)
1630499c3e17SSepherosa Ziehau {
1631499c3e17SSepherosa Ziehau 	struct hn_softc *sc = xsc;
1632499c3e17SSepherosa Ziehau 
1633499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
1634499c3e17SSepherosa Ziehau 
1635499c3e17SSepherosa Ziehau 	if (sc->hn_vf_ifp == NULL)
1636499c3e17SSepherosa Ziehau 		goto done;
1637499c3e17SSepherosa Ziehau 
1638499c3e17SSepherosa Ziehau 	if (!hn_ismyvf(sc, ifp))
1639499c3e17SSepherosa Ziehau 		goto done;
1640499c3e17SSepherosa Ziehau 
16419c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
16429c6cae24SSepherosa Ziehau 		/*
16439c6cae24SSepherosa Ziehau 		 * Make sure that the delayed initialization is not running.
16449c6cae24SSepherosa Ziehau 		 *
16459c6cae24SSepherosa Ziehau 		 * NOTE:
16469c6cae24SSepherosa Ziehau 		 * - This lock _must_ be released, since the hn_vf_init task
16479c6cae24SSepherosa Ziehau 		 *   will try holding this lock.
16489c6cae24SSepherosa Ziehau 		 * - It is safe to release this lock here, since the
16499c6cae24SSepherosa Ziehau 		 *   hn_ifnet_attevent() is interlocked by the hn_vf_ifp.
16509c6cae24SSepherosa Ziehau 		 *
16519c6cae24SSepherosa Ziehau 		 * XXX racy, if hn(4) ever detached.
16529c6cae24SSepherosa Ziehau 		 */
16539c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
16549c6cae24SSepherosa Ziehau 		taskqueue_drain_timeout(sc->hn_vf_taskq, &sc->hn_vf_init);
16559c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
16569c6cae24SSepherosa Ziehau 
16579c6cae24SSepherosa Ziehau 		KASSERT(sc->hn_vf_input != NULL, ("%s VF input is not saved",
16589c6cae24SSepherosa Ziehau 		    sc->hn_ifp->if_xname));
16599c6cae24SSepherosa Ziehau 		ifp->if_input = sc->hn_vf_input;
16609c6cae24SSepherosa Ziehau 		sc->hn_vf_input = NULL;
16619c6cae24SSepherosa Ziehau 
16629c6cae24SSepherosa Ziehau 		if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
16639c6cae24SSepherosa Ziehau 			hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH);
16649c6cae24SSepherosa Ziehau 
16659c6cae24SSepherosa Ziehau 		if (sc->hn_vf_rdytick == 0) {
16669c6cae24SSepherosa Ziehau 			/*
16679c6cae24SSepherosa Ziehau 			 * The VF was ready; restore some settings.
16689c6cae24SSepherosa Ziehau 			 */
16699c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_capabilities = sc->hn_saved_caps;
16709c6cae24SSepherosa Ziehau 			/*
16719c6cae24SSepherosa Ziehau 			 * NOTE:
16729c6cae24SSepherosa Ziehau 			 * There is _no_ need to fixup if_capenable and
16739c6cae24SSepherosa Ziehau 			 * if_hwassist, since the if_capabilities before
16749c6cae24SSepherosa Ziehau 			 * restoration was an intersection of the VF's
16759c6cae24SSepherosa Ziehau 			 * if_capabilites and the synthetic device's
16769c6cae24SSepherosa Ziehau 			 * if_capabilites.
16779c6cae24SSepherosa Ziehau 			 */
16789c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomax = sc->hn_saved_tsomax;
16799c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomaxsegcount =
16809c6cae24SSepherosa Ziehau 			    sc->hn_saved_tsosegcnt;
16819c6cae24SSepherosa Ziehau 			sc->hn_ifp->if_hw_tsomaxsegsize = sc->hn_saved_tsosegsz;
16829c6cae24SSepherosa Ziehau 		}
16839c6cae24SSepherosa Ziehau 
16849c6cae24SSepherosa Ziehau 		/*
16859c6cae24SSepherosa Ziehau 		 * Resume link status management, which was suspended
16869c6cae24SSepherosa Ziehau 		 * by hn_ifnet_attevent().
16879c6cae24SSepherosa Ziehau 		 */
16889c6cae24SSepherosa Ziehau 		hn_resume_mgmt(sc);
16899c6cae24SSepherosa Ziehau 	}
16909c6cae24SSepherosa Ziehau 
1691a97fff19SSepherosa Ziehau 	/* Mark transparent mode VF as disabled. */
1692a97fff19SSepherosa Ziehau 	hn_xpnt_vf_setdisable(sc, true /* clear hn_vf_ifp */);
1693499c3e17SSepherosa Ziehau 
1694499c3e17SSepherosa Ziehau 	rm_wlock(&hn_vfmap_lock);
1695499c3e17SSepherosa Ziehau 
1696499c3e17SSepherosa Ziehau 	KASSERT(ifp->if_index < hn_vfmap_size,
1697499c3e17SSepherosa Ziehau 	    ("ifindex %d, vfmapsize %d", ifp->if_index, hn_vfmap_size));
1698499c3e17SSepherosa Ziehau 	if (hn_vfmap[ifp->if_index] != NULL) {
1699499c3e17SSepherosa Ziehau 		KASSERT(hn_vfmap[ifp->if_index] == sc->hn_ifp,
1700499c3e17SSepherosa Ziehau 		    ("%s: ifindex %d was mapped to %s",
1701499c3e17SSepherosa Ziehau 		     ifp->if_xname, ifp->if_index,
1702499c3e17SSepherosa Ziehau 		     hn_vfmap[ifp->if_index]->if_xname));
1703499c3e17SSepherosa Ziehau 		hn_vfmap[ifp->if_index] = NULL;
1704499c3e17SSepherosa Ziehau 	}
1705499c3e17SSepherosa Ziehau 
1706499c3e17SSepherosa Ziehau 	rm_wunlock(&hn_vfmap_lock);
1707499c3e17SSepherosa Ziehau done:
1708499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
1709499c3e17SSepherosa Ziehau }
1710499c3e17SSepherosa Ziehau 
17119c6cae24SSepherosa Ziehau static void
17129c6cae24SSepherosa Ziehau hn_ifnet_lnkevent(void *xsc, struct ifnet *ifp, int link_state)
17139c6cae24SSepherosa Ziehau {
17149c6cae24SSepherosa Ziehau 	struct hn_softc *sc = xsc;
17159c6cae24SSepherosa Ziehau 
17169c6cae24SSepherosa Ziehau 	if (sc->hn_vf_ifp == ifp)
17179c6cae24SSepherosa Ziehau 		if_link_state_change(sc->hn_ifp, link_state);
17189c6cae24SSepherosa Ziehau }
17199c6cae24SSepherosa Ziehau 
172015516c77SSepherosa Ziehau static int
172115516c77SSepherosa Ziehau hn_probe(device_t dev)
172215516c77SSepherosa Ziehau {
172315516c77SSepherosa Ziehau 
1724c2d50b26SSepherosa Ziehau 	if (VMBUS_PROBE_GUID(device_get_parent(dev), dev, &hn_guid) == 0) {
172515516c77SSepherosa Ziehau 		device_set_desc(dev, "Hyper-V Network Interface");
172615516c77SSepherosa Ziehau 		return BUS_PROBE_DEFAULT;
172715516c77SSepherosa Ziehau 	}
172815516c77SSepherosa Ziehau 	return ENXIO;
172915516c77SSepherosa Ziehau }
173015516c77SSepherosa Ziehau 
173115516c77SSepherosa Ziehau static int
173215516c77SSepherosa Ziehau hn_attach(device_t dev)
173315516c77SSepherosa Ziehau {
173415516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
173515516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
173615516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
173715516c77SSepherosa Ziehau 	uint8_t eaddr[ETHER_ADDR_LEN];
173815516c77SSepherosa Ziehau 	struct ifnet *ifp = NULL;
173915516c77SSepherosa Ziehau 	int error, ring_cnt, tx_ring_cnt;
174015516c77SSepherosa Ziehau 
174115516c77SSepherosa Ziehau 	sc->hn_dev = dev;
174215516c77SSepherosa Ziehau 	sc->hn_prichan = vmbus_get_channel(dev);
174315516c77SSepherosa Ziehau 	HN_LOCK_INIT(sc);
17449c6cae24SSepherosa Ziehau 	rm_init(&sc->hn_vf_lock, "hnvf");
17459c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && hn_xpnt_vf_accbpf)
17469c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF;
174715516c77SSepherosa Ziehau 
174815516c77SSepherosa Ziehau 	/*
1749dc13fee6SSepherosa Ziehau 	 * Initialize these tunables once.
1750dc13fee6SSepherosa Ziehau 	 */
1751dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = hn_tx_agg_size;
1752dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = hn_tx_agg_pkts;
1753dc13fee6SSepherosa Ziehau 
1754dc13fee6SSepherosa Ziehau 	/*
175515516c77SSepherosa Ziehau 	 * Setup taskqueue for transmission.
175615516c77SSepherosa Ziehau 	 */
17570e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_INDEP) {
1758fdd0222aSSepherosa Ziehau 		int i;
1759fdd0222aSSepherosa Ziehau 
1760fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs =
1761fdd0222aSSepherosa Ziehau 		    malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
1762fdd0222aSSepherosa Ziehau 		    M_DEVBUF, M_WAITOK);
1763fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i) {
1764fdd0222aSSepherosa Ziehau 			sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx",
1765fdd0222aSSepherosa Ziehau 			    M_WAITOK, taskqueue_thread_enqueue,
1766fdd0222aSSepherosa Ziehau 			    &sc->hn_tx_taskqs[i]);
1767fdd0222aSSepherosa Ziehau 			taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET,
1768fdd0222aSSepherosa Ziehau 			    "%s tx%d", device_get_nameunit(dev), i);
1769fdd0222aSSepherosa Ziehau 		}
17700e11868dSSepherosa Ziehau 	} else if (hn_tx_taskq_mode == HN_TX_TASKQ_M_GLOBAL) {
1771fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs = hn_tx_taskque;
177215516c77SSepherosa Ziehau 	}
177315516c77SSepherosa Ziehau 
177415516c77SSepherosa Ziehau 	/*
177515516c77SSepherosa Ziehau 	 * Setup taskqueue for mangement tasks, e.g. link status.
177615516c77SSepherosa Ziehau 	 */
177715516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK,
177815516c77SSepherosa Ziehau 	    taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0);
177915516c77SSepherosa Ziehau 	taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
178015516c77SSepherosa Ziehau 	    device_get_nameunit(dev));
178115516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
178215516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc);
178315516c77SSepherosa Ziehau 	TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0,
178415516c77SSepherosa Ziehau 	    hn_netchg_status_taskfunc, sc);
178515516c77SSepherosa Ziehau 
17869c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf) {
17879c6cae24SSepherosa Ziehau 		/*
17889c6cae24SSepherosa Ziehau 		 * Setup taskqueue for VF tasks, e.g. delayed VF bringing up.
17899c6cae24SSepherosa Ziehau 		 */
17909c6cae24SSepherosa Ziehau 		sc->hn_vf_taskq = taskqueue_create("hn_vf", M_WAITOK,
17919c6cae24SSepherosa Ziehau 		    taskqueue_thread_enqueue, &sc->hn_vf_taskq);
17929c6cae24SSepherosa Ziehau 		taskqueue_start_threads(&sc->hn_vf_taskq, 1, PI_NET, "%s vf",
17939c6cae24SSepherosa Ziehau 		    device_get_nameunit(dev));
17949c6cae24SSepherosa Ziehau 		TIMEOUT_TASK_INIT(sc->hn_vf_taskq, &sc->hn_vf_init, 0,
17959c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_init_taskfunc, sc);
17969c6cae24SSepherosa Ziehau 	}
17979c6cae24SSepherosa Ziehau 
179815516c77SSepherosa Ziehau 	/*
179915516c77SSepherosa Ziehau 	 * Allocate ifnet and setup its name earlier, so that if_printf
180015516c77SSepherosa Ziehau 	 * can be used by functions, which will be called after
180115516c77SSepherosa Ziehau 	 * ether_ifattach().
180215516c77SSepherosa Ziehau 	 */
180315516c77SSepherosa Ziehau 	ifp = sc->hn_ifp = if_alloc(IFT_ETHER);
180415516c77SSepherosa Ziehau 	ifp->if_softc = sc;
180515516c77SSepherosa Ziehau 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
180615516c77SSepherosa Ziehau 
180715516c77SSepherosa Ziehau 	/*
180815516c77SSepherosa Ziehau 	 * Initialize ifmedia earlier so that it can be unconditionally
180915516c77SSepherosa Ziehau 	 * destroyed, if error happened later on.
181015516c77SSepherosa Ziehau 	 */
181115516c77SSepherosa Ziehau 	ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts);
181215516c77SSepherosa Ziehau 
181315516c77SSepherosa Ziehau 	/*
181415516c77SSepherosa Ziehau 	 * Figure out the # of RX rings (ring_cnt) and the # of TX rings
181515516c77SSepherosa Ziehau 	 * to use (tx_ring_cnt).
181615516c77SSepherosa Ziehau 	 *
181715516c77SSepherosa Ziehau 	 * NOTE:
181815516c77SSepherosa Ziehau 	 * The # of RX rings to use is same as the # of channels to use.
181915516c77SSepherosa Ziehau 	 */
182015516c77SSepherosa Ziehau 	ring_cnt = hn_chan_cnt;
182115516c77SSepherosa Ziehau 	if (ring_cnt <= 0) {
182215516c77SSepherosa Ziehau 		/* Default */
182315516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
182415516c77SSepherosa Ziehau 		if (ring_cnt > HN_RING_CNT_DEF_MAX)
182515516c77SSepherosa Ziehau 			ring_cnt = HN_RING_CNT_DEF_MAX;
182615516c77SSepherosa Ziehau 	} else if (ring_cnt > mp_ncpus) {
182715516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
182815516c77SSepherosa Ziehau 	}
182934d68912SSepherosa Ziehau #ifdef RSS
183034d68912SSepherosa Ziehau 	if (ring_cnt > rss_getnumbuckets())
183134d68912SSepherosa Ziehau 		ring_cnt = rss_getnumbuckets();
183234d68912SSepherosa Ziehau #endif
183315516c77SSepherosa Ziehau 
183415516c77SSepherosa Ziehau 	tx_ring_cnt = hn_tx_ring_cnt;
183515516c77SSepherosa Ziehau 	if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt)
183615516c77SSepherosa Ziehau 		tx_ring_cnt = ring_cnt;
183723bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
183815516c77SSepherosa Ziehau 	if (hn_use_if_start) {
183915516c77SSepherosa Ziehau 		/* ifnet.if_start only needs one TX ring. */
184015516c77SSepherosa Ziehau 		tx_ring_cnt = 1;
184115516c77SSepherosa Ziehau 	}
184223bf9e15SSepherosa Ziehau #endif
184315516c77SSepherosa Ziehau 
184415516c77SSepherosa Ziehau 	/*
184515516c77SSepherosa Ziehau 	 * Set the leader CPU for channels.
184615516c77SSepherosa Ziehau 	 */
184715516c77SSepherosa Ziehau 	sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus;
184815516c77SSepherosa Ziehau 
184915516c77SSepherosa Ziehau 	/*
185015516c77SSepherosa Ziehau 	 * Create enough TX/RX rings, even if only limited number of
185115516c77SSepherosa Ziehau 	 * channels can be allocated.
185215516c77SSepherosa Ziehau 	 */
185315516c77SSepherosa Ziehau 	error = hn_create_tx_data(sc, tx_ring_cnt);
185415516c77SSepherosa Ziehau 	if (error)
185515516c77SSepherosa Ziehau 		goto failed;
185615516c77SSepherosa Ziehau 	error = hn_create_rx_data(sc, ring_cnt);
185715516c77SSepherosa Ziehau 	if (error)
185815516c77SSepherosa Ziehau 		goto failed;
185915516c77SSepherosa Ziehau 
186015516c77SSepherosa Ziehau 	/*
186115516c77SSepherosa Ziehau 	 * Create transaction context for NVS and RNDIS transactions.
186215516c77SSepherosa Ziehau 	 */
186315516c77SSepherosa Ziehau 	sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
186415516c77SSepherosa Ziehau 	    HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
186525641fc7SSepherosa Ziehau 	if (sc->hn_xact == NULL) {
186625641fc7SSepherosa Ziehau 		error = ENXIO;
186715516c77SSepherosa Ziehau 		goto failed;
186825641fc7SSepherosa Ziehau 	}
186925641fc7SSepherosa Ziehau 
187025641fc7SSepherosa Ziehau 	/*
187125641fc7SSepherosa Ziehau 	 * Install orphan handler for the revocation of this device's
187225641fc7SSepherosa Ziehau 	 * primary channel.
187325641fc7SSepherosa Ziehau 	 *
187425641fc7SSepherosa Ziehau 	 * NOTE:
187525641fc7SSepherosa Ziehau 	 * The processing order is critical here:
187625641fc7SSepherosa Ziehau 	 * Install the orphan handler, _before_ testing whether this
187725641fc7SSepherosa Ziehau 	 * device's primary channel has been revoked or not.
187825641fc7SSepherosa Ziehau 	 */
187925641fc7SSepherosa Ziehau 	vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact);
188025641fc7SSepherosa Ziehau 	if (vmbus_chan_is_revoked(sc->hn_prichan)) {
188125641fc7SSepherosa Ziehau 		error = ENXIO;
188225641fc7SSepherosa Ziehau 		goto failed;
188325641fc7SSepherosa Ziehau 	}
188415516c77SSepherosa Ziehau 
188515516c77SSepherosa Ziehau 	/*
188615516c77SSepherosa Ziehau 	 * Attach the synthetic parts, i.e. NVS and RNDIS.
188715516c77SSepherosa Ziehau 	 */
188815516c77SSepherosa Ziehau 	error = hn_synth_attach(sc, ETHERMTU);
188915516c77SSepherosa Ziehau 	if (error)
189015516c77SSepherosa Ziehau 		goto failed;
189115516c77SSepherosa Ziehau 
189215516c77SSepherosa Ziehau 	error = hn_rndis_get_eaddr(sc, eaddr);
189315516c77SSepherosa Ziehau 	if (error)
189415516c77SSepherosa Ziehau 		goto failed;
189515516c77SSepherosa Ziehau 
189615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
189715516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
189815516c77SSepherosa Ziehau 		/*
189915516c77SSepherosa Ziehau 		 * Reduce TCP segment aggregation limit for multiple
190015516c77SSepherosa Ziehau 		 * RX rings to increase ACK timeliness.
190115516c77SSepherosa Ziehau 		 */
190215516c77SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF);
190315516c77SSepherosa Ziehau 	}
190415516c77SSepherosa Ziehau #endif
190515516c77SSepherosa Ziehau 
190615516c77SSepherosa Ziehau 	/*
190715516c77SSepherosa Ziehau 	 * Fixup TX stuffs after synthetic parts are attached.
190815516c77SSepherosa Ziehau 	 */
190915516c77SSepherosa Ziehau 	hn_fixup_tx_data(sc);
191015516c77SSepherosa Ziehau 
191115516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
191215516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
191315516c77SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD,
191415516c77SSepherosa Ziehau 	    &sc->hn_nvs_ver, 0, "NVS version");
191515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version",
191615516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
191715516c77SSepherosa Ziehau 	    hn_ndis_version_sysctl, "A", "NDIS version");
191815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps",
191915516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
192015516c77SSepherosa Ziehau 	    hn_caps_sysctl, "A", "capabilities");
192115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist",
192215516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
192315516c77SSepherosa Ziehau 	    hn_hwassist_sysctl, "A", "hwassist");
19249c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_max",
19259c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomax, 0, "max TSO size");
19269c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegcnt",
19279c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomaxsegcount, 0,
19289c6cae24SSepherosa Ziehau 	    "max # of TSO segments");
19299c6cae24SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tso_maxsegsz",
19309c6cae24SSepherosa Ziehau 	    CTLFLAG_RD, &ifp->if_hw_tsomaxsegsize, 0,
19319c6cae24SSepherosa Ziehau 	    "max size of TSO segment");
193215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter",
193315516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
193415516c77SSepherosa Ziehau 	    hn_rxfilter_sysctl, "A", "rxfilter");
193515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash",
193615516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
193715516c77SSepherosa Ziehau 	    hn_rss_hash_sysctl, "A", "RSS hash");
193815516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size",
193915516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count");
194034d68912SSepherosa Ziehau #ifndef RSS
194134d68912SSepherosa Ziehau 	/*
194234d68912SSepherosa Ziehau 	 * Don't allow RSS key/indirect table changes, if RSS is defined.
194334d68912SSepherosa Ziehau 	 */
194415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key",
194515516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
194615516c77SSepherosa Ziehau 	    hn_rss_key_sysctl, "IU", "RSS key");
194715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind",
194815516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
194915516c77SSepherosa Ziehau 	    hn_rss_ind_sysctl, "IU", "RSS indirect table");
195034d68912SSepherosa Ziehau #endif
1951dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size",
1952dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_size, 0,
1953dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation size limit");
1954dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts",
1955dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0,
1956dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation count limit");
1957dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align",
1958dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_align, 0,
1959dc13fee6SSepherosa Ziehau 	    "RNDIS packet transmission aggregation alignment");
1960dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size",
1961dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
1962dc13fee6SSepherosa Ziehau 	    hn_txagg_size_sysctl, "I",
1963dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation size, 0 -- disable, -1 -- auto");
1964dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts",
1965dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
1966dc13fee6SSepherosa Ziehau 	    hn_txagg_pkts_sysctl, "I",
1967dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation packets, "
1968dc13fee6SSepherosa Ziehau 	    "0 -- disable, -1 -- auto");
19696c1204dfSSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "polling",
19706c1204dfSSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
19716c1204dfSSepherosa Ziehau 	    hn_polling_sysctl, "I",
19726c1204dfSSepherosa Ziehau 	    "Polling frequency: [100,1000000], 0 disable polling");
197340d60d6eSDexuan Cui 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf",
197440d60d6eSDexuan Cui 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
197540d60d6eSDexuan Cui 	    hn_vf_sysctl, "A", "Virtual Function's name");
19769c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf) {
1977499c3e17SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxvf",
1978499c3e17SSepherosa Ziehau 		    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
1979499c3e17SSepherosa Ziehau 		    hn_rxvf_sysctl, "A", "activated Virtual Function's name");
19809c6cae24SSepherosa Ziehau 	} else {
19819c6cae24SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_enabled",
19829c6cae24SSepherosa Ziehau 		    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
19839c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_enabled_sysctl, "I",
19849c6cae24SSepherosa Ziehau 		    "Transparent VF enabled");
19859c6cae24SSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf_xpnt_accbpf",
19869c6cae24SSepherosa Ziehau 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
19879c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_accbpf_sysctl, "I",
19889c6cae24SSepherosa Ziehau 		    "Accurate BPF for transparent VF");
19899c6cae24SSepherosa Ziehau 	}
199015516c77SSepherosa Ziehau 
199115516c77SSepherosa Ziehau 	/*
199215516c77SSepherosa Ziehau 	 * Setup the ifmedia, which has been initialized earlier.
199315516c77SSepherosa Ziehau 	 */
199415516c77SSepherosa Ziehau 	ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL);
199515516c77SSepherosa Ziehau 	ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO);
199615516c77SSepherosa Ziehau 	/* XXX ifmedia_set really should do this for us */
199715516c77SSepherosa Ziehau 	sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media;
199815516c77SSepherosa Ziehau 
199915516c77SSepherosa Ziehau 	/*
200015516c77SSepherosa Ziehau 	 * Setup the ifnet for this interface.
200115516c77SSepherosa Ziehau 	 */
200215516c77SSepherosa Ziehau 
200315516c77SSepherosa Ziehau 	ifp->if_baudrate = IF_Gbps(10);
200415516c77SSepherosa Ziehau 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
200515516c77SSepherosa Ziehau 	ifp->if_ioctl = hn_ioctl;
200615516c77SSepherosa Ziehau 	ifp->if_init = hn_init;
200723bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
200815516c77SSepherosa Ziehau 	if (hn_use_if_start) {
200915516c77SSepherosa Ziehau 		int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]);
201015516c77SSepherosa Ziehau 
201115516c77SSepherosa Ziehau 		ifp->if_start = hn_start;
201215516c77SSepherosa Ziehau 		IFQ_SET_MAXLEN(&ifp->if_snd, qdepth);
201315516c77SSepherosa Ziehau 		ifp->if_snd.ifq_drv_maxlen = qdepth - 1;
201415516c77SSepherosa Ziehau 		IFQ_SET_READY(&ifp->if_snd);
201523bf9e15SSepherosa Ziehau 	} else
201623bf9e15SSepherosa Ziehau #endif
201723bf9e15SSepherosa Ziehau 	{
201815516c77SSepherosa Ziehau 		ifp->if_transmit = hn_transmit;
201915516c77SSepherosa Ziehau 		ifp->if_qflush = hn_xmit_qflush;
202015516c77SSepherosa Ziehau 	}
202115516c77SSepherosa Ziehau 
20229c6cae24SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO | IFCAP_LINKSTATE;
202315516c77SSepherosa Ziehau #ifdef foo
202415516c77SSepherosa Ziehau 	/* We can't diff IPv6 packets from IPv4 packets on RX path. */
202515516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM_IPV6;
202615516c77SSepherosa Ziehau #endif
202715516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_VLAN) {
202815516c77SSepherosa Ziehau 		/* XXX not sure about VLAN_MTU. */
202915516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
203015516c77SSepherosa Ziehau 	}
203115516c77SSepherosa Ziehau 
203215516c77SSepherosa Ziehau 	ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist;
203315516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP_MASK)
203415516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM;
203515516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP6_MASK)
203615516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM_IPV6;
203715516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO4) {
203815516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO4;
203915516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP_TSO;
204015516c77SSepherosa Ziehau 	}
204115516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO6) {
204215516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO6;
204315516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP6_TSO;
204415516c77SSepherosa Ziehau 	}
204515516c77SSepherosa Ziehau 
204615516c77SSepherosa Ziehau 	/* Enable all available capabilities by default. */
204715516c77SSepherosa Ziehau 	ifp->if_capenable = ifp->if_capabilities;
204815516c77SSepherosa Ziehau 
20497960e6baSSepherosa Ziehau 	/*
20507960e6baSSepherosa Ziehau 	 * Disable IPv6 TSO and TXCSUM by default, they still can
20517960e6baSSepherosa Ziehau 	 * be enabled through SIOCSIFCAP.
20527960e6baSSepherosa Ziehau 	 */
20537960e6baSSepherosa Ziehau 	ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
20547960e6baSSepherosa Ziehau 	ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO);
20557960e6baSSepherosa Ziehau 
205615516c77SSepherosa Ziehau 	if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) {
20579c6cae24SSepherosa Ziehau 		/*
20589c6cae24SSepherosa Ziehau 		 * Lock hn_set_tso_maxsize() to simplify its
20599c6cae24SSepherosa Ziehau 		 * internal logic.
20609c6cae24SSepherosa Ziehau 		 */
20619c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
206215516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU);
20639c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
206415516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX;
206515516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = PAGE_SIZE;
206615516c77SSepherosa Ziehau 	}
206715516c77SSepherosa Ziehau 
206815516c77SSepherosa Ziehau 	ether_ifattach(ifp, eaddr);
206915516c77SSepherosa Ziehau 
207015516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) {
207115516c77SSepherosa Ziehau 		if_printf(ifp, "TSO segcnt %u segsz %u\n",
207215516c77SSepherosa Ziehau 		    ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize);
207315516c77SSepherosa Ziehau 	}
207415516c77SSepherosa Ziehau 
207515516c77SSepherosa Ziehau 	/* Inform the upper layer about the long frame support. */
207615516c77SSepherosa Ziehau 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
207715516c77SSepherosa Ziehau 
207815516c77SSepherosa Ziehau 	/*
207915516c77SSepherosa Ziehau 	 * Kick off link status check.
208015516c77SSepherosa Ziehau 	 */
208115516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
208215516c77SSepherosa Ziehau 	hn_update_link_status(sc);
208315516c77SSepherosa Ziehau 
20849c6cae24SSepherosa Ziehau 	if (!hn_xpnt_vf) {
20855bdfd3fdSDexuan Cui 		sc->hn_ifnet_evthand = EVENTHANDLER_REGISTER(ifnet_event,
20865bdfd3fdSDexuan Cui 		    hn_ifnet_event, sc, EVENTHANDLER_PRI_ANY);
20875bdfd3fdSDexuan Cui 		sc->hn_ifaddr_evthand = EVENTHANDLER_REGISTER(ifaddr_event,
20885bdfd3fdSDexuan Cui 		    hn_ifaddr_event, sc, EVENTHANDLER_PRI_ANY);
20899c6cae24SSepherosa Ziehau 	} else {
20909c6cae24SSepherosa Ziehau 		sc->hn_ifnet_lnkhand = EVENTHANDLER_REGISTER(ifnet_link_event,
20919c6cae24SSepherosa Ziehau 		    hn_ifnet_lnkevent, sc, EVENTHANDLER_PRI_ANY);
20929c6cae24SSepherosa Ziehau 	}
20935bdfd3fdSDexuan Cui 
2094f41e0df4SSepherosa Ziehau 	/*
2095f41e0df4SSepherosa Ziehau 	 * NOTE:
2096f41e0df4SSepherosa Ziehau 	 * Subscribe ether_ifattach event, instead of ifnet_arrival event,
2097f41e0df4SSepherosa Ziehau 	 * since interface's LLADDR is needed; interface LLADDR is not
2098f41e0df4SSepherosa Ziehau 	 * available when ifnet_arrival event is triggered.
2099f41e0df4SSepherosa Ziehau 	 */
2100499c3e17SSepherosa Ziehau 	sc->hn_ifnet_atthand = EVENTHANDLER_REGISTER(ether_ifattach_event,
2101499c3e17SSepherosa Ziehau 	    hn_ifnet_attevent, sc, EVENTHANDLER_PRI_ANY);
2102499c3e17SSepherosa Ziehau 	sc->hn_ifnet_dethand = EVENTHANDLER_REGISTER(ifnet_departure_event,
2103499c3e17SSepherosa Ziehau 	    hn_ifnet_detevent, sc, EVENTHANDLER_PRI_ANY);
2104499c3e17SSepherosa Ziehau 
210515516c77SSepherosa Ziehau 	return (0);
210615516c77SSepherosa Ziehau failed:
210715516c77SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)
210815516c77SSepherosa Ziehau 		hn_synth_detach(sc);
210915516c77SSepherosa Ziehau 	hn_detach(dev);
211015516c77SSepherosa Ziehau 	return (error);
211115516c77SSepherosa Ziehau }
211215516c77SSepherosa Ziehau 
211315516c77SSepherosa Ziehau static int
211415516c77SSepherosa Ziehau hn_detach(device_t dev)
211515516c77SSepherosa Ziehau {
211615516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
2117499c3e17SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp, *vf_ifp;
211815516c77SSepherosa Ziehau 
21199c6cae24SSepherosa Ziehau 	if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) {
21209c6cae24SSepherosa Ziehau 		/*
21219c6cae24SSepherosa Ziehau 		 * In case that the vmbus missed the orphan handler
21229c6cae24SSepherosa Ziehau 		 * installation.
21239c6cae24SSepherosa Ziehau 		 */
21249c6cae24SSepherosa Ziehau 		vmbus_xact_ctx_orphan(sc->hn_xact);
21259c6cae24SSepherosa Ziehau 	}
21269c6cae24SSepherosa Ziehau 
21275bdfd3fdSDexuan Cui 	if (sc->hn_ifaddr_evthand != NULL)
21285bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifaddr_event, sc->hn_ifaddr_evthand);
21295bdfd3fdSDexuan Cui 	if (sc->hn_ifnet_evthand != NULL)
21305bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifnet_event, sc->hn_ifnet_evthand);
2131499c3e17SSepherosa Ziehau 	if (sc->hn_ifnet_atthand != NULL) {
2132499c3e17SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ether_ifattach_event,
2133499c3e17SSepherosa Ziehau 		    sc->hn_ifnet_atthand);
2134499c3e17SSepherosa Ziehau 	}
2135499c3e17SSepherosa Ziehau 	if (sc->hn_ifnet_dethand != NULL) {
2136499c3e17SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ifnet_departure_event,
2137499c3e17SSepherosa Ziehau 		    sc->hn_ifnet_dethand);
2138499c3e17SSepherosa Ziehau 	}
21399c6cae24SSepherosa Ziehau 	if (sc->hn_ifnet_lnkhand != NULL)
21409c6cae24SSepherosa Ziehau 		EVENTHANDLER_DEREGISTER(ifnet_link_event, sc->hn_ifnet_lnkhand);
2141499c3e17SSepherosa Ziehau 
2142499c3e17SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
2143499c3e17SSepherosa Ziehau 	__compiler_membar();
2144499c3e17SSepherosa Ziehau 	if (vf_ifp != NULL)
2145499c3e17SSepherosa Ziehau 		hn_ifnet_detevent(sc, vf_ifp);
21465bdfd3fdSDexuan Cui 
214715516c77SSepherosa Ziehau 	if (device_is_attached(dev)) {
214815516c77SSepherosa Ziehau 		HN_LOCK(sc);
214915516c77SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
215015516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
21515bdfd3fdSDexuan Cui 				hn_stop(sc, true);
215215516c77SSepherosa Ziehau 			/*
215315516c77SSepherosa Ziehau 			 * NOTE:
215415516c77SSepherosa Ziehau 			 * hn_stop() only suspends data, so managment
215515516c77SSepherosa Ziehau 			 * stuffs have to be suspended manually here.
215615516c77SSepherosa Ziehau 			 */
215715516c77SSepherosa Ziehau 			hn_suspend_mgmt(sc);
215815516c77SSepherosa Ziehau 			hn_synth_detach(sc);
215915516c77SSepherosa Ziehau 		}
216015516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
216115516c77SSepherosa Ziehau 		ether_ifdetach(ifp);
216215516c77SSepherosa Ziehau 	}
216315516c77SSepherosa Ziehau 
216415516c77SSepherosa Ziehau 	ifmedia_removeall(&sc->hn_media);
216515516c77SSepherosa Ziehau 	hn_destroy_rx_data(sc);
216615516c77SSepherosa Ziehau 	hn_destroy_tx_data(sc);
216715516c77SSepherosa Ziehau 
21680e11868dSSepherosa Ziehau 	if (sc->hn_tx_taskqs != NULL && sc->hn_tx_taskqs != hn_tx_taskque) {
2169fdd0222aSSepherosa Ziehau 		int i;
2170fdd0222aSSepherosa Ziehau 
2171fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
2172fdd0222aSSepherosa Ziehau 			taskqueue_free(sc->hn_tx_taskqs[i]);
2173fdd0222aSSepherosa Ziehau 		free(sc->hn_tx_taskqs, M_DEVBUF);
2174fdd0222aSSepherosa Ziehau 	}
217515516c77SSepherosa Ziehau 	taskqueue_free(sc->hn_mgmt_taskq0);
21769c6cae24SSepherosa Ziehau 	if (sc->hn_vf_taskq != NULL)
21779c6cae24SSepherosa Ziehau 		taskqueue_free(sc->hn_vf_taskq);
217815516c77SSepherosa Ziehau 
217925641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL) {
218025641fc7SSepherosa Ziehau 		/*
218125641fc7SSepherosa Ziehau 		 * Uninstall the orphan handler _before_ the xact is
218225641fc7SSepherosa Ziehau 		 * destructed.
218325641fc7SSepherosa Ziehau 		 */
218425641fc7SSepherosa Ziehau 		vmbus_chan_unset_orphan(sc->hn_prichan);
218515516c77SSepherosa Ziehau 		vmbus_xact_ctx_destroy(sc->hn_xact);
218625641fc7SSepherosa Ziehau 	}
218715516c77SSepherosa Ziehau 
218815516c77SSepherosa Ziehau 	if_free(ifp);
218915516c77SSepherosa Ziehau 
219015516c77SSepherosa Ziehau 	HN_LOCK_DESTROY(sc);
21919c6cae24SSepherosa Ziehau 	rm_destroy(&sc->hn_vf_lock);
219215516c77SSepherosa Ziehau 	return (0);
219315516c77SSepherosa Ziehau }
219415516c77SSepherosa Ziehau 
219515516c77SSepherosa Ziehau static int
219615516c77SSepherosa Ziehau hn_shutdown(device_t dev)
219715516c77SSepherosa Ziehau {
219815516c77SSepherosa Ziehau 
219915516c77SSepherosa Ziehau 	return (0);
220015516c77SSepherosa Ziehau }
220115516c77SSepherosa Ziehau 
220215516c77SSepherosa Ziehau static void
220315516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc)
220415516c77SSepherosa Ziehau {
220515516c77SSepherosa Ziehau 	uint32_t link_status;
220615516c77SSepherosa Ziehau 	int error;
220715516c77SSepherosa Ziehau 
220815516c77SSepherosa Ziehau 	error = hn_rndis_get_linkstatus(sc, &link_status);
220915516c77SSepherosa Ziehau 	if (error) {
221015516c77SSepherosa Ziehau 		/* XXX what to do? */
221115516c77SSepherosa Ziehau 		return;
221215516c77SSepherosa Ziehau 	}
221315516c77SSepherosa Ziehau 
221415516c77SSepherosa Ziehau 	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
221515516c77SSepherosa Ziehau 		sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
221615516c77SSepherosa Ziehau 	else
221715516c77SSepherosa Ziehau 		sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
221815516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp,
221915516c77SSepherosa Ziehau 	    (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ?
222015516c77SSepherosa Ziehau 	    LINK_STATE_UP : LINK_STATE_DOWN);
222115516c77SSepherosa Ziehau }
222215516c77SSepherosa Ziehau 
222315516c77SSepherosa Ziehau static void
222415516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused)
222515516c77SSepherosa Ziehau {
222615516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
222715516c77SSepherosa Ziehau 
222815516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
222915516c77SSepherosa Ziehau 		return;
223015516c77SSepherosa Ziehau 	hn_link_status(sc);
223115516c77SSepherosa Ziehau }
223215516c77SSepherosa Ziehau 
223315516c77SSepherosa Ziehau static void
223415516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused)
223515516c77SSepherosa Ziehau {
223615516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
223715516c77SSepherosa Ziehau 
223815516c77SSepherosa Ziehau 	/* Prevent any link status checks from running. */
223915516c77SSepherosa Ziehau 	sc->hn_link_flags |= HN_LINK_FLAG_NETCHG;
224015516c77SSepherosa Ziehau 
224115516c77SSepherosa Ziehau 	/*
224215516c77SSepherosa Ziehau 	 * Fake up a [link down --> link up] state change; 5 seconds
224315516c77SSepherosa Ziehau 	 * delay is used, which closely simulates miibus reaction
224415516c77SSepherosa Ziehau 	 * upon link down event.
224515516c77SSepherosa Ziehau 	 */
224615516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
224715516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
224815516c77SSepherosa Ziehau 	taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0,
224915516c77SSepherosa Ziehau 	    &sc->hn_netchg_status, 5 * hz);
225015516c77SSepherosa Ziehau }
225115516c77SSepherosa Ziehau 
225215516c77SSepherosa Ziehau static void
225315516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused)
225415516c77SSepherosa Ziehau {
225515516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
225615516c77SSepherosa Ziehau 
225715516c77SSepherosa Ziehau 	/* Re-allow link status checks. */
225815516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG;
225915516c77SSepherosa Ziehau 	hn_link_status(sc);
226015516c77SSepherosa Ziehau }
226115516c77SSepherosa Ziehau 
226215516c77SSepherosa Ziehau static void
226315516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc)
226415516c77SSepherosa Ziehau {
226515516c77SSepherosa Ziehau 
226615516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
226715516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
226815516c77SSepherosa Ziehau }
226915516c77SSepherosa Ziehau 
227015516c77SSepherosa Ziehau static void
227115516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc)
227215516c77SSepherosa Ziehau {
227315516c77SSepherosa Ziehau 
227415516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
227515516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init);
227615516c77SSepherosa Ziehau }
227715516c77SSepherosa Ziehau 
227815516c77SSepherosa Ziehau static __inline int
227915516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
228015516c77SSepherosa Ziehau     struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
228115516c77SSepherosa Ziehau {
228215516c77SSepherosa Ziehau 	struct mbuf *m = *m_head;
228315516c77SSepherosa Ziehau 	int error;
228415516c77SSepherosa Ziehau 
228515516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim"));
228615516c77SSepherosa Ziehau 
228715516c77SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap,
228815516c77SSepherosa Ziehau 	    m, segs, nsegs, BUS_DMA_NOWAIT);
228915516c77SSepherosa Ziehau 	if (error == EFBIG) {
229015516c77SSepherosa Ziehau 		struct mbuf *m_new;
229115516c77SSepherosa Ziehau 
229215516c77SSepherosa Ziehau 		m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX);
229315516c77SSepherosa Ziehau 		if (m_new == NULL)
229415516c77SSepherosa Ziehau 			return ENOBUFS;
229515516c77SSepherosa Ziehau 		else
229615516c77SSepherosa Ziehau 			*m_head = m = m_new;
229715516c77SSepherosa Ziehau 		txr->hn_tx_collapsed++;
229815516c77SSepherosa Ziehau 
229915516c77SSepherosa Ziehau 		error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag,
230015516c77SSepherosa Ziehau 		    txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT);
230115516c77SSepherosa Ziehau 	}
230215516c77SSepherosa Ziehau 	if (!error) {
230315516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap,
230415516c77SSepherosa Ziehau 		    BUS_DMASYNC_PREWRITE);
230515516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_DMAMAP;
230615516c77SSepherosa Ziehau 	}
230715516c77SSepherosa Ziehau 	return error;
230815516c77SSepherosa Ziehau }
230915516c77SSepherosa Ziehau 
231015516c77SSepherosa Ziehau static __inline int
231115516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd)
231215516c77SSepherosa Ziehau {
231315516c77SSepherosa Ziehau 
231415516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0,
231515516c77SSepherosa Ziehau 	    ("put an onlist txd %#x", txd->flags));
2316dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2317dc13fee6SSepherosa Ziehau 	    ("put an onagg txd %#x", txd->flags));
231815516c77SSepherosa Ziehau 
231915516c77SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
232015516c77SSepherosa Ziehau 	if (atomic_fetchadd_int(&txd->refs, -1) != 1)
232115516c77SSepherosa Ziehau 		return 0;
232215516c77SSepherosa Ziehau 
2323dc13fee6SSepherosa Ziehau 	if (!STAILQ_EMPTY(&txd->agg_list)) {
2324dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tmp_txd;
2325dc13fee6SSepherosa Ziehau 
2326dc13fee6SSepherosa Ziehau 		while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) {
2327dc13fee6SSepherosa Ziehau 			int freed;
2328dc13fee6SSepherosa Ziehau 
2329dc13fee6SSepherosa Ziehau 			KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list),
2330dc13fee6SSepherosa Ziehau 			    ("resursive aggregation on aggregated txdesc"));
2331dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG),
2332dc13fee6SSepherosa Ziehau 			    ("not aggregated txdesc"));
2333dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
2334dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc uses dmamap"));
2335dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
2336dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc consumes "
2337dc13fee6SSepherosa Ziehau 			     "chimney sending buffer"));
2338dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_size == 0,
2339dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc has non-zero "
2340dc13fee6SSepherosa Ziehau 			     "chimney sending size"));
2341dc13fee6SSepherosa Ziehau 
2342dc13fee6SSepherosa Ziehau 			STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link);
2343dc13fee6SSepherosa Ziehau 			tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG;
2344dc13fee6SSepherosa Ziehau 			freed = hn_txdesc_put(txr, tmp_txd);
2345dc13fee6SSepherosa Ziehau 			KASSERT(freed, ("failed to free aggregated txdesc"));
2346dc13fee6SSepherosa Ziehau 		}
2347dc13fee6SSepherosa Ziehau 	}
2348dc13fee6SSepherosa Ziehau 
234915516c77SSepherosa Ziehau 	if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) {
235015516c77SSepherosa Ziehau 		KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
235115516c77SSepherosa Ziehau 		    ("chim txd uses dmamap"));
235215516c77SSepherosa Ziehau 		hn_chim_free(txr->hn_sc, txd->chim_index);
235315516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
2354dc13fee6SSepherosa Ziehau 		txd->chim_size = 0;
235515516c77SSepherosa Ziehau 	} else if (txd->flags & HN_TXD_FLAG_DMAMAP) {
235615516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag,
235715516c77SSepherosa Ziehau 		    txd->data_dmap, BUS_DMASYNC_POSTWRITE);
235815516c77SSepherosa Ziehau 		bus_dmamap_unload(txr->hn_tx_data_dtag,
235915516c77SSepherosa Ziehau 		    txd->data_dmap);
236015516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_DMAMAP;
236115516c77SSepherosa Ziehau 	}
236215516c77SSepherosa Ziehau 
236315516c77SSepherosa Ziehau 	if (txd->m != NULL) {
236415516c77SSepherosa Ziehau 		m_freem(txd->m);
236515516c77SSepherosa Ziehau 		txd->m = NULL;
236615516c77SSepherosa Ziehau 	}
236715516c77SSepherosa Ziehau 
236815516c77SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONLIST;
236915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
237015516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
237115516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_avail >= 0 &&
237215516c77SSepherosa Ziehau 	    txr->hn_txdesc_avail < txr->hn_txdesc_cnt,
237315516c77SSepherosa Ziehau 	    ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail));
237415516c77SSepherosa Ziehau 	txr->hn_txdesc_avail++;
237515516c77SSepherosa Ziehau 	SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
237615516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
237785e4ae1eSSepherosa Ziehau #else	/* HN_USE_TXDESC_BUFRING */
237885e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
237915516c77SSepherosa Ziehau 	atomic_add_int(&txr->hn_txdesc_avail, 1);
238015516c77SSepherosa Ziehau #endif
238185e4ae1eSSepherosa Ziehau 	buf_ring_enqueue(txr->hn_txdesc_br, txd);
238285e4ae1eSSepherosa Ziehau #endif	/* !HN_USE_TXDESC_BUFRING */
238315516c77SSepherosa Ziehau 
238415516c77SSepherosa Ziehau 	return 1;
238515516c77SSepherosa Ziehau }
238615516c77SSepherosa Ziehau 
238715516c77SSepherosa Ziehau static __inline struct hn_txdesc *
238815516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr)
238915516c77SSepherosa Ziehau {
239015516c77SSepherosa Ziehau 	struct hn_txdesc *txd;
239115516c77SSepherosa Ziehau 
239215516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
239315516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
239415516c77SSepherosa Ziehau 	txd = SLIST_FIRST(&txr->hn_txlist);
239515516c77SSepherosa Ziehau 	if (txd != NULL) {
239615516c77SSepherosa Ziehau 		KASSERT(txr->hn_txdesc_avail > 0,
239715516c77SSepherosa Ziehau 		    ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail));
239815516c77SSepherosa Ziehau 		txr->hn_txdesc_avail--;
239915516c77SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&txr->hn_txlist, link);
240015516c77SSepherosa Ziehau 	}
240115516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
240215516c77SSepherosa Ziehau #else
240315516c77SSepherosa Ziehau 	txd = buf_ring_dequeue_sc(txr->hn_txdesc_br);
240415516c77SSepherosa Ziehau #endif
240515516c77SSepherosa Ziehau 
240615516c77SSepherosa Ziehau 	if (txd != NULL) {
240715516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
240885e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
240915516c77SSepherosa Ziehau 		atomic_subtract_int(&txr->hn_txdesc_avail, 1);
241015516c77SSepherosa Ziehau #endif
241185e4ae1eSSepherosa Ziehau #endif	/* HN_USE_TXDESC_BUFRING */
241215516c77SSepherosa Ziehau 		KASSERT(txd->m == NULL && txd->refs == 0 &&
2413dc13fee6SSepherosa Ziehau 		    STAILQ_EMPTY(&txd->agg_list) &&
241415516c77SSepherosa Ziehau 		    txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
2415dc13fee6SSepherosa Ziehau 		    txd->chim_size == 0 &&
241615516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONLIST) &&
2417dc13fee6SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONAGG) == 0 &&
241815516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd"));
241915516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_ONLIST;
242015516c77SSepherosa Ziehau 		txd->refs = 1;
242115516c77SSepherosa Ziehau 	}
242215516c77SSepherosa Ziehau 	return txd;
242315516c77SSepherosa Ziehau }
242415516c77SSepherosa Ziehau 
242515516c77SSepherosa Ziehau static __inline void
242615516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd)
242715516c77SSepherosa Ziehau {
242815516c77SSepherosa Ziehau 
242915516c77SSepherosa Ziehau 	/* 0->1 transition will never work */
243025641fc7SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
243115516c77SSepherosa Ziehau 	atomic_add_int(&txd->refs, 1);
243215516c77SSepherosa Ziehau }
243315516c77SSepherosa Ziehau 
2434dc13fee6SSepherosa Ziehau static __inline void
2435dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd)
2436dc13fee6SSepherosa Ziehau {
2437dc13fee6SSepherosa Ziehau 
2438dc13fee6SSepherosa Ziehau 	KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2439dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on aggregating txdesc"));
2440dc13fee6SSepherosa Ziehau 
2441dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
2442dc13fee6SSepherosa Ziehau 	    ("already aggregated"));
2443dc13fee6SSepherosa Ziehau 	KASSERT(STAILQ_EMPTY(&txd->agg_list),
2444dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on to-be-aggregated txdesc"));
2445dc13fee6SSepherosa Ziehau 
2446dc13fee6SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONAGG;
2447dc13fee6SSepherosa Ziehau 	STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link);
2448dc13fee6SSepherosa Ziehau }
2449dc13fee6SSepherosa Ziehau 
245015516c77SSepherosa Ziehau static bool
245115516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr)
245215516c77SSepherosa Ziehau {
245315516c77SSepherosa Ziehau 	bool pending = false;
245415516c77SSepherosa Ziehau 
245515516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
245615516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
245715516c77SSepherosa Ziehau 	if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt)
245815516c77SSepherosa Ziehau 		pending = true;
245915516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
246015516c77SSepherosa Ziehau #else
246115516c77SSepherosa Ziehau 	if (!buf_ring_full(txr->hn_txdesc_br))
246215516c77SSepherosa Ziehau 		pending = true;
246315516c77SSepherosa Ziehau #endif
246415516c77SSepherosa Ziehau 	return (pending);
246515516c77SSepherosa Ziehau }
246615516c77SSepherosa Ziehau 
246715516c77SSepherosa Ziehau static __inline void
246815516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr)
246915516c77SSepherosa Ziehau {
247015516c77SSepherosa Ziehau 	txr->hn_has_txeof = 0;
247115516c77SSepherosa Ziehau 	txr->hn_txeof(txr);
247215516c77SSepherosa Ziehau }
247315516c77SSepherosa Ziehau 
247415516c77SSepherosa Ziehau static void
247515516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc,
247615516c77SSepherosa Ziehau     struct vmbus_channel *chan, const void *data __unused, int dlen __unused)
247715516c77SSepherosa Ziehau {
247815516c77SSepherosa Ziehau 	struct hn_txdesc *txd = sndc->hn_cbarg;
247915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
248015516c77SSepherosa Ziehau 
248115516c77SSepherosa Ziehau 	txr = txd->txr;
248215516c77SSepherosa Ziehau 	KASSERT(txr->hn_chan == chan,
248315516c77SSepherosa Ziehau 	    ("channel mismatch, on chan%u, should be chan%u",
2484aa1a2adcSSepherosa Ziehau 	     vmbus_chan_id(chan), vmbus_chan_id(txr->hn_chan)));
248515516c77SSepherosa Ziehau 
248615516c77SSepherosa Ziehau 	txr->hn_has_txeof = 1;
248715516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
248815516c77SSepherosa Ziehau 
248915516c77SSepherosa Ziehau 	++txr->hn_txdone_cnt;
249015516c77SSepherosa Ziehau 	if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) {
249115516c77SSepherosa Ziehau 		txr->hn_txdone_cnt = 0;
249215516c77SSepherosa Ziehau 		if (txr->hn_oactive)
249315516c77SSepherosa Ziehau 			hn_txeof(txr);
249415516c77SSepherosa Ziehau 	}
249515516c77SSepherosa Ziehau }
249615516c77SSepherosa Ziehau 
249715516c77SSepherosa Ziehau static void
249815516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
249915516c77SSepherosa Ziehau {
250015516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
250115516c77SSepherosa Ziehau 	tcp_lro_flush_all(&rxr->hn_lro);
250215516c77SSepherosa Ziehau #endif
250315516c77SSepherosa Ziehau 
250415516c77SSepherosa Ziehau 	/*
250515516c77SSepherosa Ziehau 	 * NOTE:
250615516c77SSepherosa Ziehau 	 * 'txr' could be NULL, if multiple channels and
250715516c77SSepherosa Ziehau 	 * ifnet.if_start method are enabled.
250815516c77SSepherosa Ziehau 	 */
250915516c77SSepherosa Ziehau 	if (txr == NULL || !txr->hn_has_txeof)
251015516c77SSepherosa Ziehau 		return;
251115516c77SSepherosa Ziehau 
251215516c77SSepherosa Ziehau 	txr->hn_txdone_cnt = 0;
251315516c77SSepherosa Ziehau 	hn_txeof(txr);
251415516c77SSepherosa Ziehau }
251515516c77SSepherosa Ziehau 
251615516c77SSepherosa Ziehau static __inline uint32_t
251715516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs)
251815516c77SSepherosa Ziehau {
251915516c77SSepherosa Ziehau 
252015516c77SSepherosa Ziehau 	KASSERT(ofs >= sizeof(struct rndis_packet_msg),
252115516c77SSepherosa Ziehau 	    ("invalid RNDIS packet msg offset %u", ofs));
252215516c77SSepherosa Ziehau 	return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset));
252315516c77SSepherosa Ziehau }
252415516c77SSepherosa Ziehau 
252515516c77SSepherosa Ziehau static __inline void *
252615516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
252715516c77SSepherosa Ziehau     size_t pi_dlen, uint32_t pi_type)
252815516c77SSepherosa Ziehau {
252915516c77SSepherosa Ziehau 	const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
253015516c77SSepherosa Ziehau 	struct rndis_pktinfo *pi;
253115516c77SSepherosa Ziehau 
253215516c77SSepherosa Ziehau 	KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
253315516c77SSepherosa Ziehau 	    ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
253415516c77SSepherosa Ziehau 
253515516c77SSepherosa Ziehau 	/*
253615516c77SSepherosa Ziehau 	 * Per-packet-info does not move; it only grows.
253715516c77SSepherosa Ziehau 	 *
253815516c77SSepherosa Ziehau 	 * NOTE:
253915516c77SSepherosa Ziehau 	 * rm_pktinfooffset in this phase counts from the beginning
254015516c77SSepherosa Ziehau 	 * of rndis_packet_msg.
254115516c77SSepherosa Ziehau 	 */
254215516c77SSepherosa Ziehau 	KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
254315516c77SSepherosa Ziehau 	    ("%u pktinfo overflows RNDIS packet msg", pi_type));
254415516c77SSepherosa Ziehau 	pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
254515516c77SSepherosa Ziehau 	    pkt->rm_pktinfolen);
254615516c77SSepherosa Ziehau 	pkt->rm_pktinfolen += pi_size;
254715516c77SSepherosa Ziehau 
254815516c77SSepherosa Ziehau 	pi->rm_size = pi_size;
254915516c77SSepherosa Ziehau 	pi->rm_type = pi_type;
255015516c77SSepherosa Ziehau 	pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
255115516c77SSepherosa Ziehau 
255215516c77SSepherosa Ziehau 	return (pi->rm_data);
255315516c77SSepherosa Ziehau }
255415516c77SSepherosa Ziehau 
2555dc13fee6SSepherosa Ziehau static __inline int
2556dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr)
2557dc13fee6SSepherosa Ziehau {
2558dc13fee6SSepherosa Ziehau 	struct hn_txdesc *txd;
2559dc13fee6SSepherosa Ziehau 	struct mbuf *m;
2560dc13fee6SSepherosa Ziehau 	int error, pkts;
2561dc13fee6SSepherosa Ziehau 
2562dc13fee6SSepherosa Ziehau 	txd = txr->hn_agg_txd;
2563dc13fee6SSepherosa Ziehau 	KASSERT(txd != NULL, ("no aggregate txdesc"));
2564dc13fee6SSepherosa Ziehau 
2565dc13fee6SSepherosa Ziehau 	/*
2566dc13fee6SSepherosa Ziehau 	 * Since hn_txpkt() will reset this temporary stat, save
2567dc13fee6SSepherosa Ziehau 	 * it now, so that oerrors can be updated properly, if
2568dc13fee6SSepherosa Ziehau 	 * hn_txpkt() ever fails.
2569dc13fee6SSepherosa Ziehau 	 */
2570dc13fee6SSepherosa Ziehau 	pkts = txr->hn_stat_pkts;
2571dc13fee6SSepherosa Ziehau 
2572dc13fee6SSepherosa Ziehau 	/*
2573dc13fee6SSepherosa Ziehau 	 * Since txd's mbuf will _not_ be freed upon hn_txpkt()
2574dc13fee6SSepherosa Ziehau 	 * failure, save it for later freeing, if hn_txpkt() ever
2575dc13fee6SSepherosa Ziehau 	 * fails.
2576dc13fee6SSepherosa Ziehau 	 */
2577dc13fee6SSepherosa Ziehau 	m = txd->m;
2578dc13fee6SSepherosa Ziehau 	error = hn_txpkt(ifp, txr, txd);
2579dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
2580dc13fee6SSepherosa Ziehau 		/* txd is freed, but m is not. */
2581dc13fee6SSepherosa Ziehau 		m_freem(m);
2582dc13fee6SSepherosa Ziehau 
2583dc13fee6SSepherosa Ziehau 		txr->hn_flush_failed++;
2584dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts);
2585dc13fee6SSepherosa Ziehau 	}
2586dc13fee6SSepherosa Ziehau 
2587dc13fee6SSepherosa Ziehau 	/* Reset all aggregation states. */
2588dc13fee6SSepherosa Ziehau 	txr->hn_agg_txd = NULL;
2589dc13fee6SSepherosa Ziehau 	txr->hn_agg_szleft = 0;
2590dc13fee6SSepherosa Ziehau 	txr->hn_agg_pktleft = 0;
2591dc13fee6SSepherosa Ziehau 	txr->hn_agg_prevpkt = NULL;
2592dc13fee6SSepherosa Ziehau 
2593dc13fee6SSepherosa Ziehau 	return (error);
2594dc13fee6SSepherosa Ziehau }
2595dc13fee6SSepherosa Ziehau 
2596dc13fee6SSepherosa Ziehau static void *
2597dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
2598dc13fee6SSepherosa Ziehau     int pktsize)
2599dc13fee6SSepherosa Ziehau {
2600dc13fee6SSepherosa Ziehau 	void *chim;
2601dc13fee6SSepherosa Ziehau 
2602dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL) {
2603dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) {
2604dc13fee6SSepherosa Ziehau 			struct hn_txdesc *agg_txd = txr->hn_agg_txd;
2605dc13fee6SSepherosa Ziehau 			struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt;
2606dc13fee6SSepherosa Ziehau 			int olen;
2607dc13fee6SSepherosa Ziehau 
2608dc13fee6SSepherosa Ziehau 			/*
2609dc13fee6SSepherosa Ziehau 			 * Update the previous RNDIS packet's total length,
2610dc13fee6SSepherosa Ziehau 			 * it can be increased due to the mandatory alignment
2611dc13fee6SSepherosa Ziehau 			 * padding for this RNDIS packet.  And update the
2612dc13fee6SSepherosa Ziehau 			 * aggregating txdesc's chimney sending buffer size
2613dc13fee6SSepherosa Ziehau 			 * accordingly.
2614dc13fee6SSepherosa Ziehau 			 *
2615dc13fee6SSepherosa Ziehau 			 * XXX
2616dc13fee6SSepherosa Ziehau 			 * Zero-out the padding, as required by the RNDIS spec.
2617dc13fee6SSepherosa Ziehau 			 */
2618dc13fee6SSepherosa Ziehau 			olen = pkt->rm_len;
2619dc13fee6SSepherosa Ziehau 			pkt->rm_len = roundup2(olen, txr->hn_agg_align);
2620dc13fee6SSepherosa Ziehau 			agg_txd->chim_size += pkt->rm_len - olen;
2621dc13fee6SSepherosa Ziehau 
2622dc13fee6SSepherosa Ziehau 			/* Link this txdesc to the parent. */
2623dc13fee6SSepherosa Ziehau 			hn_txdesc_agg(agg_txd, txd);
2624dc13fee6SSepherosa Ziehau 
2625dc13fee6SSepherosa Ziehau 			chim = (uint8_t *)pkt + pkt->rm_len;
2626dc13fee6SSepherosa Ziehau 			/* Save the current packet for later fixup. */
2627dc13fee6SSepherosa Ziehau 			txr->hn_agg_prevpkt = chim;
2628dc13fee6SSepherosa Ziehau 
2629dc13fee6SSepherosa Ziehau 			txr->hn_agg_pktleft--;
2630dc13fee6SSepherosa Ziehau 			txr->hn_agg_szleft -= pktsize;
2631dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_szleft <=
2632dc13fee6SSepherosa Ziehau 			    HN_PKTSIZE_MIN(txr->hn_agg_align)) {
2633dc13fee6SSepherosa Ziehau 				/*
2634dc13fee6SSepherosa Ziehau 				 * Probably can't aggregate more packets,
2635dc13fee6SSepherosa Ziehau 				 * flush this aggregating txdesc proactively.
2636dc13fee6SSepherosa Ziehau 				 */
2637dc13fee6SSepherosa Ziehau 				txr->hn_agg_pktleft = 0;
2638dc13fee6SSepherosa Ziehau 			}
2639dc13fee6SSepherosa Ziehau 			/* Done! */
2640dc13fee6SSepherosa Ziehau 			return (chim);
2641dc13fee6SSepherosa Ziehau 		}
2642dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
2643dc13fee6SSepherosa Ziehau 	}
2644dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
2645dc13fee6SSepherosa Ziehau 
2646dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney_tried++;
2647dc13fee6SSepherosa Ziehau 	txd->chim_index = hn_chim_alloc(txr->hn_sc);
2648dc13fee6SSepherosa Ziehau 	if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID)
2649dc13fee6SSepherosa Ziehau 		return (NULL);
2650dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney++;
2651dc13fee6SSepherosa Ziehau 
2652dc13fee6SSepherosa Ziehau 	chim = txr->hn_sc->hn_chim +
2653dc13fee6SSepherosa Ziehau 	    (txd->chim_index * txr->hn_sc->hn_chim_szmax);
2654dc13fee6SSepherosa Ziehau 
2655dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_pktmax > 1 &&
2656dc13fee6SSepherosa Ziehau 	    txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) {
2657dc13fee6SSepherosa Ziehau 		txr->hn_agg_txd = txd;
2658dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1;
2659dc13fee6SSepherosa Ziehau 		txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize;
2660dc13fee6SSepherosa Ziehau 		txr->hn_agg_prevpkt = chim;
2661dc13fee6SSepherosa Ziehau 	}
2662dc13fee6SSepherosa Ziehau 	return (chim);
2663dc13fee6SSepherosa Ziehau }
2664dc13fee6SSepherosa Ziehau 
266515516c77SSepherosa Ziehau /*
266615516c77SSepherosa Ziehau  * NOTE:
266715516c77SSepherosa Ziehau  * If this function fails, then both txd and m_head0 will be freed.
266815516c77SSepherosa Ziehau  */
266915516c77SSepherosa Ziehau static int
2670dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
2671dc13fee6SSepherosa Ziehau     struct mbuf **m_head0)
267215516c77SSepherosa Ziehau {
267315516c77SSepherosa Ziehau 	bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX];
267415516c77SSepherosa Ziehau 	int error, nsegs, i;
267515516c77SSepherosa Ziehau 	struct mbuf *m_head = *m_head0;
267615516c77SSepherosa Ziehau 	struct rndis_packet_msg *pkt;
267715516c77SSepherosa Ziehau 	uint32_t *pi_data;
26788966e5d5SSepherosa Ziehau 	void *chim = NULL;
2679dc13fee6SSepherosa Ziehau 	int pkt_hlen, pkt_size;
268015516c77SSepherosa Ziehau 
268115516c77SSepherosa Ziehau 	pkt = txd->rndis_pkt;
2682dc13fee6SSepherosa Ziehau 	pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align);
2683dc13fee6SSepherosa Ziehau 	if (pkt_size < txr->hn_chim_size) {
2684dc13fee6SSepherosa Ziehau 		chim = hn_try_txagg(ifp, txr, txd, pkt_size);
2685dc13fee6SSepherosa Ziehau 		if (chim != NULL)
26868966e5d5SSepherosa Ziehau 			pkt = chim;
2687dc13fee6SSepherosa Ziehau 	} else {
2688dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL)
2689dc13fee6SSepherosa Ziehau 			hn_flush_txagg(ifp, txr);
26908966e5d5SSepherosa Ziehau 	}
26918966e5d5SSepherosa Ziehau 
269215516c77SSepherosa Ziehau 	pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
26938fe90f73SSepherosa Ziehau 	pkt->rm_len = m_head->m_pkthdr.len;
26949130c4f7SSepherosa Ziehau 	pkt->rm_dataoffset = 0;
269515516c77SSepherosa Ziehau 	pkt->rm_datalen = m_head->m_pkthdr.len;
2696dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataoffset = 0;
2697dc13fee6SSepherosa Ziehau 	pkt->rm_oobdatalen = 0;
2698dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataelements = 0;
269915516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = sizeof(*pkt);
270015516c77SSepherosa Ziehau 	pkt->rm_pktinfolen = 0;
2701dc13fee6SSepherosa Ziehau 	pkt->rm_vchandle = 0;
2702dc13fee6SSepherosa Ziehau 	pkt->rm_reserved = 0;
270315516c77SSepherosa Ziehau 
270415516c77SSepherosa Ziehau 	if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) {
270515516c77SSepherosa Ziehau 		/*
270615516c77SSepherosa Ziehau 		 * Set the hash value for this packet, so that the host could
270715516c77SSepherosa Ziehau 		 * dispatch the TX done event for this packet back to this TX
270815516c77SSepherosa Ziehau 		 * ring's channel.
270915516c77SSepherosa Ziehau 		 */
271015516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
271115516c77SSepherosa Ziehau 		    HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL);
271215516c77SSepherosa Ziehau 		*pi_data = txr->hn_tx_idx;
271315516c77SSepherosa Ziehau 	}
271415516c77SSepherosa Ziehau 
271515516c77SSepherosa Ziehau 	if (m_head->m_flags & M_VLANTAG) {
271615516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
271715516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
271815516c77SSepherosa Ziehau 		*pi_data = NDIS_VLAN_INFO_MAKE(
271915516c77SSepherosa Ziehau 		    EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag),
272015516c77SSepherosa Ziehau 		    EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag),
272115516c77SSepherosa Ziehau 		    EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag));
272215516c77SSepherosa Ziehau 	}
272315516c77SSepherosa Ziehau 
272415516c77SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
272515516c77SSepherosa Ziehau #if defined(INET6) || defined(INET)
272615516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
272715516c77SSepherosa Ziehau 		    NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO);
272815516c77SSepherosa Ziehau #ifdef INET
272915516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
273015516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV4(0,
273115516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
273215516c77SSepherosa Ziehau 		}
273315516c77SSepherosa Ziehau #endif
273415516c77SSepherosa Ziehau #if defined(INET6) && defined(INET)
273515516c77SSepherosa Ziehau 		else
273615516c77SSepherosa Ziehau #endif
273715516c77SSepherosa Ziehau #ifdef INET6
273815516c77SSepherosa Ziehau 		{
273915516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV6(0,
274015516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
274115516c77SSepherosa Ziehau 		}
274215516c77SSepherosa Ziehau #endif
274315516c77SSepherosa Ziehau #endif	/* INET6 || INET */
274415516c77SSepherosa Ziehau 	} else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) {
274515516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
274615516c77SSepherosa Ziehau 		    NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
274715516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
274815516c77SSepherosa Ziehau 		    (CSUM_IP6_TCP | CSUM_IP6_UDP)) {
274915516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV6;
275015516c77SSepherosa Ziehau 		} else {
275115516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV4;
275215516c77SSepherosa Ziehau 			if (m_head->m_pkthdr.csum_flags & CSUM_IP)
275315516c77SSepherosa Ziehau 				*pi_data |= NDIS_TXCSUM_INFO_IPCS;
275415516c77SSepherosa Ziehau 		}
275515516c77SSepherosa Ziehau 
275615516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP))
275715516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_TCPCS;
275815516c77SSepherosa Ziehau 		else if (m_head->m_pkthdr.csum_flags &
275915516c77SSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP6_UDP))
276015516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_UDPCS;
276115516c77SSepherosa Ziehau 	}
276215516c77SSepherosa Ziehau 
2763dc13fee6SSepherosa Ziehau 	pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
27648fe90f73SSepherosa Ziehau 	/* Fixup RNDIS packet message total length */
27658fe90f73SSepherosa Ziehau 	pkt->rm_len += pkt_hlen;
276615516c77SSepherosa Ziehau 	/* Convert RNDIS packet message offsets */
27679130c4f7SSepherosa Ziehau 	pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt_hlen);
276815516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset);
276915516c77SSepherosa Ziehau 
277015516c77SSepherosa Ziehau 	/*
27718966e5d5SSepherosa Ziehau 	 * Fast path: Chimney sending.
277215516c77SSepherosa Ziehau 	 */
27738966e5d5SSepherosa Ziehau 	if (chim != NULL) {
2774dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tgt_txd = txd;
2775dc13fee6SSepherosa Ziehau 
2776dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL) {
2777dc13fee6SSepherosa Ziehau 			tgt_txd = txr->hn_agg_txd;
2778dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
2779dc13fee6SSepherosa Ziehau 			*m_head0 = NULL;
2780dc13fee6SSepherosa Ziehau #endif
2781dc13fee6SSepherosa Ziehau 		}
2782dc13fee6SSepherosa Ziehau 
2783dc13fee6SSepherosa Ziehau 		KASSERT(pkt == chim,
2784dc13fee6SSepherosa Ziehau 		    ("RNDIS pkt not in chimney sending buffer"));
2785dc13fee6SSepherosa Ziehau 		KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID,
2786dc13fee6SSepherosa Ziehau 		    ("chimney sending buffer is not used"));
2787dc13fee6SSepherosa Ziehau 		tgt_txd->chim_size += pkt->rm_len;
278815516c77SSepherosa Ziehau 
27898966e5d5SSepherosa Ziehau 		m_copydata(m_head, 0, m_head->m_pkthdr.len,
2790dc13fee6SSepherosa Ziehau 		    ((uint8_t *)chim) + pkt_hlen);
279115516c77SSepherosa Ziehau 
279215516c77SSepherosa Ziehau 		txr->hn_gpa_cnt = 0;
279315516c77SSepherosa Ziehau 		txr->hn_sendpkt = hn_txpkt_chim;
279415516c77SSepherosa Ziehau 		goto done;
279515516c77SSepherosa Ziehau 	}
2796dc13fee6SSepherosa Ziehau 
2797dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc"));
27988966e5d5SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
27998966e5d5SSepherosa Ziehau 	    ("chimney buffer is used"));
28008966e5d5SSepherosa Ziehau 	KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc"));
280115516c77SSepherosa Ziehau 
280215516c77SSepherosa Ziehau 	error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs);
2803dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
280415516c77SSepherosa Ziehau 		int freed;
280515516c77SSepherosa Ziehau 
280615516c77SSepherosa Ziehau 		/*
280715516c77SSepherosa Ziehau 		 * This mbuf is not linked w/ the txd yet, so free it now.
280815516c77SSepherosa Ziehau 		 */
280915516c77SSepherosa Ziehau 		m_freem(m_head);
281015516c77SSepherosa Ziehau 		*m_head0 = NULL;
281115516c77SSepherosa Ziehau 
281215516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
281315516c77SSepherosa Ziehau 		KASSERT(freed != 0,
281415516c77SSepherosa Ziehau 		    ("fail to free txd upon txdma error"));
281515516c77SSepherosa Ziehau 
281615516c77SSepherosa Ziehau 		txr->hn_txdma_failed++;
2817dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
281815516c77SSepherosa Ziehau 		return error;
281915516c77SSepherosa Ziehau 	}
282015516c77SSepherosa Ziehau 	*m_head0 = m_head;
282115516c77SSepherosa Ziehau 
282215516c77SSepherosa Ziehau 	/* +1 RNDIS packet message */
282315516c77SSepherosa Ziehau 	txr->hn_gpa_cnt = nsegs + 1;
282415516c77SSepherosa Ziehau 
282515516c77SSepherosa Ziehau 	/* send packet with page buffer */
282615516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr);
282715516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK;
2828dc13fee6SSepherosa Ziehau 	txr->hn_gpa[0].gpa_len = pkt_hlen;
282915516c77SSepherosa Ziehau 
283015516c77SSepherosa Ziehau 	/*
283115516c77SSepherosa Ziehau 	 * Fill the page buffers with mbuf info after the page
283215516c77SSepherosa Ziehau 	 * buffer for RNDIS packet message.
283315516c77SSepherosa Ziehau 	 */
283415516c77SSepherosa Ziehau 	for (i = 0; i < nsegs; ++i) {
283515516c77SSepherosa Ziehau 		struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1];
283615516c77SSepherosa Ziehau 
283715516c77SSepherosa Ziehau 		gpa->gpa_page = atop(segs[i].ds_addr);
283815516c77SSepherosa Ziehau 		gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK;
283915516c77SSepherosa Ziehau 		gpa->gpa_len = segs[i].ds_len;
284015516c77SSepherosa Ziehau 	}
284115516c77SSepherosa Ziehau 
284215516c77SSepherosa Ziehau 	txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
284315516c77SSepherosa Ziehau 	txd->chim_size = 0;
284415516c77SSepherosa Ziehau 	txr->hn_sendpkt = hn_txpkt_sglist;
284515516c77SSepherosa Ziehau done:
284615516c77SSepherosa Ziehau 	txd->m = m_head;
284715516c77SSepherosa Ziehau 
284815516c77SSepherosa Ziehau 	/* Set the completion routine */
284915516c77SSepherosa Ziehau 	hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd);
285015516c77SSepherosa Ziehau 
2851dc13fee6SSepherosa Ziehau 	/* Update temporary stats for later use. */
2852dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts++;
2853dc13fee6SSepherosa Ziehau 	txr->hn_stat_size += m_head->m_pkthdr.len;
2854dc13fee6SSepherosa Ziehau 	if (m_head->m_flags & M_MCAST)
2855dc13fee6SSepherosa Ziehau 		txr->hn_stat_mcasts++;
2856dc13fee6SSepherosa Ziehau 
285715516c77SSepherosa Ziehau 	return 0;
285815516c77SSepherosa Ziehau }
285915516c77SSepherosa Ziehau 
286015516c77SSepherosa Ziehau /*
286115516c77SSepherosa Ziehau  * NOTE:
286215516c77SSepherosa Ziehau  * If this function fails, then txd will be freed, but the mbuf
286315516c77SSepherosa Ziehau  * associated w/ the txd will _not_ be freed.
286415516c77SSepherosa Ziehau  */
286515516c77SSepherosa Ziehau static int
286615516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd)
286715516c77SSepherosa Ziehau {
28688e7d3136SSepherosa Ziehau 	int error, send_failed = 0, has_bpf;
286915516c77SSepherosa Ziehau 
287015516c77SSepherosa Ziehau again:
28718e7d3136SSepherosa Ziehau 	has_bpf = bpf_peers_present(ifp->if_bpf);
28728e7d3136SSepherosa Ziehau 	if (has_bpf) {
287315516c77SSepherosa Ziehau 		/*
28748e7d3136SSepherosa Ziehau 		 * Make sure that this txd and any aggregated txds are not
28758e7d3136SSepherosa Ziehau 		 * freed before ETHER_BPF_MTAP.
287615516c77SSepherosa Ziehau 		 */
287715516c77SSepherosa Ziehau 		hn_txdesc_hold(txd);
28788e7d3136SSepherosa Ziehau 	}
287915516c77SSepherosa Ziehau 	error = txr->hn_sendpkt(txr, txd);
288015516c77SSepherosa Ziehau 	if (!error) {
28818e7d3136SSepherosa Ziehau 		if (has_bpf) {
2882dc13fee6SSepherosa Ziehau 			const struct hn_txdesc *tmp_txd;
2883dc13fee6SSepherosa Ziehau 
288415516c77SSepherosa Ziehau 			ETHER_BPF_MTAP(ifp, txd->m);
2885dc13fee6SSepherosa Ziehau 			STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link)
2886dc13fee6SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, tmp_txd->m);
2887dc13fee6SSepherosa Ziehau 		}
2888dc13fee6SSepherosa Ziehau 
2889dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts);
289023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
289123bf9e15SSepherosa Ziehau 		if (!hn_use_if_start)
289223bf9e15SSepherosa Ziehau #endif
289323bf9e15SSepherosa Ziehau 		{
289415516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OBYTES,
2895dc13fee6SSepherosa Ziehau 			    txr->hn_stat_size);
2896dc13fee6SSepherosa Ziehau 			if (txr->hn_stat_mcasts != 0) {
2897dc13fee6SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OMCASTS,
2898dc13fee6SSepherosa Ziehau 				    txr->hn_stat_mcasts);
289915516c77SSepherosa Ziehau 			}
2900dc13fee6SSepherosa Ziehau 		}
2901dc13fee6SSepherosa Ziehau 		txr->hn_pkts += txr->hn_stat_pkts;
2902dc13fee6SSepherosa Ziehau 		txr->hn_sends++;
290315516c77SSepherosa Ziehau 	}
29048e7d3136SSepherosa Ziehau 	if (has_bpf)
290515516c77SSepherosa Ziehau 		hn_txdesc_put(txr, txd);
290615516c77SSepherosa Ziehau 
290715516c77SSepherosa Ziehau 	if (__predict_false(error)) {
290815516c77SSepherosa Ziehau 		int freed;
290915516c77SSepherosa Ziehau 
291015516c77SSepherosa Ziehau 		/*
291115516c77SSepherosa Ziehau 		 * This should "really rarely" happen.
291215516c77SSepherosa Ziehau 		 *
291315516c77SSepherosa Ziehau 		 * XXX Too many RX to be acked or too many sideband
291415516c77SSepherosa Ziehau 		 * commands to run?  Ask netvsc_channel_rollup()
291515516c77SSepherosa Ziehau 		 * to kick start later.
291615516c77SSepherosa Ziehau 		 */
291715516c77SSepherosa Ziehau 		txr->hn_has_txeof = 1;
291815516c77SSepherosa Ziehau 		if (!send_failed) {
291915516c77SSepherosa Ziehau 			txr->hn_send_failed++;
292015516c77SSepherosa Ziehau 			send_failed = 1;
292115516c77SSepherosa Ziehau 			/*
292215516c77SSepherosa Ziehau 			 * Try sending again after set hn_has_txeof;
292315516c77SSepherosa Ziehau 			 * in case that we missed the last
292415516c77SSepherosa Ziehau 			 * netvsc_channel_rollup().
292515516c77SSepherosa Ziehau 			 */
292615516c77SSepherosa Ziehau 			goto again;
292715516c77SSepherosa Ziehau 		}
292815516c77SSepherosa Ziehau 		if_printf(ifp, "send failed\n");
292915516c77SSepherosa Ziehau 
293015516c77SSepherosa Ziehau 		/*
293115516c77SSepherosa Ziehau 		 * Caller will perform further processing on the
293215516c77SSepherosa Ziehau 		 * associated mbuf, so don't free it in hn_txdesc_put();
293315516c77SSepherosa Ziehau 		 * only unload it from the DMA map in hn_txdesc_put(),
293415516c77SSepherosa Ziehau 		 * if it was loaded.
293515516c77SSepherosa Ziehau 		 */
293615516c77SSepherosa Ziehau 		txd->m = NULL;
293715516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
293815516c77SSepherosa Ziehau 		KASSERT(freed != 0,
293915516c77SSepherosa Ziehau 		    ("fail to free txd upon send error"));
294015516c77SSepherosa Ziehau 
294115516c77SSepherosa Ziehau 		txr->hn_send_failed++;
294215516c77SSepherosa Ziehau 	}
2943dc13fee6SSepherosa Ziehau 
2944dc13fee6SSepherosa Ziehau 	/* Reset temporary stats, after this sending is done. */
2945dc13fee6SSepherosa Ziehau 	txr->hn_stat_size = 0;
2946dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts = 0;
2947dc13fee6SSepherosa Ziehau 	txr->hn_stat_mcasts = 0;
2948dc13fee6SSepherosa Ziehau 
2949dc13fee6SSepherosa Ziehau 	return (error);
295015516c77SSepherosa Ziehau }
295115516c77SSepherosa Ziehau 
295215516c77SSepherosa Ziehau /*
295315516c77SSepherosa Ziehau  * Append the specified data to the indicated mbuf chain,
295415516c77SSepherosa Ziehau  * Extend the mbuf chain if the new data does not fit in
295515516c77SSepherosa Ziehau  * existing space.
295615516c77SSepherosa Ziehau  *
295715516c77SSepherosa Ziehau  * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c.
295815516c77SSepherosa Ziehau  * There should be an equivalent in the kernel mbuf code,
295915516c77SSepherosa Ziehau  * but there does not appear to be one yet.
296015516c77SSepherosa Ziehau  *
296115516c77SSepherosa Ziehau  * Differs from m_append() in that additional mbufs are
296215516c77SSepherosa Ziehau  * allocated with cluster size MJUMPAGESIZE, and filled
296315516c77SSepherosa Ziehau  * accordingly.
296415516c77SSepherosa Ziehau  *
296515516c77SSepherosa Ziehau  * Return 1 if able to complete the job; otherwise 0.
296615516c77SSepherosa Ziehau  */
296715516c77SSepherosa Ziehau static int
296815516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp)
296915516c77SSepherosa Ziehau {
297015516c77SSepherosa Ziehau 	struct mbuf *m, *n;
297115516c77SSepherosa Ziehau 	int remainder, space;
297215516c77SSepherosa Ziehau 
297315516c77SSepherosa Ziehau 	for (m = m0; m->m_next != NULL; m = m->m_next)
297415516c77SSepherosa Ziehau 		;
297515516c77SSepherosa Ziehau 	remainder = len;
297615516c77SSepherosa Ziehau 	space = M_TRAILINGSPACE(m);
297715516c77SSepherosa Ziehau 	if (space > 0) {
297815516c77SSepherosa Ziehau 		/*
297915516c77SSepherosa Ziehau 		 * Copy into available space.
298015516c77SSepherosa Ziehau 		 */
298115516c77SSepherosa Ziehau 		if (space > remainder)
298215516c77SSepherosa Ziehau 			space = remainder;
298315516c77SSepherosa Ziehau 		bcopy(cp, mtod(m, caddr_t) + m->m_len, space);
298415516c77SSepherosa Ziehau 		m->m_len += space;
298515516c77SSepherosa Ziehau 		cp += space;
298615516c77SSepherosa Ziehau 		remainder -= space;
298715516c77SSepherosa Ziehau 	}
298815516c77SSepherosa Ziehau 	while (remainder > 0) {
298915516c77SSepherosa Ziehau 		/*
299015516c77SSepherosa Ziehau 		 * Allocate a new mbuf; could check space
299115516c77SSepherosa Ziehau 		 * and allocate a cluster instead.
299215516c77SSepherosa Ziehau 		 */
299315516c77SSepherosa Ziehau 		n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE);
299415516c77SSepherosa Ziehau 		if (n == NULL)
299515516c77SSepherosa Ziehau 			break;
299615516c77SSepherosa Ziehau 		n->m_len = min(MJUMPAGESIZE, remainder);
299715516c77SSepherosa Ziehau 		bcopy(cp, mtod(n, caddr_t), n->m_len);
299815516c77SSepherosa Ziehau 		cp += n->m_len;
299915516c77SSepherosa Ziehau 		remainder -= n->m_len;
300015516c77SSepherosa Ziehau 		m->m_next = n;
300115516c77SSepherosa Ziehau 		m = n;
300215516c77SSepherosa Ziehau 	}
300315516c77SSepherosa Ziehau 	if (m0->m_flags & M_PKTHDR)
300415516c77SSepherosa Ziehau 		m0->m_pkthdr.len += len - remainder;
300515516c77SSepherosa Ziehau 
300615516c77SSepherosa Ziehau 	return (remainder == 0);
300715516c77SSepherosa Ziehau }
300815516c77SSepherosa Ziehau 
300915516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
301015516c77SSepherosa Ziehau static __inline int
301115516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m)
301215516c77SSepherosa Ziehau {
301315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
301415516c77SSepherosa Ziehau 	if (hn_lro_mbufq_depth) {
301515516c77SSepherosa Ziehau 		tcp_lro_queue_mbuf(lc, m);
301615516c77SSepherosa Ziehau 		return 0;
301715516c77SSepherosa Ziehau 	}
301815516c77SSepherosa Ziehau #endif
301915516c77SSepherosa Ziehau 	return tcp_lro_rx(lc, m, 0);
302015516c77SSepherosa Ziehau }
302115516c77SSepherosa Ziehau #endif
302215516c77SSepherosa Ziehau 
302315516c77SSepherosa Ziehau static int
302415516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
302515516c77SSepherosa Ziehau     const struct hn_rxinfo *info)
302615516c77SSepherosa Ziehau {
3027a97fff19SSepherosa Ziehau 	struct ifnet *ifp, *hn_ifp = rxr->hn_ifp;
302815516c77SSepherosa Ziehau 	struct mbuf *m_new;
302915516c77SSepherosa Ziehau 	int size, do_lro = 0, do_csum = 1;
303015516c77SSepherosa Ziehau 	int hash_type;
303115516c77SSepherosa Ziehau 
3032a97fff19SSepherosa Ziehau 	/*
3033a97fff19SSepherosa Ziehau 	 * If the non-transparent mode VF is active, inject this packet
3034a97fff19SSepherosa Ziehau 	 * into the VF.
3035a97fff19SSepherosa Ziehau 	 */
3036a97fff19SSepherosa Ziehau 	ifp = rxr->hn_rxvf_ifp ? rxr->hn_rxvf_ifp : hn_ifp;
30375bdfd3fdSDexuan Cui 
3038b3b75d9cSSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
3039b3b75d9cSSepherosa Ziehau 		/*
3040b3b75d9cSSepherosa Ziehau 		 * NOTE:
3041b3b75d9cSSepherosa Ziehau 		 * See the NOTE of hn_rndis_init_fixat().  This
3042b3b75d9cSSepherosa Ziehau 		 * function can be reached, immediately after the
3043b3b75d9cSSepherosa Ziehau 		 * RNDIS is initialized but before the ifnet is
3044b3b75d9cSSepherosa Ziehau 		 * setup on the hn_attach() path; drop the unexpected
3045b3b75d9cSSepherosa Ziehau 		 * packets.
3046b3b75d9cSSepherosa Ziehau 		 */
3047b3b75d9cSSepherosa Ziehau 		return (0);
3048b3b75d9cSSepherosa Ziehau 	}
3049b3b75d9cSSepherosa Ziehau 
3050a97fff19SSepherosa Ziehau 	if (__predict_false(dlen < ETHER_HDR_LEN)) {
3051a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IERRORS, 1);
3052a97fff19SSepherosa Ziehau 		return (0);
3053a97fff19SSepherosa Ziehau 	}
3054a97fff19SSepherosa Ziehau 
3055c927d681SDexuan Cui 	if (dlen <= MHLEN) {
305615516c77SSepherosa Ziehau 		m_new = m_gethdr(M_NOWAIT, MT_DATA);
305715516c77SSepherosa Ziehau 		if (m_new == NULL) {
3058a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1);
305915516c77SSepherosa Ziehau 			return (0);
306015516c77SSepherosa Ziehau 		}
306115516c77SSepherosa Ziehau 		memcpy(mtod(m_new, void *), data, dlen);
306215516c77SSepherosa Ziehau 		m_new->m_pkthdr.len = m_new->m_len = dlen;
306315516c77SSepherosa Ziehau 		rxr->hn_small_pkts++;
306415516c77SSepherosa Ziehau 	} else {
306515516c77SSepherosa Ziehau 		/*
306615516c77SSepherosa Ziehau 		 * Get an mbuf with a cluster.  For packets 2K or less,
306715516c77SSepherosa Ziehau 		 * get a standard 2K cluster.  For anything larger, get a
306815516c77SSepherosa Ziehau 		 * 4K cluster.  Any buffers larger than 4K can cause problems
306915516c77SSepherosa Ziehau 		 * if looped around to the Hyper-V TX channel, so avoid them.
307015516c77SSepherosa Ziehau 		 */
307115516c77SSepherosa Ziehau 		size = MCLBYTES;
307215516c77SSepherosa Ziehau 		if (dlen > MCLBYTES) {
307315516c77SSepherosa Ziehau 			/* 4096 */
307415516c77SSepherosa Ziehau 			size = MJUMPAGESIZE;
307515516c77SSepherosa Ziehau 		}
307615516c77SSepherosa Ziehau 
307715516c77SSepherosa Ziehau 		m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size);
307815516c77SSepherosa Ziehau 		if (m_new == NULL) {
3079a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IQDROPS, 1);
308015516c77SSepherosa Ziehau 			return (0);
308115516c77SSepherosa Ziehau 		}
308215516c77SSepherosa Ziehau 
308315516c77SSepherosa Ziehau 		hv_m_append(m_new, dlen, data);
308415516c77SSepherosa Ziehau 	}
308515516c77SSepherosa Ziehau 	m_new->m_pkthdr.rcvif = ifp;
308615516c77SSepherosa Ziehau 
3087a97fff19SSepherosa Ziehau 	if (__predict_false((hn_ifp->if_capenable & IFCAP_RXCSUM) == 0))
308815516c77SSepherosa Ziehau 		do_csum = 0;
308915516c77SSepherosa Ziehau 
309015516c77SSepherosa Ziehau 	/* receive side checksum offload */
309115516c77SSepherosa Ziehau 	if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) {
309215516c77SSepherosa Ziehau 		/* IP csum offload */
309315516c77SSepherosa Ziehau 		if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) {
309415516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
309515516c77SSepherosa Ziehau 			    (CSUM_IP_CHECKED | CSUM_IP_VALID);
309615516c77SSepherosa Ziehau 			rxr->hn_csum_ip++;
309715516c77SSepherosa Ziehau 		}
309815516c77SSepherosa Ziehau 
309915516c77SSepherosa Ziehau 		/* TCP/UDP csum offload */
310015516c77SSepherosa Ziehau 		if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK |
310115516c77SSepherosa Ziehau 		     NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) {
310215516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
310315516c77SSepherosa Ziehau 			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
310415516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_data = 0xffff;
310515516c77SSepherosa Ziehau 			if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK)
310615516c77SSepherosa Ziehau 				rxr->hn_csum_tcp++;
310715516c77SSepherosa Ziehau 			else
310815516c77SSepherosa Ziehau 				rxr->hn_csum_udp++;
310915516c77SSepherosa Ziehau 		}
311015516c77SSepherosa Ziehau 
311115516c77SSepherosa Ziehau 		/*
311215516c77SSepherosa Ziehau 		 * XXX
311315516c77SSepherosa Ziehau 		 * As of this write (Oct 28th, 2016), host side will turn
311415516c77SSepherosa Ziehau 		 * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so
311515516c77SSepherosa Ziehau 		 * the do_lro setting here is actually _not_ accurate.  We
311615516c77SSepherosa Ziehau 		 * depend on the RSS hash type check to reset do_lro.
311715516c77SSepherosa Ziehau 		 */
311815516c77SSepherosa Ziehau 		if ((info->csum_info &
311915516c77SSepherosa Ziehau 		     (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) ==
312015516c77SSepherosa Ziehau 		    (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK))
312115516c77SSepherosa Ziehau 			do_lro = 1;
312215516c77SSepherosa Ziehau 	} else {
312315516c77SSepherosa Ziehau 		const struct ether_header *eh;
312415516c77SSepherosa Ziehau 		uint16_t etype;
312515516c77SSepherosa Ziehau 		int hoff;
312615516c77SSepherosa Ziehau 
312715516c77SSepherosa Ziehau 		hoff = sizeof(*eh);
3128a97fff19SSepherosa Ziehau 		/* Checked at the beginning of this function. */
3129a97fff19SSepherosa Ziehau 		KASSERT(m_new->m_len >= hoff, ("not ethernet frame"));
3130a97fff19SSepherosa Ziehau 
313115516c77SSepherosa Ziehau 		eh = mtod(m_new, struct ether_header *);
313215516c77SSepherosa Ziehau 		etype = ntohs(eh->ether_type);
313315516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_VLAN) {
313415516c77SSepherosa Ziehau 			const struct ether_vlan_header *evl;
313515516c77SSepherosa Ziehau 
313615516c77SSepherosa Ziehau 			hoff = sizeof(*evl);
313715516c77SSepherosa Ziehau 			if (m_new->m_len < hoff)
313815516c77SSepherosa Ziehau 				goto skip;
313915516c77SSepherosa Ziehau 			evl = mtod(m_new, struct ether_vlan_header *);
314015516c77SSepherosa Ziehau 			etype = ntohs(evl->evl_proto);
314115516c77SSepherosa Ziehau 		}
314215516c77SSepherosa Ziehau 
314315516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_IP) {
314415516c77SSepherosa Ziehau 			int pr;
314515516c77SSepherosa Ziehau 
314615516c77SSepherosa Ziehau 			pr = hn_check_iplen(m_new, hoff);
314715516c77SSepherosa Ziehau 			if (pr == IPPROTO_TCP) {
314815516c77SSepherosa Ziehau 				if (do_csum &&
314915516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
315015516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_TCP)) {
315115516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
315215516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
315315516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
315415516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
315515516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
315615516c77SSepherosa Ziehau 				}
315715516c77SSepherosa Ziehau 				do_lro = 1;
315815516c77SSepherosa Ziehau 			} else if (pr == IPPROTO_UDP) {
315915516c77SSepherosa Ziehau 				if (do_csum &&
316015516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
316115516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_UDP)) {
316215516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
316315516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
316415516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
316515516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
316615516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
316715516c77SSepherosa Ziehau 				}
316815516c77SSepherosa Ziehau 			} else if (pr != IPPROTO_DONE && do_csum &&
316915516c77SSepherosa Ziehau 			    (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) {
317015516c77SSepherosa Ziehau 				rxr->hn_csum_trusted++;
317115516c77SSepherosa Ziehau 				m_new->m_pkthdr.csum_flags |=
317215516c77SSepherosa Ziehau 				    (CSUM_IP_CHECKED | CSUM_IP_VALID);
317315516c77SSepherosa Ziehau 			}
317415516c77SSepherosa Ziehau 		}
317515516c77SSepherosa Ziehau 	}
317615516c77SSepherosa Ziehau skip:
317715516c77SSepherosa Ziehau 	if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) {
317815516c77SSepherosa Ziehau 		m_new->m_pkthdr.ether_vtag = EVL_MAKETAG(
317915516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_ID(info->vlan_info),
318015516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_PRI(info->vlan_info),
318115516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_CFI(info->vlan_info));
318215516c77SSepherosa Ziehau 		m_new->m_flags |= M_VLANTAG;
318315516c77SSepherosa Ziehau 	}
318415516c77SSepherosa Ziehau 
3185a97fff19SSepherosa Ziehau 	/*
3186a97fff19SSepherosa Ziehau 	 * If VF is activated (tranparent/non-transparent mode does not
3187a97fff19SSepherosa Ziehau 	 * matter here).
3188a97fff19SSepherosa Ziehau 	 *
3189a97fff19SSepherosa Ziehau 	 * - Don't setup mbuf hash, if 'options RSS' is set.
3190a97fff19SSepherosa Ziehau 	 *
3191a97fff19SSepherosa Ziehau 	 *   In Azure, when VF is activated, TCP SYN and SYN|ACK go
3192a97fff19SSepherosa Ziehau 	 *   through hn(4) while the rest of segments and ACKs belonging
3193a97fff19SSepherosa Ziehau 	 *   to the same TCP 4-tuple go through the VF.  So don't setup
3194a97fff19SSepherosa Ziehau 	 *   mbuf hash, if a VF is activated and 'options RSS' is not
3195a97fff19SSepherosa Ziehau 	 *   enabled.  hn(4) and the VF may use neither the same RSS
3196a97fff19SSepherosa Ziehau 	 *   hash key nor the same RSS hash function, so the hash value
3197a97fff19SSepherosa Ziehau 	 *   for packets belonging to the same flow could be different!
3198a97fff19SSepherosa Ziehau 	 *
3199a97fff19SSepherosa Ziehau 	 * - Disable LRO
3200a97fff19SSepherosa Ziehau 	 *
3201a97fff19SSepherosa Ziehau 	 *   hn(4) will only receive broadcast packets, multicast packets,
3202a97fff19SSepherosa Ziehau 	 *   TCP SYN and SYN|ACK (in Azure), LRO is useless for these
3203a97fff19SSepherosa Ziehau 	 *   packet types.
3204a97fff19SSepherosa Ziehau 	 *
3205a97fff19SSepherosa Ziehau 	 *   For non-transparent, we definitely _cannot_ enable LRO at
3206a97fff19SSepherosa Ziehau 	 *   all, since the LRO flush will use hn(4) as the receiving
3207a97fff19SSepherosa Ziehau 	 *   interface; i.e. hn_ifp->if_input(hn_ifp, m).
3208a97fff19SSepherosa Ziehau 	 */
3209a97fff19SSepherosa Ziehau 	if (hn_ifp != ifp || (rxr->hn_rx_flags & HN_RX_FLAG_XPNT_VF)) {
3210a97fff19SSepherosa Ziehau 		do_lro = 0;	/* disable LRO. */
3211a97fff19SSepherosa Ziehau #ifndef RSS
3212a97fff19SSepherosa Ziehau 		goto skip_hash;	/* skip mbuf hash setup */
3213a97fff19SSepherosa Ziehau #endif
3214a97fff19SSepherosa Ziehau 	}
3215a97fff19SSepherosa Ziehau 
321615516c77SSepherosa Ziehau 	if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) {
321715516c77SSepherosa Ziehau 		rxr->hn_rss_pkts++;
321815516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = info->hash_value;
321915516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE_HASH;
322015516c77SSepherosa Ziehau 		if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) ==
322115516c77SSepherosa Ziehau 		    NDIS_HASH_FUNCTION_TOEPLITZ) {
322215516c77SSepherosa Ziehau 			uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK);
322315516c77SSepherosa Ziehau 
322415516c77SSepherosa Ziehau 			/*
322515516c77SSepherosa Ziehau 			 * NOTE:
322615516c77SSepherosa Ziehau 			 * do_lro is resetted, if the hash types are not TCP
322715516c77SSepherosa Ziehau 			 * related.  See the comment in the above csum_flags
322815516c77SSepherosa Ziehau 			 * setup section.
322915516c77SSepherosa Ziehau 			 */
323015516c77SSepherosa Ziehau 			switch (type) {
323115516c77SSepherosa Ziehau 			case NDIS_HASH_IPV4:
323215516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV4;
323315516c77SSepherosa Ziehau 				do_lro = 0;
323415516c77SSepherosa Ziehau 				break;
323515516c77SSepherosa Ziehau 
323615516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV4:
323715516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV4;
323815516c77SSepherosa Ziehau 				break;
323915516c77SSepherosa Ziehau 
324015516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6:
324115516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6;
324215516c77SSepherosa Ziehau 				do_lro = 0;
324315516c77SSepherosa Ziehau 				break;
324415516c77SSepherosa Ziehau 
324515516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6_EX:
324615516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6_EX;
324715516c77SSepherosa Ziehau 				do_lro = 0;
324815516c77SSepherosa Ziehau 				break;
324915516c77SSepherosa Ziehau 
325015516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6:
325115516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6;
325215516c77SSepherosa Ziehau 				break;
325315516c77SSepherosa Ziehau 
325415516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6_EX:
325515516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX;
325615516c77SSepherosa Ziehau 				break;
325715516c77SSepherosa Ziehau 			}
325815516c77SSepherosa Ziehau 		}
325915516c77SSepherosa Ziehau 	} else {
326015516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
326115516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE;
326215516c77SSepherosa Ziehau 	}
326315516c77SSepherosa Ziehau 	M_HASHTYPE_SET(m_new, hash_type);
326415516c77SSepherosa Ziehau 
3265a97fff19SSepherosa Ziehau #ifndef RSS
3266a97fff19SSepherosa Ziehau skip_hash:
3267a97fff19SSepherosa Ziehau #endif
3268a97fff19SSepherosa Ziehau 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
3269a97fff19SSepherosa Ziehau 	if (hn_ifp != ifp) {
3270a97fff19SSepherosa Ziehau 		const struct ether_header *eh;
3271a97fff19SSepherosa Ziehau 
327215516c77SSepherosa Ziehau 		/*
3273a97fff19SSepherosa Ziehau 		 * Non-transparent mode VF is activated.
327415516c77SSepherosa Ziehau 		 */
327515516c77SSepherosa Ziehau 
3276a97fff19SSepherosa Ziehau 		/*
3277a97fff19SSepherosa Ziehau 		 * Allow tapping on hn(4).
3278a97fff19SSepherosa Ziehau 		 */
3279a97fff19SSepherosa Ziehau 		ETHER_BPF_MTAP(hn_ifp, m_new);
3280a97fff19SSepherosa Ziehau 
3281a97fff19SSepherosa Ziehau 		/*
3282a97fff19SSepherosa Ziehau 		 * Update hn(4)'s stats.
3283a97fff19SSepherosa Ziehau 		 */
3284a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IPACKETS, 1);
3285a97fff19SSepherosa Ziehau 		if_inc_counter(hn_ifp, IFCOUNTER_IBYTES, m_new->m_pkthdr.len);
3286a97fff19SSepherosa Ziehau 		/* Checked at the beginning of this function. */
3287a97fff19SSepherosa Ziehau 		KASSERT(m_new->m_len >= ETHER_HDR_LEN, ("not ethernet frame"));
3288a97fff19SSepherosa Ziehau 		eh = mtod(m_new, struct ether_header *);
3289a97fff19SSepherosa Ziehau 		if (ETHER_IS_MULTICAST(eh->ether_dhost))
3290a97fff19SSepherosa Ziehau 			if_inc_counter(hn_ifp, IFCOUNTER_IMCASTS, 1);
3291a97fff19SSepherosa Ziehau 	}
329215516c77SSepherosa Ziehau 	rxr->hn_pkts++;
329315516c77SSepherosa Ziehau 
3294a97fff19SSepherosa Ziehau 	if ((hn_ifp->if_capenable & IFCAP_LRO) && do_lro) {
329515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
329615516c77SSepherosa Ziehau 		struct lro_ctrl *lro = &rxr->hn_lro;
329715516c77SSepherosa Ziehau 
329815516c77SSepherosa Ziehau 		if (lro->lro_cnt) {
329915516c77SSepherosa Ziehau 			rxr->hn_lro_tried++;
330015516c77SSepherosa Ziehau 			if (hn_lro_rx(lro, m_new) == 0) {
330115516c77SSepherosa Ziehau 				/* DONE! */
330215516c77SSepherosa Ziehau 				return 0;
330315516c77SSepherosa Ziehau 			}
330415516c77SSepherosa Ziehau 		}
330515516c77SSepherosa Ziehau #endif
330615516c77SSepherosa Ziehau 	}
3307a97fff19SSepherosa Ziehau 	ifp->if_input(ifp, m_new);
330815516c77SSepherosa Ziehau 
330915516c77SSepherosa Ziehau 	return (0);
331015516c77SSepherosa Ziehau }
331115516c77SSepherosa Ziehau 
331215516c77SSepherosa Ziehau static int
331315516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
331415516c77SSepherosa Ziehau {
331515516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
33169c6cae24SSepherosa Ziehau 	struct ifreq *ifr = (struct ifreq *)data, ifr_vf;
33179c6cae24SSepherosa Ziehau 	struct ifnet *vf_ifp;
331815516c77SSepherosa Ziehau 	int mask, error = 0;
331915516c77SSepherosa Ziehau 
332015516c77SSepherosa Ziehau 	switch (cmd) {
332115516c77SSepherosa Ziehau 	case SIOCSIFMTU:
332215516c77SSepherosa Ziehau 		if (ifr->ifr_mtu > HN_MTU_MAX) {
332315516c77SSepherosa Ziehau 			error = EINVAL;
332415516c77SSepherosa Ziehau 			break;
332515516c77SSepherosa Ziehau 		}
332615516c77SSepherosa Ziehau 
332715516c77SSepherosa Ziehau 		HN_LOCK(sc);
332815516c77SSepherosa Ziehau 
332915516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
333015516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
333115516c77SSepherosa Ziehau 			break;
333215516c77SSepherosa Ziehau 		}
333315516c77SSepherosa Ziehau 
333415516c77SSepherosa Ziehau 		if ((sc->hn_caps & HN_CAP_MTU) == 0) {
333515516c77SSepherosa Ziehau 			/* Can't change MTU */
333615516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
333715516c77SSepherosa Ziehau 			error = EOPNOTSUPP;
333815516c77SSepherosa Ziehau 			break;
333915516c77SSepherosa Ziehau 		}
334015516c77SSepherosa Ziehau 
334115516c77SSepherosa Ziehau 		if (ifp->if_mtu == ifr->ifr_mtu) {
334215516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
334315516c77SSepherosa Ziehau 			break;
334415516c77SSepherosa Ziehau 		}
334515516c77SSepherosa Ziehau 
33469c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
33479c6cae24SSepherosa Ziehau 			vf_ifp = sc->hn_vf_ifp;
33489c6cae24SSepherosa Ziehau 			ifr_vf = *ifr;
33499c6cae24SSepherosa Ziehau 			strlcpy(ifr_vf.ifr_name, vf_ifp->if_xname,
33509c6cae24SSepherosa Ziehau 			    sizeof(ifr_vf.ifr_name));
33519c6cae24SSepherosa Ziehau 			error = vf_ifp->if_ioctl(vf_ifp, SIOCSIFMTU,
33529c6cae24SSepherosa Ziehau 			    (caddr_t)&ifr_vf);
33539c6cae24SSepherosa Ziehau 			if (error) {
33549c6cae24SSepherosa Ziehau 				HN_UNLOCK(sc);
33559c6cae24SSepherosa Ziehau 				if_printf(ifp, "%s SIOCSIFMTU %d failed: %d\n",
33569c6cae24SSepherosa Ziehau 				    vf_ifp->if_xname, ifr->ifr_mtu, error);
33579c6cae24SSepherosa Ziehau 				break;
33589c6cae24SSepherosa Ziehau 			}
33599c6cae24SSepherosa Ziehau 		}
33609c6cae24SSepherosa Ziehau 
336115516c77SSepherosa Ziehau 		/*
336215516c77SSepherosa Ziehau 		 * Suspend this interface before the synthetic parts
336315516c77SSepherosa Ziehau 		 * are ripped.
336415516c77SSepherosa Ziehau 		 */
336515516c77SSepherosa Ziehau 		hn_suspend(sc);
336615516c77SSepherosa Ziehau 
336715516c77SSepherosa Ziehau 		/*
336815516c77SSepherosa Ziehau 		 * Detach the synthetics parts, i.e. NVS and RNDIS.
336915516c77SSepherosa Ziehau 		 */
337015516c77SSepherosa Ziehau 		hn_synth_detach(sc);
337115516c77SSepherosa Ziehau 
337215516c77SSepherosa Ziehau 		/*
337315516c77SSepherosa Ziehau 		 * Reattach the synthetic parts, i.e. NVS and RNDIS,
337415516c77SSepherosa Ziehau 		 * with the new MTU setting.
337515516c77SSepherosa Ziehau 		 */
337615516c77SSepherosa Ziehau 		error = hn_synth_attach(sc, ifr->ifr_mtu);
337715516c77SSepherosa Ziehau 		if (error) {
337815516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
337915516c77SSepherosa Ziehau 			break;
338015516c77SSepherosa Ziehau 		}
338115516c77SSepherosa Ziehau 
338215516c77SSepherosa Ziehau 		/*
338315516c77SSepherosa Ziehau 		 * Commit the requested MTU, after the synthetic parts
338415516c77SSepherosa Ziehau 		 * have been successfully attached.
338515516c77SSepherosa Ziehau 		 */
338615516c77SSepherosa Ziehau 		ifp->if_mtu = ifr->ifr_mtu;
338715516c77SSepherosa Ziehau 
338815516c77SSepherosa Ziehau 		/*
33899c6cae24SSepherosa Ziehau 		 * Synthetic parts' reattach may change the chimney
33909c6cae24SSepherosa Ziehau 		 * sending size; update it.
339115516c77SSepherosa Ziehau 		 */
339215516c77SSepherosa Ziehau 		if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax)
339315516c77SSepherosa Ziehau 			hn_set_chim_size(sc, sc->hn_chim_szmax);
33949c6cae24SSepherosa Ziehau 
33959c6cae24SSepherosa Ziehau 		/*
33969c6cae24SSepherosa Ziehau 		 * Make sure that various parameters based on MTU are
33979c6cae24SSepherosa Ziehau 		 * still valid, after the MTU change.
33989c6cae24SSepherosa Ziehau 		 */
33999c6cae24SSepherosa Ziehau 		hn_mtu_change_fixup(sc);
340015516c77SSepherosa Ziehau 
340115516c77SSepherosa Ziehau 		/*
340215516c77SSepherosa Ziehau 		 * All done!  Resume the interface now.
340315516c77SSepherosa Ziehau 		 */
340415516c77SSepherosa Ziehau 		hn_resume(sc);
340515516c77SSepherosa Ziehau 
3406d0cd8231SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXVF) ||
3407d0cd8231SSepherosa Ziehau 		    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
34089c6cae24SSepherosa Ziehau 			/*
34099c6cae24SSepherosa Ziehau 			 * Since we have reattached the NVS part,
34109c6cae24SSepherosa Ziehau 			 * change the datapath to VF again; in case
34119c6cae24SSepherosa Ziehau 			 * that it is lost, after the NVS was detached.
34129c6cae24SSepherosa Ziehau 			 */
34139c6cae24SSepherosa Ziehau 			hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_VF);
34149c6cae24SSepherosa Ziehau 		}
34159c6cae24SSepherosa Ziehau 
341615516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
341715516c77SSepherosa Ziehau 		break;
341815516c77SSepherosa Ziehau 
341915516c77SSepherosa Ziehau 	case SIOCSIFFLAGS:
342015516c77SSepherosa Ziehau 		HN_LOCK(sc);
342115516c77SSepherosa Ziehau 
342215516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
342315516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
342415516c77SSepherosa Ziehau 			break;
342515516c77SSepherosa Ziehau 		}
342615516c77SSepherosa Ziehau 
34279c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc))
34289c6cae24SSepherosa Ziehau 			hn_xpnt_vf_saveifflags(sc);
34299c6cae24SSepherosa Ziehau 
343015516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_UP) {
3431fdc4f478SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
3432fdc4f478SSepherosa Ziehau 				/*
3433fdc4f478SSepherosa Ziehau 				 * Caller meight hold mutex, e.g.
3434fdc4f478SSepherosa Ziehau 				 * bpf; use busy-wait for the RNDIS
3435fdc4f478SSepherosa Ziehau 				 * reply.
3436fdc4f478SSepherosa Ziehau 				 */
3437fdc4f478SSepherosa Ziehau 				HN_NO_SLEEPING(sc);
3438c08f7b2cSSepherosa Ziehau 				hn_rxfilter_config(sc);
3439fdc4f478SSepherosa Ziehau 				HN_SLEEPING_OK(sc);
34409c6cae24SSepherosa Ziehau 
34419c6cae24SSepherosa Ziehau 				if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
34429c6cae24SSepherosa Ziehau 					error = hn_xpnt_vf_iocsetflags(sc);
3443fdc4f478SSepherosa Ziehau 			} else {
344415516c77SSepherosa Ziehau 				hn_init_locked(sc);
3445fdc4f478SSepherosa Ziehau 			}
344615516c77SSepherosa Ziehau 		} else {
344715516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
34485bdfd3fdSDexuan Cui 				hn_stop(sc, false);
344915516c77SSepherosa Ziehau 		}
345015516c77SSepherosa Ziehau 		sc->hn_if_flags = ifp->if_flags;
345115516c77SSepherosa Ziehau 
345215516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
345315516c77SSepherosa Ziehau 		break;
345415516c77SSepherosa Ziehau 
345515516c77SSepherosa Ziehau 	case SIOCSIFCAP:
345615516c77SSepherosa Ziehau 		HN_LOCK(sc);
34579c6cae24SSepherosa Ziehau 
34589c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
34599c6cae24SSepherosa Ziehau 			ifr_vf = *ifr;
34609c6cae24SSepherosa Ziehau 			strlcpy(ifr_vf.ifr_name, sc->hn_vf_ifp->if_xname,
34619c6cae24SSepherosa Ziehau 			    sizeof(ifr_vf.ifr_name));
34629c6cae24SSepherosa Ziehau 			error = hn_xpnt_vf_iocsetcaps(sc, &ifr_vf);
34639c6cae24SSepherosa Ziehau 			HN_UNLOCK(sc);
34649c6cae24SSepherosa Ziehau 			break;
34659c6cae24SSepherosa Ziehau 		}
34669c6cae24SSepherosa Ziehau 
34679c6cae24SSepherosa Ziehau 		/*
34689c6cae24SSepherosa Ziehau 		 * Fix up requested capabilities w/ supported capabilities,
34699c6cae24SSepherosa Ziehau 		 * since the supported capabilities could have been changed.
34709c6cae24SSepherosa Ziehau 		 */
34719c6cae24SSepherosa Ziehau 		mask = (ifr->ifr_reqcap & ifp->if_capabilities) ^
34729c6cae24SSepherosa Ziehau 		    ifp->if_capenable;
347315516c77SSepherosa Ziehau 
347415516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM) {
347515516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM;
347615516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM)
347715516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc);
347815516c77SSepherosa Ziehau 			else
347915516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc);
348015516c77SSepherosa Ziehau 		}
348115516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM_IPV6) {
348215516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
348315516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
348415516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc);
348515516c77SSepherosa Ziehau 			else
348615516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc);
348715516c77SSepherosa Ziehau 		}
348815516c77SSepherosa Ziehau 
348915516c77SSepherosa Ziehau 		/* TODO: flip RNDIS offload parameters for RXCSUM. */
349015516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM)
349115516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM;
349215516c77SSepherosa Ziehau #ifdef foo
349315516c77SSepherosa Ziehau 		/* We can't diff IPv6 packets from IPv4 packets on RX path. */
349415516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM_IPV6)
349515516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
349615516c77SSepherosa Ziehau #endif
349715516c77SSepherosa Ziehau 
349815516c77SSepherosa Ziehau 		if (mask & IFCAP_LRO)
349915516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_LRO;
350015516c77SSepherosa Ziehau 
350115516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO4) {
350215516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO4;
350315516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO4)
350415516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP_TSO;
350515516c77SSepherosa Ziehau 			else
350615516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP_TSO;
350715516c77SSepherosa Ziehau 		}
350815516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO6) {
350915516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO6;
351015516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO6)
351115516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP6_TSO;
351215516c77SSepherosa Ziehau 			else
351315516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP6_TSO;
351415516c77SSepherosa Ziehau 		}
351515516c77SSepherosa Ziehau 
351615516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
351715516c77SSepherosa Ziehau 		break;
351815516c77SSepherosa Ziehau 
351915516c77SSepherosa Ziehau 	case SIOCADDMULTI:
352015516c77SSepherosa Ziehau 	case SIOCDELMULTI:
352115516c77SSepherosa Ziehau 		HN_LOCK(sc);
352215516c77SSepherosa Ziehau 
352315516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
352415516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
352515516c77SSepherosa Ziehau 			break;
352615516c77SSepherosa Ziehau 		}
3527fdc4f478SSepherosa Ziehau 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
3528fdc4f478SSepherosa Ziehau 			/*
3529fdc4f478SSepherosa Ziehau 			 * Multicast uses mutex; use busy-wait for
3530fdc4f478SSepherosa Ziehau 			 * the RNDIS reply.
3531fdc4f478SSepherosa Ziehau 			 */
3532fdc4f478SSepherosa Ziehau 			HN_NO_SLEEPING(sc);
3533c08f7b2cSSepherosa Ziehau 			hn_rxfilter_config(sc);
3534fdc4f478SSepherosa Ziehau 			HN_SLEEPING_OK(sc);
3535fdc4f478SSepherosa Ziehau 		}
353615516c77SSepherosa Ziehau 
35379c6cae24SSepherosa Ziehau 		/* XXX vlan(4) style mcast addr maintenance */
35389c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
35399c6cae24SSepherosa Ziehau 			int old_if_flags;
35409c6cae24SSepherosa Ziehau 
35419c6cae24SSepherosa Ziehau 			old_if_flags = sc->hn_vf_ifp->if_flags;
35429c6cae24SSepherosa Ziehau 			hn_xpnt_vf_saveifflags(sc);
35439c6cae24SSepherosa Ziehau 
35449c6cae24SSepherosa Ziehau 			if ((sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) &&
35459c6cae24SSepherosa Ziehau 			    ((old_if_flags ^ sc->hn_vf_ifp->if_flags) &
35469c6cae24SSepherosa Ziehau 			     IFF_ALLMULTI))
35479c6cae24SSepherosa Ziehau 				error = hn_xpnt_vf_iocsetflags(sc);
35489c6cae24SSepherosa Ziehau 		}
35499c6cae24SSepherosa Ziehau 
355015516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
355115516c77SSepherosa Ziehau 		break;
355215516c77SSepherosa Ziehau 
355315516c77SSepherosa Ziehau 	case SIOCSIFMEDIA:
355415516c77SSepherosa Ziehau 	case SIOCGIFMEDIA:
35559c6cae24SSepherosa Ziehau 		HN_LOCK(sc);
35569c6cae24SSepherosa Ziehau 		if (hn_xpnt_vf_isready(sc)) {
35579c6cae24SSepherosa Ziehau 			/*
35589c6cae24SSepherosa Ziehau 			 * SIOCGIFMEDIA expects ifmediareq, so don't
35599c6cae24SSepherosa Ziehau 			 * create and pass ifr_vf to the VF here; just
35609c6cae24SSepherosa Ziehau 			 * replace the ifr_name.
35619c6cae24SSepherosa Ziehau 			 */
35629c6cae24SSepherosa Ziehau 			vf_ifp = sc->hn_vf_ifp;
35639c6cae24SSepherosa Ziehau 			strlcpy(ifr->ifr_name, vf_ifp->if_xname,
35649c6cae24SSepherosa Ziehau 			    sizeof(ifr->ifr_name));
35659c6cae24SSepherosa Ziehau 			error = vf_ifp->if_ioctl(vf_ifp, cmd, data);
35669c6cae24SSepherosa Ziehau 			/* Restore the ifr_name. */
35679c6cae24SSepherosa Ziehau 			strlcpy(ifr->ifr_name, ifp->if_xname,
35689c6cae24SSepherosa Ziehau 			    sizeof(ifr->ifr_name));
35699c6cae24SSepherosa Ziehau 			HN_UNLOCK(sc);
35709c6cae24SSepherosa Ziehau 			break;
35719c6cae24SSepherosa Ziehau 		}
35729c6cae24SSepherosa Ziehau 		HN_UNLOCK(sc);
357315516c77SSepherosa Ziehau 		error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd);
357415516c77SSepherosa Ziehau 		break;
357515516c77SSepherosa Ziehau 
357615516c77SSepherosa Ziehau 	default:
357715516c77SSepherosa Ziehau 		error = ether_ioctl(ifp, cmd, data);
357815516c77SSepherosa Ziehau 		break;
357915516c77SSepherosa Ziehau 	}
358015516c77SSepherosa Ziehau 	return (error);
358115516c77SSepherosa Ziehau }
358215516c77SSepherosa Ziehau 
358315516c77SSepherosa Ziehau static void
35845bdfd3fdSDexuan Cui hn_stop(struct hn_softc *sc, bool detaching)
358515516c77SSepherosa Ziehau {
358615516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
358715516c77SSepherosa Ziehau 	int i;
358815516c77SSepherosa Ziehau 
358915516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
359015516c77SSepherosa Ziehau 
359115516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
359215516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
359315516c77SSepherosa Ziehau 
35949c6cae24SSepherosa Ziehau 	/* Clear RUNNING bit ASAP. */
35959c6cae24SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
35969c6cae24SSepherosa Ziehau 
35976c1204dfSSepherosa Ziehau 	/* Disable polling. */
35986c1204dfSSepherosa Ziehau 	hn_polling(sc, 0);
35996c1204dfSSepherosa Ziehau 
36009c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) {
36019c6cae24SSepherosa Ziehau 		KASSERT(sc->hn_vf_ifp != NULL,
36029c6cae24SSepherosa Ziehau 		    ("%s: VF is not attached", ifp->if_xname));
36039c6cae24SSepherosa Ziehau 
3604a97fff19SSepherosa Ziehau 		/* Mark transparent mode VF as disabled. */
3605a97fff19SSepherosa Ziehau 		hn_xpnt_vf_setdisable(sc, false /* keep hn_vf_ifp */);
36069c6cae24SSepherosa Ziehau 
36079c6cae24SSepherosa Ziehau 		/*
36089c6cae24SSepherosa Ziehau 		 * NOTE:
36099c6cae24SSepherosa Ziehau 		 * Datapath setting must happen _before_ bringing
36109c6cae24SSepherosa Ziehau 		 * the VF down.
36119c6cae24SSepherosa Ziehau 		 */
36129c6cae24SSepherosa Ziehau 		hn_nvs_set_datapath(sc, HN_NVS_DATAPATH_SYNTH);
36139c6cae24SSepherosa Ziehau 
36149c6cae24SSepherosa Ziehau 		/*
36159c6cae24SSepherosa Ziehau 		 * Bring the VF down.
36169c6cae24SSepherosa Ziehau 		 */
36179c6cae24SSepherosa Ziehau 		hn_xpnt_vf_saveifflags(sc);
36189c6cae24SSepherosa Ziehau 		sc->hn_vf_ifp->if_flags &= ~IFF_UP;
36199c6cae24SSepherosa Ziehau 		hn_xpnt_vf_iocsetflags(sc);
36209c6cae24SSepherosa Ziehau 	}
36219c6cae24SSepherosa Ziehau 
36229c6cae24SSepherosa Ziehau 	/* Suspend data transfers. */
362315516c77SSepherosa Ziehau 	hn_suspend_data(sc);
362415516c77SSepherosa Ziehau 
362515516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
362615516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
362715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
362815516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
36295bdfd3fdSDexuan Cui 
36305bdfd3fdSDexuan Cui 	/*
36319c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is active, make sure
36329c6cae24SSepherosa Ziehau 	 * that the RX filter still allows packet reception.
36335bdfd3fdSDexuan Cui 	 */
3634962f0357SSepherosa Ziehau 	if (!detaching && (sc->hn_flags & HN_FLAG_RXVF))
36355bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
363615516c77SSepherosa Ziehau }
363715516c77SSepherosa Ziehau 
363815516c77SSepherosa Ziehau static void
363915516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc)
364015516c77SSepherosa Ziehau {
364115516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
364215516c77SSepherosa Ziehau 	int i;
364315516c77SSepherosa Ziehau 
364415516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
364515516c77SSepherosa Ziehau 
364615516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
364715516c77SSepherosa Ziehau 		return;
364815516c77SSepherosa Ziehau 
364915516c77SSepherosa Ziehau 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
365015516c77SSepherosa Ziehau 		return;
365115516c77SSepherosa Ziehau 
365215516c77SSepherosa Ziehau 	/* Configure RX filter */
3653c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
365415516c77SSepherosa Ziehau 
365515516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
365615516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
365715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
365815516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
365915516c77SSepherosa Ziehau 
366015516c77SSepherosa Ziehau 	/* Clear TX 'suspended' bit. */
366115516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_inuse);
366215516c77SSepherosa Ziehau 
36639c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_isready(sc)) {
36649c6cae24SSepherosa Ziehau 		/* Initialize transparent VF. */
36659c6cae24SSepherosa Ziehau 		hn_xpnt_vf_init(sc);
36669c6cae24SSepherosa Ziehau 	}
36679c6cae24SSepherosa Ziehau 
366815516c77SSepherosa Ziehau 	/* Everything is ready; unleash! */
366915516c77SSepherosa Ziehau 	atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
36706c1204dfSSepherosa Ziehau 
36716c1204dfSSepherosa Ziehau 	/* Re-enable polling if requested. */
36726c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz > 0)
36736c1204dfSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
367415516c77SSepherosa Ziehau }
367515516c77SSepherosa Ziehau 
367615516c77SSepherosa Ziehau static void
367715516c77SSepherosa Ziehau hn_init(void *xsc)
367815516c77SSepherosa Ziehau {
367915516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
368015516c77SSepherosa Ziehau 
368115516c77SSepherosa Ziehau 	HN_LOCK(sc);
368215516c77SSepherosa Ziehau 	hn_init_locked(sc);
368315516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
368415516c77SSepherosa Ziehau }
368515516c77SSepherosa Ziehau 
368615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
368715516c77SSepherosa Ziehau 
368815516c77SSepherosa Ziehau static int
368915516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
369015516c77SSepherosa Ziehau {
369115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
369215516c77SSepherosa Ziehau 	unsigned int lenlim;
369315516c77SSepherosa Ziehau 	int error;
369415516c77SSepherosa Ziehau 
369515516c77SSepherosa Ziehau 	lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim;
369615516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &lenlim, 0, req);
369715516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
369815516c77SSepherosa Ziehau 		return error;
369915516c77SSepherosa Ziehau 
370015516c77SSepherosa Ziehau 	HN_LOCK(sc);
370115516c77SSepherosa Ziehau 	if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) ||
370215516c77SSepherosa Ziehau 	    lenlim > TCP_LRO_LENGTH_MAX) {
370315516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
370415516c77SSepherosa Ziehau 		return EINVAL;
370515516c77SSepherosa Ziehau 	}
370615516c77SSepherosa Ziehau 	hn_set_lro_lenlim(sc, lenlim);
370715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
370815516c77SSepherosa Ziehau 
370915516c77SSepherosa Ziehau 	return 0;
371015516c77SSepherosa Ziehau }
371115516c77SSepherosa Ziehau 
371215516c77SSepherosa Ziehau static int
371315516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS)
371415516c77SSepherosa Ziehau {
371515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
371615516c77SSepherosa Ziehau 	int ackcnt, error, i;
371715516c77SSepherosa Ziehau 
371815516c77SSepherosa Ziehau 	/*
371915516c77SSepherosa Ziehau 	 * lro_ackcnt_lim is append count limit,
372015516c77SSepherosa Ziehau 	 * +1 to turn it into aggregation limit.
372115516c77SSepherosa Ziehau 	 */
372215516c77SSepherosa Ziehau 	ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1;
372315516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &ackcnt, 0, req);
372415516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
372515516c77SSepherosa Ziehau 		return error;
372615516c77SSepherosa Ziehau 
372715516c77SSepherosa Ziehau 	if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1))
372815516c77SSepherosa Ziehau 		return EINVAL;
372915516c77SSepherosa Ziehau 
373015516c77SSepherosa Ziehau 	/*
373115516c77SSepherosa Ziehau 	 * Convert aggregation limit back to append
373215516c77SSepherosa Ziehau 	 * count limit.
373315516c77SSepherosa Ziehau 	 */
373415516c77SSepherosa Ziehau 	--ackcnt;
373515516c77SSepherosa Ziehau 	HN_LOCK(sc);
3736a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
373715516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt;
373815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
373915516c77SSepherosa Ziehau 	return 0;
374015516c77SSepherosa Ziehau }
374115516c77SSepherosa Ziehau 
374215516c77SSepherosa Ziehau #endif
374315516c77SSepherosa Ziehau 
374415516c77SSepherosa Ziehau static int
374515516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS)
374615516c77SSepherosa Ziehau {
374715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
374815516c77SSepherosa Ziehau 	int hcsum = arg2;
374915516c77SSepherosa Ziehau 	int on, error, i;
375015516c77SSepherosa Ziehau 
375115516c77SSepherosa Ziehau 	on = 0;
375215516c77SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum)
375315516c77SSepherosa Ziehau 		on = 1;
375415516c77SSepherosa Ziehau 
375515516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &on, 0, req);
375615516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
375715516c77SSepherosa Ziehau 		return error;
375815516c77SSepherosa Ziehau 
375915516c77SSepherosa Ziehau 	HN_LOCK(sc);
3760a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
376115516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
376215516c77SSepherosa Ziehau 
376315516c77SSepherosa Ziehau 		if (on)
376415516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= hcsum;
376515516c77SSepherosa Ziehau 		else
376615516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum &= ~hcsum;
376715516c77SSepherosa Ziehau 	}
376815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
376915516c77SSepherosa Ziehau 	return 0;
377015516c77SSepherosa Ziehau }
377115516c77SSepherosa Ziehau 
377215516c77SSepherosa Ziehau static int
377315516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS)
377415516c77SSepherosa Ziehau {
377515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
377615516c77SSepherosa Ziehau 	int chim_size, error;
377715516c77SSepherosa Ziehau 
377815516c77SSepherosa Ziehau 	chim_size = sc->hn_tx_ring[0].hn_chim_size;
377915516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &chim_size, 0, req);
378015516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
378115516c77SSepherosa Ziehau 		return error;
378215516c77SSepherosa Ziehau 
378315516c77SSepherosa Ziehau 	if (chim_size > sc->hn_chim_szmax || chim_size <= 0)
378415516c77SSepherosa Ziehau 		return EINVAL;
378515516c77SSepherosa Ziehau 
378615516c77SSepherosa Ziehau 	HN_LOCK(sc);
378715516c77SSepherosa Ziehau 	hn_set_chim_size(sc, chim_size);
378815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
378915516c77SSepherosa Ziehau 	return 0;
379015516c77SSepherosa Ziehau }
379115516c77SSepherosa Ziehau 
379215516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
379315516c77SSepherosa Ziehau static int
379415516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS)
379515516c77SSepherosa Ziehau {
379615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
379715516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
379815516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
379915516c77SSepherosa Ziehau 	uint64_t stat;
380015516c77SSepherosa Ziehau 
380115516c77SSepherosa Ziehau 	stat = 0;
380215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
380315516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
380415516c77SSepherosa Ziehau 		stat += *((int *)((uint8_t *)rxr + ofs));
380515516c77SSepherosa Ziehau 	}
380615516c77SSepherosa Ziehau 
380715516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
380815516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
380915516c77SSepherosa Ziehau 		return error;
381015516c77SSepherosa Ziehau 
381115516c77SSepherosa Ziehau 	/* Zero out this stat. */
381215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
381315516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
381415516c77SSepherosa Ziehau 		*((int *)((uint8_t *)rxr + ofs)) = 0;
381515516c77SSepherosa Ziehau 	}
381615516c77SSepherosa Ziehau 	return 0;
381715516c77SSepherosa Ziehau }
381815516c77SSepherosa Ziehau #else
381915516c77SSepherosa Ziehau static int
382015516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS)
382115516c77SSepherosa Ziehau {
382215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
382315516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
382415516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
382515516c77SSepherosa Ziehau 	uint64_t stat;
382615516c77SSepherosa Ziehau 
382715516c77SSepherosa Ziehau 	stat = 0;
3828a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
382915516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
383015516c77SSepherosa Ziehau 		stat += *((uint64_t *)((uint8_t *)rxr + ofs));
383115516c77SSepherosa Ziehau 	}
383215516c77SSepherosa Ziehau 
383315516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
383415516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
383515516c77SSepherosa Ziehau 		return error;
383615516c77SSepherosa Ziehau 
383715516c77SSepherosa Ziehau 	/* Zero out this stat. */
3838a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
383915516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
384015516c77SSepherosa Ziehau 		*((uint64_t *)((uint8_t *)rxr + ofs)) = 0;
384115516c77SSepherosa Ziehau 	}
384215516c77SSepherosa Ziehau 	return 0;
384315516c77SSepherosa Ziehau }
384415516c77SSepherosa Ziehau 
384515516c77SSepherosa Ziehau #endif
384615516c77SSepherosa Ziehau 
384715516c77SSepherosa Ziehau static int
384815516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
384915516c77SSepherosa Ziehau {
385015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
385115516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
385215516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
385315516c77SSepherosa Ziehau 	u_long stat;
385415516c77SSepherosa Ziehau 
385515516c77SSepherosa Ziehau 	stat = 0;
3856a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
385715516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
385815516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)rxr + ofs));
385915516c77SSepherosa Ziehau 	}
386015516c77SSepherosa Ziehau 
386115516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
386215516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
386315516c77SSepherosa Ziehau 		return error;
386415516c77SSepherosa Ziehau 
386515516c77SSepherosa Ziehau 	/* Zero out this stat. */
3866a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
386715516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
386815516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)rxr + ofs)) = 0;
386915516c77SSepherosa Ziehau 	}
387015516c77SSepherosa Ziehau 	return 0;
387115516c77SSepherosa Ziehau }
387215516c77SSepherosa Ziehau 
387315516c77SSepherosa Ziehau static int
387415516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
387515516c77SSepherosa Ziehau {
387615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
387715516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
387815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
387915516c77SSepherosa Ziehau 	u_long stat;
388015516c77SSepherosa Ziehau 
388115516c77SSepherosa Ziehau 	stat = 0;
3882a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
388315516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
388415516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)txr + ofs));
388515516c77SSepherosa Ziehau 	}
388615516c77SSepherosa Ziehau 
388715516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
388815516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
388915516c77SSepherosa Ziehau 		return error;
389015516c77SSepherosa Ziehau 
389115516c77SSepherosa Ziehau 	/* Zero out this stat. */
3892a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
389315516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
389415516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)txr + ofs)) = 0;
389515516c77SSepherosa Ziehau 	}
389615516c77SSepherosa Ziehau 	return 0;
389715516c77SSepherosa Ziehau }
389815516c77SSepherosa Ziehau 
389915516c77SSepherosa Ziehau static int
390015516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS)
390115516c77SSepherosa Ziehau {
390215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
390315516c77SSepherosa Ziehau 	int ofs = arg2, i, error, conf;
390415516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
390515516c77SSepherosa Ziehau 
390615516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[0];
390715516c77SSepherosa Ziehau 	conf = *((int *)((uint8_t *)txr + ofs));
390815516c77SSepherosa Ziehau 
390915516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &conf, 0, req);
391015516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
391115516c77SSepherosa Ziehau 		return error;
391215516c77SSepherosa Ziehau 
391315516c77SSepherosa Ziehau 	HN_LOCK(sc);
3914a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
391515516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
391615516c77SSepherosa Ziehau 		*((int *)((uint8_t *)txr + ofs)) = conf;
391715516c77SSepherosa Ziehau 	}
391815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
391915516c77SSepherosa Ziehau 
392015516c77SSepherosa Ziehau 	return 0;
392115516c77SSepherosa Ziehau }
392215516c77SSepherosa Ziehau 
392315516c77SSepherosa Ziehau static int
3924dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS)
3925dc13fee6SSepherosa Ziehau {
3926dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
3927dc13fee6SSepherosa Ziehau 	int error, size;
3928dc13fee6SSepherosa Ziehau 
3929dc13fee6SSepherosa Ziehau 	size = sc->hn_agg_size;
3930dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &size, 0, req);
3931dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
3932dc13fee6SSepherosa Ziehau 		return (error);
3933dc13fee6SSepherosa Ziehau 
3934dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
3935dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = size;
3936dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
3937dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
3938dc13fee6SSepherosa Ziehau 
3939dc13fee6SSepherosa Ziehau 	return (0);
3940dc13fee6SSepherosa Ziehau }
3941dc13fee6SSepherosa Ziehau 
3942dc13fee6SSepherosa Ziehau static int
3943dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS)
3944dc13fee6SSepherosa Ziehau {
3945dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
3946dc13fee6SSepherosa Ziehau 	int error, pkts;
3947dc13fee6SSepherosa Ziehau 
3948dc13fee6SSepherosa Ziehau 	pkts = sc->hn_agg_pkts;
3949dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pkts, 0, req);
3950dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
3951dc13fee6SSepherosa Ziehau 		return (error);
3952dc13fee6SSepherosa Ziehau 
3953dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
3954dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = pkts;
3955dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
3956dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
3957dc13fee6SSepherosa Ziehau 
3958dc13fee6SSepherosa Ziehau 	return (0);
3959dc13fee6SSepherosa Ziehau }
3960dc13fee6SSepherosa Ziehau 
3961dc13fee6SSepherosa Ziehau static int
3962dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS)
3963dc13fee6SSepherosa Ziehau {
3964dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
3965dc13fee6SSepherosa Ziehau 	int pkts;
3966dc13fee6SSepherosa Ziehau 
3967dc13fee6SSepherosa Ziehau 	pkts = sc->hn_tx_ring[0].hn_agg_pktmax;
3968dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &pkts, 0, req));
3969dc13fee6SSepherosa Ziehau }
3970dc13fee6SSepherosa Ziehau 
3971dc13fee6SSepherosa Ziehau static int
3972dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS)
3973dc13fee6SSepherosa Ziehau {
3974dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
3975dc13fee6SSepherosa Ziehau 	int align;
3976dc13fee6SSepherosa Ziehau 
3977dc13fee6SSepherosa Ziehau 	align = sc->hn_tx_ring[0].hn_agg_align;
3978dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &align, 0, req));
3979dc13fee6SSepherosa Ziehau }
3980dc13fee6SSepherosa Ziehau 
39816c1204dfSSepherosa Ziehau static void
39826c1204dfSSepherosa Ziehau hn_chan_polling(struct vmbus_channel *chan, u_int pollhz)
39836c1204dfSSepherosa Ziehau {
39846c1204dfSSepherosa Ziehau 	if (pollhz == 0)
39856c1204dfSSepherosa Ziehau 		vmbus_chan_poll_disable(chan);
39866c1204dfSSepherosa Ziehau 	else
39876c1204dfSSepherosa Ziehau 		vmbus_chan_poll_enable(chan, pollhz);
39886c1204dfSSepherosa Ziehau }
39896c1204dfSSepherosa Ziehau 
39906c1204dfSSepherosa Ziehau static void
39916c1204dfSSepherosa Ziehau hn_polling(struct hn_softc *sc, u_int pollhz)
39926c1204dfSSepherosa Ziehau {
39936c1204dfSSepherosa Ziehau 	int nsubch = sc->hn_rx_ring_inuse - 1;
39946c1204dfSSepherosa Ziehau 
39956c1204dfSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
39966c1204dfSSepherosa Ziehau 
39976c1204dfSSepherosa Ziehau 	if (nsubch > 0) {
39986c1204dfSSepherosa Ziehau 		struct vmbus_channel **subch;
39996c1204dfSSepherosa Ziehau 		int i;
40006c1204dfSSepherosa Ziehau 
40016c1204dfSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
40026c1204dfSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
40036c1204dfSSepherosa Ziehau 			hn_chan_polling(subch[i], pollhz);
40046c1204dfSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
40056c1204dfSSepherosa Ziehau 	}
40066c1204dfSSepherosa Ziehau 	hn_chan_polling(sc->hn_prichan, pollhz);
40076c1204dfSSepherosa Ziehau }
40086c1204dfSSepherosa Ziehau 
40096c1204dfSSepherosa Ziehau static int
40106c1204dfSSepherosa Ziehau hn_polling_sysctl(SYSCTL_HANDLER_ARGS)
40116c1204dfSSepherosa Ziehau {
40126c1204dfSSepherosa Ziehau 	struct hn_softc *sc = arg1;
40136c1204dfSSepherosa Ziehau 	int pollhz, error;
40146c1204dfSSepherosa Ziehau 
40156c1204dfSSepherosa Ziehau 	pollhz = sc->hn_pollhz;
40166c1204dfSSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pollhz, 0, req);
40176c1204dfSSepherosa Ziehau 	if (error || req->newptr == NULL)
40186c1204dfSSepherosa Ziehau 		return (error);
40196c1204dfSSepherosa Ziehau 
40206c1204dfSSepherosa Ziehau 	if (pollhz != 0 &&
40216c1204dfSSepherosa Ziehau 	    (pollhz < VMBUS_CHAN_POLLHZ_MIN || pollhz > VMBUS_CHAN_POLLHZ_MAX))
40226c1204dfSSepherosa Ziehau 		return (EINVAL);
40236c1204dfSSepherosa Ziehau 
40246c1204dfSSepherosa Ziehau 	HN_LOCK(sc);
40256c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz != pollhz) {
40266c1204dfSSepherosa Ziehau 		sc->hn_pollhz = pollhz;
40276c1204dfSSepherosa Ziehau 		if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) &&
40286c1204dfSSepherosa Ziehau 		    (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
40296c1204dfSSepherosa Ziehau 			hn_polling(sc, sc->hn_pollhz);
40306c1204dfSSepherosa Ziehau 	}
40316c1204dfSSepherosa Ziehau 	HN_UNLOCK(sc);
40326c1204dfSSepherosa Ziehau 
40336c1204dfSSepherosa Ziehau 	return (0);
40346c1204dfSSepherosa Ziehau }
40356c1204dfSSepherosa Ziehau 
4036dc13fee6SSepherosa Ziehau static int
403715516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS)
403815516c77SSepherosa Ziehau {
403915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
404015516c77SSepherosa Ziehau 	char verstr[16];
404115516c77SSepherosa Ziehau 
404215516c77SSepherosa Ziehau 	snprintf(verstr, sizeof(verstr), "%u.%u",
404315516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
404415516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
404515516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
404615516c77SSepherosa Ziehau }
404715516c77SSepherosa Ziehau 
404815516c77SSepherosa Ziehau static int
404915516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS)
405015516c77SSepherosa Ziehau {
405115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
405215516c77SSepherosa Ziehau 	char caps_str[128];
405315516c77SSepherosa Ziehau 	uint32_t caps;
405415516c77SSepherosa Ziehau 
405515516c77SSepherosa Ziehau 	HN_LOCK(sc);
405615516c77SSepherosa Ziehau 	caps = sc->hn_caps;
405715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
405815516c77SSepherosa Ziehau 	snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS);
405915516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req);
406015516c77SSepherosa Ziehau }
406115516c77SSepherosa Ziehau 
406215516c77SSepherosa Ziehau static int
406315516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS)
406415516c77SSepherosa Ziehau {
406515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
406615516c77SSepherosa Ziehau 	char assist_str[128];
406715516c77SSepherosa Ziehau 	uint32_t hwassist;
406815516c77SSepherosa Ziehau 
406915516c77SSepherosa Ziehau 	HN_LOCK(sc);
407015516c77SSepherosa Ziehau 	hwassist = sc->hn_ifp->if_hwassist;
407115516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
407215516c77SSepherosa Ziehau 	snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS);
407315516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req);
407415516c77SSepherosa Ziehau }
407515516c77SSepherosa Ziehau 
407615516c77SSepherosa Ziehau static int
407715516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS)
407815516c77SSepherosa Ziehau {
407915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
408015516c77SSepherosa Ziehau 	char filter_str[128];
408115516c77SSepherosa Ziehau 	uint32_t filter;
408215516c77SSepherosa Ziehau 
408315516c77SSepherosa Ziehau 	HN_LOCK(sc);
408415516c77SSepherosa Ziehau 	filter = sc->hn_rx_filter;
408515516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
408615516c77SSepherosa Ziehau 	snprintf(filter_str, sizeof(filter_str), "%b", filter,
408715516c77SSepherosa Ziehau 	    NDIS_PACKET_TYPES);
408815516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req);
408915516c77SSepherosa Ziehau }
409015516c77SSepherosa Ziehau 
409134d68912SSepherosa Ziehau #ifndef RSS
409234d68912SSepherosa Ziehau 
409315516c77SSepherosa Ziehau static int
409415516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
409515516c77SSepherosa Ziehau {
409615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
409715516c77SSepherosa Ziehau 	int error;
409815516c77SSepherosa Ziehau 
409915516c77SSepherosa Ziehau 	HN_LOCK(sc);
410015516c77SSepherosa Ziehau 
410115516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
410215516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
410315516c77SSepherosa Ziehau 		goto back;
410415516c77SSepherosa Ziehau 
410515516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
410615516c77SSepherosa Ziehau 	if (error)
410715516c77SSepherosa Ziehau 		goto back;
410815516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
410915516c77SSepherosa Ziehau 
411015516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
411115516c77SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
411215516c77SSepherosa Ziehau 	} else {
411315516c77SSepherosa Ziehau 		/* Not RSS capable, at least for now; just save the RSS key. */
411415516c77SSepherosa Ziehau 		error = 0;
411515516c77SSepherosa Ziehau 	}
411615516c77SSepherosa Ziehau back:
411715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
411815516c77SSepherosa Ziehau 	return (error);
411915516c77SSepherosa Ziehau }
412015516c77SSepherosa Ziehau 
412115516c77SSepherosa Ziehau static int
412215516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS)
412315516c77SSepherosa Ziehau {
412415516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
412515516c77SSepherosa Ziehau 	int error;
412615516c77SSepherosa Ziehau 
412715516c77SSepherosa Ziehau 	HN_LOCK(sc);
412815516c77SSepherosa Ziehau 
412915516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
413015516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
413115516c77SSepherosa Ziehau 		goto back;
413215516c77SSepherosa Ziehau 
413315516c77SSepherosa Ziehau 	/*
413415516c77SSepherosa Ziehau 	 * Don't allow RSS indirect table change, if this interface is not
413515516c77SSepherosa Ziehau 	 * RSS capable currently.
413615516c77SSepherosa Ziehau 	 */
413715516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
413815516c77SSepherosa Ziehau 		error = EOPNOTSUPP;
413915516c77SSepherosa Ziehau 		goto back;
414015516c77SSepherosa Ziehau 	}
414115516c77SSepherosa Ziehau 
414215516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
414315516c77SSepherosa Ziehau 	if (error)
414415516c77SSepherosa Ziehau 		goto back;
414515516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSIND;
414615516c77SSepherosa Ziehau 
4147afd4971bSSepherosa Ziehau 	hn_rss_ind_fixup(sc);
414815516c77SSepherosa Ziehau 	error = hn_rss_reconfig(sc);
414915516c77SSepherosa Ziehau back:
415015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
415115516c77SSepherosa Ziehau 	return (error);
415215516c77SSepherosa Ziehau }
415315516c77SSepherosa Ziehau 
415434d68912SSepherosa Ziehau #endif	/* !RSS */
415534d68912SSepherosa Ziehau 
415615516c77SSepherosa Ziehau static int
415715516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS)
415815516c77SSepherosa Ziehau {
415915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
416015516c77SSepherosa Ziehau 	char hash_str[128];
416115516c77SSepherosa Ziehau 	uint32_t hash;
416215516c77SSepherosa Ziehau 
416315516c77SSepherosa Ziehau 	HN_LOCK(sc);
416415516c77SSepherosa Ziehau 	hash = sc->hn_rss_hash;
416515516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
416615516c77SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
416715516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
416815516c77SSepherosa Ziehau }
416915516c77SSepherosa Ziehau 
417015516c77SSepherosa Ziehau static int
417140d60d6eSDexuan Cui hn_vf_sysctl(SYSCTL_HANDLER_ARGS)
417240d60d6eSDexuan Cui {
417340d60d6eSDexuan Cui 	struct hn_softc *sc = arg1;
4174499c3e17SSepherosa Ziehau 	char vf_name[IFNAMSIZ + 1];
4175962f0357SSepherosa Ziehau 	struct ifnet *vf_ifp;
417640d60d6eSDexuan Cui 
417740d60d6eSDexuan Cui 	HN_LOCK(sc);
417840d60d6eSDexuan Cui 	vf_name[0] = '\0';
4179962f0357SSepherosa Ziehau 	vf_ifp = sc->hn_vf_ifp;
4180962f0357SSepherosa Ziehau 	if (vf_ifp != NULL)
4181962f0357SSepherosa Ziehau 		snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname);
418240d60d6eSDexuan Cui 	HN_UNLOCK(sc);
418340d60d6eSDexuan Cui 	return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req);
418440d60d6eSDexuan Cui }
418540d60d6eSDexuan Cui 
418640d60d6eSDexuan Cui static int
4187499c3e17SSepherosa Ziehau hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS)
4188499c3e17SSepherosa Ziehau {
4189499c3e17SSepherosa Ziehau 	struct hn_softc *sc = arg1;
4190499c3e17SSepherosa Ziehau 	char vf_name[IFNAMSIZ + 1];
4191962f0357SSepherosa Ziehau 	struct ifnet *vf_ifp;
4192499c3e17SSepherosa Ziehau 
4193499c3e17SSepherosa Ziehau 	HN_LOCK(sc);
4194499c3e17SSepherosa Ziehau 	vf_name[0] = '\0';
4195962f0357SSepherosa Ziehau 	vf_ifp = sc->hn_rx_ring[0].hn_rxvf_ifp;
4196962f0357SSepherosa Ziehau 	if (vf_ifp != NULL)
4197962f0357SSepherosa Ziehau 		snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname);
4198499c3e17SSepherosa Ziehau 	HN_UNLOCK(sc);
4199499c3e17SSepherosa Ziehau 	return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req);
4200499c3e17SSepherosa Ziehau }
4201499c3e17SSepherosa Ziehau 
4202499c3e17SSepherosa Ziehau static int
4203499c3e17SSepherosa Ziehau hn_vflist_sysctl(SYSCTL_HANDLER_ARGS)
4204499c3e17SSepherosa Ziehau {
4205499c3e17SSepherosa Ziehau 	struct rm_priotracker pt;
4206499c3e17SSepherosa Ziehau 	struct sbuf *sb;
4207499c3e17SSepherosa Ziehau 	int error, i;
4208499c3e17SSepherosa Ziehau 	bool first;
4209499c3e17SSepherosa Ziehau 
4210499c3e17SSepherosa Ziehau 	error = sysctl_wire_old_buffer(req, 0);
4211499c3e17SSepherosa Ziehau 	if (error != 0)
4212499c3e17SSepherosa Ziehau 		return (error);
4213499c3e17SSepherosa Ziehau 
4214499c3e17SSepherosa Ziehau 	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4215499c3e17SSepherosa Ziehau 	if (sb == NULL)
4216499c3e17SSepherosa Ziehau 		return (ENOMEM);
4217499c3e17SSepherosa Ziehau 
4218499c3e17SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
4219499c3e17SSepherosa Ziehau 
4220499c3e17SSepherosa Ziehau 	first = true;
4221499c3e17SSepherosa Ziehau 	for (i = 0; i < hn_vfmap_size; ++i) {
4222499c3e17SSepherosa Ziehau 		struct ifnet *ifp;
4223499c3e17SSepherosa Ziehau 
4224499c3e17SSepherosa Ziehau 		if (hn_vfmap[i] == NULL)
4225499c3e17SSepherosa Ziehau 			continue;
4226499c3e17SSepherosa Ziehau 
4227499c3e17SSepherosa Ziehau 		ifp = ifnet_byindex(i);
4228499c3e17SSepherosa Ziehau 		if (ifp != NULL) {
4229499c3e17SSepherosa Ziehau 			if (first)
4230499c3e17SSepherosa Ziehau 				sbuf_printf(sb, "%s", ifp->if_xname);
4231499c3e17SSepherosa Ziehau 			else
4232499c3e17SSepherosa Ziehau 				sbuf_printf(sb, " %s", ifp->if_xname);
4233499c3e17SSepherosa Ziehau 			first = false;
4234499c3e17SSepherosa Ziehau 		}
4235499c3e17SSepherosa Ziehau 	}
4236499c3e17SSepherosa Ziehau 
4237499c3e17SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
4238499c3e17SSepherosa Ziehau 
4239499c3e17SSepherosa Ziehau 	error = sbuf_finish(sb);
4240499c3e17SSepherosa Ziehau 	sbuf_delete(sb);
4241499c3e17SSepherosa Ziehau 	return (error);
4242499c3e17SSepherosa Ziehau }
4243499c3e17SSepherosa Ziehau 
4244499c3e17SSepherosa Ziehau static int
4245499c3e17SSepherosa Ziehau hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS)
4246499c3e17SSepherosa Ziehau {
4247499c3e17SSepherosa Ziehau 	struct rm_priotracker pt;
4248499c3e17SSepherosa Ziehau 	struct sbuf *sb;
4249499c3e17SSepherosa Ziehau 	int error, i;
4250499c3e17SSepherosa Ziehau 	bool first;
4251499c3e17SSepherosa Ziehau 
4252499c3e17SSepherosa Ziehau 	error = sysctl_wire_old_buffer(req, 0);
4253499c3e17SSepherosa Ziehau 	if (error != 0)
4254499c3e17SSepherosa Ziehau 		return (error);
4255499c3e17SSepherosa Ziehau 
4256499c3e17SSepherosa Ziehau 	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
4257499c3e17SSepherosa Ziehau 	if (sb == NULL)
4258499c3e17SSepherosa Ziehau 		return (ENOMEM);
4259499c3e17SSepherosa Ziehau 
4260499c3e17SSepherosa Ziehau 	rm_rlock(&hn_vfmap_lock, &pt);
4261499c3e17SSepherosa Ziehau 
4262499c3e17SSepherosa Ziehau 	first = true;
4263499c3e17SSepherosa Ziehau 	for (i = 0; i < hn_vfmap_size; ++i) {
4264499c3e17SSepherosa Ziehau 		struct ifnet *ifp, *hn_ifp;
4265499c3e17SSepherosa Ziehau 
4266499c3e17SSepherosa Ziehau 		hn_ifp = hn_vfmap[i];
4267499c3e17SSepherosa Ziehau 		if (hn_ifp == NULL)
4268499c3e17SSepherosa Ziehau 			continue;
4269499c3e17SSepherosa Ziehau 
4270499c3e17SSepherosa Ziehau 		ifp = ifnet_byindex(i);
4271499c3e17SSepherosa Ziehau 		if (ifp != NULL) {
4272499c3e17SSepherosa Ziehau 			if (first) {
4273499c3e17SSepherosa Ziehau 				sbuf_printf(sb, "%s:%s", ifp->if_xname,
4274499c3e17SSepherosa Ziehau 				    hn_ifp->if_xname);
4275499c3e17SSepherosa Ziehau 			} else {
4276499c3e17SSepherosa Ziehau 				sbuf_printf(sb, " %s:%s", ifp->if_xname,
4277499c3e17SSepherosa Ziehau 				    hn_ifp->if_xname);
4278499c3e17SSepherosa Ziehau 			}
4279499c3e17SSepherosa Ziehau 			first = false;
4280499c3e17SSepherosa Ziehau 		}
4281499c3e17SSepherosa Ziehau 	}
4282499c3e17SSepherosa Ziehau 
4283499c3e17SSepherosa Ziehau 	rm_runlock(&hn_vfmap_lock, &pt);
4284499c3e17SSepherosa Ziehau 
4285499c3e17SSepherosa Ziehau 	error = sbuf_finish(sb);
4286499c3e17SSepherosa Ziehau 	sbuf_delete(sb);
4287499c3e17SSepherosa Ziehau 	return (error);
4288499c3e17SSepherosa Ziehau }
4289499c3e17SSepherosa Ziehau 
4290499c3e17SSepherosa Ziehau static int
42919c6cae24SSepherosa Ziehau hn_xpnt_vf_accbpf_sysctl(SYSCTL_HANDLER_ARGS)
42929c6cae24SSepherosa Ziehau {
42939c6cae24SSepherosa Ziehau 	struct hn_softc *sc = arg1;
42949c6cae24SSepherosa Ziehau 	int error, onoff = 0;
42959c6cae24SSepherosa Ziehau 
42969c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF)
42979c6cae24SSepherosa Ziehau 		onoff = 1;
42989c6cae24SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &onoff, 0, req);
42999c6cae24SSepherosa Ziehau 	if (error || req->newptr == NULL)
43009c6cae24SSepherosa Ziehau 		return (error);
43019c6cae24SSepherosa Ziehau 
43029c6cae24SSepherosa Ziehau 	HN_LOCK(sc);
43039c6cae24SSepherosa Ziehau 	/* NOTE: hn_vf_lock for hn_transmit() */
43049c6cae24SSepherosa Ziehau 	rm_wlock(&sc->hn_vf_lock);
43059c6cae24SSepherosa Ziehau 	if (onoff)
43069c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags |= HN_XVFFLAG_ACCBPF;
43079c6cae24SSepherosa Ziehau 	else
43089c6cae24SSepherosa Ziehau 		sc->hn_xvf_flags &= ~HN_XVFFLAG_ACCBPF;
43099c6cae24SSepherosa Ziehau 	rm_wunlock(&sc->hn_vf_lock);
43109c6cae24SSepherosa Ziehau 	HN_UNLOCK(sc);
43119c6cae24SSepherosa Ziehau 
43129c6cae24SSepherosa Ziehau 	return (0);
43139c6cae24SSepherosa Ziehau }
43149c6cae24SSepherosa Ziehau 
43159c6cae24SSepherosa Ziehau static int
43169c6cae24SSepherosa Ziehau hn_xpnt_vf_enabled_sysctl(SYSCTL_HANDLER_ARGS)
43179c6cae24SSepherosa Ziehau {
43189c6cae24SSepherosa Ziehau 	struct hn_softc *sc = arg1;
43199c6cae24SSepherosa Ziehau 	int enabled = 0;
43209c6cae24SSepherosa Ziehau 
43219c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
43229c6cae24SSepherosa Ziehau 		enabled = 1;
43239c6cae24SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &enabled, 0, req));
43249c6cae24SSepherosa Ziehau }
43259c6cae24SSepherosa Ziehau 
43269c6cae24SSepherosa Ziehau static int
432715516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff)
432815516c77SSepherosa Ziehau {
432915516c77SSepherosa Ziehau 	const struct ip *ip;
433015516c77SSepherosa Ziehau 	int len, iphlen, iplen;
433115516c77SSepherosa Ziehau 	const struct tcphdr *th;
433215516c77SSepherosa Ziehau 	int thoff;				/* TCP data offset */
433315516c77SSepherosa Ziehau 
433415516c77SSepherosa Ziehau 	len = hoff + sizeof(struct ip);
433515516c77SSepherosa Ziehau 
433615516c77SSepherosa Ziehau 	/* The packet must be at least the size of an IP header. */
433715516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < len)
433815516c77SSepherosa Ziehau 		return IPPROTO_DONE;
433915516c77SSepherosa Ziehau 
434015516c77SSepherosa Ziehau 	/* The fixed IP header must reside completely in the first mbuf. */
434115516c77SSepherosa Ziehau 	if (m->m_len < len)
434215516c77SSepherosa Ziehau 		return IPPROTO_DONE;
434315516c77SSepherosa Ziehau 
434415516c77SSepherosa Ziehau 	ip = mtodo(m, hoff);
434515516c77SSepherosa Ziehau 
434615516c77SSepherosa Ziehau 	/* Bound check the packet's stated IP header length. */
434715516c77SSepherosa Ziehau 	iphlen = ip->ip_hl << 2;
434815516c77SSepherosa Ziehau 	if (iphlen < sizeof(struct ip))		/* minimum header length */
434915516c77SSepherosa Ziehau 		return IPPROTO_DONE;
435015516c77SSepherosa Ziehau 
435115516c77SSepherosa Ziehau 	/* The full IP header must reside completely in the one mbuf. */
435215516c77SSepherosa Ziehau 	if (m->m_len < hoff + iphlen)
435315516c77SSepherosa Ziehau 		return IPPROTO_DONE;
435415516c77SSepherosa Ziehau 
435515516c77SSepherosa Ziehau 	iplen = ntohs(ip->ip_len);
435615516c77SSepherosa Ziehau 
435715516c77SSepherosa Ziehau 	/*
435815516c77SSepherosa Ziehau 	 * Check that the amount of data in the buffers is as
435915516c77SSepherosa Ziehau 	 * at least much as the IP header would have us expect.
436015516c77SSepherosa Ziehau 	 */
436115516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < hoff + iplen)
436215516c77SSepherosa Ziehau 		return IPPROTO_DONE;
436315516c77SSepherosa Ziehau 
436415516c77SSepherosa Ziehau 	/*
436515516c77SSepherosa Ziehau 	 * Ignore IP fragments.
436615516c77SSepherosa Ziehau 	 */
436715516c77SSepherosa Ziehau 	if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF))
436815516c77SSepherosa Ziehau 		return IPPROTO_DONE;
436915516c77SSepherosa Ziehau 
437015516c77SSepherosa Ziehau 	/*
437115516c77SSepherosa Ziehau 	 * The TCP/IP or UDP/IP header must be entirely contained within
437215516c77SSepherosa Ziehau 	 * the first fragment of a packet.
437315516c77SSepherosa Ziehau 	 */
437415516c77SSepherosa Ziehau 	switch (ip->ip_p) {
437515516c77SSepherosa Ziehau 	case IPPROTO_TCP:
437615516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct tcphdr))
437715516c77SSepherosa Ziehau 			return IPPROTO_DONE;
437815516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct tcphdr))
437915516c77SSepherosa Ziehau 			return IPPROTO_DONE;
438015516c77SSepherosa Ziehau 		th = (const struct tcphdr *)((const uint8_t *)ip + iphlen);
438115516c77SSepherosa Ziehau 		thoff = th->th_off << 2;
438215516c77SSepherosa Ziehau 		if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen)
438315516c77SSepherosa Ziehau 			return IPPROTO_DONE;
438415516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + thoff)
438515516c77SSepherosa Ziehau 			return IPPROTO_DONE;
438615516c77SSepherosa Ziehau 		break;
438715516c77SSepherosa Ziehau 	case IPPROTO_UDP:
438815516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct udphdr))
438915516c77SSepherosa Ziehau 			return IPPROTO_DONE;
439015516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct udphdr))
439115516c77SSepherosa Ziehau 			return IPPROTO_DONE;
439215516c77SSepherosa Ziehau 		break;
439315516c77SSepherosa Ziehau 	default:
439415516c77SSepherosa Ziehau 		if (iplen < iphlen)
439515516c77SSepherosa Ziehau 			return IPPROTO_DONE;
439615516c77SSepherosa Ziehau 		break;
439715516c77SSepherosa Ziehau 	}
439815516c77SSepherosa Ziehau 	return ip->ip_p;
439915516c77SSepherosa Ziehau }
440015516c77SSepherosa Ziehau 
440115516c77SSepherosa Ziehau static int
440215516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt)
440315516c77SSepherosa Ziehau {
440415516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
440515516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
440615516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
440715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
440815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
440915516c77SSepherosa Ziehau 	int lroent_cnt;
441015516c77SSepherosa Ziehau #endif
441115516c77SSepherosa Ziehau #endif
441215516c77SSepherosa Ziehau 	int i;
441315516c77SSepherosa Ziehau 
441415516c77SSepherosa Ziehau 	/*
441515516c77SSepherosa Ziehau 	 * Create RXBUF for reception.
441615516c77SSepherosa Ziehau 	 *
441715516c77SSepherosa Ziehau 	 * NOTE:
441815516c77SSepherosa Ziehau 	 * - It is shared by all channels.
441915516c77SSepherosa Ziehau 	 * - A large enough buffer is allocated, certain version of NVSes
442015516c77SSepherosa Ziehau 	 *   may further limit the usable space.
442115516c77SSepherosa Ziehau 	 */
442215516c77SSepherosa Ziehau 	sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
442315516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma,
442415516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
442515516c77SSepherosa Ziehau 	if (sc->hn_rxbuf == NULL) {
442615516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate rxbuf failed\n");
442715516c77SSepherosa Ziehau 		return (ENOMEM);
442815516c77SSepherosa Ziehau 	}
442915516c77SSepherosa Ziehau 
443015516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = ring_cnt;
443115516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt;
443215516c77SSepherosa Ziehau 
443315516c77SSepherosa Ziehau 	sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt,
443415516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
443515516c77SSepherosa Ziehau 
443615516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
443715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
443815516c77SSepherosa Ziehau 	lroent_cnt = hn_lro_entry_count;
443915516c77SSepherosa Ziehau 	if (lroent_cnt < TCP_LRO_ENTRIES)
444015516c77SSepherosa Ziehau 		lroent_cnt = TCP_LRO_ENTRIES;
444115516c77SSepherosa Ziehau 	if (bootverbose)
444215516c77SSepherosa Ziehau 		device_printf(dev, "LRO: entry count %d\n", lroent_cnt);
444315516c77SSepherosa Ziehau #endif
444415516c77SSepherosa Ziehau #endif	/* INET || INET6 */
444515516c77SSepherosa Ziehau 
444615516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
444715516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
444815516c77SSepherosa Ziehau 
444915516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.rx sysctl tree */
445015516c77SSepherosa Ziehau 	sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx",
445115516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
445215516c77SSepherosa Ziehau 
445315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
445415516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
445515516c77SSepherosa Ziehau 
445615516c77SSepherosa Ziehau 		rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
445715516c77SSepherosa Ziehau 		    PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE,
445815516c77SSepherosa Ziehau 		    &rxr->hn_br_dma, BUS_DMA_WAITOK);
445915516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL) {
446015516c77SSepherosa Ziehau 			device_printf(dev, "allocate bufring failed\n");
446115516c77SSepherosa Ziehau 			return (ENOMEM);
446215516c77SSepherosa Ziehau 		}
446315516c77SSepherosa Ziehau 
446415516c77SSepherosa Ziehau 		if (hn_trust_hosttcp)
446515516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP;
446615516c77SSepherosa Ziehau 		if (hn_trust_hostudp)
446715516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP;
446815516c77SSepherosa Ziehau 		if (hn_trust_hostip)
446915516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP;
447015516c77SSepherosa Ziehau 		rxr->hn_ifp = sc->hn_ifp;
447115516c77SSepherosa Ziehau 		if (i < sc->hn_tx_ring_cnt)
447215516c77SSepherosa Ziehau 			rxr->hn_txr = &sc->hn_tx_ring[i];
447315516c77SSepherosa Ziehau 		rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF;
447415516c77SSepherosa Ziehau 		rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK);
447515516c77SSepherosa Ziehau 		rxr->hn_rx_idx = i;
447615516c77SSepherosa Ziehau 		rxr->hn_rxbuf = sc->hn_rxbuf;
447715516c77SSepherosa Ziehau 
447815516c77SSepherosa Ziehau 		/*
447915516c77SSepherosa Ziehau 		 * Initialize LRO.
448015516c77SSepherosa Ziehau 		 */
448115516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
448215516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
448315516c77SSepherosa Ziehau 		tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt,
448415516c77SSepherosa Ziehau 		    hn_lro_mbufq_depth);
448515516c77SSepherosa Ziehau #else
448615516c77SSepherosa Ziehau 		tcp_lro_init(&rxr->hn_lro);
448715516c77SSepherosa Ziehau 		rxr->hn_lro.ifp = sc->hn_ifp;
448815516c77SSepherosa Ziehau #endif
448915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
449015516c77SSepherosa Ziehau 		rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF;
449115516c77SSepherosa Ziehau 		rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF;
449215516c77SSepherosa Ziehau #endif
449315516c77SSepherosa Ziehau #endif	/* INET || INET6 */
449415516c77SSepherosa Ziehau 
449515516c77SSepherosa Ziehau 		if (sc->hn_rx_sysctl_tree != NULL) {
449615516c77SSepherosa Ziehau 			char name[16];
449715516c77SSepherosa Ziehau 
449815516c77SSepherosa Ziehau 			/*
449915516c77SSepherosa Ziehau 			 * Create per RX ring sysctl tree:
450015516c77SSepherosa Ziehau 			 * dev.hn.UNIT.rx.RINGID
450115516c77SSepherosa Ziehau 			 */
450215516c77SSepherosa Ziehau 			snprintf(name, sizeof(name), "%d", i);
450315516c77SSepherosa Ziehau 			rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx,
450415516c77SSepherosa Ziehau 			    SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree),
450515516c77SSepherosa Ziehau 			    OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
450615516c77SSepherosa Ziehau 
450715516c77SSepherosa Ziehau 			if (rxr->hn_rx_sysctl_tree != NULL) {
450815516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
450915516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
451015516c77SSepherosa Ziehau 				    OID_AUTO, "packets", CTLFLAG_RW,
451115516c77SSepherosa Ziehau 				    &rxr->hn_pkts, "# of packets received");
451215516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
451315516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
451415516c77SSepherosa Ziehau 				    OID_AUTO, "rss_pkts", CTLFLAG_RW,
451515516c77SSepherosa Ziehau 				    &rxr->hn_rss_pkts,
451615516c77SSepherosa Ziehau 				    "# of packets w/ RSS info received");
451715516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx,
451815516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
451915516c77SSepherosa Ziehau 				    OID_AUTO, "pktbuf_len", CTLFLAG_RD,
452015516c77SSepherosa Ziehau 				    &rxr->hn_pktbuf_len, 0,
452115516c77SSepherosa Ziehau 				    "Temporary channel packet buffer length");
452215516c77SSepherosa Ziehau 			}
452315516c77SSepherosa Ziehau 		}
452415516c77SSepherosa Ziehau 	}
452515516c77SSepherosa Ziehau 
452615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued",
452715516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
452815516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_queued),
452915516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
453015516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
453115516c77SSepherosa Ziehau #else
453215516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
453315516c77SSepherosa Ziehau #endif
453415516c77SSepherosa Ziehau 	    "LU", "LRO queued");
453515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed",
453615516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
453715516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_flushed),
453815516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
453915516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
454015516c77SSepherosa Ziehau #else
454115516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
454215516c77SSepherosa Ziehau #endif
454315516c77SSepherosa Ziehau 	    "LU", "LRO flushed");
454415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried",
454515516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
454615516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro_tried),
454715516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries");
454815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
454915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim",
455015516c77SSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
455115516c77SSepherosa Ziehau 	    hn_lro_lenlim_sysctl, "IU",
455215516c77SSepherosa Ziehau 	    "Max # of data bytes to be aggregated by LRO");
455315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim",
455415516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
455515516c77SSepherosa Ziehau 	    hn_lro_ackcnt_sysctl, "I",
455615516c77SSepherosa Ziehau 	    "Max # of ACKs to be aggregated by LRO");
455715516c77SSepherosa Ziehau #endif
455815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp",
455915516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP,
456015516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
456115516c77SSepherosa Ziehau 	    "Trust tcp segement verification on host side, "
456215516c77SSepherosa Ziehau 	    "when csum info is missing");
456315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp",
456415516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP,
456515516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
456615516c77SSepherosa Ziehau 	    "Trust udp datagram verification on host side, "
456715516c77SSepherosa Ziehau 	    "when csum info is missing");
456815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip",
456915516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP,
457015516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
457115516c77SSepherosa Ziehau 	    "Trust ip packet verification on host side, "
457215516c77SSepherosa Ziehau 	    "when csum info is missing");
457315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip",
457415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
457515516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_ip),
457615516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP");
457715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp",
457815516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
457915516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_tcp),
458015516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP");
458115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp",
458215516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
458315516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_udp),
458415516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP");
458515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted",
458615516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
458715516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_trusted),
458815516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU",
458915516c77SSepherosa Ziehau 	    "# of packets that we trust host's csum verification");
459015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts",
459115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
459215516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_small_pkts),
459315516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of small packets received");
459415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed",
459515516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
459615516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_ack_failed),
459715516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures");
459815516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt",
459915516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings");
460015516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse",
460115516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings");
460215516c77SSepherosa Ziehau 
460315516c77SSepherosa Ziehau 	return (0);
460415516c77SSepherosa Ziehau }
460515516c77SSepherosa Ziehau 
460615516c77SSepherosa Ziehau static void
460715516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc)
460815516c77SSepherosa Ziehau {
460915516c77SSepherosa Ziehau 	int i;
461015516c77SSepherosa Ziehau 
461115516c77SSepherosa Ziehau 	if (sc->hn_rxbuf != NULL) {
46122494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0)
461315516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf);
46142494d735SSepherosa Ziehau 		else
46152494d735SSepherosa Ziehau 			device_printf(sc->hn_dev, "RXBUF is referenced\n");
461615516c77SSepherosa Ziehau 		sc->hn_rxbuf = NULL;
461715516c77SSepherosa Ziehau 	}
461815516c77SSepherosa Ziehau 
461915516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_cnt == 0)
462015516c77SSepherosa Ziehau 		return;
462115516c77SSepherosa Ziehau 
462215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
462315516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
462415516c77SSepherosa Ziehau 
462515516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL)
462615516c77SSepherosa Ziehau 			continue;
46272494d735SSepherosa Ziehau 		if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) {
462815516c77SSepherosa Ziehau 			hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br);
46292494d735SSepherosa Ziehau 		} else {
46302494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
46312494d735SSepherosa Ziehau 			    "%dth channel bufring is referenced", i);
46322494d735SSepherosa Ziehau 		}
463315516c77SSepherosa Ziehau 		rxr->hn_br = NULL;
463415516c77SSepherosa Ziehau 
463515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
463615516c77SSepherosa Ziehau 		tcp_lro_free(&rxr->hn_lro);
463715516c77SSepherosa Ziehau #endif
463815516c77SSepherosa Ziehau 		free(rxr->hn_pktbuf, M_DEVBUF);
463915516c77SSepherosa Ziehau 	}
464015516c77SSepherosa Ziehau 	free(sc->hn_rx_ring, M_DEVBUF);
464115516c77SSepherosa Ziehau 	sc->hn_rx_ring = NULL;
464215516c77SSepherosa Ziehau 
464315516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = 0;
464415516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = 0;
464515516c77SSepherosa Ziehau }
464615516c77SSepherosa Ziehau 
464715516c77SSepherosa Ziehau static int
464815516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id)
464915516c77SSepherosa Ziehau {
465015516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[id];
465115516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
465215516c77SSepherosa Ziehau 	bus_dma_tag_t parent_dtag;
465315516c77SSepherosa Ziehau 	int error, i;
465415516c77SSepherosa Ziehau 
465515516c77SSepherosa Ziehau 	txr->hn_sc = sc;
465615516c77SSepherosa Ziehau 	txr->hn_tx_idx = id;
465715516c77SSepherosa Ziehau 
465815516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
465915516c77SSepherosa Ziehau 	mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN);
466015516c77SSepherosa Ziehau #endif
466115516c77SSepherosa Ziehau 	mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF);
466215516c77SSepherosa Ziehau 
466315516c77SSepherosa Ziehau 	txr->hn_txdesc_cnt = HN_TX_DESC_CNT;
466415516c77SSepherosa Ziehau 	txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt,
466515516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
466615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
466715516c77SSepherosa Ziehau 	SLIST_INIT(&txr->hn_txlist);
466815516c77SSepherosa Ziehau #else
466915516c77SSepherosa Ziehau 	txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF,
467015516c77SSepherosa Ziehau 	    M_WAITOK, &txr->hn_tx_lock);
467115516c77SSepherosa Ziehau #endif
467215516c77SSepherosa Ziehau 
46730e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_EVTTQ) {
46740e11868dSSepherosa Ziehau 		txr->hn_tx_taskq = VMBUS_GET_EVENT_TASKQ(
46750e11868dSSepherosa Ziehau 		    device_get_parent(dev), dev, HN_RING_IDX2CPU(sc, id));
46760e11868dSSepherosa Ziehau 	} else {
4677fdd0222aSSepherosa Ziehau 		txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt];
46780e11868dSSepherosa Ziehau 	}
467915516c77SSepherosa Ziehau 
468023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
468115516c77SSepherosa Ziehau 	if (hn_use_if_start) {
468215516c77SSepherosa Ziehau 		txr->hn_txeof = hn_start_txeof;
468315516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr);
468415516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr);
468523bf9e15SSepherosa Ziehau 	} else
468623bf9e15SSepherosa Ziehau #endif
468723bf9e15SSepherosa Ziehau 	{
468815516c77SSepherosa Ziehau 		int br_depth;
468915516c77SSepherosa Ziehau 
469015516c77SSepherosa Ziehau 		txr->hn_txeof = hn_xmit_txeof;
469115516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr);
469215516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr);
469315516c77SSepherosa Ziehau 
469415516c77SSepherosa Ziehau 		br_depth = hn_get_txswq_depth(txr);
469515516c77SSepherosa Ziehau 		txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF,
469615516c77SSepherosa Ziehau 		    M_WAITOK, &txr->hn_tx_lock);
469715516c77SSepherosa Ziehau 	}
469815516c77SSepherosa Ziehau 
469915516c77SSepherosa Ziehau 	txr->hn_direct_tx_size = hn_direct_tx_size;
470015516c77SSepherosa Ziehau 
470115516c77SSepherosa Ziehau 	/*
470215516c77SSepherosa Ziehau 	 * Always schedule transmission instead of trying to do direct
470315516c77SSepherosa Ziehau 	 * transmission.  This one gives the best performance so far.
470415516c77SSepherosa Ziehau 	 */
470515516c77SSepherosa Ziehau 	txr->hn_sched_tx = 1;
470615516c77SSepherosa Ziehau 
470715516c77SSepherosa Ziehau 	parent_dtag = bus_get_dma_tag(dev);
470815516c77SSepherosa Ziehau 
470915516c77SSepherosa Ziehau 	/* DMA tag for RNDIS packet messages. */
471015516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
471115516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_ALIGN,		/* alignment */
471215516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_BOUNDARY,	/* boundary */
471315516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
471415516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
471515516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
471615516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsize */
471715516c77SSepherosa Ziehau 	    1,				/* nsegments */
471815516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsegsize */
471915516c77SSepherosa Ziehau 	    0,				/* flags */
472015516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
472115516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
472215516c77SSepherosa Ziehau 	    &txr->hn_tx_rndis_dtag);
472315516c77SSepherosa Ziehau 	if (error) {
472415516c77SSepherosa Ziehau 		device_printf(dev, "failed to create rndis dmatag\n");
472515516c77SSepherosa Ziehau 		return error;
472615516c77SSepherosa Ziehau 	}
472715516c77SSepherosa Ziehau 
472815516c77SSepherosa Ziehau 	/* DMA tag for data. */
472915516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
473015516c77SSepherosa Ziehau 	    1,				/* alignment */
473115516c77SSepherosa Ziehau 	    HN_TX_DATA_BOUNDARY,	/* boundary */
473215516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
473315516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
473415516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
473515516c77SSepherosa Ziehau 	    HN_TX_DATA_MAXSIZE,		/* maxsize */
473615516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGCNT_MAX,	/* nsegments */
473715516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGSIZE,		/* maxsegsize */
473815516c77SSepherosa Ziehau 	    0,				/* flags */
473915516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
474015516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
474115516c77SSepherosa Ziehau 	    &txr->hn_tx_data_dtag);
474215516c77SSepherosa Ziehau 	if (error) {
474315516c77SSepherosa Ziehau 		device_printf(dev, "failed to create data dmatag\n");
474415516c77SSepherosa Ziehau 		return error;
474515516c77SSepherosa Ziehau 	}
474615516c77SSepherosa Ziehau 
474715516c77SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i) {
474815516c77SSepherosa Ziehau 		struct hn_txdesc *txd = &txr->hn_txdesc[i];
474915516c77SSepherosa Ziehau 
475015516c77SSepherosa Ziehau 		txd->txr = txr;
475115516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
4752dc13fee6SSepherosa Ziehau 		STAILQ_INIT(&txd->agg_list);
475315516c77SSepherosa Ziehau 
475415516c77SSepherosa Ziehau 		/*
475515516c77SSepherosa Ziehau 		 * Allocate and load RNDIS packet message.
475615516c77SSepherosa Ziehau 		 */
475715516c77SSepherosa Ziehau         	error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag,
475815516c77SSepherosa Ziehau 		    (void **)&txd->rndis_pkt,
475915516c77SSepherosa Ziehau 		    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
476015516c77SSepherosa Ziehau 		    &txd->rndis_pkt_dmap);
476115516c77SSepherosa Ziehau 		if (error) {
476215516c77SSepherosa Ziehau 			device_printf(dev,
476315516c77SSepherosa Ziehau 			    "failed to allocate rndis_packet_msg, %d\n", i);
476415516c77SSepherosa Ziehau 			return error;
476515516c77SSepherosa Ziehau 		}
476615516c77SSepherosa Ziehau 
476715516c77SSepherosa Ziehau 		error = bus_dmamap_load(txr->hn_tx_rndis_dtag,
476815516c77SSepherosa Ziehau 		    txd->rndis_pkt_dmap,
476915516c77SSepherosa Ziehau 		    txd->rndis_pkt, HN_RNDIS_PKT_LEN,
477015516c77SSepherosa Ziehau 		    hyperv_dma_map_paddr, &txd->rndis_pkt_paddr,
477115516c77SSepherosa Ziehau 		    BUS_DMA_NOWAIT);
477215516c77SSepherosa Ziehau 		if (error) {
477315516c77SSepherosa Ziehau 			device_printf(dev,
477415516c77SSepherosa Ziehau 			    "failed to load rndis_packet_msg, %d\n", i);
477515516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
477615516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
477715516c77SSepherosa Ziehau 			return error;
477815516c77SSepherosa Ziehau 		}
477915516c77SSepherosa Ziehau 
478015516c77SSepherosa Ziehau 		/* DMA map for TX data. */
478115516c77SSepherosa Ziehau 		error = bus_dmamap_create(txr->hn_tx_data_dtag, 0,
478215516c77SSepherosa Ziehau 		    &txd->data_dmap);
478315516c77SSepherosa Ziehau 		if (error) {
478415516c77SSepherosa Ziehau 			device_printf(dev,
478515516c77SSepherosa Ziehau 			    "failed to allocate tx data dmamap\n");
478615516c77SSepherosa Ziehau 			bus_dmamap_unload(txr->hn_tx_rndis_dtag,
478715516c77SSepherosa Ziehau 			    txd->rndis_pkt_dmap);
478815516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
478915516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
479015516c77SSepherosa Ziehau 			return error;
479115516c77SSepherosa Ziehau 		}
479215516c77SSepherosa Ziehau 
479315516c77SSepherosa Ziehau 		/* All set, put it to list */
479415516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_ONLIST;
479515516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
479615516c77SSepherosa Ziehau 		SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
479715516c77SSepherosa Ziehau #else
479815516c77SSepherosa Ziehau 		buf_ring_enqueue(txr->hn_txdesc_br, txd);
479915516c77SSepherosa Ziehau #endif
480015516c77SSepherosa Ziehau 	}
480115516c77SSepherosa Ziehau 	txr->hn_txdesc_avail = txr->hn_txdesc_cnt;
480215516c77SSepherosa Ziehau 
480315516c77SSepherosa Ziehau 	if (sc->hn_tx_sysctl_tree != NULL) {
480415516c77SSepherosa Ziehau 		struct sysctl_oid_list *child;
480515516c77SSepherosa Ziehau 		struct sysctl_ctx_list *ctx;
480615516c77SSepherosa Ziehau 		char name[16];
480715516c77SSepherosa Ziehau 
480815516c77SSepherosa Ziehau 		/*
480915516c77SSepherosa Ziehau 		 * Create per TX ring sysctl tree:
481015516c77SSepherosa Ziehau 		 * dev.hn.UNIT.tx.RINGID
481115516c77SSepherosa Ziehau 		 */
481215516c77SSepherosa Ziehau 		ctx = device_get_sysctl_ctx(dev);
481315516c77SSepherosa Ziehau 		child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree);
481415516c77SSepherosa Ziehau 
481515516c77SSepherosa Ziehau 		snprintf(name, sizeof(name), "%d", id);
481615516c77SSepherosa Ziehau 		txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
481715516c77SSepherosa Ziehau 		    name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
481815516c77SSepherosa Ziehau 
481915516c77SSepherosa Ziehau 		if (txr->hn_tx_sysctl_tree != NULL) {
482015516c77SSepherosa Ziehau 			child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree);
482115516c77SSepherosa Ziehau 
482285e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
482315516c77SSepherosa Ziehau 			SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail",
482415516c77SSepherosa Ziehau 			    CTLFLAG_RD, &txr->hn_txdesc_avail, 0,
482515516c77SSepherosa Ziehau 			    "# of available TX descs");
482685e4ae1eSSepherosa Ziehau #endif
482723bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
482823bf9e15SSepherosa Ziehau 			if (!hn_use_if_start)
482923bf9e15SSepherosa Ziehau #endif
483023bf9e15SSepherosa Ziehau 			{
483115516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive",
483215516c77SSepherosa Ziehau 				    CTLFLAG_RD, &txr->hn_oactive, 0,
483315516c77SSepherosa Ziehau 				    "over active");
483415516c77SSepherosa Ziehau 			}
483515516c77SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets",
483615516c77SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_pkts,
483715516c77SSepherosa Ziehau 			    "# of packets transmitted");
4838dc13fee6SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends",
4839dc13fee6SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_sends, "# of sends");
484015516c77SSepherosa Ziehau 		}
484115516c77SSepherosa Ziehau 	}
484215516c77SSepherosa Ziehau 
484315516c77SSepherosa Ziehau 	return 0;
484415516c77SSepherosa Ziehau }
484515516c77SSepherosa Ziehau 
484615516c77SSepherosa Ziehau static void
484715516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd)
484815516c77SSepherosa Ziehau {
484915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = txd->txr;
485015516c77SSepherosa Ziehau 
485115516c77SSepherosa Ziehau 	KASSERT(txd->m == NULL, ("still has mbuf installed"));
485215516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped"));
485315516c77SSepherosa Ziehau 
485415516c77SSepherosa Ziehau 	bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap);
485515516c77SSepherosa Ziehau 	bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt,
485615516c77SSepherosa Ziehau 	    txd->rndis_pkt_dmap);
485715516c77SSepherosa Ziehau 	bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap);
485815516c77SSepherosa Ziehau }
485915516c77SSepherosa Ziehau 
486015516c77SSepherosa Ziehau static void
486125641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd)
486225641fc7SSepherosa Ziehau {
486325641fc7SSepherosa Ziehau 
486425641fc7SSepherosa Ziehau 	KASSERT(txd->refs == 0 || txd->refs == 1,
486525641fc7SSepherosa Ziehau 	    ("invalid txd refs %d", txd->refs));
486625641fc7SSepherosa Ziehau 
486725641fc7SSepherosa Ziehau 	/* Aggregated txds will be freed by their aggregating txd. */
486825641fc7SSepherosa Ziehau 	if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) {
486925641fc7SSepherosa Ziehau 		int freed;
487025641fc7SSepherosa Ziehau 
487125641fc7SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
487225641fc7SSepherosa Ziehau 		KASSERT(freed, ("can't free txdesc"));
487325641fc7SSepherosa Ziehau 	}
487425641fc7SSepherosa Ziehau }
487525641fc7SSepherosa Ziehau 
487625641fc7SSepherosa Ziehau static void
487715516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr)
487815516c77SSepherosa Ziehau {
487925641fc7SSepherosa Ziehau 	int i;
488015516c77SSepherosa Ziehau 
488115516c77SSepherosa Ziehau 	if (txr->hn_txdesc == NULL)
488215516c77SSepherosa Ziehau 		return;
488315516c77SSepherosa Ziehau 
488425641fc7SSepherosa Ziehau 	/*
488525641fc7SSepherosa Ziehau 	 * NOTE:
488625641fc7SSepherosa Ziehau 	 * Because the freeing of aggregated txds will be deferred
488725641fc7SSepherosa Ziehau 	 * to the aggregating txd, two passes are used here:
488825641fc7SSepherosa Ziehau 	 * - The first pass GCes any pending txds.  This GC is necessary,
488925641fc7SSepherosa Ziehau 	 *   since if the channels are revoked, hypervisor will not
489025641fc7SSepherosa Ziehau 	 *   deliver send-done for all pending txds.
489125641fc7SSepherosa Ziehau 	 * - The second pass frees the busdma stuffs, i.e. after all txds
489225641fc7SSepherosa Ziehau 	 *   were freed.
489325641fc7SSepherosa Ziehau 	 */
489425641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
489525641fc7SSepherosa Ziehau 		hn_txdesc_gc(txr, &txr->hn_txdesc[i]);
489625641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
489725641fc7SSepherosa Ziehau 		hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]);
489815516c77SSepherosa Ziehau 
489915516c77SSepherosa Ziehau 	if (txr->hn_tx_data_dtag != NULL)
490015516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_data_dtag);
490115516c77SSepherosa Ziehau 	if (txr->hn_tx_rndis_dtag != NULL)
490215516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_rndis_dtag);
490315516c77SSepherosa Ziehau 
490415516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
490515516c77SSepherosa Ziehau 	buf_ring_free(txr->hn_txdesc_br, M_DEVBUF);
490615516c77SSepherosa Ziehau #endif
490715516c77SSepherosa Ziehau 
490815516c77SSepherosa Ziehau 	free(txr->hn_txdesc, M_DEVBUF);
490915516c77SSepherosa Ziehau 	txr->hn_txdesc = NULL;
491015516c77SSepherosa Ziehau 
491115516c77SSepherosa Ziehau 	if (txr->hn_mbuf_br != NULL)
491215516c77SSepherosa Ziehau 		buf_ring_free(txr->hn_mbuf_br, M_DEVBUF);
491315516c77SSepherosa Ziehau 
491415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
491515516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_txlist_spin);
491615516c77SSepherosa Ziehau #endif
491715516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_tx_lock);
491815516c77SSepherosa Ziehau }
491915516c77SSepherosa Ziehau 
492015516c77SSepherosa Ziehau static int
492115516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt)
492215516c77SSepherosa Ziehau {
492315516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
492415516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
492515516c77SSepherosa Ziehau 	int i;
492615516c77SSepherosa Ziehau 
492715516c77SSepherosa Ziehau 	/*
492815516c77SSepherosa Ziehau 	 * Create TXBUF for chimney sending.
492915516c77SSepherosa Ziehau 	 *
493015516c77SSepherosa Ziehau 	 * NOTE: It is shared by all channels.
493115516c77SSepherosa Ziehau 	 */
493215516c77SSepherosa Ziehau 	sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev),
493315516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma,
493415516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
493515516c77SSepherosa Ziehau 	if (sc->hn_chim == NULL) {
493615516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate txbuf failed\n");
493715516c77SSepherosa Ziehau 		return (ENOMEM);
493815516c77SSepherosa Ziehau 	}
493915516c77SSepherosa Ziehau 
494015516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = ring_cnt;
494115516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
494215516c77SSepherosa Ziehau 
494315516c77SSepherosa Ziehau 	sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt,
494415516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
494515516c77SSepherosa Ziehau 
494615516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(sc->hn_dev);
494715516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev));
494815516c77SSepherosa Ziehau 
494915516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.tx sysctl tree */
495015516c77SSepherosa Ziehau 	sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx",
495115516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
495215516c77SSepherosa Ziehau 
495315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
495415516c77SSepherosa Ziehau 		int error;
495515516c77SSepherosa Ziehau 
495615516c77SSepherosa Ziehau 		error = hn_tx_ring_create(sc, i);
495715516c77SSepherosa Ziehau 		if (error)
495815516c77SSepherosa Ziehau 			return error;
495915516c77SSepherosa Ziehau 	}
496015516c77SSepherosa Ziehau 
496115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs",
496215516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
496315516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_no_txdescs),
496415516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs");
496515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed",
496615516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
496715516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_send_failed),
496815516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure");
496915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed",
497015516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
497115516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_txdma_failed),
497215516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure");
4973dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed",
4974dc13fee6SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
4975dc13fee6SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_flush_failed),
4976dc13fee6SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU",
4977dc13fee6SSepherosa Ziehau 	    "# of packet transmission aggregation flush failure");
497815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed",
497915516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
498015516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_collapsed),
498115516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed");
498215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney",
498315516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
498415516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney),
498515516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send");
498615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried",
498715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
498815516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney_tried),
498915516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries");
499015516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt",
499115516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0,
499215516c77SSepherosa Ziehau 	    "# of total TX descs");
499315516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max",
499415516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_chim_szmax, 0,
499515516c77SSepherosa Ziehau 	    "Chimney send packet size upper boundary");
499615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size",
499715516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
499815516c77SSepherosa Ziehau 	    hn_chim_size_sysctl, "I", "Chimney send packet size limit");
499915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size",
500015516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
500115516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_direct_tx_size),
500215516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
500315516c77SSepherosa Ziehau 	    "Size of the packet for direct transmission");
500415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx",
500515516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
500615516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_sched_tx),
500715516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
500815516c77SSepherosa Ziehau 	    "Always schedule transmission "
500915516c77SSepherosa Ziehau 	    "instead of doing direct transmission");
501015516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt",
501115516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings");
501215516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse",
501315516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings");
5014dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax",
5015dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0,
5016dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation size");
5017dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax",
5018dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
5019dc13fee6SSepherosa Ziehau 	    hn_txagg_pktmax_sysctl, "I",
5020dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation packets");
5021dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align",
5022dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
5023dc13fee6SSepherosa Ziehau 	    hn_txagg_align_sysctl, "I",
5024dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation alignment");
502515516c77SSepherosa Ziehau 
502615516c77SSepherosa Ziehau 	return 0;
502715516c77SSepherosa Ziehau }
502815516c77SSepherosa Ziehau 
502915516c77SSepherosa Ziehau static void
503015516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size)
503115516c77SSepherosa Ziehau {
503215516c77SSepherosa Ziehau 	int i;
503315516c77SSepherosa Ziehau 
5034a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
503515516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_chim_size = chim_size;
503615516c77SSepherosa Ziehau }
503715516c77SSepherosa Ziehau 
503815516c77SSepherosa Ziehau static void
503915516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu)
504015516c77SSepherosa Ziehau {
504115516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
50429c6cae24SSepherosa Ziehau 	u_int hw_tsomax;
504315516c77SSepherosa Ziehau 	int tso_minlen;
504415516c77SSepherosa Ziehau 
50459c6cae24SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
50469c6cae24SSepherosa Ziehau 
504715516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0)
504815516c77SSepherosa Ziehau 		return;
504915516c77SSepherosa Ziehau 
505015516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_sgmin >= 2,
505115516c77SSepherosa Ziehau 	    ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin));
505215516c77SSepherosa Ziehau 	tso_minlen = sc->hn_ndis_tso_sgmin * mtu;
505315516c77SSepherosa Ziehau 
505415516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen &&
505515516c77SSepherosa Ziehau 	    sc->hn_ndis_tso_szmax <= IP_MAXPACKET,
505615516c77SSepherosa Ziehau 	    ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax));
505715516c77SSepherosa Ziehau 
505815516c77SSepherosa Ziehau 	if (tso_maxlen < tso_minlen)
505915516c77SSepherosa Ziehau 		tso_maxlen = tso_minlen;
506015516c77SSepherosa Ziehau 	else if (tso_maxlen > IP_MAXPACKET)
506115516c77SSepherosa Ziehau 		tso_maxlen = IP_MAXPACKET;
506215516c77SSepherosa Ziehau 	if (tso_maxlen > sc->hn_ndis_tso_szmax)
506315516c77SSepherosa Ziehau 		tso_maxlen = sc->hn_ndis_tso_szmax;
50649c6cae24SSepherosa Ziehau 	hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
50659c6cae24SSepherosa Ziehau 
50669c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_isready(sc)) {
50679c6cae24SSepherosa Ziehau 		if (hw_tsomax > sc->hn_vf_ifp->if_hw_tsomax)
50689c6cae24SSepherosa Ziehau 			hw_tsomax = sc->hn_vf_ifp->if_hw_tsomax;
50699c6cae24SSepherosa Ziehau 	}
50709c6cae24SSepherosa Ziehau 	ifp->if_hw_tsomax = hw_tsomax;
507115516c77SSepherosa Ziehau 	if (bootverbose)
507215516c77SSepherosa Ziehau 		if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax);
507315516c77SSepherosa Ziehau }
507415516c77SSepherosa Ziehau 
507515516c77SSepherosa Ziehau static void
507615516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc)
507715516c77SSepherosa Ziehau {
507815516c77SSepherosa Ziehau 	uint64_t csum_assist;
507915516c77SSepherosa Ziehau 	int i;
508015516c77SSepherosa Ziehau 
508115516c77SSepherosa Ziehau 	hn_set_chim_size(sc, sc->hn_chim_szmax);
508215516c77SSepherosa Ziehau 	if (hn_tx_chimney_size > 0 &&
508315516c77SSepherosa Ziehau 	    hn_tx_chimney_size < sc->hn_chim_szmax)
508415516c77SSepherosa Ziehau 		hn_set_chim_size(sc, hn_tx_chimney_size);
508515516c77SSepherosa Ziehau 
508615516c77SSepherosa Ziehau 	csum_assist = 0;
508715516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_IPCS)
508815516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP;
508915516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP4CS)
509015516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_TCP;
509115516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP4CS)
509215516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_UDP;
509315516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP6CS)
509415516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_TCP;
509515516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP6CS)
509615516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_UDP;
509715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
509815516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_csum_assist = csum_assist;
509915516c77SSepherosa Ziehau 
510015516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_HASHVAL) {
510115516c77SSepherosa Ziehau 		/*
510215516c77SSepherosa Ziehau 		 * Support HASHVAL pktinfo on TX path.
510315516c77SSepherosa Ziehau 		 */
510415516c77SSepherosa Ziehau 		if (bootverbose)
510515516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n");
510615516c77SSepherosa Ziehau 		for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
510715516c77SSepherosa Ziehau 			sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL;
510815516c77SSepherosa Ziehau 	}
510915516c77SSepherosa Ziehau }
511015516c77SSepherosa Ziehau 
511115516c77SSepherosa Ziehau static void
511215516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc)
511315516c77SSepherosa Ziehau {
511415516c77SSepherosa Ziehau 	int i;
511515516c77SSepherosa Ziehau 
511615516c77SSepherosa Ziehau 	if (sc->hn_chim != NULL) {
51172494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) {
511815516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim);
51192494d735SSepherosa Ziehau 		} else {
51202494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
51212494d735SSepherosa Ziehau 			    "chimney sending buffer is referenced");
51222494d735SSepherosa Ziehau 		}
512315516c77SSepherosa Ziehau 		sc->hn_chim = NULL;
512415516c77SSepherosa Ziehau 	}
512515516c77SSepherosa Ziehau 
512615516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt == 0)
512715516c77SSepherosa Ziehau 		return;
512815516c77SSepherosa Ziehau 
512915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
513015516c77SSepherosa Ziehau 		hn_tx_ring_destroy(&sc->hn_tx_ring[i]);
513115516c77SSepherosa Ziehau 
513215516c77SSepherosa Ziehau 	free(sc->hn_tx_ring, M_DEVBUF);
513315516c77SSepherosa Ziehau 	sc->hn_tx_ring = NULL;
513415516c77SSepherosa Ziehau 
513515516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = 0;
513615516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = 0;
513715516c77SSepherosa Ziehau }
513815516c77SSepherosa Ziehau 
513923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
514023bf9e15SSepherosa Ziehau 
514115516c77SSepherosa Ziehau static void
514215516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused)
514315516c77SSepherosa Ziehau {
514415516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
514515516c77SSepherosa Ziehau 
514615516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
514715516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
514815516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
514915516c77SSepherosa Ziehau }
515015516c77SSepherosa Ziehau 
515123bf9e15SSepherosa Ziehau static int
515223bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len)
515323bf9e15SSepherosa Ziehau {
515423bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
515523bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
5156dc13fee6SSepherosa Ziehau 	int sched = 0;
515723bf9e15SSepherosa Ziehau 
515823bf9e15SSepherosa Ziehau 	KASSERT(hn_use_if_start,
515923bf9e15SSepherosa Ziehau 	    ("hn_start_locked is called, when if_start is disabled"));
516023bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
516123bf9e15SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
5162dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
516323bf9e15SSepherosa Ziehau 
516423bf9e15SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
5165dc13fee6SSepherosa Ziehau 		return (0);
516623bf9e15SSepherosa Ziehau 
516723bf9e15SSepherosa Ziehau 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
516823bf9e15SSepherosa Ziehau 	    IFF_DRV_RUNNING)
5169dc13fee6SSepherosa Ziehau 		return (0);
517023bf9e15SSepherosa Ziehau 
517123bf9e15SSepherosa Ziehau 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
517223bf9e15SSepherosa Ziehau 		struct hn_txdesc *txd;
517323bf9e15SSepherosa Ziehau 		struct mbuf *m_head;
517423bf9e15SSepherosa Ziehau 		int error;
517523bf9e15SSepherosa Ziehau 
517623bf9e15SSepherosa Ziehau 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
517723bf9e15SSepherosa Ziehau 		if (m_head == NULL)
517823bf9e15SSepherosa Ziehau 			break;
517923bf9e15SSepherosa Ziehau 
518023bf9e15SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
518123bf9e15SSepherosa Ziehau 			/*
518223bf9e15SSepherosa Ziehau 			 * This sending could be time consuming; let callers
518323bf9e15SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
518423bf9e15SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
518523bf9e15SSepherosa Ziehau 			 */
518623bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
5187dc13fee6SSepherosa Ziehau 			sched = 1;
5188dc13fee6SSepherosa Ziehau 			break;
518923bf9e15SSepherosa Ziehau 		}
519023bf9e15SSepherosa Ziehau 
5191edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
5192edd3f315SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
5193edd3f315SSepherosa Ziehau 			m_head = hn_tso_fixup(m_head);
5194edd3f315SSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
5195edd3f315SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5196edd3f315SSepherosa Ziehau 				continue;
5197edd3f315SSepherosa Ziehau 			}
5198edd3f315SSepherosa Ziehau 		}
5199edd3f315SSepherosa Ziehau #endif
5200edd3f315SSepherosa Ziehau 
520123bf9e15SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
520223bf9e15SSepherosa Ziehau 		if (txd == NULL) {
520323bf9e15SSepherosa Ziehau 			txr->hn_no_txdescs++;
520423bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
520523bf9e15SSepherosa Ziehau 			atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
520623bf9e15SSepherosa Ziehau 			break;
520723bf9e15SSepherosa Ziehau 		}
520823bf9e15SSepherosa Ziehau 
5209dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
521023bf9e15SSepherosa Ziehau 		if (error) {
521123bf9e15SSepherosa Ziehau 			/* Both txd and m_head are freed */
5212dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
5213dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
521423bf9e15SSepherosa Ziehau 			continue;
521523bf9e15SSepherosa Ziehau 		}
521623bf9e15SSepherosa Ziehau 
5217dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
5218dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
5219dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
5220dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
5221dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
5222dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
5223dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
5224dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
5225dc13fee6SSepherosa Ziehau 					break;
5226dc13fee6SSepherosa Ziehau 				}
5227dc13fee6SSepherosa Ziehau 			} else {
5228dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
522923bf9e15SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
523023bf9e15SSepherosa Ziehau 				if (__predict_false(error)) {
523123bf9e15SSepherosa Ziehau 					/* txd is freed, but m_head is not */
523223bf9e15SSepherosa Ziehau 					IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
5233dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
5234dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
523523bf9e15SSepherosa Ziehau 					break;
523623bf9e15SSepherosa Ziehau 				}
523723bf9e15SSepherosa Ziehau 			}
5238dc13fee6SSepherosa Ziehau 		}
5239dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
5240dc13fee6SSepherosa Ziehau 		else {
5241dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
5242dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
5243dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
5244dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
5245dc13fee6SSepherosa Ziehau 		}
5246dc13fee6SSepherosa Ziehau #endif
5247dc13fee6SSepherosa Ziehau 	}
5248dc13fee6SSepherosa Ziehau 
5249dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
5250dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
5251dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
5252dc13fee6SSepherosa Ziehau 	return (sched);
525323bf9e15SSepherosa Ziehau }
525423bf9e15SSepherosa Ziehau 
525523bf9e15SSepherosa Ziehau static void
525623bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp)
525723bf9e15SSepherosa Ziehau {
525823bf9e15SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
525923bf9e15SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[0];
526023bf9e15SSepherosa Ziehau 
526123bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
526223bf9e15SSepherosa Ziehau 		goto do_sched;
526323bf9e15SSepherosa Ziehau 
526423bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
526523bf9e15SSepherosa Ziehau 		int sched;
526623bf9e15SSepherosa Ziehau 
526723bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
526823bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
526923bf9e15SSepherosa Ziehau 		if (!sched)
527023bf9e15SSepherosa Ziehau 			return;
527123bf9e15SSepherosa Ziehau 	}
527223bf9e15SSepherosa Ziehau do_sched:
527323bf9e15SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
527423bf9e15SSepherosa Ziehau }
527523bf9e15SSepherosa Ziehau 
527615516c77SSepherosa Ziehau static void
527715516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused)
527815516c77SSepherosa Ziehau {
527915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
528015516c77SSepherosa Ziehau 
528115516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
528215516c77SSepherosa Ziehau 	atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE);
528315516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
528415516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
528515516c77SSepherosa Ziehau }
528615516c77SSepherosa Ziehau 
528723bf9e15SSepherosa Ziehau static void
528823bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr)
528923bf9e15SSepherosa Ziehau {
529023bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
529123bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
529223bf9e15SSepherosa Ziehau 
529323bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
529423bf9e15SSepherosa Ziehau 
529523bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
529623bf9e15SSepherosa Ziehau 		goto do_sched;
529723bf9e15SSepherosa Ziehau 
529823bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
529923bf9e15SSepherosa Ziehau 		int sched;
530023bf9e15SSepherosa Ziehau 
530123bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
530223bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
530323bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
530423bf9e15SSepherosa Ziehau 		if (sched) {
530523bf9e15SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
530623bf9e15SSepherosa Ziehau 			    &txr->hn_tx_task);
530723bf9e15SSepherosa Ziehau 		}
530823bf9e15SSepherosa Ziehau 	} else {
530923bf9e15SSepherosa Ziehau do_sched:
531023bf9e15SSepherosa Ziehau 		/*
531123bf9e15SSepherosa Ziehau 		 * Release the OACTIVE earlier, with the hope, that
531223bf9e15SSepherosa Ziehau 		 * others could catch up.  The task will clear the
531323bf9e15SSepherosa Ziehau 		 * flag again with the hn_tx_lock to avoid possible
531423bf9e15SSepherosa Ziehau 		 * races.
531523bf9e15SSepherosa Ziehau 		 */
531623bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
531723bf9e15SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
531823bf9e15SSepherosa Ziehau 	}
531923bf9e15SSepherosa Ziehau }
532023bf9e15SSepherosa Ziehau 
532123bf9e15SSepherosa Ziehau #endif	/* HN_IFSTART_SUPPORT */
532223bf9e15SSepherosa Ziehau 
532315516c77SSepherosa Ziehau static int
532415516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len)
532515516c77SSepherosa Ziehau {
532615516c77SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
532715516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
532815516c77SSepherosa Ziehau 	struct mbuf *m_head;
5329dc13fee6SSepherosa Ziehau 	int sched = 0;
533015516c77SSepherosa Ziehau 
533115516c77SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
533223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
533315516c77SSepherosa Ziehau 	KASSERT(hn_use_if_start == 0,
533415516c77SSepherosa Ziehau 	    ("hn_xmit is called, when if_start is enabled"));
533523bf9e15SSepherosa Ziehau #endif
5336dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
533715516c77SSepherosa Ziehau 
533815516c77SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
5339dc13fee6SSepherosa Ziehau 		return (0);
534015516c77SSepherosa Ziehau 
534115516c77SSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive)
5342dc13fee6SSepherosa Ziehau 		return (0);
534315516c77SSepherosa Ziehau 
534415516c77SSepherosa Ziehau 	while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) {
534515516c77SSepherosa Ziehau 		struct hn_txdesc *txd;
534615516c77SSepherosa Ziehau 		int error;
534715516c77SSepherosa Ziehau 
534815516c77SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
534915516c77SSepherosa Ziehau 			/*
535015516c77SSepherosa Ziehau 			 * This sending could be time consuming; let callers
535115516c77SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
535215516c77SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
535315516c77SSepherosa Ziehau 			 */
535415516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
5355dc13fee6SSepherosa Ziehau 			sched = 1;
5356dc13fee6SSepherosa Ziehau 			break;
535715516c77SSepherosa Ziehau 		}
535815516c77SSepherosa Ziehau 
535915516c77SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
536015516c77SSepherosa Ziehau 		if (txd == NULL) {
536115516c77SSepherosa Ziehau 			txr->hn_no_txdescs++;
536215516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
536315516c77SSepherosa Ziehau 			txr->hn_oactive = 1;
536415516c77SSepherosa Ziehau 			break;
536515516c77SSepherosa Ziehau 		}
536615516c77SSepherosa Ziehau 
5367dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
536815516c77SSepherosa Ziehau 		if (error) {
536915516c77SSepherosa Ziehau 			/* Both txd and m_head are freed; discard */
5370dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
5371dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
537215516c77SSepherosa Ziehau 			drbr_advance(ifp, txr->hn_mbuf_br);
537315516c77SSepherosa Ziehau 			continue;
537415516c77SSepherosa Ziehau 		}
537515516c77SSepherosa Ziehau 
5376dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
5377dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
5378dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
5379dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
5380dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
538115516c77SSepherosa Ziehau 				if (__predict_false(error)) {
538215516c77SSepherosa Ziehau 					txr->hn_oactive = 1;
538315516c77SSepherosa Ziehau 					break;
538415516c77SSepherosa Ziehau 				}
5385dc13fee6SSepherosa Ziehau 			} else {
5386dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
5387dc13fee6SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
5388dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
5389dc13fee6SSepherosa Ziehau 					/* txd is freed, but m_head is not */
5390dc13fee6SSepherosa Ziehau 					drbr_putback(ifp, txr->hn_mbuf_br,
5391dc13fee6SSepherosa Ziehau 					    m_head);
5392dc13fee6SSepherosa Ziehau 					txr->hn_oactive = 1;
5393dc13fee6SSepherosa Ziehau 					break;
5394dc13fee6SSepherosa Ziehau 				}
5395dc13fee6SSepherosa Ziehau 			}
5396dc13fee6SSepherosa Ziehau 		}
5397dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
5398dc13fee6SSepherosa Ziehau 		else {
5399dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
5400dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
5401dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
5402dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
5403dc13fee6SSepherosa Ziehau 		}
5404dc13fee6SSepherosa Ziehau #endif
540515516c77SSepherosa Ziehau 
540615516c77SSepherosa Ziehau 		/* Sent */
540715516c77SSepherosa Ziehau 		drbr_advance(ifp, txr->hn_mbuf_br);
540815516c77SSepherosa Ziehau 	}
5409dc13fee6SSepherosa Ziehau 
5410dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
5411dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
5412dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
5413dc13fee6SSepherosa Ziehau 	return (sched);
541415516c77SSepherosa Ziehau }
541515516c77SSepherosa Ziehau 
541615516c77SSepherosa Ziehau static int
541715516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m)
541815516c77SSepherosa Ziehau {
541915516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
542015516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
542115516c77SSepherosa Ziehau 	int error, idx = 0;
542215516c77SSepherosa Ziehau 
54239c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED) {
54249c6cae24SSepherosa Ziehau 		struct rm_priotracker pt;
54259c6cae24SSepherosa Ziehau 
54269c6cae24SSepherosa Ziehau 		rm_rlock(&sc->hn_vf_lock, &pt);
54279c6cae24SSepherosa Ziehau 		if (__predict_true(sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)) {
54289c6cae24SSepherosa Ziehau 			struct mbuf *m_bpf = NULL;
54299c6cae24SSepherosa Ziehau 			int obytes, omcast;
54309c6cae24SSepherosa Ziehau 
54319c6cae24SSepherosa Ziehau 			obytes = m->m_pkthdr.len;
54329c6cae24SSepherosa Ziehau 			if (m->m_flags & M_MCAST)
54339c6cae24SSepherosa Ziehau 				omcast = 1;
54349c6cae24SSepherosa Ziehau 
54359c6cae24SSepherosa Ziehau 			if (sc->hn_xvf_flags & HN_XVFFLAG_ACCBPF) {
54369c6cae24SSepherosa Ziehau 				if (bpf_peers_present(ifp->if_bpf)) {
54379c6cae24SSepherosa Ziehau 					m_bpf = m_copypacket(m, M_NOWAIT);
54389c6cae24SSepherosa Ziehau 					if (m_bpf == NULL) {
54399c6cae24SSepherosa Ziehau 						/*
54409c6cae24SSepherosa Ziehau 						 * Failed to grab a shallow
54419c6cae24SSepherosa Ziehau 						 * copy; tap now.
54429c6cae24SSepherosa Ziehau 						 */
54439c6cae24SSepherosa Ziehau 						ETHER_BPF_MTAP(ifp, m);
54449c6cae24SSepherosa Ziehau 					}
54459c6cae24SSepherosa Ziehau 				}
54469c6cae24SSepherosa Ziehau 			} else {
54479c6cae24SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, m);
54489c6cae24SSepherosa Ziehau 			}
54499c6cae24SSepherosa Ziehau 
54509c6cae24SSepherosa Ziehau 			error = sc->hn_vf_ifp->if_transmit(sc->hn_vf_ifp, m);
54519c6cae24SSepherosa Ziehau 			rm_runlock(&sc->hn_vf_lock, &pt);
54529c6cae24SSepherosa Ziehau 
54539c6cae24SSepherosa Ziehau 			if (m_bpf != NULL) {
54549c6cae24SSepherosa Ziehau 				if (!error)
54559c6cae24SSepherosa Ziehau 					ETHER_BPF_MTAP(ifp, m_bpf);
54569c6cae24SSepherosa Ziehau 				m_freem(m_bpf);
54579c6cae24SSepherosa Ziehau 			}
54589c6cae24SSepherosa Ziehau 
54599c6cae24SSepherosa Ziehau 			if (error == ENOBUFS) {
54609c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
54619c6cae24SSepherosa Ziehau 			} else if (error) {
54629c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
54639c6cae24SSepherosa Ziehau 			} else {
54649c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
54659c6cae24SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OBYTES, obytes);
54669c6cae24SSepherosa Ziehau 				if (omcast) {
54679c6cae24SSepherosa Ziehau 					if_inc_counter(ifp, IFCOUNTER_OMCASTS,
54689c6cae24SSepherosa Ziehau 					    omcast);
54699c6cae24SSepherosa Ziehau 				}
54709c6cae24SSepherosa Ziehau 			}
54719c6cae24SSepherosa Ziehau 			return (error);
54729c6cae24SSepherosa Ziehau 		}
54739c6cae24SSepherosa Ziehau 		rm_runlock(&sc->hn_vf_lock, &pt);
54749c6cae24SSepherosa Ziehau 	}
54759c6cae24SSepherosa Ziehau 
5476edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
5477edd3f315SSepherosa Ziehau 	/*
5478edd3f315SSepherosa Ziehau 	 * Perform TSO packet header fixup now, since the TSO
5479edd3f315SSepherosa Ziehau 	 * packet header should be cache-hot.
5480edd3f315SSepherosa Ziehau 	 */
5481edd3f315SSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
5482edd3f315SSepherosa Ziehau 		m = hn_tso_fixup(m);
5483edd3f315SSepherosa Ziehau 		if (__predict_false(m == NULL)) {
5484edd3f315SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
5485edd3f315SSepherosa Ziehau 			return EIO;
5486edd3f315SSepherosa Ziehau 		}
5487edd3f315SSepherosa Ziehau 	}
5488edd3f315SSepherosa Ziehau #endif
5489edd3f315SSepherosa Ziehau 
549015516c77SSepherosa Ziehau 	/*
549115516c77SSepherosa Ziehau 	 * Select the TX ring based on flowid
549215516c77SSepherosa Ziehau 	 */
549334d68912SSepherosa Ziehau 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
549434d68912SSepherosa Ziehau #ifdef RSS
549534d68912SSepherosa Ziehau 		uint32_t bid;
549634d68912SSepherosa Ziehau 
549734d68912SSepherosa Ziehau 		if (rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m),
549834d68912SSepherosa Ziehau 		    &bid) == 0)
549934d68912SSepherosa Ziehau 			idx = bid % sc->hn_tx_ring_inuse;
550034d68912SSepherosa Ziehau 		else
550134d68912SSepherosa Ziehau #endif
5502cc0c6ebcSSepherosa Ziehau 		{
5503cc0c6ebcSSepherosa Ziehau #if defined(INET6) || defined(INET)
5504cc0c6ebcSSepherosa Ziehau 			int tcpsyn = 0;
5505cc0c6ebcSSepherosa Ziehau 
5506cc0c6ebcSSepherosa Ziehau 			if (m->m_pkthdr.len < 128 &&
5507cc0c6ebcSSepherosa Ziehau 			    (m->m_pkthdr.csum_flags &
5508cc0c6ebcSSepherosa Ziehau 			     (CSUM_IP_TCP | CSUM_IP6_TCP)) &&
5509cc0c6ebcSSepherosa Ziehau 			    (m->m_pkthdr.csum_flags & CSUM_TSO) == 0) {
5510cc0c6ebcSSepherosa Ziehau 				m = hn_check_tcpsyn(m, &tcpsyn);
5511cc0c6ebcSSepherosa Ziehau 				if (__predict_false(m == NULL)) {
5512cc0c6ebcSSepherosa Ziehau 					if_inc_counter(ifp,
5513cc0c6ebcSSepherosa Ziehau 					    IFCOUNTER_OERRORS, 1);
5514cc0c6ebcSSepherosa Ziehau 					return (EIO);
5515cc0c6ebcSSepherosa Ziehau 				}
5516cc0c6ebcSSepherosa Ziehau 			}
5517cc0c6ebcSSepherosa Ziehau #else
5518cc0c6ebcSSepherosa Ziehau 			const int tcpsyn = 0;
5519cc0c6ebcSSepherosa Ziehau #endif
5520cc0c6ebcSSepherosa Ziehau 			if (tcpsyn)
5521cc0c6ebcSSepherosa Ziehau 				idx = 0;
5522cc0c6ebcSSepherosa Ziehau 			else
552315516c77SSepherosa Ziehau 				idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse;
552434d68912SSepherosa Ziehau 		}
5525cc0c6ebcSSepherosa Ziehau 	}
552615516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[idx];
552715516c77SSepherosa Ziehau 
552815516c77SSepherosa Ziehau 	error = drbr_enqueue(ifp, txr->hn_mbuf_br, m);
552915516c77SSepherosa Ziehau 	if (error) {
553015516c77SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
553115516c77SSepherosa Ziehau 		return error;
553215516c77SSepherosa Ziehau 	}
553315516c77SSepherosa Ziehau 
553415516c77SSepherosa Ziehau 	if (txr->hn_oactive)
553515516c77SSepherosa Ziehau 		return 0;
553615516c77SSepherosa Ziehau 
553715516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
553815516c77SSepherosa Ziehau 		goto do_sched;
553915516c77SSepherosa Ziehau 
554015516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
554115516c77SSepherosa Ziehau 		int sched;
554215516c77SSepherosa Ziehau 
554315516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
554415516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
554515516c77SSepherosa Ziehau 		if (!sched)
554615516c77SSepherosa Ziehau 			return 0;
554715516c77SSepherosa Ziehau 	}
554815516c77SSepherosa Ziehau do_sched:
554915516c77SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
555015516c77SSepherosa Ziehau 	return 0;
555115516c77SSepherosa Ziehau }
555215516c77SSepherosa Ziehau 
555315516c77SSepherosa Ziehau static void
555415516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr)
555515516c77SSepherosa Ziehau {
555615516c77SSepherosa Ziehau 	struct mbuf *m;
555715516c77SSepherosa Ziehau 
555815516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
555915516c77SSepherosa Ziehau 	while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL)
556015516c77SSepherosa Ziehau 		m_freem(m);
556115516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
556215516c77SSepherosa Ziehau }
556315516c77SSepherosa Ziehau 
556415516c77SSepherosa Ziehau static void
556515516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp)
556615516c77SSepherosa Ziehau {
556715516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
55689c6cae24SSepherosa Ziehau 	struct rm_priotracker pt;
556915516c77SSepherosa Ziehau 	int i;
557015516c77SSepherosa Ziehau 
557115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
557215516c77SSepherosa Ziehau 		hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
557315516c77SSepherosa Ziehau 	if_qflush(ifp);
55749c6cae24SSepherosa Ziehau 
55759c6cae24SSepherosa Ziehau 	rm_rlock(&sc->hn_vf_lock, &pt);
55769c6cae24SSepherosa Ziehau 	if (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED)
55779c6cae24SSepherosa Ziehau 		sc->hn_vf_ifp->if_qflush(sc->hn_vf_ifp);
55789c6cae24SSepherosa Ziehau 	rm_runlock(&sc->hn_vf_lock, &pt);
557915516c77SSepherosa Ziehau }
558015516c77SSepherosa Ziehau 
558115516c77SSepherosa Ziehau static void
558215516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr)
558315516c77SSepherosa Ziehau {
558415516c77SSepherosa Ziehau 
558515516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
558615516c77SSepherosa Ziehau 		goto do_sched;
558715516c77SSepherosa Ziehau 
558815516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
558915516c77SSepherosa Ziehau 		int sched;
559015516c77SSepherosa Ziehau 
559115516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
559215516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
559315516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
559415516c77SSepherosa Ziehau 		if (sched) {
559515516c77SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
559615516c77SSepherosa Ziehau 			    &txr->hn_tx_task);
559715516c77SSepherosa Ziehau 		}
559815516c77SSepherosa Ziehau 	} else {
559915516c77SSepherosa Ziehau do_sched:
560015516c77SSepherosa Ziehau 		/*
560115516c77SSepherosa Ziehau 		 * Release the oactive earlier, with the hope, that
560215516c77SSepherosa Ziehau 		 * others could catch up.  The task will clear the
560315516c77SSepherosa Ziehau 		 * oactive again with the hn_tx_lock to avoid possible
560415516c77SSepherosa Ziehau 		 * races.
560515516c77SSepherosa Ziehau 		 */
560615516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
560715516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
560815516c77SSepherosa Ziehau 	}
560915516c77SSepherosa Ziehau }
561015516c77SSepherosa Ziehau 
561115516c77SSepherosa Ziehau static void
561215516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused)
561315516c77SSepherosa Ziehau {
561415516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
561515516c77SSepherosa Ziehau 
561615516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
561715516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
561815516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
561915516c77SSepherosa Ziehau }
562015516c77SSepherosa Ziehau 
562115516c77SSepherosa Ziehau static void
562215516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused)
562315516c77SSepherosa Ziehau {
562415516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
562515516c77SSepherosa Ziehau 
562615516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
562715516c77SSepherosa Ziehau 	txr->hn_oactive = 0;
562815516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
562915516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
563015516c77SSepherosa Ziehau }
563115516c77SSepherosa Ziehau 
563215516c77SSepherosa Ziehau static int
563315516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan)
563415516c77SSepherosa Ziehau {
563515516c77SSepherosa Ziehau 	struct vmbus_chan_br cbr;
563615516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
563715516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = NULL;
563815516c77SSepherosa Ziehau 	int idx, error;
563915516c77SSepherosa Ziehau 
564015516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
564115516c77SSepherosa Ziehau 
564215516c77SSepherosa Ziehau 	/*
564315516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
564415516c77SSepherosa Ziehau 	 */
564515516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
564615516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
564715516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
564815516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
564915516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0,
565015516c77SSepherosa Ziehau 	    ("RX ring %d already attached", idx));
565115516c77SSepherosa Ziehau 	rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED;
56523ab0fea1SDexuan Cui 	rxr->hn_chan = chan;
565315516c77SSepherosa Ziehau 
565415516c77SSepherosa Ziehau 	if (bootverbose) {
565515516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n",
565615516c77SSepherosa Ziehau 		    idx, vmbus_chan_id(chan));
565715516c77SSepherosa Ziehau 	}
565815516c77SSepherosa Ziehau 
565915516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
566015516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[idx];
566115516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0,
566215516c77SSepherosa Ziehau 		    ("TX ring %d already attached", idx));
566315516c77SSepherosa Ziehau 		txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED;
566415516c77SSepherosa Ziehau 
566515516c77SSepherosa Ziehau 		txr->hn_chan = chan;
566615516c77SSepherosa Ziehau 		if (bootverbose) {
566715516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n",
566815516c77SSepherosa Ziehau 			    idx, vmbus_chan_id(chan));
566915516c77SSepherosa Ziehau 		}
567015516c77SSepherosa Ziehau 	}
567115516c77SSepherosa Ziehau 
567215516c77SSepherosa Ziehau 	/* Bind this channel to a proper CPU. */
56730e11868dSSepherosa Ziehau 	vmbus_chan_cpu_set(chan, HN_RING_IDX2CPU(sc, idx));
567415516c77SSepherosa Ziehau 
567515516c77SSepherosa Ziehau 	/*
567615516c77SSepherosa Ziehau 	 * Open this channel
567715516c77SSepherosa Ziehau 	 */
567815516c77SSepherosa Ziehau 	cbr.cbr = rxr->hn_br;
567915516c77SSepherosa Ziehau 	cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr;
568015516c77SSepherosa Ziehau 	cbr.cbr_txsz = HN_TXBR_SIZE;
568115516c77SSepherosa Ziehau 	cbr.cbr_rxsz = HN_RXBR_SIZE;
568215516c77SSepherosa Ziehau 	error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr);
568315516c77SSepherosa Ziehau 	if (error) {
568471e8ac56SSepherosa Ziehau 		if (error == EISCONN) {
568571e8ac56SSepherosa Ziehau 			if_printf(sc->hn_ifp, "bufring is connected after "
568671e8ac56SSepherosa Ziehau 			    "chan%u open failure\n", vmbus_chan_id(chan));
568771e8ac56SSepherosa Ziehau 			rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
568871e8ac56SSepherosa Ziehau 		} else {
568915516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "open chan%u failed: %d\n",
569015516c77SSepherosa Ziehau 			    vmbus_chan_id(chan), error);
569171e8ac56SSepherosa Ziehau 		}
569215516c77SSepherosa Ziehau 	}
569315516c77SSepherosa Ziehau 	return (error);
569415516c77SSepherosa Ziehau }
569515516c77SSepherosa Ziehau 
569615516c77SSepherosa Ziehau static void
569715516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan)
569815516c77SSepherosa Ziehau {
569915516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
57002494d735SSepherosa Ziehau 	int idx, error;
570115516c77SSepherosa Ziehau 
570215516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
570315516c77SSepherosa Ziehau 
570415516c77SSepherosa Ziehau 	/*
570515516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
570615516c77SSepherosa Ziehau 	 */
570715516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
570815516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
570915516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
571015516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
571115516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED),
571215516c77SSepherosa Ziehau 	    ("RX ring %d is not attached", idx));
571315516c77SSepherosa Ziehau 	rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
571415516c77SSepherosa Ziehau 
571515516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
571615516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[idx];
571715516c77SSepherosa Ziehau 
571815516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED),
571915516c77SSepherosa Ziehau 		    ("TX ring %d is not attached attached", idx));
572015516c77SSepherosa Ziehau 		txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
572115516c77SSepherosa Ziehau 	}
572215516c77SSepherosa Ziehau 
572315516c77SSepherosa Ziehau 	/*
572415516c77SSepherosa Ziehau 	 * Close this channel.
572515516c77SSepherosa Ziehau 	 *
572615516c77SSepherosa Ziehau 	 * NOTE:
572715516c77SSepherosa Ziehau 	 * Channel closing does _not_ destroy the target channel.
572815516c77SSepherosa Ziehau 	 */
57292494d735SSepherosa Ziehau 	error = vmbus_chan_close_direct(chan);
57302494d735SSepherosa Ziehau 	if (error == EISCONN) {
5731aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u bufring is connected "
5732aa1a2adcSSepherosa Ziehau 		    "after being closed\n", vmbus_chan_id(chan));
57332494d735SSepherosa Ziehau 		rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
57342494d735SSepherosa Ziehau 	} else if (error) {
5735aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u close failed: %d\n",
5736aa1a2adcSSepherosa Ziehau 		    vmbus_chan_id(chan), error);
57372494d735SSepherosa Ziehau 	}
573815516c77SSepherosa Ziehau }
573915516c77SSepherosa Ziehau 
574015516c77SSepherosa Ziehau static int
574115516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc)
574215516c77SSepherosa Ziehau {
574315516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
574415516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
574515516c77SSepherosa Ziehau 	int i, error = 0;
574615516c77SSepherosa Ziehau 
574771e8ac56SSepherosa Ziehau 	KASSERT(subchan_cnt > 0, ("no sub-channels"));
574815516c77SSepherosa Ziehau 
574915516c77SSepherosa Ziehau 	/* Attach the sub-channels. */
575015516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
575115516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i) {
575271e8ac56SSepherosa Ziehau 		int error1;
575371e8ac56SSepherosa Ziehau 
575471e8ac56SSepherosa Ziehau 		error1 = hn_chan_attach(sc, subchans[i]);
575571e8ac56SSepherosa Ziehau 		if (error1) {
575671e8ac56SSepherosa Ziehau 			error = error1;
575771e8ac56SSepherosa Ziehau 			/* Move on; all channels will be detached later. */
575871e8ac56SSepherosa Ziehau 		}
575915516c77SSepherosa Ziehau 	}
576015516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
576115516c77SSepherosa Ziehau 
576215516c77SSepherosa Ziehau 	if (error) {
576315516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error);
576415516c77SSepherosa Ziehau 	} else {
576515516c77SSepherosa Ziehau 		if (bootverbose) {
576615516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "%d sub-channels attached\n",
576715516c77SSepherosa Ziehau 			    subchan_cnt);
576815516c77SSepherosa Ziehau 		}
576915516c77SSepherosa Ziehau 	}
577015516c77SSepherosa Ziehau 	return (error);
577115516c77SSepherosa Ziehau }
577215516c77SSepherosa Ziehau 
577315516c77SSepherosa Ziehau static void
577415516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc)
577515516c77SSepherosa Ziehau {
577615516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
577715516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
577815516c77SSepherosa Ziehau 	int i;
577915516c77SSepherosa Ziehau 
578015516c77SSepherosa Ziehau 	if (subchan_cnt == 0)
578115516c77SSepherosa Ziehau 		goto back;
578215516c77SSepherosa Ziehau 
578315516c77SSepherosa Ziehau 	/* Detach the sub-channels. */
578415516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
578515516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i)
578615516c77SSepherosa Ziehau 		hn_chan_detach(sc, subchans[i]);
578715516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
578815516c77SSepherosa Ziehau 
578915516c77SSepherosa Ziehau back:
579015516c77SSepherosa Ziehau 	/*
579115516c77SSepherosa Ziehau 	 * Detach the primary channel, _after_ all sub-channels
579215516c77SSepherosa Ziehau 	 * are detached.
579315516c77SSepherosa Ziehau 	 */
579415516c77SSepherosa Ziehau 	hn_chan_detach(sc, sc->hn_prichan);
579515516c77SSepherosa Ziehau 
579615516c77SSepherosa Ziehau 	/* Wait for sub-channels to be destroyed, if any. */
579715516c77SSepherosa Ziehau 	vmbus_subchan_drain(sc->hn_prichan);
579815516c77SSepherosa Ziehau 
579915516c77SSepherosa Ziehau #ifdef INVARIANTS
580015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
580115516c77SSepherosa Ziehau 		KASSERT((sc->hn_rx_ring[i].hn_rx_flags &
580215516c77SSepherosa Ziehau 		    HN_RX_FLAG_ATTACHED) == 0,
580315516c77SSepherosa Ziehau 		    ("%dth RX ring is still attached", i));
580415516c77SSepherosa Ziehau 	}
580515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
580615516c77SSepherosa Ziehau 		KASSERT((sc->hn_tx_ring[i].hn_tx_flags &
580715516c77SSepherosa Ziehau 		    HN_TX_FLAG_ATTACHED) == 0,
580815516c77SSepherosa Ziehau 		    ("%dth TX ring is still attached", i));
580915516c77SSepherosa Ziehau 	}
581015516c77SSepherosa Ziehau #endif
581115516c77SSepherosa Ziehau }
581215516c77SSepherosa Ziehau 
581315516c77SSepherosa Ziehau static int
581415516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch)
581515516c77SSepherosa Ziehau {
581615516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
581715516c77SSepherosa Ziehau 	int nchan, rxr_cnt, error;
581815516c77SSepherosa Ziehau 
581915516c77SSepherosa Ziehau 	nchan = *nsubch + 1;
582015516c77SSepherosa Ziehau 	if (nchan == 1) {
582115516c77SSepherosa Ziehau 		/*
582215516c77SSepherosa Ziehau 		 * Multiple RX/TX rings are not requested.
582315516c77SSepherosa Ziehau 		 */
582415516c77SSepherosa Ziehau 		*nsubch = 0;
582515516c77SSepherosa Ziehau 		return (0);
582615516c77SSepherosa Ziehau 	}
582715516c77SSepherosa Ziehau 
582815516c77SSepherosa Ziehau 	/*
582915516c77SSepherosa Ziehau 	 * Query RSS capabilities, e.g. # of RX rings, and # of indirect
583015516c77SSepherosa Ziehau 	 * table entries.
583115516c77SSepherosa Ziehau 	 */
583215516c77SSepherosa Ziehau 	error = hn_rndis_query_rsscaps(sc, &rxr_cnt);
583315516c77SSepherosa Ziehau 	if (error) {
583415516c77SSepherosa Ziehau 		/* No RSS; this is benign. */
583515516c77SSepherosa Ziehau 		*nsubch = 0;
583615516c77SSepherosa Ziehau 		return (0);
583715516c77SSepherosa Ziehau 	}
583815516c77SSepherosa Ziehau 	if (bootverbose) {
583915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
584015516c77SSepherosa Ziehau 		    rxr_cnt, nchan);
584115516c77SSepherosa Ziehau 	}
584215516c77SSepherosa Ziehau 
584315516c77SSepherosa Ziehau 	if (nchan > rxr_cnt)
584415516c77SSepherosa Ziehau 		nchan = rxr_cnt;
584515516c77SSepherosa Ziehau 	if (nchan == 1) {
584615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n");
584715516c77SSepherosa Ziehau 		*nsubch = 0;
584815516c77SSepherosa Ziehau 		return (0);
584915516c77SSepherosa Ziehau 	}
585015516c77SSepherosa Ziehau 
585115516c77SSepherosa Ziehau 	/*
585215516c77SSepherosa Ziehau 	 * Allocate sub-channels from NVS.
585315516c77SSepherosa Ziehau 	 */
585415516c77SSepherosa Ziehau 	*nsubch = nchan - 1;
585515516c77SSepherosa Ziehau 	error = hn_nvs_alloc_subchans(sc, nsubch);
585615516c77SSepherosa Ziehau 	if (error || *nsubch == 0) {
585715516c77SSepherosa Ziehau 		/* Failed to allocate sub-channels. */
585815516c77SSepherosa Ziehau 		*nsubch = 0;
585915516c77SSepherosa Ziehau 		return (0);
586015516c77SSepherosa Ziehau 	}
586115516c77SSepherosa Ziehau 
586215516c77SSepherosa Ziehau 	/*
586315516c77SSepherosa Ziehau 	 * Wait for all sub-channels to become ready before moving on.
586415516c77SSepherosa Ziehau 	 */
586515516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch);
586615516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, *nsubch);
586715516c77SSepherosa Ziehau 	return (0);
586815516c77SSepherosa Ziehau }
586915516c77SSepherosa Ziehau 
58702494d735SSepherosa Ziehau static bool
58712494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc)
58722494d735SSepherosa Ziehau {
58732494d735SSepherosa Ziehau 	int i;
58742494d735SSepherosa Ziehau 
58752494d735SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_ERRORS)
58762494d735SSepherosa Ziehau 		return (false);
58772494d735SSepherosa Ziehau 
58782494d735SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
58792494d735SSepherosa Ziehau 		const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
58802494d735SSepherosa Ziehau 
58812494d735SSepherosa Ziehau 		if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF)
58822494d735SSepherosa Ziehau 			return (false);
58832494d735SSepherosa Ziehau 	}
58842494d735SSepherosa Ziehau 	return (true);
58852494d735SSepherosa Ziehau }
58862494d735SSepherosa Ziehau 
5887b3b75d9cSSepherosa Ziehau /*
5888b3b75d9cSSepherosa Ziehau  * Make sure that the RX filter is zero after the successful
5889b3b75d9cSSepherosa Ziehau  * RNDIS initialization.
5890b3b75d9cSSepherosa Ziehau  *
5891b3b75d9cSSepherosa Ziehau  * NOTE:
5892b3b75d9cSSepherosa Ziehau  * Under certain conditions on certain versions of Hyper-V,
5893b3b75d9cSSepherosa Ziehau  * the RNDIS rxfilter is _not_ zero on the hypervisor side
5894b3b75d9cSSepherosa Ziehau  * after the successful RNDIS initialization, which breaks
5895b3b75d9cSSepherosa Ziehau  * the assumption of any following code (well, it breaks the
5896b3b75d9cSSepherosa Ziehau  * RNDIS API contract actually).  Clear the RNDIS rxfilter
5897b3b75d9cSSepherosa Ziehau  * explicitly, drain packets sneaking through, and drain the
5898b3b75d9cSSepherosa Ziehau  * interrupt taskqueues scheduled due to the stealth packets.
5899b3b75d9cSSepherosa Ziehau  */
5900b3b75d9cSSepherosa Ziehau static void
5901b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(struct hn_softc *sc, int nchan)
5902b3b75d9cSSepherosa Ziehau {
5903b3b75d9cSSepherosa Ziehau 
5904b3b75d9cSSepherosa Ziehau 	hn_disable_rx(sc);
5905b3b75d9cSSepherosa Ziehau 	hn_drain_rxtx(sc, nchan);
5906b3b75d9cSSepherosa Ziehau }
5907b3b75d9cSSepherosa Ziehau 
590815516c77SSepherosa Ziehau static int
590915516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu)
591015516c77SSepherosa Ziehau {
591171e8ac56SSepherosa Ziehau #define ATTACHED_NVS		0x0002
591271e8ac56SSepherosa Ziehau #define ATTACHED_RNDIS		0x0004
591371e8ac56SSepherosa Ziehau 
591415516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
5915b3b75d9cSSepherosa Ziehau 	int error, nsubch, nchan = 1, i, rndis_inited;
591671e8ac56SSepherosa Ziehau 	uint32_t old_caps, attached = 0;
591715516c77SSepherosa Ziehau 
591815516c77SSepherosa Ziehau 	KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0,
591915516c77SSepherosa Ziehau 	    ("synthetic parts were attached"));
592015516c77SSepherosa Ziehau 
59212494d735SSepherosa Ziehau 	if (!hn_synth_attachable(sc))
59222494d735SSepherosa Ziehau 		return (ENXIO);
59232494d735SSepherosa Ziehau 
592415516c77SSepherosa Ziehau 	/* Save capabilities for later verification. */
592515516c77SSepherosa Ziehau 	old_caps = sc->hn_caps;
592615516c77SSepherosa Ziehau 	sc->hn_caps = 0;
592715516c77SSepherosa Ziehau 
592815516c77SSepherosa Ziehau 	/* Clear RSS stuffs. */
592915516c77SSepherosa Ziehau 	sc->hn_rss_ind_size = 0;
593015516c77SSepherosa Ziehau 	sc->hn_rss_hash = 0;
593115516c77SSepherosa Ziehau 
593215516c77SSepherosa Ziehau 	/*
593315516c77SSepherosa Ziehau 	 * Attach the primary channel _before_ attaching NVS and RNDIS.
593415516c77SSepherosa Ziehau 	 */
593515516c77SSepherosa Ziehau 	error = hn_chan_attach(sc, sc->hn_prichan);
593615516c77SSepherosa Ziehau 	if (error)
593771e8ac56SSepherosa Ziehau 		goto failed;
593815516c77SSepherosa Ziehau 
593915516c77SSepherosa Ziehau 	/*
594015516c77SSepherosa Ziehau 	 * Attach NVS.
594115516c77SSepherosa Ziehau 	 */
594215516c77SSepherosa Ziehau 	error = hn_nvs_attach(sc, mtu);
594315516c77SSepherosa Ziehau 	if (error)
594471e8ac56SSepherosa Ziehau 		goto failed;
594571e8ac56SSepherosa Ziehau 	attached |= ATTACHED_NVS;
594615516c77SSepherosa Ziehau 
594715516c77SSepherosa Ziehau 	/*
594815516c77SSepherosa Ziehau 	 * Attach RNDIS _after_ NVS is attached.
594915516c77SSepherosa Ziehau 	 */
5950b3b75d9cSSepherosa Ziehau 	error = hn_rndis_attach(sc, mtu, &rndis_inited);
5951b3b75d9cSSepherosa Ziehau 	if (rndis_inited)
5952b3b75d9cSSepherosa Ziehau 		attached |= ATTACHED_RNDIS;
595315516c77SSepherosa Ziehau 	if (error)
595471e8ac56SSepherosa Ziehau 		goto failed;
595515516c77SSepherosa Ziehau 
595615516c77SSepherosa Ziehau 	/*
595715516c77SSepherosa Ziehau 	 * Make sure capabilities are not changed.
595815516c77SSepherosa Ziehau 	 */
595915516c77SSepherosa Ziehau 	if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) {
596015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n",
596115516c77SSepherosa Ziehau 		    old_caps, sc->hn_caps);
596271e8ac56SSepherosa Ziehau 		error = ENXIO;
596371e8ac56SSepherosa Ziehau 		goto failed;
596415516c77SSepherosa Ziehau 	}
596515516c77SSepherosa Ziehau 
596615516c77SSepherosa Ziehau 	/*
596715516c77SSepherosa Ziehau 	 * Allocate sub-channels for multi-TX/RX rings.
596815516c77SSepherosa Ziehau 	 *
596915516c77SSepherosa Ziehau 	 * NOTE:
597015516c77SSepherosa Ziehau 	 * The # of RX rings that can be used is equivalent to the # of
597115516c77SSepherosa Ziehau 	 * channels to be requested.
597215516c77SSepherosa Ziehau 	 */
597315516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_cnt - 1;
597415516c77SSepherosa Ziehau 	error = hn_synth_alloc_subchans(sc, &nsubch);
597515516c77SSepherosa Ziehau 	if (error)
597671e8ac56SSepherosa Ziehau 		goto failed;
597771e8ac56SSepherosa Ziehau 	/* NOTE: _Full_ synthetic parts detach is required now. */
597871e8ac56SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED;
597915516c77SSepherosa Ziehau 
598071e8ac56SSepherosa Ziehau 	/*
598171e8ac56SSepherosa Ziehau 	 * Set the # of TX/RX rings that could be used according to
598271e8ac56SSepherosa Ziehau 	 * the # of channels that NVS offered.
598371e8ac56SSepherosa Ziehau 	 */
598415516c77SSepherosa Ziehau 	nchan = nsubch + 1;
598571e8ac56SSepherosa Ziehau 	hn_set_ring_inuse(sc, nchan);
598615516c77SSepherosa Ziehau 	if (nchan == 1) {
598715516c77SSepherosa Ziehau 		/* Only the primary channel can be used; done */
598815516c77SSepherosa Ziehau 		goto back;
598915516c77SSepherosa Ziehau 	}
599015516c77SSepherosa Ziehau 
599115516c77SSepherosa Ziehau 	/*
599271e8ac56SSepherosa Ziehau 	 * Attach the sub-channels.
5993afd4971bSSepherosa Ziehau 	 *
5994afd4971bSSepherosa Ziehau 	 * NOTE: hn_set_ring_inuse() _must_ have been called.
599515516c77SSepherosa Ziehau 	 */
599671e8ac56SSepherosa Ziehau 	error = hn_attach_subchans(sc);
599771e8ac56SSepherosa Ziehau 	if (error)
599871e8ac56SSepherosa Ziehau 		goto failed;
599915516c77SSepherosa Ziehau 
600071e8ac56SSepherosa Ziehau 	/*
600171e8ac56SSepherosa Ziehau 	 * Configure RSS key and indirect table _after_ all sub-channels
600271e8ac56SSepherosa Ziehau 	 * are attached.
600371e8ac56SSepherosa Ziehau 	 */
600415516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) {
600515516c77SSepherosa Ziehau 		/*
600615516c77SSepherosa Ziehau 		 * RSS key is not set yet; set it to the default RSS key.
600715516c77SSepherosa Ziehau 		 */
600815516c77SSepherosa Ziehau 		if (bootverbose)
600915516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS key\n");
601034d68912SSepherosa Ziehau #ifdef RSS
601134d68912SSepherosa Ziehau 		rss_getkey(rss->rss_key);
601234d68912SSepherosa Ziehau #else
601315516c77SSepherosa Ziehau 		memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key));
601434d68912SSepherosa Ziehau #endif
601515516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
601615516c77SSepherosa Ziehau 	}
601715516c77SSepherosa Ziehau 
601815516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) {
601915516c77SSepherosa Ziehau 		/*
602015516c77SSepherosa Ziehau 		 * RSS indirect table is not set yet; set it up in round-
602115516c77SSepherosa Ziehau 		 * robin fashion.
602215516c77SSepherosa Ziehau 		 */
602315516c77SSepherosa Ziehau 		if (bootverbose) {
602415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS indirect "
602515516c77SSepherosa Ziehau 			    "table\n");
602615516c77SSepherosa Ziehau 		}
602734d68912SSepherosa Ziehau 		for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
602834d68912SSepherosa Ziehau 			uint32_t subidx;
602934d68912SSepherosa Ziehau 
603034d68912SSepherosa Ziehau #ifdef RSS
603134d68912SSepherosa Ziehau 			subidx = rss_get_indirection_to_bucket(i);
603234d68912SSepherosa Ziehau #else
603334d68912SSepherosa Ziehau 			subidx = i;
603434d68912SSepherosa Ziehau #endif
603534d68912SSepherosa Ziehau 			rss->rss_ind[i] = subidx % nchan;
603634d68912SSepherosa Ziehau 		}
603715516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSIND;
603815516c77SSepherosa Ziehau 	} else {
603915516c77SSepherosa Ziehau 		/*
604015516c77SSepherosa Ziehau 		 * # of usable channels may be changed, so we have to
604115516c77SSepherosa Ziehau 		 * make sure that all entries in RSS indirect table
604215516c77SSepherosa Ziehau 		 * are valid.
6043afd4971bSSepherosa Ziehau 		 *
6044afd4971bSSepherosa Ziehau 		 * NOTE: hn_set_ring_inuse() _must_ have been called.
604515516c77SSepherosa Ziehau 		 */
6046afd4971bSSepherosa Ziehau 		hn_rss_ind_fixup(sc);
604715516c77SSepherosa Ziehau 	}
604815516c77SSepherosa Ziehau 
604915516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
605015516c77SSepherosa Ziehau 	if (error)
605171e8ac56SSepherosa Ziehau 		goto failed;
605271e8ac56SSepherosa Ziehau back:
6053dc13fee6SSepherosa Ziehau 	/*
6054dc13fee6SSepherosa Ziehau 	 * Fixup transmission aggregation setup.
6055dc13fee6SSepherosa Ziehau 	 */
6056dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
6057b3b75d9cSSepherosa Ziehau 	hn_rndis_init_fixat(sc, nchan);
605815516c77SSepherosa Ziehau 	return (0);
605971e8ac56SSepherosa Ziehau 
606071e8ac56SSepherosa Ziehau failed:
606171e8ac56SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
6062b3b75d9cSSepherosa Ziehau 		hn_rndis_init_fixat(sc, nchan);
606371e8ac56SSepherosa Ziehau 		hn_synth_detach(sc);
606471e8ac56SSepherosa Ziehau 	} else {
6065b3b75d9cSSepherosa Ziehau 		if (attached & ATTACHED_RNDIS) {
6066b3b75d9cSSepherosa Ziehau 			hn_rndis_init_fixat(sc, nchan);
606771e8ac56SSepherosa Ziehau 			hn_rndis_detach(sc);
6068b3b75d9cSSepherosa Ziehau 		}
606971e8ac56SSepherosa Ziehau 		if (attached & ATTACHED_NVS)
607071e8ac56SSepherosa Ziehau 			hn_nvs_detach(sc);
607171e8ac56SSepherosa Ziehau 		hn_chan_detach(sc, sc->hn_prichan);
607271e8ac56SSepherosa Ziehau 		/* Restore old capabilities. */
607371e8ac56SSepherosa Ziehau 		sc->hn_caps = old_caps;
607471e8ac56SSepherosa Ziehau 	}
607571e8ac56SSepherosa Ziehau 	return (error);
607671e8ac56SSepherosa Ziehau 
607771e8ac56SSepherosa Ziehau #undef ATTACHED_RNDIS
607871e8ac56SSepherosa Ziehau #undef ATTACHED_NVS
607915516c77SSepherosa Ziehau }
608015516c77SSepherosa Ziehau 
608115516c77SSepherosa Ziehau /*
608215516c77SSepherosa Ziehau  * NOTE:
608315516c77SSepherosa Ziehau  * The interface must have been suspended though hn_suspend(), before
608415516c77SSepherosa Ziehau  * this function get called.
608515516c77SSepherosa Ziehau  */
608615516c77SSepherosa Ziehau static void
608715516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc)
608815516c77SSepherosa Ziehau {
608915516c77SSepherosa Ziehau 
609015516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
609115516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
609215516c77SSepherosa Ziehau 
609315516c77SSepherosa Ziehau 	/* Detach the RNDIS first. */
609415516c77SSepherosa Ziehau 	hn_rndis_detach(sc);
609515516c77SSepherosa Ziehau 
609615516c77SSepherosa Ziehau 	/* Detach NVS. */
609715516c77SSepherosa Ziehau 	hn_nvs_detach(sc);
609815516c77SSepherosa Ziehau 
609915516c77SSepherosa Ziehau 	/* Detach all of the channels. */
610015516c77SSepherosa Ziehau 	hn_detach_allchans(sc);
610115516c77SSepherosa Ziehau 
610215516c77SSepherosa Ziehau 	sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED;
610315516c77SSepherosa Ziehau }
610415516c77SSepherosa Ziehau 
610515516c77SSepherosa Ziehau static void
610615516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt)
610715516c77SSepherosa Ziehau {
610815516c77SSepherosa Ziehau 	KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt,
610915516c77SSepherosa Ziehau 	    ("invalid ring count %d", ring_cnt));
611015516c77SSepherosa Ziehau 
611115516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt > ring_cnt)
611215516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = ring_cnt;
611315516c77SSepherosa Ziehau 	else
611415516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
611515516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = ring_cnt;
611615516c77SSepherosa Ziehau 
611734d68912SSepherosa Ziehau #ifdef RSS
611834d68912SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse != rss_getnumbuckets()) {
611934d68912SSepherosa Ziehau 		if_printf(sc->hn_ifp, "# of RX rings (%d) does not match "
612034d68912SSepherosa Ziehau 		    "# of RSS buckets (%d)\n", sc->hn_rx_ring_inuse,
612134d68912SSepherosa Ziehau 		    rss_getnumbuckets());
612234d68912SSepherosa Ziehau 	}
612334d68912SSepherosa Ziehau #endif
612434d68912SSepherosa Ziehau 
612515516c77SSepherosa Ziehau 	if (bootverbose) {
612615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n",
612715516c77SSepherosa Ziehau 		    sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
612815516c77SSepherosa Ziehau 	}
612915516c77SSepherosa Ziehau }
613015516c77SSepherosa Ziehau 
613115516c77SSepherosa Ziehau static void
613225641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan)
613315516c77SSepherosa Ziehau {
613415516c77SSepherosa Ziehau 
613525641fc7SSepherosa Ziehau 	/*
613625641fc7SSepherosa Ziehau 	 * NOTE:
613725641fc7SSepherosa Ziehau 	 * The TX bufring will not be drained by the hypervisor,
613825641fc7SSepherosa Ziehau 	 * if the primary channel is revoked.
613925641fc7SSepherosa Ziehau 	 */
614025641fc7SSepherosa Ziehau 	while (!vmbus_chan_rx_empty(chan) ||
614125641fc7SSepherosa Ziehau 	    (!vmbus_chan_is_revoked(sc->hn_prichan) &&
614225641fc7SSepherosa Ziehau 	     !vmbus_chan_tx_empty(chan)))
614315516c77SSepherosa Ziehau 		pause("waitch", 1);
614415516c77SSepherosa Ziehau 	vmbus_chan_intr_drain(chan);
614515516c77SSepherosa Ziehau }
614615516c77SSepherosa Ziehau 
614715516c77SSepherosa Ziehau static void
6148b3b75d9cSSepherosa Ziehau hn_disable_rx(struct hn_softc *sc)
6149b3b75d9cSSepherosa Ziehau {
6150b3b75d9cSSepherosa Ziehau 
6151b3b75d9cSSepherosa Ziehau 	/*
6152b3b75d9cSSepherosa Ziehau 	 * Disable RX by clearing RX filter forcefully.
6153b3b75d9cSSepherosa Ziehau 	 */
6154b3b75d9cSSepherosa Ziehau 	sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE;
6155b3b75d9cSSepherosa Ziehau 	hn_rndis_set_rxfilter(sc, sc->hn_rx_filter); /* ignore error */
6156b3b75d9cSSepherosa Ziehau 
6157b3b75d9cSSepherosa Ziehau 	/*
6158b3b75d9cSSepherosa Ziehau 	 * Give RNDIS enough time to flush all pending data packets.
6159b3b75d9cSSepherosa Ziehau 	 */
6160b3b75d9cSSepherosa Ziehau 	pause("waitrx", (200 * hz) / 1000);
6161b3b75d9cSSepherosa Ziehau }
6162b3b75d9cSSepherosa Ziehau 
6163b3b75d9cSSepherosa Ziehau /*
6164b3b75d9cSSepherosa Ziehau  * NOTE:
6165b3b75d9cSSepherosa Ziehau  * RX/TX _must_ have been suspended/disabled, before this function
6166b3b75d9cSSepherosa Ziehau  * is called.
6167b3b75d9cSSepherosa Ziehau  */
6168b3b75d9cSSepherosa Ziehau static void
6169b3b75d9cSSepherosa Ziehau hn_drain_rxtx(struct hn_softc *sc, int nchan)
617015516c77SSepherosa Ziehau {
617115516c77SSepherosa Ziehau 	struct vmbus_channel **subch = NULL;
6172b3b75d9cSSepherosa Ziehau 	int nsubch;
6173b3b75d9cSSepherosa Ziehau 
6174b3b75d9cSSepherosa Ziehau 	/*
6175b3b75d9cSSepherosa Ziehau 	 * Drain RX/TX bufrings and interrupts.
6176b3b75d9cSSepherosa Ziehau 	 */
6177b3b75d9cSSepherosa Ziehau 	nsubch = nchan - 1;
6178b3b75d9cSSepherosa Ziehau 	if (nsubch > 0)
6179b3b75d9cSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
6180b3b75d9cSSepherosa Ziehau 
6181b3b75d9cSSepherosa Ziehau 	if (subch != NULL) {
6182b3b75d9cSSepherosa Ziehau 		int i;
6183b3b75d9cSSepherosa Ziehau 
6184b3b75d9cSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
6185b3b75d9cSSepherosa Ziehau 			hn_chan_drain(sc, subch[i]);
6186b3b75d9cSSepherosa Ziehau 	}
6187b3b75d9cSSepherosa Ziehau 	hn_chan_drain(sc, sc->hn_prichan);
6188b3b75d9cSSepherosa Ziehau 
6189b3b75d9cSSepherosa Ziehau 	if (subch != NULL)
6190b3b75d9cSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
6191b3b75d9cSSepherosa Ziehau }
6192b3b75d9cSSepherosa Ziehau 
6193b3b75d9cSSepherosa Ziehau static void
6194b3b75d9cSSepherosa Ziehau hn_suspend_data(struct hn_softc *sc)
6195b3b75d9cSSepherosa Ziehau {
619625641fc7SSepherosa Ziehau 	struct hn_tx_ring *txr;
6197b3b75d9cSSepherosa Ziehau 	int i;
619815516c77SSepherosa Ziehau 
619915516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
620015516c77SSepherosa Ziehau 
620115516c77SSepherosa Ziehau 	/*
620215516c77SSepherosa Ziehau 	 * Suspend TX.
620315516c77SSepherosa Ziehau 	 */
620415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
620525641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
620615516c77SSepherosa Ziehau 
620715516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
620815516c77SSepherosa Ziehau 		txr->hn_suspended = 1;
620915516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
621015516c77SSepherosa Ziehau 		/* No one is able send more packets now. */
621115516c77SSepherosa Ziehau 
621225641fc7SSepherosa Ziehau 		/*
621325641fc7SSepherosa Ziehau 		 * Wait for all pending sends to finish.
621425641fc7SSepherosa Ziehau 		 *
621525641fc7SSepherosa Ziehau 		 * NOTE:
621625641fc7SSepherosa Ziehau 		 * We will _not_ receive all pending send-done, if the
621725641fc7SSepherosa Ziehau 		 * primary channel is revoked.
621825641fc7SSepherosa Ziehau 		 */
621925641fc7SSepherosa Ziehau 		while (hn_tx_ring_pending(txr) &&
622025641fc7SSepherosa Ziehau 		    !vmbus_chan_is_revoked(sc->hn_prichan))
622115516c77SSepherosa Ziehau 			pause("hnwtx", 1 /* 1 tick */);
622215516c77SSepherosa Ziehau 	}
622315516c77SSepherosa Ziehau 
622415516c77SSepherosa Ziehau 	/*
6225b3b75d9cSSepherosa Ziehau 	 * Disable RX.
622615516c77SSepherosa Ziehau 	 */
6227b3b75d9cSSepherosa Ziehau 	hn_disable_rx(sc);
622815516c77SSepherosa Ziehau 
622915516c77SSepherosa Ziehau 	/*
6230b3b75d9cSSepherosa Ziehau 	 * Drain RX/TX.
623115516c77SSepherosa Ziehau 	 */
6232b3b75d9cSSepherosa Ziehau 	hn_drain_rxtx(sc, sc->hn_rx_ring_inuse);
623325641fc7SSepherosa Ziehau 
623425641fc7SSepherosa Ziehau 	/*
623525641fc7SSepherosa Ziehau 	 * Drain any pending TX tasks.
623625641fc7SSepherosa Ziehau 	 *
623725641fc7SSepherosa Ziehau 	 * NOTE:
6238b3b75d9cSSepherosa Ziehau 	 * The above hn_drain_rxtx() can dispatch TX tasks, so the TX
6239b3b75d9cSSepherosa Ziehau 	 * tasks will have to be drained _after_ the above hn_drain_rxtx().
624025641fc7SSepherosa Ziehau 	 */
624125641fc7SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
624225641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
624325641fc7SSepherosa Ziehau 
624425641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task);
624525641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task);
624625641fc7SSepherosa Ziehau 	}
624715516c77SSepherosa Ziehau }
624815516c77SSepherosa Ziehau 
624915516c77SSepherosa Ziehau static void
625015516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused)
625115516c77SSepherosa Ziehau {
625215516c77SSepherosa Ziehau 
625315516c77SSepherosa Ziehau 	((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL;
625415516c77SSepherosa Ziehau }
625515516c77SSepherosa Ziehau 
625615516c77SSepherosa Ziehau static void
625715516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc)
625815516c77SSepherosa Ziehau {
625915516c77SSepherosa Ziehau 	struct task task;
626015516c77SSepherosa Ziehau 
626115516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
626215516c77SSepherosa Ziehau 
626315516c77SSepherosa Ziehau 	/*
626415516c77SSepherosa Ziehau 	 * Make sure that hn_mgmt_taskq0 can nolonger be accessed
626515516c77SSepherosa Ziehau 	 * through hn_mgmt_taskq.
626615516c77SSepherosa Ziehau 	 */
626715516c77SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc);
626815516c77SSepherosa Ziehau 	vmbus_chan_run_task(sc->hn_prichan, &task);
626915516c77SSepherosa Ziehau 
627015516c77SSepherosa Ziehau 	/*
627115516c77SSepherosa Ziehau 	 * Make sure that all pending management tasks are completed.
627215516c77SSepherosa Ziehau 	 */
627315516c77SSepherosa Ziehau 	taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init);
627415516c77SSepherosa Ziehau 	taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status);
627515516c77SSepherosa Ziehau 	taskqueue_drain_all(sc->hn_mgmt_taskq0);
627615516c77SSepherosa Ziehau }
627715516c77SSepherosa Ziehau 
627815516c77SSepherosa Ziehau static void
627915516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc)
628015516c77SSepherosa Ziehau {
628115516c77SSepherosa Ziehau 
628287f8129dSSepherosa Ziehau 	/* Disable polling. */
628387f8129dSSepherosa Ziehau 	hn_polling(sc, 0);
628487f8129dSSepherosa Ziehau 
62859c6cae24SSepherosa Ziehau 	/*
62869c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, the synthetic
62879c6cae24SSepherosa Ziehau 	 * device is receiving packets, so the data path of the
62889c6cae24SSepherosa Ziehau 	 * synthetic device must be suspended.
62899c6cae24SSepherosa Ziehau 	 */
62905bdfd3fdSDexuan Cui 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
6291962f0357SSepherosa Ziehau 	    (sc->hn_flags & HN_FLAG_RXVF))
629215516c77SSepherosa Ziehau 		hn_suspend_data(sc);
629315516c77SSepherosa Ziehau 	hn_suspend_mgmt(sc);
629415516c77SSepherosa Ziehau }
629515516c77SSepherosa Ziehau 
629615516c77SSepherosa Ziehau static void
629715516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt)
629815516c77SSepherosa Ziehau {
629915516c77SSepherosa Ziehau 	int i;
630015516c77SSepherosa Ziehau 
630115516c77SSepherosa Ziehau 	KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt,
630215516c77SSepherosa Ziehau 	    ("invalid TX ring count %d", tx_ring_cnt));
630315516c77SSepherosa Ziehau 
630415516c77SSepherosa Ziehau 	for (i = 0; i < tx_ring_cnt; ++i) {
630515516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
630615516c77SSepherosa Ziehau 
630715516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
630815516c77SSepherosa Ziehau 		txr->hn_suspended = 0;
630915516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
631015516c77SSepherosa Ziehau 	}
631115516c77SSepherosa Ziehau }
631215516c77SSepherosa Ziehau 
631315516c77SSepherosa Ziehau static void
631415516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc)
631515516c77SSepherosa Ziehau {
631615516c77SSepherosa Ziehau 	int i;
631715516c77SSepherosa Ziehau 
631815516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
631915516c77SSepherosa Ziehau 
632015516c77SSepherosa Ziehau 	/*
632115516c77SSepherosa Ziehau 	 * Re-enable RX.
632215516c77SSepherosa Ziehau 	 */
6323c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
632415516c77SSepherosa Ziehau 
632515516c77SSepherosa Ziehau 	/*
632615516c77SSepherosa Ziehau 	 * Make sure to clear suspend status on "all" TX rings,
632715516c77SSepherosa Ziehau 	 * since hn_tx_ring_inuse can be changed after
632815516c77SSepherosa Ziehau 	 * hn_suspend_data().
632915516c77SSepherosa Ziehau 	 */
633015516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_cnt);
633115516c77SSepherosa Ziehau 
633223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
633323bf9e15SSepherosa Ziehau 	if (!hn_use_if_start)
633423bf9e15SSepherosa Ziehau #endif
633523bf9e15SSepherosa Ziehau 	{
633615516c77SSepherosa Ziehau 		/*
633715516c77SSepherosa Ziehau 		 * Flush unused drbrs, since hn_tx_ring_inuse may be
633815516c77SSepherosa Ziehau 		 * reduced.
633915516c77SSepherosa Ziehau 		 */
634015516c77SSepherosa Ziehau 		for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i)
634115516c77SSepherosa Ziehau 			hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
634215516c77SSepherosa Ziehau 	}
634315516c77SSepherosa Ziehau 
634415516c77SSepherosa Ziehau 	/*
634515516c77SSepherosa Ziehau 	 * Kick start TX.
634615516c77SSepherosa Ziehau 	 */
634715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
634815516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
634915516c77SSepherosa Ziehau 
635015516c77SSepherosa Ziehau 		/*
635115516c77SSepherosa Ziehau 		 * Use txeof task, so that any pending oactive can be
635215516c77SSepherosa Ziehau 		 * cleared properly.
635315516c77SSepherosa Ziehau 		 */
635415516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
635515516c77SSepherosa Ziehau 	}
635615516c77SSepherosa Ziehau }
635715516c77SSepherosa Ziehau 
635815516c77SSepherosa Ziehau static void
635915516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc)
636015516c77SSepherosa Ziehau {
636115516c77SSepherosa Ziehau 
636215516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
636315516c77SSepherosa Ziehau 
636415516c77SSepherosa Ziehau 	/*
636515516c77SSepherosa Ziehau 	 * Kick off network change detection, if it was pending.
636615516c77SSepherosa Ziehau 	 * If no network change was pending, start link status
636715516c77SSepherosa Ziehau 	 * checks, which is more lightweight than network change
636815516c77SSepherosa Ziehau 	 * detection.
636915516c77SSepherosa Ziehau 	 */
637015516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
637115516c77SSepherosa Ziehau 		hn_change_network(sc);
637215516c77SSepherosa Ziehau 	else
637315516c77SSepherosa Ziehau 		hn_update_link_status(sc);
637415516c77SSepherosa Ziehau }
637515516c77SSepherosa Ziehau 
637615516c77SSepherosa Ziehau static void
637715516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc)
637815516c77SSepherosa Ziehau {
637915516c77SSepherosa Ziehau 
63809c6cae24SSepherosa Ziehau 	/*
63819c6cae24SSepherosa Ziehau 	 * If the non-transparent mode VF is activated, the synthetic
63829c6cae24SSepherosa Ziehau 	 * device have to receive packets, so the data path of the
63839c6cae24SSepherosa Ziehau 	 * synthetic device must be resumed.
63849c6cae24SSepherosa Ziehau 	 */
63855bdfd3fdSDexuan Cui 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
6386962f0357SSepherosa Ziehau 	    (sc->hn_flags & HN_FLAG_RXVF))
638715516c77SSepherosa Ziehau 		hn_resume_data(sc);
63885bdfd3fdSDexuan Cui 
63895bdfd3fdSDexuan Cui 	/*
63909c6cae24SSepherosa Ziehau 	 * Don't resume link status change if VF is attached/activated.
63919c6cae24SSepherosa Ziehau 	 * - In the non-transparent VF mode, the synthetic device marks
63929c6cae24SSepherosa Ziehau 	 *   link down until the VF is deactivated; i.e. VF is down.
63939c6cae24SSepherosa Ziehau 	 * - In transparent VF mode, VF's media status is used until
63949c6cae24SSepherosa Ziehau 	 *   the VF is detached.
63955bdfd3fdSDexuan Cui 	 */
63969c6cae24SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_RXVF) == 0 &&
63979c6cae24SSepherosa Ziehau 	    !(hn_xpnt_vf && sc->hn_vf_ifp != NULL))
639815516c77SSepherosa Ziehau 		hn_resume_mgmt(sc);
639987f8129dSSepherosa Ziehau 
640087f8129dSSepherosa Ziehau 	/*
640187f8129dSSepherosa Ziehau 	 * Re-enable polling if this interface is running and
640287f8129dSSepherosa Ziehau 	 * the polling is requested.
640387f8129dSSepherosa Ziehau 	 */
640487f8129dSSepherosa Ziehau 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->hn_pollhz > 0)
640587f8129dSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
640615516c77SSepherosa Ziehau }
640715516c77SSepherosa Ziehau 
640815516c77SSepherosa Ziehau static void
640915516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen)
641015516c77SSepherosa Ziehau {
641115516c77SSepherosa Ziehau 	const struct rndis_status_msg *msg;
641215516c77SSepherosa Ziehau 	int ofs;
641315516c77SSepherosa Ziehau 
641415516c77SSepherosa Ziehau 	if (dlen < sizeof(*msg)) {
641515516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid RNDIS status\n");
641615516c77SSepherosa Ziehau 		return;
641715516c77SSepherosa Ziehau 	}
641815516c77SSepherosa Ziehau 	msg = data;
641915516c77SSepherosa Ziehau 
642015516c77SSepherosa Ziehau 	switch (msg->rm_status) {
642115516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_CONNECT:
642215516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_DISCONNECT:
642315516c77SSepherosa Ziehau 		hn_update_link_status(sc);
642415516c77SSepherosa Ziehau 		break;
642515516c77SSepherosa Ziehau 
642615516c77SSepherosa Ziehau 	case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
642740905afaSSepherosa Ziehau 	case RNDIS_STATUS_LINK_SPEED_CHANGE:
642815516c77SSepherosa Ziehau 		/* Not really useful; ignore. */
642915516c77SSepherosa Ziehau 		break;
643015516c77SSepherosa Ziehau 
643115516c77SSepherosa Ziehau 	case RNDIS_STATUS_NETWORK_CHANGE:
643215516c77SSepherosa Ziehau 		ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
643315516c77SSepherosa Ziehau 		if (dlen < ofs + msg->rm_stbuflen ||
643415516c77SSepherosa Ziehau 		    msg->rm_stbuflen < sizeof(uint32_t)) {
643515516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed\n");
643615516c77SSepherosa Ziehau 		} else {
643715516c77SSepherosa Ziehau 			uint32_t change;
643815516c77SSepherosa Ziehau 
643915516c77SSepherosa Ziehau 			memcpy(&change, ((const uint8_t *)msg) + ofs,
644015516c77SSepherosa Ziehau 			    sizeof(change));
644115516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed, change %u\n",
644215516c77SSepherosa Ziehau 			    change);
644315516c77SSepherosa Ziehau 		}
644415516c77SSepherosa Ziehau 		hn_change_network(sc);
644515516c77SSepherosa Ziehau 		break;
644615516c77SSepherosa Ziehau 
644715516c77SSepherosa Ziehau 	default:
644815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
644915516c77SSepherosa Ziehau 		    msg->rm_status);
645015516c77SSepherosa Ziehau 		break;
645115516c77SSepherosa Ziehau 	}
645215516c77SSepherosa Ziehau }
645315516c77SSepherosa Ziehau 
645415516c77SSepherosa Ziehau static int
645515516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info)
645615516c77SSepherosa Ziehau {
645715516c77SSepherosa Ziehau 	const struct rndis_pktinfo *pi = info_data;
645815516c77SSepherosa Ziehau 	uint32_t mask = 0;
645915516c77SSepherosa Ziehau 
646015516c77SSepherosa Ziehau 	while (info_dlen != 0) {
646115516c77SSepherosa Ziehau 		const void *data;
646215516c77SSepherosa Ziehau 		uint32_t dlen;
646315516c77SSepherosa Ziehau 
646415516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < sizeof(*pi)))
646515516c77SSepherosa Ziehau 			return (EINVAL);
646615516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < pi->rm_size))
646715516c77SSepherosa Ziehau 			return (EINVAL);
646815516c77SSepherosa Ziehau 		info_dlen -= pi->rm_size;
646915516c77SSepherosa Ziehau 
647015516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
647115516c77SSepherosa Ziehau 			return (EINVAL);
647215516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
647315516c77SSepherosa Ziehau 			return (EINVAL);
647415516c77SSepherosa Ziehau 		dlen = pi->rm_size - pi->rm_pktinfooffset;
647515516c77SSepherosa Ziehau 		data = pi->rm_data;
647615516c77SSepherosa Ziehau 
647715516c77SSepherosa Ziehau 		switch (pi->rm_type) {
647815516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_VLAN:
647915516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
648015516c77SSepherosa Ziehau 				return (EINVAL);
648115516c77SSepherosa Ziehau 			info->vlan_info = *((const uint32_t *)data);
648215516c77SSepherosa Ziehau 			mask |= HN_RXINFO_VLAN;
648315516c77SSepherosa Ziehau 			break;
648415516c77SSepherosa Ziehau 
648515516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_CSUM:
648615516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
648715516c77SSepherosa Ziehau 				return (EINVAL);
648815516c77SSepherosa Ziehau 			info->csum_info = *((const uint32_t *)data);
648915516c77SSepherosa Ziehau 			mask |= HN_RXINFO_CSUM;
649015516c77SSepherosa Ziehau 			break;
649115516c77SSepherosa Ziehau 
649215516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHVAL:
649315516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
649415516c77SSepherosa Ziehau 				return (EINVAL);
649515516c77SSepherosa Ziehau 			info->hash_value = *((const uint32_t *)data);
649615516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHVAL;
649715516c77SSepherosa Ziehau 			break;
649815516c77SSepherosa Ziehau 
649915516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHINF:
650015516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
650115516c77SSepherosa Ziehau 				return (EINVAL);
650215516c77SSepherosa Ziehau 			info->hash_info = *((const uint32_t *)data);
650315516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHINF;
650415516c77SSepherosa Ziehau 			break;
650515516c77SSepherosa Ziehau 
650615516c77SSepherosa Ziehau 		default:
650715516c77SSepherosa Ziehau 			goto next;
650815516c77SSepherosa Ziehau 		}
650915516c77SSepherosa Ziehau 
651015516c77SSepherosa Ziehau 		if (mask == HN_RXINFO_ALL) {
651115516c77SSepherosa Ziehau 			/* All found; done */
651215516c77SSepherosa Ziehau 			break;
651315516c77SSepherosa Ziehau 		}
651415516c77SSepherosa Ziehau next:
651515516c77SSepherosa Ziehau 		pi = (const struct rndis_pktinfo *)
651615516c77SSepherosa Ziehau 		    ((const uint8_t *)pi + pi->rm_size);
651715516c77SSepherosa Ziehau 	}
651815516c77SSepherosa Ziehau 
651915516c77SSepherosa Ziehau 	/*
652015516c77SSepherosa Ziehau 	 * Final fixup.
652115516c77SSepherosa Ziehau 	 * - If there is no hash value, invalidate the hash info.
652215516c77SSepherosa Ziehau 	 */
652315516c77SSepherosa Ziehau 	if ((mask & HN_RXINFO_HASHVAL) == 0)
652415516c77SSepherosa Ziehau 		info->hash_info = HN_NDIS_HASH_INFO_INVALID;
652515516c77SSepherosa Ziehau 	return (0);
652615516c77SSepherosa Ziehau }
652715516c77SSepherosa Ziehau 
652815516c77SSepherosa Ziehau static __inline bool
652915516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
653015516c77SSepherosa Ziehau {
653115516c77SSepherosa Ziehau 
653215516c77SSepherosa Ziehau 	if (off < check_off) {
653315516c77SSepherosa Ziehau 		if (__predict_true(off + len <= check_off))
653415516c77SSepherosa Ziehau 			return (false);
653515516c77SSepherosa Ziehau 	} else if (off > check_off) {
653615516c77SSepherosa Ziehau 		if (__predict_true(check_off + check_len <= off))
653715516c77SSepherosa Ziehau 			return (false);
653815516c77SSepherosa Ziehau 	}
653915516c77SSepherosa Ziehau 	return (true);
654015516c77SSepherosa Ziehau }
654115516c77SSepherosa Ziehau 
654215516c77SSepherosa Ziehau static void
654315516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen)
654415516c77SSepherosa Ziehau {
654515516c77SSepherosa Ziehau 	const struct rndis_packet_msg *pkt;
654615516c77SSepherosa Ziehau 	struct hn_rxinfo info;
654715516c77SSepherosa Ziehau 	int data_off, pktinfo_off, data_len, pktinfo_len;
654815516c77SSepherosa Ziehau 
654915516c77SSepherosa Ziehau 	/*
655015516c77SSepherosa Ziehau 	 * Check length.
655115516c77SSepherosa Ziehau 	 */
655215516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*pkt))) {
655315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
655415516c77SSepherosa Ziehau 		return;
655515516c77SSepherosa Ziehau 	}
655615516c77SSepherosa Ziehau 	pkt = data;
655715516c77SSepherosa Ziehau 
655815516c77SSepherosa Ziehau 	if (__predict_false(dlen < pkt->rm_len)) {
655915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
656015516c77SSepherosa Ziehau 		    "dlen %d, msglen %u\n", dlen, pkt->rm_len);
656115516c77SSepherosa Ziehau 		return;
656215516c77SSepherosa Ziehau 	}
656315516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_len <
656415516c77SSepherosa Ziehau 	    pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
656515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
656615516c77SSepherosa Ziehau 		    "msglen %u, data %u, oob %u, pktinfo %u\n",
656715516c77SSepherosa Ziehau 		    pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
656815516c77SSepherosa Ziehau 		    pkt->rm_pktinfolen);
656915516c77SSepherosa Ziehau 		return;
657015516c77SSepherosa Ziehau 	}
657115516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_datalen == 0)) {
657215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
657315516c77SSepherosa Ziehau 		return;
657415516c77SSepherosa Ziehau 	}
657515516c77SSepherosa Ziehau 
657615516c77SSepherosa Ziehau 	/*
657715516c77SSepherosa Ziehau 	 * Check offests.
657815516c77SSepherosa Ziehau 	 */
657915516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs)			\
658015516c77SSepherosa Ziehau 	((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN ||	\
658115516c77SSepherosa Ziehau 	 ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
658215516c77SSepherosa Ziehau 
658315516c77SSepherosa Ziehau 	/* XXX Hyper-V does not meet data offset alignment requirement */
658415516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
658515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
658615516c77SSepherosa Ziehau 		    "data offset %u\n", pkt->rm_dataoffset);
658715516c77SSepherosa Ziehau 		return;
658815516c77SSepherosa Ziehau 	}
658915516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdataoffset > 0 &&
659015516c77SSepherosa Ziehau 	    IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
659115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
659215516c77SSepherosa Ziehau 		    "oob offset %u\n", pkt->rm_oobdataoffset);
659315516c77SSepherosa Ziehau 		return;
659415516c77SSepherosa Ziehau 	}
659515516c77SSepherosa Ziehau 	if (__predict_true(pkt->rm_pktinfooffset > 0) &&
659615516c77SSepherosa Ziehau 	    __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
659715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
659815516c77SSepherosa Ziehau 		    "pktinfo offset %u\n", pkt->rm_pktinfooffset);
659915516c77SSepherosa Ziehau 		return;
660015516c77SSepherosa Ziehau 	}
660115516c77SSepherosa Ziehau 
660215516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID
660315516c77SSepherosa Ziehau 
660415516c77SSepherosa Ziehau 	data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
660515516c77SSepherosa Ziehau 	data_len = pkt->rm_datalen;
660615516c77SSepherosa Ziehau 	pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
660715516c77SSepherosa Ziehau 	pktinfo_len = pkt->rm_pktinfolen;
660815516c77SSepherosa Ziehau 
660915516c77SSepherosa Ziehau 	/*
661015516c77SSepherosa Ziehau 	 * Check OOB coverage.
661115516c77SSepherosa Ziehau 	 */
661215516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdatalen != 0)) {
661315516c77SSepherosa Ziehau 		int oob_off, oob_len;
661415516c77SSepherosa Ziehau 
661515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "got oobdata\n");
661615516c77SSepherosa Ziehau 		oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
661715516c77SSepherosa Ziehau 		oob_len = pkt->rm_oobdatalen;
661815516c77SSepherosa Ziehau 
661915516c77SSepherosa Ziehau 		if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
662015516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
662115516c77SSepherosa Ziehau 			    "oob overflow, msglen %u, oob abs %d len %d\n",
662215516c77SSepherosa Ziehau 			    pkt->rm_len, oob_off, oob_len);
662315516c77SSepherosa Ziehau 			return;
662415516c77SSepherosa Ziehau 		}
662515516c77SSepherosa Ziehau 
662615516c77SSepherosa Ziehau 		/*
662715516c77SSepherosa Ziehau 		 * Check against data.
662815516c77SSepherosa Ziehau 		 */
662915516c77SSepherosa Ziehau 		if (hn_rndis_check_overlap(oob_off, oob_len,
663015516c77SSepherosa Ziehau 		    data_off, data_len)) {
663115516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
663215516c77SSepherosa Ziehau 			    "oob overlaps data, oob abs %d len %d, "
663315516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
663415516c77SSepherosa Ziehau 			    oob_off, oob_len, data_off, data_len);
663515516c77SSepherosa Ziehau 			return;
663615516c77SSepherosa Ziehau 		}
663715516c77SSepherosa Ziehau 
663815516c77SSepherosa Ziehau 		/*
663915516c77SSepherosa Ziehau 		 * Check against pktinfo.
664015516c77SSepherosa Ziehau 		 */
664115516c77SSepherosa Ziehau 		if (pktinfo_len != 0 &&
664215516c77SSepherosa Ziehau 		    hn_rndis_check_overlap(oob_off, oob_len,
664315516c77SSepherosa Ziehau 		    pktinfo_off, pktinfo_len)) {
664415516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
664515516c77SSepherosa Ziehau 			    "oob overlaps pktinfo, oob abs %d len %d, "
664615516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
664715516c77SSepherosa Ziehau 			    oob_off, oob_len, pktinfo_off, pktinfo_len);
664815516c77SSepherosa Ziehau 			return;
664915516c77SSepherosa Ziehau 		}
665015516c77SSepherosa Ziehau 	}
665115516c77SSepherosa Ziehau 
665215516c77SSepherosa Ziehau 	/*
665315516c77SSepherosa Ziehau 	 * Check per-packet-info coverage and find useful per-packet-info.
665415516c77SSepherosa Ziehau 	 */
665515516c77SSepherosa Ziehau 	info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
665615516c77SSepherosa Ziehau 	info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
665715516c77SSepherosa Ziehau 	info.hash_info = HN_NDIS_HASH_INFO_INVALID;
665815516c77SSepherosa Ziehau 	if (__predict_true(pktinfo_len != 0)) {
665915516c77SSepherosa Ziehau 		bool overlap;
666015516c77SSepherosa Ziehau 		int error;
666115516c77SSepherosa Ziehau 
666215516c77SSepherosa Ziehau 		if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
666315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
666415516c77SSepherosa Ziehau 			    "pktinfo overflow, msglen %u, "
666515516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
666615516c77SSepherosa Ziehau 			    pkt->rm_len, pktinfo_off, pktinfo_len);
666715516c77SSepherosa Ziehau 			return;
666815516c77SSepherosa Ziehau 		}
666915516c77SSepherosa Ziehau 
667015516c77SSepherosa Ziehau 		/*
667115516c77SSepherosa Ziehau 		 * Check packet info coverage.
667215516c77SSepherosa Ziehau 		 */
667315516c77SSepherosa Ziehau 		overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
667415516c77SSepherosa Ziehau 		    data_off, data_len);
667515516c77SSepherosa Ziehau 		if (__predict_false(overlap)) {
667615516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
667715516c77SSepherosa Ziehau 			    "pktinfo overlap data, pktinfo abs %d len %d, "
667815516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
667915516c77SSepherosa Ziehau 			    pktinfo_off, pktinfo_len, data_off, data_len);
668015516c77SSepherosa Ziehau 			return;
668115516c77SSepherosa Ziehau 		}
668215516c77SSepherosa Ziehau 
668315516c77SSepherosa Ziehau 		/*
668415516c77SSepherosa Ziehau 		 * Find useful per-packet-info.
668515516c77SSepherosa Ziehau 		 */
668615516c77SSepherosa Ziehau 		error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
668715516c77SSepherosa Ziehau 		    pktinfo_len, &info);
668815516c77SSepherosa Ziehau 		if (__predict_false(error)) {
668915516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
669015516c77SSepherosa Ziehau 			    "pktinfo\n");
669115516c77SSepherosa Ziehau 			return;
669215516c77SSepherosa Ziehau 		}
669315516c77SSepherosa Ziehau 	}
669415516c77SSepherosa Ziehau 
669515516c77SSepherosa Ziehau 	if (__predict_false(data_off + data_len > pkt->rm_len)) {
669615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
669715516c77SSepherosa Ziehau 		    "data overflow, msglen %u, data abs %d len %d\n",
669815516c77SSepherosa Ziehau 		    pkt->rm_len, data_off, data_len);
669915516c77SSepherosa Ziehau 		return;
670015516c77SSepherosa Ziehau 	}
670115516c77SSepherosa Ziehau 	hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
670215516c77SSepherosa Ziehau }
670315516c77SSepherosa Ziehau 
670415516c77SSepherosa Ziehau static __inline void
670515516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen)
670615516c77SSepherosa Ziehau {
670715516c77SSepherosa Ziehau 	const struct rndis_msghdr *hdr;
670815516c77SSepherosa Ziehau 
670915516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*hdr))) {
671015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
671115516c77SSepherosa Ziehau 		return;
671215516c77SSepherosa Ziehau 	}
671315516c77SSepherosa Ziehau 	hdr = data;
671415516c77SSepherosa Ziehau 
671515516c77SSepherosa Ziehau 	if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) {
671615516c77SSepherosa Ziehau 		/* Hot data path. */
671715516c77SSepherosa Ziehau 		hn_rndis_rx_data(rxr, data, dlen);
671815516c77SSepherosa Ziehau 		/* Done! */
671915516c77SSepherosa Ziehau 		return;
672015516c77SSepherosa Ziehau 	}
672115516c77SSepherosa Ziehau 
672215516c77SSepherosa Ziehau 	if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG)
672315516c77SSepherosa Ziehau 		hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen);
672415516c77SSepherosa Ziehau 	else
672515516c77SSepherosa Ziehau 		hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen);
672615516c77SSepherosa Ziehau }
672715516c77SSepherosa Ziehau 
672815516c77SSepherosa Ziehau static void
672915516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
673015516c77SSepherosa Ziehau {
673115516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *hdr;
673215516c77SSepherosa Ziehau 
673315516c77SSepherosa Ziehau 	if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) {
673415516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid nvs notify\n");
673515516c77SSepherosa Ziehau 		return;
673615516c77SSepherosa Ziehau 	}
673715516c77SSepherosa Ziehau 	hdr = VMBUS_CHANPKT_CONST_DATA(pkt);
673815516c77SSepherosa Ziehau 
673915516c77SSepherosa Ziehau 	if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) {
674015516c77SSepherosa Ziehau 		/* Useless; ignore */
674115516c77SSepherosa Ziehau 		return;
674215516c77SSepherosa Ziehau 	}
674315516c77SSepherosa Ziehau 	if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type);
674415516c77SSepherosa Ziehau }
674515516c77SSepherosa Ziehau 
674615516c77SSepherosa Ziehau static void
674715516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan,
674815516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkt)
674915516c77SSepherosa Ziehau {
675015516c77SSepherosa Ziehau 	struct hn_nvs_sendctx *sndc;
675115516c77SSepherosa Ziehau 
675215516c77SSepherosa Ziehau 	sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid;
675315516c77SSepherosa Ziehau 	sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt),
675415516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_DATALEN(pkt));
675515516c77SSepherosa Ziehau 	/*
675615516c77SSepherosa Ziehau 	 * NOTE:
675715516c77SSepherosa Ziehau 	 * 'sndc' CAN NOT be accessed anymore, since it can be freed by
675815516c77SSepherosa Ziehau 	 * its callback.
675915516c77SSepherosa Ziehau 	 */
676015516c77SSepherosa Ziehau }
676115516c77SSepherosa Ziehau 
676215516c77SSepherosa Ziehau static void
676315516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
676415516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkthdr)
676515516c77SSepherosa Ziehau {
676615516c77SSepherosa Ziehau 	const struct vmbus_chanpkt_rxbuf *pkt;
676715516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *nvs_hdr;
676815516c77SSepherosa Ziehau 	int count, i, hlen;
676915516c77SSepherosa Ziehau 
677015516c77SSepherosa Ziehau 	if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) {
677115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n");
677215516c77SSepherosa Ziehau 		return;
677315516c77SSepherosa Ziehau 	}
677415516c77SSepherosa Ziehau 	nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr);
677515516c77SSepherosa Ziehau 
677615516c77SSepherosa Ziehau 	/* Make sure that this is a RNDIS message. */
677715516c77SSepherosa Ziehau 	if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) {
677815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n",
677915516c77SSepherosa Ziehau 		    nvs_hdr->nvs_type);
678015516c77SSepherosa Ziehau 		return;
678115516c77SSepherosa Ziehau 	}
678215516c77SSepherosa Ziehau 
678315516c77SSepherosa Ziehau 	hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen);
678415516c77SSepherosa Ziehau 	if (__predict_false(hlen < sizeof(*pkt))) {
678515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n");
678615516c77SSepherosa Ziehau 		return;
678715516c77SSepherosa Ziehau 	}
678815516c77SSepherosa Ziehau 	pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
678915516c77SSepherosa Ziehau 
679015516c77SSepherosa Ziehau 	if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) {
679115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n",
679215516c77SSepherosa Ziehau 		    pkt->cp_rxbuf_id);
679315516c77SSepherosa Ziehau 		return;
679415516c77SSepherosa Ziehau 	}
679515516c77SSepherosa Ziehau 
679615516c77SSepherosa Ziehau 	count = pkt->cp_rxbuf_cnt;
679715516c77SSepherosa Ziehau 	if (__predict_false(hlen <
679815516c77SSepherosa Ziehau 	    __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) {
679915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count);
680015516c77SSepherosa Ziehau 		return;
680115516c77SSepherosa Ziehau 	}
680215516c77SSepherosa Ziehau 
680315516c77SSepherosa Ziehau 	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
680415516c77SSepherosa Ziehau 	for (i = 0; i < count; ++i) {
680515516c77SSepherosa Ziehau 		int ofs, len;
680615516c77SSepherosa Ziehau 
680715516c77SSepherosa Ziehau 		ofs = pkt->cp_rxbuf[i].rb_ofs;
680815516c77SSepherosa Ziehau 		len = pkt->cp_rxbuf[i].rb_len;
680915516c77SSepherosa Ziehau 		if (__predict_false(ofs + len > HN_RXBUF_SIZE)) {
681015516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, "
681115516c77SSepherosa Ziehau 			    "ofs %d, len %d\n", i, ofs, len);
681215516c77SSepherosa Ziehau 			continue;
681315516c77SSepherosa Ziehau 		}
681415516c77SSepherosa Ziehau 		hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len);
681515516c77SSepherosa Ziehau 	}
681615516c77SSepherosa Ziehau 
681715516c77SSepherosa Ziehau 	/*
681815516c77SSepherosa Ziehau 	 * Ack the consumed RXBUF associated w/ this channel packet,
681915516c77SSepherosa Ziehau 	 * so that this RXBUF can be recycled by the hypervisor.
682015516c77SSepherosa Ziehau 	 */
682115516c77SSepherosa Ziehau 	hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid);
682215516c77SSepherosa Ziehau }
682315516c77SSepherosa Ziehau 
682415516c77SSepherosa Ziehau static void
682515516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
682615516c77SSepherosa Ziehau     uint64_t tid)
682715516c77SSepherosa Ziehau {
682815516c77SSepherosa Ziehau 	struct hn_nvs_rndis_ack ack;
682915516c77SSepherosa Ziehau 	int retries, error;
683015516c77SSepherosa Ziehau 
683115516c77SSepherosa Ziehau 	ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK;
683215516c77SSepherosa Ziehau 	ack.nvs_status = HN_NVS_STATUS_OK;
683315516c77SSepherosa Ziehau 
683415516c77SSepherosa Ziehau 	retries = 0;
683515516c77SSepherosa Ziehau again:
683615516c77SSepherosa Ziehau 	error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP,
683715516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid);
683815516c77SSepherosa Ziehau 	if (__predict_false(error == EAGAIN)) {
683915516c77SSepherosa Ziehau 		/*
684015516c77SSepherosa Ziehau 		 * NOTE:
684115516c77SSepherosa Ziehau 		 * This should _not_ happen in real world, since the
684215516c77SSepherosa Ziehau 		 * consumption of the TX bufring from the TX path is
684315516c77SSepherosa Ziehau 		 * controlled.
684415516c77SSepherosa Ziehau 		 */
684515516c77SSepherosa Ziehau 		if (rxr->hn_ack_failed == 0)
684615516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "RXBUF ack retry\n");
684715516c77SSepherosa Ziehau 		rxr->hn_ack_failed++;
684815516c77SSepherosa Ziehau 		retries++;
684915516c77SSepherosa Ziehau 		if (retries < 10) {
685015516c77SSepherosa Ziehau 			DELAY(100);
685115516c77SSepherosa Ziehau 			goto again;
685215516c77SSepherosa Ziehau 		}
685315516c77SSepherosa Ziehau 		/* RXBUF leaks! */
685415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "RXBUF ack failed\n");
685515516c77SSepherosa Ziehau 	}
685615516c77SSepherosa Ziehau }
685715516c77SSepherosa Ziehau 
685815516c77SSepherosa Ziehau static void
685915516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr)
686015516c77SSepherosa Ziehau {
686115516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr = xrxr;
686215516c77SSepherosa Ziehau 	struct hn_softc *sc = rxr->hn_ifp->if_softc;
686315516c77SSepherosa Ziehau 
686415516c77SSepherosa Ziehau 	for (;;) {
686515516c77SSepherosa Ziehau 		struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf;
686615516c77SSepherosa Ziehau 		int error, pktlen;
686715516c77SSepherosa Ziehau 
686815516c77SSepherosa Ziehau 		pktlen = rxr->hn_pktbuf_len;
686915516c77SSepherosa Ziehau 		error = vmbus_chan_recv_pkt(chan, pkt, &pktlen);
687015516c77SSepherosa Ziehau 		if (__predict_false(error == ENOBUFS)) {
687115516c77SSepherosa Ziehau 			void *nbuf;
687215516c77SSepherosa Ziehau 			int nlen;
687315516c77SSepherosa Ziehau 
687415516c77SSepherosa Ziehau 			/*
687515516c77SSepherosa Ziehau 			 * Expand channel packet buffer.
687615516c77SSepherosa Ziehau 			 *
687715516c77SSepherosa Ziehau 			 * XXX
687815516c77SSepherosa Ziehau 			 * Use M_WAITOK here, since allocation failure
687915516c77SSepherosa Ziehau 			 * is fatal.
688015516c77SSepherosa Ziehau 			 */
688115516c77SSepherosa Ziehau 			nlen = rxr->hn_pktbuf_len * 2;
688215516c77SSepherosa Ziehau 			while (nlen < pktlen)
688315516c77SSepherosa Ziehau 				nlen *= 2;
688415516c77SSepherosa Ziehau 			nbuf = malloc(nlen, M_DEVBUF, M_WAITOK);
688515516c77SSepherosa Ziehau 
688615516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n",
688715516c77SSepherosa Ziehau 			    rxr->hn_pktbuf_len, nlen);
688815516c77SSepherosa Ziehau 
688915516c77SSepherosa Ziehau 			free(rxr->hn_pktbuf, M_DEVBUF);
689015516c77SSepherosa Ziehau 			rxr->hn_pktbuf = nbuf;
689115516c77SSepherosa Ziehau 			rxr->hn_pktbuf_len = nlen;
689215516c77SSepherosa Ziehau 			/* Retry! */
689315516c77SSepherosa Ziehau 			continue;
689415516c77SSepherosa Ziehau 		} else if (__predict_false(error == EAGAIN)) {
689515516c77SSepherosa Ziehau 			/* No more channel packets; done! */
689615516c77SSepherosa Ziehau 			break;
689715516c77SSepherosa Ziehau 		}
689815516c77SSepherosa Ziehau 		KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error));
689915516c77SSepherosa Ziehau 
690015516c77SSepherosa Ziehau 		switch (pkt->cph_type) {
690115516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_COMP:
690215516c77SSepherosa Ziehau 			hn_nvs_handle_comp(sc, chan, pkt);
690315516c77SSepherosa Ziehau 			break;
690415516c77SSepherosa Ziehau 
690515516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_RXBUF:
690615516c77SSepherosa Ziehau 			hn_nvs_handle_rxbuf(rxr, chan, pkt);
690715516c77SSepherosa Ziehau 			break;
690815516c77SSepherosa Ziehau 
690915516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_INBAND:
691015516c77SSepherosa Ziehau 			hn_nvs_handle_notify(sc, pkt);
691115516c77SSepherosa Ziehau 			break;
691215516c77SSepherosa Ziehau 
691315516c77SSepherosa Ziehau 		default:
691415516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "unknown chan pkt %u\n",
691515516c77SSepherosa Ziehau 			    pkt->cph_type);
691615516c77SSepherosa Ziehau 			break;
691715516c77SSepherosa Ziehau 		}
691815516c77SSepherosa Ziehau 	}
691915516c77SSepherosa Ziehau 	hn_chan_rollup(rxr, rxr->hn_txr);
692015516c77SSepherosa Ziehau }
692115516c77SSepherosa Ziehau 
692215516c77SSepherosa Ziehau static void
6923499c3e17SSepherosa Ziehau hn_sysinit(void *arg __unused)
692415516c77SSepherosa Ziehau {
6925fdd0222aSSepherosa Ziehau 	int i;
6926fdd0222aSSepherosa Ziehau 
69279c6cae24SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
69289c6cae24SSepherosa Ziehau 	/*
69299c6cae24SSepherosa Ziehau 	 * Don't use ifnet.if_start if transparent VF mode is requested;
69309c6cae24SSepherosa Ziehau 	 * mainly due to the IFF_DRV_OACTIVE flag.
69319c6cae24SSepherosa Ziehau 	 */
69329c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf && hn_use_if_start) {
69339c6cae24SSepherosa Ziehau 		hn_use_if_start = 0;
69349c6cae24SSepherosa Ziehau 		printf("hn: tranparent VF mode, if_transmit will be used, "
69359c6cae24SSepherosa Ziehau 		    "instead of if_start\n");
69369c6cae24SSepherosa Ziehau 	}
69379c6cae24SSepherosa Ziehau #endif
69389c6cae24SSepherosa Ziehau 	if (hn_xpnt_vf_attwait < HN_XPNT_VF_ATTWAIT_MIN) {
69399c6cae24SSepherosa Ziehau 		printf("hn: invalid transparent VF attach routing "
69409c6cae24SSepherosa Ziehau 		    "wait timeout %d, reset to %d\n",
69419c6cae24SSepherosa Ziehau 		    hn_xpnt_vf_attwait, HN_XPNT_VF_ATTWAIT_MIN);
69429c6cae24SSepherosa Ziehau 		hn_xpnt_vf_attwait = HN_XPNT_VF_ATTWAIT_MIN;
69439c6cae24SSepherosa Ziehau 	}
69449c6cae24SSepherosa Ziehau 
6945fdd0222aSSepherosa Ziehau 	/*
6946499c3e17SSepherosa Ziehau 	 * Initialize VF map.
6947499c3e17SSepherosa Ziehau 	 */
6948499c3e17SSepherosa Ziehau 	rm_init_flags(&hn_vfmap_lock, "hn_vfmap", RM_SLEEPABLE);
6949499c3e17SSepherosa Ziehau 	hn_vfmap_size = HN_VFMAP_SIZE_DEF;
6950499c3e17SSepherosa Ziehau 	hn_vfmap = malloc(sizeof(struct ifnet *) * hn_vfmap_size, M_DEVBUF,
6951499c3e17SSepherosa Ziehau 	    M_WAITOK | M_ZERO);
6952499c3e17SSepherosa Ziehau 
6953499c3e17SSepherosa Ziehau 	/*
6954fdd0222aSSepherosa Ziehau 	 * Fix the # of TX taskqueues.
6955fdd0222aSSepherosa Ziehau 	 */
6956fdd0222aSSepherosa Ziehau 	if (hn_tx_taskq_cnt <= 0)
6957fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = 1;
6958fdd0222aSSepherosa Ziehau 	else if (hn_tx_taskq_cnt > mp_ncpus)
6959fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = mp_ncpus;
696015516c77SSepherosa Ziehau 
69610e11868dSSepherosa Ziehau 	/*
69620e11868dSSepherosa Ziehau 	 * Fix the TX taskqueue mode.
69630e11868dSSepherosa Ziehau 	 */
69640e11868dSSepherosa Ziehau 	switch (hn_tx_taskq_mode) {
69650e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_INDEP:
69660e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_GLOBAL:
69670e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_EVTTQ:
69680e11868dSSepherosa Ziehau 		break;
69690e11868dSSepherosa Ziehau 	default:
69700e11868dSSepherosa Ziehau 		hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
69710e11868dSSepherosa Ziehau 		break;
69720e11868dSSepherosa Ziehau 	}
69730e11868dSSepherosa Ziehau 
697415516c77SSepherosa Ziehau 	if (vm_guest != VM_GUEST_HV)
697515516c77SSepherosa Ziehau 		return;
697615516c77SSepherosa Ziehau 
69770e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode != HN_TX_TASKQ_M_GLOBAL)
697815516c77SSepherosa Ziehau 		return;
697915516c77SSepherosa Ziehau 
6980fdd0222aSSepherosa Ziehau 	hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
6981fdd0222aSSepherosa Ziehau 	    M_DEVBUF, M_WAITOK);
6982fdd0222aSSepherosa Ziehau 	for (i = 0; i < hn_tx_taskq_cnt; ++i) {
6983fdd0222aSSepherosa Ziehau 		hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK,
6984fdd0222aSSepherosa Ziehau 		    taskqueue_thread_enqueue, &hn_tx_taskque[i]);
6985fdd0222aSSepherosa Ziehau 		taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET,
6986fdd0222aSSepherosa Ziehau 		    "hn tx%d", i);
6987fdd0222aSSepherosa Ziehau 	}
698815516c77SSepherosa Ziehau }
6989499c3e17SSepherosa Ziehau SYSINIT(hn_sysinit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysinit, NULL);
699015516c77SSepherosa Ziehau 
699115516c77SSepherosa Ziehau static void
6992499c3e17SSepherosa Ziehau hn_sysuninit(void *arg __unused)
699315516c77SSepherosa Ziehau {
699415516c77SSepherosa Ziehau 
6995fdd0222aSSepherosa Ziehau 	if (hn_tx_taskque != NULL) {
6996fdd0222aSSepherosa Ziehau 		int i;
6997fdd0222aSSepherosa Ziehau 
6998fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
6999fdd0222aSSepherosa Ziehau 			taskqueue_free(hn_tx_taskque[i]);
7000fdd0222aSSepherosa Ziehau 		free(hn_tx_taskque, M_DEVBUF);
7001fdd0222aSSepherosa Ziehau 	}
7002499c3e17SSepherosa Ziehau 
7003499c3e17SSepherosa Ziehau 	if (hn_vfmap != NULL)
7004499c3e17SSepherosa Ziehau 		free(hn_vfmap, M_DEVBUF);
7005499c3e17SSepherosa Ziehau 	rm_destroy(&hn_vfmap_lock);
700615516c77SSepherosa Ziehau }
7007499c3e17SSepherosa Ziehau SYSUNINIT(hn_sysuninit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysuninit, NULL);
7008