xref: /freebsd/sys/dev/hyperv/netvsc/if_hn.c (revision cc0c6ebc14730454def063239426c32f0b83adc7)
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);
264b3b75d9cSSepherosa Ziehau static void			hn_rndis_init_fixat(struct hn_softc *, int);
26515516c77SSepherosa Ziehau 
26615516c77SSepherosa Ziehau static void			hn_nvs_handle_notify(struct hn_softc *,
26715516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
26815516c77SSepherosa Ziehau static void			hn_nvs_handle_comp(struct hn_softc *,
26915516c77SSepherosa Ziehau 				    struct vmbus_channel *,
27015516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
27115516c77SSepherosa Ziehau static void			hn_nvs_handle_rxbuf(struct hn_rx_ring *,
27215516c77SSepherosa Ziehau 				    struct vmbus_channel *,
27315516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
27415516c77SSepherosa Ziehau static void			hn_nvs_ack_rxbuf(struct hn_rx_ring *,
27515516c77SSepherosa Ziehau 				    struct vmbus_channel *, uint64_t);
27615516c77SSepherosa Ziehau 
27715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
27815516c77SSepherosa Ziehau static int			hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS);
27915516c77SSepherosa Ziehau static int			hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS);
28015516c77SSepherosa Ziehau #endif
28115516c77SSepherosa Ziehau static int			hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS);
28215516c77SSepherosa Ziehau static int			hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS);
28315516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
28415516c77SSepherosa Ziehau static int			hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS);
28515516c77SSepherosa Ziehau #else
28615516c77SSepherosa Ziehau static int			hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS);
28715516c77SSepherosa Ziehau #endif
28815516c77SSepherosa Ziehau static int			hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
28915516c77SSepherosa Ziehau static int			hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
29015516c77SSepherosa Ziehau static int			hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS);
29115516c77SSepherosa Ziehau static int			hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS);
29215516c77SSepherosa Ziehau static int			hn_caps_sysctl(SYSCTL_HANDLER_ARGS);
29315516c77SSepherosa Ziehau static int			hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS);
29415516c77SSepherosa Ziehau static int			hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS);
29534d68912SSepherosa Ziehau #ifndef RSS
29615516c77SSepherosa Ziehau static int			hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS);
29715516c77SSepherosa Ziehau static int			hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS);
29834d68912SSepherosa Ziehau #endif
29915516c77SSepherosa Ziehau static int			hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS);
300dc13fee6SSepherosa Ziehau static int			hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS);
301dc13fee6SSepherosa Ziehau static int			hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS);
302dc13fee6SSepherosa Ziehau static int			hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS);
303dc13fee6SSepherosa Ziehau static int			hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS);
3046c1204dfSSepherosa Ziehau static int			hn_polling_sysctl(SYSCTL_HANDLER_ARGS);
30540d60d6eSDexuan Cui static int			hn_vf_sysctl(SYSCTL_HANDLER_ARGS);
30615516c77SSepherosa Ziehau 
3075bdfd3fdSDexuan Cui static void			hn_stop(struct hn_softc *, bool);
30815516c77SSepherosa Ziehau static void			hn_init_locked(struct hn_softc *);
30915516c77SSepherosa Ziehau static int			hn_chan_attach(struct hn_softc *,
31015516c77SSepherosa Ziehau 				    struct vmbus_channel *);
31115516c77SSepherosa Ziehau static void			hn_chan_detach(struct hn_softc *,
31215516c77SSepherosa Ziehau 				    struct vmbus_channel *);
31315516c77SSepherosa Ziehau static int			hn_attach_subchans(struct hn_softc *);
31415516c77SSepherosa Ziehau static void			hn_detach_allchans(struct hn_softc *);
31515516c77SSepherosa Ziehau static void			hn_chan_rollup(struct hn_rx_ring *,
31615516c77SSepherosa Ziehau 				    struct hn_tx_ring *);
31715516c77SSepherosa Ziehau static void			hn_set_ring_inuse(struct hn_softc *, int);
31815516c77SSepherosa Ziehau static int			hn_synth_attach(struct hn_softc *, int);
31915516c77SSepherosa Ziehau static void			hn_synth_detach(struct hn_softc *);
32015516c77SSepherosa Ziehau static int			hn_synth_alloc_subchans(struct hn_softc *,
32115516c77SSepherosa Ziehau 				    int *);
3222494d735SSepherosa Ziehau static bool			hn_synth_attachable(const struct hn_softc *);
32315516c77SSepherosa Ziehau static void			hn_suspend(struct hn_softc *);
32415516c77SSepherosa Ziehau static void			hn_suspend_data(struct hn_softc *);
32515516c77SSepherosa Ziehau static void			hn_suspend_mgmt(struct hn_softc *);
32615516c77SSepherosa Ziehau static void			hn_resume(struct hn_softc *);
32715516c77SSepherosa Ziehau static void			hn_resume_data(struct hn_softc *);
32815516c77SSepherosa Ziehau static void			hn_resume_mgmt(struct hn_softc *);
32915516c77SSepherosa Ziehau static void			hn_suspend_mgmt_taskfunc(void *, int);
33025641fc7SSepherosa Ziehau static void			hn_chan_drain(struct hn_softc *,
33125641fc7SSepherosa Ziehau 				    struct vmbus_channel *);
332b3b75d9cSSepherosa Ziehau static void			hn_disable_rx(struct hn_softc *);
333b3b75d9cSSepherosa Ziehau static void			hn_drain_rxtx(struct hn_softc *, int);
3346c1204dfSSepherosa Ziehau static void			hn_polling(struct hn_softc *, u_int);
3356c1204dfSSepherosa Ziehau static void			hn_chan_polling(struct vmbus_channel *, u_int);
33615516c77SSepherosa Ziehau 
33715516c77SSepherosa Ziehau static void			hn_update_link_status(struct hn_softc *);
33815516c77SSepherosa Ziehau static void			hn_change_network(struct hn_softc *);
33915516c77SSepherosa Ziehau static void			hn_link_taskfunc(void *, int);
34015516c77SSepherosa Ziehau static void			hn_netchg_init_taskfunc(void *, int);
34115516c77SSepherosa Ziehau static void			hn_netchg_status_taskfunc(void *, int);
34215516c77SSepherosa Ziehau static void			hn_link_status(struct hn_softc *);
34315516c77SSepherosa Ziehau 
34415516c77SSepherosa Ziehau static int			hn_create_rx_data(struct hn_softc *, int);
34515516c77SSepherosa Ziehau static void			hn_destroy_rx_data(struct hn_softc *);
34615516c77SSepherosa Ziehau static int			hn_check_iplen(const struct mbuf *, int);
347f1b0a43fSSepherosa Ziehau static int			hn_set_rxfilter(struct hn_softc *, uint32_t);
348c08f7b2cSSepherosa Ziehau static int			hn_rxfilter_config(struct hn_softc *);
34934d68912SSepherosa Ziehau #ifndef RSS
35015516c77SSepherosa Ziehau static int			hn_rss_reconfig(struct hn_softc *);
35134d68912SSepherosa Ziehau #endif
352afd4971bSSepherosa Ziehau static void			hn_rss_ind_fixup(struct hn_softc *);
35315516c77SSepherosa Ziehau static int			hn_rxpkt(struct hn_rx_ring *, const void *,
35415516c77SSepherosa Ziehau 				    int, const struct hn_rxinfo *);
35515516c77SSepherosa Ziehau 
35615516c77SSepherosa Ziehau static int			hn_tx_ring_create(struct hn_softc *, int);
35715516c77SSepherosa Ziehau static void			hn_tx_ring_destroy(struct hn_tx_ring *);
35815516c77SSepherosa Ziehau static int			hn_create_tx_data(struct hn_softc *, int);
35915516c77SSepherosa Ziehau static void			hn_fixup_tx_data(struct hn_softc *);
36015516c77SSepherosa Ziehau static void			hn_destroy_tx_data(struct hn_softc *);
36115516c77SSepherosa Ziehau static void			hn_txdesc_dmamap_destroy(struct hn_txdesc *);
36225641fc7SSepherosa Ziehau static void			hn_txdesc_gc(struct hn_tx_ring *,
36325641fc7SSepherosa Ziehau 				    struct hn_txdesc *);
364dc13fee6SSepherosa Ziehau static int			hn_encap(struct ifnet *, struct hn_tx_ring *,
36515516c77SSepherosa Ziehau 				    struct hn_txdesc *, struct mbuf **);
36615516c77SSepherosa Ziehau static int			hn_txpkt(struct ifnet *, struct hn_tx_ring *,
36715516c77SSepherosa Ziehau 				    struct hn_txdesc *);
36815516c77SSepherosa Ziehau static void			hn_set_chim_size(struct hn_softc *, int);
36915516c77SSepherosa Ziehau static void			hn_set_tso_maxsize(struct hn_softc *, int, int);
37015516c77SSepherosa Ziehau static bool			hn_tx_ring_pending(struct hn_tx_ring *);
37115516c77SSepherosa Ziehau static void			hn_tx_ring_qflush(struct hn_tx_ring *);
37215516c77SSepherosa Ziehau static void			hn_resume_tx(struct hn_softc *, int);
373dc13fee6SSepherosa Ziehau static void			hn_set_txagg(struct hn_softc *);
374dc13fee6SSepherosa Ziehau static void			*hn_try_txagg(struct ifnet *,
375dc13fee6SSepherosa Ziehau 				    struct hn_tx_ring *, struct hn_txdesc *,
376dc13fee6SSepherosa Ziehau 				    int);
37715516c77SSepherosa Ziehau static int			hn_get_txswq_depth(const struct hn_tx_ring *);
37815516c77SSepherosa Ziehau static void			hn_txpkt_done(struct hn_nvs_sendctx *,
37915516c77SSepherosa Ziehau 				    struct hn_softc *, struct vmbus_channel *,
38015516c77SSepherosa Ziehau 				    const void *, int);
38115516c77SSepherosa Ziehau static int			hn_txpkt_sglist(struct hn_tx_ring *,
38215516c77SSepherosa Ziehau 				    struct hn_txdesc *);
38315516c77SSepherosa Ziehau static int			hn_txpkt_chim(struct hn_tx_ring *,
38415516c77SSepherosa Ziehau 				    struct hn_txdesc *);
38515516c77SSepherosa Ziehau static int			hn_xmit(struct hn_tx_ring *, int);
38615516c77SSepherosa Ziehau static void			hn_xmit_taskfunc(void *, int);
38715516c77SSepherosa Ziehau static void			hn_xmit_txeof(struct hn_tx_ring *);
38815516c77SSepherosa Ziehau static void			hn_xmit_txeof_taskfunc(void *, int);
38923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
39015516c77SSepherosa Ziehau static int			hn_start_locked(struct hn_tx_ring *, int);
39115516c77SSepherosa Ziehau static void			hn_start_taskfunc(void *, int);
39215516c77SSepherosa Ziehau static void			hn_start_txeof(struct hn_tx_ring *);
39315516c77SSepherosa Ziehau static void			hn_start_txeof_taskfunc(void *, int);
39423bf9e15SSepherosa Ziehau #endif
39515516c77SSepherosa Ziehau 
39615516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
39715516c77SSepherosa Ziehau     "Hyper-V network interface");
39815516c77SSepherosa Ziehau 
39915516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */
40015516c77SSepherosa Ziehau static int			hn_trust_hosttcp = 1;
40115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN,
40215516c77SSepherosa Ziehau     &hn_trust_hosttcp, 0,
40315516c77SSepherosa Ziehau     "Trust tcp segement verification on host side, "
40415516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
40515516c77SSepherosa Ziehau 
40615516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */
40715516c77SSepherosa Ziehau static int			hn_trust_hostudp = 1;
40815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN,
40915516c77SSepherosa Ziehau     &hn_trust_hostudp, 0,
41015516c77SSepherosa Ziehau     "Trust udp datagram verification on host side, "
41115516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
41215516c77SSepherosa Ziehau 
41315516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */
41415516c77SSepherosa Ziehau static int			hn_trust_hostip = 1;
41515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN,
41615516c77SSepherosa Ziehau     &hn_trust_hostip, 0,
41715516c77SSepherosa Ziehau     "Trust ip packet verification on host side, "
41815516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
41915516c77SSepherosa Ziehau 
42015516c77SSepherosa Ziehau /* Limit TSO burst size */
42115516c77SSepherosa Ziehau static int			hn_tso_maxlen = IP_MAXPACKET;
42215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN,
42315516c77SSepherosa Ziehau     &hn_tso_maxlen, 0, "TSO burst limit");
42415516c77SSepherosa Ziehau 
42515516c77SSepherosa Ziehau /* Limit chimney send size */
42615516c77SSepherosa Ziehau static int			hn_tx_chimney_size = 0;
42715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN,
42815516c77SSepherosa Ziehau     &hn_tx_chimney_size, 0, "Chimney send packet size limit");
42915516c77SSepherosa Ziehau 
43015516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */
43115516c77SSepherosa Ziehau static int			hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF;
43215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN,
43315516c77SSepherosa Ziehau     &hn_direct_tx_size, 0, "Size of the packet for direct transmission");
43415516c77SSepherosa Ziehau 
43515516c77SSepherosa Ziehau /* # of LRO entries per RX ring */
43615516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
43715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
43815516c77SSepherosa Ziehau static int			hn_lro_entry_count = HN_LROENT_CNT_DEF;
43915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN,
44015516c77SSepherosa Ziehau     &hn_lro_entry_count, 0, "LRO entry count");
44115516c77SSepherosa Ziehau #endif
44215516c77SSepherosa Ziehau #endif
44315516c77SSepherosa Ziehau 
444fdd0222aSSepherosa Ziehau static int			hn_tx_taskq_cnt = 1;
445fdd0222aSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_cnt, CTLFLAG_RDTUN,
446fdd0222aSSepherosa Ziehau     &hn_tx_taskq_cnt, 0, "# of TX taskqueues");
447fdd0222aSSepherosa Ziehau 
4480e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_INDEP	0
4490e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_GLOBAL	1
4500e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_EVTTQ	2
4510e11868dSSepherosa Ziehau 
4520e11868dSSepherosa Ziehau static int			hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
4530e11868dSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_mode, CTLFLAG_RDTUN,
4540e11868dSSepherosa Ziehau     &hn_tx_taskq_mode, 0, "TX taskqueue modes: "
4550e11868dSSepherosa Ziehau     "0 - independent, 1 - share global tx taskqs, 2 - share event taskqs");
4560e11868dSSepherosa Ziehau 
45715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
45815516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 0;
45915516c77SSepherosa Ziehau #else
46015516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 1;
46115516c77SSepherosa Ziehau #endif
46215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD,
46315516c77SSepherosa Ziehau     &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors");
46415516c77SSepherosa Ziehau 
46523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
46615516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */
46715516c77SSepherosa Ziehau static int			hn_use_if_start = 0;
46815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN,
46915516c77SSepherosa Ziehau     &hn_use_if_start, 0, "Use if_start TX method");
47023bf9e15SSepherosa Ziehau #endif
47115516c77SSepherosa Ziehau 
47215516c77SSepherosa Ziehau /* # of channels to use */
47315516c77SSepherosa Ziehau static int			hn_chan_cnt = 0;
47415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN,
47515516c77SSepherosa Ziehau     &hn_chan_cnt, 0,
47615516c77SSepherosa Ziehau     "# of channels to use; each channel has one RX ring and one TX ring");
47715516c77SSepherosa Ziehau 
47815516c77SSepherosa Ziehau /* # of transmit rings to use */
47915516c77SSepherosa Ziehau static int			hn_tx_ring_cnt = 0;
48015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN,
48115516c77SSepherosa Ziehau     &hn_tx_ring_cnt, 0, "# of TX rings to use");
48215516c77SSepherosa Ziehau 
48315516c77SSepherosa Ziehau /* Software TX ring deptch */
48415516c77SSepherosa Ziehau static int			hn_tx_swq_depth = 0;
48515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN,
48615516c77SSepherosa Ziehau     &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING");
48715516c77SSepherosa Ziehau 
48815516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */
48915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
49015516c77SSepherosa Ziehau static u_int			hn_lro_mbufq_depth = 0;
49115516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN,
49215516c77SSepherosa Ziehau     &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue");
49315516c77SSepherosa Ziehau #endif
49415516c77SSepherosa Ziehau 
495dc13fee6SSepherosa Ziehau /* Packet transmission aggregation size limit */
496dc13fee6SSepherosa Ziehau static int			hn_tx_agg_size = -1;
497dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN,
498dc13fee6SSepherosa Ziehau     &hn_tx_agg_size, 0, "Packet transmission aggregation size limit");
499dc13fee6SSepherosa Ziehau 
500dc13fee6SSepherosa Ziehau /* Packet transmission aggregation count limit */
501fa915c4dSSepherosa Ziehau static int			hn_tx_agg_pkts = -1;
502dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN,
503dc13fee6SSepherosa Ziehau     &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit");
504dc13fee6SSepherosa Ziehau 
50515516c77SSepherosa Ziehau static u_int			hn_cpu_index;	/* next CPU for channel */
506fdd0222aSSepherosa Ziehau static struct taskqueue		**hn_tx_taskque;/* shared TX taskqueues */
50715516c77SSepherosa Ziehau 
50834d68912SSepherosa Ziehau #ifndef RSS
50915516c77SSepherosa Ziehau static const uint8_t
51015516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
51115516c77SSepherosa Ziehau 	0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
51215516c77SSepherosa Ziehau 	0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
51315516c77SSepherosa Ziehau 	0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
51415516c77SSepherosa Ziehau 	0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
51515516c77SSepherosa Ziehau 	0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
51615516c77SSepherosa Ziehau };
51734d68912SSepherosa Ziehau #endif	/* !RSS */
51815516c77SSepherosa Ziehau 
51915516c77SSepherosa Ziehau static device_method_t hn_methods[] = {
52015516c77SSepherosa Ziehau 	/* Device interface */
52115516c77SSepherosa Ziehau 	DEVMETHOD(device_probe,		hn_probe),
52215516c77SSepherosa Ziehau 	DEVMETHOD(device_attach,	hn_attach),
52315516c77SSepherosa Ziehau 	DEVMETHOD(device_detach,	hn_detach),
52415516c77SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	hn_shutdown),
52515516c77SSepherosa Ziehau 	DEVMETHOD_END
52615516c77SSepherosa Ziehau };
52715516c77SSepherosa Ziehau 
52815516c77SSepherosa Ziehau static driver_t hn_driver = {
52915516c77SSepherosa Ziehau 	"hn",
53015516c77SSepherosa Ziehau 	hn_methods,
53115516c77SSepherosa Ziehau 	sizeof(struct hn_softc)
53215516c77SSepherosa Ziehau };
53315516c77SSepherosa Ziehau 
53415516c77SSepherosa Ziehau static devclass_t hn_devclass;
53515516c77SSepherosa Ziehau 
53615516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0);
53715516c77SSepherosa Ziehau MODULE_VERSION(hn, 1);
53815516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1);
53915516c77SSepherosa Ziehau 
54015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
54115516c77SSepherosa Ziehau static void
54215516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim)
54315516c77SSepherosa Ziehau {
54415516c77SSepherosa Ziehau 	int i;
54515516c77SSepherosa Ziehau 
546a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
54715516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim;
54815516c77SSepherosa Ziehau }
54915516c77SSepherosa Ziehau #endif
55015516c77SSepherosa Ziehau 
55115516c77SSepherosa Ziehau static int
55215516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd)
55315516c77SSepherosa Ziehau {
55415516c77SSepherosa Ziehau 
55515516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
55615516c77SSepherosa Ziehau 	    txd->chim_size == 0, ("invalid rndis sglist txd"));
55715516c77SSepherosa Ziehau 	return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA,
55815516c77SSepherosa Ziehau 	    &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt));
55915516c77SSepherosa Ziehau }
56015516c77SSepherosa Ziehau 
56115516c77SSepherosa Ziehau static int
56215516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd)
56315516c77SSepherosa Ziehau {
56415516c77SSepherosa Ziehau 	struct hn_nvs_rndis rndis;
56515516c77SSepherosa Ziehau 
56615516c77SSepherosa Ziehau 	KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID &&
56715516c77SSepherosa Ziehau 	    txd->chim_size > 0, ("invalid rndis chim txd"));
56815516c77SSepherosa Ziehau 
56915516c77SSepherosa Ziehau 	rndis.nvs_type = HN_NVS_TYPE_RNDIS;
57015516c77SSepherosa Ziehau 	rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA;
57115516c77SSepherosa Ziehau 	rndis.nvs_chim_idx = txd->chim_index;
57215516c77SSepherosa Ziehau 	rndis.nvs_chim_sz = txd->chim_size;
57315516c77SSepherosa Ziehau 
57415516c77SSepherosa Ziehau 	return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC,
57515516c77SSepherosa Ziehau 	    &rndis, sizeof(rndis), &txd->send_ctx));
57615516c77SSepherosa Ziehau }
57715516c77SSepherosa Ziehau 
57815516c77SSepherosa Ziehau static __inline uint32_t
57915516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc)
58015516c77SSepherosa Ziehau {
58115516c77SSepherosa Ziehau 	int i, bmap_cnt = sc->hn_chim_bmap_cnt;
58215516c77SSepherosa Ziehau 	u_long *bmap = sc->hn_chim_bmap;
58315516c77SSepherosa Ziehau 	uint32_t ret = HN_NVS_CHIM_IDX_INVALID;
58415516c77SSepherosa Ziehau 
58515516c77SSepherosa Ziehau 	for (i = 0; i < bmap_cnt; ++i) {
58615516c77SSepherosa Ziehau 		int idx;
58715516c77SSepherosa Ziehau 
58815516c77SSepherosa Ziehau 		idx = ffsl(~bmap[i]);
58915516c77SSepherosa Ziehau 		if (idx == 0)
59015516c77SSepherosa Ziehau 			continue;
59115516c77SSepherosa Ziehau 
59215516c77SSepherosa Ziehau 		--idx; /* ffsl is 1-based */
59315516c77SSepherosa Ziehau 		KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt,
59415516c77SSepherosa Ziehau 		    ("invalid i %d and idx %d", i, idx));
59515516c77SSepherosa Ziehau 
59615516c77SSepherosa Ziehau 		if (atomic_testandset_long(&bmap[i], idx))
59715516c77SSepherosa Ziehau 			continue;
59815516c77SSepherosa Ziehau 
59915516c77SSepherosa Ziehau 		ret = i * LONG_BIT + idx;
60015516c77SSepherosa Ziehau 		break;
60115516c77SSepherosa Ziehau 	}
60215516c77SSepherosa Ziehau 	return (ret);
60315516c77SSepherosa Ziehau }
60415516c77SSepherosa Ziehau 
60515516c77SSepherosa Ziehau static __inline void
60615516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx)
60715516c77SSepherosa Ziehau {
60815516c77SSepherosa Ziehau 	u_long mask;
60915516c77SSepherosa Ziehau 	uint32_t idx;
61015516c77SSepherosa Ziehau 
61115516c77SSepherosa Ziehau 	idx = chim_idx / LONG_BIT;
61215516c77SSepherosa Ziehau 	KASSERT(idx < sc->hn_chim_bmap_cnt,
61315516c77SSepherosa Ziehau 	    ("invalid chimney index 0x%x", chim_idx));
61415516c77SSepherosa Ziehau 
61515516c77SSepherosa Ziehau 	mask = 1UL << (chim_idx % LONG_BIT);
61615516c77SSepherosa Ziehau 	KASSERT(sc->hn_chim_bmap[idx] & mask,
61715516c77SSepherosa Ziehau 	    ("index bitmap 0x%lx, chimney index %u, "
61815516c77SSepherosa Ziehau 	     "bitmap idx %d, bitmask 0x%lx",
61915516c77SSepherosa Ziehau 	     sc->hn_chim_bmap[idx], chim_idx, idx, mask));
62015516c77SSepherosa Ziehau 
62115516c77SSepherosa Ziehau 	atomic_clear_long(&sc->hn_chim_bmap[idx], mask);
62215516c77SSepherosa Ziehau }
62315516c77SSepherosa Ziehau 
624edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
625*cc0c6ebcSSepherosa Ziehau 
626*cc0c6ebcSSepherosa Ziehau #define PULLUP_HDR(m, len)				\
627*cc0c6ebcSSepherosa Ziehau do {							\
628*cc0c6ebcSSepherosa Ziehau 	if (__predict_false((m)->m_len < (len))) {	\
629*cc0c6ebcSSepherosa Ziehau 		(m) = m_pullup((m), (len));		\
630*cc0c6ebcSSepherosa Ziehau 		if ((m) == NULL)			\
631*cc0c6ebcSSepherosa Ziehau 			return (NULL);			\
632*cc0c6ebcSSepherosa Ziehau 	}						\
633*cc0c6ebcSSepherosa Ziehau } while (0)
634*cc0c6ebcSSepherosa Ziehau 
635edd3f315SSepherosa Ziehau /*
636edd3f315SSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
637edd3f315SSepherosa Ziehau  */
638edd3f315SSepherosa Ziehau static __inline struct mbuf *
639edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head)
640edd3f315SSepherosa Ziehau {
641edd3f315SSepherosa Ziehau 	struct ether_vlan_header *evl;
642edd3f315SSepherosa Ziehau 	struct tcphdr *th;
643edd3f315SSepherosa Ziehau 	int ehlen;
644edd3f315SSepherosa Ziehau 
645edd3f315SSepherosa Ziehau 	KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable"));
646edd3f315SSepherosa Ziehau 
647edd3f315SSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
648edd3f315SSepherosa Ziehau 	evl = mtod(m_head, struct ether_vlan_header *);
649edd3f315SSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
650edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
651edd3f315SSepherosa Ziehau 	else
652edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
653edd3f315SSepherosa Ziehau 
654edd3f315SSepherosa Ziehau #ifdef INET
655edd3f315SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
656edd3f315SSepherosa Ziehau 		struct ip *ip;
657edd3f315SSepherosa Ziehau 		int iphlen;
658edd3f315SSepherosa Ziehau 
659edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
660edd3f315SSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
661edd3f315SSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
662edd3f315SSepherosa Ziehau 
663edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
664edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + iphlen);
665edd3f315SSepherosa Ziehau 
666edd3f315SSepherosa Ziehau 		ip->ip_len = 0;
667edd3f315SSepherosa Ziehau 		ip->ip_sum = 0;
668edd3f315SSepherosa Ziehau 		th->th_sum = in_pseudo(ip->ip_src.s_addr,
669edd3f315SSepherosa Ziehau 		    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
670edd3f315SSepherosa Ziehau 	}
671edd3f315SSepherosa Ziehau #endif
672edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET)
673edd3f315SSepherosa Ziehau 	else
674edd3f315SSepherosa Ziehau #endif
675edd3f315SSepherosa Ziehau #ifdef INET6
676edd3f315SSepherosa Ziehau 	{
677edd3f315SSepherosa Ziehau 		struct ip6_hdr *ip6;
678edd3f315SSepherosa Ziehau 
679edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
680edd3f315SSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
681edd3f315SSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP) {
682edd3f315SSepherosa Ziehau 			m_freem(m_head);
683edd3f315SSepherosa Ziehau 			return (NULL);
684edd3f315SSepherosa Ziehau 		}
685edd3f315SSepherosa Ziehau 
686edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
687edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + sizeof(*ip6));
688edd3f315SSepherosa Ziehau 
689edd3f315SSepherosa Ziehau 		ip6->ip6_plen = 0;
690edd3f315SSepherosa Ziehau 		th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
691edd3f315SSepherosa Ziehau 	}
692edd3f315SSepherosa Ziehau #endif
693edd3f315SSepherosa Ziehau 	return (m_head);
694edd3f315SSepherosa Ziehau 
695edd3f315SSepherosa Ziehau }
696*cc0c6ebcSSepherosa Ziehau 
697*cc0c6ebcSSepherosa Ziehau /*
698*cc0c6ebcSSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
699*cc0c6ebcSSepherosa Ziehau  */
700*cc0c6ebcSSepherosa Ziehau static __inline struct mbuf *
701*cc0c6ebcSSepherosa Ziehau hn_check_tcpsyn(struct mbuf *m_head, int *tcpsyn)
702*cc0c6ebcSSepherosa Ziehau {
703*cc0c6ebcSSepherosa Ziehau 	const struct ether_vlan_header *evl;
704*cc0c6ebcSSepherosa Ziehau 	const struct tcphdr *th;
705*cc0c6ebcSSepherosa Ziehau 	int ehlen;
706*cc0c6ebcSSepherosa Ziehau 
707*cc0c6ebcSSepherosa Ziehau 	*tcpsyn = 0;
708*cc0c6ebcSSepherosa Ziehau 
709*cc0c6ebcSSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
710*cc0c6ebcSSepherosa Ziehau 	evl = mtod(m_head, const struct ether_vlan_header *);
711*cc0c6ebcSSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
712*cc0c6ebcSSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
713*cc0c6ebcSSepherosa Ziehau 	else
714*cc0c6ebcSSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
715*cc0c6ebcSSepherosa Ziehau 
716*cc0c6ebcSSepherosa Ziehau #ifdef INET
717*cc0c6ebcSSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_IP_TCP) {
718*cc0c6ebcSSepherosa Ziehau 		const struct ip *ip;
719*cc0c6ebcSSepherosa Ziehau 		int iphlen;
720*cc0c6ebcSSepherosa Ziehau 
721*cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
722*cc0c6ebcSSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
723*cc0c6ebcSSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
724*cc0c6ebcSSepherosa Ziehau 
725*cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
726*cc0c6ebcSSepherosa Ziehau 		th = mtodo(m_head, ehlen + iphlen);
727*cc0c6ebcSSepherosa Ziehau 		if (th->th_flags & TH_SYN)
728*cc0c6ebcSSepherosa Ziehau 			*tcpsyn = 1;
729*cc0c6ebcSSepherosa Ziehau 	}
730*cc0c6ebcSSepherosa Ziehau #endif
731*cc0c6ebcSSepherosa Ziehau #if defined(INET6) && defined(INET)
732*cc0c6ebcSSepherosa Ziehau 	else
733*cc0c6ebcSSepherosa Ziehau #endif
734*cc0c6ebcSSepherosa Ziehau #ifdef INET6
735*cc0c6ebcSSepherosa Ziehau 	{
736*cc0c6ebcSSepherosa Ziehau 		const struct ip6_hdr *ip6;
737*cc0c6ebcSSepherosa Ziehau 
738*cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
739*cc0c6ebcSSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
740*cc0c6ebcSSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP)
741*cc0c6ebcSSepherosa Ziehau 			return (m_head);
742*cc0c6ebcSSepherosa Ziehau 
743*cc0c6ebcSSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
744*cc0c6ebcSSepherosa Ziehau 		th = mtodo(m_head, ehlen + sizeof(*ip6));
745*cc0c6ebcSSepherosa Ziehau 		if (th->th_flags & TH_SYN)
746*cc0c6ebcSSepherosa Ziehau 			*tcpsyn = 1;
747*cc0c6ebcSSepherosa Ziehau 	}
748*cc0c6ebcSSepherosa Ziehau #endif
749*cc0c6ebcSSepherosa Ziehau 	return (m_head);
750*cc0c6ebcSSepherosa Ziehau }
751*cc0c6ebcSSepherosa Ziehau 
752*cc0c6ebcSSepherosa Ziehau #undef PULLUP_HDR
753*cc0c6ebcSSepherosa Ziehau 
754edd3f315SSepherosa Ziehau #endif	/* INET6 || INET */
755edd3f315SSepherosa Ziehau 
75615516c77SSepherosa Ziehau static int
757f1b0a43fSSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc, uint32_t filter)
758f1b0a43fSSepherosa Ziehau {
759f1b0a43fSSepherosa Ziehau 	int error = 0;
760f1b0a43fSSepherosa Ziehau 
761f1b0a43fSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
762f1b0a43fSSepherosa Ziehau 
763f1b0a43fSSepherosa Ziehau 	if (sc->hn_rx_filter != filter) {
764f1b0a43fSSepherosa Ziehau 		error = hn_rndis_set_rxfilter(sc, filter);
765f1b0a43fSSepherosa Ziehau 		if (!error)
766f1b0a43fSSepherosa Ziehau 			sc->hn_rx_filter = filter;
767f1b0a43fSSepherosa Ziehau 	}
768f1b0a43fSSepherosa Ziehau 	return (error);
769f1b0a43fSSepherosa Ziehau }
770f1b0a43fSSepherosa Ziehau 
771f1b0a43fSSepherosa Ziehau static int
772c08f7b2cSSepherosa Ziehau hn_rxfilter_config(struct hn_softc *sc)
77315516c77SSepherosa Ziehau {
77415516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
77515516c77SSepherosa Ziehau 	uint32_t filter;
77615516c77SSepherosa Ziehau 
77715516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
77815516c77SSepherosa Ziehau 
7795bdfd3fdSDexuan Cui 	if ((ifp->if_flags & IFF_PROMISC) ||
7805bdfd3fdSDexuan Cui 	    (sc->hn_flags & HN_FLAG_VF)) {
78115516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_PROMISCUOUS;
78215516c77SSepherosa Ziehau 	} else {
78315516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_DIRECTED;
78415516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_BROADCAST)
78515516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_BROADCAST;
78615516c77SSepherosa Ziehau 		/* TODO: support multicast list */
78715516c77SSepherosa Ziehau 		if ((ifp->if_flags & IFF_ALLMULTI) ||
78815516c77SSepherosa Ziehau 		    !TAILQ_EMPTY(&ifp->if_multiaddrs))
78915516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
79015516c77SSepherosa Ziehau 	}
791f1b0a43fSSepherosa Ziehau 	return (hn_set_rxfilter(sc, filter));
79215516c77SSepherosa Ziehau }
79315516c77SSepherosa Ziehau 
794dc13fee6SSepherosa Ziehau static void
795dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc)
796dc13fee6SSepherosa Ziehau {
797dc13fee6SSepherosa Ziehau 	uint32_t size, pkts;
798dc13fee6SSepherosa Ziehau 	int i;
799dc13fee6SSepherosa Ziehau 
800dc13fee6SSepherosa Ziehau 	/*
801dc13fee6SSepherosa Ziehau 	 * Setup aggregation size.
802dc13fee6SSepherosa Ziehau 	 */
803dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_size < 0)
804dc13fee6SSepherosa Ziehau 		size = UINT32_MAX;
805dc13fee6SSepherosa Ziehau 	else
806dc13fee6SSepherosa Ziehau 		size = sc->hn_agg_size;
807dc13fee6SSepherosa Ziehau 
808dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_size < size)
809dc13fee6SSepherosa Ziehau 		size = sc->hn_rndis_agg_size;
810dc13fee6SSepherosa Ziehau 
811a4364cfeSSepherosa Ziehau 	/* NOTE: We only aggregate packets using chimney sending buffers. */
812a4364cfeSSepherosa Ziehau 	if (size > (uint32_t)sc->hn_chim_szmax)
813a4364cfeSSepherosa Ziehau 		size = sc->hn_chim_szmax;
814a4364cfeSSepherosa Ziehau 
815dc13fee6SSepherosa Ziehau 	if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) {
816dc13fee6SSepherosa Ziehau 		/* Disable */
817dc13fee6SSepherosa Ziehau 		size = 0;
818dc13fee6SSepherosa Ziehau 		pkts = 0;
819dc13fee6SSepherosa Ziehau 		goto done;
820dc13fee6SSepherosa Ziehau 	}
821dc13fee6SSepherosa Ziehau 
822dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'int'. */
823dc13fee6SSepherosa Ziehau 	if (size > INT_MAX)
824dc13fee6SSepherosa Ziehau 		size = INT_MAX;
825dc13fee6SSepherosa Ziehau 
826dc13fee6SSepherosa Ziehau 	/*
827dc13fee6SSepherosa Ziehau 	 * Setup aggregation packet count.
828dc13fee6SSepherosa Ziehau 	 */
829dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_pkts < 0)
830dc13fee6SSepherosa Ziehau 		pkts = UINT32_MAX;
831dc13fee6SSepherosa Ziehau 	else
832dc13fee6SSepherosa Ziehau 		pkts = sc->hn_agg_pkts;
833dc13fee6SSepherosa Ziehau 
834dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_pkts < pkts)
835dc13fee6SSepherosa Ziehau 		pkts = sc->hn_rndis_agg_pkts;
836dc13fee6SSepherosa Ziehau 
837dc13fee6SSepherosa Ziehau 	if (pkts <= 1) {
838dc13fee6SSepherosa Ziehau 		/* Disable */
839dc13fee6SSepherosa Ziehau 		size = 0;
840dc13fee6SSepherosa Ziehau 		pkts = 0;
841dc13fee6SSepherosa Ziehau 		goto done;
842dc13fee6SSepherosa Ziehau 	}
843dc13fee6SSepherosa Ziehau 
844dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
845dc13fee6SSepherosa Ziehau 	if (pkts > SHRT_MAX)
846dc13fee6SSepherosa Ziehau 		pkts = SHRT_MAX;
847dc13fee6SSepherosa Ziehau 
848dc13fee6SSepherosa Ziehau done:
849dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
850dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_align > SHRT_MAX) {
851dc13fee6SSepherosa Ziehau 		/* Disable */
852dc13fee6SSepherosa Ziehau 		size = 0;
853dc13fee6SSepherosa Ziehau 		pkts = 0;
854dc13fee6SSepherosa Ziehau 	}
855dc13fee6SSepherosa Ziehau 
856dc13fee6SSepherosa Ziehau 	if (bootverbose) {
857dc13fee6SSepherosa Ziehau 		if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n",
858dc13fee6SSepherosa Ziehau 		    size, pkts, sc->hn_rndis_agg_align);
859dc13fee6SSepherosa Ziehau 	}
860dc13fee6SSepherosa Ziehau 
861dc13fee6SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
862dc13fee6SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
863dc13fee6SSepherosa Ziehau 
864dc13fee6SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
865dc13fee6SSepherosa Ziehau 		txr->hn_agg_szmax = size;
866dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktmax = pkts;
867dc13fee6SSepherosa Ziehau 		txr->hn_agg_align = sc->hn_rndis_agg_align;
868dc13fee6SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
869dc13fee6SSepherosa Ziehau 	}
870dc13fee6SSepherosa Ziehau }
871dc13fee6SSepherosa Ziehau 
87215516c77SSepherosa Ziehau static int
87315516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr)
87415516c77SSepherosa Ziehau {
87515516c77SSepherosa Ziehau 
87615516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet"));
87715516c77SSepherosa Ziehau 	if (hn_tx_swq_depth < txr->hn_txdesc_cnt)
87815516c77SSepherosa Ziehau 		return txr->hn_txdesc_cnt;
87915516c77SSepherosa Ziehau 	return hn_tx_swq_depth;
88015516c77SSepherosa Ziehau }
88115516c77SSepherosa Ziehau 
88234d68912SSepherosa Ziehau #ifndef RSS
88315516c77SSepherosa Ziehau static int
88415516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc)
88515516c77SSepherosa Ziehau {
88615516c77SSepherosa Ziehau 	int error;
88715516c77SSepherosa Ziehau 
88815516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
88915516c77SSepherosa Ziehau 
89015516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
89115516c77SSepherosa Ziehau 		return (ENXIO);
89215516c77SSepherosa Ziehau 
89315516c77SSepherosa Ziehau 	/*
89415516c77SSepherosa Ziehau 	 * Disable RSS first.
89515516c77SSepherosa Ziehau 	 *
89615516c77SSepherosa Ziehau 	 * NOTE:
89715516c77SSepherosa Ziehau 	 * Direct reconfiguration by setting the UNCHG flags does
89815516c77SSepherosa Ziehau 	 * _not_ work properly.
89915516c77SSepherosa Ziehau 	 */
90015516c77SSepherosa Ziehau 	if (bootverbose)
90115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "disable RSS\n");
90215516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE);
90315516c77SSepherosa Ziehau 	if (error) {
90415516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS disable failed\n");
90515516c77SSepherosa Ziehau 		return (error);
90615516c77SSepherosa Ziehau 	}
90715516c77SSepherosa Ziehau 
90815516c77SSepherosa Ziehau 	/*
90915516c77SSepherosa Ziehau 	 * Reenable the RSS w/ the updated RSS key or indirect
91015516c77SSepherosa Ziehau 	 * table.
91115516c77SSepherosa Ziehau 	 */
91215516c77SSepherosa Ziehau 	if (bootverbose)
91315516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "reconfig RSS\n");
91415516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
91515516c77SSepherosa Ziehau 	if (error) {
91615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS reconfig failed\n");
91715516c77SSepherosa Ziehau 		return (error);
91815516c77SSepherosa Ziehau 	}
91915516c77SSepherosa Ziehau 	return (0);
92015516c77SSepherosa Ziehau }
92134d68912SSepherosa Ziehau #endif	/* !RSS */
92215516c77SSepherosa Ziehau 
92315516c77SSepherosa Ziehau static void
924afd4971bSSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc)
92515516c77SSepherosa Ziehau {
92615516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
927afd4971bSSepherosa Ziehau 	int i, nchan;
92815516c77SSepherosa Ziehau 
929afd4971bSSepherosa Ziehau 	nchan = sc->hn_rx_ring_inuse;
93015516c77SSepherosa Ziehau 	KASSERT(nchan > 1, ("invalid # of channels %d", nchan));
93115516c77SSepherosa Ziehau 
93215516c77SSepherosa Ziehau 	/*
93315516c77SSepherosa Ziehau 	 * Check indirect table to make sure that all channels in it
93415516c77SSepherosa Ziehau 	 * can be used.
93515516c77SSepherosa Ziehau 	 */
93615516c77SSepherosa Ziehau 	for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
93715516c77SSepherosa Ziehau 		if (rss->rss_ind[i] >= nchan) {
93815516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp,
93915516c77SSepherosa Ziehau 			    "RSS indirect table %d fixup: %u -> %d\n",
94015516c77SSepherosa Ziehau 			    i, rss->rss_ind[i], nchan - 1);
94115516c77SSepherosa Ziehau 			rss->rss_ind[i] = nchan - 1;
94215516c77SSepherosa Ziehau 		}
94315516c77SSepherosa Ziehau 	}
94415516c77SSepherosa Ziehau }
94515516c77SSepherosa Ziehau 
94615516c77SSepherosa Ziehau static int
94715516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused)
94815516c77SSepherosa Ziehau {
94915516c77SSepherosa Ziehau 
95015516c77SSepherosa Ziehau 	return EOPNOTSUPP;
95115516c77SSepherosa Ziehau }
95215516c77SSepherosa Ziehau 
95315516c77SSepherosa Ziehau static void
95415516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
95515516c77SSepherosa Ziehau {
95615516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
95715516c77SSepherosa Ziehau 
95815516c77SSepherosa Ziehau 	ifmr->ifm_status = IFM_AVALID;
95915516c77SSepherosa Ziehau 	ifmr->ifm_active = IFM_ETHER;
96015516c77SSepherosa Ziehau 
96115516c77SSepherosa Ziehau 	if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) {
96215516c77SSepherosa Ziehau 		ifmr->ifm_active |= IFM_NONE;
96315516c77SSepherosa Ziehau 		return;
96415516c77SSepherosa Ziehau 	}
96515516c77SSepherosa Ziehau 	ifmr->ifm_status |= IFM_ACTIVE;
96615516c77SSepherosa Ziehau 	ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
96715516c77SSepherosa Ziehau }
96815516c77SSepherosa Ziehau 
9695bdfd3fdSDexuan Cui static void
9705bdfd3fdSDexuan Cui hn_update_vf_task(void *arg, int pending __unused)
9715bdfd3fdSDexuan Cui {
9725bdfd3fdSDexuan Cui 	struct hn_update_vf *uv = arg;
9735bdfd3fdSDexuan Cui 
9745bdfd3fdSDexuan Cui 	uv->rxr->hn_vf = uv->vf;
9755bdfd3fdSDexuan Cui }
9765bdfd3fdSDexuan Cui 
9775bdfd3fdSDexuan Cui static void
9785bdfd3fdSDexuan Cui hn_update_vf(struct hn_softc *sc, struct ifnet *vf)
9795bdfd3fdSDexuan Cui {
9805bdfd3fdSDexuan Cui 	struct hn_rx_ring *rxr;
9815bdfd3fdSDexuan Cui 	struct hn_update_vf uv;
9825bdfd3fdSDexuan Cui 	struct task task;
9835bdfd3fdSDexuan Cui 	int i;
9845bdfd3fdSDexuan Cui 
9855bdfd3fdSDexuan Cui 	HN_LOCK_ASSERT(sc);
9865bdfd3fdSDexuan Cui 
9875bdfd3fdSDexuan Cui 	TASK_INIT(&task, 0, hn_update_vf_task, &uv);
9885bdfd3fdSDexuan Cui 
9895bdfd3fdSDexuan Cui 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
9905bdfd3fdSDexuan Cui 		rxr = &sc->hn_rx_ring[i];
9915bdfd3fdSDexuan Cui 
9925bdfd3fdSDexuan Cui 		if (i < sc->hn_rx_ring_inuse) {
9935bdfd3fdSDexuan Cui 			uv.rxr = rxr;
9945bdfd3fdSDexuan Cui 			uv.vf = vf;
9955bdfd3fdSDexuan Cui 			vmbus_chan_run_task(rxr->hn_chan, &task);
9965bdfd3fdSDexuan Cui 		} else {
9975bdfd3fdSDexuan Cui 			rxr->hn_vf = vf;
9985bdfd3fdSDexuan Cui 		}
9995bdfd3fdSDexuan Cui 	}
10005bdfd3fdSDexuan Cui }
10015bdfd3fdSDexuan Cui 
10025bdfd3fdSDexuan Cui static void
10035bdfd3fdSDexuan Cui hn_set_vf(struct hn_softc *sc, struct ifnet *ifp, bool vf)
10045bdfd3fdSDexuan Cui {
10055bdfd3fdSDexuan Cui 	struct ifnet *hn_ifp;
10065bdfd3fdSDexuan Cui 
10075bdfd3fdSDexuan Cui 	HN_LOCK(sc);
10085bdfd3fdSDexuan Cui 
10095bdfd3fdSDexuan Cui 	if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
10105bdfd3fdSDexuan Cui 		goto out;
10115bdfd3fdSDexuan Cui 
10125bdfd3fdSDexuan Cui 	hn_ifp = sc->hn_ifp;
10135bdfd3fdSDexuan Cui 
10145bdfd3fdSDexuan Cui 	if (ifp == hn_ifp)
10155bdfd3fdSDexuan Cui 		goto out;
10165bdfd3fdSDexuan Cui 
10175bdfd3fdSDexuan Cui 	if (ifp->if_alloctype != IFT_ETHER)
10185bdfd3fdSDexuan Cui 		goto out;
10195bdfd3fdSDexuan Cui 
10205bdfd3fdSDexuan Cui 	/* Ignore lagg/vlan interfaces */
10215bdfd3fdSDexuan Cui 	if (strcmp(ifp->if_dname, "lagg") == 0 ||
10225bdfd3fdSDexuan Cui 	    strcmp(ifp->if_dname, "vlan") == 0)
10235bdfd3fdSDexuan Cui 		goto out;
10245bdfd3fdSDexuan Cui 
10255bdfd3fdSDexuan Cui 	if (bcmp(IF_LLADDR(ifp), IF_LLADDR(hn_ifp), ETHER_ADDR_LEN) != 0)
10265bdfd3fdSDexuan Cui 		goto out;
10275bdfd3fdSDexuan Cui 
10285bdfd3fdSDexuan Cui 	/* Now we're sure 'ifp' is a real VF device. */
10295bdfd3fdSDexuan Cui 	if (vf) {
10305bdfd3fdSDexuan Cui 		if (sc->hn_flags & HN_FLAG_VF)
10315bdfd3fdSDexuan Cui 			goto out;
10325bdfd3fdSDexuan Cui 
10335bdfd3fdSDexuan Cui 		sc->hn_flags |= HN_FLAG_VF;
10345bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
10355bdfd3fdSDexuan Cui 	} else {
10365bdfd3fdSDexuan Cui 		if (!(sc->hn_flags & HN_FLAG_VF))
10375bdfd3fdSDexuan Cui 			goto out;
10385bdfd3fdSDexuan Cui 
10395bdfd3fdSDexuan Cui 		sc->hn_flags &= ~HN_FLAG_VF;
10405bdfd3fdSDexuan Cui 		if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
10415bdfd3fdSDexuan Cui 			hn_rxfilter_config(sc);
10425bdfd3fdSDexuan Cui 		else
10435bdfd3fdSDexuan Cui 			hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE);
10445bdfd3fdSDexuan Cui 	}
10455bdfd3fdSDexuan Cui 
10465bdfd3fdSDexuan Cui 	hn_nvs_set_datapath(sc,
10475bdfd3fdSDexuan Cui 	    vf ? HN_NVS_DATAPATH_VF : HN_NVS_DATAPATH_SYNTHETIC);
10485bdfd3fdSDexuan Cui 
10495bdfd3fdSDexuan Cui 	hn_update_vf(sc, vf ? ifp : NULL);
10505bdfd3fdSDexuan Cui 
10515bdfd3fdSDexuan Cui 	if (vf) {
10525bdfd3fdSDexuan Cui 		hn_suspend_mgmt(sc);
10535bdfd3fdSDexuan Cui 		sc->hn_link_flags &=
10545bdfd3fdSDexuan Cui 		    ~(HN_LINK_FLAG_LINKUP | HN_LINK_FLAG_NETCHG);
10555bdfd3fdSDexuan Cui 		if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
10565bdfd3fdSDexuan Cui 	} else {
10575bdfd3fdSDexuan Cui 		hn_resume_mgmt(sc);
10585bdfd3fdSDexuan Cui 	}
10595bdfd3fdSDexuan Cui 
106033408a34SDexuan Cui 	devctl_notify("HYPERV_NIC_VF", if_name(hn_ifp),
106133408a34SDexuan Cui 	    vf ? "VF_UP" : "VF_DOWN", NULL);
106233408a34SDexuan Cui 
10635bdfd3fdSDexuan Cui 	if (bootverbose)
10645bdfd3fdSDexuan Cui 		if_printf(hn_ifp, "Data path is switched %s %s\n",
10655bdfd3fdSDexuan Cui 		    vf ? "to" : "from", if_name(ifp));
10665bdfd3fdSDexuan Cui out:
10675bdfd3fdSDexuan Cui 	HN_UNLOCK(sc);
10685bdfd3fdSDexuan Cui }
10695bdfd3fdSDexuan Cui 
10705bdfd3fdSDexuan Cui static void
10715bdfd3fdSDexuan Cui hn_ifnet_event(void *arg, struct ifnet *ifp, int event)
10725bdfd3fdSDexuan Cui {
10735bdfd3fdSDexuan Cui 	if (event != IFNET_EVENT_UP && event != IFNET_EVENT_DOWN)
10745bdfd3fdSDexuan Cui 		return;
10755bdfd3fdSDexuan Cui 
10765bdfd3fdSDexuan Cui 	hn_set_vf(arg, ifp, event == IFNET_EVENT_UP);
10775bdfd3fdSDexuan Cui }
10785bdfd3fdSDexuan Cui 
10795bdfd3fdSDexuan Cui static void
10805bdfd3fdSDexuan Cui hn_ifaddr_event(void *arg, struct ifnet *ifp)
10815bdfd3fdSDexuan Cui {
10825bdfd3fdSDexuan Cui 	hn_set_vf(arg, ifp, ifp->if_flags & IFF_UP);
10835bdfd3fdSDexuan Cui }
10845bdfd3fdSDexuan Cui 
108515516c77SSepherosa Ziehau /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
108615516c77SSepherosa Ziehau static const struct hyperv_guid g_net_vsc_device_type = {
108715516c77SSepherosa Ziehau 	.hv_guid = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
108815516c77SSepherosa Ziehau 		0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E}
108915516c77SSepherosa Ziehau };
109015516c77SSepherosa Ziehau 
109115516c77SSepherosa Ziehau static int
109215516c77SSepherosa Ziehau hn_probe(device_t dev)
109315516c77SSepherosa Ziehau {
109415516c77SSepherosa Ziehau 
109515516c77SSepherosa Ziehau 	if (VMBUS_PROBE_GUID(device_get_parent(dev), dev,
109615516c77SSepherosa Ziehau 	    &g_net_vsc_device_type) == 0) {
109715516c77SSepherosa Ziehau 		device_set_desc(dev, "Hyper-V Network Interface");
109815516c77SSepherosa Ziehau 		return BUS_PROBE_DEFAULT;
109915516c77SSepherosa Ziehau 	}
110015516c77SSepherosa Ziehau 	return ENXIO;
110115516c77SSepherosa Ziehau }
110215516c77SSepherosa Ziehau 
110315516c77SSepherosa Ziehau static int
110415516c77SSepherosa Ziehau hn_attach(device_t dev)
110515516c77SSepherosa Ziehau {
110615516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
110715516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
110815516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
110915516c77SSepherosa Ziehau 	uint8_t eaddr[ETHER_ADDR_LEN];
111015516c77SSepherosa Ziehau 	struct ifnet *ifp = NULL;
111115516c77SSepherosa Ziehau 	int error, ring_cnt, tx_ring_cnt;
111215516c77SSepherosa Ziehau 
111315516c77SSepherosa Ziehau 	sc->hn_dev = dev;
111415516c77SSepherosa Ziehau 	sc->hn_prichan = vmbus_get_channel(dev);
111515516c77SSepherosa Ziehau 	HN_LOCK_INIT(sc);
111615516c77SSepherosa Ziehau 
111715516c77SSepherosa Ziehau 	/*
1118dc13fee6SSepherosa Ziehau 	 * Initialize these tunables once.
1119dc13fee6SSepherosa Ziehau 	 */
1120dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = hn_tx_agg_size;
1121dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = hn_tx_agg_pkts;
1122dc13fee6SSepherosa Ziehau 
1123dc13fee6SSepherosa Ziehau 	/*
112415516c77SSepherosa Ziehau 	 * Setup taskqueue for transmission.
112515516c77SSepherosa Ziehau 	 */
11260e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_INDEP) {
1127fdd0222aSSepherosa Ziehau 		int i;
1128fdd0222aSSepherosa Ziehau 
1129fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs =
1130fdd0222aSSepherosa Ziehau 		    malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
1131fdd0222aSSepherosa Ziehau 		    M_DEVBUF, M_WAITOK);
1132fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i) {
1133fdd0222aSSepherosa Ziehau 			sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx",
1134fdd0222aSSepherosa Ziehau 			    M_WAITOK, taskqueue_thread_enqueue,
1135fdd0222aSSepherosa Ziehau 			    &sc->hn_tx_taskqs[i]);
1136fdd0222aSSepherosa Ziehau 			taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET,
1137fdd0222aSSepherosa Ziehau 			    "%s tx%d", device_get_nameunit(dev), i);
1138fdd0222aSSepherosa Ziehau 		}
11390e11868dSSepherosa Ziehau 	} else if (hn_tx_taskq_mode == HN_TX_TASKQ_M_GLOBAL) {
1140fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs = hn_tx_taskque;
114115516c77SSepherosa Ziehau 	}
114215516c77SSepherosa Ziehau 
114315516c77SSepherosa Ziehau 	/*
114415516c77SSepherosa Ziehau 	 * Setup taskqueue for mangement tasks, e.g. link status.
114515516c77SSepherosa Ziehau 	 */
114615516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK,
114715516c77SSepherosa Ziehau 	    taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0);
114815516c77SSepherosa Ziehau 	taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
114915516c77SSepherosa Ziehau 	    device_get_nameunit(dev));
115015516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
115115516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc);
115215516c77SSepherosa Ziehau 	TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0,
115315516c77SSepherosa Ziehau 	    hn_netchg_status_taskfunc, sc);
115415516c77SSepherosa Ziehau 
115515516c77SSepherosa Ziehau 	/*
115615516c77SSepherosa Ziehau 	 * Allocate ifnet and setup its name earlier, so that if_printf
115715516c77SSepherosa Ziehau 	 * can be used by functions, which will be called after
115815516c77SSepherosa Ziehau 	 * ether_ifattach().
115915516c77SSepherosa Ziehau 	 */
116015516c77SSepherosa Ziehau 	ifp = sc->hn_ifp = if_alloc(IFT_ETHER);
116115516c77SSepherosa Ziehau 	ifp->if_softc = sc;
116215516c77SSepherosa Ziehau 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
116315516c77SSepherosa Ziehau 
116415516c77SSepherosa Ziehau 	/*
116515516c77SSepherosa Ziehau 	 * Initialize ifmedia earlier so that it can be unconditionally
116615516c77SSepherosa Ziehau 	 * destroyed, if error happened later on.
116715516c77SSepherosa Ziehau 	 */
116815516c77SSepherosa Ziehau 	ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts);
116915516c77SSepherosa Ziehau 
117015516c77SSepherosa Ziehau 	/*
117115516c77SSepherosa Ziehau 	 * Figure out the # of RX rings (ring_cnt) and the # of TX rings
117215516c77SSepherosa Ziehau 	 * to use (tx_ring_cnt).
117315516c77SSepherosa Ziehau 	 *
117415516c77SSepherosa Ziehau 	 * NOTE:
117515516c77SSepherosa Ziehau 	 * The # of RX rings to use is same as the # of channels to use.
117615516c77SSepherosa Ziehau 	 */
117715516c77SSepherosa Ziehau 	ring_cnt = hn_chan_cnt;
117815516c77SSepherosa Ziehau 	if (ring_cnt <= 0) {
117915516c77SSepherosa Ziehau 		/* Default */
118015516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
118115516c77SSepherosa Ziehau 		if (ring_cnt > HN_RING_CNT_DEF_MAX)
118215516c77SSepherosa Ziehau 			ring_cnt = HN_RING_CNT_DEF_MAX;
118315516c77SSepherosa Ziehau 	} else if (ring_cnt > mp_ncpus) {
118415516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
118515516c77SSepherosa Ziehau 	}
118634d68912SSepherosa Ziehau #ifdef RSS
118734d68912SSepherosa Ziehau 	if (ring_cnt > rss_getnumbuckets())
118834d68912SSepherosa Ziehau 		ring_cnt = rss_getnumbuckets();
118934d68912SSepherosa Ziehau #endif
119015516c77SSepherosa Ziehau 
119115516c77SSepherosa Ziehau 	tx_ring_cnt = hn_tx_ring_cnt;
119215516c77SSepherosa Ziehau 	if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt)
119315516c77SSepherosa Ziehau 		tx_ring_cnt = ring_cnt;
119423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
119515516c77SSepherosa Ziehau 	if (hn_use_if_start) {
119615516c77SSepherosa Ziehau 		/* ifnet.if_start only needs one TX ring. */
119715516c77SSepherosa Ziehau 		tx_ring_cnt = 1;
119815516c77SSepherosa Ziehau 	}
119923bf9e15SSepherosa Ziehau #endif
120015516c77SSepherosa Ziehau 
120115516c77SSepherosa Ziehau 	/*
120215516c77SSepherosa Ziehau 	 * Set the leader CPU for channels.
120315516c77SSepherosa Ziehau 	 */
120415516c77SSepherosa Ziehau 	sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus;
120515516c77SSepherosa Ziehau 
120615516c77SSepherosa Ziehau 	/*
120715516c77SSepherosa Ziehau 	 * Create enough TX/RX rings, even if only limited number of
120815516c77SSepherosa Ziehau 	 * channels can be allocated.
120915516c77SSepherosa Ziehau 	 */
121015516c77SSepherosa Ziehau 	error = hn_create_tx_data(sc, tx_ring_cnt);
121115516c77SSepherosa Ziehau 	if (error)
121215516c77SSepherosa Ziehau 		goto failed;
121315516c77SSepherosa Ziehau 	error = hn_create_rx_data(sc, ring_cnt);
121415516c77SSepherosa Ziehau 	if (error)
121515516c77SSepherosa Ziehau 		goto failed;
121615516c77SSepherosa Ziehau 
121715516c77SSepherosa Ziehau 	/*
121815516c77SSepherosa Ziehau 	 * Create transaction context for NVS and RNDIS transactions.
121915516c77SSepherosa Ziehau 	 */
122015516c77SSepherosa Ziehau 	sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
122115516c77SSepherosa Ziehau 	    HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
122225641fc7SSepherosa Ziehau 	if (sc->hn_xact == NULL) {
122325641fc7SSepherosa Ziehau 		error = ENXIO;
122415516c77SSepherosa Ziehau 		goto failed;
122525641fc7SSepherosa Ziehau 	}
122625641fc7SSepherosa Ziehau 
122725641fc7SSepherosa Ziehau 	/*
122825641fc7SSepherosa Ziehau 	 * Install orphan handler for the revocation of this device's
122925641fc7SSepherosa Ziehau 	 * primary channel.
123025641fc7SSepherosa Ziehau 	 *
123125641fc7SSepherosa Ziehau 	 * NOTE:
123225641fc7SSepherosa Ziehau 	 * The processing order is critical here:
123325641fc7SSepherosa Ziehau 	 * Install the orphan handler, _before_ testing whether this
123425641fc7SSepherosa Ziehau 	 * device's primary channel has been revoked or not.
123525641fc7SSepherosa Ziehau 	 */
123625641fc7SSepherosa Ziehau 	vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact);
123725641fc7SSepherosa Ziehau 	if (vmbus_chan_is_revoked(sc->hn_prichan)) {
123825641fc7SSepherosa Ziehau 		error = ENXIO;
123925641fc7SSepherosa Ziehau 		goto failed;
124025641fc7SSepherosa Ziehau 	}
124115516c77SSepherosa Ziehau 
124215516c77SSepherosa Ziehau 	/*
124315516c77SSepherosa Ziehau 	 * Attach the synthetic parts, i.e. NVS and RNDIS.
124415516c77SSepherosa Ziehau 	 */
124515516c77SSepherosa Ziehau 	error = hn_synth_attach(sc, ETHERMTU);
124615516c77SSepherosa Ziehau 	if (error)
124715516c77SSepherosa Ziehau 		goto failed;
124815516c77SSepherosa Ziehau 
124915516c77SSepherosa Ziehau 	error = hn_rndis_get_eaddr(sc, eaddr);
125015516c77SSepherosa Ziehau 	if (error)
125115516c77SSepherosa Ziehau 		goto failed;
125215516c77SSepherosa Ziehau 
125315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
125415516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
125515516c77SSepherosa Ziehau 		/*
125615516c77SSepherosa Ziehau 		 * Reduce TCP segment aggregation limit for multiple
125715516c77SSepherosa Ziehau 		 * RX rings to increase ACK timeliness.
125815516c77SSepherosa Ziehau 		 */
125915516c77SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF);
126015516c77SSepherosa Ziehau 	}
126115516c77SSepherosa Ziehau #endif
126215516c77SSepherosa Ziehau 
126315516c77SSepherosa Ziehau 	/*
126415516c77SSepherosa Ziehau 	 * Fixup TX stuffs after synthetic parts are attached.
126515516c77SSepherosa Ziehau 	 */
126615516c77SSepherosa Ziehau 	hn_fixup_tx_data(sc);
126715516c77SSepherosa Ziehau 
126815516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
126915516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
127015516c77SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD,
127115516c77SSepherosa Ziehau 	    &sc->hn_nvs_ver, 0, "NVS version");
127215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version",
127315516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
127415516c77SSepherosa Ziehau 	    hn_ndis_version_sysctl, "A", "NDIS version");
127515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps",
127615516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
127715516c77SSepherosa Ziehau 	    hn_caps_sysctl, "A", "capabilities");
127815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist",
127915516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
128015516c77SSepherosa Ziehau 	    hn_hwassist_sysctl, "A", "hwassist");
128115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter",
128215516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
128315516c77SSepherosa Ziehau 	    hn_rxfilter_sysctl, "A", "rxfilter");
128415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash",
128515516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
128615516c77SSepherosa Ziehau 	    hn_rss_hash_sysctl, "A", "RSS hash");
128715516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size",
128815516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count");
128934d68912SSepherosa Ziehau #ifndef RSS
129034d68912SSepherosa Ziehau 	/*
129134d68912SSepherosa Ziehau 	 * Don't allow RSS key/indirect table changes, if RSS is defined.
129234d68912SSepherosa Ziehau 	 */
129315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key",
129415516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
129515516c77SSepherosa Ziehau 	    hn_rss_key_sysctl, "IU", "RSS key");
129615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind",
129715516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
129815516c77SSepherosa Ziehau 	    hn_rss_ind_sysctl, "IU", "RSS indirect table");
129934d68912SSepherosa Ziehau #endif
1300dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size",
1301dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_size, 0,
1302dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation size limit");
1303dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts",
1304dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0,
1305dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation count limit");
1306dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align",
1307dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_align, 0,
1308dc13fee6SSepherosa Ziehau 	    "RNDIS packet transmission aggregation alignment");
1309dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size",
1310dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
1311dc13fee6SSepherosa Ziehau 	    hn_txagg_size_sysctl, "I",
1312dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation size, 0 -- disable, -1 -- auto");
1313dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts",
1314dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
1315dc13fee6SSepherosa Ziehau 	    hn_txagg_pkts_sysctl, "I",
1316dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation packets, "
1317dc13fee6SSepherosa Ziehau 	    "0 -- disable, -1 -- auto");
13186c1204dfSSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "polling",
13196c1204dfSSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
13206c1204dfSSepherosa Ziehau 	    hn_polling_sysctl, "I",
13216c1204dfSSepherosa Ziehau 	    "Polling frequency: [100,1000000], 0 disable polling");
132240d60d6eSDexuan Cui 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf",
132340d60d6eSDexuan Cui 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
132440d60d6eSDexuan Cui 	    hn_vf_sysctl, "A", "Virtual Function's name");
132515516c77SSepherosa Ziehau 
132615516c77SSepherosa Ziehau 	/*
132715516c77SSepherosa Ziehau 	 * Setup the ifmedia, which has been initialized earlier.
132815516c77SSepherosa Ziehau 	 */
132915516c77SSepherosa Ziehau 	ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL);
133015516c77SSepherosa Ziehau 	ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO);
133115516c77SSepherosa Ziehau 	/* XXX ifmedia_set really should do this for us */
133215516c77SSepherosa Ziehau 	sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media;
133315516c77SSepherosa Ziehau 
133415516c77SSepherosa Ziehau 	/*
133515516c77SSepherosa Ziehau 	 * Setup the ifnet for this interface.
133615516c77SSepherosa Ziehau 	 */
133715516c77SSepherosa Ziehau 
133815516c77SSepherosa Ziehau 	ifp->if_baudrate = IF_Gbps(10);
133915516c77SSepherosa Ziehau 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
134015516c77SSepherosa Ziehau 	ifp->if_ioctl = hn_ioctl;
134115516c77SSepherosa Ziehau 	ifp->if_init = hn_init;
134223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
134315516c77SSepherosa Ziehau 	if (hn_use_if_start) {
134415516c77SSepherosa Ziehau 		int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]);
134515516c77SSepherosa Ziehau 
134615516c77SSepherosa Ziehau 		ifp->if_start = hn_start;
134715516c77SSepherosa Ziehau 		IFQ_SET_MAXLEN(&ifp->if_snd, qdepth);
134815516c77SSepherosa Ziehau 		ifp->if_snd.ifq_drv_maxlen = qdepth - 1;
134915516c77SSepherosa Ziehau 		IFQ_SET_READY(&ifp->if_snd);
135023bf9e15SSepherosa Ziehau 	} else
135123bf9e15SSepherosa Ziehau #endif
135223bf9e15SSepherosa Ziehau 	{
135315516c77SSepherosa Ziehau 		ifp->if_transmit = hn_transmit;
135415516c77SSepherosa Ziehau 		ifp->if_qflush = hn_xmit_qflush;
135515516c77SSepherosa Ziehau 	}
135615516c77SSepherosa Ziehau 
135715516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO;
135815516c77SSepherosa Ziehau #ifdef foo
135915516c77SSepherosa Ziehau 	/* We can't diff IPv6 packets from IPv4 packets on RX path. */
136015516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM_IPV6;
136115516c77SSepherosa Ziehau #endif
136215516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_VLAN) {
136315516c77SSepherosa Ziehau 		/* XXX not sure about VLAN_MTU. */
136415516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
136515516c77SSepherosa Ziehau 	}
136615516c77SSepherosa Ziehau 
136715516c77SSepherosa Ziehau 	ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist;
136815516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP_MASK)
136915516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM;
137015516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP6_MASK)
137115516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM_IPV6;
137215516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO4) {
137315516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO4;
137415516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP_TSO;
137515516c77SSepherosa Ziehau 	}
137615516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO6) {
137715516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO6;
137815516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP6_TSO;
137915516c77SSepherosa Ziehau 	}
138015516c77SSepherosa Ziehau 
138115516c77SSepherosa Ziehau 	/* Enable all available capabilities by default. */
138215516c77SSepherosa Ziehau 	ifp->if_capenable = ifp->if_capabilities;
138315516c77SSepherosa Ziehau 
13847960e6baSSepherosa Ziehau 	/*
13857960e6baSSepherosa Ziehau 	 * Disable IPv6 TSO and TXCSUM by default, they still can
13867960e6baSSepherosa Ziehau 	 * be enabled through SIOCSIFCAP.
13877960e6baSSepherosa Ziehau 	 */
13887960e6baSSepherosa Ziehau 	ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
13897960e6baSSepherosa Ziehau 	ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO);
13907960e6baSSepherosa Ziehau 
139115516c77SSepherosa Ziehau 	if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) {
139215516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU);
139315516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX;
139415516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = PAGE_SIZE;
139515516c77SSepherosa Ziehau 	}
139615516c77SSepherosa Ziehau 
139715516c77SSepherosa Ziehau 	ether_ifattach(ifp, eaddr);
139815516c77SSepherosa Ziehau 
139915516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) {
140015516c77SSepherosa Ziehau 		if_printf(ifp, "TSO segcnt %u segsz %u\n",
140115516c77SSepherosa Ziehau 		    ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize);
140215516c77SSepherosa Ziehau 	}
140315516c77SSepherosa Ziehau 
140415516c77SSepherosa Ziehau 	/* Inform the upper layer about the long frame support. */
140515516c77SSepherosa Ziehau 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
140615516c77SSepherosa Ziehau 
140715516c77SSepherosa Ziehau 	/*
140815516c77SSepherosa Ziehau 	 * Kick off link status check.
140915516c77SSepherosa Ziehau 	 */
141015516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
141115516c77SSepherosa Ziehau 	hn_update_link_status(sc);
141215516c77SSepherosa Ziehau 
14135bdfd3fdSDexuan Cui 	sc->hn_ifnet_evthand = EVENTHANDLER_REGISTER(ifnet_event,
14145bdfd3fdSDexuan Cui 	    hn_ifnet_event, sc, EVENTHANDLER_PRI_ANY);
14155bdfd3fdSDexuan Cui 
14165bdfd3fdSDexuan Cui 	sc->hn_ifaddr_evthand = EVENTHANDLER_REGISTER(ifaddr_event,
14175bdfd3fdSDexuan Cui 	    hn_ifaddr_event, sc, EVENTHANDLER_PRI_ANY);
14185bdfd3fdSDexuan Cui 
141915516c77SSepherosa Ziehau 	return (0);
142015516c77SSepherosa Ziehau failed:
142115516c77SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)
142215516c77SSepherosa Ziehau 		hn_synth_detach(sc);
142315516c77SSepherosa Ziehau 	hn_detach(dev);
142415516c77SSepherosa Ziehau 	return (error);
142515516c77SSepherosa Ziehau }
142615516c77SSepherosa Ziehau 
142715516c77SSepherosa Ziehau static int
142815516c77SSepherosa Ziehau hn_detach(device_t dev)
142915516c77SSepherosa Ziehau {
143015516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
143115516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
143215516c77SSepherosa Ziehau 
14335bdfd3fdSDexuan Cui 	if (sc->hn_ifaddr_evthand != NULL)
14345bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifaddr_event, sc->hn_ifaddr_evthand);
14355bdfd3fdSDexuan Cui 	if (sc->hn_ifnet_evthand != NULL)
14365bdfd3fdSDexuan Cui 		EVENTHANDLER_DEREGISTER(ifnet_event, sc->hn_ifnet_evthand);
14375bdfd3fdSDexuan Cui 
143825641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) {
143925641fc7SSepherosa Ziehau 		/*
144025641fc7SSepherosa Ziehau 		 * In case that the vmbus missed the orphan handler
144125641fc7SSepherosa Ziehau 		 * installation.
144225641fc7SSepherosa Ziehau 		 */
144325641fc7SSepherosa Ziehau 		vmbus_xact_ctx_orphan(sc->hn_xact);
144425641fc7SSepherosa Ziehau 	}
144525641fc7SSepherosa Ziehau 
144615516c77SSepherosa Ziehau 	if (device_is_attached(dev)) {
144715516c77SSepherosa Ziehau 		HN_LOCK(sc);
144815516c77SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
144915516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
14505bdfd3fdSDexuan Cui 				hn_stop(sc, true);
145115516c77SSepherosa Ziehau 			/*
145215516c77SSepherosa Ziehau 			 * NOTE:
145315516c77SSepherosa Ziehau 			 * hn_stop() only suspends data, so managment
145415516c77SSepherosa Ziehau 			 * stuffs have to be suspended manually here.
145515516c77SSepherosa Ziehau 			 */
145615516c77SSepherosa Ziehau 			hn_suspend_mgmt(sc);
145715516c77SSepherosa Ziehau 			hn_synth_detach(sc);
145815516c77SSepherosa Ziehau 		}
145915516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
146015516c77SSepherosa Ziehau 		ether_ifdetach(ifp);
146115516c77SSepherosa Ziehau 	}
146215516c77SSepherosa Ziehau 
146315516c77SSepherosa Ziehau 	ifmedia_removeall(&sc->hn_media);
146415516c77SSepherosa Ziehau 	hn_destroy_rx_data(sc);
146515516c77SSepherosa Ziehau 	hn_destroy_tx_data(sc);
146615516c77SSepherosa Ziehau 
14670e11868dSSepherosa Ziehau 	if (sc->hn_tx_taskqs != NULL && sc->hn_tx_taskqs != hn_tx_taskque) {
1468fdd0222aSSepherosa Ziehau 		int i;
1469fdd0222aSSepherosa Ziehau 
1470fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
1471fdd0222aSSepherosa Ziehau 			taskqueue_free(sc->hn_tx_taskqs[i]);
1472fdd0222aSSepherosa Ziehau 		free(sc->hn_tx_taskqs, M_DEVBUF);
1473fdd0222aSSepherosa Ziehau 	}
147415516c77SSepherosa Ziehau 	taskqueue_free(sc->hn_mgmt_taskq0);
147515516c77SSepherosa Ziehau 
147625641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL) {
147725641fc7SSepherosa Ziehau 		/*
147825641fc7SSepherosa Ziehau 		 * Uninstall the orphan handler _before_ the xact is
147925641fc7SSepherosa Ziehau 		 * destructed.
148025641fc7SSepherosa Ziehau 		 */
148125641fc7SSepherosa Ziehau 		vmbus_chan_unset_orphan(sc->hn_prichan);
148215516c77SSepherosa Ziehau 		vmbus_xact_ctx_destroy(sc->hn_xact);
148325641fc7SSepherosa Ziehau 	}
148415516c77SSepherosa Ziehau 
148515516c77SSepherosa Ziehau 	if_free(ifp);
148615516c77SSepherosa Ziehau 
148715516c77SSepherosa Ziehau 	HN_LOCK_DESTROY(sc);
148815516c77SSepherosa Ziehau 	return (0);
148915516c77SSepherosa Ziehau }
149015516c77SSepherosa Ziehau 
149115516c77SSepherosa Ziehau static int
149215516c77SSepherosa Ziehau hn_shutdown(device_t dev)
149315516c77SSepherosa Ziehau {
149415516c77SSepherosa Ziehau 
149515516c77SSepherosa Ziehau 	return (0);
149615516c77SSepherosa Ziehau }
149715516c77SSepherosa Ziehau 
149815516c77SSepherosa Ziehau static void
149915516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc)
150015516c77SSepherosa Ziehau {
150115516c77SSepherosa Ziehau 	uint32_t link_status;
150215516c77SSepherosa Ziehau 	int error;
150315516c77SSepherosa Ziehau 
150415516c77SSepherosa Ziehau 	error = hn_rndis_get_linkstatus(sc, &link_status);
150515516c77SSepherosa Ziehau 	if (error) {
150615516c77SSepherosa Ziehau 		/* XXX what to do? */
150715516c77SSepherosa Ziehau 		return;
150815516c77SSepherosa Ziehau 	}
150915516c77SSepherosa Ziehau 
151015516c77SSepherosa Ziehau 	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
151115516c77SSepherosa Ziehau 		sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
151215516c77SSepherosa Ziehau 	else
151315516c77SSepherosa Ziehau 		sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
151415516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp,
151515516c77SSepherosa Ziehau 	    (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ?
151615516c77SSepherosa Ziehau 	    LINK_STATE_UP : LINK_STATE_DOWN);
151715516c77SSepherosa Ziehau }
151815516c77SSepherosa Ziehau 
151915516c77SSepherosa Ziehau static void
152015516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused)
152115516c77SSepherosa Ziehau {
152215516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
152315516c77SSepherosa Ziehau 
152415516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
152515516c77SSepherosa Ziehau 		return;
152615516c77SSepherosa Ziehau 	hn_link_status(sc);
152715516c77SSepherosa Ziehau }
152815516c77SSepherosa Ziehau 
152915516c77SSepherosa Ziehau static void
153015516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused)
153115516c77SSepherosa Ziehau {
153215516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
153315516c77SSepherosa Ziehau 
153415516c77SSepherosa Ziehau 	/* Prevent any link status checks from running. */
153515516c77SSepherosa Ziehau 	sc->hn_link_flags |= HN_LINK_FLAG_NETCHG;
153615516c77SSepherosa Ziehau 
153715516c77SSepherosa Ziehau 	/*
153815516c77SSepherosa Ziehau 	 * Fake up a [link down --> link up] state change; 5 seconds
153915516c77SSepherosa Ziehau 	 * delay is used, which closely simulates miibus reaction
154015516c77SSepherosa Ziehau 	 * upon link down event.
154115516c77SSepherosa Ziehau 	 */
154215516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
154315516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
154415516c77SSepherosa Ziehau 	taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0,
154515516c77SSepherosa Ziehau 	    &sc->hn_netchg_status, 5 * hz);
154615516c77SSepherosa Ziehau }
154715516c77SSepherosa Ziehau 
154815516c77SSepherosa Ziehau static void
154915516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused)
155015516c77SSepherosa Ziehau {
155115516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
155215516c77SSepherosa Ziehau 
155315516c77SSepherosa Ziehau 	/* Re-allow link status checks. */
155415516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG;
155515516c77SSepherosa Ziehau 	hn_link_status(sc);
155615516c77SSepherosa Ziehau }
155715516c77SSepherosa Ziehau 
155815516c77SSepherosa Ziehau static void
155915516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc)
156015516c77SSepherosa Ziehau {
156115516c77SSepherosa Ziehau 
156215516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
156315516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
156415516c77SSepherosa Ziehau }
156515516c77SSepherosa Ziehau 
156615516c77SSepherosa Ziehau static void
156715516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc)
156815516c77SSepherosa Ziehau {
156915516c77SSepherosa Ziehau 
157015516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
157115516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init);
157215516c77SSepherosa Ziehau }
157315516c77SSepherosa Ziehau 
157415516c77SSepherosa Ziehau static __inline int
157515516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
157615516c77SSepherosa Ziehau     struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
157715516c77SSepherosa Ziehau {
157815516c77SSepherosa Ziehau 	struct mbuf *m = *m_head;
157915516c77SSepherosa Ziehau 	int error;
158015516c77SSepherosa Ziehau 
158115516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim"));
158215516c77SSepherosa Ziehau 
158315516c77SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap,
158415516c77SSepherosa Ziehau 	    m, segs, nsegs, BUS_DMA_NOWAIT);
158515516c77SSepherosa Ziehau 	if (error == EFBIG) {
158615516c77SSepherosa Ziehau 		struct mbuf *m_new;
158715516c77SSepherosa Ziehau 
158815516c77SSepherosa Ziehau 		m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX);
158915516c77SSepherosa Ziehau 		if (m_new == NULL)
159015516c77SSepherosa Ziehau 			return ENOBUFS;
159115516c77SSepherosa Ziehau 		else
159215516c77SSepherosa Ziehau 			*m_head = m = m_new;
159315516c77SSepherosa Ziehau 		txr->hn_tx_collapsed++;
159415516c77SSepherosa Ziehau 
159515516c77SSepherosa Ziehau 		error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag,
159615516c77SSepherosa Ziehau 		    txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT);
159715516c77SSepherosa Ziehau 	}
159815516c77SSepherosa Ziehau 	if (!error) {
159915516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap,
160015516c77SSepherosa Ziehau 		    BUS_DMASYNC_PREWRITE);
160115516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_DMAMAP;
160215516c77SSepherosa Ziehau 	}
160315516c77SSepherosa Ziehau 	return error;
160415516c77SSepherosa Ziehau }
160515516c77SSepherosa Ziehau 
160615516c77SSepherosa Ziehau static __inline int
160715516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd)
160815516c77SSepherosa Ziehau {
160915516c77SSepherosa Ziehau 
161015516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0,
161115516c77SSepherosa Ziehau 	    ("put an onlist txd %#x", txd->flags));
1612dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1613dc13fee6SSepherosa Ziehau 	    ("put an onagg txd %#x", txd->flags));
161415516c77SSepherosa Ziehau 
161515516c77SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
161615516c77SSepherosa Ziehau 	if (atomic_fetchadd_int(&txd->refs, -1) != 1)
161715516c77SSepherosa Ziehau 		return 0;
161815516c77SSepherosa Ziehau 
1619dc13fee6SSepherosa Ziehau 	if (!STAILQ_EMPTY(&txd->agg_list)) {
1620dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tmp_txd;
1621dc13fee6SSepherosa Ziehau 
1622dc13fee6SSepherosa Ziehau 		while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) {
1623dc13fee6SSepherosa Ziehau 			int freed;
1624dc13fee6SSepherosa Ziehau 
1625dc13fee6SSepherosa Ziehau 			KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list),
1626dc13fee6SSepherosa Ziehau 			    ("resursive aggregation on aggregated txdesc"));
1627dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG),
1628dc13fee6SSepherosa Ziehau 			    ("not aggregated txdesc"));
1629dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
1630dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc uses dmamap"));
1631dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
1632dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc consumes "
1633dc13fee6SSepherosa Ziehau 			     "chimney sending buffer"));
1634dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_size == 0,
1635dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc has non-zero "
1636dc13fee6SSepherosa Ziehau 			     "chimney sending size"));
1637dc13fee6SSepherosa Ziehau 
1638dc13fee6SSepherosa Ziehau 			STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link);
1639dc13fee6SSepherosa Ziehau 			tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG;
1640dc13fee6SSepherosa Ziehau 			freed = hn_txdesc_put(txr, tmp_txd);
1641dc13fee6SSepherosa Ziehau 			KASSERT(freed, ("failed to free aggregated txdesc"));
1642dc13fee6SSepherosa Ziehau 		}
1643dc13fee6SSepherosa Ziehau 	}
1644dc13fee6SSepherosa Ziehau 
164515516c77SSepherosa Ziehau 	if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) {
164615516c77SSepherosa Ziehau 		KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
164715516c77SSepherosa Ziehau 		    ("chim txd uses dmamap"));
164815516c77SSepherosa Ziehau 		hn_chim_free(txr->hn_sc, txd->chim_index);
164915516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
1650dc13fee6SSepherosa Ziehau 		txd->chim_size = 0;
165115516c77SSepherosa Ziehau 	} else if (txd->flags & HN_TXD_FLAG_DMAMAP) {
165215516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag,
165315516c77SSepherosa Ziehau 		    txd->data_dmap, BUS_DMASYNC_POSTWRITE);
165415516c77SSepherosa Ziehau 		bus_dmamap_unload(txr->hn_tx_data_dtag,
165515516c77SSepherosa Ziehau 		    txd->data_dmap);
165615516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_DMAMAP;
165715516c77SSepherosa Ziehau 	}
165815516c77SSepherosa Ziehau 
165915516c77SSepherosa Ziehau 	if (txd->m != NULL) {
166015516c77SSepherosa Ziehau 		m_freem(txd->m);
166115516c77SSepherosa Ziehau 		txd->m = NULL;
166215516c77SSepherosa Ziehau 	}
166315516c77SSepherosa Ziehau 
166415516c77SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONLIST;
166515516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
166615516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
166715516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_avail >= 0 &&
166815516c77SSepherosa Ziehau 	    txr->hn_txdesc_avail < txr->hn_txdesc_cnt,
166915516c77SSepherosa Ziehau 	    ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail));
167015516c77SSepherosa Ziehau 	txr->hn_txdesc_avail++;
167115516c77SSepherosa Ziehau 	SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
167215516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
167385e4ae1eSSepherosa Ziehau #else	/* HN_USE_TXDESC_BUFRING */
167485e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
167515516c77SSepherosa Ziehau 	atomic_add_int(&txr->hn_txdesc_avail, 1);
167615516c77SSepherosa Ziehau #endif
167785e4ae1eSSepherosa Ziehau 	buf_ring_enqueue(txr->hn_txdesc_br, txd);
167885e4ae1eSSepherosa Ziehau #endif	/* !HN_USE_TXDESC_BUFRING */
167915516c77SSepherosa Ziehau 
168015516c77SSepherosa Ziehau 	return 1;
168115516c77SSepherosa Ziehau }
168215516c77SSepherosa Ziehau 
168315516c77SSepherosa Ziehau static __inline struct hn_txdesc *
168415516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr)
168515516c77SSepherosa Ziehau {
168615516c77SSepherosa Ziehau 	struct hn_txdesc *txd;
168715516c77SSepherosa Ziehau 
168815516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
168915516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
169015516c77SSepherosa Ziehau 	txd = SLIST_FIRST(&txr->hn_txlist);
169115516c77SSepherosa Ziehau 	if (txd != NULL) {
169215516c77SSepherosa Ziehau 		KASSERT(txr->hn_txdesc_avail > 0,
169315516c77SSepherosa Ziehau 		    ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail));
169415516c77SSepherosa Ziehau 		txr->hn_txdesc_avail--;
169515516c77SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&txr->hn_txlist, link);
169615516c77SSepherosa Ziehau 	}
169715516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
169815516c77SSepherosa Ziehau #else
169915516c77SSepherosa Ziehau 	txd = buf_ring_dequeue_sc(txr->hn_txdesc_br);
170015516c77SSepherosa Ziehau #endif
170115516c77SSepherosa Ziehau 
170215516c77SSepherosa Ziehau 	if (txd != NULL) {
170315516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
170485e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
170515516c77SSepherosa Ziehau 		atomic_subtract_int(&txr->hn_txdesc_avail, 1);
170615516c77SSepherosa Ziehau #endif
170785e4ae1eSSepherosa Ziehau #endif	/* HN_USE_TXDESC_BUFRING */
170815516c77SSepherosa Ziehau 		KASSERT(txd->m == NULL && txd->refs == 0 &&
1709dc13fee6SSepherosa Ziehau 		    STAILQ_EMPTY(&txd->agg_list) &&
171015516c77SSepherosa Ziehau 		    txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
1711dc13fee6SSepherosa Ziehau 		    txd->chim_size == 0 &&
171215516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONLIST) &&
1713dc13fee6SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONAGG) == 0 &&
171415516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd"));
171515516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_ONLIST;
171615516c77SSepherosa Ziehau 		txd->refs = 1;
171715516c77SSepherosa Ziehau 	}
171815516c77SSepherosa Ziehau 	return txd;
171915516c77SSepherosa Ziehau }
172015516c77SSepherosa Ziehau 
172115516c77SSepherosa Ziehau static __inline void
172215516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd)
172315516c77SSepherosa Ziehau {
172415516c77SSepherosa Ziehau 
172515516c77SSepherosa Ziehau 	/* 0->1 transition will never work */
172625641fc7SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
172715516c77SSepherosa Ziehau 	atomic_add_int(&txd->refs, 1);
172815516c77SSepherosa Ziehau }
172915516c77SSepherosa Ziehau 
1730dc13fee6SSepherosa Ziehau static __inline void
1731dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd)
1732dc13fee6SSepherosa Ziehau {
1733dc13fee6SSepherosa Ziehau 
1734dc13fee6SSepherosa Ziehau 	KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1735dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on aggregating txdesc"));
1736dc13fee6SSepherosa Ziehau 
1737dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1738dc13fee6SSepherosa Ziehau 	    ("already aggregated"));
1739dc13fee6SSepherosa Ziehau 	KASSERT(STAILQ_EMPTY(&txd->agg_list),
1740dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on to-be-aggregated txdesc"));
1741dc13fee6SSepherosa Ziehau 
1742dc13fee6SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONAGG;
1743dc13fee6SSepherosa Ziehau 	STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link);
1744dc13fee6SSepherosa Ziehau }
1745dc13fee6SSepherosa Ziehau 
174615516c77SSepherosa Ziehau static bool
174715516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr)
174815516c77SSepherosa Ziehau {
174915516c77SSepherosa Ziehau 	bool pending = false;
175015516c77SSepherosa Ziehau 
175115516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
175215516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
175315516c77SSepherosa Ziehau 	if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt)
175415516c77SSepherosa Ziehau 		pending = true;
175515516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
175615516c77SSepherosa Ziehau #else
175715516c77SSepherosa Ziehau 	if (!buf_ring_full(txr->hn_txdesc_br))
175815516c77SSepherosa Ziehau 		pending = true;
175915516c77SSepherosa Ziehau #endif
176015516c77SSepherosa Ziehau 	return (pending);
176115516c77SSepherosa Ziehau }
176215516c77SSepherosa Ziehau 
176315516c77SSepherosa Ziehau static __inline void
176415516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr)
176515516c77SSepherosa Ziehau {
176615516c77SSepherosa Ziehau 	txr->hn_has_txeof = 0;
176715516c77SSepherosa Ziehau 	txr->hn_txeof(txr);
176815516c77SSepherosa Ziehau }
176915516c77SSepherosa Ziehau 
177015516c77SSepherosa Ziehau static void
177115516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc,
177215516c77SSepherosa Ziehau     struct vmbus_channel *chan, const void *data __unused, int dlen __unused)
177315516c77SSepherosa Ziehau {
177415516c77SSepherosa Ziehau 	struct hn_txdesc *txd = sndc->hn_cbarg;
177515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
177615516c77SSepherosa Ziehau 
177715516c77SSepherosa Ziehau 	txr = txd->txr;
177815516c77SSepherosa Ziehau 	KASSERT(txr->hn_chan == chan,
177915516c77SSepherosa Ziehau 	    ("channel mismatch, on chan%u, should be chan%u",
1780aa1a2adcSSepherosa Ziehau 	     vmbus_chan_id(chan), vmbus_chan_id(txr->hn_chan)));
178115516c77SSepherosa Ziehau 
178215516c77SSepherosa Ziehau 	txr->hn_has_txeof = 1;
178315516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
178415516c77SSepherosa Ziehau 
178515516c77SSepherosa Ziehau 	++txr->hn_txdone_cnt;
178615516c77SSepherosa Ziehau 	if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) {
178715516c77SSepherosa Ziehau 		txr->hn_txdone_cnt = 0;
178815516c77SSepherosa Ziehau 		if (txr->hn_oactive)
178915516c77SSepherosa Ziehau 			hn_txeof(txr);
179015516c77SSepherosa Ziehau 	}
179115516c77SSepherosa Ziehau }
179215516c77SSepherosa Ziehau 
179315516c77SSepherosa Ziehau static void
179415516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
179515516c77SSepherosa Ziehau {
179615516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
179715516c77SSepherosa Ziehau 	tcp_lro_flush_all(&rxr->hn_lro);
179815516c77SSepherosa Ziehau #endif
179915516c77SSepherosa Ziehau 
180015516c77SSepherosa Ziehau 	/*
180115516c77SSepherosa Ziehau 	 * NOTE:
180215516c77SSepherosa Ziehau 	 * 'txr' could be NULL, if multiple channels and
180315516c77SSepherosa Ziehau 	 * ifnet.if_start method are enabled.
180415516c77SSepherosa Ziehau 	 */
180515516c77SSepherosa Ziehau 	if (txr == NULL || !txr->hn_has_txeof)
180615516c77SSepherosa Ziehau 		return;
180715516c77SSepherosa Ziehau 
180815516c77SSepherosa Ziehau 	txr->hn_txdone_cnt = 0;
180915516c77SSepherosa Ziehau 	hn_txeof(txr);
181015516c77SSepherosa Ziehau }
181115516c77SSepherosa Ziehau 
181215516c77SSepherosa Ziehau static __inline uint32_t
181315516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs)
181415516c77SSepherosa Ziehau {
181515516c77SSepherosa Ziehau 
181615516c77SSepherosa Ziehau 	KASSERT(ofs >= sizeof(struct rndis_packet_msg),
181715516c77SSepherosa Ziehau 	    ("invalid RNDIS packet msg offset %u", ofs));
181815516c77SSepherosa Ziehau 	return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset));
181915516c77SSepherosa Ziehau }
182015516c77SSepherosa Ziehau 
182115516c77SSepherosa Ziehau static __inline void *
182215516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
182315516c77SSepherosa Ziehau     size_t pi_dlen, uint32_t pi_type)
182415516c77SSepherosa Ziehau {
182515516c77SSepherosa Ziehau 	const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
182615516c77SSepherosa Ziehau 	struct rndis_pktinfo *pi;
182715516c77SSepherosa Ziehau 
182815516c77SSepherosa Ziehau 	KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
182915516c77SSepherosa Ziehau 	    ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
183015516c77SSepherosa Ziehau 
183115516c77SSepherosa Ziehau 	/*
183215516c77SSepherosa Ziehau 	 * Per-packet-info does not move; it only grows.
183315516c77SSepherosa Ziehau 	 *
183415516c77SSepherosa Ziehau 	 * NOTE:
183515516c77SSepherosa Ziehau 	 * rm_pktinfooffset in this phase counts from the beginning
183615516c77SSepherosa Ziehau 	 * of rndis_packet_msg.
183715516c77SSepherosa Ziehau 	 */
183815516c77SSepherosa Ziehau 	KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
183915516c77SSepherosa Ziehau 	    ("%u pktinfo overflows RNDIS packet msg", pi_type));
184015516c77SSepherosa Ziehau 	pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
184115516c77SSepherosa Ziehau 	    pkt->rm_pktinfolen);
184215516c77SSepherosa Ziehau 	pkt->rm_pktinfolen += pi_size;
184315516c77SSepherosa Ziehau 
184415516c77SSepherosa Ziehau 	pi->rm_size = pi_size;
184515516c77SSepherosa Ziehau 	pi->rm_type = pi_type;
184615516c77SSepherosa Ziehau 	pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
184715516c77SSepherosa Ziehau 
184815516c77SSepherosa Ziehau 	return (pi->rm_data);
184915516c77SSepherosa Ziehau }
185015516c77SSepherosa Ziehau 
1851dc13fee6SSepherosa Ziehau static __inline int
1852dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr)
1853dc13fee6SSepherosa Ziehau {
1854dc13fee6SSepherosa Ziehau 	struct hn_txdesc *txd;
1855dc13fee6SSepherosa Ziehau 	struct mbuf *m;
1856dc13fee6SSepherosa Ziehau 	int error, pkts;
1857dc13fee6SSepherosa Ziehau 
1858dc13fee6SSepherosa Ziehau 	txd = txr->hn_agg_txd;
1859dc13fee6SSepherosa Ziehau 	KASSERT(txd != NULL, ("no aggregate txdesc"));
1860dc13fee6SSepherosa Ziehau 
1861dc13fee6SSepherosa Ziehau 	/*
1862dc13fee6SSepherosa Ziehau 	 * Since hn_txpkt() will reset this temporary stat, save
1863dc13fee6SSepherosa Ziehau 	 * it now, so that oerrors can be updated properly, if
1864dc13fee6SSepherosa Ziehau 	 * hn_txpkt() ever fails.
1865dc13fee6SSepherosa Ziehau 	 */
1866dc13fee6SSepherosa Ziehau 	pkts = txr->hn_stat_pkts;
1867dc13fee6SSepherosa Ziehau 
1868dc13fee6SSepherosa Ziehau 	/*
1869dc13fee6SSepherosa Ziehau 	 * Since txd's mbuf will _not_ be freed upon hn_txpkt()
1870dc13fee6SSepherosa Ziehau 	 * failure, save it for later freeing, if hn_txpkt() ever
1871dc13fee6SSepherosa Ziehau 	 * fails.
1872dc13fee6SSepherosa Ziehau 	 */
1873dc13fee6SSepherosa Ziehau 	m = txd->m;
1874dc13fee6SSepherosa Ziehau 	error = hn_txpkt(ifp, txr, txd);
1875dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
1876dc13fee6SSepherosa Ziehau 		/* txd is freed, but m is not. */
1877dc13fee6SSepherosa Ziehau 		m_freem(m);
1878dc13fee6SSepherosa Ziehau 
1879dc13fee6SSepherosa Ziehau 		txr->hn_flush_failed++;
1880dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts);
1881dc13fee6SSepherosa Ziehau 	}
1882dc13fee6SSepherosa Ziehau 
1883dc13fee6SSepherosa Ziehau 	/* Reset all aggregation states. */
1884dc13fee6SSepherosa Ziehau 	txr->hn_agg_txd = NULL;
1885dc13fee6SSepherosa Ziehau 	txr->hn_agg_szleft = 0;
1886dc13fee6SSepherosa Ziehau 	txr->hn_agg_pktleft = 0;
1887dc13fee6SSepherosa Ziehau 	txr->hn_agg_prevpkt = NULL;
1888dc13fee6SSepherosa Ziehau 
1889dc13fee6SSepherosa Ziehau 	return (error);
1890dc13fee6SSepherosa Ziehau }
1891dc13fee6SSepherosa Ziehau 
1892dc13fee6SSepherosa Ziehau static void *
1893dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
1894dc13fee6SSepherosa Ziehau     int pktsize)
1895dc13fee6SSepherosa Ziehau {
1896dc13fee6SSepherosa Ziehau 	void *chim;
1897dc13fee6SSepherosa Ziehau 
1898dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL) {
1899dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) {
1900dc13fee6SSepherosa Ziehau 			struct hn_txdesc *agg_txd = txr->hn_agg_txd;
1901dc13fee6SSepherosa Ziehau 			struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt;
1902dc13fee6SSepherosa Ziehau 			int olen;
1903dc13fee6SSepherosa Ziehau 
1904dc13fee6SSepherosa Ziehau 			/*
1905dc13fee6SSepherosa Ziehau 			 * Update the previous RNDIS packet's total length,
1906dc13fee6SSepherosa Ziehau 			 * it can be increased due to the mandatory alignment
1907dc13fee6SSepherosa Ziehau 			 * padding for this RNDIS packet.  And update the
1908dc13fee6SSepherosa Ziehau 			 * aggregating txdesc's chimney sending buffer size
1909dc13fee6SSepherosa Ziehau 			 * accordingly.
1910dc13fee6SSepherosa Ziehau 			 *
1911dc13fee6SSepherosa Ziehau 			 * XXX
1912dc13fee6SSepherosa Ziehau 			 * Zero-out the padding, as required by the RNDIS spec.
1913dc13fee6SSepherosa Ziehau 			 */
1914dc13fee6SSepherosa Ziehau 			olen = pkt->rm_len;
1915dc13fee6SSepherosa Ziehau 			pkt->rm_len = roundup2(olen, txr->hn_agg_align);
1916dc13fee6SSepherosa Ziehau 			agg_txd->chim_size += pkt->rm_len - olen;
1917dc13fee6SSepherosa Ziehau 
1918dc13fee6SSepherosa Ziehau 			/* Link this txdesc to the parent. */
1919dc13fee6SSepherosa Ziehau 			hn_txdesc_agg(agg_txd, txd);
1920dc13fee6SSepherosa Ziehau 
1921dc13fee6SSepherosa Ziehau 			chim = (uint8_t *)pkt + pkt->rm_len;
1922dc13fee6SSepherosa Ziehau 			/* Save the current packet for later fixup. */
1923dc13fee6SSepherosa Ziehau 			txr->hn_agg_prevpkt = chim;
1924dc13fee6SSepherosa Ziehau 
1925dc13fee6SSepherosa Ziehau 			txr->hn_agg_pktleft--;
1926dc13fee6SSepherosa Ziehau 			txr->hn_agg_szleft -= pktsize;
1927dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_szleft <=
1928dc13fee6SSepherosa Ziehau 			    HN_PKTSIZE_MIN(txr->hn_agg_align)) {
1929dc13fee6SSepherosa Ziehau 				/*
1930dc13fee6SSepherosa Ziehau 				 * Probably can't aggregate more packets,
1931dc13fee6SSepherosa Ziehau 				 * flush this aggregating txdesc proactively.
1932dc13fee6SSepherosa Ziehau 				 */
1933dc13fee6SSepherosa Ziehau 				txr->hn_agg_pktleft = 0;
1934dc13fee6SSepherosa Ziehau 			}
1935dc13fee6SSepherosa Ziehau 			/* Done! */
1936dc13fee6SSepherosa Ziehau 			return (chim);
1937dc13fee6SSepherosa Ziehau 		}
1938dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
1939dc13fee6SSepherosa Ziehau 	}
1940dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
1941dc13fee6SSepherosa Ziehau 
1942dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney_tried++;
1943dc13fee6SSepherosa Ziehau 	txd->chim_index = hn_chim_alloc(txr->hn_sc);
1944dc13fee6SSepherosa Ziehau 	if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID)
1945dc13fee6SSepherosa Ziehau 		return (NULL);
1946dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney++;
1947dc13fee6SSepherosa Ziehau 
1948dc13fee6SSepherosa Ziehau 	chim = txr->hn_sc->hn_chim +
1949dc13fee6SSepherosa Ziehau 	    (txd->chim_index * txr->hn_sc->hn_chim_szmax);
1950dc13fee6SSepherosa Ziehau 
1951dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_pktmax > 1 &&
1952dc13fee6SSepherosa Ziehau 	    txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) {
1953dc13fee6SSepherosa Ziehau 		txr->hn_agg_txd = txd;
1954dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1;
1955dc13fee6SSepherosa Ziehau 		txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize;
1956dc13fee6SSepherosa Ziehau 		txr->hn_agg_prevpkt = chim;
1957dc13fee6SSepherosa Ziehau 	}
1958dc13fee6SSepherosa Ziehau 	return (chim);
1959dc13fee6SSepherosa Ziehau }
1960dc13fee6SSepherosa Ziehau 
196115516c77SSepherosa Ziehau /*
196215516c77SSepherosa Ziehau  * NOTE:
196315516c77SSepherosa Ziehau  * If this function fails, then both txd and m_head0 will be freed.
196415516c77SSepherosa Ziehau  */
196515516c77SSepherosa Ziehau static int
1966dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
1967dc13fee6SSepherosa Ziehau     struct mbuf **m_head0)
196815516c77SSepherosa Ziehau {
196915516c77SSepherosa Ziehau 	bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX];
197015516c77SSepherosa Ziehau 	int error, nsegs, i;
197115516c77SSepherosa Ziehau 	struct mbuf *m_head = *m_head0;
197215516c77SSepherosa Ziehau 	struct rndis_packet_msg *pkt;
197315516c77SSepherosa Ziehau 	uint32_t *pi_data;
19748966e5d5SSepherosa Ziehau 	void *chim = NULL;
1975dc13fee6SSepherosa Ziehau 	int pkt_hlen, pkt_size;
197615516c77SSepherosa Ziehau 
197715516c77SSepherosa Ziehau 	pkt = txd->rndis_pkt;
1978dc13fee6SSepherosa Ziehau 	pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align);
1979dc13fee6SSepherosa Ziehau 	if (pkt_size < txr->hn_chim_size) {
1980dc13fee6SSepherosa Ziehau 		chim = hn_try_txagg(ifp, txr, txd, pkt_size);
1981dc13fee6SSepherosa Ziehau 		if (chim != NULL)
19828966e5d5SSepherosa Ziehau 			pkt = chim;
1983dc13fee6SSepherosa Ziehau 	} else {
1984dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL)
1985dc13fee6SSepherosa Ziehau 			hn_flush_txagg(ifp, txr);
19868966e5d5SSepherosa Ziehau 	}
19878966e5d5SSepherosa Ziehau 
198815516c77SSepherosa Ziehau 	pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
19898fe90f73SSepherosa Ziehau 	pkt->rm_len = m_head->m_pkthdr.len;
19909130c4f7SSepherosa Ziehau 	pkt->rm_dataoffset = 0;
199115516c77SSepherosa Ziehau 	pkt->rm_datalen = m_head->m_pkthdr.len;
1992dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataoffset = 0;
1993dc13fee6SSepherosa Ziehau 	pkt->rm_oobdatalen = 0;
1994dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataelements = 0;
199515516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = sizeof(*pkt);
199615516c77SSepherosa Ziehau 	pkt->rm_pktinfolen = 0;
1997dc13fee6SSepherosa Ziehau 	pkt->rm_vchandle = 0;
1998dc13fee6SSepherosa Ziehau 	pkt->rm_reserved = 0;
199915516c77SSepherosa Ziehau 
200015516c77SSepherosa Ziehau 	if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) {
200115516c77SSepherosa Ziehau 		/*
200215516c77SSepherosa Ziehau 		 * Set the hash value for this packet, so that the host could
200315516c77SSepherosa Ziehau 		 * dispatch the TX done event for this packet back to this TX
200415516c77SSepherosa Ziehau 		 * ring's channel.
200515516c77SSepherosa Ziehau 		 */
200615516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
200715516c77SSepherosa Ziehau 		    HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL);
200815516c77SSepherosa Ziehau 		*pi_data = txr->hn_tx_idx;
200915516c77SSepherosa Ziehau 	}
201015516c77SSepherosa Ziehau 
201115516c77SSepherosa Ziehau 	if (m_head->m_flags & M_VLANTAG) {
201215516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
201315516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
201415516c77SSepherosa Ziehau 		*pi_data = NDIS_VLAN_INFO_MAKE(
201515516c77SSepherosa Ziehau 		    EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag),
201615516c77SSepherosa Ziehau 		    EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag),
201715516c77SSepherosa Ziehau 		    EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag));
201815516c77SSepherosa Ziehau 	}
201915516c77SSepherosa Ziehau 
202015516c77SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
202115516c77SSepherosa Ziehau #if defined(INET6) || defined(INET)
202215516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
202315516c77SSepherosa Ziehau 		    NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO);
202415516c77SSepherosa Ziehau #ifdef INET
202515516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
202615516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV4(0,
202715516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
202815516c77SSepherosa Ziehau 		}
202915516c77SSepherosa Ziehau #endif
203015516c77SSepherosa Ziehau #if defined(INET6) && defined(INET)
203115516c77SSepherosa Ziehau 		else
203215516c77SSepherosa Ziehau #endif
203315516c77SSepherosa Ziehau #ifdef INET6
203415516c77SSepherosa Ziehau 		{
203515516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV6(0,
203615516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
203715516c77SSepherosa Ziehau 		}
203815516c77SSepherosa Ziehau #endif
203915516c77SSepherosa Ziehau #endif	/* INET6 || INET */
204015516c77SSepherosa Ziehau 	} else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) {
204115516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
204215516c77SSepherosa Ziehau 		    NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
204315516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
204415516c77SSepherosa Ziehau 		    (CSUM_IP6_TCP | CSUM_IP6_UDP)) {
204515516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV6;
204615516c77SSepherosa Ziehau 		} else {
204715516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV4;
204815516c77SSepherosa Ziehau 			if (m_head->m_pkthdr.csum_flags & CSUM_IP)
204915516c77SSepherosa Ziehau 				*pi_data |= NDIS_TXCSUM_INFO_IPCS;
205015516c77SSepherosa Ziehau 		}
205115516c77SSepherosa Ziehau 
205215516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP))
205315516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_TCPCS;
205415516c77SSepherosa Ziehau 		else if (m_head->m_pkthdr.csum_flags &
205515516c77SSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP6_UDP))
205615516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_UDPCS;
205715516c77SSepherosa Ziehau 	}
205815516c77SSepherosa Ziehau 
2059dc13fee6SSepherosa Ziehau 	pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
20608fe90f73SSepherosa Ziehau 	/* Fixup RNDIS packet message total length */
20618fe90f73SSepherosa Ziehau 	pkt->rm_len += pkt_hlen;
206215516c77SSepherosa Ziehau 	/* Convert RNDIS packet message offsets */
20639130c4f7SSepherosa Ziehau 	pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt_hlen);
206415516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset);
206515516c77SSepherosa Ziehau 
206615516c77SSepherosa Ziehau 	/*
20678966e5d5SSepherosa Ziehau 	 * Fast path: Chimney sending.
206815516c77SSepherosa Ziehau 	 */
20698966e5d5SSepherosa Ziehau 	if (chim != NULL) {
2070dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tgt_txd = txd;
2071dc13fee6SSepherosa Ziehau 
2072dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL) {
2073dc13fee6SSepherosa Ziehau 			tgt_txd = txr->hn_agg_txd;
2074dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
2075dc13fee6SSepherosa Ziehau 			*m_head0 = NULL;
2076dc13fee6SSepherosa Ziehau #endif
2077dc13fee6SSepherosa Ziehau 		}
2078dc13fee6SSepherosa Ziehau 
2079dc13fee6SSepherosa Ziehau 		KASSERT(pkt == chim,
2080dc13fee6SSepherosa Ziehau 		    ("RNDIS pkt not in chimney sending buffer"));
2081dc13fee6SSepherosa Ziehau 		KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID,
2082dc13fee6SSepherosa Ziehau 		    ("chimney sending buffer is not used"));
2083dc13fee6SSepherosa Ziehau 		tgt_txd->chim_size += pkt->rm_len;
208415516c77SSepherosa Ziehau 
20858966e5d5SSepherosa Ziehau 		m_copydata(m_head, 0, m_head->m_pkthdr.len,
2086dc13fee6SSepherosa Ziehau 		    ((uint8_t *)chim) + pkt_hlen);
208715516c77SSepherosa Ziehau 
208815516c77SSepherosa Ziehau 		txr->hn_gpa_cnt = 0;
208915516c77SSepherosa Ziehau 		txr->hn_sendpkt = hn_txpkt_chim;
209015516c77SSepherosa Ziehau 		goto done;
209115516c77SSepherosa Ziehau 	}
2092dc13fee6SSepherosa Ziehau 
2093dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc"));
20948966e5d5SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
20958966e5d5SSepherosa Ziehau 	    ("chimney buffer is used"));
20968966e5d5SSepherosa Ziehau 	KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc"));
209715516c77SSepherosa Ziehau 
209815516c77SSepherosa Ziehau 	error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs);
2099dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
210015516c77SSepherosa Ziehau 		int freed;
210115516c77SSepherosa Ziehau 
210215516c77SSepherosa Ziehau 		/*
210315516c77SSepherosa Ziehau 		 * This mbuf is not linked w/ the txd yet, so free it now.
210415516c77SSepherosa Ziehau 		 */
210515516c77SSepherosa Ziehau 		m_freem(m_head);
210615516c77SSepherosa Ziehau 		*m_head0 = NULL;
210715516c77SSepherosa Ziehau 
210815516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
210915516c77SSepherosa Ziehau 		KASSERT(freed != 0,
211015516c77SSepherosa Ziehau 		    ("fail to free txd upon txdma error"));
211115516c77SSepherosa Ziehau 
211215516c77SSepherosa Ziehau 		txr->hn_txdma_failed++;
2113dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
211415516c77SSepherosa Ziehau 		return error;
211515516c77SSepherosa Ziehau 	}
211615516c77SSepherosa Ziehau 	*m_head0 = m_head;
211715516c77SSepherosa Ziehau 
211815516c77SSepherosa Ziehau 	/* +1 RNDIS packet message */
211915516c77SSepherosa Ziehau 	txr->hn_gpa_cnt = nsegs + 1;
212015516c77SSepherosa Ziehau 
212115516c77SSepherosa Ziehau 	/* send packet with page buffer */
212215516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr);
212315516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK;
2124dc13fee6SSepherosa Ziehau 	txr->hn_gpa[0].gpa_len = pkt_hlen;
212515516c77SSepherosa Ziehau 
212615516c77SSepherosa Ziehau 	/*
212715516c77SSepherosa Ziehau 	 * Fill the page buffers with mbuf info after the page
212815516c77SSepherosa Ziehau 	 * buffer for RNDIS packet message.
212915516c77SSepherosa Ziehau 	 */
213015516c77SSepherosa Ziehau 	for (i = 0; i < nsegs; ++i) {
213115516c77SSepherosa Ziehau 		struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1];
213215516c77SSepherosa Ziehau 
213315516c77SSepherosa Ziehau 		gpa->gpa_page = atop(segs[i].ds_addr);
213415516c77SSepherosa Ziehau 		gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK;
213515516c77SSepherosa Ziehau 		gpa->gpa_len = segs[i].ds_len;
213615516c77SSepherosa Ziehau 	}
213715516c77SSepherosa Ziehau 
213815516c77SSepherosa Ziehau 	txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
213915516c77SSepherosa Ziehau 	txd->chim_size = 0;
214015516c77SSepherosa Ziehau 	txr->hn_sendpkt = hn_txpkt_sglist;
214115516c77SSepherosa Ziehau done:
214215516c77SSepherosa Ziehau 	txd->m = m_head;
214315516c77SSepherosa Ziehau 
214415516c77SSepherosa Ziehau 	/* Set the completion routine */
214515516c77SSepherosa Ziehau 	hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd);
214615516c77SSepherosa Ziehau 
2147dc13fee6SSepherosa Ziehau 	/* Update temporary stats for later use. */
2148dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts++;
2149dc13fee6SSepherosa Ziehau 	txr->hn_stat_size += m_head->m_pkthdr.len;
2150dc13fee6SSepherosa Ziehau 	if (m_head->m_flags & M_MCAST)
2151dc13fee6SSepherosa Ziehau 		txr->hn_stat_mcasts++;
2152dc13fee6SSepherosa Ziehau 
215315516c77SSepherosa Ziehau 	return 0;
215415516c77SSepherosa Ziehau }
215515516c77SSepherosa Ziehau 
215615516c77SSepherosa Ziehau /*
215715516c77SSepherosa Ziehau  * NOTE:
215815516c77SSepherosa Ziehau  * If this function fails, then txd will be freed, but the mbuf
215915516c77SSepherosa Ziehau  * associated w/ the txd will _not_ be freed.
216015516c77SSepherosa Ziehau  */
216115516c77SSepherosa Ziehau static int
216215516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd)
216315516c77SSepherosa Ziehau {
21648e7d3136SSepherosa Ziehau 	int error, send_failed = 0, has_bpf;
216515516c77SSepherosa Ziehau 
216615516c77SSepherosa Ziehau again:
21678e7d3136SSepherosa Ziehau 	has_bpf = bpf_peers_present(ifp->if_bpf);
21688e7d3136SSepherosa Ziehau 	if (has_bpf) {
216915516c77SSepherosa Ziehau 		/*
21708e7d3136SSepherosa Ziehau 		 * Make sure that this txd and any aggregated txds are not
21718e7d3136SSepherosa Ziehau 		 * freed before ETHER_BPF_MTAP.
217215516c77SSepherosa Ziehau 		 */
217315516c77SSepherosa Ziehau 		hn_txdesc_hold(txd);
21748e7d3136SSepherosa Ziehau 	}
217515516c77SSepherosa Ziehau 	error = txr->hn_sendpkt(txr, txd);
217615516c77SSepherosa Ziehau 	if (!error) {
21778e7d3136SSepherosa Ziehau 		if (has_bpf) {
2178dc13fee6SSepherosa Ziehau 			const struct hn_txdesc *tmp_txd;
2179dc13fee6SSepherosa Ziehau 
218015516c77SSepherosa Ziehau 			ETHER_BPF_MTAP(ifp, txd->m);
2181dc13fee6SSepherosa Ziehau 			STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link)
2182dc13fee6SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, tmp_txd->m);
2183dc13fee6SSepherosa Ziehau 		}
2184dc13fee6SSepherosa Ziehau 
2185dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts);
218623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
218723bf9e15SSepherosa Ziehau 		if (!hn_use_if_start)
218823bf9e15SSepherosa Ziehau #endif
218923bf9e15SSepherosa Ziehau 		{
219015516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OBYTES,
2191dc13fee6SSepherosa Ziehau 			    txr->hn_stat_size);
2192dc13fee6SSepherosa Ziehau 			if (txr->hn_stat_mcasts != 0) {
2193dc13fee6SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OMCASTS,
2194dc13fee6SSepherosa Ziehau 				    txr->hn_stat_mcasts);
219515516c77SSepherosa Ziehau 			}
2196dc13fee6SSepherosa Ziehau 		}
2197dc13fee6SSepherosa Ziehau 		txr->hn_pkts += txr->hn_stat_pkts;
2198dc13fee6SSepherosa Ziehau 		txr->hn_sends++;
219915516c77SSepherosa Ziehau 	}
22008e7d3136SSepherosa Ziehau 	if (has_bpf)
220115516c77SSepherosa Ziehau 		hn_txdesc_put(txr, txd);
220215516c77SSepherosa Ziehau 
220315516c77SSepherosa Ziehau 	if (__predict_false(error)) {
220415516c77SSepherosa Ziehau 		int freed;
220515516c77SSepherosa Ziehau 
220615516c77SSepherosa Ziehau 		/*
220715516c77SSepherosa Ziehau 		 * This should "really rarely" happen.
220815516c77SSepherosa Ziehau 		 *
220915516c77SSepherosa Ziehau 		 * XXX Too many RX to be acked or too many sideband
221015516c77SSepherosa Ziehau 		 * commands to run?  Ask netvsc_channel_rollup()
221115516c77SSepherosa Ziehau 		 * to kick start later.
221215516c77SSepherosa Ziehau 		 */
221315516c77SSepherosa Ziehau 		txr->hn_has_txeof = 1;
221415516c77SSepherosa Ziehau 		if (!send_failed) {
221515516c77SSepherosa Ziehau 			txr->hn_send_failed++;
221615516c77SSepherosa Ziehau 			send_failed = 1;
221715516c77SSepherosa Ziehau 			/*
221815516c77SSepherosa Ziehau 			 * Try sending again after set hn_has_txeof;
221915516c77SSepherosa Ziehau 			 * in case that we missed the last
222015516c77SSepherosa Ziehau 			 * netvsc_channel_rollup().
222115516c77SSepherosa Ziehau 			 */
222215516c77SSepherosa Ziehau 			goto again;
222315516c77SSepherosa Ziehau 		}
222415516c77SSepherosa Ziehau 		if_printf(ifp, "send failed\n");
222515516c77SSepherosa Ziehau 
222615516c77SSepherosa Ziehau 		/*
222715516c77SSepherosa Ziehau 		 * Caller will perform further processing on the
222815516c77SSepherosa Ziehau 		 * associated mbuf, so don't free it in hn_txdesc_put();
222915516c77SSepherosa Ziehau 		 * only unload it from the DMA map in hn_txdesc_put(),
223015516c77SSepherosa Ziehau 		 * if it was loaded.
223115516c77SSepherosa Ziehau 		 */
223215516c77SSepherosa Ziehau 		txd->m = NULL;
223315516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
223415516c77SSepherosa Ziehau 		KASSERT(freed != 0,
223515516c77SSepherosa Ziehau 		    ("fail to free txd upon send error"));
223615516c77SSepherosa Ziehau 
223715516c77SSepherosa Ziehau 		txr->hn_send_failed++;
223815516c77SSepherosa Ziehau 	}
2239dc13fee6SSepherosa Ziehau 
2240dc13fee6SSepherosa Ziehau 	/* Reset temporary stats, after this sending is done. */
2241dc13fee6SSepherosa Ziehau 	txr->hn_stat_size = 0;
2242dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts = 0;
2243dc13fee6SSepherosa Ziehau 	txr->hn_stat_mcasts = 0;
2244dc13fee6SSepherosa Ziehau 
2245dc13fee6SSepherosa Ziehau 	return (error);
224615516c77SSepherosa Ziehau }
224715516c77SSepherosa Ziehau 
224815516c77SSepherosa Ziehau /*
224915516c77SSepherosa Ziehau  * Append the specified data to the indicated mbuf chain,
225015516c77SSepherosa Ziehau  * Extend the mbuf chain if the new data does not fit in
225115516c77SSepherosa Ziehau  * existing space.
225215516c77SSepherosa Ziehau  *
225315516c77SSepherosa Ziehau  * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c.
225415516c77SSepherosa Ziehau  * There should be an equivalent in the kernel mbuf code,
225515516c77SSepherosa Ziehau  * but there does not appear to be one yet.
225615516c77SSepherosa Ziehau  *
225715516c77SSepherosa Ziehau  * Differs from m_append() in that additional mbufs are
225815516c77SSepherosa Ziehau  * allocated with cluster size MJUMPAGESIZE, and filled
225915516c77SSepherosa Ziehau  * accordingly.
226015516c77SSepherosa Ziehau  *
226115516c77SSepherosa Ziehau  * Return 1 if able to complete the job; otherwise 0.
226215516c77SSepherosa Ziehau  */
226315516c77SSepherosa Ziehau static int
226415516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp)
226515516c77SSepherosa Ziehau {
226615516c77SSepherosa Ziehau 	struct mbuf *m, *n;
226715516c77SSepherosa Ziehau 	int remainder, space;
226815516c77SSepherosa Ziehau 
226915516c77SSepherosa Ziehau 	for (m = m0; m->m_next != NULL; m = m->m_next)
227015516c77SSepherosa Ziehau 		;
227115516c77SSepherosa Ziehau 	remainder = len;
227215516c77SSepherosa Ziehau 	space = M_TRAILINGSPACE(m);
227315516c77SSepherosa Ziehau 	if (space > 0) {
227415516c77SSepherosa Ziehau 		/*
227515516c77SSepherosa Ziehau 		 * Copy into available space.
227615516c77SSepherosa Ziehau 		 */
227715516c77SSepherosa Ziehau 		if (space > remainder)
227815516c77SSepherosa Ziehau 			space = remainder;
227915516c77SSepherosa Ziehau 		bcopy(cp, mtod(m, caddr_t) + m->m_len, space);
228015516c77SSepherosa Ziehau 		m->m_len += space;
228115516c77SSepherosa Ziehau 		cp += space;
228215516c77SSepherosa Ziehau 		remainder -= space;
228315516c77SSepherosa Ziehau 	}
228415516c77SSepherosa Ziehau 	while (remainder > 0) {
228515516c77SSepherosa Ziehau 		/*
228615516c77SSepherosa Ziehau 		 * Allocate a new mbuf; could check space
228715516c77SSepherosa Ziehau 		 * and allocate a cluster instead.
228815516c77SSepherosa Ziehau 		 */
228915516c77SSepherosa Ziehau 		n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE);
229015516c77SSepherosa Ziehau 		if (n == NULL)
229115516c77SSepherosa Ziehau 			break;
229215516c77SSepherosa Ziehau 		n->m_len = min(MJUMPAGESIZE, remainder);
229315516c77SSepherosa Ziehau 		bcopy(cp, mtod(n, caddr_t), n->m_len);
229415516c77SSepherosa Ziehau 		cp += n->m_len;
229515516c77SSepherosa Ziehau 		remainder -= n->m_len;
229615516c77SSepherosa Ziehau 		m->m_next = n;
229715516c77SSepherosa Ziehau 		m = n;
229815516c77SSepherosa Ziehau 	}
229915516c77SSepherosa Ziehau 	if (m0->m_flags & M_PKTHDR)
230015516c77SSepherosa Ziehau 		m0->m_pkthdr.len += len - remainder;
230115516c77SSepherosa Ziehau 
230215516c77SSepherosa Ziehau 	return (remainder == 0);
230315516c77SSepherosa Ziehau }
230415516c77SSepherosa Ziehau 
230515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
230615516c77SSepherosa Ziehau static __inline int
230715516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m)
230815516c77SSepherosa Ziehau {
230915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
231015516c77SSepherosa Ziehau 	if (hn_lro_mbufq_depth) {
231115516c77SSepherosa Ziehau 		tcp_lro_queue_mbuf(lc, m);
231215516c77SSepherosa Ziehau 		return 0;
231315516c77SSepherosa Ziehau 	}
231415516c77SSepherosa Ziehau #endif
231515516c77SSepherosa Ziehau 	return tcp_lro_rx(lc, m, 0);
231615516c77SSepherosa Ziehau }
231715516c77SSepherosa Ziehau #endif
231815516c77SSepherosa Ziehau 
231915516c77SSepherosa Ziehau static int
232015516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
232115516c77SSepherosa Ziehau     const struct hn_rxinfo *info)
232215516c77SSepherosa Ziehau {
23235bdfd3fdSDexuan Cui 	struct ifnet *ifp;
232415516c77SSepherosa Ziehau 	struct mbuf *m_new;
232515516c77SSepherosa Ziehau 	int size, do_lro = 0, do_csum = 1;
232615516c77SSepherosa Ziehau 	int hash_type;
232715516c77SSepherosa Ziehau 
23285bdfd3fdSDexuan Cui 	/* If the VF is active, inject the packet through the VF */
23295bdfd3fdSDexuan Cui 	ifp = rxr->hn_vf ? rxr->hn_vf : rxr->hn_ifp;
23305bdfd3fdSDexuan Cui 
2331b3b75d9cSSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
2332b3b75d9cSSepherosa Ziehau 		/*
2333b3b75d9cSSepherosa Ziehau 		 * NOTE:
2334b3b75d9cSSepherosa Ziehau 		 * See the NOTE of hn_rndis_init_fixat().  This
2335b3b75d9cSSepherosa Ziehau 		 * function can be reached, immediately after the
2336b3b75d9cSSepherosa Ziehau 		 * RNDIS is initialized but before the ifnet is
2337b3b75d9cSSepherosa Ziehau 		 * setup on the hn_attach() path; drop the unexpected
2338b3b75d9cSSepherosa Ziehau 		 * packets.
2339b3b75d9cSSepherosa Ziehau 		 */
2340b3b75d9cSSepherosa Ziehau 		return (0);
2341b3b75d9cSSepherosa Ziehau 	}
2342b3b75d9cSSepherosa Ziehau 
2343c927d681SDexuan Cui 	if (dlen <= MHLEN) {
234415516c77SSepherosa Ziehau 		m_new = m_gethdr(M_NOWAIT, MT_DATA);
234515516c77SSepherosa Ziehau 		if (m_new == NULL) {
234615516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
234715516c77SSepherosa Ziehau 			return (0);
234815516c77SSepherosa Ziehau 		}
234915516c77SSepherosa Ziehau 		memcpy(mtod(m_new, void *), data, dlen);
235015516c77SSepherosa Ziehau 		m_new->m_pkthdr.len = m_new->m_len = dlen;
235115516c77SSepherosa Ziehau 		rxr->hn_small_pkts++;
235215516c77SSepherosa Ziehau 	} else {
235315516c77SSepherosa Ziehau 		/*
235415516c77SSepherosa Ziehau 		 * Get an mbuf with a cluster.  For packets 2K or less,
235515516c77SSepherosa Ziehau 		 * get a standard 2K cluster.  For anything larger, get a
235615516c77SSepherosa Ziehau 		 * 4K cluster.  Any buffers larger than 4K can cause problems
235715516c77SSepherosa Ziehau 		 * if looped around to the Hyper-V TX channel, so avoid them.
235815516c77SSepherosa Ziehau 		 */
235915516c77SSepherosa Ziehau 		size = MCLBYTES;
236015516c77SSepherosa Ziehau 		if (dlen > MCLBYTES) {
236115516c77SSepherosa Ziehau 			/* 4096 */
236215516c77SSepherosa Ziehau 			size = MJUMPAGESIZE;
236315516c77SSepherosa Ziehau 		}
236415516c77SSepherosa Ziehau 
236515516c77SSepherosa Ziehau 		m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size);
236615516c77SSepherosa Ziehau 		if (m_new == NULL) {
236715516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
236815516c77SSepherosa Ziehau 			return (0);
236915516c77SSepherosa Ziehau 		}
237015516c77SSepherosa Ziehau 
237115516c77SSepherosa Ziehau 		hv_m_append(m_new, dlen, data);
237215516c77SSepherosa Ziehau 	}
237315516c77SSepherosa Ziehau 	m_new->m_pkthdr.rcvif = ifp;
237415516c77SSepherosa Ziehau 
237515516c77SSepherosa Ziehau 	if (__predict_false((ifp->if_capenable & IFCAP_RXCSUM) == 0))
237615516c77SSepherosa Ziehau 		do_csum = 0;
237715516c77SSepherosa Ziehau 
237815516c77SSepherosa Ziehau 	/* receive side checksum offload */
237915516c77SSepherosa Ziehau 	if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) {
238015516c77SSepherosa Ziehau 		/* IP csum offload */
238115516c77SSepherosa Ziehau 		if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) {
238215516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
238315516c77SSepherosa Ziehau 			    (CSUM_IP_CHECKED | CSUM_IP_VALID);
238415516c77SSepherosa Ziehau 			rxr->hn_csum_ip++;
238515516c77SSepherosa Ziehau 		}
238615516c77SSepherosa Ziehau 
238715516c77SSepherosa Ziehau 		/* TCP/UDP csum offload */
238815516c77SSepherosa Ziehau 		if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK |
238915516c77SSepherosa Ziehau 		     NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) {
239015516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
239115516c77SSepherosa Ziehau 			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
239215516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_data = 0xffff;
239315516c77SSepherosa Ziehau 			if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK)
239415516c77SSepherosa Ziehau 				rxr->hn_csum_tcp++;
239515516c77SSepherosa Ziehau 			else
239615516c77SSepherosa Ziehau 				rxr->hn_csum_udp++;
239715516c77SSepherosa Ziehau 		}
239815516c77SSepherosa Ziehau 
239915516c77SSepherosa Ziehau 		/*
240015516c77SSepherosa Ziehau 		 * XXX
240115516c77SSepherosa Ziehau 		 * As of this write (Oct 28th, 2016), host side will turn
240215516c77SSepherosa Ziehau 		 * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so
240315516c77SSepherosa Ziehau 		 * the do_lro setting here is actually _not_ accurate.  We
240415516c77SSepherosa Ziehau 		 * depend on the RSS hash type check to reset do_lro.
240515516c77SSepherosa Ziehau 		 */
240615516c77SSepherosa Ziehau 		if ((info->csum_info &
240715516c77SSepherosa Ziehau 		     (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) ==
240815516c77SSepherosa Ziehau 		    (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK))
240915516c77SSepherosa Ziehau 			do_lro = 1;
241015516c77SSepherosa Ziehau 	} else {
241115516c77SSepherosa Ziehau 		const struct ether_header *eh;
241215516c77SSepherosa Ziehau 		uint16_t etype;
241315516c77SSepherosa Ziehau 		int hoff;
241415516c77SSepherosa Ziehau 
241515516c77SSepherosa Ziehau 		hoff = sizeof(*eh);
241615516c77SSepherosa Ziehau 		if (m_new->m_len < hoff)
241715516c77SSepherosa Ziehau 			goto skip;
241815516c77SSepherosa Ziehau 		eh = mtod(m_new, struct ether_header *);
241915516c77SSepherosa Ziehau 		etype = ntohs(eh->ether_type);
242015516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_VLAN) {
242115516c77SSepherosa Ziehau 			const struct ether_vlan_header *evl;
242215516c77SSepherosa Ziehau 
242315516c77SSepherosa Ziehau 			hoff = sizeof(*evl);
242415516c77SSepherosa Ziehau 			if (m_new->m_len < hoff)
242515516c77SSepherosa Ziehau 				goto skip;
242615516c77SSepherosa Ziehau 			evl = mtod(m_new, struct ether_vlan_header *);
242715516c77SSepherosa Ziehau 			etype = ntohs(evl->evl_proto);
242815516c77SSepherosa Ziehau 		}
242915516c77SSepherosa Ziehau 
243015516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_IP) {
243115516c77SSepherosa Ziehau 			int pr;
243215516c77SSepherosa Ziehau 
243315516c77SSepherosa Ziehau 			pr = hn_check_iplen(m_new, hoff);
243415516c77SSepherosa Ziehau 			if (pr == IPPROTO_TCP) {
243515516c77SSepherosa Ziehau 				if (do_csum &&
243615516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
243715516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_TCP)) {
243815516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
243915516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
244015516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
244115516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
244215516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
244315516c77SSepherosa Ziehau 				}
244415516c77SSepherosa Ziehau 				do_lro = 1;
244515516c77SSepherosa Ziehau 			} else if (pr == IPPROTO_UDP) {
244615516c77SSepherosa Ziehau 				if (do_csum &&
244715516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
244815516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_UDP)) {
244915516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
245015516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
245115516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
245215516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
245315516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
245415516c77SSepherosa Ziehau 				}
245515516c77SSepherosa Ziehau 			} else if (pr != IPPROTO_DONE && do_csum &&
245615516c77SSepherosa Ziehau 			    (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) {
245715516c77SSepherosa Ziehau 				rxr->hn_csum_trusted++;
245815516c77SSepherosa Ziehau 				m_new->m_pkthdr.csum_flags |=
245915516c77SSepherosa Ziehau 				    (CSUM_IP_CHECKED | CSUM_IP_VALID);
246015516c77SSepherosa Ziehau 			}
246115516c77SSepherosa Ziehau 		}
246215516c77SSepherosa Ziehau 	}
246315516c77SSepherosa Ziehau skip:
246415516c77SSepherosa Ziehau 	if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) {
246515516c77SSepherosa Ziehau 		m_new->m_pkthdr.ether_vtag = EVL_MAKETAG(
246615516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_ID(info->vlan_info),
246715516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_PRI(info->vlan_info),
246815516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_CFI(info->vlan_info));
246915516c77SSepherosa Ziehau 		m_new->m_flags |= M_VLANTAG;
247015516c77SSepherosa Ziehau 	}
247115516c77SSepherosa Ziehau 
247215516c77SSepherosa Ziehau 	if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) {
247315516c77SSepherosa Ziehau 		rxr->hn_rss_pkts++;
247415516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = info->hash_value;
247515516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE_HASH;
247615516c77SSepherosa Ziehau 		if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) ==
247715516c77SSepherosa Ziehau 		    NDIS_HASH_FUNCTION_TOEPLITZ) {
247815516c77SSepherosa Ziehau 			uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK);
247915516c77SSepherosa Ziehau 
248015516c77SSepherosa Ziehau 			/*
248115516c77SSepherosa Ziehau 			 * NOTE:
248215516c77SSepherosa Ziehau 			 * do_lro is resetted, if the hash types are not TCP
248315516c77SSepherosa Ziehau 			 * related.  See the comment in the above csum_flags
248415516c77SSepherosa Ziehau 			 * setup section.
248515516c77SSepherosa Ziehau 			 */
248615516c77SSepherosa Ziehau 			switch (type) {
248715516c77SSepherosa Ziehau 			case NDIS_HASH_IPV4:
248815516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV4;
248915516c77SSepherosa Ziehau 				do_lro = 0;
249015516c77SSepherosa Ziehau 				break;
249115516c77SSepherosa Ziehau 
249215516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV4:
249315516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV4;
249415516c77SSepherosa Ziehau 				break;
249515516c77SSepherosa Ziehau 
249615516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6:
249715516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6;
249815516c77SSepherosa Ziehau 				do_lro = 0;
249915516c77SSepherosa Ziehau 				break;
250015516c77SSepherosa Ziehau 
250115516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6_EX:
250215516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6_EX;
250315516c77SSepherosa Ziehau 				do_lro = 0;
250415516c77SSepherosa Ziehau 				break;
250515516c77SSepherosa Ziehau 
250615516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6:
250715516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6;
250815516c77SSepherosa Ziehau 				break;
250915516c77SSepherosa Ziehau 
251015516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6_EX:
251115516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX;
251215516c77SSepherosa Ziehau 				break;
251315516c77SSepherosa Ziehau 			}
251415516c77SSepherosa Ziehau 		}
251515516c77SSepherosa Ziehau 	} else {
251615516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
251715516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE;
251815516c77SSepherosa Ziehau 	}
251915516c77SSepherosa Ziehau 	M_HASHTYPE_SET(m_new, hash_type);
252015516c77SSepherosa Ziehau 
252115516c77SSepherosa Ziehau 	/*
252215516c77SSepherosa Ziehau 	 * Note:  Moved RX completion back to hv_nv_on_receive() so all
252315516c77SSepherosa Ziehau 	 * messages (not just data messages) will trigger a response.
252415516c77SSepherosa Ziehau 	 */
252515516c77SSepherosa Ziehau 
252615516c77SSepherosa Ziehau 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
252715516c77SSepherosa Ziehau 	rxr->hn_pkts++;
252815516c77SSepherosa Ziehau 
252915516c77SSepherosa Ziehau 	if ((ifp->if_capenable & IFCAP_LRO) && do_lro) {
253015516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
253115516c77SSepherosa Ziehau 		struct lro_ctrl *lro = &rxr->hn_lro;
253215516c77SSepherosa Ziehau 
253315516c77SSepherosa Ziehau 		if (lro->lro_cnt) {
253415516c77SSepherosa Ziehau 			rxr->hn_lro_tried++;
253515516c77SSepherosa Ziehau 			if (hn_lro_rx(lro, m_new) == 0) {
253615516c77SSepherosa Ziehau 				/* DONE! */
253715516c77SSepherosa Ziehau 				return 0;
253815516c77SSepherosa Ziehau 			}
253915516c77SSepherosa Ziehau 		}
254015516c77SSepherosa Ziehau #endif
254115516c77SSepherosa Ziehau 	}
254215516c77SSepherosa Ziehau 
254315516c77SSepherosa Ziehau 	/* We're not holding the lock here, so don't release it */
254415516c77SSepherosa Ziehau 	(*ifp->if_input)(ifp, m_new);
254515516c77SSepherosa Ziehau 
254615516c77SSepherosa Ziehau 	return (0);
254715516c77SSepherosa Ziehau }
254815516c77SSepherosa Ziehau 
254915516c77SSepherosa Ziehau static int
255015516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
255115516c77SSepherosa Ziehau {
255215516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
255315516c77SSepherosa Ziehau 	struct ifreq *ifr = (struct ifreq *)data;
255415516c77SSepherosa Ziehau 	int mask, error = 0;
255515516c77SSepherosa Ziehau 
255615516c77SSepherosa Ziehau 	switch (cmd) {
255715516c77SSepherosa Ziehau 	case SIOCSIFMTU:
255815516c77SSepherosa Ziehau 		if (ifr->ifr_mtu > HN_MTU_MAX) {
255915516c77SSepherosa Ziehau 			error = EINVAL;
256015516c77SSepherosa Ziehau 			break;
256115516c77SSepherosa Ziehau 		}
256215516c77SSepherosa Ziehau 
256315516c77SSepherosa Ziehau 		HN_LOCK(sc);
256415516c77SSepherosa Ziehau 
256515516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
256615516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
256715516c77SSepherosa Ziehau 			break;
256815516c77SSepherosa Ziehau 		}
256915516c77SSepherosa Ziehau 
257015516c77SSepherosa Ziehau 		if ((sc->hn_caps & HN_CAP_MTU) == 0) {
257115516c77SSepherosa Ziehau 			/* Can't change MTU */
257215516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
257315516c77SSepherosa Ziehau 			error = EOPNOTSUPP;
257415516c77SSepherosa Ziehau 			break;
257515516c77SSepherosa Ziehau 		}
257615516c77SSepherosa Ziehau 
257715516c77SSepherosa Ziehau 		if (ifp->if_mtu == ifr->ifr_mtu) {
257815516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
257915516c77SSepherosa Ziehau 			break;
258015516c77SSepherosa Ziehau 		}
258115516c77SSepherosa Ziehau 
258215516c77SSepherosa Ziehau 		/*
258315516c77SSepherosa Ziehau 		 * Suspend this interface before the synthetic parts
258415516c77SSepherosa Ziehau 		 * are ripped.
258515516c77SSepherosa Ziehau 		 */
258615516c77SSepherosa Ziehau 		hn_suspend(sc);
258715516c77SSepherosa Ziehau 
258815516c77SSepherosa Ziehau 		/*
258915516c77SSepherosa Ziehau 		 * Detach the synthetics parts, i.e. NVS and RNDIS.
259015516c77SSepherosa Ziehau 		 */
259115516c77SSepherosa Ziehau 		hn_synth_detach(sc);
259215516c77SSepherosa Ziehau 
259315516c77SSepherosa Ziehau 		/*
259415516c77SSepherosa Ziehau 		 * Reattach the synthetic parts, i.e. NVS and RNDIS,
259515516c77SSepherosa Ziehau 		 * with the new MTU setting.
259615516c77SSepherosa Ziehau 		 */
259715516c77SSepherosa Ziehau 		error = hn_synth_attach(sc, ifr->ifr_mtu);
259815516c77SSepherosa Ziehau 		if (error) {
259915516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
260015516c77SSepherosa Ziehau 			break;
260115516c77SSepherosa Ziehau 		}
260215516c77SSepherosa Ziehau 
260315516c77SSepherosa Ziehau 		/*
260415516c77SSepherosa Ziehau 		 * Commit the requested MTU, after the synthetic parts
260515516c77SSepherosa Ziehau 		 * have been successfully attached.
260615516c77SSepherosa Ziehau 		 */
260715516c77SSepherosa Ziehau 		ifp->if_mtu = ifr->ifr_mtu;
260815516c77SSepherosa Ziehau 
260915516c77SSepherosa Ziehau 		/*
261015516c77SSepherosa Ziehau 		 * Make sure that various parameters based on MTU are
261115516c77SSepherosa Ziehau 		 * still valid, after the MTU change.
261215516c77SSepherosa Ziehau 		 */
261315516c77SSepherosa Ziehau 		if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax)
261415516c77SSepherosa Ziehau 			hn_set_chim_size(sc, sc->hn_chim_szmax);
261515516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu);
261615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
261715516c77SSepherosa Ziehau 		if (sc->hn_rx_ring[0].hn_lro.lro_length_lim <
261815516c77SSepherosa Ziehau 		    HN_LRO_LENLIM_MIN(ifp))
261915516c77SSepherosa Ziehau 			hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
262015516c77SSepherosa Ziehau #endif
262115516c77SSepherosa Ziehau 
262215516c77SSepherosa Ziehau 		/*
262315516c77SSepherosa Ziehau 		 * All done!  Resume the interface now.
262415516c77SSepherosa Ziehau 		 */
262515516c77SSepherosa Ziehau 		hn_resume(sc);
262615516c77SSepherosa Ziehau 
262715516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
262815516c77SSepherosa Ziehau 		break;
262915516c77SSepherosa Ziehau 
263015516c77SSepherosa Ziehau 	case SIOCSIFFLAGS:
263115516c77SSepherosa Ziehau 		HN_LOCK(sc);
263215516c77SSepherosa Ziehau 
263315516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
263415516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
263515516c77SSepherosa Ziehau 			break;
263615516c77SSepherosa Ziehau 		}
263715516c77SSepherosa Ziehau 
263815516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_UP) {
2639fdc4f478SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2640fdc4f478SSepherosa Ziehau 				/*
2641fdc4f478SSepherosa Ziehau 				 * Caller meight hold mutex, e.g.
2642fdc4f478SSepherosa Ziehau 				 * bpf; use busy-wait for the RNDIS
2643fdc4f478SSepherosa Ziehau 				 * reply.
2644fdc4f478SSepherosa Ziehau 				 */
2645fdc4f478SSepherosa Ziehau 				HN_NO_SLEEPING(sc);
2646c08f7b2cSSepherosa Ziehau 				hn_rxfilter_config(sc);
2647fdc4f478SSepherosa Ziehau 				HN_SLEEPING_OK(sc);
2648fdc4f478SSepherosa Ziehau 			} else {
264915516c77SSepherosa Ziehau 				hn_init_locked(sc);
2650fdc4f478SSepherosa Ziehau 			}
265115516c77SSepherosa Ziehau 		} else {
265215516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
26535bdfd3fdSDexuan Cui 				hn_stop(sc, false);
265415516c77SSepherosa Ziehau 		}
265515516c77SSepherosa Ziehau 		sc->hn_if_flags = ifp->if_flags;
265615516c77SSepherosa Ziehau 
265715516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
265815516c77SSepherosa Ziehau 		break;
265915516c77SSepherosa Ziehau 
266015516c77SSepherosa Ziehau 	case SIOCSIFCAP:
266115516c77SSepherosa Ziehau 		HN_LOCK(sc);
266215516c77SSepherosa Ziehau 		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
266315516c77SSepherosa Ziehau 
266415516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM) {
266515516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM;
266615516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM)
266715516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc);
266815516c77SSepherosa Ziehau 			else
266915516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc);
267015516c77SSepherosa Ziehau 		}
267115516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM_IPV6) {
267215516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
267315516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
267415516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc);
267515516c77SSepherosa Ziehau 			else
267615516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc);
267715516c77SSepherosa Ziehau 		}
267815516c77SSepherosa Ziehau 
267915516c77SSepherosa Ziehau 		/* TODO: flip RNDIS offload parameters for RXCSUM. */
268015516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM)
268115516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM;
268215516c77SSepherosa Ziehau #ifdef foo
268315516c77SSepherosa Ziehau 		/* We can't diff IPv6 packets from IPv4 packets on RX path. */
268415516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM_IPV6)
268515516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
268615516c77SSepherosa Ziehau #endif
268715516c77SSepherosa Ziehau 
268815516c77SSepherosa Ziehau 		if (mask & IFCAP_LRO)
268915516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_LRO;
269015516c77SSepherosa Ziehau 
269115516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO4) {
269215516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO4;
269315516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO4)
269415516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP_TSO;
269515516c77SSepherosa Ziehau 			else
269615516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP_TSO;
269715516c77SSepherosa Ziehau 		}
269815516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO6) {
269915516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO6;
270015516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO6)
270115516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP6_TSO;
270215516c77SSepherosa Ziehau 			else
270315516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP6_TSO;
270415516c77SSepherosa Ziehau 		}
270515516c77SSepherosa Ziehau 
270615516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
270715516c77SSepherosa Ziehau 		break;
270815516c77SSepherosa Ziehau 
270915516c77SSepherosa Ziehau 	case SIOCADDMULTI:
271015516c77SSepherosa Ziehau 	case SIOCDELMULTI:
271115516c77SSepherosa Ziehau 		HN_LOCK(sc);
271215516c77SSepherosa Ziehau 
271315516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
271415516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
271515516c77SSepherosa Ziehau 			break;
271615516c77SSepherosa Ziehau 		}
2717fdc4f478SSepherosa Ziehau 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2718fdc4f478SSepherosa Ziehau 			/*
2719fdc4f478SSepherosa Ziehau 			 * Multicast uses mutex; use busy-wait for
2720fdc4f478SSepherosa Ziehau 			 * the RNDIS reply.
2721fdc4f478SSepherosa Ziehau 			 */
2722fdc4f478SSepherosa Ziehau 			HN_NO_SLEEPING(sc);
2723c08f7b2cSSepherosa Ziehau 			hn_rxfilter_config(sc);
2724fdc4f478SSepherosa Ziehau 			HN_SLEEPING_OK(sc);
2725fdc4f478SSepherosa Ziehau 		}
272615516c77SSepherosa Ziehau 
272715516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
272815516c77SSepherosa Ziehau 		break;
272915516c77SSepherosa Ziehau 
273015516c77SSepherosa Ziehau 	case SIOCSIFMEDIA:
273115516c77SSepherosa Ziehau 	case SIOCGIFMEDIA:
273215516c77SSepherosa Ziehau 		error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd);
273315516c77SSepherosa Ziehau 		break;
273415516c77SSepherosa Ziehau 
273515516c77SSepherosa Ziehau 	default:
273615516c77SSepherosa Ziehau 		error = ether_ioctl(ifp, cmd, data);
273715516c77SSepherosa Ziehau 		break;
273815516c77SSepherosa Ziehau 	}
273915516c77SSepherosa Ziehau 	return (error);
274015516c77SSepherosa Ziehau }
274115516c77SSepherosa Ziehau 
274215516c77SSepherosa Ziehau static void
27435bdfd3fdSDexuan Cui hn_stop(struct hn_softc *sc, bool detaching)
274415516c77SSepherosa Ziehau {
274515516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
274615516c77SSepherosa Ziehau 	int i;
274715516c77SSepherosa Ziehau 
274815516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
274915516c77SSepherosa Ziehau 
275015516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
275115516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
275215516c77SSepherosa Ziehau 
27536c1204dfSSepherosa Ziehau 	/* Disable polling. */
27546c1204dfSSepherosa Ziehau 	hn_polling(sc, 0);
27556c1204dfSSepherosa Ziehau 
275615516c77SSepherosa Ziehau 	/* Clear RUNNING bit _before_ hn_suspend_data() */
275715516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
275815516c77SSepherosa Ziehau 	hn_suspend_data(sc);
275915516c77SSepherosa Ziehau 
276015516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
276115516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
276215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
276315516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
27645bdfd3fdSDexuan Cui 
27655bdfd3fdSDexuan Cui 	/*
27665bdfd3fdSDexuan Cui 	 * If the VF is active, make sure the filter is not 0, even if
27675bdfd3fdSDexuan Cui 	 * the synthetic NIC is down.
27685bdfd3fdSDexuan Cui 	 */
27695bdfd3fdSDexuan Cui 	if (!detaching && (sc->hn_flags & HN_FLAG_VF))
27705bdfd3fdSDexuan Cui 		hn_rxfilter_config(sc);
277115516c77SSepherosa Ziehau }
277215516c77SSepherosa Ziehau 
277315516c77SSepherosa Ziehau static void
277415516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc)
277515516c77SSepherosa Ziehau {
277615516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
277715516c77SSepherosa Ziehau 	int i;
277815516c77SSepherosa Ziehau 
277915516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
278015516c77SSepherosa Ziehau 
278115516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
278215516c77SSepherosa Ziehau 		return;
278315516c77SSepherosa Ziehau 
278415516c77SSepherosa Ziehau 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
278515516c77SSepherosa Ziehau 		return;
278615516c77SSepherosa Ziehau 
278715516c77SSepherosa Ziehau 	/* Configure RX filter */
2788c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
278915516c77SSepherosa Ziehau 
279015516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
279115516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
279215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
279315516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
279415516c77SSepherosa Ziehau 
279515516c77SSepherosa Ziehau 	/* Clear TX 'suspended' bit. */
279615516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_inuse);
279715516c77SSepherosa Ziehau 
279815516c77SSepherosa Ziehau 	/* Everything is ready; unleash! */
279915516c77SSepherosa Ziehau 	atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
28006c1204dfSSepherosa Ziehau 
28016c1204dfSSepherosa Ziehau 	/* Re-enable polling if requested. */
28026c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz > 0)
28036c1204dfSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
280415516c77SSepherosa Ziehau }
280515516c77SSepherosa Ziehau 
280615516c77SSepherosa Ziehau static void
280715516c77SSepherosa Ziehau hn_init(void *xsc)
280815516c77SSepherosa Ziehau {
280915516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
281015516c77SSepherosa Ziehau 
281115516c77SSepherosa Ziehau 	HN_LOCK(sc);
281215516c77SSepherosa Ziehau 	hn_init_locked(sc);
281315516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
281415516c77SSepherosa Ziehau }
281515516c77SSepherosa Ziehau 
281615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
281715516c77SSepherosa Ziehau 
281815516c77SSepherosa Ziehau static int
281915516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
282015516c77SSepherosa Ziehau {
282115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
282215516c77SSepherosa Ziehau 	unsigned int lenlim;
282315516c77SSepherosa Ziehau 	int error;
282415516c77SSepherosa Ziehau 
282515516c77SSepherosa Ziehau 	lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim;
282615516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &lenlim, 0, req);
282715516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
282815516c77SSepherosa Ziehau 		return error;
282915516c77SSepherosa Ziehau 
283015516c77SSepherosa Ziehau 	HN_LOCK(sc);
283115516c77SSepherosa Ziehau 	if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) ||
283215516c77SSepherosa Ziehau 	    lenlim > TCP_LRO_LENGTH_MAX) {
283315516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
283415516c77SSepherosa Ziehau 		return EINVAL;
283515516c77SSepherosa Ziehau 	}
283615516c77SSepherosa Ziehau 	hn_set_lro_lenlim(sc, lenlim);
283715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
283815516c77SSepherosa Ziehau 
283915516c77SSepherosa Ziehau 	return 0;
284015516c77SSepherosa Ziehau }
284115516c77SSepherosa Ziehau 
284215516c77SSepherosa Ziehau static int
284315516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS)
284415516c77SSepherosa Ziehau {
284515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
284615516c77SSepherosa Ziehau 	int ackcnt, error, i;
284715516c77SSepherosa Ziehau 
284815516c77SSepherosa Ziehau 	/*
284915516c77SSepherosa Ziehau 	 * lro_ackcnt_lim is append count limit,
285015516c77SSepherosa Ziehau 	 * +1 to turn it into aggregation limit.
285115516c77SSepherosa Ziehau 	 */
285215516c77SSepherosa Ziehau 	ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1;
285315516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &ackcnt, 0, req);
285415516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
285515516c77SSepherosa Ziehau 		return error;
285615516c77SSepherosa Ziehau 
285715516c77SSepherosa Ziehau 	if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1))
285815516c77SSepherosa Ziehau 		return EINVAL;
285915516c77SSepherosa Ziehau 
286015516c77SSepherosa Ziehau 	/*
286115516c77SSepherosa Ziehau 	 * Convert aggregation limit back to append
286215516c77SSepherosa Ziehau 	 * count limit.
286315516c77SSepherosa Ziehau 	 */
286415516c77SSepherosa Ziehau 	--ackcnt;
286515516c77SSepherosa Ziehau 	HN_LOCK(sc);
2866a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
286715516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt;
286815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
286915516c77SSepherosa Ziehau 	return 0;
287015516c77SSepherosa Ziehau }
287115516c77SSepherosa Ziehau 
287215516c77SSepherosa Ziehau #endif
287315516c77SSepherosa Ziehau 
287415516c77SSepherosa Ziehau static int
287515516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS)
287615516c77SSepherosa Ziehau {
287715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
287815516c77SSepherosa Ziehau 	int hcsum = arg2;
287915516c77SSepherosa Ziehau 	int on, error, i;
288015516c77SSepherosa Ziehau 
288115516c77SSepherosa Ziehau 	on = 0;
288215516c77SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum)
288315516c77SSepherosa Ziehau 		on = 1;
288415516c77SSepherosa Ziehau 
288515516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &on, 0, req);
288615516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
288715516c77SSepherosa Ziehau 		return error;
288815516c77SSepherosa Ziehau 
288915516c77SSepherosa Ziehau 	HN_LOCK(sc);
2890a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
289115516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
289215516c77SSepherosa Ziehau 
289315516c77SSepherosa Ziehau 		if (on)
289415516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= hcsum;
289515516c77SSepherosa Ziehau 		else
289615516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum &= ~hcsum;
289715516c77SSepherosa Ziehau 	}
289815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
289915516c77SSepherosa Ziehau 	return 0;
290015516c77SSepherosa Ziehau }
290115516c77SSepherosa Ziehau 
290215516c77SSepherosa Ziehau static int
290315516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS)
290415516c77SSepherosa Ziehau {
290515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
290615516c77SSepherosa Ziehau 	int chim_size, error;
290715516c77SSepherosa Ziehau 
290815516c77SSepherosa Ziehau 	chim_size = sc->hn_tx_ring[0].hn_chim_size;
290915516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &chim_size, 0, req);
291015516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
291115516c77SSepherosa Ziehau 		return error;
291215516c77SSepherosa Ziehau 
291315516c77SSepherosa Ziehau 	if (chim_size > sc->hn_chim_szmax || chim_size <= 0)
291415516c77SSepherosa Ziehau 		return EINVAL;
291515516c77SSepherosa Ziehau 
291615516c77SSepherosa Ziehau 	HN_LOCK(sc);
291715516c77SSepherosa Ziehau 	hn_set_chim_size(sc, chim_size);
291815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
291915516c77SSepherosa Ziehau 	return 0;
292015516c77SSepherosa Ziehau }
292115516c77SSepherosa Ziehau 
292215516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
292315516c77SSepherosa Ziehau static int
292415516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS)
292515516c77SSepherosa Ziehau {
292615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
292715516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
292815516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
292915516c77SSepherosa Ziehau 	uint64_t stat;
293015516c77SSepherosa Ziehau 
293115516c77SSepherosa Ziehau 	stat = 0;
293215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
293315516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
293415516c77SSepherosa Ziehau 		stat += *((int *)((uint8_t *)rxr + ofs));
293515516c77SSepherosa Ziehau 	}
293615516c77SSepherosa Ziehau 
293715516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
293815516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
293915516c77SSepherosa Ziehau 		return error;
294015516c77SSepherosa Ziehau 
294115516c77SSepherosa Ziehau 	/* Zero out this stat. */
294215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
294315516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
294415516c77SSepherosa Ziehau 		*((int *)((uint8_t *)rxr + ofs)) = 0;
294515516c77SSepherosa Ziehau 	}
294615516c77SSepherosa Ziehau 	return 0;
294715516c77SSepherosa Ziehau }
294815516c77SSepherosa Ziehau #else
294915516c77SSepherosa Ziehau static int
295015516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS)
295115516c77SSepherosa Ziehau {
295215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
295315516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
295415516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
295515516c77SSepherosa Ziehau 	uint64_t stat;
295615516c77SSepherosa Ziehau 
295715516c77SSepherosa Ziehau 	stat = 0;
2958a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
295915516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
296015516c77SSepherosa Ziehau 		stat += *((uint64_t *)((uint8_t *)rxr + ofs));
296115516c77SSepherosa Ziehau 	}
296215516c77SSepherosa Ziehau 
296315516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
296415516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
296515516c77SSepherosa Ziehau 		return error;
296615516c77SSepherosa Ziehau 
296715516c77SSepherosa Ziehau 	/* Zero out this stat. */
2968a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
296915516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
297015516c77SSepherosa Ziehau 		*((uint64_t *)((uint8_t *)rxr + ofs)) = 0;
297115516c77SSepherosa Ziehau 	}
297215516c77SSepherosa Ziehau 	return 0;
297315516c77SSepherosa Ziehau }
297415516c77SSepherosa Ziehau 
297515516c77SSepherosa Ziehau #endif
297615516c77SSepherosa Ziehau 
297715516c77SSepherosa Ziehau static int
297815516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
297915516c77SSepherosa Ziehau {
298015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
298115516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
298215516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
298315516c77SSepherosa Ziehau 	u_long stat;
298415516c77SSepherosa Ziehau 
298515516c77SSepherosa Ziehau 	stat = 0;
2986a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
298715516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
298815516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)rxr + ofs));
298915516c77SSepherosa Ziehau 	}
299015516c77SSepherosa Ziehau 
299115516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
299215516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
299315516c77SSepherosa Ziehau 		return error;
299415516c77SSepherosa Ziehau 
299515516c77SSepherosa Ziehau 	/* Zero out this stat. */
2996a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
299715516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
299815516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)rxr + ofs)) = 0;
299915516c77SSepherosa Ziehau 	}
300015516c77SSepherosa Ziehau 	return 0;
300115516c77SSepherosa Ziehau }
300215516c77SSepherosa Ziehau 
300315516c77SSepherosa Ziehau static int
300415516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
300515516c77SSepherosa Ziehau {
300615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
300715516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
300815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
300915516c77SSepherosa Ziehau 	u_long stat;
301015516c77SSepherosa Ziehau 
301115516c77SSepherosa Ziehau 	stat = 0;
3012a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
301315516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
301415516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)txr + ofs));
301515516c77SSepherosa Ziehau 	}
301615516c77SSepherosa Ziehau 
301715516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
301815516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
301915516c77SSepherosa Ziehau 		return error;
302015516c77SSepherosa Ziehau 
302115516c77SSepherosa Ziehau 	/* Zero out this stat. */
3022a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
302315516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
302415516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)txr + ofs)) = 0;
302515516c77SSepherosa Ziehau 	}
302615516c77SSepherosa Ziehau 	return 0;
302715516c77SSepherosa Ziehau }
302815516c77SSepherosa Ziehau 
302915516c77SSepherosa Ziehau static int
303015516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS)
303115516c77SSepherosa Ziehau {
303215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
303315516c77SSepherosa Ziehau 	int ofs = arg2, i, error, conf;
303415516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
303515516c77SSepherosa Ziehau 
303615516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[0];
303715516c77SSepherosa Ziehau 	conf = *((int *)((uint8_t *)txr + ofs));
303815516c77SSepherosa Ziehau 
303915516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &conf, 0, req);
304015516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
304115516c77SSepherosa Ziehau 		return error;
304215516c77SSepherosa Ziehau 
304315516c77SSepherosa Ziehau 	HN_LOCK(sc);
3044a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
304515516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
304615516c77SSepherosa Ziehau 		*((int *)((uint8_t *)txr + ofs)) = conf;
304715516c77SSepherosa Ziehau 	}
304815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
304915516c77SSepherosa Ziehau 
305015516c77SSepherosa Ziehau 	return 0;
305115516c77SSepherosa Ziehau }
305215516c77SSepherosa Ziehau 
305315516c77SSepherosa Ziehau static int
3054dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS)
3055dc13fee6SSepherosa Ziehau {
3056dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
3057dc13fee6SSepherosa Ziehau 	int error, size;
3058dc13fee6SSepherosa Ziehau 
3059dc13fee6SSepherosa Ziehau 	size = sc->hn_agg_size;
3060dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &size, 0, req);
3061dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
3062dc13fee6SSepherosa Ziehau 		return (error);
3063dc13fee6SSepherosa Ziehau 
3064dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
3065dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = size;
3066dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
3067dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
3068dc13fee6SSepherosa Ziehau 
3069dc13fee6SSepherosa Ziehau 	return (0);
3070dc13fee6SSepherosa Ziehau }
3071dc13fee6SSepherosa Ziehau 
3072dc13fee6SSepherosa Ziehau static int
3073dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS)
3074dc13fee6SSepherosa Ziehau {
3075dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
3076dc13fee6SSepherosa Ziehau 	int error, pkts;
3077dc13fee6SSepherosa Ziehau 
3078dc13fee6SSepherosa Ziehau 	pkts = sc->hn_agg_pkts;
3079dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pkts, 0, req);
3080dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
3081dc13fee6SSepherosa Ziehau 		return (error);
3082dc13fee6SSepherosa Ziehau 
3083dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
3084dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = pkts;
3085dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
3086dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
3087dc13fee6SSepherosa Ziehau 
3088dc13fee6SSepherosa Ziehau 	return (0);
3089dc13fee6SSepherosa Ziehau }
3090dc13fee6SSepherosa Ziehau 
3091dc13fee6SSepherosa Ziehau static int
3092dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS)
3093dc13fee6SSepherosa Ziehau {
3094dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
3095dc13fee6SSepherosa Ziehau 	int pkts;
3096dc13fee6SSepherosa Ziehau 
3097dc13fee6SSepherosa Ziehau 	pkts = sc->hn_tx_ring[0].hn_agg_pktmax;
3098dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &pkts, 0, req));
3099dc13fee6SSepherosa Ziehau }
3100dc13fee6SSepherosa Ziehau 
3101dc13fee6SSepherosa Ziehau static int
3102dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS)
3103dc13fee6SSepherosa Ziehau {
3104dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
3105dc13fee6SSepherosa Ziehau 	int align;
3106dc13fee6SSepherosa Ziehau 
3107dc13fee6SSepherosa Ziehau 	align = sc->hn_tx_ring[0].hn_agg_align;
3108dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &align, 0, req));
3109dc13fee6SSepherosa Ziehau }
3110dc13fee6SSepherosa Ziehau 
31116c1204dfSSepherosa Ziehau static void
31126c1204dfSSepherosa Ziehau hn_chan_polling(struct vmbus_channel *chan, u_int pollhz)
31136c1204dfSSepherosa Ziehau {
31146c1204dfSSepherosa Ziehau 	if (pollhz == 0)
31156c1204dfSSepherosa Ziehau 		vmbus_chan_poll_disable(chan);
31166c1204dfSSepherosa Ziehau 	else
31176c1204dfSSepherosa Ziehau 		vmbus_chan_poll_enable(chan, pollhz);
31186c1204dfSSepherosa Ziehau }
31196c1204dfSSepherosa Ziehau 
31206c1204dfSSepherosa Ziehau static void
31216c1204dfSSepherosa Ziehau hn_polling(struct hn_softc *sc, u_int pollhz)
31226c1204dfSSepherosa Ziehau {
31236c1204dfSSepherosa Ziehau 	int nsubch = sc->hn_rx_ring_inuse - 1;
31246c1204dfSSepherosa Ziehau 
31256c1204dfSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
31266c1204dfSSepherosa Ziehau 
31276c1204dfSSepherosa Ziehau 	if (nsubch > 0) {
31286c1204dfSSepherosa Ziehau 		struct vmbus_channel **subch;
31296c1204dfSSepherosa Ziehau 		int i;
31306c1204dfSSepherosa Ziehau 
31316c1204dfSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
31326c1204dfSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
31336c1204dfSSepherosa Ziehau 			hn_chan_polling(subch[i], pollhz);
31346c1204dfSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
31356c1204dfSSepherosa Ziehau 	}
31366c1204dfSSepherosa Ziehau 	hn_chan_polling(sc->hn_prichan, pollhz);
31376c1204dfSSepherosa Ziehau }
31386c1204dfSSepherosa Ziehau 
31396c1204dfSSepherosa Ziehau static int
31406c1204dfSSepherosa Ziehau hn_polling_sysctl(SYSCTL_HANDLER_ARGS)
31416c1204dfSSepherosa Ziehau {
31426c1204dfSSepherosa Ziehau 	struct hn_softc *sc = arg1;
31436c1204dfSSepherosa Ziehau 	int pollhz, error;
31446c1204dfSSepherosa Ziehau 
31456c1204dfSSepherosa Ziehau 	pollhz = sc->hn_pollhz;
31466c1204dfSSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pollhz, 0, req);
31476c1204dfSSepherosa Ziehau 	if (error || req->newptr == NULL)
31486c1204dfSSepherosa Ziehau 		return (error);
31496c1204dfSSepherosa Ziehau 
31506c1204dfSSepherosa Ziehau 	if (pollhz != 0 &&
31516c1204dfSSepherosa Ziehau 	    (pollhz < VMBUS_CHAN_POLLHZ_MIN || pollhz > VMBUS_CHAN_POLLHZ_MAX))
31526c1204dfSSepherosa Ziehau 		return (EINVAL);
31536c1204dfSSepherosa Ziehau 
31546c1204dfSSepherosa Ziehau 	HN_LOCK(sc);
31556c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz != pollhz) {
31566c1204dfSSepherosa Ziehau 		sc->hn_pollhz = pollhz;
31576c1204dfSSepherosa Ziehau 		if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) &&
31586c1204dfSSepherosa Ziehau 		    (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
31596c1204dfSSepherosa Ziehau 			hn_polling(sc, sc->hn_pollhz);
31606c1204dfSSepherosa Ziehau 	}
31616c1204dfSSepherosa Ziehau 	HN_UNLOCK(sc);
31626c1204dfSSepherosa Ziehau 
31636c1204dfSSepherosa Ziehau 	return (0);
31646c1204dfSSepherosa Ziehau }
31656c1204dfSSepherosa Ziehau 
3166dc13fee6SSepherosa Ziehau static int
316715516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS)
316815516c77SSepherosa Ziehau {
316915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
317015516c77SSepherosa Ziehau 	char verstr[16];
317115516c77SSepherosa Ziehau 
317215516c77SSepherosa Ziehau 	snprintf(verstr, sizeof(verstr), "%u.%u",
317315516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
317415516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
317515516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
317615516c77SSepherosa Ziehau }
317715516c77SSepherosa Ziehau 
317815516c77SSepherosa Ziehau static int
317915516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS)
318015516c77SSepherosa Ziehau {
318115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
318215516c77SSepherosa Ziehau 	char caps_str[128];
318315516c77SSepherosa Ziehau 	uint32_t caps;
318415516c77SSepherosa Ziehau 
318515516c77SSepherosa Ziehau 	HN_LOCK(sc);
318615516c77SSepherosa Ziehau 	caps = sc->hn_caps;
318715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
318815516c77SSepherosa Ziehau 	snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS);
318915516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req);
319015516c77SSepherosa Ziehau }
319115516c77SSepherosa Ziehau 
319215516c77SSepherosa Ziehau static int
319315516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS)
319415516c77SSepherosa Ziehau {
319515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
319615516c77SSepherosa Ziehau 	char assist_str[128];
319715516c77SSepherosa Ziehau 	uint32_t hwassist;
319815516c77SSepherosa Ziehau 
319915516c77SSepherosa Ziehau 	HN_LOCK(sc);
320015516c77SSepherosa Ziehau 	hwassist = sc->hn_ifp->if_hwassist;
320115516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
320215516c77SSepherosa Ziehau 	snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS);
320315516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req);
320415516c77SSepherosa Ziehau }
320515516c77SSepherosa Ziehau 
320615516c77SSepherosa Ziehau static int
320715516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS)
320815516c77SSepherosa Ziehau {
320915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
321015516c77SSepherosa Ziehau 	char filter_str[128];
321115516c77SSepherosa Ziehau 	uint32_t filter;
321215516c77SSepherosa Ziehau 
321315516c77SSepherosa Ziehau 	HN_LOCK(sc);
321415516c77SSepherosa Ziehau 	filter = sc->hn_rx_filter;
321515516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
321615516c77SSepherosa Ziehau 	snprintf(filter_str, sizeof(filter_str), "%b", filter,
321715516c77SSepherosa Ziehau 	    NDIS_PACKET_TYPES);
321815516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req);
321915516c77SSepherosa Ziehau }
322015516c77SSepherosa Ziehau 
322134d68912SSepherosa Ziehau #ifndef RSS
322234d68912SSepherosa Ziehau 
322315516c77SSepherosa Ziehau static int
322415516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
322515516c77SSepherosa Ziehau {
322615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
322715516c77SSepherosa Ziehau 	int error;
322815516c77SSepherosa Ziehau 
322915516c77SSepherosa Ziehau 	HN_LOCK(sc);
323015516c77SSepherosa Ziehau 
323115516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
323215516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
323315516c77SSepherosa Ziehau 		goto back;
323415516c77SSepherosa Ziehau 
323515516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
323615516c77SSepherosa Ziehau 	if (error)
323715516c77SSepherosa Ziehau 		goto back;
323815516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
323915516c77SSepherosa Ziehau 
324015516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
324115516c77SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
324215516c77SSepherosa Ziehau 	} else {
324315516c77SSepherosa Ziehau 		/* Not RSS capable, at least for now; just save the RSS key. */
324415516c77SSepherosa Ziehau 		error = 0;
324515516c77SSepherosa Ziehau 	}
324615516c77SSepherosa Ziehau back:
324715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
324815516c77SSepherosa Ziehau 	return (error);
324915516c77SSepherosa Ziehau }
325015516c77SSepherosa Ziehau 
325115516c77SSepherosa Ziehau static int
325215516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS)
325315516c77SSepherosa Ziehau {
325415516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
325515516c77SSepherosa Ziehau 	int error;
325615516c77SSepherosa Ziehau 
325715516c77SSepherosa Ziehau 	HN_LOCK(sc);
325815516c77SSepherosa Ziehau 
325915516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
326015516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
326115516c77SSepherosa Ziehau 		goto back;
326215516c77SSepherosa Ziehau 
326315516c77SSepherosa Ziehau 	/*
326415516c77SSepherosa Ziehau 	 * Don't allow RSS indirect table change, if this interface is not
326515516c77SSepherosa Ziehau 	 * RSS capable currently.
326615516c77SSepherosa Ziehau 	 */
326715516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
326815516c77SSepherosa Ziehau 		error = EOPNOTSUPP;
326915516c77SSepherosa Ziehau 		goto back;
327015516c77SSepherosa Ziehau 	}
327115516c77SSepherosa Ziehau 
327215516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
327315516c77SSepherosa Ziehau 	if (error)
327415516c77SSepherosa Ziehau 		goto back;
327515516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSIND;
327615516c77SSepherosa Ziehau 
3277afd4971bSSepherosa Ziehau 	hn_rss_ind_fixup(sc);
327815516c77SSepherosa Ziehau 	error = hn_rss_reconfig(sc);
327915516c77SSepherosa Ziehau back:
328015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
328115516c77SSepherosa Ziehau 	return (error);
328215516c77SSepherosa Ziehau }
328315516c77SSepherosa Ziehau 
328434d68912SSepherosa Ziehau #endif	/* !RSS */
328534d68912SSepherosa Ziehau 
328615516c77SSepherosa Ziehau static int
328715516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS)
328815516c77SSepherosa Ziehau {
328915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
329015516c77SSepherosa Ziehau 	char hash_str[128];
329115516c77SSepherosa Ziehau 	uint32_t hash;
329215516c77SSepherosa Ziehau 
329315516c77SSepherosa Ziehau 	HN_LOCK(sc);
329415516c77SSepherosa Ziehau 	hash = sc->hn_rss_hash;
329515516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
329615516c77SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
329715516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
329815516c77SSepherosa Ziehau }
329915516c77SSepherosa Ziehau 
330015516c77SSepherosa Ziehau static int
330140d60d6eSDexuan Cui hn_vf_sysctl(SYSCTL_HANDLER_ARGS)
330240d60d6eSDexuan Cui {
330340d60d6eSDexuan Cui 	struct hn_softc *sc = arg1;
330440d60d6eSDexuan Cui 	char vf_name[128];
330540d60d6eSDexuan Cui 	struct ifnet *vf;
330640d60d6eSDexuan Cui 
330740d60d6eSDexuan Cui 	HN_LOCK(sc);
330840d60d6eSDexuan Cui 	vf_name[0] = '\0';
330940d60d6eSDexuan Cui 	vf = sc->hn_rx_ring[0].hn_vf;
331040d60d6eSDexuan Cui 	if (vf != NULL)
331140d60d6eSDexuan Cui 		snprintf(vf_name, sizeof(vf_name), "%s", if_name(vf));
331240d60d6eSDexuan Cui 	HN_UNLOCK(sc);
331340d60d6eSDexuan Cui 	return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req);
331440d60d6eSDexuan Cui }
331540d60d6eSDexuan Cui 
331640d60d6eSDexuan Cui static int
331715516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff)
331815516c77SSepherosa Ziehau {
331915516c77SSepherosa Ziehau 	const struct ip *ip;
332015516c77SSepherosa Ziehau 	int len, iphlen, iplen;
332115516c77SSepherosa Ziehau 	const struct tcphdr *th;
332215516c77SSepherosa Ziehau 	int thoff;				/* TCP data offset */
332315516c77SSepherosa Ziehau 
332415516c77SSepherosa Ziehau 	len = hoff + sizeof(struct ip);
332515516c77SSepherosa Ziehau 
332615516c77SSepherosa Ziehau 	/* The packet must be at least the size of an IP header. */
332715516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < len)
332815516c77SSepherosa Ziehau 		return IPPROTO_DONE;
332915516c77SSepherosa Ziehau 
333015516c77SSepherosa Ziehau 	/* The fixed IP header must reside completely in the first mbuf. */
333115516c77SSepherosa Ziehau 	if (m->m_len < len)
333215516c77SSepherosa Ziehau 		return IPPROTO_DONE;
333315516c77SSepherosa Ziehau 
333415516c77SSepherosa Ziehau 	ip = mtodo(m, hoff);
333515516c77SSepherosa Ziehau 
333615516c77SSepherosa Ziehau 	/* Bound check the packet's stated IP header length. */
333715516c77SSepherosa Ziehau 	iphlen = ip->ip_hl << 2;
333815516c77SSepherosa Ziehau 	if (iphlen < sizeof(struct ip))		/* minimum header length */
333915516c77SSepherosa Ziehau 		return IPPROTO_DONE;
334015516c77SSepherosa Ziehau 
334115516c77SSepherosa Ziehau 	/* The full IP header must reside completely in the one mbuf. */
334215516c77SSepherosa Ziehau 	if (m->m_len < hoff + iphlen)
334315516c77SSepherosa Ziehau 		return IPPROTO_DONE;
334415516c77SSepherosa Ziehau 
334515516c77SSepherosa Ziehau 	iplen = ntohs(ip->ip_len);
334615516c77SSepherosa Ziehau 
334715516c77SSepherosa Ziehau 	/*
334815516c77SSepherosa Ziehau 	 * Check that the amount of data in the buffers is as
334915516c77SSepherosa Ziehau 	 * at least much as the IP header would have us expect.
335015516c77SSepherosa Ziehau 	 */
335115516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < hoff + iplen)
335215516c77SSepherosa Ziehau 		return IPPROTO_DONE;
335315516c77SSepherosa Ziehau 
335415516c77SSepherosa Ziehau 	/*
335515516c77SSepherosa Ziehau 	 * Ignore IP fragments.
335615516c77SSepherosa Ziehau 	 */
335715516c77SSepherosa Ziehau 	if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF))
335815516c77SSepherosa Ziehau 		return IPPROTO_DONE;
335915516c77SSepherosa Ziehau 
336015516c77SSepherosa Ziehau 	/*
336115516c77SSepherosa Ziehau 	 * The TCP/IP or UDP/IP header must be entirely contained within
336215516c77SSepherosa Ziehau 	 * the first fragment of a packet.
336315516c77SSepherosa Ziehau 	 */
336415516c77SSepherosa Ziehau 	switch (ip->ip_p) {
336515516c77SSepherosa Ziehau 	case IPPROTO_TCP:
336615516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct tcphdr))
336715516c77SSepherosa Ziehau 			return IPPROTO_DONE;
336815516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct tcphdr))
336915516c77SSepherosa Ziehau 			return IPPROTO_DONE;
337015516c77SSepherosa Ziehau 		th = (const struct tcphdr *)((const uint8_t *)ip + iphlen);
337115516c77SSepherosa Ziehau 		thoff = th->th_off << 2;
337215516c77SSepherosa Ziehau 		if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen)
337315516c77SSepherosa Ziehau 			return IPPROTO_DONE;
337415516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + thoff)
337515516c77SSepherosa Ziehau 			return IPPROTO_DONE;
337615516c77SSepherosa Ziehau 		break;
337715516c77SSepherosa Ziehau 	case IPPROTO_UDP:
337815516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct udphdr))
337915516c77SSepherosa Ziehau 			return IPPROTO_DONE;
338015516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct udphdr))
338115516c77SSepherosa Ziehau 			return IPPROTO_DONE;
338215516c77SSepherosa Ziehau 		break;
338315516c77SSepherosa Ziehau 	default:
338415516c77SSepherosa Ziehau 		if (iplen < iphlen)
338515516c77SSepherosa Ziehau 			return IPPROTO_DONE;
338615516c77SSepherosa Ziehau 		break;
338715516c77SSepherosa Ziehau 	}
338815516c77SSepherosa Ziehau 	return ip->ip_p;
338915516c77SSepherosa Ziehau }
339015516c77SSepherosa Ziehau 
339115516c77SSepherosa Ziehau static int
339215516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt)
339315516c77SSepherosa Ziehau {
339415516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
339515516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
339615516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
339715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
339815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
339915516c77SSepherosa Ziehau 	int lroent_cnt;
340015516c77SSepherosa Ziehau #endif
340115516c77SSepherosa Ziehau #endif
340215516c77SSepherosa Ziehau 	int i;
340315516c77SSepherosa Ziehau 
340415516c77SSepherosa Ziehau 	/*
340515516c77SSepherosa Ziehau 	 * Create RXBUF for reception.
340615516c77SSepherosa Ziehau 	 *
340715516c77SSepherosa Ziehau 	 * NOTE:
340815516c77SSepherosa Ziehau 	 * - It is shared by all channels.
340915516c77SSepherosa Ziehau 	 * - A large enough buffer is allocated, certain version of NVSes
341015516c77SSepherosa Ziehau 	 *   may further limit the usable space.
341115516c77SSepherosa Ziehau 	 */
341215516c77SSepherosa Ziehau 	sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
341315516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma,
341415516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
341515516c77SSepherosa Ziehau 	if (sc->hn_rxbuf == NULL) {
341615516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate rxbuf failed\n");
341715516c77SSepherosa Ziehau 		return (ENOMEM);
341815516c77SSepherosa Ziehau 	}
341915516c77SSepherosa Ziehau 
342015516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = ring_cnt;
342115516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt;
342215516c77SSepherosa Ziehau 
342315516c77SSepherosa Ziehau 	sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt,
342415516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
342515516c77SSepherosa Ziehau 
342615516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
342715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
342815516c77SSepherosa Ziehau 	lroent_cnt = hn_lro_entry_count;
342915516c77SSepherosa Ziehau 	if (lroent_cnt < TCP_LRO_ENTRIES)
343015516c77SSepherosa Ziehau 		lroent_cnt = TCP_LRO_ENTRIES;
343115516c77SSepherosa Ziehau 	if (bootverbose)
343215516c77SSepherosa Ziehau 		device_printf(dev, "LRO: entry count %d\n", lroent_cnt);
343315516c77SSepherosa Ziehau #endif
343415516c77SSepherosa Ziehau #endif	/* INET || INET6 */
343515516c77SSepherosa Ziehau 
343615516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
343715516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
343815516c77SSepherosa Ziehau 
343915516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.rx sysctl tree */
344015516c77SSepherosa Ziehau 	sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx",
344115516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
344215516c77SSepherosa Ziehau 
344315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
344415516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
344515516c77SSepherosa Ziehau 
344615516c77SSepherosa Ziehau 		rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
344715516c77SSepherosa Ziehau 		    PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE,
344815516c77SSepherosa Ziehau 		    &rxr->hn_br_dma, BUS_DMA_WAITOK);
344915516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL) {
345015516c77SSepherosa Ziehau 			device_printf(dev, "allocate bufring failed\n");
345115516c77SSepherosa Ziehau 			return (ENOMEM);
345215516c77SSepherosa Ziehau 		}
345315516c77SSepherosa Ziehau 
345415516c77SSepherosa Ziehau 		if (hn_trust_hosttcp)
345515516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP;
345615516c77SSepherosa Ziehau 		if (hn_trust_hostudp)
345715516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP;
345815516c77SSepherosa Ziehau 		if (hn_trust_hostip)
345915516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP;
346015516c77SSepherosa Ziehau 		rxr->hn_ifp = sc->hn_ifp;
346115516c77SSepherosa Ziehau 		if (i < sc->hn_tx_ring_cnt)
346215516c77SSepherosa Ziehau 			rxr->hn_txr = &sc->hn_tx_ring[i];
346315516c77SSepherosa Ziehau 		rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF;
346415516c77SSepherosa Ziehau 		rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK);
346515516c77SSepherosa Ziehau 		rxr->hn_rx_idx = i;
346615516c77SSepherosa Ziehau 		rxr->hn_rxbuf = sc->hn_rxbuf;
346715516c77SSepherosa Ziehau 
346815516c77SSepherosa Ziehau 		/*
346915516c77SSepherosa Ziehau 		 * Initialize LRO.
347015516c77SSepherosa Ziehau 		 */
347115516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
347215516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
347315516c77SSepherosa Ziehau 		tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt,
347415516c77SSepherosa Ziehau 		    hn_lro_mbufq_depth);
347515516c77SSepherosa Ziehau #else
347615516c77SSepherosa Ziehau 		tcp_lro_init(&rxr->hn_lro);
347715516c77SSepherosa Ziehau 		rxr->hn_lro.ifp = sc->hn_ifp;
347815516c77SSepherosa Ziehau #endif
347915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
348015516c77SSepherosa Ziehau 		rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF;
348115516c77SSepherosa Ziehau 		rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF;
348215516c77SSepherosa Ziehau #endif
348315516c77SSepherosa Ziehau #endif	/* INET || INET6 */
348415516c77SSepherosa Ziehau 
348515516c77SSepherosa Ziehau 		if (sc->hn_rx_sysctl_tree != NULL) {
348615516c77SSepherosa Ziehau 			char name[16];
348715516c77SSepherosa Ziehau 
348815516c77SSepherosa Ziehau 			/*
348915516c77SSepherosa Ziehau 			 * Create per RX ring sysctl tree:
349015516c77SSepherosa Ziehau 			 * dev.hn.UNIT.rx.RINGID
349115516c77SSepherosa Ziehau 			 */
349215516c77SSepherosa Ziehau 			snprintf(name, sizeof(name), "%d", i);
349315516c77SSepherosa Ziehau 			rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx,
349415516c77SSepherosa Ziehau 			    SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree),
349515516c77SSepherosa Ziehau 			    OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
349615516c77SSepherosa Ziehau 
349715516c77SSepherosa Ziehau 			if (rxr->hn_rx_sysctl_tree != NULL) {
349815516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
349915516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
350015516c77SSepherosa Ziehau 				    OID_AUTO, "packets", CTLFLAG_RW,
350115516c77SSepherosa Ziehau 				    &rxr->hn_pkts, "# of packets received");
350215516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
350315516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
350415516c77SSepherosa Ziehau 				    OID_AUTO, "rss_pkts", CTLFLAG_RW,
350515516c77SSepherosa Ziehau 				    &rxr->hn_rss_pkts,
350615516c77SSepherosa Ziehau 				    "# of packets w/ RSS info received");
350715516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx,
350815516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
350915516c77SSepherosa Ziehau 				    OID_AUTO, "pktbuf_len", CTLFLAG_RD,
351015516c77SSepherosa Ziehau 				    &rxr->hn_pktbuf_len, 0,
351115516c77SSepherosa Ziehau 				    "Temporary channel packet buffer length");
351215516c77SSepherosa Ziehau 			}
351315516c77SSepherosa Ziehau 		}
351415516c77SSepherosa Ziehau 	}
351515516c77SSepherosa Ziehau 
351615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued",
351715516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
351815516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_queued),
351915516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
352015516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
352115516c77SSepherosa Ziehau #else
352215516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
352315516c77SSepherosa Ziehau #endif
352415516c77SSepherosa Ziehau 	    "LU", "LRO queued");
352515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed",
352615516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
352715516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_flushed),
352815516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
352915516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
353015516c77SSepherosa Ziehau #else
353115516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
353215516c77SSepherosa Ziehau #endif
353315516c77SSepherosa Ziehau 	    "LU", "LRO flushed");
353415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried",
353515516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
353615516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro_tried),
353715516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries");
353815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
353915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim",
354015516c77SSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
354115516c77SSepherosa Ziehau 	    hn_lro_lenlim_sysctl, "IU",
354215516c77SSepherosa Ziehau 	    "Max # of data bytes to be aggregated by LRO");
354315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim",
354415516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
354515516c77SSepherosa Ziehau 	    hn_lro_ackcnt_sysctl, "I",
354615516c77SSepherosa Ziehau 	    "Max # of ACKs to be aggregated by LRO");
354715516c77SSepherosa Ziehau #endif
354815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp",
354915516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP,
355015516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
355115516c77SSepherosa Ziehau 	    "Trust tcp segement verification on host side, "
355215516c77SSepherosa Ziehau 	    "when csum info is missing");
355315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp",
355415516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP,
355515516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
355615516c77SSepherosa Ziehau 	    "Trust udp datagram verification on host side, "
355715516c77SSepherosa Ziehau 	    "when csum info is missing");
355815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip",
355915516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP,
356015516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
356115516c77SSepherosa Ziehau 	    "Trust ip packet verification on host side, "
356215516c77SSepherosa Ziehau 	    "when csum info is missing");
356315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip",
356415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
356515516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_ip),
356615516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP");
356715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp",
356815516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
356915516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_tcp),
357015516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP");
357115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp",
357215516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
357315516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_udp),
357415516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP");
357515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted",
357615516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
357715516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_trusted),
357815516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU",
357915516c77SSepherosa Ziehau 	    "# of packets that we trust host's csum verification");
358015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts",
358115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
358215516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_small_pkts),
358315516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of small packets received");
358415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed",
358515516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
358615516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_ack_failed),
358715516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures");
358815516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt",
358915516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings");
359015516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse",
359115516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings");
359215516c77SSepherosa Ziehau 
359315516c77SSepherosa Ziehau 	return (0);
359415516c77SSepherosa Ziehau }
359515516c77SSepherosa Ziehau 
359615516c77SSepherosa Ziehau static void
359715516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc)
359815516c77SSepherosa Ziehau {
359915516c77SSepherosa Ziehau 	int i;
360015516c77SSepherosa Ziehau 
360115516c77SSepherosa Ziehau 	if (sc->hn_rxbuf != NULL) {
36022494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0)
360315516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf);
36042494d735SSepherosa Ziehau 		else
36052494d735SSepherosa Ziehau 			device_printf(sc->hn_dev, "RXBUF is referenced\n");
360615516c77SSepherosa Ziehau 		sc->hn_rxbuf = NULL;
360715516c77SSepherosa Ziehau 	}
360815516c77SSepherosa Ziehau 
360915516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_cnt == 0)
361015516c77SSepherosa Ziehau 		return;
361115516c77SSepherosa Ziehau 
361215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
361315516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
361415516c77SSepherosa Ziehau 
361515516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL)
361615516c77SSepherosa Ziehau 			continue;
36172494d735SSepherosa Ziehau 		if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) {
361815516c77SSepherosa Ziehau 			hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br);
36192494d735SSepherosa Ziehau 		} else {
36202494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
36212494d735SSepherosa Ziehau 			    "%dth channel bufring is referenced", i);
36222494d735SSepherosa Ziehau 		}
362315516c77SSepherosa Ziehau 		rxr->hn_br = NULL;
362415516c77SSepherosa Ziehau 
362515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
362615516c77SSepherosa Ziehau 		tcp_lro_free(&rxr->hn_lro);
362715516c77SSepherosa Ziehau #endif
362815516c77SSepherosa Ziehau 		free(rxr->hn_pktbuf, M_DEVBUF);
362915516c77SSepherosa Ziehau 	}
363015516c77SSepherosa Ziehau 	free(sc->hn_rx_ring, M_DEVBUF);
363115516c77SSepherosa Ziehau 	sc->hn_rx_ring = NULL;
363215516c77SSepherosa Ziehau 
363315516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = 0;
363415516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = 0;
363515516c77SSepherosa Ziehau }
363615516c77SSepherosa Ziehau 
363715516c77SSepherosa Ziehau static int
363815516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id)
363915516c77SSepherosa Ziehau {
364015516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[id];
364115516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
364215516c77SSepherosa Ziehau 	bus_dma_tag_t parent_dtag;
364315516c77SSepherosa Ziehau 	int error, i;
364415516c77SSepherosa Ziehau 
364515516c77SSepherosa Ziehau 	txr->hn_sc = sc;
364615516c77SSepherosa Ziehau 	txr->hn_tx_idx = id;
364715516c77SSepherosa Ziehau 
364815516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
364915516c77SSepherosa Ziehau 	mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN);
365015516c77SSepherosa Ziehau #endif
365115516c77SSepherosa Ziehau 	mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF);
365215516c77SSepherosa Ziehau 
365315516c77SSepherosa Ziehau 	txr->hn_txdesc_cnt = HN_TX_DESC_CNT;
365415516c77SSepherosa Ziehau 	txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt,
365515516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
365615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
365715516c77SSepherosa Ziehau 	SLIST_INIT(&txr->hn_txlist);
365815516c77SSepherosa Ziehau #else
365915516c77SSepherosa Ziehau 	txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF,
366015516c77SSepherosa Ziehau 	    M_WAITOK, &txr->hn_tx_lock);
366115516c77SSepherosa Ziehau #endif
366215516c77SSepherosa Ziehau 
36630e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_EVTTQ) {
36640e11868dSSepherosa Ziehau 		txr->hn_tx_taskq = VMBUS_GET_EVENT_TASKQ(
36650e11868dSSepherosa Ziehau 		    device_get_parent(dev), dev, HN_RING_IDX2CPU(sc, id));
36660e11868dSSepherosa Ziehau 	} else {
3667fdd0222aSSepherosa Ziehau 		txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt];
36680e11868dSSepherosa Ziehau 	}
366915516c77SSepherosa Ziehau 
367023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
367115516c77SSepherosa Ziehau 	if (hn_use_if_start) {
367215516c77SSepherosa Ziehau 		txr->hn_txeof = hn_start_txeof;
367315516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr);
367415516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr);
367523bf9e15SSepherosa Ziehau 	} else
367623bf9e15SSepherosa Ziehau #endif
367723bf9e15SSepherosa Ziehau 	{
367815516c77SSepherosa Ziehau 		int br_depth;
367915516c77SSepherosa Ziehau 
368015516c77SSepherosa Ziehau 		txr->hn_txeof = hn_xmit_txeof;
368115516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr);
368215516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr);
368315516c77SSepherosa Ziehau 
368415516c77SSepherosa Ziehau 		br_depth = hn_get_txswq_depth(txr);
368515516c77SSepherosa Ziehau 		txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF,
368615516c77SSepherosa Ziehau 		    M_WAITOK, &txr->hn_tx_lock);
368715516c77SSepherosa Ziehau 	}
368815516c77SSepherosa Ziehau 
368915516c77SSepherosa Ziehau 	txr->hn_direct_tx_size = hn_direct_tx_size;
369015516c77SSepherosa Ziehau 
369115516c77SSepherosa Ziehau 	/*
369215516c77SSepherosa Ziehau 	 * Always schedule transmission instead of trying to do direct
369315516c77SSepherosa Ziehau 	 * transmission.  This one gives the best performance so far.
369415516c77SSepherosa Ziehau 	 */
369515516c77SSepherosa Ziehau 	txr->hn_sched_tx = 1;
369615516c77SSepherosa Ziehau 
369715516c77SSepherosa Ziehau 	parent_dtag = bus_get_dma_tag(dev);
369815516c77SSepherosa Ziehau 
369915516c77SSepherosa Ziehau 	/* DMA tag for RNDIS packet messages. */
370015516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
370115516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_ALIGN,		/* alignment */
370215516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_BOUNDARY,	/* boundary */
370315516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
370415516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
370515516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
370615516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsize */
370715516c77SSepherosa Ziehau 	    1,				/* nsegments */
370815516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsegsize */
370915516c77SSepherosa Ziehau 	    0,				/* flags */
371015516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
371115516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
371215516c77SSepherosa Ziehau 	    &txr->hn_tx_rndis_dtag);
371315516c77SSepherosa Ziehau 	if (error) {
371415516c77SSepherosa Ziehau 		device_printf(dev, "failed to create rndis dmatag\n");
371515516c77SSepherosa Ziehau 		return error;
371615516c77SSepherosa Ziehau 	}
371715516c77SSepherosa Ziehau 
371815516c77SSepherosa Ziehau 	/* DMA tag for data. */
371915516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
372015516c77SSepherosa Ziehau 	    1,				/* alignment */
372115516c77SSepherosa Ziehau 	    HN_TX_DATA_BOUNDARY,	/* boundary */
372215516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
372315516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
372415516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
372515516c77SSepherosa Ziehau 	    HN_TX_DATA_MAXSIZE,		/* maxsize */
372615516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGCNT_MAX,	/* nsegments */
372715516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGSIZE,		/* maxsegsize */
372815516c77SSepherosa Ziehau 	    0,				/* flags */
372915516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
373015516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
373115516c77SSepherosa Ziehau 	    &txr->hn_tx_data_dtag);
373215516c77SSepherosa Ziehau 	if (error) {
373315516c77SSepherosa Ziehau 		device_printf(dev, "failed to create data dmatag\n");
373415516c77SSepherosa Ziehau 		return error;
373515516c77SSepherosa Ziehau 	}
373615516c77SSepherosa Ziehau 
373715516c77SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i) {
373815516c77SSepherosa Ziehau 		struct hn_txdesc *txd = &txr->hn_txdesc[i];
373915516c77SSepherosa Ziehau 
374015516c77SSepherosa Ziehau 		txd->txr = txr;
374115516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
3742dc13fee6SSepherosa Ziehau 		STAILQ_INIT(&txd->agg_list);
374315516c77SSepherosa Ziehau 
374415516c77SSepherosa Ziehau 		/*
374515516c77SSepherosa Ziehau 		 * Allocate and load RNDIS packet message.
374615516c77SSepherosa Ziehau 		 */
374715516c77SSepherosa Ziehau         	error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag,
374815516c77SSepherosa Ziehau 		    (void **)&txd->rndis_pkt,
374915516c77SSepherosa Ziehau 		    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
375015516c77SSepherosa Ziehau 		    &txd->rndis_pkt_dmap);
375115516c77SSepherosa Ziehau 		if (error) {
375215516c77SSepherosa Ziehau 			device_printf(dev,
375315516c77SSepherosa Ziehau 			    "failed to allocate rndis_packet_msg, %d\n", i);
375415516c77SSepherosa Ziehau 			return error;
375515516c77SSepherosa Ziehau 		}
375615516c77SSepherosa Ziehau 
375715516c77SSepherosa Ziehau 		error = bus_dmamap_load(txr->hn_tx_rndis_dtag,
375815516c77SSepherosa Ziehau 		    txd->rndis_pkt_dmap,
375915516c77SSepherosa Ziehau 		    txd->rndis_pkt, HN_RNDIS_PKT_LEN,
376015516c77SSepherosa Ziehau 		    hyperv_dma_map_paddr, &txd->rndis_pkt_paddr,
376115516c77SSepherosa Ziehau 		    BUS_DMA_NOWAIT);
376215516c77SSepherosa Ziehau 		if (error) {
376315516c77SSepherosa Ziehau 			device_printf(dev,
376415516c77SSepherosa Ziehau 			    "failed to load rndis_packet_msg, %d\n", i);
376515516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
376615516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
376715516c77SSepherosa Ziehau 			return error;
376815516c77SSepherosa Ziehau 		}
376915516c77SSepherosa Ziehau 
377015516c77SSepherosa Ziehau 		/* DMA map for TX data. */
377115516c77SSepherosa Ziehau 		error = bus_dmamap_create(txr->hn_tx_data_dtag, 0,
377215516c77SSepherosa Ziehau 		    &txd->data_dmap);
377315516c77SSepherosa Ziehau 		if (error) {
377415516c77SSepherosa Ziehau 			device_printf(dev,
377515516c77SSepherosa Ziehau 			    "failed to allocate tx data dmamap\n");
377615516c77SSepherosa Ziehau 			bus_dmamap_unload(txr->hn_tx_rndis_dtag,
377715516c77SSepherosa Ziehau 			    txd->rndis_pkt_dmap);
377815516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
377915516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
378015516c77SSepherosa Ziehau 			return error;
378115516c77SSepherosa Ziehau 		}
378215516c77SSepherosa Ziehau 
378315516c77SSepherosa Ziehau 		/* All set, put it to list */
378415516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_ONLIST;
378515516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
378615516c77SSepherosa Ziehau 		SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
378715516c77SSepherosa Ziehau #else
378815516c77SSepherosa Ziehau 		buf_ring_enqueue(txr->hn_txdesc_br, txd);
378915516c77SSepherosa Ziehau #endif
379015516c77SSepherosa Ziehau 	}
379115516c77SSepherosa Ziehau 	txr->hn_txdesc_avail = txr->hn_txdesc_cnt;
379215516c77SSepherosa Ziehau 
379315516c77SSepherosa Ziehau 	if (sc->hn_tx_sysctl_tree != NULL) {
379415516c77SSepherosa Ziehau 		struct sysctl_oid_list *child;
379515516c77SSepherosa Ziehau 		struct sysctl_ctx_list *ctx;
379615516c77SSepherosa Ziehau 		char name[16];
379715516c77SSepherosa Ziehau 
379815516c77SSepherosa Ziehau 		/*
379915516c77SSepherosa Ziehau 		 * Create per TX ring sysctl tree:
380015516c77SSepherosa Ziehau 		 * dev.hn.UNIT.tx.RINGID
380115516c77SSepherosa Ziehau 		 */
380215516c77SSepherosa Ziehau 		ctx = device_get_sysctl_ctx(dev);
380315516c77SSepherosa Ziehau 		child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree);
380415516c77SSepherosa Ziehau 
380515516c77SSepherosa Ziehau 		snprintf(name, sizeof(name), "%d", id);
380615516c77SSepherosa Ziehau 		txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
380715516c77SSepherosa Ziehau 		    name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
380815516c77SSepherosa Ziehau 
380915516c77SSepherosa Ziehau 		if (txr->hn_tx_sysctl_tree != NULL) {
381015516c77SSepherosa Ziehau 			child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree);
381115516c77SSepherosa Ziehau 
381285e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
381315516c77SSepherosa Ziehau 			SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail",
381415516c77SSepherosa Ziehau 			    CTLFLAG_RD, &txr->hn_txdesc_avail, 0,
381515516c77SSepherosa Ziehau 			    "# of available TX descs");
381685e4ae1eSSepherosa Ziehau #endif
381723bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
381823bf9e15SSepherosa Ziehau 			if (!hn_use_if_start)
381923bf9e15SSepherosa Ziehau #endif
382023bf9e15SSepherosa Ziehau 			{
382115516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive",
382215516c77SSepherosa Ziehau 				    CTLFLAG_RD, &txr->hn_oactive, 0,
382315516c77SSepherosa Ziehau 				    "over active");
382415516c77SSepherosa Ziehau 			}
382515516c77SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets",
382615516c77SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_pkts,
382715516c77SSepherosa Ziehau 			    "# of packets transmitted");
3828dc13fee6SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends",
3829dc13fee6SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_sends, "# of sends");
383015516c77SSepherosa Ziehau 		}
383115516c77SSepherosa Ziehau 	}
383215516c77SSepherosa Ziehau 
383315516c77SSepherosa Ziehau 	return 0;
383415516c77SSepherosa Ziehau }
383515516c77SSepherosa Ziehau 
383615516c77SSepherosa Ziehau static void
383715516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd)
383815516c77SSepherosa Ziehau {
383915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = txd->txr;
384015516c77SSepherosa Ziehau 
384115516c77SSepherosa Ziehau 	KASSERT(txd->m == NULL, ("still has mbuf installed"));
384215516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped"));
384315516c77SSepherosa Ziehau 
384415516c77SSepherosa Ziehau 	bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap);
384515516c77SSepherosa Ziehau 	bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt,
384615516c77SSepherosa Ziehau 	    txd->rndis_pkt_dmap);
384715516c77SSepherosa Ziehau 	bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap);
384815516c77SSepherosa Ziehau }
384915516c77SSepherosa Ziehau 
385015516c77SSepherosa Ziehau static void
385125641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd)
385225641fc7SSepherosa Ziehau {
385325641fc7SSepherosa Ziehau 
385425641fc7SSepherosa Ziehau 	KASSERT(txd->refs == 0 || txd->refs == 1,
385525641fc7SSepherosa Ziehau 	    ("invalid txd refs %d", txd->refs));
385625641fc7SSepherosa Ziehau 
385725641fc7SSepherosa Ziehau 	/* Aggregated txds will be freed by their aggregating txd. */
385825641fc7SSepherosa Ziehau 	if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) {
385925641fc7SSepherosa Ziehau 		int freed;
386025641fc7SSepherosa Ziehau 
386125641fc7SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
386225641fc7SSepherosa Ziehau 		KASSERT(freed, ("can't free txdesc"));
386325641fc7SSepherosa Ziehau 	}
386425641fc7SSepherosa Ziehau }
386525641fc7SSepherosa Ziehau 
386625641fc7SSepherosa Ziehau static void
386715516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr)
386815516c77SSepherosa Ziehau {
386925641fc7SSepherosa Ziehau 	int i;
387015516c77SSepherosa Ziehau 
387115516c77SSepherosa Ziehau 	if (txr->hn_txdesc == NULL)
387215516c77SSepherosa Ziehau 		return;
387315516c77SSepherosa Ziehau 
387425641fc7SSepherosa Ziehau 	/*
387525641fc7SSepherosa Ziehau 	 * NOTE:
387625641fc7SSepherosa Ziehau 	 * Because the freeing of aggregated txds will be deferred
387725641fc7SSepherosa Ziehau 	 * to the aggregating txd, two passes are used here:
387825641fc7SSepherosa Ziehau 	 * - The first pass GCes any pending txds.  This GC is necessary,
387925641fc7SSepherosa Ziehau 	 *   since if the channels are revoked, hypervisor will not
388025641fc7SSepherosa Ziehau 	 *   deliver send-done for all pending txds.
388125641fc7SSepherosa Ziehau 	 * - The second pass frees the busdma stuffs, i.e. after all txds
388225641fc7SSepherosa Ziehau 	 *   were freed.
388325641fc7SSepherosa Ziehau 	 */
388425641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
388525641fc7SSepherosa Ziehau 		hn_txdesc_gc(txr, &txr->hn_txdesc[i]);
388625641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
388725641fc7SSepherosa Ziehau 		hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]);
388815516c77SSepherosa Ziehau 
388915516c77SSepherosa Ziehau 	if (txr->hn_tx_data_dtag != NULL)
389015516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_data_dtag);
389115516c77SSepherosa Ziehau 	if (txr->hn_tx_rndis_dtag != NULL)
389215516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_rndis_dtag);
389315516c77SSepherosa Ziehau 
389415516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
389515516c77SSepherosa Ziehau 	buf_ring_free(txr->hn_txdesc_br, M_DEVBUF);
389615516c77SSepherosa Ziehau #endif
389715516c77SSepherosa Ziehau 
389815516c77SSepherosa Ziehau 	free(txr->hn_txdesc, M_DEVBUF);
389915516c77SSepherosa Ziehau 	txr->hn_txdesc = NULL;
390015516c77SSepherosa Ziehau 
390115516c77SSepherosa Ziehau 	if (txr->hn_mbuf_br != NULL)
390215516c77SSepherosa Ziehau 		buf_ring_free(txr->hn_mbuf_br, M_DEVBUF);
390315516c77SSepherosa Ziehau 
390415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
390515516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_txlist_spin);
390615516c77SSepherosa Ziehau #endif
390715516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_tx_lock);
390815516c77SSepherosa Ziehau }
390915516c77SSepherosa Ziehau 
391015516c77SSepherosa Ziehau static int
391115516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt)
391215516c77SSepherosa Ziehau {
391315516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
391415516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
391515516c77SSepherosa Ziehau 	int i;
391615516c77SSepherosa Ziehau 
391715516c77SSepherosa Ziehau 	/*
391815516c77SSepherosa Ziehau 	 * Create TXBUF for chimney sending.
391915516c77SSepherosa Ziehau 	 *
392015516c77SSepherosa Ziehau 	 * NOTE: It is shared by all channels.
392115516c77SSepherosa Ziehau 	 */
392215516c77SSepherosa Ziehau 	sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev),
392315516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma,
392415516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
392515516c77SSepherosa Ziehau 	if (sc->hn_chim == NULL) {
392615516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate txbuf failed\n");
392715516c77SSepherosa Ziehau 		return (ENOMEM);
392815516c77SSepherosa Ziehau 	}
392915516c77SSepherosa Ziehau 
393015516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = ring_cnt;
393115516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
393215516c77SSepherosa Ziehau 
393315516c77SSepherosa Ziehau 	sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt,
393415516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
393515516c77SSepherosa Ziehau 
393615516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(sc->hn_dev);
393715516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev));
393815516c77SSepherosa Ziehau 
393915516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.tx sysctl tree */
394015516c77SSepherosa Ziehau 	sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx",
394115516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
394215516c77SSepherosa Ziehau 
394315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
394415516c77SSepherosa Ziehau 		int error;
394515516c77SSepherosa Ziehau 
394615516c77SSepherosa Ziehau 		error = hn_tx_ring_create(sc, i);
394715516c77SSepherosa Ziehau 		if (error)
394815516c77SSepherosa Ziehau 			return error;
394915516c77SSepherosa Ziehau 	}
395015516c77SSepherosa Ziehau 
395115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs",
395215516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
395315516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_no_txdescs),
395415516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs");
395515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed",
395615516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
395715516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_send_failed),
395815516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure");
395915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed",
396015516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
396115516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_txdma_failed),
396215516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure");
3963dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed",
3964dc13fee6SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
3965dc13fee6SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_flush_failed),
3966dc13fee6SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU",
3967dc13fee6SSepherosa Ziehau 	    "# of packet transmission aggregation flush failure");
396815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed",
396915516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
397015516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_collapsed),
397115516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed");
397215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney",
397315516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
397415516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney),
397515516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send");
397615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried",
397715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
397815516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney_tried),
397915516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries");
398015516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt",
398115516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0,
398215516c77SSepherosa Ziehau 	    "# of total TX descs");
398315516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max",
398415516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_chim_szmax, 0,
398515516c77SSepherosa Ziehau 	    "Chimney send packet size upper boundary");
398615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size",
398715516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
398815516c77SSepherosa Ziehau 	    hn_chim_size_sysctl, "I", "Chimney send packet size limit");
398915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size",
399015516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
399115516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_direct_tx_size),
399215516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
399315516c77SSepherosa Ziehau 	    "Size of the packet for direct transmission");
399415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx",
399515516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
399615516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_sched_tx),
399715516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
399815516c77SSepherosa Ziehau 	    "Always schedule transmission "
399915516c77SSepherosa Ziehau 	    "instead of doing direct transmission");
400015516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt",
400115516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings");
400215516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse",
400315516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings");
4004dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax",
4005dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0,
4006dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation size");
4007dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax",
4008dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
4009dc13fee6SSepherosa Ziehau 	    hn_txagg_pktmax_sysctl, "I",
4010dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation packets");
4011dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align",
4012dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
4013dc13fee6SSepherosa Ziehau 	    hn_txagg_align_sysctl, "I",
4014dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation alignment");
401515516c77SSepherosa Ziehau 
401615516c77SSepherosa Ziehau 	return 0;
401715516c77SSepherosa Ziehau }
401815516c77SSepherosa Ziehau 
401915516c77SSepherosa Ziehau static void
402015516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size)
402115516c77SSepherosa Ziehau {
402215516c77SSepherosa Ziehau 	int i;
402315516c77SSepherosa Ziehau 
4024a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
402515516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_chim_size = chim_size;
402615516c77SSepherosa Ziehau }
402715516c77SSepherosa Ziehau 
402815516c77SSepherosa Ziehau static void
402915516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu)
403015516c77SSepherosa Ziehau {
403115516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
403215516c77SSepherosa Ziehau 	int tso_minlen;
403315516c77SSepherosa Ziehau 
403415516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0)
403515516c77SSepherosa Ziehau 		return;
403615516c77SSepherosa Ziehau 
403715516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_sgmin >= 2,
403815516c77SSepherosa Ziehau 	    ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin));
403915516c77SSepherosa Ziehau 	tso_minlen = sc->hn_ndis_tso_sgmin * mtu;
404015516c77SSepherosa Ziehau 
404115516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen &&
404215516c77SSepherosa Ziehau 	    sc->hn_ndis_tso_szmax <= IP_MAXPACKET,
404315516c77SSepherosa Ziehau 	    ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax));
404415516c77SSepherosa Ziehau 
404515516c77SSepherosa Ziehau 	if (tso_maxlen < tso_minlen)
404615516c77SSepherosa Ziehau 		tso_maxlen = tso_minlen;
404715516c77SSepherosa Ziehau 	else if (tso_maxlen > IP_MAXPACKET)
404815516c77SSepherosa Ziehau 		tso_maxlen = IP_MAXPACKET;
404915516c77SSepherosa Ziehau 	if (tso_maxlen > sc->hn_ndis_tso_szmax)
405015516c77SSepherosa Ziehau 		tso_maxlen = sc->hn_ndis_tso_szmax;
405115516c77SSepherosa Ziehau 	ifp->if_hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
405215516c77SSepherosa Ziehau 	if (bootverbose)
405315516c77SSepherosa Ziehau 		if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax);
405415516c77SSepherosa Ziehau }
405515516c77SSepherosa Ziehau 
405615516c77SSepherosa Ziehau static void
405715516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc)
405815516c77SSepherosa Ziehau {
405915516c77SSepherosa Ziehau 	uint64_t csum_assist;
406015516c77SSepherosa Ziehau 	int i;
406115516c77SSepherosa Ziehau 
406215516c77SSepherosa Ziehau 	hn_set_chim_size(sc, sc->hn_chim_szmax);
406315516c77SSepherosa Ziehau 	if (hn_tx_chimney_size > 0 &&
406415516c77SSepherosa Ziehau 	    hn_tx_chimney_size < sc->hn_chim_szmax)
406515516c77SSepherosa Ziehau 		hn_set_chim_size(sc, hn_tx_chimney_size);
406615516c77SSepherosa Ziehau 
406715516c77SSepherosa Ziehau 	csum_assist = 0;
406815516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_IPCS)
406915516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP;
407015516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP4CS)
407115516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_TCP;
407215516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP4CS)
407315516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_UDP;
407415516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP6CS)
407515516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_TCP;
407615516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP6CS)
407715516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_UDP;
407815516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
407915516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_csum_assist = csum_assist;
408015516c77SSepherosa Ziehau 
408115516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_HASHVAL) {
408215516c77SSepherosa Ziehau 		/*
408315516c77SSepherosa Ziehau 		 * Support HASHVAL pktinfo on TX path.
408415516c77SSepherosa Ziehau 		 */
408515516c77SSepherosa Ziehau 		if (bootverbose)
408615516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n");
408715516c77SSepherosa Ziehau 		for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
408815516c77SSepherosa Ziehau 			sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL;
408915516c77SSepherosa Ziehau 	}
409015516c77SSepherosa Ziehau }
409115516c77SSepherosa Ziehau 
409215516c77SSepherosa Ziehau static void
409315516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc)
409415516c77SSepherosa Ziehau {
409515516c77SSepherosa Ziehau 	int i;
409615516c77SSepherosa Ziehau 
409715516c77SSepherosa Ziehau 	if (sc->hn_chim != NULL) {
40982494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) {
409915516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim);
41002494d735SSepherosa Ziehau 		} else {
41012494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
41022494d735SSepherosa Ziehau 			    "chimney sending buffer is referenced");
41032494d735SSepherosa Ziehau 		}
410415516c77SSepherosa Ziehau 		sc->hn_chim = NULL;
410515516c77SSepherosa Ziehau 	}
410615516c77SSepherosa Ziehau 
410715516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt == 0)
410815516c77SSepherosa Ziehau 		return;
410915516c77SSepherosa Ziehau 
411015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
411115516c77SSepherosa Ziehau 		hn_tx_ring_destroy(&sc->hn_tx_ring[i]);
411215516c77SSepherosa Ziehau 
411315516c77SSepherosa Ziehau 	free(sc->hn_tx_ring, M_DEVBUF);
411415516c77SSepherosa Ziehau 	sc->hn_tx_ring = NULL;
411515516c77SSepherosa Ziehau 
411615516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = 0;
411715516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = 0;
411815516c77SSepherosa Ziehau }
411915516c77SSepherosa Ziehau 
412023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
412123bf9e15SSepherosa Ziehau 
412215516c77SSepherosa Ziehau static void
412315516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused)
412415516c77SSepherosa Ziehau {
412515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
412615516c77SSepherosa Ziehau 
412715516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
412815516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
412915516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
413015516c77SSepherosa Ziehau }
413115516c77SSepherosa Ziehau 
413223bf9e15SSepherosa Ziehau static int
413323bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len)
413423bf9e15SSepherosa Ziehau {
413523bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
413623bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
4137dc13fee6SSepherosa Ziehau 	int sched = 0;
413823bf9e15SSepherosa Ziehau 
413923bf9e15SSepherosa Ziehau 	KASSERT(hn_use_if_start,
414023bf9e15SSepherosa Ziehau 	    ("hn_start_locked is called, when if_start is disabled"));
414123bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
414223bf9e15SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
4143dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
414423bf9e15SSepherosa Ziehau 
414523bf9e15SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
4146dc13fee6SSepherosa Ziehau 		return (0);
414723bf9e15SSepherosa Ziehau 
414823bf9e15SSepherosa Ziehau 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
414923bf9e15SSepherosa Ziehau 	    IFF_DRV_RUNNING)
4150dc13fee6SSepherosa Ziehau 		return (0);
415123bf9e15SSepherosa Ziehau 
415223bf9e15SSepherosa Ziehau 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
415323bf9e15SSepherosa Ziehau 		struct hn_txdesc *txd;
415423bf9e15SSepherosa Ziehau 		struct mbuf *m_head;
415523bf9e15SSepherosa Ziehau 		int error;
415623bf9e15SSepherosa Ziehau 
415723bf9e15SSepherosa Ziehau 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
415823bf9e15SSepherosa Ziehau 		if (m_head == NULL)
415923bf9e15SSepherosa Ziehau 			break;
416023bf9e15SSepherosa Ziehau 
416123bf9e15SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
416223bf9e15SSepherosa Ziehau 			/*
416323bf9e15SSepherosa Ziehau 			 * This sending could be time consuming; let callers
416423bf9e15SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
416523bf9e15SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
416623bf9e15SSepherosa Ziehau 			 */
416723bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
4168dc13fee6SSepherosa Ziehau 			sched = 1;
4169dc13fee6SSepherosa Ziehau 			break;
417023bf9e15SSepherosa Ziehau 		}
417123bf9e15SSepherosa Ziehau 
4172edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
4173edd3f315SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
4174edd3f315SSepherosa Ziehau 			m_head = hn_tso_fixup(m_head);
4175edd3f315SSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
4176edd3f315SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
4177edd3f315SSepherosa Ziehau 				continue;
4178edd3f315SSepherosa Ziehau 			}
4179edd3f315SSepherosa Ziehau 		}
4180edd3f315SSepherosa Ziehau #endif
4181edd3f315SSepherosa Ziehau 
418223bf9e15SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
418323bf9e15SSepherosa Ziehau 		if (txd == NULL) {
418423bf9e15SSepherosa Ziehau 			txr->hn_no_txdescs++;
418523bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
418623bf9e15SSepherosa Ziehau 			atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
418723bf9e15SSepherosa Ziehau 			break;
418823bf9e15SSepherosa Ziehau 		}
418923bf9e15SSepherosa Ziehau 
4190dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
419123bf9e15SSepherosa Ziehau 		if (error) {
419223bf9e15SSepherosa Ziehau 			/* Both txd and m_head are freed */
4193dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
4194dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
419523bf9e15SSepherosa Ziehau 			continue;
419623bf9e15SSepherosa Ziehau 		}
419723bf9e15SSepherosa Ziehau 
4198dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
4199dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
4200dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
4201dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
4202dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
4203dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
4204dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
4205dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
4206dc13fee6SSepherosa Ziehau 					break;
4207dc13fee6SSepherosa Ziehau 				}
4208dc13fee6SSepherosa Ziehau 			} else {
4209dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
421023bf9e15SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
421123bf9e15SSepherosa Ziehau 				if (__predict_false(error)) {
421223bf9e15SSepherosa Ziehau 					/* txd is freed, but m_head is not */
421323bf9e15SSepherosa Ziehau 					IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
4214dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
4215dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
421623bf9e15SSepherosa Ziehau 					break;
421723bf9e15SSepherosa Ziehau 				}
421823bf9e15SSepherosa Ziehau 			}
4219dc13fee6SSepherosa Ziehau 		}
4220dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
4221dc13fee6SSepherosa Ziehau 		else {
4222dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
4223dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
4224dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
4225dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
4226dc13fee6SSepherosa Ziehau 		}
4227dc13fee6SSepherosa Ziehau #endif
4228dc13fee6SSepherosa Ziehau 	}
4229dc13fee6SSepherosa Ziehau 
4230dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
4231dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
4232dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
4233dc13fee6SSepherosa Ziehau 	return (sched);
423423bf9e15SSepherosa Ziehau }
423523bf9e15SSepherosa Ziehau 
423623bf9e15SSepherosa Ziehau static void
423723bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp)
423823bf9e15SSepherosa Ziehau {
423923bf9e15SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
424023bf9e15SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[0];
424123bf9e15SSepherosa Ziehau 
424223bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
424323bf9e15SSepherosa Ziehau 		goto do_sched;
424423bf9e15SSepherosa Ziehau 
424523bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
424623bf9e15SSepherosa Ziehau 		int sched;
424723bf9e15SSepherosa Ziehau 
424823bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
424923bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
425023bf9e15SSepherosa Ziehau 		if (!sched)
425123bf9e15SSepherosa Ziehau 			return;
425223bf9e15SSepherosa Ziehau 	}
425323bf9e15SSepherosa Ziehau do_sched:
425423bf9e15SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
425523bf9e15SSepherosa Ziehau }
425623bf9e15SSepherosa Ziehau 
425715516c77SSepherosa Ziehau static void
425815516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused)
425915516c77SSepherosa Ziehau {
426015516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
426115516c77SSepherosa Ziehau 
426215516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
426315516c77SSepherosa Ziehau 	atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE);
426415516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
426515516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
426615516c77SSepherosa Ziehau }
426715516c77SSepherosa Ziehau 
426823bf9e15SSepherosa Ziehau static void
426923bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr)
427023bf9e15SSepherosa Ziehau {
427123bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
427223bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
427323bf9e15SSepherosa Ziehau 
427423bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
427523bf9e15SSepherosa Ziehau 
427623bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
427723bf9e15SSepherosa Ziehau 		goto do_sched;
427823bf9e15SSepherosa Ziehau 
427923bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
428023bf9e15SSepherosa Ziehau 		int sched;
428123bf9e15SSepherosa Ziehau 
428223bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
428323bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
428423bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
428523bf9e15SSepherosa Ziehau 		if (sched) {
428623bf9e15SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
428723bf9e15SSepherosa Ziehau 			    &txr->hn_tx_task);
428823bf9e15SSepherosa Ziehau 		}
428923bf9e15SSepherosa Ziehau 	} else {
429023bf9e15SSepherosa Ziehau do_sched:
429123bf9e15SSepherosa Ziehau 		/*
429223bf9e15SSepherosa Ziehau 		 * Release the OACTIVE earlier, with the hope, that
429323bf9e15SSepherosa Ziehau 		 * others could catch up.  The task will clear the
429423bf9e15SSepherosa Ziehau 		 * flag again with the hn_tx_lock to avoid possible
429523bf9e15SSepherosa Ziehau 		 * races.
429623bf9e15SSepherosa Ziehau 		 */
429723bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
429823bf9e15SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
429923bf9e15SSepherosa Ziehau 	}
430023bf9e15SSepherosa Ziehau }
430123bf9e15SSepherosa Ziehau 
430223bf9e15SSepherosa Ziehau #endif	/* HN_IFSTART_SUPPORT */
430323bf9e15SSepherosa Ziehau 
430415516c77SSepherosa Ziehau static int
430515516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len)
430615516c77SSepherosa Ziehau {
430715516c77SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
430815516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
430915516c77SSepherosa Ziehau 	struct mbuf *m_head;
4310dc13fee6SSepherosa Ziehau 	int sched = 0;
431115516c77SSepherosa Ziehau 
431215516c77SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
431323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
431415516c77SSepherosa Ziehau 	KASSERT(hn_use_if_start == 0,
431515516c77SSepherosa Ziehau 	    ("hn_xmit is called, when if_start is enabled"));
431623bf9e15SSepherosa Ziehau #endif
4317dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
431815516c77SSepherosa Ziehau 
431915516c77SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
4320dc13fee6SSepherosa Ziehau 		return (0);
432115516c77SSepherosa Ziehau 
432215516c77SSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive)
4323dc13fee6SSepherosa Ziehau 		return (0);
432415516c77SSepherosa Ziehau 
432515516c77SSepherosa Ziehau 	while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) {
432615516c77SSepherosa Ziehau 		struct hn_txdesc *txd;
432715516c77SSepherosa Ziehau 		int error;
432815516c77SSepherosa Ziehau 
432915516c77SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
433015516c77SSepherosa Ziehau 			/*
433115516c77SSepherosa Ziehau 			 * This sending could be time consuming; let callers
433215516c77SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
433315516c77SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
433415516c77SSepherosa Ziehau 			 */
433515516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
4336dc13fee6SSepherosa Ziehau 			sched = 1;
4337dc13fee6SSepherosa Ziehau 			break;
433815516c77SSepherosa Ziehau 		}
433915516c77SSepherosa Ziehau 
434015516c77SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
434115516c77SSepherosa Ziehau 		if (txd == NULL) {
434215516c77SSepherosa Ziehau 			txr->hn_no_txdescs++;
434315516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
434415516c77SSepherosa Ziehau 			txr->hn_oactive = 1;
434515516c77SSepherosa Ziehau 			break;
434615516c77SSepherosa Ziehau 		}
434715516c77SSepherosa Ziehau 
4348dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
434915516c77SSepherosa Ziehau 		if (error) {
435015516c77SSepherosa Ziehau 			/* Both txd and m_head are freed; discard */
4351dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
4352dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
435315516c77SSepherosa Ziehau 			drbr_advance(ifp, txr->hn_mbuf_br);
435415516c77SSepherosa Ziehau 			continue;
435515516c77SSepherosa Ziehau 		}
435615516c77SSepherosa Ziehau 
4357dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
4358dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
4359dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
4360dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
4361dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
436215516c77SSepherosa Ziehau 				if (__predict_false(error)) {
436315516c77SSepherosa Ziehau 					txr->hn_oactive = 1;
436415516c77SSepherosa Ziehau 					break;
436515516c77SSepherosa Ziehau 				}
4366dc13fee6SSepherosa Ziehau 			} else {
4367dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
4368dc13fee6SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
4369dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
4370dc13fee6SSepherosa Ziehau 					/* txd is freed, but m_head is not */
4371dc13fee6SSepherosa Ziehau 					drbr_putback(ifp, txr->hn_mbuf_br,
4372dc13fee6SSepherosa Ziehau 					    m_head);
4373dc13fee6SSepherosa Ziehau 					txr->hn_oactive = 1;
4374dc13fee6SSepherosa Ziehau 					break;
4375dc13fee6SSepherosa Ziehau 				}
4376dc13fee6SSepherosa Ziehau 			}
4377dc13fee6SSepherosa Ziehau 		}
4378dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
4379dc13fee6SSepherosa Ziehau 		else {
4380dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
4381dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
4382dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
4383dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
4384dc13fee6SSepherosa Ziehau 		}
4385dc13fee6SSepherosa Ziehau #endif
438615516c77SSepherosa Ziehau 
438715516c77SSepherosa Ziehau 		/* Sent */
438815516c77SSepherosa Ziehau 		drbr_advance(ifp, txr->hn_mbuf_br);
438915516c77SSepherosa Ziehau 	}
4390dc13fee6SSepherosa Ziehau 
4391dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
4392dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
4393dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
4394dc13fee6SSepherosa Ziehau 	return (sched);
439515516c77SSepherosa Ziehau }
439615516c77SSepherosa Ziehau 
439715516c77SSepherosa Ziehau static int
439815516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m)
439915516c77SSepherosa Ziehau {
440015516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
440115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
440215516c77SSepherosa Ziehau 	int error, idx = 0;
440315516c77SSepherosa Ziehau 
4404edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
4405edd3f315SSepherosa Ziehau 	/*
4406edd3f315SSepherosa Ziehau 	 * Perform TSO packet header fixup now, since the TSO
4407edd3f315SSepherosa Ziehau 	 * packet header should be cache-hot.
4408edd3f315SSepherosa Ziehau 	 */
4409edd3f315SSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
4410edd3f315SSepherosa Ziehau 		m = hn_tso_fixup(m);
4411edd3f315SSepherosa Ziehau 		if (__predict_false(m == NULL)) {
4412edd3f315SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
4413edd3f315SSepherosa Ziehau 			return EIO;
4414edd3f315SSepherosa Ziehau 		}
4415edd3f315SSepherosa Ziehau 	}
4416edd3f315SSepherosa Ziehau #endif
4417edd3f315SSepherosa Ziehau 
441815516c77SSepherosa Ziehau 	/*
441915516c77SSepherosa Ziehau 	 * Select the TX ring based on flowid
442015516c77SSepherosa Ziehau 	 */
442134d68912SSepherosa Ziehau 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
442234d68912SSepherosa Ziehau #ifdef RSS
442334d68912SSepherosa Ziehau 		uint32_t bid;
442434d68912SSepherosa Ziehau 
442534d68912SSepherosa Ziehau 		if (rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m),
442634d68912SSepherosa Ziehau 		    &bid) == 0)
442734d68912SSepherosa Ziehau 			idx = bid % sc->hn_tx_ring_inuse;
442834d68912SSepherosa Ziehau 		else
442934d68912SSepherosa Ziehau #endif
4430*cc0c6ebcSSepherosa Ziehau 		{
4431*cc0c6ebcSSepherosa Ziehau #if defined(INET6) || defined(INET)
4432*cc0c6ebcSSepherosa Ziehau 			int tcpsyn = 0;
4433*cc0c6ebcSSepherosa Ziehau 
4434*cc0c6ebcSSepherosa Ziehau 			if (m->m_pkthdr.len < 128 &&
4435*cc0c6ebcSSepherosa Ziehau 			    (m->m_pkthdr.csum_flags &
4436*cc0c6ebcSSepherosa Ziehau 			     (CSUM_IP_TCP | CSUM_IP6_TCP)) &&
4437*cc0c6ebcSSepherosa Ziehau 			    (m->m_pkthdr.csum_flags & CSUM_TSO) == 0) {
4438*cc0c6ebcSSepherosa Ziehau 				m = hn_check_tcpsyn(m, &tcpsyn);
4439*cc0c6ebcSSepherosa Ziehau 				if (__predict_false(m == NULL)) {
4440*cc0c6ebcSSepherosa Ziehau 					if_inc_counter(ifp,
4441*cc0c6ebcSSepherosa Ziehau 					    IFCOUNTER_OERRORS, 1);
4442*cc0c6ebcSSepherosa Ziehau 					return (EIO);
4443*cc0c6ebcSSepherosa Ziehau 				}
4444*cc0c6ebcSSepherosa Ziehau 			}
4445*cc0c6ebcSSepherosa Ziehau #else
4446*cc0c6ebcSSepherosa Ziehau 			const int tcpsyn = 0;
4447*cc0c6ebcSSepherosa Ziehau #endif
4448*cc0c6ebcSSepherosa Ziehau 			if (tcpsyn)
4449*cc0c6ebcSSepherosa Ziehau 				idx = 0;
4450*cc0c6ebcSSepherosa Ziehau 			else
445115516c77SSepherosa Ziehau 				idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse;
445234d68912SSepherosa Ziehau 		}
4453*cc0c6ebcSSepherosa Ziehau 	}
445415516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[idx];
445515516c77SSepherosa Ziehau 
445615516c77SSepherosa Ziehau 	error = drbr_enqueue(ifp, txr->hn_mbuf_br, m);
445715516c77SSepherosa Ziehau 	if (error) {
445815516c77SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
445915516c77SSepherosa Ziehau 		return error;
446015516c77SSepherosa Ziehau 	}
446115516c77SSepherosa Ziehau 
446215516c77SSepherosa Ziehau 	if (txr->hn_oactive)
446315516c77SSepherosa Ziehau 		return 0;
446415516c77SSepherosa Ziehau 
446515516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
446615516c77SSepherosa Ziehau 		goto do_sched;
446715516c77SSepherosa Ziehau 
446815516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
446915516c77SSepherosa Ziehau 		int sched;
447015516c77SSepherosa Ziehau 
447115516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
447215516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
447315516c77SSepherosa Ziehau 		if (!sched)
447415516c77SSepherosa Ziehau 			return 0;
447515516c77SSepherosa Ziehau 	}
447615516c77SSepherosa Ziehau do_sched:
447715516c77SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
447815516c77SSepherosa Ziehau 	return 0;
447915516c77SSepherosa Ziehau }
448015516c77SSepherosa Ziehau 
448115516c77SSepherosa Ziehau static void
448215516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr)
448315516c77SSepherosa Ziehau {
448415516c77SSepherosa Ziehau 	struct mbuf *m;
448515516c77SSepherosa Ziehau 
448615516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
448715516c77SSepherosa Ziehau 	while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL)
448815516c77SSepherosa Ziehau 		m_freem(m);
448915516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
449015516c77SSepherosa Ziehau }
449115516c77SSepherosa Ziehau 
449215516c77SSepherosa Ziehau static void
449315516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp)
449415516c77SSepherosa Ziehau {
449515516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
449615516c77SSepherosa Ziehau 	int i;
449715516c77SSepherosa Ziehau 
449815516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
449915516c77SSepherosa Ziehau 		hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
450015516c77SSepherosa Ziehau 	if_qflush(ifp);
450115516c77SSepherosa Ziehau }
450215516c77SSepherosa Ziehau 
450315516c77SSepherosa Ziehau static void
450415516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr)
450515516c77SSepherosa Ziehau {
450615516c77SSepherosa Ziehau 
450715516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
450815516c77SSepherosa Ziehau 		goto do_sched;
450915516c77SSepherosa Ziehau 
451015516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
451115516c77SSepherosa Ziehau 		int sched;
451215516c77SSepherosa Ziehau 
451315516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
451415516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
451515516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
451615516c77SSepherosa Ziehau 		if (sched) {
451715516c77SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
451815516c77SSepherosa Ziehau 			    &txr->hn_tx_task);
451915516c77SSepherosa Ziehau 		}
452015516c77SSepherosa Ziehau 	} else {
452115516c77SSepherosa Ziehau do_sched:
452215516c77SSepherosa Ziehau 		/*
452315516c77SSepherosa Ziehau 		 * Release the oactive earlier, with the hope, that
452415516c77SSepherosa Ziehau 		 * others could catch up.  The task will clear the
452515516c77SSepherosa Ziehau 		 * oactive again with the hn_tx_lock to avoid possible
452615516c77SSepherosa Ziehau 		 * races.
452715516c77SSepherosa Ziehau 		 */
452815516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
452915516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
453015516c77SSepherosa Ziehau 	}
453115516c77SSepherosa Ziehau }
453215516c77SSepherosa Ziehau 
453315516c77SSepherosa Ziehau static void
453415516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused)
453515516c77SSepherosa Ziehau {
453615516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
453715516c77SSepherosa Ziehau 
453815516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
453915516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
454015516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
454115516c77SSepherosa Ziehau }
454215516c77SSepherosa Ziehau 
454315516c77SSepherosa Ziehau static void
454415516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused)
454515516c77SSepherosa Ziehau {
454615516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
454715516c77SSepherosa Ziehau 
454815516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
454915516c77SSepherosa Ziehau 	txr->hn_oactive = 0;
455015516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
455115516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
455215516c77SSepherosa Ziehau }
455315516c77SSepherosa Ziehau 
455415516c77SSepherosa Ziehau static int
455515516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan)
455615516c77SSepherosa Ziehau {
455715516c77SSepherosa Ziehau 	struct vmbus_chan_br cbr;
455815516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
455915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = NULL;
456015516c77SSepherosa Ziehau 	int idx, error;
456115516c77SSepherosa Ziehau 
456215516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
456315516c77SSepherosa Ziehau 
456415516c77SSepherosa Ziehau 	/*
456515516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
456615516c77SSepherosa Ziehau 	 */
456715516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
456815516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
456915516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
457015516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
457115516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0,
457215516c77SSepherosa Ziehau 	    ("RX ring %d already attached", idx));
457315516c77SSepherosa Ziehau 	rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED;
45743ab0fea1SDexuan Cui 	rxr->hn_chan = chan;
457515516c77SSepherosa Ziehau 
457615516c77SSepherosa Ziehau 	if (bootverbose) {
457715516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n",
457815516c77SSepherosa Ziehau 		    idx, vmbus_chan_id(chan));
457915516c77SSepherosa Ziehau 	}
458015516c77SSepherosa Ziehau 
458115516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
458215516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[idx];
458315516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0,
458415516c77SSepherosa Ziehau 		    ("TX ring %d already attached", idx));
458515516c77SSepherosa Ziehau 		txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED;
458615516c77SSepherosa Ziehau 
458715516c77SSepherosa Ziehau 		txr->hn_chan = chan;
458815516c77SSepherosa Ziehau 		if (bootverbose) {
458915516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n",
459015516c77SSepherosa Ziehau 			    idx, vmbus_chan_id(chan));
459115516c77SSepherosa Ziehau 		}
459215516c77SSepherosa Ziehau 	}
459315516c77SSepherosa Ziehau 
459415516c77SSepherosa Ziehau 	/* Bind this channel to a proper CPU. */
45950e11868dSSepherosa Ziehau 	vmbus_chan_cpu_set(chan, HN_RING_IDX2CPU(sc, idx));
459615516c77SSepherosa Ziehau 
459715516c77SSepherosa Ziehau 	/*
459815516c77SSepherosa Ziehau 	 * Open this channel
459915516c77SSepherosa Ziehau 	 */
460015516c77SSepherosa Ziehau 	cbr.cbr = rxr->hn_br;
460115516c77SSepherosa Ziehau 	cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr;
460215516c77SSepherosa Ziehau 	cbr.cbr_txsz = HN_TXBR_SIZE;
460315516c77SSepherosa Ziehau 	cbr.cbr_rxsz = HN_RXBR_SIZE;
460415516c77SSepherosa Ziehau 	error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr);
460515516c77SSepherosa Ziehau 	if (error) {
460671e8ac56SSepherosa Ziehau 		if (error == EISCONN) {
460771e8ac56SSepherosa Ziehau 			if_printf(sc->hn_ifp, "bufring is connected after "
460871e8ac56SSepherosa Ziehau 			    "chan%u open failure\n", vmbus_chan_id(chan));
460971e8ac56SSepherosa Ziehau 			rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
461071e8ac56SSepherosa Ziehau 		} else {
461115516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "open chan%u failed: %d\n",
461215516c77SSepherosa Ziehau 			    vmbus_chan_id(chan), error);
461371e8ac56SSepherosa Ziehau 		}
461415516c77SSepherosa Ziehau 	}
461515516c77SSepherosa Ziehau 	return (error);
461615516c77SSepherosa Ziehau }
461715516c77SSepherosa Ziehau 
461815516c77SSepherosa Ziehau static void
461915516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan)
462015516c77SSepherosa Ziehau {
462115516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
46222494d735SSepherosa Ziehau 	int idx, error;
462315516c77SSepherosa Ziehau 
462415516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
462515516c77SSepherosa Ziehau 
462615516c77SSepherosa Ziehau 	/*
462715516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
462815516c77SSepherosa Ziehau 	 */
462915516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
463015516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
463115516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
463215516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
463315516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED),
463415516c77SSepherosa Ziehau 	    ("RX ring %d is not attached", idx));
463515516c77SSepherosa Ziehau 	rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
463615516c77SSepherosa Ziehau 
463715516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
463815516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[idx];
463915516c77SSepherosa Ziehau 
464015516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED),
464115516c77SSepherosa Ziehau 		    ("TX ring %d is not attached attached", idx));
464215516c77SSepherosa Ziehau 		txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
464315516c77SSepherosa Ziehau 	}
464415516c77SSepherosa Ziehau 
464515516c77SSepherosa Ziehau 	/*
464615516c77SSepherosa Ziehau 	 * Close this channel.
464715516c77SSepherosa Ziehau 	 *
464815516c77SSepherosa Ziehau 	 * NOTE:
464915516c77SSepherosa Ziehau 	 * Channel closing does _not_ destroy the target channel.
465015516c77SSepherosa Ziehau 	 */
46512494d735SSepherosa Ziehau 	error = vmbus_chan_close_direct(chan);
46522494d735SSepherosa Ziehau 	if (error == EISCONN) {
4653aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u bufring is connected "
4654aa1a2adcSSepherosa Ziehau 		    "after being closed\n", vmbus_chan_id(chan));
46552494d735SSepherosa Ziehau 		rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
46562494d735SSepherosa Ziehau 	} else if (error) {
4657aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u close failed: %d\n",
4658aa1a2adcSSepherosa Ziehau 		    vmbus_chan_id(chan), error);
46592494d735SSepherosa Ziehau 	}
466015516c77SSepherosa Ziehau }
466115516c77SSepherosa Ziehau 
466215516c77SSepherosa Ziehau static int
466315516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc)
466415516c77SSepherosa Ziehau {
466515516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
466615516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
466715516c77SSepherosa Ziehau 	int i, error = 0;
466815516c77SSepherosa Ziehau 
466971e8ac56SSepherosa Ziehau 	KASSERT(subchan_cnt > 0, ("no sub-channels"));
467015516c77SSepherosa Ziehau 
467115516c77SSepherosa Ziehau 	/* Attach the sub-channels. */
467215516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
467315516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i) {
467471e8ac56SSepherosa Ziehau 		int error1;
467571e8ac56SSepherosa Ziehau 
467671e8ac56SSepherosa Ziehau 		error1 = hn_chan_attach(sc, subchans[i]);
467771e8ac56SSepherosa Ziehau 		if (error1) {
467871e8ac56SSepherosa Ziehau 			error = error1;
467971e8ac56SSepherosa Ziehau 			/* Move on; all channels will be detached later. */
468071e8ac56SSepherosa Ziehau 		}
468115516c77SSepherosa Ziehau 	}
468215516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
468315516c77SSepherosa Ziehau 
468415516c77SSepherosa Ziehau 	if (error) {
468515516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error);
468615516c77SSepherosa Ziehau 	} else {
468715516c77SSepherosa Ziehau 		if (bootverbose) {
468815516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "%d sub-channels attached\n",
468915516c77SSepherosa Ziehau 			    subchan_cnt);
469015516c77SSepherosa Ziehau 		}
469115516c77SSepherosa Ziehau 	}
469215516c77SSepherosa Ziehau 	return (error);
469315516c77SSepherosa Ziehau }
469415516c77SSepherosa Ziehau 
469515516c77SSepherosa Ziehau static void
469615516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc)
469715516c77SSepherosa Ziehau {
469815516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
469915516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
470015516c77SSepherosa Ziehau 	int i;
470115516c77SSepherosa Ziehau 
470215516c77SSepherosa Ziehau 	if (subchan_cnt == 0)
470315516c77SSepherosa Ziehau 		goto back;
470415516c77SSepherosa Ziehau 
470515516c77SSepherosa Ziehau 	/* Detach the sub-channels. */
470615516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
470715516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i)
470815516c77SSepherosa Ziehau 		hn_chan_detach(sc, subchans[i]);
470915516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
471015516c77SSepherosa Ziehau 
471115516c77SSepherosa Ziehau back:
471215516c77SSepherosa Ziehau 	/*
471315516c77SSepherosa Ziehau 	 * Detach the primary channel, _after_ all sub-channels
471415516c77SSepherosa Ziehau 	 * are detached.
471515516c77SSepherosa Ziehau 	 */
471615516c77SSepherosa Ziehau 	hn_chan_detach(sc, sc->hn_prichan);
471715516c77SSepherosa Ziehau 
471815516c77SSepherosa Ziehau 	/* Wait for sub-channels to be destroyed, if any. */
471915516c77SSepherosa Ziehau 	vmbus_subchan_drain(sc->hn_prichan);
472015516c77SSepherosa Ziehau 
472115516c77SSepherosa Ziehau #ifdef INVARIANTS
472215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
472315516c77SSepherosa Ziehau 		KASSERT((sc->hn_rx_ring[i].hn_rx_flags &
472415516c77SSepherosa Ziehau 		    HN_RX_FLAG_ATTACHED) == 0,
472515516c77SSepherosa Ziehau 		    ("%dth RX ring is still attached", i));
472615516c77SSepherosa Ziehau 	}
472715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
472815516c77SSepherosa Ziehau 		KASSERT((sc->hn_tx_ring[i].hn_tx_flags &
472915516c77SSepherosa Ziehau 		    HN_TX_FLAG_ATTACHED) == 0,
473015516c77SSepherosa Ziehau 		    ("%dth TX ring is still attached", i));
473115516c77SSepherosa Ziehau 	}
473215516c77SSepherosa Ziehau #endif
473315516c77SSepherosa Ziehau }
473415516c77SSepherosa Ziehau 
473515516c77SSepherosa Ziehau static int
473615516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch)
473715516c77SSepherosa Ziehau {
473815516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
473915516c77SSepherosa Ziehau 	int nchan, rxr_cnt, error;
474015516c77SSepherosa Ziehau 
474115516c77SSepherosa Ziehau 	nchan = *nsubch + 1;
474215516c77SSepherosa Ziehau 	if (nchan == 1) {
474315516c77SSepherosa Ziehau 		/*
474415516c77SSepherosa Ziehau 		 * Multiple RX/TX rings are not requested.
474515516c77SSepherosa Ziehau 		 */
474615516c77SSepherosa Ziehau 		*nsubch = 0;
474715516c77SSepherosa Ziehau 		return (0);
474815516c77SSepherosa Ziehau 	}
474915516c77SSepherosa Ziehau 
475015516c77SSepherosa Ziehau 	/*
475115516c77SSepherosa Ziehau 	 * Query RSS capabilities, e.g. # of RX rings, and # of indirect
475215516c77SSepherosa Ziehau 	 * table entries.
475315516c77SSepherosa Ziehau 	 */
475415516c77SSepherosa Ziehau 	error = hn_rndis_query_rsscaps(sc, &rxr_cnt);
475515516c77SSepherosa Ziehau 	if (error) {
475615516c77SSepherosa Ziehau 		/* No RSS; this is benign. */
475715516c77SSepherosa Ziehau 		*nsubch = 0;
475815516c77SSepherosa Ziehau 		return (0);
475915516c77SSepherosa Ziehau 	}
476015516c77SSepherosa Ziehau 	if (bootverbose) {
476115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
476215516c77SSepherosa Ziehau 		    rxr_cnt, nchan);
476315516c77SSepherosa Ziehau 	}
476415516c77SSepherosa Ziehau 
476515516c77SSepherosa Ziehau 	if (nchan > rxr_cnt)
476615516c77SSepherosa Ziehau 		nchan = rxr_cnt;
476715516c77SSepherosa Ziehau 	if (nchan == 1) {
476815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n");
476915516c77SSepherosa Ziehau 		*nsubch = 0;
477015516c77SSepherosa Ziehau 		return (0);
477115516c77SSepherosa Ziehau 	}
477215516c77SSepherosa Ziehau 
477315516c77SSepherosa Ziehau 	/*
477415516c77SSepherosa Ziehau 	 * Allocate sub-channels from NVS.
477515516c77SSepherosa Ziehau 	 */
477615516c77SSepherosa Ziehau 	*nsubch = nchan - 1;
477715516c77SSepherosa Ziehau 	error = hn_nvs_alloc_subchans(sc, nsubch);
477815516c77SSepherosa Ziehau 	if (error || *nsubch == 0) {
477915516c77SSepherosa Ziehau 		/* Failed to allocate sub-channels. */
478015516c77SSepherosa Ziehau 		*nsubch = 0;
478115516c77SSepherosa Ziehau 		return (0);
478215516c77SSepherosa Ziehau 	}
478315516c77SSepherosa Ziehau 
478415516c77SSepherosa Ziehau 	/*
478515516c77SSepherosa Ziehau 	 * Wait for all sub-channels to become ready before moving on.
478615516c77SSepherosa Ziehau 	 */
478715516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch);
478815516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, *nsubch);
478915516c77SSepherosa Ziehau 	return (0);
479015516c77SSepherosa Ziehau }
479115516c77SSepherosa Ziehau 
47922494d735SSepherosa Ziehau static bool
47932494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc)
47942494d735SSepherosa Ziehau {
47952494d735SSepherosa Ziehau 	int i;
47962494d735SSepherosa Ziehau 
47972494d735SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_ERRORS)
47982494d735SSepherosa Ziehau 		return (false);
47992494d735SSepherosa Ziehau 
48002494d735SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
48012494d735SSepherosa Ziehau 		const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
48022494d735SSepherosa Ziehau 
48032494d735SSepherosa Ziehau 		if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF)
48042494d735SSepherosa Ziehau 			return (false);
48052494d735SSepherosa Ziehau 	}
48062494d735SSepherosa Ziehau 	return (true);
48072494d735SSepherosa Ziehau }
48082494d735SSepherosa Ziehau 
4809b3b75d9cSSepherosa Ziehau /*
4810b3b75d9cSSepherosa Ziehau  * Make sure that the RX filter is zero after the successful
4811b3b75d9cSSepherosa Ziehau  * RNDIS initialization.
4812b3b75d9cSSepherosa Ziehau  *
4813b3b75d9cSSepherosa Ziehau  * NOTE:
4814b3b75d9cSSepherosa Ziehau  * Under certain conditions on certain versions of Hyper-V,
4815b3b75d9cSSepherosa Ziehau  * the RNDIS rxfilter is _not_ zero on the hypervisor side
4816b3b75d9cSSepherosa Ziehau  * after the successful RNDIS initialization, which breaks
4817b3b75d9cSSepherosa Ziehau  * the assumption of any following code (well, it breaks the
4818b3b75d9cSSepherosa Ziehau  * RNDIS API contract actually).  Clear the RNDIS rxfilter
4819b3b75d9cSSepherosa Ziehau  * explicitly, drain packets sneaking through, and drain the
4820b3b75d9cSSepherosa Ziehau  * interrupt taskqueues scheduled due to the stealth packets.
4821b3b75d9cSSepherosa Ziehau  */
4822b3b75d9cSSepherosa Ziehau static void
4823b3b75d9cSSepherosa Ziehau hn_rndis_init_fixat(struct hn_softc *sc, int nchan)
4824b3b75d9cSSepherosa Ziehau {
4825b3b75d9cSSepherosa Ziehau 
4826b3b75d9cSSepherosa Ziehau 	hn_disable_rx(sc);
4827b3b75d9cSSepherosa Ziehau 	hn_drain_rxtx(sc, nchan);
4828b3b75d9cSSepherosa Ziehau }
4829b3b75d9cSSepherosa Ziehau 
483015516c77SSepherosa Ziehau static int
483115516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu)
483215516c77SSepherosa Ziehau {
483371e8ac56SSepherosa Ziehau #define ATTACHED_NVS		0x0002
483471e8ac56SSepherosa Ziehau #define ATTACHED_RNDIS		0x0004
483571e8ac56SSepherosa Ziehau 
483615516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
4837b3b75d9cSSepherosa Ziehau 	int error, nsubch, nchan = 1, i, rndis_inited;
483871e8ac56SSepherosa Ziehau 	uint32_t old_caps, attached = 0;
483915516c77SSepherosa Ziehau 
484015516c77SSepherosa Ziehau 	KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0,
484115516c77SSepherosa Ziehau 	    ("synthetic parts were attached"));
484215516c77SSepherosa Ziehau 
48432494d735SSepherosa Ziehau 	if (!hn_synth_attachable(sc))
48442494d735SSepherosa Ziehau 		return (ENXIO);
48452494d735SSepherosa Ziehau 
484615516c77SSepherosa Ziehau 	/* Save capabilities for later verification. */
484715516c77SSepherosa Ziehau 	old_caps = sc->hn_caps;
484815516c77SSepherosa Ziehau 	sc->hn_caps = 0;
484915516c77SSepherosa Ziehau 
485015516c77SSepherosa Ziehau 	/* Clear RSS stuffs. */
485115516c77SSepherosa Ziehau 	sc->hn_rss_ind_size = 0;
485215516c77SSepherosa Ziehau 	sc->hn_rss_hash = 0;
485315516c77SSepherosa Ziehau 
485415516c77SSepherosa Ziehau 	/*
485515516c77SSepherosa Ziehau 	 * Attach the primary channel _before_ attaching NVS and RNDIS.
485615516c77SSepherosa Ziehau 	 */
485715516c77SSepherosa Ziehau 	error = hn_chan_attach(sc, sc->hn_prichan);
485815516c77SSepherosa Ziehau 	if (error)
485971e8ac56SSepherosa Ziehau 		goto failed;
486015516c77SSepherosa Ziehau 
486115516c77SSepherosa Ziehau 	/*
486215516c77SSepherosa Ziehau 	 * Attach NVS.
486315516c77SSepherosa Ziehau 	 */
486415516c77SSepherosa Ziehau 	error = hn_nvs_attach(sc, mtu);
486515516c77SSepherosa Ziehau 	if (error)
486671e8ac56SSepherosa Ziehau 		goto failed;
486771e8ac56SSepherosa Ziehau 	attached |= ATTACHED_NVS;
486815516c77SSepherosa Ziehau 
486915516c77SSepherosa Ziehau 	/*
487015516c77SSepherosa Ziehau 	 * Attach RNDIS _after_ NVS is attached.
487115516c77SSepherosa Ziehau 	 */
4872b3b75d9cSSepherosa Ziehau 	error = hn_rndis_attach(sc, mtu, &rndis_inited);
4873b3b75d9cSSepherosa Ziehau 	if (rndis_inited)
4874b3b75d9cSSepherosa Ziehau 		attached |= ATTACHED_RNDIS;
487515516c77SSepherosa Ziehau 	if (error)
487671e8ac56SSepherosa Ziehau 		goto failed;
487715516c77SSepherosa Ziehau 
487815516c77SSepherosa Ziehau 	/*
487915516c77SSepherosa Ziehau 	 * Make sure capabilities are not changed.
488015516c77SSepherosa Ziehau 	 */
488115516c77SSepherosa Ziehau 	if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) {
488215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n",
488315516c77SSepherosa Ziehau 		    old_caps, sc->hn_caps);
488471e8ac56SSepherosa Ziehau 		error = ENXIO;
488571e8ac56SSepherosa Ziehau 		goto failed;
488615516c77SSepherosa Ziehau 	}
488715516c77SSepherosa Ziehau 
488815516c77SSepherosa Ziehau 	/*
488915516c77SSepherosa Ziehau 	 * Allocate sub-channels for multi-TX/RX rings.
489015516c77SSepherosa Ziehau 	 *
489115516c77SSepherosa Ziehau 	 * NOTE:
489215516c77SSepherosa Ziehau 	 * The # of RX rings that can be used is equivalent to the # of
489315516c77SSepherosa Ziehau 	 * channels to be requested.
489415516c77SSepherosa Ziehau 	 */
489515516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_cnt - 1;
489615516c77SSepherosa Ziehau 	error = hn_synth_alloc_subchans(sc, &nsubch);
489715516c77SSepherosa Ziehau 	if (error)
489871e8ac56SSepherosa Ziehau 		goto failed;
489971e8ac56SSepherosa Ziehau 	/* NOTE: _Full_ synthetic parts detach is required now. */
490071e8ac56SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED;
490115516c77SSepherosa Ziehau 
490271e8ac56SSepherosa Ziehau 	/*
490371e8ac56SSepherosa Ziehau 	 * Set the # of TX/RX rings that could be used according to
490471e8ac56SSepherosa Ziehau 	 * the # of channels that NVS offered.
490571e8ac56SSepherosa Ziehau 	 */
490615516c77SSepherosa Ziehau 	nchan = nsubch + 1;
490771e8ac56SSepherosa Ziehau 	hn_set_ring_inuse(sc, nchan);
490815516c77SSepherosa Ziehau 	if (nchan == 1) {
490915516c77SSepherosa Ziehau 		/* Only the primary channel can be used; done */
491015516c77SSepherosa Ziehau 		goto back;
491115516c77SSepherosa Ziehau 	}
491215516c77SSepherosa Ziehau 
491315516c77SSepherosa Ziehau 	/*
491471e8ac56SSepherosa Ziehau 	 * Attach the sub-channels.
4915afd4971bSSepherosa Ziehau 	 *
4916afd4971bSSepherosa Ziehau 	 * NOTE: hn_set_ring_inuse() _must_ have been called.
491715516c77SSepherosa Ziehau 	 */
491871e8ac56SSepherosa Ziehau 	error = hn_attach_subchans(sc);
491971e8ac56SSepherosa Ziehau 	if (error)
492071e8ac56SSepherosa Ziehau 		goto failed;
492115516c77SSepherosa Ziehau 
492271e8ac56SSepherosa Ziehau 	/*
492371e8ac56SSepherosa Ziehau 	 * Configure RSS key and indirect table _after_ all sub-channels
492471e8ac56SSepherosa Ziehau 	 * are attached.
492571e8ac56SSepherosa Ziehau 	 */
492615516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) {
492715516c77SSepherosa Ziehau 		/*
492815516c77SSepherosa Ziehau 		 * RSS key is not set yet; set it to the default RSS key.
492915516c77SSepherosa Ziehau 		 */
493015516c77SSepherosa Ziehau 		if (bootverbose)
493115516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS key\n");
493234d68912SSepherosa Ziehau #ifdef RSS
493334d68912SSepherosa Ziehau 		rss_getkey(rss->rss_key);
493434d68912SSepherosa Ziehau #else
493515516c77SSepherosa Ziehau 		memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key));
493634d68912SSepherosa Ziehau #endif
493715516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
493815516c77SSepherosa Ziehau 	}
493915516c77SSepherosa Ziehau 
494015516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) {
494115516c77SSepherosa Ziehau 		/*
494215516c77SSepherosa Ziehau 		 * RSS indirect table is not set yet; set it up in round-
494315516c77SSepherosa Ziehau 		 * robin fashion.
494415516c77SSepherosa Ziehau 		 */
494515516c77SSepherosa Ziehau 		if (bootverbose) {
494615516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS indirect "
494715516c77SSepherosa Ziehau 			    "table\n");
494815516c77SSepherosa Ziehau 		}
494934d68912SSepherosa Ziehau 		for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
495034d68912SSepherosa Ziehau 			uint32_t subidx;
495134d68912SSepherosa Ziehau 
495234d68912SSepherosa Ziehau #ifdef RSS
495334d68912SSepherosa Ziehau 			subidx = rss_get_indirection_to_bucket(i);
495434d68912SSepherosa Ziehau #else
495534d68912SSepherosa Ziehau 			subidx = i;
495634d68912SSepherosa Ziehau #endif
495734d68912SSepherosa Ziehau 			rss->rss_ind[i] = subidx % nchan;
495834d68912SSepherosa Ziehau 		}
495915516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSIND;
496015516c77SSepherosa Ziehau 	} else {
496115516c77SSepherosa Ziehau 		/*
496215516c77SSepherosa Ziehau 		 * # of usable channels may be changed, so we have to
496315516c77SSepherosa Ziehau 		 * make sure that all entries in RSS indirect table
496415516c77SSepherosa Ziehau 		 * are valid.
4965afd4971bSSepherosa Ziehau 		 *
4966afd4971bSSepherosa Ziehau 		 * NOTE: hn_set_ring_inuse() _must_ have been called.
496715516c77SSepherosa Ziehau 		 */
4968afd4971bSSepherosa Ziehau 		hn_rss_ind_fixup(sc);
496915516c77SSepherosa Ziehau 	}
497015516c77SSepherosa Ziehau 
497115516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
497215516c77SSepherosa Ziehau 	if (error)
497371e8ac56SSepherosa Ziehau 		goto failed;
497471e8ac56SSepherosa Ziehau back:
4975dc13fee6SSepherosa Ziehau 	/*
4976dc13fee6SSepherosa Ziehau 	 * Fixup transmission aggregation setup.
4977dc13fee6SSepherosa Ziehau 	 */
4978dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
4979b3b75d9cSSepherosa Ziehau 	hn_rndis_init_fixat(sc, nchan);
498015516c77SSepherosa Ziehau 	return (0);
498171e8ac56SSepherosa Ziehau 
498271e8ac56SSepherosa Ziehau failed:
498371e8ac56SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
4984b3b75d9cSSepherosa Ziehau 		hn_rndis_init_fixat(sc, nchan);
498571e8ac56SSepherosa Ziehau 		hn_synth_detach(sc);
498671e8ac56SSepherosa Ziehau 	} else {
4987b3b75d9cSSepherosa Ziehau 		if (attached & ATTACHED_RNDIS) {
4988b3b75d9cSSepherosa Ziehau 			hn_rndis_init_fixat(sc, nchan);
498971e8ac56SSepherosa Ziehau 			hn_rndis_detach(sc);
4990b3b75d9cSSepherosa Ziehau 		}
499171e8ac56SSepherosa Ziehau 		if (attached & ATTACHED_NVS)
499271e8ac56SSepherosa Ziehau 			hn_nvs_detach(sc);
499371e8ac56SSepherosa Ziehau 		hn_chan_detach(sc, sc->hn_prichan);
499471e8ac56SSepherosa Ziehau 		/* Restore old capabilities. */
499571e8ac56SSepherosa Ziehau 		sc->hn_caps = old_caps;
499671e8ac56SSepherosa Ziehau 	}
499771e8ac56SSepherosa Ziehau 	return (error);
499871e8ac56SSepherosa Ziehau 
499971e8ac56SSepherosa Ziehau #undef ATTACHED_RNDIS
500071e8ac56SSepherosa Ziehau #undef ATTACHED_NVS
500115516c77SSepherosa Ziehau }
500215516c77SSepherosa Ziehau 
500315516c77SSepherosa Ziehau /*
500415516c77SSepherosa Ziehau  * NOTE:
500515516c77SSepherosa Ziehau  * The interface must have been suspended though hn_suspend(), before
500615516c77SSepherosa Ziehau  * this function get called.
500715516c77SSepherosa Ziehau  */
500815516c77SSepherosa Ziehau static void
500915516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc)
501015516c77SSepherosa Ziehau {
501115516c77SSepherosa Ziehau 
501215516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
501315516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
501415516c77SSepherosa Ziehau 
501515516c77SSepherosa Ziehau 	/* Detach the RNDIS first. */
501615516c77SSepherosa Ziehau 	hn_rndis_detach(sc);
501715516c77SSepherosa Ziehau 
501815516c77SSepherosa Ziehau 	/* Detach NVS. */
501915516c77SSepherosa Ziehau 	hn_nvs_detach(sc);
502015516c77SSepherosa Ziehau 
502115516c77SSepherosa Ziehau 	/* Detach all of the channels. */
502215516c77SSepherosa Ziehau 	hn_detach_allchans(sc);
502315516c77SSepherosa Ziehau 
502415516c77SSepherosa Ziehau 	sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED;
502515516c77SSepherosa Ziehau }
502615516c77SSepherosa Ziehau 
502715516c77SSepherosa Ziehau static void
502815516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt)
502915516c77SSepherosa Ziehau {
503015516c77SSepherosa Ziehau 	KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt,
503115516c77SSepherosa Ziehau 	    ("invalid ring count %d", ring_cnt));
503215516c77SSepherosa Ziehau 
503315516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt > ring_cnt)
503415516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = ring_cnt;
503515516c77SSepherosa Ziehau 	else
503615516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
503715516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = ring_cnt;
503815516c77SSepherosa Ziehau 
503934d68912SSepherosa Ziehau #ifdef RSS
504034d68912SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse != rss_getnumbuckets()) {
504134d68912SSepherosa Ziehau 		if_printf(sc->hn_ifp, "# of RX rings (%d) does not match "
504234d68912SSepherosa Ziehau 		    "# of RSS buckets (%d)\n", sc->hn_rx_ring_inuse,
504334d68912SSepherosa Ziehau 		    rss_getnumbuckets());
504434d68912SSepherosa Ziehau 	}
504534d68912SSepherosa Ziehau #endif
504634d68912SSepherosa Ziehau 
504715516c77SSepherosa Ziehau 	if (bootverbose) {
504815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n",
504915516c77SSepherosa Ziehau 		    sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
505015516c77SSepherosa Ziehau 	}
505115516c77SSepherosa Ziehau }
505215516c77SSepherosa Ziehau 
505315516c77SSepherosa Ziehau static void
505425641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan)
505515516c77SSepherosa Ziehau {
505615516c77SSepherosa Ziehau 
505725641fc7SSepherosa Ziehau 	/*
505825641fc7SSepherosa Ziehau 	 * NOTE:
505925641fc7SSepherosa Ziehau 	 * The TX bufring will not be drained by the hypervisor,
506025641fc7SSepherosa Ziehau 	 * if the primary channel is revoked.
506125641fc7SSepherosa Ziehau 	 */
506225641fc7SSepherosa Ziehau 	while (!vmbus_chan_rx_empty(chan) ||
506325641fc7SSepherosa Ziehau 	    (!vmbus_chan_is_revoked(sc->hn_prichan) &&
506425641fc7SSepherosa Ziehau 	     !vmbus_chan_tx_empty(chan)))
506515516c77SSepherosa Ziehau 		pause("waitch", 1);
506615516c77SSepherosa Ziehau 	vmbus_chan_intr_drain(chan);
506715516c77SSepherosa Ziehau }
506815516c77SSepherosa Ziehau 
506915516c77SSepherosa Ziehau static void
5070b3b75d9cSSepherosa Ziehau hn_disable_rx(struct hn_softc *sc)
5071b3b75d9cSSepherosa Ziehau {
5072b3b75d9cSSepherosa Ziehau 
5073b3b75d9cSSepherosa Ziehau 	/*
5074b3b75d9cSSepherosa Ziehau 	 * Disable RX by clearing RX filter forcefully.
5075b3b75d9cSSepherosa Ziehau 	 */
5076b3b75d9cSSepherosa Ziehau 	sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE;
5077b3b75d9cSSepherosa Ziehau 	hn_rndis_set_rxfilter(sc, sc->hn_rx_filter); /* ignore error */
5078b3b75d9cSSepherosa Ziehau 
5079b3b75d9cSSepherosa Ziehau 	/*
5080b3b75d9cSSepherosa Ziehau 	 * Give RNDIS enough time to flush all pending data packets.
5081b3b75d9cSSepherosa Ziehau 	 */
5082b3b75d9cSSepherosa Ziehau 	pause("waitrx", (200 * hz) / 1000);
5083b3b75d9cSSepherosa Ziehau }
5084b3b75d9cSSepherosa Ziehau 
5085b3b75d9cSSepherosa Ziehau /*
5086b3b75d9cSSepherosa Ziehau  * NOTE:
5087b3b75d9cSSepherosa Ziehau  * RX/TX _must_ have been suspended/disabled, before this function
5088b3b75d9cSSepherosa Ziehau  * is called.
5089b3b75d9cSSepherosa Ziehau  */
5090b3b75d9cSSepherosa Ziehau static void
5091b3b75d9cSSepherosa Ziehau hn_drain_rxtx(struct hn_softc *sc, int nchan)
509215516c77SSepherosa Ziehau {
509315516c77SSepherosa Ziehau 	struct vmbus_channel **subch = NULL;
5094b3b75d9cSSepherosa Ziehau 	int nsubch;
5095b3b75d9cSSepherosa Ziehau 
5096b3b75d9cSSepherosa Ziehau 	/*
5097b3b75d9cSSepherosa Ziehau 	 * Drain RX/TX bufrings and interrupts.
5098b3b75d9cSSepherosa Ziehau 	 */
5099b3b75d9cSSepherosa Ziehau 	nsubch = nchan - 1;
5100b3b75d9cSSepherosa Ziehau 	if (nsubch > 0)
5101b3b75d9cSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
5102b3b75d9cSSepherosa Ziehau 
5103b3b75d9cSSepherosa Ziehau 	if (subch != NULL) {
5104b3b75d9cSSepherosa Ziehau 		int i;
5105b3b75d9cSSepherosa Ziehau 
5106b3b75d9cSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
5107b3b75d9cSSepherosa Ziehau 			hn_chan_drain(sc, subch[i]);
5108b3b75d9cSSepherosa Ziehau 	}
5109b3b75d9cSSepherosa Ziehau 	hn_chan_drain(sc, sc->hn_prichan);
5110b3b75d9cSSepherosa Ziehau 
5111b3b75d9cSSepherosa Ziehau 	if (subch != NULL)
5112b3b75d9cSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
5113b3b75d9cSSepherosa Ziehau }
5114b3b75d9cSSepherosa Ziehau 
5115b3b75d9cSSepherosa Ziehau static void
5116b3b75d9cSSepherosa Ziehau hn_suspend_data(struct hn_softc *sc)
5117b3b75d9cSSepherosa Ziehau {
511825641fc7SSepherosa Ziehau 	struct hn_tx_ring *txr;
5119b3b75d9cSSepherosa Ziehau 	int i;
512015516c77SSepherosa Ziehau 
512115516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
512215516c77SSepherosa Ziehau 
512315516c77SSepherosa Ziehau 	/*
512415516c77SSepherosa Ziehau 	 * Suspend TX.
512515516c77SSepherosa Ziehau 	 */
512615516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
512725641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
512815516c77SSepherosa Ziehau 
512915516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
513015516c77SSepherosa Ziehau 		txr->hn_suspended = 1;
513115516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
513215516c77SSepherosa Ziehau 		/* No one is able send more packets now. */
513315516c77SSepherosa Ziehau 
513425641fc7SSepherosa Ziehau 		/*
513525641fc7SSepherosa Ziehau 		 * Wait for all pending sends to finish.
513625641fc7SSepherosa Ziehau 		 *
513725641fc7SSepherosa Ziehau 		 * NOTE:
513825641fc7SSepherosa Ziehau 		 * We will _not_ receive all pending send-done, if the
513925641fc7SSepherosa Ziehau 		 * primary channel is revoked.
514025641fc7SSepherosa Ziehau 		 */
514125641fc7SSepherosa Ziehau 		while (hn_tx_ring_pending(txr) &&
514225641fc7SSepherosa Ziehau 		    !vmbus_chan_is_revoked(sc->hn_prichan))
514315516c77SSepherosa Ziehau 			pause("hnwtx", 1 /* 1 tick */);
514415516c77SSepherosa Ziehau 	}
514515516c77SSepherosa Ziehau 
514615516c77SSepherosa Ziehau 	/*
5147b3b75d9cSSepherosa Ziehau 	 * Disable RX.
514815516c77SSepherosa Ziehau 	 */
5149b3b75d9cSSepherosa Ziehau 	hn_disable_rx(sc);
515015516c77SSepherosa Ziehau 
515115516c77SSepherosa Ziehau 	/*
5152b3b75d9cSSepherosa Ziehau 	 * Drain RX/TX.
515315516c77SSepherosa Ziehau 	 */
5154b3b75d9cSSepherosa Ziehau 	hn_drain_rxtx(sc, sc->hn_rx_ring_inuse);
515525641fc7SSepherosa Ziehau 
515625641fc7SSepherosa Ziehau 	/*
515725641fc7SSepherosa Ziehau 	 * Drain any pending TX tasks.
515825641fc7SSepherosa Ziehau 	 *
515925641fc7SSepherosa Ziehau 	 * NOTE:
5160b3b75d9cSSepherosa Ziehau 	 * The above hn_drain_rxtx() can dispatch TX tasks, so the TX
5161b3b75d9cSSepherosa Ziehau 	 * tasks will have to be drained _after_ the above hn_drain_rxtx().
516225641fc7SSepherosa Ziehau 	 */
516325641fc7SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
516425641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
516525641fc7SSepherosa Ziehau 
516625641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task);
516725641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task);
516825641fc7SSepherosa Ziehau 	}
516915516c77SSepherosa Ziehau }
517015516c77SSepherosa Ziehau 
517115516c77SSepherosa Ziehau static void
517215516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused)
517315516c77SSepherosa Ziehau {
517415516c77SSepherosa Ziehau 
517515516c77SSepherosa Ziehau 	((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL;
517615516c77SSepherosa Ziehau }
517715516c77SSepherosa Ziehau 
517815516c77SSepherosa Ziehau static void
517915516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc)
518015516c77SSepherosa Ziehau {
518115516c77SSepherosa Ziehau 	struct task task;
518215516c77SSepherosa Ziehau 
518315516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
518415516c77SSepherosa Ziehau 
518515516c77SSepherosa Ziehau 	/*
518615516c77SSepherosa Ziehau 	 * Make sure that hn_mgmt_taskq0 can nolonger be accessed
518715516c77SSepherosa Ziehau 	 * through hn_mgmt_taskq.
518815516c77SSepherosa Ziehau 	 */
518915516c77SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc);
519015516c77SSepherosa Ziehau 	vmbus_chan_run_task(sc->hn_prichan, &task);
519115516c77SSepherosa Ziehau 
519215516c77SSepherosa Ziehau 	/*
519315516c77SSepherosa Ziehau 	 * Make sure that all pending management tasks are completed.
519415516c77SSepherosa Ziehau 	 */
519515516c77SSepherosa Ziehau 	taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init);
519615516c77SSepherosa Ziehau 	taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status);
519715516c77SSepherosa Ziehau 	taskqueue_drain_all(sc->hn_mgmt_taskq0);
519815516c77SSepherosa Ziehau }
519915516c77SSepherosa Ziehau 
520015516c77SSepherosa Ziehau static void
520115516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc)
520215516c77SSepherosa Ziehau {
520315516c77SSepherosa Ziehau 
520487f8129dSSepherosa Ziehau 	/* Disable polling. */
520587f8129dSSepherosa Ziehau 	hn_polling(sc, 0);
520687f8129dSSepherosa Ziehau 
52075bdfd3fdSDexuan Cui 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
52085bdfd3fdSDexuan Cui 	    (sc->hn_flags & HN_FLAG_VF))
520915516c77SSepherosa Ziehau 		hn_suspend_data(sc);
521015516c77SSepherosa Ziehau 	hn_suspend_mgmt(sc);
521115516c77SSepherosa Ziehau }
521215516c77SSepherosa Ziehau 
521315516c77SSepherosa Ziehau static void
521415516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt)
521515516c77SSepherosa Ziehau {
521615516c77SSepherosa Ziehau 	int i;
521715516c77SSepherosa Ziehau 
521815516c77SSepherosa Ziehau 	KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt,
521915516c77SSepherosa Ziehau 	    ("invalid TX ring count %d", tx_ring_cnt));
522015516c77SSepherosa Ziehau 
522115516c77SSepherosa Ziehau 	for (i = 0; i < tx_ring_cnt; ++i) {
522215516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
522315516c77SSepherosa Ziehau 
522415516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
522515516c77SSepherosa Ziehau 		txr->hn_suspended = 0;
522615516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
522715516c77SSepherosa Ziehau 	}
522815516c77SSepherosa Ziehau }
522915516c77SSepherosa Ziehau 
523015516c77SSepherosa Ziehau static void
523115516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc)
523215516c77SSepherosa Ziehau {
523315516c77SSepherosa Ziehau 	int i;
523415516c77SSepherosa Ziehau 
523515516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
523615516c77SSepherosa Ziehau 
523715516c77SSepherosa Ziehau 	/*
523815516c77SSepherosa Ziehau 	 * Re-enable RX.
523915516c77SSepherosa Ziehau 	 */
5240c08f7b2cSSepherosa Ziehau 	hn_rxfilter_config(sc);
524115516c77SSepherosa Ziehau 
524215516c77SSepherosa Ziehau 	/*
524315516c77SSepherosa Ziehau 	 * Make sure to clear suspend status on "all" TX rings,
524415516c77SSepherosa Ziehau 	 * since hn_tx_ring_inuse can be changed after
524515516c77SSepherosa Ziehau 	 * hn_suspend_data().
524615516c77SSepherosa Ziehau 	 */
524715516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_cnt);
524815516c77SSepherosa Ziehau 
524923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
525023bf9e15SSepherosa Ziehau 	if (!hn_use_if_start)
525123bf9e15SSepherosa Ziehau #endif
525223bf9e15SSepherosa Ziehau 	{
525315516c77SSepherosa Ziehau 		/*
525415516c77SSepherosa Ziehau 		 * Flush unused drbrs, since hn_tx_ring_inuse may be
525515516c77SSepherosa Ziehau 		 * reduced.
525615516c77SSepherosa Ziehau 		 */
525715516c77SSepherosa Ziehau 		for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i)
525815516c77SSepherosa Ziehau 			hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
525915516c77SSepherosa Ziehau 	}
526015516c77SSepherosa Ziehau 
526115516c77SSepherosa Ziehau 	/*
526215516c77SSepherosa Ziehau 	 * Kick start TX.
526315516c77SSepherosa Ziehau 	 */
526415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
526515516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
526615516c77SSepherosa Ziehau 
526715516c77SSepherosa Ziehau 		/*
526815516c77SSepherosa Ziehau 		 * Use txeof task, so that any pending oactive can be
526915516c77SSepherosa Ziehau 		 * cleared properly.
527015516c77SSepherosa Ziehau 		 */
527115516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
527215516c77SSepherosa Ziehau 	}
527315516c77SSepherosa Ziehau }
527415516c77SSepherosa Ziehau 
527515516c77SSepherosa Ziehau static void
527615516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc)
527715516c77SSepherosa Ziehau {
527815516c77SSepherosa Ziehau 
527915516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
528015516c77SSepherosa Ziehau 
528115516c77SSepherosa Ziehau 	/*
528215516c77SSepherosa Ziehau 	 * Kick off network change detection, if it was pending.
528315516c77SSepherosa Ziehau 	 * If no network change was pending, start link status
528415516c77SSepherosa Ziehau 	 * checks, which is more lightweight than network change
528515516c77SSepherosa Ziehau 	 * detection.
528615516c77SSepherosa Ziehau 	 */
528715516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
528815516c77SSepherosa Ziehau 		hn_change_network(sc);
528915516c77SSepherosa Ziehau 	else
529015516c77SSepherosa Ziehau 		hn_update_link_status(sc);
529115516c77SSepherosa Ziehau }
529215516c77SSepherosa Ziehau 
529315516c77SSepherosa Ziehau static void
529415516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc)
529515516c77SSepherosa Ziehau {
529615516c77SSepherosa Ziehau 
52975bdfd3fdSDexuan Cui 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) ||
52985bdfd3fdSDexuan Cui 	    (sc->hn_flags & HN_FLAG_VF))
529915516c77SSepherosa Ziehau 		hn_resume_data(sc);
53005bdfd3fdSDexuan Cui 
53015bdfd3fdSDexuan Cui 	/*
53025bdfd3fdSDexuan Cui 	 * When the VF is activated, the synthetic interface is changed
53035bdfd3fdSDexuan Cui 	 * to DOWN in hn_set_vf(). Here, if the VF is still active, we
53045bdfd3fdSDexuan Cui 	 * don't call hn_resume_mgmt() until the VF is deactivated in
53055bdfd3fdSDexuan Cui 	 * hn_set_vf().
53065bdfd3fdSDexuan Cui 	 */
53075bdfd3fdSDexuan Cui 	if (!(sc->hn_flags & HN_FLAG_VF))
530815516c77SSepherosa Ziehau 		hn_resume_mgmt(sc);
530987f8129dSSepherosa Ziehau 
531087f8129dSSepherosa Ziehau 	/*
531187f8129dSSepherosa Ziehau 	 * Re-enable polling if this interface is running and
531287f8129dSSepherosa Ziehau 	 * the polling is requested.
531387f8129dSSepherosa Ziehau 	 */
531487f8129dSSepherosa Ziehau 	if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->hn_pollhz > 0)
531587f8129dSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
531615516c77SSepherosa Ziehau }
531715516c77SSepherosa Ziehau 
531815516c77SSepherosa Ziehau static void
531915516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen)
532015516c77SSepherosa Ziehau {
532115516c77SSepherosa Ziehau 	const struct rndis_status_msg *msg;
532215516c77SSepherosa Ziehau 	int ofs;
532315516c77SSepherosa Ziehau 
532415516c77SSepherosa Ziehau 	if (dlen < sizeof(*msg)) {
532515516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid RNDIS status\n");
532615516c77SSepherosa Ziehau 		return;
532715516c77SSepherosa Ziehau 	}
532815516c77SSepherosa Ziehau 	msg = data;
532915516c77SSepherosa Ziehau 
533015516c77SSepherosa Ziehau 	switch (msg->rm_status) {
533115516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_CONNECT:
533215516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_DISCONNECT:
533315516c77SSepherosa Ziehau 		hn_update_link_status(sc);
533415516c77SSepherosa Ziehau 		break;
533515516c77SSepherosa Ziehau 
533615516c77SSepherosa Ziehau 	case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
533715516c77SSepherosa Ziehau 		/* Not really useful; ignore. */
533815516c77SSepherosa Ziehau 		break;
533915516c77SSepherosa Ziehau 
534015516c77SSepherosa Ziehau 	case RNDIS_STATUS_NETWORK_CHANGE:
534115516c77SSepherosa Ziehau 		ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
534215516c77SSepherosa Ziehau 		if (dlen < ofs + msg->rm_stbuflen ||
534315516c77SSepherosa Ziehau 		    msg->rm_stbuflen < sizeof(uint32_t)) {
534415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed\n");
534515516c77SSepherosa Ziehau 		} else {
534615516c77SSepherosa Ziehau 			uint32_t change;
534715516c77SSepherosa Ziehau 
534815516c77SSepherosa Ziehau 			memcpy(&change, ((const uint8_t *)msg) + ofs,
534915516c77SSepherosa Ziehau 			    sizeof(change));
535015516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed, change %u\n",
535115516c77SSepherosa Ziehau 			    change);
535215516c77SSepherosa Ziehau 		}
535315516c77SSepherosa Ziehau 		hn_change_network(sc);
535415516c77SSepherosa Ziehau 		break;
535515516c77SSepherosa Ziehau 
535615516c77SSepherosa Ziehau 	default:
535715516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
535815516c77SSepherosa Ziehau 		    msg->rm_status);
535915516c77SSepherosa Ziehau 		break;
536015516c77SSepherosa Ziehau 	}
536115516c77SSepherosa Ziehau }
536215516c77SSepherosa Ziehau 
536315516c77SSepherosa Ziehau static int
536415516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info)
536515516c77SSepherosa Ziehau {
536615516c77SSepherosa Ziehau 	const struct rndis_pktinfo *pi = info_data;
536715516c77SSepherosa Ziehau 	uint32_t mask = 0;
536815516c77SSepherosa Ziehau 
536915516c77SSepherosa Ziehau 	while (info_dlen != 0) {
537015516c77SSepherosa Ziehau 		const void *data;
537115516c77SSepherosa Ziehau 		uint32_t dlen;
537215516c77SSepherosa Ziehau 
537315516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < sizeof(*pi)))
537415516c77SSepherosa Ziehau 			return (EINVAL);
537515516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < pi->rm_size))
537615516c77SSepherosa Ziehau 			return (EINVAL);
537715516c77SSepherosa Ziehau 		info_dlen -= pi->rm_size;
537815516c77SSepherosa Ziehau 
537915516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
538015516c77SSepherosa Ziehau 			return (EINVAL);
538115516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
538215516c77SSepherosa Ziehau 			return (EINVAL);
538315516c77SSepherosa Ziehau 		dlen = pi->rm_size - pi->rm_pktinfooffset;
538415516c77SSepherosa Ziehau 		data = pi->rm_data;
538515516c77SSepherosa Ziehau 
538615516c77SSepherosa Ziehau 		switch (pi->rm_type) {
538715516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_VLAN:
538815516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
538915516c77SSepherosa Ziehau 				return (EINVAL);
539015516c77SSepherosa Ziehau 			info->vlan_info = *((const uint32_t *)data);
539115516c77SSepherosa Ziehau 			mask |= HN_RXINFO_VLAN;
539215516c77SSepherosa Ziehau 			break;
539315516c77SSepherosa Ziehau 
539415516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_CSUM:
539515516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
539615516c77SSepherosa Ziehau 				return (EINVAL);
539715516c77SSepherosa Ziehau 			info->csum_info = *((const uint32_t *)data);
539815516c77SSepherosa Ziehau 			mask |= HN_RXINFO_CSUM;
539915516c77SSepherosa Ziehau 			break;
540015516c77SSepherosa Ziehau 
540115516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHVAL:
540215516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
540315516c77SSepherosa Ziehau 				return (EINVAL);
540415516c77SSepherosa Ziehau 			info->hash_value = *((const uint32_t *)data);
540515516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHVAL;
540615516c77SSepherosa Ziehau 			break;
540715516c77SSepherosa Ziehau 
540815516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHINF:
540915516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
541015516c77SSepherosa Ziehau 				return (EINVAL);
541115516c77SSepherosa Ziehau 			info->hash_info = *((const uint32_t *)data);
541215516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHINF;
541315516c77SSepherosa Ziehau 			break;
541415516c77SSepherosa Ziehau 
541515516c77SSepherosa Ziehau 		default:
541615516c77SSepherosa Ziehau 			goto next;
541715516c77SSepherosa Ziehau 		}
541815516c77SSepherosa Ziehau 
541915516c77SSepherosa Ziehau 		if (mask == HN_RXINFO_ALL) {
542015516c77SSepherosa Ziehau 			/* All found; done */
542115516c77SSepherosa Ziehau 			break;
542215516c77SSepherosa Ziehau 		}
542315516c77SSepherosa Ziehau next:
542415516c77SSepherosa Ziehau 		pi = (const struct rndis_pktinfo *)
542515516c77SSepherosa Ziehau 		    ((const uint8_t *)pi + pi->rm_size);
542615516c77SSepherosa Ziehau 	}
542715516c77SSepherosa Ziehau 
542815516c77SSepherosa Ziehau 	/*
542915516c77SSepherosa Ziehau 	 * Final fixup.
543015516c77SSepherosa Ziehau 	 * - If there is no hash value, invalidate the hash info.
543115516c77SSepherosa Ziehau 	 */
543215516c77SSepherosa Ziehau 	if ((mask & HN_RXINFO_HASHVAL) == 0)
543315516c77SSepherosa Ziehau 		info->hash_info = HN_NDIS_HASH_INFO_INVALID;
543415516c77SSepherosa Ziehau 	return (0);
543515516c77SSepherosa Ziehau }
543615516c77SSepherosa Ziehau 
543715516c77SSepherosa Ziehau static __inline bool
543815516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
543915516c77SSepherosa Ziehau {
544015516c77SSepherosa Ziehau 
544115516c77SSepherosa Ziehau 	if (off < check_off) {
544215516c77SSepherosa Ziehau 		if (__predict_true(off + len <= check_off))
544315516c77SSepherosa Ziehau 			return (false);
544415516c77SSepherosa Ziehau 	} else if (off > check_off) {
544515516c77SSepherosa Ziehau 		if (__predict_true(check_off + check_len <= off))
544615516c77SSepherosa Ziehau 			return (false);
544715516c77SSepherosa Ziehau 	}
544815516c77SSepherosa Ziehau 	return (true);
544915516c77SSepherosa Ziehau }
545015516c77SSepherosa Ziehau 
545115516c77SSepherosa Ziehau static void
545215516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen)
545315516c77SSepherosa Ziehau {
545415516c77SSepherosa Ziehau 	const struct rndis_packet_msg *pkt;
545515516c77SSepherosa Ziehau 	struct hn_rxinfo info;
545615516c77SSepherosa Ziehau 	int data_off, pktinfo_off, data_len, pktinfo_len;
545715516c77SSepherosa Ziehau 
545815516c77SSepherosa Ziehau 	/*
545915516c77SSepherosa Ziehau 	 * Check length.
546015516c77SSepherosa Ziehau 	 */
546115516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*pkt))) {
546215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
546315516c77SSepherosa Ziehau 		return;
546415516c77SSepherosa Ziehau 	}
546515516c77SSepherosa Ziehau 	pkt = data;
546615516c77SSepherosa Ziehau 
546715516c77SSepherosa Ziehau 	if (__predict_false(dlen < pkt->rm_len)) {
546815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
546915516c77SSepherosa Ziehau 		    "dlen %d, msglen %u\n", dlen, pkt->rm_len);
547015516c77SSepherosa Ziehau 		return;
547115516c77SSepherosa Ziehau 	}
547215516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_len <
547315516c77SSepherosa Ziehau 	    pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
547415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
547515516c77SSepherosa Ziehau 		    "msglen %u, data %u, oob %u, pktinfo %u\n",
547615516c77SSepherosa Ziehau 		    pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
547715516c77SSepherosa Ziehau 		    pkt->rm_pktinfolen);
547815516c77SSepherosa Ziehau 		return;
547915516c77SSepherosa Ziehau 	}
548015516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_datalen == 0)) {
548115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
548215516c77SSepherosa Ziehau 		return;
548315516c77SSepherosa Ziehau 	}
548415516c77SSepherosa Ziehau 
548515516c77SSepherosa Ziehau 	/*
548615516c77SSepherosa Ziehau 	 * Check offests.
548715516c77SSepherosa Ziehau 	 */
548815516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs)			\
548915516c77SSepherosa Ziehau 	((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN ||	\
549015516c77SSepherosa Ziehau 	 ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
549115516c77SSepherosa Ziehau 
549215516c77SSepherosa Ziehau 	/* XXX Hyper-V does not meet data offset alignment requirement */
549315516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
549415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
549515516c77SSepherosa Ziehau 		    "data offset %u\n", pkt->rm_dataoffset);
549615516c77SSepherosa Ziehau 		return;
549715516c77SSepherosa Ziehau 	}
549815516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdataoffset > 0 &&
549915516c77SSepherosa Ziehau 	    IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
550015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
550115516c77SSepherosa Ziehau 		    "oob offset %u\n", pkt->rm_oobdataoffset);
550215516c77SSepherosa Ziehau 		return;
550315516c77SSepherosa Ziehau 	}
550415516c77SSepherosa Ziehau 	if (__predict_true(pkt->rm_pktinfooffset > 0) &&
550515516c77SSepherosa Ziehau 	    __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
550615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
550715516c77SSepherosa Ziehau 		    "pktinfo offset %u\n", pkt->rm_pktinfooffset);
550815516c77SSepherosa Ziehau 		return;
550915516c77SSepherosa Ziehau 	}
551015516c77SSepherosa Ziehau 
551115516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID
551215516c77SSepherosa Ziehau 
551315516c77SSepherosa Ziehau 	data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
551415516c77SSepherosa Ziehau 	data_len = pkt->rm_datalen;
551515516c77SSepherosa Ziehau 	pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
551615516c77SSepherosa Ziehau 	pktinfo_len = pkt->rm_pktinfolen;
551715516c77SSepherosa Ziehau 
551815516c77SSepherosa Ziehau 	/*
551915516c77SSepherosa Ziehau 	 * Check OOB coverage.
552015516c77SSepherosa Ziehau 	 */
552115516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdatalen != 0)) {
552215516c77SSepherosa Ziehau 		int oob_off, oob_len;
552315516c77SSepherosa Ziehau 
552415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "got oobdata\n");
552515516c77SSepherosa Ziehau 		oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
552615516c77SSepherosa Ziehau 		oob_len = pkt->rm_oobdatalen;
552715516c77SSepherosa Ziehau 
552815516c77SSepherosa Ziehau 		if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
552915516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
553015516c77SSepherosa Ziehau 			    "oob overflow, msglen %u, oob abs %d len %d\n",
553115516c77SSepherosa Ziehau 			    pkt->rm_len, oob_off, oob_len);
553215516c77SSepherosa Ziehau 			return;
553315516c77SSepherosa Ziehau 		}
553415516c77SSepherosa Ziehau 
553515516c77SSepherosa Ziehau 		/*
553615516c77SSepherosa Ziehau 		 * Check against data.
553715516c77SSepherosa Ziehau 		 */
553815516c77SSepherosa Ziehau 		if (hn_rndis_check_overlap(oob_off, oob_len,
553915516c77SSepherosa Ziehau 		    data_off, data_len)) {
554015516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
554115516c77SSepherosa Ziehau 			    "oob overlaps data, oob abs %d len %d, "
554215516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
554315516c77SSepherosa Ziehau 			    oob_off, oob_len, data_off, data_len);
554415516c77SSepherosa Ziehau 			return;
554515516c77SSepherosa Ziehau 		}
554615516c77SSepherosa Ziehau 
554715516c77SSepherosa Ziehau 		/*
554815516c77SSepherosa Ziehau 		 * Check against pktinfo.
554915516c77SSepherosa Ziehau 		 */
555015516c77SSepherosa Ziehau 		if (pktinfo_len != 0 &&
555115516c77SSepherosa Ziehau 		    hn_rndis_check_overlap(oob_off, oob_len,
555215516c77SSepherosa Ziehau 		    pktinfo_off, pktinfo_len)) {
555315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
555415516c77SSepherosa Ziehau 			    "oob overlaps pktinfo, oob abs %d len %d, "
555515516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
555615516c77SSepherosa Ziehau 			    oob_off, oob_len, pktinfo_off, pktinfo_len);
555715516c77SSepherosa Ziehau 			return;
555815516c77SSepherosa Ziehau 		}
555915516c77SSepherosa Ziehau 	}
556015516c77SSepherosa Ziehau 
556115516c77SSepherosa Ziehau 	/*
556215516c77SSepherosa Ziehau 	 * Check per-packet-info coverage and find useful per-packet-info.
556315516c77SSepherosa Ziehau 	 */
556415516c77SSepherosa Ziehau 	info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
556515516c77SSepherosa Ziehau 	info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
556615516c77SSepherosa Ziehau 	info.hash_info = HN_NDIS_HASH_INFO_INVALID;
556715516c77SSepherosa Ziehau 	if (__predict_true(pktinfo_len != 0)) {
556815516c77SSepherosa Ziehau 		bool overlap;
556915516c77SSepherosa Ziehau 		int error;
557015516c77SSepherosa Ziehau 
557115516c77SSepherosa Ziehau 		if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
557215516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
557315516c77SSepherosa Ziehau 			    "pktinfo overflow, msglen %u, "
557415516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
557515516c77SSepherosa Ziehau 			    pkt->rm_len, pktinfo_off, pktinfo_len);
557615516c77SSepherosa Ziehau 			return;
557715516c77SSepherosa Ziehau 		}
557815516c77SSepherosa Ziehau 
557915516c77SSepherosa Ziehau 		/*
558015516c77SSepherosa Ziehau 		 * Check packet info coverage.
558115516c77SSepherosa Ziehau 		 */
558215516c77SSepherosa Ziehau 		overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
558315516c77SSepherosa Ziehau 		    data_off, data_len);
558415516c77SSepherosa Ziehau 		if (__predict_false(overlap)) {
558515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
558615516c77SSepherosa Ziehau 			    "pktinfo overlap data, pktinfo abs %d len %d, "
558715516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
558815516c77SSepherosa Ziehau 			    pktinfo_off, pktinfo_len, data_off, data_len);
558915516c77SSepherosa Ziehau 			return;
559015516c77SSepherosa Ziehau 		}
559115516c77SSepherosa Ziehau 
559215516c77SSepherosa Ziehau 		/*
559315516c77SSepherosa Ziehau 		 * Find useful per-packet-info.
559415516c77SSepherosa Ziehau 		 */
559515516c77SSepherosa Ziehau 		error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
559615516c77SSepherosa Ziehau 		    pktinfo_len, &info);
559715516c77SSepherosa Ziehau 		if (__predict_false(error)) {
559815516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
559915516c77SSepherosa Ziehau 			    "pktinfo\n");
560015516c77SSepherosa Ziehau 			return;
560115516c77SSepherosa Ziehau 		}
560215516c77SSepherosa Ziehau 	}
560315516c77SSepherosa Ziehau 
560415516c77SSepherosa Ziehau 	if (__predict_false(data_off + data_len > pkt->rm_len)) {
560515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
560615516c77SSepherosa Ziehau 		    "data overflow, msglen %u, data abs %d len %d\n",
560715516c77SSepherosa Ziehau 		    pkt->rm_len, data_off, data_len);
560815516c77SSepherosa Ziehau 		return;
560915516c77SSepherosa Ziehau 	}
561015516c77SSepherosa Ziehau 	hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
561115516c77SSepherosa Ziehau }
561215516c77SSepherosa Ziehau 
561315516c77SSepherosa Ziehau static __inline void
561415516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen)
561515516c77SSepherosa Ziehau {
561615516c77SSepherosa Ziehau 	const struct rndis_msghdr *hdr;
561715516c77SSepherosa Ziehau 
561815516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*hdr))) {
561915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
562015516c77SSepherosa Ziehau 		return;
562115516c77SSepherosa Ziehau 	}
562215516c77SSepherosa Ziehau 	hdr = data;
562315516c77SSepherosa Ziehau 
562415516c77SSepherosa Ziehau 	if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) {
562515516c77SSepherosa Ziehau 		/* Hot data path. */
562615516c77SSepherosa Ziehau 		hn_rndis_rx_data(rxr, data, dlen);
562715516c77SSepherosa Ziehau 		/* Done! */
562815516c77SSepherosa Ziehau 		return;
562915516c77SSepherosa Ziehau 	}
563015516c77SSepherosa Ziehau 
563115516c77SSepherosa Ziehau 	if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG)
563215516c77SSepherosa Ziehau 		hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen);
563315516c77SSepherosa Ziehau 	else
563415516c77SSepherosa Ziehau 		hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen);
563515516c77SSepherosa Ziehau }
563615516c77SSepherosa Ziehau 
563715516c77SSepherosa Ziehau static void
563815516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
563915516c77SSepherosa Ziehau {
564015516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *hdr;
564115516c77SSepherosa Ziehau 
564215516c77SSepherosa Ziehau 	if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) {
564315516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid nvs notify\n");
564415516c77SSepherosa Ziehau 		return;
564515516c77SSepherosa Ziehau 	}
564615516c77SSepherosa Ziehau 	hdr = VMBUS_CHANPKT_CONST_DATA(pkt);
564715516c77SSepherosa Ziehau 
564815516c77SSepherosa Ziehau 	if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) {
564915516c77SSepherosa Ziehau 		/* Useless; ignore */
565015516c77SSepherosa Ziehau 		return;
565115516c77SSepherosa Ziehau 	}
565215516c77SSepherosa Ziehau 	if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type);
565315516c77SSepherosa Ziehau }
565415516c77SSepherosa Ziehau 
565515516c77SSepherosa Ziehau static void
565615516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan,
565715516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkt)
565815516c77SSepherosa Ziehau {
565915516c77SSepherosa Ziehau 	struct hn_nvs_sendctx *sndc;
566015516c77SSepherosa Ziehau 
566115516c77SSepherosa Ziehau 	sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid;
566215516c77SSepherosa Ziehau 	sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt),
566315516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_DATALEN(pkt));
566415516c77SSepherosa Ziehau 	/*
566515516c77SSepherosa Ziehau 	 * NOTE:
566615516c77SSepherosa Ziehau 	 * 'sndc' CAN NOT be accessed anymore, since it can be freed by
566715516c77SSepherosa Ziehau 	 * its callback.
566815516c77SSepherosa Ziehau 	 */
566915516c77SSepherosa Ziehau }
567015516c77SSepherosa Ziehau 
567115516c77SSepherosa Ziehau static void
567215516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
567315516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkthdr)
567415516c77SSepherosa Ziehau {
567515516c77SSepherosa Ziehau 	const struct vmbus_chanpkt_rxbuf *pkt;
567615516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *nvs_hdr;
567715516c77SSepherosa Ziehau 	int count, i, hlen;
567815516c77SSepherosa Ziehau 
567915516c77SSepherosa Ziehau 	if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) {
568015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n");
568115516c77SSepherosa Ziehau 		return;
568215516c77SSepherosa Ziehau 	}
568315516c77SSepherosa Ziehau 	nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr);
568415516c77SSepherosa Ziehau 
568515516c77SSepherosa Ziehau 	/* Make sure that this is a RNDIS message. */
568615516c77SSepherosa Ziehau 	if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) {
568715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n",
568815516c77SSepherosa Ziehau 		    nvs_hdr->nvs_type);
568915516c77SSepherosa Ziehau 		return;
569015516c77SSepherosa Ziehau 	}
569115516c77SSepherosa Ziehau 
569215516c77SSepherosa Ziehau 	hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen);
569315516c77SSepherosa Ziehau 	if (__predict_false(hlen < sizeof(*pkt))) {
569415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n");
569515516c77SSepherosa Ziehau 		return;
569615516c77SSepherosa Ziehau 	}
569715516c77SSepherosa Ziehau 	pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
569815516c77SSepherosa Ziehau 
569915516c77SSepherosa Ziehau 	if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) {
570015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n",
570115516c77SSepherosa Ziehau 		    pkt->cp_rxbuf_id);
570215516c77SSepherosa Ziehau 		return;
570315516c77SSepherosa Ziehau 	}
570415516c77SSepherosa Ziehau 
570515516c77SSepherosa Ziehau 	count = pkt->cp_rxbuf_cnt;
570615516c77SSepherosa Ziehau 	if (__predict_false(hlen <
570715516c77SSepherosa Ziehau 	    __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) {
570815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count);
570915516c77SSepherosa Ziehau 		return;
571015516c77SSepherosa Ziehau 	}
571115516c77SSepherosa Ziehau 
571215516c77SSepherosa Ziehau 	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
571315516c77SSepherosa Ziehau 	for (i = 0; i < count; ++i) {
571415516c77SSepherosa Ziehau 		int ofs, len;
571515516c77SSepherosa Ziehau 
571615516c77SSepherosa Ziehau 		ofs = pkt->cp_rxbuf[i].rb_ofs;
571715516c77SSepherosa Ziehau 		len = pkt->cp_rxbuf[i].rb_len;
571815516c77SSepherosa Ziehau 		if (__predict_false(ofs + len > HN_RXBUF_SIZE)) {
571915516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, "
572015516c77SSepherosa Ziehau 			    "ofs %d, len %d\n", i, ofs, len);
572115516c77SSepherosa Ziehau 			continue;
572215516c77SSepherosa Ziehau 		}
572315516c77SSepherosa Ziehau 		hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len);
572415516c77SSepherosa Ziehau 	}
572515516c77SSepherosa Ziehau 
572615516c77SSepherosa Ziehau 	/*
572715516c77SSepherosa Ziehau 	 * Ack the consumed RXBUF associated w/ this channel packet,
572815516c77SSepherosa Ziehau 	 * so that this RXBUF can be recycled by the hypervisor.
572915516c77SSepherosa Ziehau 	 */
573015516c77SSepherosa Ziehau 	hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid);
573115516c77SSepherosa Ziehau }
573215516c77SSepherosa Ziehau 
573315516c77SSepherosa Ziehau static void
573415516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
573515516c77SSepherosa Ziehau     uint64_t tid)
573615516c77SSepherosa Ziehau {
573715516c77SSepherosa Ziehau 	struct hn_nvs_rndis_ack ack;
573815516c77SSepherosa Ziehau 	int retries, error;
573915516c77SSepherosa Ziehau 
574015516c77SSepherosa Ziehau 	ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK;
574115516c77SSepherosa Ziehau 	ack.nvs_status = HN_NVS_STATUS_OK;
574215516c77SSepherosa Ziehau 
574315516c77SSepherosa Ziehau 	retries = 0;
574415516c77SSepherosa Ziehau again:
574515516c77SSepherosa Ziehau 	error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP,
574615516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid);
574715516c77SSepherosa Ziehau 	if (__predict_false(error == EAGAIN)) {
574815516c77SSepherosa Ziehau 		/*
574915516c77SSepherosa Ziehau 		 * NOTE:
575015516c77SSepherosa Ziehau 		 * This should _not_ happen in real world, since the
575115516c77SSepherosa Ziehau 		 * consumption of the TX bufring from the TX path is
575215516c77SSepherosa Ziehau 		 * controlled.
575315516c77SSepherosa Ziehau 		 */
575415516c77SSepherosa Ziehau 		if (rxr->hn_ack_failed == 0)
575515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "RXBUF ack retry\n");
575615516c77SSepherosa Ziehau 		rxr->hn_ack_failed++;
575715516c77SSepherosa Ziehau 		retries++;
575815516c77SSepherosa Ziehau 		if (retries < 10) {
575915516c77SSepherosa Ziehau 			DELAY(100);
576015516c77SSepherosa Ziehau 			goto again;
576115516c77SSepherosa Ziehau 		}
576215516c77SSepherosa Ziehau 		/* RXBUF leaks! */
576315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "RXBUF ack failed\n");
576415516c77SSepherosa Ziehau 	}
576515516c77SSepherosa Ziehau }
576615516c77SSepherosa Ziehau 
576715516c77SSepherosa Ziehau static void
576815516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr)
576915516c77SSepherosa Ziehau {
577015516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr = xrxr;
577115516c77SSepherosa Ziehau 	struct hn_softc *sc = rxr->hn_ifp->if_softc;
577215516c77SSepherosa Ziehau 
577315516c77SSepherosa Ziehau 	for (;;) {
577415516c77SSepherosa Ziehau 		struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf;
577515516c77SSepherosa Ziehau 		int error, pktlen;
577615516c77SSepherosa Ziehau 
577715516c77SSepherosa Ziehau 		pktlen = rxr->hn_pktbuf_len;
577815516c77SSepherosa Ziehau 		error = vmbus_chan_recv_pkt(chan, pkt, &pktlen);
577915516c77SSepherosa Ziehau 		if (__predict_false(error == ENOBUFS)) {
578015516c77SSepherosa Ziehau 			void *nbuf;
578115516c77SSepherosa Ziehau 			int nlen;
578215516c77SSepherosa Ziehau 
578315516c77SSepherosa Ziehau 			/*
578415516c77SSepherosa Ziehau 			 * Expand channel packet buffer.
578515516c77SSepherosa Ziehau 			 *
578615516c77SSepherosa Ziehau 			 * XXX
578715516c77SSepherosa Ziehau 			 * Use M_WAITOK here, since allocation failure
578815516c77SSepherosa Ziehau 			 * is fatal.
578915516c77SSepherosa Ziehau 			 */
579015516c77SSepherosa Ziehau 			nlen = rxr->hn_pktbuf_len * 2;
579115516c77SSepherosa Ziehau 			while (nlen < pktlen)
579215516c77SSepherosa Ziehau 				nlen *= 2;
579315516c77SSepherosa Ziehau 			nbuf = malloc(nlen, M_DEVBUF, M_WAITOK);
579415516c77SSepherosa Ziehau 
579515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n",
579615516c77SSepherosa Ziehau 			    rxr->hn_pktbuf_len, nlen);
579715516c77SSepherosa Ziehau 
579815516c77SSepherosa Ziehau 			free(rxr->hn_pktbuf, M_DEVBUF);
579915516c77SSepherosa Ziehau 			rxr->hn_pktbuf = nbuf;
580015516c77SSepherosa Ziehau 			rxr->hn_pktbuf_len = nlen;
580115516c77SSepherosa Ziehau 			/* Retry! */
580215516c77SSepherosa Ziehau 			continue;
580315516c77SSepherosa Ziehau 		} else if (__predict_false(error == EAGAIN)) {
580415516c77SSepherosa Ziehau 			/* No more channel packets; done! */
580515516c77SSepherosa Ziehau 			break;
580615516c77SSepherosa Ziehau 		}
580715516c77SSepherosa Ziehau 		KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error));
580815516c77SSepherosa Ziehau 
580915516c77SSepherosa Ziehau 		switch (pkt->cph_type) {
581015516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_COMP:
581115516c77SSepherosa Ziehau 			hn_nvs_handle_comp(sc, chan, pkt);
581215516c77SSepherosa Ziehau 			break;
581315516c77SSepherosa Ziehau 
581415516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_RXBUF:
581515516c77SSepherosa Ziehau 			hn_nvs_handle_rxbuf(rxr, chan, pkt);
581615516c77SSepherosa Ziehau 			break;
581715516c77SSepherosa Ziehau 
581815516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_INBAND:
581915516c77SSepherosa Ziehau 			hn_nvs_handle_notify(sc, pkt);
582015516c77SSepherosa Ziehau 			break;
582115516c77SSepherosa Ziehau 
582215516c77SSepherosa Ziehau 		default:
582315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "unknown chan pkt %u\n",
582415516c77SSepherosa Ziehau 			    pkt->cph_type);
582515516c77SSepherosa Ziehau 			break;
582615516c77SSepherosa Ziehau 		}
582715516c77SSepherosa Ziehau 	}
582815516c77SSepherosa Ziehau 	hn_chan_rollup(rxr, rxr->hn_txr);
582915516c77SSepherosa Ziehau }
583015516c77SSepherosa Ziehau 
583115516c77SSepherosa Ziehau static void
583215516c77SSepherosa Ziehau hn_tx_taskq_create(void *arg __unused)
583315516c77SSepherosa Ziehau {
5834fdd0222aSSepherosa Ziehau 	int i;
5835fdd0222aSSepherosa Ziehau 
5836fdd0222aSSepherosa Ziehau 	/*
5837fdd0222aSSepherosa Ziehau 	 * Fix the # of TX taskqueues.
5838fdd0222aSSepherosa Ziehau 	 */
5839fdd0222aSSepherosa Ziehau 	if (hn_tx_taskq_cnt <= 0)
5840fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = 1;
5841fdd0222aSSepherosa Ziehau 	else if (hn_tx_taskq_cnt > mp_ncpus)
5842fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = mp_ncpus;
584315516c77SSepherosa Ziehau 
58440e11868dSSepherosa Ziehau 	/*
58450e11868dSSepherosa Ziehau 	 * Fix the TX taskqueue mode.
58460e11868dSSepherosa Ziehau 	 */
58470e11868dSSepherosa Ziehau 	switch (hn_tx_taskq_mode) {
58480e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_INDEP:
58490e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_GLOBAL:
58500e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_EVTTQ:
58510e11868dSSepherosa Ziehau 		break;
58520e11868dSSepherosa Ziehau 	default:
58530e11868dSSepherosa Ziehau 		hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
58540e11868dSSepherosa Ziehau 		break;
58550e11868dSSepherosa Ziehau 	}
58560e11868dSSepherosa Ziehau 
585715516c77SSepherosa Ziehau 	if (vm_guest != VM_GUEST_HV)
585815516c77SSepherosa Ziehau 		return;
585915516c77SSepherosa Ziehau 
58600e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode != HN_TX_TASKQ_M_GLOBAL)
586115516c77SSepherosa Ziehau 		return;
586215516c77SSepherosa Ziehau 
5863fdd0222aSSepherosa Ziehau 	hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
5864fdd0222aSSepherosa Ziehau 	    M_DEVBUF, M_WAITOK);
5865fdd0222aSSepherosa Ziehau 	for (i = 0; i < hn_tx_taskq_cnt; ++i) {
5866fdd0222aSSepherosa Ziehau 		hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK,
5867fdd0222aSSepherosa Ziehau 		    taskqueue_thread_enqueue, &hn_tx_taskque[i]);
5868fdd0222aSSepherosa Ziehau 		taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET,
5869fdd0222aSSepherosa Ziehau 		    "hn tx%d", i);
5870fdd0222aSSepherosa Ziehau 	}
587115516c77SSepherosa Ziehau }
587215516c77SSepherosa Ziehau SYSINIT(hn_txtq_create, SI_SUB_DRIVERS, SI_ORDER_SECOND,
587315516c77SSepherosa Ziehau     hn_tx_taskq_create, NULL);
587415516c77SSepherosa Ziehau 
587515516c77SSepherosa Ziehau static void
587615516c77SSepherosa Ziehau hn_tx_taskq_destroy(void *arg __unused)
587715516c77SSepherosa Ziehau {
587815516c77SSepherosa Ziehau 
5879fdd0222aSSepherosa Ziehau 	if (hn_tx_taskque != NULL) {
5880fdd0222aSSepherosa Ziehau 		int i;
5881fdd0222aSSepherosa Ziehau 
5882fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
5883fdd0222aSSepherosa Ziehau 			taskqueue_free(hn_tx_taskque[i]);
5884fdd0222aSSepherosa Ziehau 		free(hn_tx_taskque, M_DEVBUF);
5885fdd0222aSSepherosa Ziehau 	}
588615516c77SSepherosa Ziehau }
588715516c77SSepherosa Ziehau SYSUNINIT(hn_txtq_destroy, SI_SUB_DRIVERS, SI_ORDER_SECOND,
588815516c77SSepherosa Ziehau     hn_tx_taskq_destroy, NULL);
5889