xref: /freebsd/sys/dev/hyperv/netvsc/if_hn.c (revision b3b75d9c84098cdf4295cb68405bd737e5052264)
115516c77SSepherosa Ziehau /*-
215516c77SSepherosa Ziehau  * Copyright (c) 2010-2012 Citrix Inc.
315516c77SSepherosa Ziehau  * Copyright (c) 2009-2012,2016 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>
7215516c77SSepherosa Ziehau #include <sys/smp.h>
7315516c77SSepherosa Ziehau #include <sys/socket.h>
7415516c77SSepherosa Ziehau #include <sys/sockio.h>
7515516c77SSepherosa Ziehau #include <sys/sx.h>
7615516c77SSepherosa Ziehau #include <sys/sysctl.h>
7715516c77SSepherosa Ziehau #include <sys/systm.h>
7815516c77SSepherosa Ziehau #include <sys/taskqueue.h>
7915516c77SSepherosa Ziehau #include <sys/buf_ring.h>
805bdfd3fdSDexuan Cui #include <sys/eventhandler.h>
8115516c77SSepherosa Ziehau 
8215516c77SSepherosa Ziehau #include <machine/atomic.h>
8315516c77SSepherosa Ziehau #include <machine/in_cksum.h>
8415516c77SSepherosa Ziehau 
8515516c77SSepherosa Ziehau #include <net/bpf.h>
8615516c77SSepherosa Ziehau #include <net/ethernet.h>
8715516c77SSepherosa Ziehau #include <net/if.h>
885bdfd3fdSDexuan Cui #include <net/if_dl.h>
8915516c77SSepherosa Ziehau #include <net/if_media.h>
9015516c77SSepherosa Ziehau #include <net/if_types.h>
9115516c77SSepherosa Ziehau #include <net/if_var.h>
9215516c77SSepherosa Ziehau #include <net/rndis.h>
9334d68912SSepherosa Ziehau #ifdef RSS
9434d68912SSepherosa Ziehau #include <net/rss_config.h>
9534d68912SSepherosa Ziehau #endif
9615516c77SSepherosa Ziehau 
9715516c77SSepherosa Ziehau #include <netinet/in_systm.h>
9815516c77SSepherosa Ziehau #include <netinet/in.h>
9915516c77SSepherosa Ziehau #include <netinet/ip.h>
10015516c77SSepherosa Ziehau #include <netinet/ip6.h>
10115516c77SSepherosa Ziehau #include <netinet/tcp.h>
10215516c77SSepherosa Ziehau #include <netinet/tcp_lro.h>
10315516c77SSepherosa Ziehau #include <netinet/udp.h>
10415516c77SSepherosa Ziehau 
10515516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h>
10615516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv_busdma.h>
10715516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus.h>
10815516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus_xact.h>
10915516c77SSepherosa Ziehau 
11015516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/ndis.h>
11115516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnreg.h>
11215516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnvar.h>
11315516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_nvs.h>
11415516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_rndis.h>
11515516c77SSepherosa Ziehau 
11615516c77SSepherosa Ziehau #include "vmbus_if.h"
11715516c77SSepherosa Ziehau 
11823bf9e15SSepherosa Ziehau #define HN_IFSTART_SUPPORT
11923bf9e15SSepherosa Ziehau 
12015516c77SSepherosa Ziehau #define HN_RING_CNT_DEF_MAX		8
12115516c77SSepherosa Ziehau 
12215516c77SSepherosa Ziehau /* YYY should get it from the underlying channel */
12315516c77SSepherosa Ziehau #define HN_TX_DESC_CNT			512
12415516c77SSepherosa Ziehau 
12515516c77SSepherosa Ziehau #define HN_RNDIS_PKT_LEN					\
12615516c77SSepherosa Ziehau 	(sizeof(struct rndis_packet_msg) +			\
12715516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) +	\
12815516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) +		\
12915516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) +		\
13015516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_TXCSUM_INFO_SIZE))
13115516c77SSepherosa Ziehau #define HN_RNDIS_PKT_BOUNDARY		PAGE_SIZE
13215516c77SSepherosa Ziehau #define HN_RNDIS_PKT_ALIGN		CACHE_LINE_SIZE
13315516c77SSepherosa Ziehau 
13415516c77SSepherosa Ziehau #define HN_TX_DATA_BOUNDARY		PAGE_SIZE
13515516c77SSepherosa Ziehau #define HN_TX_DATA_MAXSIZE		IP_MAXPACKET
13615516c77SSepherosa Ziehau #define HN_TX_DATA_SEGSIZE		PAGE_SIZE
13715516c77SSepherosa Ziehau /* -1 for RNDIS packet message */
13815516c77SSepherosa Ziehau #define HN_TX_DATA_SEGCNT_MAX		(HN_GPACNT_MAX - 1)
13915516c77SSepherosa Ziehau 
14015516c77SSepherosa Ziehau #define HN_DIRECT_TX_SIZE_DEF		128
14115516c77SSepherosa Ziehau 
14215516c77SSepherosa Ziehau #define HN_EARLY_TXEOF_THRESH		8
14315516c77SSepherosa Ziehau 
14415516c77SSepherosa Ziehau #define HN_PKTBUF_LEN_DEF		(16 * 1024)
14515516c77SSepherosa Ziehau 
14615516c77SSepherosa Ziehau #define HN_LROENT_CNT_DEF		128
14715516c77SSepherosa Ziehau 
14815516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MULTIRX_DEF	(12 * ETHERMTU)
14915516c77SSepherosa Ziehau #define HN_LRO_LENLIM_DEF		(25 * ETHERMTU)
15015516c77SSepherosa Ziehau /* YYY 2*MTU is a bit rough, but should be good enough. */
15115516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MIN(ifp)		(2 * (ifp)->if_mtu)
15215516c77SSepherosa Ziehau 
15315516c77SSepherosa Ziehau #define HN_LRO_ACKCNT_DEF		1
15415516c77SSepherosa Ziehau 
15515516c77SSepherosa Ziehau #define HN_LOCK_INIT(sc)		\
15615516c77SSepherosa Ziehau 	sx_init(&(sc)->hn_lock, device_get_nameunit((sc)->hn_dev))
15715516c77SSepherosa Ziehau #define HN_LOCK_DESTROY(sc)		sx_destroy(&(sc)->hn_lock)
15815516c77SSepherosa Ziehau #define HN_LOCK_ASSERT(sc)		sx_assert(&(sc)->hn_lock, SA_XLOCKED)
159fdc4f478SSepherosa Ziehau #define HN_LOCK(sc)					\
160fdc4f478SSepherosa Ziehau do {							\
161fdc4f478SSepherosa Ziehau 	while (sx_try_xlock(&(sc)->hn_lock) == 0)	\
162fdc4f478SSepherosa Ziehau 		DELAY(1000);				\
163fdc4f478SSepherosa Ziehau } while (0)
16415516c77SSepherosa Ziehau #define HN_UNLOCK(sc)			sx_xunlock(&(sc)->hn_lock)
16515516c77SSepherosa Ziehau 
16615516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK			(CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP)
16715516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK		(CSUM_IP6_TCP | CSUM_IP6_UDP)
16815516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc)		\
16915516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK)
17015516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc)	\
17115516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK)
17215516c77SSepherosa Ziehau 
173dc13fee6SSepherosa Ziehau #define HN_PKTSIZE_MIN(align)		\
174dc13fee6SSepherosa Ziehau 	roundup2(ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN + \
175dc13fee6SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN, (align))
176dc13fee6SSepherosa Ziehau #define HN_PKTSIZE(m, align)		\
177dc13fee6SSepherosa Ziehau 	roundup2((m)->m_pkthdr.len + HN_RNDIS_PKT_LEN, (align))
178dc13fee6SSepherosa Ziehau 
17934d68912SSepherosa Ziehau #ifdef RSS
18034d68912SSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx)	rss_getcpu((idx) % rss_getnumbuckets())
18134d68912SSepherosa Ziehau #else
1820e11868dSSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx)	(((sc)->hn_cpu + (idx)) % mp_ncpus)
18334d68912SSepherosa Ziehau #endif
1840e11868dSSepherosa Ziehau 
18515516c77SSepherosa Ziehau struct hn_txdesc {
18615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
18715516c77SSepherosa Ziehau 	SLIST_ENTRY(hn_txdesc)		link;
18815516c77SSepherosa Ziehau #endif
189dc13fee6SSepherosa Ziehau 	STAILQ_ENTRY(hn_txdesc)		agg_link;
190dc13fee6SSepherosa Ziehau 
191dc13fee6SSepherosa Ziehau 	/* Aggregated txdescs, in sending order. */
192dc13fee6SSepherosa Ziehau 	STAILQ_HEAD(, hn_txdesc)	agg_list;
193dc13fee6SSepherosa Ziehau 
194dc13fee6SSepherosa Ziehau 	/* The oldest packet, if transmission aggregation happens. */
19515516c77SSepherosa Ziehau 	struct mbuf			*m;
19615516c77SSepherosa Ziehau 	struct hn_tx_ring		*txr;
19715516c77SSepherosa Ziehau 	int				refs;
19815516c77SSepherosa Ziehau 	uint32_t			flags;	/* HN_TXD_FLAG_ */
19915516c77SSepherosa Ziehau 	struct hn_nvs_sendctx		send_ctx;
20015516c77SSepherosa Ziehau 	uint32_t			chim_index;
20115516c77SSepherosa Ziehau 	int				chim_size;
20215516c77SSepherosa Ziehau 
20315516c77SSepherosa Ziehau 	bus_dmamap_t			data_dmap;
20415516c77SSepherosa Ziehau 
20515516c77SSepherosa Ziehau 	bus_addr_t			rndis_pkt_paddr;
20615516c77SSepherosa Ziehau 	struct rndis_packet_msg		*rndis_pkt;
20715516c77SSepherosa Ziehau 	bus_dmamap_t			rndis_pkt_dmap;
20815516c77SSepherosa Ziehau };
20915516c77SSepherosa Ziehau 
21015516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST		0x0001
21115516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP		0x0002
212dc13fee6SSepherosa Ziehau #define HN_TXD_FLAG_ONAGG		0x0004
21315516c77SSepherosa Ziehau 
21415516c77SSepherosa Ziehau struct hn_rxinfo {
21515516c77SSepherosa Ziehau 	uint32_t			vlan_info;
21615516c77SSepherosa Ziehau 	uint32_t			csum_info;
21715516c77SSepherosa Ziehau 	uint32_t			hash_info;
21815516c77SSepherosa Ziehau 	uint32_t			hash_value;
21915516c77SSepherosa Ziehau };
22015516c77SSepherosa Ziehau 
2215bdfd3fdSDexuan Cui struct hn_update_vf {
2225bdfd3fdSDexuan Cui 	struct hn_rx_ring	*rxr;
2235bdfd3fdSDexuan Cui 	struct ifnet		*vf;
2245bdfd3fdSDexuan Cui };
2255bdfd3fdSDexuan Cui 
22615516c77SSepherosa Ziehau #define HN_RXINFO_VLAN			0x0001
22715516c77SSepherosa Ziehau #define HN_RXINFO_CSUM			0x0002
22815516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF		0x0004
22915516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL		0x0008
23015516c77SSepherosa Ziehau #define HN_RXINFO_ALL			\
23115516c77SSepherosa Ziehau 	(HN_RXINFO_VLAN |		\
23215516c77SSepherosa Ziehau 	 HN_RXINFO_CSUM |		\
23315516c77SSepherosa Ziehau 	 HN_RXINFO_HASHINF |		\
23415516c77SSepherosa Ziehau 	 HN_RXINFO_HASHVAL)
23515516c77SSepherosa Ziehau 
23615516c77SSepherosa Ziehau #define HN_NDIS_VLAN_INFO_INVALID	0xffffffff
23715516c77SSepherosa Ziehau #define HN_NDIS_RXCSUM_INFO_INVALID	0
23815516c77SSepherosa Ziehau #define HN_NDIS_HASH_INFO_INVALID	0
23915516c77SSepherosa Ziehau 
24015516c77SSepherosa Ziehau static int			hn_probe(device_t);
24115516c77SSepherosa Ziehau static int			hn_attach(device_t);
24215516c77SSepherosa Ziehau static int			hn_detach(device_t);
24315516c77SSepherosa Ziehau static int			hn_shutdown(device_t);
24415516c77SSepherosa Ziehau static void			hn_chan_callback(struct vmbus_channel *,
24515516c77SSepherosa Ziehau 				    void *);
24615516c77SSepherosa Ziehau 
24715516c77SSepherosa Ziehau static void			hn_init(void *);
24815516c77SSepherosa Ziehau static int			hn_ioctl(struct ifnet *, u_long, caddr_t);
24923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
25015516c77SSepherosa Ziehau static void			hn_start(struct ifnet *);
25123bf9e15SSepherosa Ziehau #endif
25215516c77SSepherosa Ziehau static int			hn_transmit(struct ifnet *, struct mbuf *);
25315516c77SSepherosa Ziehau static void			hn_xmit_qflush(struct ifnet *);
25415516c77SSepherosa Ziehau static int			hn_ifmedia_upd(struct ifnet *);
25515516c77SSepherosa Ziehau static void			hn_ifmedia_sts(struct ifnet *,
25615516c77SSepherosa Ziehau 				    struct ifmediareq *);
25715516c77SSepherosa Ziehau 
25815516c77SSepherosa Ziehau static int			hn_rndis_rxinfo(const void *, int,
25915516c77SSepherosa Ziehau 				    struct hn_rxinfo *);
26015516c77SSepherosa Ziehau static void			hn_rndis_rx_data(struct hn_rx_ring *,
26115516c77SSepherosa Ziehau 				    const void *, int);
26215516c77SSepherosa Ziehau static void			hn_rndis_rx_status(struct hn_softc *,
26315516c77SSepherosa Ziehau 				    const void *, int);
264*b3b75d9cSSepherosa Ziehau static void			hn_rndis_init_fixat(struct hn_softc *, int);
26515516c77SSepherosa Ziehau 
26615516c77SSepherosa Ziehau static void			hn_nvs_handle_notify(struct hn_softc *,
26715516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
26815516c77SSepherosa Ziehau static void			hn_nvs_handle_comp(struct hn_softc *,
26915516c77SSepherosa Ziehau 				    struct vmbus_channel *,
27015516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
27115516c77SSepherosa Ziehau static void			hn_nvs_handle_rxbuf(struct hn_rx_ring *,
27215516c77SSepherosa Ziehau 				    struct vmbus_channel *,
27315516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
27415516c77SSepherosa Ziehau static void			hn_nvs_ack_rxbuf(struct hn_rx_ring *,
27515516c77SSepherosa Ziehau 				    struct vmbus_channel *, uint64_t);
27615516c77SSepherosa Ziehau 
27715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
27815516c77SSepherosa Ziehau static int			hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS);
27915516c77SSepherosa Ziehau static int			hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS);
28015516c77SSepherosa Ziehau #endif
28115516c77SSepherosa Ziehau static int			hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS);
28215516c77SSepherosa Ziehau static int			hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS);
28315516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
28415516c77SSepherosa Ziehau static int			hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS);
28515516c77SSepherosa Ziehau #else
28615516c77SSepherosa Ziehau static int			hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS);
28715516c77SSepherosa Ziehau #endif
28815516c77SSepherosa Ziehau static int			hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
28915516c77SSepherosa Ziehau static int			hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
29015516c77SSepherosa Ziehau static int			hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS);
29115516c77SSepherosa Ziehau static int			hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS);
29215516c77SSepherosa Ziehau static int			hn_caps_sysctl(SYSCTL_HANDLER_ARGS);
29315516c77SSepherosa Ziehau static int			hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS);
29415516c77SSepherosa Ziehau static int			hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS);
29534d68912SSepherosa Ziehau #ifndef RSS
29615516c77SSepherosa Ziehau static int			hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS);
29715516c77SSepherosa Ziehau static int			hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS);
29834d68912SSepherosa Ziehau #endif
29915516c77SSepherosa Ziehau static int			hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS);
300dc13fee6SSepherosa Ziehau static int			hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS);
301dc13fee6SSepherosa Ziehau static int			hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS);
302dc13fee6SSepherosa Ziehau static int			hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS);
303dc13fee6SSepherosa Ziehau static int			hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS);
3046c1204dfSSepherosa Ziehau static int			hn_polling_sysctl(SYSCTL_HANDLER_ARGS);
30540d60d6eSDexuan Cui static int			hn_vf_sysctl(SYSCTL_HANDLER_ARGS);
30615516c77SSepherosa Ziehau 
3075bdfd3fdSDexuan Cui static void			hn_stop(struct hn_softc *, bool);
30815516c77SSepherosa Ziehau static void			hn_init_locked(struct hn_softc *);
30915516c77SSepherosa Ziehau static int			hn_chan_attach(struct hn_softc *,
31015516c77SSepherosa Ziehau 				    struct vmbus_channel *);
31115516c77SSepherosa Ziehau static void			hn_chan_detach(struct hn_softc *,
31215516c77SSepherosa Ziehau 				    struct vmbus_channel *);
31315516c77SSepherosa Ziehau static int			hn_attach_subchans(struct hn_softc *);
31415516c77SSepherosa Ziehau static void			hn_detach_allchans(struct hn_softc *);
31515516c77SSepherosa Ziehau static void			hn_chan_rollup(struct hn_rx_ring *,
31615516c77SSepherosa Ziehau 				    struct hn_tx_ring *);
31715516c77SSepherosa Ziehau static void			hn_set_ring_inuse(struct hn_softc *, int);
31815516c77SSepherosa Ziehau static int			hn_synth_attach(struct hn_softc *, int);
31915516c77SSepherosa Ziehau static void			hn_synth_detach(struct hn_softc *);
32015516c77SSepherosa Ziehau static int			hn_synth_alloc_subchans(struct hn_softc *,
32115516c77SSepherosa Ziehau 				    int *);
3222494d735SSepherosa Ziehau static bool			hn_synth_attachable(const struct hn_softc *);
32315516c77SSepherosa Ziehau static void			hn_suspend(struct hn_softc *);
32415516c77SSepherosa Ziehau static void			hn_suspend_data(struct hn_softc *);
32515516c77SSepherosa Ziehau static void			hn_suspend_mgmt(struct hn_softc *);
32615516c77SSepherosa Ziehau static void			hn_resume(struct hn_softc *);
32715516c77SSepherosa Ziehau static void			hn_resume_data(struct hn_softc *);
32815516c77SSepherosa Ziehau static void			hn_resume_mgmt(struct hn_softc *);
32915516c77SSepherosa Ziehau static void			hn_suspend_mgmt_taskfunc(void *, int);
33025641fc7SSepherosa Ziehau static void			hn_chan_drain(struct hn_softc *,
33125641fc7SSepherosa Ziehau 				    struct vmbus_channel *);
332*b3b75d9cSSepherosa Ziehau static void			hn_disable_rx(struct hn_softc *);
333*b3b75d9cSSepherosa Ziehau static void			hn_drain_rxtx(struct hn_softc *, int);
3346c1204dfSSepherosa Ziehau static void			hn_polling(struct hn_softc *, u_int);
3356c1204dfSSepherosa Ziehau static void			hn_chan_polling(struct vmbus_channel *, u_int);
33615516c77SSepherosa Ziehau 
33715516c77SSepherosa Ziehau static void			hn_update_link_status(struct hn_softc *);
33815516c77SSepherosa Ziehau static void			hn_change_network(struct hn_softc *);
33915516c77SSepherosa Ziehau static void			hn_link_taskfunc(void *, int);
34015516c77SSepherosa Ziehau static void			hn_netchg_init_taskfunc(void *, int);
34115516c77SSepherosa Ziehau static void			hn_netchg_status_taskfunc(void *, int);
34215516c77SSepherosa Ziehau static void			hn_link_status(struct hn_softc *);
34315516c77SSepherosa Ziehau 
34415516c77SSepherosa Ziehau static int			hn_create_rx_data(struct hn_softc *, int);
34515516c77SSepherosa Ziehau static void			hn_destroy_rx_data(struct hn_softc *);
34615516c77SSepherosa Ziehau static int			hn_check_iplen(const struct mbuf *, int);
347f1b0a43fSSepherosa Ziehau static int			hn_set_rxfilter(struct hn_softc *, uint32_t);
348c08f7b2cSSepherosa Ziehau static int			hn_rxfilter_config(struct hn_softc *);
34934d68912SSepherosa Ziehau #ifndef RSS
35015516c77SSepherosa Ziehau static int			hn_rss_reconfig(struct hn_softc *);
35134d68912SSepherosa Ziehau #endif
352afd4971bSSepherosa Ziehau static void			hn_rss_ind_fixup(struct hn_softc *);
35315516c77SSepherosa Ziehau static int			hn_rxpkt(struct hn_rx_ring *, const void *,
35415516c77SSepherosa Ziehau 				    int, const struct hn_rxinfo *);
35515516c77SSepherosa Ziehau 
35615516c77SSepherosa Ziehau static int			hn_tx_ring_create(struct hn_softc *, int);
35715516c77SSepherosa Ziehau static void			hn_tx_ring_destroy(struct hn_tx_ring *);
35815516c77SSepherosa Ziehau static int			hn_create_tx_data(struct hn_softc *, int);
35915516c77SSepherosa Ziehau static void			hn_fixup_tx_data(struct hn_softc *);
36015516c77SSepherosa Ziehau static void			hn_destroy_tx_data(struct hn_softc *);
36115516c77SSepherosa Ziehau static void			hn_txdesc_dmamap_destroy(struct hn_txdesc *);
36225641fc7SSepherosa Ziehau static void			hn_txdesc_gc(struct hn_tx_ring *,
36325641fc7SSepherosa Ziehau 				    struct hn_txdesc *);
364dc13fee6SSepherosa Ziehau static int			hn_encap(struct ifnet *, struct hn_tx_ring *,
36515516c77SSepherosa Ziehau 				    struct hn_txdesc *, struct mbuf **);
36615516c77SSepherosa Ziehau static int			hn_txpkt(struct ifnet *, struct hn_tx_ring *,
36715516c77SSepherosa Ziehau 				    struct hn_txdesc *);
36815516c77SSepherosa Ziehau static void			hn_set_chim_size(struct hn_softc *, int);
36915516c77SSepherosa Ziehau static void			hn_set_tso_maxsize(struct hn_softc *, int, int);
37015516c77SSepherosa Ziehau static bool			hn_tx_ring_pending(struct hn_tx_ring *);
37115516c77SSepherosa Ziehau static void			hn_tx_ring_qflush(struct hn_tx_ring *);
37215516c77SSepherosa Ziehau static void			hn_resume_tx(struct hn_softc *, int);
373dc13fee6SSepherosa Ziehau static void			hn_set_txagg(struct hn_softc *);
374dc13fee6SSepherosa Ziehau static void			*hn_try_txagg(struct ifnet *,
375dc13fee6SSepherosa Ziehau 				    struct hn_tx_ring *, struct hn_txdesc *,
376dc13fee6SSepherosa Ziehau 				    int);
37715516c77SSepherosa Ziehau static int			hn_get_txswq_depth(const struct hn_tx_ring *);
37815516c77SSepherosa Ziehau static void			hn_txpkt_done(struct hn_nvs_sendctx *,
37915516c77SSepherosa Ziehau 				    struct hn_softc *, struct vmbus_channel *,
38015516c77SSepherosa Ziehau 				    const void *, int);
38115516c77SSepherosa Ziehau static int			hn_txpkt_sglist(struct hn_tx_ring *,
38215516c77SSepherosa Ziehau 				    struct hn_txdesc *);
38315516c77SSepherosa Ziehau static int			hn_txpkt_chim(struct hn_tx_ring *,
38415516c77SSepherosa Ziehau 				    struct hn_txdesc *);
38515516c77SSepherosa Ziehau static int			hn_xmit(struct hn_tx_ring *, int);
38615516c77SSepherosa Ziehau static void			hn_xmit_taskfunc(void *, int);
38715516c77SSepherosa Ziehau static void			hn_xmit_txeof(struct hn_tx_ring *);
38815516c77SSepherosa Ziehau static void			hn_xmit_txeof_taskfunc(void *, int);
38923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
39015516c77SSepherosa Ziehau static int			hn_start_locked(struct hn_tx_ring *, int);
39115516c77SSepherosa Ziehau static void			hn_start_taskfunc(void *, int);
39215516c77SSepherosa Ziehau static void			hn_start_txeof(struct hn_tx_ring *);
39315516c77SSepherosa Ziehau static void			hn_start_txeof_taskfunc(void *, int);
39423bf9e15SSepherosa Ziehau #endif
39515516c77SSepherosa Ziehau 
39615516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
39715516c77SSepherosa Ziehau     "Hyper-V network interface");
39815516c77SSepherosa Ziehau 
39915516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */
40015516c77SSepherosa Ziehau static int			hn_trust_hosttcp = 1;
40115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN,
40215516c77SSepherosa Ziehau     &hn_trust_hosttcp, 0,
40315516c77SSepherosa Ziehau     "Trust tcp segement verification on host side, "
40415516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
40515516c77SSepherosa Ziehau 
40615516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */
40715516c77SSepherosa Ziehau static int			hn_trust_hostudp = 1;
40815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN,
40915516c77SSepherosa Ziehau     &hn_trust_hostudp, 0,
41015516c77SSepherosa Ziehau     "Trust udp datagram verification on host side, "
41115516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
41215516c77SSepherosa Ziehau 
41315516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */
41415516c77SSepherosa Ziehau static int			hn_trust_hostip = 1;
41515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN,
41615516c77SSepherosa Ziehau     &hn_trust_hostip, 0,
41715516c77SSepherosa Ziehau     "Trust ip packet verification on host side, "
41815516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
41915516c77SSepherosa Ziehau 
42015516c77SSepherosa Ziehau /* Limit TSO burst size */
42115516c77SSepherosa Ziehau static int			hn_tso_maxlen = IP_MAXPACKET;
42215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN,
42315516c77SSepherosa Ziehau     &hn_tso_maxlen, 0, "TSO burst limit");
42415516c77SSepherosa Ziehau 
42515516c77SSepherosa Ziehau /* Limit chimney send size */
42615516c77SSepherosa Ziehau static int			hn_tx_chimney_size = 0;
42715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN,
42815516c77SSepherosa Ziehau     &hn_tx_chimney_size, 0, "Chimney send packet size limit");
42915516c77SSepherosa Ziehau 
43015516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */
43115516c77SSepherosa Ziehau static int			hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF;
43215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN,
43315516c77SSepherosa Ziehau     &hn_direct_tx_size, 0, "Size of the packet for direct transmission");
43415516c77SSepherosa Ziehau 
43515516c77SSepherosa Ziehau /* # of LRO entries per RX ring */
43615516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
43715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
43815516c77SSepherosa Ziehau static int			hn_lro_entry_count = HN_LROENT_CNT_DEF;
43915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN,
44015516c77SSepherosa Ziehau     &hn_lro_entry_count, 0, "LRO entry count");
44115516c77SSepherosa Ziehau #endif
44215516c77SSepherosa Ziehau #endif
44315516c77SSepherosa Ziehau 
444fdd0222aSSepherosa Ziehau static int			hn_tx_taskq_cnt = 1;
445fdd0222aSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_cnt, CTLFLAG_RDTUN,
446fdd0222aSSepherosa Ziehau     &hn_tx_taskq_cnt, 0, "# of TX taskqueues");
447fdd0222aSSepherosa Ziehau 
4480e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_INDEP	0
4490e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_GLOBAL	1
4500e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_EVTTQ	2
4510e11868dSSepherosa Ziehau 
4520e11868dSSepherosa Ziehau static int			hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
4530e11868dSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_mode, CTLFLAG_RDTUN,
4540e11868dSSepherosa Ziehau     &hn_tx_taskq_mode, 0, "TX taskqueue modes: "
4550e11868dSSepherosa Ziehau     "0 - independent, 1 - share global tx taskqs, 2 - share event taskqs");
4560e11868dSSepherosa Ziehau 
45715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
45815516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 0;
45915516c77SSepherosa Ziehau #else
46015516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 1;
46115516c77SSepherosa Ziehau #endif
46215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD,
46315516c77SSepherosa Ziehau     &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors");
46415516c77SSepherosa Ziehau 
46523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
46615516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */
46715516c77SSepherosa Ziehau static int			hn_use_if_start = 0;
46815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN,
46915516c77SSepherosa Ziehau     &hn_use_if_start, 0, "Use if_start TX method");
47023bf9e15SSepherosa Ziehau #endif
47115516c77SSepherosa Ziehau 
47215516c77SSepherosa Ziehau /* # of channels to use */
47315516c77SSepherosa Ziehau static int			hn_chan_cnt = 0;
47415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN,
47515516c77SSepherosa Ziehau     &hn_chan_cnt, 0,
47615516c77SSepherosa Ziehau     "# of channels to use; each channel has one RX ring and one TX ring");
47715516c77SSepherosa Ziehau 
47815516c77SSepherosa Ziehau /* # of transmit rings to use */
47915516c77SSepherosa Ziehau static int			hn_tx_ring_cnt = 0;
48015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN,
48115516c77SSepherosa Ziehau     &hn_tx_ring_cnt, 0, "# of TX rings to use");
48215516c77SSepherosa Ziehau 
48315516c77SSepherosa Ziehau /* Software TX ring deptch */
48415516c77SSepherosa Ziehau static int			hn_tx_swq_depth = 0;
48515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN,
48615516c77SSepherosa Ziehau     &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING");
48715516c77SSepherosa Ziehau 
48815516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */
48915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
49015516c77SSepherosa Ziehau static u_int			hn_lro_mbufq_depth = 0;
49115516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN,
49215516c77SSepherosa Ziehau     &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue");
49315516c77SSepherosa Ziehau #endif
49415516c77SSepherosa Ziehau 
495dc13fee6SSepherosa Ziehau /* Packet transmission aggregation size limit */
496dc13fee6SSepherosa Ziehau static int			hn_tx_agg_size = -1;
497dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN,
498dc13fee6SSepherosa Ziehau     &hn_tx_agg_size, 0, "Packet transmission aggregation size limit");
499dc13fee6SSepherosa Ziehau 
500dc13fee6SSepherosa Ziehau /* Packet transmission aggregation count limit */
501fa915c4dSSepherosa Ziehau static int			hn_tx_agg_pkts = -1;
502dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN,
503dc13fee6SSepherosa Ziehau     &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit");
504dc13fee6SSepherosa Ziehau 
50515516c77SSepherosa Ziehau static u_int			hn_cpu_index;	/* next CPU for channel */
506fdd0222aSSepherosa Ziehau static struct taskqueue		**hn_tx_taskque;/* shared TX taskqueues */
50715516c77SSepherosa Ziehau 
50834d68912SSepherosa Ziehau #ifndef RSS
50915516c77SSepherosa Ziehau static const uint8_t
51015516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
51115516c77SSepherosa Ziehau 	0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
51215516c77SSepherosa Ziehau 	0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
51315516c77SSepherosa Ziehau 	0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
51415516c77SSepherosa Ziehau 	0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
51515516c77SSepherosa Ziehau 	0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
51615516c77SSepherosa Ziehau };
51734d68912SSepherosa Ziehau #endif	/* !RSS */
51815516c77SSepherosa Ziehau 
51915516c77SSepherosa Ziehau static device_method_t hn_methods[] = {
52015516c77SSepherosa Ziehau 	/* Device interface */
52115516c77SSepherosa Ziehau 	DEVMETHOD(device_probe,		hn_probe),
52215516c77SSepherosa Ziehau 	DEVMETHOD(device_attach,	hn_attach),
52315516c77SSepherosa Ziehau 	DEVMETHOD(device_detach,	hn_detach),
52415516c77SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	hn_shutdown),
52515516c77SSepherosa Ziehau 	DEVMETHOD_END
52615516c77SSepherosa Ziehau };
52715516c77SSepherosa Ziehau 
52815516c77SSepherosa Ziehau static driver_t hn_driver = {
52915516c77SSepherosa Ziehau 	"hn",
53015516c77SSepherosa Ziehau 	hn_methods,
53115516c77SSepherosa Ziehau 	sizeof(struct hn_softc)
53215516c77SSepherosa Ziehau };
53315516c77SSepherosa Ziehau 
53415516c77SSepherosa Ziehau static devclass_t hn_devclass;
53515516c77SSepherosa Ziehau 
53615516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0);
53715516c77SSepherosa Ziehau MODULE_VERSION(hn, 1);
53815516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1);
53915516c77SSepherosa Ziehau 
54015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
54115516c77SSepherosa Ziehau static void
54215516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim)
54315516c77SSepherosa Ziehau {
54415516c77SSepherosa Ziehau 	int i;
54515516c77SSepherosa Ziehau 
546a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
54715516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim;
54815516c77SSepherosa Ziehau }
54915516c77SSepherosa Ziehau #endif
55015516c77SSepherosa Ziehau 
55115516c77SSepherosa Ziehau static int
55215516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd)
55315516c77SSepherosa Ziehau {
55415516c77SSepherosa Ziehau 
55515516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
55615516c77SSepherosa Ziehau 	    txd->chim_size == 0, ("invalid rndis sglist txd"));
55715516c77SSepherosa Ziehau 	return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA,
55815516c77SSepherosa Ziehau 	    &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt));
55915516c77SSepherosa Ziehau }
56015516c77SSepherosa Ziehau 
56115516c77SSepherosa Ziehau static int
56215516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd)
56315516c77SSepherosa Ziehau {
56415516c77SSepherosa Ziehau 	struct hn_nvs_rndis rndis;
56515516c77SSepherosa Ziehau 
56615516c77SSepherosa Ziehau 	KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID &&
56715516c77SSepherosa Ziehau 	    txd->chim_size > 0, ("invalid rndis chim txd"));
56815516c77SSepherosa Ziehau 
56915516c77SSepherosa Ziehau 	rndis.nvs_type = HN_NVS_TYPE_RNDIS;
57015516c77SSepherosa Ziehau 	rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA;
57115516c77SSepherosa Ziehau 	rndis.nvs_chim_idx = txd->chim_index;
57215516c77SSepherosa Ziehau 	rndis.nvs_chim_sz = txd->chim_size;
57315516c77SSepherosa Ziehau 
57415516c77SSepherosa Ziehau 	return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC,
57515516c77SSepherosa Ziehau 	    &rndis, sizeof(rndis), &txd->send_ctx));
57615516c77SSepherosa Ziehau }
57715516c77SSepherosa Ziehau 
57815516c77SSepherosa Ziehau static __inline uint32_t
57915516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc)
58015516c77SSepherosa Ziehau {
58115516c77SSepherosa Ziehau 	int i, bmap_cnt = sc->hn_chim_bmap_cnt;
58215516c77SSepherosa Ziehau 	u_long *bmap = sc->hn_chim_bmap;
58315516c77SSepherosa Ziehau 	uint32_t ret = HN_NVS_CHIM_IDX_INVALID;
58415516c77SSepherosa Ziehau 
58515516c77SSepherosa Ziehau 	for (i = 0; i < bmap_cnt; ++i) {
58615516c77SSepherosa Ziehau 		int idx;
58715516c77SSepherosa Ziehau 
58815516c77SSepherosa Ziehau 		idx = ffsl(~bmap[i]);
58915516c77SSepherosa Ziehau 		if (idx == 0)
59015516c77SSepherosa Ziehau 			continue;
59115516c77SSepherosa Ziehau 
59215516c77SSepherosa Ziehau 		--idx; /* ffsl is 1-based */
59315516c77SSepherosa Ziehau 		KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt,
59415516c77SSepherosa Ziehau 		    ("invalid i %d and idx %d", i, idx));
59515516c77SSepherosa Ziehau 
59615516c77SSepherosa Ziehau 		if (atomic_testandset_long(&bmap[i], idx))
59715516c77SSepherosa Ziehau 			continue;
59815516c77SSepherosa Ziehau 
59915516c77SSepherosa Ziehau 		ret = i * LONG_BIT + idx;
60015516c77SSepherosa Ziehau 		break;
60115516c77SSepherosa Ziehau 	}
60215516c77SSepherosa Ziehau 	return (ret);
60315516c77SSepherosa Ziehau }
60415516c77SSepherosa Ziehau 
60515516c77SSepherosa Ziehau static __inline void
60615516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx)
60715516c77SSepherosa Ziehau {
60815516c77SSepherosa Ziehau 	u_long mask;
60915516c77SSepherosa Ziehau 	uint32_t idx;
61015516c77SSepherosa Ziehau 
61115516c77SSepherosa Ziehau 	idx = chim_idx / LONG_BIT;
61215516c77SSepherosa Ziehau 	KASSERT(idx < sc->hn_chim_bmap_cnt,
61315516c77SSepherosa Ziehau 	    ("invalid chimney index 0x%x", chim_idx));
61415516c77SSepherosa Ziehau 
61515516c77SSepherosa Ziehau 	mask = 1UL << (chim_idx % LONG_BIT);
61615516c77SSepherosa Ziehau 	KASSERT(sc->hn_chim_bmap[idx] & mask,
61715516c77SSepherosa Ziehau 	    ("index bitmap 0x%lx, chimney index %u, "
61815516c77SSepherosa Ziehau 	     "bitmap idx %d, bitmask 0x%lx",
61915516c77SSepherosa Ziehau 	     sc->hn_chim_bmap[idx], chim_idx, idx, mask));
62015516c77SSepherosa Ziehau 
62115516c77SSepherosa Ziehau 	atomic_clear_long(&sc->hn_chim_bmap[idx], mask);
62215516c77SSepherosa Ziehau }
62315516c77SSepherosa Ziehau 
624edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
625edd3f315SSepherosa Ziehau /*
626edd3f315SSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
627edd3f315SSepherosa Ziehau  */
628edd3f315SSepherosa Ziehau static __inline struct mbuf *
629edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head)
630edd3f315SSepherosa Ziehau {
631edd3f315SSepherosa Ziehau 	struct ether_vlan_header *evl;
632edd3f315SSepherosa Ziehau 	struct tcphdr *th;
633edd3f315SSepherosa Ziehau 	int ehlen;
634edd3f315SSepherosa Ziehau 
635edd3f315SSepherosa Ziehau 	KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable"));
636edd3f315SSepherosa Ziehau 
637edd3f315SSepherosa Ziehau #define PULLUP_HDR(m, len)				\
638edd3f315SSepherosa Ziehau do {							\
639edd3f315SSepherosa Ziehau 	if (__predict_false((m)->m_len < (len))) {	\
640edd3f315SSepherosa Ziehau 		(m) = m_pullup((m), (len));		\
641edd3f315SSepherosa Ziehau 		if ((m) == NULL)			\
642edd3f315SSepherosa Ziehau 			return (NULL);			\
643edd3f315SSepherosa Ziehau 	}						\
644edd3f315SSepherosa Ziehau } while (0)
645edd3f315SSepherosa Ziehau 
646edd3f315SSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
647edd3f315SSepherosa Ziehau 	evl = mtod(m_head, struct ether_vlan_header *);
648edd3f315SSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
649edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
650edd3f315SSepherosa Ziehau 	else
651edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
652edd3f315SSepherosa Ziehau 
653edd3f315SSepherosa Ziehau #ifdef INET
654edd3f315SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
655edd3f315SSepherosa Ziehau 		struct ip *ip;
656edd3f315SSepherosa Ziehau 		int iphlen;
657edd3f315SSepherosa Ziehau 
658edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
659edd3f315SSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
660edd3f315SSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
661edd3f315SSepherosa Ziehau 
662edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
663edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + iphlen);
664edd3f315SSepherosa Ziehau 
665edd3f315SSepherosa Ziehau 		ip->ip_len = 0;
666edd3f315SSepherosa Ziehau 		ip->ip_sum = 0;
667edd3f315SSepherosa Ziehau 		th->th_sum = in_pseudo(ip->ip_src.s_addr,
668edd3f315SSepherosa Ziehau 		    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
669edd3f315SSepherosa Ziehau 	}
670edd3f315SSepherosa Ziehau #endif
671edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET)
672edd3f315SSepherosa Ziehau 	else
673edd3f315SSepherosa Ziehau #endif
674edd3f315SSepherosa Ziehau #ifdef INET6
675edd3f315SSepherosa Ziehau 	{
676edd3f315SSepherosa Ziehau 		struct ip6_hdr *ip6;
677edd3f315SSepherosa Ziehau 
678edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
679edd3f315SSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
680edd3f315SSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP) {
681edd3f315SSepherosa Ziehau 			m_freem(m_head);
682edd3f315SSepherosa Ziehau 			return (NULL);
683edd3f315SSepherosa Ziehau 		}
684edd3f315SSepherosa Ziehau 
685edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
686edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + sizeof(*ip6));
687edd3f315SSepherosa Ziehau 
688edd3f315SSepherosa Ziehau 		ip6->ip6_plen = 0;
689edd3f315SSepherosa Ziehau 		th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
690edd3f315SSepherosa Ziehau 	}
691edd3f315SSepherosa Ziehau #endif
692edd3f315SSepherosa Ziehau 	return (m_head);
693edd3f315SSepherosa Ziehau 
694edd3f315SSepherosa Ziehau #undef PULLUP_HDR
695edd3f315SSepherosa Ziehau }
696edd3f315SSepherosa Ziehau #endif	/* INET6 || INET */
697edd3f315SSepherosa Ziehau 
69815516c77SSepherosa Ziehau static int
699f1b0a43fSSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc, uint32_t filter)
700f1b0a43fSSepherosa Ziehau {
701f1b0a43fSSepherosa Ziehau 	int error = 0;
702f1b0a43fSSepherosa Ziehau 
703f1b0a43fSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
704f1b0a43fSSepherosa Ziehau 
705f1b0a43fSSepherosa Ziehau 	if (sc->hn_rx_filter != filter) {
706f1b0a43fSSepherosa Ziehau 		error = hn_rndis_set_rxfilter(sc, filter);
707f1b0a43fSSepherosa Ziehau 		if (!error)
708f1b0a43fSSepherosa Ziehau 			sc->hn_rx_filter = filter;
709f1b0a43fSSepherosa Ziehau 	}
710f1b0a43fSSepherosa Ziehau 	return (error);
711f1b0a43fSSepherosa Ziehau }
712f1b0a43fSSepherosa Ziehau 
713f1b0a43fSSepherosa Ziehau static int
714c08f7b2cSSepherosa Ziehau hn_rxfilter_config(struct hn_softc *sc)
71515516c77SSepherosa Ziehau {
71615516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
71715516c77SSepherosa Ziehau 	uint32_t filter;
71815516c77SSepherosa Ziehau 
71915516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
72015516c77SSepherosa Ziehau 
7215bdfd3fdSDexuan Cui 	if ((ifp->if_flags & IFF_PROMISC) ||
7225bdfd3fdSDexuan Cui 	    (sc->hn_flags & HN_FLAG_VF)) {
72315516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_PROMISCUOUS;
72415516c77SSepherosa Ziehau 	} else {
72515516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_DIRECTED;
72615516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_BROADCAST)
72715516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_BROADCAST;
72815516c77SSepherosa Ziehau 		/* TODO: support multicast list */
72915516c77SSepherosa Ziehau 		if ((ifp->if_flags & IFF_ALLMULTI) ||
73015516c77SSepherosa Ziehau 		    !TAILQ_EMPTY(&ifp->if_multiaddrs))
73115516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
73215516c77SSepherosa Ziehau 	}
733f1b0a43fSSepherosa Ziehau 	return (hn_set_rxfilter(sc, filter));
73415516c77SSepherosa Ziehau }
73515516c77SSepherosa Ziehau 
736dc13fee6SSepherosa Ziehau static void
737dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc)
738dc13fee6SSepherosa Ziehau {
739dc13fee6SSepherosa Ziehau 	uint32_t size, pkts;
740dc13fee6SSepherosa Ziehau 	int i;
741dc13fee6SSepherosa Ziehau 
742dc13fee6SSepherosa Ziehau 	/*
743dc13fee6SSepherosa Ziehau 	 * Setup aggregation size.
744dc13fee6SSepherosa Ziehau 	 */
745dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_size < 0)
746dc13fee6SSepherosa Ziehau 		size = UINT32_MAX;
747dc13fee6SSepherosa Ziehau 	else
748dc13fee6SSepherosa Ziehau 		size = sc->hn_agg_size;
749dc13fee6SSepherosa Ziehau 
750dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_size < size)
751dc13fee6SSepherosa Ziehau 		size = sc->hn_rndis_agg_size;
752dc13fee6SSepherosa Ziehau 
753a4364cfeSSepherosa Ziehau 	/* NOTE: We only aggregate packets using chimney sending buffers. */
754a4364cfeSSepherosa Ziehau 	if (size > (uint32_t)sc->hn_chim_szmax)
755a4364cfeSSepherosa Ziehau 		size = sc->hn_chim_szmax;
756a4364cfeSSepherosa Ziehau 
757dc13fee6SSepherosa Ziehau 	if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) {
758dc13fee6SSepherosa Ziehau 		/* Disable */
759dc13fee6SSepherosa Ziehau 		size = 0;
760dc13fee6SSepherosa Ziehau 		pkts = 0;
761dc13fee6SSepherosa Ziehau 		goto done;
762dc13fee6SSepherosa Ziehau 	}
763dc13fee6SSepherosa Ziehau 
764dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'int'. */
765dc13fee6SSepherosa Ziehau 	if (size > INT_MAX)
766dc13fee6SSepherosa Ziehau 		size = INT_MAX;
767dc13fee6SSepherosa Ziehau 
768dc13fee6SSepherosa Ziehau 	/*
769dc13fee6SSepherosa Ziehau 	 * Setup aggregation packet count.
770dc13fee6SSepherosa Ziehau 	 */
771dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_pkts < 0)
772dc13fee6SSepherosa Ziehau 		pkts = UINT32_MAX;
773dc13fee6SSepherosa Ziehau 	else
774dc13fee6SSepherosa Ziehau 		pkts = sc->hn_agg_pkts;
775dc13fee6SSepherosa Ziehau 
776dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_pkts < pkts)
777dc13fee6SSepherosa Ziehau 		pkts = sc->hn_rndis_agg_pkts;
778dc13fee6SSepherosa Ziehau 
779dc13fee6SSepherosa Ziehau 	if (pkts <= 1) {
780dc13fee6SSepherosa Ziehau 		/* Disable */
781dc13fee6SSepherosa Ziehau 		size = 0;
782dc13fee6SSepherosa Ziehau 		pkts = 0;
783dc13fee6SSepherosa Ziehau 		goto done;
784dc13fee6SSepherosa Ziehau 	}
785dc13fee6SSepherosa Ziehau 
786dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
787dc13fee6SSepherosa Ziehau 	if (pkts > SHRT_MAX)
788dc13fee6SSepherosa Ziehau 		pkts = SHRT_MAX;
789dc13fee6SSepherosa Ziehau 
790dc13fee6SSepherosa Ziehau done:
791dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
792dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_align > SHRT_MAX) {
793dc13fee6SSepherosa Ziehau 		/* Disable */
794dc13fee6SSepherosa Ziehau 		size = 0;
795dc13fee6SSepherosa Ziehau 		pkts = 0;
796dc13fee6SSepherosa Ziehau 	}
797dc13fee6SSepherosa Ziehau 
798dc13fee6SSepherosa Ziehau 	if (bootverbose) {
799dc13fee6SSepherosa Ziehau 		if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n",
800dc13fee6SSepherosa Ziehau 		    size, pkts, sc->hn_rndis_agg_align);
801dc13fee6SSepherosa Ziehau 	}
802dc13fee6SSepherosa Ziehau 
803dc13fee6SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
804dc13fee6SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
805dc13fee6SSepherosa Ziehau 
806dc13fee6SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
807dc13fee6SSepherosa Ziehau 		txr->hn_agg_szmax = size;
808dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktmax = pkts;
809dc13fee6SSepherosa Ziehau 		txr->hn_agg_align = sc->hn_rndis_agg_align;
810dc13fee6SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
811dc13fee6SSepherosa Ziehau 	}
812dc13fee6SSepherosa Ziehau }
813dc13fee6SSepherosa Ziehau 
81415516c77SSepherosa Ziehau static int
81515516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr)
81615516c77SSepherosa Ziehau {
81715516c77SSepherosa Ziehau 
81815516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet"));
81915516c77SSepherosa Ziehau 	if (hn_tx_swq_depth < txr->hn_txdesc_cnt)
82015516c77SSepherosa Ziehau 		return txr->hn_txdesc_cnt;
82115516c77SSepherosa Ziehau 	return hn_tx_swq_depth;
82215516c77SSepherosa Ziehau }
82315516c77SSepherosa Ziehau 
82434d68912SSepherosa Ziehau #ifndef RSS
82515516c77SSepherosa Ziehau static int
82615516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc)
82715516c77SSepherosa Ziehau {
82815516c77SSepherosa Ziehau 	int error;
82915516c77SSepherosa Ziehau 
83015516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
83115516c77SSepherosa Ziehau 
83215516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
83315516c77SSepherosa Ziehau 		return (ENXIO);
83415516c77SSepherosa Ziehau 
83515516c77SSepherosa Ziehau 	/*
83615516c77SSepherosa Ziehau 	 * Disable RSS first.
83715516c77SSepherosa Ziehau 	 *
83815516c77SSepherosa Ziehau 	 * NOTE:
83915516c77SSepherosa Ziehau 	 * Direct reconfiguration by setting the UNCHG flags does
84015516c77SSepherosa Ziehau 	 * _not_ work properly.
84115516c77SSepherosa Ziehau 	 */
84215516c77SSepherosa Ziehau 	if (bootverbose)
84315516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "disable RSS\n");
84415516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE);
84515516c77SSepherosa Ziehau 	if (error) {
84615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS disable failed\n");
84715516c77SSepherosa Ziehau 		return (error);
84815516c77SSepherosa Ziehau 	}
84915516c77SSepherosa Ziehau 
85015516c77SSepherosa Ziehau 	/*
85115516c77SSepherosa Ziehau 	 * Reenable the RSS w/ the updated RSS key or indirect
85215516c77SSepherosa Ziehau 	 * table.
85315516c77SSepherosa Ziehau 	 */
85415516c77SSepherosa Ziehau 	if (bootverbose)
85515516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "reconfig RSS\n");
85615516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
85715516c77SSepherosa Ziehau 	if (error) {
85815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS reconfig failed\n");
85915516c77SSepherosa Ziehau 		return (error);
86015516c77SSepherosa Ziehau 	}
86115516c77SSepherosa Ziehau 	return (0);
86215516c77SSepherosa Ziehau }
86334d68912SSepherosa Ziehau #endif	/* !RSS */
86415516c77SSepherosa Ziehau 
86515516c77SSepherosa Ziehau static void
866afd4971bSSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc)
86715516c77SSepherosa Ziehau {
86815516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
869afd4971bSSepherosa Ziehau 	int i, nchan;
87015516c77SSepherosa Ziehau 
871afd4971bSSepherosa Ziehau 	nchan = sc->hn_rx_ring_inuse;
87215516c77SSepherosa Ziehau 	KASSERT(nchan > 1, ("invalid # of channels %d", nchan));
87315516c77SSepherosa Ziehau 
87415516c77SSepherosa Ziehau 	/*
87515516c77SSepherosa Ziehau 	 * Check indirect table to make sure that all channels in it
87615516c77SSepherosa Ziehau 	 * can be used.
87715516c77SSepherosa Ziehau 	 */
87815516c77SSepherosa Ziehau 	for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
87915516c77SSepherosa Ziehau 		if (rss->rss_ind[i] >= nchan) {
88015516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp,
88115516c77SSepherosa Ziehau 			    "RSS indirect table %d fixup: %u -> %d\n",
88215516c77SSepherosa Ziehau 			    i, rss->rss_ind[i], nchan - 1);
88315516c77SSepherosa Ziehau 			rss->rss_ind[i] = nchan - 1;
88415516c77SSepherosa Ziehau 		}
88515516c77SSepherosa Ziehau 	}
88615516c77SSepherosa Ziehau }
88715516c77SSepherosa Ziehau 
88815516c77SSepherosa Ziehau static int
88915516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused)
89015516c77SSepherosa Ziehau {
89115516c77SSepherosa Ziehau 
89215516c77SSepherosa Ziehau 	return EOPNOTSUPP;
89315516c77SSepherosa Ziehau }
89415516c77SSepherosa Ziehau 
89515516c77SSepherosa Ziehau static void
89615516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
89715516c77SSepherosa Ziehau {
89815516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
89915516c77SSepherosa Ziehau 
90015516c77SSepherosa Ziehau 	ifmr->ifm_status = IFM_AVALID;
90115516c77SSepherosa Ziehau 	ifmr->ifm_active = IFM_ETHER;
90215516c77SSepherosa Ziehau 
90315516c77SSepherosa Ziehau 	if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) {
90415516c77SSepherosa Ziehau 		ifmr->ifm_active |= IFM_NONE;
90515516c77SSepherosa Ziehau 		return;
90615516c77SSepherosa Ziehau 	}
90715516c77SSepherosa Ziehau 	ifmr->ifm_status |= IFM_ACTIVE;
90815516c77SSepherosa Ziehau 	ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
90915516c77SSepherosa Ziehau }
91015516c77SSepherosa Ziehau 
9115bdfd3fdSDexuan Cui static void
9125bdfd3fdSDexuan Cui hn_update_vf_task(void *arg, int pending __unused)
9135bdfd3fdSDexuan Cui {
9145bdfd3fdSDexuan Cui 	struct hn_update_vf *uv = arg;
9155bdfd3fdSDexuan Cui 
9165bdfd3fdSDexuan Cui 	uv->rxr->hn_vf = uv->vf;
9175bdfd3fdSDexuan Cui }
9185bdfd3fdSDexuan Cui 
9195bdfd3fdSDexuan Cui static void
9205bdfd3fdSDexuan Cui hn_update_vf(struct hn_softc *sc, struct ifnet *vf)
9215bdfd3fdSDexuan Cui {
9225bdfd3fdSDexuan Cui 	struct hn_rx_ring *rxr;
9235bdfd3fdSDexuan Cui 	struct hn_update_vf uv;
9245bdfd3fdSDexuan Cui 	struct task task;
9255bdfd3fdSDexuan Cui 	int i;
9265bdfd3fdSDexuan Cui 
9275bdfd3fdSDexuan Cui 	HN_LOCK_ASSERT(sc);
9285bdfd3fdSDexuan Cui 
9295bdfd3fdSDexuan Cui 	TASK_INIT(&task, 0, hn_update_vf_task, &uv);
9305bdfd3fdSDexuan Cui 
9315bdfd3fdSDexuan Cui 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
9325bdfd3fdSDexuan Cui 		rxr = &sc->hn_rx_ring[i];
9335bdfd3fdSDexuan Cui 
9345bdfd3fdSDexuan Cui 		if (i < sc->hn_rx_ring_inuse) {
9355bdfd3fdSDexuan Cui 			uv.rxr = rxr;
9365bdfd3fdSDexuan Cui 			uv.vf = vf;
9375bdfd3fdSDexuan Cui 			vmbus_chan_run_task(rxr->hn_chan, &task);
9385bdfd3fdSDexuan Cui 		} else {
9395bdfd3fdSDexuan Cui 			rxr->hn_vf = vf;
9405bdfd3fdSDexuan Cui 		}
9415bdfd3fdSDexuan Cui 	}
9425bdfd3fdSDexuan Cui }
9435bdfd3fdSDexuan Cui 
9445bdfd3fdSDexuan Cui static void
9455bdfd3fdSDexuan Cui hn_set_vf(struct hn_softc *sc, struct ifnet *ifp, bool vf)
9465bdfd3fdSDexuan Cui {
9475bdfd3fdSDexuan Cui 	struct ifnet *hn_ifp;
9485bdfd3fdSDexuan Cui 
9495bdfd3fdSDexuan Cui 	HN_LOCK(sc);
9505bdfd3fdSDexuan Cui 
9515bdfd3fdSDexuan Cui 	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
9525bdfd3fdSDexuan Cui 		goto out;
9535bdfd3fdSDexuan Cui 
9545bdfd3fdSDexuan Cui 	hn_ifp = sc->hn_ifp;
9555bdfd3fdSDexuan Cui 
9565bdfd3fdSDexuan Cui 	if (ifp == hn_ifp)
9575bdfd3fdSDexuan Cui 		goto out;
9585bdfd3fdSDexuan Cui 
9595bdfd3fdSDexuan Cui 	if (ifp->if_alloctype != IFT_ETHER)
9605bdfd3fdSDexuan Cui 		goto out;
9615bdfd3fdSDexuan Cui 
9625bdfd3fdSDexuan Cui 	/* Ignore lagg/vlan interfaces */
9635bdfd3fdSDexuan Cui 	if (strcmp(ifp->if_dname, "lagg") == 0 ||
9645bdfd3fdSDexuan Cui 	    strcmp(ifp->if_dname, "vlan") == 0)
9655bdfd3fdSDexuan Cui 		goto out;
9665bdfd3fdSDexuan Cui 
9675bdfd3fdSDexuan Cui 	if (bcmp(IF_LLADDR(ifp), IF_LLADDR(hn_ifp), ETHER_ADDR_LEN) != 0)
9685bdfd3fdSDexuan Cui 		goto out;
9695bdfd3fdSDexuan Cui 
9705bdfd3fdSDexuan Cui 	/* Now we're sure 'ifp' is a real VF device. */
9715bdfd3fdSDexuan Cui 	if (vf) {
9725bdfd3fdSDexuan Cui 		if (sc->hn_flags & HN_FLAG_VF)
9735bdfd3fdSDexuan Cui 			goto out;
9745bdfd3fdSDexuan Cui 
9755bdfd3fdSDexuan Cui 		sc->hn_flags |= HN_FLAG_VF;
9765bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
9775bdfd3fdSDexuan Cui 	} else {
9785bdfd3fdSDexuan Cui 		if (!(sc->hn_flags & HN_FLAG_VF))
9795bdfd3fdSDexuan Cui 			goto out;
9805bdfd3fdSDexuan Cui 
9815bdfd3fdSDexuan Cui 		sc->hn_flags &= ~HN_FLAG_VF;
9825bdfd3fdSDexuan Cui 		if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
9835bdfd3fdSDexuan Cui 			hn_rxfilter_config(sc);
9845bdfd3fdSDexuan Cui 		else
9855bdfd3fdSDexuan Cui 			hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE);
9865bdfd3fdSDexuan Cui 	}
9875bdfd3fdSDexuan Cui 
9885bdfd3fdSDexuan Cui 	hn_nvs_set_datapath(sc,
9895bdfd3fdSDexuan Cui 	    vf ? HN_NVS_DATAPATH_VF : HN_NVS_DATAPATH_SYNTHETIC);
9905bdfd3fdSDexuan Cui 
9915bdfd3fdSDexuan Cui 	hn_update_vf(sc, vf ? ifp : NULL);
9925bdfd3fdSDexuan Cui 
9935bdfd3fdSDexuan Cui 	if (vf) {
9945bdfd3fdSDexuan Cui 		hn_suspend_mgmt(sc);
9955bdfd3fdSDexuan Cui 		sc->hn_link_flags &=
9965bdfd3fdSDexuan Cui 		    ~(HN_LINK_FLAG_LINKUP | HN_LINK_FLAG_NETCHG);
9975bdfd3fdSDexuan Cui 		if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
9985bdfd3fdSDexuan Cui 	} else {
9995bdfd3fdSDexuan Cui 		hn_resume_mgmt(sc);
10005bdfd3fdSDexuan Cui 	}
10015bdfd3fdSDexuan Cui 
100233408a34SDexuan Cui 	devctl_notify("HYPERV_NIC_VF", if_name(hn_ifp),
100333408a34SDexuan Cui 	    vf ? "VF_UP" : "VF_DOWN", NULL);
100433408a34SDexuan Cui 
10055bdfd3fdSDexuan Cui 	if (bootverbose)
10065bdfd3fdSDexuan Cui 		if_printf(hn_ifp, "Data path is switched %s %s\n",
10075bdfd3fdSDexuan Cui 		    vf ? "to" : "from", if_name(ifp));
10085bdfd3fdSDexuan Cui out:
10095bdfd3fdSDexuan Cui 	HN_UNLOCK(sc);
10105bdfd3fdSDexuan Cui }
10115bdfd3fdSDexuan Cui 
10125bdfd3fdSDexuan Cui static void
10135bdfd3fdSDexuan Cui hn_ifnet_event(void *arg, struct ifnet *ifp, int event)
10145bdfd3fdSDexuan Cui {
10155bdfd3fdSDexuan Cui 	if (event != IFNET_EVENT_UP && event != IFNET_EVENT_DOWN)
10165bdfd3fdSDexuan Cui 		return;
10175bdfd3fdSDexuan Cui 
10185bdfd3fdSDexuan Cui 	hn_set_vf(arg, ifp, event == IFNET_EVENT_UP);
10195bdfd3fdSDexuan Cui }
10205bdfd3fdSDexuan Cui 
10215bdfd3fdSDexuan Cui static void
10225bdfd3fdSDexuan Cui hn_ifaddr_event(void *arg, struct ifnet *ifp)
10235bdfd3fdSDexuan Cui {
10245bdfd3fdSDexuan Cui 	hn_set_vf(arg, ifp, ifp->if_flags & IFF_UP);
10255bdfd3fdSDexuan Cui }
10265bdfd3fdSDexuan Cui 
102715516c77SSepherosa Ziehau /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
102815516c77SSepherosa Ziehau static const struct hyperv_guid g_net_vsc_device_type = {
102915516c77SSepherosa Ziehau 	.hv_guid = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
103015516c77SSepherosa Ziehau 		0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E}
103115516c77SSepherosa Ziehau };
103215516c77SSepherosa Ziehau 
103315516c77SSepherosa Ziehau static int
103415516c77SSepherosa Ziehau hn_probe(device_t dev)
103515516c77SSepherosa Ziehau {
103615516c77SSepherosa Ziehau 
103715516c77SSepherosa Ziehau 	if (VMBUS_PROBE_GUID(device_get_parent(dev), dev,
103815516c77SSepherosa Ziehau 	    &g_net_vsc_device_type) == 0) {
103915516c77SSepherosa Ziehau 		device_set_desc(dev, "Hyper-V Network Interface");
104015516c77SSepherosa Ziehau 		return BUS_PROBE_DEFAULT;
104115516c77SSepherosa Ziehau 	}
104215516c77SSepherosa Ziehau 	return ENXIO;
104315516c77SSepherosa Ziehau }
104415516c77SSepherosa Ziehau 
104515516c77SSepherosa Ziehau static int
104615516c77SSepherosa Ziehau hn_attach(device_t dev)
104715516c77SSepherosa Ziehau {
104815516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
104915516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
105015516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
105115516c77SSepherosa Ziehau 	uint8_t eaddr[ETHER_ADDR_LEN];
105215516c77SSepherosa Ziehau 	struct ifnet *ifp = NULL;
105315516c77SSepherosa Ziehau 	int error, ring_cnt, tx_ring_cnt;
105415516c77SSepherosa Ziehau 
105515516c77SSepherosa Ziehau 	sc->hn_dev = dev;
105615516c77SSepherosa Ziehau 	sc->hn_prichan = vmbus_get_channel(dev);
105715516c77SSepherosa Ziehau 	HN_LOCK_INIT(sc);
105815516c77SSepherosa Ziehau 
105915516c77SSepherosa Ziehau 	/*
1060dc13fee6SSepherosa Ziehau 	 * Initialize these tunables once.
1061dc13fee6SSepherosa Ziehau 	 */
1062dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = hn_tx_agg_size;
1063dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = hn_tx_agg_pkts;
1064dc13fee6SSepherosa Ziehau 
1065dc13fee6SSepherosa Ziehau 	/*
106615516c77SSepherosa Ziehau 	 * Setup taskqueue for transmission.
106715516c77SSepherosa Ziehau 	 */
10680e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_INDEP) {
1069fdd0222aSSepherosa Ziehau 		int i;
1070fdd0222aSSepherosa Ziehau 
1071fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs =
1072fdd0222aSSepherosa Ziehau 		    malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
1073fdd0222aSSepherosa Ziehau 		    M_DEVBUF, M_WAITOK);
1074fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i) {
1075fdd0222aSSepherosa Ziehau 			sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx",
1076fdd0222aSSepherosa Ziehau 			    M_WAITOK, taskqueue_thread_enqueue,
1077fdd0222aSSepherosa Ziehau 			    &sc->hn_tx_taskqs[i]);
1078fdd0222aSSepherosa Ziehau 			taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET,
1079fdd0222aSSepherosa Ziehau 			    "%s tx%d", device_get_nameunit(dev), i);
1080fdd0222aSSepherosa Ziehau 		}
10810e11868dSSepherosa Ziehau 	} else if (hn_tx_taskq_mode == HN_TX_TASKQ_M_GLOBAL) {
1082fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs = hn_tx_taskque;
108315516c77SSepherosa Ziehau 	}
108415516c77SSepherosa Ziehau 
108515516c77SSepherosa Ziehau 	/*
108615516c77SSepherosa Ziehau 	 * Setup taskqueue for mangement tasks, e.g. link status.
108715516c77SSepherosa Ziehau 	 */
108815516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK,
108915516c77SSepherosa Ziehau 	    taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0);
109015516c77SSepherosa Ziehau 	taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
109115516c77SSepherosa Ziehau 	    device_get_nameunit(dev));
109215516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
109315516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc);
109415516c77SSepherosa Ziehau 	TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0,
109515516c77SSepherosa Ziehau 	    hn_netchg_status_taskfunc, sc);
109615516c77SSepherosa Ziehau 
109715516c77SSepherosa Ziehau 	/*
109815516c77SSepherosa Ziehau 	 * Allocate ifnet and setup its name earlier, so that if_printf
109915516c77SSepherosa Ziehau 	 * can be used by functions, which will be called after
110015516c77SSepherosa Ziehau 	 * ether_ifattach().
110115516c77SSepherosa Ziehau 	 */
110215516c77SSepherosa Ziehau 	ifp = sc->hn_ifp = if_alloc(IFT_ETHER);
110315516c77SSepherosa Ziehau 	ifp->if_softc = sc;
110415516c77SSepherosa Ziehau 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
110515516c77SSepherosa Ziehau 
110615516c77SSepherosa Ziehau 	/*
110715516c77SSepherosa Ziehau 	 * Initialize ifmedia earlier so that it can be unconditionally
110815516c77SSepherosa Ziehau 	 * destroyed, if error happened later on.
110915516c77SSepherosa Ziehau 	 */
111015516c77SSepherosa Ziehau 	ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts);
111115516c77SSepherosa Ziehau 
111215516c77SSepherosa Ziehau 	/*
111315516c77SSepherosa Ziehau 	 * Figure out the # of RX rings (ring_cnt) and the # of TX rings
111415516c77SSepherosa Ziehau 	 * to use (tx_ring_cnt).
111515516c77SSepherosa Ziehau 	 *
111615516c77SSepherosa Ziehau 	 * NOTE:
111715516c77SSepherosa Ziehau 	 * The # of RX rings to use is same as the # of channels to use.
111815516c77SSepherosa Ziehau 	 */
111915516c77SSepherosa Ziehau 	ring_cnt = hn_chan_cnt;
112015516c77SSepherosa Ziehau 	if (ring_cnt <= 0) {
112115516c77SSepherosa Ziehau 		/* Default */
112215516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
112315516c77SSepherosa Ziehau 		if (ring_cnt > HN_RING_CNT_DEF_MAX)
112415516c77SSepherosa Ziehau 			ring_cnt = HN_RING_CNT_DEF_MAX;
112515516c77SSepherosa Ziehau 	} else if (ring_cnt > mp_ncpus) {
112615516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
112715516c77SSepherosa Ziehau 	}
112834d68912SSepherosa Ziehau #ifdef RSS
112934d68912SSepherosa Ziehau 	if (ring_cnt > rss_getnumbuckets())
113034d68912SSepherosa Ziehau 		ring_cnt = rss_getnumbuckets();
113134d68912SSepherosa Ziehau #endif
113215516c77SSepherosa Ziehau 
113315516c77SSepherosa Ziehau 	tx_ring_cnt = hn_tx_ring_cnt;
113415516c77SSepherosa Ziehau 	if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt)
113515516c77SSepherosa Ziehau 		tx_ring_cnt = ring_cnt;
113623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
113715516c77SSepherosa Ziehau 	if (hn_use_if_start) {
113815516c77SSepherosa Ziehau 		/* ifnet.if_start only needs one TX ring. */
113915516c77SSepherosa Ziehau 		tx_ring_cnt = 1;
114015516c77SSepherosa Ziehau 	}
114123bf9e15SSepherosa Ziehau #endif
114215516c77SSepherosa Ziehau 
114315516c77SSepherosa Ziehau 	/*
114415516c77SSepherosa Ziehau 	 * Set the leader CPU for channels.
114515516c77SSepherosa Ziehau 	 */
114615516c77SSepherosa Ziehau 	sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus;
114715516c77SSepherosa Ziehau 
114815516c77SSepherosa Ziehau 	/*
114915516c77SSepherosa Ziehau 	 * Create enough TX/RX rings, even if only limited number of
115015516c77SSepherosa Ziehau 	 * channels can be allocated.
115115516c77SSepherosa Ziehau 	 */
115215516c77SSepherosa Ziehau 	error = hn_create_tx_data(sc, tx_ring_cnt);
115315516c77SSepherosa Ziehau 	if (error)
115415516c77SSepherosa Ziehau 		goto failed;
115515516c77SSepherosa Ziehau 	error = hn_create_rx_data(sc, ring_cnt);
115615516c77SSepherosa Ziehau 	if (error)
115715516c77SSepherosa Ziehau 		goto failed;
115815516c77SSepherosa Ziehau 
115915516c77SSepherosa Ziehau 	/*
116015516c77SSepherosa Ziehau 	 * Create transaction context for NVS and RNDIS transactions.
116115516c77SSepherosa Ziehau 	 */
116215516c77SSepherosa Ziehau 	sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
116315516c77SSepherosa Ziehau 	    HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
116425641fc7SSepherosa Ziehau 	if (sc->hn_xact == NULL) {
116525641fc7SSepherosa Ziehau 		error = ENXIO;
116615516c77SSepherosa Ziehau 		goto failed;
116725641fc7SSepherosa Ziehau 	}
116825641fc7SSepherosa Ziehau 
116925641fc7SSepherosa Ziehau 	/*
117025641fc7SSepherosa Ziehau 	 * Install orphan handler for the revocation of this device's
117125641fc7SSepherosa Ziehau 	 * primary channel.
117225641fc7SSepherosa Ziehau 	 *
117325641fc7SSepherosa Ziehau 	 * NOTE:
117425641fc7SSepherosa Ziehau 	 * The processing order is critical here:
117525641fc7SSepherosa Ziehau 	 * Install the orphan handler, _before_ testing whether this
117625641fc7SSepherosa Ziehau 	 * device's primary channel has been revoked or not.
117725641fc7SSepherosa Ziehau 	 */
117825641fc7SSepherosa Ziehau 	vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact);
117925641fc7SSepherosa Ziehau 	if (vmbus_chan_is_revoked(sc->hn_prichan)) {
118025641fc7SSepherosa Ziehau 		error = ENXIO;
118125641fc7SSepherosa Ziehau 		goto failed;
118225641fc7SSepherosa Ziehau 	}
118315516c77SSepherosa Ziehau 
118415516c77SSepherosa Ziehau 	/*
118515516c77SSepherosa Ziehau 	 * Attach the synthetic parts, i.e. NVS and RNDIS.
118615516c77SSepherosa Ziehau 	 */
118715516c77SSepherosa Ziehau 	error = hn_synth_attach(sc, ETHERMTU);
118815516c77SSepherosa Ziehau 	if (error)
118915516c77SSepherosa Ziehau 		goto failed;
119015516c77SSepherosa Ziehau 
119115516c77SSepherosa Ziehau 	error = hn_rndis_get_eaddr(sc, eaddr);
119215516c77SSepherosa Ziehau 	if (error)
119315516c77SSepherosa Ziehau 		goto failed;
119415516c77SSepherosa Ziehau 
119515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
119615516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
119715516c77SSepherosa Ziehau 		/*
119815516c77SSepherosa Ziehau 		 * Reduce TCP segment aggregation limit for multiple
119915516c77SSepherosa Ziehau 		 * RX rings to increase ACK timeliness.
120015516c77SSepherosa Ziehau 		 */
120115516c77SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF);
120215516c77SSepherosa Ziehau 	}
120315516c77SSepherosa Ziehau #endif
120415516c77SSepherosa Ziehau 
120515516c77SSepherosa Ziehau 	/*
120615516c77SSepherosa Ziehau 	 * Fixup TX stuffs after synthetic parts are attached.
120715516c77SSepherosa Ziehau 	 */
120815516c77SSepherosa Ziehau 	hn_fixup_tx_data(sc);
120915516c77SSepherosa Ziehau 
121015516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
121115516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
121215516c77SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD,
121315516c77SSepherosa Ziehau 	    &sc->hn_nvs_ver, 0, "NVS version");
121415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version",
121515516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
121615516c77SSepherosa Ziehau 	    hn_ndis_version_sysctl, "A", "NDIS version");
121715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps",
121815516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
121915516c77SSepherosa Ziehau 	    hn_caps_sysctl, "A", "capabilities");
122015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist",
122115516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
122215516c77SSepherosa Ziehau 	    hn_hwassist_sysctl, "A", "hwassist");
122315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter",
122415516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
122515516c77SSepherosa Ziehau 	    hn_rxfilter_sysctl, "A", "rxfilter");
122615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash",
122715516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
122815516c77SSepherosa Ziehau 	    hn_rss_hash_sysctl, "A", "RSS hash");
122915516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size",
123015516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count");
123134d68912SSepherosa Ziehau #ifndef RSS
123234d68912SSepherosa Ziehau 	/*
123334d68912SSepherosa Ziehau 	 * Don't allow RSS key/indirect table changes, if RSS is defined.
123434d68912SSepherosa Ziehau 	 */
123515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key",
123615516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
123715516c77SSepherosa Ziehau 	    hn_rss_key_sysctl, "IU", "RSS key");
123815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind",
123915516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
124015516c77SSepherosa Ziehau 	    hn_rss_ind_sysctl, "IU", "RSS indirect table");
124134d68912SSepherosa Ziehau #endif
1242dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size",
1243dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_size, 0,
1244dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation size limit");
1245dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts",
1246dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0,
1247dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation count limit");
1248dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align",
1249dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_align, 0,
1250dc13fee6SSepherosa Ziehau 	    "RNDIS packet transmission aggregation alignment");
1251dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size",
1252dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
1253dc13fee6SSepherosa Ziehau 	    hn_txagg_size_sysctl, "I",
1254dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation size, 0 -- disable, -1 -- auto");
1255dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts",
1256dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
1257dc13fee6SSepherosa Ziehau 	    hn_txagg_pkts_sysctl, "I",
1258dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation packets, "
1259dc13fee6SSepherosa Ziehau 	    "0 -- disable, -1 -- auto");
12606c1204dfSSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "polling",
12616c1204dfSSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
12626c1204dfSSepherosa Ziehau 	    hn_polling_sysctl, "I",
12636c1204dfSSepherosa Ziehau 	    "Polling frequency: [100,1000000], 0 disable polling");
126440d60d6eSDexuan Cui 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf",
126540d60d6eSDexuan Cui 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
126640d60d6eSDexuan Cui 	    hn_vf_sysctl, "A", "Virtual Function's name");
126715516c77SSepherosa Ziehau 
126815516c77SSepherosa Ziehau 	/*
126915516c77SSepherosa Ziehau 	 * Setup the ifmedia, which has been initialized earlier.
127015516c77SSepherosa Ziehau 	 */
127115516c77SSepherosa Ziehau 	ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL);
127215516c77SSepherosa Ziehau 	ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO);
127315516c77SSepherosa Ziehau 	/* XXX ifmedia_set really should do this for us */
127415516c77SSepherosa Ziehau 	sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media;
127515516c77SSepherosa Ziehau 
127615516c77SSepherosa Ziehau 	/*
127715516c77SSepherosa Ziehau 	 * Setup the ifnet for this interface.
127815516c77SSepherosa Ziehau 	 */
127915516c77SSepherosa Ziehau 
128015516c77SSepherosa Ziehau 	ifp->if_baudrate = IF_Gbps(10);
128115516c77SSepherosa Ziehau 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
128215516c77SSepherosa Ziehau 	ifp->if_ioctl = hn_ioctl;
128315516c77SSepherosa Ziehau 	ifp->if_init = hn_init;
128423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
128515516c77SSepherosa Ziehau 	if (hn_use_if_start) {
128615516c77SSepherosa Ziehau 		int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]);
128715516c77SSepherosa Ziehau 
128815516c77SSepherosa Ziehau 		ifp->if_start = hn_start;
128915516c77SSepherosa Ziehau 		IFQ_SET_MAXLEN(&ifp->if_snd, qdepth);
129015516c77SSepherosa Ziehau 		ifp->if_snd.ifq_drv_maxlen = qdepth - 1;
129115516c77SSepherosa Ziehau 		IFQ_SET_READY(&ifp->if_snd);
129223bf9e15SSepherosa Ziehau 	} else
129323bf9e15SSepherosa Ziehau #endif
129423bf9e15SSepherosa Ziehau 	{
129515516c77SSepherosa Ziehau 		ifp->if_transmit = hn_transmit;
129615516c77SSepherosa Ziehau 		ifp->if_qflush = hn_xmit_qflush;
129715516c77SSepherosa Ziehau 	}
129815516c77SSepherosa Ziehau 
129915516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO;
130015516c77SSepherosa Ziehau #ifdef foo
130115516c77SSepherosa Ziehau 	/* We can't diff IPv6 packets from IPv4 packets on RX path. */
130215516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM_IPV6;
130315516c77SSepherosa Ziehau #endif
130415516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_VLAN) {
130515516c77SSepherosa Ziehau 		/* XXX not sure about VLAN_MTU. */
130615516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
130715516c77SSepherosa Ziehau 	}
130815516c77SSepherosa Ziehau 
130915516c77SSepherosa Ziehau 	ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist;
131015516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP_MASK)
131115516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM;
131215516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP6_MASK)
131315516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM_IPV6;
131415516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO4) {
131515516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO4;
131615516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP_TSO;
131715516c77SSepherosa Ziehau 	}
131815516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO6) {
131915516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO6;
132015516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP6_TSO;
132115516c77SSepherosa Ziehau 	}
132215516c77SSepherosa Ziehau 
132315516c77SSepherosa Ziehau 	/* Enable all available capabilities by default. */
132415516c77SSepherosa Ziehau 	ifp->if_capenable = ifp->if_capabilities;
132515516c77SSepherosa Ziehau 
13267960e6baSSepherosa Ziehau 	/*
13277960e6baSSepherosa Ziehau 	 * Disable IPv6 TSO and TXCSUM by default, they still can
13287960e6baSSepherosa Ziehau 	 * be enabled through SIOCSIFCAP.
13297960e6baSSepherosa Ziehau 	 */
13307960e6baSSepherosa Ziehau 	ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
13317960e6baSSepherosa Ziehau 	ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO);
13327960e6baSSepherosa Ziehau 
133315516c77SSepherosa Ziehau 	if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) {
133415516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU);
133515516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX;
133615516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = PAGE_SIZE;
133715516c77SSepherosa Ziehau 	}
133815516c77SSepherosa Ziehau 
133915516c77SSepherosa Ziehau 	ether_ifattach(ifp, eaddr);
134015516c77SSepherosa Ziehau 
134115516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) {
134215516c77SSepherosa Ziehau 		if_printf(ifp, "TSO segcnt %u segsz %u\n",
134315516c77SSepherosa Ziehau 		    ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize);
134415516c77SSepherosa Ziehau 	}
134515516c77SSepherosa Ziehau 
134615516c77SSepherosa Ziehau 	/* Inform the upper layer about the long frame support. */
134715516c77SSepherosa Ziehau 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
134815516c77SSepherosa Ziehau 
134915516c77SSepherosa Ziehau 	/*
135015516c77SSepherosa Ziehau 	 * Kick off link status check.
135115516c77SSepherosa Ziehau 	 */
135215516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
135315516c77SSepherosa Ziehau 	hn_update_link_status(sc);
135415516c77SSepherosa Ziehau 
13555bdfd3fdSDexuan Cui 	sc->hn_ifnet_evthand = EVENTHANDLER_REGISTER(ifnet_event,
13565bdfd3fdSDexuan Cui 	    hn_ifnet_event, sc, EVENTHANDLER_PRI_ANY);
13575bdfd3fdSDexuan Cui 
13585bdfd3fdSDexuan Cui 	sc->hn_ifaddr_evthand = EVENTHANDLER_REGISTER(ifaddr_event,
13595bdfd3fdSDexuan Cui 	    hn_ifaddr_event, sc, EVENTHANDLER_PRI_ANY);
13605bdfd3fdSDexuan Cui 
136115516c77SSepherosa Ziehau 	return (0);
136215516c77SSepherosa Ziehau failed:
136315516c77SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)
136415516c77SSepherosa Ziehau 		hn_synth_detach(sc);
136515516c77SSepherosa Ziehau 	hn_detach(dev);
136615516c77SSepherosa Ziehau 	return (error);
136715516c77SSepherosa Ziehau }
136815516c77SSepherosa Ziehau 
136915516c77SSepherosa Ziehau static int
137015516c77SSepherosa Ziehau hn_detach(device_t dev)
137115516c77SSepherosa Ziehau {
137215516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
137315516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
137415516c77SSepherosa Ziehau 
13755bdfd3fdSDexuan Cui 	if (sc->hn_ifaddr_evthand != NULL)
13765bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifaddr_event, sc->hn_ifaddr_evthand);
13775bdfd3fdSDexuan Cui 	if (sc->hn_ifnet_evthand != NULL)
13785bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifnet_event, sc->hn_ifnet_evthand);
13795bdfd3fdSDexuan Cui 
138025641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) {
138125641fc7SSepherosa Ziehau 		/*
138225641fc7SSepherosa Ziehau 		 * In case that the vmbus missed the orphan handler
138325641fc7SSepherosa Ziehau 		 * installation.
138425641fc7SSepherosa Ziehau 		 */
138525641fc7SSepherosa Ziehau 		vmbus_xact_ctx_orphan(sc->hn_xact);
138625641fc7SSepherosa Ziehau 	}
138725641fc7SSepherosa Ziehau 
138815516c77SSepherosa Ziehau 	if (device_is_attached(dev)) {
138915516c77SSepherosa Ziehau 		HN_LOCK(sc);
139015516c77SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
139115516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
13925bdfd3fdSDexuan Cui 				hn_stop(sc, true);
139315516c77SSepherosa Ziehau 			/*
139415516c77SSepherosa Ziehau 			 * NOTE:
139515516c77SSepherosa Ziehau 			 * hn_stop() only suspends data, so managment
139615516c77SSepherosa Ziehau 			 * stuffs have to be suspended manually here.
139715516c77SSepherosa Ziehau 			 */
139815516c77SSepherosa Ziehau 			hn_suspend_mgmt(sc);
139915516c77SSepherosa Ziehau 			hn_synth_detach(sc);
140015516c77SSepherosa Ziehau 		}
140115516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
140215516c77SSepherosa Ziehau 		ether_ifdetach(ifp);
140315516c77SSepherosa Ziehau 	}
140415516c77SSepherosa Ziehau 
140515516c77SSepherosa Ziehau 	ifmedia_removeall(&sc->hn_media);
140615516c77SSepherosa Ziehau 	hn_destroy_rx_data(sc);
140715516c77SSepherosa Ziehau 	hn_destroy_tx_data(sc);
140815516c77SSepherosa Ziehau 
14090e11868dSSepherosa Ziehau 	if (sc->hn_tx_taskqs != NULL && sc->hn_tx_taskqs != hn_tx_taskque) {
1410fdd0222aSSepherosa Ziehau 		int i;
1411fdd0222aSSepherosa Ziehau 
1412fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
1413fdd0222aSSepherosa Ziehau 			taskqueue_free(sc->hn_tx_taskqs[i]);
1414fdd0222aSSepherosa Ziehau 		free(sc->hn_tx_taskqs, M_DEVBUF);
1415fdd0222aSSepherosa Ziehau 	}
141615516c77SSepherosa Ziehau 	taskqueue_free(sc->hn_mgmt_taskq0);
141715516c77SSepherosa Ziehau 
141825641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL) {
141925641fc7SSepherosa Ziehau 		/*
142025641fc7SSepherosa Ziehau 		 * Uninstall the orphan handler _before_ the xact is
142125641fc7SSepherosa Ziehau 		 * destructed.
142225641fc7SSepherosa Ziehau 		 */
142325641fc7SSepherosa Ziehau 		vmbus_chan_unset_orphan(sc->hn_prichan);
142415516c77SSepherosa Ziehau 		vmbus_xact_ctx_destroy(sc->hn_xact);
142525641fc7SSepherosa Ziehau 	}
142615516c77SSepherosa Ziehau 
142715516c77SSepherosa Ziehau 	if_free(ifp);
142815516c77SSepherosa Ziehau 
142915516c77SSepherosa Ziehau 	HN_LOCK_DESTROY(sc);
143015516c77SSepherosa Ziehau 	return (0);
143115516c77SSepherosa Ziehau }
143215516c77SSepherosa Ziehau 
143315516c77SSepherosa Ziehau static int
143415516c77SSepherosa Ziehau hn_shutdown(device_t dev)
143515516c77SSepherosa Ziehau {
143615516c77SSepherosa Ziehau 
143715516c77SSepherosa Ziehau 	return (0);
143815516c77SSepherosa Ziehau }
143915516c77SSepherosa Ziehau 
144015516c77SSepherosa Ziehau static void
144115516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc)
144215516c77SSepherosa Ziehau {
144315516c77SSepherosa Ziehau 	uint32_t link_status;
144415516c77SSepherosa Ziehau 	int error;
144515516c77SSepherosa Ziehau 
144615516c77SSepherosa Ziehau 	error = hn_rndis_get_linkstatus(sc, &link_status);
144715516c77SSepherosa Ziehau 	if (error) {
144815516c77SSepherosa Ziehau 		/* XXX what to do? */
144915516c77SSepherosa Ziehau 		return;
145015516c77SSepherosa Ziehau 	}
145115516c77SSepherosa Ziehau 
145215516c77SSepherosa Ziehau 	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
145315516c77SSepherosa Ziehau 		sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
145415516c77SSepherosa Ziehau 	else
145515516c77SSepherosa Ziehau 		sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
145615516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp,
145715516c77SSepherosa Ziehau 	    (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ?
145815516c77SSepherosa Ziehau 	    LINK_STATE_UP : LINK_STATE_DOWN);
145915516c77SSepherosa Ziehau }
146015516c77SSepherosa Ziehau 
146115516c77SSepherosa Ziehau static void
146215516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused)
146315516c77SSepherosa Ziehau {
146415516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
146515516c77SSepherosa Ziehau 
146615516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
146715516c77SSepherosa Ziehau 		return;
146815516c77SSepherosa Ziehau 	hn_link_status(sc);
146915516c77SSepherosa Ziehau }
147015516c77SSepherosa Ziehau 
147115516c77SSepherosa Ziehau static void
147215516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused)
147315516c77SSepherosa Ziehau {
147415516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
147515516c77SSepherosa Ziehau 
147615516c77SSepherosa Ziehau 	/* Prevent any link status checks from running. */
147715516c77SSepherosa Ziehau 	sc->hn_link_flags |= HN_LINK_FLAG_NETCHG;
147815516c77SSepherosa Ziehau 
147915516c77SSepherosa Ziehau 	/*
148015516c77SSepherosa Ziehau 	 * Fake up a [link down --> link up] state change; 5 seconds
148115516c77SSepherosa Ziehau 	 * delay is used, which closely simulates miibus reaction
148215516c77SSepherosa Ziehau 	 * upon link down event.
148315516c77SSepherosa Ziehau 	 */
148415516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
148515516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
148615516c77SSepherosa Ziehau 	taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0,
148715516c77SSepherosa Ziehau 	    &sc->hn_netchg_status, 5 * hz);
148815516c77SSepherosa Ziehau }
148915516c77SSepherosa Ziehau 
149015516c77SSepherosa Ziehau static void
149115516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused)
149215516c77SSepherosa Ziehau {
149315516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
149415516c77SSepherosa Ziehau 
149515516c77SSepherosa Ziehau 	/* Re-allow link status checks. */
149615516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG;
149715516c77SSepherosa Ziehau 	hn_link_status(sc);
149815516c77SSepherosa Ziehau }
149915516c77SSepherosa Ziehau 
150015516c77SSepherosa Ziehau static void
150115516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc)
150215516c77SSepherosa Ziehau {
150315516c77SSepherosa Ziehau 
150415516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
150515516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
150615516c77SSepherosa Ziehau }
150715516c77SSepherosa Ziehau 
150815516c77SSepherosa Ziehau static void
150915516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc)
151015516c77SSepherosa Ziehau {
151115516c77SSepherosa Ziehau 
151215516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
151315516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init);
151415516c77SSepherosa Ziehau }
151515516c77SSepherosa Ziehau 
151615516c77SSepherosa Ziehau static __inline int
151715516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
151815516c77SSepherosa Ziehau     struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
151915516c77SSepherosa Ziehau {
152015516c77SSepherosa Ziehau 	struct mbuf *m = *m_head;
152115516c77SSepherosa Ziehau 	int error;
152215516c77SSepherosa Ziehau 
152315516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim"));
152415516c77SSepherosa Ziehau 
152515516c77SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap,
152615516c77SSepherosa Ziehau 	    m, segs, nsegs, BUS_DMA_NOWAIT);
152715516c77SSepherosa Ziehau 	if (error == EFBIG) {
152815516c77SSepherosa Ziehau 		struct mbuf *m_new;
152915516c77SSepherosa Ziehau 
153015516c77SSepherosa Ziehau 		m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX);
153115516c77SSepherosa Ziehau 		if (m_new == NULL)
153215516c77SSepherosa Ziehau 			return ENOBUFS;
153315516c77SSepherosa Ziehau 		else
153415516c77SSepherosa Ziehau 			*m_head = m = m_new;
153515516c77SSepherosa Ziehau 		txr->hn_tx_collapsed++;
153615516c77SSepherosa Ziehau 
153715516c77SSepherosa Ziehau 		error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag,
153815516c77SSepherosa Ziehau 		    txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT);
153915516c77SSepherosa Ziehau 	}
154015516c77SSepherosa Ziehau 	if (!error) {
154115516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap,
154215516c77SSepherosa Ziehau 		    BUS_DMASYNC_PREWRITE);
154315516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_DMAMAP;
154415516c77SSepherosa Ziehau 	}
154515516c77SSepherosa Ziehau 	return error;
154615516c77SSepherosa Ziehau }
154715516c77SSepherosa Ziehau 
154815516c77SSepherosa Ziehau static __inline int
154915516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd)
155015516c77SSepherosa Ziehau {
155115516c77SSepherosa Ziehau 
155215516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0,
155315516c77SSepherosa Ziehau 	    ("put an onlist txd %#x", txd->flags));
1554dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1555dc13fee6SSepherosa Ziehau 	    ("put an onagg txd %#x", txd->flags));
155615516c77SSepherosa Ziehau 
155715516c77SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
155815516c77SSepherosa Ziehau 	if (atomic_fetchadd_int(&txd->refs, -1) != 1)
155915516c77SSepherosa Ziehau 		return 0;
156015516c77SSepherosa Ziehau 
1561dc13fee6SSepherosa Ziehau 	if (!STAILQ_EMPTY(&txd->agg_list)) {
1562dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tmp_txd;
1563dc13fee6SSepherosa Ziehau 
1564dc13fee6SSepherosa Ziehau 		while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) {
1565dc13fee6SSepherosa Ziehau 			int freed;
1566dc13fee6SSepherosa Ziehau 
1567dc13fee6SSepherosa Ziehau 			KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list),
1568dc13fee6SSepherosa Ziehau 			    ("resursive aggregation on aggregated txdesc"));
1569dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG),
1570dc13fee6SSepherosa Ziehau 			    ("not aggregated txdesc"));
1571dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
1572dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc uses dmamap"));
1573dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
1574dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc consumes "
1575dc13fee6SSepherosa Ziehau 			     "chimney sending buffer"));
1576dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_size == 0,
1577dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc has non-zero "
1578dc13fee6SSepherosa Ziehau 			     "chimney sending size"));
1579dc13fee6SSepherosa Ziehau 
1580dc13fee6SSepherosa Ziehau 			STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link);
1581dc13fee6SSepherosa Ziehau 			tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG;
1582dc13fee6SSepherosa Ziehau 			freed = hn_txdesc_put(txr, tmp_txd);
1583dc13fee6SSepherosa Ziehau 			KASSERT(freed, ("failed to free aggregated txdesc"));
1584dc13fee6SSepherosa Ziehau 		}
1585dc13fee6SSepherosa Ziehau 	}
1586dc13fee6SSepherosa Ziehau 
158715516c77SSepherosa Ziehau 	if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) {
158815516c77SSepherosa Ziehau 		KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
158915516c77SSepherosa Ziehau 		    ("chim txd uses dmamap"));
159015516c77SSepherosa Ziehau 		hn_chim_free(txr->hn_sc, txd->chim_index);
159115516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
1592dc13fee6SSepherosa Ziehau 		txd->chim_size = 0;
159315516c77SSepherosa Ziehau 	} else if (txd->flags & HN_TXD_FLAG_DMAMAP) {
159415516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag,
159515516c77SSepherosa Ziehau 		    txd->data_dmap, BUS_DMASYNC_POSTWRITE);
159615516c77SSepherosa Ziehau 		bus_dmamap_unload(txr->hn_tx_data_dtag,
159715516c77SSepherosa Ziehau 		    txd->data_dmap);
159815516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_DMAMAP;
159915516c77SSepherosa Ziehau 	}
160015516c77SSepherosa Ziehau 
160115516c77SSepherosa Ziehau 	if (txd->m != NULL) {
160215516c77SSepherosa Ziehau 		m_freem(txd->m);
160315516c77SSepherosa Ziehau 		txd->m = NULL;
160415516c77SSepherosa Ziehau 	}
160515516c77SSepherosa Ziehau 
160615516c77SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONLIST;
160715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
160815516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
160915516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_avail >= 0 &&
161015516c77SSepherosa Ziehau 	    txr->hn_txdesc_avail < txr->hn_txdesc_cnt,
161115516c77SSepherosa Ziehau 	    ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail));
161215516c77SSepherosa Ziehau 	txr->hn_txdesc_avail++;
161315516c77SSepherosa Ziehau 	SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
161415516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
161585e4ae1eSSepherosa Ziehau #else	/* HN_USE_TXDESC_BUFRING */
161685e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
161715516c77SSepherosa Ziehau 	atomic_add_int(&txr->hn_txdesc_avail, 1);
161815516c77SSepherosa Ziehau #endif
161985e4ae1eSSepherosa Ziehau 	buf_ring_enqueue(txr->hn_txdesc_br, txd);
162085e4ae1eSSepherosa Ziehau #endif	/* !HN_USE_TXDESC_BUFRING */
162115516c77SSepherosa Ziehau 
162215516c77SSepherosa Ziehau 	return 1;
162315516c77SSepherosa Ziehau }
162415516c77SSepherosa Ziehau 
162515516c77SSepherosa Ziehau static __inline struct hn_txdesc *
162615516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr)
162715516c77SSepherosa Ziehau {
162815516c77SSepherosa Ziehau 	struct hn_txdesc *txd;
162915516c77SSepherosa Ziehau 
163015516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
163115516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
163215516c77SSepherosa Ziehau 	txd = SLIST_FIRST(&txr->hn_txlist);
163315516c77SSepherosa Ziehau 	if (txd != NULL) {
163415516c77SSepherosa Ziehau 		KASSERT(txr->hn_txdesc_avail > 0,
163515516c77SSepherosa Ziehau 		    ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail));
163615516c77SSepherosa Ziehau 		txr->hn_txdesc_avail--;
163715516c77SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&txr->hn_txlist, link);
163815516c77SSepherosa Ziehau 	}
163915516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
164015516c77SSepherosa Ziehau #else
164115516c77SSepherosa Ziehau 	txd = buf_ring_dequeue_sc(txr->hn_txdesc_br);
164215516c77SSepherosa Ziehau #endif
164315516c77SSepherosa Ziehau 
164415516c77SSepherosa Ziehau 	if (txd != NULL) {
164515516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
164685e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
164715516c77SSepherosa Ziehau 		atomic_subtract_int(&txr->hn_txdesc_avail, 1);
164815516c77SSepherosa Ziehau #endif
164985e4ae1eSSepherosa Ziehau #endif	/* HN_USE_TXDESC_BUFRING */
165015516c77SSepherosa Ziehau 		KASSERT(txd->m == NULL && txd->refs == 0 &&
1651dc13fee6SSepherosa Ziehau 		    STAILQ_EMPTY(&txd->agg_list) &&
165215516c77SSepherosa Ziehau 		    txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
1653dc13fee6SSepherosa Ziehau 		    txd->chim_size == 0 &&
165415516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONLIST) &&
1655dc13fee6SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONAGG) == 0 &&
165615516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd"));
165715516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_ONLIST;
165815516c77SSepherosa Ziehau 		txd->refs = 1;
165915516c77SSepherosa Ziehau 	}
166015516c77SSepherosa Ziehau 	return txd;
166115516c77SSepherosa Ziehau }
166215516c77SSepherosa Ziehau 
166315516c77SSepherosa Ziehau static __inline void
166415516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd)
166515516c77SSepherosa Ziehau {
166615516c77SSepherosa Ziehau 
166715516c77SSepherosa Ziehau 	/* 0->1 transition will never work */
166825641fc7SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
166915516c77SSepherosa Ziehau 	atomic_add_int(&txd->refs, 1);
167015516c77SSepherosa Ziehau }
167115516c77SSepherosa Ziehau 
1672dc13fee6SSepherosa Ziehau static __inline void
1673dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd)
1674dc13fee6SSepherosa Ziehau {
1675dc13fee6SSepherosa Ziehau 
1676dc13fee6SSepherosa Ziehau 	KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1677dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on aggregating txdesc"));
1678dc13fee6SSepherosa Ziehau 
1679dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1680dc13fee6SSepherosa Ziehau 	    ("already aggregated"));
1681dc13fee6SSepherosa Ziehau 	KASSERT(STAILQ_EMPTY(&txd->agg_list),
1682dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on to-be-aggregated txdesc"));
1683dc13fee6SSepherosa Ziehau 
1684dc13fee6SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONAGG;
1685dc13fee6SSepherosa Ziehau 	STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link);
1686dc13fee6SSepherosa Ziehau }
1687dc13fee6SSepherosa Ziehau 
168815516c77SSepherosa Ziehau static bool
168915516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr)
169015516c77SSepherosa Ziehau {
169115516c77SSepherosa Ziehau 	bool pending = false;
169215516c77SSepherosa Ziehau 
169315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
169415516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
169515516c77SSepherosa Ziehau 	if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt)
169615516c77SSepherosa Ziehau 		pending = true;
169715516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
169815516c77SSepherosa Ziehau #else
169915516c77SSepherosa Ziehau 	if (!buf_ring_full(txr->hn_txdesc_br))
170015516c77SSepherosa Ziehau 		pending = true;
170115516c77SSepherosa Ziehau #endif
170215516c77SSepherosa Ziehau 	return (pending);
170315516c77SSepherosa Ziehau }
170415516c77SSepherosa Ziehau 
170515516c77SSepherosa Ziehau static __inline void
170615516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr)
170715516c77SSepherosa Ziehau {
170815516c77SSepherosa Ziehau 	txr->hn_has_txeof = 0;
170915516c77SSepherosa Ziehau 	txr->hn_txeof(txr);
171015516c77SSepherosa Ziehau }
171115516c77SSepherosa Ziehau 
171215516c77SSepherosa Ziehau static void
171315516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc,
171415516c77SSepherosa Ziehau     struct vmbus_channel *chan, const void *data __unused, int dlen __unused)
171515516c77SSepherosa Ziehau {
171615516c77SSepherosa Ziehau 	struct hn_txdesc *txd = sndc->hn_cbarg;
171715516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
171815516c77SSepherosa Ziehau 
171915516c77SSepherosa Ziehau 	txr = txd->txr;
172015516c77SSepherosa Ziehau 	KASSERT(txr->hn_chan == chan,
172115516c77SSepherosa Ziehau 	    ("channel mismatch, on chan%u, should be chan%u",
1722aa1a2adcSSepherosa Ziehau 	     vmbus_chan_id(chan), vmbus_chan_id(txr->hn_chan)));
172315516c77SSepherosa Ziehau 
172415516c77SSepherosa Ziehau 	txr->hn_has_txeof = 1;
172515516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
172615516c77SSepherosa Ziehau 
172715516c77SSepherosa Ziehau 	++txr->hn_txdone_cnt;
172815516c77SSepherosa Ziehau 	if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) {
172915516c77SSepherosa Ziehau 		txr->hn_txdone_cnt = 0;
173015516c77SSepherosa Ziehau 		if (txr->hn_oactive)
173115516c77SSepherosa Ziehau 			hn_txeof(txr);
173215516c77SSepherosa Ziehau 	}
173315516c77SSepherosa Ziehau }
173415516c77SSepherosa Ziehau 
173515516c77SSepherosa Ziehau static void
173615516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
173715516c77SSepherosa Ziehau {
173815516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
173915516c77SSepherosa Ziehau 	tcp_lro_flush_all(&rxr->hn_lro);
174015516c77SSepherosa Ziehau #endif
174115516c77SSepherosa Ziehau 
174215516c77SSepherosa Ziehau 	/*
174315516c77SSepherosa Ziehau 	 * NOTE:
174415516c77SSepherosa Ziehau 	 * 'txr' could be NULL, if multiple channels and
174515516c77SSepherosa Ziehau 	 * ifnet.if_start method are enabled.
174615516c77SSepherosa Ziehau 	 */
174715516c77SSepherosa Ziehau 	if (txr == NULL || !txr->hn_has_txeof)
174815516c77SSepherosa Ziehau 		return;
174915516c77SSepherosa Ziehau 
175015516c77SSepherosa Ziehau 	txr->hn_txdone_cnt = 0;
175115516c77SSepherosa Ziehau 	hn_txeof(txr);
175215516c77SSepherosa Ziehau }
175315516c77SSepherosa Ziehau 
175415516c77SSepherosa Ziehau static __inline uint32_t
175515516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs)
175615516c77SSepherosa Ziehau {
175715516c77SSepherosa Ziehau 
175815516c77SSepherosa Ziehau 	KASSERT(ofs >= sizeof(struct rndis_packet_msg),
175915516c77SSepherosa Ziehau 	    ("invalid RNDIS packet msg offset %u", ofs));
176015516c77SSepherosa Ziehau 	return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset));
176115516c77SSepherosa Ziehau }
176215516c77SSepherosa Ziehau 
176315516c77SSepherosa Ziehau static __inline void *
176415516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
176515516c77SSepherosa Ziehau     size_t pi_dlen, uint32_t pi_type)
176615516c77SSepherosa Ziehau {
176715516c77SSepherosa Ziehau 	const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
176815516c77SSepherosa Ziehau 	struct rndis_pktinfo *pi;
176915516c77SSepherosa Ziehau 
177015516c77SSepherosa Ziehau 	KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
177115516c77SSepherosa Ziehau 	    ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
177215516c77SSepherosa Ziehau 
177315516c77SSepherosa Ziehau 	/*
177415516c77SSepherosa Ziehau 	 * Per-packet-info does not move; it only grows.
177515516c77SSepherosa Ziehau 	 *
177615516c77SSepherosa Ziehau 	 * NOTE:
177715516c77SSepherosa Ziehau 	 * rm_pktinfooffset in this phase counts from the beginning
177815516c77SSepherosa Ziehau 	 * of rndis_packet_msg.
177915516c77SSepherosa Ziehau 	 */
178015516c77SSepherosa Ziehau 	KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
178115516c77SSepherosa Ziehau 	    ("%u pktinfo overflows RNDIS packet msg", pi_type));
178215516c77SSepherosa Ziehau 	pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
178315516c77SSepherosa Ziehau 	    pkt->rm_pktinfolen);
178415516c77SSepherosa Ziehau 	pkt->rm_pktinfolen += pi_size;
178515516c77SSepherosa Ziehau 
178615516c77SSepherosa Ziehau 	pi->rm_size = pi_size;
178715516c77SSepherosa Ziehau 	pi->rm_type = pi_type;
178815516c77SSepherosa Ziehau 	pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
178915516c77SSepherosa Ziehau 
179015516c77SSepherosa Ziehau 	return (pi->rm_data);
179115516c77SSepherosa Ziehau }
179215516c77SSepherosa Ziehau 
1793dc13fee6SSepherosa Ziehau static __inline int
1794dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr)
1795dc13fee6SSepherosa Ziehau {
1796dc13fee6SSepherosa Ziehau 	struct hn_txdesc *txd;
1797dc13fee6SSepherosa Ziehau 	struct mbuf *m;
1798dc13fee6SSepherosa Ziehau 	int error, pkts;
1799dc13fee6SSepherosa Ziehau 
1800dc13fee6SSepherosa Ziehau 	txd = txr->hn_agg_txd;
1801dc13fee6SSepherosa Ziehau 	KASSERT(txd != NULL, ("no aggregate txdesc"));
1802dc13fee6SSepherosa Ziehau 
1803dc13fee6SSepherosa Ziehau 	/*
1804dc13fee6SSepherosa Ziehau 	 * Since hn_txpkt() will reset this temporary stat, save
1805dc13fee6SSepherosa Ziehau 	 * it now, so that oerrors can be updated properly, if
1806dc13fee6SSepherosa Ziehau 	 * hn_txpkt() ever fails.
1807dc13fee6SSepherosa Ziehau 	 */
1808dc13fee6SSepherosa Ziehau 	pkts = txr->hn_stat_pkts;
1809dc13fee6SSepherosa Ziehau 
1810dc13fee6SSepherosa Ziehau 	/*
1811dc13fee6SSepherosa Ziehau 	 * Since txd's mbuf will _not_ be freed upon hn_txpkt()
1812dc13fee6SSepherosa Ziehau 	 * failure, save it for later freeing, if hn_txpkt() ever
1813dc13fee6SSepherosa Ziehau 	 * fails.
1814dc13fee6SSepherosa Ziehau 	 */
1815dc13fee6SSepherosa Ziehau 	m = txd->m;
1816dc13fee6SSepherosa Ziehau 	error = hn_txpkt(ifp, txr, txd);
1817dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
1818dc13fee6SSepherosa Ziehau 		/* txd is freed, but m is not. */
1819dc13fee6SSepherosa Ziehau 		m_freem(m);
1820dc13fee6SSepherosa Ziehau 
1821dc13fee6SSepherosa Ziehau 		txr->hn_flush_failed++;
1822dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts);
1823dc13fee6SSepherosa Ziehau 	}
1824dc13fee6SSepherosa Ziehau 
1825dc13fee6SSepherosa Ziehau 	/* Reset all aggregation states. */
1826dc13fee6SSepherosa Ziehau 	txr->hn_agg_txd = NULL;
1827dc13fee6SSepherosa Ziehau 	txr->hn_agg_szleft = 0;
1828dc13fee6SSepherosa Ziehau 	txr->hn_agg_pktleft = 0;
1829dc13fee6SSepherosa Ziehau 	txr->hn_agg_prevpkt = NULL;
1830dc13fee6SSepherosa Ziehau 
1831dc13fee6SSepherosa Ziehau 	return (error);
1832dc13fee6SSepherosa Ziehau }
1833dc13fee6SSepherosa Ziehau 
1834dc13fee6SSepherosa Ziehau static void *
1835dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
1836dc13fee6SSepherosa Ziehau     int pktsize)
1837dc13fee6SSepherosa Ziehau {
1838dc13fee6SSepherosa Ziehau 	void *chim;
1839dc13fee6SSepherosa Ziehau 
1840dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL) {
1841dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) {
1842dc13fee6SSepherosa Ziehau 			struct hn_txdesc *agg_txd = txr->hn_agg_txd;
1843dc13fee6SSepherosa Ziehau 			struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt;
1844dc13fee6SSepherosa Ziehau 			int olen;
1845dc13fee6SSepherosa Ziehau 
1846dc13fee6SSepherosa Ziehau 			/*
1847dc13fee6SSepherosa Ziehau 			 * Update the previous RNDIS packet's total length,
1848dc13fee6SSepherosa Ziehau 			 * it can be increased due to the mandatory alignment
1849dc13fee6SSepherosa Ziehau 			 * padding for this RNDIS packet.  And update the
1850dc13fee6SSepherosa Ziehau 			 * aggregating txdesc's chimney sending buffer size
1851dc13fee6SSepherosa Ziehau 			 * accordingly.
1852dc13fee6SSepherosa Ziehau 			 *
1853dc13fee6SSepherosa Ziehau 			 * XXX
1854dc13fee6SSepherosa Ziehau 			 * Zero-out the padding, as required by the RNDIS spec.
1855dc13fee6SSepherosa Ziehau 			 */
1856dc13fee6SSepherosa Ziehau 			olen = pkt->rm_len;
1857dc13fee6SSepherosa Ziehau 			pkt->rm_len = roundup2(olen, txr->hn_agg_align);
1858dc13fee6SSepherosa Ziehau 			agg_txd->chim_size += pkt->rm_len - olen;
1859dc13fee6SSepherosa Ziehau 
1860dc13fee6SSepherosa Ziehau 			/* Link this txdesc to the parent. */
1861dc13fee6SSepherosa Ziehau 			hn_txdesc_agg(agg_txd, txd);
1862dc13fee6SSepherosa Ziehau 
1863dc13fee6SSepherosa Ziehau 			chim = (uint8_t *)pkt + pkt->rm_len;
1864dc13fee6SSepherosa Ziehau 			/* Save the current packet for later fixup. */
1865dc13fee6SSepherosa Ziehau 			txr->hn_agg_prevpkt = chim;
1866dc13fee6SSepherosa Ziehau 
1867dc13fee6SSepherosa Ziehau 			txr->hn_agg_pktleft--;
1868dc13fee6SSepherosa Ziehau 			txr->hn_agg_szleft -= pktsize;
1869dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_szleft <=
1870dc13fee6SSepherosa Ziehau 			    HN_PKTSIZE_MIN(txr->hn_agg_align)) {
1871dc13fee6SSepherosa Ziehau 				/*
1872dc13fee6SSepherosa Ziehau 				 * Probably can't aggregate more packets,
1873dc13fee6SSepherosa Ziehau 				 * flush this aggregating txdesc proactively.
1874dc13fee6SSepherosa Ziehau 				 */
1875dc13fee6SSepherosa Ziehau 				txr->hn_agg_pktleft = 0;
1876dc13fee6SSepherosa Ziehau 			}
1877dc13fee6SSepherosa Ziehau 			/* Done! */
1878dc13fee6SSepherosa Ziehau 			return (chim);
1879dc13fee6SSepherosa Ziehau 		}
1880dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
1881dc13fee6SSepherosa Ziehau 	}
1882dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
1883dc13fee6SSepherosa Ziehau 
1884dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney_tried++;
1885dc13fee6SSepherosa Ziehau 	txd->chim_index = hn_chim_alloc(txr->hn_sc);
1886dc13fee6SSepherosa Ziehau 	if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID)
1887dc13fee6SSepherosa Ziehau 		return (NULL);
1888dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney++;
1889dc13fee6SSepherosa Ziehau 
1890dc13fee6SSepherosa Ziehau 	chim = txr->hn_sc->hn_chim +
1891dc13fee6SSepherosa Ziehau 	    (txd->chim_index * txr->hn_sc->hn_chim_szmax);
1892dc13fee6SSepherosa Ziehau 
1893dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_pktmax > 1 &&
1894dc13fee6SSepherosa Ziehau 	    txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) {
1895dc13fee6SSepherosa Ziehau 		txr->hn_agg_txd = txd;
1896dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1;
1897dc13fee6SSepherosa Ziehau 		txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize;
1898dc13fee6SSepherosa Ziehau 		txr->hn_agg_prevpkt = chim;
1899dc13fee6SSepherosa Ziehau 	}
1900dc13fee6SSepherosa Ziehau 	return (chim);
1901dc13fee6SSepherosa Ziehau }
1902dc13fee6SSepherosa Ziehau 
190315516c77SSepherosa Ziehau /*
190415516c77SSepherosa Ziehau  * NOTE:
190515516c77SSepherosa Ziehau  * If this function fails, then both txd and m_head0 will be freed.
190615516c77SSepherosa Ziehau  */
190715516c77SSepherosa Ziehau static int
1908dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
1909dc13fee6SSepherosa Ziehau     struct mbuf **m_head0)
191015516c77SSepherosa Ziehau {
191115516c77SSepherosa Ziehau 	bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX];
191215516c77SSepherosa Ziehau 	int error, nsegs, i;
191315516c77SSepherosa Ziehau 	struct mbuf *m_head = *m_head0;
191415516c77SSepherosa Ziehau 	struct rndis_packet_msg *pkt;
191515516c77SSepherosa Ziehau 	uint32_t *pi_data;
19168966e5d5SSepherosa Ziehau 	void *chim = NULL;
1917dc13fee6SSepherosa Ziehau 	int pkt_hlen, pkt_size;
191815516c77SSepherosa Ziehau 
191915516c77SSepherosa Ziehau 	pkt = txd->rndis_pkt;
1920dc13fee6SSepherosa Ziehau 	pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align);
1921dc13fee6SSepherosa Ziehau 	if (pkt_size < txr->hn_chim_size) {
1922dc13fee6SSepherosa Ziehau 		chim = hn_try_txagg(ifp, txr, txd, pkt_size);
1923dc13fee6SSepherosa Ziehau 		if (chim != NULL)
19248966e5d5SSepherosa Ziehau 			pkt = chim;
1925dc13fee6SSepherosa Ziehau 	} else {
1926dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL)
1927dc13fee6SSepherosa Ziehau 			hn_flush_txagg(ifp, txr);
19288966e5d5SSepherosa Ziehau 	}
19298966e5d5SSepherosa Ziehau 
193015516c77SSepherosa Ziehau 	pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
19318fe90f73SSepherosa Ziehau 	pkt->rm_len = m_head->m_pkthdr.len;
19329130c4f7SSepherosa Ziehau 	pkt->rm_dataoffset = 0;
193315516c77SSepherosa Ziehau 	pkt->rm_datalen = m_head->m_pkthdr.len;
1934dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataoffset = 0;
1935dc13fee6SSepherosa Ziehau 	pkt->rm_oobdatalen = 0;
1936dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataelements = 0;
193715516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = sizeof(*pkt);
193815516c77SSepherosa Ziehau 	pkt->rm_pktinfolen = 0;
1939dc13fee6SSepherosa Ziehau 	pkt->rm_vchandle = 0;
1940dc13fee6SSepherosa Ziehau 	pkt->rm_reserved = 0;
194115516c77SSepherosa Ziehau 
194215516c77SSepherosa Ziehau 	if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) {
194315516c77SSepherosa Ziehau 		/*
194415516c77SSepherosa Ziehau 		 * Set the hash value for this packet, so that the host could
194515516c77SSepherosa Ziehau 		 * dispatch the TX done event for this packet back to this TX
194615516c77SSepherosa Ziehau 		 * ring's channel.
194715516c77SSepherosa Ziehau 		 */
194815516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
194915516c77SSepherosa Ziehau 		    HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL);
195015516c77SSepherosa Ziehau 		*pi_data = txr->hn_tx_idx;
195115516c77SSepherosa Ziehau 	}
195215516c77SSepherosa Ziehau 
195315516c77SSepherosa Ziehau 	if (m_head->m_flags & M_VLANTAG) {
195415516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
195515516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
195615516c77SSepherosa Ziehau 		*pi_data = NDIS_VLAN_INFO_MAKE(
195715516c77SSepherosa Ziehau 		    EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag),
195815516c77SSepherosa Ziehau 		    EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag),
195915516c77SSepherosa Ziehau 		    EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag));
196015516c77SSepherosa Ziehau 	}
196115516c77SSepherosa Ziehau 
196215516c77SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
196315516c77SSepherosa Ziehau #if defined(INET6) || defined(INET)
196415516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
196515516c77SSepherosa Ziehau 		    NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO);
196615516c77SSepherosa Ziehau #ifdef INET
196715516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
196815516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV4(0,
196915516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
197015516c77SSepherosa Ziehau 		}
197115516c77SSepherosa Ziehau #endif
197215516c77SSepherosa Ziehau #if defined(INET6) && defined(INET)
197315516c77SSepherosa Ziehau 		else
197415516c77SSepherosa Ziehau #endif
197515516c77SSepherosa Ziehau #ifdef INET6
197615516c77SSepherosa Ziehau 		{
197715516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV6(0,
197815516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
197915516c77SSepherosa Ziehau 		}
198015516c77SSepherosa Ziehau #endif
198115516c77SSepherosa Ziehau #endif	/* INET6 || INET */
198215516c77SSepherosa Ziehau 	} else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) {
198315516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
198415516c77SSepherosa Ziehau 		    NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
198515516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
198615516c77SSepherosa Ziehau 		    (CSUM_IP6_TCP | CSUM_IP6_UDP)) {
198715516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV6;
198815516c77SSepherosa Ziehau 		} else {
198915516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV4;
199015516c77SSepherosa Ziehau 			if (m_head->m_pkthdr.csum_flags & CSUM_IP)
199115516c77SSepherosa Ziehau 				*pi_data |= NDIS_TXCSUM_INFO_IPCS;
199215516c77SSepherosa Ziehau 		}
199315516c77SSepherosa Ziehau 
199415516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP))
199515516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_TCPCS;
199615516c77SSepherosa Ziehau 		else if (m_head->m_pkthdr.csum_flags &
199715516c77SSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP6_UDP))
199815516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_UDPCS;
199915516c77SSepherosa Ziehau 	}
200015516c77SSepherosa Ziehau 
2001dc13fee6SSepherosa Ziehau 	pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
20028fe90f73SSepherosa Ziehau 	/* Fixup RNDIS packet message total length */
20038fe90f73SSepherosa Ziehau 	pkt->rm_len += pkt_hlen;
200415516c77SSepherosa Ziehau 	/* Convert RNDIS packet message offsets */
20059130c4f7SSepherosa Ziehau 	pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt_hlen);
200615516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset);
200715516c77SSepherosa Ziehau 
200815516c77SSepherosa Ziehau 	/*
20098966e5d5SSepherosa Ziehau 	 * Fast path: Chimney sending.
201015516c77SSepherosa Ziehau 	 */
20118966e5d5SSepherosa Ziehau 	if (chim != NULL) {
2012dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tgt_txd = txd;
2013dc13fee6SSepherosa Ziehau 
2014dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL) {
2015dc13fee6SSepherosa Ziehau 			tgt_txd = txr->hn_agg_txd;
2016dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
2017dc13fee6SSepherosa Ziehau 			*m_head0 = NULL;
2018dc13fee6SSepherosa Ziehau #endif
2019dc13fee6SSepherosa Ziehau 		}
2020dc13fee6SSepherosa Ziehau 
2021dc13fee6SSepherosa Ziehau 		KASSERT(pkt == chim,
2022dc13fee6SSepherosa Ziehau 		    ("RNDIS pkt not in chimney sending buffer"));
2023dc13fee6SSepherosa Ziehau 		KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID,
2024dc13fee6SSepherosa Ziehau 		    ("chimney sending buffer is not used"));
2025dc13fee6SSepherosa Ziehau 		tgt_txd->chim_size += pkt->rm_len;
202615516c77SSepherosa Ziehau 
20278966e5d5SSepherosa Ziehau 		m_copydata(m_head, 0, m_head->m_pkthdr.len,
2028dc13fee6SSepherosa Ziehau 		    ((uint8_t *)chim) + pkt_hlen);
202915516c77SSepherosa Ziehau 
203015516c77SSepherosa Ziehau 		txr->hn_gpa_cnt = 0;
203115516c77SSepherosa Ziehau 		txr->hn_sendpkt = hn_txpkt_chim;
203215516c77SSepherosa Ziehau 		goto done;
203315516c77SSepherosa Ziehau 	}
2034dc13fee6SSepherosa Ziehau 
2035dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc"));
20368966e5d5SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
20378966e5d5SSepherosa Ziehau 	    ("chimney buffer is used"));
20388966e5d5SSepherosa Ziehau 	KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc"));
203915516c77SSepherosa Ziehau 
204015516c77SSepherosa Ziehau 	error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs);
2041dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
204215516c77SSepherosa Ziehau 		int freed;
204315516c77SSepherosa Ziehau 
204415516c77SSepherosa Ziehau 		/*
204515516c77SSepherosa Ziehau 		 * This mbuf is not linked w/ the txd yet, so free it now.
204615516c77SSepherosa Ziehau 		 */
204715516c77SSepherosa Ziehau 		m_freem(m_head);
204815516c77SSepherosa Ziehau 		*m_head0 = NULL;
204915516c77SSepherosa Ziehau 
205015516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
205115516c77SSepherosa Ziehau 		KASSERT(freed != 0,
205215516c77SSepherosa Ziehau 		    ("fail to free txd upon txdma error"));
205315516c77SSepherosa Ziehau 
205415516c77SSepherosa Ziehau 		txr->hn_txdma_failed++;
2055dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
205615516c77SSepherosa Ziehau 		return error;
205715516c77SSepherosa Ziehau 	}
205815516c77SSepherosa Ziehau 	*m_head0 = m_head;
205915516c77SSepherosa Ziehau 
206015516c77SSepherosa Ziehau 	/* +1 RNDIS packet message */
206115516c77SSepherosa Ziehau 	txr->hn_gpa_cnt = nsegs + 1;
206215516c77SSepherosa Ziehau 
206315516c77SSepherosa Ziehau 	/* send packet with page buffer */
206415516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr);
206515516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK;
2066dc13fee6SSepherosa Ziehau 	txr->hn_gpa[0].gpa_len = pkt_hlen;
206715516c77SSepherosa Ziehau 
206815516c77SSepherosa Ziehau 	/*
206915516c77SSepherosa Ziehau 	 * Fill the page buffers with mbuf info after the page
207015516c77SSepherosa Ziehau 	 * buffer for RNDIS packet message.
207115516c77SSepherosa Ziehau 	 */
207215516c77SSepherosa Ziehau 	for (i = 0; i < nsegs; ++i) {
207315516c77SSepherosa Ziehau 		struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1];
207415516c77SSepherosa Ziehau 
207515516c77SSepherosa Ziehau 		gpa->gpa_page = atop(segs[i].ds_addr);
207615516c77SSepherosa Ziehau 		gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK;
207715516c77SSepherosa Ziehau 		gpa->gpa_len = segs[i].ds_len;
207815516c77SSepherosa Ziehau 	}
207915516c77SSepherosa Ziehau 
208015516c77SSepherosa Ziehau 	txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
208115516c77SSepherosa Ziehau 	txd->chim_size = 0;
208215516c77SSepherosa Ziehau 	txr->hn_sendpkt = hn_txpkt_sglist;
208315516c77SSepherosa Ziehau done:
208415516c77SSepherosa Ziehau 	txd->m = m_head;
208515516c77SSepherosa Ziehau 
208615516c77SSepherosa Ziehau 	/* Set the completion routine */
208715516c77SSepherosa Ziehau 	hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd);
208815516c77SSepherosa Ziehau 
2089dc13fee6SSepherosa Ziehau 	/* Update temporary stats for later use. */
2090dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts++;
2091dc13fee6SSepherosa Ziehau 	txr->hn_stat_size += m_head->m_pkthdr.len;
2092dc13fee6SSepherosa Ziehau 	if (m_head->m_flags & M_MCAST)
2093dc13fee6SSepherosa Ziehau 		txr->hn_stat_mcasts++;
2094dc13fee6SSepherosa Ziehau 
209515516c77SSepherosa Ziehau 	return 0;
209615516c77SSepherosa Ziehau }
209715516c77SSepherosa Ziehau 
209815516c77SSepherosa Ziehau /*
209915516c77SSepherosa Ziehau  * NOTE:
210015516c77SSepherosa Ziehau  * If this function fails, then txd will be freed, but the mbuf
210115516c77SSepherosa Ziehau  * associated w/ the txd will _not_ be freed.
210215516c77SSepherosa Ziehau  */
210315516c77SSepherosa Ziehau static int
210415516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd)
210515516c77SSepherosa Ziehau {
21068e7d3136SSepherosa Ziehau 	int error, send_failed = 0, has_bpf;
210715516c77SSepherosa Ziehau 
210815516c77SSepherosa Ziehau again:
21098e7d3136SSepherosa Ziehau 	has_bpf = bpf_peers_present(ifp->if_bpf);
21108e7d3136SSepherosa Ziehau 	if (has_bpf) {
211115516c77SSepherosa Ziehau 		/*
21128e7d3136SSepherosa Ziehau 		 * Make sure that this txd and any aggregated txds are not
21138e7d3136SSepherosa Ziehau 		 * freed before ETHER_BPF_MTAP.
211415516c77SSepherosa Ziehau 		 */
211515516c77SSepherosa Ziehau 		hn_txdesc_hold(txd);
21168e7d3136SSepherosa Ziehau 	}
211715516c77SSepherosa Ziehau 	error = txr->hn_sendpkt(txr, txd);
211815516c77SSepherosa Ziehau 	if (!error) {
21198e7d3136SSepherosa Ziehau 		if (has_bpf) {
2120dc13fee6SSepherosa Ziehau 			const struct hn_txdesc *tmp_txd;
2121dc13fee6SSepherosa Ziehau 
212215516c77SSepherosa Ziehau 			ETHER_BPF_MTAP(ifp, txd->m);
2123dc13fee6SSepherosa Ziehau 			STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link)
2124dc13fee6SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, tmp_txd->m);
2125dc13fee6SSepherosa Ziehau 		}
2126dc13fee6SSepherosa Ziehau 
2127dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts);
212823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
212923bf9e15SSepherosa Ziehau 		if (!hn_use_if_start)
213023bf9e15SSepherosa Ziehau #endif
213123bf9e15SSepherosa Ziehau 		{
213215516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OBYTES,
2133dc13fee6SSepherosa Ziehau 			    txr->hn_stat_size);
2134dc13fee6SSepherosa Ziehau 			if (txr->hn_stat_mcasts != 0) {
2135dc13fee6SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OMCASTS,
2136dc13fee6SSepherosa Ziehau 				    txr->hn_stat_mcasts);
213715516c77SSepherosa Ziehau 			}
2138dc13fee6SSepherosa Ziehau 		}
2139dc13fee6SSepherosa Ziehau 		txr->hn_pkts += txr->hn_stat_pkts;
2140dc13fee6SSepherosa Ziehau 		txr->hn_sends++;
214115516c77SSepherosa Ziehau 	}
21428e7d3136SSepherosa Ziehau 	if (has_bpf)
214315516c77SSepherosa Ziehau 		hn_txdesc_put(txr, txd);
214415516c77SSepherosa Ziehau 
214515516c77SSepherosa Ziehau 	if (__predict_false(error)) {
214615516c77SSepherosa Ziehau 		int freed;
214715516c77SSepherosa Ziehau 
214815516c77SSepherosa Ziehau 		/*
214915516c77SSepherosa Ziehau 		 * This should "really rarely" happen.
215015516c77SSepherosa Ziehau 		 *
215115516c77SSepherosa Ziehau 		 * XXX Too many RX to be acked or too many sideband
215215516c77SSepherosa Ziehau 		 * commands to run?  Ask netvsc_channel_rollup()
215315516c77SSepherosa Ziehau 		 * to kick start later.
215415516c77SSepherosa Ziehau 		 */
215515516c77SSepherosa Ziehau 		txr->hn_has_txeof = 1;
215615516c77SSepherosa Ziehau 		if (!send_failed) {
215715516c77SSepherosa Ziehau 			txr->hn_send_failed++;
215815516c77SSepherosa Ziehau 			send_failed = 1;
215915516c77SSepherosa Ziehau 			/*
216015516c77SSepherosa Ziehau 			 * Try sending again after set hn_has_txeof;
216115516c77SSepherosa Ziehau 			 * in case that we missed the last
216215516c77SSepherosa Ziehau 			 * netvsc_channel_rollup().
216315516c77SSepherosa Ziehau 			 */
216415516c77SSepherosa Ziehau 			goto again;
216515516c77SSepherosa Ziehau 		}
216615516c77SSepherosa Ziehau 		if_printf(ifp, "send failed\n");
216715516c77SSepherosa Ziehau 
216815516c77SSepherosa Ziehau 		/*
216915516c77SSepherosa Ziehau 		 * Caller will perform further processing on the
217015516c77SSepherosa Ziehau 		 * associated mbuf, so don't free it in hn_txdesc_put();
217115516c77SSepherosa Ziehau 		 * only unload it from the DMA map in hn_txdesc_put(),
217215516c77SSepherosa Ziehau 		 * if it was loaded.
217315516c77SSepherosa Ziehau 		 */
217415516c77SSepherosa Ziehau 		txd->m = NULL;
217515516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
217615516c77SSepherosa Ziehau 		KASSERT(freed != 0,
217715516c77SSepherosa Ziehau 		    ("fail to free txd upon send error"));
217815516c77SSepherosa Ziehau 
217915516c77SSepherosa Ziehau 		txr->hn_send_failed++;
218015516c77SSepherosa Ziehau 	}
2181dc13fee6SSepherosa Ziehau 
2182dc13fee6SSepherosa Ziehau 	/* Reset temporary stats, after this sending is done. */
2183dc13fee6SSepherosa Ziehau 	txr->hn_stat_size = 0;
2184dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts = 0;
2185dc13fee6SSepherosa Ziehau 	txr->hn_stat_mcasts = 0;
2186dc13fee6SSepherosa Ziehau 
2187dc13fee6SSepherosa Ziehau 	return (error);
218815516c77SSepherosa Ziehau }
218915516c77SSepherosa Ziehau 
219015516c77SSepherosa Ziehau /*
219115516c77SSepherosa Ziehau  * Append the specified data to the indicated mbuf chain,
219215516c77SSepherosa Ziehau  * Extend the mbuf chain if the new data does not fit in
219315516c77SSepherosa Ziehau  * existing space.
219415516c77SSepherosa Ziehau  *
219515516c77SSepherosa Ziehau  * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c.
219615516c77SSepherosa Ziehau  * There should be an equivalent in the kernel mbuf code,
219715516c77SSepherosa Ziehau  * but there does not appear to be one yet.
219815516c77SSepherosa Ziehau  *
219915516c77SSepherosa Ziehau  * Differs from m_append() in that additional mbufs are
220015516c77SSepherosa Ziehau  * allocated with cluster size MJUMPAGESIZE, and filled
220115516c77SSepherosa Ziehau  * accordingly.
220215516c77SSepherosa Ziehau  *
220315516c77SSepherosa Ziehau  * Return 1 if able to complete the job; otherwise 0.
220415516c77SSepherosa Ziehau  */
220515516c77SSepherosa Ziehau static int
220615516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp)
220715516c77SSepherosa Ziehau {
220815516c77SSepherosa Ziehau 	struct mbuf *m, *n;
220915516c77SSepherosa Ziehau 	int remainder, space;
221015516c77SSepherosa Ziehau 
221115516c77SSepherosa Ziehau 	for (m = m0; m->m_next != NULL; m = m->m_next)
221215516c77SSepherosa Ziehau 		;
221315516c77SSepherosa Ziehau 	remainder = len;
221415516c77SSepherosa Ziehau 	space = M_TRAILINGSPACE(m);
221515516c77SSepherosa Ziehau 	if (space > 0) {
221615516c77SSepherosa Ziehau 		/*
221715516c77SSepherosa Ziehau 		 * Copy into available space.
221815516c77SSepherosa Ziehau 		 */
221915516c77SSepherosa Ziehau 		if (space > remainder)
222015516c77SSepherosa Ziehau 			space = remainder;
222115516c77SSepherosa Ziehau 		bcopy(cp, mtod(m, caddr_t) + m->m_len, space);
222215516c77SSepherosa Ziehau 		m->m_len += space;
222315516c77SSepherosa Ziehau 		cp += space;
222415516c77SSepherosa Ziehau 		remainder -= space;
222515516c77SSepherosa Ziehau 	}
222615516c77SSepherosa Ziehau 	while (remainder > 0) {
222715516c77SSepherosa Ziehau 		/*
222815516c77SSepherosa Ziehau 		 * Allocate a new mbuf; could check space
222915516c77SSepherosa Ziehau 		 * and allocate a cluster instead.
223015516c77SSepherosa Ziehau 		 */
223115516c77SSepherosa Ziehau 		n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE);
223215516c77SSepherosa Ziehau 		if (n == NULL)
223315516c77SSepherosa Ziehau 			break;
223415516c77SSepherosa Ziehau 		n->m_len = min(MJUMPAGESIZE, remainder);
223515516c77SSepherosa Ziehau 		bcopy(cp, mtod(n, caddr_t), n->m_len);
223615516c77SSepherosa Ziehau 		cp += n->m_len;
223715516c77SSepherosa Ziehau 		remainder -= n->m_len;
223815516c77SSepherosa Ziehau 		m->m_next = n;
223915516c77SSepherosa Ziehau 		m = n;
224015516c77SSepherosa Ziehau 	}
224115516c77SSepherosa Ziehau 	if (m0->m_flags & M_PKTHDR)
224215516c77SSepherosa Ziehau 		m0->m_pkthdr.len += len - remainder;
224315516c77SSepherosa Ziehau 
224415516c77SSepherosa Ziehau 	return (remainder == 0);
224515516c77SSepherosa Ziehau }
224615516c77SSepherosa Ziehau 
224715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
224815516c77SSepherosa Ziehau static __inline int
224915516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m)
225015516c77SSepherosa Ziehau {
225115516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
225215516c77SSepherosa Ziehau 	if (hn_lro_mbufq_depth) {
225315516c77SSepherosa Ziehau 		tcp_lro_queue_mbuf(lc, m);
225415516c77SSepherosa Ziehau 		return 0;
225515516c77SSepherosa Ziehau 	}
225615516c77SSepherosa Ziehau #endif
225715516c77SSepherosa Ziehau 	return tcp_lro_rx(lc, m, 0);
225815516c77SSepherosa Ziehau }
225915516c77SSepherosa Ziehau #endif
226015516c77SSepherosa Ziehau 
226115516c77SSepherosa Ziehau static int
226215516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
226315516c77SSepherosa Ziehau     const struct hn_rxinfo *info)
226415516c77SSepherosa Ziehau {
22655bdfd3fdSDexuan Cui 	struct ifnet *ifp;
226615516c77SSepherosa Ziehau 	struct mbuf *m_new;
226715516c77SSepherosa Ziehau 	int size, do_lro = 0, do_csum = 1;
226815516c77SSepherosa Ziehau 	int hash_type;
226915516c77SSepherosa Ziehau 
22705bdfd3fdSDexuan Cui 	/* If the VF is active, inject the packet through the VF */
22715bdfd3fdSDexuan Cui 	ifp = rxr->hn_vf ? rxr->hn_vf : rxr->hn_ifp;
22725bdfd3fdSDexuan Cui 
2273*b3b75d9cSSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
2274*b3b75d9cSSepherosa Ziehau 		/*
2275*b3b75d9cSSepherosa Ziehau 		 * NOTE:
2276*b3b75d9cSSepherosa Ziehau 		 * See the NOTE of hn_rndis_init_fixat().  This
2277*b3b75d9cSSepherosa Ziehau 		 * function can be reached, immediately after the
2278*b3b75d9cSSepherosa Ziehau 		 * RNDIS is initialized but before the ifnet is
2279*b3b75d9cSSepherosa Ziehau 		 * setup on the hn_attach() path; drop the unexpected
2280*b3b75d9cSSepherosa Ziehau 		 * packets.
2281*b3b75d9cSSepherosa Ziehau 		 */
2282*b3b75d9cSSepherosa Ziehau 		return (0);
2283*b3b75d9cSSepherosa Ziehau 	}
2284*b3b75d9cSSepherosa Ziehau 
2285c927d681SDexuan Cui 	if (dlen <= MHLEN) {
228615516c77SSepherosa Ziehau 		m_new = m_gethdr(M_NOWAIT, MT_DATA);
228715516c77SSepherosa Ziehau 		if (m_new == NULL) {
228815516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
228915516c77SSepherosa Ziehau 			return (0);
229015516c77SSepherosa Ziehau 		}
229115516c77SSepherosa Ziehau 		memcpy(mtod(m_new, void *), data, dlen);
229215516c77SSepherosa Ziehau 		m_new->m_pkthdr.len = m_new->m_len = dlen;
229315516c77SSepherosa Ziehau 		rxr->hn_small_pkts++;
229415516c77SSepherosa Ziehau 	} else {
229515516c77SSepherosa Ziehau 		/*
229615516c77SSepherosa Ziehau 		 * Get an mbuf with a cluster.  For packets 2K or less,
229715516c77SSepherosa Ziehau 		 * get a standard 2K cluster.  For anything larger, get a
229815516c77SSepherosa Ziehau 		 * 4K cluster.  Any buffers larger than 4K can cause problems
229915516c77SSepherosa Ziehau 		 * if looped around to the Hyper-V TX channel, so avoid them.
230015516c77SSepherosa Ziehau 		 */
230115516c77SSepherosa Ziehau 		size = MCLBYTES;
230215516c77SSepherosa Ziehau 		if (dlen > MCLBYTES) {
230315516c77SSepherosa Ziehau 			/* 4096 */
230415516c77SSepherosa Ziehau 			size = MJUMPAGESIZE;
230515516c77SSepherosa Ziehau 		}
230615516c77SSepherosa Ziehau 
230715516c77SSepherosa Ziehau 		m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size);
230815516c77SSepherosa Ziehau 		if (m_new == NULL) {
230915516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
231015516c77SSepherosa Ziehau 			return (0);
231115516c77SSepherosa Ziehau 		}
231215516c77SSepherosa Ziehau 
231315516c77SSepherosa Ziehau 		hv_m_append(m_new, dlen, data);
231415516c77SSepherosa Ziehau 	}
231515516c77SSepherosa Ziehau 	m_new->m_pkthdr.rcvif = ifp;
231615516c77SSepherosa Ziehau 
231715516c77SSepherosa Ziehau 	if (__predict_false((ifp->if_capenable & IFCAP_RXCSUM) == 0))
231815516c77SSepherosa Ziehau 		do_csum = 0;
231915516c77SSepherosa Ziehau 
232015516c77SSepherosa Ziehau 	/* receive side checksum offload */
232115516c77SSepherosa Ziehau 	if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) {
232215516c77SSepherosa Ziehau 		/* IP csum offload */
232315516c77SSepherosa Ziehau 		if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) {
232415516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
232515516c77SSepherosa Ziehau 			    (CSUM_IP_CHECKED | CSUM_IP_VALID);
232615516c77SSepherosa Ziehau 			rxr->hn_csum_ip++;
232715516c77SSepherosa Ziehau 		}
232815516c77SSepherosa Ziehau 
232915516c77SSepherosa Ziehau 		/* TCP/UDP csum offload */
233015516c77SSepherosa Ziehau 		if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK |
233115516c77SSepherosa Ziehau 		     NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) {
233215516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
233315516c77SSepherosa Ziehau 			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
233415516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_data = 0xffff;
233515516c77SSepherosa Ziehau 			if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK)
233615516c77SSepherosa Ziehau 				rxr->hn_csum_tcp++;
233715516c77SSepherosa Ziehau 			else
233815516c77SSepherosa Ziehau 				rxr->hn_csum_udp++;
233915516c77SSepherosa Ziehau 		}
234015516c77SSepherosa Ziehau 
234115516c77SSepherosa Ziehau 		/*
234215516c77SSepherosa Ziehau 		 * XXX
234315516c77SSepherosa Ziehau 		 * As of this write (Oct 28th, 2016), host side will turn
234415516c77SSepherosa Ziehau 		 * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so
234515516c77SSepherosa Ziehau 		 * the do_lro setting here is actually _not_ accurate.  We
234615516c77SSepherosa Ziehau 		 * depend on the RSS hash type check to reset do_lro.
234715516c77SSepherosa Ziehau 		 */
234815516c77SSepherosa Ziehau 		if ((info->csum_info &
234915516c77SSepherosa Ziehau 		     (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) ==
235015516c77SSepherosa Ziehau 		    (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK))
235115516c77SSepherosa Ziehau 			do_lro = 1;
235215516c77SSepherosa Ziehau 	} else {
235315516c77SSepherosa Ziehau 		const struct ether_header *eh;
235415516c77SSepherosa Ziehau 		uint16_t etype;
235515516c77SSepherosa Ziehau 		int hoff;
235615516c77SSepherosa Ziehau 
235715516c77SSepherosa Ziehau 		hoff = sizeof(*eh);
235815516c77SSepherosa Ziehau 		if (m_new->m_len < hoff)
235915516c77SSepherosa Ziehau 			goto skip;
236015516c77SSepherosa Ziehau 		eh = mtod(m_new, struct ether_header *);
236115516c77SSepherosa Ziehau 		etype = ntohs(eh->ether_type);
236215516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_VLAN) {
236315516c77SSepherosa Ziehau 			const struct ether_vlan_header *evl;
236415516c77SSepherosa Ziehau 
236515516c77SSepherosa Ziehau 			hoff = sizeof(*evl);
236615516c77SSepherosa Ziehau 			if (m_new->m_len < hoff)
236715516c77SSepherosa Ziehau 				goto skip;
236815516c77SSepherosa Ziehau 			evl = mtod(m_new, struct ether_vlan_header *);
236915516c77SSepherosa Ziehau 			etype = ntohs(evl->evl_proto);
237015516c77SSepherosa Ziehau 		}
237115516c77SSepherosa Ziehau 
237215516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_IP) {
237315516c77SSepherosa Ziehau 			int pr;
237415516c77SSepherosa Ziehau 
237515516c77SSepherosa Ziehau 			pr = hn_check_iplen(m_new, hoff);
237615516c77SSepherosa Ziehau 			if (pr == IPPROTO_TCP) {
237715516c77SSepherosa Ziehau 				if (do_csum &&
237815516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
237915516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_TCP)) {
238015516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
238115516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
238215516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
238315516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
238415516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
238515516c77SSepherosa Ziehau 				}
238615516c77SSepherosa Ziehau 				do_lro = 1;
238715516c77SSepherosa Ziehau 			} else if (pr == IPPROTO_UDP) {
238815516c77SSepherosa Ziehau 				if (do_csum &&
238915516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
239015516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_UDP)) {
239115516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
239215516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
239315516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
239415516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
239515516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
239615516c77SSepherosa Ziehau 				}
239715516c77SSepherosa Ziehau 			} else if (pr != IPPROTO_DONE && do_csum &&
239815516c77SSepherosa Ziehau 			    (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) {
239915516c77SSepherosa Ziehau 				rxr->hn_csum_trusted++;
240015516c77SSepherosa Ziehau 				m_new->m_pkthdr.csum_flags |=
240115516c77SSepherosa Ziehau 				    (CSUM_IP_CHECKED | CSUM_IP_VALID);
240215516c77SSepherosa Ziehau 			}
240315516c77SSepherosa Ziehau 		}
240415516c77SSepherosa Ziehau 	}
240515516c77SSepherosa Ziehau skip:
240615516c77SSepherosa Ziehau 	if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) {
240715516c77SSepherosa Ziehau 		m_new->m_pkthdr.ether_vtag = EVL_MAKETAG(
240815516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_ID(info->vlan_info),
240915516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_PRI(info->vlan_info),
241015516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_CFI(info->vlan_info));
241115516c77SSepherosa Ziehau 		m_new->m_flags |= M_VLANTAG;
241215516c77SSepherosa Ziehau 	}
241315516c77SSepherosa Ziehau 
241415516c77SSepherosa Ziehau 	if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) {
241515516c77SSepherosa Ziehau 		rxr->hn_rss_pkts++;
241615516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = info->hash_value;
241715516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE_HASH;
241815516c77SSepherosa Ziehau 		if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) ==
241915516c77SSepherosa Ziehau 		    NDIS_HASH_FUNCTION_TOEPLITZ) {
242015516c77SSepherosa Ziehau 			uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK);
242115516c77SSepherosa Ziehau 
242215516c77SSepherosa Ziehau 			/*
242315516c77SSepherosa Ziehau 			 * NOTE:
242415516c77SSepherosa Ziehau 			 * do_lro is resetted, if the hash types are not TCP
242515516c77SSepherosa Ziehau 			 * related.  See the comment in the above csum_flags
242615516c77SSepherosa Ziehau 			 * setup section.
242715516c77SSepherosa Ziehau 			 */
242815516c77SSepherosa Ziehau 			switch (type) {
242915516c77SSepherosa Ziehau 			case NDIS_HASH_IPV4:
243015516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV4;
243115516c77SSepherosa Ziehau 				do_lro = 0;
243215516c77SSepherosa Ziehau 				break;
243315516c77SSepherosa Ziehau 
243415516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV4:
243515516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV4;
243615516c77SSepherosa Ziehau 				break;
243715516c77SSepherosa Ziehau 
243815516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6:
243915516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6;
244015516c77SSepherosa Ziehau 				do_lro = 0;
244115516c77SSepherosa Ziehau 				break;
244215516c77SSepherosa Ziehau 
244315516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6_EX:
244415516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6_EX;
244515516c77SSepherosa Ziehau 				do_lro = 0;
244615516c77SSepherosa Ziehau 				break;
244715516c77SSepherosa Ziehau 
244815516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6:
244915516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6;
245015516c77SSepherosa Ziehau 				break;
245115516c77SSepherosa Ziehau 
245215516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6_EX:
245315516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX;
245415516c77SSepherosa Ziehau 				break;
245515516c77SSepherosa Ziehau 			}
245615516c77SSepherosa Ziehau 		}
245715516c77SSepherosa Ziehau 	} else {
245815516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
245915516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE;
246015516c77SSepherosa Ziehau 	}
246115516c77SSepherosa Ziehau 	M_HASHTYPE_SET(m_new, hash_type);
246215516c77SSepherosa Ziehau 
246315516c77SSepherosa Ziehau 	/*
246415516c77SSepherosa Ziehau 	 * Note:  Moved RX completion back to hv_nv_on_receive() so all
246515516c77SSepherosa Ziehau 	 * messages (not just data messages) will trigger a response.
246615516c77SSepherosa Ziehau 	 */
246715516c77SSepherosa Ziehau 
246815516c77SSepherosa Ziehau 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
246915516c77SSepherosa Ziehau 	rxr->hn_pkts++;
247015516c77SSepherosa Ziehau 
247115516c77SSepherosa Ziehau 	if ((ifp->if_capenable & IFCAP_LRO) && do_lro) {
247215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
247315516c77SSepherosa Ziehau 		struct lro_ctrl *lro = &rxr->hn_lro;
247415516c77SSepherosa Ziehau 
247515516c77SSepherosa Ziehau 		if (lro->lro_cnt) {
247615516c77SSepherosa Ziehau 			rxr->hn_lro_tried++;
247715516c77SSepherosa Ziehau 			if (hn_lro_rx(lro, m_new) == 0) {
247815516c77SSepherosa Ziehau 				/* DONE! */
247915516c77SSepherosa Ziehau 				return 0;
248015516c77SSepherosa Ziehau 			}
248115516c77SSepherosa Ziehau 		}
248215516c77SSepherosa Ziehau #endif
248315516c77SSepherosa Ziehau 	}
248415516c77SSepherosa Ziehau 
248515516c77SSepherosa Ziehau 	/* We're not holding the lock here, so don't release it */
248615516c77SSepherosa Ziehau 	(*ifp->if_input)(ifp, m_new);
248715516c77SSepherosa Ziehau 
248815516c77SSepherosa Ziehau 	return (0);
248915516c77SSepherosa Ziehau }
249015516c77SSepherosa Ziehau 
249115516c77SSepherosa Ziehau static int
249215516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
249315516c77SSepherosa Ziehau {
249415516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
249515516c77SSepherosa Ziehau 	struct ifreq *ifr = (struct ifreq *)data;
249615516c77SSepherosa Ziehau 	int mask, error = 0;
249715516c77SSepherosa Ziehau 
249815516c77SSepherosa Ziehau 	switch (cmd) {
249915516c77SSepherosa Ziehau 	case SIOCSIFMTU:
250015516c77SSepherosa Ziehau 		if (ifr->ifr_mtu > HN_MTU_MAX) {
250115516c77SSepherosa Ziehau 			error = EINVAL;
250215516c77SSepherosa Ziehau 			break;
250315516c77SSepherosa Ziehau 		}
250415516c77SSepherosa Ziehau 
250515516c77SSepherosa Ziehau 		HN_LOCK(sc);
250615516c77SSepherosa Ziehau 
250715516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
250815516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
250915516c77SSepherosa Ziehau 			break;
251015516c77SSepherosa Ziehau 		}
251115516c77SSepherosa Ziehau 
251215516c77SSepherosa Ziehau 		if ((sc->hn_caps & HN_CAP_MTU) == 0) {
251315516c77SSepherosa Ziehau 			/* Can't change MTU */
251415516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
251515516c77SSepherosa Ziehau 			error = EOPNOTSUPP;
251615516c77SSepherosa Ziehau 			break;
251715516c77SSepherosa Ziehau 		}
251815516c77SSepherosa Ziehau 
251915516c77SSepherosa Ziehau 		if (ifp->if_mtu == ifr->ifr_mtu) {
252015516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
252115516c77SSepherosa Ziehau 			break;
252215516c77SSepherosa Ziehau 		}
252315516c77SSepherosa Ziehau 
252415516c77SSepherosa Ziehau 		/*
252515516c77SSepherosa Ziehau 		 * Suspend this interface before the synthetic parts
252615516c77SSepherosa Ziehau 		 * are ripped.
252715516c77SSepherosa Ziehau 		 */
252815516c77SSepherosa Ziehau 		hn_suspend(sc);
252915516c77SSepherosa Ziehau 
253015516c77SSepherosa Ziehau 		/*
253115516c77SSepherosa Ziehau 		 * Detach the synthetics parts, i.e. NVS and RNDIS.
253215516c77SSepherosa Ziehau 		 */
253315516c77SSepherosa Ziehau 		hn_synth_detach(sc);
253415516c77SSepherosa Ziehau 
253515516c77SSepherosa Ziehau 		/*
253615516c77SSepherosa Ziehau 		 * Reattach the synthetic parts, i.e. NVS and RNDIS,
253715516c77SSepherosa Ziehau 		 * with the new MTU setting.
253815516c77SSepherosa Ziehau 		 */
253915516c77SSepherosa Ziehau 		error = hn_synth_attach(sc, ifr->ifr_mtu);
254015516c77SSepherosa Ziehau 		if (error) {
254115516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
254215516c77SSepherosa Ziehau 			break;
254315516c77SSepherosa Ziehau 		}
254415516c77SSepherosa Ziehau 
254515516c77SSepherosa Ziehau 		/*
254615516c77SSepherosa Ziehau 		 * Commit the requested MTU, after the synthetic parts
254715516c77SSepherosa Ziehau 		 * have been successfully attached.
254815516c77SSepherosa Ziehau 		 */
254915516c77SSepherosa Ziehau 		ifp->if_mtu = ifr->ifr_mtu;
255015516c77SSepherosa Ziehau 
255115516c77SSepherosa Ziehau 		/*
255215516c77SSepherosa Ziehau 		 * Make sure that various parameters based on MTU are
255315516c77SSepherosa Ziehau 		 * still valid, after the MTU change.
255415516c77SSepherosa Ziehau 		 */
255515516c77SSepherosa Ziehau 		if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax)
255615516c77SSepherosa Ziehau 			hn_set_chim_size(sc, sc->hn_chim_szmax);
255715516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu);
255815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
255915516c77SSepherosa Ziehau 		if (sc->hn_rx_ring[0].hn_lro.lro_length_lim <
256015516c77SSepherosa Ziehau 		    HN_LRO_LENLIM_MIN(ifp))
256115516c77SSepherosa Ziehau 			hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
256215516c77SSepherosa Ziehau #endif
256315516c77SSepherosa Ziehau 
256415516c77SSepherosa Ziehau 		/*
256515516c77SSepherosa Ziehau 		 * All done!  Resume the interface now.
256615516c77SSepherosa Ziehau 		 */
256715516c77SSepherosa Ziehau 		hn_resume(sc);
256815516c77SSepherosa Ziehau 
256915516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
257015516c77SSepherosa Ziehau 		break;
257115516c77SSepherosa Ziehau 
257215516c77SSepherosa Ziehau 	case SIOCSIFFLAGS:
257315516c77SSepherosa Ziehau 		HN_LOCK(sc);
257415516c77SSepherosa Ziehau 
257515516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
257615516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
257715516c77SSepherosa Ziehau 			break;
257815516c77SSepherosa Ziehau 		}
257915516c77SSepherosa Ziehau 
258015516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_UP) {
2581fdc4f478SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2582fdc4f478SSepherosa Ziehau 				/*
2583fdc4f478SSepherosa Ziehau 				 * Caller meight hold mutex, e.g.
2584fdc4f478SSepherosa Ziehau 				 * bpf; use busy-wait for the RNDIS
2585fdc4f478SSepherosa Ziehau 				 * reply.
2586fdc4f478SSepherosa Ziehau 				 */
2587fdc4f478SSepherosa Ziehau 				HN_NO_SLEEPING(sc);
2588c08f7b2cSSepherosa Ziehau 				hn_rxfilter_config(sc);
2589fdc4f478SSepherosa Ziehau 				HN_SLEEPING_OK(sc);
2590fdc4f478SSepherosa Ziehau 			} else {
259115516c77SSepherosa Ziehau 				hn_init_locked(sc);
2592fdc4f478SSepherosa Ziehau 			}
259315516c77SSepherosa Ziehau 		} else {
259415516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
25955bdfd3fdSDexuan Cui 				hn_stop(sc, false);
259615516c77SSepherosa Ziehau 		}
259715516c77SSepherosa Ziehau 		sc->hn_if_flags = ifp->if_flags;
259815516c77SSepherosa Ziehau 
259915516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
260015516c77SSepherosa Ziehau 		break;
260115516c77SSepherosa Ziehau 
260215516c77SSepherosa Ziehau 	case SIOCSIFCAP:
260315516c77SSepherosa Ziehau 		HN_LOCK(sc);
260415516c77SSepherosa Ziehau 		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
260515516c77SSepherosa Ziehau 
260615516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM) {
260715516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM;
260815516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM)
260915516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc);
261015516c77SSepherosa Ziehau 			else
261115516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc);
261215516c77SSepherosa Ziehau 		}
261315516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM_IPV6) {
261415516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
261515516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
261615516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc);
261715516c77SSepherosa Ziehau 			else
261815516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc);
261915516c77SSepherosa Ziehau 		}
262015516c77SSepherosa Ziehau 
262115516c77SSepherosa Ziehau 		/* TODO: flip RNDIS offload parameters for RXCSUM. */
262215516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM)
262315516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM;
262415516c77SSepherosa Ziehau #ifdef foo
262515516c77SSepherosa Ziehau 		/* We can't diff IPv6 packets from IPv4 packets on RX path. */
262615516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM_IPV6)
262715516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
262815516c77SSepherosa Ziehau #endif
262915516c77SSepherosa Ziehau 
263015516c77SSepherosa Ziehau 		if (mask & IFCAP_LRO)
263115516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_LRO;
263215516c77SSepherosa Ziehau 
263315516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO4) {
263415516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO4;
263515516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO4)
263615516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP_TSO;
263715516c77SSepherosa Ziehau 			else
263815516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP_TSO;
263915516c77SSepherosa Ziehau 		}
264015516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO6) {
264115516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO6;
264215516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO6)
264315516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP6_TSO;
264415516c77SSepherosa Ziehau 			else
264515516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP6_TSO;
264615516c77SSepherosa Ziehau 		}
264715516c77SSepherosa Ziehau 
264815516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
264915516c77SSepherosa Ziehau 		break;
265015516c77SSepherosa Ziehau 
265115516c77SSepherosa Ziehau 	case SIOCADDMULTI:
265215516c77SSepherosa Ziehau 	case SIOCDELMULTI:
265315516c77SSepherosa Ziehau 		HN_LOCK(sc);
265415516c77SSepherosa Ziehau 
265515516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
265615516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
265715516c77SSepherosa Ziehau 			break;
265815516c77SSepherosa Ziehau 		}
2659fdc4f478SSepherosa Ziehau 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2660fdc4f478SSepherosa Ziehau 			/*
2661fdc4f478SSepherosa Ziehau 			 * Multicast uses mutex; use busy-wait for
2662fdc4f478SSepherosa Ziehau 			 * the RNDIS reply.
2663fdc4f478SSepherosa Ziehau 			 */
2664fdc4f478SSepherosa Ziehau 			HN_NO_SLEEPING(sc);
2665c08f7b2cSSepherosa Ziehau 			hn_rxfilter_config(sc);
2666fdc4f478SSepherosa Ziehau 			HN_SLEEPING_OK(sc);
2667fdc4f478SSepherosa Ziehau 		}
266815516c77SSepherosa Ziehau 
266915516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
267015516c77SSepherosa Ziehau 		break;
267115516c77SSepherosa Ziehau 
267215516c77SSepherosa Ziehau 	case SIOCSIFMEDIA:
267315516c77SSepherosa Ziehau 	case SIOCGIFMEDIA:
267415516c77SSepherosa Ziehau 		error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd);
267515516c77SSepherosa Ziehau 		break;
267615516c77SSepherosa Ziehau 
267715516c77SSepherosa Ziehau 	default:
267815516c77SSepherosa Ziehau 		error = ether_ioctl(ifp, cmd, data);
267915516c77SSepherosa Ziehau 		break;
268015516c77SSepherosa Ziehau 	}
268115516c77SSepherosa Ziehau 	return (error);
268215516c77SSepherosa Ziehau }
268315516c77SSepherosa Ziehau 
268415516c77SSepherosa Ziehau static void
26855bdfd3fdSDexuan Cui hn_stop(struct hn_softc *sc, bool detaching)
268615516c77SSepherosa Ziehau {
268715516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
268815516c77SSepherosa Ziehau 	int i;
268915516c77SSepherosa Ziehau 
269015516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
269115516c77SSepherosa Ziehau 
269215516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
269315516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
269415516c77SSepherosa Ziehau 
26956c1204dfSSepherosa Ziehau 	/* Disable polling. */
26966c1204dfSSepherosa Ziehau 	hn_polling(sc, 0);
26976c1204dfSSepherosa Ziehau 
269815516c77SSepherosa Ziehau 	/* Clear RUNNING bit _before_ hn_suspend_data() */
269915516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
270015516c77SSepherosa Ziehau 	hn_suspend_data(sc);
270115516c77SSepherosa Ziehau 
270215516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
270315516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
270415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
270515516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
27065bdfd3fdSDexuan Cui 
27075bdfd3fdSDexuan Cui 	/*
27085bdfd3fdSDexuan Cui 	 * If the VF is active, make sure the filter is not 0, even if
27095bdfd3fdSDexuan Cui 	 * the synthetic NIC is down.
27105bdfd3fdSDexuan Cui 	 */
27115bdfd3fdSDexuan Cui 	if (!detaching && (sc->hn_flags & HN_FLAG_VF))
27125bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
271315516c77SSepherosa Ziehau }
271415516c77SSepherosa Ziehau 
271515516c77SSepherosa Ziehau static void
271615516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc)
271715516c77SSepherosa Ziehau {
271815516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
271915516c77SSepherosa Ziehau 	int i;
272015516c77SSepherosa Ziehau 
272115516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
272215516c77SSepherosa Ziehau 
272315516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
272415516c77SSepherosa Ziehau 		return;
272515516c77SSepherosa Ziehau 
272615516c77SSepherosa Ziehau 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
272715516c77SSepherosa Ziehau 		return;
272815516c77SSepherosa Ziehau 
272915516c77SSepherosa Ziehau 	/* Configure RX filter */
2730c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
273115516c77SSepherosa Ziehau 
273215516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
273315516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
273415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
273515516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
273615516c77SSepherosa Ziehau 
273715516c77SSepherosa Ziehau 	/* Clear TX 'suspended' bit. */
273815516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_inuse);
273915516c77SSepherosa Ziehau 
274015516c77SSepherosa Ziehau 	/* Everything is ready; unleash! */
274115516c77SSepherosa Ziehau 	atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
27426c1204dfSSepherosa Ziehau 
27436c1204dfSSepherosa Ziehau 	/* Re-enable polling if requested. */
27446c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz > 0)
27456c1204dfSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
274615516c77SSepherosa Ziehau }
274715516c77SSepherosa Ziehau 
274815516c77SSepherosa Ziehau static void
274915516c77SSepherosa Ziehau hn_init(void *xsc)
275015516c77SSepherosa Ziehau {
275115516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
275215516c77SSepherosa Ziehau 
275315516c77SSepherosa Ziehau 	HN_LOCK(sc);
275415516c77SSepherosa Ziehau 	hn_init_locked(sc);
275515516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
275615516c77SSepherosa Ziehau }
275715516c77SSepherosa Ziehau 
275815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
275915516c77SSepherosa Ziehau 
276015516c77SSepherosa Ziehau static int
276115516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
276215516c77SSepherosa Ziehau {
276315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
276415516c77SSepherosa Ziehau 	unsigned int lenlim;
276515516c77SSepherosa Ziehau 	int error;
276615516c77SSepherosa Ziehau 
276715516c77SSepherosa Ziehau 	lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim;
276815516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &lenlim, 0, req);
276915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
277015516c77SSepherosa Ziehau 		return error;
277115516c77SSepherosa Ziehau 
277215516c77SSepherosa Ziehau 	HN_LOCK(sc);
277315516c77SSepherosa Ziehau 	if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) ||
277415516c77SSepherosa Ziehau 	    lenlim > TCP_LRO_LENGTH_MAX) {
277515516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
277615516c77SSepherosa Ziehau 		return EINVAL;
277715516c77SSepherosa Ziehau 	}
277815516c77SSepherosa Ziehau 	hn_set_lro_lenlim(sc, lenlim);
277915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
278015516c77SSepherosa Ziehau 
278115516c77SSepherosa Ziehau 	return 0;
278215516c77SSepherosa Ziehau }
278315516c77SSepherosa Ziehau 
278415516c77SSepherosa Ziehau static int
278515516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS)
278615516c77SSepherosa Ziehau {
278715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
278815516c77SSepherosa Ziehau 	int ackcnt, error, i;
278915516c77SSepherosa Ziehau 
279015516c77SSepherosa Ziehau 	/*
279115516c77SSepherosa Ziehau 	 * lro_ackcnt_lim is append count limit,
279215516c77SSepherosa Ziehau 	 * +1 to turn it into aggregation limit.
279315516c77SSepherosa Ziehau 	 */
279415516c77SSepherosa Ziehau 	ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1;
279515516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &ackcnt, 0, req);
279615516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
279715516c77SSepherosa Ziehau 		return error;
279815516c77SSepherosa Ziehau 
279915516c77SSepherosa Ziehau 	if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1))
280015516c77SSepherosa Ziehau 		return EINVAL;
280115516c77SSepherosa Ziehau 
280215516c77SSepherosa Ziehau 	/*
280315516c77SSepherosa Ziehau 	 * Convert aggregation limit back to append
280415516c77SSepherosa Ziehau 	 * count limit.
280515516c77SSepherosa Ziehau 	 */
280615516c77SSepherosa Ziehau 	--ackcnt;
280715516c77SSepherosa Ziehau 	HN_LOCK(sc);
2808a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
280915516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt;
281015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
281115516c77SSepherosa Ziehau 	return 0;
281215516c77SSepherosa Ziehau }
281315516c77SSepherosa Ziehau 
281415516c77SSepherosa Ziehau #endif
281515516c77SSepherosa Ziehau 
281615516c77SSepherosa Ziehau static int
281715516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS)
281815516c77SSepherosa Ziehau {
281915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
282015516c77SSepherosa Ziehau 	int hcsum = arg2;
282115516c77SSepherosa Ziehau 	int on, error, i;
282215516c77SSepherosa Ziehau 
282315516c77SSepherosa Ziehau 	on = 0;
282415516c77SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum)
282515516c77SSepherosa Ziehau 		on = 1;
282615516c77SSepherosa Ziehau 
282715516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &on, 0, req);
282815516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
282915516c77SSepherosa Ziehau 		return error;
283015516c77SSepherosa Ziehau 
283115516c77SSepherosa Ziehau 	HN_LOCK(sc);
2832a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
283315516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
283415516c77SSepherosa Ziehau 
283515516c77SSepherosa Ziehau 		if (on)
283615516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= hcsum;
283715516c77SSepherosa Ziehau 		else
283815516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum &= ~hcsum;
283915516c77SSepherosa Ziehau 	}
284015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
284115516c77SSepherosa Ziehau 	return 0;
284215516c77SSepherosa Ziehau }
284315516c77SSepherosa Ziehau 
284415516c77SSepherosa Ziehau static int
284515516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS)
284615516c77SSepherosa Ziehau {
284715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
284815516c77SSepherosa Ziehau 	int chim_size, error;
284915516c77SSepherosa Ziehau 
285015516c77SSepherosa Ziehau 	chim_size = sc->hn_tx_ring[0].hn_chim_size;
285115516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &chim_size, 0, req);
285215516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
285315516c77SSepherosa Ziehau 		return error;
285415516c77SSepherosa Ziehau 
285515516c77SSepherosa Ziehau 	if (chim_size > sc->hn_chim_szmax || chim_size <= 0)
285615516c77SSepherosa Ziehau 		return EINVAL;
285715516c77SSepherosa Ziehau 
285815516c77SSepherosa Ziehau 	HN_LOCK(sc);
285915516c77SSepherosa Ziehau 	hn_set_chim_size(sc, chim_size);
286015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
286115516c77SSepherosa Ziehau 	return 0;
286215516c77SSepherosa Ziehau }
286315516c77SSepherosa Ziehau 
286415516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
286515516c77SSepherosa Ziehau static int
286615516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS)
286715516c77SSepherosa Ziehau {
286815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
286915516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
287015516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
287115516c77SSepherosa Ziehau 	uint64_t stat;
287215516c77SSepherosa Ziehau 
287315516c77SSepherosa Ziehau 	stat = 0;
287415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
287515516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
287615516c77SSepherosa Ziehau 		stat += *((int *)((uint8_t *)rxr + ofs));
287715516c77SSepherosa Ziehau 	}
287815516c77SSepherosa Ziehau 
287915516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
288015516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
288115516c77SSepherosa Ziehau 		return error;
288215516c77SSepherosa Ziehau 
288315516c77SSepherosa Ziehau 	/* Zero out this stat. */
288415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
288515516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
288615516c77SSepherosa Ziehau 		*((int *)((uint8_t *)rxr + ofs)) = 0;
288715516c77SSepherosa Ziehau 	}
288815516c77SSepherosa Ziehau 	return 0;
288915516c77SSepherosa Ziehau }
289015516c77SSepherosa Ziehau #else
289115516c77SSepherosa Ziehau static int
289215516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS)
289315516c77SSepherosa Ziehau {
289415516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
289515516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
289615516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
289715516c77SSepherosa Ziehau 	uint64_t stat;
289815516c77SSepherosa Ziehau 
289915516c77SSepherosa Ziehau 	stat = 0;
2900a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
290115516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
290215516c77SSepherosa Ziehau 		stat += *((uint64_t *)((uint8_t *)rxr + ofs));
290315516c77SSepherosa Ziehau 	}
290415516c77SSepherosa Ziehau 
290515516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
290615516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
290715516c77SSepherosa Ziehau 		return error;
290815516c77SSepherosa Ziehau 
290915516c77SSepherosa Ziehau 	/* Zero out this stat. */
2910a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
291115516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
291215516c77SSepherosa Ziehau 		*((uint64_t *)((uint8_t *)rxr + ofs)) = 0;
291315516c77SSepherosa Ziehau 	}
291415516c77SSepherosa Ziehau 	return 0;
291515516c77SSepherosa Ziehau }
291615516c77SSepherosa Ziehau 
291715516c77SSepherosa Ziehau #endif
291815516c77SSepherosa Ziehau 
291915516c77SSepherosa Ziehau static int
292015516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
292115516c77SSepherosa Ziehau {
292215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
292315516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
292415516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
292515516c77SSepherosa Ziehau 	u_long stat;
292615516c77SSepherosa Ziehau 
292715516c77SSepherosa Ziehau 	stat = 0;
2928a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
292915516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
293015516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)rxr + ofs));
293115516c77SSepherosa Ziehau 	}
293215516c77SSepherosa Ziehau 
293315516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
293415516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
293515516c77SSepherosa Ziehau 		return error;
293615516c77SSepherosa Ziehau 
293715516c77SSepherosa Ziehau 	/* Zero out this stat. */
2938a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
293915516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
294015516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)rxr + ofs)) = 0;
294115516c77SSepherosa Ziehau 	}
294215516c77SSepherosa Ziehau 	return 0;
294315516c77SSepherosa Ziehau }
294415516c77SSepherosa Ziehau 
294515516c77SSepherosa Ziehau static int
294615516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
294715516c77SSepherosa Ziehau {
294815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
294915516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
295015516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
295115516c77SSepherosa Ziehau 	u_long stat;
295215516c77SSepherosa Ziehau 
295315516c77SSepherosa Ziehau 	stat = 0;
2954a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
295515516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
295615516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)txr + ofs));
295715516c77SSepherosa Ziehau 	}
295815516c77SSepherosa Ziehau 
295915516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
296015516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
296115516c77SSepherosa Ziehau 		return error;
296215516c77SSepherosa Ziehau 
296315516c77SSepherosa Ziehau 	/* Zero out this stat. */
2964a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
296515516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
296615516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)txr + ofs)) = 0;
296715516c77SSepherosa Ziehau 	}
296815516c77SSepherosa Ziehau 	return 0;
296915516c77SSepherosa Ziehau }
297015516c77SSepherosa Ziehau 
297115516c77SSepherosa Ziehau static int
297215516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS)
297315516c77SSepherosa Ziehau {
297415516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
297515516c77SSepherosa Ziehau 	int ofs = arg2, i, error, conf;
297615516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
297715516c77SSepherosa Ziehau 
297815516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[0];
297915516c77SSepherosa Ziehau 	conf = *((int *)((uint8_t *)txr + ofs));
298015516c77SSepherosa Ziehau 
298115516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &conf, 0, req);
298215516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
298315516c77SSepherosa Ziehau 		return error;
298415516c77SSepherosa Ziehau 
298515516c77SSepherosa Ziehau 	HN_LOCK(sc);
2986a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
298715516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
298815516c77SSepherosa Ziehau 		*((int *)((uint8_t *)txr + ofs)) = conf;
298915516c77SSepherosa Ziehau 	}
299015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
299115516c77SSepherosa Ziehau 
299215516c77SSepherosa Ziehau 	return 0;
299315516c77SSepherosa Ziehau }
299415516c77SSepherosa Ziehau 
299515516c77SSepherosa Ziehau static int
2996dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS)
2997dc13fee6SSepherosa Ziehau {
2998dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2999dc13fee6SSepherosa Ziehau 	int error, size;
3000dc13fee6SSepherosa Ziehau 
3001dc13fee6SSepherosa Ziehau 	size = sc->hn_agg_size;
3002dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &size, 0, req);
3003dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
3004dc13fee6SSepherosa Ziehau 		return (error);
3005dc13fee6SSepherosa Ziehau 
3006dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
3007dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = size;
3008dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
3009dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
3010dc13fee6SSepherosa Ziehau 
3011dc13fee6SSepherosa Ziehau 	return (0);
3012dc13fee6SSepherosa Ziehau }
3013dc13fee6SSepherosa Ziehau 
3014dc13fee6SSepherosa Ziehau static int
3015dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS)
3016dc13fee6SSepherosa Ziehau {
3017dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
3018dc13fee6SSepherosa Ziehau 	int error, pkts;
3019dc13fee6SSepherosa Ziehau 
3020dc13fee6SSepherosa Ziehau 	pkts = sc->hn_agg_pkts;
3021dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pkts, 0, req);
3022dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
3023dc13fee6SSepherosa Ziehau 		return (error);
3024dc13fee6SSepherosa Ziehau 
3025dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
3026dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = pkts;
3027dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
3028dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
3029dc13fee6SSepherosa Ziehau 
3030dc13fee6SSepherosa Ziehau 	return (0);
3031dc13fee6SSepherosa Ziehau }
3032dc13fee6SSepherosa Ziehau 
3033dc13fee6SSepherosa Ziehau static int
3034dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS)
3035dc13fee6SSepherosa Ziehau {
3036dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
3037dc13fee6SSepherosa Ziehau 	int pkts;
3038dc13fee6SSepherosa Ziehau 
3039dc13fee6SSepherosa Ziehau 	pkts = sc->hn_tx_ring[0].hn_agg_pktmax;
3040dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &pkts, 0, req));
3041dc13fee6SSepherosa Ziehau }
3042dc13fee6SSepherosa Ziehau 
3043dc13fee6SSepherosa Ziehau static int
3044dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS)
3045dc13fee6SSepherosa Ziehau {
3046dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
3047dc13fee6SSepherosa Ziehau 	int align;
3048dc13fee6SSepherosa Ziehau 
3049dc13fee6SSepherosa Ziehau 	align = sc->hn_tx_ring[0].hn_agg_align;
3050dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &align, 0, req));
3051dc13fee6SSepherosa Ziehau }
3052dc13fee6SSepherosa Ziehau 
30536c1204dfSSepherosa Ziehau static void
30546c1204dfSSepherosa Ziehau hn_chan_polling(struct vmbus_channel *chan, u_int pollhz)
30556c1204dfSSepherosa Ziehau {
30566c1204dfSSepherosa Ziehau 	if (pollhz == 0)
30576c1204dfSSepherosa Ziehau 		vmbus_chan_poll_disable(chan);
30586c1204dfSSepherosa Ziehau 	else
30596c1204dfSSepherosa Ziehau 		vmbus_chan_poll_enable(chan, pollhz);
30606c1204dfSSepherosa Ziehau }
30616c1204dfSSepherosa Ziehau 
30626c1204dfSSepherosa Ziehau static void
30636c1204dfSSepherosa Ziehau hn_polling(struct hn_softc *sc, u_int pollhz)
30646c1204dfSSepherosa Ziehau {
30656c1204dfSSepherosa Ziehau 	int nsubch = sc->hn_rx_ring_inuse - 1;
30666c1204dfSSepherosa Ziehau 
30676c1204dfSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
30686c1204dfSSepherosa Ziehau 
30696c1204dfSSepherosa Ziehau 	if (nsubch > 0) {
30706c1204dfSSepherosa Ziehau 		struct vmbus_channel **subch;
30716c1204dfSSepherosa Ziehau 		int i;
30726c1204dfSSepherosa Ziehau 
30736c1204dfSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
30746c1204dfSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
30756c1204dfSSepherosa Ziehau 			hn_chan_polling(subch[i], pollhz);
30766c1204dfSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
30776c1204dfSSepherosa Ziehau 	}
30786c1204dfSSepherosa Ziehau 	hn_chan_polling(sc->hn_prichan, pollhz);
30796c1204dfSSepherosa Ziehau }
30806c1204dfSSepherosa Ziehau 
30816c1204dfSSepherosa Ziehau static int
30826c1204dfSSepherosa Ziehau hn_polling_sysctl(SYSCTL_HANDLER_ARGS)
30836c1204dfSSepherosa Ziehau {
30846c1204dfSSepherosa Ziehau 	struct hn_softc *sc = arg1;
30856c1204dfSSepherosa Ziehau 	int pollhz, error;
30866c1204dfSSepherosa Ziehau 
30876c1204dfSSepherosa Ziehau 	pollhz = sc->hn_pollhz;
30886c1204dfSSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pollhz, 0, req);
30896c1204dfSSepherosa Ziehau 	if (error || req->newptr == NULL)
30906c1204dfSSepherosa Ziehau 		return (error);
30916c1204dfSSepherosa Ziehau 
30926c1204dfSSepherosa Ziehau 	if (pollhz != 0 &&
30936c1204dfSSepherosa Ziehau 	    (pollhz < VMBUS_CHAN_POLLHZ_MIN || pollhz > VMBUS_CHAN_POLLHZ_MAX))
30946c1204dfSSepherosa Ziehau 		return (EINVAL);
30956c1204dfSSepherosa Ziehau 
30966c1204dfSSepherosa Ziehau 	HN_LOCK(sc);
30976c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz != pollhz) {
30986c1204dfSSepherosa Ziehau 		sc->hn_pollhz = pollhz;
30996c1204dfSSepherosa Ziehau 		if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) &&
31006c1204dfSSepherosa Ziehau 		    (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
31016c1204dfSSepherosa Ziehau 			hn_polling(sc, sc->hn_pollhz);
31026c1204dfSSepherosa Ziehau 	}
31036c1204dfSSepherosa Ziehau 	HN_UNLOCK(sc);
31046c1204dfSSepherosa Ziehau 
31056c1204dfSSepherosa Ziehau 	return (0);
31066c1204dfSSepherosa Ziehau }
31076c1204dfSSepherosa Ziehau 
3108dc13fee6SSepherosa Ziehau static int
310915516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS)
311015516c77SSepherosa Ziehau {
311115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
311215516c77SSepherosa Ziehau 	char verstr[16];
311315516c77SSepherosa Ziehau 
311415516c77SSepherosa Ziehau 	snprintf(verstr, sizeof(verstr), "%u.%u",
311515516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
311615516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
311715516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
311815516c77SSepherosa Ziehau }
311915516c77SSepherosa Ziehau 
312015516c77SSepherosa Ziehau static int
312115516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS)
312215516c77SSepherosa Ziehau {
312315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
312415516c77SSepherosa Ziehau 	char caps_str[128];
312515516c77SSepherosa Ziehau 	uint32_t caps;
312615516c77SSepherosa Ziehau 
312715516c77SSepherosa Ziehau 	HN_LOCK(sc);
312815516c77SSepherosa Ziehau 	caps = sc->hn_caps;
312915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
313015516c77SSepherosa Ziehau 	snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS);
313115516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req);
313215516c77SSepherosa Ziehau }
313315516c77SSepherosa Ziehau 
313415516c77SSepherosa Ziehau static int
313515516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS)
313615516c77SSepherosa Ziehau {
313715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
313815516c77SSepherosa Ziehau 	char assist_str[128];
313915516c77SSepherosa Ziehau 	uint32_t hwassist;
314015516c77SSepherosa Ziehau 
314115516c77SSepherosa Ziehau 	HN_LOCK(sc);
314215516c77SSepherosa Ziehau 	hwassist = sc->hn_ifp->if_hwassist;
314315516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
314415516c77SSepherosa Ziehau 	snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS);
314515516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req);
314615516c77SSepherosa Ziehau }
314715516c77SSepherosa Ziehau 
314815516c77SSepherosa Ziehau static int
314915516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS)
315015516c77SSepherosa Ziehau {
315115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
315215516c77SSepherosa Ziehau 	char filter_str[128];
315315516c77SSepherosa Ziehau 	uint32_t filter;
315415516c77SSepherosa Ziehau 
315515516c77SSepherosa Ziehau 	HN_LOCK(sc);
315615516c77SSepherosa Ziehau 	filter = sc->hn_rx_filter;
315715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
315815516c77SSepherosa Ziehau 	snprintf(filter_str, sizeof(filter_str), "%b", filter,
315915516c77SSepherosa Ziehau 	    NDIS_PACKET_TYPES);
316015516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req);
316115516c77SSepherosa Ziehau }
316215516c77SSepherosa Ziehau 
316334d68912SSepherosa Ziehau #ifndef RSS
316434d68912SSepherosa Ziehau 
316515516c77SSepherosa Ziehau static int
316615516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
316715516c77SSepherosa Ziehau {
316815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
316915516c77SSepherosa Ziehau 	int error;
317015516c77SSepherosa Ziehau 
317115516c77SSepherosa Ziehau 	HN_LOCK(sc);
317215516c77SSepherosa Ziehau 
317315516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
317415516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
317515516c77SSepherosa Ziehau 		goto back;
317615516c77SSepherosa Ziehau 
317715516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
317815516c77SSepherosa Ziehau 	if (error)
317915516c77SSepherosa Ziehau 		goto back;
318015516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
318115516c77SSepherosa Ziehau 
318215516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
318315516c77SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
318415516c77SSepherosa Ziehau 	} else {
318515516c77SSepherosa Ziehau 		/* Not RSS capable, at least for now; just save the RSS key. */
318615516c77SSepherosa Ziehau 		error = 0;
318715516c77SSepherosa Ziehau 	}
318815516c77SSepherosa Ziehau back:
318915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
319015516c77SSepherosa Ziehau 	return (error);
319115516c77SSepherosa Ziehau }
319215516c77SSepherosa Ziehau 
319315516c77SSepherosa Ziehau static int
319415516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS)
319515516c77SSepherosa Ziehau {
319615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
319715516c77SSepherosa Ziehau 	int error;
319815516c77SSepherosa Ziehau 
319915516c77SSepherosa Ziehau 	HN_LOCK(sc);
320015516c77SSepherosa Ziehau 
320115516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
320215516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
320315516c77SSepherosa Ziehau 		goto back;
320415516c77SSepherosa Ziehau 
320515516c77SSepherosa Ziehau 	/*
320615516c77SSepherosa Ziehau 	 * Don't allow RSS indirect table change, if this interface is not
320715516c77SSepherosa Ziehau 	 * RSS capable currently.
320815516c77SSepherosa Ziehau 	 */
320915516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
321015516c77SSepherosa Ziehau 		error = EOPNOTSUPP;
321115516c77SSepherosa Ziehau 		goto back;
321215516c77SSepherosa Ziehau 	}
321315516c77SSepherosa Ziehau 
321415516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
321515516c77SSepherosa Ziehau 	if (error)
321615516c77SSepherosa Ziehau 		goto back;
321715516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSIND;
321815516c77SSepherosa Ziehau 
3219afd4971bSSepherosa Ziehau 	hn_rss_ind_fixup(sc);
322015516c77SSepherosa Ziehau 	error = hn_rss_reconfig(sc);
322115516c77SSepherosa Ziehau back:
322215516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
322315516c77SSepherosa Ziehau 	return (error);
322415516c77SSepherosa Ziehau }
322515516c77SSepherosa Ziehau 
322634d68912SSepherosa Ziehau #endif	/* !RSS */
322734d68912SSepherosa Ziehau 
322815516c77SSepherosa Ziehau static int
322915516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS)
323015516c77SSepherosa Ziehau {
323115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
323215516c77SSepherosa Ziehau 	char hash_str[128];
323315516c77SSepherosa Ziehau 	uint32_t hash;
323415516c77SSepherosa Ziehau 
323515516c77SSepherosa Ziehau 	HN_LOCK(sc);
323615516c77SSepherosa Ziehau 	hash = sc->hn_rss_hash;
323715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
323815516c77SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
323915516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
324015516c77SSepherosa Ziehau }
324115516c77SSepherosa Ziehau 
324215516c77SSepherosa Ziehau static int
324340d60d6eSDexuan Cui hn_vf_sysctl(SYSCTL_HANDLER_ARGS)
324440d60d6eSDexuan Cui {
324540d60d6eSDexuan Cui 	struct hn_softc *sc = arg1;
324640d60d6eSDexuan Cui 	char vf_name[128];
324740d60d6eSDexuan Cui 	struct ifnet *vf;
324840d60d6eSDexuan Cui 
324940d60d6eSDexuan Cui 	HN_LOCK(sc);
325040d60d6eSDexuan Cui 	vf_name[0] = '\0';
325140d60d6eSDexuan Cui 	vf = sc->hn_rx_ring[0].hn_vf;
325240d60d6eSDexuan Cui 	if (vf != NULL)
325340d60d6eSDexuan Cui 		snprintf(vf_name, sizeof(vf_name), "%s", if_name(vf));
325440d60d6eSDexuan Cui 	HN_UNLOCK(sc);
325540d60d6eSDexuan Cui 	return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req);
325640d60d6eSDexuan Cui }
325740d60d6eSDexuan Cui 
325840d60d6eSDexuan Cui static int
325915516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff)
326015516c77SSepherosa Ziehau {
326115516c77SSepherosa Ziehau 	const struct ip *ip;
326215516c77SSepherosa Ziehau 	int len, iphlen, iplen;
326315516c77SSepherosa Ziehau 	const struct tcphdr *th;
326415516c77SSepherosa Ziehau 	int thoff;				/* TCP data offset */
326515516c77SSepherosa Ziehau 
326615516c77SSepherosa Ziehau 	len = hoff + sizeof(struct ip);
326715516c77SSepherosa Ziehau 
326815516c77SSepherosa Ziehau 	/* The packet must be at least the size of an IP header. */
326915516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < len)
327015516c77SSepherosa Ziehau 		return IPPROTO_DONE;
327115516c77SSepherosa Ziehau 
327215516c77SSepherosa Ziehau 	/* The fixed IP header must reside completely in the first mbuf. */
327315516c77SSepherosa Ziehau 	if (m->m_len < len)
327415516c77SSepherosa Ziehau 		return IPPROTO_DONE;
327515516c77SSepherosa Ziehau 
327615516c77SSepherosa Ziehau 	ip = mtodo(m, hoff);
327715516c77SSepherosa Ziehau 
327815516c77SSepherosa Ziehau 	/* Bound check the packet's stated IP header length. */
327915516c77SSepherosa Ziehau 	iphlen = ip->ip_hl << 2;
328015516c77SSepherosa Ziehau 	if (iphlen < sizeof(struct ip))		/* minimum header length */
328115516c77SSepherosa Ziehau 		return IPPROTO_DONE;
328215516c77SSepherosa Ziehau 
328315516c77SSepherosa Ziehau 	/* The full IP header must reside completely in the one mbuf. */
328415516c77SSepherosa Ziehau 	if (m->m_len < hoff + iphlen)
328515516c77SSepherosa Ziehau 		return IPPROTO_DONE;
328615516c77SSepherosa Ziehau 
328715516c77SSepherosa Ziehau 	iplen = ntohs(ip->ip_len);
328815516c77SSepherosa Ziehau 
328915516c77SSepherosa Ziehau 	/*
329015516c77SSepherosa Ziehau 	 * Check that the amount of data in the buffers is as
329115516c77SSepherosa Ziehau 	 * at least much as the IP header would have us expect.
329215516c77SSepherosa Ziehau 	 */
329315516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < hoff + iplen)
329415516c77SSepherosa Ziehau 		return IPPROTO_DONE;
329515516c77SSepherosa Ziehau 
329615516c77SSepherosa Ziehau 	/*
329715516c77SSepherosa Ziehau 	 * Ignore IP fragments.
329815516c77SSepherosa Ziehau 	 */
329915516c77SSepherosa Ziehau 	if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF))
330015516c77SSepherosa Ziehau 		return IPPROTO_DONE;
330115516c77SSepherosa Ziehau 
330215516c77SSepherosa Ziehau 	/*
330315516c77SSepherosa Ziehau 	 * The TCP/IP or UDP/IP header must be entirely contained within
330415516c77SSepherosa Ziehau 	 * the first fragment of a packet.
330515516c77SSepherosa Ziehau 	 */
330615516c77SSepherosa Ziehau 	switch (ip->ip_p) {
330715516c77SSepherosa Ziehau 	case IPPROTO_TCP:
330815516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct tcphdr))
330915516c77SSepherosa Ziehau 			return IPPROTO_DONE;
331015516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct tcphdr))
331115516c77SSepherosa Ziehau 			return IPPROTO_DONE;
331215516c77SSepherosa Ziehau 		th = (const struct tcphdr *)((const uint8_t *)ip + iphlen);
331315516c77SSepherosa Ziehau 		thoff = th->th_off << 2;
331415516c77SSepherosa Ziehau 		if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen)
331515516c77SSepherosa Ziehau 			return IPPROTO_DONE;
331615516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + thoff)
331715516c77SSepherosa Ziehau 			return IPPROTO_DONE;
331815516c77SSepherosa Ziehau 		break;
331915516c77SSepherosa Ziehau 	case IPPROTO_UDP:
332015516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct udphdr))
332115516c77SSepherosa Ziehau 			return IPPROTO_DONE;
332215516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct udphdr))
332315516c77SSepherosa Ziehau 			return IPPROTO_DONE;
332415516c77SSepherosa Ziehau 		break;
332515516c77SSepherosa Ziehau 	default:
332615516c77SSepherosa Ziehau 		if (iplen < iphlen)
332715516c77SSepherosa Ziehau 			return IPPROTO_DONE;
332815516c77SSepherosa Ziehau 		break;
332915516c77SSepherosa Ziehau 	}
333015516c77SSepherosa Ziehau 	return ip->ip_p;
333115516c77SSepherosa Ziehau }
333215516c77SSepherosa Ziehau 
333315516c77SSepherosa Ziehau static int
333415516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt)
333515516c77SSepherosa Ziehau {
333615516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
333715516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
333815516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
333915516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
334015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
334115516c77SSepherosa Ziehau 	int lroent_cnt;
334215516c77SSepherosa Ziehau #endif
334315516c77SSepherosa Ziehau #endif
334415516c77SSepherosa Ziehau 	int i;
334515516c77SSepherosa Ziehau 
334615516c77SSepherosa Ziehau 	/*
334715516c77SSepherosa Ziehau 	 * Create RXBUF for reception.
334815516c77SSepherosa Ziehau 	 *
334915516c77SSepherosa Ziehau 	 * NOTE:
335015516c77SSepherosa Ziehau 	 * - It is shared by all channels.
335115516c77SSepherosa Ziehau 	 * - A large enough buffer is allocated, certain version of NVSes
335215516c77SSepherosa Ziehau 	 *   may further limit the usable space.
335315516c77SSepherosa Ziehau 	 */
335415516c77SSepherosa Ziehau 	sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
335515516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma,
335615516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
335715516c77SSepherosa Ziehau 	if (sc->hn_rxbuf == NULL) {
335815516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate rxbuf failed\n");
335915516c77SSepherosa Ziehau 		return (ENOMEM);
336015516c77SSepherosa Ziehau 	}
336115516c77SSepherosa Ziehau 
336215516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = ring_cnt;
336315516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt;
336415516c77SSepherosa Ziehau 
336515516c77SSepherosa Ziehau 	sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt,
336615516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
336715516c77SSepherosa Ziehau 
336815516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
336915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
337015516c77SSepherosa Ziehau 	lroent_cnt = hn_lro_entry_count;
337115516c77SSepherosa Ziehau 	if (lroent_cnt < TCP_LRO_ENTRIES)
337215516c77SSepherosa Ziehau 		lroent_cnt = TCP_LRO_ENTRIES;
337315516c77SSepherosa Ziehau 	if (bootverbose)
337415516c77SSepherosa Ziehau 		device_printf(dev, "LRO: entry count %d\n", lroent_cnt);
337515516c77SSepherosa Ziehau #endif
337615516c77SSepherosa Ziehau #endif	/* INET || INET6 */
337715516c77SSepherosa Ziehau 
337815516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
337915516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
338015516c77SSepherosa Ziehau 
338115516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.rx sysctl tree */
338215516c77SSepherosa Ziehau 	sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx",
338315516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
338415516c77SSepherosa Ziehau 
338515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
338615516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
338715516c77SSepherosa Ziehau 
338815516c77SSepherosa Ziehau 		rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
338915516c77SSepherosa Ziehau 		    PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE,
339015516c77SSepherosa Ziehau 		    &rxr->hn_br_dma, BUS_DMA_WAITOK);
339115516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL) {
339215516c77SSepherosa Ziehau 			device_printf(dev, "allocate bufring failed\n");
339315516c77SSepherosa Ziehau 			return (ENOMEM);
339415516c77SSepherosa Ziehau 		}
339515516c77SSepherosa Ziehau 
339615516c77SSepherosa Ziehau 		if (hn_trust_hosttcp)
339715516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP;
339815516c77SSepherosa Ziehau 		if (hn_trust_hostudp)
339915516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP;
340015516c77SSepherosa Ziehau 		if (hn_trust_hostip)
340115516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP;
340215516c77SSepherosa Ziehau 		rxr->hn_ifp = sc->hn_ifp;
340315516c77SSepherosa Ziehau 		if (i < sc->hn_tx_ring_cnt)
340415516c77SSepherosa Ziehau 			rxr->hn_txr = &sc->hn_tx_ring[i];
340515516c77SSepherosa Ziehau 		rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF;
340615516c77SSepherosa Ziehau 		rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK);
340715516c77SSepherosa Ziehau 		rxr->hn_rx_idx = i;
340815516c77SSepherosa Ziehau 		rxr->hn_rxbuf = sc->hn_rxbuf;
340915516c77SSepherosa Ziehau 
341015516c77SSepherosa Ziehau 		/*
341115516c77SSepherosa Ziehau 		 * Initialize LRO.
341215516c77SSepherosa Ziehau 		 */
341315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
341415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
341515516c77SSepherosa Ziehau 		tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt,
341615516c77SSepherosa Ziehau 		    hn_lro_mbufq_depth);
341715516c77SSepherosa Ziehau #else
341815516c77SSepherosa Ziehau 		tcp_lro_init(&rxr->hn_lro);
341915516c77SSepherosa Ziehau 		rxr->hn_lro.ifp = sc->hn_ifp;
342015516c77SSepherosa Ziehau #endif
342115516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
342215516c77SSepherosa Ziehau 		rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF;
342315516c77SSepherosa Ziehau 		rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF;
342415516c77SSepherosa Ziehau #endif
342515516c77SSepherosa Ziehau #endif	/* INET || INET6 */
342615516c77SSepherosa Ziehau 
342715516c77SSepherosa Ziehau 		if (sc->hn_rx_sysctl_tree != NULL) {
342815516c77SSepherosa Ziehau 			char name[16];
342915516c77SSepherosa Ziehau 
343015516c77SSepherosa Ziehau 			/*
343115516c77SSepherosa Ziehau 			 * Create per RX ring sysctl tree:
343215516c77SSepherosa Ziehau 			 * dev.hn.UNIT.rx.RINGID
343315516c77SSepherosa Ziehau 			 */
343415516c77SSepherosa Ziehau 			snprintf(name, sizeof(name), "%d", i);
343515516c77SSepherosa Ziehau 			rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx,
343615516c77SSepherosa Ziehau 			    SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree),
343715516c77SSepherosa Ziehau 			    OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
343815516c77SSepherosa Ziehau 
343915516c77SSepherosa Ziehau 			if (rxr->hn_rx_sysctl_tree != NULL) {
344015516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
344115516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
344215516c77SSepherosa Ziehau 				    OID_AUTO, "packets", CTLFLAG_RW,
344315516c77SSepherosa Ziehau 				    &rxr->hn_pkts, "# of packets received");
344415516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
344515516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
344615516c77SSepherosa Ziehau 				    OID_AUTO, "rss_pkts", CTLFLAG_RW,
344715516c77SSepherosa Ziehau 				    &rxr->hn_rss_pkts,
344815516c77SSepherosa Ziehau 				    "# of packets w/ RSS info received");
344915516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx,
345015516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
345115516c77SSepherosa Ziehau 				    OID_AUTO, "pktbuf_len", CTLFLAG_RD,
345215516c77SSepherosa Ziehau 				    &rxr->hn_pktbuf_len, 0,
345315516c77SSepherosa Ziehau 				    "Temporary channel packet buffer length");
345415516c77SSepherosa Ziehau 			}
345515516c77SSepherosa Ziehau 		}
345615516c77SSepherosa Ziehau 	}
345715516c77SSepherosa Ziehau 
345815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued",
345915516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
346015516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_queued),
346115516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
346215516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
346315516c77SSepherosa Ziehau #else
346415516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
346515516c77SSepherosa Ziehau #endif
346615516c77SSepherosa Ziehau 	    "LU", "LRO queued");
346715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed",
346815516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
346915516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_flushed),
347015516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
347115516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
347215516c77SSepherosa Ziehau #else
347315516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
347415516c77SSepherosa Ziehau #endif
347515516c77SSepherosa Ziehau 	    "LU", "LRO flushed");
347615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried",
347715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
347815516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro_tried),
347915516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries");
348015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
348115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim",
348215516c77SSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
348315516c77SSepherosa Ziehau 	    hn_lro_lenlim_sysctl, "IU",
348415516c77SSepherosa Ziehau 	    "Max # of data bytes to be aggregated by LRO");
348515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim",
348615516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
348715516c77SSepherosa Ziehau 	    hn_lro_ackcnt_sysctl, "I",
348815516c77SSepherosa Ziehau 	    "Max # of ACKs to be aggregated by LRO");
348915516c77SSepherosa Ziehau #endif
349015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp",
349115516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP,
349215516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
349315516c77SSepherosa Ziehau 	    "Trust tcp segement verification on host side, "
349415516c77SSepherosa Ziehau 	    "when csum info is missing");
349515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp",
349615516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP,
349715516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
349815516c77SSepherosa Ziehau 	    "Trust udp datagram verification on host side, "
349915516c77SSepherosa Ziehau 	    "when csum info is missing");
350015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip",
350115516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP,
350215516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
350315516c77SSepherosa Ziehau 	    "Trust ip packet verification on host side, "
350415516c77SSepherosa Ziehau 	    "when csum info is missing");
350515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip",
350615516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
350715516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_ip),
350815516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP");
350915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp",
351015516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
351115516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_tcp),
351215516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP");
351315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp",
351415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
351515516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_udp),
351615516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP");
351715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted",
351815516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
351915516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_trusted),
352015516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU",
352115516c77SSepherosa Ziehau 	    "# of packets that we trust host's csum verification");
352215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts",
352315516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
352415516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_small_pkts),
352515516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of small packets received");
352615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed",
352715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
352815516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_ack_failed),
352915516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures");
353015516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt",
353115516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings");
353215516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse",
353315516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings");
353415516c77SSepherosa Ziehau 
353515516c77SSepherosa Ziehau 	return (0);
353615516c77SSepherosa Ziehau }
353715516c77SSepherosa Ziehau 
353815516c77SSepherosa Ziehau static void
353915516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc)
354015516c77SSepherosa Ziehau {
354115516c77SSepherosa Ziehau 	int i;
354215516c77SSepherosa Ziehau 
354315516c77SSepherosa Ziehau 	if (sc->hn_rxbuf != NULL) {
35442494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0)
354515516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf);
35462494d735SSepherosa Ziehau 		else
35472494d735SSepherosa Ziehau 			device_printf(sc->hn_dev, "RXBUF is referenced\n");
354815516c77SSepherosa Ziehau 		sc->hn_rxbuf = NULL;
354915516c77SSepherosa Ziehau 	}
355015516c77SSepherosa Ziehau 
355115516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_cnt == 0)
355215516c77SSepherosa Ziehau 		return;
355315516c77SSepherosa Ziehau 
355415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
355515516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
355615516c77SSepherosa Ziehau 
355715516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL)
355815516c77SSepherosa Ziehau 			continue;
35592494d735SSepherosa Ziehau 		if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) {
356015516c77SSepherosa Ziehau 			hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br);
35612494d735SSepherosa Ziehau 		} else {
35622494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
35632494d735SSepherosa Ziehau 			    "%dth channel bufring is referenced", i);
35642494d735SSepherosa Ziehau 		}
356515516c77SSepherosa Ziehau 		rxr->hn_br = NULL;
356615516c77SSepherosa Ziehau 
356715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
356815516c77SSepherosa Ziehau 		tcp_lro_free(&rxr->hn_lro);
356915516c77SSepherosa Ziehau #endif
357015516c77SSepherosa Ziehau 		free(rxr->hn_pktbuf, M_DEVBUF);
357115516c77SSepherosa Ziehau 	}
357215516c77SSepherosa Ziehau 	free(sc->hn_rx_ring, M_DEVBUF);
357315516c77SSepherosa Ziehau 	sc->hn_rx_ring = NULL;
357415516c77SSepherosa Ziehau 
357515516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = 0;
357615516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = 0;
357715516c77SSepherosa Ziehau }
357815516c77SSepherosa Ziehau 
357915516c77SSepherosa Ziehau static int
358015516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id)
358115516c77SSepherosa Ziehau {
358215516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[id];
358315516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
358415516c77SSepherosa Ziehau 	bus_dma_tag_t parent_dtag;
358515516c77SSepherosa Ziehau 	int error, i;
358615516c77SSepherosa Ziehau 
358715516c77SSepherosa Ziehau 	txr->hn_sc = sc;
358815516c77SSepherosa Ziehau 	txr->hn_tx_idx = id;
358915516c77SSepherosa Ziehau 
359015516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
359115516c77SSepherosa Ziehau 	mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN);
359215516c77SSepherosa Ziehau #endif
359315516c77SSepherosa Ziehau 	mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF);
359415516c77SSepherosa Ziehau 
359515516c77SSepherosa Ziehau 	txr->hn_txdesc_cnt = HN_TX_DESC_CNT;
359615516c77SSepherosa Ziehau 	txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt,
359715516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
359815516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
359915516c77SSepherosa Ziehau 	SLIST_INIT(&txr->hn_txlist);
360015516c77SSepherosa Ziehau #else
360115516c77SSepherosa Ziehau 	txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF,
360215516c77SSepherosa Ziehau 	    M_WAITOK, &txr->hn_tx_lock);
360315516c77SSepherosa Ziehau #endif
360415516c77SSepherosa Ziehau 
36050e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_EVTTQ) {
36060e11868dSSepherosa Ziehau 		txr->hn_tx_taskq = VMBUS_GET_EVENT_TASKQ(
36070e11868dSSepherosa Ziehau 		    device_get_parent(dev), dev, HN_RING_IDX2CPU(sc, id));
36080e11868dSSepherosa Ziehau 	} else {
3609fdd0222aSSepherosa Ziehau 		txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt];
36100e11868dSSepherosa Ziehau 	}
361115516c77SSepherosa Ziehau 
361223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
361315516c77SSepherosa Ziehau 	if (hn_use_if_start) {
361415516c77SSepherosa Ziehau 		txr->hn_txeof = hn_start_txeof;
361515516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr);
361615516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr);
361723bf9e15SSepherosa Ziehau 	} else
361823bf9e15SSepherosa Ziehau #endif
361923bf9e15SSepherosa Ziehau 	{
362015516c77SSepherosa Ziehau 		int br_depth;
362115516c77SSepherosa Ziehau 
362215516c77SSepherosa Ziehau 		txr->hn_txeof = hn_xmit_txeof;
362315516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr);
362415516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr);
362515516c77SSepherosa Ziehau 
362615516c77SSepherosa Ziehau 		br_depth = hn_get_txswq_depth(txr);
362715516c77SSepherosa Ziehau 		txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF,
362815516c77SSepherosa Ziehau 		    M_WAITOK, &txr->hn_tx_lock);
362915516c77SSepherosa Ziehau 	}
363015516c77SSepherosa Ziehau 
363115516c77SSepherosa Ziehau 	txr->hn_direct_tx_size = hn_direct_tx_size;
363215516c77SSepherosa Ziehau 
363315516c77SSepherosa Ziehau 	/*
363415516c77SSepherosa Ziehau 	 * Always schedule transmission instead of trying to do direct
363515516c77SSepherosa Ziehau 	 * transmission.  This one gives the best performance so far.
363615516c77SSepherosa Ziehau 	 */
363715516c77SSepherosa Ziehau 	txr->hn_sched_tx = 1;
363815516c77SSepherosa Ziehau 
363915516c77SSepherosa Ziehau 	parent_dtag = bus_get_dma_tag(dev);
364015516c77SSepherosa Ziehau 
364115516c77SSepherosa Ziehau 	/* DMA tag for RNDIS packet messages. */
364215516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
364315516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_ALIGN,		/* alignment */
364415516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_BOUNDARY,	/* boundary */
364515516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
364615516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
364715516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
364815516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsize */
364915516c77SSepherosa Ziehau 	    1,				/* nsegments */
365015516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsegsize */
365115516c77SSepherosa Ziehau 	    0,				/* flags */
365215516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
365315516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
365415516c77SSepherosa Ziehau 	    &txr->hn_tx_rndis_dtag);
365515516c77SSepherosa Ziehau 	if (error) {
365615516c77SSepherosa Ziehau 		device_printf(dev, "failed to create rndis dmatag\n");
365715516c77SSepherosa Ziehau 		return error;
365815516c77SSepherosa Ziehau 	}
365915516c77SSepherosa Ziehau 
366015516c77SSepherosa Ziehau 	/* DMA tag for data. */
366115516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
366215516c77SSepherosa Ziehau 	    1,				/* alignment */
366315516c77SSepherosa Ziehau 	    HN_TX_DATA_BOUNDARY,	/* boundary */
366415516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
366515516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
366615516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
366715516c77SSepherosa Ziehau 	    HN_TX_DATA_MAXSIZE,		/* maxsize */
366815516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGCNT_MAX,	/* nsegments */
366915516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGSIZE,		/* maxsegsize */
367015516c77SSepherosa Ziehau 	    0,				/* flags */
367115516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
367215516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
367315516c77SSepherosa Ziehau 	    &txr->hn_tx_data_dtag);
367415516c77SSepherosa Ziehau 	if (error) {
367515516c77SSepherosa Ziehau 		device_printf(dev, "failed to create data dmatag\n");
367615516c77SSepherosa Ziehau 		return error;
367715516c77SSepherosa Ziehau 	}
367815516c77SSepherosa Ziehau 
367915516c77SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i) {
368015516c77SSepherosa Ziehau 		struct hn_txdesc *txd = &txr->hn_txdesc[i];
368115516c77SSepherosa Ziehau 
368215516c77SSepherosa Ziehau 		txd->txr = txr;
368315516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
3684dc13fee6SSepherosa Ziehau 		STAILQ_INIT(&txd->agg_list);
368515516c77SSepherosa Ziehau 
368615516c77SSepherosa Ziehau 		/*
368715516c77SSepherosa Ziehau 		 * Allocate and load RNDIS packet message.
368815516c77SSepherosa Ziehau 		 */
368915516c77SSepherosa Ziehau         	error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag,
369015516c77SSepherosa Ziehau 		    (void **)&txd->rndis_pkt,
369115516c77SSepherosa Ziehau 		    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
369215516c77SSepherosa Ziehau 		    &txd->rndis_pkt_dmap);
369315516c77SSepherosa Ziehau 		if (error) {
369415516c77SSepherosa Ziehau 			device_printf(dev,
369515516c77SSepherosa Ziehau 			    "failed to allocate rndis_packet_msg, %d\n", i);
369615516c77SSepherosa Ziehau 			return error;
369715516c77SSepherosa Ziehau 		}
369815516c77SSepherosa Ziehau 
369915516c77SSepherosa Ziehau 		error = bus_dmamap_load(txr->hn_tx_rndis_dtag,
370015516c77SSepherosa Ziehau 		    txd->rndis_pkt_dmap,
370115516c77SSepherosa Ziehau 		    txd->rndis_pkt, HN_RNDIS_PKT_LEN,
370215516c77SSepherosa Ziehau 		    hyperv_dma_map_paddr, &txd->rndis_pkt_paddr,
370315516c77SSepherosa Ziehau 		    BUS_DMA_NOWAIT);
370415516c77SSepherosa Ziehau 		if (error) {
370515516c77SSepherosa Ziehau 			device_printf(dev,
370615516c77SSepherosa Ziehau 			    "failed to load rndis_packet_msg, %d\n", i);
370715516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
370815516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
370915516c77SSepherosa Ziehau 			return error;
371015516c77SSepherosa Ziehau 		}
371115516c77SSepherosa Ziehau 
371215516c77SSepherosa Ziehau 		/* DMA map for TX data. */
371315516c77SSepherosa Ziehau 		error = bus_dmamap_create(txr->hn_tx_data_dtag, 0,
371415516c77SSepherosa Ziehau 		    &txd->data_dmap);
371515516c77SSepherosa Ziehau 		if (error) {
371615516c77SSepherosa Ziehau 			device_printf(dev,
371715516c77SSepherosa Ziehau 			    "failed to allocate tx data dmamap\n");
371815516c77SSepherosa Ziehau 			bus_dmamap_unload(txr->hn_tx_rndis_dtag,
371915516c77SSepherosa Ziehau 			    txd->rndis_pkt_dmap);
372015516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
372115516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
372215516c77SSepherosa Ziehau 			return error;
372315516c77SSepherosa Ziehau 		}
372415516c77SSepherosa Ziehau 
372515516c77SSepherosa Ziehau 		/* All set, put it to list */
372615516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_ONLIST;
372715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
372815516c77SSepherosa Ziehau 		SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
372915516c77SSepherosa Ziehau #else
373015516c77SSepherosa Ziehau 		buf_ring_enqueue(txr->hn_txdesc_br, txd);
373115516c77SSepherosa Ziehau #endif
373215516c77SSepherosa Ziehau 	}
373315516c77SSepherosa Ziehau 	txr->hn_txdesc_avail = txr->hn_txdesc_cnt;
373415516c77SSepherosa Ziehau 
373515516c77SSepherosa Ziehau 	if (sc->hn_tx_sysctl_tree != NULL) {
373615516c77SSepherosa Ziehau 		struct sysctl_oid_list *child;
373715516c77SSepherosa Ziehau 		struct sysctl_ctx_list *ctx;
373815516c77SSepherosa Ziehau 		char name[16];
373915516c77SSepherosa Ziehau 
374015516c77SSepherosa Ziehau 		/*
374115516c77SSepherosa Ziehau 		 * Create per TX ring sysctl tree:
374215516c77SSepherosa Ziehau 		 * dev.hn.UNIT.tx.RINGID
374315516c77SSepherosa Ziehau 		 */
374415516c77SSepherosa Ziehau 		ctx = device_get_sysctl_ctx(dev);
374515516c77SSepherosa Ziehau 		child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree);
374615516c77SSepherosa Ziehau 
374715516c77SSepherosa Ziehau 		snprintf(name, sizeof(name), "%d", id);
374815516c77SSepherosa Ziehau 		txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
374915516c77SSepherosa Ziehau 		    name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
375015516c77SSepherosa Ziehau 
375115516c77SSepherosa Ziehau 		if (txr->hn_tx_sysctl_tree != NULL) {
375215516c77SSepherosa Ziehau 			child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree);
375315516c77SSepherosa Ziehau 
375485e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
375515516c77SSepherosa Ziehau 			SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail",
375615516c77SSepherosa Ziehau 			    CTLFLAG_RD, &txr->hn_txdesc_avail, 0,
375715516c77SSepherosa Ziehau 			    "# of available TX descs");
375885e4ae1eSSepherosa Ziehau #endif
375923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
376023bf9e15SSepherosa Ziehau 			if (!hn_use_if_start)
376123bf9e15SSepherosa Ziehau #endif
376223bf9e15SSepherosa Ziehau 			{
376315516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive",
376415516c77SSepherosa Ziehau 				    CTLFLAG_RD, &txr->hn_oactive, 0,
376515516c77SSepherosa Ziehau 				    "over active");
376615516c77SSepherosa Ziehau 			}
376715516c77SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets",
376815516c77SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_pkts,
376915516c77SSepherosa Ziehau 			    "# of packets transmitted");
3770dc13fee6SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends",
3771dc13fee6SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_sends, "# of sends");
377215516c77SSepherosa Ziehau 		}
377315516c77SSepherosa Ziehau 	}
377415516c77SSepherosa Ziehau 
377515516c77SSepherosa Ziehau 	return 0;
377615516c77SSepherosa Ziehau }
377715516c77SSepherosa Ziehau 
377815516c77SSepherosa Ziehau static void
377915516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd)
378015516c77SSepherosa Ziehau {
378115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = txd->txr;
378215516c77SSepherosa Ziehau 
378315516c77SSepherosa Ziehau 	KASSERT(txd->m == NULL, ("still has mbuf installed"));
378415516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped"));
378515516c77SSepherosa Ziehau 
378615516c77SSepherosa Ziehau 	bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap);
378715516c77SSepherosa Ziehau 	bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt,
378815516c77SSepherosa Ziehau 	    txd->rndis_pkt_dmap);
378915516c77SSepherosa Ziehau 	bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap);
379015516c77SSepherosa Ziehau }
379115516c77SSepherosa Ziehau 
379215516c77SSepherosa Ziehau static void
379325641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd)
379425641fc7SSepherosa Ziehau {
379525641fc7SSepherosa Ziehau 
379625641fc7SSepherosa Ziehau 	KASSERT(txd->refs == 0 || txd->refs == 1,
379725641fc7SSepherosa Ziehau 	    ("invalid txd refs %d", txd->refs));
379825641fc7SSepherosa Ziehau 
379925641fc7SSepherosa Ziehau 	/* Aggregated txds will be freed by their aggregating txd. */
380025641fc7SSepherosa Ziehau 	if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) {
380125641fc7SSepherosa Ziehau 		int freed;
380225641fc7SSepherosa Ziehau 
380325641fc7SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
380425641fc7SSepherosa Ziehau 		KASSERT(freed, ("can't free txdesc"));
380525641fc7SSepherosa Ziehau 	}
380625641fc7SSepherosa Ziehau }
380725641fc7SSepherosa Ziehau 
380825641fc7SSepherosa Ziehau static void
380915516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr)
381015516c77SSepherosa Ziehau {
381125641fc7SSepherosa Ziehau 	int i;
381215516c77SSepherosa Ziehau 
381315516c77SSepherosa Ziehau 	if (txr->hn_txdesc == NULL)
381415516c77SSepherosa Ziehau 		return;
381515516c77SSepherosa Ziehau 
381625641fc7SSepherosa Ziehau 	/*
381725641fc7SSepherosa Ziehau 	 * NOTE:
381825641fc7SSepherosa Ziehau 	 * Because the freeing of aggregated txds will be deferred
381925641fc7SSepherosa Ziehau 	 * to the aggregating txd, two passes are used here:
382025641fc7SSepherosa Ziehau 	 * - The first pass GCes any pending txds.  This GC is necessary,
382125641fc7SSepherosa Ziehau 	 *   since if the channels are revoked, hypervisor will not
382225641fc7SSepherosa Ziehau 	 *   deliver send-done for all pending txds.
382325641fc7SSepherosa Ziehau 	 * - The second pass frees the busdma stuffs, i.e. after all txds
382425641fc7SSepherosa Ziehau 	 *   were freed.
382525641fc7SSepherosa Ziehau 	 */
382625641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
382725641fc7SSepherosa Ziehau 		hn_txdesc_gc(txr, &txr->hn_txdesc[i]);
382825641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
382925641fc7SSepherosa Ziehau 		hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]);
383015516c77SSepherosa Ziehau 
383115516c77SSepherosa Ziehau 	if (txr->hn_tx_data_dtag != NULL)
383215516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_data_dtag);
383315516c77SSepherosa Ziehau 	if (txr->hn_tx_rndis_dtag != NULL)
383415516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_rndis_dtag);
383515516c77SSepherosa Ziehau 
383615516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
383715516c77SSepherosa Ziehau 	buf_ring_free(txr->hn_txdesc_br, M_DEVBUF);
383815516c77SSepherosa Ziehau #endif
383915516c77SSepherosa Ziehau 
384015516c77SSepherosa Ziehau 	free(txr->hn_txdesc, M_DEVBUF);
384115516c77SSepherosa Ziehau 	txr->hn_txdesc = NULL;
384215516c77SSepherosa Ziehau 
384315516c77SSepherosa Ziehau 	if (txr->hn_mbuf_br != NULL)
384415516c77SSepherosa Ziehau 		buf_ring_free(txr->hn_mbuf_br, M_DEVBUF);
384515516c77SSepherosa Ziehau 
384615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
384715516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_txlist_spin);
384815516c77SSepherosa Ziehau #endif
384915516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_tx_lock);
385015516c77SSepherosa Ziehau }
385115516c77SSepherosa Ziehau 
385215516c77SSepherosa Ziehau static int
385315516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt)
385415516c77SSepherosa Ziehau {
385515516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
385615516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
385715516c77SSepherosa Ziehau 	int i;
385815516c77SSepherosa Ziehau 
385915516c77SSepherosa Ziehau 	/*
386015516c77SSepherosa Ziehau 	 * Create TXBUF for chimney sending.
386115516c77SSepherosa Ziehau 	 *
386215516c77SSepherosa Ziehau 	 * NOTE: It is shared by all channels.
386315516c77SSepherosa Ziehau 	 */
386415516c77SSepherosa Ziehau 	sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev),
386515516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma,
386615516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
386715516c77SSepherosa Ziehau 	if (sc->hn_chim == NULL) {
386815516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate txbuf failed\n");
386915516c77SSepherosa Ziehau 		return (ENOMEM);
387015516c77SSepherosa Ziehau 	}
387115516c77SSepherosa Ziehau 
387215516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = ring_cnt;
387315516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
387415516c77SSepherosa Ziehau 
387515516c77SSepherosa Ziehau 	sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt,
387615516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
387715516c77SSepherosa Ziehau 
387815516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(sc->hn_dev);
387915516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev));
388015516c77SSepherosa Ziehau 
388115516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.tx sysctl tree */
388215516c77SSepherosa Ziehau 	sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx",
388315516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
388415516c77SSepherosa Ziehau 
388515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
388615516c77SSepherosa Ziehau 		int error;
388715516c77SSepherosa Ziehau 
388815516c77SSepherosa Ziehau 		error = hn_tx_ring_create(sc, i);
388915516c77SSepherosa Ziehau 		if (error)
389015516c77SSepherosa Ziehau 			return error;
389115516c77SSepherosa Ziehau 	}
389215516c77SSepherosa Ziehau 
389315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs",
389415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
389515516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_no_txdescs),
389615516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs");
389715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed",
389815516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
389915516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_send_failed),
390015516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure");
390115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed",
390215516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
390315516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_txdma_failed),
390415516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure");
3905dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed",
3906dc13fee6SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
3907dc13fee6SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_flush_failed),
3908dc13fee6SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU",
3909dc13fee6SSepherosa Ziehau 	    "# of packet transmission aggregation flush failure");
391015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed",
391115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
391215516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_collapsed),
391315516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed");
391415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney",
391515516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
391615516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney),
391715516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send");
391815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried",
391915516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
392015516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney_tried),
392115516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries");
392215516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt",
392315516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0,
392415516c77SSepherosa Ziehau 	    "# of total TX descs");
392515516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max",
392615516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_chim_szmax, 0,
392715516c77SSepherosa Ziehau 	    "Chimney send packet size upper boundary");
392815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size",
392915516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
393015516c77SSepherosa Ziehau 	    hn_chim_size_sysctl, "I", "Chimney send packet size limit");
393115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size",
393215516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
393315516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_direct_tx_size),
393415516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
393515516c77SSepherosa Ziehau 	    "Size of the packet for direct transmission");
393615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx",
393715516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
393815516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_sched_tx),
393915516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
394015516c77SSepherosa Ziehau 	    "Always schedule transmission "
394115516c77SSepherosa Ziehau 	    "instead of doing direct transmission");
394215516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt",
394315516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings");
394415516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse",
394515516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings");
3946dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax",
3947dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0,
3948dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation size");
3949dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax",
3950dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
3951dc13fee6SSepherosa Ziehau 	    hn_txagg_pktmax_sysctl, "I",
3952dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation packets");
3953dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align",
3954dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
3955dc13fee6SSepherosa Ziehau 	    hn_txagg_align_sysctl, "I",
3956dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation alignment");
395715516c77SSepherosa Ziehau 
395815516c77SSepherosa Ziehau 	return 0;
395915516c77SSepherosa Ziehau }
396015516c77SSepherosa Ziehau 
396115516c77SSepherosa Ziehau static void
396215516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size)
396315516c77SSepherosa Ziehau {
396415516c77SSepherosa Ziehau 	int i;
396515516c77SSepherosa Ziehau 
3966a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
396715516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_chim_size = chim_size;
396815516c77SSepherosa Ziehau }
396915516c77SSepherosa Ziehau 
397015516c77SSepherosa Ziehau static void
397115516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu)
397215516c77SSepherosa Ziehau {
397315516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
397415516c77SSepherosa Ziehau 	int tso_minlen;
397515516c77SSepherosa Ziehau 
397615516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0)
397715516c77SSepherosa Ziehau 		return;
397815516c77SSepherosa Ziehau 
397915516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_sgmin >= 2,
398015516c77SSepherosa Ziehau 	    ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin));
398115516c77SSepherosa Ziehau 	tso_minlen = sc->hn_ndis_tso_sgmin * mtu;
398215516c77SSepherosa Ziehau 
398315516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen &&
398415516c77SSepherosa Ziehau 	    sc->hn_ndis_tso_szmax <= IP_MAXPACKET,
398515516c77SSepherosa Ziehau 	    ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax));
398615516c77SSepherosa Ziehau 
398715516c77SSepherosa Ziehau 	if (tso_maxlen < tso_minlen)
398815516c77SSepherosa Ziehau 		tso_maxlen = tso_minlen;
398915516c77SSepherosa Ziehau 	else if (tso_maxlen > IP_MAXPACKET)
399015516c77SSepherosa Ziehau 		tso_maxlen = IP_MAXPACKET;
399115516c77SSepherosa Ziehau 	if (tso_maxlen > sc->hn_ndis_tso_szmax)
399215516c77SSepherosa Ziehau 		tso_maxlen = sc->hn_ndis_tso_szmax;
399315516c77SSepherosa Ziehau 	ifp->if_hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
399415516c77SSepherosa Ziehau 	if (bootverbose)
399515516c77SSepherosa Ziehau 		if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax);
399615516c77SSepherosa Ziehau }
399715516c77SSepherosa Ziehau 
399815516c77SSepherosa Ziehau static void
399915516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc)
400015516c77SSepherosa Ziehau {
400115516c77SSepherosa Ziehau 	uint64_t csum_assist;
400215516c77SSepherosa Ziehau 	int i;
400315516c77SSepherosa Ziehau 
400415516c77SSepherosa Ziehau 	hn_set_chim_size(sc, sc->hn_chim_szmax);
400515516c77SSepherosa Ziehau 	if (hn_tx_chimney_size > 0 &&
400615516c77SSepherosa Ziehau 	    hn_tx_chimney_size < sc->hn_chim_szmax)
400715516c77SSepherosa Ziehau 		hn_set_chim_size(sc, hn_tx_chimney_size);
400815516c77SSepherosa Ziehau 
400915516c77SSepherosa Ziehau 	csum_assist = 0;
401015516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_IPCS)
401115516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP;
401215516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP4CS)
401315516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_TCP;
401415516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP4CS)
401515516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_UDP;
401615516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP6CS)
401715516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_TCP;
401815516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP6CS)
401915516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_UDP;
402015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
402115516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_csum_assist = csum_assist;
402215516c77SSepherosa Ziehau 
402315516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_HASHVAL) {
402415516c77SSepherosa Ziehau 		/*
402515516c77SSepherosa Ziehau 		 * Support HASHVAL pktinfo on TX path.
402615516c77SSepherosa Ziehau 		 */
402715516c77SSepherosa Ziehau 		if (bootverbose)
402815516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n");
402915516c77SSepherosa Ziehau 		for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
403015516c77SSepherosa Ziehau 			sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL;
403115516c77SSepherosa Ziehau 	}
403215516c77SSepherosa Ziehau }
403315516c77SSepherosa Ziehau 
403415516c77SSepherosa Ziehau static void
403515516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc)
403615516c77SSepherosa Ziehau {
403715516c77SSepherosa Ziehau 	int i;
403815516c77SSepherosa Ziehau 
403915516c77SSepherosa Ziehau 	if (sc->hn_chim != NULL) {
40402494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) {
404115516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim);
40422494d735SSepherosa Ziehau 		} else {
40432494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
40442494d735SSepherosa Ziehau 			    "chimney sending buffer is referenced");
40452494d735SSepherosa Ziehau 		}
404615516c77SSepherosa Ziehau 		sc->hn_chim = NULL;
404715516c77SSepherosa Ziehau 	}
404815516c77SSepherosa Ziehau 
404915516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt == 0)
405015516c77SSepherosa Ziehau 		return;
405115516c77SSepherosa Ziehau 
405215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
405315516c77SSepherosa Ziehau 		hn_tx_ring_destroy(&sc->hn_tx_ring[i]);
405415516c77SSepherosa Ziehau 
405515516c77SSepherosa Ziehau 	free(sc->hn_tx_ring, M_DEVBUF);
405615516c77SSepherosa Ziehau 	sc->hn_tx_ring = NULL;
405715516c77SSepherosa Ziehau 
405815516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = 0;
405915516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = 0;
406015516c77SSepherosa Ziehau }
406115516c77SSepherosa Ziehau 
406223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
406323bf9e15SSepherosa Ziehau 
406415516c77SSepherosa Ziehau static void
406515516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused)
406615516c77SSepherosa Ziehau {
406715516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
406815516c77SSepherosa Ziehau 
406915516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
407015516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
407115516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
407215516c77SSepherosa Ziehau }
407315516c77SSepherosa Ziehau 
407423bf9e15SSepherosa Ziehau static int
407523bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len)
407623bf9e15SSepherosa Ziehau {
407723bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
407823bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
4079dc13fee6SSepherosa Ziehau 	int sched = 0;
408023bf9e15SSepherosa Ziehau 
408123bf9e15SSepherosa Ziehau 	KASSERT(hn_use_if_start,
408223bf9e15SSepherosa Ziehau 	    ("hn_start_locked is called, when if_start is disabled"));
408323bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
408423bf9e15SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
4085dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
408623bf9e15SSepherosa Ziehau 
408723bf9e15SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
4088dc13fee6SSepherosa Ziehau 		return (0);
408923bf9e15SSepherosa Ziehau 
409023bf9e15SSepherosa Ziehau 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
409123bf9e15SSepherosa Ziehau 	    IFF_DRV_RUNNING)
4092dc13fee6SSepherosa Ziehau 		return (0);
409323bf9e15SSepherosa Ziehau 
409423bf9e15SSepherosa Ziehau 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
409523bf9e15SSepherosa Ziehau 		struct hn_txdesc *txd;
409623bf9e15SSepherosa Ziehau 		struct mbuf *m_head;
409723bf9e15SSepherosa Ziehau 		int error;
409823bf9e15SSepherosa Ziehau 
409923bf9e15SSepherosa Ziehau 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
410023bf9e15SSepherosa Ziehau 		if (m_head == NULL)
410123bf9e15SSepherosa Ziehau 			break;
410223bf9e15SSepherosa Ziehau 
410323bf9e15SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
410423bf9e15SSepherosa Ziehau 			/*
410523bf9e15SSepherosa Ziehau 			 * This sending could be time consuming; let callers
410623bf9e15SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
410723bf9e15SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
410823bf9e15SSepherosa Ziehau 			 */
410923bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
4110dc13fee6SSepherosa Ziehau 			sched = 1;
4111dc13fee6SSepherosa Ziehau 			break;
411223bf9e15SSepherosa Ziehau 		}
411323bf9e15SSepherosa Ziehau 
4114edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
4115edd3f315SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
4116edd3f315SSepherosa Ziehau 			m_head = hn_tso_fixup(m_head);
4117edd3f315SSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
4118edd3f315SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
4119edd3f315SSepherosa Ziehau 				continue;
4120edd3f315SSepherosa Ziehau 			}
4121edd3f315SSepherosa Ziehau 		}
4122edd3f315SSepherosa Ziehau #endif
4123edd3f315SSepherosa Ziehau 
412423bf9e15SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
412523bf9e15SSepherosa Ziehau 		if (txd == NULL) {
412623bf9e15SSepherosa Ziehau 			txr->hn_no_txdescs++;
412723bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
412823bf9e15SSepherosa Ziehau 			atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
412923bf9e15SSepherosa Ziehau 			break;
413023bf9e15SSepherosa Ziehau 		}
413123bf9e15SSepherosa Ziehau 
4132dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
413323bf9e15SSepherosa Ziehau 		if (error) {
413423bf9e15SSepherosa Ziehau 			/* Both txd and m_head are freed */
4135dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
4136dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
413723bf9e15SSepherosa Ziehau 			continue;
413823bf9e15SSepherosa Ziehau 		}
413923bf9e15SSepherosa Ziehau 
4140dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
4141dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
4142dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
4143dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
4144dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
4145dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
4146dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
4147dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
4148dc13fee6SSepherosa Ziehau 					break;
4149dc13fee6SSepherosa Ziehau 				}
4150dc13fee6SSepherosa Ziehau 			} else {
4151dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
415223bf9e15SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
415323bf9e15SSepherosa Ziehau 				if (__predict_false(error)) {
415423bf9e15SSepherosa Ziehau 					/* txd is freed, but m_head is not */
415523bf9e15SSepherosa Ziehau 					IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
4156dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
4157dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
415823bf9e15SSepherosa Ziehau 					break;
415923bf9e15SSepherosa Ziehau 				}
416023bf9e15SSepherosa Ziehau 			}
4161dc13fee6SSepherosa Ziehau 		}
4162dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
4163dc13fee6SSepherosa Ziehau 		else {
4164dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
4165dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
4166dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
4167dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
4168dc13fee6SSepherosa Ziehau 		}
4169dc13fee6SSepherosa Ziehau #endif
4170dc13fee6SSepherosa Ziehau 	}
4171dc13fee6SSepherosa Ziehau 
4172dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
4173dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
4174dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
4175dc13fee6SSepherosa Ziehau 	return (sched);
417623bf9e15SSepherosa Ziehau }
417723bf9e15SSepherosa Ziehau 
417823bf9e15SSepherosa Ziehau static void
417923bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp)
418023bf9e15SSepherosa Ziehau {
418123bf9e15SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
418223bf9e15SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[0];
418323bf9e15SSepherosa Ziehau 
418423bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
418523bf9e15SSepherosa Ziehau 		goto do_sched;
418623bf9e15SSepherosa Ziehau 
418723bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
418823bf9e15SSepherosa Ziehau 		int sched;
418923bf9e15SSepherosa Ziehau 
419023bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
419123bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
419223bf9e15SSepherosa Ziehau 		if (!sched)
419323bf9e15SSepherosa Ziehau 			return;
419423bf9e15SSepherosa Ziehau 	}
419523bf9e15SSepherosa Ziehau do_sched:
419623bf9e15SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
419723bf9e15SSepherosa Ziehau }
419823bf9e15SSepherosa Ziehau 
419915516c77SSepherosa Ziehau static void
420015516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused)
420115516c77SSepherosa Ziehau {
420215516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
420315516c77SSepherosa Ziehau 
420415516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
420515516c77SSepherosa Ziehau 	atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE);
420615516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
420715516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
420815516c77SSepherosa Ziehau }
420915516c77SSepherosa Ziehau 
421023bf9e15SSepherosa Ziehau static void
421123bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr)
421223bf9e15SSepherosa Ziehau {
421323bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
421423bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
421523bf9e15SSepherosa Ziehau 
421623bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
421723bf9e15SSepherosa Ziehau 
421823bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
421923bf9e15SSepherosa Ziehau 		goto do_sched;
422023bf9e15SSepherosa Ziehau 
422123bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
422223bf9e15SSepherosa Ziehau 		int sched;
422323bf9e15SSepherosa Ziehau 
422423bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
422523bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
422623bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
422723bf9e15SSepherosa Ziehau 		if (sched) {
422823bf9e15SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
422923bf9e15SSepherosa Ziehau 			    &txr->hn_tx_task);
423023bf9e15SSepherosa Ziehau 		}
423123bf9e15SSepherosa Ziehau 	} else {
423223bf9e15SSepherosa Ziehau do_sched:
423323bf9e15SSepherosa Ziehau 		/*
423423bf9e15SSepherosa Ziehau 		 * Release the OACTIVE earlier, with the hope, that
423523bf9e15SSepherosa Ziehau 		 * others could catch up.  The task will clear the
423623bf9e15SSepherosa Ziehau 		 * flag again with the hn_tx_lock to avoid possible
423723bf9e15SSepherosa Ziehau 		 * races.
423823bf9e15SSepherosa Ziehau 		 */
423923bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
424023bf9e15SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
424123bf9e15SSepherosa Ziehau 	}
424223bf9e15SSepherosa Ziehau }
424323bf9e15SSepherosa Ziehau 
424423bf9e15SSepherosa Ziehau #endif	/* HN_IFSTART_SUPPORT */
424523bf9e15SSepherosa Ziehau 
424615516c77SSepherosa Ziehau static int
424715516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len)
424815516c77SSepherosa Ziehau {
424915516c77SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
425015516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
425115516c77SSepherosa Ziehau 	struct mbuf *m_head;
4252dc13fee6SSepherosa Ziehau 	int sched = 0;
425315516c77SSepherosa Ziehau 
425415516c77SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
425523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
425615516c77SSepherosa Ziehau 	KASSERT(hn_use_if_start == 0,
425715516c77SSepherosa Ziehau 	    ("hn_xmit is called, when if_start is enabled"));
425823bf9e15SSepherosa Ziehau #endif
4259dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
426015516c77SSepherosa Ziehau 
426115516c77SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
4262dc13fee6SSepherosa Ziehau 		return (0);
426315516c77SSepherosa Ziehau 
426415516c77SSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive)
4265dc13fee6SSepherosa Ziehau 		return (0);
426615516c77SSepherosa Ziehau 
426715516c77SSepherosa Ziehau 	while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) {
426815516c77SSepherosa Ziehau 		struct hn_txdesc *txd;
426915516c77SSepherosa Ziehau 		int error;
427015516c77SSepherosa Ziehau 
427115516c77SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
427215516c77SSepherosa Ziehau 			/*
427315516c77SSepherosa Ziehau 			 * This sending could be time consuming; let callers
427415516c77SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
427515516c77SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
427615516c77SSepherosa Ziehau 			 */
427715516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
4278dc13fee6SSepherosa Ziehau 			sched = 1;
4279dc13fee6SSepherosa Ziehau 			break;
428015516c77SSepherosa Ziehau 		}
428115516c77SSepherosa Ziehau 
428215516c77SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
428315516c77SSepherosa Ziehau 		if (txd == NULL) {
428415516c77SSepherosa Ziehau 			txr->hn_no_txdescs++;
428515516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
428615516c77SSepherosa Ziehau 			txr->hn_oactive = 1;
428715516c77SSepherosa Ziehau 			break;
428815516c77SSepherosa Ziehau 		}
428915516c77SSepherosa Ziehau 
4290dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
429115516c77SSepherosa Ziehau 		if (error) {
429215516c77SSepherosa Ziehau 			/* Both txd and m_head are freed; discard */
4293dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
4294dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
429515516c77SSepherosa Ziehau 			drbr_advance(ifp, txr->hn_mbuf_br);
429615516c77SSepherosa Ziehau 			continue;
429715516c77SSepherosa Ziehau 		}
429815516c77SSepherosa Ziehau 
4299dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
4300dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
4301dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
4302dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
4303dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
430415516c77SSepherosa Ziehau 				if (__predict_false(error)) {
430515516c77SSepherosa Ziehau 					txr->hn_oactive = 1;
430615516c77SSepherosa Ziehau 					break;
430715516c77SSepherosa Ziehau 				}
4308dc13fee6SSepherosa Ziehau 			} else {
4309dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
4310dc13fee6SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
4311dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
4312dc13fee6SSepherosa Ziehau 					/* txd is freed, but m_head is not */
4313dc13fee6SSepherosa Ziehau 					drbr_putback(ifp, txr->hn_mbuf_br,
4314dc13fee6SSepherosa Ziehau 					    m_head);
4315dc13fee6SSepherosa Ziehau 					txr->hn_oactive = 1;
4316dc13fee6SSepherosa Ziehau 					break;
4317dc13fee6SSepherosa Ziehau 				}
4318dc13fee6SSepherosa Ziehau 			}
4319dc13fee6SSepherosa Ziehau 		}
4320dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
4321dc13fee6SSepherosa Ziehau 		else {
4322dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
4323dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
4324dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
4325dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
4326dc13fee6SSepherosa Ziehau 		}
4327dc13fee6SSepherosa Ziehau #endif
432815516c77SSepherosa Ziehau 
432915516c77SSepherosa Ziehau 		/* Sent */
433015516c77SSepherosa Ziehau 		drbr_advance(ifp, txr->hn_mbuf_br);
433115516c77SSepherosa Ziehau 	}
4332dc13fee6SSepherosa Ziehau 
4333dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
4334dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
4335dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
4336dc13fee6SSepherosa Ziehau 	return (sched);
433715516c77SSepherosa Ziehau }
433815516c77SSepherosa Ziehau 
433915516c77SSepherosa Ziehau static int
434015516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m)
434115516c77SSepherosa Ziehau {
434215516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
434315516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
434415516c77SSepherosa Ziehau 	int error, idx = 0;
434515516c77SSepherosa Ziehau 
4346edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
4347edd3f315SSepherosa Ziehau 	/*
4348edd3f315SSepherosa Ziehau 	 * Perform TSO packet header fixup now, since the TSO
4349edd3f315SSepherosa Ziehau 	 * packet header should be cache-hot.
4350edd3f315SSepherosa Ziehau 	 */
4351edd3f315SSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
4352edd3f315SSepherosa Ziehau 		m = hn_tso_fixup(m);
4353edd3f315SSepherosa Ziehau 		if (__predict_false(m == NULL)) {
4354edd3f315SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
4355edd3f315SSepherosa Ziehau 			return EIO;
4356edd3f315SSepherosa Ziehau 		}
4357edd3f315SSepherosa Ziehau 	}
4358edd3f315SSepherosa Ziehau #endif
4359edd3f315SSepherosa Ziehau 
436015516c77SSepherosa Ziehau 	/*
436115516c77SSepherosa Ziehau 	 * Select the TX ring based on flowid
436215516c77SSepherosa Ziehau 	 */
436334d68912SSepherosa Ziehau 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
436434d68912SSepherosa Ziehau #ifdef RSS
436534d68912SSepherosa Ziehau 		uint32_t bid;
436634d68912SSepherosa Ziehau 
436734d68912SSepherosa Ziehau 		if (rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m),
436834d68912SSepherosa Ziehau 		    &bid) == 0)
436934d68912SSepherosa Ziehau 			idx = bid % sc->hn_tx_ring_inuse;
437034d68912SSepherosa Ziehau 		else
437134d68912SSepherosa Ziehau #endif
437215516c77SSepherosa Ziehau 			idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse;
437334d68912SSepherosa Ziehau 	}
437415516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[idx];
437515516c77SSepherosa Ziehau 
437615516c77SSepherosa Ziehau 	error = drbr_enqueue(ifp, txr->hn_mbuf_br, m);
437715516c77SSepherosa Ziehau 	if (error) {
437815516c77SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
437915516c77SSepherosa Ziehau 		return error;
438015516c77SSepherosa Ziehau 	}
438115516c77SSepherosa Ziehau 
438215516c77SSepherosa Ziehau 	if (txr->hn_oactive)
438315516c77SSepherosa Ziehau 		return 0;
438415516c77SSepherosa Ziehau 
438515516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
438615516c77SSepherosa Ziehau 		goto do_sched;
438715516c77SSepherosa Ziehau 
438815516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
438915516c77SSepherosa Ziehau 		int sched;
439015516c77SSepherosa Ziehau 
439115516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
439215516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
439315516c77SSepherosa Ziehau 		if (!sched)
439415516c77SSepherosa Ziehau 			return 0;
439515516c77SSepherosa Ziehau 	}
439615516c77SSepherosa Ziehau do_sched:
439715516c77SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
439815516c77SSepherosa Ziehau 	return 0;
439915516c77SSepherosa Ziehau }
440015516c77SSepherosa Ziehau 
440115516c77SSepherosa Ziehau static void
440215516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr)
440315516c77SSepherosa Ziehau {
440415516c77SSepherosa Ziehau 	struct mbuf *m;
440515516c77SSepherosa Ziehau 
440615516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
440715516c77SSepherosa Ziehau 	while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL)
440815516c77SSepherosa Ziehau 		m_freem(m);
440915516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
441015516c77SSepherosa Ziehau }
441115516c77SSepherosa Ziehau 
441215516c77SSepherosa Ziehau static void
441315516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp)
441415516c77SSepherosa Ziehau {
441515516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
441615516c77SSepherosa Ziehau 	int i;
441715516c77SSepherosa Ziehau 
441815516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
441915516c77SSepherosa Ziehau 		hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
442015516c77SSepherosa Ziehau 	if_qflush(ifp);
442115516c77SSepherosa Ziehau }
442215516c77SSepherosa Ziehau 
442315516c77SSepherosa Ziehau static void
442415516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr)
442515516c77SSepherosa Ziehau {
442615516c77SSepherosa Ziehau 
442715516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
442815516c77SSepherosa Ziehau 		goto do_sched;
442915516c77SSepherosa Ziehau 
443015516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
443115516c77SSepherosa Ziehau 		int sched;
443215516c77SSepherosa Ziehau 
443315516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
443415516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
443515516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
443615516c77SSepherosa Ziehau 		if (sched) {
443715516c77SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
443815516c77SSepherosa Ziehau 			    &txr->hn_tx_task);
443915516c77SSepherosa Ziehau 		}
444015516c77SSepherosa Ziehau 	} else {
444115516c77SSepherosa Ziehau do_sched:
444215516c77SSepherosa Ziehau 		/*
444315516c77SSepherosa Ziehau 		 * Release the oactive earlier, with the hope, that
444415516c77SSepherosa Ziehau 		 * others could catch up.  The task will clear the
444515516c77SSepherosa Ziehau 		 * oactive again with the hn_tx_lock to avoid possible
444615516c77SSepherosa Ziehau 		 * races.
444715516c77SSepherosa Ziehau 		 */
444815516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
444915516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
445015516c77SSepherosa Ziehau 	}
445115516c77SSepherosa Ziehau }
445215516c77SSepherosa Ziehau 
445315516c77SSepherosa Ziehau static void
445415516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused)
445515516c77SSepherosa Ziehau {
445615516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
445715516c77SSepherosa Ziehau 
445815516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
445915516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
446015516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
446115516c77SSepherosa Ziehau }
446215516c77SSepherosa Ziehau 
446315516c77SSepherosa Ziehau static void
446415516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused)
446515516c77SSepherosa Ziehau {
446615516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
446715516c77SSepherosa Ziehau 
446815516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
446915516c77SSepherosa Ziehau 	txr->hn_oactive = 0;
447015516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
447115516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
447215516c77SSepherosa Ziehau }
447315516c77SSepherosa Ziehau 
447415516c77SSepherosa Ziehau static int
447515516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan)
447615516c77SSepherosa Ziehau {
447715516c77SSepherosa Ziehau 	struct vmbus_chan_br cbr;
447815516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
447915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = NULL;
448015516c77SSepherosa Ziehau 	int idx, error;
448115516c77SSepherosa Ziehau 
448215516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
448315516c77SSepherosa Ziehau 
448415516c77SSepherosa Ziehau 	/*
448515516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
448615516c77SSepherosa Ziehau 	 */
448715516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
448815516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
448915516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
449015516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
449115516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0,
449215516c77SSepherosa Ziehau 	    ("RX ring %d already attached", idx));
449315516c77SSepherosa Ziehau 	rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED;
44943ab0fea1SDexuan Cui 	rxr->hn_chan = chan;
449515516c77SSepherosa Ziehau 
449615516c77SSepherosa Ziehau 	if (bootverbose) {
449715516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n",
449815516c77SSepherosa Ziehau 		    idx, vmbus_chan_id(chan));
449915516c77SSepherosa Ziehau 	}
450015516c77SSepherosa Ziehau 
450115516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
450215516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[idx];
450315516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0,
450415516c77SSepherosa Ziehau 		    ("TX ring %d already attached", idx));
450515516c77SSepherosa Ziehau 		txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED;
450615516c77SSepherosa Ziehau 
450715516c77SSepherosa Ziehau 		txr->hn_chan = chan;
450815516c77SSepherosa Ziehau 		if (bootverbose) {
450915516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n",
451015516c77SSepherosa Ziehau 			    idx, vmbus_chan_id(chan));
451115516c77SSepherosa Ziehau 		}
451215516c77SSepherosa Ziehau 	}
451315516c77SSepherosa Ziehau 
451415516c77SSepherosa Ziehau 	/* Bind this channel to a proper CPU. */
45150e11868dSSepherosa Ziehau 	vmbus_chan_cpu_set(chan, HN_RING_IDX2CPU(sc, idx));
451615516c77SSepherosa Ziehau 
451715516c77SSepherosa Ziehau 	/*
451815516c77SSepherosa Ziehau 	 * Open this channel
451915516c77SSepherosa Ziehau 	 */
452015516c77SSepherosa Ziehau 	cbr.cbr = rxr->hn_br;
452115516c77SSepherosa Ziehau 	cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr;
452215516c77SSepherosa Ziehau 	cbr.cbr_txsz = HN_TXBR_SIZE;
452315516c77SSepherosa Ziehau 	cbr.cbr_rxsz = HN_RXBR_SIZE;
452415516c77SSepherosa Ziehau 	error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr);
452515516c77SSepherosa Ziehau 	if (error) {
452671e8ac56SSepherosa Ziehau 		if (error == EISCONN) {
452771e8ac56SSepherosa Ziehau 			if_printf(sc->hn_ifp, "bufring is connected after "
452871e8ac56SSepherosa Ziehau 			    "chan%u open failure\n", vmbus_chan_id(chan));
452971e8ac56SSepherosa Ziehau 			rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
453071e8ac56SSepherosa Ziehau 		} else {
453115516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "open chan%u failed: %d\n",
453215516c77SSepherosa Ziehau 			    vmbus_chan_id(chan), error);
453371e8ac56SSepherosa Ziehau 		}
453415516c77SSepherosa Ziehau 	}
453515516c77SSepherosa Ziehau 	return (error);
453615516c77SSepherosa Ziehau }
453715516c77SSepherosa Ziehau 
453815516c77SSepherosa Ziehau static void
453915516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan)
454015516c77SSepherosa Ziehau {
454115516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
45422494d735SSepherosa Ziehau 	int idx, error;
454315516c77SSepherosa Ziehau 
454415516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
454515516c77SSepherosa Ziehau 
454615516c77SSepherosa Ziehau 	/*
454715516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
454815516c77SSepherosa Ziehau 	 */
454915516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
455015516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
455115516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
455215516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
455315516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED),
455415516c77SSepherosa Ziehau 	    ("RX ring %d is not attached", idx));
455515516c77SSepherosa Ziehau 	rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
455615516c77SSepherosa Ziehau 
455715516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
455815516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[idx];
455915516c77SSepherosa Ziehau 
456015516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED),
456115516c77SSepherosa Ziehau 		    ("TX ring %d is not attached attached", idx));
456215516c77SSepherosa Ziehau 		txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
456315516c77SSepherosa Ziehau 	}
456415516c77SSepherosa Ziehau 
456515516c77SSepherosa Ziehau 	/*
456615516c77SSepherosa Ziehau 	 * Close this channel.
456715516c77SSepherosa Ziehau 	 *
456815516c77SSepherosa Ziehau 	 * NOTE:
456915516c77SSepherosa Ziehau 	 * Channel closing does _not_ destroy the target channel.
457015516c77SSepherosa Ziehau 	 */
45712494d735SSepherosa Ziehau 	error = vmbus_chan_close_direct(chan);
45722494d735SSepherosa Ziehau 	if (error == EISCONN) {
4573aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u bufring is connected "
4574aa1a2adcSSepherosa Ziehau 		    "after being closed\n", vmbus_chan_id(chan));
45752494d735SSepherosa Ziehau 		rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
45762494d735SSepherosa Ziehau 	} else if (error) {
4577aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u close failed: %d\n",
4578aa1a2adcSSepherosa Ziehau 		    vmbus_chan_id(chan), error);
45792494d735SSepherosa Ziehau 	}
458015516c77SSepherosa Ziehau }
458115516c77SSepherosa Ziehau 
458215516c77SSepherosa Ziehau static int
458315516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc)
458415516c77SSepherosa Ziehau {
458515516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
458615516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
458715516c77SSepherosa Ziehau 	int i, error = 0;
458815516c77SSepherosa Ziehau 
458971e8ac56SSepherosa Ziehau 	KASSERT(subchan_cnt > 0, ("no sub-channels"));
459015516c77SSepherosa Ziehau 
459115516c77SSepherosa Ziehau 	/* Attach the sub-channels. */
459215516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
459315516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i) {
459471e8ac56SSepherosa Ziehau 		int error1;
459571e8ac56SSepherosa Ziehau 
459671e8ac56SSepherosa Ziehau 		error1 = hn_chan_attach(sc, subchans[i]);
459771e8ac56SSepherosa Ziehau 		if (error1) {
459871e8ac56SSepherosa Ziehau 			error = error1;
459971e8ac56SSepherosa Ziehau 			/* Move on; all channels will be detached later. */
460071e8ac56SSepherosa Ziehau 		}
460115516c77SSepherosa Ziehau 	}
460215516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
460315516c77SSepherosa Ziehau 
460415516c77SSepherosa Ziehau 	if (error) {
460515516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error);
460615516c77SSepherosa Ziehau 	} else {
460715516c77SSepherosa Ziehau 		if (bootverbose) {
460815516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "%d sub-channels attached\n",
460915516c77SSepherosa Ziehau 			    subchan_cnt);
461015516c77SSepherosa Ziehau 		}
461115516c77SSepherosa Ziehau 	}
461215516c77SSepherosa Ziehau 	return (error);
461315516c77SSepherosa Ziehau }
461415516c77SSepherosa Ziehau 
461515516c77SSepherosa Ziehau static void
461615516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc)
461715516c77SSepherosa Ziehau {
461815516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
461915516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
462015516c77SSepherosa Ziehau 	int i;
462115516c77SSepherosa Ziehau 
462215516c77SSepherosa Ziehau 	if (subchan_cnt == 0)
462315516c77SSepherosa Ziehau 		goto back;
462415516c77SSepherosa Ziehau 
462515516c77SSepherosa Ziehau 	/* Detach the sub-channels. */
462615516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
462715516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i)
462815516c77SSepherosa Ziehau 		hn_chan_detach(sc, subchans[i]);
462915516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
463015516c77SSepherosa Ziehau 
463115516c77SSepherosa Ziehau back:
463215516c77SSepherosa Ziehau 	/*
463315516c77SSepherosa Ziehau 	 * Detach the primary channel, _after_ all sub-channels
463415516c77SSepherosa Ziehau 	 * are detached.
463515516c77SSepherosa Ziehau 	 */
463615516c77SSepherosa Ziehau 	hn_chan_detach(sc, sc->hn_prichan);
463715516c77SSepherosa Ziehau 
463815516c77SSepherosa Ziehau 	/* Wait for sub-channels to be destroyed, if any. */
463915516c77SSepherosa Ziehau 	vmbus_subchan_drain(sc->hn_prichan);
464015516c77SSepherosa Ziehau 
464115516c77SSepherosa Ziehau #ifdef INVARIANTS
464215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
464315516c77SSepherosa Ziehau 		KASSERT((sc->hn_rx_ring[i].hn_rx_flags &
464415516c77SSepherosa Ziehau 		    HN_RX_FLAG_ATTACHED) == 0,
464515516c77SSepherosa Ziehau 		    ("%dth RX ring is still attached", i));
464615516c77SSepherosa Ziehau 	}
464715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
464815516c77SSepherosa Ziehau 		KASSERT((sc->hn_tx_ring[i].hn_tx_flags &
464915516c77SSepherosa Ziehau 		    HN_TX_FLAG_ATTACHED) == 0,
465015516c77SSepherosa Ziehau 		    ("%dth TX ring is still attached", i));
465115516c77SSepherosa Ziehau 	}
465215516c77SSepherosa Ziehau #endif
465315516c77SSepherosa Ziehau }
465415516c77SSepherosa Ziehau 
465515516c77SSepherosa Ziehau static int
465615516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch)
465715516c77SSepherosa Ziehau {
465815516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
465915516c77SSepherosa Ziehau 	int nchan, rxr_cnt, error;
466015516c77SSepherosa Ziehau 
466115516c77SSepherosa Ziehau 	nchan = *nsubch + 1;
466215516c77SSepherosa Ziehau 	if (nchan == 1) {
466315516c77SSepherosa Ziehau 		/*
466415516c77SSepherosa Ziehau 		 * Multiple RX/TX rings are not requested.
466515516c77SSepherosa Ziehau 		 */
466615516c77SSepherosa Ziehau 		*nsubch = 0;
466715516c77SSepherosa Ziehau 		return (0);
466815516c77SSepherosa Ziehau 	}
466915516c77SSepherosa Ziehau 
467015516c77SSepherosa Ziehau 	/*
467115516c77SSepherosa Ziehau 	 * Query RSS capabilities, e.g. # of RX rings, and # of indirect
467215516c77SSepherosa Ziehau 	 * table entries.
467315516c77SSepherosa Ziehau 	 */
467415516c77SSepherosa Ziehau 	error = hn_rndis_query_rsscaps(sc, &rxr_cnt);
467515516c77SSepherosa Ziehau 	if (error) {
467615516c77SSepherosa Ziehau 		/* No RSS; this is benign. */
467715516c77SSepherosa Ziehau 		*nsubch = 0;
467815516c77SSepherosa Ziehau 		return (0);
467915516c77SSepherosa Ziehau 	}
468015516c77SSepherosa Ziehau 	if (bootverbose) {
468115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
468215516c77SSepherosa Ziehau 		    rxr_cnt, nchan);
468315516c77SSepherosa Ziehau 	}
468415516c77SSepherosa Ziehau 
468515516c77SSepherosa Ziehau 	if (nchan > rxr_cnt)
468615516c77SSepherosa Ziehau 		nchan = rxr_cnt;
468715516c77SSepherosa Ziehau 	if (nchan == 1) {
468815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n");
468915516c77SSepherosa Ziehau 		*nsubch = 0;
469015516c77SSepherosa Ziehau 		return (0);
469115516c77SSepherosa Ziehau 	}
469215516c77SSepherosa Ziehau 
469315516c77SSepherosa Ziehau 	/*
469415516c77SSepherosa Ziehau 	 * Allocate sub-channels from NVS.
469515516c77SSepherosa Ziehau 	 */
469615516c77SSepherosa Ziehau 	*nsubch = nchan - 1;
469715516c77SSepherosa Ziehau 	error = hn_nvs_alloc_subchans(sc, nsubch);
469815516c77SSepherosa Ziehau 	if (error || *nsubch == 0) {
469915516c77SSepherosa Ziehau 		/* Failed to allocate sub-channels. */
470015516c77SSepherosa Ziehau 		*nsubch = 0;
470115516c77SSepherosa Ziehau 		return (0);
470215516c77SSepherosa Ziehau 	}
470315516c77SSepherosa Ziehau 
470415516c77SSepherosa Ziehau 	/*
470515516c77SSepherosa Ziehau 	 * Wait for all sub-channels to become ready before moving on.
470615516c77SSepherosa Ziehau 	 */
470715516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch);
470815516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, *nsubch);
470915516c77SSepherosa Ziehau 	return (0);
471015516c77SSepherosa Ziehau }
471115516c77SSepherosa Ziehau 
47122494d735SSepherosa Ziehau static bool
47132494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc)
47142494d735SSepherosa Ziehau {
47152494d735SSepherosa Ziehau 	int i;
47162494d735SSepherosa Ziehau 
47172494d735SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_ERRORS)
47182494d735SSepherosa Ziehau 		return (false);
47192494d735SSepherosa Ziehau 
47202494d735SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
47212494d735SSepherosa Ziehau 		const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
47222494d735SSepherosa Ziehau 
47232494d735SSepherosa Ziehau 		if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF)
47242494d735SSepherosa Ziehau 			return (false);
47252494d735SSepherosa Ziehau 	}
47262494d735SSepherosa Ziehau 	return (true);
47272494d735SSepherosa Ziehau }
47282494d735SSepherosa Ziehau 
4729*b3b75d9cSSepherosa Ziehau /*
4730*b3b75d9cSSepherosa Ziehau  * Make sure that the RX filter is zero after the successful
4731*b3b75d9cSSepherosa Ziehau  * RNDIS initialization.
4732*b3b75d9cSSepherosa Ziehau  *
4733*b3b75d9cSSepherosa Ziehau  * NOTE:
4734*b3b75d9cSSepherosa Ziehau  * Under certain conditions on certain versions of Hyper-V,
4735*b3b75d9cSSepherosa Ziehau  * the RNDIS rxfilter is _not_ zero on the hypervisor side
4736*b3b75d9cSSepherosa Ziehau  * after the successful RNDIS initialization, which breaks
4737*b3b75d9cSSepherosa Ziehau  * the assumption of any following code (well, it breaks the
4738*b3b75d9cSSepherosa Ziehau  * RNDIS API contract actually).  Clear the RNDIS rxfilter
4739*b3b75d9cSSepherosa Ziehau  * explicitly, drain packets sneaking through, and drain the
4740*b3b75d9cSSepherosa Ziehau  * interrupt taskqueues scheduled due to the stealth packets.
4741*b3b75d9cSSepherosa Ziehau  */
4742*b3b75d9cSSepherosa Ziehau static void
4743*b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(struct hn_softc *sc, int nchan)
4744*b3b75d9cSSepherosa Ziehau {
4745*b3b75d9cSSepherosa Ziehau 
4746*b3b75d9cSSepherosa Ziehau 	hn_disable_rx(sc);
4747*b3b75d9cSSepherosa Ziehau 	hn_drain_rxtx(sc, nchan);
4748*b3b75d9cSSepherosa Ziehau }
4749*b3b75d9cSSepherosa Ziehau 
475015516c77SSepherosa Ziehau static int
475115516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu)
475215516c77SSepherosa Ziehau {
475371e8ac56SSepherosa Ziehau #define ATTACHED_NVS		0x0002
475471e8ac56SSepherosa Ziehau #define ATTACHED_RNDIS		0x0004
475571e8ac56SSepherosa Ziehau 
475615516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
4757*b3b75d9cSSepherosa Ziehau 	int error, nsubch, nchan = 1, i, rndis_inited;
475871e8ac56SSepherosa Ziehau 	uint32_t old_caps, attached = 0;
475915516c77SSepherosa Ziehau 
476015516c77SSepherosa Ziehau 	KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0,
476115516c77SSepherosa Ziehau 	    ("synthetic parts were attached"));
476215516c77SSepherosa Ziehau 
47632494d735SSepherosa Ziehau 	if (!hn_synth_attachable(sc))
47642494d735SSepherosa Ziehau 		return (ENXIO);
47652494d735SSepherosa Ziehau 
476615516c77SSepherosa Ziehau 	/* Save capabilities for later verification. */
476715516c77SSepherosa Ziehau 	old_caps = sc->hn_caps;
476815516c77SSepherosa Ziehau 	sc->hn_caps = 0;
476915516c77SSepherosa Ziehau 
477015516c77SSepherosa Ziehau 	/* Clear RSS stuffs. */
477115516c77SSepherosa Ziehau 	sc->hn_rss_ind_size = 0;
477215516c77SSepherosa Ziehau 	sc->hn_rss_hash = 0;
477315516c77SSepherosa Ziehau 
477415516c77SSepherosa Ziehau 	/*
477515516c77SSepherosa Ziehau 	 * Attach the primary channel _before_ attaching NVS and RNDIS.
477615516c77SSepherosa Ziehau 	 */
477715516c77SSepherosa Ziehau 	error = hn_chan_attach(sc, sc->hn_prichan);
477815516c77SSepherosa Ziehau 	if (error)
477971e8ac56SSepherosa Ziehau 		goto failed;
478015516c77SSepherosa Ziehau 
478115516c77SSepherosa Ziehau 	/*
478215516c77SSepherosa Ziehau 	 * Attach NVS.
478315516c77SSepherosa Ziehau 	 */
478415516c77SSepherosa Ziehau 	error = hn_nvs_attach(sc, mtu);
478515516c77SSepherosa Ziehau 	if (error)
478671e8ac56SSepherosa Ziehau 		goto failed;
478771e8ac56SSepherosa Ziehau 	attached |= ATTACHED_NVS;
478815516c77SSepherosa Ziehau 
478915516c77SSepherosa Ziehau 	/*
479015516c77SSepherosa Ziehau 	 * Attach RNDIS _after_ NVS is attached.
479115516c77SSepherosa Ziehau 	 */
4792*b3b75d9cSSepherosa Ziehau 	error = hn_rndis_attach(sc, mtu, &rndis_inited);
4793*b3b75d9cSSepherosa Ziehau 	if (rndis_inited)
4794*b3b75d9cSSepherosa Ziehau 		attached |= ATTACHED_RNDIS;
479515516c77SSepherosa Ziehau 	if (error)
479671e8ac56SSepherosa Ziehau 		goto failed;
479715516c77SSepherosa Ziehau 
479815516c77SSepherosa Ziehau 	/*
479915516c77SSepherosa Ziehau 	 * Make sure capabilities are not changed.
480015516c77SSepherosa Ziehau 	 */
480115516c77SSepherosa Ziehau 	if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) {
480215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n",
480315516c77SSepherosa Ziehau 		    old_caps, sc->hn_caps);
480471e8ac56SSepherosa Ziehau 		error = ENXIO;
480571e8ac56SSepherosa Ziehau 		goto failed;
480615516c77SSepherosa Ziehau 	}
480715516c77SSepherosa Ziehau 
480815516c77SSepherosa Ziehau 	/*
480915516c77SSepherosa Ziehau 	 * Allocate sub-channels for multi-TX/RX rings.
481015516c77SSepherosa Ziehau 	 *
481115516c77SSepherosa Ziehau 	 * NOTE:
481215516c77SSepherosa Ziehau 	 * The # of RX rings that can be used is equivalent to the # of
481315516c77SSepherosa Ziehau 	 * channels to be requested.
481415516c77SSepherosa Ziehau 	 */
481515516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_cnt - 1;
481615516c77SSepherosa Ziehau 	error = hn_synth_alloc_subchans(sc, &nsubch);
481715516c77SSepherosa Ziehau 	if (error)
481871e8ac56SSepherosa Ziehau 		goto failed;
481971e8ac56SSepherosa Ziehau 	/* NOTE: _Full_ synthetic parts detach is required now. */
482071e8ac56SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED;
482115516c77SSepherosa Ziehau 
482271e8ac56SSepherosa Ziehau 	/*
482371e8ac56SSepherosa Ziehau 	 * Set the # of TX/RX rings that could be used according to
482471e8ac56SSepherosa Ziehau 	 * the # of channels that NVS offered.
482571e8ac56SSepherosa Ziehau 	 */
482615516c77SSepherosa Ziehau 	nchan = nsubch + 1;
482771e8ac56SSepherosa Ziehau 	hn_set_ring_inuse(sc, nchan);
482815516c77SSepherosa Ziehau 	if (nchan == 1) {
482915516c77SSepherosa Ziehau 		/* Only the primary channel can be used; done */
483015516c77SSepherosa Ziehau 		goto back;
483115516c77SSepherosa Ziehau 	}
483215516c77SSepherosa Ziehau 
483315516c77SSepherosa Ziehau 	/*
483471e8ac56SSepherosa Ziehau 	 * Attach the sub-channels.
4835afd4971bSSepherosa Ziehau 	 *
4836afd4971bSSepherosa Ziehau 	 * NOTE: hn_set_ring_inuse() _must_ have been called.
483715516c77SSepherosa Ziehau 	 */
483871e8ac56SSepherosa Ziehau 	error = hn_attach_subchans(sc);
483971e8ac56SSepherosa Ziehau 	if (error)
484071e8ac56SSepherosa Ziehau 		goto failed;
484115516c77SSepherosa Ziehau 
484271e8ac56SSepherosa Ziehau 	/*
484371e8ac56SSepherosa Ziehau 	 * Configure RSS key and indirect table _after_ all sub-channels
484471e8ac56SSepherosa Ziehau 	 * are attached.
484571e8ac56SSepherosa Ziehau 	 */
484615516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) {
484715516c77SSepherosa Ziehau 		/*
484815516c77SSepherosa Ziehau 		 * RSS key is not set yet; set it to the default RSS key.
484915516c77SSepherosa Ziehau 		 */
485015516c77SSepherosa Ziehau 		if (bootverbose)
485115516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS key\n");
485234d68912SSepherosa Ziehau #ifdef RSS
485334d68912SSepherosa Ziehau 		rss_getkey(rss->rss_key);
485434d68912SSepherosa Ziehau #else
485515516c77SSepherosa Ziehau 		memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key));
485634d68912SSepherosa Ziehau #endif
485715516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
485815516c77SSepherosa Ziehau 	}
485915516c77SSepherosa Ziehau 
486015516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) {
486115516c77SSepherosa Ziehau 		/*
486215516c77SSepherosa Ziehau 		 * RSS indirect table is not set yet; set it up in round-
486315516c77SSepherosa Ziehau 		 * robin fashion.
486415516c77SSepherosa Ziehau 		 */
486515516c77SSepherosa Ziehau 		if (bootverbose) {
486615516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS indirect "
486715516c77SSepherosa Ziehau 			    "table\n");
486815516c77SSepherosa Ziehau 		}
486934d68912SSepherosa Ziehau 		for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
487034d68912SSepherosa Ziehau 			uint32_t subidx;
487134d68912SSepherosa Ziehau 
487234d68912SSepherosa Ziehau #ifdef RSS
487334d68912SSepherosa Ziehau 			subidx = rss_get_indirection_to_bucket(i);
487434d68912SSepherosa Ziehau #else
487534d68912SSepherosa Ziehau 			subidx = i;
487634d68912SSepherosa Ziehau #endif
487734d68912SSepherosa Ziehau 			rss->rss_ind[i] = subidx % nchan;
487834d68912SSepherosa Ziehau 		}
487915516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSIND;
488015516c77SSepherosa Ziehau 	} else {
488115516c77SSepherosa Ziehau 		/*
488215516c77SSepherosa Ziehau 		 * # of usable channels may be changed, so we have to
488315516c77SSepherosa Ziehau 		 * make sure that all entries in RSS indirect table
488415516c77SSepherosa Ziehau 		 * are valid.
4885afd4971bSSepherosa Ziehau 		 *
4886afd4971bSSepherosa Ziehau 		 * NOTE: hn_set_ring_inuse() _must_ have been called.
488715516c77SSepherosa Ziehau 		 */
4888afd4971bSSepherosa Ziehau 		hn_rss_ind_fixup(sc);
488915516c77SSepherosa Ziehau 	}
489015516c77SSepherosa Ziehau 
489115516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
489215516c77SSepherosa Ziehau 	if (error)
489371e8ac56SSepherosa Ziehau 		goto failed;
489471e8ac56SSepherosa Ziehau back:
4895dc13fee6SSepherosa Ziehau 	/*
4896dc13fee6SSepherosa Ziehau 	 * Fixup transmission aggregation setup.
4897dc13fee6SSepherosa Ziehau 	 */
4898dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
4899*b3b75d9cSSepherosa Ziehau 	hn_rndis_init_fixat(sc, nchan);
490015516c77SSepherosa Ziehau 	return (0);
490171e8ac56SSepherosa Ziehau 
490271e8ac56SSepherosa Ziehau failed:
490371e8ac56SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
4904*b3b75d9cSSepherosa Ziehau 		hn_rndis_init_fixat(sc, nchan);
490571e8ac56SSepherosa Ziehau 		hn_synth_detach(sc);
490671e8ac56SSepherosa Ziehau 	} else {
4907*b3b75d9cSSepherosa Ziehau 		if (attached & ATTACHED_RNDIS) {
4908*b3b75d9cSSepherosa Ziehau 			hn_rndis_init_fixat(sc, nchan);
490971e8ac56SSepherosa Ziehau 			hn_rndis_detach(sc);
4910*b3b75d9cSSepherosa Ziehau 		}
491171e8ac56SSepherosa Ziehau 		if (attached & ATTACHED_NVS)
491271e8ac56SSepherosa Ziehau 			hn_nvs_detach(sc);
491371e8ac56SSepherosa Ziehau 		hn_chan_detach(sc, sc->hn_prichan);
491471e8ac56SSepherosa Ziehau 		/* Restore old capabilities. */
491571e8ac56SSepherosa Ziehau 		sc->hn_caps = old_caps;
491671e8ac56SSepherosa Ziehau 	}
491771e8ac56SSepherosa Ziehau 	return (error);
491871e8ac56SSepherosa Ziehau 
491971e8ac56SSepherosa Ziehau #undef ATTACHED_RNDIS
492071e8ac56SSepherosa Ziehau #undef ATTACHED_NVS
492115516c77SSepherosa Ziehau }
492215516c77SSepherosa Ziehau 
492315516c77SSepherosa Ziehau /*
492415516c77SSepherosa Ziehau  * NOTE:
492515516c77SSepherosa Ziehau  * The interface must have been suspended though hn_suspend(), before
492615516c77SSepherosa Ziehau  * this function get called.
492715516c77SSepherosa Ziehau  */
492815516c77SSepherosa Ziehau static void
492915516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc)
493015516c77SSepherosa Ziehau {
493115516c77SSepherosa Ziehau 
493215516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
493315516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
493415516c77SSepherosa Ziehau 
493515516c77SSepherosa Ziehau 	/* Detach the RNDIS first. */
493615516c77SSepherosa Ziehau 	hn_rndis_detach(sc);
493715516c77SSepherosa Ziehau 
493815516c77SSepherosa Ziehau 	/* Detach NVS. */
493915516c77SSepherosa Ziehau 	hn_nvs_detach(sc);
494015516c77SSepherosa Ziehau 
494115516c77SSepherosa Ziehau 	/* Detach all of the channels. */
494215516c77SSepherosa Ziehau 	hn_detach_allchans(sc);
494315516c77SSepherosa Ziehau 
494415516c77SSepherosa Ziehau 	sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED;
494515516c77SSepherosa Ziehau }
494615516c77SSepherosa Ziehau 
494715516c77SSepherosa Ziehau static void
494815516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt)
494915516c77SSepherosa Ziehau {
495015516c77SSepherosa Ziehau 	KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt,
495115516c77SSepherosa Ziehau 	    ("invalid ring count %d", ring_cnt));
495215516c77SSepherosa Ziehau 
495315516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt > ring_cnt)
495415516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = ring_cnt;
495515516c77SSepherosa Ziehau 	else
495615516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
495715516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = ring_cnt;
495815516c77SSepherosa Ziehau 
495934d68912SSepherosa Ziehau #ifdef RSS
496034d68912SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse != rss_getnumbuckets()) {
496134d68912SSepherosa Ziehau 		if_printf(sc->hn_ifp, "# of RX rings (%d) does not match "
496234d68912SSepherosa Ziehau 		    "# of RSS buckets (%d)\n", sc->hn_rx_ring_inuse,
496334d68912SSepherosa Ziehau 		    rss_getnumbuckets());
496434d68912SSepherosa Ziehau 	}
496534d68912SSepherosa Ziehau #endif
496634d68912SSepherosa Ziehau 
496715516c77SSepherosa Ziehau 	if (bootverbose) {
496815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n",
496915516c77SSepherosa Ziehau 		    sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
497015516c77SSepherosa Ziehau 	}
497115516c77SSepherosa Ziehau }
497215516c77SSepherosa Ziehau 
497315516c77SSepherosa Ziehau static void
497425641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan)
497515516c77SSepherosa Ziehau {
497615516c77SSepherosa Ziehau 
497725641fc7SSepherosa Ziehau 	/*
497825641fc7SSepherosa Ziehau 	 * NOTE:
497925641fc7SSepherosa Ziehau 	 * The TX bufring will not be drained by the hypervisor,
498025641fc7SSepherosa Ziehau 	 * if the primary channel is revoked.
498125641fc7SSepherosa Ziehau 	 */
498225641fc7SSepherosa Ziehau 	while (!vmbus_chan_rx_empty(chan) ||
498325641fc7SSepherosa Ziehau 	    (!vmbus_chan_is_revoked(sc->hn_prichan) &&
498425641fc7SSepherosa Ziehau 	     !vmbus_chan_tx_empty(chan)))
498515516c77SSepherosa Ziehau 		pause("waitch", 1);
498615516c77SSepherosa Ziehau 	vmbus_chan_intr_drain(chan);
498715516c77SSepherosa Ziehau }
498815516c77SSepherosa Ziehau 
498915516c77SSepherosa Ziehau static void
4990*b3b75d9cSSepherosa Ziehau hn_disable_rx(struct hn_softc *sc)
4991*b3b75d9cSSepherosa Ziehau {
4992*b3b75d9cSSepherosa Ziehau 
4993*b3b75d9cSSepherosa Ziehau 	/*
4994*b3b75d9cSSepherosa Ziehau 	 * Disable RX by clearing RX filter forcefully.
4995*b3b75d9cSSepherosa Ziehau 	 */
4996*b3b75d9cSSepherosa Ziehau 	sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE;
4997*b3b75d9cSSepherosa Ziehau 	hn_rndis_set_rxfilter(sc, sc->hn_rx_filter); /* ignore error */
4998*b3b75d9cSSepherosa Ziehau 
4999*b3b75d9cSSepherosa Ziehau 	/*
5000*b3b75d9cSSepherosa Ziehau 	 * Give RNDIS enough time to flush all pending data packets.
5001*b3b75d9cSSepherosa Ziehau 	 */
5002*b3b75d9cSSepherosa Ziehau 	pause("waitrx", (200 * hz) / 1000);
5003*b3b75d9cSSepherosa Ziehau }
5004*b3b75d9cSSepherosa Ziehau 
5005*b3b75d9cSSepherosa Ziehau /*
5006*b3b75d9cSSepherosa Ziehau  * NOTE:
5007*b3b75d9cSSepherosa Ziehau  * RX/TX _must_ have been suspended/disabled, before this function
5008*b3b75d9cSSepherosa Ziehau  * is called.
5009*b3b75d9cSSepherosa Ziehau  */
5010*b3b75d9cSSepherosa Ziehau static void
5011*b3b75d9cSSepherosa Ziehau hn_drain_rxtx(struct hn_softc *sc, int nchan)
501215516c77SSepherosa Ziehau {
501315516c77SSepherosa Ziehau 	struct vmbus_channel **subch = NULL;
5014*b3b75d9cSSepherosa Ziehau 	int nsubch;
5015*b3b75d9cSSepherosa Ziehau 
5016*b3b75d9cSSepherosa Ziehau 	/*
5017*b3b75d9cSSepherosa Ziehau 	 * Drain RX/TX bufrings and interrupts.
5018*b3b75d9cSSepherosa Ziehau 	 */
5019*b3b75d9cSSepherosa Ziehau 	nsubch = nchan - 1;
5020*b3b75d9cSSepherosa Ziehau 	if (nsubch > 0)
5021*b3b75d9cSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
5022*b3b75d9cSSepherosa Ziehau 
5023*b3b75d9cSSepherosa Ziehau 	if (subch != NULL) {
5024*b3b75d9cSSepherosa Ziehau 		int i;
5025*b3b75d9cSSepherosa Ziehau 
5026*b3b75d9cSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
5027*b3b75d9cSSepherosa Ziehau 			hn_chan_drain(sc, subch[i]);
5028*b3b75d9cSSepherosa Ziehau 	}
5029*b3b75d9cSSepherosa Ziehau 	hn_chan_drain(sc, sc->hn_prichan);
5030*b3b75d9cSSepherosa Ziehau 
5031*b3b75d9cSSepherosa Ziehau 	if (subch != NULL)
5032*b3b75d9cSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
5033*b3b75d9cSSepherosa Ziehau }
5034*b3b75d9cSSepherosa Ziehau 
5035*b3b75d9cSSepherosa Ziehau static void
5036*b3b75d9cSSepherosa Ziehau hn_suspend_data(struct hn_softc *sc)
5037*b3b75d9cSSepherosa Ziehau {
503825641fc7SSepherosa Ziehau 	struct hn_tx_ring *txr;
5039*b3b75d9cSSepherosa Ziehau 	int i;
504015516c77SSepherosa Ziehau 
504115516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
504215516c77SSepherosa Ziehau 
504315516c77SSepherosa Ziehau 	/*
504415516c77SSepherosa Ziehau 	 * Suspend TX.
504515516c77SSepherosa Ziehau 	 */
504615516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
504725641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
504815516c77SSepherosa Ziehau 
504915516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
505015516c77SSepherosa Ziehau 		txr->hn_suspended = 1;
505115516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
505215516c77SSepherosa Ziehau 		/* No one is able send more packets now. */
505315516c77SSepherosa Ziehau 
505425641fc7SSepherosa Ziehau 		/*
505525641fc7SSepherosa Ziehau 		 * Wait for all pending sends to finish.
505625641fc7SSepherosa Ziehau 		 *
505725641fc7SSepherosa Ziehau 		 * NOTE:
505825641fc7SSepherosa Ziehau 		 * We will _not_ receive all pending send-done, if the
505925641fc7SSepherosa Ziehau 		 * primary channel is revoked.
506025641fc7SSepherosa Ziehau 		 */
506125641fc7SSepherosa Ziehau 		while (hn_tx_ring_pending(txr) &&
506225641fc7SSepherosa Ziehau 		    !vmbus_chan_is_revoked(sc->hn_prichan))
506315516c77SSepherosa Ziehau 			pause("hnwtx", 1 /* 1 tick */);
506415516c77SSepherosa Ziehau 	}
506515516c77SSepherosa Ziehau 
506615516c77SSepherosa Ziehau 	/*
5067*b3b75d9cSSepherosa Ziehau 	 * Disable RX.
506815516c77SSepherosa Ziehau 	 */
5069*b3b75d9cSSepherosa Ziehau 	hn_disable_rx(sc);
507015516c77SSepherosa Ziehau 
507115516c77SSepherosa Ziehau 	/*
5072*b3b75d9cSSepherosa Ziehau 	 * Drain RX/TX.
507315516c77SSepherosa Ziehau 	 */
5074*b3b75d9cSSepherosa Ziehau 	hn_drain_rxtx(sc, sc->hn_rx_ring_inuse);
507525641fc7SSepherosa Ziehau 
507625641fc7SSepherosa Ziehau 	/*
507725641fc7SSepherosa Ziehau 	 * Drain any pending TX tasks.
507825641fc7SSepherosa Ziehau 	 *
507925641fc7SSepherosa Ziehau 	 * NOTE:
5080*b3b75d9cSSepherosa Ziehau 	 * The above hn_drain_rxtx() can dispatch TX tasks, so the TX
5081*b3b75d9cSSepherosa Ziehau 	 * tasks will have to be drained _after_ the above hn_drain_rxtx().
508225641fc7SSepherosa Ziehau 	 */
508325641fc7SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
508425641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
508525641fc7SSepherosa Ziehau 
508625641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task);
508725641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task);
508825641fc7SSepherosa Ziehau 	}
508915516c77SSepherosa Ziehau }
509015516c77SSepherosa Ziehau 
509115516c77SSepherosa Ziehau static void
509215516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused)
509315516c77SSepherosa Ziehau {
509415516c77SSepherosa Ziehau 
509515516c77SSepherosa Ziehau 	((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL;
509615516c77SSepherosa Ziehau }
509715516c77SSepherosa Ziehau 
509815516c77SSepherosa Ziehau static void
509915516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc)
510015516c77SSepherosa Ziehau {
510115516c77SSepherosa Ziehau 	struct task task;
510215516c77SSepherosa Ziehau 
510315516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
510415516c77SSepherosa Ziehau 
510515516c77SSepherosa Ziehau 	/*
510615516c77SSepherosa Ziehau 	 * Make sure that hn_mgmt_taskq0 can nolonger be accessed
510715516c77SSepherosa Ziehau 	 * through hn_mgmt_taskq.
510815516c77SSepherosa Ziehau 	 */
510915516c77SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc);
511015516c77SSepherosa Ziehau 	vmbus_chan_run_task(sc->hn_prichan, &task);
511115516c77SSepherosa Ziehau 
511215516c77SSepherosa Ziehau 	/*
511315516c77SSepherosa Ziehau 	 * Make sure that all pending management tasks are completed.
511415516c77SSepherosa Ziehau 	 */
511515516c77SSepherosa Ziehau 	taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init);
511615516c77SSepherosa Ziehau 	taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status);
511715516c77SSepherosa Ziehau 	taskqueue_drain_all(sc->hn_mgmt_taskq0);
511815516c77SSepherosa Ziehau }
511915516c77SSepherosa Ziehau 
512015516c77SSepherosa Ziehau static void
512115516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc)
512215516c77SSepherosa Ziehau {
512315516c77SSepherosa Ziehau 
512487f8129dSSepherosa Ziehau 	/* Disable polling. */
512587f8129dSSepherosa Ziehau 	hn_polling(sc, 0);
512687f8129dSSepherosa Ziehau 
51275bdfd3fdSDexuan Cui 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
51285bdfd3fdSDexuan Cui 	    (sc->hn_flags & HN_FLAG_VF))
512915516c77SSepherosa Ziehau 		hn_suspend_data(sc);
513015516c77SSepherosa Ziehau 	hn_suspend_mgmt(sc);
513115516c77SSepherosa Ziehau }
513215516c77SSepherosa Ziehau 
513315516c77SSepherosa Ziehau static void
513415516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt)
513515516c77SSepherosa Ziehau {
513615516c77SSepherosa Ziehau 	int i;
513715516c77SSepherosa Ziehau 
513815516c77SSepherosa Ziehau 	KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt,
513915516c77SSepherosa Ziehau 	    ("invalid TX ring count %d", tx_ring_cnt));
514015516c77SSepherosa Ziehau 
514115516c77SSepherosa Ziehau 	for (i = 0; i < tx_ring_cnt; ++i) {
514215516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
514315516c77SSepherosa Ziehau 
514415516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
514515516c77SSepherosa Ziehau 		txr->hn_suspended = 0;
514615516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
514715516c77SSepherosa Ziehau 	}
514815516c77SSepherosa Ziehau }
514915516c77SSepherosa Ziehau 
515015516c77SSepherosa Ziehau static void
515115516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc)
515215516c77SSepherosa Ziehau {
515315516c77SSepherosa Ziehau 	int i;
515415516c77SSepherosa Ziehau 
515515516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
515615516c77SSepherosa Ziehau 
515715516c77SSepherosa Ziehau 	/*
515815516c77SSepherosa Ziehau 	 * Re-enable RX.
515915516c77SSepherosa Ziehau 	 */
5160c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
516115516c77SSepherosa Ziehau 
516215516c77SSepherosa Ziehau 	/*
516315516c77SSepherosa Ziehau 	 * Make sure to clear suspend status on "all" TX rings,
516415516c77SSepherosa Ziehau 	 * since hn_tx_ring_inuse can be changed after
516515516c77SSepherosa Ziehau 	 * hn_suspend_data().
516615516c77SSepherosa Ziehau 	 */
516715516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_cnt);
516815516c77SSepherosa Ziehau 
516923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
517023bf9e15SSepherosa Ziehau 	if (!hn_use_if_start)
517123bf9e15SSepherosa Ziehau #endif
517223bf9e15SSepherosa Ziehau 	{
517315516c77SSepherosa Ziehau 		/*
517415516c77SSepherosa Ziehau 		 * Flush unused drbrs, since hn_tx_ring_inuse may be
517515516c77SSepherosa Ziehau 		 * reduced.
517615516c77SSepherosa Ziehau 		 */
517715516c77SSepherosa Ziehau 		for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i)
517815516c77SSepherosa Ziehau 			hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
517915516c77SSepherosa Ziehau 	}
518015516c77SSepherosa Ziehau 
518115516c77SSepherosa Ziehau 	/*
518215516c77SSepherosa Ziehau 	 * Kick start TX.
518315516c77SSepherosa Ziehau 	 */
518415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
518515516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
518615516c77SSepherosa Ziehau 
518715516c77SSepherosa Ziehau 		/*
518815516c77SSepherosa Ziehau 		 * Use txeof task, so that any pending oactive can be
518915516c77SSepherosa Ziehau 		 * cleared properly.
519015516c77SSepherosa Ziehau 		 */
519115516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
519215516c77SSepherosa Ziehau 	}
519315516c77SSepherosa Ziehau }
519415516c77SSepherosa Ziehau 
519515516c77SSepherosa Ziehau static void
519615516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc)
519715516c77SSepherosa Ziehau {
519815516c77SSepherosa Ziehau 
519915516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
520015516c77SSepherosa Ziehau 
520115516c77SSepherosa Ziehau 	/*
520215516c77SSepherosa Ziehau 	 * Kick off network change detection, if it was pending.
520315516c77SSepherosa Ziehau 	 * If no network change was pending, start link status
520415516c77SSepherosa Ziehau 	 * checks, which is more lightweight than network change
520515516c77SSepherosa Ziehau 	 * detection.
520615516c77SSepherosa Ziehau 	 */
520715516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
520815516c77SSepherosa Ziehau 		hn_change_network(sc);
520915516c77SSepherosa Ziehau 	else
521015516c77SSepherosa Ziehau 		hn_update_link_status(sc);
521115516c77SSepherosa Ziehau }
521215516c77SSepherosa Ziehau 
521315516c77SSepherosa Ziehau static void
521415516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc)
521515516c77SSepherosa Ziehau {
521615516c77SSepherosa Ziehau 
52175bdfd3fdSDexuan Cui 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
52185bdfd3fdSDexuan Cui 	    (sc->hn_flags & HN_FLAG_VF))
521915516c77SSepherosa Ziehau 		hn_resume_data(sc);
52205bdfd3fdSDexuan Cui 
52215bdfd3fdSDexuan Cui 	/*
52225bdfd3fdSDexuan Cui 	 * When the VF is activated, the synthetic interface is changed
52235bdfd3fdSDexuan Cui 	 * to DOWN in hn_set_vf(). Here, if the VF is still active, we
52245bdfd3fdSDexuan Cui 	 * don't call hn_resume_mgmt() until the VF is deactivated in
52255bdfd3fdSDexuan Cui 	 * hn_set_vf().
52265bdfd3fdSDexuan Cui 	 */
52275bdfd3fdSDexuan Cui 	if (!(sc->hn_flags & HN_FLAG_VF))
522815516c77SSepherosa Ziehau 		hn_resume_mgmt(sc);
522987f8129dSSepherosa Ziehau 
523087f8129dSSepherosa Ziehau 	/*
523187f8129dSSepherosa Ziehau 	 * Re-enable polling if this interface is running and
523287f8129dSSepherosa Ziehau 	 * the polling is requested.
523387f8129dSSepherosa Ziehau 	 */
523487f8129dSSepherosa Ziehau 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->hn_pollhz > 0)
523587f8129dSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
523615516c77SSepherosa Ziehau }
523715516c77SSepherosa Ziehau 
523815516c77SSepherosa Ziehau static void
523915516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen)
524015516c77SSepherosa Ziehau {
524115516c77SSepherosa Ziehau 	const struct rndis_status_msg *msg;
524215516c77SSepherosa Ziehau 	int ofs;
524315516c77SSepherosa Ziehau 
524415516c77SSepherosa Ziehau 	if (dlen < sizeof(*msg)) {
524515516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid RNDIS status\n");
524615516c77SSepherosa Ziehau 		return;
524715516c77SSepherosa Ziehau 	}
524815516c77SSepherosa Ziehau 	msg = data;
524915516c77SSepherosa Ziehau 
525015516c77SSepherosa Ziehau 	switch (msg->rm_status) {
525115516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_CONNECT:
525215516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_DISCONNECT:
525315516c77SSepherosa Ziehau 		hn_update_link_status(sc);
525415516c77SSepherosa Ziehau 		break;
525515516c77SSepherosa Ziehau 
525615516c77SSepherosa Ziehau 	case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
525715516c77SSepherosa Ziehau 		/* Not really useful; ignore. */
525815516c77SSepherosa Ziehau 		break;
525915516c77SSepherosa Ziehau 
526015516c77SSepherosa Ziehau 	case RNDIS_STATUS_NETWORK_CHANGE:
526115516c77SSepherosa Ziehau 		ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
526215516c77SSepherosa Ziehau 		if (dlen < ofs + msg->rm_stbuflen ||
526315516c77SSepherosa Ziehau 		    msg->rm_stbuflen < sizeof(uint32_t)) {
526415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed\n");
526515516c77SSepherosa Ziehau 		} else {
526615516c77SSepherosa Ziehau 			uint32_t change;
526715516c77SSepherosa Ziehau 
526815516c77SSepherosa Ziehau 			memcpy(&change, ((const uint8_t *)msg) + ofs,
526915516c77SSepherosa Ziehau 			    sizeof(change));
527015516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed, change %u\n",
527115516c77SSepherosa Ziehau 			    change);
527215516c77SSepherosa Ziehau 		}
527315516c77SSepherosa Ziehau 		hn_change_network(sc);
527415516c77SSepherosa Ziehau 		break;
527515516c77SSepherosa Ziehau 
527615516c77SSepherosa Ziehau 	default:
527715516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
527815516c77SSepherosa Ziehau 		    msg->rm_status);
527915516c77SSepherosa Ziehau 		break;
528015516c77SSepherosa Ziehau 	}
528115516c77SSepherosa Ziehau }
528215516c77SSepherosa Ziehau 
528315516c77SSepherosa Ziehau static int
528415516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info)
528515516c77SSepherosa Ziehau {
528615516c77SSepherosa Ziehau 	const struct rndis_pktinfo *pi = info_data;
528715516c77SSepherosa Ziehau 	uint32_t mask = 0;
528815516c77SSepherosa Ziehau 
528915516c77SSepherosa Ziehau 	while (info_dlen != 0) {
529015516c77SSepherosa Ziehau 		const void *data;
529115516c77SSepherosa Ziehau 		uint32_t dlen;
529215516c77SSepherosa Ziehau 
529315516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < sizeof(*pi)))
529415516c77SSepherosa Ziehau 			return (EINVAL);
529515516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < pi->rm_size))
529615516c77SSepherosa Ziehau 			return (EINVAL);
529715516c77SSepherosa Ziehau 		info_dlen -= pi->rm_size;
529815516c77SSepherosa Ziehau 
529915516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
530015516c77SSepherosa Ziehau 			return (EINVAL);
530115516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
530215516c77SSepherosa Ziehau 			return (EINVAL);
530315516c77SSepherosa Ziehau 		dlen = pi->rm_size - pi->rm_pktinfooffset;
530415516c77SSepherosa Ziehau 		data = pi->rm_data;
530515516c77SSepherosa Ziehau 
530615516c77SSepherosa Ziehau 		switch (pi->rm_type) {
530715516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_VLAN:
530815516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
530915516c77SSepherosa Ziehau 				return (EINVAL);
531015516c77SSepherosa Ziehau 			info->vlan_info = *((const uint32_t *)data);
531115516c77SSepherosa Ziehau 			mask |= HN_RXINFO_VLAN;
531215516c77SSepherosa Ziehau 			break;
531315516c77SSepherosa Ziehau 
531415516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_CSUM:
531515516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
531615516c77SSepherosa Ziehau 				return (EINVAL);
531715516c77SSepherosa Ziehau 			info->csum_info = *((const uint32_t *)data);
531815516c77SSepherosa Ziehau 			mask |= HN_RXINFO_CSUM;
531915516c77SSepherosa Ziehau 			break;
532015516c77SSepherosa Ziehau 
532115516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHVAL:
532215516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
532315516c77SSepherosa Ziehau 				return (EINVAL);
532415516c77SSepherosa Ziehau 			info->hash_value = *((const uint32_t *)data);
532515516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHVAL;
532615516c77SSepherosa Ziehau 			break;
532715516c77SSepherosa Ziehau 
532815516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHINF:
532915516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
533015516c77SSepherosa Ziehau 				return (EINVAL);
533115516c77SSepherosa Ziehau 			info->hash_info = *((const uint32_t *)data);
533215516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHINF;
533315516c77SSepherosa Ziehau 			break;
533415516c77SSepherosa Ziehau 
533515516c77SSepherosa Ziehau 		default:
533615516c77SSepherosa Ziehau 			goto next;
533715516c77SSepherosa Ziehau 		}
533815516c77SSepherosa Ziehau 
533915516c77SSepherosa Ziehau 		if (mask == HN_RXINFO_ALL) {
534015516c77SSepherosa Ziehau 			/* All found; done */
534115516c77SSepherosa Ziehau 			break;
534215516c77SSepherosa Ziehau 		}
534315516c77SSepherosa Ziehau next:
534415516c77SSepherosa Ziehau 		pi = (const struct rndis_pktinfo *)
534515516c77SSepherosa Ziehau 		    ((const uint8_t *)pi + pi->rm_size);
534615516c77SSepherosa Ziehau 	}
534715516c77SSepherosa Ziehau 
534815516c77SSepherosa Ziehau 	/*
534915516c77SSepherosa Ziehau 	 * Final fixup.
535015516c77SSepherosa Ziehau 	 * - If there is no hash value, invalidate the hash info.
535115516c77SSepherosa Ziehau 	 */
535215516c77SSepherosa Ziehau 	if ((mask & HN_RXINFO_HASHVAL) == 0)
535315516c77SSepherosa Ziehau 		info->hash_info = HN_NDIS_HASH_INFO_INVALID;
535415516c77SSepherosa Ziehau 	return (0);
535515516c77SSepherosa Ziehau }
535615516c77SSepherosa Ziehau 
535715516c77SSepherosa Ziehau static __inline bool
535815516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
535915516c77SSepherosa Ziehau {
536015516c77SSepherosa Ziehau 
536115516c77SSepherosa Ziehau 	if (off < check_off) {
536215516c77SSepherosa Ziehau 		if (__predict_true(off + len <= check_off))
536315516c77SSepherosa Ziehau 			return (false);
536415516c77SSepherosa Ziehau 	} else if (off > check_off) {
536515516c77SSepherosa Ziehau 		if (__predict_true(check_off + check_len <= off))
536615516c77SSepherosa Ziehau 			return (false);
536715516c77SSepherosa Ziehau 	}
536815516c77SSepherosa Ziehau 	return (true);
536915516c77SSepherosa Ziehau }
537015516c77SSepherosa Ziehau 
537115516c77SSepherosa Ziehau static void
537215516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen)
537315516c77SSepherosa Ziehau {
537415516c77SSepherosa Ziehau 	const struct rndis_packet_msg *pkt;
537515516c77SSepherosa Ziehau 	struct hn_rxinfo info;
537615516c77SSepherosa Ziehau 	int data_off, pktinfo_off, data_len, pktinfo_len;
537715516c77SSepherosa Ziehau 
537815516c77SSepherosa Ziehau 	/*
537915516c77SSepherosa Ziehau 	 * Check length.
538015516c77SSepherosa Ziehau 	 */
538115516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*pkt))) {
538215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
538315516c77SSepherosa Ziehau 		return;
538415516c77SSepherosa Ziehau 	}
538515516c77SSepherosa Ziehau 	pkt = data;
538615516c77SSepherosa Ziehau 
538715516c77SSepherosa Ziehau 	if (__predict_false(dlen < pkt->rm_len)) {
538815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
538915516c77SSepherosa Ziehau 		    "dlen %d, msglen %u\n", dlen, pkt->rm_len);
539015516c77SSepherosa Ziehau 		return;
539115516c77SSepherosa Ziehau 	}
539215516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_len <
539315516c77SSepherosa Ziehau 	    pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
539415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
539515516c77SSepherosa Ziehau 		    "msglen %u, data %u, oob %u, pktinfo %u\n",
539615516c77SSepherosa Ziehau 		    pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
539715516c77SSepherosa Ziehau 		    pkt->rm_pktinfolen);
539815516c77SSepherosa Ziehau 		return;
539915516c77SSepherosa Ziehau 	}
540015516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_datalen == 0)) {
540115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
540215516c77SSepherosa Ziehau 		return;
540315516c77SSepherosa Ziehau 	}
540415516c77SSepherosa Ziehau 
540515516c77SSepherosa Ziehau 	/*
540615516c77SSepherosa Ziehau 	 * Check offests.
540715516c77SSepherosa Ziehau 	 */
540815516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs)			\
540915516c77SSepherosa Ziehau 	((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN ||	\
541015516c77SSepherosa Ziehau 	 ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
541115516c77SSepherosa Ziehau 
541215516c77SSepherosa Ziehau 	/* XXX Hyper-V does not meet data offset alignment requirement */
541315516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
541415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
541515516c77SSepherosa Ziehau 		    "data offset %u\n", pkt->rm_dataoffset);
541615516c77SSepherosa Ziehau 		return;
541715516c77SSepherosa Ziehau 	}
541815516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdataoffset > 0 &&
541915516c77SSepherosa Ziehau 	    IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
542015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
542115516c77SSepherosa Ziehau 		    "oob offset %u\n", pkt->rm_oobdataoffset);
542215516c77SSepherosa Ziehau 		return;
542315516c77SSepherosa Ziehau 	}
542415516c77SSepherosa Ziehau 	if (__predict_true(pkt->rm_pktinfooffset > 0) &&
542515516c77SSepherosa Ziehau 	    __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
542615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
542715516c77SSepherosa Ziehau 		    "pktinfo offset %u\n", pkt->rm_pktinfooffset);
542815516c77SSepherosa Ziehau 		return;
542915516c77SSepherosa Ziehau 	}
543015516c77SSepherosa Ziehau 
543115516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID
543215516c77SSepherosa Ziehau 
543315516c77SSepherosa Ziehau 	data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
543415516c77SSepherosa Ziehau 	data_len = pkt->rm_datalen;
543515516c77SSepherosa Ziehau 	pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
543615516c77SSepherosa Ziehau 	pktinfo_len = pkt->rm_pktinfolen;
543715516c77SSepherosa Ziehau 
543815516c77SSepherosa Ziehau 	/*
543915516c77SSepherosa Ziehau 	 * Check OOB coverage.
544015516c77SSepherosa Ziehau 	 */
544115516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdatalen != 0)) {
544215516c77SSepherosa Ziehau 		int oob_off, oob_len;
544315516c77SSepherosa Ziehau 
544415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "got oobdata\n");
544515516c77SSepherosa Ziehau 		oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
544615516c77SSepherosa Ziehau 		oob_len = pkt->rm_oobdatalen;
544715516c77SSepherosa Ziehau 
544815516c77SSepherosa Ziehau 		if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
544915516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
545015516c77SSepherosa Ziehau 			    "oob overflow, msglen %u, oob abs %d len %d\n",
545115516c77SSepherosa Ziehau 			    pkt->rm_len, oob_off, oob_len);
545215516c77SSepherosa Ziehau 			return;
545315516c77SSepherosa Ziehau 		}
545415516c77SSepherosa Ziehau 
545515516c77SSepherosa Ziehau 		/*
545615516c77SSepherosa Ziehau 		 * Check against data.
545715516c77SSepherosa Ziehau 		 */
545815516c77SSepherosa Ziehau 		if (hn_rndis_check_overlap(oob_off, oob_len,
545915516c77SSepherosa Ziehau 		    data_off, data_len)) {
546015516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
546115516c77SSepherosa Ziehau 			    "oob overlaps data, oob abs %d len %d, "
546215516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
546315516c77SSepherosa Ziehau 			    oob_off, oob_len, data_off, data_len);
546415516c77SSepherosa Ziehau 			return;
546515516c77SSepherosa Ziehau 		}
546615516c77SSepherosa Ziehau 
546715516c77SSepherosa Ziehau 		/*
546815516c77SSepherosa Ziehau 		 * Check against pktinfo.
546915516c77SSepherosa Ziehau 		 */
547015516c77SSepherosa Ziehau 		if (pktinfo_len != 0 &&
547115516c77SSepherosa Ziehau 		    hn_rndis_check_overlap(oob_off, oob_len,
547215516c77SSepherosa Ziehau 		    pktinfo_off, pktinfo_len)) {
547315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
547415516c77SSepherosa Ziehau 			    "oob overlaps pktinfo, oob abs %d len %d, "
547515516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
547615516c77SSepherosa Ziehau 			    oob_off, oob_len, pktinfo_off, pktinfo_len);
547715516c77SSepherosa Ziehau 			return;
547815516c77SSepherosa Ziehau 		}
547915516c77SSepherosa Ziehau 	}
548015516c77SSepherosa Ziehau 
548115516c77SSepherosa Ziehau 	/*
548215516c77SSepherosa Ziehau 	 * Check per-packet-info coverage and find useful per-packet-info.
548315516c77SSepherosa Ziehau 	 */
548415516c77SSepherosa Ziehau 	info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
548515516c77SSepherosa Ziehau 	info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
548615516c77SSepherosa Ziehau 	info.hash_info = HN_NDIS_HASH_INFO_INVALID;
548715516c77SSepherosa Ziehau 	if (__predict_true(pktinfo_len != 0)) {
548815516c77SSepherosa Ziehau 		bool overlap;
548915516c77SSepherosa Ziehau 		int error;
549015516c77SSepherosa Ziehau 
549115516c77SSepherosa Ziehau 		if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
549215516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
549315516c77SSepherosa Ziehau 			    "pktinfo overflow, msglen %u, "
549415516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
549515516c77SSepherosa Ziehau 			    pkt->rm_len, pktinfo_off, pktinfo_len);
549615516c77SSepherosa Ziehau 			return;
549715516c77SSepherosa Ziehau 		}
549815516c77SSepherosa Ziehau 
549915516c77SSepherosa Ziehau 		/*
550015516c77SSepherosa Ziehau 		 * Check packet info coverage.
550115516c77SSepherosa Ziehau 		 */
550215516c77SSepherosa Ziehau 		overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
550315516c77SSepherosa Ziehau 		    data_off, data_len);
550415516c77SSepherosa Ziehau 		if (__predict_false(overlap)) {
550515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
550615516c77SSepherosa Ziehau 			    "pktinfo overlap data, pktinfo abs %d len %d, "
550715516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
550815516c77SSepherosa Ziehau 			    pktinfo_off, pktinfo_len, data_off, data_len);
550915516c77SSepherosa Ziehau 			return;
551015516c77SSepherosa Ziehau 		}
551115516c77SSepherosa Ziehau 
551215516c77SSepherosa Ziehau 		/*
551315516c77SSepherosa Ziehau 		 * Find useful per-packet-info.
551415516c77SSepherosa Ziehau 		 */
551515516c77SSepherosa Ziehau 		error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
551615516c77SSepherosa Ziehau 		    pktinfo_len, &info);
551715516c77SSepherosa Ziehau 		if (__predict_false(error)) {
551815516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
551915516c77SSepherosa Ziehau 			    "pktinfo\n");
552015516c77SSepherosa Ziehau 			return;
552115516c77SSepherosa Ziehau 		}
552215516c77SSepherosa Ziehau 	}
552315516c77SSepherosa Ziehau 
552415516c77SSepherosa Ziehau 	if (__predict_false(data_off + data_len > pkt->rm_len)) {
552515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
552615516c77SSepherosa Ziehau 		    "data overflow, msglen %u, data abs %d len %d\n",
552715516c77SSepherosa Ziehau 		    pkt->rm_len, data_off, data_len);
552815516c77SSepherosa Ziehau 		return;
552915516c77SSepherosa Ziehau 	}
553015516c77SSepherosa Ziehau 	hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
553115516c77SSepherosa Ziehau }
553215516c77SSepherosa Ziehau 
553315516c77SSepherosa Ziehau static __inline void
553415516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen)
553515516c77SSepherosa Ziehau {
553615516c77SSepherosa Ziehau 	const struct rndis_msghdr *hdr;
553715516c77SSepherosa Ziehau 
553815516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*hdr))) {
553915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
554015516c77SSepherosa Ziehau 		return;
554115516c77SSepherosa Ziehau 	}
554215516c77SSepherosa Ziehau 	hdr = data;
554315516c77SSepherosa Ziehau 
554415516c77SSepherosa Ziehau 	if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) {
554515516c77SSepherosa Ziehau 		/* Hot data path. */
554615516c77SSepherosa Ziehau 		hn_rndis_rx_data(rxr, data, dlen);
554715516c77SSepherosa Ziehau 		/* Done! */
554815516c77SSepherosa Ziehau 		return;
554915516c77SSepherosa Ziehau 	}
555015516c77SSepherosa Ziehau 
555115516c77SSepherosa Ziehau 	if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG)
555215516c77SSepherosa Ziehau 		hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen);
555315516c77SSepherosa Ziehau 	else
555415516c77SSepherosa Ziehau 		hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen);
555515516c77SSepherosa Ziehau }
555615516c77SSepherosa Ziehau 
555715516c77SSepherosa Ziehau static void
555815516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
555915516c77SSepherosa Ziehau {
556015516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *hdr;
556115516c77SSepherosa Ziehau 
556215516c77SSepherosa Ziehau 	if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) {
556315516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid nvs notify\n");
556415516c77SSepherosa Ziehau 		return;
556515516c77SSepherosa Ziehau 	}
556615516c77SSepherosa Ziehau 	hdr = VMBUS_CHANPKT_CONST_DATA(pkt);
556715516c77SSepherosa Ziehau 
556815516c77SSepherosa Ziehau 	if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) {
556915516c77SSepherosa Ziehau 		/* Useless; ignore */
557015516c77SSepherosa Ziehau 		return;
557115516c77SSepherosa Ziehau 	}
557215516c77SSepherosa Ziehau 	if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type);
557315516c77SSepherosa Ziehau }
557415516c77SSepherosa Ziehau 
557515516c77SSepherosa Ziehau static void
557615516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan,
557715516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkt)
557815516c77SSepherosa Ziehau {
557915516c77SSepherosa Ziehau 	struct hn_nvs_sendctx *sndc;
558015516c77SSepherosa Ziehau 
558115516c77SSepherosa Ziehau 	sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid;
558215516c77SSepherosa Ziehau 	sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt),
558315516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_DATALEN(pkt));
558415516c77SSepherosa Ziehau 	/*
558515516c77SSepherosa Ziehau 	 * NOTE:
558615516c77SSepherosa Ziehau 	 * 'sndc' CAN NOT be accessed anymore, since it can be freed by
558715516c77SSepherosa Ziehau 	 * its callback.
558815516c77SSepherosa Ziehau 	 */
558915516c77SSepherosa Ziehau }
559015516c77SSepherosa Ziehau 
559115516c77SSepherosa Ziehau static void
559215516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
559315516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkthdr)
559415516c77SSepherosa Ziehau {
559515516c77SSepherosa Ziehau 	const struct vmbus_chanpkt_rxbuf *pkt;
559615516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *nvs_hdr;
559715516c77SSepherosa Ziehau 	int count, i, hlen;
559815516c77SSepherosa Ziehau 
559915516c77SSepherosa Ziehau 	if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) {
560015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n");
560115516c77SSepherosa Ziehau 		return;
560215516c77SSepherosa Ziehau 	}
560315516c77SSepherosa Ziehau 	nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr);
560415516c77SSepherosa Ziehau 
560515516c77SSepherosa Ziehau 	/* Make sure that this is a RNDIS message. */
560615516c77SSepherosa Ziehau 	if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) {
560715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n",
560815516c77SSepherosa Ziehau 		    nvs_hdr->nvs_type);
560915516c77SSepherosa Ziehau 		return;
561015516c77SSepherosa Ziehau 	}
561115516c77SSepherosa Ziehau 
561215516c77SSepherosa Ziehau 	hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen);
561315516c77SSepherosa Ziehau 	if (__predict_false(hlen < sizeof(*pkt))) {
561415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n");
561515516c77SSepherosa Ziehau 		return;
561615516c77SSepherosa Ziehau 	}
561715516c77SSepherosa Ziehau 	pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
561815516c77SSepherosa Ziehau 
561915516c77SSepherosa Ziehau 	if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) {
562015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n",
562115516c77SSepherosa Ziehau 		    pkt->cp_rxbuf_id);
562215516c77SSepherosa Ziehau 		return;
562315516c77SSepherosa Ziehau 	}
562415516c77SSepherosa Ziehau 
562515516c77SSepherosa Ziehau 	count = pkt->cp_rxbuf_cnt;
562615516c77SSepherosa Ziehau 	if (__predict_false(hlen <
562715516c77SSepherosa Ziehau 	    __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) {
562815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count);
562915516c77SSepherosa Ziehau 		return;
563015516c77SSepherosa Ziehau 	}
563115516c77SSepherosa Ziehau 
563215516c77SSepherosa Ziehau 	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
563315516c77SSepherosa Ziehau 	for (i = 0; i < count; ++i) {
563415516c77SSepherosa Ziehau 		int ofs, len;
563515516c77SSepherosa Ziehau 
563615516c77SSepherosa Ziehau 		ofs = pkt->cp_rxbuf[i].rb_ofs;
563715516c77SSepherosa Ziehau 		len = pkt->cp_rxbuf[i].rb_len;
563815516c77SSepherosa Ziehau 		if (__predict_false(ofs + len > HN_RXBUF_SIZE)) {
563915516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, "
564015516c77SSepherosa Ziehau 			    "ofs %d, len %d\n", i, ofs, len);
564115516c77SSepherosa Ziehau 			continue;
564215516c77SSepherosa Ziehau 		}
564315516c77SSepherosa Ziehau 		hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len);
564415516c77SSepherosa Ziehau 	}
564515516c77SSepherosa Ziehau 
564615516c77SSepherosa Ziehau 	/*
564715516c77SSepherosa Ziehau 	 * Ack the consumed RXBUF associated w/ this channel packet,
564815516c77SSepherosa Ziehau 	 * so that this RXBUF can be recycled by the hypervisor.
564915516c77SSepherosa Ziehau 	 */
565015516c77SSepherosa Ziehau 	hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid);
565115516c77SSepherosa Ziehau }
565215516c77SSepherosa Ziehau 
565315516c77SSepherosa Ziehau static void
565415516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
565515516c77SSepherosa Ziehau     uint64_t tid)
565615516c77SSepherosa Ziehau {
565715516c77SSepherosa Ziehau 	struct hn_nvs_rndis_ack ack;
565815516c77SSepherosa Ziehau 	int retries, error;
565915516c77SSepherosa Ziehau 
566015516c77SSepherosa Ziehau 	ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK;
566115516c77SSepherosa Ziehau 	ack.nvs_status = HN_NVS_STATUS_OK;
566215516c77SSepherosa Ziehau 
566315516c77SSepherosa Ziehau 	retries = 0;
566415516c77SSepherosa Ziehau again:
566515516c77SSepherosa Ziehau 	error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP,
566615516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid);
566715516c77SSepherosa Ziehau 	if (__predict_false(error == EAGAIN)) {
566815516c77SSepherosa Ziehau 		/*
566915516c77SSepherosa Ziehau 		 * NOTE:
567015516c77SSepherosa Ziehau 		 * This should _not_ happen in real world, since the
567115516c77SSepherosa Ziehau 		 * consumption of the TX bufring from the TX path is
567215516c77SSepherosa Ziehau 		 * controlled.
567315516c77SSepherosa Ziehau 		 */
567415516c77SSepherosa Ziehau 		if (rxr->hn_ack_failed == 0)
567515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "RXBUF ack retry\n");
567615516c77SSepherosa Ziehau 		rxr->hn_ack_failed++;
567715516c77SSepherosa Ziehau 		retries++;
567815516c77SSepherosa Ziehau 		if (retries < 10) {
567915516c77SSepherosa Ziehau 			DELAY(100);
568015516c77SSepherosa Ziehau 			goto again;
568115516c77SSepherosa Ziehau 		}
568215516c77SSepherosa Ziehau 		/* RXBUF leaks! */
568315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "RXBUF ack failed\n");
568415516c77SSepherosa Ziehau 	}
568515516c77SSepherosa Ziehau }
568615516c77SSepherosa Ziehau 
568715516c77SSepherosa Ziehau static void
568815516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr)
568915516c77SSepherosa Ziehau {
569015516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr = xrxr;
569115516c77SSepherosa Ziehau 	struct hn_softc *sc = rxr->hn_ifp->if_softc;
569215516c77SSepherosa Ziehau 
569315516c77SSepherosa Ziehau 	for (;;) {
569415516c77SSepherosa Ziehau 		struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf;
569515516c77SSepherosa Ziehau 		int error, pktlen;
569615516c77SSepherosa Ziehau 
569715516c77SSepherosa Ziehau 		pktlen = rxr->hn_pktbuf_len;
569815516c77SSepherosa Ziehau 		error = vmbus_chan_recv_pkt(chan, pkt, &pktlen);
569915516c77SSepherosa Ziehau 		if (__predict_false(error == ENOBUFS)) {
570015516c77SSepherosa Ziehau 			void *nbuf;
570115516c77SSepherosa Ziehau 			int nlen;
570215516c77SSepherosa Ziehau 
570315516c77SSepherosa Ziehau 			/*
570415516c77SSepherosa Ziehau 			 * Expand channel packet buffer.
570515516c77SSepherosa Ziehau 			 *
570615516c77SSepherosa Ziehau 			 * XXX
570715516c77SSepherosa Ziehau 			 * Use M_WAITOK here, since allocation failure
570815516c77SSepherosa Ziehau 			 * is fatal.
570915516c77SSepherosa Ziehau 			 */
571015516c77SSepherosa Ziehau 			nlen = rxr->hn_pktbuf_len * 2;
571115516c77SSepherosa Ziehau 			while (nlen < pktlen)
571215516c77SSepherosa Ziehau 				nlen *= 2;
571315516c77SSepherosa Ziehau 			nbuf = malloc(nlen, M_DEVBUF, M_WAITOK);
571415516c77SSepherosa Ziehau 
571515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n",
571615516c77SSepherosa Ziehau 			    rxr->hn_pktbuf_len, nlen);
571715516c77SSepherosa Ziehau 
571815516c77SSepherosa Ziehau 			free(rxr->hn_pktbuf, M_DEVBUF);
571915516c77SSepherosa Ziehau 			rxr->hn_pktbuf = nbuf;
572015516c77SSepherosa Ziehau 			rxr->hn_pktbuf_len = nlen;
572115516c77SSepherosa Ziehau 			/* Retry! */
572215516c77SSepherosa Ziehau 			continue;
572315516c77SSepherosa Ziehau 		} else if (__predict_false(error == EAGAIN)) {
572415516c77SSepherosa Ziehau 			/* No more channel packets; done! */
572515516c77SSepherosa Ziehau 			break;
572615516c77SSepherosa Ziehau 		}
572715516c77SSepherosa Ziehau 		KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error));
572815516c77SSepherosa Ziehau 
572915516c77SSepherosa Ziehau 		switch (pkt->cph_type) {
573015516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_COMP:
573115516c77SSepherosa Ziehau 			hn_nvs_handle_comp(sc, chan, pkt);
573215516c77SSepherosa Ziehau 			break;
573315516c77SSepherosa Ziehau 
573415516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_RXBUF:
573515516c77SSepherosa Ziehau 			hn_nvs_handle_rxbuf(rxr, chan, pkt);
573615516c77SSepherosa Ziehau 			break;
573715516c77SSepherosa Ziehau 
573815516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_INBAND:
573915516c77SSepherosa Ziehau 			hn_nvs_handle_notify(sc, pkt);
574015516c77SSepherosa Ziehau 			break;
574115516c77SSepherosa Ziehau 
574215516c77SSepherosa Ziehau 		default:
574315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "unknown chan pkt %u\n",
574415516c77SSepherosa Ziehau 			    pkt->cph_type);
574515516c77SSepherosa Ziehau 			break;
574615516c77SSepherosa Ziehau 		}
574715516c77SSepherosa Ziehau 	}
574815516c77SSepherosa Ziehau 	hn_chan_rollup(rxr, rxr->hn_txr);
574915516c77SSepherosa Ziehau }
575015516c77SSepherosa Ziehau 
575115516c77SSepherosa Ziehau static void
575215516c77SSepherosa Ziehau hn_tx_taskq_create(void *arg __unused)
575315516c77SSepherosa Ziehau {
5754fdd0222aSSepherosa Ziehau 	int i;
5755fdd0222aSSepherosa Ziehau 
5756fdd0222aSSepherosa Ziehau 	/*
5757fdd0222aSSepherosa Ziehau 	 * Fix the # of TX taskqueues.
5758fdd0222aSSepherosa Ziehau 	 */
5759fdd0222aSSepherosa Ziehau 	if (hn_tx_taskq_cnt <= 0)
5760fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = 1;
5761fdd0222aSSepherosa Ziehau 	else if (hn_tx_taskq_cnt > mp_ncpus)
5762fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = mp_ncpus;
576315516c77SSepherosa Ziehau 
57640e11868dSSepherosa Ziehau 	/*
57650e11868dSSepherosa Ziehau 	 * Fix the TX taskqueue mode.
57660e11868dSSepherosa Ziehau 	 */
57670e11868dSSepherosa Ziehau 	switch (hn_tx_taskq_mode) {
57680e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_INDEP:
57690e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_GLOBAL:
57700e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_EVTTQ:
57710e11868dSSepherosa Ziehau 		break;
57720e11868dSSepherosa Ziehau 	default:
57730e11868dSSepherosa Ziehau 		hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
57740e11868dSSepherosa Ziehau 		break;
57750e11868dSSepherosa Ziehau 	}
57760e11868dSSepherosa Ziehau 
577715516c77SSepherosa Ziehau 	if (vm_guest != VM_GUEST_HV)
577815516c77SSepherosa Ziehau 		return;
577915516c77SSepherosa Ziehau 
57800e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode != HN_TX_TASKQ_M_GLOBAL)
578115516c77SSepherosa Ziehau 		return;
578215516c77SSepherosa Ziehau 
5783fdd0222aSSepherosa Ziehau 	hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
5784fdd0222aSSepherosa Ziehau 	    M_DEVBUF, M_WAITOK);
5785fdd0222aSSepherosa Ziehau 	for (i = 0; i < hn_tx_taskq_cnt; ++i) {
5786fdd0222aSSepherosa Ziehau 		hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK,
5787fdd0222aSSepherosa Ziehau 		    taskqueue_thread_enqueue, &hn_tx_taskque[i]);
5788fdd0222aSSepherosa Ziehau 		taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET,
5789fdd0222aSSepherosa Ziehau 		    "hn tx%d", i);
5790fdd0222aSSepherosa Ziehau 	}
579115516c77SSepherosa Ziehau }
579215516c77SSepherosa Ziehau SYSINIT(hn_txtq_create, SI_SUB_DRIVERS, SI_ORDER_SECOND,
579315516c77SSepherosa Ziehau     hn_tx_taskq_create, NULL);
579415516c77SSepherosa Ziehau 
579515516c77SSepherosa Ziehau static void
579615516c77SSepherosa Ziehau hn_tx_taskq_destroy(void *arg __unused)
579715516c77SSepherosa Ziehau {
579815516c77SSepherosa Ziehau 
5799fdd0222aSSepherosa Ziehau 	if (hn_tx_taskque != NULL) {
5800fdd0222aSSepherosa Ziehau 		int i;
5801fdd0222aSSepherosa Ziehau 
5802fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
5803fdd0222aSSepherosa Ziehau 			taskqueue_free(hn_tx_taskque[i]);
5804fdd0222aSSepherosa Ziehau 		free(hn_tx_taskque, M_DEVBUF);
5805fdd0222aSSepherosa Ziehau 	}
580615516c77SSepherosa Ziehau }
580715516c77SSepherosa Ziehau SYSUNINIT(hn_txtq_destroy, SI_SUB_DRIVERS, SI_ORDER_SECOND,
580815516c77SSepherosa Ziehau     hn_tx_taskq_destroy, NULL);
5809