xref: /freebsd/sys/dev/hyperv/netvsc/if_hn.c (revision 33408a34c44bd558498d0ee59ee2b3a96b5ee740)
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);
26415516c77SSepherosa Ziehau 
26515516c77SSepherosa Ziehau static void			hn_nvs_handle_notify(struct hn_softc *,
26615516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
26715516c77SSepherosa Ziehau static void			hn_nvs_handle_comp(struct hn_softc *,
26815516c77SSepherosa Ziehau 				    struct vmbus_channel *,
26915516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
27015516c77SSepherosa Ziehau static void			hn_nvs_handle_rxbuf(struct hn_rx_ring *,
27115516c77SSepherosa Ziehau 				    struct vmbus_channel *,
27215516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
27315516c77SSepherosa Ziehau static void			hn_nvs_ack_rxbuf(struct hn_rx_ring *,
27415516c77SSepherosa Ziehau 				    struct vmbus_channel *, uint64_t);
27515516c77SSepherosa Ziehau 
27615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
27715516c77SSepherosa Ziehau static int			hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS);
27815516c77SSepherosa Ziehau static int			hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS);
27915516c77SSepherosa Ziehau #endif
28015516c77SSepherosa Ziehau static int			hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS);
28115516c77SSepherosa Ziehau static int			hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS);
28215516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
28315516c77SSepherosa Ziehau static int			hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS);
28415516c77SSepherosa Ziehau #else
28515516c77SSepherosa Ziehau static int			hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS);
28615516c77SSepherosa Ziehau #endif
28715516c77SSepherosa Ziehau static int			hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
28815516c77SSepherosa Ziehau static int			hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
28915516c77SSepherosa Ziehau static int			hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS);
29015516c77SSepherosa Ziehau static int			hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS);
29115516c77SSepherosa Ziehau static int			hn_caps_sysctl(SYSCTL_HANDLER_ARGS);
29215516c77SSepherosa Ziehau static int			hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS);
29315516c77SSepherosa Ziehau static int			hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS);
29434d68912SSepherosa Ziehau #ifndef RSS
29515516c77SSepherosa Ziehau static int			hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS);
29615516c77SSepherosa Ziehau static int			hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS);
29734d68912SSepherosa Ziehau #endif
29815516c77SSepherosa Ziehau static int			hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS);
299dc13fee6SSepherosa Ziehau static int			hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS);
300dc13fee6SSepherosa Ziehau static int			hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS);
301dc13fee6SSepherosa Ziehau static int			hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS);
302dc13fee6SSepherosa Ziehau static int			hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS);
3036c1204dfSSepherosa Ziehau static int			hn_polling_sysctl(SYSCTL_HANDLER_ARGS);
30440d60d6eSDexuan Cui static int			hn_vf_sysctl(SYSCTL_HANDLER_ARGS);
30515516c77SSepherosa Ziehau 
3065bdfd3fdSDexuan Cui static void			hn_stop(struct hn_softc *, bool);
30715516c77SSepherosa Ziehau static void			hn_init_locked(struct hn_softc *);
30815516c77SSepherosa Ziehau static int			hn_chan_attach(struct hn_softc *,
30915516c77SSepherosa Ziehau 				    struct vmbus_channel *);
31015516c77SSepherosa Ziehau static void			hn_chan_detach(struct hn_softc *,
31115516c77SSepherosa Ziehau 				    struct vmbus_channel *);
31215516c77SSepherosa Ziehau static int			hn_attach_subchans(struct hn_softc *);
31315516c77SSepherosa Ziehau static void			hn_detach_allchans(struct hn_softc *);
31415516c77SSepherosa Ziehau static void			hn_chan_rollup(struct hn_rx_ring *,
31515516c77SSepherosa Ziehau 				    struct hn_tx_ring *);
31615516c77SSepherosa Ziehau static void			hn_set_ring_inuse(struct hn_softc *, int);
31715516c77SSepherosa Ziehau static int			hn_synth_attach(struct hn_softc *, int);
31815516c77SSepherosa Ziehau static void			hn_synth_detach(struct hn_softc *);
31915516c77SSepherosa Ziehau static int			hn_synth_alloc_subchans(struct hn_softc *,
32015516c77SSepherosa Ziehau 				    int *);
3212494d735SSepherosa Ziehau static bool			hn_synth_attachable(const struct hn_softc *);
32215516c77SSepherosa Ziehau static void			hn_suspend(struct hn_softc *);
32315516c77SSepherosa Ziehau static void			hn_suspend_data(struct hn_softc *);
32415516c77SSepherosa Ziehau static void			hn_suspend_mgmt(struct hn_softc *);
32515516c77SSepherosa Ziehau static void			hn_resume(struct hn_softc *);
32615516c77SSepherosa Ziehau static void			hn_resume_data(struct hn_softc *);
32715516c77SSepherosa Ziehau static void			hn_resume_mgmt(struct hn_softc *);
32815516c77SSepherosa Ziehau static void			hn_suspend_mgmt_taskfunc(void *, int);
32925641fc7SSepherosa Ziehau static void			hn_chan_drain(struct hn_softc *,
33025641fc7SSepherosa Ziehau 				    struct vmbus_channel *);
3316c1204dfSSepherosa Ziehau static void			hn_polling(struct hn_softc *, u_int);
3326c1204dfSSepherosa Ziehau static void			hn_chan_polling(struct vmbus_channel *, u_int);
33315516c77SSepherosa Ziehau 
33415516c77SSepherosa Ziehau static void			hn_update_link_status(struct hn_softc *);
33515516c77SSepherosa Ziehau static void			hn_change_network(struct hn_softc *);
33615516c77SSepherosa Ziehau static void			hn_link_taskfunc(void *, int);
33715516c77SSepherosa Ziehau static void			hn_netchg_init_taskfunc(void *, int);
33815516c77SSepherosa Ziehau static void			hn_netchg_status_taskfunc(void *, int);
33915516c77SSepherosa Ziehau static void			hn_link_status(struct hn_softc *);
34015516c77SSepherosa Ziehau 
34115516c77SSepherosa Ziehau static int			hn_create_rx_data(struct hn_softc *, int);
34215516c77SSepherosa Ziehau static void			hn_destroy_rx_data(struct hn_softc *);
34315516c77SSepherosa Ziehau static int			hn_check_iplen(const struct mbuf *, int);
344f1b0a43fSSepherosa Ziehau static int			hn_set_rxfilter(struct hn_softc *, uint32_t);
345c08f7b2cSSepherosa Ziehau static int			hn_rxfilter_config(struct hn_softc *);
34634d68912SSepherosa Ziehau #ifndef RSS
34715516c77SSepherosa Ziehau static int			hn_rss_reconfig(struct hn_softc *);
34834d68912SSepherosa Ziehau #endif
349afd4971bSSepherosa Ziehau static void			hn_rss_ind_fixup(struct hn_softc *);
35015516c77SSepherosa Ziehau static int			hn_rxpkt(struct hn_rx_ring *, const void *,
35115516c77SSepherosa Ziehau 				    int, const struct hn_rxinfo *);
35215516c77SSepherosa Ziehau 
35315516c77SSepherosa Ziehau static int			hn_tx_ring_create(struct hn_softc *, int);
35415516c77SSepherosa Ziehau static void			hn_tx_ring_destroy(struct hn_tx_ring *);
35515516c77SSepherosa Ziehau static int			hn_create_tx_data(struct hn_softc *, int);
35615516c77SSepherosa Ziehau static void			hn_fixup_tx_data(struct hn_softc *);
35715516c77SSepherosa Ziehau static void			hn_destroy_tx_data(struct hn_softc *);
35815516c77SSepherosa Ziehau static void			hn_txdesc_dmamap_destroy(struct hn_txdesc *);
35925641fc7SSepherosa Ziehau static void			hn_txdesc_gc(struct hn_tx_ring *,
36025641fc7SSepherosa Ziehau 				    struct hn_txdesc *);
361dc13fee6SSepherosa Ziehau static int			hn_encap(struct ifnet *, struct hn_tx_ring *,
36215516c77SSepherosa Ziehau 				    struct hn_txdesc *, struct mbuf **);
36315516c77SSepherosa Ziehau static int			hn_txpkt(struct ifnet *, struct hn_tx_ring *,
36415516c77SSepherosa Ziehau 				    struct hn_txdesc *);
36515516c77SSepherosa Ziehau static void			hn_set_chim_size(struct hn_softc *, int);
36615516c77SSepherosa Ziehau static void			hn_set_tso_maxsize(struct hn_softc *, int, int);
36715516c77SSepherosa Ziehau static bool			hn_tx_ring_pending(struct hn_tx_ring *);
36815516c77SSepherosa Ziehau static void			hn_tx_ring_qflush(struct hn_tx_ring *);
36915516c77SSepherosa Ziehau static void			hn_resume_tx(struct hn_softc *, int);
370dc13fee6SSepherosa Ziehau static void			hn_set_txagg(struct hn_softc *);
371dc13fee6SSepherosa Ziehau static void			*hn_try_txagg(struct ifnet *,
372dc13fee6SSepherosa Ziehau 				    struct hn_tx_ring *, struct hn_txdesc *,
373dc13fee6SSepherosa Ziehau 				    int);
37415516c77SSepherosa Ziehau static int			hn_get_txswq_depth(const struct hn_tx_ring *);
37515516c77SSepherosa Ziehau static void			hn_txpkt_done(struct hn_nvs_sendctx *,
37615516c77SSepherosa Ziehau 				    struct hn_softc *, struct vmbus_channel *,
37715516c77SSepherosa Ziehau 				    const void *, int);
37815516c77SSepherosa Ziehau static int			hn_txpkt_sglist(struct hn_tx_ring *,
37915516c77SSepherosa Ziehau 				    struct hn_txdesc *);
38015516c77SSepherosa Ziehau static int			hn_txpkt_chim(struct hn_tx_ring *,
38115516c77SSepherosa Ziehau 				    struct hn_txdesc *);
38215516c77SSepherosa Ziehau static int			hn_xmit(struct hn_tx_ring *, int);
38315516c77SSepherosa Ziehau static void			hn_xmit_taskfunc(void *, int);
38415516c77SSepherosa Ziehau static void			hn_xmit_txeof(struct hn_tx_ring *);
38515516c77SSepherosa Ziehau static void			hn_xmit_txeof_taskfunc(void *, int);
38623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
38715516c77SSepherosa Ziehau static int			hn_start_locked(struct hn_tx_ring *, int);
38815516c77SSepherosa Ziehau static void			hn_start_taskfunc(void *, int);
38915516c77SSepherosa Ziehau static void			hn_start_txeof(struct hn_tx_ring *);
39015516c77SSepherosa Ziehau static void			hn_start_txeof_taskfunc(void *, int);
39123bf9e15SSepherosa Ziehau #endif
39215516c77SSepherosa Ziehau 
39315516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
39415516c77SSepherosa Ziehau     "Hyper-V network interface");
39515516c77SSepherosa Ziehau 
39615516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */
39715516c77SSepherosa Ziehau static int			hn_trust_hosttcp = 1;
39815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN,
39915516c77SSepherosa Ziehau     &hn_trust_hosttcp, 0,
40015516c77SSepherosa Ziehau     "Trust tcp segement verification on host side, "
40115516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
40215516c77SSepherosa Ziehau 
40315516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */
40415516c77SSepherosa Ziehau static int			hn_trust_hostudp = 1;
40515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN,
40615516c77SSepherosa Ziehau     &hn_trust_hostudp, 0,
40715516c77SSepherosa Ziehau     "Trust udp datagram verification on host side, "
40815516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
40915516c77SSepherosa Ziehau 
41015516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */
41115516c77SSepherosa Ziehau static int			hn_trust_hostip = 1;
41215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN,
41315516c77SSepherosa Ziehau     &hn_trust_hostip, 0,
41415516c77SSepherosa Ziehau     "Trust ip packet verification on host side, "
41515516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
41615516c77SSepherosa Ziehau 
41715516c77SSepherosa Ziehau /* Limit TSO burst size */
41815516c77SSepherosa Ziehau static int			hn_tso_maxlen = IP_MAXPACKET;
41915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN,
42015516c77SSepherosa Ziehau     &hn_tso_maxlen, 0, "TSO burst limit");
42115516c77SSepherosa Ziehau 
42215516c77SSepherosa Ziehau /* Limit chimney send size */
42315516c77SSepherosa Ziehau static int			hn_tx_chimney_size = 0;
42415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN,
42515516c77SSepherosa Ziehau     &hn_tx_chimney_size, 0, "Chimney send packet size limit");
42615516c77SSepherosa Ziehau 
42715516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */
42815516c77SSepherosa Ziehau static int			hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF;
42915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN,
43015516c77SSepherosa Ziehau     &hn_direct_tx_size, 0, "Size of the packet for direct transmission");
43115516c77SSepherosa Ziehau 
43215516c77SSepherosa Ziehau /* # of LRO entries per RX ring */
43315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
43415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
43515516c77SSepherosa Ziehau static int			hn_lro_entry_count = HN_LROENT_CNT_DEF;
43615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN,
43715516c77SSepherosa Ziehau     &hn_lro_entry_count, 0, "LRO entry count");
43815516c77SSepherosa Ziehau #endif
43915516c77SSepherosa Ziehau #endif
44015516c77SSepherosa Ziehau 
441fdd0222aSSepherosa Ziehau static int			hn_tx_taskq_cnt = 1;
442fdd0222aSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_cnt, CTLFLAG_RDTUN,
443fdd0222aSSepherosa Ziehau     &hn_tx_taskq_cnt, 0, "# of TX taskqueues");
444fdd0222aSSepherosa Ziehau 
4450e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_INDEP	0
4460e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_GLOBAL	1
4470e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_EVTTQ	2
4480e11868dSSepherosa Ziehau 
4490e11868dSSepherosa Ziehau static int			hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
4500e11868dSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_mode, CTLFLAG_RDTUN,
4510e11868dSSepherosa Ziehau     &hn_tx_taskq_mode, 0, "TX taskqueue modes: "
4520e11868dSSepherosa Ziehau     "0 - independent, 1 - share global tx taskqs, 2 - share event taskqs");
4530e11868dSSepherosa Ziehau 
45415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
45515516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 0;
45615516c77SSepherosa Ziehau #else
45715516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 1;
45815516c77SSepherosa Ziehau #endif
45915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD,
46015516c77SSepherosa Ziehau     &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors");
46115516c77SSepherosa Ziehau 
46223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
46315516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */
46415516c77SSepherosa Ziehau static int			hn_use_if_start = 0;
46515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN,
46615516c77SSepherosa Ziehau     &hn_use_if_start, 0, "Use if_start TX method");
46723bf9e15SSepherosa Ziehau #endif
46815516c77SSepherosa Ziehau 
46915516c77SSepherosa Ziehau /* # of channels to use */
47015516c77SSepherosa Ziehau static int			hn_chan_cnt = 0;
47115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN,
47215516c77SSepherosa Ziehau     &hn_chan_cnt, 0,
47315516c77SSepherosa Ziehau     "# of channels to use; each channel has one RX ring and one TX ring");
47415516c77SSepherosa Ziehau 
47515516c77SSepherosa Ziehau /* # of transmit rings to use */
47615516c77SSepherosa Ziehau static int			hn_tx_ring_cnt = 0;
47715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN,
47815516c77SSepherosa Ziehau     &hn_tx_ring_cnt, 0, "# of TX rings to use");
47915516c77SSepherosa Ziehau 
48015516c77SSepherosa Ziehau /* Software TX ring deptch */
48115516c77SSepherosa Ziehau static int			hn_tx_swq_depth = 0;
48215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN,
48315516c77SSepherosa Ziehau     &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING");
48415516c77SSepherosa Ziehau 
48515516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */
48615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
48715516c77SSepherosa Ziehau static u_int			hn_lro_mbufq_depth = 0;
48815516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN,
48915516c77SSepherosa Ziehau     &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue");
49015516c77SSepherosa Ziehau #endif
49115516c77SSepherosa Ziehau 
492dc13fee6SSepherosa Ziehau /* Packet transmission aggregation size limit */
493dc13fee6SSepherosa Ziehau static int			hn_tx_agg_size = -1;
494dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN,
495dc13fee6SSepherosa Ziehau     &hn_tx_agg_size, 0, "Packet transmission aggregation size limit");
496dc13fee6SSepherosa Ziehau 
497dc13fee6SSepherosa Ziehau /* Packet transmission aggregation count limit */
498fa915c4dSSepherosa Ziehau static int			hn_tx_agg_pkts = -1;
499dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN,
500dc13fee6SSepherosa Ziehau     &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit");
501dc13fee6SSepherosa Ziehau 
50215516c77SSepherosa Ziehau static u_int			hn_cpu_index;	/* next CPU for channel */
503fdd0222aSSepherosa Ziehau static struct taskqueue		**hn_tx_taskque;/* shared TX taskqueues */
50415516c77SSepherosa Ziehau 
50534d68912SSepherosa Ziehau #ifndef RSS
50615516c77SSepherosa Ziehau static const uint8_t
50715516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
50815516c77SSepherosa Ziehau 	0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
50915516c77SSepherosa Ziehau 	0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
51015516c77SSepherosa Ziehau 	0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
51115516c77SSepherosa Ziehau 	0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
51215516c77SSepherosa Ziehau 	0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
51315516c77SSepherosa Ziehau };
51434d68912SSepherosa Ziehau #endif	/* !RSS */
51515516c77SSepherosa Ziehau 
51615516c77SSepherosa Ziehau static device_method_t hn_methods[] = {
51715516c77SSepherosa Ziehau 	/* Device interface */
51815516c77SSepherosa Ziehau 	DEVMETHOD(device_probe,		hn_probe),
51915516c77SSepherosa Ziehau 	DEVMETHOD(device_attach,	hn_attach),
52015516c77SSepherosa Ziehau 	DEVMETHOD(device_detach,	hn_detach),
52115516c77SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	hn_shutdown),
52215516c77SSepherosa Ziehau 	DEVMETHOD_END
52315516c77SSepherosa Ziehau };
52415516c77SSepherosa Ziehau 
52515516c77SSepherosa Ziehau static driver_t hn_driver = {
52615516c77SSepherosa Ziehau 	"hn",
52715516c77SSepherosa Ziehau 	hn_methods,
52815516c77SSepherosa Ziehau 	sizeof(struct hn_softc)
52915516c77SSepherosa Ziehau };
53015516c77SSepherosa Ziehau 
53115516c77SSepherosa Ziehau static devclass_t hn_devclass;
53215516c77SSepherosa Ziehau 
53315516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0);
53415516c77SSepherosa Ziehau MODULE_VERSION(hn, 1);
53515516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1);
53615516c77SSepherosa Ziehau 
53715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
53815516c77SSepherosa Ziehau static void
53915516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim)
54015516c77SSepherosa Ziehau {
54115516c77SSepherosa Ziehau 	int i;
54215516c77SSepherosa Ziehau 
543a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
54415516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim;
54515516c77SSepherosa Ziehau }
54615516c77SSepherosa Ziehau #endif
54715516c77SSepherosa Ziehau 
54815516c77SSepherosa Ziehau static int
54915516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd)
55015516c77SSepherosa Ziehau {
55115516c77SSepherosa Ziehau 
55215516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
55315516c77SSepherosa Ziehau 	    txd->chim_size == 0, ("invalid rndis sglist txd"));
55415516c77SSepherosa Ziehau 	return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA,
55515516c77SSepherosa Ziehau 	    &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt));
55615516c77SSepherosa Ziehau }
55715516c77SSepherosa Ziehau 
55815516c77SSepherosa Ziehau static int
55915516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd)
56015516c77SSepherosa Ziehau {
56115516c77SSepherosa Ziehau 	struct hn_nvs_rndis rndis;
56215516c77SSepherosa Ziehau 
56315516c77SSepherosa Ziehau 	KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID &&
56415516c77SSepherosa Ziehau 	    txd->chim_size > 0, ("invalid rndis chim txd"));
56515516c77SSepherosa Ziehau 
56615516c77SSepherosa Ziehau 	rndis.nvs_type = HN_NVS_TYPE_RNDIS;
56715516c77SSepherosa Ziehau 	rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA;
56815516c77SSepherosa Ziehau 	rndis.nvs_chim_idx = txd->chim_index;
56915516c77SSepherosa Ziehau 	rndis.nvs_chim_sz = txd->chim_size;
57015516c77SSepherosa Ziehau 
57115516c77SSepherosa Ziehau 	return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC,
57215516c77SSepherosa Ziehau 	    &rndis, sizeof(rndis), &txd->send_ctx));
57315516c77SSepherosa Ziehau }
57415516c77SSepherosa Ziehau 
57515516c77SSepherosa Ziehau static __inline uint32_t
57615516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc)
57715516c77SSepherosa Ziehau {
57815516c77SSepherosa Ziehau 	int i, bmap_cnt = sc->hn_chim_bmap_cnt;
57915516c77SSepherosa Ziehau 	u_long *bmap = sc->hn_chim_bmap;
58015516c77SSepherosa Ziehau 	uint32_t ret = HN_NVS_CHIM_IDX_INVALID;
58115516c77SSepherosa Ziehau 
58215516c77SSepherosa Ziehau 	for (i = 0; i < bmap_cnt; ++i) {
58315516c77SSepherosa Ziehau 		int idx;
58415516c77SSepherosa Ziehau 
58515516c77SSepherosa Ziehau 		idx = ffsl(~bmap[i]);
58615516c77SSepherosa Ziehau 		if (idx == 0)
58715516c77SSepherosa Ziehau 			continue;
58815516c77SSepherosa Ziehau 
58915516c77SSepherosa Ziehau 		--idx; /* ffsl is 1-based */
59015516c77SSepherosa Ziehau 		KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt,
59115516c77SSepherosa Ziehau 		    ("invalid i %d and idx %d", i, idx));
59215516c77SSepherosa Ziehau 
59315516c77SSepherosa Ziehau 		if (atomic_testandset_long(&bmap[i], idx))
59415516c77SSepherosa Ziehau 			continue;
59515516c77SSepherosa Ziehau 
59615516c77SSepherosa Ziehau 		ret = i * LONG_BIT + idx;
59715516c77SSepherosa Ziehau 		break;
59815516c77SSepherosa Ziehau 	}
59915516c77SSepherosa Ziehau 	return (ret);
60015516c77SSepherosa Ziehau }
60115516c77SSepherosa Ziehau 
60215516c77SSepherosa Ziehau static __inline void
60315516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx)
60415516c77SSepherosa Ziehau {
60515516c77SSepherosa Ziehau 	u_long mask;
60615516c77SSepherosa Ziehau 	uint32_t idx;
60715516c77SSepherosa Ziehau 
60815516c77SSepherosa Ziehau 	idx = chim_idx / LONG_BIT;
60915516c77SSepherosa Ziehau 	KASSERT(idx < sc->hn_chim_bmap_cnt,
61015516c77SSepherosa Ziehau 	    ("invalid chimney index 0x%x", chim_idx));
61115516c77SSepherosa Ziehau 
61215516c77SSepherosa Ziehau 	mask = 1UL << (chim_idx % LONG_BIT);
61315516c77SSepherosa Ziehau 	KASSERT(sc->hn_chim_bmap[idx] & mask,
61415516c77SSepherosa Ziehau 	    ("index bitmap 0x%lx, chimney index %u, "
61515516c77SSepherosa Ziehau 	     "bitmap idx %d, bitmask 0x%lx",
61615516c77SSepherosa Ziehau 	     sc->hn_chim_bmap[idx], chim_idx, idx, mask));
61715516c77SSepherosa Ziehau 
61815516c77SSepherosa Ziehau 	atomic_clear_long(&sc->hn_chim_bmap[idx], mask);
61915516c77SSepherosa Ziehau }
62015516c77SSepherosa Ziehau 
621edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
622edd3f315SSepherosa Ziehau /*
623edd3f315SSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
624edd3f315SSepherosa Ziehau  */
625edd3f315SSepherosa Ziehau static __inline struct mbuf *
626edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head)
627edd3f315SSepherosa Ziehau {
628edd3f315SSepherosa Ziehau 	struct ether_vlan_header *evl;
629edd3f315SSepherosa Ziehau 	struct tcphdr *th;
630edd3f315SSepherosa Ziehau 	int ehlen;
631edd3f315SSepherosa Ziehau 
632edd3f315SSepherosa Ziehau 	KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable"));
633edd3f315SSepherosa Ziehau 
634edd3f315SSepherosa Ziehau #define PULLUP_HDR(m, len)				\
635edd3f315SSepherosa Ziehau do {							\
636edd3f315SSepherosa Ziehau 	if (__predict_false((m)->m_len < (len))) {	\
637edd3f315SSepherosa Ziehau 		(m) = m_pullup((m), (len));		\
638edd3f315SSepherosa Ziehau 		if ((m) == NULL)			\
639edd3f315SSepherosa Ziehau 			return (NULL);			\
640edd3f315SSepherosa Ziehau 	}						\
641edd3f315SSepherosa Ziehau } while (0)
642edd3f315SSepherosa Ziehau 
643edd3f315SSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
644edd3f315SSepherosa Ziehau 	evl = mtod(m_head, struct ether_vlan_header *);
645edd3f315SSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
646edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
647edd3f315SSepherosa Ziehau 	else
648edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
649edd3f315SSepherosa Ziehau 
650edd3f315SSepherosa Ziehau #ifdef INET
651edd3f315SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
652edd3f315SSepherosa Ziehau 		struct ip *ip;
653edd3f315SSepherosa Ziehau 		int iphlen;
654edd3f315SSepherosa Ziehau 
655edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
656edd3f315SSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
657edd3f315SSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
658edd3f315SSepherosa Ziehau 
659edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
660edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + iphlen);
661edd3f315SSepherosa Ziehau 
662edd3f315SSepherosa Ziehau 		ip->ip_len = 0;
663edd3f315SSepherosa Ziehau 		ip->ip_sum = 0;
664edd3f315SSepherosa Ziehau 		th->th_sum = in_pseudo(ip->ip_src.s_addr,
665edd3f315SSepherosa Ziehau 		    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
666edd3f315SSepherosa Ziehau 	}
667edd3f315SSepherosa Ziehau #endif
668edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET)
669edd3f315SSepherosa Ziehau 	else
670edd3f315SSepherosa Ziehau #endif
671edd3f315SSepherosa Ziehau #ifdef INET6
672edd3f315SSepherosa Ziehau 	{
673edd3f315SSepherosa Ziehau 		struct ip6_hdr *ip6;
674edd3f315SSepherosa Ziehau 
675edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
676edd3f315SSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
677edd3f315SSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP) {
678edd3f315SSepherosa Ziehau 			m_freem(m_head);
679edd3f315SSepherosa Ziehau 			return (NULL);
680edd3f315SSepherosa Ziehau 		}
681edd3f315SSepherosa Ziehau 
682edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
683edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + sizeof(*ip6));
684edd3f315SSepherosa Ziehau 
685edd3f315SSepherosa Ziehau 		ip6->ip6_plen = 0;
686edd3f315SSepherosa Ziehau 		th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
687edd3f315SSepherosa Ziehau 	}
688edd3f315SSepherosa Ziehau #endif
689edd3f315SSepherosa Ziehau 	return (m_head);
690edd3f315SSepherosa Ziehau 
691edd3f315SSepherosa Ziehau #undef PULLUP_HDR
692edd3f315SSepherosa Ziehau }
693edd3f315SSepherosa Ziehau #endif	/* INET6 || INET */
694edd3f315SSepherosa Ziehau 
69515516c77SSepherosa Ziehau static int
696f1b0a43fSSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc, uint32_t filter)
697f1b0a43fSSepherosa Ziehau {
698f1b0a43fSSepherosa Ziehau 	int error = 0;
699f1b0a43fSSepherosa Ziehau 
700f1b0a43fSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
701f1b0a43fSSepherosa Ziehau 
702f1b0a43fSSepherosa Ziehau 	if (sc->hn_rx_filter != filter) {
703f1b0a43fSSepherosa Ziehau 		error = hn_rndis_set_rxfilter(sc, filter);
704f1b0a43fSSepherosa Ziehau 		if (!error)
705f1b0a43fSSepherosa Ziehau 			sc->hn_rx_filter = filter;
706f1b0a43fSSepherosa Ziehau 	}
707f1b0a43fSSepherosa Ziehau 	return (error);
708f1b0a43fSSepherosa Ziehau }
709f1b0a43fSSepherosa Ziehau 
710f1b0a43fSSepherosa Ziehau static int
711c08f7b2cSSepherosa Ziehau hn_rxfilter_config(struct hn_softc *sc)
71215516c77SSepherosa Ziehau {
71315516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
71415516c77SSepherosa Ziehau 	uint32_t filter;
71515516c77SSepherosa Ziehau 
71615516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
71715516c77SSepherosa Ziehau 
7185bdfd3fdSDexuan Cui 	if ((ifp->if_flags & IFF_PROMISC) ||
7195bdfd3fdSDexuan Cui 	    (sc->hn_flags & HN_FLAG_VF)) {
72015516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_PROMISCUOUS;
72115516c77SSepherosa Ziehau 	} else {
72215516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_DIRECTED;
72315516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_BROADCAST)
72415516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_BROADCAST;
72515516c77SSepherosa Ziehau 		/* TODO: support multicast list */
72615516c77SSepherosa Ziehau 		if ((ifp->if_flags & IFF_ALLMULTI) ||
72715516c77SSepherosa Ziehau 		    !TAILQ_EMPTY(&ifp->if_multiaddrs))
72815516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
72915516c77SSepherosa Ziehau 	}
730f1b0a43fSSepherosa Ziehau 	return (hn_set_rxfilter(sc, filter));
73115516c77SSepherosa Ziehau }
73215516c77SSepherosa Ziehau 
733dc13fee6SSepherosa Ziehau static void
734dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc)
735dc13fee6SSepherosa Ziehau {
736dc13fee6SSepherosa Ziehau 	uint32_t size, pkts;
737dc13fee6SSepherosa Ziehau 	int i;
738dc13fee6SSepherosa Ziehau 
739dc13fee6SSepherosa Ziehau 	/*
740dc13fee6SSepherosa Ziehau 	 * Setup aggregation size.
741dc13fee6SSepherosa Ziehau 	 */
742dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_size < 0)
743dc13fee6SSepherosa Ziehau 		size = UINT32_MAX;
744dc13fee6SSepherosa Ziehau 	else
745dc13fee6SSepherosa Ziehau 		size = sc->hn_agg_size;
746dc13fee6SSepherosa Ziehau 
747dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_size < size)
748dc13fee6SSepherosa Ziehau 		size = sc->hn_rndis_agg_size;
749dc13fee6SSepherosa Ziehau 
750a4364cfeSSepherosa Ziehau 	/* NOTE: We only aggregate packets using chimney sending buffers. */
751a4364cfeSSepherosa Ziehau 	if (size > (uint32_t)sc->hn_chim_szmax)
752a4364cfeSSepherosa Ziehau 		size = sc->hn_chim_szmax;
753a4364cfeSSepherosa Ziehau 
754dc13fee6SSepherosa Ziehau 	if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) {
755dc13fee6SSepherosa Ziehau 		/* Disable */
756dc13fee6SSepherosa Ziehau 		size = 0;
757dc13fee6SSepherosa Ziehau 		pkts = 0;
758dc13fee6SSepherosa Ziehau 		goto done;
759dc13fee6SSepherosa Ziehau 	}
760dc13fee6SSepherosa Ziehau 
761dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'int'. */
762dc13fee6SSepherosa Ziehau 	if (size > INT_MAX)
763dc13fee6SSepherosa Ziehau 		size = INT_MAX;
764dc13fee6SSepherosa Ziehau 
765dc13fee6SSepherosa Ziehau 	/*
766dc13fee6SSepherosa Ziehau 	 * Setup aggregation packet count.
767dc13fee6SSepherosa Ziehau 	 */
768dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_pkts < 0)
769dc13fee6SSepherosa Ziehau 		pkts = UINT32_MAX;
770dc13fee6SSepherosa Ziehau 	else
771dc13fee6SSepherosa Ziehau 		pkts = sc->hn_agg_pkts;
772dc13fee6SSepherosa Ziehau 
773dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_pkts < pkts)
774dc13fee6SSepherosa Ziehau 		pkts = sc->hn_rndis_agg_pkts;
775dc13fee6SSepherosa Ziehau 
776dc13fee6SSepherosa Ziehau 	if (pkts <= 1) {
777dc13fee6SSepherosa Ziehau 		/* Disable */
778dc13fee6SSepherosa Ziehau 		size = 0;
779dc13fee6SSepherosa Ziehau 		pkts = 0;
780dc13fee6SSepherosa Ziehau 		goto done;
781dc13fee6SSepherosa Ziehau 	}
782dc13fee6SSepherosa Ziehau 
783dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
784dc13fee6SSepherosa Ziehau 	if (pkts > SHRT_MAX)
785dc13fee6SSepherosa Ziehau 		pkts = SHRT_MAX;
786dc13fee6SSepherosa Ziehau 
787dc13fee6SSepherosa Ziehau done:
788dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
789dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_align > SHRT_MAX) {
790dc13fee6SSepherosa Ziehau 		/* Disable */
791dc13fee6SSepherosa Ziehau 		size = 0;
792dc13fee6SSepherosa Ziehau 		pkts = 0;
793dc13fee6SSepherosa Ziehau 	}
794dc13fee6SSepherosa Ziehau 
795dc13fee6SSepherosa Ziehau 	if (bootverbose) {
796dc13fee6SSepherosa Ziehau 		if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n",
797dc13fee6SSepherosa Ziehau 		    size, pkts, sc->hn_rndis_agg_align);
798dc13fee6SSepherosa Ziehau 	}
799dc13fee6SSepherosa Ziehau 
800dc13fee6SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
801dc13fee6SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
802dc13fee6SSepherosa Ziehau 
803dc13fee6SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
804dc13fee6SSepherosa Ziehau 		txr->hn_agg_szmax = size;
805dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktmax = pkts;
806dc13fee6SSepherosa Ziehau 		txr->hn_agg_align = sc->hn_rndis_agg_align;
807dc13fee6SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
808dc13fee6SSepherosa Ziehau 	}
809dc13fee6SSepherosa Ziehau }
810dc13fee6SSepherosa Ziehau 
81115516c77SSepherosa Ziehau static int
81215516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr)
81315516c77SSepherosa Ziehau {
81415516c77SSepherosa Ziehau 
81515516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet"));
81615516c77SSepherosa Ziehau 	if (hn_tx_swq_depth < txr->hn_txdesc_cnt)
81715516c77SSepherosa Ziehau 		return txr->hn_txdesc_cnt;
81815516c77SSepherosa Ziehau 	return hn_tx_swq_depth;
81915516c77SSepherosa Ziehau }
82015516c77SSepherosa Ziehau 
82134d68912SSepherosa Ziehau #ifndef RSS
82215516c77SSepherosa Ziehau static int
82315516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc)
82415516c77SSepherosa Ziehau {
82515516c77SSepherosa Ziehau 	int error;
82615516c77SSepherosa Ziehau 
82715516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
82815516c77SSepherosa Ziehau 
82915516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
83015516c77SSepherosa Ziehau 		return (ENXIO);
83115516c77SSepherosa Ziehau 
83215516c77SSepherosa Ziehau 	/*
83315516c77SSepherosa Ziehau 	 * Disable RSS first.
83415516c77SSepherosa Ziehau 	 *
83515516c77SSepherosa Ziehau 	 * NOTE:
83615516c77SSepherosa Ziehau 	 * Direct reconfiguration by setting the UNCHG flags does
83715516c77SSepherosa Ziehau 	 * _not_ work properly.
83815516c77SSepherosa Ziehau 	 */
83915516c77SSepherosa Ziehau 	if (bootverbose)
84015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "disable RSS\n");
84115516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE);
84215516c77SSepherosa Ziehau 	if (error) {
84315516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS disable failed\n");
84415516c77SSepherosa Ziehau 		return (error);
84515516c77SSepherosa Ziehau 	}
84615516c77SSepherosa Ziehau 
84715516c77SSepherosa Ziehau 	/*
84815516c77SSepherosa Ziehau 	 * Reenable the RSS w/ the updated RSS key or indirect
84915516c77SSepherosa Ziehau 	 * table.
85015516c77SSepherosa Ziehau 	 */
85115516c77SSepherosa Ziehau 	if (bootverbose)
85215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "reconfig RSS\n");
85315516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
85415516c77SSepherosa Ziehau 	if (error) {
85515516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS reconfig failed\n");
85615516c77SSepherosa Ziehau 		return (error);
85715516c77SSepherosa Ziehau 	}
85815516c77SSepherosa Ziehau 	return (0);
85915516c77SSepherosa Ziehau }
86034d68912SSepherosa Ziehau #endif	/* !RSS */
86115516c77SSepherosa Ziehau 
86215516c77SSepherosa Ziehau static void
863afd4971bSSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc)
86415516c77SSepherosa Ziehau {
86515516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
866afd4971bSSepherosa Ziehau 	int i, nchan;
86715516c77SSepherosa Ziehau 
868afd4971bSSepherosa Ziehau 	nchan = sc->hn_rx_ring_inuse;
86915516c77SSepherosa Ziehau 	KASSERT(nchan > 1, ("invalid # of channels %d", nchan));
87015516c77SSepherosa Ziehau 
87115516c77SSepherosa Ziehau 	/*
87215516c77SSepherosa Ziehau 	 * Check indirect table to make sure that all channels in it
87315516c77SSepherosa Ziehau 	 * can be used.
87415516c77SSepherosa Ziehau 	 */
87515516c77SSepherosa Ziehau 	for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
87615516c77SSepherosa Ziehau 		if (rss->rss_ind[i] >= nchan) {
87715516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp,
87815516c77SSepherosa Ziehau 			    "RSS indirect table %d fixup: %u -> %d\n",
87915516c77SSepherosa Ziehau 			    i, rss->rss_ind[i], nchan - 1);
88015516c77SSepherosa Ziehau 			rss->rss_ind[i] = nchan - 1;
88115516c77SSepherosa Ziehau 		}
88215516c77SSepherosa Ziehau 	}
88315516c77SSepherosa Ziehau }
88415516c77SSepherosa Ziehau 
88515516c77SSepherosa Ziehau static int
88615516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused)
88715516c77SSepherosa Ziehau {
88815516c77SSepherosa Ziehau 
88915516c77SSepherosa Ziehau 	return EOPNOTSUPP;
89015516c77SSepherosa Ziehau }
89115516c77SSepherosa Ziehau 
89215516c77SSepherosa Ziehau static void
89315516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
89415516c77SSepherosa Ziehau {
89515516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
89615516c77SSepherosa Ziehau 
89715516c77SSepherosa Ziehau 	ifmr->ifm_status = IFM_AVALID;
89815516c77SSepherosa Ziehau 	ifmr->ifm_active = IFM_ETHER;
89915516c77SSepherosa Ziehau 
90015516c77SSepherosa Ziehau 	if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) {
90115516c77SSepherosa Ziehau 		ifmr->ifm_active |= IFM_NONE;
90215516c77SSepherosa Ziehau 		return;
90315516c77SSepherosa Ziehau 	}
90415516c77SSepherosa Ziehau 	ifmr->ifm_status |= IFM_ACTIVE;
90515516c77SSepherosa Ziehau 	ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
90615516c77SSepherosa Ziehau }
90715516c77SSepherosa Ziehau 
9085bdfd3fdSDexuan Cui static void
9095bdfd3fdSDexuan Cui hn_update_vf_task(void *arg, int pending __unused)
9105bdfd3fdSDexuan Cui {
9115bdfd3fdSDexuan Cui 	struct hn_update_vf *uv = arg;
9125bdfd3fdSDexuan Cui 
9135bdfd3fdSDexuan Cui 	uv->rxr->hn_vf = uv->vf;
9145bdfd3fdSDexuan Cui }
9155bdfd3fdSDexuan Cui 
9165bdfd3fdSDexuan Cui static void
9175bdfd3fdSDexuan Cui hn_update_vf(struct hn_softc *sc, struct ifnet *vf)
9185bdfd3fdSDexuan Cui {
9195bdfd3fdSDexuan Cui 	struct hn_rx_ring *rxr;
9205bdfd3fdSDexuan Cui 	struct hn_update_vf uv;
9215bdfd3fdSDexuan Cui 	struct task task;
9225bdfd3fdSDexuan Cui 	int i;
9235bdfd3fdSDexuan Cui 
9245bdfd3fdSDexuan Cui 	HN_LOCK_ASSERT(sc);
9255bdfd3fdSDexuan Cui 
9265bdfd3fdSDexuan Cui 	TASK_INIT(&task, 0, hn_update_vf_task, &uv);
9275bdfd3fdSDexuan Cui 
9285bdfd3fdSDexuan Cui 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
9295bdfd3fdSDexuan Cui 		rxr = &sc->hn_rx_ring[i];
9305bdfd3fdSDexuan Cui 
9315bdfd3fdSDexuan Cui 		if (i < sc->hn_rx_ring_inuse) {
9325bdfd3fdSDexuan Cui 			uv.rxr = rxr;
9335bdfd3fdSDexuan Cui 			uv.vf = vf;
9345bdfd3fdSDexuan Cui 			vmbus_chan_run_task(rxr->hn_chan, &task);
9355bdfd3fdSDexuan Cui 		} else {
9365bdfd3fdSDexuan Cui 			rxr->hn_vf = vf;
9375bdfd3fdSDexuan Cui 		}
9385bdfd3fdSDexuan Cui 	}
9395bdfd3fdSDexuan Cui }
9405bdfd3fdSDexuan Cui 
9415bdfd3fdSDexuan Cui static void
9425bdfd3fdSDexuan Cui hn_set_vf(struct hn_softc *sc, struct ifnet *ifp, bool vf)
9435bdfd3fdSDexuan Cui {
9445bdfd3fdSDexuan Cui 	struct ifnet *hn_ifp;
9455bdfd3fdSDexuan Cui 
9465bdfd3fdSDexuan Cui 	HN_LOCK(sc);
9475bdfd3fdSDexuan Cui 
9485bdfd3fdSDexuan Cui 	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
9495bdfd3fdSDexuan Cui 		goto out;
9505bdfd3fdSDexuan Cui 
9515bdfd3fdSDexuan Cui 	hn_ifp = sc->hn_ifp;
9525bdfd3fdSDexuan Cui 
9535bdfd3fdSDexuan Cui 	if (ifp == hn_ifp)
9545bdfd3fdSDexuan Cui 		goto out;
9555bdfd3fdSDexuan Cui 
9565bdfd3fdSDexuan Cui 	if (ifp->if_alloctype != IFT_ETHER)
9575bdfd3fdSDexuan Cui 		goto out;
9585bdfd3fdSDexuan Cui 
9595bdfd3fdSDexuan Cui 	/* Ignore lagg/vlan interfaces */
9605bdfd3fdSDexuan Cui 	if (strcmp(ifp->if_dname, "lagg") == 0 ||
9615bdfd3fdSDexuan Cui 	    strcmp(ifp->if_dname, "vlan") == 0)
9625bdfd3fdSDexuan Cui 		goto out;
9635bdfd3fdSDexuan Cui 
9645bdfd3fdSDexuan Cui 	if (bcmp(IF_LLADDR(ifp), IF_LLADDR(hn_ifp), ETHER_ADDR_LEN) != 0)
9655bdfd3fdSDexuan Cui 		goto out;
9665bdfd3fdSDexuan Cui 
9675bdfd3fdSDexuan Cui 	/* Now we're sure 'ifp' is a real VF device. */
9685bdfd3fdSDexuan Cui 	if (vf) {
9695bdfd3fdSDexuan Cui 		if (sc->hn_flags & HN_FLAG_VF)
9705bdfd3fdSDexuan Cui 			goto out;
9715bdfd3fdSDexuan Cui 
9725bdfd3fdSDexuan Cui 		sc->hn_flags |= HN_FLAG_VF;
9735bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
9745bdfd3fdSDexuan Cui 	} else {
9755bdfd3fdSDexuan Cui 		if (!(sc->hn_flags & HN_FLAG_VF))
9765bdfd3fdSDexuan Cui 			goto out;
9775bdfd3fdSDexuan Cui 
9785bdfd3fdSDexuan Cui 		sc->hn_flags &= ~HN_FLAG_VF;
9795bdfd3fdSDexuan Cui 		if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
9805bdfd3fdSDexuan Cui 			hn_rxfilter_config(sc);
9815bdfd3fdSDexuan Cui 		else
9825bdfd3fdSDexuan Cui 			hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE);
9835bdfd3fdSDexuan Cui 	}
9845bdfd3fdSDexuan Cui 
9855bdfd3fdSDexuan Cui 	hn_nvs_set_datapath(sc,
9865bdfd3fdSDexuan Cui 	    vf ? HN_NVS_DATAPATH_VF : HN_NVS_DATAPATH_SYNTHETIC);
9875bdfd3fdSDexuan Cui 
9885bdfd3fdSDexuan Cui 	hn_update_vf(sc, vf ? ifp : NULL);
9895bdfd3fdSDexuan Cui 
9905bdfd3fdSDexuan Cui 	if (vf) {
9915bdfd3fdSDexuan Cui 		hn_suspend_mgmt(sc);
9925bdfd3fdSDexuan Cui 		sc->hn_link_flags &=
9935bdfd3fdSDexuan Cui 		    ~(HN_LINK_FLAG_LINKUP | HN_LINK_FLAG_NETCHG);
9945bdfd3fdSDexuan Cui 		if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
9955bdfd3fdSDexuan Cui 	} else {
9965bdfd3fdSDexuan Cui 		hn_resume_mgmt(sc);
9975bdfd3fdSDexuan Cui 	}
9985bdfd3fdSDexuan Cui 
999*33408a34SDexuan Cui 	devctl_notify("HYPERV_NIC_VF", if_name(hn_ifp),
1000*33408a34SDexuan Cui 	    vf ? "VF_UP" : "VF_DOWN", NULL);
1001*33408a34SDexuan Cui 
10025bdfd3fdSDexuan Cui 	if (bootverbose)
10035bdfd3fdSDexuan Cui 		if_printf(hn_ifp, "Data path is switched %s %s\n",
10045bdfd3fdSDexuan Cui 		    vf ? "to" : "from", if_name(ifp));
10055bdfd3fdSDexuan Cui out:
10065bdfd3fdSDexuan Cui 	HN_UNLOCK(sc);
10075bdfd3fdSDexuan Cui }
10085bdfd3fdSDexuan Cui 
10095bdfd3fdSDexuan Cui static void
10105bdfd3fdSDexuan Cui hn_ifnet_event(void *arg, struct ifnet *ifp, int event)
10115bdfd3fdSDexuan Cui {
10125bdfd3fdSDexuan Cui 	if (event != IFNET_EVENT_UP && event != IFNET_EVENT_DOWN)
10135bdfd3fdSDexuan Cui 		return;
10145bdfd3fdSDexuan Cui 
10155bdfd3fdSDexuan Cui 	hn_set_vf(arg, ifp, event == IFNET_EVENT_UP);
10165bdfd3fdSDexuan Cui }
10175bdfd3fdSDexuan Cui 
10185bdfd3fdSDexuan Cui static void
10195bdfd3fdSDexuan Cui hn_ifaddr_event(void *arg, struct ifnet *ifp)
10205bdfd3fdSDexuan Cui {
10215bdfd3fdSDexuan Cui 	hn_set_vf(arg, ifp, ifp->if_flags & IFF_UP);
10225bdfd3fdSDexuan Cui }
10235bdfd3fdSDexuan Cui 
102415516c77SSepherosa Ziehau /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
102515516c77SSepherosa Ziehau static const struct hyperv_guid g_net_vsc_device_type = {
102615516c77SSepherosa Ziehau 	.hv_guid = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
102715516c77SSepherosa Ziehau 		0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E}
102815516c77SSepherosa Ziehau };
102915516c77SSepherosa Ziehau 
103015516c77SSepherosa Ziehau static int
103115516c77SSepherosa Ziehau hn_probe(device_t dev)
103215516c77SSepherosa Ziehau {
103315516c77SSepherosa Ziehau 
103415516c77SSepherosa Ziehau 	if (VMBUS_PROBE_GUID(device_get_parent(dev), dev,
103515516c77SSepherosa Ziehau 	    &g_net_vsc_device_type) == 0) {
103615516c77SSepherosa Ziehau 		device_set_desc(dev, "Hyper-V Network Interface");
103715516c77SSepherosa Ziehau 		return BUS_PROBE_DEFAULT;
103815516c77SSepherosa Ziehau 	}
103915516c77SSepherosa Ziehau 	return ENXIO;
104015516c77SSepherosa Ziehau }
104115516c77SSepherosa Ziehau 
104215516c77SSepherosa Ziehau static int
104315516c77SSepherosa Ziehau hn_attach(device_t dev)
104415516c77SSepherosa Ziehau {
104515516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
104615516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
104715516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
104815516c77SSepherosa Ziehau 	uint8_t eaddr[ETHER_ADDR_LEN];
104915516c77SSepherosa Ziehau 	struct ifnet *ifp = NULL;
105015516c77SSepherosa Ziehau 	int error, ring_cnt, tx_ring_cnt;
105115516c77SSepherosa Ziehau 
105215516c77SSepherosa Ziehau 	sc->hn_dev = dev;
105315516c77SSepherosa Ziehau 	sc->hn_prichan = vmbus_get_channel(dev);
105415516c77SSepherosa Ziehau 	HN_LOCK_INIT(sc);
105515516c77SSepherosa Ziehau 
105615516c77SSepherosa Ziehau 	/*
1057dc13fee6SSepherosa Ziehau 	 * Initialize these tunables once.
1058dc13fee6SSepherosa Ziehau 	 */
1059dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = hn_tx_agg_size;
1060dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = hn_tx_agg_pkts;
1061dc13fee6SSepherosa Ziehau 
1062dc13fee6SSepherosa Ziehau 	/*
106315516c77SSepherosa Ziehau 	 * Setup taskqueue for transmission.
106415516c77SSepherosa Ziehau 	 */
10650e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_INDEP) {
1066fdd0222aSSepherosa Ziehau 		int i;
1067fdd0222aSSepherosa Ziehau 
1068fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs =
1069fdd0222aSSepherosa Ziehau 		    malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
1070fdd0222aSSepherosa Ziehau 		    M_DEVBUF, M_WAITOK);
1071fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i) {
1072fdd0222aSSepherosa Ziehau 			sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx",
1073fdd0222aSSepherosa Ziehau 			    M_WAITOK, taskqueue_thread_enqueue,
1074fdd0222aSSepherosa Ziehau 			    &sc->hn_tx_taskqs[i]);
1075fdd0222aSSepherosa Ziehau 			taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET,
1076fdd0222aSSepherosa Ziehau 			    "%s tx%d", device_get_nameunit(dev), i);
1077fdd0222aSSepherosa Ziehau 		}
10780e11868dSSepherosa Ziehau 	} else if (hn_tx_taskq_mode == HN_TX_TASKQ_M_GLOBAL) {
1079fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs = hn_tx_taskque;
108015516c77SSepherosa Ziehau 	}
108115516c77SSepherosa Ziehau 
108215516c77SSepherosa Ziehau 	/*
108315516c77SSepherosa Ziehau 	 * Setup taskqueue for mangement tasks, e.g. link status.
108415516c77SSepherosa Ziehau 	 */
108515516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK,
108615516c77SSepherosa Ziehau 	    taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0);
108715516c77SSepherosa Ziehau 	taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
108815516c77SSepherosa Ziehau 	    device_get_nameunit(dev));
108915516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
109015516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc);
109115516c77SSepherosa Ziehau 	TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0,
109215516c77SSepherosa Ziehau 	    hn_netchg_status_taskfunc, sc);
109315516c77SSepherosa Ziehau 
109415516c77SSepherosa Ziehau 	/*
109515516c77SSepherosa Ziehau 	 * Allocate ifnet and setup its name earlier, so that if_printf
109615516c77SSepherosa Ziehau 	 * can be used by functions, which will be called after
109715516c77SSepherosa Ziehau 	 * ether_ifattach().
109815516c77SSepherosa Ziehau 	 */
109915516c77SSepherosa Ziehau 	ifp = sc->hn_ifp = if_alloc(IFT_ETHER);
110015516c77SSepherosa Ziehau 	ifp->if_softc = sc;
110115516c77SSepherosa Ziehau 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
110215516c77SSepherosa Ziehau 
110315516c77SSepherosa Ziehau 	/*
110415516c77SSepherosa Ziehau 	 * Initialize ifmedia earlier so that it can be unconditionally
110515516c77SSepherosa Ziehau 	 * destroyed, if error happened later on.
110615516c77SSepherosa Ziehau 	 */
110715516c77SSepherosa Ziehau 	ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts);
110815516c77SSepherosa Ziehau 
110915516c77SSepherosa Ziehau 	/*
111015516c77SSepherosa Ziehau 	 * Figure out the # of RX rings (ring_cnt) and the # of TX rings
111115516c77SSepherosa Ziehau 	 * to use (tx_ring_cnt).
111215516c77SSepherosa Ziehau 	 *
111315516c77SSepherosa Ziehau 	 * NOTE:
111415516c77SSepherosa Ziehau 	 * The # of RX rings to use is same as the # of channels to use.
111515516c77SSepherosa Ziehau 	 */
111615516c77SSepherosa Ziehau 	ring_cnt = hn_chan_cnt;
111715516c77SSepherosa Ziehau 	if (ring_cnt <= 0) {
111815516c77SSepherosa Ziehau 		/* Default */
111915516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
112015516c77SSepherosa Ziehau 		if (ring_cnt > HN_RING_CNT_DEF_MAX)
112115516c77SSepherosa Ziehau 			ring_cnt = HN_RING_CNT_DEF_MAX;
112215516c77SSepherosa Ziehau 	} else if (ring_cnt > mp_ncpus) {
112315516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
112415516c77SSepherosa Ziehau 	}
112534d68912SSepherosa Ziehau #ifdef RSS
112634d68912SSepherosa Ziehau 	if (ring_cnt > rss_getnumbuckets())
112734d68912SSepherosa Ziehau 		ring_cnt = rss_getnumbuckets();
112834d68912SSepherosa Ziehau #endif
112915516c77SSepherosa Ziehau 
113015516c77SSepherosa Ziehau 	tx_ring_cnt = hn_tx_ring_cnt;
113115516c77SSepherosa Ziehau 	if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt)
113215516c77SSepherosa Ziehau 		tx_ring_cnt = ring_cnt;
113323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
113415516c77SSepherosa Ziehau 	if (hn_use_if_start) {
113515516c77SSepherosa Ziehau 		/* ifnet.if_start only needs one TX ring. */
113615516c77SSepherosa Ziehau 		tx_ring_cnt = 1;
113715516c77SSepherosa Ziehau 	}
113823bf9e15SSepherosa Ziehau #endif
113915516c77SSepherosa Ziehau 
114015516c77SSepherosa Ziehau 	/*
114115516c77SSepherosa Ziehau 	 * Set the leader CPU for channels.
114215516c77SSepherosa Ziehau 	 */
114315516c77SSepherosa Ziehau 	sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus;
114415516c77SSepherosa Ziehau 
114515516c77SSepherosa Ziehau 	/*
114615516c77SSepherosa Ziehau 	 * Create enough TX/RX rings, even if only limited number of
114715516c77SSepherosa Ziehau 	 * channels can be allocated.
114815516c77SSepherosa Ziehau 	 */
114915516c77SSepherosa Ziehau 	error = hn_create_tx_data(sc, tx_ring_cnt);
115015516c77SSepherosa Ziehau 	if (error)
115115516c77SSepherosa Ziehau 		goto failed;
115215516c77SSepherosa Ziehau 	error = hn_create_rx_data(sc, ring_cnt);
115315516c77SSepherosa Ziehau 	if (error)
115415516c77SSepherosa Ziehau 		goto failed;
115515516c77SSepherosa Ziehau 
115615516c77SSepherosa Ziehau 	/*
115715516c77SSepherosa Ziehau 	 * Create transaction context for NVS and RNDIS transactions.
115815516c77SSepherosa Ziehau 	 */
115915516c77SSepherosa Ziehau 	sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
116015516c77SSepherosa Ziehau 	    HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
116125641fc7SSepherosa Ziehau 	if (sc->hn_xact == NULL) {
116225641fc7SSepherosa Ziehau 		error = ENXIO;
116315516c77SSepherosa Ziehau 		goto failed;
116425641fc7SSepherosa Ziehau 	}
116525641fc7SSepherosa Ziehau 
116625641fc7SSepherosa Ziehau 	/*
116725641fc7SSepherosa Ziehau 	 * Install orphan handler for the revocation of this device's
116825641fc7SSepherosa Ziehau 	 * primary channel.
116925641fc7SSepherosa Ziehau 	 *
117025641fc7SSepherosa Ziehau 	 * NOTE:
117125641fc7SSepherosa Ziehau 	 * The processing order is critical here:
117225641fc7SSepherosa Ziehau 	 * Install the orphan handler, _before_ testing whether this
117325641fc7SSepherosa Ziehau 	 * device's primary channel has been revoked or not.
117425641fc7SSepherosa Ziehau 	 */
117525641fc7SSepherosa Ziehau 	vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact);
117625641fc7SSepherosa Ziehau 	if (vmbus_chan_is_revoked(sc->hn_prichan)) {
117725641fc7SSepherosa Ziehau 		error = ENXIO;
117825641fc7SSepherosa Ziehau 		goto failed;
117925641fc7SSepherosa Ziehau 	}
118015516c77SSepherosa Ziehau 
118115516c77SSepherosa Ziehau 	/*
118215516c77SSepherosa Ziehau 	 * Attach the synthetic parts, i.e. NVS and RNDIS.
118315516c77SSepherosa Ziehau 	 */
118415516c77SSepherosa Ziehau 	error = hn_synth_attach(sc, ETHERMTU);
118515516c77SSepherosa Ziehau 	if (error)
118615516c77SSepherosa Ziehau 		goto failed;
118715516c77SSepherosa Ziehau 
118815516c77SSepherosa Ziehau 	error = hn_rndis_get_eaddr(sc, eaddr);
118915516c77SSepherosa Ziehau 	if (error)
119015516c77SSepherosa Ziehau 		goto failed;
119115516c77SSepherosa Ziehau 
119215516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
119315516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
119415516c77SSepherosa Ziehau 		/*
119515516c77SSepherosa Ziehau 		 * Reduce TCP segment aggregation limit for multiple
119615516c77SSepherosa Ziehau 		 * RX rings to increase ACK timeliness.
119715516c77SSepherosa Ziehau 		 */
119815516c77SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF);
119915516c77SSepherosa Ziehau 	}
120015516c77SSepherosa Ziehau #endif
120115516c77SSepherosa Ziehau 
120215516c77SSepherosa Ziehau 	/*
120315516c77SSepherosa Ziehau 	 * Fixup TX stuffs after synthetic parts are attached.
120415516c77SSepherosa Ziehau 	 */
120515516c77SSepherosa Ziehau 	hn_fixup_tx_data(sc);
120615516c77SSepherosa Ziehau 
120715516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
120815516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
120915516c77SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD,
121015516c77SSepherosa Ziehau 	    &sc->hn_nvs_ver, 0, "NVS version");
121115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version",
121215516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
121315516c77SSepherosa Ziehau 	    hn_ndis_version_sysctl, "A", "NDIS version");
121415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps",
121515516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
121615516c77SSepherosa Ziehau 	    hn_caps_sysctl, "A", "capabilities");
121715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist",
121815516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
121915516c77SSepherosa Ziehau 	    hn_hwassist_sysctl, "A", "hwassist");
122015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter",
122115516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
122215516c77SSepherosa Ziehau 	    hn_rxfilter_sysctl, "A", "rxfilter");
122315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash",
122415516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
122515516c77SSepherosa Ziehau 	    hn_rss_hash_sysctl, "A", "RSS hash");
122615516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size",
122715516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count");
122834d68912SSepherosa Ziehau #ifndef RSS
122934d68912SSepherosa Ziehau 	/*
123034d68912SSepherosa Ziehau 	 * Don't allow RSS key/indirect table changes, if RSS is defined.
123134d68912SSepherosa Ziehau 	 */
123215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key",
123315516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
123415516c77SSepherosa Ziehau 	    hn_rss_key_sysctl, "IU", "RSS key");
123515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind",
123615516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
123715516c77SSepherosa Ziehau 	    hn_rss_ind_sysctl, "IU", "RSS indirect table");
123834d68912SSepherosa Ziehau #endif
1239dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size",
1240dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_size, 0,
1241dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation size limit");
1242dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts",
1243dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0,
1244dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation count limit");
1245dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align",
1246dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_align, 0,
1247dc13fee6SSepherosa Ziehau 	    "RNDIS packet transmission aggregation alignment");
1248dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size",
1249dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
1250dc13fee6SSepherosa Ziehau 	    hn_txagg_size_sysctl, "I",
1251dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation size, 0 -- disable, -1 -- auto");
1252dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts",
1253dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
1254dc13fee6SSepherosa Ziehau 	    hn_txagg_pkts_sysctl, "I",
1255dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation packets, "
1256dc13fee6SSepherosa Ziehau 	    "0 -- disable, -1 -- auto");
12576c1204dfSSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "polling",
12586c1204dfSSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
12596c1204dfSSepherosa Ziehau 	    hn_polling_sysctl, "I",
12606c1204dfSSepherosa Ziehau 	    "Polling frequency: [100,1000000], 0 disable polling");
126140d60d6eSDexuan Cui 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf",
126240d60d6eSDexuan Cui 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
126340d60d6eSDexuan Cui 	    hn_vf_sysctl, "A", "Virtual Function's name");
126415516c77SSepherosa Ziehau 
126515516c77SSepherosa Ziehau 	/*
126615516c77SSepherosa Ziehau 	 * Setup the ifmedia, which has been initialized earlier.
126715516c77SSepherosa Ziehau 	 */
126815516c77SSepherosa Ziehau 	ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL);
126915516c77SSepherosa Ziehau 	ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO);
127015516c77SSepherosa Ziehau 	/* XXX ifmedia_set really should do this for us */
127115516c77SSepherosa Ziehau 	sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media;
127215516c77SSepherosa Ziehau 
127315516c77SSepherosa Ziehau 	/*
127415516c77SSepherosa Ziehau 	 * Setup the ifnet for this interface.
127515516c77SSepherosa Ziehau 	 */
127615516c77SSepherosa Ziehau 
127715516c77SSepherosa Ziehau 	ifp->if_baudrate = IF_Gbps(10);
127815516c77SSepherosa Ziehau 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
127915516c77SSepherosa Ziehau 	ifp->if_ioctl = hn_ioctl;
128015516c77SSepherosa Ziehau 	ifp->if_init = hn_init;
128123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
128215516c77SSepherosa Ziehau 	if (hn_use_if_start) {
128315516c77SSepherosa Ziehau 		int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]);
128415516c77SSepherosa Ziehau 
128515516c77SSepherosa Ziehau 		ifp->if_start = hn_start;
128615516c77SSepherosa Ziehau 		IFQ_SET_MAXLEN(&ifp->if_snd, qdepth);
128715516c77SSepherosa Ziehau 		ifp->if_snd.ifq_drv_maxlen = qdepth - 1;
128815516c77SSepherosa Ziehau 		IFQ_SET_READY(&ifp->if_snd);
128923bf9e15SSepherosa Ziehau 	} else
129023bf9e15SSepherosa Ziehau #endif
129123bf9e15SSepherosa Ziehau 	{
129215516c77SSepherosa Ziehau 		ifp->if_transmit = hn_transmit;
129315516c77SSepherosa Ziehau 		ifp->if_qflush = hn_xmit_qflush;
129415516c77SSepherosa Ziehau 	}
129515516c77SSepherosa Ziehau 
129615516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO;
129715516c77SSepherosa Ziehau #ifdef foo
129815516c77SSepherosa Ziehau 	/* We can't diff IPv6 packets from IPv4 packets on RX path. */
129915516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM_IPV6;
130015516c77SSepherosa Ziehau #endif
130115516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_VLAN) {
130215516c77SSepherosa Ziehau 		/* XXX not sure about VLAN_MTU. */
130315516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
130415516c77SSepherosa Ziehau 	}
130515516c77SSepherosa Ziehau 
130615516c77SSepherosa Ziehau 	ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist;
130715516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP_MASK)
130815516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM;
130915516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP6_MASK)
131015516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM_IPV6;
131115516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO4) {
131215516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO4;
131315516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP_TSO;
131415516c77SSepherosa Ziehau 	}
131515516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO6) {
131615516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO6;
131715516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP6_TSO;
131815516c77SSepherosa Ziehau 	}
131915516c77SSepherosa Ziehau 
132015516c77SSepherosa Ziehau 	/* Enable all available capabilities by default. */
132115516c77SSepherosa Ziehau 	ifp->if_capenable = ifp->if_capabilities;
132215516c77SSepherosa Ziehau 
13237960e6baSSepherosa Ziehau 	/*
13247960e6baSSepherosa Ziehau 	 * Disable IPv6 TSO and TXCSUM by default, they still can
13257960e6baSSepherosa Ziehau 	 * be enabled through SIOCSIFCAP.
13267960e6baSSepherosa Ziehau 	 */
13277960e6baSSepherosa Ziehau 	ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
13287960e6baSSepherosa Ziehau 	ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO);
13297960e6baSSepherosa Ziehau 
133015516c77SSepherosa Ziehau 	if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) {
133115516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU);
133215516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX;
133315516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = PAGE_SIZE;
133415516c77SSepherosa Ziehau 	}
133515516c77SSepherosa Ziehau 
133615516c77SSepherosa Ziehau 	ether_ifattach(ifp, eaddr);
133715516c77SSepherosa Ziehau 
133815516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) {
133915516c77SSepherosa Ziehau 		if_printf(ifp, "TSO segcnt %u segsz %u\n",
134015516c77SSepherosa Ziehau 		    ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize);
134115516c77SSepherosa Ziehau 	}
134215516c77SSepherosa Ziehau 
134315516c77SSepherosa Ziehau 	/* Inform the upper layer about the long frame support. */
134415516c77SSepherosa Ziehau 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
134515516c77SSepherosa Ziehau 
134615516c77SSepherosa Ziehau 	/*
134715516c77SSepherosa Ziehau 	 * Kick off link status check.
134815516c77SSepherosa Ziehau 	 */
134915516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
135015516c77SSepherosa Ziehau 	hn_update_link_status(sc);
135115516c77SSepherosa Ziehau 
13525bdfd3fdSDexuan Cui 	sc->hn_ifnet_evthand = EVENTHANDLER_REGISTER(ifnet_event,
13535bdfd3fdSDexuan Cui 	    hn_ifnet_event, sc, EVENTHANDLER_PRI_ANY);
13545bdfd3fdSDexuan Cui 
13555bdfd3fdSDexuan Cui 	sc->hn_ifaddr_evthand = EVENTHANDLER_REGISTER(ifaddr_event,
13565bdfd3fdSDexuan Cui 	    hn_ifaddr_event, sc, EVENTHANDLER_PRI_ANY);
13575bdfd3fdSDexuan Cui 
135815516c77SSepherosa Ziehau 	return (0);
135915516c77SSepherosa Ziehau failed:
136015516c77SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)
136115516c77SSepherosa Ziehau 		hn_synth_detach(sc);
136215516c77SSepherosa Ziehau 	hn_detach(dev);
136315516c77SSepherosa Ziehau 	return (error);
136415516c77SSepherosa Ziehau }
136515516c77SSepherosa Ziehau 
136615516c77SSepherosa Ziehau static int
136715516c77SSepherosa Ziehau hn_detach(device_t dev)
136815516c77SSepherosa Ziehau {
136915516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
137015516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
137115516c77SSepherosa Ziehau 
13725bdfd3fdSDexuan Cui 	if (sc->hn_ifaddr_evthand != NULL)
13735bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifaddr_event, sc->hn_ifaddr_evthand);
13745bdfd3fdSDexuan Cui 	if (sc->hn_ifnet_evthand != NULL)
13755bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifnet_event, sc->hn_ifnet_evthand);
13765bdfd3fdSDexuan Cui 
137725641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) {
137825641fc7SSepherosa Ziehau 		/*
137925641fc7SSepherosa Ziehau 		 * In case that the vmbus missed the orphan handler
138025641fc7SSepherosa Ziehau 		 * installation.
138125641fc7SSepherosa Ziehau 		 */
138225641fc7SSepherosa Ziehau 		vmbus_xact_ctx_orphan(sc->hn_xact);
138325641fc7SSepherosa Ziehau 	}
138425641fc7SSepherosa Ziehau 
138515516c77SSepherosa Ziehau 	if (device_is_attached(dev)) {
138615516c77SSepherosa Ziehau 		HN_LOCK(sc);
138715516c77SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
138815516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
13895bdfd3fdSDexuan Cui 				hn_stop(sc, true);
139015516c77SSepherosa Ziehau 			/*
139115516c77SSepherosa Ziehau 			 * NOTE:
139215516c77SSepherosa Ziehau 			 * hn_stop() only suspends data, so managment
139315516c77SSepherosa Ziehau 			 * stuffs have to be suspended manually here.
139415516c77SSepherosa Ziehau 			 */
139515516c77SSepherosa Ziehau 			hn_suspend_mgmt(sc);
139615516c77SSepherosa Ziehau 			hn_synth_detach(sc);
139715516c77SSepherosa Ziehau 		}
139815516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
139915516c77SSepherosa Ziehau 		ether_ifdetach(ifp);
140015516c77SSepherosa Ziehau 	}
140115516c77SSepherosa Ziehau 
140215516c77SSepherosa Ziehau 	ifmedia_removeall(&sc->hn_media);
140315516c77SSepherosa Ziehau 	hn_destroy_rx_data(sc);
140415516c77SSepherosa Ziehau 	hn_destroy_tx_data(sc);
140515516c77SSepherosa Ziehau 
14060e11868dSSepherosa Ziehau 	if (sc->hn_tx_taskqs != NULL && sc->hn_tx_taskqs != hn_tx_taskque) {
1407fdd0222aSSepherosa Ziehau 		int i;
1408fdd0222aSSepherosa Ziehau 
1409fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
1410fdd0222aSSepherosa Ziehau 			taskqueue_free(sc->hn_tx_taskqs[i]);
1411fdd0222aSSepherosa Ziehau 		free(sc->hn_tx_taskqs, M_DEVBUF);
1412fdd0222aSSepherosa Ziehau 	}
141315516c77SSepherosa Ziehau 	taskqueue_free(sc->hn_mgmt_taskq0);
141415516c77SSepherosa Ziehau 
141525641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL) {
141625641fc7SSepherosa Ziehau 		/*
141725641fc7SSepherosa Ziehau 		 * Uninstall the orphan handler _before_ the xact is
141825641fc7SSepherosa Ziehau 		 * destructed.
141925641fc7SSepherosa Ziehau 		 */
142025641fc7SSepherosa Ziehau 		vmbus_chan_unset_orphan(sc->hn_prichan);
142115516c77SSepherosa Ziehau 		vmbus_xact_ctx_destroy(sc->hn_xact);
142225641fc7SSepherosa Ziehau 	}
142315516c77SSepherosa Ziehau 
142415516c77SSepherosa Ziehau 	if_free(ifp);
142515516c77SSepherosa Ziehau 
142615516c77SSepherosa Ziehau 	HN_LOCK_DESTROY(sc);
142715516c77SSepherosa Ziehau 	return (0);
142815516c77SSepherosa Ziehau }
142915516c77SSepherosa Ziehau 
143015516c77SSepherosa Ziehau static int
143115516c77SSepherosa Ziehau hn_shutdown(device_t dev)
143215516c77SSepherosa Ziehau {
143315516c77SSepherosa Ziehau 
143415516c77SSepherosa Ziehau 	return (0);
143515516c77SSepherosa Ziehau }
143615516c77SSepherosa Ziehau 
143715516c77SSepherosa Ziehau static void
143815516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc)
143915516c77SSepherosa Ziehau {
144015516c77SSepherosa Ziehau 	uint32_t link_status;
144115516c77SSepherosa Ziehau 	int error;
144215516c77SSepherosa Ziehau 
144315516c77SSepherosa Ziehau 	error = hn_rndis_get_linkstatus(sc, &link_status);
144415516c77SSepherosa Ziehau 	if (error) {
144515516c77SSepherosa Ziehau 		/* XXX what to do? */
144615516c77SSepherosa Ziehau 		return;
144715516c77SSepherosa Ziehau 	}
144815516c77SSepherosa Ziehau 
144915516c77SSepherosa Ziehau 	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
145015516c77SSepherosa Ziehau 		sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
145115516c77SSepherosa Ziehau 	else
145215516c77SSepherosa Ziehau 		sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
145315516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp,
145415516c77SSepherosa Ziehau 	    (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ?
145515516c77SSepherosa Ziehau 	    LINK_STATE_UP : LINK_STATE_DOWN);
145615516c77SSepherosa Ziehau }
145715516c77SSepherosa Ziehau 
145815516c77SSepherosa Ziehau static void
145915516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused)
146015516c77SSepherosa Ziehau {
146115516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
146215516c77SSepherosa Ziehau 
146315516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
146415516c77SSepherosa Ziehau 		return;
146515516c77SSepherosa Ziehau 	hn_link_status(sc);
146615516c77SSepherosa Ziehau }
146715516c77SSepherosa Ziehau 
146815516c77SSepherosa Ziehau static void
146915516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused)
147015516c77SSepherosa Ziehau {
147115516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
147215516c77SSepherosa Ziehau 
147315516c77SSepherosa Ziehau 	/* Prevent any link status checks from running. */
147415516c77SSepherosa Ziehau 	sc->hn_link_flags |= HN_LINK_FLAG_NETCHG;
147515516c77SSepherosa Ziehau 
147615516c77SSepherosa Ziehau 	/*
147715516c77SSepherosa Ziehau 	 * Fake up a [link down --> link up] state change; 5 seconds
147815516c77SSepherosa Ziehau 	 * delay is used, which closely simulates miibus reaction
147915516c77SSepherosa Ziehau 	 * upon link down event.
148015516c77SSepherosa Ziehau 	 */
148115516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
148215516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
148315516c77SSepherosa Ziehau 	taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0,
148415516c77SSepherosa Ziehau 	    &sc->hn_netchg_status, 5 * hz);
148515516c77SSepherosa Ziehau }
148615516c77SSepherosa Ziehau 
148715516c77SSepherosa Ziehau static void
148815516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused)
148915516c77SSepherosa Ziehau {
149015516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
149115516c77SSepherosa Ziehau 
149215516c77SSepherosa Ziehau 	/* Re-allow link status checks. */
149315516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG;
149415516c77SSepherosa Ziehau 	hn_link_status(sc);
149515516c77SSepherosa Ziehau }
149615516c77SSepherosa Ziehau 
149715516c77SSepherosa Ziehau static void
149815516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc)
149915516c77SSepherosa Ziehau {
150015516c77SSepherosa Ziehau 
150115516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
150215516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
150315516c77SSepherosa Ziehau }
150415516c77SSepherosa Ziehau 
150515516c77SSepherosa Ziehau static void
150615516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc)
150715516c77SSepherosa Ziehau {
150815516c77SSepherosa Ziehau 
150915516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
151015516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init);
151115516c77SSepherosa Ziehau }
151215516c77SSepherosa Ziehau 
151315516c77SSepherosa Ziehau static __inline int
151415516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
151515516c77SSepherosa Ziehau     struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
151615516c77SSepherosa Ziehau {
151715516c77SSepherosa Ziehau 	struct mbuf *m = *m_head;
151815516c77SSepherosa Ziehau 	int error;
151915516c77SSepherosa Ziehau 
152015516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim"));
152115516c77SSepherosa Ziehau 
152215516c77SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap,
152315516c77SSepherosa Ziehau 	    m, segs, nsegs, BUS_DMA_NOWAIT);
152415516c77SSepherosa Ziehau 	if (error == EFBIG) {
152515516c77SSepherosa Ziehau 		struct mbuf *m_new;
152615516c77SSepherosa Ziehau 
152715516c77SSepherosa Ziehau 		m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX);
152815516c77SSepherosa Ziehau 		if (m_new == NULL)
152915516c77SSepherosa Ziehau 			return ENOBUFS;
153015516c77SSepherosa Ziehau 		else
153115516c77SSepherosa Ziehau 			*m_head = m = m_new;
153215516c77SSepherosa Ziehau 		txr->hn_tx_collapsed++;
153315516c77SSepherosa Ziehau 
153415516c77SSepherosa Ziehau 		error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag,
153515516c77SSepherosa Ziehau 		    txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT);
153615516c77SSepherosa Ziehau 	}
153715516c77SSepherosa Ziehau 	if (!error) {
153815516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap,
153915516c77SSepherosa Ziehau 		    BUS_DMASYNC_PREWRITE);
154015516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_DMAMAP;
154115516c77SSepherosa Ziehau 	}
154215516c77SSepherosa Ziehau 	return error;
154315516c77SSepherosa Ziehau }
154415516c77SSepherosa Ziehau 
154515516c77SSepherosa Ziehau static __inline int
154615516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd)
154715516c77SSepherosa Ziehau {
154815516c77SSepherosa Ziehau 
154915516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0,
155015516c77SSepherosa Ziehau 	    ("put an onlist txd %#x", txd->flags));
1551dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1552dc13fee6SSepherosa Ziehau 	    ("put an onagg txd %#x", txd->flags));
155315516c77SSepherosa Ziehau 
155415516c77SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
155515516c77SSepherosa Ziehau 	if (atomic_fetchadd_int(&txd->refs, -1) != 1)
155615516c77SSepherosa Ziehau 		return 0;
155715516c77SSepherosa Ziehau 
1558dc13fee6SSepherosa Ziehau 	if (!STAILQ_EMPTY(&txd->agg_list)) {
1559dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tmp_txd;
1560dc13fee6SSepherosa Ziehau 
1561dc13fee6SSepherosa Ziehau 		while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) {
1562dc13fee6SSepherosa Ziehau 			int freed;
1563dc13fee6SSepherosa Ziehau 
1564dc13fee6SSepherosa Ziehau 			KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list),
1565dc13fee6SSepherosa Ziehau 			    ("resursive aggregation on aggregated txdesc"));
1566dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG),
1567dc13fee6SSepherosa Ziehau 			    ("not aggregated txdesc"));
1568dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
1569dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc uses dmamap"));
1570dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
1571dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc consumes "
1572dc13fee6SSepherosa Ziehau 			     "chimney sending buffer"));
1573dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_size == 0,
1574dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc has non-zero "
1575dc13fee6SSepherosa Ziehau 			     "chimney sending size"));
1576dc13fee6SSepherosa Ziehau 
1577dc13fee6SSepherosa Ziehau 			STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link);
1578dc13fee6SSepherosa Ziehau 			tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG;
1579dc13fee6SSepherosa Ziehau 			freed = hn_txdesc_put(txr, tmp_txd);
1580dc13fee6SSepherosa Ziehau 			KASSERT(freed, ("failed to free aggregated txdesc"));
1581dc13fee6SSepherosa Ziehau 		}
1582dc13fee6SSepherosa Ziehau 	}
1583dc13fee6SSepherosa Ziehau 
158415516c77SSepherosa Ziehau 	if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) {
158515516c77SSepherosa Ziehau 		KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
158615516c77SSepherosa Ziehau 		    ("chim txd uses dmamap"));
158715516c77SSepherosa Ziehau 		hn_chim_free(txr->hn_sc, txd->chim_index);
158815516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
1589dc13fee6SSepherosa Ziehau 		txd->chim_size = 0;
159015516c77SSepherosa Ziehau 	} else if (txd->flags & HN_TXD_FLAG_DMAMAP) {
159115516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag,
159215516c77SSepherosa Ziehau 		    txd->data_dmap, BUS_DMASYNC_POSTWRITE);
159315516c77SSepherosa Ziehau 		bus_dmamap_unload(txr->hn_tx_data_dtag,
159415516c77SSepherosa Ziehau 		    txd->data_dmap);
159515516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_DMAMAP;
159615516c77SSepherosa Ziehau 	}
159715516c77SSepherosa Ziehau 
159815516c77SSepherosa Ziehau 	if (txd->m != NULL) {
159915516c77SSepherosa Ziehau 		m_freem(txd->m);
160015516c77SSepherosa Ziehau 		txd->m = NULL;
160115516c77SSepherosa Ziehau 	}
160215516c77SSepherosa Ziehau 
160315516c77SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONLIST;
160415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
160515516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
160615516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_avail >= 0 &&
160715516c77SSepherosa Ziehau 	    txr->hn_txdesc_avail < txr->hn_txdesc_cnt,
160815516c77SSepherosa Ziehau 	    ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail));
160915516c77SSepherosa Ziehau 	txr->hn_txdesc_avail++;
161015516c77SSepherosa Ziehau 	SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
161115516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
161285e4ae1eSSepherosa Ziehau #else	/* HN_USE_TXDESC_BUFRING */
161385e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
161415516c77SSepherosa Ziehau 	atomic_add_int(&txr->hn_txdesc_avail, 1);
161515516c77SSepherosa Ziehau #endif
161685e4ae1eSSepherosa Ziehau 	buf_ring_enqueue(txr->hn_txdesc_br, txd);
161785e4ae1eSSepherosa Ziehau #endif	/* !HN_USE_TXDESC_BUFRING */
161815516c77SSepherosa Ziehau 
161915516c77SSepherosa Ziehau 	return 1;
162015516c77SSepherosa Ziehau }
162115516c77SSepherosa Ziehau 
162215516c77SSepherosa Ziehau static __inline struct hn_txdesc *
162315516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr)
162415516c77SSepherosa Ziehau {
162515516c77SSepherosa Ziehau 	struct hn_txdesc *txd;
162615516c77SSepherosa Ziehau 
162715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
162815516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
162915516c77SSepherosa Ziehau 	txd = SLIST_FIRST(&txr->hn_txlist);
163015516c77SSepherosa Ziehau 	if (txd != NULL) {
163115516c77SSepherosa Ziehau 		KASSERT(txr->hn_txdesc_avail > 0,
163215516c77SSepherosa Ziehau 		    ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail));
163315516c77SSepherosa Ziehau 		txr->hn_txdesc_avail--;
163415516c77SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&txr->hn_txlist, link);
163515516c77SSepherosa Ziehau 	}
163615516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
163715516c77SSepherosa Ziehau #else
163815516c77SSepherosa Ziehau 	txd = buf_ring_dequeue_sc(txr->hn_txdesc_br);
163915516c77SSepherosa Ziehau #endif
164015516c77SSepherosa Ziehau 
164115516c77SSepherosa Ziehau 	if (txd != NULL) {
164215516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
164385e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
164415516c77SSepherosa Ziehau 		atomic_subtract_int(&txr->hn_txdesc_avail, 1);
164515516c77SSepherosa Ziehau #endif
164685e4ae1eSSepherosa Ziehau #endif	/* HN_USE_TXDESC_BUFRING */
164715516c77SSepherosa Ziehau 		KASSERT(txd->m == NULL && txd->refs == 0 &&
1648dc13fee6SSepherosa Ziehau 		    STAILQ_EMPTY(&txd->agg_list) &&
164915516c77SSepherosa Ziehau 		    txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
1650dc13fee6SSepherosa Ziehau 		    txd->chim_size == 0 &&
165115516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONLIST) &&
1652dc13fee6SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONAGG) == 0 &&
165315516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd"));
165415516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_ONLIST;
165515516c77SSepherosa Ziehau 		txd->refs = 1;
165615516c77SSepherosa Ziehau 	}
165715516c77SSepherosa Ziehau 	return txd;
165815516c77SSepherosa Ziehau }
165915516c77SSepherosa Ziehau 
166015516c77SSepherosa Ziehau static __inline void
166115516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd)
166215516c77SSepherosa Ziehau {
166315516c77SSepherosa Ziehau 
166415516c77SSepherosa Ziehau 	/* 0->1 transition will never work */
166525641fc7SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
166615516c77SSepherosa Ziehau 	atomic_add_int(&txd->refs, 1);
166715516c77SSepherosa Ziehau }
166815516c77SSepherosa Ziehau 
1669dc13fee6SSepherosa Ziehau static __inline void
1670dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd)
1671dc13fee6SSepherosa Ziehau {
1672dc13fee6SSepherosa Ziehau 
1673dc13fee6SSepherosa Ziehau 	KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1674dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on aggregating txdesc"));
1675dc13fee6SSepherosa Ziehau 
1676dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1677dc13fee6SSepherosa Ziehau 	    ("already aggregated"));
1678dc13fee6SSepherosa Ziehau 	KASSERT(STAILQ_EMPTY(&txd->agg_list),
1679dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on to-be-aggregated txdesc"));
1680dc13fee6SSepherosa Ziehau 
1681dc13fee6SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONAGG;
1682dc13fee6SSepherosa Ziehau 	STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link);
1683dc13fee6SSepherosa Ziehau }
1684dc13fee6SSepherosa Ziehau 
168515516c77SSepherosa Ziehau static bool
168615516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr)
168715516c77SSepherosa Ziehau {
168815516c77SSepherosa Ziehau 	bool pending = false;
168915516c77SSepherosa Ziehau 
169015516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
169115516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
169215516c77SSepherosa Ziehau 	if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt)
169315516c77SSepherosa Ziehau 		pending = true;
169415516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
169515516c77SSepherosa Ziehau #else
169615516c77SSepherosa Ziehau 	if (!buf_ring_full(txr->hn_txdesc_br))
169715516c77SSepherosa Ziehau 		pending = true;
169815516c77SSepherosa Ziehau #endif
169915516c77SSepherosa Ziehau 	return (pending);
170015516c77SSepherosa Ziehau }
170115516c77SSepherosa Ziehau 
170215516c77SSepherosa Ziehau static __inline void
170315516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr)
170415516c77SSepherosa Ziehau {
170515516c77SSepherosa Ziehau 	txr->hn_has_txeof = 0;
170615516c77SSepherosa Ziehau 	txr->hn_txeof(txr);
170715516c77SSepherosa Ziehau }
170815516c77SSepherosa Ziehau 
170915516c77SSepherosa Ziehau static void
171015516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc,
171115516c77SSepherosa Ziehau     struct vmbus_channel *chan, const void *data __unused, int dlen __unused)
171215516c77SSepherosa Ziehau {
171315516c77SSepherosa Ziehau 	struct hn_txdesc *txd = sndc->hn_cbarg;
171415516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
171515516c77SSepherosa Ziehau 
171615516c77SSepherosa Ziehau 	txr = txd->txr;
171715516c77SSepherosa Ziehau 	KASSERT(txr->hn_chan == chan,
171815516c77SSepherosa Ziehau 	    ("channel mismatch, on chan%u, should be chan%u",
1719aa1a2adcSSepherosa Ziehau 	     vmbus_chan_id(chan), vmbus_chan_id(txr->hn_chan)));
172015516c77SSepherosa Ziehau 
172115516c77SSepherosa Ziehau 	txr->hn_has_txeof = 1;
172215516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
172315516c77SSepherosa Ziehau 
172415516c77SSepherosa Ziehau 	++txr->hn_txdone_cnt;
172515516c77SSepherosa Ziehau 	if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) {
172615516c77SSepherosa Ziehau 		txr->hn_txdone_cnt = 0;
172715516c77SSepherosa Ziehau 		if (txr->hn_oactive)
172815516c77SSepherosa Ziehau 			hn_txeof(txr);
172915516c77SSepherosa Ziehau 	}
173015516c77SSepherosa Ziehau }
173115516c77SSepherosa Ziehau 
173215516c77SSepherosa Ziehau static void
173315516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
173415516c77SSepherosa Ziehau {
173515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
173615516c77SSepherosa Ziehau 	tcp_lro_flush_all(&rxr->hn_lro);
173715516c77SSepherosa Ziehau #endif
173815516c77SSepherosa Ziehau 
173915516c77SSepherosa Ziehau 	/*
174015516c77SSepherosa Ziehau 	 * NOTE:
174115516c77SSepherosa Ziehau 	 * 'txr' could be NULL, if multiple channels and
174215516c77SSepherosa Ziehau 	 * ifnet.if_start method are enabled.
174315516c77SSepherosa Ziehau 	 */
174415516c77SSepherosa Ziehau 	if (txr == NULL || !txr->hn_has_txeof)
174515516c77SSepherosa Ziehau 		return;
174615516c77SSepherosa Ziehau 
174715516c77SSepherosa Ziehau 	txr->hn_txdone_cnt = 0;
174815516c77SSepherosa Ziehau 	hn_txeof(txr);
174915516c77SSepherosa Ziehau }
175015516c77SSepherosa Ziehau 
175115516c77SSepherosa Ziehau static __inline uint32_t
175215516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs)
175315516c77SSepherosa Ziehau {
175415516c77SSepherosa Ziehau 
175515516c77SSepherosa Ziehau 	KASSERT(ofs >= sizeof(struct rndis_packet_msg),
175615516c77SSepherosa Ziehau 	    ("invalid RNDIS packet msg offset %u", ofs));
175715516c77SSepherosa Ziehau 	return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset));
175815516c77SSepherosa Ziehau }
175915516c77SSepherosa Ziehau 
176015516c77SSepherosa Ziehau static __inline void *
176115516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
176215516c77SSepherosa Ziehau     size_t pi_dlen, uint32_t pi_type)
176315516c77SSepherosa Ziehau {
176415516c77SSepherosa Ziehau 	const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
176515516c77SSepherosa Ziehau 	struct rndis_pktinfo *pi;
176615516c77SSepherosa Ziehau 
176715516c77SSepherosa Ziehau 	KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
176815516c77SSepherosa Ziehau 	    ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
176915516c77SSepherosa Ziehau 
177015516c77SSepherosa Ziehau 	/*
177115516c77SSepherosa Ziehau 	 * Per-packet-info does not move; it only grows.
177215516c77SSepherosa Ziehau 	 *
177315516c77SSepherosa Ziehau 	 * NOTE:
177415516c77SSepherosa Ziehau 	 * rm_pktinfooffset in this phase counts from the beginning
177515516c77SSepherosa Ziehau 	 * of rndis_packet_msg.
177615516c77SSepherosa Ziehau 	 */
177715516c77SSepherosa Ziehau 	KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
177815516c77SSepherosa Ziehau 	    ("%u pktinfo overflows RNDIS packet msg", pi_type));
177915516c77SSepherosa Ziehau 	pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
178015516c77SSepherosa Ziehau 	    pkt->rm_pktinfolen);
178115516c77SSepherosa Ziehau 	pkt->rm_pktinfolen += pi_size;
178215516c77SSepherosa Ziehau 
178315516c77SSepherosa Ziehau 	pi->rm_size = pi_size;
178415516c77SSepherosa Ziehau 	pi->rm_type = pi_type;
178515516c77SSepherosa Ziehau 	pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
178615516c77SSepherosa Ziehau 
178715516c77SSepherosa Ziehau 	/* Data immediately follow per-packet-info. */
178815516c77SSepherosa Ziehau 	pkt->rm_dataoffset += pi_size;
178915516c77SSepherosa Ziehau 
179015516c77SSepherosa Ziehau 	/* Update RNDIS packet msg length */
179115516c77SSepherosa Ziehau 	pkt->rm_len += pi_size;
179215516c77SSepherosa Ziehau 
179315516c77SSepherosa Ziehau 	return (pi->rm_data);
179415516c77SSepherosa Ziehau }
179515516c77SSepherosa Ziehau 
1796dc13fee6SSepherosa Ziehau static __inline int
1797dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr)
1798dc13fee6SSepherosa Ziehau {
1799dc13fee6SSepherosa Ziehau 	struct hn_txdesc *txd;
1800dc13fee6SSepherosa Ziehau 	struct mbuf *m;
1801dc13fee6SSepherosa Ziehau 	int error, pkts;
1802dc13fee6SSepherosa Ziehau 
1803dc13fee6SSepherosa Ziehau 	txd = txr->hn_agg_txd;
1804dc13fee6SSepherosa Ziehau 	KASSERT(txd != NULL, ("no aggregate txdesc"));
1805dc13fee6SSepherosa Ziehau 
1806dc13fee6SSepherosa Ziehau 	/*
1807dc13fee6SSepherosa Ziehau 	 * Since hn_txpkt() will reset this temporary stat, save
1808dc13fee6SSepherosa Ziehau 	 * it now, so that oerrors can be updated properly, if
1809dc13fee6SSepherosa Ziehau 	 * hn_txpkt() ever fails.
1810dc13fee6SSepherosa Ziehau 	 */
1811dc13fee6SSepherosa Ziehau 	pkts = txr->hn_stat_pkts;
1812dc13fee6SSepherosa Ziehau 
1813dc13fee6SSepherosa Ziehau 	/*
1814dc13fee6SSepherosa Ziehau 	 * Since txd's mbuf will _not_ be freed upon hn_txpkt()
1815dc13fee6SSepherosa Ziehau 	 * failure, save it for later freeing, if hn_txpkt() ever
1816dc13fee6SSepherosa Ziehau 	 * fails.
1817dc13fee6SSepherosa Ziehau 	 */
1818dc13fee6SSepherosa Ziehau 	m = txd->m;
1819dc13fee6SSepherosa Ziehau 	error = hn_txpkt(ifp, txr, txd);
1820dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
1821dc13fee6SSepherosa Ziehau 		/* txd is freed, but m is not. */
1822dc13fee6SSepherosa Ziehau 		m_freem(m);
1823dc13fee6SSepherosa Ziehau 
1824dc13fee6SSepherosa Ziehau 		txr->hn_flush_failed++;
1825dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts);
1826dc13fee6SSepherosa Ziehau 	}
1827dc13fee6SSepherosa Ziehau 
1828dc13fee6SSepherosa Ziehau 	/* Reset all aggregation states. */
1829dc13fee6SSepherosa Ziehau 	txr->hn_agg_txd = NULL;
1830dc13fee6SSepherosa Ziehau 	txr->hn_agg_szleft = 0;
1831dc13fee6SSepherosa Ziehau 	txr->hn_agg_pktleft = 0;
1832dc13fee6SSepherosa Ziehau 	txr->hn_agg_prevpkt = NULL;
1833dc13fee6SSepherosa Ziehau 
1834dc13fee6SSepherosa Ziehau 	return (error);
1835dc13fee6SSepherosa Ziehau }
1836dc13fee6SSepherosa Ziehau 
1837dc13fee6SSepherosa Ziehau static void *
1838dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
1839dc13fee6SSepherosa Ziehau     int pktsize)
1840dc13fee6SSepherosa Ziehau {
1841dc13fee6SSepherosa Ziehau 	void *chim;
1842dc13fee6SSepherosa Ziehau 
1843dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL) {
1844dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) {
1845dc13fee6SSepherosa Ziehau 			struct hn_txdesc *agg_txd = txr->hn_agg_txd;
1846dc13fee6SSepherosa Ziehau 			struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt;
1847dc13fee6SSepherosa Ziehau 			int olen;
1848dc13fee6SSepherosa Ziehau 
1849dc13fee6SSepherosa Ziehau 			/*
1850dc13fee6SSepherosa Ziehau 			 * Update the previous RNDIS packet's total length,
1851dc13fee6SSepherosa Ziehau 			 * it can be increased due to the mandatory alignment
1852dc13fee6SSepherosa Ziehau 			 * padding for this RNDIS packet.  And update the
1853dc13fee6SSepherosa Ziehau 			 * aggregating txdesc's chimney sending buffer size
1854dc13fee6SSepherosa Ziehau 			 * accordingly.
1855dc13fee6SSepherosa Ziehau 			 *
1856dc13fee6SSepherosa Ziehau 			 * XXX
1857dc13fee6SSepherosa Ziehau 			 * Zero-out the padding, as required by the RNDIS spec.
1858dc13fee6SSepherosa Ziehau 			 */
1859dc13fee6SSepherosa Ziehau 			olen = pkt->rm_len;
1860dc13fee6SSepherosa Ziehau 			pkt->rm_len = roundup2(olen, txr->hn_agg_align);
1861dc13fee6SSepherosa Ziehau 			agg_txd->chim_size += pkt->rm_len - olen;
1862dc13fee6SSepherosa Ziehau 
1863dc13fee6SSepherosa Ziehau 			/* Link this txdesc to the parent. */
1864dc13fee6SSepherosa Ziehau 			hn_txdesc_agg(agg_txd, txd);
1865dc13fee6SSepherosa Ziehau 
1866dc13fee6SSepherosa Ziehau 			chim = (uint8_t *)pkt + pkt->rm_len;
1867dc13fee6SSepherosa Ziehau 			/* Save the current packet for later fixup. */
1868dc13fee6SSepherosa Ziehau 			txr->hn_agg_prevpkt = chim;
1869dc13fee6SSepherosa Ziehau 
1870dc13fee6SSepherosa Ziehau 			txr->hn_agg_pktleft--;
1871dc13fee6SSepherosa Ziehau 			txr->hn_agg_szleft -= pktsize;
1872dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_szleft <=
1873dc13fee6SSepherosa Ziehau 			    HN_PKTSIZE_MIN(txr->hn_agg_align)) {
1874dc13fee6SSepherosa Ziehau 				/*
1875dc13fee6SSepherosa Ziehau 				 * Probably can't aggregate more packets,
1876dc13fee6SSepherosa Ziehau 				 * flush this aggregating txdesc proactively.
1877dc13fee6SSepherosa Ziehau 				 */
1878dc13fee6SSepherosa Ziehau 				txr->hn_agg_pktleft = 0;
1879dc13fee6SSepherosa Ziehau 			}
1880dc13fee6SSepherosa Ziehau 			/* Done! */
1881dc13fee6SSepherosa Ziehau 			return (chim);
1882dc13fee6SSepherosa Ziehau 		}
1883dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
1884dc13fee6SSepherosa Ziehau 	}
1885dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
1886dc13fee6SSepherosa Ziehau 
1887dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney_tried++;
1888dc13fee6SSepherosa Ziehau 	txd->chim_index = hn_chim_alloc(txr->hn_sc);
1889dc13fee6SSepherosa Ziehau 	if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID)
1890dc13fee6SSepherosa Ziehau 		return (NULL);
1891dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney++;
1892dc13fee6SSepherosa Ziehau 
1893dc13fee6SSepherosa Ziehau 	chim = txr->hn_sc->hn_chim +
1894dc13fee6SSepherosa Ziehau 	    (txd->chim_index * txr->hn_sc->hn_chim_szmax);
1895dc13fee6SSepherosa Ziehau 
1896dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_pktmax > 1 &&
1897dc13fee6SSepherosa Ziehau 	    txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) {
1898dc13fee6SSepherosa Ziehau 		txr->hn_agg_txd = txd;
1899dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1;
1900dc13fee6SSepherosa Ziehau 		txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize;
1901dc13fee6SSepherosa Ziehau 		txr->hn_agg_prevpkt = chim;
1902dc13fee6SSepherosa Ziehau 	}
1903dc13fee6SSepherosa Ziehau 	return (chim);
1904dc13fee6SSepherosa Ziehau }
1905dc13fee6SSepherosa Ziehau 
190615516c77SSepherosa Ziehau /*
190715516c77SSepherosa Ziehau  * NOTE:
190815516c77SSepherosa Ziehau  * If this function fails, then both txd and m_head0 will be freed.
190915516c77SSepherosa Ziehau  */
191015516c77SSepherosa Ziehau static int
1911dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
1912dc13fee6SSepherosa Ziehau     struct mbuf **m_head0)
191315516c77SSepherosa Ziehau {
191415516c77SSepherosa Ziehau 	bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX];
191515516c77SSepherosa Ziehau 	int error, nsegs, i;
191615516c77SSepherosa Ziehau 	struct mbuf *m_head = *m_head0;
191715516c77SSepherosa Ziehau 	struct rndis_packet_msg *pkt;
191815516c77SSepherosa Ziehau 	uint32_t *pi_data;
19198966e5d5SSepherosa Ziehau 	void *chim = NULL;
1920dc13fee6SSepherosa Ziehau 	int pkt_hlen, pkt_size;
192115516c77SSepherosa Ziehau 
192215516c77SSepherosa Ziehau 	pkt = txd->rndis_pkt;
1923dc13fee6SSepherosa Ziehau 	pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align);
1924dc13fee6SSepherosa Ziehau 	if (pkt_size < txr->hn_chim_size) {
1925dc13fee6SSepherosa Ziehau 		chim = hn_try_txagg(ifp, txr, txd, pkt_size);
1926dc13fee6SSepherosa Ziehau 		if (chim != NULL)
19278966e5d5SSepherosa Ziehau 			pkt = chim;
1928dc13fee6SSepherosa Ziehau 	} else {
1929dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL)
1930dc13fee6SSepherosa Ziehau 			hn_flush_txagg(ifp, txr);
19318966e5d5SSepherosa Ziehau 	}
19328966e5d5SSepherosa Ziehau 
193315516c77SSepherosa Ziehau 	pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
193415516c77SSepherosa Ziehau 	pkt->rm_len = sizeof(*pkt) + m_head->m_pkthdr.len;
193515516c77SSepherosa Ziehau 	pkt->rm_dataoffset = sizeof(*pkt);
193615516c77SSepherosa Ziehau 	pkt->rm_datalen = m_head->m_pkthdr.len;
1937dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataoffset = 0;
1938dc13fee6SSepherosa Ziehau 	pkt->rm_oobdatalen = 0;
1939dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataelements = 0;
194015516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = sizeof(*pkt);
194115516c77SSepherosa Ziehau 	pkt->rm_pktinfolen = 0;
1942dc13fee6SSepherosa Ziehau 	pkt->rm_vchandle = 0;
1943dc13fee6SSepherosa Ziehau 	pkt->rm_reserved = 0;
194415516c77SSepherosa Ziehau 
194515516c77SSepherosa Ziehau 	if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) {
194615516c77SSepherosa Ziehau 		/*
194715516c77SSepherosa Ziehau 		 * Set the hash value for this packet, so that the host could
194815516c77SSepherosa Ziehau 		 * dispatch the TX done event for this packet back to this TX
194915516c77SSepherosa Ziehau 		 * ring's channel.
195015516c77SSepherosa Ziehau 		 */
195115516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
195215516c77SSepherosa Ziehau 		    HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL);
195315516c77SSepherosa Ziehau 		*pi_data = txr->hn_tx_idx;
195415516c77SSepherosa Ziehau 	}
195515516c77SSepherosa Ziehau 
195615516c77SSepherosa Ziehau 	if (m_head->m_flags & M_VLANTAG) {
195715516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
195815516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
195915516c77SSepherosa Ziehau 		*pi_data = NDIS_VLAN_INFO_MAKE(
196015516c77SSepherosa Ziehau 		    EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag),
196115516c77SSepherosa Ziehau 		    EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag),
196215516c77SSepherosa Ziehau 		    EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag));
196315516c77SSepherosa Ziehau 	}
196415516c77SSepherosa Ziehau 
196515516c77SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
196615516c77SSepherosa Ziehau #if defined(INET6) || defined(INET)
196715516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
196815516c77SSepherosa Ziehau 		    NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO);
196915516c77SSepherosa Ziehau #ifdef INET
197015516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
197115516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV4(0,
197215516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
197315516c77SSepherosa Ziehau 		}
197415516c77SSepherosa Ziehau #endif
197515516c77SSepherosa Ziehau #if defined(INET6) && defined(INET)
197615516c77SSepherosa Ziehau 		else
197715516c77SSepherosa Ziehau #endif
197815516c77SSepherosa Ziehau #ifdef INET6
197915516c77SSepherosa Ziehau 		{
198015516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV6(0,
198115516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
198215516c77SSepherosa Ziehau 		}
198315516c77SSepherosa Ziehau #endif
198415516c77SSepherosa Ziehau #endif	/* INET6 || INET */
198515516c77SSepherosa Ziehau 	} else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) {
198615516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
198715516c77SSepherosa Ziehau 		    NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
198815516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
198915516c77SSepherosa Ziehau 		    (CSUM_IP6_TCP | CSUM_IP6_UDP)) {
199015516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV6;
199115516c77SSepherosa Ziehau 		} else {
199215516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV4;
199315516c77SSepherosa Ziehau 			if (m_head->m_pkthdr.csum_flags & CSUM_IP)
199415516c77SSepherosa Ziehau 				*pi_data |= NDIS_TXCSUM_INFO_IPCS;
199515516c77SSepherosa Ziehau 		}
199615516c77SSepherosa Ziehau 
199715516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP))
199815516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_TCPCS;
199915516c77SSepherosa Ziehau 		else if (m_head->m_pkthdr.csum_flags &
200015516c77SSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP6_UDP))
200115516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_UDPCS;
200215516c77SSepherosa Ziehau 	}
200315516c77SSepherosa Ziehau 
2004dc13fee6SSepherosa Ziehau 	pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
200515516c77SSepherosa Ziehau 	/* Convert RNDIS packet message offsets */
200615516c77SSepherosa Ziehau 	pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt->rm_dataoffset);
200715516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset);
200815516c77SSepherosa Ziehau 
200915516c77SSepherosa Ziehau 	/*
20108966e5d5SSepherosa Ziehau 	 * Fast path: Chimney sending.
201115516c77SSepherosa Ziehau 	 */
20128966e5d5SSepherosa Ziehau 	if (chim != NULL) {
2013dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tgt_txd = txd;
2014dc13fee6SSepherosa Ziehau 
2015dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL) {
2016dc13fee6SSepherosa Ziehau 			tgt_txd = txr->hn_agg_txd;
2017dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
2018dc13fee6SSepherosa Ziehau 			*m_head0 = NULL;
2019dc13fee6SSepherosa Ziehau #endif
2020dc13fee6SSepherosa Ziehau 		}
2021dc13fee6SSepherosa Ziehau 
2022dc13fee6SSepherosa Ziehau 		KASSERT(pkt == chim,
2023dc13fee6SSepherosa Ziehau 		    ("RNDIS pkt not in chimney sending buffer"));
2024dc13fee6SSepherosa Ziehau 		KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID,
2025dc13fee6SSepherosa Ziehau 		    ("chimney sending buffer is not used"));
2026dc13fee6SSepherosa Ziehau 		tgt_txd->chim_size += pkt->rm_len;
202715516c77SSepherosa Ziehau 
20288966e5d5SSepherosa Ziehau 		m_copydata(m_head, 0, m_head->m_pkthdr.len,
2029dc13fee6SSepherosa Ziehau 		    ((uint8_t *)chim) + pkt_hlen);
203015516c77SSepherosa Ziehau 
203115516c77SSepherosa Ziehau 		txr->hn_gpa_cnt = 0;
203215516c77SSepherosa Ziehau 		txr->hn_sendpkt = hn_txpkt_chim;
203315516c77SSepherosa Ziehau 		goto done;
203415516c77SSepherosa Ziehau 	}
2035dc13fee6SSepherosa Ziehau 
2036dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc"));
20378966e5d5SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
20388966e5d5SSepherosa Ziehau 	    ("chimney buffer is used"));
20398966e5d5SSepherosa Ziehau 	KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc"));
204015516c77SSepherosa Ziehau 
204115516c77SSepherosa Ziehau 	error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs);
2042dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
204315516c77SSepherosa Ziehau 		int freed;
204415516c77SSepherosa Ziehau 
204515516c77SSepherosa Ziehau 		/*
204615516c77SSepherosa Ziehau 		 * This mbuf is not linked w/ the txd yet, so free it now.
204715516c77SSepherosa Ziehau 		 */
204815516c77SSepherosa Ziehau 		m_freem(m_head);
204915516c77SSepherosa Ziehau 		*m_head0 = NULL;
205015516c77SSepherosa Ziehau 
205115516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
205215516c77SSepherosa Ziehau 		KASSERT(freed != 0,
205315516c77SSepherosa Ziehau 		    ("fail to free txd upon txdma error"));
205415516c77SSepherosa Ziehau 
205515516c77SSepherosa Ziehau 		txr->hn_txdma_failed++;
2056dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
205715516c77SSepherosa Ziehau 		return error;
205815516c77SSepherosa Ziehau 	}
205915516c77SSepherosa Ziehau 	*m_head0 = m_head;
206015516c77SSepherosa Ziehau 
206115516c77SSepherosa Ziehau 	/* +1 RNDIS packet message */
206215516c77SSepherosa Ziehau 	txr->hn_gpa_cnt = nsegs + 1;
206315516c77SSepherosa Ziehau 
206415516c77SSepherosa Ziehau 	/* send packet with page buffer */
206515516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr);
206615516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK;
2067dc13fee6SSepherosa Ziehau 	txr->hn_gpa[0].gpa_len = pkt_hlen;
206815516c77SSepherosa Ziehau 
206915516c77SSepherosa Ziehau 	/*
207015516c77SSepherosa Ziehau 	 * Fill the page buffers with mbuf info after the page
207115516c77SSepherosa Ziehau 	 * buffer for RNDIS packet message.
207215516c77SSepherosa Ziehau 	 */
207315516c77SSepherosa Ziehau 	for (i = 0; i < nsegs; ++i) {
207415516c77SSepherosa Ziehau 		struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1];
207515516c77SSepherosa Ziehau 
207615516c77SSepherosa Ziehau 		gpa->gpa_page = atop(segs[i].ds_addr);
207715516c77SSepherosa Ziehau 		gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK;
207815516c77SSepherosa Ziehau 		gpa->gpa_len = segs[i].ds_len;
207915516c77SSepherosa Ziehau 	}
208015516c77SSepherosa Ziehau 
208115516c77SSepherosa Ziehau 	txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
208215516c77SSepherosa Ziehau 	txd->chim_size = 0;
208315516c77SSepherosa Ziehau 	txr->hn_sendpkt = hn_txpkt_sglist;
208415516c77SSepherosa Ziehau done:
208515516c77SSepherosa Ziehau 	txd->m = m_head;
208615516c77SSepherosa Ziehau 
208715516c77SSepherosa Ziehau 	/* Set the completion routine */
208815516c77SSepherosa Ziehau 	hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd);
208915516c77SSepherosa Ziehau 
2090dc13fee6SSepherosa Ziehau 	/* Update temporary stats for later use. */
2091dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts++;
2092dc13fee6SSepherosa Ziehau 	txr->hn_stat_size += m_head->m_pkthdr.len;
2093dc13fee6SSepherosa Ziehau 	if (m_head->m_flags & M_MCAST)
2094dc13fee6SSepherosa Ziehau 		txr->hn_stat_mcasts++;
2095dc13fee6SSepherosa Ziehau 
209615516c77SSepherosa Ziehau 	return 0;
209715516c77SSepherosa Ziehau }
209815516c77SSepherosa Ziehau 
209915516c77SSepherosa Ziehau /*
210015516c77SSepherosa Ziehau  * NOTE:
210115516c77SSepherosa Ziehau  * If this function fails, then txd will be freed, but the mbuf
210215516c77SSepherosa Ziehau  * associated w/ the txd will _not_ be freed.
210315516c77SSepherosa Ziehau  */
210415516c77SSepherosa Ziehau static int
210515516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd)
210615516c77SSepherosa Ziehau {
21078e7d3136SSepherosa Ziehau 	int error, send_failed = 0, has_bpf;
210815516c77SSepherosa Ziehau 
210915516c77SSepherosa Ziehau again:
21108e7d3136SSepherosa Ziehau 	has_bpf = bpf_peers_present(ifp->if_bpf);
21118e7d3136SSepherosa Ziehau 	if (has_bpf) {
211215516c77SSepherosa Ziehau 		/*
21138e7d3136SSepherosa Ziehau 		 * Make sure that this txd and any aggregated txds are not
21148e7d3136SSepherosa Ziehau 		 * freed before ETHER_BPF_MTAP.
211515516c77SSepherosa Ziehau 		 */
211615516c77SSepherosa Ziehau 		hn_txdesc_hold(txd);
21178e7d3136SSepherosa Ziehau 	}
211815516c77SSepherosa Ziehau 	error = txr->hn_sendpkt(txr, txd);
211915516c77SSepherosa Ziehau 	if (!error) {
21208e7d3136SSepherosa Ziehau 		if (has_bpf) {
2121dc13fee6SSepherosa Ziehau 			const struct hn_txdesc *tmp_txd;
2122dc13fee6SSepherosa Ziehau 
212315516c77SSepherosa Ziehau 			ETHER_BPF_MTAP(ifp, txd->m);
2124dc13fee6SSepherosa Ziehau 			STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link)
2125dc13fee6SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, tmp_txd->m);
2126dc13fee6SSepherosa Ziehau 		}
2127dc13fee6SSepherosa Ziehau 
2128dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts);
212923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
213023bf9e15SSepherosa Ziehau 		if (!hn_use_if_start)
213123bf9e15SSepherosa Ziehau #endif
213223bf9e15SSepherosa Ziehau 		{
213315516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OBYTES,
2134dc13fee6SSepherosa Ziehau 			    txr->hn_stat_size);
2135dc13fee6SSepherosa Ziehau 			if (txr->hn_stat_mcasts != 0) {
2136dc13fee6SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OMCASTS,
2137dc13fee6SSepherosa Ziehau 				    txr->hn_stat_mcasts);
213815516c77SSepherosa Ziehau 			}
2139dc13fee6SSepherosa Ziehau 		}
2140dc13fee6SSepherosa Ziehau 		txr->hn_pkts += txr->hn_stat_pkts;
2141dc13fee6SSepherosa Ziehau 		txr->hn_sends++;
214215516c77SSepherosa Ziehau 	}
21438e7d3136SSepherosa Ziehau 	if (has_bpf)
214415516c77SSepherosa Ziehau 		hn_txdesc_put(txr, txd);
214515516c77SSepherosa Ziehau 
214615516c77SSepherosa Ziehau 	if (__predict_false(error)) {
214715516c77SSepherosa Ziehau 		int freed;
214815516c77SSepherosa Ziehau 
214915516c77SSepherosa Ziehau 		/*
215015516c77SSepherosa Ziehau 		 * This should "really rarely" happen.
215115516c77SSepherosa Ziehau 		 *
215215516c77SSepherosa Ziehau 		 * XXX Too many RX to be acked or too many sideband
215315516c77SSepherosa Ziehau 		 * commands to run?  Ask netvsc_channel_rollup()
215415516c77SSepherosa Ziehau 		 * to kick start later.
215515516c77SSepherosa Ziehau 		 */
215615516c77SSepherosa Ziehau 		txr->hn_has_txeof = 1;
215715516c77SSepherosa Ziehau 		if (!send_failed) {
215815516c77SSepherosa Ziehau 			txr->hn_send_failed++;
215915516c77SSepherosa Ziehau 			send_failed = 1;
216015516c77SSepherosa Ziehau 			/*
216115516c77SSepherosa Ziehau 			 * Try sending again after set hn_has_txeof;
216215516c77SSepherosa Ziehau 			 * in case that we missed the last
216315516c77SSepherosa Ziehau 			 * netvsc_channel_rollup().
216415516c77SSepherosa Ziehau 			 */
216515516c77SSepherosa Ziehau 			goto again;
216615516c77SSepherosa Ziehau 		}
216715516c77SSepherosa Ziehau 		if_printf(ifp, "send failed\n");
216815516c77SSepherosa Ziehau 
216915516c77SSepherosa Ziehau 		/*
217015516c77SSepherosa Ziehau 		 * Caller will perform further processing on the
217115516c77SSepherosa Ziehau 		 * associated mbuf, so don't free it in hn_txdesc_put();
217215516c77SSepherosa Ziehau 		 * only unload it from the DMA map in hn_txdesc_put(),
217315516c77SSepherosa Ziehau 		 * if it was loaded.
217415516c77SSepherosa Ziehau 		 */
217515516c77SSepherosa Ziehau 		txd->m = NULL;
217615516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
217715516c77SSepherosa Ziehau 		KASSERT(freed != 0,
217815516c77SSepherosa Ziehau 		    ("fail to free txd upon send error"));
217915516c77SSepherosa Ziehau 
218015516c77SSepherosa Ziehau 		txr->hn_send_failed++;
218115516c77SSepherosa Ziehau 	}
2182dc13fee6SSepherosa Ziehau 
2183dc13fee6SSepherosa Ziehau 	/* Reset temporary stats, after this sending is done. */
2184dc13fee6SSepherosa Ziehau 	txr->hn_stat_size = 0;
2185dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts = 0;
2186dc13fee6SSepherosa Ziehau 	txr->hn_stat_mcasts = 0;
2187dc13fee6SSepherosa Ziehau 
2188dc13fee6SSepherosa Ziehau 	return (error);
218915516c77SSepherosa Ziehau }
219015516c77SSepherosa Ziehau 
219115516c77SSepherosa Ziehau /*
219215516c77SSepherosa Ziehau  * Append the specified data to the indicated mbuf chain,
219315516c77SSepherosa Ziehau  * Extend the mbuf chain if the new data does not fit in
219415516c77SSepherosa Ziehau  * existing space.
219515516c77SSepherosa Ziehau  *
219615516c77SSepherosa Ziehau  * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c.
219715516c77SSepherosa Ziehau  * There should be an equivalent in the kernel mbuf code,
219815516c77SSepherosa Ziehau  * but there does not appear to be one yet.
219915516c77SSepherosa Ziehau  *
220015516c77SSepherosa Ziehau  * Differs from m_append() in that additional mbufs are
220115516c77SSepherosa Ziehau  * allocated with cluster size MJUMPAGESIZE, and filled
220215516c77SSepherosa Ziehau  * accordingly.
220315516c77SSepherosa Ziehau  *
220415516c77SSepherosa Ziehau  * Return 1 if able to complete the job; otherwise 0.
220515516c77SSepherosa Ziehau  */
220615516c77SSepherosa Ziehau static int
220715516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp)
220815516c77SSepherosa Ziehau {
220915516c77SSepherosa Ziehau 	struct mbuf *m, *n;
221015516c77SSepherosa Ziehau 	int remainder, space;
221115516c77SSepherosa Ziehau 
221215516c77SSepherosa Ziehau 	for (m = m0; m->m_next != NULL; m = m->m_next)
221315516c77SSepherosa Ziehau 		;
221415516c77SSepherosa Ziehau 	remainder = len;
221515516c77SSepherosa Ziehau 	space = M_TRAILINGSPACE(m);
221615516c77SSepherosa Ziehau 	if (space > 0) {
221715516c77SSepherosa Ziehau 		/*
221815516c77SSepherosa Ziehau 		 * Copy into available space.
221915516c77SSepherosa Ziehau 		 */
222015516c77SSepherosa Ziehau 		if (space > remainder)
222115516c77SSepherosa Ziehau 			space = remainder;
222215516c77SSepherosa Ziehau 		bcopy(cp, mtod(m, caddr_t) + m->m_len, space);
222315516c77SSepherosa Ziehau 		m->m_len += space;
222415516c77SSepherosa Ziehau 		cp += space;
222515516c77SSepherosa Ziehau 		remainder -= space;
222615516c77SSepherosa Ziehau 	}
222715516c77SSepherosa Ziehau 	while (remainder > 0) {
222815516c77SSepherosa Ziehau 		/*
222915516c77SSepherosa Ziehau 		 * Allocate a new mbuf; could check space
223015516c77SSepherosa Ziehau 		 * and allocate a cluster instead.
223115516c77SSepherosa Ziehau 		 */
223215516c77SSepherosa Ziehau 		n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE);
223315516c77SSepherosa Ziehau 		if (n == NULL)
223415516c77SSepherosa Ziehau 			break;
223515516c77SSepherosa Ziehau 		n->m_len = min(MJUMPAGESIZE, remainder);
223615516c77SSepherosa Ziehau 		bcopy(cp, mtod(n, caddr_t), n->m_len);
223715516c77SSepherosa Ziehau 		cp += n->m_len;
223815516c77SSepherosa Ziehau 		remainder -= n->m_len;
223915516c77SSepherosa Ziehau 		m->m_next = n;
224015516c77SSepherosa Ziehau 		m = n;
224115516c77SSepherosa Ziehau 	}
224215516c77SSepherosa Ziehau 	if (m0->m_flags & M_PKTHDR)
224315516c77SSepherosa Ziehau 		m0->m_pkthdr.len += len - remainder;
224415516c77SSepherosa Ziehau 
224515516c77SSepherosa Ziehau 	return (remainder == 0);
224615516c77SSepherosa Ziehau }
224715516c77SSepherosa Ziehau 
224815516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
224915516c77SSepherosa Ziehau static __inline int
225015516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m)
225115516c77SSepherosa Ziehau {
225215516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
225315516c77SSepherosa Ziehau 	if (hn_lro_mbufq_depth) {
225415516c77SSepherosa Ziehau 		tcp_lro_queue_mbuf(lc, m);
225515516c77SSepherosa Ziehau 		return 0;
225615516c77SSepherosa Ziehau 	}
225715516c77SSepherosa Ziehau #endif
225815516c77SSepherosa Ziehau 	return tcp_lro_rx(lc, m, 0);
225915516c77SSepherosa Ziehau }
226015516c77SSepherosa Ziehau #endif
226115516c77SSepherosa Ziehau 
226215516c77SSepherosa Ziehau static int
226315516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
226415516c77SSepherosa Ziehau     const struct hn_rxinfo *info)
226515516c77SSepherosa Ziehau {
22665bdfd3fdSDexuan Cui 	struct ifnet *ifp;
226715516c77SSepherosa Ziehau 	struct mbuf *m_new;
226815516c77SSepherosa Ziehau 	int size, do_lro = 0, do_csum = 1;
226915516c77SSepherosa Ziehau 	int hash_type;
227015516c77SSepherosa Ziehau 
22715bdfd3fdSDexuan Cui 	/* If the VF is active, inject the packet through the VF */
22725bdfd3fdSDexuan Cui 	ifp = rxr->hn_vf ? rxr->hn_vf : rxr->hn_ifp;
22735bdfd3fdSDexuan Cui 
2274c927d681SDexuan Cui 	if (dlen <= MHLEN) {
227515516c77SSepherosa Ziehau 		m_new = m_gethdr(M_NOWAIT, MT_DATA);
227615516c77SSepherosa Ziehau 		if (m_new == NULL) {
227715516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
227815516c77SSepherosa Ziehau 			return (0);
227915516c77SSepherosa Ziehau 		}
228015516c77SSepherosa Ziehau 		memcpy(mtod(m_new, void *), data, dlen);
228115516c77SSepherosa Ziehau 		m_new->m_pkthdr.len = m_new->m_len = dlen;
228215516c77SSepherosa Ziehau 		rxr->hn_small_pkts++;
228315516c77SSepherosa Ziehau 	} else {
228415516c77SSepherosa Ziehau 		/*
228515516c77SSepherosa Ziehau 		 * Get an mbuf with a cluster.  For packets 2K or less,
228615516c77SSepherosa Ziehau 		 * get a standard 2K cluster.  For anything larger, get a
228715516c77SSepherosa Ziehau 		 * 4K cluster.  Any buffers larger than 4K can cause problems
228815516c77SSepherosa Ziehau 		 * if looped around to the Hyper-V TX channel, so avoid them.
228915516c77SSepherosa Ziehau 		 */
229015516c77SSepherosa Ziehau 		size = MCLBYTES;
229115516c77SSepherosa Ziehau 		if (dlen > MCLBYTES) {
229215516c77SSepherosa Ziehau 			/* 4096 */
229315516c77SSepherosa Ziehau 			size = MJUMPAGESIZE;
229415516c77SSepherosa Ziehau 		}
229515516c77SSepherosa Ziehau 
229615516c77SSepherosa Ziehau 		m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size);
229715516c77SSepherosa Ziehau 		if (m_new == NULL) {
229815516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
229915516c77SSepherosa Ziehau 			return (0);
230015516c77SSepherosa Ziehau 		}
230115516c77SSepherosa Ziehau 
230215516c77SSepherosa Ziehau 		hv_m_append(m_new, dlen, data);
230315516c77SSepherosa Ziehau 	}
230415516c77SSepherosa Ziehau 	m_new->m_pkthdr.rcvif = ifp;
230515516c77SSepherosa Ziehau 
230615516c77SSepherosa Ziehau 	if (__predict_false((ifp->if_capenable & IFCAP_RXCSUM) == 0))
230715516c77SSepherosa Ziehau 		do_csum = 0;
230815516c77SSepherosa Ziehau 
230915516c77SSepherosa Ziehau 	/* receive side checksum offload */
231015516c77SSepherosa Ziehau 	if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) {
231115516c77SSepherosa Ziehau 		/* IP csum offload */
231215516c77SSepherosa Ziehau 		if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) {
231315516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
231415516c77SSepherosa Ziehau 			    (CSUM_IP_CHECKED | CSUM_IP_VALID);
231515516c77SSepherosa Ziehau 			rxr->hn_csum_ip++;
231615516c77SSepherosa Ziehau 		}
231715516c77SSepherosa Ziehau 
231815516c77SSepherosa Ziehau 		/* TCP/UDP csum offload */
231915516c77SSepherosa Ziehau 		if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK |
232015516c77SSepherosa Ziehau 		     NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) {
232115516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
232215516c77SSepherosa Ziehau 			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
232315516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_data = 0xffff;
232415516c77SSepherosa Ziehau 			if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK)
232515516c77SSepherosa Ziehau 				rxr->hn_csum_tcp++;
232615516c77SSepherosa Ziehau 			else
232715516c77SSepherosa Ziehau 				rxr->hn_csum_udp++;
232815516c77SSepherosa Ziehau 		}
232915516c77SSepherosa Ziehau 
233015516c77SSepherosa Ziehau 		/*
233115516c77SSepherosa Ziehau 		 * XXX
233215516c77SSepherosa Ziehau 		 * As of this write (Oct 28th, 2016), host side will turn
233315516c77SSepherosa Ziehau 		 * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so
233415516c77SSepherosa Ziehau 		 * the do_lro setting here is actually _not_ accurate.  We
233515516c77SSepherosa Ziehau 		 * depend on the RSS hash type check to reset do_lro.
233615516c77SSepherosa Ziehau 		 */
233715516c77SSepherosa Ziehau 		if ((info->csum_info &
233815516c77SSepherosa Ziehau 		     (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) ==
233915516c77SSepherosa Ziehau 		    (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK))
234015516c77SSepherosa Ziehau 			do_lro = 1;
234115516c77SSepherosa Ziehau 	} else {
234215516c77SSepherosa Ziehau 		const struct ether_header *eh;
234315516c77SSepherosa Ziehau 		uint16_t etype;
234415516c77SSepherosa Ziehau 		int hoff;
234515516c77SSepherosa Ziehau 
234615516c77SSepherosa Ziehau 		hoff = sizeof(*eh);
234715516c77SSepherosa Ziehau 		if (m_new->m_len < hoff)
234815516c77SSepherosa Ziehau 			goto skip;
234915516c77SSepherosa Ziehau 		eh = mtod(m_new, struct ether_header *);
235015516c77SSepherosa Ziehau 		etype = ntohs(eh->ether_type);
235115516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_VLAN) {
235215516c77SSepherosa Ziehau 			const struct ether_vlan_header *evl;
235315516c77SSepherosa Ziehau 
235415516c77SSepherosa Ziehau 			hoff = sizeof(*evl);
235515516c77SSepherosa Ziehau 			if (m_new->m_len < hoff)
235615516c77SSepherosa Ziehau 				goto skip;
235715516c77SSepherosa Ziehau 			evl = mtod(m_new, struct ether_vlan_header *);
235815516c77SSepherosa Ziehau 			etype = ntohs(evl->evl_proto);
235915516c77SSepherosa Ziehau 		}
236015516c77SSepherosa Ziehau 
236115516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_IP) {
236215516c77SSepherosa Ziehau 			int pr;
236315516c77SSepherosa Ziehau 
236415516c77SSepherosa Ziehau 			pr = hn_check_iplen(m_new, hoff);
236515516c77SSepherosa Ziehau 			if (pr == IPPROTO_TCP) {
236615516c77SSepherosa Ziehau 				if (do_csum &&
236715516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
236815516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_TCP)) {
236915516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
237015516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
237115516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
237215516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
237315516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
237415516c77SSepherosa Ziehau 				}
237515516c77SSepherosa Ziehau 				do_lro = 1;
237615516c77SSepherosa Ziehau 			} else if (pr == IPPROTO_UDP) {
237715516c77SSepherosa Ziehau 				if (do_csum &&
237815516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
237915516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_UDP)) {
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 			} else if (pr != IPPROTO_DONE && do_csum &&
238715516c77SSepherosa Ziehau 			    (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) {
238815516c77SSepherosa Ziehau 				rxr->hn_csum_trusted++;
238915516c77SSepherosa Ziehau 				m_new->m_pkthdr.csum_flags |=
239015516c77SSepherosa Ziehau 				    (CSUM_IP_CHECKED | CSUM_IP_VALID);
239115516c77SSepherosa Ziehau 			}
239215516c77SSepherosa Ziehau 		}
239315516c77SSepherosa Ziehau 	}
239415516c77SSepherosa Ziehau skip:
239515516c77SSepherosa Ziehau 	if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) {
239615516c77SSepherosa Ziehau 		m_new->m_pkthdr.ether_vtag = EVL_MAKETAG(
239715516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_ID(info->vlan_info),
239815516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_PRI(info->vlan_info),
239915516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_CFI(info->vlan_info));
240015516c77SSepherosa Ziehau 		m_new->m_flags |= M_VLANTAG;
240115516c77SSepherosa Ziehau 	}
240215516c77SSepherosa Ziehau 
240315516c77SSepherosa Ziehau 	if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) {
240415516c77SSepherosa Ziehau 		rxr->hn_rss_pkts++;
240515516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = info->hash_value;
240615516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE_HASH;
240715516c77SSepherosa Ziehau 		if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) ==
240815516c77SSepherosa Ziehau 		    NDIS_HASH_FUNCTION_TOEPLITZ) {
240915516c77SSepherosa Ziehau 			uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK);
241015516c77SSepherosa Ziehau 
241115516c77SSepherosa Ziehau 			/*
241215516c77SSepherosa Ziehau 			 * NOTE:
241315516c77SSepherosa Ziehau 			 * do_lro is resetted, if the hash types are not TCP
241415516c77SSepherosa Ziehau 			 * related.  See the comment in the above csum_flags
241515516c77SSepherosa Ziehau 			 * setup section.
241615516c77SSepherosa Ziehau 			 */
241715516c77SSepherosa Ziehau 			switch (type) {
241815516c77SSepherosa Ziehau 			case NDIS_HASH_IPV4:
241915516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV4;
242015516c77SSepherosa Ziehau 				do_lro = 0;
242115516c77SSepherosa Ziehau 				break;
242215516c77SSepherosa Ziehau 
242315516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV4:
242415516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV4;
242515516c77SSepherosa Ziehau 				break;
242615516c77SSepherosa Ziehau 
242715516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6:
242815516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6;
242915516c77SSepherosa Ziehau 				do_lro = 0;
243015516c77SSepherosa Ziehau 				break;
243115516c77SSepherosa Ziehau 
243215516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6_EX:
243315516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6_EX;
243415516c77SSepherosa Ziehau 				do_lro = 0;
243515516c77SSepherosa Ziehau 				break;
243615516c77SSepherosa Ziehau 
243715516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6:
243815516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6;
243915516c77SSepherosa Ziehau 				break;
244015516c77SSepherosa Ziehau 
244115516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6_EX:
244215516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX;
244315516c77SSepherosa Ziehau 				break;
244415516c77SSepherosa Ziehau 			}
244515516c77SSepherosa Ziehau 		}
244615516c77SSepherosa Ziehau 	} else {
244715516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
244815516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE;
244915516c77SSepherosa Ziehau 	}
245015516c77SSepherosa Ziehau 	M_HASHTYPE_SET(m_new, hash_type);
245115516c77SSepherosa Ziehau 
245215516c77SSepherosa Ziehau 	/*
245315516c77SSepherosa Ziehau 	 * Note:  Moved RX completion back to hv_nv_on_receive() so all
245415516c77SSepherosa Ziehau 	 * messages (not just data messages) will trigger a response.
245515516c77SSepherosa Ziehau 	 */
245615516c77SSepherosa Ziehau 
245715516c77SSepherosa Ziehau 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
245815516c77SSepherosa Ziehau 	rxr->hn_pkts++;
245915516c77SSepherosa Ziehau 
246015516c77SSepherosa Ziehau 	if ((ifp->if_capenable & IFCAP_LRO) && do_lro) {
246115516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
246215516c77SSepherosa Ziehau 		struct lro_ctrl *lro = &rxr->hn_lro;
246315516c77SSepherosa Ziehau 
246415516c77SSepherosa Ziehau 		if (lro->lro_cnt) {
246515516c77SSepherosa Ziehau 			rxr->hn_lro_tried++;
246615516c77SSepherosa Ziehau 			if (hn_lro_rx(lro, m_new) == 0) {
246715516c77SSepherosa Ziehau 				/* DONE! */
246815516c77SSepherosa Ziehau 				return 0;
246915516c77SSepherosa Ziehau 			}
247015516c77SSepherosa Ziehau 		}
247115516c77SSepherosa Ziehau #endif
247215516c77SSepherosa Ziehau 	}
247315516c77SSepherosa Ziehau 
247415516c77SSepherosa Ziehau 	/* We're not holding the lock here, so don't release it */
247515516c77SSepherosa Ziehau 	(*ifp->if_input)(ifp, m_new);
247615516c77SSepherosa Ziehau 
247715516c77SSepherosa Ziehau 	return (0);
247815516c77SSepherosa Ziehau }
247915516c77SSepherosa Ziehau 
248015516c77SSepherosa Ziehau static int
248115516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
248215516c77SSepherosa Ziehau {
248315516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
248415516c77SSepherosa Ziehau 	struct ifreq *ifr = (struct ifreq *)data;
248515516c77SSepherosa Ziehau 	int mask, error = 0;
248615516c77SSepherosa Ziehau 
248715516c77SSepherosa Ziehau 	switch (cmd) {
248815516c77SSepherosa Ziehau 	case SIOCSIFMTU:
248915516c77SSepherosa Ziehau 		if (ifr->ifr_mtu > HN_MTU_MAX) {
249015516c77SSepherosa Ziehau 			error = EINVAL;
249115516c77SSepherosa Ziehau 			break;
249215516c77SSepherosa Ziehau 		}
249315516c77SSepherosa Ziehau 
249415516c77SSepherosa Ziehau 		HN_LOCK(sc);
249515516c77SSepherosa Ziehau 
249615516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
249715516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
249815516c77SSepherosa Ziehau 			break;
249915516c77SSepherosa Ziehau 		}
250015516c77SSepherosa Ziehau 
250115516c77SSepherosa Ziehau 		if ((sc->hn_caps & HN_CAP_MTU) == 0) {
250215516c77SSepherosa Ziehau 			/* Can't change MTU */
250315516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
250415516c77SSepherosa Ziehau 			error = EOPNOTSUPP;
250515516c77SSepherosa Ziehau 			break;
250615516c77SSepherosa Ziehau 		}
250715516c77SSepherosa Ziehau 
250815516c77SSepherosa Ziehau 		if (ifp->if_mtu == ifr->ifr_mtu) {
250915516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
251015516c77SSepherosa Ziehau 			break;
251115516c77SSepherosa Ziehau 		}
251215516c77SSepherosa Ziehau 
251315516c77SSepherosa Ziehau 		/*
251415516c77SSepherosa Ziehau 		 * Suspend this interface before the synthetic parts
251515516c77SSepherosa Ziehau 		 * are ripped.
251615516c77SSepherosa Ziehau 		 */
251715516c77SSepherosa Ziehau 		hn_suspend(sc);
251815516c77SSepherosa Ziehau 
251915516c77SSepherosa Ziehau 		/*
252015516c77SSepherosa Ziehau 		 * Detach the synthetics parts, i.e. NVS and RNDIS.
252115516c77SSepherosa Ziehau 		 */
252215516c77SSepherosa Ziehau 		hn_synth_detach(sc);
252315516c77SSepherosa Ziehau 
252415516c77SSepherosa Ziehau 		/*
252515516c77SSepherosa Ziehau 		 * Reattach the synthetic parts, i.e. NVS and RNDIS,
252615516c77SSepherosa Ziehau 		 * with the new MTU setting.
252715516c77SSepherosa Ziehau 		 */
252815516c77SSepherosa Ziehau 		error = hn_synth_attach(sc, ifr->ifr_mtu);
252915516c77SSepherosa Ziehau 		if (error) {
253015516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
253115516c77SSepherosa Ziehau 			break;
253215516c77SSepherosa Ziehau 		}
253315516c77SSepherosa Ziehau 
253415516c77SSepherosa Ziehau 		/*
253515516c77SSepherosa Ziehau 		 * Commit the requested MTU, after the synthetic parts
253615516c77SSepherosa Ziehau 		 * have been successfully attached.
253715516c77SSepherosa Ziehau 		 */
253815516c77SSepherosa Ziehau 		ifp->if_mtu = ifr->ifr_mtu;
253915516c77SSepherosa Ziehau 
254015516c77SSepherosa Ziehau 		/*
254115516c77SSepherosa Ziehau 		 * Make sure that various parameters based on MTU are
254215516c77SSepherosa Ziehau 		 * still valid, after the MTU change.
254315516c77SSepherosa Ziehau 		 */
254415516c77SSepherosa Ziehau 		if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax)
254515516c77SSepherosa Ziehau 			hn_set_chim_size(sc, sc->hn_chim_szmax);
254615516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu);
254715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
254815516c77SSepherosa Ziehau 		if (sc->hn_rx_ring[0].hn_lro.lro_length_lim <
254915516c77SSepherosa Ziehau 		    HN_LRO_LENLIM_MIN(ifp))
255015516c77SSepherosa Ziehau 			hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
255115516c77SSepherosa Ziehau #endif
255215516c77SSepherosa Ziehau 
255315516c77SSepherosa Ziehau 		/*
255415516c77SSepherosa Ziehau 		 * All done!  Resume the interface now.
255515516c77SSepherosa Ziehau 		 */
255615516c77SSepherosa Ziehau 		hn_resume(sc);
255715516c77SSepherosa Ziehau 
255815516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
255915516c77SSepherosa Ziehau 		break;
256015516c77SSepherosa Ziehau 
256115516c77SSepherosa Ziehau 	case SIOCSIFFLAGS:
256215516c77SSepherosa Ziehau 		HN_LOCK(sc);
256315516c77SSepherosa Ziehau 
256415516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
256515516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
256615516c77SSepherosa Ziehau 			break;
256715516c77SSepherosa Ziehau 		}
256815516c77SSepherosa Ziehau 
256915516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_UP) {
2570fdc4f478SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2571fdc4f478SSepherosa Ziehau 				/*
2572fdc4f478SSepherosa Ziehau 				 * Caller meight hold mutex, e.g.
2573fdc4f478SSepherosa Ziehau 				 * bpf; use busy-wait for the RNDIS
2574fdc4f478SSepherosa Ziehau 				 * reply.
2575fdc4f478SSepherosa Ziehau 				 */
2576fdc4f478SSepherosa Ziehau 				HN_NO_SLEEPING(sc);
2577c08f7b2cSSepherosa Ziehau 				hn_rxfilter_config(sc);
2578fdc4f478SSepherosa Ziehau 				HN_SLEEPING_OK(sc);
2579fdc4f478SSepherosa Ziehau 			} else {
258015516c77SSepherosa Ziehau 				hn_init_locked(sc);
2581fdc4f478SSepherosa Ziehau 			}
258215516c77SSepherosa Ziehau 		} else {
258315516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
25845bdfd3fdSDexuan Cui 				hn_stop(sc, false);
258515516c77SSepherosa Ziehau 		}
258615516c77SSepherosa Ziehau 		sc->hn_if_flags = ifp->if_flags;
258715516c77SSepherosa Ziehau 
258815516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
258915516c77SSepherosa Ziehau 		break;
259015516c77SSepherosa Ziehau 
259115516c77SSepherosa Ziehau 	case SIOCSIFCAP:
259215516c77SSepherosa Ziehau 		HN_LOCK(sc);
259315516c77SSepherosa Ziehau 		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
259415516c77SSepherosa Ziehau 
259515516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM) {
259615516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM;
259715516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM)
259815516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc);
259915516c77SSepherosa Ziehau 			else
260015516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc);
260115516c77SSepherosa Ziehau 		}
260215516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM_IPV6) {
260315516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
260415516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
260515516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc);
260615516c77SSepherosa Ziehau 			else
260715516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc);
260815516c77SSepherosa Ziehau 		}
260915516c77SSepherosa Ziehau 
261015516c77SSepherosa Ziehau 		/* TODO: flip RNDIS offload parameters for RXCSUM. */
261115516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM)
261215516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM;
261315516c77SSepherosa Ziehau #ifdef foo
261415516c77SSepherosa Ziehau 		/* We can't diff IPv6 packets from IPv4 packets on RX path. */
261515516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM_IPV6)
261615516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
261715516c77SSepherosa Ziehau #endif
261815516c77SSepherosa Ziehau 
261915516c77SSepherosa Ziehau 		if (mask & IFCAP_LRO)
262015516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_LRO;
262115516c77SSepherosa Ziehau 
262215516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO4) {
262315516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO4;
262415516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO4)
262515516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP_TSO;
262615516c77SSepherosa Ziehau 			else
262715516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP_TSO;
262815516c77SSepherosa Ziehau 		}
262915516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO6) {
263015516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO6;
263115516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO6)
263215516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP6_TSO;
263315516c77SSepherosa Ziehau 			else
263415516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP6_TSO;
263515516c77SSepherosa Ziehau 		}
263615516c77SSepherosa Ziehau 
263715516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
263815516c77SSepherosa Ziehau 		break;
263915516c77SSepherosa Ziehau 
264015516c77SSepherosa Ziehau 	case SIOCADDMULTI:
264115516c77SSepherosa Ziehau 	case SIOCDELMULTI:
264215516c77SSepherosa Ziehau 		HN_LOCK(sc);
264315516c77SSepherosa Ziehau 
264415516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
264515516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
264615516c77SSepherosa Ziehau 			break;
264715516c77SSepherosa Ziehau 		}
2648fdc4f478SSepherosa Ziehau 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2649fdc4f478SSepherosa Ziehau 			/*
2650fdc4f478SSepherosa Ziehau 			 * Multicast uses mutex; use busy-wait for
2651fdc4f478SSepherosa Ziehau 			 * the RNDIS reply.
2652fdc4f478SSepherosa Ziehau 			 */
2653fdc4f478SSepherosa Ziehau 			HN_NO_SLEEPING(sc);
2654c08f7b2cSSepherosa Ziehau 			hn_rxfilter_config(sc);
2655fdc4f478SSepherosa Ziehau 			HN_SLEEPING_OK(sc);
2656fdc4f478SSepherosa Ziehau 		}
265715516c77SSepherosa Ziehau 
265815516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
265915516c77SSepherosa Ziehau 		break;
266015516c77SSepherosa Ziehau 
266115516c77SSepherosa Ziehau 	case SIOCSIFMEDIA:
266215516c77SSepherosa Ziehau 	case SIOCGIFMEDIA:
266315516c77SSepherosa Ziehau 		error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd);
266415516c77SSepherosa Ziehau 		break;
266515516c77SSepherosa Ziehau 
266615516c77SSepherosa Ziehau 	default:
266715516c77SSepherosa Ziehau 		error = ether_ioctl(ifp, cmd, data);
266815516c77SSepherosa Ziehau 		break;
266915516c77SSepherosa Ziehau 	}
267015516c77SSepherosa Ziehau 	return (error);
267115516c77SSepherosa Ziehau }
267215516c77SSepherosa Ziehau 
267315516c77SSepherosa Ziehau static void
26745bdfd3fdSDexuan Cui hn_stop(struct hn_softc *sc, bool detaching)
267515516c77SSepherosa Ziehau {
267615516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
267715516c77SSepherosa Ziehau 	int i;
267815516c77SSepherosa Ziehau 
267915516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
268015516c77SSepherosa Ziehau 
268115516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
268215516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
268315516c77SSepherosa Ziehau 
26846c1204dfSSepherosa Ziehau 	/* Disable polling. */
26856c1204dfSSepherosa Ziehau 	hn_polling(sc, 0);
26866c1204dfSSepherosa Ziehau 
268715516c77SSepherosa Ziehau 	/* Clear RUNNING bit _before_ hn_suspend_data() */
268815516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
268915516c77SSepherosa Ziehau 	hn_suspend_data(sc);
269015516c77SSepherosa Ziehau 
269115516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
269215516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
269315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
269415516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
26955bdfd3fdSDexuan Cui 
26965bdfd3fdSDexuan Cui 	/*
26975bdfd3fdSDexuan Cui 	 * If the VF is active, make sure the filter is not 0, even if
26985bdfd3fdSDexuan Cui 	 * the synthetic NIC is down.
26995bdfd3fdSDexuan Cui 	 */
27005bdfd3fdSDexuan Cui 	if (!detaching && (sc->hn_flags & HN_FLAG_VF))
27015bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
270215516c77SSepherosa Ziehau }
270315516c77SSepherosa Ziehau 
270415516c77SSepherosa Ziehau static void
270515516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc)
270615516c77SSepherosa Ziehau {
270715516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
270815516c77SSepherosa Ziehau 	int i;
270915516c77SSepherosa Ziehau 
271015516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
271115516c77SSepherosa Ziehau 
271215516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
271315516c77SSepherosa Ziehau 		return;
271415516c77SSepherosa Ziehau 
271515516c77SSepherosa Ziehau 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
271615516c77SSepherosa Ziehau 		return;
271715516c77SSepherosa Ziehau 
271815516c77SSepherosa Ziehau 	/* Configure RX filter */
2719c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
272015516c77SSepherosa Ziehau 
272115516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
272215516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
272315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
272415516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
272515516c77SSepherosa Ziehau 
272615516c77SSepherosa Ziehau 	/* Clear TX 'suspended' bit. */
272715516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_inuse);
272815516c77SSepherosa Ziehau 
272915516c77SSepherosa Ziehau 	/* Everything is ready; unleash! */
273015516c77SSepherosa Ziehau 	atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
27316c1204dfSSepherosa Ziehau 
27326c1204dfSSepherosa Ziehau 	/* Re-enable polling if requested. */
27336c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz > 0)
27346c1204dfSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
273515516c77SSepherosa Ziehau }
273615516c77SSepherosa Ziehau 
273715516c77SSepherosa Ziehau static void
273815516c77SSepherosa Ziehau hn_init(void *xsc)
273915516c77SSepherosa Ziehau {
274015516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
274115516c77SSepherosa Ziehau 
274215516c77SSepherosa Ziehau 	HN_LOCK(sc);
274315516c77SSepherosa Ziehau 	hn_init_locked(sc);
274415516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
274515516c77SSepherosa Ziehau }
274615516c77SSepherosa Ziehau 
274715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
274815516c77SSepherosa Ziehau 
274915516c77SSepherosa Ziehau static int
275015516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
275115516c77SSepherosa Ziehau {
275215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
275315516c77SSepherosa Ziehau 	unsigned int lenlim;
275415516c77SSepherosa Ziehau 	int error;
275515516c77SSepherosa Ziehau 
275615516c77SSepherosa Ziehau 	lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim;
275715516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &lenlim, 0, req);
275815516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
275915516c77SSepherosa Ziehau 		return error;
276015516c77SSepherosa Ziehau 
276115516c77SSepherosa Ziehau 	HN_LOCK(sc);
276215516c77SSepherosa Ziehau 	if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) ||
276315516c77SSepherosa Ziehau 	    lenlim > TCP_LRO_LENGTH_MAX) {
276415516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
276515516c77SSepherosa Ziehau 		return EINVAL;
276615516c77SSepherosa Ziehau 	}
276715516c77SSepherosa Ziehau 	hn_set_lro_lenlim(sc, lenlim);
276815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
276915516c77SSepherosa Ziehau 
277015516c77SSepherosa Ziehau 	return 0;
277115516c77SSepherosa Ziehau }
277215516c77SSepherosa Ziehau 
277315516c77SSepherosa Ziehau static int
277415516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS)
277515516c77SSepherosa Ziehau {
277615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
277715516c77SSepherosa Ziehau 	int ackcnt, error, i;
277815516c77SSepherosa Ziehau 
277915516c77SSepherosa Ziehau 	/*
278015516c77SSepherosa Ziehau 	 * lro_ackcnt_lim is append count limit,
278115516c77SSepherosa Ziehau 	 * +1 to turn it into aggregation limit.
278215516c77SSepherosa Ziehau 	 */
278315516c77SSepherosa Ziehau 	ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1;
278415516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &ackcnt, 0, req);
278515516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
278615516c77SSepherosa Ziehau 		return error;
278715516c77SSepherosa Ziehau 
278815516c77SSepherosa Ziehau 	if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1))
278915516c77SSepherosa Ziehau 		return EINVAL;
279015516c77SSepherosa Ziehau 
279115516c77SSepherosa Ziehau 	/*
279215516c77SSepherosa Ziehau 	 * Convert aggregation limit back to append
279315516c77SSepherosa Ziehau 	 * count limit.
279415516c77SSepherosa Ziehau 	 */
279515516c77SSepherosa Ziehau 	--ackcnt;
279615516c77SSepherosa Ziehau 	HN_LOCK(sc);
2797a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
279815516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt;
279915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
280015516c77SSepherosa Ziehau 	return 0;
280115516c77SSepherosa Ziehau }
280215516c77SSepherosa Ziehau 
280315516c77SSepherosa Ziehau #endif
280415516c77SSepherosa Ziehau 
280515516c77SSepherosa Ziehau static int
280615516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS)
280715516c77SSepherosa Ziehau {
280815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
280915516c77SSepherosa Ziehau 	int hcsum = arg2;
281015516c77SSepherosa Ziehau 	int on, error, i;
281115516c77SSepherosa Ziehau 
281215516c77SSepherosa Ziehau 	on = 0;
281315516c77SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum)
281415516c77SSepherosa Ziehau 		on = 1;
281515516c77SSepherosa Ziehau 
281615516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &on, 0, req);
281715516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
281815516c77SSepherosa Ziehau 		return error;
281915516c77SSepherosa Ziehau 
282015516c77SSepherosa Ziehau 	HN_LOCK(sc);
2821a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
282215516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
282315516c77SSepherosa Ziehau 
282415516c77SSepherosa Ziehau 		if (on)
282515516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= hcsum;
282615516c77SSepherosa Ziehau 		else
282715516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum &= ~hcsum;
282815516c77SSepherosa Ziehau 	}
282915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
283015516c77SSepherosa Ziehau 	return 0;
283115516c77SSepherosa Ziehau }
283215516c77SSepherosa Ziehau 
283315516c77SSepherosa Ziehau static int
283415516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS)
283515516c77SSepherosa Ziehau {
283615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
283715516c77SSepherosa Ziehau 	int chim_size, error;
283815516c77SSepherosa Ziehau 
283915516c77SSepherosa Ziehau 	chim_size = sc->hn_tx_ring[0].hn_chim_size;
284015516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &chim_size, 0, req);
284115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
284215516c77SSepherosa Ziehau 		return error;
284315516c77SSepherosa Ziehau 
284415516c77SSepherosa Ziehau 	if (chim_size > sc->hn_chim_szmax || chim_size <= 0)
284515516c77SSepherosa Ziehau 		return EINVAL;
284615516c77SSepherosa Ziehau 
284715516c77SSepherosa Ziehau 	HN_LOCK(sc);
284815516c77SSepherosa Ziehau 	hn_set_chim_size(sc, chim_size);
284915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
285015516c77SSepherosa Ziehau 	return 0;
285115516c77SSepherosa Ziehau }
285215516c77SSepherosa Ziehau 
285315516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
285415516c77SSepherosa Ziehau static int
285515516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS)
285615516c77SSepherosa Ziehau {
285715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
285815516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
285915516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
286015516c77SSepherosa Ziehau 	uint64_t stat;
286115516c77SSepherosa Ziehau 
286215516c77SSepherosa Ziehau 	stat = 0;
286315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
286415516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
286515516c77SSepherosa Ziehau 		stat += *((int *)((uint8_t *)rxr + ofs));
286615516c77SSepherosa Ziehau 	}
286715516c77SSepherosa Ziehau 
286815516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
286915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
287015516c77SSepherosa Ziehau 		return error;
287115516c77SSepherosa Ziehau 
287215516c77SSepherosa Ziehau 	/* Zero out this stat. */
287315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
287415516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
287515516c77SSepherosa Ziehau 		*((int *)((uint8_t *)rxr + ofs)) = 0;
287615516c77SSepherosa Ziehau 	}
287715516c77SSepherosa Ziehau 	return 0;
287815516c77SSepherosa Ziehau }
287915516c77SSepherosa Ziehau #else
288015516c77SSepherosa Ziehau static int
288115516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS)
288215516c77SSepherosa Ziehau {
288315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
288415516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
288515516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
288615516c77SSepherosa Ziehau 	uint64_t stat;
288715516c77SSepherosa Ziehau 
288815516c77SSepherosa Ziehau 	stat = 0;
2889a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
289015516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
289115516c77SSepherosa Ziehau 		stat += *((uint64_t *)((uint8_t *)rxr + ofs));
289215516c77SSepherosa Ziehau 	}
289315516c77SSepherosa Ziehau 
289415516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
289515516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
289615516c77SSepherosa Ziehau 		return error;
289715516c77SSepherosa Ziehau 
289815516c77SSepherosa Ziehau 	/* Zero out this stat. */
2899a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
290015516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
290115516c77SSepherosa Ziehau 		*((uint64_t *)((uint8_t *)rxr + ofs)) = 0;
290215516c77SSepherosa Ziehau 	}
290315516c77SSepherosa Ziehau 	return 0;
290415516c77SSepherosa Ziehau }
290515516c77SSepherosa Ziehau 
290615516c77SSepherosa Ziehau #endif
290715516c77SSepherosa Ziehau 
290815516c77SSepherosa Ziehau static int
290915516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
291015516c77SSepherosa Ziehau {
291115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
291215516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
291315516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
291415516c77SSepherosa Ziehau 	u_long stat;
291515516c77SSepherosa Ziehau 
291615516c77SSepherosa Ziehau 	stat = 0;
2917a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
291815516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
291915516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)rxr + ofs));
292015516c77SSepherosa Ziehau 	}
292115516c77SSepherosa Ziehau 
292215516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
292315516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
292415516c77SSepherosa Ziehau 		return error;
292515516c77SSepherosa Ziehau 
292615516c77SSepherosa Ziehau 	/* Zero out this stat. */
2927a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
292815516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
292915516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)rxr + ofs)) = 0;
293015516c77SSepherosa Ziehau 	}
293115516c77SSepherosa Ziehau 	return 0;
293215516c77SSepherosa Ziehau }
293315516c77SSepherosa Ziehau 
293415516c77SSepherosa Ziehau static int
293515516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
293615516c77SSepherosa Ziehau {
293715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
293815516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
293915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
294015516c77SSepherosa Ziehau 	u_long stat;
294115516c77SSepherosa Ziehau 
294215516c77SSepherosa Ziehau 	stat = 0;
2943a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
294415516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
294515516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)txr + ofs));
294615516c77SSepherosa Ziehau 	}
294715516c77SSepherosa Ziehau 
294815516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
294915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
295015516c77SSepherosa Ziehau 		return error;
295115516c77SSepherosa Ziehau 
295215516c77SSepherosa Ziehau 	/* Zero out this stat. */
2953a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
295415516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
295515516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)txr + ofs)) = 0;
295615516c77SSepherosa Ziehau 	}
295715516c77SSepherosa Ziehau 	return 0;
295815516c77SSepherosa Ziehau }
295915516c77SSepherosa Ziehau 
296015516c77SSepherosa Ziehau static int
296115516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS)
296215516c77SSepherosa Ziehau {
296315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
296415516c77SSepherosa Ziehau 	int ofs = arg2, i, error, conf;
296515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
296615516c77SSepherosa Ziehau 
296715516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[0];
296815516c77SSepherosa Ziehau 	conf = *((int *)((uint8_t *)txr + ofs));
296915516c77SSepherosa Ziehau 
297015516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &conf, 0, req);
297115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
297215516c77SSepherosa Ziehau 		return error;
297315516c77SSepherosa Ziehau 
297415516c77SSepherosa Ziehau 	HN_LOCK(sc);
2975a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
297615516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
297715516c77SSepherosa Ziehau 		*((int *)((uint8_t *)txr + ofs)) = conf;
297815516c77SSepherosa Ziehau 	}
297915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
298015516c77SSepherosa Ziehau 
298115516c77SSepherosa Ziehau 	return 0;
298215516c77SSepherosa Ziehau }
298315516c77SSepherosa Ziehau 
298415516c77SSepherosa Ziehau static int
2985dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS)
2986dc13fee6SSepherosa Ziehau {
2987dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2988dc13fee6SSepherosa Ziehau 	int error, size;
2989dc13fee6SSepherosa Ziehau 
2990dc13fee6SSepherosa Ziehau 	size = sc->hn_agg_size;
2991dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &size, 0, req);
2992dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
2993dc13fee6SSepherosa Ziehau 		return (error);
2994dc13fee6SSepherosa Ziehau 
2995dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
2996dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = size;
2997dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
2998dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
2999dc13fee6SSepherosa Ziehau 
3000dc13fee6SSepherosa Ziehau 	return (0);
3001dc13fee6SSepherosa Ziehau }
3002dc13fee6SSepherosa Ziehau 
3003dc13fee6SSepherosa Ziehau static int
3004dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS)
3005dc13fee6SSepherosa Ziehau {
3006dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
3007dc13fee6SSepherosa Ziehau 	int error, pkts;
3008dc13fee6SSepherosa Ziehau 
3009dc13fee6SSepherosa Ziehau 	pkts = sc->hn_agg_pkts;
3010dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pkts, 0, req);
3011dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
3012dc13fee6SSepherosa Ziehau 		return (error);
3013dc13fee6SSepherosa Ziehau 
3014dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
3015dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = pkts;
3016dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
3017dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
3018dc13fee6SSepherosa Ziehau 
3019dc13fee6SSepherosa Ziehau 	return (0);
3020dc13fee6SSepherosa Ziehau }
3021dc13fee6SSepherosa Ziehau 
3022dc13fee6SSepherosa Ziehau static int
3023dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS)
3024dc13fee6SSepherosa Ziehau {
3025dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
3026dc13fee6SSepherosa Ziehau 	int pkts;
3027dc13fee6SSepherosa Ziehau 
3028dc13fee6SSepherosa Ziehau 	pkts = sc->hn_tx_ring[0].hn_agg_pktmax;
3029dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &pkts, 0, req));
3030dc13fee6SSepherosa Ziehau }
3031dc13fee6SSepherosa Ziehau 
3032dc13fee6SSepherosa Ziehau static int
3033dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS)
3034dc13fee6SSepherosa Ziehau {
3035dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
3036dc13fee6SSepherosa Ziehau 	int align;
3037dc13fee6SSepherosa Ziehau 
3038dc13fee6SSepherosa Ziehau 	align = sc->hn_tx_ring[0].hn_agg_align;
3039dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &align, 0, req));
3040dc13fee6SSepherosa Ziehau }
3041dc13fee6SSepherosa Ziehau 
30426c1204dfSSepherosa Ziehau static void
30436c1204dfSSepherosa Ziehau hn_chan_polling(struct vmbus_channel *chan, u_int pollhz)
30446c1204dfSSepherosa Ziehau {
30456c1204dfSSepherosa Ziehau 	if (pollhz == 0)
30466c1204dfSSepherosa Ziehau 		vmbus_chan_poll_disable(chan);
30476c1204dfSSepherosa Ziehau 	else
30486c1204dfSSepherosa Ziehau 		vmbus_chan_poll_enable(chan, pollhz);
30496c1204dfSSepherosa Ziehau }
30506c1204dfSSepherosa Ziehau 
30516c1204dfSSepherosa Ziehau static void
30526c1204dfSSepherosa Ziehau hn_polling(struct hn_softc *sc, u_int pollhz)
30536c1204dfSSepherosa Ziehau {
30546c1204dfSSepherosa Ziehau 	int nsubch = sc->hn_rx_ring_inuse - 1;
30556c1204dfSSepherosa Ziehau 
30566c1204dfSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
30576c1204dfSSepherosa Ziehau 
30586c1204dfSSepherosa Ziehau 	if (nsubch > 0) {
30596c1204dfSSepherosa Ziehau 		struct vmbus_channel **subch;
30606c1204dfSSepherosa Ziehau 		int i;
30616c1204dfSSepherosa Ziehau 
30626c1204dfSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
30636c1204dfSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
30646c1204dfSSepherosa Ziehau 			hn_chan_polling(subch[i], pollhz);
30656c1204dfSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
30666c1204dfSSepherosa Ziehau 	}
30676c1204dfSSepherosa Ziehau 	hn_chan_polling(sc->hn_prichan, pollhz);
30686c1204dfSSepherosa Ziehau }
30696c1204dfSSepherosa Ziehau 
30706c1204dfSSepherosa Ziehau static int
30716c1204dfSSepherosa Ziehau hn_polling_sysctl(SYSCTL_HANDLER_ARGS)
30726c1204dfSSepherosa Ziehau {
30736c1204dfSSepherosa Ziehau 	struct hn_softc *sc = arg1;
30746c1204dfSSepherosa Ziehau 	int pollhz, error;
30756c1204dfSSepherosa Ziehau 
30766c1204dfSSepherosa Ziehau 	pollhz = sc->hn_pollhz;
30776c1204dfSSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pollhz, 0, req);
30786c1204dfSSepherosa Ziehau 	if (error || req->newptr == NULL)
30796c1204dfSSepherosa Ziehau 		return (error);
30806c1204dfSSepherosa Ziehau 
30816c1204dfSSepherosa Ziehau 	if (pollhz != 0 &&
30826c1204dfSSepherosa Ziehau 	    (pollhz < VMBUS_CHAN_POLLHZ_MIN || pollhz > VMBUS_CHAN_POLLHZ_MAX))
30836c1204dfSSepherosa Ziehau 		return (EINVAL);
30846c1204dfSSepherosa Ziehau 
30856c1204dfSSepherosa Ziehau 	HN_LOCK(sc);
30866c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz != pollhz) {
30876c1204dfSSepherosa Ziehau 		sc->hn_pollhz = pollhz;
30886c1204dfSSepherosa Ziehau 		if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) &&
30896c1204dfSSepherosa Ziehau 		    (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
30906c1204dfSSepherosa Ziehau 			hn_polling(sc, sc->hn_pollhz);
30916c1204dfSSepherosa Ziehau 	}
30926c1204dfSSepherosa Ziehau 	HN_UNLOCK(sc);
30936c1204dfSSepherosa Ziehau 
30946c1204dfSSepherosa Ziehau 	return (0);
30956c1204dfSSepherosa Ziehau }
30966c1204dfSSepherosa Ziehau 
3097dc13fee6SSepherosa Ziehau static int
309815516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS)
309915516c77SSepherosa Ziehau {
310015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
310115516c77SSepherosa Ziehau 	char verstr[16];
310215516c77SSepherosa Ziehau 
310315516c77SSepherosa Ziehau 	snprintf(verstr, sizeof(verstr), "%u.%u",
310415516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
310515516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
310615516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
310715516c77SSepherosa Ziehau }
310815516c77SSepherosa Ziehau 
310915516c77SSepherosa Ziehau static int
311015516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS)
311115516c77SSepherosa Ziehau {
311215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
311315516c77SSepherosa Ziehau 	char caps_str[128];
311415516c77SSepherosa Ziehau 	uint32_t caps;
311515516c77SSepherosa Ziehau 
311615516c77SSepherosa Ziehau 	HN_LOCK(sc);
311715516c77SSepherosa Ziehau 	caps = sc->hn_caps;
311815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
311915516c77SSepherosa Ziehau 	snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS);
312015516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req);
312115516c77SSepherosa Ziehau }
312215516c77SSepherosa Ziehau 
312315516c77SSepherosa Ziehau static int
312415516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS)
312515516c77SSepherosa Ziehau {
312615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
312715516c77SSepherosa Ziehau 	char assist_str[128];
312815516c77SSepherosa Ziehau 	uint32_t hwassist;
312915516c77SSepherosa Ziehau 
313015516c77SSepherosa Ziehau 	HN_LOCK(sc);
313115516c77SSepherosa Ziehau 	hwassist = sc->hn_ifp->if_hwassist;
313215516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
313315516c77SSepherosa Ziehau 	snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS);
313415516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req);
313515516c77SSepherosa Ziehau }
313615516c77SSepherosa Ziehau 
313715516c77SSepherosa Ziehau static int
313815516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS)
313915516c77SSepherosa Ziehau {
314015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
314115516c77SSepherosa Ziehau 	char filter_str[128];
314215516c77SSepherosa Ziehau 	uint32_t filter;
314315516c77SSepherosa Ziehau 
314415516c77SSepherosa Ziehau 	HN_LOCK(sc);
314515516c77SSepherosa Ziehau 	filter = sc->hn_rx_filter;
314615516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
314715516c77SSepherosa Ziehau 	snprintf(filter_str, sizeof(filter_str), "%b", filter,
314815516c77SSepherosa Ziehau 	    NDIS_PACKET_TYPES);
314915516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req);
315015516c77SSepherosa Ziehau }
315115516c77SSepherosa Ziehau 
315234d68912SSepherosa Ziehau #ifndef RSS
315334d68912SSepherosa Ziehau 
315415516c77SSepherosa Ziehau static int
315515516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
315615516c77SSepherosa Ziehau {
315715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
315815516c77SSepherosa Ziehau 	int error;
315915516c77SSepherosa Ziehau 
316015516c77SSepherosa Ziehau 	HN_LOCK(sc);
316115516c77SSepherosa Ziehau 
316215516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
316315516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
316415516c77SSepherosa Ziehau 		goto back;
316515516c77SSepherosa Ziehau 
316615516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
316715516c77SSepherosa Ziehau 	if (error)
316815516c77SSepherosa Ziehau 		goto back;
316915516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
317015516c77SSepherosa Ziehau 
317115516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
317215516c77SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
317315516c77SSepherosa Ziehau 	} else {
317415516c77SSepherosa Ziehau 		/* Not RSS capable, at least for now; just save the RSS key. */
317515516c77SSepherosa Ziehau 		error = 0;
317615516c77SSepherosa Ziehau 	}
317715516c77SSepherosa Ziehau back:
317815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
317915516c77SSepherosa Ziehau 	return (error);
318015516c77SSepherosa Ziehau }
318115516c77SSepherosa Ziehau 
318215516c77SSepherosa Ziehau static int
318315516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS)
318415516c77SSepherosa Ziehau {
318515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
318615516c77SSepherosa Ziehau 	int error;
318715516c77SSepherosa Ziehau 
318815516c77SSepherosa Ziehau 	HN_LOCK(sc);
318915516c77SSepherosa Ziehau 
319015516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
319115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
319215516c77SSepherosa Ziehau 		goto back;
319315516c77SSepherosa Ziehau 
319415516c77SSepherosa Ziehau 	/*
319515516c77SSepherosa Ziehau 	 * Don't allow RSS indirect table change, if this interface is not
319615516c77SSepherosa Ziehau 	 * RSS capable currently.
319715516c77SSepherosa Ziehau 	 */
319815516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
319915516c77SSepherosa Ziehau 		error = EOPNOTSUPP;
320015516c77SSepherosa Ziehau 		goto back;
320115516c77SSepherosa Ziehau 	}
320215516c77SSepherosa Ziehau 
320315516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
320415516c77SSepherosa Ziehau 	if (error)
320515516c77SSepherosa Ziehau 		goto back;
320615516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSIND;
320715516c77SSepherosa Ziehau 
3208afd4971bSSepherosa Ziehau 	hn_rss_ind_fixup(sc);
320915516c77SSepherosa Ziehau 	error = hn_rss_reconfig(sc);
321015516c77SSepherosa Ziehau back:
321115516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
321215516c77SSepherosa Ziehau 	return (error);
321315516c77SSepherosa Ziehau }
321415516c77SSepherosa Ziehau 
321534d68912SSepherosa Ziehau #endif	/* !RSS */
321634d68912SSepherosa Ziehau 
321715516c77SSepherosa Ziehau static int
321815516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS)
321915516c77SSepherosa Ziehau {
322015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
322115516c77SSepherosa Ziehau 	char hash_str[128];
322215516c77SSepherosa Ziehau 	uint32_t hash;
322315516c77SSepherosa Ziehau 
322415516c77SSepherosa Ziehau 	HN_LOCK(sc);
322515516c77SSepherosa Ziehau 	hash = sc->hn_rss_hash;
322615516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
322715516c77SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
322815516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
322915516c77SSepherosa Ziehau }
323015516c77SSepherosa Ziehau 
323115516c77SSepherosa Ziehau static int
323240d60d6eSDexuan Cui hn_vf_sysctl(SYSCTL_HANDLER_ARGS)
323340d60d6eSDexuan Cui {
323440d60d6eSDexuan Cui 	struct hn_softc *sc = arg1;
323540d60d6eSDexuan Cui 	char vf_name[128];
323640d60d6eSDexuan Cui 	struct ifnet *vf;
323740d60d6eSDexuan Cui 
323840d60d6eSDexuan Cui 	HN_LOCK(sc);
323940d60d6eSDexuan Cui 	vf_name[0] = '\0';
324040d60d6eSDexuan Cui 	vf = sc->hn_rx_ring[0].hn_vf;
324140d60d6eSDexuan Cui 	if (vf != NULL)
324240d60d6eSDexuan Cui 		snprintf(vf_name, sizeof(vf_name), "%s", if_name(vf));
324340d60d6eSDexuan Cui 	HN_UNLOCK(sc);
324440d60d6eSDexuan Cui 	return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req);
324540d60d6eSDexuan Cui }
324640d60d6eSDexuan Cui 
324740d60d6eSDexuan Cui static int
324815516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff)
324915516c77SSepherosa Ziehau {
325015516c77SSepherosa Ziehau 	const struct ip *ip;
325115516c77SSepherosa Ziehau 	int len, iphlen, iplen;
325215516c77SSepherosa Ziehau 	const struct tcphdr *th;
325315516c77SSepherosa Ziehau 	int thoff;				/* TCP data offset */
325415516c77SSepherosa Ziehau 
325515516c77SSepherosa Ziehau 	len = hoff + sizeof(struct ip);
325615516c77SSepherosa Ziehau 
325715516c77SSepherosa Ziehau 	/* The packet must be at least the size of an IP header. */
325815516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < len)
325915516c77SSepherosa Ziehau 		return IPPROTO_DONE;
326015516c77SSepherosa Ziehau 
326115516c77SSepherosa Ziehau 	/* The fixed IP header must reside completely in the first mbuf. */
326215516c77SSepherosa Ziehau 	if (m->m_len < len)
326315516c77SSepherosa Ziehau 		return IPPROTO_DONE;
326415516c77SSepherosa Ziehau 
326515516c77SSepherosa Ziehau 	ip = mtodo(m, hoff);
326615516c77SSepherosa Ziehau 
326715516c77SSepherosa Ziehau 	/* Bound check the packet's stated IP header length. */
326815516c77SSepherosa Ziehau 	iphlen = ip->ip_hl << 2;
326915516c77SSepherosa Ziehau 	if (iphlen < sizeof(struct ip))		/* minimum header length */
327015516c77SSepherosa Ziehau 		return IPPROTO_DONE;
327115516c77SSepherosa Ziehau 
327215516c77SSepherosa Ziehau 	/* The full IP header must reside completely in the one mbuf. */
327315516c77SSepherosa Ziehau 	if (m->m_len < hoff + iphlen)
327415516c77SSepherosa Ziehau 		return IPPROTO_DONE;
327515516c77SSepherosa Ziehau 
327615516c77SSepherosa Ziehau 	iplen = ntohs(ip->ip_len);
327715516c77SSepherosa Ziehau 
327815516c77SSepherosa Ziehau 	/*
327915516c77SSepherosa Ziehau 	 * Check that the amount of data in the buffers is as
328015516c77SSepherosa Ziehau 	 * at least much as the IP header would have us expect.
328115516c77SSepherosa Ziehau 	 */
328215516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < hoff + iplen)
328315516c77SSepherosa Ziehau 		return IPPROTO_DONE;
328415516c77SSepherosa Ziehau 
328515516c77SSepherosa Ziehau 	/*
328615516c77SSepherosa Ziehau 	 * Ignore IP fragments.
328715516c77SSepherosa Ziehau 	 */
328815516c77SSepherosa Ziehau 	if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF))
328915516c77SSepherosa Ziehau 		return IPPROTO_DONE;
329015516c77SSepherosa Ziehau 
329115516c77SSepherosa Ziehau 	/*
329215516c77SSepherosa Ziehau 	 * The TCP/IP or UDP/IP header must be entirely contained within
329315516c77SSepherosa Ziehau 	 * the first fragment of a packet.
329415516c77SSepherosa Ziehau 	 */
329515516c77SSepherosa Ziehau 	switch (ip->ip_p) {
329615516c77SSepherosa Ziehau 	case IPPROTO_TCP:
329715516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct tcphdr))
329815516c77SSepherosa Ziehau 			return IPPROTO_DONE;
329915516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct tcphdr))
330015516c77SSepherosa Ziehau 			return IPPROTO_DONE;
330115516c77SSepherosa Ziehau 		th = (const struct tcphdr *)((const uint8_t *)ip + iphlen);
330215516c77SSepherosa Ziehau 		thoff = th->th_off << 2;
330315516c77SSepherosa Ziehau 		if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen)
330415516c77SSepherosa Ziehau 			return IPPROTO_DONE;
330515516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + thoff)
330615516c77SSepherosa Ziehau 			return IPPROTO_DONE;
330715516c77SSepherosa Ziehau 		break;
330815516c77SSepherosa Ziehau 	case IPPROTO_UDP:
330915516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct udphdr))
331015516c77SSepherosa Ziehau 			return IPPROTO_DONE;
331115516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct udphdr))
331215516c77SSepherosa Ziehau 			return IPPROTO_DONE;
331315516c77SSepherosa Ziehau 		break;
331415516c77SSepherosa Ziehau 	default:
331515516c77SSepherosa Ziehau 		if (iplen < iphlen)
331615516c77SSepherosa Ziehau 			return IPPROTO_DONE;
331715516c77SSepherosa Ziehau 		break;
331815516c77SSepherosa Ziehau 	}
331915516c77SSepherosa Ziehau 	return ip->ip_p;
332015516c77SSepherosa Ziehau }
332115516c77SSepherosa Ziehau 
332215516c77SSepherosa Ziehau static int
332315516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt)
332415516c77SSepherosa Ziehau {
332515516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
332615516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
332715516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
332815516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
332915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
333015516c77SSepherosa Ziehau 	int lroent_cnt;
333115516c77SSepherosa Ziehau #endif
333215516c77SSepherosa Ziehau #endif
333315516c77SSepherosa Ziehau 	int i;
333415516c77SSepherosa Ziehau 
333515516c77SSepherosa Ziehau 	/*
333615516c77SSepherosa Ziehau 	 * Create RXBUF for reception.
333715516c77SSepherosa Ziehau 	 *
333815516c77SSepherosa Ziehau 	 * NOTE:
333915516c77SSepherosa Ziehau 	 * - It is shared by all channels.
334015516c77SSepherosa Ziehau 	 * - A large enough buffer is allocated, certain version of NVSes
334115516c77SSepherosa Ziehau 	 *   may further limit the usable space.
334215516c77SSepherosa Ziehau 	 */
334315516c77SSepherosa Ziehau 	sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
334415516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma,
334515516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
334615516c77SSepherosa Ziehau 	if (sc->hn_rxbuf == NULL) {
334715516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate rxbuf failed\n");
334815516c77SSepherosa Ziehau 		return (ENOMEM);
334915516c77SSepherosa Ziehau 	}
335015516c77SSepherosa Ziehau 
335115516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = ring_cnt;
335215516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt;
335315516c77SSepherosa Ziehau 
335415516c77SSepherosa Ziehau 	sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt,
335515516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
335615516c77SSepherosa Ziehau 
335715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
335815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
335915516c77SSepherosa Ziehau 	lroent_cnt = hn_lro_entry_count;
336015516c77SSepherosa Ziehau 	if (lroent_cnt < TCP_LRO_ENTRIES)
336115516c77SSepherosa Ziehau 		lroent_cnt = TCP_LRO_ENTRIES;
336215516c77SSepherosa Ziehau 	if (bootverbose)
336315516c77SSepherosa Ziehau 		device_printf(dev, "LRO: entry count %d\n", lroent_cnt);
336415516c77SSepherosa Ziehau #endif
336515516c77SSepherosa Ziehau #endif	/* INET || INET6 */
336615516c77SSepherosa Ziehau 
336715516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
336815516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
336915516c77SSepherosa Ziehau 
337015516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.rx sysctl tree */
337115516c77SSepherosa Ziehau 	sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx",
337215516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
337315516c77SSepherosa Ziehau 
337415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
337515516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
337615516c77SSepherosa Ziehau 
337715516c77SSepherosa Ziehau 		rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
337815516c77SSepherosa Ziehau 		    PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE,
337915516c77SSepherosa Ziehau 		    &rxr->hn_br_dma, BUS_DMA_WAITOK);
338015516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL) {
338115516c77SSepherosa Ziehau 			device_printf(dev, "allocate bufring failed\n");
338215516c77SSepherosa Ziehau 			return (ENOMEM);
338315516c77SSepherosa Ziehau 		}
338415516c77SSepherosa Ziehau 
338515516c77SSepherosa Ziehau 		if (hn_trust_hosttcp)
338615516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP;
338715516c77SSepherosa Ziehau 		if (hn_trust_hostudp)
338815516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP;
338915516c77SSepherosa Ziehau 		if (hn_trust_hostip)
339015516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP;
339115516c77SSepherosa Ziehau 		rxr->hn_ifp = sc->hn_ifp;
339215516c77SSepherosa Ziehau 		if (i < sc->hn_tx_ring_cnt)
339315516c77SSepherosa Ziehau 			rxr->hn_txr = &sc->hn_tx_ring[i];
339415516c77SSepherosa Ziehau 		rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF;
339515516c77SSepherosa Ziehau 		rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK);
339615516c77SSepherosa Ziehau 		rxr->hn_rx_idx = i;
339715516c77SSepherosa Ziehau 		rxr->hn_rxbuf = sc->hn_rxbuf;
339815516c77SSepherosa Ziehau 
339915516c77SSepherosa Ziehau 		/*
340015516c77SSepherosa Ziehau 		 * Initialize LRO.
340115516c77SSepherosa Ziehau 		 */
340215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
340315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
340415516c77SSepherosa Ziehau 		tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt,
340515516c77SSepherosa Ziehau 		    hn_lro_mbufq_depth);
340615516c77SSepherosa Ziehau #else
340715516c77SSepherosa Ziehau 		tcp_lro_init(&rxr->hn_lro);
340815516c77SSepherosa Ziehau 		rxr->hn_lro.ifp = sc->hn_ifp;
340915516c77SSepherosa Ziehau #endif
341015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
341115516c77SSepherosa Ziehau 		rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF;
341215516c77SSepherosa Ziehau 		rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF;
341315516c77SSepherosa Ziehau #endif
341415516c77SSepherosa Ziehau #endif	/* INET || INET6 */
341515516c77SSepherosa Ziehau 
341615516c77SSepherosa Ziehau 		if (sc->hn_rx_sysctl_tree != NULL) {
341715516c77SSepherosa Ziehau 			char name[16];
341815516c77SSepherosa Ziehau 
341915516c77SSepherosa Ziehau 			/*
342015516c77SSepherosa Ziehau 			 * Create per RX ring sysctl tree:
342115516c77SSepherosa Ziehau 			 * dev.hn.UNIT.rx.RINGID
342215516c77SSepherosa Ziehau 			 */
342315516c77SSepherosa Ziehau 			snprintf(name, sizeof(name), "%d", i);
342415516c77SSepherosa Ziehau 			rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx,
342515516c77SSepherosa Ziehau 			    SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree),
342615516c77SSepherosa Ziehau 			    OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
342715516c77SSepherosa Ziehau 
342815516c77SSepherosa Ziehau 			if (rxr->hn_rx_sysctl_tree != NULL) {
342915516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
343015516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
343115516c77SSepherosa Ziehau 				    OID_AUTO, "packets", CTLFLAG_RW,
343215516c77SSepherosa Ziehau 				    &rxr->hn_pkts, "# of packets received");
343315516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
343415516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
343515516c77SSepherosa Ziehau 				    OID_AUTO, "rss_pkts", CTLFLAG_RW,
343615516c77SSepherosa Ziehau 				    &rxr->hn_rss_pkts,
343715516c77SSepherosa Ziehau 				    "# of packets w/ RSS info received");
343815516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx,
343915516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
344015516c77SSepherosa Ziehau 				    OID_AUTO, "pktbuf_len", CTLFLAG_RD,
344115516c77SSepherosa Ziehau 				    &rxr->hn_pktbuf_len, 0,
344215516c77SSepherosa Ziehau 				    "Temporary channel packet buffer length");
344315516c77SSepherosa Ziehau 			}
344415516c77SSepherosa Ziehau 		}
344515516c77SSepherosa Ziehau 	}
344615516c77SSepherosa Ziehau 
344715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued",
344815516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
344915516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_queued),
345015516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
345115516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
345215516c77SSepherosa Ziehau #else
345315516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
345415516c77SSepherosa Ziehau #endif
345515516c77SSepherosa Ziehau 	    "LU", "LRO queued");
345615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed",
345715516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
345815516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_flushed),
345915516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
346015516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
346115516c77SSepherosa Ziehau #else
346215516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
346315516c77SSepherosa Ziehau #endif
346415516c77SSepherosa Ziehau 	    "LU", "LRO flushed");
346515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried",
346615516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
346715516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro_tried),
346815516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries");
346915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
347015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim",
347115516c77SSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
347215516c77SSepherosa Ziehau 	    hn_lro_lenlim_sysctl, "IU",
347315516c77SSepherosa Ziehau 	    "Max # of data bytes to be aggregated by LRO");
347415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim",
347515516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
347615516c77SSepherosa Ziehau 	    hn_lro_ackcnt_sysctl, "I",
347715516c77SSepherosa Ziehau 	    "Max # of ACKs to be aggregated by LRO");
347815516c77SSepherosa Ziehau #endif
347915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp",
348015516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP,
348115516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
348215516c77SSepherosa Ziehau 	    "Trust tcp segement verification on host side, "
348315516c77SSepherosa Ziehau 	    "when csum info is missing");
348415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp",
348515516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP,
348615516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
348715516c77SSepherosa Ziehau 	    "Trust udp datagram verification on host side, "
348815516c77SSepherosa Ziehau 	    "when csum info is missing");
348915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip",
349015516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP,
349115516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
349215516c77SSepherosa Ziehau 	    "Trust ip packet verification on host side, "
349315516c77SSepherosa Ziehau 	    "when csum info is missing");
349415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip",
349515516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
349615516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_ip),
349715516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP");
349815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp",
349915516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
350015516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_tcp),
350115516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP");
350215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp",
350315516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
350415516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_udp),
350515516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP");
350615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted",
350715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
350815516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_trusted),
350915516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU",
351015516c77SSepherosa Ziehau 	    "# of packets that we trust host's csum verification");
351115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts",
351215516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
351315516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_small_pkts),
351415516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of small packets received");
351515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed",
351615516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
351715516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_ack_failed),
351815516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures");
351915516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt",
352015516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings");
352115516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse",
352215516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings");
352315516c77SSepherosa Ziehau 
352415516c77SSepherosa Ziehau 	return (0);
352515516c77SSepherosa Ziehau }
352615516c77SSepherosa Ziehau 
352715516c77SSepherosa Ziehau static void
352815516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc)
352915516c77SSepherosa Ziehau {
353015516c77SSepherosa Ziehau 	int i;
353115516c77SSepherosa Ziehau 
353215516c77SSepherosa Ziehau 	if (sc->hn_rxbuf != NULL) {
35332494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0)
353415516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf);
35352494d735SSepherosa Ziehau 		else
35362494d735SSepherosa Ziehau 			device_printf(sc->hn_dev, "RXBUF is referenced\n");
353715516c77SSepherosa Ziehau 		sc->hn_rxbuf = NULL;
353815516c77SSepherosa Ziehau 	}
353915516c77SSepherosa Ziehau 
354015516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_cnt == 0)
354115516c77SSepherosa Ziehau 		return;
354215516c77SSepherosa Ziehau 
354315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
354415516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
354515516c77SSepherosa Ziehau 
354615516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL)
354715516c77SSepherosa Ziehau 			continue;
35482494d735SSepherosa Ziehau 		if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) {
354915516c77SSepherosa Ziehau 			hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br);
35502494d735SSepherosa Ziehau 		} else {
35512494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
35522494d735SSepherosa Ziehau 			    "%dth channel bufring is referenced", i);
35532494d735SSepherosa Ziehau 		}
355415516c77SSepherosa Ziehau 		rxr->hn_br = NULL;
355515516c77SSepherosa Ziehau 
355615516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
355715516c77SSepherosa Ziehau 		tcp_lro_free(&rxr->hn_lro);
355815516c77SSepherosa Ziehau #endif
355915516c77SSepherosa Ziehau 		free(rxr->hn_pktbuf, M_DEVBUF);
356015516c77SSepherosa Ziehau 	}
356115516c77SSepherosa Ziehau 	free(sc->hn_rx_ring, M_DEVBUF);
356215516c77SSepherosa Ziehau 	sc->hn_rx_ring = NULL;
356315516c77SSepherosa Ziehau 
356415516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = 0;
356515516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = 0;
356615516c77SSepherosa Ziehau }
356715516c77SSepherosa Ziehau 
356815516c77SSepherosa Ziehau static int
356915516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id)
357015516c77SSepherosa Ziehau {
357115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[id];
357215516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
357315516c77SSepherosa Ziehau 	bus_dma_tag_t parent_dtag;
357415516c77SSepherosa Ziehau 	int error, i;
357515516c77SSepherosa Ziehau 
357615516c77SSepherosa Ziehau 	txr->hn_sc = sc;
357715516c77SSepherosa Ziehau 	txr->hn_tx_idx = id;
357815516c77SSepherosa Ziehau 
357915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
358015516c77SSepherosa Ziehau 	mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN);
358115516c77SSepherosa Ziehau #endif
358215516c77SSepherosa Ziehau 	mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF);
358315516c77SSepherosa Ziehau 
358415516c77SSepherosa Ziehau 	txr->hn_txdesc_cnt = HN_TX_DESC_CNT;
358515516c77SSepherosa Ziehau 	txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt,
358615516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
358715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
358815516c77SSepherosa Ziehau 	SLIST_INIT(&txr->hn_txlist);
358915516c77SSepherosa Ziehau #else
359015516c77SSepherosa Ziehau 	txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF,
359115516c77SSepherosa Ziehau 	    M_WAITOK, &txr->hn_tx_lock);
359215516c77SSepherosa Ziehau #endif
359315516c77SSepherosa Ziehau 
35940e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_EVTTQ) {
35950e11868dSSepherosa Ziehau 		txr->hn_tx_taskq = VMBUS_GET_EVENT_TASKQ(
35960e11868dSSepherosa Ziehau 		    device_get_parent(dev), dev, HN_RING_IDX2CPU(sc, id));
35970e11868dSSepherosa Ziehau 	} else {
3598fdd0222aSSepherosa Ziehau 		txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt];
35990e11868dSSepherosa Ziehau 	}
360015516c77SSepherosa Ziehau 
360123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
360215516c77SSepherosa Ziehau 	if (hn_use_if_start) {
360315516c77SSepherosa Ziehau 		txr->hn_txeof = hn_start_txeof;
360415516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr);
360515516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr);
360623bf9e15SSepherosa Ziehau 	} else
360723bf9e15SSepherosa Ziehau #endif
360823bf9e15SSepherosa Ziehau 	{
360915516c77SSepherosa Ziehau 		int br_depth;
361015516c77SSepherosa Ziehau 
361115516c77SSepherosa Ziehau 		txr->hn_txeof = hn_xmit_txeof;
361215516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr);
361315516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr);
361415516c77SSepherosa Ziehau 
361515516c77SSepherosa Ziehau 		br_depth = hn_get_txswq_depth(txr);
361615516c77SSepherosa Ziehau 		txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF,
361715516c77SSepherosa Ziehau 		    M_WAITOK, &txr->hn_tx_lock);
361815516c77SSepherosa Ziehau 	}
361915516c77SSepherosa Ziehau 
362015516c77SSepherosa Ziehau 	txr->hn_direct_tx_size = hn_direct_tx_size;
362115516c77SSepherosa Ziehau 
362215516c77SSepherosa Ziehau 	/*
362315516c77SSepherosa Ziehau 	 * Always schedule transmission instead of trying to do direct
362415516c77SSepherosa Ziehau 	 * transmission.  This one gives the best performance so far.
362515516c77SSepherosa Ziehau 	 */
362615516c77SSepherosa Ziehau 	txr->hn_sched_tx = 1;
362715516c77SSepherosa Ziehau 
362815516c77SSepherosa Ziehau 	parent_dtag = bus_get_dma_tag(dev);
362915516c77SSepherosa Ziehau 
363015516c77SSepherosa Ziehau 	/* DMA tag for RNDIS packet messages. */
363115516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
363215516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_ALIGN,		/* alignment */
363315516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_BOUNDARY,	/* boundary */
363415516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
363515516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
363615516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
363715516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsize */
363815516c77SSepherosa Ziehau 	    1,				/* nsegments */
363915516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsegsize */
364015516c77SSepherosa Ziehau 	    0,				/* flags */
364115516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
364215516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
364315516c77SSepherosa Ziehau 	    &txr->hn_tx_rndis_dtag);
364415516c77SSepherosa Ziehau 	if (error) {
364515516c77SSepherosa Ziehau 		device_printf(dev, "failed to create rndis dmatag\n");
364615516c77SSepherosa Ziehau 		return error;
364715516c77SSepherosa Ziehau 	}
364815516c77SSepherosa Ziehau 
364915516c77SSepherosa Ziehau 	/* DMA tag for data. */
365015516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
365115516c77SSepherosa Ziehau 	    1,				/* alignment */
365215516c77SSepherosa Ziehau 	    HN_TX_DATA_BOUNDARY,	/* boundary */
365315516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
365415516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
365515516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
365615516c77SSepherosa Ziehau 	    HN_TX_DATA_MAXSIZE,		/* maxsize */
365715516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGCNT_MAX,	/* nsegments */
365815516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGSIZE,		/* maxsegsize */
365915516c77SSepherosa Ziehau 	    0,				/* flags */
366015516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
366115516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
366215516c77SSepherosa Ziehau 	    &txr->hn_tx_data_dtag);
366315516c77SSepherosa Ziehau 	if (error) {
366415516c77SSepherosa Ziehau 		device_printf(dev, "failed to create data dmatag\n");
366515516c77SSepherosa Ziehau 		return error;
366615516c77SSepherosa Ziehau 	}
366715516c77SSepherosa Ziehau 
366815516c77SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i) {
366915516c77SSepherosa Ziehau 		struct hn_txdesc *txd = &txr->hn_txdesc[i];
367015516c77SSepherosa Ziehau 
367115516c77SSepherosa Ziehau 		txd->txr = txr;
367215516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
3673dc13fee6SSepherosa Ziehau 		STAILQ_INIT(&txd->agg_list);
367415516c77SSepherosa Ziehau 
367515516c77SSepherosa Ziehau 		/*
367615516c77SSepherosa Ziehau 		 * Allocate and load RNDIS packet message.
367715516c77SSepherosa Ziehau 		 */
367815516c77SSepherosa Ziehau         	error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag,
367915516c77SSepherosa Ziehau 		    (void **)&txd->rndis_pkt,
368015516c77SSepherosa Ziehau 		    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
368115516c77SSepherosa Ziehau 		    &txd->rndis_pkt_dmap);
368215516c77SSepherosa Ziehau 		if (error) {
368315516c77SSepherosa Ziehau 			device_printf(dev,
368415516c77SSepherosa Ziehau 			    "failed to allocate rndis_packet_msg, %d\n", i);
368515516c77SSepherosa Ziehau 			return error;
368615516c77SSepherosa Ziehau 		}
368715516c77SSepherosa Ziehau 
368815516c77SSepherosa Ziehau 		error = bus_dmamap_load(txr->hn_tx_rndis_dtag,
368915516c77SSepherosa Ziehau 		    txd->rndis_pkt_dmap,
369015516c77SSepherosa Ziehau 		    txd->rndis_pkt, HN_RNDIS_PKT_LEN,
369115516c77SSepherosa Ziehau 		    hyperv_dma_map_paddr, &txd->rndis_pkt_paddr,
369215516c77SSepherosa Ziehau 		    BUS_DMA_NOWAIT);
369315516c77SSepherosa Ziehau 		if (error) {
369415516c77SSepherosa Ziehau 			device_printf(dev,
369515516c77SSepherosa Ziehau 			    "failed to load rndis_packet_msg, %d\n", i);
369615516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
369715516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
369815516c77SSepherosa Ziehau 			return error;
369915516c77SSepherosa Ziehau 		}
370015516c77SSepherosa Ziehau 
370115516c77SSepherosa Ziehau 		/* DMA map for TX data. */
370215516c77SSepherosa Ziehau 		error = bus_dmamap_create(txr->hn_tx_data_dtag, 0,
370315516c77SSepherosa Ziehau 		    &txd->data_dmap);
370415516c77SSepherosa Ziehau 		if (error) {
370515516c77SSepherosa Ziehau 			device_printf(dev,
370615516c77SSepherosa Ziehau 			    "failed to allocate tx data dmamap\n");
370715516c77SSepherosa Ziehau 			bus_dmamap_unload(txr->hn_tx_rndis_dtag,
370815516c77SSepherosa Ziehau 			    txd->rndis_pkt_dmap);
370915516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
371015516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
371115516c77SSepherosa Ziehau 			return error;
371215516c77SSepherosa Ziehau 		}
371315516c77SSepherosa Ziehau 
371415516c77SSepherosa Ziehau 		/* All set, put it to list */
371515516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_ONLIST;
371615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
371715516c77SSepherosa Ziehau 		SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
371815516c77SSepherosa Ziehau #else
371915516c77SSepherosa Ziehau 		buf_ring_enqueue(txr->hn_txdesc_br, txd);
372015516c77SSepherosa Ziehau #endif
372115516c77SSepherosa Ziehau 	}
372215516c77SSepherosa Ziehau 	txr->hn_txdesc_avail = txr->hn_txdesc_cnt;
372315516c77SSepherosa Ziehau 
372415516c77SSepherosa Ziehau 	if (sc->hn_tx_sysctl_tree != NULL) {
372515516c77SSepherosa Ziehau 		struct sysctl_oid_list *child;
372615516c77SSepherosa Ziehau 		struct sysctl_ctx_list *ctx;
372715516c77SSepherosa Ziehau 		char name[16];
372815516c77SSepherosa Ziehau 
372915516c77SSepherosa Ziehau 		/*
373015516c77SSepherosa Ziehau 		 * Create per TX ring sysctl tree:
373115516c77SSepherosa Ziehau 		 * dev.hn.UNIT.tx.RINGID
373215516c77SSepherosa Ziehau 		 */
373315516c77SSepherosa Ziehau 		ctx = device_get_sysctl_ctx(dev);
373415516c77SSepherosa Ziehau 		child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree);
373515516c77SSepherosa Ziehau 
373615516c77SSepherosa Ziehau 		snprintf(name, sizeof(name), "%d", id);
373715516c77SSepherosa Ziehau 		txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
373815516c77SSepherosa Ziehau 		    name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
373915516c77SSepherosa Ziehau 
374015516c77SSepherosa Ziehau 		if (txr->hn_tx_sysctl_tree != NULL) {
374115516c77SSepherosa Ziehau 			child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree);
374215516c77SSepherosa Ziehau 
374385e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
374415516c77SSepherosa Ziehau 			SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail",
374515516c77SSepherosa Ziehau 			    CTLFLAG_RD, &txr->hn_txdesc_avail, 0,
374615516c77SSepherosa Ziehau 			    "# of available TX descs");
374785e4ae1eSSepherosa Ziehau #endif
374823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
374923bf9e15SSepherosa Ziehau 			if (!hn_use_if_start)
375023bf9e15SSepherosa Ziehau #endif
375123bf9e15SSepherosa Ziehau 			{
375215516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive",
375315516c77SSepherosa Ziehau 				    CTLFLAG_RD, &txr->hn_oactive, 0,
375415516c77SSepherosa Ziehau 				    "over active");
375515516c77SSepherosa Ziehau 			}
375615516c77SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets",
375715516c77SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_pkts,
375815516c77SSepherosa Ziehau 			    "# of packets transmitted");
3759dc13fee6SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends",
3760dc13fee6SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_sends, "# of sends");
376115516c77SSepherosa Ziehau 		}
376215516c77SSepherosa Ziehau 	}
376315516c77SSepherosa Ziehau 
376415516c77SSepherosa Ziehau 	return 0;
376515516c77SSepherosa Ziehau }
376615516c77SSepherosa Ziehau 
376715516c77SSepherosa Ziehau static void
376815516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd)
376915516c77SSepherosa Ziehau {
377015516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = txd->txr;
377115516c77SSepherosa Ziehau 
377215516c77SSepherosa Ziehau 	KASSERT(txd->m == NULL, ("still has mbuf installed"));
377315516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped"));
377415516c77SSepherosa Ziehau 
377515516c77SSepherosa Ziehau 	bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap);
377615516c77SSepherosa Ziehau 	bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt,
377715516c77SSepherosa Ziehau 	    txd->rndis_pkt_dmap);
377815516c77SSepherosa Ziehau 	bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap);
377915516c77SSepherosa Ziehau }
378015516c77SSepherosa Ziehau 
378115516c77SSepherosa Ziehau static void
378225641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd)
378325641fc7SSepherosa Ziehau {
378425641fc7SSepherosa Ziehau 
378525641fc7SSepherosa Ziehau 	KASSERT(txd->refs == 0 || txd->refs == 1,
378625641fc7SSepherosa Ziehau 	    ("invalid txd refs %d", txd->refs));
378725641fc7SSepherosa Ziehau 
378825641fc7SSepherosa Ziehau 	/* Aggregated txds will be freed by their aggregating txd. */
378925641fc7SSepherosa Ziehau 	if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) {
379025641fc7SSepherosa Ziehau 		int freed;
379125641fc7SSepherosa Ziehau 
379225641fc7SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
379325641fc7SSepherosa Ziehau 		KASSERT(freed, ("can't free txdesc"));
379425641fc7SSepherosa Ziehau 	}
379525641fc7SSepherosa Ziehau }
379625641fc7SSepherosa Ziehau 
379725641fc7SSepherosa Ziehau static void
379815516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr)
379915516c77SSepherosa Ziehau {
380025641fc7SSepherosa Ziehau 	int i;
380115516c77SSepherosa Ziehau 
380215516c77SSepherosa Ziehau 	if (txr->hn_txdesc == NULL)
380315516c77SSepherosa Ziehau 		return;
380415516c77SSepherosa Ziehau 
380525641fc7SSepherosa Ziehau 	/*
380625641fc7SSepherosa Ziehau 	 * NOTE:
380725641fc7SSepherosa Ziehau 	 * Because the freeing of aggregated txds will be deferred
380825641fc7SSepherosa Ziehau 	 * to the aggregating txd, two passes are used here:
380925641fc7SSepherosa Ziehau 	 * - The first pass GCes any pending txds.  This GC is necessary,
381025641fc7SSepherosa Ziehau 	 *   since if the channels are revoked, hypervisor will not
381125641fc7SSepherosa Ziehau 	 *   deliver send-done for all pending txds.
381225641fc7SSepherosa Ziehau 	 * - The second pass frees the busdma stuffs, i.e. after all txds
381325641fc7SSepherosa Ziehau 	 *   were freed.
381425641fc7SSepherosa Ziehau 	 */
381525641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
381625641fc7SSepherosa Ziehau 		hn_txdesc_gc(txr, &txr->hn_txdesc[i]);
381725641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
381825641fc7SSepherosa Ziehau 		hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]);
381915516c77SSepherosa Ziehau 
382015516c77SSepherosa Ziehau 	if (txr->hn_tx_data_dtag != NULL)
382115516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_data_dtag);
382215516c77SSepherosa Ziehau 	if (txr->hn_tx_rndis_dtag != NULL)
382315516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_rndis_dtag);
382415516c77SSepherosa Ziehau 
382515516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
382615516c77SSepherosa Ziehau 	buf_ring_free(txr->hn_txdesc_br, M_DEVBUF);
382715516c77SSepherosa Ziehau #endif
382815516c77SSepherosa Ziehau 
382915516c77SSepherosa Ziehau 	free(txr->hn_txdesc, M_DEVBUF);
383015516c77SSepherosa Ziehau 	txr->hn_txdesc = NULL;
383115516c77SSepherosa Ziehau 
383215516c77SSepherosa Ziehau 	if (txr->hn_mbuf_br != NULL)
383315516c77SSepherosa Ziehau 		buf_ring_free(txr->hn_mbuf_br, M_DEVBUF);
383415516c77SSepherosa Ziehau 
383515516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
383615516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_txlist_spin);
383715516c77SSepherosa Ziehau #endif
383815516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_tx_lock);
383915516c77SSepherosa Ziehau }
384015516c77SSepherosa Ziehau 
384115516c77SSepherosa Ziehau static int
384215516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt)
384315516c77SSepherosa Ziehau {
384415516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
384515516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
384615516c77SSepherosa Ziehau 	int i;
384715516c77SSepherosa Ziehau 
384815516c77SSepherosa Ziehau 	/*
384915516c77SSepherosa Ziehau 	 * Create TXBUF for chimney sending.
385015516c77SSepherosa Ziehau 	 *
385115516c77SSepherosa Ziehau 	 * NOTE: It is shared by all channels.
385215516c77SSepherosa Ziehau 	 */
385315516c77SSepherosa Ziehau 	sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev),
385415516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma,
385515516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
385615516c77SSepherosa Ziehau 	if (sc->hn_chim == NULL) {
385715516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate txbuf failed\n");
385815516c77SSepherosa Ziehau 		return (ENOMEM);
385915516c77SSepherosa Ziehau 	}
386015516c77SSepherosa Ziehau 
386115516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = ring_cnt;
386215516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
386315516c77SSepherosa Ziehau 
386415516c77SSepherosa Ziehau 	sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt,
386515516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
386615516c77SSepherosa Ziehau 
386715516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(sc->hn_dev);
386815516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev));
386915516c77SSepherosa Ziehau 
387015516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.tx sysctl tree */
387115516c77SSepherosa Ziehau 	sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx",
387215516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
387315516c77SSepherosa Ziehau 
387415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
387515516c77SSepherosa Ziehau 		int error;
387615516c77SSepherosa Ziehau 
387715516c77SSepherosa Ziehau 		error = hn_tx_ring_create(sc, i);
387815516c77SSepherosa Ziehau 		if (error)
387915516c77SSepherosa Ziehau 			return error;
388015516c77SSepherosa Ziehau 	}
388115516c77SSepherosa Ziehau 
388215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs",
388315516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
388415516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_no_txdescs),
388515516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs");
388615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed",
388715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
388815516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_send_failed),
388915516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure");
389015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed",
389115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
389215516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_txdma_failed),
389315516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure");
3894dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed",
3895dc13fee6SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
3896dc13fee6SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_flush_failed),
3897dc13fee6SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU",
3898dc13fee6SSepherosa Ziehau 	    "# of packet transmission aggregation flush failure");
389915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed",
390015516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
390115516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_collapsed),
390215516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed");
390315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney",
390415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
390515516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney),
390615516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send");
390715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried",
390815516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
390915516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney_tried),
391015516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries");
391115516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt",
391215516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0,
391315516c77SSepherosa Ziehau 	    "# of total TX descs");
391415516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max",
391515516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_chim_szmax, 0,
391615516c77SSepherosa Ziehau 	    "Chimney send packet size upper boundary");
391715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size",
391815516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
391915516c77SSepherosa Ziehau 	    hn_chim_size_sysctl, "I", "Chimney send packet size limit");
392015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size",
392115516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
392215516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_direct_tx_size),
392315516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
392415516c77SSepherosa Ziehau 	    "Size of the packet for direct transmission");
392515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx",
392615516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
392715516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_sched_tx),
392815516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
392915516c77SSepherosa Ziehau 	    "Always schedule transmission "
393015516c77SSepherosa Ziehau 	    "instead of doing direct transmission");
393115516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt",
393215516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings");
393315516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse",
393415516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings");
3935dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax",
3936dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0,
3937dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation size");
3938dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax",
3939dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
3940dc13fee6SSepherosa Ziehau 	    hn_txagg_pktmax_sysctl, "I",
3941dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation packets");
3942dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align",
3943dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
3944dc13fee6SSepherosa Ziehau 	    hn_txagg_align_sysctl, "I",
3945dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation alignment");
394615516c77SSepherosa Ziehau 
394715516c77SSepherosa Ziehau 	return 0;
394815516c77SSepherosa Ziehau }
394915516c77SSepherosa Ziehau 
395015516c77SSepherosa Ziehau static void
395115516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size)
395215516c77SSepherosa Ziehau {
395315516c77SSepherosa Ziehau 	int i;
395415516c77SSepherosa Ziehau 
3955a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
395615516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_chim_size = chim_size;
395715516c77SSepherosa Ziehau }
395815516c77SSepherosa Ziehau 
395915516c77SSepherosa Ziehau static void
396015516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu)
396115516c77SSepherosa Ziehau {
396215516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
396315516c77SSepherosa Ziehau 	int tso_minlen;
396415516c77SSepherosa Ziehau 
396515516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0)
396615516c77SSepherosa Ziehau 		return;
396715516c77SSepherosa Ziehau 
396815516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_sgmin >= 2,
396915516c77SSepherosa Ziehau 	    ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin));
397015516c77SSepherosa Ziehau 	tso_minlen = sc->hn_ndis_tso_sgmin * mtu;
397115516c77SSepherosa Ziehau 
397215516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen &&
397315516c77SSepherosa Ziehau 	    sc->hn_ndis_tso_szmax <= IP_MAXPACKET,
397415516c77SSepherosa Ziehau 	    ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax));
397515516c77SSepherosa Ziehau 
397615516c77SSepherosa Ziehau 	if (tso_maxlen < tso_minlen)
397715516c77SSepherosa Ziehau 		tso_maxlen = tso_minlen;
397815516c77SSepherosa Ziehau 	else if (tso_maxlen > IP_MAXPACKET)
397915516c77SSepherosa Ziehau 		tso_maxlen = IP_MAXPACKET;
398015516c77SSepherosa Ziehau 	if (tso_maxlen > sc->hn_ndis_tso_szmax)
398115516c77SSepherosa Ziehau 		tso_maxlen = sc->hn_ndis_tso_szmax;
398215516c77SSepherosa Ziehau 	ifp->if_hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
398315516c77SSepherosa Ziehau 	if (bootverbose)
398415516c77SSepherosa Ziehau 		if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax);
398515516c77SSepherosa Ziehau }
398615516c77SSepherosa Ziehau 
398715516c77SSepherosa Ziehau static void
398815516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc)
398915516c77SSepherosa Ziehau {
399015516c77SSepherosa Ziehau 	uint64_t csum_assist;
399115516c77SSepherosa Ziehau 	int i;
399215516c77SSepherosa Ziehau 
399315516c77SSepherosa Ziehau 	hn_set_chim_size(sc, sc->hn_chim_szmax);
399415516c77SSepherosa Ziehau 	if (hn_tx_chimney_size > 0 &&
399515516c77SSepherosa Ziehau 	    hn_tx_chimney_size < sc->hn_chim_szmax)
399615516c77SSepherosa Ziehau 		hn_set_chim_size(sc, hn_tx_chimney_size);
399715516c77SSepherosa Ziehau 
399815516c77SSepherosa Ziehau 	csum_assist = 0;
399915516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_IPCS)
400015516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP;
400115516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP4CS)
400215516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_TCP;
400315516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP4CS)
400415516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_UDP;
400515516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP6CS)
400615516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_TCP;
400715516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP6CS)
400815516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_UDP;
400915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
401015516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_csum_assist = csum_assist;
401115516c77SSepherosa Ziehau 
401215516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_HASHVAL) {
401315516c77SSepherosa Ziehau 		/*
401415516c77SSepherosa Ziehau 		 * Support HASHVAL pktinfo on TX path.
401515516c77SSepherosa Ziehau 		 */
401615516c77SSepherosa Ziehau 		if (bootverbose)
401715516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n");
401815516c77SSepherosa Ziehau 		for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
401915516c77SSepherosa Ziehau 			sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL;
402015516c77SSepherosa Ziehau 	}
402115516c77SSepherosa Ziehau }
402215516c77SSepherosa Ziehau 
402315516c77SSepherosa Ziehau static void
402415516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc)
402515516c77SSepherosa Ziehau {
402615516c77SSepherosa Ziehau 	int i;
402715516c77SSepherosa Ziehau 
402815516c77SSepherosa Ziehau 	if (sc->hn_chim != NULL) {
40292494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) {
403015516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim);
40312494d735SSepherosa Ziehau 		} else {
40322494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
40332494d735SSepherosa Ziehau 			    "chimney sending buffer is referenced");
40342494d735SSepherosa Ziehau 		}
403515516c77SSepherosa Ziehau 		sc->hn_chim = NULL;
403615516c77SSepherosa Ziehau 	}
403715516c77SSepherosa Ziehau 
403815516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt == 0)
403915516c77SSepherosa Ziehau 		return;
404015516c77SSepherosa Ziehau 
404115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
404215516c77SSepherosa Ziehau 		hn_tx_ring_destroy(&sc->hn_tx_ring[i]);
404315516c77SSepherosa Ziehau 
404415516c77SSepherosa Ziehau 	free(sc->hn_tx_ring, M_DEVBUF);
404515516c77SSepherosa Ziehau 	sc->hn_tx_ring = NULL;
404615516c77SSepherosa Ziehau 
404715516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = 0;
404815516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = 0;
404915516c77SSepherosa Ziehau }
405015516c77SSepherosa Ziehau 
405123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
405223bf9e15SSepherosa Ziehau 
405315516c77SSepherosa Ziehau static void
405415516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused)
405515516c77SSepherosa Ziehau {
405615516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
405715516c77SSepherosa Ziehau 
405815516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
405915516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
406015516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
406115516c77SSepherosa Ziehau }
406215516c77SSepherosa Ziehau 
406323bf9e15SSepherosa Ziehau static int
406423bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len)
406523bf9e15SSepherosa Ziehau {
406623bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
406723bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
4068dc13fee6SSepherosa Ziehau 	int sched = 0;
406923bf9e15SSepherosa Ziehau 
407023bf9e15SSepherosa Ziehau 	KASSERT(hn_use_if_start,
407123bf9e15SSepherosa Ziehau 	    ("hn_start_locked is called, when if_start is disabled"));
407223bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
407323bf9e15SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
4074dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
407523bf9e15SSepherosa Ziehau 
407623bf9e15SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
4077dc13fee6SSepherosa Ziehau 		return (0);
407823bf9e15SSepherosa Ziehau 
407923bf9e15SSepherosa Ziehau 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
408023bf9e15SSepherosa Ziehau 	    IFF_DRV_RUNNING)
4081dc13fee6SSepherosa Ziehau 		return (0);
408223bf9e15SSepherosa Ziehau 
408323bf9e15SSepherosa Ziehau 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
408423bf9e15SSepherosa Ziehau 		struct hn_txdesc *txd;
408523bf9e15SSepherosa Ziehau 		struct mbuf *m_head;
408623bf9e15SSepherosa Ziehau 		int error;
408723bf9e15SSepherosa Ziehau 
408823bf9e15SSepherosa Ziehau 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
408923bf9e15SSepherosa Ziehau 		if (m_head == NULL)
409023bf9e15SSepherosa Ziehau 			break;
409123bf9e15SSepherosa Ziehau 
409223bf9e15SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
409323bf9e15SSepherosa Ziehau 			/*
409423bf9e15SSepherosa Ziehau 			 * This sending could be time consuming; let callers
409523bf9e15SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
409623bf9e15SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
409723bf9e15SSepherosa Ziehau 			 */
409823bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
4099dc13fee6SSepherosa Ziehau 			sched = 1;
4100dc13fee6SSepherosa Ziehau 			break;
410123bf9e15SSepherosa Ziehau 		}
410223bf9e15SSepherosa Ziehau 
4103edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
4104edd3f315SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
4105edd3f315SSepherosa Ziehau 			m_head = hn_tso_fixup(m_head);
4106edd3f315SSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
4107edd3f315SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
4108edd3f315SSepherosa Ziehau 				continue;
4109edd3f315SSepherosa Ziehau 			}
4110edd3f315SSepherosa Ziehau 		}
4111edd3f315SSepherosa Ziehau #endif
4112edd3f315SSepherosa Ziehau 
411323bf9e15SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
411423bf9e15SSepherosa Ziehau 		if (txd == NULL) {
411523bf9e15SSepherosa Ziehau 			txr->hn_no_txdescs++;
411623bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
411723bf9e15SSepherosa Ziehau 			atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
411823bf9e15SSepherosa Ziehau 			break;
411923bf9e15SSepherosa Ziehau 		}
412023bf9e15SSepherosa Ziehau 
4121dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
412223bf9e15SSepherosa Ziehau 		if (error) {
412323bf9e15SSepherosa Ziehau 			/* Both txd and m_head are freed */
4124dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
4125dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
412623bf9e15SSepherosa Ziehau 			continue;
412723bf9e15SSepherosa Ziehau 		}
412823bf9e15SSepherosa Ziehau 
4129dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
4130dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
4131dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
4132dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
4133dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
4134dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
4135dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
4136dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
4137dc13fee6SSepherosa Ziehau 					break;
4138dc13fee6SSepherosa Ziehau 				}
4139dc13fee6SSepherosa Ziehau 			} else {
4140dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
414123bf9e15SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
414223bf9e15SSepherosa Ziehau 				if (__predict_false(error)) {
414323bf9e15SSepherosa Ziehau 					/* txd is freed, but m_head is not */
414423bf9e15SSepherosa Ziehau 					IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
4145dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
4146dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
414723bf9e15SSepherosa Ziehau 					break;
414823bf9e15SSepherosa Ziehau 				}
414923bf9e15SSepherosa Ziehau 			}
4150dc13fee6SSepherosa Ziehau 		}
4151dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
4152dc13fee6SSepherosa Ziehau 		else {
4153dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
4154dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
4155dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
4156dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
4157dc13fee6SSepherosa Ziehau 		}
4158dc13fee6SSepherosa Ziehau #endif
4159dc13fee6SSepherosa Ziehau 	}
4160dc13fee6SSepherosa Ziehau 
4161dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
4162dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
4163dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
4164dc13fee6SSepherosa Ziehau 	return (sched);
416523bf9e15SSepherosa Ziehau }
416623bf9e15SSepherosa Ziehau 
416723bf9e15SSepherosa Ziehau static void
416823bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp)
416923bf9e15SSepherosa Ziehau {
417023bf9e15SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
417123bf9e15SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[0];
417223bf9e15SSepherosa Ziehau 
417323bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
417423bf9e15SSepherosa Ziehau 		goto do_sched;
417523bf9e15SSepherosa Ziehau 
417623bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
417723bf9e15SSepherosa Ziehau 		int sched;
417823bf9e15SSepherosa Ziehau 
417923bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
418023bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
418123bf9e15SSepherosa Ziehau 		if (!sched)
418223bf9e15SSepherosa Ziehau 			return;
418323bf9e15SSepherosa Ziehau 	}
418423bf9e15SSepherosa Ziehau do_sched:
418523bf9e15SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
418623bf9e15SSepherosa Ziehau }
418723bf9e15SSepherosa Ziehau 
418815516c77SSepherosa Ziehau static void
418915516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused)
419015516c77SSepherosa Ziehau {
419115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
419215516c77SSepherosa Ziehau 
419315516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
419415516c77SSepherosa Ziehau 	atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE);
419515516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
419615516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
419715516c77SSepherosa Ziehau }
419815516c77SSepherosa Ziehau 
419923bf9e15SSepherosa Ziehau static void
420023bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr)
420123bf9e15SSepherosa Ziehau {
420223bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
420323bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
420423bf9e15SSepherosa Ziehau 
420523bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
420623bf9e15SSepherosa Ziehau 
420723bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
420823bf9e15SSepherosa Ziehau 		goto do_sched;
420923bf9e15SSepherosa Ziehau 
421023bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
421123bf9e15SSepherosa Ziehau 		int sched;
421223bf9e15SSepherosa Ziehau 
421323bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
421423bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
421523bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
421623bf9e15SSepherosa Ziehau 		if (sched) {
421723bf9e15SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
421823bf9e15SSepherosa Ziehau 			    &txr->hn_tx_task);
421923bf9e15SSepherosa Ziehau 		}
422023bf9e15SSepherosa Ziehau 	} else {
422123bf9e15SSepherosa Ziehau do_sched:
422223bf9e15SSepherosa Ziehau 		/*
422323bf9e15SSepherosa Ziehau 		 * Release the OACTIVE earlier, with the hope, that
422423bf9e15SSepherosa Ziehau 		 * others could catch up.  The task will clear the
422523bf9e15SSepherosa Ziehau 		 * flag again with the hn_tx_lock to avoid possible
422623bf9e15SSepherosa Ziehau 		 * races.
422723bf9e15SSepherosa Ziehau 		 */
422823bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
422923bf9e15SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
423023bf9e15SSepherosa Ziehau 	}
423123bf9e15SSepherosa Ziehau }
423223bf9e15SSepherosa Ziehau 
423323bf9e15SSepherosa Ziehau #endif	/* HN_IFSTART_SUPPORT */
423423bf9e15SSepherosa Ziehau 
423515516c77SSepherosa Ziehau static int
423615516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len)
423715516c77SSepherosa Ziehau {
423815516c77SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
423915516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
424015516c77SSepherosa Ziehau 	struct mbuf *m_head;
4241dc13fee6SSepherosa Ziehau 	int sched = 0;
424215516c77SSepherosa Ziehau 
424315516c77SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
424423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
424515516c77SSepherosa Ziehau 	KASSERT(hn_use_if_start == 0,
424615516c77SSepherosa Ziehau 	    ("hn_xmit is called, when if_start is enabled"));
424723bf9e15SSepherosa Ziehau #endif
4248dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
424915516c77SSepherosa Ziehau 
425015516c77SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
4251dc13fee6SSepherosa Ziehau 		return (0);
425215516c77SSepherosa Ziehau 
425315516c77SSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive)
4254dc13fee6SSepherosa Ziehau 		return (0);
425515516c77SSepherosa Ziehau 
425615516c77SSepherosa Ziehau 	while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) {
425715516c77SSepherosa Ziehau 		struct hn_txdesc *txd;
425815516c77SSepherosa Ziehau 		int error;
425915516c77SSepherosa Ziehau 
426015516c77SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
426115516c77SSepherosa Ziehau 			/*
426215516c77SSepherosa Ziehau 			 * This sending could be time consuming; let callers
426315516c77SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
426415516c77SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
426515516c77SSepherosa Ziehau 			 */
426615516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
4267dc13fee6SSepherosa Ziehau 			sched = 1;
4268dc13fee6SSepherosa Ziehau 			break;
426915516c77SSepherosa Ziehau 		}
427015516c77SSepherosa Ziehau 
427115516c77SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
427215516c77SSepherosa Ziehau 		if (txd == NULL) {
427315516c77SSepherosa Ziehau 			txr->hn_no_txdescs++;
427415516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
427515516c77SSepherosa Ziehau 			txr->hn_oactive = 1;
427615516c77SSepherosa Ziehau 			break;
427715516c77SSepherosa Ziehau 		}
427815516c77SSepherosa Ziehau 
4279dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
428015516c77SSepherosa Ziehau 		if (error) {
428115516c77SSepherosa Ziehau 			/* Both txd and m_head are freed; discard */
4282dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
4283dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
428415516c77SSepherosa Ziehau 			drbr_advance(ifp, txr->hn_mbuf_br);
428515516c77SSepherosa Ziehau 			continue;
428615516c77SSepherosa Ziehau 		}
428715516c77SSepherosa Ziehau 
4288dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
4289dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
4290dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
4291dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
4292dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
429315516c77SSepherosa Ziehau 				if (__predict_false(error)) {
429415516c77SSepherosa Ziehau 					txr->hn_oactive = 1;
429515516c77SSepherosa Ziehau 					break;
429615516c77SSepherosa Ziehau 				}
4297dc13fee6SSepherosa Ziehau 			} else {
4298dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
4299dc13fee6SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
4300dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
4301dc13fee6SSepherosa Ziehau 					/* txd is freed, but m_head is not */
4302dc13fee6SSepherosa Ziehau 					drbr_putback(ifp, txr->hn_mbuf_br,
4303dc13fee6SSepherosa Ziehau 					    m_head);
4304dc13fee6SSepherosa Ziehau 					txr->hn_oactive = 1;
4305dc13fee6SSepherosa Ziehau 					break;
4306dc13fee6SSepherosa Ziehau 				}
4307dc13fee6SSepherosa Ziehau 			}
4308dc13fee6SSepherosa Ziehau 		}
4309dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
4310dc13fee6SSepherosa Ziehau 		else {
4311dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
4312dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
4313dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
4314dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
4315dc13fee6SSepherosa Ziehau 		}
4316dc13fee6SSepherosa Ziehau #endif
431715516c77SSepherosa Ziehau 
431815516c77SSepherosa Ziehau 		/* Sent */
431915516c77SSepherosa Ziehau 		drbr_advance(ifp, txr->hn_mbuf_br);
432015516c77SSepherosa Ziehau 	}
4321dc13fee6SSepherosa Ziehau 
4322dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
4323dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
4324dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
4325dc13fee6SSepherosa Ziehau 	return (sched);
432615516c77SSepherosa Ziehau }
432715516c77SSepherosa Ziehau 
432815516c77SSepherosa Ziehau static int
432915516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m)
433015516c77SSepherosa Ziehau {
433115516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
433215516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
433315516c77SSepherosa Ziehau 	int error, idx = 0;
433415516c77SSepherosa Ziehau 
4335edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
4336edd3f315SSepherosa Ziehau 	/*
4337edd3f315SSepherosa Ziehau 	 * Perform TSO packet header fixup now, since the TSO
4338edd3f315SSepherosa Ziehau 	 * packet header should be cache-hot.
4339edd3f315SSepherosa Ziehau 	 */
4340edd3f315SSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
4341edd3f315SSepherosa Ziehau 		m = hn_tso_fixup(m);
4342edd3f315SSepherosa Ziehau 		if (__predict_false(m == NULL)) {
4343edd3f315SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
4344edd3f315SSepherosa Ziehau 			return EIO;
4345edd3f315SSepherosa Ziehau 		}
4346edd3f315SSepherosa Ziehau 	}
4347edd3f315SSepherosa Ziehau #endif
4348edd3f315SSepherosa Ziehau 
434915516c77SSepherosa Ziehau 	/*
435015516c77SSepherosa Ziehau 	 * Select the TX ring based on flowid
435115516c77SSepherosa Ziehau 	 */
435234d68912SSepherosa Ziehau 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
435334d68912SSepherosa Ziehau #ifdef RSS
435434d68912SSepherosa Ziehau 		uint32_t bid;
435534d68912SSepherosa Ziehau 
435634d68912SSepherosa Ziehau 		if (rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m),
435734d68912SSepherosa Ziehau 		    &bid) == 0)
435834d68912SSepherosa Ziehau 			idx = bid % sc->hn_tx_ring_inuse;
435934d68912SSepherosa Ziehau 		else
436034d68912SSepherosa Ziehau #endif
436115516c77SSepherosa Ziehau 			idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse;
436234d68912SSepherosa Ziehau 	}
436315516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[idx];
436415516c77SSepherosa Ziehau 
436515516c77SSepherosa Ziehau 	error = drbr_enqueue(ifp, txr->hn_mbuf_br, m);
436615516c77SSepherosa Ziehau 	if (error) {
436715516c77SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
436815516c77SSepherosa Ziehau 		return error;
436915516c77SSepherosa Ziehau 	}
437015516c77SSepherosa Ziehau 
437115516c77SSepherosa Ziehau 	if (txr->hn_oactive)
437215516c77SSepherosa Ziehau 		return 0;
437315516c77SSepherosa Ziehau 
437415516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
437515516c77SSepherosa Ziehau 		goto do_sched;
437615516c77SSepherosa Ziehau 
437715516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
437815516c77SSepherosa Ziehau 		int sched;
437915516c77SSepherosa Ziehau 
438015516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
438115516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
438215516c77SSepherosa Ziehau 		if (!sched)
438315516c77SSepherosa Ziehau 			return 0;
438415516c77SSepherosa Ziehau 	}
438515516c77SSepherosa Ziehau do_sched:
438615516c77SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
438715516c77SSepherosa Ziehau 	return 0;
438815516c77SSepherosa Ziehau }
438915516c77SSepherosa Ziehau 
439015516c77SSepherosa Ziehau static void
439115516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr)
439215516c77SSepherosa Ziehau {
439315516c77SSepherosa Ziehau 	struct mbuf *m;
439415516c77SSepherosa Ziehau 
439515516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
439615516c77SSepherosa Ziehau 	while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL)
439715516c77SSepherosa Ziehau 		m_freem(m);
439815516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
439915516c77SSepherosa Ziehau }
440015516c77SSepherosa Ziehau 
440115516c77SSepherosa Ziehau static void
440215516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp)
440315516c77SSepherosa Ziehau {
440415516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
440515516c77SSepherosa Ziehau 	int i;
440615516c77SSepherosa Ziehau 
440715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
440815516c77SSepherosa Ziehau 		hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
440915516c77SSepherosa Ziehau 	if_qflush(ifp);
441015516c77SSepherosa Ziehau }
441115516c77SSepherosa Ziehau 
441215516c77SSepherosa Ziehau static void
441315516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr)
441415516c77SSepherosa Ziehau {
441515516c77SSepherosa Ziehau 
441615516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
441715516c77SSepherosa Ziehau 		goto do_sched;
441815516c77SSepherosa Ziehau 
441915516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
442015516c77SSepherosa Ziehau 		int sched;
442115516c77SSepherosa Ziehau 
442215516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
442315516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
442415516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
442515516c77SSepherosa Ziehau 		if (sched) {
442615516c77SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
442715516c77SSepherosa Ziehau 			    &txr->hn_tx_task);
442815516c77SSepherosa Ziehau 		}
442915516c77SSepherosa Ziehau 	} else {
443015516c77SSepherosa Ziehau do_sched:
443115516c77SSepherosa Ziehau 		/*
443215516c77SSepherosa Ziehau 		 * Release the oactive earlier, with the hope, that
443315516c77SSepherosa Ziehau 		 * others could catch up.  The task will clear the
443415516c77SSepherosa Ziehau 		 * oactive again with the hn_tx_lock to avoid possible
443515516c77SSepherosa Ziehau 		 * races.
443615516c77SSepherosa Ziehau 		 */
443715516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
443815516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
443915516c77SSepherosa Ziehau 	}
444015516c77SSepherosa Ziehau }
444115516c77SSepherosa Ziehau 
444215516c77SSepherosa Ziehau static void
444315516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused)
444415516c77SSepherosa Ziehau {
444515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
444615516c77SSepherosa Ziehau 
444715516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
444815516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
444915516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
445015516c77SSepherosa Ziehau }
445115516c77SSepherosa Ziehau 
445215516c77SSepherosa Ziehau static void
445315516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused)
445415516c77SSepherosa Ziehau {
445515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
445615516c77SSepherosa Ziehau 
445715516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
445815516c77SSepherosa Ziehau 	txr->hn_oactive = 0;
445915516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
446015516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
446115516c77SSepherosa Ziehau }
446215516c77SSepherosa Ziehau 
446315516c77SSepherosa Ziehau static int
446415516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan)
446515516c77SSepherosa Ziehau {
446615516c77SSepherosa Ziehau 	struct vmbus_chan_br cbr;
446715516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
446815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = NULL;
446915516c77SSepherosa Ziehau 	int idx, error;
447015516c77SSepherosa Ziehau 
447115516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
447215516c77SSepherosa Ziehau 
447315516c77SSepherosa Ziehau 	/*
447415516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
447515516c77SSepherosa Ziehau 	 */
447615516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
447715516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
447815516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
447915516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
448015516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0,
448115516c77SSepherosa Ziehau 	    ("RX ring %d already attached", idx));
448215516c77SSepherosa Ziehau 	rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED;
44833ab0fea1SDexuan Cui 	rxr->hn_chan = chan;
448415516c77SSepherosa Ziehau 
448515516c77SSepherosa Ziehau 	if (bootverbose) {
448615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n",
448715516c77SSepherosa Ziehau 		    idx, vmbus_chan_id(chan));
448815516c77SSepherosa Ziehau 	}
448915516c77SSepherosa Ziehau 
449015516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
449115516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[idx];
449215516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0,
449315516c77SSepherosa Ziehau 		    ("TX ring %d already attached", idx));
449415516c77SSepherosa Ziehau 		txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED;
449515516c77SSepherosa Ziehau 
449615516c77SSepherosa Ziehau 		txr->hn_chan = chan;
449715516c77SSepherosa Ziehau 		if (bootverbose) {
449815516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n",
449915516c77SSepherosa Ziehau 			    idx, vmbus_chan_id(chan));
450015516c77SSepherosa Ziehau 		}
450115516c77SSepherosa Ziehau 	}
450215516c77SSepherosa Ziehau 
450315516c77SSepherosa Ziehau 	/* Bind this channel to a proper CPU. */
45040e11868dSSepherosa Ziehau 	vmbus_chan_cpu_set(chan, HN_RING_IDX2CPU(sc, idx));
450515516c77SSepherosa Ziehau 
450615516c77SSepherosa Ziehau 	/*
450715516c77SSepherosa Ziehau 	 * Open this channel
450815516c77SSepherosa Ziehau 	 */
450915516c77SSepherosa Ziehau 	cbr.cbr = rxr->hn_br;
451015516c77SSepherosa Ziehau 	cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr;
451115516c77SSepherosa Ziehau 	cbr.cbr_txsz = HN_TXBR_SIZE;
451215516c77SSepherosa Ziehau 	cbr.cbr_rxsz = HN_RXBR_SIZE;
451315516c77SSepherosa Ziehau 	error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr);
451415516c77SSepherosa Ziehau 	if (error) {
451571e8ac56SSepherosa Ziehau 		if (error == EISCONN) {
451671e8ac56SSepherosa Ziehau 			if_printf(sc->hn_ifp, "bufring is connected after "
451771e8ac56SSepherosa Ziehau 			    "chan%u open failure\n", vmbus_chan_id(chan));
451871e8ac56SSepherosa Ziehau 			rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
451971e8ac56SSepherosa Ziehau 		} else {
452015516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "open chan%u failed: %d\n",
452115516c77SSepherosa Ziehau 			    vmbus_chan_id(chan), error);
452271e8ac56SSepherosa Ziehau 		}
452315516c77SSepherosa Ziehau 	}
452415516c77SSepherosa Ziehau 	return (error);
452515516c77SSepherosa Ziehau }
452615516c77SSepherosa Ziehau 
452715516c77SSepherosa Ziehau static void
452815516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan)
452915516c77SSepherosa Ziehau {
453015516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
45312494d735SSepherosa Ziehau 	int idx, error;
453215516c77SSepherosa Ziehau 
453315516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
453415516c77SSepherosa Ziehau 
453515516c77SSepherosa Ziehau 	/*
453615516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
453715516c77SSepherosa Ziehau 	 */
453815516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
453915516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
454015516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
454115516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
454215516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED),
454315516c77SSepherosa Ziehau 	    ("RX ring %d is not attached", idx));
454415516c77SSepherosa Ziehau 	rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
454515516c77SSepherosa Ziehau 
454615516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
454715516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[idx];
454815516c77SSepherosa Ziehau 
454915516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED),
455015516c77SSepherosa Ziehau 		    ("TX ring %d is not attached attached", idx));
455115516c77SSepherosa Ziehau 		txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
455215516c77SSepherosa Ziehau 	}
455315516c77SSepherosa Ziehau 
455415516c77SSepherosa Ziehau 	/*
455515516c77SSepherosa Ziehau 	 * Close this channel.
455615516c77SSepherosa Ziehau 	 *
455715516c77SSepherosa Ziehau 	 * NOTE:
455815516c77SSepherosa Ziehau 	 * Channel closing does _not_ destroy the target channel.
455915516c77SSepherosa Ziehau 	 */
45602494d735SSepherosa Ziehau 	error = vmbus_chan_close_direct(chan);
45612494d735SSepherosa Ziehau 	if (error == EISCONN) {
4562aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u bufring is connected "
4563aa1a2adcSSepherosa Ziehau 		    "after being closed\n", vmbus_chan_id(chan));
45642494d735SSepherosa Ziehau 		rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
45652494d735SSepherosa Ziehau 	} else if (error) {
4566aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u close failed: %d\n",
4567aa1a2adcSSepherosa Ziehau 		    vmbus_chan_id(chan), error);
45682494d735SSepherosa Ziehau 	}
456915516c77SSepherosa Ziehau }
457015516c77SSepherosa Ziehau 
457115516c77SSepherosa Ziehau static int
457215516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc)
457315516c77SSepherosa Ziehau {
457415516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
457515516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
457615516c77SSepherosa Ziehau 	int i, error = 0;
457715516c77SSepherosa Ziehau 
457871e8ac56SSepherosa Ziehau 	KASSERT(subchan_cnt > 0, ("no sub-channels"));
457915516c77SSepherosa Ziehau 
458015516c77SSepherosa Ziehau 	/* Attach the sub-channels. */
458115516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
458215516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i) {
458371e8ac56SSepherosa Ziehau 		int error1;
458471e8ac56SSepherosa Ziehau 
458571e8ac56SSepherosa Ziehau 		error1 = hn_chan_attach(sc, subchans[i]);
458671e8ac56SSepherosa Ziehau 		if (error1) {
458771e8ac56SSepherosa Ziehau 			error = error1;
458871e8ac56SSepherosa Ziehau 			/* Move on; all channels will be detached later. */
458971e8ac56SSepherosa Ziehau 		}
459015516c77SSepherosa Ziehau 	}
459115516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
459215516c77SSepherosa Ziehau 
459315516c77SSepherosa Ziehau 	if (error) {
459415516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error);
459515516c77SSepherosa Ziehau 	} else {
459615516c77SSepherosa Ziehau 		if (bootverbose) {
459715516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "%d sub-channels attached\n",
459815516c77SSepherosa Ziehau 			    subchan_cnt);
459915516c77SSepherosa Ziehau 		}
460015516c77SSepherosa Ziehau 	}
460115516c77SSepherosa Ziehau 	return (error);
460215516c77SSepherosa Ziehau }
460315516c77SSepherosa Ziehau 
460415516c77SSepherosa Ziehau static void
460515516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc)
460615516c77SSepherosa Ziehau {
460715516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
460815516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
460915516c77SSepherosa Ziehau 	int i;
461015516c77SSepherosa Ziehau 
461115516c77SSepherosa Ziehau 	if (subchan_cnt == 0)
461215516c77SSepherosa Ziehau 		goto back;
461315516c77SSepherosa Ziehau 
461415516c77SSepherosa Ziehau 	/* Detach the sub-channels. */
461515516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
461615516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i)
461715516c77SSepherosa Ziehau 		hn_chan_detach(sc, subchans[i]);
461815516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
461915516c77SSepherosa Ziehau 
462015516c77SSepherosa Ziehau back:
462115516c77SSepherosa Ziehau 	/*
462215516c77SSepherosa Ziehau 	 * Detach the primary channel, _after_ all sub-channels
462315516c77SSepherosa Ziehau 	 * are detached.
462415516c77SSepherosa Ziehau 	 */
462515516c77SSepherosa Ziehau 	hn_chan_detach(sc, sc->hn_prichan);
462615516c77SSepherosa Ziehau 
462715516c77SSepherosa Ziehau 	/* Wait for sub-channels to be destroyed, if any. */
462815516c77SSepherosa Ziehau 	vmbus_subchan_drain(sc->hn_prichan);
462915516c77SSepherosa Ziehau 
463015516c77SSepherosa Ziehau #ifdef INVARIANTS
463115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
463215516c77SSepherosa Ziehau 		KASSERT((sc->hn_rx_ring[i].hn_rx_flags &
463315516c77SSepherosa Ziehau 		    HN_RX_FLAG_ATTACHED) == 0,
463415516c77SSepherosa Ziehau 		    ("%dth RX ring is still attached", i));
463515516c77SSepherosa Ziehau 	}
463615516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
463715516c77SSepherosa Ziehau 		KASSERT((sc->hn_tx_ring[i].hn_tx_flags &
463815516c77SSepherosa Ziehau 		    HN_TX_FLAG_ATTACHED) == 0,
463915516c77SSepherosa Ziehau 		    ("%dth TX ring is still attached", i));
464015516c77SSepherosa Ziehau 	}
464115516c77SSepherosa Ziehau #endif
464215516c77SSepherosa Ziehau }
464315516c77SSepherosa Ziehau 
464415516c77SSepherosa Ziehau static int
464515516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch)
464615516c77SSepherosa Ziehau {
464715516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
464815516c77SSepherosa Ziehau 	int nchan, rxr_cnt, error;
464915516c77SSepherosa Ziehau 
465015516c77SSepherosa Ziehau 	nchan = *nsubch + 1;
465115516c77SSepherosa Ziehau 	if (nchan == 1) {
465215516c77SSepherosa Ziehau 		/*
465315516c77SSepherosa Ziehau 		 * Multiple RX/TX rings are not requested.
465415516c77SSepherosa Ziehau 		 */
465515516c77SSepherosa Ziehau 		*nsubch = 0;
465615516c77SSepherosa Ziehau 		return (0);
465715516c77SSepherosa Ziehau 	}
465815516c77SSepherosa Ziehau 
465915516c77SSepherosa Ziehau 	/*
466015516c77SSepherosa Ziehau 	 * Query RSS capabilities, e.g. # of RX rings, and # of indirect
466115516c77SSepherosa Ziehau 	 * table entries.
466215516c77SSepherosa Ziehau 	 */
466315516c77SSepherosa Ziehau 	error = hn_rndis_query_rsscaps(sc, &rxr_cnt);
466415516c77SSepherosa Ziehau 	if (error) {
466515516c77SSepherosa Ziehau 		/* No RSS; this is benign. */
466615516c77SSepherosa Ziehau 		*nsubch = 0;
466715516c77SSepherosa Ziehau 		return (0);
466815516c77SSepherosa Ziehau 	}
466915516c77SSepherosa Ziehau 	if (bootverbose) {
467015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
467115516c77SSepherosa Ziehau 		    rxr_cnt, nchan);
467215516c77SSepherosa Ziehau 	}
467315516c77SSepherosa Ziehau 
467415516c77SSepherosa Ziehau 	if (nchan > rxr_cnt)
467515516c77SSepherosa Ziehau 		nchan = rxr_cnt;
467615516c77SSepherosa Ziehau 	if (nchan == 1) {
467715516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n");
467815516c77SSepherosa Ziehau 		*nsubch = 0;
467915516c77SSepherosa Ziehau 		return (0);
468015516c77SSepherosa Ziehau 	}
468115516c77SSepherosa Ziehau 
468215516c77SSepherosa Ziehau 	/*
468315516c77SSepherosa Ziehau 	 * Allocate sub-channels from NVS.
468415516c77SSepherosa Ziehau 	 */
468515516c77SSepherosa Ziehau 	*nsubch = nchan - 1;
468615516c77SSepherosa Ziehau 	error = hn_nvs_alloc_subchans(sc, nsubch);
468715516c77SSepherosa Ziehau 	if (error || *nsubch == 0) {
468815516c77SSepherosa Ziehau 		/* Failed to allocate sub-channels. */
468915516c77SSepherosa Ziehau 		*nsubch = 0;
469015516c77SSepherosa Ziehau 		return (0);
469115516c77SSepherosa Ziehau 	}
469215516c77SSepherosa Ziehau 
469315516c77SSepherosa Ziehau 	/*
469415516c77SSepherosa Ziehau 	 * Wait for all sub-channels to become ready before moving on.
469515516c77SSepherosa Ziehau 	 */
469615516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch);
469715516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, *nsubch);
469815516c77SSepherosa Ziehau 	return (0);
469915516c77SSepherosa Ziehau }
470015516c77SSepherosa Ziehau 
47012494d735SSepherosa Ziehau static bool
47022494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc)
47032494d735SSepherosa Ziehau {
47042494d735SSepherosa Ziehau 	int i;
47052494d735SSepherosa Ziehau 
47062494d735SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_ERRORS)
47072494d735SSepherosa Ziehau 		return (false);
47082494d735SSepherosa Ziehau 
47092494d735SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
47102494d735SSepherosa Ziehau 		const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
47112494d735SSepherosa Ziehau 
47122494d735SSepherosa Ziehau 		if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF)
47132494d735SSepherosa Ziehau 			return (false);
47142494d735SSepherosa Ziehau 	}
47152494d735SSepherosa Ziehau 	return (true);
47162494d735SSepherosa Ziehau }
47172494d735SSepherosa Ziehau 
471815516c77SSepherosa Ziehau static int
471915516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu)
472015516c77SSepherosa Ziehau {
472171e8ac56SSepherosa Ziehau #define ATTACHED_NVS		0x0002
472271e8ac56SSepherosa Ziehau #define ATTACHED_RNDIS		0x0004
472371e8ac56SSepherosa Ziehau 
472415516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
472515516c77SSepherosa Ziehau 	int error, nsubch, nchan, i;
472671e8ac56SSepherosa Ziehau 	uint32_t old_caps, attached = 0;
472715516c77SSepherosa Ziehau 
472815516c77SSepherosa Ziehau 	KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0,
472915516c77SSepherosa Ziehau 	    ("synthetic parts were attached"));
473015516c77SSepherosa Ziehau 
47312494d735SSepherosa Ziehau 	if (!hn_synth_attachable(sc))
47322494d735SSepherosa Ziehau 		return (ENXIO);
47332494d735SSepherosa Ziehau 
473415516c77SSepherosa Ziehau 	/* Save capabilities for later verification. */
473515516c77SSepherosa Ziehau 	old_caps = sc->hn_caps;
473615516c77SSepherosa Ziehau 	sc->hn_caps = 0;
473715516c77SSepherosa Ziehau 
473815516c77SSepherosa Ziehau 	/* Clear RSS stuffs. */
473915516c77SSepherosa Ziehau 	sc->hn_rss_ind_size = 0;
474015516c77SSepherosa Ziehau 	sc->hn_rss_hash = 0;
474115516c77SSepherosa Ziehau 
474215516c77SSepherosa Ziehau 	/*
474315516c77SSepherosa Ziehau 	 * Attach the primary channel _before_ attaching NVS and RNDIS.
474415516c77SSepherosa Ziehau 	 */
474515516c77SSepherosa Ziehau 	error = hn_chan_attach(sc, sc->hn_prichan);
474615516c77SSepherosa Ziehau 	if (error)
474771e8ac56SSepherosa Ziehau 		goto failed;
474815516c77SSepherosa Ziehau 
474915516c77SSepherosa Ziehau 	/*
475015516c77SSepherosa Ziehau 	 * Attach NVS.
475115516c77SSepherosa Ziehau 	 */
475215516c77SSepherosa Ziehau 	error = hn_nvs_attach(sc, mtu);
475315516c77SSepherosa Ziehau 	if (error)
475471e8ac56SSepherosa Ziehau 		goto failed;
475571e8ac56SSepherosa Ziehau 	attached |= ATTACHED_NVS;
475615516c77SSepherosa Ziehau 
475715516c77SSepherosa Ziehau 	/*
475815516c77SSepherosa Ziehau 	 * Attach RNDIS _after_ NVS is attached.
475915516c77SSepherosa Ziehau 	 */
476015516c77SSepherosa Ziehau 	error = hn_rndis_attach(sc, mtu);
476115516c77SSepherosa Ziehau 	if (error)
476271e8ac56SSepherosa Ziehau 		goto failed;
476371e8ac56SSepherosa Ziehau 	attached |= ATTACHED_RNDIS;
476415516c77SSepherosa Ziehau 
476515516c77SSepherosa Ziehau 	/*
476615516c77SSepherosa Ziehau 	 * Make sure capabilities are not changed.
476715516c77SSepherosa Ziehau 	 */
476815516c77SSepherosa Ziehau 	if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) {
476915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n",
477015516c77SSepherosa Ziehau 		    old_caps, sc->hn_caps);
477171e8ac56SSepherosa Ziehau 		error = ENXIO;
477271e8ac56SSepherosa Ziehau 		goto failed;
477315516c77SSepherosa Ziehau 	}
477415516c77SSepherosa Ziehau 
477515516c77SSepherosa Ziehau 	/*
477615516c77SSepherosa Ziehau 	 * Allocate sub-channels for multi-TX/RX rings.
477715516c77SSepherosa Ziehau 	 *
477815516c77SSepherosa Ziehau 	 * NOTE:
477915516c77SSepherosa Ziehau 	 * The # of RX rings that can be used is equivalent to the # of
478015516c77SSepherosa Ziehau 	 * channels to be requested.
478115516c77SSepherosa Ziehau 	 */
478215516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_cnt - 1;
478315516c77SSepherosa Ziehau 	error = hn_synth_alloc_subchans(sc, &nsubch);
478415516c77SSepherosa Ziehau 	if (error)
478571e8ac56SSepherosa Ziehau 		goto failed;
478671e8ac56SSepherosa Ziehau 	/* NOTE: _Full_ synthetic parts detach is required now. */
478771e8ac56SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED;
478815516c77SSepherosa Ziehau 
478971e8ac56SSepherosa Ziehau 	/*
479071e8ac56SSepherosa Ziehau 	 * Set the # of TX/RX rings that could be used according to
479171e8ac56SSepherosa Ziehau 	 * the # of channels that NVS offered.
479271e8ac56SSepherosa Ziehau 	 */
479315516c77SSepherosa Ziehau 	nchan = nsubch + 1;
479471e8ac56SSepherosa Ziehau 	hn_set_ring_inuse(sc, nchan);
479515516c77SSepherosa Ziehau 	if (nchan == 1) {
479615516c77SSepherosa Ziehau 		/* Only the primary channel can be used; done */
479715516c77SSepherosa Ziehau 		goto back;
479815516c77SSepherosa Ziehau 	}
479915516c77SSepherosa Ziehau 
480015516c77SSepherosa Ziehau 	/*
480171e8ac56SSepherosa Ziehau 	 * Attach the sub-channels.
4802afd4971bSSepherosa Ziehau 	 *
4803afd4971bSSepherosa Ziehau 	 * NOTE: hn_set_ring_inuse() _must_ have been called.
480415516c77SSepherosa Ziehau 	 */
480571e8ac56SSepherosa Ziehau 	error = hn_attach_subchans(sc);
480671e8ac56SSepherosa Ziehau 	if (error)
480771e8ac56SSepherosa Ziehau 		goto failed;
480815516c77SSepherosa Ziehau 
480971e8ac56SSepherosa Ziehau 	/*
481071e8ac56SSepherosa Ziehau 	 * Configure RSS key and indirect table _after_ all sub-channels
481171e8ac56SSepherosa Ziehau 	 * are attached.
481271e8ac56SSepherosa Ziehau 	 */
481315516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) {
481415516c77SSepherosa Ziehau 		/*
481515516c77SSepherosa Ziehau 		 * RSS key is not set yet; set it to the default RSS key.
481615516c77SSepherosa Ziehau 		 */
481715516c77SSepherosa Ziehau 		if (bootverbose)
481815516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS key\n");
481934d68912SSepherosa Ziehau #ifdef RSS
482034d68912SSepherosa Ziehau 		rss_getkey(rss->rss_key);
482134d68912SSepherosa Ziehau #else
482215516c77SSepherosa Ziehau 		memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key));
482334d68912SSepherosa Ziehau #endif
482415516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
482515516c77SSepherosa Ziehau 	}
482615516c77SSepherosa Ziehau 
482715516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) {
482815516c77SSepherosa Ziehau 		/*
482915516c77SSepherosa Ziehau 		 * RSS indirect table is not set yet; set it up in round-
483015516c77SSepherosa Ziehau 		 * robin fashion.
483115516c77SSepherosa Ziehau 		 */
483215516c77SSepherosa Ziehau 		if (bootverbose) {
483315516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS indirect "
483415516c77SSepherosa Ziehau 			    "table\n");
483515516c77SSepherosa Ziehau 		}
483634d68912SSepherosa Ziehau 		for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
483734d68912SSepherosa Ziehau 			uint32_t subidx;
483834d68912SSepherosa Ziehau 
483934d68912SSepherosa Ziehau #ifdef RSS
484034d68912SSepherosa Ziehau 			subidx = rss_get_indirection_to_bucket(i);
484134d68912SSepherosa Ziehau #else
484234d68912SSepherosa Ziehau 			subidx = i;
484334d68912SSepherosa Ziehau #endif
484434d68912SSepherosa Ziehau 			rss->rss_ind[i] = subidx % nchan;
484534d68912SSepherosa Ziehau 		}
484615516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSIND;
484715516c77SSepherosa Ziehau 	} else {
484815516c77SSepherosa Ziehau 		/*
484915516c77SSepherosa Ziehau 		 * # of usable channels may be changed, so we have to
485015516c77SSepherosa Ziehau 		 * make sure that all entries in RSS indirect table
485115516c77SSepherosa Ziehau 		 * are valid.
4852afd4971bSSepherosa Ziehau 		 *
4853afd4971bSSepherosa Ziehau 		 * NOTE: hn_set_ring_inuse() _must_ have been called.
485415516c77SSepherosa Ziehau 		 */
4855afd4971bSSepherosa Ziehau 		hn_rss_ind_fixup(sc);
485615516c77SSepherosa Ziehau 	}
485715516c77SSepherosa Ziehau 
485815516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
485915516c77SSepherosa Ziehau 	if (error)
486071e8ac56SSepherosa Ziehau 		goto failed;
486171e8ac56SSepherosa Ziehau back:
4862dc13fee6SSepherosa Ziehau 	/*
4863dc13fee6SSepherosa Ziehau 	 * Fixup transmission aggregation setup.
4864dc13fee6SSepherosa Ziehau 	 */
4865dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
486615516c77SSepherosa Ziehau 	return (0);
486771e8ac56SSepherosa Ziehau 
486871e8ac56SSepherosa Ziehau failed:
486971e8ac56SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
487071e8ac56SSepherosa Ziehau 		hn_synth_detach(sc);
487171e8ac56SSepherosa Ziehau 	} else {
487271e8ac56SSepherosa Ziehau 		if (attached & ATTACHED_RNDIS)
487371e8ac56SSepherosa Ziehau 			hn_rndis_detach(sc);
487471e8ac56SSepherosa Ziehau 		if (attached & ATTACHED_NVS)
487571e8ac56SSepherosa Ziehau 			hn_nvs_detach(sc);
487671e8ac56SSepherosa Ziehau 		hn_chan_detach(sc, sc->hn_prichan);
487771e8ac56SSepherosa Ziehau 		/* Restore old capabilities. */
487871e8ac56SSepherosa Ziehau 		sc->hn_caps = old_caps;
487971e8ac56SSepherosa Ziehau 	}
488071e8ac56SSepherosa Ziehau 	return (error);
488171e8ac56SSepherosa Ziehau 
488271e8ac56SSepherosa Ziehau #undef ATTACHED_RNDIS
488371e8ac56SSepherosa Ziehau #undef ATTACHED_NVS
488415516c77SSepherosa Ziehau }
488515516c77SSepherosa Ziehau 
488615516c77SSepherosa Ziehau /*
488715516c77SSepherosa Ziehau  * NOTE:
488815516c77SSepherosa Ziehau  * The interface must have been suspended though hn_suspend(), before
488915516c77SSepherosa Ziehau  * this function get called.
489015516c77SSepherosa Ziehau  */
489115516c77SSepherosa Ziehau static void
489215516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc)
489315516c77SSepherosa Ziehau {
489415516c77SSepherosa Ziehau 
489515516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
489615516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
489715516c77SSepherosa Ziehau 
489815516c77SSepherosa Ziehau 	/* Detach the RNDIS first. */
489915516c77SSepherosa Ziehau 	hn_rndis_detach(sc);
490015516c77SSepherosa Ziehau 
490115516c77SSepherosa Ziehau 	/* Detach NVS. */
490215516c77SSepherosa Ziehau 	hn_nvs_detach(sc);
490315516c77SSepherosa Ziehau 
490415516c77SSepherosa Ziehau 	/* Detach all of the channels. */
490515516c77SSepherosa Ziehau 	hn_detach_allchans(sc);
490615516c77SSepherosa Ziehau 
490715516c77SSepherosa Ziehau 	sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED;
490815516c77SSepherosa Ziehau }
490915516c77SSepherosa Ziehau 
491015516c77SSepherosa Ziehau static void
491115516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt)
491215516c77SSepherosa Ziehau {
491315516c77SSepherosa Ziehau 	KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt,
491415516c77SSepherosa Ziehau 	    ("invalid ring count %d", ring_cnt));
491515516c77SSepherosa Ziehau 
491615516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt > ring_cnt)
491715516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = ring_cnt;
491815516c77SSepherosa Ziehau 	else
491915516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
492015516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = ring_cnt;
492115516c77SSepherosa Ziehau 
492234d68912SSepherosa Ziehau #ifdef RSS
492334d68912SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse != rss_getnumbuckets()) {
492434d68912SSepherosa Ziehau 		if_printf(sc->hn_ifp, "# of RX rings (%d) does not match "
492534d68912SSepherosa Ziehau 		    "# of RSS buckets (%d)\n", sc->hn_rx_ring_inuse,
492634d68912SSepherosa Ziehau 		    rss_getnumbuckets());
492734d68912SSepherosa Ziehau 	}
492834d68912SSepherosa Ziehau #endif
492934d68912SSepherosa Ziehau 
493015516c77SSepherosa Ziehau 	if (bootverbose) {
493115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n",
493215516c77SSepherosa Ziehau 		    sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
493315516c77SSepherosa Ziehau 	}
493415516c77SSepherosa Ziehau }
493515516c77SSepherosa Ziehau 
493615516c77SSepherosa Ziehau static void
493725641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan)
493815516c77SSepherosa Ziehau {
493915516c77SSepherosa Ziehau 
494025641fc7SSepherosa Ziehau 	/*
494125641fc7SSepherosa Ziehau 	 * NOTE:
494225641fc7SSepherosa Ziehau 	 * The TX bufring will not be drained by the hypervisor,
494325641fc7SSepherosa Ziehau 	 * if the primary channel is revoked.
494425641fc7SSepherosa Ziehau 	 */
494525641fc7SSepherosa Ziehau 	while (!vmbus_chan_rx_empty(chan) ||
494625641fc7SSepherosa Ziehau 	    (!vmbus_chan_is_revoked(sc->hn_prichan) &&
494725641fc7SSepherosa Ziehau 	     !vmbus_chan_tx_empty(chan)))
494815516c77SSepherosa Ziehau 		pause("waitch", 1);
494915516c77SSepherosa Ziehau 	vmbus_chan_intr_drain(chan);
495015516c77SSepherosa Ziehau }
495115516c77SSepherosa Ziehau 
495215516c77SSepherosa Ziehau static void
495315516c77SSepherosa Ziehau hn_suspend_data(struct hn_softc *sc)
495415516c77SSepherosa Ziehau {
495515516c77SSepherosa Ziehau 	struct vmbus_channel **subch = NULL;
495625641fc7SSepherosa Ziehau 	struct hn_tx_ring *txr;
495715516c77SSepherosa Ziehau 	int i, nsubch;
495815516c77SSepherosa Ziehau 
495915516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
496015516c77SSepherosa Ziehau 
496115516c77SSepherosa Ziehau 	/*
496215516c77SSepherosa Ziehau 	 * Suspend TX.
496315516c77SSepherosa Ziehau 	 */
496415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
496525641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
496615516c77SSepherosa Ziehau 
496715516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
496815516c77SSepherosa Ziehau 		txr->hn_suspended = 1;
496915516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
497015516c77SSepherosa Ziehau 		/* No one is able send more packets now. */
497115516c77SSepherosa Ziehau 
497225641fc7SSepherosa Ziehau 		/*
497325641fc7SSepherosa Ziehau 		 * Wait for all pending sends to finish.
497425641fc7SSepherosa Ziehau 		 *
497525641fc7SSepherosa Ziehau 		 * NOTE:
497625641fc7SSepherosa Ziehau 		 * We will _not_ receive all pending send-done, if the
497725641fc7SSepherosa Ziehau 		 * primary channel is revoked.
497825641fc7SSepherosa Ziehau 		 */
497925641fc7SSepherosa Ziehau 		while (hn_tx_ring_pending(txr) &&
498025641fc7SSepherosa Ziehau 		    !vmbus_chan_is_revoked(sc->hn_prichan))
498115516c77SSepherosa Ziehau 			pause("hnwtx", 1 /* 1 tick */);
498215516c77SSepherosa Ziehau 	}
498315516c77SSepherosa Ziehau 
498415516c77SSepherosa Ziehau 	/*
498515516c77SSepherosa Ziehau 	 * Disable RX by clearing RX filter.
498615516c77SSepherosa Ziehau 	 */
4987f1b0a43fSSepherosa Ziehau 	hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE);
498815516c77SSepherosa Ziehau 
498915516c77SSepherosa Ziehau 	/*
499015516c77SSepherosa Ziehau 	 * Give RNDIS enough time to flush all pending data packets.
499115516c77SSepherosa Ziehau 	 */
499215516c77SSepherosa Ziehau 	pause("waitrx", (200 * hz) / 1000);
499315516c77SSepherosa Ziehau 
499415516c77SSepherosa Ziehau 	/*
499515516c77SSepherosa Ziehau 	 * Drain RX/TX bufrings and interrupts.
499615516c77SSepherosa Ziehau 	 */
499715516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_inuse - 1;
499815516c77SSepherosa Ziehau 	if (nsubch > 0)
499915516c77SSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
500015516c77SSepherosa Ziehau 
500115516c77SSepherosa Ziehau 	if (subch != NULL) {
500215516c77SSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
500325641fc7SSepherosa Ziehau 			hn_chan_drain(sc, subch[i]);
500415516c77SSepherosa Ziehau 	}
500525641fc7SSepherosa Ziehau 	hn_chan_drain(sc, sc->hn_prichan);
500615516c77SSepherosa Ziehau 
500715516c77SSepherosa Ziehau 	if (subch != NULL)
500815516c77SSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
500925641fc7SSepherosa Ziehau 
501025641fc7SSepherosa Ziehau 	/*
501125641fc7SSepherosa Ziehau 	 * Drain any pending TX tasks.
501225641fc7SSepherosa Ziehau 	 *
501325641fc7SSepherosa Ziehau 	 * NOTE:
501425641fc7SSepherosa Ziehau 	 * The above hn_chan_drain() can dispatch TX tasks, so the TX
501525641fc7SSepherosa Ziehau 	 * tasks will have to be drained _after_ the above hn_chan_drain()
501625641fc7SSepherosa Ziehau 	 * calls.
501725641fc7SSepherosa Ziehau 	 */
501825641fc7SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
501925641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
502025641fc7SSepherosa Ziehau 
502125641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task);
502225641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task);
502325641fc7SSepherosa Ziehau 	}
502415516c77SSepherosa Ziehau }
502515516c77SSepherosa Ziehau 
502615516c77SSepherosa Ziehau static void
502715516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused)
502815516c77SSepherosa Ziehau {
502915516c77SSepherosa Ziehau 
503015516c77SSepherosa Ziehau 	((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL;
503115516c77SSepherosa Ziehau }
503215516c77SSepherosa Ziehau 
503315516c77SSepherosa Ziehau static void
503415516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc)
503515516c77SSepherosa Ziehau {
503615516c77SSepherosa Ziehau 	struct task task;
503715516c77SSepherosa Ziehau 
503815516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
503915516c77SSepherosa Ziehau 
504015516c77SSepherosa Ziehau 	/*
504115516c77SSepherosa Ziehau 	 * Make sure that hn_mgmt_taskq0 can nolonger be accessed
504215516c77SSepherosa Ziehau 	 * through hn_mgmt_taskq.
504315516c77SSepherosa Ziehau 	 */
504415516c77SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc);
504515516c77SSepherosa Ziehau 	vmbus_chan_run_task(sc->hn_prichan, &task);
504615516c77SSepherosa Ziehau 
504715516c77SSepherosa Ziehau 	/*
504815516c77SSepherosa Ziehau 	 * Make sure that all pending management tasks are completed.
504915516c77SSepherosa Ziehau 	 */
505015516c77SSepherosa Ziehau 	taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init);
505115516c77SSepherosa Ziehau 	taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status);
505215516c77SSepherosa Ziehau 	taskqueue_drain_all(sc->hn_mgmt_taskq0);
505315516c77SSepherosa Ziehau }
505415516c77SSepherosa Ziehau 
505515516c77SSepherosa Ziehau static void
505615516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc)
505715516c77SSepherosa Ziehau {
505815516c77SSepherosa Ziehau 
505987f8129dSSepherosa Ziehau 	/* Disable polling. */
506087f8129dSSepherosa Ziehau 	hn_polling(sc, 0);
506187f8129dSSepherosa Ziehau 
50625bdfd3fdSDexuan Cui 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
50635bdfd3fdSDexuan Cui 	    (sc->hn_flags & HN_FLAG_VF))
506415516c77SSepherosa Ziehau 		hn_suspend_data(sc);
506515516c77SSepherosa Ziehau 	hn_suspend_mgmt(sc);
506615516c77SSepherosa Ziehau }
506715516c77SSepherosa Ziehau 
506815516c77SSepherosa Ziehau static void
506915516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt)
507015516c77SSepherosa Ziehau {
507115516c77SSepherosa Ziehau 	int i;
507215516c77SSepherosa Ziehau 
507315516c77SSepherosa Ziehau 	KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt,
507415516c77SSepherosa Ziehau 	    ("invalid TX ring count %d", tx_ring_cnt));
507515516c77SSepherosa Ziehau 
507615516c77SSepherosa Ziehau 	for (i = 0; i < tx_ring_cnt; ++i) {
507715516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
507815516c77SSepherosa Ziehau 
507915516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
508015516c77SSepherosa Ziehau 		txr->hn_suspended = 0;
508115516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
508215516c77SSepherosa Ziehau 	}
508315516c77SSepherosa Ziehau }
508415516c77SSepherosa Ziehau 
508515516c77SSepherosa Ziehau static void
508615516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc)
508715516c77SSepherosa Ziehau {
508815516c77SSepherosa Ziehau 	int i;
508915516c77SSepherosa Ziehau 
509015516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
509115516c77SSepherosa Ziehau 
509215516c77SSepherosa Ziehau 	/*
509315516c77SSepherosa Ziehau 	 * Re-enable RX.
509415516c77SSepherosa Ziehau 	 */
5095c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
509615516c77SSepherosa Ziehau 
509715516c77SSepherosa Ziehau 	/*
509815516c77SSepherosa Ziehau 	 * Make sure to clear suspend status on "all" TX rings,
509915516c77SSepherosa Ziehau 	 * since hn_tx_ring_inuse can be changed after
510015516c77SSepherosa Ziehau 	 * hn_suspend_data().
510115516c77SSepherosa Ziehau 	 */
510215516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_cnt);
510315516c77SSepherosa Ziehau 
510423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
510523bf9e15SSepherosa Ziehau 	if (!hn_use_if_start)
510623bf9e15SSepherosa Ziehau #endif
510723bf9e15SSepherosa Ziehau 	{
510815516c77SSepherosa Ziehau 		/*
510915516c77SSepherosa Ziehau 		 * Flush unused drbrs, since hn_tx_ring_inuse may be
511015516c77SSepherosa Ziehau 		 * reduced.
511115516c77SSepherosa Ziehau 		 */
511215516c77SSepherosa Ziehau 		for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i)
511315516c77SSepherosa Ziehau 			hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
511415516c77SSepherosa Ziehau 	}
511515516c77SSepherosa Ziehau 
511615516c77SSepherosa Ziehau 	/*
511715516c77SSepherosa Ziehau 	 * Kick start TX.
511815516c77SSepherosa Ziehau 	 */
511915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
512015516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
512115516c77SSepherosa Ziehau 
512215516c77SSepherosa Ziehau 		/*
512315516c77SSepherosa Ziehau 		 * Use txeof task, so that any pending oactive can be
512415516c77SSepherosa Ziehau 		 * cleared properly.
512515516c77SSepherosa Ziehau 		 */
512615516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
512715516c77SSepherosa Ziehau 	}
512815516c77SSepherosa Ziehau }
512915516c77SSepherosa Ziehau 
513015516c77SSepherosa Ziehau static void
513115516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc)
513215516c77SSepherosa Ziehau {
513315516c77SSepherosa Ziehau 
513415516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
513515516c77SSepherosa Ziehau 
513615516c77SSepherosa Ziehau 	/*
513715516c77SSepherosa Ziehau 	 * Kick off network change detection, if it was pending.
513815516c77SSepherosa Ziehau 	 * If no network change was pending, start link status
513915516c77SSepherosa Ziehau 	 * checks, which is more lightweight than network change
514015516c77SSepherosa Ziehau 	 * detection.
514115516c77SSepherosa Ziehau 	 */
514215516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
514315516c77SSepherosa Ziehau 		hn_change_network(sc);
514415516c77SSepherosa Ziehau 	else
514515516c77SSepherosa Ziehau 		hn_update_link_status(sc);
514615516c77SSepherosa Ziehau }
514715516c77SSepherosa Ziehau 
514815516c77SSepherosa Ziehau static void
514915516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc)
515015516c77SSepherosa Ziehau {
515115516c77SSepherosa Ziehau 
51525bdfd3fdSDexuan Cui 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
51535bdfd3fdSDexuan Cui 	    (sc->hn_flags & HN_FLAG_VF))
515415516c77SSepherosa Ziehau 		hn_resume_data(sc);
51555bdfd3fdSDexuan Cui 
51565bdfd3fdSDexuan Cui 	/*
51575bdfd3fdSDexuan Cui 	 * When the VF is activated, the synthetic interface is changed
51585bdfd3fdSDexuan Cui 	 * to DOWN in hn_set_vf(). Here, if the VF is still active, we
51595bdfd3fdSDexuan Cui 	 * don't call hn_resume_mgmt() until the VF is deactivated in
51605bdfd3fdSDexuan Cui 	 * hn_set_vf().
51615bdfd3fdSDexuan Cui 	 */
51625bdfd3fdSDexuan Cui 	if (!(sc->hn_flags & HN_FLAG_VF))
516315516c77SSepherosa Ziehau 		hn_resume_mgmt(sc);
516487f8129dSSepherosa Ziehau 
516587f8129dSSepherosa Ziehau 	/*
516687f8129dSSepherosa Ziehau 	 * Re-enable polling if this interface is running and
516787f8129dSSepherosa Ziehau 	 * the polling is requested.
516887f8129dSSepherosa Ziehau 	 */
516987f8129dSSepherosa Ziehau 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->hn_pollhz > 0)
517087f8129dSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
517115516c77SSepherosa Ziehau }
517215516c77SSepherosa Ziehau 
517315516c77SSepherosa Ziehau static void
517415516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen)
517515516c77SSepherosa Ziehau {
517615516c77SSepherosa Ziehau 	const struct rndis_status_msg *msg;
517715516c77SSepherosa Ziehau 	int ofs;
517815516c77SSepherosa Ziehau 
517915516c77SSepherosa Ziehau 	if (dlen < sizeof(*msg)) {
518015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid RNDIS status\n");
518115516c77SSepherosa Ziehau 		return;
518215516c77SSepherosa Ziehau 	}
518315516c77SSepherosa Ziehau 	msg = data;
518415516c77SSepherosa Ziehau 
518515516c77SSepherosa Ziehau 	switch (msg->rm_status) {
518615516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_CONNECT:
518715516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_DISCONNECT:
518815516c77SSepherosa Ziehau 		hn_update_link_status(sc);
518915516c77SSepherosa Ziehau 		break;
519015516c77SSepherosa Ziehau 
519115516c77SSepherosa Ziehau 	case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
519215516c77SSepherosa Ziehau 		/* Not really useful; ignore. */
519315516c77SSepherosa Ziehau 		break;
519415516c77SSepherosa Ziehau 
519515516c77SSepherosa Ziehau 	case RNDIS_STATUS_NETWORK_CHANGE:
519615516c77SSepherosa Ziehau 		ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
519715516c77SSepherosa Ziehau 		if (dlen < ofs + msg->rm_stbuflen ||
519815516c77SSepherosa Ziehau 		    msg->rm_stbuflen < sizeof(uint32_t)) {
519915516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed\n");
520015516c77SSepherosa Ziehau 		} else {
520115516c77SSepherosa Ziehau 			uint32_t change;
520215516c77SSepherosa Ziehau 
520315516c77SSepherosa Ziehau 			memcpy(&change, ((const uint8_t *)msg) + ofs,
520415516c77SSepherosa Ziehau 			    sizeof(change));
520515516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed, change %u\n",
520615516c77SSepherosa Ziehau 			    change);
520715516c77SSepherosa Ziehau 		}
520815516c77SSepherosa Ziehau 		hn_change_network(sc);
520915516c77SSepherosa Ziehau 		break;
521015516c77SSepherosa Ziehau 
521115516c77SSepherosa Ziehau 	default:
521215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
521315516c77SSepherosa Ziehau 		    msg->rm_status);
521415516c77SSepherosa Ziehau 		break;
521515516c77SSepherosa Ziehau 	}
521615516c77SSepherosa Ziehau }
521715516c77SSepherosa Ziehau 
521815516c77SSepherosa Ziehau static int
521915516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info)
522015516c77SSepherosa Ziehau {
522115516c77SSepherosa Ziehau 	const struct rndis_pktinfo *pi = info_data;
522215516c77SSepherosa Ziehau 	uint32_t mask = 0;
522315516c77SSepherosa Ziehau 
522415516c77SSepherosa Ziehau 	while (info_dlen != 0) {
522515516c77SSepherosa Ziehau 		const void *data;
522615516c77SSepherosa Ziehau 		uint32_t dlen;
522715516c77SSepherosa Ziehau 
522815516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < sizeof(*pi)))
522915516c77SSepherosa Ziehau 			return (EINVAL);
523015516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < pi->rm_size))
523115516c77SSepherosa Ziehau 			return (EINVAL);
523215516c77SSepherosa Ziehau 		info_dlen -= pi->rm_size;
523315516c77SSepherosa Ziehau 
523415516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
523515516c77SSepherosa Ziehau 			return (EINVAL);
523615516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
523715516c77SSepherosa Ziehau 			return (EINVAL);
523815516c77SSepherosa Ziehau 		dlen = pi->rm_size - pi->rm_pktinfooffset;
523915516c77SSepherosa Ziehau 		data = pi->rm_data;
524015516c77SSepherosa Ziehau 
524115516c77SSepherosa Ziehau 		switch (pi->rm_type) {
524215516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_VLAN:
524315516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
524415516c77SSepherosa Ziehau 				return (EINVAL);
524515516c77SSepherosa Ziehau 			info->vlan_info = *((const uint32_t *)data);
524615516c77SSepherosa Ziehau 			mask |= HN_RXINFO_VLAN;
524715516c77SSepherosa Ziehau 			break;
524815516c77SSepherosa Ziehau 
524915516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_CSUM:
525015516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
525115516c77SSepherosa Ziehau 				return (EINVAL);
525215516c77SSepherosa Ziehau 			info->csum_info = *((const uint32_t *)data);
525315516c77SSepherosa Ziehau 			mask |= HN_RXINFO_CSUM;
525415516c77SSepherosa Ziehau 			break;
525515516c77SSepherosa Ziehau 
525615516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHVAL:
525715516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
525815516c77SSepherosa Ziehau 				return (EINVAL);
525915516c77SSepherosa Ziehau 			info->hash_value = *((const uint32_t *)data);
526015516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHVAL;
526115516c77SSepherosa Ziehau 			break;
526215516c77SSepherosa Ziehau 
526315516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHINF:
526415516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
526515516c77SSepherosa Ziehau 				return (EINVAL);
526615516c77SSepherosa Ziehau 			info->hash_info = *((const uint32_t *)data);
526715516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHINF;
526815516c77SSepherosa Ziehau 			break;
526915516c77SSepherosa Ziehau 
527015516c77SSepherosa Ziehau 		default:
527115516c77SSepherosa Ziehau 			goto next;
527215516c77SSepherosa Ziehau 		}
527315516c77SSepherosa Ziehau 
527415516c77SSepherosa Ziehau 		if (mask == HN_RXINFO_ALL) {
527515516c77SSepherosa Ziehau 			/* All found; done */
527615516c77SSepherosa Ziehau 			break;
527715516c77SSepherosa Ziehau 		}
527815516c77SSepherosa Ziehau next:
527915516c77SSepherosa Ziehau 		pi = (const struct rndis_pktinfo *)
528015516c77SSepherosa Ziehau 		    ((const uint8_t *)pi + pi->rm_size);
528115516c77SSepherosa Ziehau 	}
528215516c77SSepherosa Ziehau 
528315516c77SSepherosa Ziehau 	/*
528415516c77SSepherosa Ziehau 	 * Final fixup.
528515516c77SSepherosa Ziehau 	 * - If there is no hash value, invalidate the hash info.
528615516c77SSepherosa Ziehau 	 */
528715516c77SSepherosa Ziehau 	if ((mask & HN_RXINFO_HASHVAL) == 0)
528815516c77SSepherosa Ziehau 		info->hash_info = HN_NDIS_HASH_INFO_INVALID;
528915516c77SSepherosa Ziehau 	return (0);
529015516c77SSepherosa Ziehau }
529115516c77SSepherosa Ziehau 
529215516c77SSepherosa Ziehau static __inline bool
529315516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
529415516c77SSepherosa Ziehau {
529515516c77SSepherosa Ziehau 
529615516c77SSepherosa Ziehau 	if (off < check_off) {
529715516c77SSepherosa Ziehau 		if (__predict_true(off + len <= check_off))
529815516c77SSepherosa Ziehau 			return (false);
529915516c77SSepherosa Ziehau 	} else if (off > check_off) {
530015516c77SSepherosa Ziehau 		if (__predict_true(check_off + check_len <= off))
530115516c77SSepherosa Ziehau 			return (false);
530215516c77SSepherosa Ziehau 	}
530315516c77SSepherosa Ziehau 	return (true);
530415516c77SSepherosa Ziehau }
530515516c77SSepherosa Ziehau 
530615516c77SSepherosa Ziehau static void
530715516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen)
530815516c77SSepherosa Ziehau {
530915516c77SSepherosa Ziehau 	const struct rndis_packet_msg *pkt;
531015516c77SSepherosa Ziehau 	struct hn_rxinfo info;
531115516c77SSepherosa Ziehau 	int data_off, pktinfo_off, data_len, pktinfo_len;
531215516c77SSepherosa Ziehau 
531315516c77SSepherosa Ziehau 	/*
531415516c77SSepherosa Ziehau 	 * Check length.
531515516c77SSepherosa Ziehau 	 */
531615516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*pkt))) {
531715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
531815516c77SSepherosa Ziehau 		return;
531915516c77SSepherosa Ziehau 	}
532015516c77SSepherosa Ziehau 	pkt = data;
532115516c77SSepherosa Ziehau 
532215516c77SSepherosa Ziehau 	if (__predict_false(dlen < pkt->rm_len)) {
532315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
532415516c77SSepherosa Ziehau 		    "dlen %d, msglen %u\n", dlen, pkt->rm_len);
532515516c77SSepherosa Ziehau 		return;
532615516c77SSepherosa Ziehau 	}
532715516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_len <
532815516c77SSepherosa Ziehau 	    pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
532915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
533015516c77SSepherosa Ziehau 		    "msglen %u, data %u, oob %u, pktinfo %u\n",
533115516c77SSepherosa Ziehau 		    pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
533215516c77SSepherosa Ziehau 		    pkt->rm_pktinfolen);
533315516c77SSepherosa Ziehau 		return;
533415516c77SSepherosa Ziehau 	}
533515516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_datalen == 0)) {
533615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
533715516c77SSepherosa Ziehau 		return;
533815516c77SSepherosa Ziehau 	}
533915516c77SSepherosa Ziehau 
534015516c77SSepherosa Ziehau 	/*
534115516c77SSepherosa Ziehau 	 * Check offests.
534215516c77SSepherosa Ziehau 	 */
534315516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs)			\
534415516c77SSepherosa Ziehau 	((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN ||	\
534515516c77SSepherosa Ziehau 	 ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
534615516c77SSepherosa Ziehau 
534715516c77SSepherosa Ziehau 	/* XXX Hyper-V does not meet data offset alignment requirement */
534815516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
534915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
535015516c77SSepherosa Ziehau 		    "data offset %u\n", pkt->rm_dataoffset);
535115516c77SSepherosa Ziehau 		return;
535215516c77SSepherosa Ziehau 	}
535315516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdataoffset > 0 &&
535415516c77SSepherosa Ziehau 	    IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
535515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
535615516c77SSepherosa Ziehau 		    "oob offset %u\n", pkt->rm_oobdataoffset);
535715516c77SSepherosa Ziehau 		return;
535815516c77SSepherosa Ziehau 	}
535915516c77SSepherosa Ziehau 	if (__predict_true(pkt->rm_pktinfooffset > 0) &&
536015516c77SSepherosa Ziehau 	    __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
536115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
536215516c77SSepherosa Ziehau 		    "pktinfo offset %u\n", pkt->rm_pktinfooffset);
536315516c77SSepherosa Ziehau 		return;
536415516c77SSepherosa Ziehau 	}
536515516c77SSepherosa Ziehau 
536615516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID
536715516c77SSepherosa Ziehau 
536815516c77SSepherosa Ziehau 	data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
536915516c77SSepherosa Ziehau 	data_len = pkt->rm_datalen;
537015516c77SSepherosa Ziehau 	pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
537115516c77SSepherosa Ziehau 	pktinfo_len = pkt->rm_pktinfolen;
537215516c77SSepherosa Ziehau 
537315516c77SSepherosa Ziehau 	/*
537415516c77SSepherosa Ziehau 	 * Check OOB coverage.
537515516c77SSepherosa Ziehau 	 */
537615516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdatalen != 0)) {
537715516c77SSepherosa Ziehau 		int oob_off, oob_len;
537815516c77SSepherosa Ziehau 
537915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "got oobdata\n");
538015516c77SSepherosa Ziehau 		oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
538115516c77SSepherosa Ziehau 		oob_len = pkt->rm_oobdatalen;
538215516c77SSepherosa Ziehau 
538315516c77SSepherosa Ziehau 		if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
538415516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
538515516c77SSepherosa Ziehau 			    "oob overflow, msglen %u, oob abs %d len %d\n",
538615516c77SSepherosa Ziehau 			    pkt->rm_len, oob_off, oob_len);
538715516c77SSepherosa Ziehau 			return;
538815516c77SSepherosa Ziehau 		}
538915516c77SSepherosa Ziehau 
539015516c77SSepherosa Ziehau 		/*
539115516c77SSepherosa Ziehau 		 * Check against data.
539215516c77SSepherosa Ziehau 		 */
539315516c77SSepherosa Ziehau 		if (hn_rndis_check_overlap(oob_off, oob_len,
539415516c77SSepherosa Ziehau 		    data_off, data_len)) {
539515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
539615516c77SSepherosa Ziehau 			    "oob overlaps data, oob abs %d len %d, "
539715516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
539815516c77SSepherosa Ziehau 			    oob_off, oob_len, data_off, data_len);
539915516c77SSepherosa Ziehau 			return;
540015516c77SSepherosa Ziehau 		}
540115516c77SSepherosa Ziehau 
540215516c77SSepherosa Ziehau 		/*
540315516c77SSepherosa Ziehau 		 * Check against pktinfo.
540415516c77SSepherosa Ziehau 		 */
540515516c77SSepherosa Ziehau 		if (pktinfo_len != 0 &&
540615516c77SSepherosa Ziehau 		    hn_rndis_check_overlap(oob_off, oob_len,
540715516c77SSepherosa Ziehau 		    pktinfo_off, pktinfo_len)) {
540815516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
540915516c77SSepherosa Ziehau 			    "oob overlaps pktinfo, oob abs %d len %d, "
541015516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
541115516c77SSepherosa Ziehau 			    oob_off, oob_len, pktinfo_off, pktinfo_len);
541215516c77SSepherosa Ziehau 			return;
541315516c77SSepherosa Ziehau 		}
541415516c77SSepherosa Ziehau 	}
541515516c77SSepherosa Ziehau 
541615516c77SSepherosa Ziehau 	/*
541715516c77SSepherosa Ziehau 	 * Check per-packet-info coverage and find useful per-packet-info.
541815516c77SSepherosa Ziehau 	 */
541915516c77SSepherosa Ziehau 	info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
542015516c77SSepherosa Ziehau 	info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
542115516c77SSepherosa Ziehau 	info.hash_info = HN_NDIS_HASH_INFO_INVALID;
542215516c77SSepherosa Ziehau 	if (__predict_true(pktinfo_len != 0)) {
542315516c77SSepherosa Ziehau 		bool overlap;
542415516c77SSepherosa Ziehau 		int error;
542515516c77SSepherosa Ziehau 
542615516c77SSepherosa Ziehau 		if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
542715516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
542815516c77SSepherosa Ziehau 			    "pktinfo overflow, msglen %u, "
542915516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
543015516c77SSepherosa Ziehau 			    pkt->rm_len, pktinfo_off, pktinfo_len);
543115516c77SSepherosa Ziehau 			return;
543215516c77SSepherosa Ziehau 		}
543315516c77SSepherosa Ziehau 
543415516c77SSepherosa Ziehau 		/*
543515516c77SSepherosa Ziehau 		 * Check packet info coverage.
543615516c77SSepherosa Ziehau 		 */
543715516c77SSepherosa Ziehau 		overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
543815516c77SSepherosa Ziehau 		    data_off, data_len);
543915516c77SSepherosa Ziehau 		if (__predict_false(overlap)) {
544015516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
544115516c77SSepherosa Ziehau 			    "pktinfo overlap data, pktinfo abs %d len %d, "
544215516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
544315516c77SSepherosa Ziehau 			    pktinfo_off, pktinfo_len, data_off, data_len);
544415516c77SSepherosa Ziehau 			return;
544515516c77SSepherosa Ziehau 		}
544615516c77SSepherosa Ziehau 
544715516c77SSepherosa Ziehau 		/*
544815516c77SSepherosa Ziehau 		 * Find useful per-packet-info.
544915516c77SSepherosa Ziehau 		 */
545015516c77SSepherosa Ziehau 		error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
545115516c77SSepherosa Ziehau 		    pktinfo_len, &info);
545215516c77SSepherosa Ziehau 		if (__predict_false(error)) {
545315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
545415516c77SSepherosa Ziehau 			    "pktinfo\n");
545515516c77SSepherosa Ziehau 			return;
545615516c77SSepherosa Ziehau 		}
545715516c77SSepherosa Ziehau 	}
545815516c77SSepherosa Ziehau 
545915516c77SSepherosa Ziehau 	if (__predict_false(data_off + data_len > pkt->rm_len)) {
546015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
546115516c77SSepherosa Ziehau 		    "data overflow, msglen %u, data abs %d len %d\n",
546215516c77SSepherosa Ziehau 		    pkt->rm_len, data_off, data_len);
546315516c77SSepherosa Ziehau 		return;
546415516c77SSepherosa Ziehau 	}
546515516c77SSepherosa Ziehau 	hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
546615516c77SSepherosa Ziehau }
546715516c77SSepherosa Ziehau 
546815516c77SSepherosa Ziehau static __inline void
546915516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen)
547015516c77SSepherosa Ziehau {
547115516c77SSepherosa Ziehau 	const struct rndis_msghdr *hdr;
547215516c77SSepherosa Ziehau 
547315516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*hdr))) {
547415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
547515516c77SSepherosa Ziehau 		return;
547615516c77SSepherosa Ziehau 	}
547715516c77SSepherosa Ziehau 	hdr = data;
547815516c77SSepherosa Ziehau 
547915516c77SSepherosa Ziehau 	if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) {
548015516c77SSepherosa Ziehau 		/* Hot data path. */
548115516c77SSepherosa Ziehau 		hn_rndis_rx_data(rxr, data, dlen);
548215516c77SSepherosa Ziehau 		/* Done! */
548315516c77SSepherosa Ziehau 		return;
548415516c77SSepherosa Ziehau 	}
548515516c77SSepherosa Ziehau 
548615516c77SSepherosa Ziehau 	if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG)
548715516c77SSepherosa Ziehau 		hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen);
548815516c77SSepherosa Ziehau 	else
548915516c77SSepherosa Ziehau 		hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen);
549015516c77SSepherosa Ziehau }
549115516c77SSepherosa Ziehau 
549215516c77SSepherosa Ziehau static void
549315516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
549415516c77SSepherosa Ziehau {
549515516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *hdr;
549615516c77SSepherosa Ziehau 
549715516c77SSepherosa Ziehau 	if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) {
549815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid nvs notify\n");
549915516c77SSepherosa Ziehau 		return;
550015516c77SSepherosa Ziehau 	}
550115516c77SSepherosa Ziehau 	hdr = VMBUS_CHANPKT_CONST_DATA(pkt);
550215516c77SSepherosa Ziehau 
550315516c77SSepherosa Ziehau 	if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) {
550415516c77SSepherosa Ziehau 		/* Useless; ignore */
550515516c77SSepherosa Ziehau 		return;
550615516c77SSepherosa Ziehau 	}
550715516c77SSepherosa Ziehau 	if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type);
550815516c77SSepherosa Ziehau }
550915516c77SSepherosa Ziehau 
551015516c77SSepherosa Ziehau static void
551115516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan,
551215516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkt)
551315516c77SSepherosa Ziehau {
551415516c77SSepherosa Ziehau 	struct hn_nvs_sendctx *sndc;
551515516c77SSepherosa Ziehau 
551615516c77SSepherosa Ziehau 	sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid;
551715516c77SSepherosa Ziehau 	sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt),
551815516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_DATALEN(pkt));
551915516c77SSepherosa Ziehau 	/*
552015516c77SSepherosa Ziehau 	 * NOTE:
552115516c77SSepherosa Ziehau 	 * 'sndc' CAN NOT be accessed anymore, since it can be freed by
552215516c77SSepherosa Ziehau 	 * its callback.
552315516c77SSepherosa Ziehau 	 */
552415516c77SSepherosa Ziehau }
552515516c77SSepherosa Ziehau 
552615516c77SSepherosa Ziehau static void
552715516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
552815516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkthdr)
552915516c77SSepherosa Ziehau {
553015516c77SSepherosa Ziehau 	const struct vmbus_chanpkt_rxbuf *pkt;
553115516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *nvs_hdr;
553215516c77SSepherosa Ziehau 	int count, i, hlen;
553315516c77SSepherosa Ziehau 
553415516c77SSepherosa Ziehau 	if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) {
553515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n");
553615516c77SSepherosa Ziehau 		return;
553715516c77SSepherosa Ziehau 	}
553815516c77SSepherosa Ziehau 	nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr);
553915516c77SSepherosa Ziehau 
554015516c77SSepherosa Ziehau 	/* Make sure that this is a RNDIS message. */
554115516c77SSepherosa Ziehau 	if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) {
554215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n",
554315516c77SSepherosa Ziehau 		    nvs_hdr->nvs_type);
554415516c77SSepherosa Ziehau 		return;
554515516c77SSepherosa Ziehau 	}
554615516c77SSepherosa Ziehau 
554715516c77SSepherosa Ziehau 	hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen);
554815516c77SSepherosa Ziehau 	if (__predict_false(hlen < sizeof(*pkt))) {
554915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n");
555015516c77SSepherosa Ziehau 		return;
555115516c77SSepherosa Ziehau 	}
555215516c77SSepherosa Ziehau 	pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
555315516c77SSepherosa Ziehau 
555415516c77SSepherosa Ziehau 	if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) {
555515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n",
555615516c77SSepherosa Ziehau 		    pkt->cp_rxbuf_id);
555715516c77SSepherosa Ziehau 		return;
555815516c77SSepherosa Ziehau 	}
555915516c77SSepherosa Ziehau 
556015516c77SSepherosa Ziehau 	count = pkt->cp_rxbuf_cnt;
556115516c77SSepherosa Ziehau 	if (__predict_false(hlen <
556215516c77SSepherosa Ziehau 	    __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) {
556315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count);
556415516c77SSepherosa Ziehau 		return;
556515516c77SSepherosa Ziehau 	}
556615516c77SSepherosa Ziehau 
556715516c77SSepherosa Ziehau 	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
556815516c77SSepherosa Ziehau 	for (i = 0; i < count; ++i) {
556915516c77SSepherosa Ziehau 		int ofs, len;
557015516c77SSepherosa Ziehau 
557115516c77SSepherosa Ziehau 		ofs = pkt->cp_rxbuf[i].rb_ofs;
557215516c77SSepherosa Ziehau 		len = pkt->cp_rxbuf[i].rb_len;
557315516c77SSepherosa Ziehau 		if (__predict_false(ofs + len > HN_RXBUF_SIZE)) {
557415516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, "
557515516c77SSepherosa Ziehau 			    "ofs %d, len %d\n", i, ofs, len);
557615516c77SSepherosa Ziehau 			continue;
557715516c77SSepherosa Ziehau 		}
557815516c77SSepherosa Ziehau 		hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len);
557915516c77SSepherosa Ziehau 	}
558015516c77SSepherosa Ziehau 
558115516c77SSepherosa Ziehau 	/*
558215516c77SSepherosa Ziehau 	 * Ack the consumed RXBUF associated w/ this channel packet,
558315516c77SSepherosa Ziehau 	 * so that this RXBUF can be recycled by the hypervisor.
558415516c77SSepherosa Ziehau 	 */
558515516c77SSepherosa Ziehau 	hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid);
558615516c77SSepherosa Ziehau }
558715516c77SSepherosa Ziehau 
558815516c77SSepherosa Ziehau static void
558915516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
559015516c77SSepherosa Ziehau     uint64_t tid)
559115516c77SSepherosa Ziehau {
559215516c77SSepherosa Ziehau 	struct hn_nvs_rndis_ack ack;
559315516c77SSepherosa Ziehau 	int retries, error;
559415516c77SSepherosa Ziehau 
559515516c77SSepherosa Ziehau 	ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK;
559615516c77SSepherosa Ziehau 	ack.nvs_status = HN_NVS_STATUS_OK;
559715516c77SSepherosa Ziehau 
559815516c77SSepherosa Ziehau 	retries = 0;
559915516c77SSepherosa Ziehau again:
560015516c77SSepherosa Ziehau 	error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP,
560115516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid);
560215516c77SSepherosa Ziehau 	if (__predict_false(error == EAGAIN)) {
560315516c77SSepherosa Ziehau 		/*
560415516c77SSepherosa Ziehau 		 * NOTE:
560515516c77SSepherosa Ziehau 		 * This should _not_ happen in real world, since the
560615516c77SSepherosa Ziehau 		 * consumption of the TX bufring from the TX path is
560715516c77SSepherosa Ziehau 		 * controlled.
560815516c77SSepherosa Ziehau 		 */
560915516c77SSepherosa Ziehau 		if (rxr->hn_ack_failed == 0)
561015516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "RXBUF ack retry\n");
561115516c77SSepherosa Ziehau 		rxr->hn_ack_failed++;
561215516c77SSepherosa Ziehau 		retries++;
561315516c77SSepherosa Ziehau 		if (retries < 10) {
561415516c77SSepherosa Ziehau 			DELAY(100);
561515516c77SSepherosa Ziehau 			goto again;
561615516c77SSepherosa Ziehau 		}
561715516c77SSepherosa Ziehau 		/* RXBUF leaks! */
561815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "RXBUF ack failed\n");
561915516c77SSepherosa Ziehau 	}
562015516c77SSepherosa Ziehau }
562115516c77SSepherosa Ziehau 
562215516c77SSepherosa Ziehau static void
562315516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr)
562415516c77SSepherosa Ziehau {
562515516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr = xrxr;
562615516c77SSepherosa Ziehau 	struct hn_softc *sc = rxr->hn_ifp->if_softc;
562715516c77SSepherosa Ziehau 
562815516c77SSepherosa Ziehau 	for (;;) {
562915516c77SSepherosa Ziehau 		struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf;
563015516c77SSepherosa Ziehau 		int error, pktlen;
563115516c77SSepherosa Ziehau 
563215516c77SSepherosa Ziehau 		pktlen = rxr->hn_pktbuf_len;
563315516c77SSepherosa Ziehau 		error = vmbus_chan_recv_pkt(chan, pkt, &pktlen);
563415516c77SSepherosa Ziehau 		if (__predict_false(error == ENOBUFS)) {
563515516c77SSepherosa Ziehau 			void *nbuf;
563615516c77SSepherosa Ziehau 			int nlen;
563715516c77SSepherosa Ziehau 
563815516c77SSepherosa Ziehau 			/*
563915516c77SSepherosa Ziehau 			 * Expand channel packet buffer.
564015516c77SSepherosa Ziehau 			 *
564115516c77SSepherosa Ziehau 			 * XXX
564215516c77SSepherosa Ziehau 			 * Use M_WAITOK here, since allocation failure
564315516c77SSepherosa Ziehau 			 * is fatal.
564415516c77SSepherosa Ziehau 			 */
564515516c77SSepherosa Ziehau 			nlen = rxr->hn_pktbuf_len * 2;
564615516c77SSepherosa Ziehau 			while (nlen < pktlen)
564715516c77SSepherosa Ziehau 				nlen *= 2;
564815516c77SSepherosa Ziehau 			nbuf = malloc(nlen, M_DEVBUF, M_WAITOK);
564915516c77SSepherosa Ziehau 
565015516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n",
565115516c77SSepherosa Ziehau 			    rxr->hn_pktbuf_len, nlen);
565215516c77SSepherosa Ziehau 
565315516c77SSepherosa Ziehau 			free(rxr->hn_pktbuf, M_DEVBUF);
565415516c77SSepherosa Ziehau 			rxr->hn_pktbuf = nbuf;
565515516c77SSepherosa Ziehau 			rxr->hn_pktbuf_len = nlen;
565615516c77SSepherosa Ziehau 			/* Retry! */
565715516c77SSepherosa Ziehau 			continue;
565815516c77SSepherosa Ziehau 		} else if (__predict_false(error == EAGAIN)) {
565915516c77SSepherosa Ziehau 			/* No more channel packets; done! */
566015516c77SSepherosa Ziehau 			break;
566115516c77SSepherosa Ziehau 		}
566215516c77SSepherosa Ziehau 		KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error));
566315516c77SSepherosa Ziehau 
566415516c77SSepherosa Ziehau 		switch (pkt->cph_type) {
566515516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_COMP:
566615516c77SSepherosa Ziehau 			hn_nvs_handle_comp(sc, chan, pkt);
566715516c77SSepherosa Ziehau 			break;
566815516c77SSepherosa Ziehau 
566915516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_RXBUF:
567015516c77SSepherosa Ziehau 			hn_nvs_handle_rxbuf(rxr, chan, pkt);
567115516c77SSepherosa Ziehau 			break;
567215516c77SSepherosa Ziehau 
567315516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_INBAND:
567415516c77SSepherosa Ziehau 			hn_nvs_handle_notify(sc, pkt);
567515516c77SSepherosa Ziehau 			break;
567615516c77SSepherosa Ziehau 
567715516c77SSepherosa Ziehau 		default:
567815516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "unknown chan pkt %u\n",
567915516c77SSepherosa Ziehau 			    pkt->cph_type);
568015516c77SSepherosa Ziehau 			break;
568115516c77SSepherosa Ziehau 		}
568215516c77SSepherosa Ziehau 	}
568315516c77SSepherosa Ziehau 	hn_chan_rollup(rxr, rxr->hn_txr);
568415516c77SSepherosa Ziehau }
568515516c77SSepherosa Ziehau 
568615516c77SSepherosa Ziehau static void
568715516c77SSepherosa Ziehau hn_tx_taskq_create(void *arg __unused)
568815516c77SSepherosa Ziehau {
5689fdd0222aSSepherosa Ziehau 	int i;
5690fdd0222aSSepherosa Ziehau 
5691fdd0222aSSepherosa Ziehau 	/*
5692fdd0222aSSepherosa Ziehau 	 * Fix the # of TX taskqueues.
5693fdd0222aSSepherosa Ziehau 	 */
5694fdd0222aSSepherosa Ziehau 	if (hn_tx_taskq_cnt <= 0)
5695fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = 1;
5696fdd0222aSSepherosa Ziehau 	else if (hn_tx_taskq_cnt > mp_ncpus)
5697fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = mp_ncpus;
569815516c77SSepherosa Ziehau 
56990e11868dSSepherosa Ziehau 	/*
57000e11868dSSepherosa Ziehau 	 * Fix the TX taskqueue mode.
57010e11868dSSepherosa Ziehau 	 */
57020e11868dSSepherosa Ziehau 	switch (hn_tx_taskq_mode) {
57030e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_INDEP:
57040e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_GLOBAL:
57050e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_EVTTQ:
57060e11868dSSepherosa Ziehau 		break;
57070e11868dSSepherosa Ziehau 	default:
57080e11868dSSepherosa Ziehau 		hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
57090e11868dSSepherosa Ziehau 		break;
57100e11868dSSepherosa Ziehau 	}
57110e11868dSSepherosa Ziehau 
571215516c77SSepherosa Ziehau 	if (vm_guest != VM_GUEST_HV)
571315516c77SSepherosa Ziehau 		return;
571415516c77SSepherosa Ziehau 
57150e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode != HN_TX_TASKQ_M_GLOBAL)
571615516c77SSepherosa Ziehau 		return;
571715516c77SSepherosa Ziehau 
5718fdd0222aSSepherosa Ziehau 	hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
5719fdd0222aSSepherosa Ziehau 	    M_DEVBUF, M_WAITOK);
5720fdd0222aSSepherosa Ziehau 	for (i = 0; i < hn_tx_taskq_cnt; ++i) {
5721fdd0222aSSepherosa Ziehau 		hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK,
5722fdd0222aSSepherosa Ziehau 		    taskqueue_thread_enqueue, &hn_tx_taskque[i]);
5723fdd0222aSSepherosa Ziehau 		taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET,
5724fdd0222aSSepherosa Ziehau 		    "hn tx%d", i);
5725fdd0222aSSepherosa Ziehau 	}
572615516c77SSepherosa Ziehau }
572715516c77SSepherosa Ziehau SYSINIT(hn_txtq_create, SI_SUB_DRIVERS, SI_ORDER_SECOND,
572815516c77SSepherosa Ziehau     hn_tx_taskq_create, NULL);
572915516c77SSepherosa Ziehau 
573015516c77SSepherosa Ziehau static void
573115516c77SSepherosa Ziehau hn_tx_taskq_destroy(void *arg __unused)
573215516c77SSepherosa Ziehau {
573315516c77SSepherosa Ziehau 
5734fdd0222aSSepherosa Ziehau 	if (hn_tx_taskque != NULL) {
5735fdd0222aSSepherosa Ziehau 		int i;
5736fdd0222aSSepherosa Ziehau 
5737fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
5738fdd0222aSSepherosa Ziehau 			taskqueue_free(hn_tx_taskque[i]);
5739fdd0222aSSepherosa Ziehau 		free(hn_tx_taskque, M_DEVBUF);
5740fdd0222aSSepherosa Ziehau 	}
574115516c77SSepherosa Ziehau }
574215516c77SSepherosa Ziehau SYSUNINIT(hn_txtq_destroy, SI_SUB_DRIVERS, SI_ORDER_SECOND,
574315516c77SSepherosa Ziehau     hn_tx_taskq_destroy, NULL);
5744