xref: /freebsd/sys/dev/hyperv/netvsc/if_hn.c (revision 0e11868dfaecc90b1a0c87b13f6bc62f86507662)
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 
5815516c77SSepherosa Ziehau #include "opt_inet6.h"
5915516c77SSepherosa Ziehau #include "opt_inet.h"
6015516c77SSepherosa Ziehau 
6115516c77SSepherosa Ziehau #include <sys/param.h>
6215516c77SSepherosa Ziehau #include <sys/bus.h>
6315516c77SSepherosa Ziehau #include <sys/kernel.h>
6415516c77SSepherosa Ziehau #include <sys/limits.h>
6515516c77SSepherosa Ziehau #include <sys/malloc.h>
6615516c77SSepherosa Ziehau #include <sys/mbuf.h>
6715516c77SSepherosa Ziehau #include <sys/module.h>
6815516c77SSepherosa Ziehau #include <sys/queue.h>
6915516c77SSepherosa Ziehau #include <sys/lock.h>
7015516c77SSepherosa Ziehau #include <sys/smp.h>
7115516c77SSepherosa Ziehau #include <sys/socket.h>
7215516c77SSepherosa Ziehau #include <sys/sockio.h>
7315516c77SSepherosa Ziehau #include <sys/sx.h>
7415516c77SSepherosa Ziehau #include <sys/sysctl.h>
7515516c77SSepherosa Ziehau #include <sys/systm.h>
7615516c77SSepherosa Ziehau #include <sys/taskqueue.h>
7715516c77SSepherosa Ziehau #include <sys/buf_ring.h>
7815516c77SSepherosa Ziehau 
7915516c77SSepherosa Ziehau #include <machine/atomic.h>
8015516c77SSepherosa Ziehau #include <machine/in_cksum.h>
8115516c77SSepherosa Ziehau 
8215516c77SSepherosa Ziehau #include <net/bpf.h>
8315516c77SSepherosa Ziehau #include <net/ethernet.h>
8415516c77SSepherosa Ziehau #include <net/if.h>
8515516c77SSepherosa Ziehau #include <net/if_media.h>
8615516c77SSepherosa Ziehau #include <net/if_types.h>
8715516c77SSepherosa Ziehau #include <net/if_var.h>
8815516c77SSepherosa Ziehau #include <net/rndis.h>
8915516c77SSepherosa Ziehau 
9015516c77SSepherosa Ziehau #include <netinet/in_systm.h>
9115516c77SSepherosa Ziehau #include <netinet/in.h>
9215516c77SSepherosa Ziehau #include <netinet/ip.h>
9315516c77SSepherosa Ziehau #include <netinet/ip6.h>
9415516c77SSepherosa Ziehau #include <netinet/tcp.h>
9515516c77SSepherosa Ziehau #include <netinet/tcp_lro.h>
9615516c77SSepherosa Ziehau #include <netinet/udp.h>
9715516c77SSepherosa Ziehau 
9815516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h>
9915516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv_busdma.h>
10015516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus.h>
10115516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus_xact.h>
10215516c77SSepherosa Ziehau 
10315516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/ndis.h>
10415516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnreg.h>
10515516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnvar.h>
10615516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_nvs.h>
10715516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_rndis.h>
10815516c77SSepherosa Ziehau 
10915516c77SSepherosa Ziehau #include "vmbus_if.h"
11015516c77SSepherosa Ziehau 
11123bf9e15SSepherosa Ziehau #define HN_IFSTART_SUPPORT
11223bf9e15SSepherosa Ziehau 
11315516c77SSepherosa Ziehau #define HN_RING_CNT_DEF_MAX		8
11415516c77SSepherosa Ziehau 
11515516c77SSepherosa Ziehau /* YYY should get it from the underlying channel */
11615516c77SSepherosa Ziehau #define HN_TX_DESC_CNT			512
11715516c77SSepherosa Ziehau 
11815516c77SSepherosa Ziehau #define HN_RNDIS_PKT_LEN					\
11915516c77SSepherosa Ziehau 	(sizeof(struct rndis_packet_msg) +			\
12015516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) +	\
12115516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) +		\
12215516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) +		\
12315516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_TXCSUM_INFO_SIZE))
12415516c77SSepherosa Ziehau #define HN_RNDIS_PKT_BOUNDARY		PAGE_SIZE
12515516c77SSepherosa Ziehau #define HN_RNDIS_PKT_ALIGN		CACHE_LINE_SIZE
12615516c77SSepherosa Ziehau 
12715516c77SSepherosa Ziehau #define HN_TX_DATA_BOUNDARY		PAGE_SIZE
12815516c77SSepherosa Ziehau #define HN_TX_DATA_MAXSIZE		IP_MAXPACKET
12915516c77SSepherosa Ziehau #define HN_TX_DATA_SEGSIZE		PAGE_SIZE
13015516c77SSepherosa Ziehau /* -1 for RNDIS packet message */
13115516c77SSepherosa Ziehau #define HN_TX_DATA_SEGCNT_MAX		(HN_GPACNT_MAX - 1)
13215516c77SSepherosa Ziehau 
13315516c77SSepherosa Ziehau #define HN_DIRECT_TX_SIZE_DEF		128
13415516c77SSepherosa Ziehau 
13515516c77SSepherosa Ziehau #define HN_EARLY_TXEOF_THRESH		8
13615516c77SSepherosa Ziehau 
13715516c77SSepherosa Ziehau #define HN_PKTBUF_LEN_DEF		(16 * 1024)
13815516c77SSepherosa Ziehau 
13915516c77SSepherosa Ziehau #define HN_LROENT_CNT_DEF		128
14015516c77SSepherosa Ziehau 
14115516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MULTIRX_DEF	(12 * ETHERMTU)
14215516c77SSepherosa Ziehau #define HN_LRO_LENLIM_DEF		(25 * ETHERMTU)
14315516c77SSepherosa Ziehau /* YYY 2*MTU is a bit rough, but should be good enough. */
14415516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MIN(ifp)		(2 * (ifp)->if_mtu)
14515516c77SSepherosa Ziehau 
14615516c77SSepherosa Ziehau #define HN_LRO_ACKCNT_DEF		1
14715516c77SSepherosa Ziehau 
14815516c77SSepherosa Ziehau #define HN_LOCK_INIT(sc)		\
14915516c77SSepherosa Ziehau 	sx_init(&(sc)->hn_lock, device_get_nameunit((sc)->hn_dev))
15015516c77SSepherosa Ziehau #define HN_LOCK_DESTROY(sc)		sx_destroy(&(sc)->hn_lock)
15115516c77SSepherosa Ziehau #define HN_LOCK_ASSERT(sc)		sx_assert(&(sc)->hn_lock, SA_XLOCKED)
152fdc4f478SSepherosa Ziehau #define HN_LOCK(sc)					\
153fdc4f478SSepherosa Ziehau do {							\
154fdc4f478SSepherosa Ziehau 	while (sx_try_xlock(&(sc)->hn_lock) == 0)	\
155fdc4f478SSepherosa Ziehau 		DELAY(1000);				\
156fdc4f478SSepherosa Ziehau } while (0)
15715516c77SSepherosa Ziehau #define HN_UNLOCK(sc)			sx_xunlock(&(sc)->hn_lock)
15815516c77SSepherosa Ziehau 
15915516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK			(CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP)
16015516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK		(CSUM_IP6_TCP | CSUM_IP6_UDP)
16115516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc)		\
16215516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK)
16315516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc)	\
16415516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK)
16515516c77SSepherosa Ziehau 
166dc13fee6SSepherosa Ziehau #define HN_PKTSIZE_MIN(align)		\
167dc13fee6SSepherosa Ziehau 	roundup2(ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN + \
168dc13fee6SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN, (align))
169dc13fee6SSepherosa Ziehau #define HN_PKTSIZE(m, align)		\
170dc13fee6SSepherosa Ziehau 	roundup2((m)->m_pkthdr.len + HN_RNDIS_PKT_LEN, (align))
171dc13fee6SSepherosa Ziehau 
172*0e11868dSSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx)	(((sc)->hn_cpu + (idx)) % mp_ncpus)
173*0e11868dSSepherosa Ziehau 
17415516c77SSepherosa Ziehau struct hn_txdesc {
17515516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
17615516c77SSepherosa Ziehau 	SLIST_ENTRY(hn_txdesc)		link;
17715516c77SSepherosa Ziehau #endif
178dc13fee6SSepherosa Ziehau 	STAILQ_ENTRY(hn_txdesc)		agg_link;
179dc13fee6SSepherosa Ziehau 
180dc13fee6SSepherosa Ziehau 	/* Aggregated txdescs, in sending order. */
181dc13fee6SSepherosa Ziehau 	STAILQ_HEAD(, hn_txdesc)	agg_list;
182dc13fee6SSepherosa Ziehau 
183dc13fee6SSepherosa Ziehau 	/* The oldest packet, if transmission aggregation happens. */
18415516c77SSepherosa Ziehau 	struct mbuf			*m;
18515516c77SSepherosa Ziehau 	struct hn_tx_ring		*txr;
18615516c77SSepherosa Ziehau 	int				refs;
18715516c77SSepherosa Ziehau 	uint32_t			flags;	/* HN_TXD_FLAG_ */
18815516c77SSepherosa Ziehau 	struct hn_nvs_sendctx		send_ctx;
18915516c77SSepherosa Ziehau 	uint32_t			chim_index;
19015516c77SSepherosa Ziehau 	int				chim_size;
19115516c77SSepherosa Ziehau 
19215516c77SSepherosa Ziehau 	bus_dmamap_t			data_dmap;
19315516c77SSepherosa Ziehau 
19415516c77SSepherosa Ziehau 	bus_addr_t			rndis_pkt_paddr;
19515516c77SSepherosa Ziehau 	struct rndis_packet_msg		*rndis_pkt;
19615516c77SSepherosa Ziehau 	bus_dmamap_t			rndis_pkt_dmap;
19715516c77SSepherosa Ziehau };
19815516c77SSepherosa Ziehau 
19915516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST		0x0001
20015516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP		0x0002
201dc13fee6SSepherosa Ziehau #define HN_TXD_FLAG_ONAGG		0x0004
20215516c77SSepherosa Ziehau 
20315516c77SSepherosa Ziehau struct hn_rxinfo {
20415516c77SSepherosa Ziehau 	uint32_t			vlan_info;
20515516c77SSepherosa Ziehau 	uint32_t			csum_info;
20615516c77SSepherosa Ziehau 	uint32_t			hash_info;
20715516c77SSepherosa Ziehau 	uint32_t			hash_value;
20815516c77SSepherosa Ziehau };
20915516c77SSepherosa Ziehau 
21015516c77SSepherosa Ziehau #define HN_RXINFO_VLAN			0x0001
21115516c77SSepherosa Ziehau #define HN_RXINFO_CSUM			0x0002
21215516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF		0x0004
21315516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL		0x0008
21415516c77SSepherosa Ziehau #define HN_RXINFO_ALL			\
21515516c77SSepherosa Ziehau 	(HN_RXINFO_VLAN |		\
21615516c77SSepherosa Ziehau 	 HN_RXINFO_CSUM |		\
21715516c77SSepherosa Ziehau 	 HN_RXINFO_HASHINF |		\
21815516c77SSepherosa Ziehau 	 HN_RXINFO_HASHVAL)
21915516c77SSepherosa Ziehau 
22015516c77SSepherosa Ziehau #define HN_NDIS_VLAN_INFO_INVALID	0xffffffff
22115516c77SSepherosa Ziehau #define HN_NDIS_RXCSUM_INFO_INVALID	0
22215516c77SSepherosa Ziehau #define HN_NDIS_HASH_INFO_INVALID	0
22315516c77SSepherosa Ziehau 
22415516c77SSepherosa Ziehau static int			hn_probe(device_t);
22515516c77SSepherosa Ziehau static int			hn_attach(device_t);
22615516c77SSepherosa Ziehau static int			hn_detach(device_t);
22715516c77SSepherosa Ziehau static int			hn_shutdown(device_t);
22815516c77SSepherosa Ziehau static void			hn_chan_callback(struct vmbus_channel *,
22915516c77SSepherosa Ziehau 				    void *);
23015516c77SSepherosa Ziehau 
23115516c77SSepherosa Ziehau static void			hn_init(void *);
23215516c77SSepherosa Ziehau static int			hn_ioctl(struct ifnet *, u_long, caddr_t);
23323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
23415516c77SSepherosa Ziehau static void			hn_start(struct ifnet *);
23523bf9e15SSepherosa Ziehau #endif
23615516c77SSepherosa Ziehau static int			hn_transmit(struct ifnet *, struct mbuf *);
23715516c77SSepherosa Ziehau static void			hn_xmit_qflush(struct ifnet *);
23815516c77SSepherosa Ziehau static int			hn_ifmedia_upd(struct ifnet *);
23915516c77SSepherosa Ziehau static void			hn_ifmedia_sts(struct ifnet *,
24015516c77SSepherosa Ziehau 				    struct ifmediareq *);
24115516c77SSepherosa Ziehau 
24215516c77SSepherosa Ziehau static int			hn_rndis_rxinfo(const void *, int,
24315516c77SSepherosa Ziehau 				    struct hn_rxinfo *);
24415516c77SSepherosa Ziehau static void			hn_rndis_rx_data(struct hn_rx_ring *,
24515516c77SSepherosa Ziehau 				    const void *, int);
24615516c77SSepherosa Ziehau static void			hn_rndis_rx_status(struct hn_softc *,
24715516c77SSepherosa Ziehau 				    const void *, int);
24815516c77SSepherosa Ziehau 
24915516c77SSepherosa Ziehau static void			hn_nvs_handle_notify(struct hn_softc *,
25015516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
25115516c77SSepherosa Ziehau static void			hn_nvs_handle_comp(struct hn_softc *,
25215516c77SSepherosa Ziehau 				    struct vmbus_channel *,
25315516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
25415516c77SSepherosa Ziehau static void			hn_nvs_handle_rxbuf(struct hn_rx_ring *,
25515516c77SSepherosa Ziehau 				    struct vmbus_channel *,
25615516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
25715516c77SSepherosa Ziehau static void			hn_nvs_ack_rxbuf(struct hn_rx_ring *,
25815516c77SSepherosa Ziehau 				    struct vmbus_channel *, uint64_t);
25915516c77SSepherosa Ziehau 
26015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
26115516c77SSepherosa Ziehau static int			hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS);
26215516c77SSepherosa Ziehau static int			hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS);
26315516c77SSepherosa Ziehau #endif
26415516c77SSepherosa Ziehau static int			hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS);
26515516c77SSepherosa Ziehau static int			hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS);
26615516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
26715516c77SSepherosa Ziehau static int			hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS);
26815516c77SSepherosa Ziehau #else
26915516c77SSepherosa Ziehau static int			hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS);
27015516c77SSepherosa Ziehau #endif
27115516c77SSepherosa Ziehau static int			hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
27215516c77SSepherosa Ziehau static int			hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
27315516c77SSepherosa Ziehau static int			hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS);
27415516c77SSepherosa Ziehau static int			hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS);
27515516c77SSepherosa Ziehau static int			hn_caps_sysctl(SYSCTL_HANDLER_ARGS);
27615516c77SSepherosa Ziehau static int			hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS);
27715516c77SSepherosa Ziehau static int			hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS);
27815516c77SSepherosa Ziehau static int			hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS);
27915516c77SSepherosa Ziehau static int			hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS);
28015516c77SSepherosa Ziehau static int			hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS);
281dc13fee6SSepherosa Ziehau static int			hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS);
282dc13fee6SSepherosa Ziehau static int			hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS);
283dc13fee6SSepherosa Ziehau static int			hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS);
284dc13fee6SSepherosa Ziehau static int			hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS);
28515516c77SSepherosa Ziehau 
28615516c77SSepherosa Ziehau static void			hn_stop(struct hn_softc *);
28715516c77SSepherosa Ziehau static void			hn_init_locked(struct hn_softc *);
28815516c77SSepherosa Ziehau static int			hn_chan_attach(struct hn_softc *,
28915516c77SSepherosa Ziehau 				    struct vmbus_channel *);
29015516c77SSepherosa Ziehau static void			hn_chan_detach(struct hn_softc *,
29115516c77SSepherosa Ziehau 				    struct vmbus_channel *);
29215516c77SSepherosa Ziehau static int			hn_attach_subchans(struct hn_softc *);
29315516c77SSepherosa Ziehau static void			hn_detach_allchans(struct hn_softc *);
29415516c77SSepherosa Ziehau static void			hn_chan_rollup(struct hn_rx_ring *,
29515516c77SSepherosa Ziehau 				    struct hn_tx_ring *);
29615516c77SSepherosa Ziehau static void			hn_set_ring_inuse(struct hn_softc *, int);
29715516c77SSepherosa Ziehau static int			hn_synth_attach(struct hn_softc *, int);
29815516c77SSepherosa Ziehau static void			hn_synth_detach(struct hn_softc *);
29915516c77SSepherosa Ziehau static int			hn_synth_alloc_subchans(struct hn_softc *,
30015516c77SSepherosa Ziehau 				    int *);
3012494d735SSepherosa Ziehau static bool			hn_synth_attachable(const struct hn_softc *);
30215516c77SSepherosa Ziehau static void			hn_suspend(struct hn_softc *);
30315516c77SSepherosa Ziehau static void			hn_suspend_data(struct hn_softc *);
30415516c77SSepherosa Ziehau static void			hn_suspend_mgmt(struct hn_softc *);
30515516c77SSepherosa Ziehau static void			hn_resume(struct hn_softc *);
30615516c77SSepherosa Ziehau static void			hn_resume_data(struct hn_softc *);
30715516c77SSepherosa Ziehau static void			hn_resume_mgmt(struct hn_softc *);
30815516c77SSepherosa Ziehau static void			hn_suspend_mgmt_taskfunc(void *, int);
30925641fc7SSepherosa Ziehau static void			hn_chan_drain(struct hn_softc *,
31025641fc7SSepherosa Ziehau 				    struct vmbus_channel *);
31115516c77SSepherosa Ziehau 
31215516c77SSepherosa Ziehau static void			hn_update_link_status(struct hn_softc *);
31315516c77SSepherosa Ziehau static void			hn_change_network(struct hn_softc *);
31415516c77SSepherosa Ziehau static void			hn_link_taskfunc(void *, int);
31515516c77SSepherosa Ziehau static void			hn_netchg_init_taskfunc(void *, int);
31615516c77SSepherosa Ziehau static void			hn_netchg_status_taskfunc(void *, int);
31715516c77SSepherosa Ziehau static void			hn_link_status(struct hn_softc *);
31815516c77SSepherosa Ziehau 
31915516c77SSepherosa Ziehau static int			hn_create_rx_data(struct hn_softc *, int);
32015516c77SSepherosa Ziehau static void			hn_destroy_rx_data(struct hn_softc *);
32115516c77SSepherosa Ziehau static int			hn_check_iplen(const struct mbuf *, int);
32215516c77SSepherosa Ziehau static int			hn_set_rxfilter(struct hn_softc *);
32315516c77SSepherosa Ziehau static int			hn_rss_reconfig(struct hn_softc *);
324afd4971bSSepherosa Ziehau static void			hn_rss_ind_fixup(struct hn_softc *);
32515516c77SSepherosa Ziehau static int			hn_rxpkt(struct hn_rx_ring *, const void *,
32615516c77SSepherosa Ziehau 				    int, const struct hn_rxinfo *);
32715516c77SSepherosa Ziehau 
32815516c77SSepherosa Ziehau static int			hn_tx_ring_create(struct hn_softc *, int);
32915516c77SSepherosa Ziehau static void			hn_tx_ring_destroy(struct hn_tx_ring *);
33015516c77SSepherosa Ziehau static int			hn_create_tx_data(struct hn_softc *, int);
33115516c77SSepherosa Ziehau static void			hn_fixup_tx_data(struct hn_softc *);
33215516c77SSepherosa Ziehau static void			hn_destroy_tx_data(struct hn_softc *);
33315516c77SSepherosa Ziehau static void			hn_txdesc_dmamap_destroy(struct hn_txdesc *);
33425641fc7SSepherosa Ziehau static void			hn_txdesc_gc(struct hn_tx_ring *,
33525641fc7SSepherosa Ziehau 				    struct hn_txdesc *);
336dc13fee6SSepherosa Ziehau static int			hn_encap(struct ifnet *, struct hn_tx_ring *,
33715516c77SSepherosa Ziehau 				    struct hn_txdesc *, struct mbuf **);
33815516c77SSepherosa Ziehau static int			hn_txpkt(struct ifnet *, struct hn_tx_ring *,
33915516c77SSepherosa Ziehau 				    struct hn_txdesc *);
34015516c77SSepherosa Ziehau static void			hn_set_chim_size(struct hn_softc *, int);
34115516c77SSepherosa Ziehau static void			hn_set_tso_maxsize(struct hn_softc *, int, int);
34215516c77SSepherosa Ziehau static bool			hn_tx_ring_pending(struct hn_tx_ring *);
34315516c77SSepherosa Ziehau static void			hn_tx_ring_qflush(struct hn_tx_ring *);
34415516c77SSepherosa Ziehau static void			hn_resume_tx(struct hn_softc *, int);
345dc13fee6SSepherosa Ziehau static void			hn_set_txagg(struct hn_softc *);
346dc13fee6SSepherosa Ziehau static void			*hn_try_txagg(struct ifnet *,
347dc13fee6SSepherosa Ziehau 				    struct hn_tx_ring *, struct hn_txdesc *,
348dc13fee6SSepherosa Ziehau 				    int);
34915516c77SSepherosa Ziehau static int			hn_get_txswq_depth(const struct hn_tx_ring *);
35015516c77SSepherosa Ziehau static void			hn_txpkt_done(struct hn_nvs_sendctx *,
35115516c77SSepherosa Ziehau 				    struct hn_softc *, struct vmbus_channel *,
35215516c77SSepherosa Ziehau 				    const void *, int);
35315516c77SSepherosa Ziehau static int			hn_txpkt_sglist(struct hn_tx_ring *,
35415516c77SSepherosa Ziehau 				    struct hn_txdesc *);
35515516c77SSepherosa Ziehau static int			hn_txpkt_chim(struct hn_tx_ring *,
35615516c77SSepherosa Ziehau 				    struct hn_txdesc *);
35715516c77SSepherosa Ziehau static int			hn_xmit(struct hn_tx_ring *, int);
35815516c77SSepherosa Ziehau static void			hn_xmit_taskfunc(void *, int);
35915516c77SSepherosa Ziehau static void			hn_xmit_txeof(struct hn_tx_ring *);
36015516c77SSepherosa Ziehau static void			hn_xmit_txeof_taskfunc(void *, int);
36123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
36215516c77SSepherosa Ziehau static int			hn_start_locked(struct hn_tx_ring *, int);
36315516c77SSepherosa Ziehau static void			hn_start_taskfunc(void *, int);
36415516c77SSepherosa Ziehau static void			hn_start_txeof(struct hn_tx_ring *);
36515516c77SSepherosa Ziehau static void			hn_start_txeof_taskfunc(void *, int);
36623bf9e15SSepherosa Ziehau #endif
36715516c77SSepherosa Ziehau 
36815516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
36915516c77SSepherosa Ziehau     "Hyper-V network interface");
37015516c77SSepherosa Ziehau 
37115516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */
37215516c77SSepherosa Ziehau static int			hn_trust_hosttcp = 1;
37315516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN,
37415516c77SSepherosa Ziehau     &hn_trust_hosttcp, 0,
37515516c77SSepherosa Ziehau     "Trust tcp segement verification on host side, "
37615516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
37715516c77SSepherosa Ziehau 
37815516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */
37915516c77SSepherosa Ziehau static int			hn_trust_hostudp = 1;
38015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN,
38115516c77SSepherosa Ziehau     &hn_trust_hostudp, 0,
38215516c77SSepherosa Ziehau     "Trust udp datagram verification on host side, "
38315516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
38415516c77SSepherosa Ziehau 
38515516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */
38615516c77SSepherosa Ziehau static int			hn_trust_hostip = 1;
38715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN,
38815516c77SSepherosa Ziehau     &hn_trust_hostip, 0,
38915516c77SSepherosa Ziehau     "Trust ip packet verification on host side, "
39015516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
39115516c77SSepherosa Ziehau 
39215516c77SSepherosa Ziehau /* Limit TSO burst size */
39315516c77SSepherosa Ziehau static int			hn_tso_maxlen = IP_MAXPACKET;
39415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN,
39515516c77SSepherosa Ziehau     &hn_tso_maxlen, 0, "TSO burst limit");
39615516c77SSepherosa Ziehau 
39715516c77SSepherosa Ziehau /* Limit chimney send size */
39815516c77SSepherosa Ziehau static int			hn_tx_chimney_size = 0;
39915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN,
40015516c77SSepherosa Ziehau     &hn_tx_chimney_size, 0, "Chimney send packet size limit");
40115516c77SSepherosa Ziehau 
40215516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */
40315516c77SSepherosa Ziehau static int			hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF;
40415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN,
40515516c77SSepherosa Ziehau     &hn_direct_tx_size, 0, "Size of the packet for direct transmission");
40615516c77SSepherosa Ziehau 
40715516c77SSepherosa Ziehau /* # of LRO entries per RX ring */
40815516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
40915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
41015516c77SSepherosa Ziehau static int			hn_lro_entry_count = HN_LROENT_CNT_DEF;
41115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN,
41215516c77SSepherosa Ziehau     &hn_lro_entry_count, 0, "LRO entry count");
41315516c77SSepherosa Ziehau #endif
41415516c77SSepherosa Ziehau #endif
41515516c77SSepherosa Ziehau 
416fdd0222aSSepherosa Ziehau static int			hn_tx_taskq_cnt = 1;
417fdd0222aSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_cnt, CTLFLAG_RDTUN,
418fdd0222aSSepherosa Ziehau     &hn_tx_taskq_cnt, 0, "# of TX taskqueues");
419fdd0222aSSepherosa Ziehau 
420*0e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_INDEP	0
421*0e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_GLOBAL	1
422*0e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_EVTTQ	2
423*0e11868dSSepherosa Ziehau 
424*0e11868dSSepherosa Ziehau static int			hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
425*0e11868dSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_mode, CTLFLAG_RDTUN,
426*0e11868dSSepherosa Ziehau     &hn_tx_taskq_mode, 0, "TX taskqueue modes: "
427*0e11868dSSepherosa Ziehau     "0 - independent, 1 - share global tx taskqs, 2 - share event taskqs");
428*0e11868dSSepherosa Ziehau 
42915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
43015516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 0;
43115516c77SSepherosa Ziehau #else
43215516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 1;
43315516c77SSepherosa Ziehau #endif
43415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD,
43515516c77SSepherosa Ziehau     &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors");
43615516c77SSepherosa Ziehau 
43723bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
43815516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */
43915516c77SSepherosa Ziehau static int			hn_use_if_start = 0;
44015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN,
44115516c77SSepherosa Ziehau     &hn_use_if_start, 0, "Use if_start TX method");
44223bf9e15SSepherosa Ziehau #endif
44315516c77SSepherosa Ziehau 
44415516c77SSepherosa Ziehau /* # of channels to use */
44515516c77SSepherosa Ziehau static int			hn_chan_cnt = 0;
44615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN,
44715516c77SSepherosa Ziehau     &hn_chan_cnt, 0,
44815516c77SSepherosa Ziehau     "# of channels to use; each channel has one RX ring and one TX ring");
44915516c77SSepherosa Ziehau 
45015516c77SSepherosa Ziehau /* # of transmit rings to use */
45115516c77SSepherosa Ziehau static int			hn_tx_ring_cnt = 0;
45215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN,
45315516c77SSepherosa Ziehau     &hn_tx_ring_cnt, 0, "# of TX rings to use");
45415516c77SSepherosa Ziehau 
45515516c77SSepherosa Ziehau /* Software TX ring deptch */
45615516c77SSepherosa Ziehau static int			hn_tx_swq_depth = 0;
45715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN,
45815516c77SSepherosa Ziehau     &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING");
45915516c77SSepherosa Ziehau 
46015516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */
46115516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
46215516c77SSepherosa Ziehau static u_int			hn_lro_mbufq_depth = 0;
46315516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN,
46415516c77SSepherosa Ziehau     &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue");
46515516c77SSepherosa Ziehau #endif
46615516c77SSepherosa Ziehau 
467dc13fee6SSepherosa Ziehau /* Packet transmission aggregation size limit */
468dc13fee6SSepherosa Ziehau static int			hn_tx_agg_size = -1;
469dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN,
470dc13fee6SSepherosa Ziehau     &hn_tx_agg_size, 0, "Packet transmission aggregation size limit");
471dc13fee6SSepherosa Ziehau 
472dc13fee6SSepherosa Ziehau /* Packet transmission aggregation count limit */
473fa915c4dSSepherosa Ziehau static int			hn_tx_agg_pkts = -1;
474dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN,
475dc13fee6SSepherosa Ziehau     &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit");
476dc13fee6SSepherosa Ziehau 
47715516c77SSepherosa Ziehau static u_int			hn_cpu_index;	/* next CPU for channel */
478fdd0222aSSepherosa Ziehau static struct taskqueue		**hn_tx_taskque;/* shared TX taskqueues */
47915516c77SSepherosa Ziehau 
48015516c77SSepherosa Ziehau static const uint8_t
48115516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
48215516c77SSepherosa Ziehau 	0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
48315516c77SSepherosa Ziehau 	0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
48415516c77SSepherosa Ziehau 	0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
48515516c77SSepherosa Ziehau 	0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
48615516c77SSepherosa Ziehau 	0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
48715516c77SSepherosa Ziehau };
48815516c77SSepherosa Ziehau 
48915516c77SSepherosa Ziehau static device_method_t hn_methods[] = {
49015516c77SSepherosa Ziehau 	/* Device interface */
49115516c77SSepherosa Ziehau 	DEVMETHOD(device_probe,		hn_probe),
49215516c77SSepherosa Ziehau 	DEVMETHOD(device_attach,	hn_attach),
49315516c77SSepherosa Ziehau 	DEVMETHOD(device_detach,	hn_detach),
49415516c77SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	hn_shutdown),
49515516c77SSepherosa Ziehau 	DEVMETHOD_END
49615516c77SSepherosa Ziehau };
49715516c77SSepherosa Ziehau 
49815516c77SSepherosa Ziehau static driver_t hn_driver = {
49915516c77SSepherosa Ziehau 	"hn",
50015516c77SSepherosa Ziehau 	hn_methods,
50115516c77SSepherosa Ziehau 	sizeof(struct hn_softc)
50215516c77SSepherosa Ziehau };
50315516c77SSepherosa Ziehau 
50415516c77SSepherosa Ziehau static devclass_t hn_devclass;
50515516c77SSepherosa Ziehau 
50615516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0);
50715516c77SSepherosa Ziehau MODULE_VERSION(hn, 1);
50815516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1);
50915516c77SSepherosa Ziehau 
51015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
51115516c77SSepherosa Ziehau static void
51215516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim)
51315516c77SSepherosa Ziehau {
51415516c77SSepherosa Ziehau 	int i;
51515516c77SSepherosa Ziehau 
516a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
51715516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim;
51815516c77SSepherosa Ziehau }
51915516c77SSepherosa Ziehau #endif
52015516c77SSepherosa Ziehau 
52115516c77SSepherosa Ziehau static int
52215516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd)
52315516c77SSepherosa Ziehau {
52415516c77SSepherosa Ziehau 
52515516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
52615516c77SSepherosa Ziehau 	    txd->chim_size == 0, ("invalid rndis sglist txd"));
52715516c77SSepherosa Ziehau 	return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA,
52815516c77SSepherosa Ziehau 	    &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt));
52915516c77SSepherosa Ziehau }
53015516c77SSepherosa Ziehau 
53115516c77SSepherosa Ziehau static int
53215516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd)
53315516c77SSepherosa Ziehau {
53415516c77SSepherosa Ziehau 	struct hn_nvs_rndis rndis;
53515516c77SSepherosa Ziehau 
53615516c77SSepherosa Ziehau 	KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID &&
53715516c77SSepherosa Ziehau 	    txd->chim_size > 0, ("invalid rndis chim txd"));
53815516c77SSepherosa Ziehau 
53915516c77SSepherosa Ziehau 	rndis.nvs_type = HN_NVS_TYPE_RNDIS;
54015516c77SSepherosa Ziehau 	rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA;
54115516c77SSepherosa Ziehau 	rndis.nvs_chim_idx = txd->chim_index;
54215516c77SSepherosa Ziehau 	rndis.nvs_chim_sz = txd->chim_size;
54315516c77SSepherosa Ziehau 
54415516c77SSepherosa Ziehau 	return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC,
54515516c77SSepherosa Ziehau 	    &rndis, sizeof(rndis), &txd->send_ctx));
54615516c77SSepherosa Ziehau }
54715516c77SSepherosa Ziehau 
54815516c77SSepherosa Ziehau static __inline uint32_t
54915516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc)
55015516c77SSepherosa Ziehau {
55115516c77SSepherosa Ziehau 	int i, bmap_cnt = sc->hn_chim_bmap_cnt;
55215516c77SSepherosa Ziehau 	u_long *bmap = sc->hn_chim_bmap;
55315516c77SSepherosa Ziehau 	uint32_t ret = HN_NVS_CHIM_IDX_INVALID;
55415516c77SSepherosa Ziehau 
55515516c77SSepherosa Ziehau 	for (i = 0; i < bmap_cnt; ++i) {
55615516c77SSepherosa Ziehau 		int idx;
55715516c77SSepherosa Ziehau 
55815516c77SSepherosa Ziehau 		idx = ffsl(~bmap[i]);
55915516c77SSepherosa Ziehau 		if (idx == 0)
56015516c77SSepherosa Ziehau 			continue;
56115516c77SSepherosa Ziehau 
56215516c77SSepherosa Ziehau 		--idx; /* ffsl is 1-based */
56315516c77SSepherosa Ziehau 		KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt,
56415516c77SSepherosa Ziehau 		    ("invalid i %d and idx %d", i, idx));
56515516c77SSepherosa Ziehau 
56615516c77SSepherosa Ziehau 		if (atomic_testandset_long(&bmap[i], idx))
56715516c77SSepherosa Ziehau 			continue;
56815516c77SSepherosa Ziehau 
56915516c77SSepherosa Ziehau 		ret = i * LONG_BIT + idx;
57015516c77SSepherosa Ziehau 		break;
57115516c77SSepherosa Ziehau 	}
57215516c77SSepherosa Ziehau 	return (ret);
57315516c77SSepherosa Ziehau }
57415516c77SSepherosa Ziehau 
57515516c77SSepherosa Ziehau static __inline void
57615516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx)
57715516c77SSepherosa Ziehau {
57815516c77SSepherosa Ziehau 	u_long mask;
57915516c77SSepherosa Ziehau 	uint32_t idx;
58015516c77SSepherosa Ziehau 
58115516c77SSepherosa Ziehau 	idx = chim_idx / LONG_BIT;
58215516c77SSepherosa Ziehau 	KASSERT(idx < sc->hn_chim_bmap_cnt,
58315516c77SSepherosa Ziehau 	    ("invalid chimney index 0x%x", chim_idx));
58415516c77SSepherosa Ziehau 
58515516c77SSepherosa Ziehau 	mask = 1UL << (chim_idx % LONG_BIT);
58615516c77SSepherosa Ziehau 	KASSERT(sc->hn_chim_bmap[idx] & mask,
58715516c77SSepherosa Ziehau 	    ("index bitmap 0x%lx, chimney index %u, "
58815516c77SSepherosa Ziehau 	     "bitmap idx %d, bitmask 0x%lx",
58915516c77SSepherosa Ziehau 	     sc->hn_chim_bmap[idx], chim_idx, idx, mask));
59015516c77SSepherosa Ziehau 
59115516c77SSepherosa Ziehau 	atomic_clear_long(&sc->hn_chim_bmap[idx], mask);
59215516c77SSepherosa Ziehau }
59315516c77SSepherosa Ziehau 
594edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
595edd3f315SSepherosa Ziehau /*
596edd3f315SSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
597edd3f315SSepherosa Ziehau  */
598edd3f315SSepherosa Ziehau static __inline struct mbuf *
599edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head)
600edd3f315SSepherosa Ziehau {
601edd3f315SSepherosa Ziehau 	struct ether_vlan_header *evl;
602edd3f315SSepherosa Ziehau 	struct tcphdr *th;
603edd3f315SSepherosa Ziehau 	int ehlen;
604edd3f315SSepherosa Ziehau 
605edd3f315SSepherosa Ziehau 	KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable"));
606edd3f315SSepherosa Ziehau 
607edd3f315SSepherosa Ziehau #define PULLUP_HDR(m, len)				\
608edd3f315SSepherosa Ziehau do {							\
609edd3f315SSepherosa Ziehau 	if (__predict_false((m)->m_len < (len))) {	\
610edd3f315SSepherosa Ziehau 		(m) = m_pullup((m), (len));		\
611edd3f315SSepherosa Ziehau 		if ((m) == NULL)			\
612edd3f315SSepherosa Ziehau 			return (NULL);			\
613edd3f315SSepherosa Ziehau 	}						\
614edd3f315SSepherosa Ziehau } while (0)
615edd3f315SSepherosa Ziehau 
616edd3f315SSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
617edd3f315SSepherosa Ziehau 	evl = mtod(m_head, struct ether_vlan_header *);
618edd3f315SSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
619edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
620edd3f315SSepherosa Ziehau 	else
621edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
622edd3f315SSepherosa Ziehau 
623edd3f315SSepherosa Ziehau #ifdef INET
624edd3f315SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
625edd3f315SSepherosa Ziehau 		struct ip *ip;
626edd3f315SSepherosa Ziehau 		int iphlen;
627edd3f315SSepherosa Ziehau 
628edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
629edd3f315SSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
630edd3f315SSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
631edd3f315SSepherosa Ziehau 
632edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
633edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + iphlen);
634edd3f315SSepherosa Ziehau 
635edd3f315SSepherosa Ziehau 		ip->ip_len = 0;
636edd3f315SSepherosa Ziehau 		ip->ip_sum = 0;
637edd3f315SSepherosa Ziehau 		th->th_sum = in_pseudo(ip->ip_src.s_addr,
638edd3f315SSepherosa Ziehau 		    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
639edd3f315SSepherosa Ziehau 	}
640edd3f315SSepherosa Ziehau #endif
641edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET)
642edd3f315SSepherosa Ziehau 	else
643edd3f315SSepherosa Ziehau #endif
644edd3f315SSepherosa Ziehau #ifdef INET6
645edd3f315SSepherosa Ziehau 	{
646edd3f315SSepherosa Ziehau 		struct ip6_hdr *ip6;
647edd3f315SSepherosa Ziehau 
648edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
649edd3f315SSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
650edd3f315SSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP) {
651edd3f315SSepherosa Ziehau 			m_freem(m_head);
652edd3f315SSepherosa Ziehau 			return (NULL);
653edd3f315SSepherosa Ziehau 		}
654edd3f315SSepherosa Ziehau 
655edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
656edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + sizeof(*ip6));
657edd3f315SSepherosa Ziehau 
658edd3f315SSepherosa Ziehau 		ip6->ip6_plen = 0;
659edd3f315SSepherosa Ziehau 		th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
660edd3f315SSepherosa Ziehau 	}
661edd3f315SSepherosa Ziehau #endif
662edd3f315SSepherosa Ziehau 	return (m_head);
663edd3f315SSepherosa Ziehau 
664edd3f315SSepherosa Ziehau #undef PULLUP_HDR
665edd3f315SSepherosa Ziehau }
666edd3f315SSepherosa Ziehau #endif	/* INET6 || INET */
667edd3f315SSepherosa Ziehau 
66815516c77SSepherosa Ziehau static int
66915516c77SSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc)
67015516c77SSepherosa Ziehau {
67115516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
67215516c77SSepherosa Ziehau 	uint32_t filter;
67315516c77SSepherosa Ziehau 	int error = 0;
67415516c77SSepherosa Ziehau 
67515516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
67615516c77SSepherosa Ziehau 
67715516c77SSepherosa Ziehau 	if (ifp->if_flags & IFF_PROMISC) {
67815516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_PROMISCUOUS;
67915516c77SSepherosa Ziehau 	} else {
68015516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_DIRECTED;
68115516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_BROADCAST)
68215516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_BROADCAST;
68315516c77SSepherosa Ziehau 		/* TODO: support multicast list */
68415516c77SSepherosa Ziehau 		if ((ifp->if_flags & IFF_ALLMULTI) ||
68515516c77SSepherosa Ziehau 		    !TAILQ_EMPTY(&ifp->if_multiaddrs))
68615516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
68715516c77SSepherosa Ziehau 	}
68815516c77SSepherosa Ziehau 
68915516c77SSepherosa Ziehau 	if (sc->hn_rx_filter != filter) {
69015516c77SSepherosa Ziehau 		error = hn_rndis_set_rxfilter(sc, filter);
69115516c77SSepherosa Ziehau 		if (!error)
69215516c77SSepherosa Ziehau 			sc->hn_rx_filter = filter;
69315516c77SSepherosa Ziehau 	}
69415516c77SSepherosa Ziehau 	return (error);
69515516c77SSepherosa Ziehau }
69615516c77SSepherosa Ziehau 
697dc13fee6SSepherosa Ziehau static void
698dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc)
699dc13fee6SSepherosa Ziehau {
700dc13fee6SSepherosa Ziehau 	uint32_t size, pkts;
701dc13fee6SSepherosa Ziehau 	int i;
702dc13fee6SSepherosa Ziehau 
703dc13fee6SSepherosa Ziehau 	/*
704dc13fee6SSepherosa Ziehau 	 * Setup aggregation size.
705dc13fee6SSepherosa Ziehau 	 */
706dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_size < 0)
707dc13fee6SSepherosa Ziehau 		size = UINT32_MAX;
708dc13fee6SSepherosa Ziehau 	else
709dc13fee6SSepherosa Ziehau 		size = sc->hn_agg_size;
710dc13fee6SSepherosa Ziehau 
711dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_size < size)
712dc13fee6SSepherosa Ziehau 		size = sc->hn_rndis_agg_size;
713dc13fee6SSepherosa Ziehau 
714a4364cfeSSepherosa Ziehau 	/* NOTE: We only aggregate packets using chimney sending buffers. */
715a4364cfeSSepherosa Ziehau 	if (size > (uint32_t)sc->hn_chim_szmax)
716a4364cfeSSepherosa Ziehau 		size = sc->hn_chim_szmax;
717a4364cfeSSepherosa Ziehau 
718dc13fee6SSepherosa Ziehau 	if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) {
719dc13fee6SSepherosa Ziehau 		/* Disable */
720dc13fee6SSepherosa Ziehau 		size = 0;
721dc13fee6SSepherosa Ziehau 		pkts = 0;
722dc13fee6SSepherosa Ziehau 		goto done;
723dc13fee6SSepherosa Ziehau 	}
724dc13fee6SSepherosa Ziehau 
725dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'int'. */
726dc13fee6SSepherosa Ziehau 	if (size > INT_MAX)
727dc13fee6SSepherosa Ziehau 		size = INT_MAX;
728dc13fee6SSepherosa Ziehau 
729dc13fee6SSepherosa Ziehau 	/*
730dc13fee6SSepherosa Ziehau 	 * Setup aggregation packet count.
731dc13fee6SSepherosa Ziehau 	 */
732dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_pkts < 0)
733dc13fee6SSepherosa Ziehau 		pkts = UINT32_MAX;
734dc13fee6SSepherosa Ziehau 	else
735dc13fee6SSepherosa Ziehau 		pkts = sc->hn_agg_pkts;
736dc13fee6SSepherosa Ziehau 
737dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_pkts < pkts)
738dc13fee6SSepherosa Ziehau 		pkts = sc->hn_rndis_agg_pkts;
739dc13fee6SSepherosa Ziehau 
740dc13fee6SSepherosa Ziehau 	if (pkts <= 1) {
741dc13fee6SSepherosa Ziehau 		/* Disable */
742dc13fee6SSepherosa Ziehau 		size = 0;
743dc13fee6SSepherosa Ziehau 		pkts = 0;
744dc13fee6SSepherosa Ziehau 		goto done;
745dc13fee6SSepherosa Ziehau 	}
746dc13fee6SSepherosa Ziehau 
747dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
748dc13fee6SSepherosa Ziehau 	if (pkts > SHRT_MAX)
749dc13fee6SSepherosa Ziehau 		pkts = SHRT_MAX;
750dc13fee6SSepherosa Ziehau 
751dc13fee6SSepherosa Ziehau done:
752dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
753dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_align > SHRT_MAX) {
754dc13fee6SSepherosa Ziehau 		/* Disable */
755dc13fee6SSepherosa Ziehau 		size = 0;
756dc13fee6SSepherosa Ziehau 		pkts = 0;
757dc13fee6SSepherosa Ziehau 	}
758dc13fee6SSepherosa Ziehau 
759dc13fee6SSepherosa Ziehau 	if (bootverbose) {
760dc13fee6SSepherosa Ziehau 		if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n",
761dc13fee6SSepherosa Ziehau 		    size, pkts, sc->hn_rndis_agg_align);
762dc13fee6SSepherosa Ziehau 	}
763dc13fee6SSepherosa Ziehau 
764dc13fee6SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
765dc13fee6SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
766dc13fee6SSepherosa Ziehau 
767dc13fee6SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
768dc13fee6SSepherosa Ziehau 		txr->hn_agg_szmax = size;
769dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktmax = pkts;
770dc13fee6SSepherosa Ziehau 		txr->hn_agg_align = sc->hn_rndis_agg_align;
771dc13fee6SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
772dc13fee6SSepherosa Ziehau 	}
773dc13fee6SSepherosa Ziehau }
774dc13fee6SSepherosa Ziehau 
77515516c77SSepherosa Ziehau static int
77615516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr)
77715516c77SSepherosa Ziehau {
77815516c77SSepherosa Ziehau 
77915516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet"));
78015516c77SSepherosa Ziehau 	if (hn_tx_swq_depth < txr->hn_txdesc_cnt)
78115516c77SSepherosa Ziehau 		return txr->hn_txdesc_cnt;
78215516c77SSepherosa Ziehau 	return hn_tx_swq_depth;
78315516c77SSepherosa Ziehau }
78415516c77SSepherosa Ziehau 
78515516c77SSepherosa Ziehau static int
78615516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc)
78715516c77SSepherosa Ziehau {
78815516c77SSepherosa Ziehau 	int error;
78915516c77SSepherosa Ziehau 
79015516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
79115516c77SSepherosa Ziehau 
79215516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
79315516c77SSepherosa Ziehau 		return (ENXIO);
79415516c77SSepherosa Ziehau 
79515516c77SSepherosa Ziehau 	/*
79615516c77SSepherosa Ziehau 	 * Disable RSS first.
79715516c77SSepherosa Ziehau 	 *
79815516c77SSepherosa Ziehau 	 * NOTE:
79915516c77SSepherosa Ziehau 	 * Direct reconfiguration by setting the UNCHG flags does
80015516c77SSepherosa Ziehau 	 * _not_ work properly.
80115516c77SSepherosa Ziehau 	 */
80215516c77SSepherosa Ziehau 	if (bootverbose)
80315516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "disable RSS\n");
80415516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE);
80515516c77SSepherosa Ziehau 	if (error) {
80615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS disable failed\n");
80715516c77SSepherosa Ziehau 		return (error);
80815516c77SSepherosa Ziehau 	}
80915516c77SSepherosa Ziehau 
81015516c77SSepherosa Ziehau 	/*
81115516c77SSepherosa Ziehau 	 * Reenable the RSS w/ the updated RSS key or indirect
81215516c77SSepherosa Ziehau 	 * table.
81315516c77SSepherosa Ziehau 	 */
81415516c77SSepherosa Ziehau 	if (bootverbose)
81515516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "reconfig RSS\n");
81615516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
81715516c77SSepherosa Ziehau 	if (error) {
81815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS reconfig failed\n");
81915516c77SSepherosa Ziehau 		return (error);
82015516c77SSepherosa Ziehau 	}
82115516c77SSepherosa Ziehau 	return (0);
82215516c77SSepherosa Ziehau }
82315516c77SSepherosa Ziehau 
82415516c77SSepherosa Ziehau static void
825afd4971bSSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc)
82615516c77SSepherosa Ziehau {
82715516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
828afd4971bSSepherosa Ziehau 	int i, nchan;
82915516c77SSepherosa Ziehau 
830afd4971bSSepherosa Ziehau 	nchan = sc->hn_rx_ring_inuse;
83115516c77SSepherosa Ziehau 	KASSERT(nchan > 1, ("invalid # of channels %d", nchan));
83215516c77SSepherosa Ziehau 
83315516c77SSepherosa Ziehau 	/*
83415516c77SSepherosa Ziehau 	 * Check indirect table to make sure that all channels in it
83515516c77SSepherosa Ziehau 	 * can be used.
83615516c77SSepherosa Ziehau 	 */
83715516c77SSepherosa Ziehau 	for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
83815516c77SSepherosa Ziehau 		if (rss->rss_ind[i] >= nchan) {
83915516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp,
84015516c77SSepherosa Ziehau 			    "RSS indirect table %d fixup: %u -> %d\n",
84115516c77SSepherosa Ziehau 			    i, rss->rss_ind[i], nchan - 1);
84215516c77SSepherosa Ziehau 			rss->rss_ind[i] = nchan - 1;
84315516c77SSepherosa Ziehau 		}
84415516c77SSepherosa Ziehau 	}
84515516c77SSepherosa Ziehau }
84615516c77SSepherosa Ziehau 
84715516c77SSepherosa Ziehau static int
84815516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused)
84915516c77SSepherosa Ziehau {
85015516c77SSepherosa Ziehau 
85115516c77SSepherosa Ziehau 	return EOPNOTSUPP;
85215516c77SSepherosa Ziehau }
85315516c77SSepherosa Ziehau 
85415516c77SSepherosa Ziehau static void
85515516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
85615516c77SSepherosa Ziehau {
85715516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
85815516c77SSepherosa Ziehau 
85915516c77SSepherosa Ziehau 	ifmr->ifm_status = IFM_AVALID;
86015516c77SSepherosa Ziehau 	ifmr->ifm_active = IFM_ETHER;
86115516c77SSepherosa Ziehau 
86215516c77SSepherosa Ziehau 	if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) {
86315516c77SSepherosa Ziehau 		ifmr->ifm_active |= IFM_NONE;
86415516c77SSepherosa Ziehau 		return;
86515516c77SSepherosa Ziehau 	}
86615516c77SSepherosa Ziehau 	ifmr->ifm_status |= IFM_ACTIVE;
86715516c77SSepherosa Ziehau 	ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
86815516c77SSepherosa Ziehau }
86915516c77SSepherosa Ziehau 
87015516c77SSepherosa Ziehau /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
87115516c77SSepherosa Ziehau static const struct hyperv_guid g_net_vsc_device_type = {
87215516c77SSepherosa Ziehau 	.hv_guid = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
87315516c77SSepherosa Ziehau 		0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E}
87415516c77SSepherosa Ziehau };
87515516c77SSepherosa Ziehau 
87615516c77SSepherosa Ziehau static int
87715516c77SSepherosa Ziehau hn_probe(device_t dev)
87815516c77SSepherosa Ziehau {
87915516c77SSepherosa Ziehau 
88015516c77SSepherosa Ziehau 	if (VMBUS_PROBE_GUID(device_get_parent(dev), dev,
88115516c77SSepherosa Ziehau 	    &g_net_vsc_device_type) == 0) {
88215516c77SSepherosa Ziehau 		device_set_desc(dev, "Hyper-V Network Interface");
88315516c77SSepherosa Ziehau 		return BUS_PROBE_DEFAULT;
88415516c77SSepherosa Ziehau 	}
88515516c77SSepherosa Ziehau 	return ENXIO;
88615516c77SSepherosa Ziehau }
88715516c77SSepherosa Ziehau 
88815516c77SSepherosa Ziehau static int
88915516c77SSepherosa Ziehau hn_attach(device_t dev)
89015516c77SSepherosa Ziehau {
89115516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
89215516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
89315516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
89415516c77SSepherosa Ziehau 	uint8_t eaddr[ETHER_ADDR_LEN];
89515516c77SSepherosa Ziehau 	struct ifnet *ifp = NULL;
89615516c77SSepherosa Ziehau 	int error, ring_cnt, tx_ring_cnt;
89715516c77SSepherosa Ziehau 
89815516c77SSepherosa Ziehau 	sc->hn_dev = dev;
89915516c77SSepherosa Ziehau 	sc->hn_prichan = vmbus_get_channel(dev);
90015516c77SSepherosa Ziehau 	HN_LOCK_INIT(sc);
90115516c77SSepherosa Ziehau 
90215516c77SSepherosa Ziehau 	/*
903dc13fee6SSepherosa Ziehau 	 * Initialize these tunables once.
904dc13fee6SSepherosa Ziehau 	 */
905dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = hn_tx_agg_size;
906dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = hn_tx_agg_pkts;
907dc13fee6SSepherosa Ziehau 
908dc13fee6SSepherosa Ziehau 	/*
90915516c77SSepherosa Ziehau 	 * Setup taskqueue for transmission.
91015516c77SSepherosa Ziehau 	 */
911*0e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_INDEP) {
912fdd0222aSSepherosa Ziehau 		int i;
913fdd0222aSSepherosa Ziehau 
914fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs =
915fdd0222aSSepherosa Ziehau 		    malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
916fdd0222aSSepherosa Ziehau 		    M_DEVBUF, M_WAITOK);
917fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i) {
918fdd0222aSSepherosa Ziehau 			sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx",
919fdd0222aSSepherosa Ziehau 			    M_WAITOK, taskqueue_thread_enqueue,
920fdd0222aSSepherosa Ziehau 			    &sc->hn_tx_taskqs[i]);
921fdd0222aSSepherosa Ziehau 			taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET,
922fdd0222aSSepherosa Ziehau 			    "%s tx%d", device_get_nameunit(dev), i);
923fdd0222aSSepherosa Ziehau 		}
924*0e11868dSSepherosa Ziehau 	} else if (hn_tx_taskq_mode == HN_TX_TASKQ_M_GLOBAL) {
925fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs = hn_tx_taskque;
92615516c77SSepherosa Ziehau 	}
92715516c77SSepherosa Ziehau 
92815516c77SSepherosa Ziehau 	/*
92915516c77SSepherosa Ziehau 	 * Setup taskqueue for mangement tasks, e.g. link status.
93015516c77SSepherosa Ziehau 	 */
93115516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK,
93215516c77SSepherosa Ziehau 	    taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0);
93315516c77SSepherosa Ziehau 	taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
93415516c77SSepherosa Ziehau 	    device_get_nameunit(dev));
93515516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
93615516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc);
93715516c77SSepherosa Ziehau 	TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0,
93815516c77SSepherosa Ziehau 	    hn_netchg_status_taskfunc, sc);
93915516c77SSepherosa Ziehau 
94015516c77SSepherosa Ziehau 	/*
94115516c77SSepherosa Ziehau 	 * Allocate ifnet and setup its name earlier, so that if_printf
94215516c77SSepherosa Ziehau 	 * can be used by functions, which will be called after
94315516c77SSepherosa Ziehau 	 * ether_ifattach().
94415516c77SSepherosa Ziehau 	 */
94515516c77SSepherosa Ziehau 	ifp = sc->hn_ifp = if_alloc(IFT_ETHER);
94615516c77SSepherosa Ziehau 	ifp->if_softc = sc;
94715516c77SSepherosa Ziehau 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
94815516c77SSepherosa Ziehau 
94915516c77SSepherosa Ziehau 	/*
95015516c77SSepherosa Ziehau 	 * Initialize ifmedia earlier so that it can be unconditionally
95115516c77SSepherosa Ziehau 	 * destroyed, if error happened later on.
95215516c77SSepherosa Ziehau 	 */
95315516c77SSepherosa Ziehau 	ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts);
95415516c77SSepherosa Ziehau 
95515516c77SSepherosa Ziehau 	/*
95615516c77SSepherosa Ziehau 	 * Figure out the # of RX rings (ring_cnt) and the # of TX rings
95715516c77SSepherosa Ziehau 	 * to use (tx_ring_cnt).
95815516c77SSepherosa Ziehau 	 *
95915516c77SSepherosa Ziehau 	 * NOTE:
96015516c77SSepherosa Ziehau 	 * The # of RX rings to use is same as the # of channels to use.
96115516c77SSepherosa Ziehau 	 */
96215516c77SSepherosa Ziehau 	ring_cnt = hn_chan_cnt;
96315516c77SSepherosa Ziehau 	if (ring_cnt <= 0) {
96415516c77SSepherosa Ziehau 		/* Default */
96515516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
96615516c77SSepherosa Ziehau 		if (ring_cnt > HN_RING_CNT_DEF_MAX)
96715516c77SSepherosa Ziehau 			ring_cnt = HN_RING_CNT_DEF_MAX;
96815516c77SSepherosa Ziehau 	} else if (ring_cnt > mp_ncpus) {
96915516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
97015516c77SSepherosa Ziehau 	}
97115516c77SSepherosa Ziehau 
97215516c77SSepherosa Ziehau 	tx_ring_cnt = hn_tx_ring_cnt;
97315516c77SSepherosa Ziehau 	if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt)
97415516c77SSepherosa Ziehau 		tx_ring_cnt = ring_cnt;
97523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
97615516c77SSepherosa Ziehau 	if (hn_use_if_start) {
97715516c77SSepherosa Ziehau 		/* ifnet.if_start only needs one TX ring. */
97815516c77SSepherosa Ziehau 		tx_ring_cnt = 1;
97915516c77SSepherosa Ziehau 	}
98023bf9e15SSepherosa Ziehau #endif
98115516c77SSepherosa Ziehau 
98215516c77SSepherosa Ziehau 	/*
98315516c77SSepherosa Ziehau 	 * Set the leader CPU for channels.
98415516c77SSepherosa Ziehau 	 */
98515516c77SSepherosa Ziehau 	sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus;
98615516c77SSepherosa Ziehau 
98715516c77SSepherosa Ziehau 	/*
98815516c77SSepherosa Ziehau 	 * Create enough TX/RX rings, even if only limited number of
98915516c77SSepherosa Ziehau 	 * channels can be allocated.
99015516c77SSepherosa Ziehau 	 */
99115516c77SSepherosa Ziehau 	error = hn_create_tx_data(sc, tx_ring_cnt);
99215516c77SSepherosa Ziehau 	if (error)
99315516c77SSepherosa Ziehau 		goto failed;
99415516c77SSepherosa Ziehau 	error = hn_create_rx_data(sc, ring_cnt);
99515516c77SSepherosa Ziehau 	if (error)
99615516c77SSepherosa Ziehau 		goto failed;
99715516c77SSepherosa Ziehau 
99815516c77SSepherosa Ziehau 	/*
99915516c77SSepherosa Ziehau 	 * Create transaction context for NVS and RNDIS transactions.
100015516c77SSepherosa Ziehau 	 */
100115516c77SSepherosa Ziehau 	sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
100215516c77SSepherosa Ziehau 	    HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
100325641fc7SSepherosa Ziehau 	if (sc->hn_xact == NULL) {
100425641fc7SSepherosa Ziehau 		error = ENXIO;
100515516c77SSepherosa Ziehau 		goto failed;
100625641fc7SSepherosa Ziehau 	}
100725641fc7SSepherosa Ziehau 
100825641fc7SSepherosa Ziehau 	/*
100925641fc7SSepherosa Ziehau 	 * Install orphan handler for the revocation of this device's
101025641fc7SSepherosa Ziehau 	 * primary channel.
101125641fc7SSepherosa Ziehau 	 *
101225641fc7SSepherosa Ziehau 	 * NOTE:
101325641fc7SSepherosa Ziehau 	 * The processing order is critical here:
101425641fc7SSepherosa Ziehau 	 * Install the orphan handler, _before_ testing whether this
101525641fc7SSepherosa Ziehau 	 * device's primary channel has been revoked or not.
101625641fc7SSepherosa Ziehau 	 */
101725641fc7SSepherosa Ziehau 	vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact);
101825641fc7SSepherosa Ziehau 	if (vmbus_chan_is_revoked(sc->hn_prichan)) {
101925641fc7SSepherosa Ziehau 		error = ENXIO;
102025641fc7SSepherosa Ziehau 		goto failed;
102125641fc7SSepherosa Ziehau 	}
102215516c77SSepherosa Ziehau 
102315516c77SSepherosa Ziehau 	/*
102415516c77SSepherosa Ziehau 	 * Attach the synthetic parts, i.e. NVS and RNDIS.
102515516c77SSepherosa Ziehau 	 */
102615516c77SSepherosa Ziehau 	error = hn_synth_attach(sc, ETHERMTU);
102715516c77SSepherosa Ziehau 	if (error)
102815516c77SSepherosa Ziehau 		goto failed;
102915516c77SSepherosa Ziehau 
103015516c77SSepherosa Ziehau 	error = hn_rndis_get_eaddr(sc, eaddr);
103115516c77SSepherosa Ziehau 	if (error)
103215516c77SSepherosa Ziehau 		goto failed;
103315516c77SSepherosa Ziehau 
103415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
103515516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
103615516c77SSepherosa Ziehau 		/*
103715516c77SSepherosa Ziehau 		 * Reduce TCP segment aggregation limit for multiple
103815516c77SSepherosa Ziehau 		 * RX rings to increase ACK timeliness.
103915516c77SSepherosa Ziehau 		 */
104015516c77SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF);
104115516c77SSepherosa Ziehau 	}
104215516c77SSepherosa Ziehau #endif
104315516c77SSepherosa Ziehau 
104415516c77SSepherosa Ziehau 	/*
104515516c77SSepherosa Ziehau 	 * Fixup TX stuffs after synthetic parts are attached.
104615516c77SSepherosa Ziehau 	 */
104715516c77SSepherosa Ziehau 	hn_fixup_tx_data(sc);
104815516c77SSepherosa Ziehau 
104915516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
105015516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
105115516c77SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD,
105215516c77SSepherosa Ziehau 	    &sc->hn_nvs_ver, 0, "NVS version");
105315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version",
105415516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
105515516c77SSepherosa Ziehau 	    hn_ndis_version_sysctl, "A", "NDIS version");
105615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps",
105715516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
105815516c77SSepherosa Ziehau 	    hn_caps_sysctl, "A", "capabilities");
105915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist",
106015516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
106115516c77SSepherosa Ziehau 	    hn_hwassist_sysctl, "A", "hwassist");
106215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter",
106315516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
106415516c77SSepherosa Ziehau 	    hn_rxfilter_sysctl, "A", "rxfilter");
106515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash",
106615516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
106715516c77SSepherosa Ziehau 	    hn_rss_hash_sysctl, "A", "RSS hash");
106815516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size",
106915516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count");
107015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key",
107115516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
107215516c77SSepherosa Ziehau 	    hn_rss_key_sysctl, "IU", "RSS key");
107315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind",
107415516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
107515516c77SSepherosa Ziehau 	    hn_rss_ind_sysctl, "IU", "RSS indirect table");
1076dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size",
1077dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_size, 0,
1078dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation size limit");
1079dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts",
1080dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0,
1081dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation count limit");
1082dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align",
1083dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_align, 0,
1084dc13fee6SSepherosa Ziehau 	    "RNDIS packet transmission aggregation alignment");
1085dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size",
1086dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
1087dc13fee6SSepherosa Ziehau 	    hn_txagg_size_sysctl, "I",
1088dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation size, 0 -- disable, -1 -- auto");
1089dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts",
1090dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
1091dc13fee6SSepherosa Ziehau 	    hn_txagg_pkts_sysctl, "I",
1092dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation packets, "
1093dc13fee6SSepherosa Ziehau 	    "0 -- disable, -1 -- auto");
109415516c77SSepherosa Ziehau 
109515516c77SSepherosa Ziehau 	/*
109615516c77SSepherosa Ziehau 	 * Setup the ifmedia, which has been initialized earlier.
109715516c77SSepherosa Ziehau 	 */
109815516c77SSepherosa Ziehau 	ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL);
109915516c77SSepherosa Ziehau 	ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO);
110015516c77SSepherosa Ziehau 	/* XXX ifmedia_set really should do this for us */
110115516c77SSepherosa Ziehau 	sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media;
110215516c77SSepherosa Ziehau 
110315516c77SSepherosa Ziehau 	/*
110415516c77SSepherosa Ziehau 	 * Setup the ifnet for this interface.
110515516c77SSepherosa Ziehau 	 */
110615516c77SSepherosa Ziehau 
110715516c77SSepherosa Ziehau 	ifp->if_baudrate = IF_Gbps(10);
110815516c77SSepherosa Ziehau 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
110915516c77SSepherosa Ziehau 	ifp->if_ioctl = hn_ioctl;
111015516c77SSepherosa Ziehau 	ifp->if_init = hn_init;
111123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
111215516c77SSepherosa Ziehau 	if (hn_use_if_start) {
111315516c77SSepherosa Ziehau 		int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]);
111415516c77SSepherosa Ziehau 
111515516c77SSepherosa Ziehau 		ifp->if_start = hn_start;
111615516c77SSepherosa Ziehau 		IFQ_SET_MAXLEN(&ifp->if_snd, qdepth);
111715516c77SSepherosa Ziehau 		ifp->if_snd.ifq_drv_maxlen = qdepth - 1;
111815516c77SSepherosa Ziehau 		IFQ_SET_READY(&ifp->if_snd);
111923bf9e15SSepherosa Ziehau 	} else
112023bf9e15SSepherosa Ziehau #endif
112123bf9e15SSepherosa Ziehau 	{
112215516c77SSepherosa Ziehau 		ifp->if_transmit = hn_transmit;
112315516c77SSepherosa Ziehau 		ifp->if_qflush = hn_xmit_qflush;
112415516c77SSepherosa Ziehau 	}
112515516c77SSepherosa Ziehau 
112615516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO;
112715516c77SSepherosa Ziehau #ifdef foo
112815516c77SSepherosa Ziehau 	/* We can't diff IPv6 packets from IPv4 packets on RX path. */
112915516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM_IPV6;
113015516c77SSepherosa Ziehau #endif
113115516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_VLAN) {
113215516c77SSepherosa Ziehau 		/* XXX not sure about VLAN_MTU. */
113315516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
113415516c77SSepherosa Ziehau 	}
113515516c77SSepherosa Ziehau 
113615516c77SSepherosa Ziehau 	ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist;
113715516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP_MASK)
113815516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM;
113915516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP6_MASK)
114015516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM_IPV6;
114115516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO4) {
114215516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO4;
114315516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP_TSO;
114415516c77SSepherosa Ziehau 	}
114515516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO6) {
114615516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO6;
114715516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP6_TSO;
114815516c77SSepherosa Ziehau 	}
114915516c77SSepherosa Ziehau 
115015516c77SSepherosa Ziehau 	/* Enable all available capabilities by default. */
115115516c77SSepherosa Ziehau 	ifp->if_capenable = ifp->if_capabilities;
115215516c77SSepherosa Ziehau 
11537960e6baSSepherosa Ziehau 	/*
11547960e6baSSepherosa Ziehau 	 * Disable IPv6 TSO and TXCSUM by default, they still can
11557960e6baSSepherosa Ziehau 	 * be enabled through SIOCSIFCAP.
11567960e6baSSepherosa Ziehau 	 */
11577960e6baSSepherosa Ziehau 	ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
11587960e6baSSepherosa Ziehau 	ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO);
11597960e6baSSepherosa Ziehau 
116015516c77SSepherosa Ziehau 	if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) {
116115516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU);
116215516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX;
116315516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = PAGE_SIZE;
116415516c77SSepherosa Ziehau 	}
116515516c77SSepherosa Ziehau 
116615516c77SSepherosa Ziehau 	ether_ifattach(ifp, eaddr);
116715516c77SSepherosa Ziehau 
116815516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) {
116915516c77SSepherosa Ziehau 		if_printf(ifp, "TSO segcnt %u segsz %u\n",
117015516c77SSepherosa Ziehau 		    ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize);
117115516c77SSepherosa Ziehau 	}
117215516c77SSepherosa Ziehau 
117315516c77SSepherosa Ziehau 	/* Inform the upper layer about the long frame support. */
117415516c77SSepherosa Ziehau 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
117515516c77SSepherosa Ziehau 
117615516c77SSepherosa Ziehau 	/*
117715516c77SSepherosa Ziehau 	 * Kick off link status check.
117815516c77SSepherosa Ziehau 	 */
117915516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
118015516c77SSepherosa Ziehau 	hn_update_link_status(sc);
118115516c77SSepherosa Ziehau 
118215516c77SSepherosa Ziehau 	return (0);
118315516c77SSepherosa Ziehau failed:
118415516c77SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)
118515516c77SSepherosa Ziehau 		hn_synth_detach(sc);
118615516c77SSepherosa Ziehau 	hn_detach(dev);
118715516c77SSepherosa Ziehau 	return (error);
118815516c77SSepherosa Ziehau }
118915516c77SSepherosa Ziehau 
119015516c77SSepherosa Ziehau static int
119115516c77SSepherosa Ziehau hn_detach(device_t dev)
119215516c77SSepherosa Ziehau {
119315516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
119415516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
119515516c77SSepherosa Ziehau 
119625641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) {
119725641fc7SSepherosa Ziehau 		/*
119825641fc7SSepherosa Ziehau 		 * In case that the vmbus missed the orphan handler
119925641fc7SSepherosa Ziehau 		 * installation.
120025641fc7SSepherosa Ziehau 		 */
120125641fc7SSepherosa Ziehau 		vmbus_xact_ctx_orphan(sc->hn_xact);
120225641fc7SSepherosa Ziehau 	}
120325641fc7SSepherosa Ziehau 
120415516c77SSepherosa Ziehau 	if (device_is_attached(dev)) {
120515516c77SSepherosa Ziehau 		HN_LOCK(sc);
120615516c77SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
120715516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
120815516c77SSepherosa Ziehau 				hn_stop(sc);
120915516c77SSepherosa Ziehau 			/*
121015516c77SSepherosa Ziehau 			 * NOTE:
121115516c77SSepherosa Ziehau 			 * hn_stop() only suspends data, so managment
121215516c77SSepherosa Ziehau 			 * stuffs have to be suspended manually here.
121315516c77SSepherosa Ziehau 			 */
121415516c77SSepherosa Ziehau 			hn_suspend_mgmt(sc);
121515516c77SSepherosa Ziehau 			hn_synth_detach(sc);
121615516c77SSepherosa Ziehau 		}
121715516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
121815516c77SSepherosa Ziehau 		ether_ifdetach(ifp);
121915516c77SSepherosa Ziehau 	}
122015516c77SSepherosa Ziehau 
122115516c77SSepherosa Ziehau 	ifmedia_removeall(&sc->hn_media);
122215516c77SSepherosa Ziehau 	hn_destroy_rx_data(sc);
122315516c77SSepherosa Ziehau 	hn_destroy_tx_data(sc);
122415516c77SSepherosa Ziehau 
1225*0e11868dSSepherosa Ziehau 	if (sc->hn_tx_taskqs != NULL && sc->hn_tx_taskqs != hn_tx_taskque) {
1226fdd0222aSSepherosa Ziehau 		int i;
1227fdd0222aSSepherosa Ziehau 
1228fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
1229fdd0222aSSepherosa Ziehau 			taskqueue_free(sc->hn_tx_taskqs[i]);
1230fdd0222aSSepherosa Ziehau 		free(sc->hn_tx_taskqs, M_DEVBUF);
1231fdd0222aSSepherosa Ziehau 	}
123215516c77SSepherosa Ziehau 	taskqueue_free(sc->hn_mgmt_taskq0);
123315516c77SSepherosa Ziehau 
123425641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL) {
123525641fc7SSepherosa Ziehau 		/*
123625641fc7SSepherosa Ziehau 		 * Uninstall the orphan handler _before_ the xact is
123725641fc7SSepherosa Ziehau 		 * destructed.
123825641fc7SSepherosa Ziehau 		 */
123925641fc7SSepherosa Ziehau 		vmbus_chan_unset_orphan(sc->hn_prichan);
124015516c77SSepherosa Ziehau 		vmbus_xact_ctx_destroy(sc->hn_xact);
124125641fc7SSepherosa Ziehau 	}
124215516c77SSepherosa Ziehau 
124315516c77SSepherosa Ziehau 	if_free(ifp);
124415516c77SSepherosa Ziehau 
124515516c77SSepherosa Ziehau 	HN_LOCK_DESTROY(sc);
124615516c77SSepherosa Ziehau 	return (0);
124715516c77SSepherosa Ziehau }
124815516c77SSepherosa Ziehau 
124915516c77SSepherosa Ziehau static int
125015516c77SSepherosa Ziehau hn_shutdown(device_t dev)
125115516c77SSepherosa Ziehau {
125215516c77SSepherosa Ziehau 
125315516c77SSepherosa Ziehau 	return (0);
125415516c77SSepherosa Ziehau }
125515516c77SSepherosa Ziehau 
125615516c77SSepherosa Ziehau static void
125715516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc)
125815516c77SSepherosa Ziehau {
125915516c77SSepherosa Ziehau 	uint32_t link_status;
126015516c77SSepherosa Ziehau 	int error;
126115516c77SSepherosa Ziehau 
126215516c77SSepherosa Ziehau 	error = hn_rndis_get_linkstatus(sc, &link_status);
126315516c77SSepherosa Ziehau 	if (error) {
126415516c77SSepherosa Ziehau 		/* XXX what to do? */
126515516c77SSepherosa Ziehau 		return;
126615516c77SSepherosa Ziehau 	}
126715516c77SSepherosa Ziehau 
126815516c77SSepherosa Ziehau 	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
126915516c77SSepherosa Ziehau 		sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
127015516c77SSepherosa Ziehau 	else
127115516c77SSepherosa Ziehau 		sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
127215516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp,
127315516c77SSepherosa Ziehau 	    (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ?
127415516c77SSepherosa Ziehau 	    LINK_STATE_UP : LINK_STATE_DOWN);
127515516c77SSepherosa Ziehau }
127615516c77SSepherosa Ziehau 
127715516c77SSepherosa Ziehau static void
127815516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused)
127915516c77SSepherosa Ziehau {
128015516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
128115516c77SSepherosa Ziehau 
128215516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
128315516c77SSepherosa Ziehau 		return;
128415516c77SSepherosa Ziehau 	hn_link_status(sc);
128515516c77SSepherosa Ziehau }
128615516c77SSepherosa Ziehau 
128715516c77SSepherosa Ziehau static void
128815516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused)
128915516c77SSepherosa Ziehau {
129015516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
129115516c77SSepherosa Ziehau 
129215516c77SSepherosa Ziehau 	/* Prevent any link status checks from running. */
129315516c77SSepherosa Ziehau 	sc->hn_link_flags |= HN_LINK_FLAG_NETCHG;
129415516c77SSepherosa Ziehau 
129515516c77SSepherosa Ziehau 	/*
129615516c77SSepherosa Ziehau 	 * Fake up a [link down --> link up] state change; 5 seconds
129715516c77SSepherosa Ziehau 	 * delay is used, which closely simulates miibus reaction
129815516c77SSepherosa Ziehau 	 * upon link down event.
129915516c77SSepherosa Ziehau 	 */
130015516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
130115516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
130215516c77SSepherosa Ziehau 	taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0,
130315516c77SSepherosa Ziehau 	    &sc->hn_netchg_status, 5 * hz);
130415516c77SSepherosa Ziehau }
130515516c77SSepherosa Ziehau 
130615516c77SSepherosa Ziehau static void
130715516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused)
130815516c77SSepherosa Ziehau {
130915516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
131015516c77SSepherosa Ziehau 
131115516c77SSepherosa Ziehau 	/* Re-allow link status checks. */
131215516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG;
131315516c77SSepherosa Ziehau 	hn_link_status(sc);
131415516c77SSepherosa Ziehau }
131515516c77SSepherosa Ziehau 
131615516c77SSepherosa Ziehau static void
131715516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc)
131815516c77SSepherosa Ziehau {
131915516c77SSepherosa Ziehau 
132015516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
132115516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
132215516c77SSepherosa Ziehau }
132315516c77SSepherosa Ziehau 
132415516c77SSepherosa Ziehau static void
132515516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc)
132615516c77SSepherosa Ziehau {
132715516c77SSepherosa Ziehau 
132815516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
132915516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init);
133015516c77SSepherosa Ziehau }
133115516c77SSepherosa Ziehau 
133215516c77SSepherosa Ziehau static __inline int
133315516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
133415516c77SSepherosa Ziehau     struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
133515516c77SSepherosa Ziehau {
133615516c77SSepherosa Ziehau 	struct mbuf *m = *m_head;
133715516c77SSepherosa Ziehau 	int error;
133815516c77SSepherosa Ziehau 
133915516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim"));
134015516c77SSepherosa Ziehau 
134115516c77SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap,
134215516c77SSepherosa Ziehau 	    m, segs, nsegs, BUS_DMA_NOWAIT);
134315516c77SSepherosa Ziehau 	if (error == EFBIG) {
134415516c77SSepherosa Ziehau 		struct mbuf *m_new;
134515516c77SSepherosa Ziehau 
134615516c77SSepherosa Ziehau 		m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX);
134715516c77SSepherosa Ziehau 		if (m_new == NULL)
134815516c77SSepherosa Ziehau 			return ENOBUFS;
134915516c77SSepherosa Ziehau 		else
135015516c77SSepherosa Ziehau 			*m_head = m = m_new;
135115516c77SSepherosa Ziehau 		txr->hn_tx_collapsed++;
135215516c77SSepherosa Ziehau 
135315516c77SSepherosa Ziehau 		error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag,
135415516c77SSepherosa Ziehau 		    txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT);
135515516c77SSepherosa Ziehau 	}
135615516c77SSepherosa Ziehau 	if (!error) {
135715516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap,
135815516c77SSepherosa Ziehau 		    BUS_DMASYNC_PREWRITE);
135915516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_DMAMAP;
136015516c77SSepherosa Ziehau 	}
136115516c77SSepherosa Ziehau 	return error;
136215516c77SSepherosa Ziehau }
136315516c77SSepherosa Ziehau 
136415516c77SSepherosa Ziehau static __inline int
136515516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd)
136615516c77SSepherosa Ziehau {
136715516c77SSepherosa Ziehau 
136815516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0,
136915516c77SSepherosa Ziehau 	    ("put an onlist txd %#x", txd->flags));
1370dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1371dc13fee6SSepherosa Ziehau 	    ("put an onagg txd %#x", txd->flags));
137215516c77SSepherosa Ziehau 
137315516c77SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
137415516c77SSepherosa Ziehau 	if (atomic_fetchadd_int(&txd->refs, -1) != 1)
137515516c77SSepherosa Ziehau 		return 0;
137615516c77SSepherosa Ziehau 
1377dc13fee6SSepherosa Ziehau 	if (!STAILQ_EMPTY(&txd->agg_list)) {
1378dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tmp_txd;
1379dc13fee6SSepherosa Ziehau 
1380dc13fee6SSepherosa Ziehau 		while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) {
1381dc13fee6SSepherosa Ziehau 			int freed;
1382dc13fee6SSepherosa Ziehau 
1383dc13fee6SSepherosa Ziehau 			KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list),
1384dc13fee6SSepherosa Ziehau 			    ("resursive aggregation on aggregated txdesc"));
1385dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG),
1386dc13fee6SSepherosa Ziehau 			    ("not aggregated txdesc"));
1387dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
1388dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc uses dmamap"));
1389dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
1390dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc consumes "
1391dc13fee6SSepherosa Ziehau 			     "chimney sending buffer"));
1392dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_size == 0,
1393dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc has non-zero "
1394dc13fee6SSepherosa Ziehau 			     "chimney sending size"));
1395dc13fee6SSepherosa Ziehau 
1396dc13fee6SSepherosa Ziehau 			STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link);
1397dc13fee6SSepherosa Ziehau 			tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG;
1398dc13fee6SSepherosa Ziehau 			freed = hn_txdesc_put(txr, tmp_txd);
1399dc13fee6SSepherosa Ziehau 			KASSERT(freed, ("failed to free aggregated txdesc"));
1400dc13fee6SSepherosa Ziehau 		}
1401dc13fee6SSepherosa Ziehau 	}
1402dc13fee6SSepherosa Ziehau 
140315516c77SSepherosa Ziehau 	if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) {
140415516c77SSepherosa Ziehau 		KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
140515516c77SSepherosa Ziehau 		    ("chim txd uses dmamap"));
140615516c77SSepherosa Ziehau 		hn_chim_free(txr->hn_sc, txd->chim_index);
140715516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
1408dc13fee6SSepherosa Ziehau 		txd->chim_size = 0;
140915516c77SSepherosa Ziehau 	} else if (txd->flags & HN_TXD_FLAG_DMAMAP) {
141015516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag,
141115516c77SSepherosa Ziehau 		    txd->data_dmap, BUS_DMASYNC_POSTWRITE);
141215516c77SSepherosa Ziehau 		bus_dmamap_unload(txr->hn_tx_data_dtag,
141315516c77SSepherosa Ziehau 		    txd->data_dmap);
141415516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_DMAMAP;
141515516c77SSepherosa Ziehau 	}
141615516c77SSepherosa Ziehau 
141715516c77SSepherosa Ziehau 	if (txd->m != NULL) {
141815516c77SSepherosa Ziehau 		m_freem(txd->m);
141915516c77SSepherosa Ziehau 		txd->m = NULL;
142015516c77SSepherosa Ziehau 	}
142115516c77SSepherosa Ziehau 
142215516c77SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONLIST;
142315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
142415516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
142515516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_avail >= 0 &&
142615516c77SSepherosa Ziehau 	    txr->hn_txdesc_avail < txr->hn_txdesc_cnt,
142715516c77SSepherosa Ziehau 	    ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail));
142815516c77SSepherosa Ziehau 	txr->hn_txdesc_avail++;
142915516c77SSepherosa Ziehau 	SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
143015516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
143115516c77SSepherosa Ziehau #else
143215516c77SSepherosa Ziehau 	atomic_add_int(&txr->hn_txdesc_avail, 1);
143315516c77SSepherosa Ziehau 	buf_ring_enqueue(txr->hn_txdesc_br, txd);
143415516c77SSepherosa Ziehau #endif
143515516c77SSepherosa Ziehau 
143615516c77SSepherosa Ziehau 	return 1;
143715516c77SSepherosa Ziehau }
143815516c77SSepherosa Ziehau 
143915516c77SSepherosa Ziehau static __inline struct hn_txdesc *
144015516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr)
144115516c77SSepherosa Ziehau {
144215516c77SSepherosa Ziehau 	struct hn_txdesc *txd;
144315516c77SSepherosa Ziehau 
144415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
144515516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
144615516c77SSepherosa Ziehau 	txd = SLIST_FIRST(&txr->hn_txlist);
144715516c77SSepherosa Ziehau 	if (txd != NULL) {
144815516c77SSepherosa Ziehau 		KASSERT(txr->hn_txdesc_avail > 0,
144915516c77SSepherosa Ziehau 		    ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail));
145015516c77SSepherosa Ziehau 		txr->hn_txdesc_avail--;
145115516c77SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&txr->hn_txlist, link);
145215516c77SSepherosa Ziehau 	}
145315516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
145415516c77SSepherosa Ziehau #else
145515516c77SSepherosa Ziehau 	txd = buf_ring_dequeue_sc(txr->hn_txdesc_br);
145615516c77SSepherosa Ziehau #endif
145715516c77SSepherosa Ziehau 
145815516c77SSepherosa Ziehau 	if (txd != NULL) {
145915516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
146015516c77SSepherosa Ziehau 		atomic_subtract_int(&txr->hn_txdesc_avail, 1);
146115516c77SSepherosa Ziehau #endif
146215516c77SSepherosa Ziehau 		KASSERT(txd->m == NULL && txd->refs == 0 &&
1463dc13fee6SSepherosa Ziehau 		    STAILQ_EMPTY(&txd->agg_list) &&
146415516c77SSepherosa Ziehau 		    txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
1465dc13fee6SSepherosa Ziehau 		    txd->chim_size == 0 &&
146615516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONLIST) &&
1467dc13fee6SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONAGG) == 0 &&
146815516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd"));
146915516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_ONLIST;
147015516c77SSepherosa Ziehau 		txd->refs = 1;
147115516c77SSepherosa Ziehau 	}
147215516c77SSepherosa Ziehau 	return txd;
147315516c77SSepherosa Ziehau }
147415516c77SSepherosa Ziehau 
147515516c77SSepherosa Ziehau static __inline void
147615516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd)
147715516c77SSepherosa Ziehau {
147815516c77SSepherosa Ziehau 
147915516c77SSepherosa Ziehau 	/* 0->1 transition will never work */
148025641fc7SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
148115516c77SSepherosa Ziehau 	atomic_add_int(&txd->refs, 1);
148215516c77SSepherosa Ziehau }
148315516c77SSepherosa Ziehau 
1484dc13fee6SSepherosa Ziehau static __inline void
1485dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd)
1486dc13fee6SSepherosa Ziehau {
1487dc13fee6SSepherosa Ziehau 
1488dc13fee6SSepherosa Ziehau 	KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1489dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on aggregating txdesc"));
1490dc13fee6SSepherosa Ziehau 
1491dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1492dc13fee6SSepherosa Ziehau 	    ("already aggregated"));
1493dc13fee6SSepherosa Ziehau 	KASSERT(STAILQ_EMPTY(&txd->agg_list),
1494dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on to-be-aggregated txdesc"));
1495dc13fee6SSepherosa Ziehau 
1496dc13fee6SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONAGG;
1497dc13fee6SSepherosa Ziehau 	STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link);
1498dc13fee6SSepherosa Ziehau }
1499dc13fee6SSepherosa Ziehau 
150015516c77SSepherosa Ziehau static bool
150115516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr)
150215516c77SSepherosa Ziehau {
150315516c77SSepherosa Ziehau 	bool pending = false;
150415516c77SSepherosa Ziehau 
150515516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
150615516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
150715516c77SSepherosa Ziehau 	if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt)
150815516c77SSepherosa Ziehau 		pending = true;
150915516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
151015516c77SSepherosa Ziehau #else
151115516c77SSepherosa Ziehau 	if (!buf_ring_full(txr->hn_txdesc_br))
151215516c77SSepherosa Ziehau 		pending = true;
151315516c77SSepherosa Ziehau #endif
151415516c77SSepherosa Ziehau 	return (pending);
151515516c77SSepherosa Ziehau }
151615516c77SSepherosa Ziehau 
151715516c77SSepherosa Ziehau static __inline void
151815516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr)
151915516c77SSepherosa Ziehau {
152015516c77SSepherosa Ziehau 	txr->hn_has_txeof = 0;
152115516c77SSepherosa Ziehau 	txr->hn_txeof(txr);
152215516c77SSepherosa Ziehau }
152315516c77SSepherosa Ziehau 
152415516c77SSepherosa Ziehau static void
152515516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc,
152615516c77SSepherosa Ziehau     struct vmbus_channel *chan, const void *data __unused, int dlen __unused)
152715516c77SSepherosa Ziehau {
152815516c77SSepherosa Ziehau 	struct hn_txdesc *txd = sndc->hn_cbarg;
152915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
153015516c77SSepherosa Ziehau 
153115516c77SSepherosa Ziehau 	txr = txd->txr;
153215516c77SSepherosa Ziehau 	KASSERT(txr->hn_chan == chan,
153315516c77SSepherosa Ziehau 	    ("channel mismatch, on chan%u, should be chan%u",
1534aa1a2adcSSepherosa Ziehau 	     vmbus_chan_id(chan), vmbus_chan_id(txr->hn_chan)));
153515516c77SSepherosa Ziehau 
153615516c77SSepherosa Ziehau 	txr->hn_has_txeof = 1;
153715516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
153815516c77SSepherosa Ziehau 
153915516c77SSepherosa Ziehau 	++txr->hn_txdone_cnt;
154015516c77SSepherosa Ziehau 	if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) {
154115516c77SSepherosa Ziehau 		txr->hn_txdone_cnt = 0;
154215516c77SSepherosa Ziehau 		if (txr->hn_oactive)
154315516c77SSepherosa Ziehau 			hn_txeof(txr);
154415516c77SSepherosa Ziehau 	}
154515516c77SSepherosa Ziehau }
154615516c77SSepherosa Ziehau 
154715516c77SSepherosa Ziehau static void
154815516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
154915516c77SSepherosa Ziehau {
155015516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
155115516c77SSepherosa Ziehau 	tcp_lro_flush_all(&rxr->hn_lro);
155215516c77SSepherosa Ziehau #endif
155315516c77SSepherosa Ziehau 
155415516c77SSepherosa Ziehau 	/*
155515516c77SSepherosa Ziehau 	 * NOTE:
155615516c77SSepherosa Ziehau 	 * 'txr' could be NULL, if multiple channels and
155715516c77SSepherosa Ziehau 	 * ifnet.if_start method are enabled.
155815516c77SSepherosa Ziehau 	 */
155915516c77SSepherosa Ziehau 	if (txr == NULL || !txr->hn_has_txeof)
156015516c77SSepherosa Ziehau 		return;
156115516c77SSepherosa Ziehau 
156215516c77SSepherosa Ziehau 	txr->hn_txdone_cnt = 0;
156315516c77SSepherosa Ziehau 	hn_txeof(txr);
156415516c77SSepherosa Ziehau }
156515516c77SSepherosa Ziehau 
156615516c77SSepherosa Ziehau static __inline uint32_t
156715516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs)
156815516c77SSepherosa Ziehau {
156915516c77SSepherosa Ziehau 
157015516c77SSepherosa Ziehau 	KASSERT(ofs >= sizeof(struct rndis_packet_msg),
157115516c77SSepherosa Ziehau 	    ("invalid RNDIS packet msg offset %u", ofs));
157215516c77SSepherosa Ziehau 	return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset));
157315516c77SSepherosa Ziehau }
157415516c77SSepherosa Ziehau 
157515516c77SSepherosa Ziehau static __inline void *
157615516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
157715516c77SSepherosa Ziehau     size_t pi_dlen, uint32_t pi_type)
157815516c77SSepherosa Ziehau {
157915516c77SSepherosa Ziehau 	const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
158015516c77SSepherosa Ziehau 	struct rndis_pktinfo *pi;
158115516c77SSepherosa Ziehau 
158215516c77SSepherosa Ziehau 	KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
158315516c77SSepherosa Ziehau 	    ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
158415516c77SSepherosa Ziehau 
158515516c77SSepherosa Ziehau 	/*
158615516c77SSepherosa Ziehau 	 * Per-packet-info does not move; it only grows.
158715516c77SSepherosa Ziehau 	 *
158815516c77SSepherosa Ziehau 	 * NOTE:
158915516c77SSepherosa Ziehau 	 * rm_pktinfooffset in this phase counts from the beginning
159015516c77SSepherosa Ziehau 	 * of rndis_packet_msg.
159115516c77SSepherosa Ziehau 	 */
159215516c77SSepherosa Ziehau 	KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
159315516c77SSepherosa Ziehau 	    ("%u pktinfo overflows RNDIS packet msg", pi_type));
159415516c77SSepherosa Ziehau 	pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
159515516c77SSepherosa Ziehau 	    pkt->rm_pktinfolen);
159615516c77SSepherosa Ziehau 	pkt->rm_pktinfolen += pi_size;
159715516c77SSepherosa Ziehau 
159815516c77SSepherosa Ziehau 	pi->rm_size = pi_size;
159915516c77SSepherosa Ziehau 	pi->rm_type = pi_type;
160015516c77SSepherosa Ziehau 	pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
160115516c77SSepherosa Ziehau 
160215516c77SSepherosa Ziehau 	/* Data immediately follow per-packet-info. */
160315516c77SSepherosa Ziehau 	pkt->rm_dataoffset += pi_size;
160415516c77SSepherosa Ziehau 
160515516c77SSepherosa Ziehau 	/* Update RNDIS packet msg length */
160615516c77SSepherosa Ziehau 	pkt->rm_len += pi_size;
160715516c77SSepherosa Ziehau 
160815516c77SSepherosa Ziehau 	return (pi->rm_data);
160915516c77SSepherosa Ziehau }
161015516c77SSepherosa Ziehau 
1611dc13fee6SSepherosa Ziehau static __inline int
1612dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr)
1613dc13fee6SSepherosa Ziehau {
1614dc13fee6SSepherosa Ziehau 	struct hn_txdesc *txd;
1615dc13fee6SSepherosa Ziehau 	struct mbuf *m;
1616dc13fee6SSepherosa Ziehau 	int error, pkts;
1617dc13fee6SSepherosa Ziehau 
1618dc13fee6SSepherosa Ziehau 	txd = txr->hn_agg_txd;
1619dc13fee6SSepherosa Ziehau 	KASSERT(txd != NULL, ("no aggregate txdesc"));
1620dc13fee6SSepherosa Ziehau 
1621dc13fee6SSepherosa Ziehau 	/*
1622dc13fee6SSepherosa Ziehau 	 * Since hn_txpkt() will reset this temporary stat, save
1623dc13fee6SSepherosa Ziehau 	 * it now, so that oerrors can be updated properly, if
1624dc13fee6SSepherosa Ziehau 	 * hn_txpkt() ever fails.
1625dc13fee6SSepherosa Ziehau 	 */
1626dc13fee6SSepherosa Ziehau 	pkts = txr->hn_stat_pkts;
1627dc13fee6SSepherosa Ziehau 
1628dc13fee6SSepherosa Ziehau 	/*
1629dc13fee6SSepherosa Ziehau 	 * Since txd's mbuf will _not_ be freed upon hn_txpkt()
1630dc13fee6SSepherosa Ziehau 	 * failure, save it for later freeing, if hn_txpkt() ever
1631dc13fee6SSepherosa Ziehau 	 * fails.
1632dc13fee6SSepherosa Ziehau 	 */
1633dc13fee6SSepherosa Ziehau 	m = txd->m;
1634dc13fee6SSepherosa Ziehau 	error = hn_txpkt(ifp, txr, txd);
1635dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
1636dc13fee6SSepherosa Ziehau 		/* txd is freed, but m is not. */
1637dc13fee6SSepherosa Ziehau 		m_freem(m);
1638dc13fee6SSepherosa Ziehau 
1639dc13fee6SSepherosa Ziehau 		txr->hn_flush_failed++;
1640dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts);
1641dc13fee6SSepherosa Ziehau 	}
1642dc13fee6SSepherosa Ziehau 
1643dc13fee6SSepherosa Ziehau 	/* Reset all aggregation states. */
1644dc13fee6SSepherosa Ziehau 	txr->hn_agg_txd = NULL;
1645dc13fee6SSepherosa Ziehau 	txr->hn_agg_szleft = 0;
1646dc13fee6SSepherosa Ziehau 	txr->hn_agg_pktleft = 0;
1647dc13fee6SSepherosa Ziehau 	txr->hn_agg_prevpkt = NULL;
1648dc13fee6SSepherosa Ziehau 
1649dc13fee6SSepherosa Ziehau 	return (error);
1650dc13fee6SSepherosa Ziehau }
1651dc13fee6SSepherosa Ziehau 
1652dc13fee6SSepherosa Ziehau static void *
1653dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
1654dc13fee6SSepherosa Ziehau     int pktsize)
1655dc13fee6SSepherosa Ziehau {
1656dc13fee6SSepherosa Ziehau 	void *chim;
1657dc13fee6SSepherosa Ziehau 
1658dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL) {
1659dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) {
1660dc13fee6SSepherosa Ziehau 			struct hn_txdesc *agg_txd = txr->hn_agg_txd;
1661dc13fee6SSepherosa Ziehau 			struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt;
1662dc13fee6SSepherosa Ziehau 			int olen;
1663dc13fee6SSepherosa Ziehau 
1664dc13fee6SSepherosa Ziehau 			/*
1665dc13fee6SSepherosa Ziehau 			 * Update the previous RNDIS packet's total length,
1666dc13fee6SSepherosa Ziehau 			 * it can be increased due to the mandatory alignment
1667dc13fee6SSepherosa Ziehau 			 * padding for this RNDIS packet.  And update the
1668dc13fee6SSepherosa Ziehau 			 * aggregating txdesc's chimney sending buffer size
1669dc13fee6SSepherosa Ziehau 			 * accordingly.
1670dc13fee6SSepherosa Ziehau 			 *
1671dc13fee6SSepherosa Ziehau 			 * XXX
1672dc13fee6SSepherosa Ziehau 			 * Zero-out the padding, as required by the RNDIS spec.
1673dc13fee6SSepherosa Ziehau 			 */
1674dc13fee6SSepherosa Ziehau 			olen = pkt->rm_len;
1675dc13fee6SSepherosa Ziehau 			pkt->rm_len = roundup2(olen, txr->hn_agg_align);
1676dc13fee6SSepherosa Ziehau 			agg_txd->chim_size += pkt->rm_len - olen;
1677dc13fee6SSepherosa Ziehau 
1678dc13fee6SSepherosa Ziehau 			/* Link this txdesc to the parent. */
1679dc13fee6SSepherosa Ziehau 			hn_txdesc_agg(agg_txd, txd);
1680dc13fee6SSepherosa Ziehau 
1681dc13fee6SSepherosa Ziehau 			chim = (uint8_t *)pkt + pkt->rm_len;
1682dc13fee6SSepherosa Ziehau 			/* Save the current packet for later fixup. */
1683dc13fee6SSepherosa Ziehau 			txr->hn_agg_prevpkt = chim;
1684dc13fee6SSepherosa Ziehau 
1685dc13fee6SSepherosa Ziehau 			txr->hn_agg_pktleft--;
1686dc13fee6SSepherosa Ziehau 			txr->hn_agg_szleft -= pktsize;
1687dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_szleft <=
1688dc13fee6SSepherosa Ziehau 			    HN_PKTSIZE_MIN(txr->hn_agg_align)) {
1689dc13fee6SSepherosa Ziehau 				/*
1690dc13fee6SSepherosa Ziehau 				 * Probably can't aggregate more packets,
1691dc13fee6SSepherosa Ziehau 				 * flush this aggregating txdesc proactively.
1692dc13fee6SSepherosa Ziehau 				 */
1693dc13fee6SSepherosa Ziehau 				txr->hn_agg_pktleft = 0;
1694dc13fee6SSepherosa Ziehau 			}
1695dc13fee6SSepherosa Ziehau 			/* Done! */
1696dc13fee6SSepherosa Ziehau 			return (chim);
1697dc13fee6SSepherosa Ziehau 		}
1698dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
1699dc13fee6SSepherosa Ziehau 	}
1700dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
1701dc13fee6SSepherosa Ziehau 
1702dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney_tried++;
1703dc13fee6SSepherosa Ziehau 	txd->chim_index = hn_chim_alloc(txr->hn_sc);
1704dc13fee6SSepherosa Ziehau 	if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID)
1705dc13fee6SSepherosa Ziehau 		return (NULL);
1706dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney++;
1707dc13fee6SSepherosa Ziehau 
1708dc13fee6SSepherosa Ziehau 	chim = txr->hn_sc->hn_chim +
1709dc13fee6SSepherosa Ziehau 	    (txd->chim_index * txr->hn_sc->hn_chim_szmax);
1710dc13fee6SSepherosa Ziehau 
1711dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_pktmax > 1 &&
1712dc13fee6SSepherosa Ziehau 	    txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) {
1713dc13fee6SSepherosa Ziehau 		txr->hn_agg_txd = txd;
1714dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1;
1715dc13fee6SSepherosa Ziehau 		txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize;
1716dc13fee6SSepherosa Ziehau 		txr->hn_agg_prevpkt = chim;
1717dc13fee6SSepherosa Ziehau 	}
1718dc13fee6SSepherosa Ziehau 	return (chim);
1719dc13fee6SSepherosa Ziehau }
1720dc13fee6SSepherosa Ziehau 
172115516c77SSepherosa Ziehau /*
172215516c77SSepherosa Ziehau  * NOTE:
172315516c77SSepherosa Ziehau  * If this function fails, then both txd and m_head0 will be freed.
172415516c77SSepherosa Ziehau  */
172515516c77SSepherosa Ziehau static int
1726dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
1727dc13fee6SSepherosa Ziehau     struct mbuf **m_head0)
172815516c77SSepherosa Ziehau {
172915516c77SSepherosa Ziehau 	bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX];
173015516c77SSepherosa Ziehau 	int error, nsegs, i;
173115516c77SSepherosa Ziehau 	struct mbuf *m_head = *m_head0;
173215516c77SSepherosa Ziehau 	struct rndis_packet_msg *pkt;
173315516c77SSepherosa Ziehau 	uint32_t *pi_data;
17348966e5d5SSepherosa Ziehau 	void *chim = NULL;
1735dc13fee6SSepherosa Ziehau 	int pkt_hlen, pkt_size;
173615516c77SSepherosa Ziehau 
173715516c77SSepherosa Ziehau 	pkt = txd->rndis_pkt;
1738dc13fee6SSepherosa Ziehau 	pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align);
1739dc13fee6SSepherosa Ziehau 	if (pkt_size < txr->hn_chim_size) {
1740dc13fee6SSepherosa Ziehau 		chim = hn_try_txagg(ifp, txr, txd, pkt_size);
1741dc13fee6SSepherosa Ziehau 		if (chim != NULL)
17428966e5d5SSepherosa Ziehau 			pkt = chim;
1743dc13fee6SSepherosa Ziehau 	} else {
1744dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL)
1745dc13fee6SSepherosa Ziehau 			hn_flush_txagg(ifp, txr);
17468966e5d5SSepherosa Ziehau 	}
17478966e5d5SSepherosa Ziehau 
174815516c77SSepherosa Ziehau 	pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
174915516c77SSepherosa Ziehau 	pkt->rm_len = sizeof(*pkt) + m_head->m_pkthdr.len;
175015516c77SSepherosa Ziehau 	pkt->rm_dataoffset = sizeof(*pkt);
175115516c77SSepherosa Ziehau 	pkt->rm_datalen = m_head->m_pkthdr.len;
1752dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataoffset = 0;
1753dc13fee6SSepherosa Ziehau 	pkt->rm_oobdatalen = 0;
1754dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataelements = 0;
175515516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = sizeof(*pkt);
175615516c77SSepherosa Ziehau 	pkt->rm_pktinfolen = 0;
1757dc13fee6SSepherosa Ziehau 	pkt->rm_vchandle = 0;
1758dc13fee6SSepherosa Ziehau 	pkt->rm_reserved = 0;
175915516c77SSepherosa Ziehau 
176015516c77SSepherosa Ziehau 	if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) {
176115516c77SSepherosa Ziehau 		/*
176215516c77SSepherosa Ziehau 		 * Set the hash value for this packet, so that the host could
176315516c77SSepherosa Ziehau 		 * dispatch the TX done event for this packet back to this TX
176415516c77SSepherosa Ziehau 		 * ring's channel.
176515516c77SSepherosa Ziehau 		 */
176615516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
176715516c77SSepherosa Ziehau 		    HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL);
176815516c77SSepherosa Ziehau 		*pi_data = txr->hn_tx_idx;
176915516c77SSepherosa Ziehau 	}
177015516c77SSepherosa Ziehau 
177115516c77SSepherosa Ziehau 	if (m_head->m_flags & M_VLANTAG) {
177215516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
177315516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
177415516c77SSepherosa Ziehau 		*pi_data = NDIS_VLAN_INFO_MAKE(
177515516c77SSepherosa Ziehau 		    EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag),
177615516c77SSepherosa Ziehau 		    EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag),
177715516c77SSepherosa Ziehau 		    EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag));
177815516c77SSepherosa Ziehau 	}
177915516c77SSepherosa Ziehau 
178015516c77SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
178115516c77SSepherosa Ziehau #if defined(INET6) || defined(INET)
178215516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
178315516c77SSepherosa Ziehau 		    NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO);
178415516c77SSepherosa Ziehau #ifdef INET
178515516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
178615516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV4(0,
178715516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
178815516c77SSepherosa Ziehau 		}
178915516c77SSepherosa Ziehau #endif
179015516c77SSepherosa Ziehau #if defined(INET6) && defined(INET)
179115516c77SSepherosa Ziehau 		else
179215516c77SSepherosa Ziehau #endif
179315516c77SSepherosa Ziehau #ifdef INET6
179415516c77SSepherosa Ziehau 		{
179515516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV6(0,
179615516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
179715516c77SSepherosa Ziehau 		}
179815516c77SSepherosa Ziehau #endif
179915516c77SSepherosa Ziehau #endif	/* INET6 || INET */
180015516c77SSepherosa Ziehau 	} else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) {
180115516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
180215516c77SSepherosa Ziehau 		    NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
180315516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
180415516c77SSepherosa Ziehau 		    (CSUM_IP6_TCP | CSUM_IP6_UDP)) {
180515516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV6;
180615516c77SSepherosa Ziehau 		} else {
180715516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV4;
180815516c77SSepherosa Ziehau 			if (m_head->m_pkthdr.csum_flags & CSUM_IP)
180915516c77SSepherosa Ziehau 				*pi_data |= NDIS_TXCSUM_INFO_IPCS;
181015516c77SSepherosa Ziehau 		}
181115516c77SSepherosa Ziehau 
181215516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP))
181315516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_TCPCS;
181415516c77SSepherosa Ziehau 		else if (m_head->m_pkthdr.csum_flags &
181515516c77SSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP6_UDP))
181615516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_UDPCS;
181715516c77SSepherosa Ziehau 	}
181815516c77SSepherosa Ziehau 
1819dc13fee6SSepherosa Ziehau 	pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
182015516c77SSepherosa Ziehau 	/* Convert RNDIS packet message offsets */
182115516c77SSepherosa Ziehau 	pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt->rm_dataoffset);
182215516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset);
182315516c77SSepherosa Ziehau 
182415516c77SSepherosa Ziehau 	/*
18258966e5d5SSepherosa Ziehau 	 * Fast path: Chimney sending.
182615516c77SSepherosa Ziehau 	 */
18278966e5d5SSepherosa Ziehau 	if (chim != NULL) {
1828dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tgt_txd = txd;
1829dc13fee6SSepherosa Ziehau 
1830dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL) {
1831dc13fee6SSepherosa Ziehau 			tgt_txd = txr->hn_agg_txd;
1832dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
1833dc13fee6SSepherosa Ziehau 			*m_head0 = NULL;
1834dc13fee6SSepherosa Ziehau #endif
1835dc13fee6SSepherosa Ziehau 		}
1836dc13fee6SSepherosa Ziehau 
1837dc13fee6SSepherosa Ziehau 		KASSERT(pkt == chim,
1838dc13fee6SSepherosa Ziehau 		    ("RNDIS pkt not in chimney sending buffer"));
1839dc13fee6SSepherosa Ziehau 		KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID,
1840dc13fee6SSepherosa Ziehau 		    ("chimney sending buffer is not used"));
1841dc13fee6SSepherosa Ziehau 		tgt_txd->chim_size += pkt->rm_len;
184215516c77SSepherosa Ziehau 
18438966e5d5SSepherosa Ziehau 		m_copydata(m_head, 0, m_head->m_pkthdr.len,
1844dc13fee6SSepherosa Ziehau 		    ((uint8_t *)chim) + pkt_hlen);
184515516c77SSepherosa Ziehau 
184615516c77SSepherosa Ziehau 		txr->hn_gpa_cnt = 0;
184715516c77SSepherosa Ziehau 		txr->hn_sendpkt = hn_txpkt_chim;
184815516c77SSepherosa Ziehau 		goto done;
184915516c77SSepherosa Ziehau 	}
1850dc13fee6SSepherosa Ziehau 
1851dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc"));
18528966e5d5SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
18538966e5d5SSepherosa Ziehau 	    ("chimney buffer is used"));
18548966e5d5SSepherosa Ziehau 	KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc"));
185515516c77SSepherosa Ziehau 
185615516c77SSepherosa Ziehau 	error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs);
1857dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
185815516c77SSepherosa Ziehau 		int freed;
185915516c77SSepherosa Ziehau 
186015516c77SSepherosa Ziehau 		/*
186115516c77SSepherosa Ziehau 		 * This mbuf is not linked w/ the txd yet, so free it now.
186215516c77SSepherosa Ziehau 		 */
186315516c77SSepherosa Ziehau 		m_freem(m_head);
186415516c77SSepherosa Ziehau 		*m_head0 = NULL;
186515516c77SSepherosa Ziehau 
186615516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
186715516c77SSepherosa Ziehau 		KASSERT(freed != 0,
186815516c77SSepherosa Ziehau 		    ("fail to free txd upon txdma error"));
186915516c77SSepherosa Ziehau 
187015516c77SSepherosa Ziehau 		txr->hn_txdma_failed++;
1871dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
187215516c77SSepherosa Ziehau 		return error;
187315516c77SSepherosa Ziehau 	}
187415516c77SSepherosa Ziehau 	*m_head0 = m_head;
187515516c77SSepherosa Ziehau 
187615516c77SSepherosa Ziehau 	/* +1 RNDIS packet message */
187715516c77SSepherosa Ziehau 	txr->hn_gpa_cnt = nsegs + 1;
187815516c77SSepherosa Ziehau 
187915516c77SSepherosa Ziehau 	/* send packet with page buffer */
188015516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr);
188115516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK;
1882dc13fee6SSepherosa Ziehau 	txr->hn_gpa[0].gpa_len = pkt_hlen;
188315516c77SSepherosa Ziehau 
188415516c77SSepherosa Ziehau 	/*
188515516c77SSepherosa Ziehau 	 * Fill the page buffers with mbuf info after the page
188615516c77SSepherosa Ziehau 	 * buffer for RNDIS packet message.
188715516c77SSepherosa Ziehau 	 */
188815516c77SSepherosa Ziehau 	for (i = 0; i < nsegs; ++i) {
188915516c77SSepherosa Ziehau 		struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1];
189015516c77SSepherosa Ziehau 
189115516c77SSepherosa Ziehau 		gpa->gpa_page = atop(segs[i].ds_addr);
189215516c77SSepherosa Ziehau 		gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK;
189315516c77SSepherosa Ziehau 		gpa->gpa_len = segs[i].ds_len;
189415516c77SSepherosa Ziehau 	}
189515516c77SSepherosa Ziehau 
189615516c77SSepherosa Ziehau 	txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
189715516c77SSepherosa Ziehau 	txd->chim_size = 0;
189815516c77SSepherosa Ziehau 	txr->hn_sendpkt = hn_txpkt_sglist;
189915516c77SSepherosa Ziehau done:
190015516c77SSepherosa Ziehau 	txd->m = m_head;
190115516c77SSepherosa Ziehau 
190215516c77SSepherosa Ziehau 	/* Set the completion routine */
190315516c77SSepherosa Ziehau 	hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd);
190415516c77SSepherosa Ziehau 
1905dc13fee6SSepherosa Ziehau 	/* Update temporary stats for later use. */
1906dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts++;
1907dc13fee6SSepherosa Ziehau 	txr->hn_stat_size += m_head->m_pkthdr.len;
1908dc13fee6SSepherosa Ziehau 	if (m_head->m_flags & M_MCAST)
1909dc13fee6SSepherosa Ziehau 		txr->hn_stat_mcasts++;
1910dc13fee6SSepherosa Ziehau 
191115516c77SSepherosa Ziehau 	return 0;
191215516c77SSepherosa Ziehau }
191315516c77SSepherosa Ziehau 
191415516c77SSepherosa Ziehau /*
191515516c77SSepherosa Ziehau  * NOTE:
191615516c77SSepherosa Ziehau  * If this function fails, then txd will be freed, but the mbuf
191715516c77SSepherosa Ziehau  * associated w/ the txd will _not_ be freed.
191815516c77SSepherosa Ziehau  */
191915516c77SSepherosa Ziehau static int
192015516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd)
192115516c77SSepherosa Ziehau {
192215516c77SSepherosa Ziehau 	int error, send_failed = 0;
192315516c77SSepherosa Ziehau 
192415516c77SSepherosa Ziehau again:
192515516c77SSepherosa Ziehau 	/*
1926dc13fee6SSepherosa Ziehau 	 * Make sure that this txd and any aggregated txds are not freed
1927dc13fee6SSepherosa Ziehau 	 * before ETHER_BPF_MTAP.
192815516c77SSepherosa Ziehau 	 */
192915516c77SSepherosa Ziehau 	hn_txdesc_hold(txd);
193015516c77SSepherosa Ziehau 	error = txr->hn_sendpkt(txr, txd);
193115516c77SSepherosa Ziehau 	if (!error) {
1932dc13fee6SSepherosa Ziehau 		if (bpf_peers_present(ifp->if_bpf)) {
1933dc13fee6SSepherosa Ziehau 			const struct hn_txdesc *tmp_txd;
1934dc13fee6SSepherosa Ziehau 
193515516c77SSepherosa Ziehau 			ETHER_BPF_MTAP(ifp, txd->m);
1936dc13fee6SSepherosa Ziehau 			STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link)
1937dc13fee6SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, tmp_txd->m);
1938dc13fee6SSepherosa Ziehau 		}
1939dc13fee6SSepherosa Ziehau 
1940dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts);
194123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
194223bf9e15SSepherosa Ziehau 		if (!hn_use_if_start)
194323bf9e15SSepherosa Ziehau #endif
194423bf9e15SSepherosa Ziehau 		{
194515516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OBYTES,
1946dc13fee6SSepherosa Ziehau 			    txr->hn_stat_size);
1947dc13fee6SSepherosa Ziehau 			if (txr->hn_stat_mcasts != 0) {
1948dc13fee6SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OMCASTS,
1949dc13fee6SSepherosa Ziehau 				    txr->hn_stat_mcasts);
195015516c77SSepherosa Ziehau 			}
1951dc13fee6SSepherosa Ziehau 		}
1952dc13fee6SSepherosa Ziehau 		txr->hn_pkts += txr->hn_stat_pkts;
1953dc13fee6SSepherosa Ziehau 		txr->hn_sends++;
195415516c77SSepherosa Ziehau 	}
195515516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
195615516c77SSepherosa Ziehau 
195715516c77SSepherosa Ziehau 	if (__predict_false(error)) {
195815516c77SSepherosa Ziehau 		int freed;
195915516c77SSepherosa Ziehau 
196015516c77SSepherosa Ziehau 		/*
196115516c77SSepherosa Ziehau 		 * This should "really rarely" happen.
196215516c77SSepherosa Ziehau 		 *
196315516c77SSepherosa Ziehau 		 * XXX Too many RX to be acked or too many sideband
196415516c77SSepherosa Ziehau 		 * commands to run?  Ask netvsc_channel_rollup()
196515516c77SSepherosa Ziehau 		 * to kick start later.
196615516c77SSepherosa Ziehau 		 */
196715516c77SSepherosa Ziehau 		txr->hn_has_txeof = 1;
196815516c77SSepherosa Ziehau 		if (!send_failed) {
196915516c77SSepherosa Ziehau 			txr->hn_send_failed++;
197015516c77SSepherosa Ziehau 			send_failed = 1;
197115516c77SSepherosa Ziehau 			/*
197215516c77SSepherosa Ziehau 			 * Try sending again after set hn_has_txeof;
197315516c77SSepherosa Ziehau 			 * in case that we missed the last
197415516c77SSepherosa Ziehau 			 * netvsc_channel_rollup().
197515516c77SSepherosa Ziehau 			 */
197615516c77SSepherosa Ziehau 			goto again;
197715516c77SSepherosa Ziehau 		}
197815516c77SSepherosa Ziehau 		if_printf(ifp, "send failed\n");
197915516c77SSepherosa Ziehau 
198015516c77SSepherosa Ziehau 		/*
198115516c77SSepherosa Ziehau 		 * Caller will perform further processing on the
198215516c77SSepherosa Ziehau 		 * associated mbuf, so don't free it in hn_txdesc_put();
198315516c77SSepherosa Ziehau 		 * only unload it from the DMA map in hn_txdesc_put(),
198415516c77SSepherosa Ziehau 		 * if it was loaded.
198515516c77SSepherosa Ziehau 		 */
198615516c77SSepherosa Ziehau 		txd->m = NULL;
198715516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
198815516c77SSepherosa Ziehau 		KASSERT(freed != 0,
198915516c77SSepherosa Ziehau 		    ("fail to free txd upon send error"));
199015516c77SSepherosa Ziehau 
199115516c77SSepherosa Ziehau 		txr->hn_send_failed++;
199215516c77SSepherosa Ziehau 	}
1993dc13fee6SSepherosa Ziehau 
1994dc13fee6SSepherosa Ziehau 	/* Reset temporary stats, after this sending is done. */
1995dc13fee6SSepherosa Ziehau 	txr->hn_stat_size = 0;
1996dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts = 0;
1997dc13fee6SSepherosa Ziehau 	txr->hn_stat_mcasts = 0;
1998dc13fee6SSepherosa Ziehau 
1999dc13fee6SSepherosa Ziehau 	return (error);
200015516c77SSepherosa Ziehau }
200115516c77SSepherosa Ziehau 
200215516c77SSepherosa Ziehau /*
200315516c77SSepherosa Ziehau  * Append the specified data to the indicated mbuf chain,
200415516c77SSepherosa Ziehau  * Extend the mbuf chain if the new data does not fit in
200515516c77SSepherosa Ziehau  * existing space.
200615516c77SSepherosa Ziehau  *
200715516c77SSepherosa Ziehau  * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c.
200815516c77SSepherosa Ziehau  * There should be an equivalent in the kernel mbuf code,
200915516c77SSepherosa Ziehau  * but there does not appear to be one yet.
201015516c77SSepherosa Ziehau  *
201115516c77SSepherosa Ziehau  * Differs from m_append() in that additional mbufs are
201215516c77SSepherosa Ziehau  * allocated with cluster size MJUMPAGESIZE, and filled
201315516c77SSepherosa Ziehau  * accordingly.
201415516c77SSepherosa Ziehau  *
201515516c77SSepherosa Ziehau  * Return 1 if able to complete the job; otherwise 0.
201615516c77SSepherosa Ziehau  */
201715516c77SSepherosa Ziehau static int
201815516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp)
201915516c77SSepherosa Ziehau {
202015516c77SSepherosa Ziehau 	struct mbuf *m, *n;
202115516c77SSepherosa Ziehau 	int remainder, space;
202215516c77SSepherosa Ziehau 
202315516c77SSepherosa Ziehau 	for (m = m0; m->m_next != NULL; m = m->m_next)
202415516c77SSepherosa Ziehau 		;
202515516c77SSepherosa Ziehau 	remainder = len;
202615516c77SSepherosa Ziehau 	space = M_TRAILINGSPACE(m);
202715516c77SSepherosa Ziehau 	if (space > 0) {
202815516c77SSepherosa Ziehau 		/*
202915516c77SSepherosa Ziehau 		 * Copy into available space.
203015516c77SSepherosa Ziehau 		 */
203115516c77SSepherosa Ziehau 		if (space > remainder)
203215516c77SSepherosa Ziehau 			space = remainder;
203315516c77SSepherosa Ziehau 		bcopy(cp, mtod(m, caddr_t) + m->m_len, space);
203415516c77SSepherosa Ziehau 		m->m_len += space;
203515516c77SSepherosa Ziehau 		cp += space;
203615516c77SSepherosa Ziehau 		remainder -= space;
203715516c77SSepherosa Ziehau 	}
203815516c77SSepherosa Ziehau 	while (remainder > 0) {
203915516c77SSepherosa Ziehau 		/*
204015516c77SSepherosa Ziehau 		 * Allocate a new mbuf; could check space
204115516c77SSepherosa Ziehau 		 * and allocate a cluster instead.
204215516c77SSepherosa Ziehau 		 */
204315516c77SSepherosa Ziehau 		n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE);
204415516c77SSepherosa Ziehau 		if (n == NULL)
204515516c77SSepherosa Ziehau 			break;
204615516c77SSepherosa Ziehau 		n->m_len = min(MJUMPAGESIZE, remainder);
204715516c77SSepherosa Ziehau 		bcopy(cp, mtod(n, caddr_t), n->m_len);
204815516c77SSepherosa Ziehau 		cp += n->m_len;
204915516c77SSepherosa Ziehau 		remainder -= n->m_len;
205015516c77SSepherosa Ziehau 		m->m_next = n;
205115516c77SSepherosa Ziehau 		m = n;
205215516c77SSepherosa Ziehau 	}
205315516c77SSepherosa Ziehau 	if (m0->m_flags & M_PKTHDR)
205415516c77SSepherosa Ziehau 		m0->m_pkthdr.len += len - remainder;
205515516c77SSepherosa Ziehau 
205615516c77SSepherosa Ziehau 	return (remainder == 0);
205715516c77SSepherosa Ziehau }
205815516c77SSepherosa Ziehau 
205915516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
206015516c77SSepherosa Ziehau static __inline int
206115516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m)
206215516c77SSepherosa Ziehau {
206315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
206415516c77SSepherosa Ziehau 	if (hn_lro_mbufq_depth) {
206515516c77SSepherosa Ziehau 		tcp_lro_queue_mbuf(lc, m);
206615516c77SSepherosa Ziehau 		return 0;
206715516c77SSepherosa Ziehau 	}
206815516c77SSepherosa Ziehau #endif
206915516c77SSepherosa Ziehau 	return tcp_lro_rx(lc, m, 0);
207015516c77SSepherosa Ziehau }
207115516c77SSepherosa Ziehau #endif
207215516c77SSepherosa Ziehau 
207315516c77SSepherosa Ziehau static int
207415516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
207515516c77SSepherosa Ziehau     const struct hn_rxinfo *info)
207615516c77SSepherosa Ziehau {
207715516c77SSepherosa Ziehau 	struct ifnet *ifp = rxr->hn_ifp;
207815516c77SSepherosa Ziehau 	struct mbuf *m_new;
207915516c77SSepherosa Ziehau 	int size, do_lro = 0, do_csum = 1;
208015516c77SSepherosa Ziehau 	int hash_type;
208115516c77SSepherosa Ziehau 
208215516c77SSepherosa Ziehau 	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
208315516c77SSepherosa Ziehau 		return (0);
208415516c77SSepherosa Ziehau 
208515516c77SSepherosa Ziehau 	/*
208615516c77SSepherosa Ziehau 	 * Bail out if packet contains more data than configured MTU.
208715516c77SSepherosa Ziehau 	 */
208815516c77SSepherosa Ziehau 	if (dlen > (ifp->if_mtu + ETHER_HDR_LEN)) {
208915516c77SSepherosa Ziehau 		return (0);
209015516c77SSepherosa Ziehau 	} else if (dlen <= MHLEN) {
209115516c77SSepherosa Ziehau 		m_new = m_gethdr(M_NOWAIT, MT_DATA);
209215516c77SSepherosa Ziehau 		if (m_new == NULL) {
209315516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
209415516c77SSepherosa Ziehau 			return (0);
209515516c77SSepherosa Ziehau 		}
209615516c77SSepherosa Ziehau 		memcpy(mtod(m_new, void *), data, dlen);
209715516c77SSepherosa Ziehau 		m_new->m_pkthdr.len = m_new->m_len = dlen;
209815516c77SSepherosa Ziehau 		rxr->hn_small_pkts++;
209915516c77SSepherosa Ziehau 	} else {
210015516c77SSepherosa Ziehau 		/*
210115516c77SSepherosa Ziehau 		 * Get an mbuf with a cluster.  For packets 2K or less,
210215516c77SSepherosa Ziehau 		 * get a standard 2K cluster.  For anything larger, get a
210315516c77SSepherosa Ziehau 		 * 4K cluster.  Any buffers larger than 4K can cause problems
210415516c77SSepherosa Ziehau 		 * if looped around to the Hyper-V TX channel, so avoid them.
210515516c77SSepherosa Ziehau 		 */
210615516c77SSepherosa Ziehau 		size = MCLBYTES;
210715516c77SSepherosa Ziehau 		if (dlen > MCLBYTES) {
210815516c77SSepherosa Ziehau 			/* 4096 */
210915516c77SSepherosa Ziehau 			size = MJUMPAGESIZE;
211015516c77SSepherosa Ziehau 		}
211115516c77SSepherosa Ziehau 
211215516c77SSepherosa Ziehau 		m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size);
211315516c77SSepherosa Ziehau 		if (m_new == NULL) {
211415516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
211515516c77SSepherosa Ziehau 			return (0);
211615516c77SSepherosa Ziehau 		}
211715516c77SSepherosa Ziehau 
211815516c77SSepherosa Ziehau 		hv_m_append(m_new, dlen, data);
211915516c77SSepherosa Ziehau 	}
212015516c77SSepherosa Ziehau 	m_new->m_pkthdr.rcvif = ifp;
212115516c77SSepherosa Ziehau 
212215516c77SSepherosa Ziehau 	if (__predict_false((ifp->if_capenable & IFCAP_RXCSUM) == 0))
212315516c77SSepherosa Ziehau 		do_csum = 0;
212415516c77SSepherosa Ziehau 
212515516c77SSepherosa Ziehau 	/* receive side checksum offload */
212615516c77SSepherosa Ziehau 	if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) {
212715516c77SSepherosa Ziehau 		/* IP csum offload */
212815516c77SSepherosa Ziehau 		if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) {
212915516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
213015516c77SSepherosa Ziehau 			    (CSUM_IP_CHECKED | CSUM_IP_VALID);
213115516c77SSepherosa Ziehau 			rxr->hn_csum_ip++;
213215516c77SSepherosa Ziehau 		}
213315516c77SSepherosa Ziehau 
213415516c77SSepherosa Ziehau 		/* TCP/UDP csum offload */
213515516c77SSepherosa Ziehau 		if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK |
213615516c77SSepherosa Ziehau 		     NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) {
213715516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
213815516c77SSepherosa Ziehau 			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
213915516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_data = 0xffff;
214015516c77SSepherosa Ziehau 			if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK)
214115516c77SSepherosa Ziehau 				rxr->hn_csum_tcp++;
214215516c77SSepherosa Ziehau 			else
214315516c77SSepherosa Ziehau 				rxr->hn_csum_udp++;
214415516c77SSepherosa Ziehau 		}
214515516c77SSepherosa Ziehau 
214615516c77SSepherosa Ziehau 		/*
214715516c77SSepherosa Ziehau 		 * XXX
214815516c77SSepherosa Ziehau 		 * As of this write (Oct 28th, 2016), host side will turn
214915516c77SSepherosa Ziehau 		 * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so
215015516c77SSepherosa Ziehau 		 * the do_lro setting here is actually _not_ accurate.  We
215115516c77SSepherosa Ziehau 		 * depend on the RSS hash type check to reset do_lro.
215215516c77SSepherosa Ziehau 		 */
215315516c77SSepherosa Ziehau 		if ((info->csum_info &
215415516c77SSepherosa Ziehau 		     (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) ==
215515516c77SSepherosa Ziehau 		    (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK))
215615516c77SSepherosa Ziehau 			do_lro = 1;
215715516c77SSepherosa Ziehau 	} else {
215815516c77SSepherosa Ziehau 		const struct ether_header *eh;
215915516c77SSepherosa Ziehau 		uint16_t etype;
216015516c77SSepherosa Ziehau 		int hoff;
216115516c77SSepherosa Ziehau 
216215516c77SSepherosa Ziehau 		hoff = sizeof(*eh);
216315516c77SSepherosa Ziehau 		if (m_new->m_len < hoff)
216415516c77SSepherosa Ziehau 			goto skip;
216515516c77SSepherosa Ziehau 		eh = mtod(m_new, struct ether_header *);
216615516c77SSepherosa Ziehau 		etype = ntohs(eh->ether_type);
216715516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_VLAN) {
216815516c77SSepherosa Ziehau 			const struct ether_vlan_header *evl;
216915516c77SSepherosa Ziehau 
217015516c77SSepherosa Ziehau 			hoff = sizeof(*evl);
217115516c77SSepherosa Ziehau 			if (m_new->m_len < hoff)
217215516c77SSepherosa Ziehau 				goto skip;
217315516c77SSepherosa Ziehau 			evl = mtod(m_new, struct ether_vlan_header *);
217415516c77SSepherosa Ziehau 			etype = ntohs(evl->evl_proto);
217515516c77SSepherosa Ziehau 		}
217615516c77SSepherosa Ziehau 
217715516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_IP) {
217815516c77SSepherosa Ziehau 			int pr;
217915516c77SSepherosa Ziehau 
218015516c77SSepherosa Ziehau 			pr = hn_check_iplen(m_new, hoff);
218115516c77SSepherosa Ziehau 			if (pr == IPPROTO_TCP) {
218215516c77SSepherosa Ziehau 				if (do_csum &&
218315516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
218415516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_TCP)) {
218515516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
218615516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
218715516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
218815516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
218915516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
219015516c77SSepherosa Ziehau 				}
219115516c77SSepherosa Ziehau 				do_lro = 1;
219215516c77SSepherosa Ziehau 			} else if (pr == IPPROTO_UDP) {
219315516c77SSepherosa Ziehau 				if (do_csum &&
219415516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
219515516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_UDP)) {
219615516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
219715516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
219815516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
219915516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
220015516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
220115516c77SSepherosa Ziehau 				}
220215516c77SSepherosa Ziehau 			} else if (pr != IPPROTO_DONE && do_csum &&
220315516c77SSepherosa Ziehau 			    (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) {
220415516c77SSepherosa Ziehau 				rxr->hn_csum_trusted++;
220515516c77SSepherosa Ziehau 				m_new->m_pkthdr.csum_flags |=
220615516c77SSepherosa Ziehau 				    (CSUM_IP_CHECKED | CSUM_IP_VALID);
220715516c77SSepherosa Ziehau 			}
220815516c77SSepherosa Ziehau 		}
220915516c77SSepherosa Ziehau 	}
221015516c77SSepherosa Ziehau skip:
221115516c77SSepherosa Ziehau 	if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) {
221215516c77SSepherosa Ziehau 		m_new->m_pkthdr.ether_vtag = EVL_MAKETAG(
221315516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_ID(info->vlan_info),
221415516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_PRI(info->vlan_info),
221515516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_CFI(info->vlan_info));
221615516c77SSepherosa Ziehau 		m_new->m_flags |= M_VLANTAG;
221715516c77SSepherosa Ziehau 	}
221815516c77SSepherosa Ziehau 
221915516c77SSepherosa Ziehau 	if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) {
222015516c77SSepherosa Ziehau 		rxr->hn_rss_pkts++;
222115516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = info->hash_value;
222215516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE_HASH;
222315516c77SSepherosa Ziehau 		if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) ==
222415516c77SSepherosa Ziehau 		    NDIS_HASH_FUNCTION_TOEPLITZ) {
222515516c77SSepherosa Ziehau 			uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK);
222615516c77SSepherosa Ziehau 
222715516c77SSepherosa Ziehau 			/*
222815516c77SSepherosa Ziehau 			 * NOTE:
222915516c77SSepherosa Ziehau 			 * do_lro is resetted, if the hash types are not TCP
223015516c77SSepherosa Ziehau 			 * related.  See the comment in the above csum_flags
223115516c77SSepherosa Ziehau 			 * setup section.
223215516c77SSepherosa Ziehau 			 */
223315516c77SSepherosa Ziehau 			switch (type) {
223415516c77SSepherosa Ziehau 			case NDIS_HASH_IPV4:
223515516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV4;
223615516c77SSepherosa Ziehau 				do_lro = 0;
223715516c77SSepherosa Ziehau 				break;
223815516c77SSepherosa Ziehau 
223915516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV4:
224015516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV4;
224115516c77SSepherosa Ziehau 				break;
224215516c77SSepherosa Ziehau 
224315516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6:
224415516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6;
224515516c77SSepherosa Ziehau 				do_lro = 0;
224615516c77SSepherosa Ziehau 				break;
224715516c77SSepherosa Ziehau 
224815516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6_EX:
224915516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6_EX;
225015516c77SSepherosa Ziehau 				do_lro = 0;
225115516c77SSepherosa Ziehau 				break;
225215516c77SSepherosa Ziehau 
225315516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6:
225415516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6;
225515516c77SSepherosa Ziehau 				break;
225615516c77SSepherosa Ziehau 
225715516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6_EX:
225815516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX;
225915516c77SSepherosa Ziehau 				break;
226015516c77SSepherosa Ziehau 			}
226115516c77SSepherosa Ziehau 		}
226215516c77SSepherosa Ziehau 	} else {
226315516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
226415516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE;
226515516c77SSepherosa Ziehau 	}
226615516c77SSepherosa Ziehau 	M_HASHTYPE_SET(m_new, hash_type);
226715516c77SSepherosa Ziehau 
226815516c77SSepherosa Ziehau 	/*
226915516c77SSepherosa Ziehau 	 * Note:  Moved RX completion back to hv_nv_on_receive() so all
227015516c77SSepherosa Ziehau 	 * messages (not just data messages) will trigger a response.
227115516c77SSepherosa Ziehau 	 */
227215516c77SSepherosa Ziehau 
227315516c77SSepherosa Ziehau 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
227415516c77SSepherosa Ziehau 	rxr->hn_pkts++;
227515516c77SSepherosa Ziehau 
227615516c77SSepherosa Ziehau 	if ((ifp->if_capenable & IFCAP_LRO) && do_lro) {
227715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
227815516c77SSepherosa Ziehau 		struct lro_ctrl *lro = &rxr->hn_lro;
227915516c77SSepherosa Ziehau 
228015516c77SSepherosa Ziehau 		if (lro->lro_cnt) {
228115516c77SSepherosa Ziehau 			rxr->hn_lro_tried++;
228215516c77SSepherosa Ziehau 			if (hn_lro_rx(lro, m_new) == 0) {
228315516c77SSepherosa Ziehau 				/* DONE! */
228415516c77SSepherosa Ziehau 				return 0;
228515516c77SSepherosa Ziehau 			}
228615516c77SSepherosa Ziehau 		}
228715516c77SSepherosa Ziehau #endif
228815516c77SSepherosa Ziehau 	}
228915516c77SSepherosa Ziehau 
229015516c77SSepherosa Ziehau 	/* We're not holding the lock here, so don't release it */
229115516c77SSepherosa Ziehau 	(*ifp->if_input)(ifp, m_new);
229215516c77SSepherosa Ziehau 
229315516c77SSepherosa Ziehau 	return (0);
229415516c77SSepherosa Ziehau }
229515516c77SSepherosa Ziehau 
229615516c77SSepherosa Ziehau static int
229715516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
229815516c77SSepherosa Ziehau {
229915516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
230015516c77SSepherosa Ziehau 	struct ifreq *ifr = (struct ifreq *)data;
230115516c77SSepherosa Ziehau 	int mask, error = 0;
230215516c77SSepherosa Ziehau 
230315516c77SSepherosa Ziehau 	switch (cmd) {
230415516c77SSepherosa Ziehau 	case SIOCSIFMTU:
230515516c77SSepherosa Ziehau 		if (ifr->ifr_mtu > HN_MTU_MAX) {
230615516c77SSepherosa Ziehau 			error = EINVAL;
230715516c77SSepherosa Ziehau 			break;
230815516c77SSepherosa Ziehau 		}
230915516c77SSepherosa Ziehau 
231015516c77SSepherosa Ziehau 		HN_LOCK(sc);
231115516c77SSepherosa Ziehau 
231215516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
231315516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
231415516c77SSepherosa Ziehau 			break;
231515516c77SSepherosa Ziehau 		}
231615516c77SSepherosa Ziehau 
231715516c77SSepherosa Ziehau 		if ((sc->hn_caps & HN_CAP_MTU) == 0) {
231815516c77SSepherosa Ziehau 			/* Can't change MTU */
231915516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
232015516c77SSepherosa Ziehau 			error = EOPNOTSUPP;
232115516c77SSepherosa Ziehau 			break;
232215516c77SSepherosa Ziehau 		}
232315516c77SSepherosa Ziehau 
232415516c77SSepherosa Ziehau 		if (ifp->if_mtu == ifr->ifr_mtu) {
232515516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
232615516c77SSepherosa Ziehau 			break;
232715516c77SSepherosa Ziehau 		}
232815516c77SSepherosa Ziehau 
232915516c77SSepherosa Ziehau 		/*
233015516c77SSepherosa Ziehau 		 * Suspend this interface before the synthetic parts
233115516c77SSepherosa Ziehau 		 * are ripped.
233215516c77SSepherosa Ziehau 		 */
233315516c77SSepherosa Ziehau 		hn_suspend(sc);
233415516c77SSepherosa Ziehau 
233515516c77SSepherosa Ziehau 		/*
233615516c77SSepherosa Ziehau 		 * Detach the synthetics parts, i.e. NVS and RNDIS.
233715516c77SSepherosa Ziehau 		 */
233815516c77SSepherosa Ziehau 		hn_synth_detach(sc);
233915516c77SSepherosa Ziehau 
234015516c77SSepherosa Ziehau 		/*
234115516c77SSepherosa Ziehau 		 * Reattach the synthetic parts, i.e. NVS and RNDIS,
234215516c77SSepherosa Ziehau 		 * with the new MTU setting.
234315516c77SSepherosa Ziehau 		 */
234415516c77SSepherosa Ziehau 		error = hn_synth_attach(sc, ifr->ifr_mtu);
234515516c77SSepherosa Ziehau 		if (error) {
234615516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
234715516c77SSepherosa Ziehau 			break;
234815516c77SSepherosa Ziehau 		}
234915516c77SSepherosa Ziehau 
235015516c77SSepherosa Ziehau 		/*
235115516c77SSepherosa Ziehau 		 * Commit the requested MTU, after the synthetic parts
235215516c77SSepherosa Ziehau 		 * have been successfully attached.
235315516c77SSepherosa Ziehau 		 */
235415516c77SSepherosa Ziehau 		ifp->if_mtu = ifr->ifr_mtu;
235515516c77SSepherosa Ziehau 
235615516c77SSepherosa Ziehau 		/*
235715516c77SSepherosa Ziehau 		 * Make sure that various parameters based on MTU are
235815516c77SSepherosa Ziehau 		 * still valid, after the MTU change.
235915516c77SSepherosa Ziehau 		 */
236015516c77SSepherosa Ziehau 		if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax)
236115516c77SSepherosa Ziehau 			hn_set_chim_size(sc, sc->hn_chim_szmax);
236215516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu);
236315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
236415516c77SSepherosa Ziehau 		if (sc->hn_rx_ring[0].hn_lro.lro_length_lim <
236515516c77SSepherosa Ziehau 		    HN_LRO_LENLIM_MIN(ifp))
236615516c77SSepherosa Ziehau 			hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
236715516c77SSepherosa Ziehau #endif
236815516c77SSepherosa Ziehau 
236915516c77SSepherosa Ziehau 		/*
237015516c77SSepherosa Ziehau 		 * All done!  Resume the interface now.
237115516c77SSepherosa Ziehau 		 */
237215516c77SSepherosa Ziehau 		hn_resume(sc);
237315516c77SSepherosa Ziehau 
237415516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
237515516c77SSepherosa Ziehau 		break;
237615516c77SSepherosa Ziehau 
237715516c77SSepherosa Ziehau 	case SIOCSIFFLAGS:
237815516c77SSepherosa Ziehau 		HN_LOCK(sc);
237915516c77SSepherosa Ziehau 
238015516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
238115516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
238215516c77SSepherosa Ziehau 			break;
238315516c77SSepherosa Ziehau 		}
238415516c77SSepherosa Ziehau 
238515516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_UP) {
2386fdc4f478SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2387fdc4f478SSepherosa Ziehau 				/*
2388fdc4f478SSepherosa Ziehau 				 * Caller meight hold mutex, e.g.
2389fdc4f478SSepherosa Ziehau 				 * bpf; use busy-wait for the RNDIS
2390fdc4f478SSepherosa Ziehau 				 * reply.
2391fdc4f478SSepherosa Ziehau 				 */
2392fdc4f478SSepherosa Ziehau 				HN_NO_SLEEPING(sc);
239315516c77SSepherosa Ziehau 				hn_set_rxfilter(sc);
2394fdc4f478SSepherosa Ziehau 				HN_SLEEPING_OK(sc);
2395fdc4f478SSepherosa Ziehau 			} else {
239615516c77SSepherosa Ziehau 				hn_init_locked(sc);
2397fdc4f478SSepherosa Ziehau 			}
239815516c77SSepherosa Ziehau 		} else {
239915516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
240015516c77SSepherosa Ziehau 				hn_stop(sc);
240115516c77SSepherosa Ziehau 		}
240215516c77SSepherosa Ziehau 		sc->hn_if_flags = ifp->if_flags;
240315516c77SSepherosa Ziehau 
240415516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
240515516c77SSepherosa Ziehau 		break;
240615516c77SSepherosa Ziehau 
240715516c77SSepherosa Ziehau 	case SIOCSIFCAP:
240815516c77SSepherosa Ziehau 		HN_LOCK(sc);
240915516c77SSepherosa Ziehau 		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
241015516c77SSepherosa Ziehau 
241115516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM) {
241215516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM;
241315516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM)
241415516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc);
241515516c77SSepherosa Ziehau 			else
241615516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc);
241715516c77SSepherosa Ziehau 		}
241815516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM_IPV6) {
241915516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
242015516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
242115516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc);
242215516c77SSepherosa Ziehau 			else
242315516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc);
242415516c77SSepherosa Ziehau 		}
242515516c77SSepherosa Ziehau 
242615516c77SSepherosa Ziehau 		/* TODO: flip RNDIS offload parameters for RXCSUM. */
242715516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM)
242815516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM;
242915516c77SSepherosa Ziehau #ifdef foo
243015516c77SSepherosa Ziehau 		/* We can't diff IPv6 packets from IPv4 packets on RX path. */
243115516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM_IPV6)
243215516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
243315516c77SSepherosa Ziehau #endif
243415516c77SSepherosa Ziehau 
243515516c77SSepherosa Ziehau 		if (mask & IFCAP_LRO)
243615516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_LRO;
243715516c77SSepherosa Ziehau 
243815516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO4) {
243915516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO4;
244015516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO4)
244115516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP_TSO;
244215516c77SSepherosa Ziehau 			else
244315516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP_TSO;
244415516c77SSepherosa Ziehau 		}
244515516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO6) {
244615516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO6;
244715516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO6)
244815516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP6_TSO;
244915516c77SSepherosa Ziehau 			else
245015516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP6_TSO;
245115516c77SSepherosa Ziehau 		}
245215516c77SSepherosa Ziehau 
245315516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
245415516c77SSepherosa Ziehau 		break;
245515516c77SSepherosa Ziehau 
245615516c77SSepherosa Ziehau 	case SIOCADDMULTI:
245715516c77SSepherosa Ziehau 	case SIOCDELMULTI:
245815516c77SSepherosa Ziehau 		HN_LOCK(sc);
245915516c77SSepherosa Ziehau 
246015516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
246115516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
246215516c77SSepherosa Ziehau 			break;
246315516c77SSepherosa Ziehau 		}
2464fdc4f478SSepherosa Ziehau 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2465fdc4f478SSepherosa Ziehau 			/*
2466fdc4f478SSepherosa Ziehau 			 * Multicast uses mutex; use busy-wait for
2467fdc4f478SSepherosa Ziehau 			 * the RNDIS reply.
2468fdc4f478SSepherosa Ziehau 			 */
2469fdc4f478SSepherosa Ziehau 			HN_NO_SLEEPING(sc);
247015516c77SSepherosa Ziehau 			hn_set_rxfilter(sc);
2471fdc4f478SSepherosa Ziehau 			HN_SLEEPING_OK(sc);
2472fdc4f478SSepherosa Ziehau 		}
247315516c77SSepherosa Ziehau 
247415516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
247515516c77SSepherosa Ziehau 		break;
247615516c77SSepherosa Ziehau 
247715516c77SSepherosa Ziehau 	case SIOCSIFMEDIA:
247815516c77SSepherosa Ziehau 	case SIOCGIFMEDIA:
247915516c77SSepherosa Ziehau 		error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd);
248015516c77SSepherosa Ziehau 		break;
248115516c77SSepherosa Ziehau 
248215516c77SSepherosa Ziehau 	default:
248315516c77SSepherosa Ziehau 		error = ether_ioctl(ifp, cmd, data);
248415516c77SSepherosa Ziehau 		break;
248515516c77SSepherosa Ziehau 	}
248615516c77SSepherosa Ziehau 	return (error);
248715516c77SSepherosa Ziehau }
248815516c77SSepherosa Ziehau 
248915516c77SSepherosa Ziehau static void
249015516c77SSepherosa Ziehau hn_stop(struct hn_softc *sc)
249115516c77SSepherosa Ziehau {
249215516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
249315516c77SSepherosa Ziehau 	int i;
249415516c77SSepherosa Ziehau 
249515516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
249615516c77SSepherosa Ziehau 
249715516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
249815516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
249915516c77SSepherosa Ziehau 
250015516c77SSepherosa Ziehau 	/* Clear RUNNING bit _before_ hn_suspend_data() */
250115516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
250215516c77SSepherosa Ziehau 	hn_suspend_data(sc);
250315516c77SSepherosa Ziehau 
250415516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
250515516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
250615516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
250715516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
250815516c77SSepherosa Ziehau }
250915516c77SSepherosa Ziehau 
251015516c77SSepherosa Ziehau static void
251115516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc)
251215516c77SSepherosa Ziehau {
251315516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
251415516c77SSepherosa Ziehau 	int i;
251515516c77SSepherosa Ziehau 
251615516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
251715516c77SSepherosa Ziehau 
251815516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
251915516c77SSepherosa Ziehau 		return;
252015516c77SSepherosa Ziehau 
252115516c77SSepherosa Ziehau 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
252215516c77SSepherosa Ziehau 		return;
252315516c77SSepherosa Ziehau 
252415516c77SSepherosa Ziehau 	/* Configure RX filter */
252515516c77SSepherosa Ziehau 	hn_set_rxfilter(sc);
252615516c77SSepherosa Ziehau 
252715516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
252815516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
252915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
253015516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
253115516c77SSepherosa Ziehau 
253215516c77SSepherosa Ziehau 	/* Clear TX 'suspended' bit. */
253315516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_inuse);
253415516c77SSepherosa Ziehau 
253515516c77SSepherosa Ziehau 	/* Everything is ready; unleash! */
253615516c77SSepherosa Ziehau 	atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
253715516c77SSepherosa Ziehau }
253815516c77SSepherosa Ziehau 
253915516c77SSepherosa Ziehau static void
254015516c77SSepherosa Ziehau hn_init(void *xsc)
254115516c77SSepherosa Ziehau {
254215516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
254315516c77SSepherosa Ziehau 
254415516c77SSepherosa Ziehau 	HN_LOCK(sc);
254515516c77SSepherosa Ziehau 	hn_init_locked(sc);
254615516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
254715516c77SSepherosa Ziehau }
254815516c77SSepherosa Ziehau 
254915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
255015516c77SSepherosa Ziehau 
255115516c77SSepherosa Ziehau static int
255215516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
255315516c77SSepherosa Ziehau {
255415516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
255515516c77SSepherosa Ziehau 	unsigned int lenlim;
255615516c77SSepherosa Ziehau 	int error;
255715516c77SSepherosa Ziehau 
255815516c77SSepherosa Ziehau 	lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim;
255915516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &lenlim, 0, req);
256015516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
256115516c77SSepherosa Ziehau 		return error;
256215516c77SSepherosa Ziehau 
256315516c77SSepherosa Ziehau 	HN_LOCK(sc);
256415516c77SSepherosa Ziehau 	if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) ||
256515516c77SSepherosa Ziehau 	    lenlim > TCP_LRO_LENGTH_MAX) {
256615516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
256715516c77SSepherosa Ziehau 		return EINVAL;
256815516c77SSepherosa Ziehau 	}
256915516c77SSepherosa Ziehau 	hn_set_lro_lenlim(sc, lenlim);
257015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
257115516c77SSepherosa Ziehau 
257215516c77SSepherosa Ziehau 	return 0;
257315516c77SSepherosa Ziehau }
257415516c77SSepherosa Ziehau 
257515516c77SSepherosa Ziehau static int
257615516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS)
257715516c77SSepherosa Ziehau {
257815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
257915516c77SSepherosa Ziehau 	int ackcnt, error, i;
258015516c77SSepherosa Ziehau 
258115516c77SSepherosa Ziehau 	/*
258215516c77SSepherosa Ziehau 	 * lro_ackcnt_lim is append count limit,
258315516c77SSepherosa Ziehau 	 * +1 to turn it into aggregation limit.
258415516c77SSepherosa Ziehau 	 */
258515516c77SSepherosa Ziehau 	ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1;
258615516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &ackcnt, 0, req);
258715516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
258815516c77SSepherosa Ziehau 		return error;
258915516c77SSepherosa Ziehau 
259015516c77SSepherosa Ziehau 	if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1))
259115516c77SSepherosa Ziehau 		return EINVAL;
259215516c77SSepherosa Ziehau 
259315516c77SSepherosa Ziehau 	/*
259415516c77SSepherosa Ziehau 	 * Convert aggregation limit back to append
259515516c77SSepherosa Ziehau 	 * count limit.
259615516c77SSepherosa Ziehau 	 */
259715516c77SSepherosa Ziehau 	--ackcnt;
259815516c77SSepherosa Ziehau 	HN_LOCK(sc);
2599a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
260015516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt;
260115516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
260215516c77SSepherosa Ziehau 	return 0;
260315516c77SSepherosa Ziehau }
260415516c77SSepherosa Ziehau 
260515516c77SSepherosa Ziehau #endif
260615516c77SSepherosa Ziehau 
260715516c77SSepherosa Ziehau static int
260815516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS)
260915516c77SSepherosa Ziehau {
261015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
261115516c77SSepherosa Ziehau 	int hcsum = arg2;
261215516c77SSepherosa Ziehau 	int on, error, i;
261315516c77SSepherosa Ziehau 
261415516c77SSepherosa Ziehau 	on = 0;
261515516c77SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum)
261615516c77SSepherosa Ziehau 		on = 1;
261715516c77SSepherosa Ziehau 
261815516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &on, 0, req);
261915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
262015516c77SSepherosa Ziehau 		return error;
262115516c77SSepherosa Ziehau 
262215516c77SSepherosa Ziehau 	HN_LOCK(sc);
2623a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
262415516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
262515516c77SSepherosa Ziehau 
262615516c77SSepherosa Ziehau 		if (on)
262715516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= hcsum;
262815516c77SSepherosa Ziehau 		else
262915516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum &= ~hcsum;
263015516c77SSepherosa Ziehau 	}
263115516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
263215516c77SSepherosa Ziehau 	return 0;
263315516c77SSepherosa Ziehau }
263415516c77SSepherosa Ziehau 
263515516c77SSepherosa Ziehau static int
263615516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS)
263715516c77SSepherosa Ziehau {
263815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
263915516c77SSepherosa Ziehau 	int chim_size, error;
264015516c77SSepherosa Ziehau 
264115516c77SSepherosa Ziehau 	chim_size = sc->hn_tx_ring[0].hn_chim_size;
264215516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &chim_size, 0, req);
264315516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
264415516c77SSepherosa Ziehau 		return error;
264515516c77SSepherosa Ziehau 
264615516c77SSepherosa Ziehau 	if (chim_size > sc->hn_chim_szmax || chim_size <= 0)
264715516c77SSepherosa Ziehau 		return EINVAL;
264815516c77SSepherosa Ziehau 
264915516c77SSepherosa Ziehau 	HN_LOCK(sc);
265015516c77SSepherosa Ziehau 	hn_set_chim_size(sc, chim_size);
265115516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
265215516c77SSepherosa Ziehau 	return 0;
265315516c77SSepherosa Ziehau }
265415516c77SSepherosa Ziehau 
265515516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
265615516c77SSepherosa Ziehau static int
265715516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS)
265815516c77SSepherosa Ziehau {
265915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
266015516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
266115516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
266215516c77SSepherosa Ziehau 	uint64_t stat;
266315516c77SSepherosa Ziehau 
266415516c77SSepherosa Ziehau 	stat = 0;
266515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
266615516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
266715516c77SSepherosa Ziehau 		stat += *((int *)((uint8_t *)rxr + ofs));
266815516c77SSepherosa Ziehau 	}
266915516c77SSepherosa Ziehau 
267015516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
267115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
267215516c77SSepherosa Ziehau 		return error;
267315516c77SSepherosa Ziehau 
267415516c77SSepherosa Ziehau 	/* Zero out this stat. */
267515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
267615516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
267715516c77SSepherosa Ziehau 		*((int *)((uint8_t *)rxr + ofs)) = 0;
267815516c77SSepherosa Ziehau 	}
267915516c77SSepherosa Ziehau 	return 0;
268015516c77SSepherosa Ziehau }
268115516c77SSepherosa Ziehau #else
268215516c77SSepherosa Ziehau static int
268315516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS)
268415516c77SSepherosa Ziehau {
268515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
268615516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
268715516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
268815516c77SSepherosa Ziehau 	uint64_t stat;
268915516c77SSepherosa Ziehau 
269015516c77SSepherosa Ziehau 	stat = 0;
2691a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
269215516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
269315516c77SSepherosa Ziehau 		stat += *((uint64_t *)((uint8_t *)rxr + ofs));
269415516c77SSepherosa Ziehau 	}
269515516c77SSepherosa Ziehau 
269615516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
269715516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
269815516c77SSepherosa Ziehau 		return error;
269915516c77SSepherosa Ziehau 
270015516c77SSepherosa Ziehau 	/* Zero out this stat. */
2701a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
270215516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
270315516c77SSepherosa Ziehau 		*((uint64_t *)((uint8_t *)rxr + ofs)) = 0;
270415516c77SSepherosa Ziehau 	}
270515516c77SSepherosa Ziehau 	return 0;
270615516c77SSepherosa Ziehau }
270715516c77SSepherosa Ziehau 
270815516c77SSepherosa Ziehau #endif
270915516c77SSepherosa Ziehau 
271015516c77SSepherosa Ziehau static int
271115516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
271215516c77SSepherosa Ziehau {
271315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
271415516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
271515516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
271615516c77SSepherosa Ziehau 	u_long stat;
271715516c77SSepherosa Ziehau 
271815516c77SSepherosa Ziehau 	stat = 0;
2719a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
272015516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
272115516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)rxr + ofs));
272215516c77SSepherosa Ziehau 	}
272315516c77SSepherosa Ziehau 
272415516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
272515516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
272615516c77SSepherosa Ziehau 		return error;
272715516c77SSepherosa Ziehau 
272815516c77SSepherosa Ziehau 	/* Zero out this stat. */
2729a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
273015516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
273115516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)rxr + ofs)) = 0;
273215516c77SSepherosa Ziehau 	}
273315516c77SSepherosa Ziehau 	return 0;
273415516c77SSepherosa Ziehau }
273515516c77SSepherosa Ziehau 
273615516c77SSepherosa Ziehau static int
273715516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
273815516c77SSepherosa Ziehau {
273915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
274015516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
274115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
274215516c77SSepherosa Ziehau 	u_long stat;
274315516c77SSepherosa Ziehau 
274415516c77SSepherosa Ziehau 	stat = 0;
2745a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
274615516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
274715516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)txr + ofs));
274815516c77SSepherosa Ziehau 	}
274915516c77SSepherosa Ziehau 
275015516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
275115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
275215516c77SSepherosa Ziehau 		return error;
275315516c77SSepherosa Ziehau 
275415516c77SSepherosa Ziehau 	/* Zero out this stat. */
2755a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
275615516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
275715516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)txr + ofs)) = 0;
275815516c77SSepherosa Ziehau 	}
275915516c77SSepherosa Ziehau 	return 0;
276015516c77SSepherosa Ziehau }
276115516c77SSepherosa Ziehau 
276215516c77SSepherosa Ziehau static int
276315516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS)
276415516c77SSepherosa Ziehau {
276515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
276615516c77SSepherosa Ziehau 	int ofs = arg2, i, error, conf;
276715516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
276815516c77SSepherosa Ziehau 
276915516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[0];
277015516c77SSepherosa Ziehau 	conf = *((int *)((uint8_t *)txr + ofs));
277115516c77SSepherosa Ziehau 
277215516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &conf, 0, req);
277315516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
277415516c77SSepherosa Ziehau 		return error;
277515516c77SSepherosa Ziehau 
277615516c77SSepherosa Ziehau 	HN_LOCK(sc);
2777a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
277815516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
277915516c77SSepherosa Ziehau 		*((int *)((uint8_t *)txr + ofs)) = conf;
278015516c77SSepherosa Ziehau 	}
278115516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
278215516c77SSepherosa Ziehau 
278315516c77SSepherosa Ziehau 	return 0;
278415516c77SSepherosa Ziehau }
278515516c77SSepherosa Ziehau 
278615516c77SSepherosa Ziehau static int
2787dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS)
2788dc13fee6SSepherosa Ziehau {
2789dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2790dc13fee6SSepherosa Ziehau 	int error, size;
2791dc13fee6SSepherosa Ziehau 
2792dc13fee6SSepherosa Ziehau 	size = sc->hn_agg_size;
2793dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &size, 0, req);
2794dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
2795dc13fee6SSepherosa Ziehau 		return (error);
2796dc13fee6SSepherosa Ziehau 
2797dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
2798dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = size;
2799dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
2800dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
2801dc13fee6SSepherosa Ziehau 
2802dc13fee6SSepherosa Ziehau 	return (0);
2803dc13fee6SSepherosa Ziehau }
2804dc13fee6SSepherosa Ziehau 
2805dc13fee6SSepherosa Ziehau static int
2806dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS)
2807dc13fee6SSepherosa Ziehau {
2808dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2809dc13fee6SSepherosa Ziehau 	int error, pkts;
2810dc13fee6SSepherosa Ziehau 
2811dc13fee6SSepherosa Ziehau 	pkts = sc->hn_agg_pkts;
2812dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pkts, 0, req);
2813dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
2814dc13fee6SSepherosa Ziehau 		return (error);
2815dc13fee6SSepherosa Ziehau 
2816dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
2817dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = pkts;
2818dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
2819dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
2820dc13fee6SSepherosa Ziehau 
2821dc13fee6SSepherosa Ziehau 	return (0);
2822dc13fee6SSepherosa Ziehau }
2823dc13fee6SSepherosa Ziehau 
2824dc13fee6SSepherosa Ziehau static int
2825dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS)
2826dc13fee6SSepherosa Ziehau {
2827dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2828dc13fee6SSepherosa Ziehau 	int pkts;
2829dc13fee6SSepherosa Ziehau 
2830dc13fee6SSepherosa Ziehau 	pkts = sc->hn_tx_ring[0].hn_agg_pktmax;
2831dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &pkts, 0, req));
2832dc13fee6SSepherosa Ziehau }
2833dc13fee6SSepherosa Ziehau 
2834dc13fee6SSepherosa Ziehau static int
2835dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS)
2836dc13fee6SSepherosa Ziehau {
2837dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2838dc13fee6SSepherosa Ziehau 	int align;
2839dc13fee6SSepherosa Ziehau 
2840dc13fee6SSepherosa Ziehau 	align = sc->hn_tx_ring[0].hn_agg_align;
2841dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &align, 0, req));
2842dc13fee6SSepherosa Ziehau }
2843dc13fee6SSepherosa Ziehau 
2844dc13fee6SSepherosa Ziehau static int
284515516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS)
284615516c77SSepherosa Ziehau {
284715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
284815516c77SSepherosa Ziehau 	char verstr[16];
284915516c77SSepherosa Ziehau 
285015516c77SSepherosa Ziehau 	snprintf(verstr, sizeof(verstr), "%u.%u",
285115516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
285215516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
285315516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
285415516c77SSepherosa Ziehau }
285515516c77SSepherosa Ziehau 
285615516c77SSepherosa Ziehau static int
285715516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS)
285815516c77SSepherosa Ziehau {
285915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
286015516c77SSepherosa Ziehau 	char caps_str[128];
286115516c77SSepherosa Ziehau 	uint32_t caps;
286215516c77SSepherosa Ziehau 
286315516c77SSepherosa Ziehau 	HN_LOCK(sc);
286415516c77SSepherosa Ziehau 	caps = sc->hn_caps;
286515516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
286615516c77SSepherosa Ziehau 	snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS);
286715516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req);
286815516c77SSepherosa Ziehau }
286915516c77SSepherosa Ziehau 
287015516c77SSepherosa Ziehau static int
287115516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS)
287215516c77SSepherosa Ziehau {
287315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
287415516c77SSepherosa Ziehau 	char assist_str[128];
287515516c77SSepherosa Ziehau 	uint32_t hwassist;
287615516c77SSepherosa Ziehau 
287715516c77SSepherosa Ziehau 	HN_LOCK(sc);
287815516c77SSepherosa Ziehau 	hwassist = sc->hn_ifp->if_hwassist;
287915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
288015516c77SSepherosa Ziehau 	snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS);
288115516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req);
288215516c77SSepherosa Ziehau }
288315516c77SSepherosa Ziehau 
288415516c77SSepherosa Ziehau static int
288515516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS)
288615516c77SSepherosa Ziehau {
288715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
288815516c77SSepherosa Ziehau 	char filter_str[128];
288915516c77SSepherosa Ziehau 	uint32_t filter;
289015516c77SSepherosa Ziehau 
289115516c77SSepherosa Ziehau 	HN_LOCK(sc);
289215516c77SSepherosa Ziehau 	filter = sc->hn_rx_filter;
289315516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
289415516c77SSepherosa Ziehau 	snprintf(filter_str, sizeof(filter_str), "%b", filter,
289515516c77SSepherosa Ziehau 	    NDIS_PACKET_TYPES);
289615516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req);
289715516c77SSepherosa Ziehau }
289815516c77SSepherosa Ziehau 
289915516c77SSepherosa Ziehau static int
290015516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
290115516c77SSepherosa Ziehau {
290215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
290315516c77SSepherosa Ziehau 	int error;
290415516c77SSepherosa Ziehau 
290515516c77SSepherosa Ziehau 	HN_LOCK(sc);
290615516c77SSepherosa Ziehau 
290715516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
290815516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
290915516c77SSepherosa Ziehau 		goto back;
291015516c77SSepherosa Ziehau 
291115516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
291215516c77SSepherosa Ziehau 	if (error)
291315516c77SSepherosa Ziehau 		goto back;
291415516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
291515516c77SSepherosa Ziehau 
291615516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
291715516c77SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
291815516c77SSepherosa Ziehau 	} else {
291915516c77SSepherosa Ziehau 		/* Not RSS capable, at least for now; just save the RSS key. */
292015516c77SSepherosa Ziehau 		error = 0;
292115516c77SSepherosa Ziehau 	}
292215516c77SSepherosa Ziehau back:
292315516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
292415516c77SSepherosa Ziehau 	return (error);
292515516c77SSepherosa Ziehau }
292615516c77SSepherosa Ziehau 
292715516c77SSepherosa Ziehau static int
292815516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS)
292915516c77SSepherosa Ziehau {
293015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
293115516c77SSepherosa Ziehau 	int error;
293215516c77SSepherosa Ziehau 
293315516c77SSepherosa Ziehau 	HN_LOCK(sc);
293415516c77SSepherosa Ziehau 
293515516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
293615516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
293715516c77SSepherosa Ziehau 		goto back;
293815516c77SSepherosa Ziehau 
293915516c77SSepherosa Ziehau 	/*
294015516c77SSepherosa Ziehau 	 * Don't allow RSS indirect table change, if this interface is not
294115516c77SSepherosa Ziehau 	 * RSS capable currently.
294215516c77SSepherosa Ziehau 	 */
294315516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
294415516c77SSepherosa Ziehau 		error = EOPNOTSUPP;
294515516c77SSepherosa Ziehau 		goto back;
294615516c77SSepherosa Ziehau 	}
294715516c77SSepherosa Ziehau 
294815516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
294915516c77SSepherosa Ziehau 	if (error)
295015516c77SSepherosa Ziehau 		goto back;
295115516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSIND;
295215516c77SSepherosa Ziehau 
2953afd4971bSSepherosa Ziehau 	hn_rss_ind_fixup(sc);
295415516c77SSepherosa Ziehau 	error = hn_rss_reconfig(sc);
295515516c77SSepherosa Ziehau back:
295615516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
295715516c77SSepherosa Ziehau 	return (error);
295815516c77SSepherosa Ziehau }
295915516c77SSepherosa Ziehau 
296015516c77SSepherosa Ziehau static int
296115516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS)
296215516c77SSepherosa Ziehau {
296315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
296415516c77SSepherosa Ziehau 	char hash_str[128];
296515516c77SSepherosa Ziehau 	uint32_t hash;
296615516c77SSepherosa Ziehau 
296715516c77SSepherosa Ziehau 	HN_LOCK(sc);
296815516c77SSepherosa Ziehau 	hash = sc->hn_rss_hash;
296915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
297015516c77SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
297115516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
297215516c77SSepherosa Ziehau }
297315516c77SSepherosa Ziehau 
297415516c77SSepherosa Ziehau static int
297515516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff)
297615516c77SSepherosa Ziehau {
297715516c77SSepherosa Ziehau 	const struct ip *ip;
297815516c77SSepherosa Ziehau 	int len, iphlen, iplen;
297915516c77SSepherosa Ziehau 	const struct tcphdr *th;
298015516c77SSepherosa Ziehau 	int thoff;				/* TCP data offset */
298115516c77SSepherosa Ziehau 
298215516c77SSepherosa Ziehau 	len = hoff + sizeof(struct ip);
298315516c77SSepherosa Ziehau 
298415516c77SSepherosa Ziehau 	/* The packet must be at least the size of an IP header. */
298515516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < len)
298615516c77SSepherosa Ziehau 		return IPPROTO_DONE;
298715516c77SSepherosa Ziehau 
298815516c77SSepherosa Ziehau 	/* The fixed IP header must reside completely in the first mbuf. */
298915516c77SSepherosa Ziehau 	if (m->m_len < len)
299015516c77SSepherosa Ziehau 		return IPPROTO_DONE;
299115516c77SSepherosa Ziehau 
299215516c77SSepherosa Ziehau 	ip = mtodo(m, hoff);
299315516c77SSepherosa Ziehau 
299415516c77SSepherosa Ziehau 	/* Bound check the packet's stated IP header length. */
299515516c77SSepherosa Ziehau 	iphlen = ip->ip_hl << 2;
299615516c77SSepherosa Ziehau 	if (iphlen < sizeof(struct ip))		/* minimum header length */
299715516c77SSepherosa Ziehau 		return IPPROTO_DONE;
299815516c77SSepherosa Ziehau 
299915516c77SSepherosa Ziehau 	/* The full IP header must reside completely in the one mbuf. */
300015516c77SSepherosa Ziehau 	if (m->m_len < hoff + iphlen)
300115516c77SSepherosa Ziehau 		return IPPROTO_DONE;
300215516c77SSepherosa Ziehau 
300315516c77SSepherosa Ziehau 	iplen = ntohs(ip->ip_len);
300415516c77SSepherosa Ziehau 
300515516c77SSepherosa Ziehau 	/*
300615516c77SSepherosa Ziehau 	 * Check that the amount of data in the buffers is as
300715516c77SSepherosa Ziehau 	 * at least much as the IP header would have us expect.
300815516c77SSepherosa Ziehau 	 */
300915516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < hoff + iplen)
301015516c77SSepherosa Ziehau 		return IPPROTO_DONE;
301115516c77SSepherosa Ziehau 
301215516c77SSepherosa Ziehau 	/*
301315516c77SSepherosa Ziehau 	 * Ignore IP fragments.
301415516c77SSepherosa Ziehau 	 */
301515516c77SSepherosa Ziehau 	if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF))
301615516c77SSepherosa Ziehau 		return IPPROTO_DONE;
301715516c77SSepherosa Ziehau 
301815516c77SSepherosa Ziehau 	/*
301915516c77SSepherosa Ziehau 	 * The TCP/IP or UDP/IP header must be entirely contained within
302015516c77SSepherosa Ziehau 	 * the first fragment of a packet.
302115516c77SSepherosa Ziehau 	 */
302215516c77SSepherosa Ziehau 	switch (ip->ip_p) {
302315516c77SSepherosa Ziehau 	case IPPROTO_TCP:
302415516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct tcphdr))
302515516c77SSepherosa Ziehau 			return IPPROTO_DONE;
302615516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct tcphdr))
302715516c77SSepherosa Ziehau 			return IPPROTO_DONE;
302815516c77SSepherosa Ziehau 		th = (const struct tcphdr *)((const uint8_t *)ip + iphlen);
302915516c77SSepherosa Ziehau 		thoff = th->th_off << 2;
303015516c77SSepherosa Ziehau 		if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen)
303115516c77SSepherosa Ziehau 			return IPPROTO_DONE;
303215516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + thoff)
303315516c77SSepherosa Ziehau 			return IPPROTO_DONE;
303415516c77SSepherosa Ziehau 		break;
303515516c77SSepherosa Ziehau 	case IPPROTO_UDP:
303615516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct udphdr))
303715516c77SSepherosa Ziehau 			return IPPROTO_DONE;
303815516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct udphdr))
303915516c77SSepherosa Ziehau 			return IPPROTO_DONE;
304015516c77SSepherosa Ziehau 		break;
304115516c77SSepherosa Ziehau 	default:
304215516c77SSepherosa Ziehau 		if (iplen < iphlen)
304315516c77SSepherosa Ziehau 			return IPPROTO_DONE;
304415516c77SSepherosa Ziehau 		break;
304515516c77SSepherosa Ziehau 	}
304615516c77SSepherosa Ziehau 	return ip->ip_p;
304715516c77SSepherosa Ziehau }
304815516c77SSepherosa Ziehau 
304915516c77SSepherosa Ziehau static int
305015516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt)
305115516c77SSepherosa Ziehau {
305215516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
305315516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
305415516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
305515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
305615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
305715516c77SSepherosa Ziehau 	int lroent_cnt;
305815516c77SSepherosa Ziehau #endif
305915516c77SSepherosa Ziehau #endif
306015516c77SSepherosa Ziehau 	int i;
306115516c77SSepherosa Ziehau 
306215516c77SSepherosa Ziehau 	/*
306315516c77SSepherosa Ziehau 	 * Create RXBUF for reception.
306415516c77SSepherosa Ziehau 	 *
306515516c77SSepherosa Ziehau 	 * NOTE:
306615516c77SSepherosa Ziehau 	 * - It is shared by all channels.
306715516c77SSepherosa Ziehau 	 * - A large enough buffer is allocated, certain version of NVSes
306815516c77SSepherosa Ziehau 	 *   may further limit the usable space.
306915516c77SSepherosa Ziehau 	 */
307015516c77SSepherosa Ziehau 	sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
307115516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma,
307215516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
307315516c77SSepherosa Ziehau 	if (sc->hn_rxbuf == NULL) {
307415516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate rxbuf failed\n");
307515516c77SSepherosa Ziehau 		return (ENOMEM);
307615516c77SSepherosa Ziehau 	}
307715516c77SSepherosa Ziehau 
307815516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = ring_cnt;
307915516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt;
308015516c77SSepherosa Ziehau 
308115516c77SSepherosa Ziehau 	sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt,
308215516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
308315516c77SSepherosa Ziehau 
308415516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
308515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
308615516c77SSepherosa Ziehau 	lroent_cnt = hn_lro_entry_count;
308715516c77SSepherosa Ziehau 	if (lroent_cnt < TCP_LRO_ENTRIES)
308815516c77SSepherosa Ziehau 		lroent_cnt = TCP_LRO_ENTRIES;
308915516c77SSepherosa Ziehau 	if (bootverbose)
309015516c77SSepherosa Ziehau 		device_printf(dev, "LRO: entry count %d\n", lroent_cnt);
309115516c77SSepherosa Ziehau #endif
309215516c77SSepherosa Ziehau #endif	/* INET || INET6 */
309315516c77SSepherosa Ziehau 
309415516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
309515516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
309615516c77SSepherosa Ziehau 
309715516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.rx sysctl tree */
309815516c77SSepherosa Ziehau 	sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx",
309915516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
310015516c77SSepherosa Ziehau 
310115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
310215516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
310315516c77SSepherosa Ziehau 
310415516c77SSepherosa Ziehau 		rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
310515516c77SSepherosa Ziehau 		    PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE,
310615516c77SSepherosa Ziehau 		    &rxr->hn_br_dma, BUS_DMA_WAITOK);
310715516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL) {
310815516c77SSepherosa Ziehau 			device_printf(dev, "allocate bufring failed\n");
310915516c77SSepherosa Ziehau 			return (ENOMEM);
311015516c77SSepherosa Ziehau 		}
311115516c77SSepherosa Ziehau 
311215516c77SSepherosa Ziehau 		if (hn_trust_hosttcp)
311315516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP;
311415516c77SSepherosa Ziehau 		if (hn_trust_hostudp)
311515516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP;
311615516c77SSepherosa Ziehau 		if (hn_trust_hostip)
311715516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP;
311815516c77SSepherosa Ziehau 		rxr->hn_ifp = sc->hn_ifp;
311915516c77SSepherosa Ziehau 		if (i < sc->hn_tx_ring_cnt)
312015516c77SSepherosa Ziehau 			rxr->hn_txr = &sc->hn_tx_ring[i];
312115516c77SSepherosa Ziehau 		rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF;
312215516c77SSepherosa Ziehau 		rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK);
312315516c77SSepherosa Ziehau 		rxr->hn_rx_idx = i;
312415516c77SSepherosa Ziehau 		rxr->hn_rxbuf = sc->hn_rxbuf;
312515516c77SSepherosa Ziehau 
312615516c77SSepherosa Ziehau 		/*
312715516c77SSepherosa Ziehau 		 * Initialize LRO.
312815516c77SSepherosa Ziehau 		 */
312915516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
313015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
313115516c77SSepherosa Ziehau 		tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt,
313215516c77SSepherosa Ziehau 		    hn_lro_mbufq_depth);
313315516c77SSepherosa Ziehau #else
313415516c77SSepherosa Ziehau 		tcp_lro_init(&rxr->hn_lro);
313515516c77SSepherosa Ziehau 		rxr->hn_lro.ifp = sc->hn_ifp;
313615516c77SSepherosa Ziehau #endif
313715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
313815516c77SSepherosa Ziehau 		rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF;
313915516c77SSepherosa Ziehau 		rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF;
314015516c77SSepherosa Ziehau #endif
314115516c77SSepherosa Ziehau #endif	/* INET || INET6 */
314215516c77SSepherosa Ziehau 
314315516c77SSepherosa Ziehau 		if (sc->hn_rx_sysctl_tree != NULL) {
314415516c77SSepherosa Ziehau 			char name[16];
314515516c77SSepherosa Ziehau 
314615516c77SSepherosa Ziehau 			/*
314715516c77SSepherosa Ziehau 			 * Create per RX ring sysctl tree:
314815516c77SSepherosa Ziehau 			 * dev.hn.UNIT.rx.RINGID
314915516c77SSepherosa Ziehau 			 */
315015516c77SSepherosa Ziehau 			snprintf(name, sizeof(name), "%d", i);
315115516c77SSepherosa Ziehau 			rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx,
315215516c77SSepherosa Ziehau 			    SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree),
315315516c77SSepherosa Ziehau 			    OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
315415516c77SSepherosa Ziehau 
315515516c77SSepherosa Ziehau 			if (rxr->hn_rx_sysctl_tree != NULL) {
315615516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
315715516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
315815516c77SSepherosa Ziehau 				    OID_AUTO, "packets", CTLFLAG_RW,
315915516c77SSepherosa Ziehau 				    &rxr->hn_pkts, "# of packets received");
316015516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
316115516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
316215516c77SSepherosa Ziehau 				    OID_AUTO, "rss_pkts", CTLFLAG_RW,
316315516c77SSepherosa Ziehau 				    &rxr->hn_rss_pkts,
316415516c77SSepherosa Ziehau 				    "# of packets w/ RSS info received");
316515516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx,
316615516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
316715516c77SSepherosa Ziehau 				    OID_AUTO, "pktbuf_len", CTLFLAG_RD,
316815516c77SSepherosa Ziehau 				    &rxr->hn_pktbuf_len, 0,
316915516c77SSepherosa Ziehau 				    "Temporary channel packet buffer length");
317015516c77SSepherosa Ziehau 			}
317115516c77SSepherosa Ziehau 		}
317215516c77SSepherosa Ziehau 	}
317315516c77SSepherosa Ziehau 
317415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued",
317515516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
317615516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_queued),
317715516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
317815516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
317915516c77SSepherosa Ziehau #else
318015516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
318115516c77SSepherosa Ziehau #endif
318215516c77SSepherosa Ziehau 	    "LU", "LRO queued");
318315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed",
318415516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
318515516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_flushed),
318615516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
318715516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
318815516c77SSepherosa Ziehau #else
318915516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
319015516c77SSepherosa Ziehau #endif
319115516c77SSepherosa Ziehau 	    "LU", "LRO flushed");
319215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried",
319315516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
319415516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro_tried),
319515516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries");
319615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
319715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim",
319815516c77SSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
319915516c77SSepherosa Ziehau 	    hn_lro_lenlim_sysctl, "IU",
320015516c77SSepherosa Ziehau 	    "Max # of data bytes to be aggregated by LRO");
320115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim",
320215516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
320315516c77SSepherosa Ziehau 	    hn_lro_ackcnt_sysctl, "I",
320415516c77SSepherosa Ziehau 	    "Max # of ACKs to be aggregated by LRO");
320515516c77SSepherosa Ziehau #endif
320615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp",
320715516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP,
320815516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
320915516c77SSepherosa Ziehau 	    "Trust tcp segement verification on host side, "
321015516c77SSepherosa Ziehau 	    "when csum info is missing");
321115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp",
321215516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP,
321315516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
321415516c77SSepherosa Ziehau 	    "Trust udp datagram verification on host side, "
321515516c77SSepherosa Ziehau 	    "when csum info is missing");
321615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip",
321715516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP,
321815516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
321915516c77SSepherosa Ziehau 	    "Trust ip packet verification on host side, "
322015516c77SSepherosa Ziehau 	    "when csum info is missing");
322115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip",
322215516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
322315516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_ip),
322415516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP");
322515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp",
322615516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
322715516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_tcp),
322815516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP");
322915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp",
323015516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
323115516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_udp),
323215516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP");
323315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted",
323415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
323515516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_trusted),
323615516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU",
323715516c77SSepherosa Ziehau 	    "# of packets that we trust host's csum verification");
323815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts",
323915516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
324015516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_small_pkts),
324115516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of small packets received");
324215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed",
324315516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
324415516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_ack_failed),
324515516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures");
324615516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt",
324715516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings");
324815516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse",
324915516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings");
325015516c77SSepherosa Ziehau 
325115516c77SSepherosa Ziehau 	return (0);
325215516c77SSepherosa Ziehau }
325315516c77SSepherosa Ziehau 
325415516c77SSepherosa Ziehau static void
325515516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc)
325615516c77SSepherosa Ziehau {
325715516c77SSepherosa Ziehau 	int i;
325815516c77SSepherosa Ziehau 
325915516c77SSepherosa Ziehau 	if (sc->hn_rxbuf != NULL) {
32602494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0)
326115516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf);
32622494d735SSepherosa Ziehau 		else
32632494d735SSepherosa Ziehau 			device_printf(sc->hn_dev, "RXBUF is referenced\n");
326415516c77SSepherosa Ziehau 		sc->hn_rxbuf = NULL;
326515516c77SSepherosa Ziehau 	}
326615516c77SSepherosa Ziehau 
326715516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_cnt == 0)
326815516c77SSepherosa Ziehau 		return;
326915516c77SSepherosa Ziehau 
327015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
327115516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
327215516c77SSepherosa Ziehau 
327315516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL)
327415516c77SSepherosa Ziehau 			continue;
32752494d735SSepherosa Ziehau 		if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) {
327615516c77SSepherosa Ziehau 			hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br);
32772494d735SSepherosa Ziehau 		} else {
32782494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
32792494d735SSepherosa Ziehau 			    "%dth channel bufring is referenced", i);
32802494d735SSepherosa Ziehau 		}
328115516c77SSepherosa Ziehau 		rxr->hn_br = NULL;
328215516c77SSepherosa Ziehau 
328315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
328415516c77SSepherosa Ziehau 		tcp_lro_free(&rxr->hn_lro);
328515516c77SSepherosa Ziehau #endif
328615516c77SSepherosa Ziehau 		free(rxr->hn_pktbuf, M_DEVBUF);
328715516c77SSepherosa Ziehau 	}
328815516c77SSepherosa Ziehau 	free(sc->hn_rx_ring, M_DEVBUF);
328915516c77SSepherosa Ziehau 	sc->hn_rx_ring = NULL;
329015516c77SSepherosa Ziehau 
329115516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = 0;
329215516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = 0;
329315516c77SSepherosa Ziehau }
329415516c77SSepherosa Ziehau 
329515516c77SSepherosa Ziehau static int
329615516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id)
329715516c77SSepherosa Ziehau {
329815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[id];
329915516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
330015516c77SSepherosa Ziehau 	bus_dma_tag_t parent_dtag;
330115516c77SSepherosa Ziehau 	int error, i;
330215516c77SSepherosa Ziehau 
330315516c77SSepherosa Ziehau 	txr->hn_sc = sc;
330415516c77SSepherosa Ziehau 	txr->hn_tx_idx = id;
330515516c77SSepherosa Ziehau 
330615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
330715516c77SSepherosa Ziehau 	mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN);
330815516c77SSepherosa Ziehau #endif
330915516c77SSepherosa Ziehau 	mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF);
331015516c77SSepherosa Ziehau 
331115516c77SSepherosa Ziehau 	txr->hn_txdesc_cnt = HN_TX_DESC_CNT;
331215516c77SSepherosa Ziehau 	txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt,
331315516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
331415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
331515516c77SSepherosa Ziehau 	SLIST_INIT(&txr->hn_txlist);
331615516c77SSepherosa Ziehau #else
331715516c77SSepherosa Ziehau 	txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF,
331815516c77SSepherosa Ziehau 	    M_WAITOK, &txr->hn_tx_lock);
331915516c77SSepherosa Ziehau #endif
332015516c77SSepherosa Ziehau 
3321*0e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_EVTTQ) {
3322*0e11868dSSepherosa Ziehau 		txr->hn_tx_taskq = VMBUS_GET_EVENT_TASKQ(
3323*0e11868dSSepherosa Ziehau 		    device_get_parent(dev), dev, HN_RING_IDX2CPU(sc, id));
3324*0e11868dSSepherosa Ziehau 	} else {
3325fdd0222aSSepherosa Ziehau 		txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt];
3326*0e11868dSSepherosa Ziehau 	}
332715516c77SSepherosa Ziehau 
332823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
332915516c77SSepherosa Ziehau 	if (hn_use_if_start) {
333015516c77SSepherosa Ziehau 		txr->hn_txeof = hn_start_txeof;
333115516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr);
333215516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr);
333323bf9e15SSepherosa Ziehau 	} else
333423bf9e15SSepherosa Ziehau #endif
333523bf9e15SSepherosa Ziehau 	{
333615516c77SSepherosa Ziehau 		int br_depth;
333715516c77SSepherosa Ziehau 
333815516c77SSepherosa Ziehau 		txr->hn_txeof = hn_xmit_txeof;
333915516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr);
334015516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr);
334115516c77SSepherosa Ziehau 
334215516c77SSepherosa Ziehau 		br_depth = hn_get_txswq_depth(txr);
334315516c77SSepherosa Ziehau 		txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF,
334415516c77SSepherosa Ziehau 		    M_WAITOK, &txr->hn_tx_lock);
334515516c77SSepherosa Ziehau 	}
334615516c77SSepherosa Ziehau 
334715516c77SSepherosa Ziehau 	txr->hn_direct_tx_size = hn_direct_tx_size;
334815516c77SSepherosa Ziehau 
334915516c77SSepherosa Ziehau 	/*
335015516c77SSepherosa Ziehau 	 * Always schedule transmission instead of trying to do direct
335115516c77SSepherosa Ziehau 	 * transmission.  This one gives the best performance so far.
335215516c77SSepherosa Ziehau 	 */
335315516c77SSepherosa Ziehau 	txr->hn_sched_tx = 1;
335415516c77SSepherosa Ziehau 
335515516c77SSepherosa Ziehau 	parent_dtag = bus_get_dma_tag(dev);
335615516c77SSepherosa Ziehau 
335715516c77SSepherosa Ziehau 	/* DMA tag for RNDIS packet messages. */
335815516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
335915516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_ALIGN,		/* alignment */
336015516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_BOUNDARY,	/* boundary */
336115516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
336215516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
336315516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
336415516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsize */
336515516c77SSepherosa Ziehau 	    1,				/* nsegments */
336615516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsegsize */
336715516c77SSepherosa Ziehau 	    0,				/* flags */
336815516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
336915516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
337015516c77SSepherosa Ziehau 	    &txr->hn_tx_rndis_dtag);
337115516c77SSepherosa Ziehau 	if (error) {
337215516c77SSepherosa Ziehau 		device_printf(dev, "failed to create rndis dmatag\n");
337315516c77SSepherosa Ziehau 		return error;
337415516c77SSepherosa Ziehau 	}
337515516c77SSepherosa Ziehau 
337615516c77SSepherosa Ziehau 	/* DMA tag for data. */
337715516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
337815516c77SSepherosa Ziehau 	    1,				/* alignment */
337915516c77SSepherosa Ziehau 	    HN_TX_DATA_BOUNDARY,	/* boundary */
338015516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
338115516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
338215516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
338315516c77SSepherosa Ziehau 	    HN_TX_DATA_MAXSIZE,		/* maxsize */
338415516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGCNT_MAX,	/* nsegments */
338515516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGSIZE,		/* maxsegsize */
338615516c77SSepherosa Ziehau 	    0,				/* flags */
338715516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
338815516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
338915516c77SSepherosa Ziehau 	    &txr->hn_tx_data_dtag);
339015516c77SSepherosa Ziehau 	if (error) {
339115516c77SSepherosa Ziehau 		device_printf(dev, "failed to create data dmatag\n");
339215516c77SSepherosa Ziehau 		return error;
339315516c77SSepherosa Ziehau 	}
339415516c77SSepherosa Ziehau 
339515516c77SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i) {
339615516c77SSepherosa Ziehau 		struct hn_txdesc *txd = &txr->hn_txdesc[i];
339715516c77SSepherosa Ziehau 
339815516c77SSepherosa Ziehau 		txd->txr = txr;
339915516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
3400dc13fee6SSepherosa Ziehau 		STAILQ_INIT(&txd->agg_list);
340115516c77SSepherosa Ziehau 
340215516c77SSepherosa Ziehau 		/*
340315516c77SSepherosa Ziehau 		 * Allocate and load RNDIS packet message.
340415516c77SSepherosa Ziehau 		 */
340515516c77SSepherosa Ziehau         	error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag,
340615516c77SSepherosa Ziehau 		    (void **)&txd->rndis_pkt,
340715516c77SSepherosa Ziehau 		    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
340815516c77SSepherosa Ziehau 		    &txd->rndis_pkt_dmap);
340915516c77SSepherosa Ziehau 		if (error) {
341015516c77SSepherosa Ziehau 			device_printf(dev,
341115516c77SSepherosa Ziehau 			    "failed to allocate rndis_packet_msg, %d\n", i);
341215516c77SSepherosa Ziehau 			return error;
341315516c77SSepherosa Ziehau 		}
341415516c77SSepherosa Ziehau 
341515516c77SSepherosa Ziehau 		error = bus_dmamap_load(txr->hn_tx_rndis_dtag,
341615516c77SSepherosa Ziehau 		    txd->rndis_pkt_dmap,
341715516c77SSepherosa Ziehau 		    txd->rndis_pkt, HN_RNDIS_PKT_LEN,
341815516c77SSepherosa Ziehau 		    hyperv_dma_map_paddr, &txd->rndis_pkt_paddr,
341915516c77SSepherosa Ziehau 		    BUS_DMA_NOWAIT);
342015516c77SSepherosa Ziehau 		if (error) {
342115516c77SSepherosa Ziehau 			device_printf(dev,
342215516c77SSepherosa Ziehau 			    "failed to load rndis_packet_msg, %d\n", i);
342315516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
342415516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
342515516c77SSepherosa Ziehau 			return error;
342615516c77SSepherosa Ziehau 		}
342715516c77SSepherosa Ziehau 
342815516c77SSepherosa Ziehau 		/* DMA map for TX data. */
342915516c77SSepherosa Ziehau 		error = bus_dmamap_create(txr->hn_tx_data_dtag, 0,
343015516c77SSepherosa Ziehau 		    &txd->data_dmap);
343115516c77SSepherosa Ziehau 		if (error) {
343215516c77SSepherosa Ziehau 			device_printf(dev,
343315516c77SSepherosa Ziehau 			    "failed to allocate tx data dmamap\n");
343415516c77SSepherosa Ziehau 			bus_dmamap_unload(txr->hn_tx_rndis_dtag,
343515516c77SSepherosa Ziehau 			    txd->rndis_pkt_dmap);
343615516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
343715516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
343815516c77SSepherosa Ziehau 			return error;
343915516c77SSepherosa Ziehau 		}
344015516c77SSepherosa Ziehau 
344115516c77SSepherosa Ziehau 		/* All set, put it to list */
344215516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_ONLIST;
344315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
344415516c77SSepherosa Ziehau 		SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
344515516c77SSepherosa Ziehau #else
344615516c77SSepherosa Ziehau 		buf_ring_enqueue(txr->hn_txdesc_br, txd);
344715516c77SSepherosa Ziehau #endif
344815516c77SSepherosa Ziehau 	}
344915516c77SSepherosa Ziehau 	txr->hn_txdesc_avail = txr->hn_txdesc_cnt;
345015516c77SSepherosa Ziehau 
345115516c77SSepherosa Ziehau 	if (sc->hn_tx_sysctl_tree != NULL) {
345215516c77SSepherosa Ziehau 		struct sysctl_oid_list *child;
345315516c77SSepherosa Ziehau 		struct sysctl_ctx_list *ctx;
345415516c77SSepherosa Ziehau 		char name[16];
345515516c77SSepherosa Ziehau 
345615516c77SSepherosa Ziehau 		/*
345715516c77SSepherosa Ziehau 		 * Create per TX ring sysctl tree:
345815516c77SSepherosa Ziehau 		 * dev.hn.UNIT.tx.RINGID
345915516c77SSepherosa Ziehau 		 */
346015516c77SSepherosa Ziehau 		ctx = device_get_sysctl_ctx(dev);
346115516c77SSepherosa Ziehau 		child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree);
346215516c77SSepherosa Ziehau 
346315516c77SSepherosa Ziehau 		snprintf(name, sizeof(name), "%d", id);
346415516c77SSepherosa Ziehau 		txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
346515516c77SSepherosa Ziehau 		    name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
346615516c77SSepherosa Ziehau 
346715516c77SSepherosa Ziehau 		if (txr->hn_tx_sysctl_tree != NULL) {
346815516c77SSepherosa Ziehau 			child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree);
346915516c77SSepherosa Ziehau 
347015516c77SSepherosa Ziehau 			SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail",
347115516c77SSepherosa Ziehau 			    CTLFLAG_RD, &txr->hn_txdesc_avail, 0,
347215516c77SSepherosa Ziehau 			    "# of available TX descs");
347323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
347423bf9e15SSepherosa Ziehau 			if (!hn_use_if_start)
347523bf9e15SSepherosa Ziehau #endif
347623bf9e15SSepherosa Ziehau 			{
347715516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive",
347815516c77SSepherosa Ziehau 				    CTLFLAG_RD, &txr->hn_oactive, 0,
347915516c77SSepherosa Ziehau 				    "over active");
348015516c77SSepherosa Ziehau 			}
348115516c77SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets",
348215516c77SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_pkts,
348315516c77SSepherosa Ziehau 			    "# of packets transmitted");
3484dc13fee6SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends",
3485dc13fee6SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_sends, "# of sends");
348615516c77SSepherosa Ziehau 		}
348715516c77SSepherosa Ziehau 	}
348815516c77SSepherosa Ziehau 
348915516c77SSepherosa Ziehau 	return 0;
349015516c77SSepherosa Ziehau }
349115516c77SSepherosa Ziehau 
349215516c77SSepherosa Ziehau static void
349315516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd)
349415516c77SSepherosa Ziehau {
349515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = txd->txr;
349615516c77SSepherosa Ziehau 
349715516c77SSepherosa Ziehau 	KASSERT(txd->m == NULL, ("still has mbuf installed"));
349815516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped"));
349915516c77SSepherosa Ziehau 
350015516c77SSepherosa Ziehau 	bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap);
350115516c77SSepherosa Ziehau 	bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt,
350215516c77SSepherosa Ziehau 	    txd->rndis_pkt_dmap);
350315516c77SSepherosa Ziehau 	bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap);
350415516c77SSepherosa Ziehau }
350515516c77SSepherosa Ziehau 
350615516c77SSepherosa Ziehau static void
350725641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd)
350825641fc7SSepherosa Ziehau {
350925641fc7SSepherosa Ziehau 
351025641fc7SSepherosa Ziehau 	KASSERT(txd->refs == 0 || txd->refs == 1,
351125641fc7SSepherosa Ziehau 	    ("invalid txd refs %d", txd->refs));
351225641fc7SSepherosa Ziehau 
351325641fc7SSepherosa Ziehau 	/* Aggregated txds will be freed by their aggregating txd. */
351425641fc7SSepherosa Ziehau 	if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) {
351525641fc7SSepherosa Ziehau 		int freed;
351625641fc7SSepherosa Ziehau 
351725641fc7SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
351825641fc7SSepherosa Ziehau 		KASSERT(freed, ("can't free txdesc"));
351925641fc7SSepherosa Ziehau 	}
352025641fc7SSepherosa Ziehau }
352125641fc7SSepherosa Ziehau 
352225641fc7SSepherosa Ziehau static void
352315516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr)
352415516c77SSepherosa Ziehau {
352525641fc7SSepherosa Ziehau 	int i;
352615516c77SSepherosa Ziehau 
352715516c77SSepherosa Ziehau 	if (txr->hn_txdesc == NULL)
352815516c77SSepherosa Ziehau 		return;
352915516c77SSepherosa Ziehau 
353025641fc7SSepherosa Ziehau 	/*
353125641fc7SSepherosa Ziehau 	 * NOTE:
353225641fc7SSepherosa Ziehau 	 * Because the freeing of aggregated txds will be deferred
353325641fc7SSepherosa Ziehau 	 * to the aggregating txd, two passes are used here:
353425641fc7SSepherosa Ziehau 	 * - The first pass GCes any pending txds.  This GC is necessary,
353525641fc7SSepherosa Ziehau 	 *   since if the channels are revoked, hypervisor will not
353625641fc7SSepherosa Ziehau 	 *   deliver send-done for all pending txds.
353725641fc7SSepherosa Ziehau 	 * - The second pass frees the busdma stuffs, i.e. after all txds
353825641fc7SSepherosa Ziehau 	 *   were freed.
353925641fc7SSepherosa Ziehau 	 */
354025641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
354125641fc7SSepherosa Ziehau 		hn_txdesc_gc(txr, &txr->hn_txdesc[i]);
354225641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
354325641fc7SSepherosa Ziehau 		hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]);
354415516c77SSepherosa Ziehau 
354515516c77SSepherosa Ziehau 	if (txr->hn_tx_data_dtag != NULL)
354615516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_data_dtag);
354715516c77SSepherosa Ziehau 	if (txr->hn_tx_rndis_dtag != NULL)
354815516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_rndis_dtag);
354915516c77SSepherosa Ziehau 
355015516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
355115516c77SSepherosa Ziehau 	buf_ring_free(txr->hn_txdesc_br, M_DEVBUF);
355215516c77SSepherosa Ziehau #endif
355315516c77SSepherosa Ziehau 
355415516c77SSepherosa Ziehau 	free(txr->hn_txdesc, M_DEVBUF);
355515516c77SSepherosa Ziehau 	txr->hn_txdesc = NULL;
355615516c77SSepherosa Ziehau 
355715516c77SSepherosa Ziehau 	if (txr->hn_mbuf_br != NULL)
355815516c77SSepherosa Ziehau 		buf_ring_free(txr->hn_mbuf_br, M_DEVBUF);
355915516c77SSepherosa Ziehau 
356015516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
356115516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_txlist_spin);
356215516c77SSepherosa Ziehau #endif
356315516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_tx_lock);
356415516c77SSepherosa Ziehau }
356515516c77SSepherosa Ziehau 
356615516c77SSepherosa Ziehau static int
356715516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt)
356815516c77SSepherosa Ziehau {
356915516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
357015516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
357115516c77SSepherosa Ziehau 	int i;
357215516c77SSepherosa Ziehau 
357315516c77SSepherosa Ziehau 	/*
357415516c77SSepherosa Ziehau 	 * Create TXBUF for chimney sending.
357515516c77SSepherosa Ziehau 	 *
357615516c77SSepherosa Ziehau 	 * NOTE: It is shared by all channels.
357715516c77SSepherosa Ziehau 	 */
357815516c77SSepherosa Ziehau 	sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev),
357915516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma,
358015516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
358115516c77SSepherosa Ziehau 	if (sc->hn_chim == NULL) {
358215516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate txbuf failed\n");
358315516c77SSepherosa Ziehau 		return (ENOMEM);
358415516c77SSepherosa Ziehau 	}
358515516c77SSepherosa Ziehau 
358615516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = ring_cnt;
358715516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
358815516c77SSepherosa Ziehau 
358915516c77SSepherosa Ziehau 	sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt,
359015516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
359115516c77SSepherosa Ziehau 
359215516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(sc->hn_dev);
359315516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev));
359415516c77SSepherosa Ziehau 
359515516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.tx sysctl tree */
359615516c77SSepherosa Ziehau 	sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx",
359715516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
359815516c77SSepherosa Ziehau 
359915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
360015516c77SSepherosa Ziehau 		int error;
360115516c77SSepherosa Ziehau 
360215516c77SSepherosa Ziehau 		error = hn_tx_ring_create(sc, i);
360315516c77SSepherosa Ziehau 		if (error)
360415516c77SSepherosa Ziehau 			return error;
360515516c77SSepherosa Ziehau 	}
360615516c77SSepherosa Ziehau 
360715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs",
360815516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
360915516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_no_txdescs),
361015516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs");
361115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed",
361215516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
361315516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_send_failed),
361415516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure");
361515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed",
361615516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
361715516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_txdma_failed),
361815516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure");
3619dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed",
3620dc13fee6SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
3621dc13fee6SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_flush_failed),
3622dc13fee6SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU",
3623dc13fee6SSepherosa Ziehau 	    "# of packet transmission aggregation flush failure");
362415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed",
362515516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
362615516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_collapsed),
362715516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed");
362815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney",
362915516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
363015516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney),
363115516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send");
363215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried",
363315516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
363415516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney_tried),
363515516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries");
363615516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt",
363715516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0,
363815516c77SSepherosa Ziehau 	    "# of total TX descs");
363915516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max",
364015516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_chim_szmax, 0,
364115516c77SSepherosa Ziehau 	    "Chimney send packet size upper boundary");
364215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size",
364315516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
364415516c77SSepherosa Ziehau 	    hn_chim_size_sysctl, "I", "Chimney send packet size limit");
364515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size",
364615516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
364715516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_direct_tx_size),
364815516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
364915516c77SSepherosa Ziehau 	    "Size of the packet for direct transmission");
365015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx",
365115516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
365215516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_sched_tx),
365315516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
365415516c77SSepherosa Ziehau 	    "Always schedule transmission "
365515516c77SSepherosa Ziehau 	    "instead of doing direct transmission");
365615516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt",
365715516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings");
365815516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse",
365915516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings");
3660dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax",
3661dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0,
3662dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation size");
3663dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax",
3664dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
3665dc13fee6SSepherosa Ziehau 	    hn_txagg_pktmax_sysctl, "I",
3666dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation packets");
3667dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align",
3668dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
3669dc13fee6SSepherosa Ziehau 	    hn_txagg_align_sysctl, "I",
3670dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation alignment");
367115516c77SSepherosa Ziehau 
367215516c77SSepherosa Ziehau 	return 0;
367315516c77SSepherosa Ziehau }
367415516c77SSepherosa Ziehau 
367515516c77SSepherosa Ziehau static void
367615516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size)
367715516c77SSepherosa Ziehau {
367815516c77SSepherosa Ziehau 	int i;
367915516c77SSepherosa Ziehau 
3680a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
368115516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_chim_size = chim_size;
368215516c77SSepherosa Ziehau }
368315516c77SSepherosa Ziehau 
368415516c77SSepherosa Ziehau static void
368515516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu)
368615516c77SSepherosa Ziehau {
368715516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
368815516c77SSepherosa Ziehau 	int tso_minlen;
368915516c77SSepherosa Ziehau 
369015516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0)
369115516c77SSepherosa Ziehau 		return;
369215516c77SSepherosa Ziehau 
369315516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_sgmin >= 2,
369415516c77SSepherosa Ziehau 	    ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin));
369515516c77SSepherosa Ziehau 	tso_minlen = sc->hn_ndis_tso_sgmin * mtu;
369615516c77SSepherosa Ziehau 
369715516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen &&
369815516c77SSepherosa Ziehau 	    sc->hn_ndis_tso_szmax <= IP_MAXPACKET,
369915516c77SSepherosa Ziehau 	    ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax));
370015516c77SSepherosa Ziehau 
370115516c77SSepherosa Ziehau 	if (tso_maxlen < tso_minlen)
370215516c77SSepherosa Ziehau 		tso_maxlen = tso_minlen;
370315516c77SSepherosa Ziehau 	else if (tso_maxlen > IP_MAXPACKET)
370415516c77SSepherosa Ziehau 		tso_maxlen = IP_MAXPACKET;
370515516c77SSepherosa Ziehau 	if (tso_maxlen > sc->hn_ndis_tso_szmax)
370615516c77SSepherosa Ziehau 		tso_maxlen = sc->hn_ndis_tso_szmax;
370715516c77SSepherosa Ziehau 	ifp->if_hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
370815516c77SSepherosa Ziehau 	if (bootverbose)
370915516c77SSepherosa Ziehau 		if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax);
371015516c77SSepherosa Ziehau }
371115516c77SSepherosa Ziehau 
371215516c77SSepherosa Ziehau static void
371315516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc)
371415516c77SSepherosa Ziehau {
371515516c77SSepherosa Ziehau 	uint64_t csum_assist;
371615516c77SSepherosa Ziehau 	int i;
371715516c77SSepherosa Ziehau 
371815516c77SSepherosa Ziehau 	hn_set_chim_size(sc, sc->hn_chim_szmax);
371915516c77SSepherosa Ziehau 	if (hn_tx_chimney_size > 0 &&
372015516c77SSepherosa Ziehau 	    hn_tx_chimney_size < sc->hn_chim_szmax)
372115516c77SSepherosa Ziehau 		hn_set_chim_size(sc, hn_tx_chimney_size);
372215516c77SSepherosa Ziehau 
372315516c77SSepherosa Ziehau 	csum_assist = 0;
372415516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_IPCS)
372515516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP;
372615516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP4CS)
372715516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_TCP;
372815516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP4CS)
372915516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_UDP;
373015516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP6CS)
373115516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_TCP;
373215516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP6CS)
373315516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_UDP;
373415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
373515516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_csum_assist = csum_assist;
373615516c77SSepherosa Ziehau 
373715516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_HASHVAL) {
373815516c77SSepherosa Ziehau 		/*
373915516c77SSepherosa Ziehau 		 * Support HASHVAL pktinfo on TX path.
374015516c77SSepherosa Ziehau 		 */
374115516c77SSepherosa Ziehau 		if (bootverbose)
374215516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n");
374315516c77SSepherosa Ziehau 		for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
374415516c77SSepherosa Ziehau 			sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL;
374515516c77SSepherosa Ziehau 	}
374615516c77SSepherosa Ziehau }
374715516c77SSepherosa Ziehau 
374815516c77SSepherosa Ziehau static void
374915516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc)
375015516c77SSepherosa Ziehau {
375115516c77SSepherosa Ziehau 	int i;
375215516c77SSepherosa Ziehau 
375315516c77SSepherosa Ziehau 	if (sc->hn_chim != NULL) {
37542494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) {
375515516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim);
37562494d735SSepherosa Ziehau 		} else {
37572494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
37582494d735SSepherosa Ziehau 			    "chimney sending buffer is referenced");
37592494d735SSepherosa Ziehau 		}
376015516c77SSepherosa Ziehau 		sc->hn_chim = NULL;
376115516c77SSepherosa Ziehau 	}
376215516c77SSepherosa Ziehau 
376315516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt == 0)
376415516c77SSepherosa Ziehau 		return;
376515516c77SSepherosa Ziehau 
376615516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
376715516c77SSepherosa Ziehau 		hn_tx_ring_destroy(&sc->hn_tx_ring[i]);
376815516c77SSepherosa Ziehau 
376915516c77SSepherosa Ziehau 	free(sc->hn_tx_ring, M_DEVBUF);
377015516c77SSepherosa Ziehau 	sc->hn_tx_ring = NULL;
377115516c77SSepherosa Ziehau 
377215516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = 0;
377315516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = 0;
377415516c77SSepherosa Ziehau }
377515516c77SSepherosa Ziehau 
377623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
377723bf9e15SSepherosa Ziehau 
377815516c77SSepherosa Ziehau static void
377915516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused)
378015516c77SSepherosa Ziehau {
378115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
378215516c77SSepherosa Ziehau 
378315516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
378415516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
378515516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
378615516c77SSepherosa Ziehau }
378715516c77SSepherosa Ziehau 
378823bf9e15SSepherosa Ziehau static int
378923bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len)
379023bf9e15SSepherosa Ziehau {
379123bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
379223bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
3793dc13fee6SSepherosa Ziehau 	int sched = 0;
379423bf9e15SSepherosa Ziehau 
379523bf9e15SSepherosa Ziehau 	KASSERT(hn_use_if_start,
379623bf9e15SSepherosa Ziehau 	    ("hn_start_locked is called, when if_start is disabled"));
379723bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
379823bf9e15SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
3799dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
380023bf9e15SSepherosa Ziehau 
380123bf9e15SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
3802dc13fee6SSepherosa Ziehau 		return (0);
380323bf9e15SSepherosa Ziehau 
380423bf9e15SSepherosa Ziehau 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
380523bf9e15SSepherosa Ziehau 	    IFF_DRV_RUNNING)
3806dc13fee6SSepherosa Ziehau 		return (0);
380723bf9e15SSepherosa Ziehau 
380823bf9e15SSepherosa Ziehau 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
380923bf9e15SSepherosa Ziehau 		struct hn_txdesc *txd;
381023bf9e15SSepherosa Ziehau 		struct mbuf *m_head;
381123bf9e15SSepherosa Ziehau 		int error;
381223bf9e15SSepherosa Ziehau 
381323bf9e15SSepherosa Ziehau 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
381423bf9e15SSepherosa Ziehau 		if (m_head == NULL)
381523bf9e15SSepherosa Ziehau 			break;
381623bf9e15SSepherosa Ziehau 
381723bf9e15SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
381823bf9e15SSepherosa Ziehau 			/*
381923bf9e15SSepherosa Ziehau 			 * This sending could be time consuming; let callers
382023bf9e15SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
382123bf9e15SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
382223bf9e15SSepherosa Ziehau 			 */
382323bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
3824dc13fee6SSepherosa Ziehau 			sched = 1;
3825dc13fee6SSepherosa Ziehau 			break;
382623bf9e15SSepherosa Ziehau 		}
382723bf9e15SSepherosa Ziehau 
3828edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
3829edd3f315SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
3830edd3f315SSepherosa Ziehau 			m_head = hn_tso_fixup(m_head);
3831edd3f315SSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
3832edd3f315SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
3833edd3f315SSepherosa Ziehau 				continue;
3834edd3f315SSepherosa Ziehau 			}
3835edd3f315SSepherosa Ziehau 		}
3836edd3f315SSepherosa Ziehau #endif
3837edd3f315SSepherosa Ziehau 
383823bf9e15SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
383923bf9e15SSepherosa Ziehau 		if (txd == NULL) {
384023bf9e15SSepherosa Ziehau 			txr->hn_no_txdescs++;
384123bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
384223bf9e15SSepherosa Ziehau 			atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
384323bf9e15SSepherosa Ziehau 			break;
384423bf9e15SSepherosa Ziehau 		}
384523bf9e15SSepherosa Ziehau 
3846dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
384723bf9e15SSepherosa Ziehau 		if (error) {
384823bf9e15SSepherosa Ziehau 			/* Both txd and m_head are freed */
3849dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
3850dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
385123bf9e15SSepherosa Ziehau 			continue;
385223bf9e15SSepherosa Ziehau 		}
385323bf9e15SSepherosa Ziehau 
3854dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
3855dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
3856dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
3857dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
3858dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
3859dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
3860dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
3861dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
3862dc13fee6SSepherosa Ziehau 					break;
3863dc13fee6SSepherosa Ziehau 				}
3864dc13fee6SSepherosa Ziehau 			} else {
3865dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
386623bf9e15SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
386723bf9e15SSepherosa Ziehau 				if (__predict_false(error)) {
386823bf9e15SSepherosa Ziehau 					/* txd is freed, but m_head is not */
386923bf9e15SSepherosa Ziehau 					IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
3870dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
3871dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
387223bf9e15SSepherosa Ziehau 					break;
387323bf9e15SSepherosa Ziehau 				}
387423bf9e15SSepherosa Ziehau 			}
3875dc13fee6SSepherosa Ziehau 		}
3876dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
3877dc13fee6SSepherosa Ziehau 		else {
3878dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
3879dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
3880dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
3881dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
3882dc13fee6SSepherosa Ziehau 		}
3883dc13fee6SSepherosa Ziehau #endif
3884dc13fee6SSepherosa Ziehau 	}
3885dc13fee6SSepherosa Ziehau 
3886dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
3887dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
3888dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
3889dc13fee6SSepherosa Ziehau 	return (sched);
389023bf9e15SSepherosa Ziehau }
389123bf9e15SSepherosa Ziehau 
389223bf9e15SSepherosa Ziehau static void
389323bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp)
389423bf9e15SSepherosa Ziehau {
389523bf9e15SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
389623bf9e15SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[0];
389723bf9e15SSepherosa Ziehau 
389823bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
389923bf9e15SSepherosa Ziehau 		goto do_sched;
390023bf9e15SSepherosa Ziehau 
390123bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
390223bf9e15SSepherosa Ziehau 		int sched;
390323bf9e15SSepherosa Ziehau 
390423bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
390523bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
390623bf9e15SSepherosa Ziehau 		if (!sched)
390723bf9e15SSepherosa Ziehau 			return;
390823bf9e15SSepherosa Ziehau 	}
390923bf9e15SSepherosa Ziehau do_sched:
391023bf9e15SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
391123bf9e15SSepherosa Ziehau }
391223bf9e15SSepherosa Ziehau 
391315516c77SSepherosa Ziehau static void
391415516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused)
391515516c77SSepherosa Ziehau {
391615516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
391715516c77SSepherosa Ziehau 
391815516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
391915516c77SSepherosa Ziehau 	atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE);
392015516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
392115516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
392215516c77SSepherosa Ziehau }
392315516c77SSepherosa Ziehau 
392423bf9e15SSepherosa Ziehau static void
392523bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr)
392623bf9e15SSepherosa Ziehau {
392723bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
392823bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
392923bf9e15SSepherosa Ziehau 
393023bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
393123bf9e15SSepherosa Ziehau 
393223bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
393323bf9e15SSepherosa Ziehau 		goto do_sched;
393423bf9e15SSepherosa Ziehau 
393523bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
393623bf9e15SSepherosa Ziehau 		int sched;
393723bf9e15SSepherosa Ziehau 
393823bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
393923bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
394023bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
394123bf9e15SSepherosa Ziehau 		if (sched) {
394223bf9e15SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
394323bf9e15SSepherosa Ziehau 			    &txr->hn_tx_task);
394423bf9e15SSepherosa Ziehau 		}
394523bf9e15SSepherosa Ziehau 	} else {
394623bf9e15SSepherosa Ziehau do_sched:
394723bf9e15SSepherosa Ziehau 		/*
394823bf9e15SSepherosa Ziehau 		 * Release the OACTIVE earlier, with the hope, that
394923bf9e15SSepherosa Ziehau 		 * others could catch up.  The task will clear the
395023bf9e15SSepherosa Ziehau 		 * flag again with the hn_tx_lock to avoid possible
395123bf9e15SSepherosa Ziehau 		 * races.
395223bf9e15SSepherosa Ziehau 		 */
395323bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
395423bf9e15SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
395523bf9e15SSepherosa Ziehau 	}
395623bf9e15SSepherosa Ziehau }
395723bf9e15SSepherosa Ziehau 
395823bf9e15SSepherosa Ziehau #endif	/* HN_IFSTART_SUPPORT */
395923bf9e15SSepherosa Ziehau 
396015516c77SSepherosa Ziehau static int
396115516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len)
396215516c77SSepherosa Ziehau {
396315516c77SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
396415516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
396515516c77SSepherosa Ziehau 	struct mbuf *m_head;
3966dc13fee6SSepherosa Ziehau 	int sched = 0;
396715516c77SSepherosa Ziehau 
396815516c77SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
396923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
397015516c77SSepherosa Ziehau 	KASSERT(hn_use_if_start == 0,
397115516c77SSepherosa Ziehau 	    ("hn_xmit is called, when if_start is enabled"));
397223bf9e15SSepherosa Ziehau #endif
3973dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
397415516c77SSepherosa Ziehau 
397515516c77SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
3976dc13fee6SSepherosa Ziehau 		return (0);
397715516c77SSepherosa Ziehau 
397815516c77SSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive)
3979dc13fee6SSepherosa Ziehau 		return (0);
398015516c77SSepherosa Ziehau 
398115516c77SSepherosa Ziehau 	while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) {
398215516c77SSepherosa Ziehau 		struct hn_txdesc *txd;
398315516c77SSepherosa Ziehau 		int error;
398415516c77SSepherosa Ziehau 
398515516c77SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
398615516c77SSepherosa Ziehau 			/*
398715516c77SSepherosa Ziehau 			 * This sending could be time consuming; let callers
398815516c77SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
398915516c77SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
399015516c77SSepherosa Ziehau 			 */
399115516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
3992dc13fee6SSepherosa Ziehau 			sched = 1;
3993dc13fee6SSepherosa Ziehau 			break;
399415516c77SSepherosa Ziehau 		}
399515516c77SSepherosa Ziehau 
399615516c77SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
399715516c77SSepherosa Ziehau 		if (txd == NULL) {
399815516c77SSepherosa Ziehau 			txr->hn_no_txdescs++;
399915516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
400015516c77SSepherosa Ziehau 			txr->hn_oactive = 1;
400115516c77SSepherosa Ziehau 			break;
400215516c77SSepherosa Ziehau 		}
400315516c77SSepherosa Ziehau 
4004dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
400515516c77SSepherosa Ziehau 		if (error) {
400615516c77SSepherosa Ziehau 			/* Both txd and m_head are freed; discard */
4007dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
4008dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
400915516c77SSepherosa Ziehau 			drbr_advance(ifp, txr->hn_mbuf_br);
401015516c77SSepherosa Ziehau 			continue;
401115516c77SSepherosa Ziehau 		}
401215516c77SSepherosa Ziehau 
4013dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
4014dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
4015dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
4016dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
4017dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
401815516c77SSepherosa Ziehau 				if (__predict_false(error)) {
401915516c77SSepherosa Ziehau 					txr->hn_oactive = 1;
402015516c77SSepherosa Ziehau 					break;
402115516c77SSepherosa Ziehau 				}
4022dc13fee6SSepherosa Ziehau 			} else {
4023dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
4024dc13fee6SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
4025dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
4026dc13fee6SSepherosa Ziehau 					/* txd is freed, but m_head is not */
4027dc13fee6SSepherosa Ziehau 					drbr_putback(ifp, txr->hn_mbuf_br,
4028dc13fee6SSepherosa Ziehau 					    m_head);
4029dc13fee6SSepherosa Ziehau 					txr->hn_oactive = 1;
4030dc13fee6SSepherosa Ziehau 					break;
4031dc13fee6SSepherosa Ziehau 				}
4032dc13fee6SSepherosa Ziehau 			}
4033dc13fee6SSepherosa Ziehau 		}
4034dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
4035dc13fee6SSepherosa Ziehau 		else {
4036dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
4037dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
4038dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
4039dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
4040dc13fee6SSepherosa Ziehau 		}
4041dc13fee6SSepherosa Ziehau #endif
404215516c77SSepherosa Ziehau 
404315516c77SSepherosa Ziehau 		/* Sent */
404415516c77SSepherosa Ziehau 		drbr_advance(ifp, txr->hn_mbuf_br);
404515516c77SSepherosa Ziehau 	}
4046dc13fee6SSepherosa Ziehau 
4047dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
4048dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
4049dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
4050dc13fee6SSepherosa Ziehau 	return (sched);
405115516c77SSepherosa Ziehau }
405215516c77SSepherosa Ziehau 
405315516c77SSepherosa Ziehau static int
405415516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m)
405515516c77SSepherosa Ziehau {
405615516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
405715516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
405815516c77SSepherosa Ziehau 	int error, idx = 0;
405915516c77SSepherosa Ziehau 
4060edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
4061edd3f315SSepherosa Ziehau 	/*
4062edd3f315SSepherosa Ziehau 	 * Perform TSO packet header fixup now, since the TSO
4063edd3f315SSepherosa Ziehau 	 * packet header should be cache-hot.
4064edd3f315SSepherosa Ziehau 	 */
4065edd3f315SSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
4066edd3f315SSepherosa Ziehau 		m = hn_tso_fixup(m);
4067edd3f315SSepherosa Ziehau 		if (__predict_false(m == NULL)) {
4068edd3f315SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
4069edd3f315SSepherosa Ziehau 			return EIO;
4070edd3f315SSepherosa Ziehau 		}
4071edd3f315SSepherosa Ziehau 	}
4072edd3f315SSepherosa Ziehau #endif
4073edd3f315SSepherosa Ziehau 
407415516c77SSepherosa Ziehau 	/*
407515516c77SSepherosa Ziehau 	 * Select the TX ring based on flowid
407615516c77SSepherosa Ziehau 	 */
407715516c77SSepherosa Ziehau 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
407815516c77SSepherosa Ziehau 		idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse;
407915516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[idx];
408015516c77SSepherosa Ziehau 
408115516c77SSepherosa Ziehau 	error = drbr_enqueue(ifp, txr->hn_mbuf_br, m);
408215516c77SSepherosa Ziehau 	if (error) {
408315516c77SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
408415516c77SSepherosa Ziehau 		return error;
408515516c77SSepherosa Ziehau 	}
408615516c77SSepherosa Ziehau 
408715516c77SSepherosa Ziehau 	if (txr->hn_oactive)
408815516c77SSepherosa Ziehau 		return 0;
408915516c77SSepherosa Ziehau 
409015516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
409115516c77SSepherosa Ziehau 		goto do_sched;
409215516c77SSepherosa Ziehau 
409315516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
409415516c77SSepherosa Ziehau 		int sched;
409515516c77SSepherosa Ziehau 
409615516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
409715516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
409815516c77SSepherosa Ziehau 		if (!sched)
409915516c77SSepherosa Ziehau 			return 0;
410015516c77SSepherosa Ziehau 	}
410115516c77SSepherosa Ziehau do_sched:
410215516c77SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
410315516c77SSepherosa Ziehau 	return 0;
410415516c77SSepherosa Ziehau }
410515516c77SSepherosa Ziehau 
410615516c77SSepherosa Ziehau static void
410715516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr)
410815516c77SSepherosa Ziehau {
410915516c77SSepherosa Ziehau 	struct mbuf *m;
411015516c77SSepherosa Ziehau 
411115516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
411215516c77SSepherosa Ziehau 	while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL)
411315516c77SSepherosa Ziehau 		m_freem(m);
411415516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
411515516c77SSepherosa Ziehau }
411615516c77SSepherosa Ziehau 
411715516c77SSepherosa Ziehau static void
411815516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp)
411915516c77SSepherosa Ziehau {
412015516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
412115516c77SSepherosa Ziehau 	int i;
412215516c77SSepherosa Ziehau 
412315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
412415516c77SSepherosa Ziehau 		hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
412515516c77SSepherosa Ziehau 	if_qflush(ifp);
412615516c77SSepherosa Ziehau }
412715516c77SSepherosa Ziehau 
412815516c77SSepherosa Ziehau static void
412915516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr)
413015516c77SSepherosa Ziehau {
413115516c77SSepherosa Ziehau 
413215516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
413315516c77SSepherosa Ziehau 		goto do_sched;
413415516c77SSepherosa Ziehau 
413515516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
413615516c77SSepherosa Ziehau 		int sched;
413715516c77SSepherosa Ziehau 
413815516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
413915516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
414015516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
414115516c77SSepherosa Ziehau 		if (sched) {
414215516c77SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
414315516c77SSepherosa Ziehau 			    &txr->hn_tx_task);
414415516c77SSepherosa Ziehau 		}
414515516c77SSepherosa Ziehau 	} else {
414615516c77SSepherosa Ziehau do_sched:
414715516c77SSepherosa Ziehau 		/*
414815516c77SSepherosa Ziehau 		 * Release the oactive earlier, with the hope, that
414915516c77SSepherosa Ziehau 		 * others could catch up.  The task will clear the
415015516c77SSepherosa Ziehau 		 * oactive again with the hn_tx_lock to avoid possible
415115516c77SSepherosa Ziehau 		 * races.
415215516c77SSepherosa Ziehau 		 */
415315516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
415415516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
415515516c77SSepherosa Ziehau 	}
415615516c77SSepherosa Ziehau }
415715516c77SSepherosa Ziehau 
415815516c77SSepherosa Ziehau static void
415915516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused)
416015516c77SSepherosa Ziehau {
416115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
416215516c77SSepherosa Ziehau 
416315516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
416415516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
416515516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
416615516c77SSepherosa Ziehau }
416715516c77SSepherosa Ziehau 
416815516c77SSepherosa Ziehau static void
416915516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused)
417015516c77SSepherosa Ziehau {
417115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
417215516c77SSepherosa Ziehau 
417315516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
417415516c77SSepherosa Ziehau 	txr->hn_oactive = 0;
417515516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
417615516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
417715516c77SSepherosa Ziehau }
417815516c77SSepherosa Ziehau 
417915516c77SSepherosa Ziehau static int
418015516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan)
418115516c77SSepherosa Ziehau {
418215516c77SSepherosa Ziehau 	struct vmbus_chan_br cbr;
418315516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
418415516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = NULL;
418515516c77SSepherosa Ziehau 	int idx, error;
418615516c77SSepherosa Ziehau 
418715516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
418815516c77SSepherosa Ziehau 
418915516c77SSepherosa Ziehau 	/*
419015516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
419115516c77SSepherosa Ziehau 	 */
419215516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
419315516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
419415516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
419515516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
419615516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0,
419715516c77SSepherosa Ziehau 	    ("RX ring %d already attached", idx));
419815516c77SSepherosa Ziehau 	rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED;
419915516c77SSepherosa Ziehau 
420015516c77SSepherosa Ziehau 	if (bootverbose) {
420115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n",
420215516c77SSepherosa Ziehau 		    idx, vmbus_chan_id(chan));
420315516c77SSepherosa Ziehau 	}
420415516c77SSepherosa Ziehau 
420515516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
420615516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[idx];
420715516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0,
420815516c77SSepherosa Ziehau 		    ("TX ring %d already attached", idx));
420915516c77SSepherosa Ziehau 		txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED;
421015516c77SSepherosa Ziehau 
421115516c77SSepherosa Ziehau 		txr->hn_chan = chan;
421215516c77SSepherosa Ziehau 		if (bootverbose) {
421315516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n",
421415516c77SSepherosa Ziehau 			    idx, vmbus_chan_id(chan));
421515516c77SSepherosa Ziehau 		}
421615516c77SSepherosa Ziehau 	}
421715516c77SSepherosa Ziehau 
421815516c77SSepherosa Ziehau 	/* Bind this channel to a proper CPU. */
4219*0e11868dSSepherosa Ziehau 	vmbus_chan_cpu_set(chan, HN_RING_IDX2CPU(sc, idx));
422015516c77SSepherosa Ziehau 
422115516c77SSepherosa Ziehau 	/*
422215516c77SSepherosa Ziehau 	 * Open this channel
422315516c77SSepherosa Ziehau 	 */
422415516c77SSepherosa Ziehau 	cbr.cbr = rxr->hn_br;
422515516c77SSepherosa Ziehau 	cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr;
422615516c77SSepherosa Ziehau 	cbr.cbr_txsz = HN_TXBR_SIZE;
422715516c77SSepherosa Ziehau 	cbr.cbr_rxsz = HN_RXBR_SIZE;
422815516c77SSepherosa Ziehau 	error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr);
422915516c77SSepherosa Ziehau 	if (error) {
423071e8ac56SSepherosa Ziehau 		if (error == EISCONN) {
423171e8ac56SSepherosa Ziehau 			if_printf(sc->hn_ifp, "bufring is connected after "
423271e8ac56SSepherosa Ziehau 			    "chan%u open failure\n", vmbus_chan_id(chan));
423371e8ac56SSepherosa Ziehau 			rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
423471e8ac56SSepherosa Ziehau 		} else {
423515516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "open chan%u failed: %d\n",
423615516c77SSepherosa Ziehau 			    vmbus_chan_id(chan), error);
423771e8ac56SSepherosa Ziehau 		}
423815516c77SSepherosa Ziehau 	}
423915516c77SSepherosa Ziehau 	return (error);
424015516c77SSepherosa Ziehau }
424115516c77SSepherosa Ziehau 
424215516c77SSepherosa Ziehau static void
424315516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan)
424415516c77SSepherosa Ziehau {
424515516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
42462494d735SSepherosa Ziehau 	int idx, error;
424715516c77SSepherosa Ziehau 
424815516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
424915516c77SSepherosa Ziehau 
425015516c77SSepherosa Ziehau 	/*
425115516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
425215516c77SSepherosa Ziehau 	 */
425315516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
425415516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
425515516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
425615516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
425715516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED),
425815516c77SSepherosa Ziehau 	    ("RX ring %d is not attached", idx));
425915516c77SSepherosa Ziehau 	rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
426015516c77SSepherosa Ziehau 
426115516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
426215516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[idx];
426315516c77SSepherosa Ziehau 
426415516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED),
426515516c77SSepherosa Ziehau 		    ("TX ring %d is not attached attached", idx));
426615516c77SSepherosa Ziehau 		txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
426715516c77SSepherosa Ziehau 	}
426815516c77SSepherosa Ziehau 
426915516c77SSepherosa Ziehau 	/*
427015516c77SSepherosa Ziehau 	 * Close this channel.
427115516c77SSepherosa Ziehau 	 *
427215516c77SSepherosa Ziehau 	 * NOTE:
427315516c77SSepherosa Ziehau 	 * Channel closing does _not_ destroy the target channel.
427415516c77SSepherosa Ziehau 	 */
42752494d735SSepherosa Ziehau 	error = vmbus_chan_close_direct(chan);
42762494d735SSepherosa Ziehau 	if (error == EISCONN) {
4277aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u bufring is connected "
4278aa1a2adcSSepherosa Ziehau 		    "after being closed\n", vmbus_chan_id(chan));
42792494d735SSepherosa Ziehau 		rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
42802494d735SSepherosa Ziehau 	} else if (error) {
4281aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u close failed: %d\n",
4282aa1a2adcSSepherosa Ziehau 		    vmbus_chan_id(chan), error);
42832494d735SSepherosa Ziehau 	}
428415516c77SSepherosa Ziehau }
428515516c77SSepherosa Ziehau 
428615516c77SSepherosa Ziehau static int
428715516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc)
428815516c77SSepherosa Ziehau {
428915516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
429015516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
429115516c77SSepherosa Ziehau 	int i, error = 0;
429215516c77SSepherosa Ziehau 
429371e8ac56SSepherosa Ziehau 	KASSERT(subchan_cnt > 0, ("no sub-channels"));
429415516c77SSepherosa Ziehau 
429515516c77SSepherosa Ziehau 	/* Attach the sub-channels. */
429615516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
429715516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i) {
429871e8ac56SSepherosa Ziehau 		int error1;
429971e8ac56SSepherosa Ziehau 
430071e8ac56SSepherosa Ziehau 		error1 = hn_chan_attach(sc, subchans[i]);
430171e8ac56SSepherosa Ziehau 		if (error1) {
430271e8ac56SSepherosa Ziehau 			error = error1;
430371e8ac56SSepherosa Ziehau 			/* Move on; all channels will be detached later. */
430471e8ac56SSepherosa Ziehau 		}
430515516c77SSepherosa Ziehau 	}
430615516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
430715516c77SSepherosa Ziehau 
430815516c77SSepherosa Ziehau 	if (error) {
430915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error);
431015516c77SSepherosa Ziehau 	} else {
431115516c77SSepherosa Ziehau 		if (bootverbose) {
431215516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "%d sub-channels attached\n",
431315516c77SSepherosa Ziehau 			    subchan_cnt);
431415516c77SSepherosa Ziehau 		}
431515516c77SSepherosa Ziehau 	}
431615516c77SSepherosa Ziehau 	return (error);
431715516c77SSepherosa Ziehau }
431815516c77SSepherosa Ziehau 
431915516c77SSepherosa Ziehau static void
432015516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc)
432115516c77SSepherosa Ziehau {
432215516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
432315516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
432415516c77SSepherosa Ziehau 	int i;
432515516c77SSepherosa Ziehau 
432615516c77SSepherosa Ziehau 	if (subchan_cnt == 0)
432715516c77SSepherosa Ziehau 		goto back;
432815516c77SSepherosa Ziehau 
432915516c77SSepherosa Ziehau 	/* Detach the sub-channels. */
433015516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
433115516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i)
433215516c77SSepherosa Ziehau 		hn_chan_detach(sc, subchans[i]);
433315516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
433415516c77SSepherosa Ziehau 
433515516c77SSepherosa Ziehau back:
433615516c77SSepherosa Ziehau 	/*
433715516c77SSepherosa Ziehau 	 * Detach the primary channel, _after_ all sub-channels
433815516c77SSepherosa Ziehau 	 * are detached.
433915516c77SSepherosa Ziehau 	 */
434015516c77SSepherosa Ziehau 	hn_chan_detach(sc, sc->hn_prichan);
434115516c77SSepherosa Ziehau 
434215516c77SSepherosa Ziehau 	/* Wait for sub-channels to be destroyed, if any. */
434315516c77SSepherosa Ziehau 	vmbus_subchan_drain(sc->hn_prichan);
434415516c77SSepherosa Ziehau 
434515516c77SSepherosa Ziehau #ifdef INVARIANTS
434615516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
434715516c77SSepherosa Ziehau 		KASSERT((sc->hn_rx_ring[i].hn_rx_flags &
434815516c77SSepherosa Ziehau 		    HN_RX_FLAG_ATTACHED) == 0,
434915516c77SSepherosa Ziehau 		    ("%dth RX ring is still attached", i));
435015516c77SSepherosa Ziehau 	}
435115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
435215516c77SSepherosa Ziehau 		KASSERT((sc->hn_tx_ring[i].hn_tx_flags &
435315516c77SSepherosa Ziehau 		    HN_TX_FLAG_ATTACHED) == 0,
435415516c77SSepherosa Ziehau 		    ("%dth TX ring is still attached", i));
435515516c77SSepherosa Ziehau 	}
435615516c77SSepherosa Ziehau #endif
435715516c77SSepherosa Ziehau }
435815516c77SSepherosa Ziehau 
435915516c77SSepherosa Ziehau static int
436015516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch)
436115516c77SSepherosa Ziehau {
436215516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
436315516c77SSepherosa Ziehau 	int nchan, rxr_cnt, error;
436415516c77SSepherosa Ziehau 
436515516c77SSepherosa Ziehau 	nchan = *nsubch + 1;
436615516c77SSepherosa Ziehau 	if (nchan == 1) {
436715516c77SSepherosa Ziehau 		/*
436815516c77SSepherosa Ziehau 		 * Multiple RX/TX rings are not requested.
436915516c77SSepherosa Ziehau 		 */
437015516c77SSepherosa Ziehau 		*nsubch = 0;
437115516c77SSepherosa Ziehau 		return (0);
437215516c77SSepherosa Ziehau 	}
437315516c77SSepherosa Ziehau 
437415516c77SSepherosa Ziehau 	/*
437515516c77SSepherosa Ziehau 	 * Query RSS capabilities, e.g. # of RX rings, and # of indirect
437615516c77SSepherosa Ziehau 	 * table entries.
437715516c77SSepherosa Ziehau 	 */
437815516c77SSepherosa Ziehau 	error = hn_rndis_query_rsscaps(sc, &rxr_cnt);
437915516c77SSepherosa Ziehau 	if (error) {
438015516c77SSepherosa Ziehau 		/* No RSS; this is benign. */
438115516c77SSepherosa Ziehau 		*nsubch = 0;
438215516c77SSepherosa Ziehau 		return (0);
438315516c77SSepherosa Ziehau 	}
438415516c77SSepherosa Ziehau 	if (bootverbose) {
438515516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
438615516c77SSepherosa Ziehau 		    rxr_cnt, nchan);
438715516c77SSepherosa Ziehau 	}
438815516c77SSepherosa Ziehau 
438915516c77SSepherosa Ziehau 	if (nchan > rxr_cnt)
439015516c77SSepherosa Ziehau 		nchan = rxr_cnt;
439115516c77SSepherosa Ziehau 	if (nchan == 1) {
439215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n");
439315516c77SSepherosa Ziehau 		*nsubch = 0;
439415516c77SSepherosa Ziehau 		return (0);
439515516c77SSepherosa Ziehau 	}
439615516c77SSepherosa Ziehau 
439715516c77SSepherosa Ziehau 	/*
439815516c77SSepherosa Ziehau 	 * Allocate sub-channels from NVS.
439915516c77SSepherosa Ziehau 	 */
440015516c77SSepherosa Ziehau 	*nsubch = nchan - 1;
440115516c77SSepherosa Ziehau 	error = hn_nvs_alloc_subchans(sc, nsubch);
440215516c77SSepherosa Ziehau 	if (error || *nsubch == 0) {
440315516c77SSepherosa Ziehau 		/* Failed to allocate sub-channels. */
440415516c77SSepherosa Ziehau 		*nsubch = 0;
440515516c77SSepherosa Ziehau 		return (0);
440615516c77SSepherosa Ziehau 	}
440715516c77SSepherosa Ziehau 
440815516c77SSepherosa Ziehau 	/*
440915516c77SSepherosa Ziehau 	 * Wait for all sub-channels to become ready before moving on.
441015516c77SSepherosa Ziehau 	 */
441115516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch);
441215516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, *nsubch);
441315516c77SSepherosa Ziehau 	return (0);
441415516c77SSepherosa Ziehau }
441515516c77SSepherosa Ziehau 
44162494d735SSepherosa Ziehau static bool
44172494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc)
44182494d735SSepherosa Ziehau {
44192494d735SSepherosa Ziehau 	int i;
44202494d735SSepherosa Ziehau 
44212494d735SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_ERRORS)
44222494d735SSepherosa Ziehau 		return (false);
44232494d735SSepherosa Ziehau 
44242494d735SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
44252494d735SSepherosa Ziehau 		const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
44262494d735SSepherosa Ziehau 
44272494d735SSepherosa Ziehau 		if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF)
44282494d735SSepherosa Ziehau 			return (false);
44292494d735SSepherosa Ziehau 	}
44302494d735SSepherosa Ziehau 	return (true);
44312494d735SSepherosa Ziehau }
44322494d735SSepherosa Ziehau 
443315516c77SSepherosa Ziehau static int
443415516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu)
443515516c77SSepherosa Ziehau {
443671e8ac56SSepherosa Ziehau #define ATTACHED_NVS		0x0002
443771e8ac56SSepherosa Ziehau #define ATTACHED_RNDIS		0x0004
443871e8ac56SSepherosa Ziehau 
443915516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
444015516c77SSepherosa Ziehau 	int error, nsubch, nchan, i;
444171e8ac56SSepherosa Ziehau 	uint32_t old_caps, attached = 0;
444215516c77SSepherosa Ziehau 
444315516c77SSepherosa Ziehau 	KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0,
444415516c77SSepherosa Ziehau 	    ("synthetic parts were attached"));
444515516c77SSepherosa Ziehau 
44462494d735SSepherosa Ziehau 	if (!hn_synth_attachable(sc))
44472494d735SSepherosa Ziehau 		return (ENXIO);
44482494d735SSepherosa Ziehau 
444915516c77SSepherosa Ziehau 	/* Save capabilities for later verification. */
445015516c77SSepherosa Ziehau 	old_caps = sc->hn_caps;
445115516c77SSepherosa Ziehau 	sc->hn_caps = 0;
445215516c77SSepherosa Ziehau 
445315516c77SSepherosa Ziehau 	/* Clear RSS stuffs. */
445415516c77SSepherosa Ziehau 	sc->hn_rss_ind_size = 0;
445515516c77SSepherosa Ziehau 	sc->hn_rss_hash = 0;
445615516c77SSepherosa Ziehau 
445715516c77SSepherosa Ziehau 	/*
445815516c77SSepherosa Ziehau 	 * Attach the primary channel _before_ attaching NVS and RNDIS.
445915516c77SSepherosa Ziehau 	 */
446015516c77SSepherosa Ziehau 	error = hn_chan_attach(sc, sc->hn_prichan);
446115516c77SSepherosa Ziehau 	if (error)
446271e8ac56SSepherosa Ziehau 		goto failed;
446315516c77SSepherosa Ziehau 
446415516c77SSepherosa Ziehau 	/*
446515516c77SSepherosa Ziehau 	 * Attach NVS.
446615516c77SSepherosa Ziehau 	 */
446715516c77SSepherosa Ziehau 	error = hn_nvs_attach(sc, mtu);
446815516c77SSepherosa Ziehau 	if (error)
446971e8ac56SSepherosa Ziehau 		goto failed;
447071e8ac56SSepherosa Ziehau 	attached |= ATTACHED_NVS;
447115516c77SSepherosa Ziehau 
447215516c77SSepherosa Ziehau 	/*
447315516c77SSepherosa Ziehau 	 * Attach RNDIS _after_ NVS is attached.
447415516c77SSepherosa Ziehau 	 */
447515516c77SSepherosa Ziehau 	error = hn_rndis_attach(sc, mtu);
447615516c77SSepherosa Ziehau 	if (error)
447771e8ac56SSepherosa Ziehau 		goto failed;
447871e8ac56SSepherosa Ziehau 	attached |= ATTACHED_RNDIS;
447915516c77SSepherosa Ziehau 
448015516c77SSepherosa Ziehau 	/*
448115516c77SSepherosa Ziehau 	 * Make sure capabilities are not changed.
448215516c77SSepherosa Ziehau 	 */
448315516c77SSepherosa Ziehau 	if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) {
448415516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n",
448515516c77SSepherosa Ziehau 		    old_caps, sc->hn_caps);
448671e8ac56SSepherosa Ziehau 		error = ENXIO;
448771e8ac56SSepherosa Ziehau 		goto failed;
448815516c77SSepherosa Ziehau 	}
448915516c77SSepherosa Ziehau 
449015516c77SSepherosa Ziehau 	/*
449115516c77SSepherosa Ziehau 	 * Allocate sub-channels for multi-TX/RX rings.
449215516c77SSepherosa Ziehau 	 *
449315516c77SSepherosa Ziehau 	 * NOTE:
449415516c77SSepherosa Ziehau 	 * The # of RX rings that can be used is equivalent to the # of
449515516c77SSepherosa Ziehau 	 * channels to be requested.
449615516c77SSepherosa Ziehau 	 */
449715516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_cnt - 1;
449815516c77SSepherosa Ziehau 	error = hn_synth_alloc_subchans(sc, &nsubch);
449915516c77SSepherosa Ziehau 	if (error)
450071e8ac56SSepherosa Ziehau 		goto failed;
450171e8ac56SSepherosa Ziehau 	/* NOTE: _Full_ synthetic parts detach is required now. */
450271e8ac56SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED;
450315516c77SSepherosa Ziehau 
450471e8ac56SSepherosa Ziehau 	/*
450571e8ac56SSepherosa Ziehau 	 * Set the # of TX/RX rings that could be used according to
450671e8ac56SSepherosa Ziehau 	 * the # of channels that NVS offered.
450771e8ac56SSepherosa Ziehau 	 */
450815516c77SSepherosa Ziehau 	nchan = nsubch + 1;
450971e8ac56SSepherosa Ziehau 	hn_set_ring_inuse(sc, nchan);
451015516c77SSepherosa Ziehau 	if (nchan == 1) {
451115516c77SSepherosa Ziehau 		/* Only the primary channel can be used; done */
451215516c77SSepherosa Ziehau 		goto back;
451315516c77SSepherosa Ziehau 	}
451415516c77SSepherosa Ziehau 
451515516c77SSepherosa Ziehau 	/*
451671e8ac56SSepherosa Ziehau 	 * Attach the sub-channels.
4517afd4971bSSepherosa Ziehau 	 *
4518afd4971bSSepherosa Ziehau 	 * NOTE: hn_set_ring_inuse() _must_ have been called.
451915516c77SSepherosa Ziehau 	 */
452071e8ac56SSepherosa Ziehau 	error = hn_attach_subchans(sc);
452171e8ac56SSepherosa Ziehau 	if (error)
452271e8ac56SSepherosa Ziehau 		goto failed;
452315516c77SSepherosa Ziehau 
452471e8ac56SSepherosa Ziehau 	/*
452571e8ac56SSepherosa Ziehau 	 * Configure RSS key and indirect table _after_ all sub-channels
452671e8ac56SSepherosa Ziehau 	 * are attached.
452771e8ac56SSepherosa Ziehau 	 */
452815516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) {
452915516c77SSepherosa Ziehau 		/*
453015516c77SSepherosa Ziehau 		 * RSS key is not set yet; set it to the default RSS key.
453115516c77SSepherosa Ziehau 		 */
453215516c77SSepherosa Ziehau 		if (bootverbose)
453315516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS key\n");
453415516c77SSepherosa Ziehau 		memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key));
453515516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
453615516c77SSepherosa Ziehau 	}
453715516c77SSepherosa Ziehau 
453815516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) {
453915516c77SSepherosa Ziehau 		/*
454015516c77SSepherosa Ziehau 		 * RSS indirect table is not set yet; set it up in round-
454115516c77SSepherosa Ziehau 		 * robin fashion.
454215516c77SSepherosa Ziehau 		 */
454315516c77SSepherosa Ziehau 		if (bootverbose) {
454415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS indirect "
454515516c77SSepherosa Ziehau 			    "table\n");
454615516c77SSepherosa Ziehau 		}
454715516c77SSepherosa Ziehau 		for (i = 0; i < NDIS_HASH_INDCNT; ++i)
454815516c77SSepherosa Ziehau 			rss->rss_ind[i] = i % nchan;
454915516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSIND;
455015516c77SSepherosa Ziehau 	} else {
455115516c77SSepherosa Ziehau 		/*
455215516c77SSepherosa Ziehau 		 * # of usable channels may be changed, so we have to
455315516c77SSepherosa Ziehau 		 * make sure that all entries in RSS indirect table
455415516c77SSepherosa Ziehau 		 * are valid.
4555afd4971bSSepherosa Ziehau 		 *
4556afd4971bSSepherosa Ziehau 		 * NOTE: hn_set_ring_inuse() _must_ have been called.
455715516c77SSepherosa Ziehau 		 */
4558afd4971bSSepherosa Ziehau 		hn_rss_ind_fixup(sc);
455915516c77SSepherosa Ziehau 	}
456015516c77SSepherosa Ziehau 
456115516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
456215516c77SSepherosa Ziehau 	if (error)
456371e8ac56SSepherosa Ziehau 		goto failed;
456471e8ac56SSepherosa Ziehau back:
4565dc13fee6SSepherosa Ziehau 	/*
4566dc13fee6SSepherosa Ziehau 	 * Fixup transmission aggregation setup.
4567dc13fee6SSepherosa Ziehau 	 */
4568dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
456915516c77SSepherosa Ziehau 	return (0);
457071e8ac56SSepherosa Ziehau 
457171e8ac56SSepherosa Ziehau failed:
457271e8ac56SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
457371e8ac56SSepherosa Ziehau 		hn_synth_detach(sc);
457471e8ac56SSepherosa Ziehau 	} else {
457571e8ac56SSepherosa Ziehau 		if (attached & ATTACHED_RNDIS)
457671e8ac56SSepherosa Ziehau 			hn_rndis_detach(sc);
457771e8ac56SSepherosa Ziehau 		if (attached & ATTACHED_NVS)
457871e8ac56SSepherosa Ziehau 			hn_nvs_detach(sc);
457971e8ac56SSepherosa Ziehau 		hn_chan_detach(sc, sc->hn_prichan);
458071e8ac56SSepherosa Ziehau 		/* Restore old capabilities. */
458171e8ac56SSepherosa Ziehau 		sc->hn_caps = old_caps;
458271e8ac56SSepherosa Ziehau 	}
458371e8ac56SSepherosa Ziehau 	return (error);
458471e8ac56SSepherosa Ziehau 
458571e8ac56SSepherosa Ziehau #undef ATTACHED_RNDIS
458671e8ac56SSepherosa Ziehau #undef ATTACHED_NVS
458715516c77SSepherosa Ziehau }
458815516c77SSepherosa Ziehau 
458915516c77SSepherosa Ziehau /*
459015516c77SSepherosa Ziehau  * NOTE:
459115516c77SSepherosa Ziehau  * The interface must have been suspended though hn_suspend(), before
459215516c77SSepherosa Ziehau  * this function get called.
459315516c77SSepherosa Ziehau  */
459415516c77SSepherosa Ziehau static void
459515516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc)
459615516c77SSepherosa Ziehau {
459715516c77SSepherosa Ziehau 
459815516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
459915516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
460015516c77SSepherosa Ziehau 
460115516c77SSepherosa Ziehau 	/* Detach the RNDIS first. */
460215516c77SSepherosa Ziehau 	hn_rndis_detach(sc);
460315516c77SSepherosa Ziehau 
460415516c77SSepherosa Ziehau 	/* Detach NVS. */
460515516c77SSepherosa Ziehau 	hn_nvs_detach(sc);
460615516c77SSepherosa Ziehau 
460715516c77SSepherosa Ziehau 	/* Detach all of the channels. */
460815516c77SSepherosa Ziehau 	hn_detach_allchans(sc);
460915516c77SSepherosa Ziehau 
461015516c77SSepherosa Ziehau 	sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED;
461115516c77SSepherosa Ziehau }
461215516c77SSepherosa Ziehau 
461315516c77SSepherosa Ziehau static void
461415516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt)
461515516c77SSepherosa Ziehau {
461615516c77SSepherosa Ziehau 	KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt,
461715516c77SSepherosa Ziehau 	    ("invalid ring count %d", ring_cnt));
461815516c77SSepherosa Ziehau 
461915516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt > ring_cnt)
462015516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = ring_cnt;
462115516c77SSepherosa Ziehau 	else
462215516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
462315516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = ring_cnt;
462415516c77SSepherosa Ziehau 
462515516c77SSepherosa Ziehau 	if (bootverbose) {
462615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n",
462715516c77SSepherosa Ziehau 		    sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
462815516c77SSepherosa Ziehau 	}
462915516c77SSepherosa Ziehau }
463015516c77SSepherosa Ziehau 
463115516c77SSepherosa Ziehau static void
463225641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan)
463315516c77SSepherosa Ziehau {
463415516c77SSepherosa Ziehau 
463525641fc7SSepherosa Ziehau 	/*
463625641fc7SSepherosa Ziehau 	 * NOTE:
463725641fc7SSepherosa Ziehau 	 * The TX bufring will not be drained by the hypervisor,
463825641fc7SSepherosa Ziehau 	 * if the primary channel is revoked.
463925641fc7SSepherosa Ziehau 	 */
464025641fc7SSepherosa Ziehau 	while (!vmbus_chan_rx_empty(chan) ||
464125641fc7SSepherosa Ziehau 	    (!vmbus_chan_is_revoked(sc->hn_prichan) &&
464225641fc7SSepherosa Ziehau 	     !vmbus_chan_tx_empty(chan)))
464315516c77SSepherosa Ziehau 		pause("waitch", 1);
464415516c77SSepherosa Ziehau 	vmbus_chan_intr_drain(chan);
464515516c77SSepherosa Ziehau }
464615516c77SSepherosa Ziehau 
464715516c77SSepherosa Ziehau static void
464815516c77SSepherosa Ziehau hn_suspend_data(struct hn_softc *sc)
464915516c77SSepherosa Ziehau {
465015516c77SSepherosa Ziehau 	struct vmbus_channel **subch = NULL;
465125641fc7SSepherosa Ziehau 	struct hn_tx_ring *txr;
465215516c77SSepherosa Ziehau 	int i, nsubch;
465315516c77SSepherosa Ziehau 
465415516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
465515516c77SSepherosa Ziehau 
465615516c77SSepherosa Ziehau 	/*
465715516c77SSepherosa Ziehau 	 * Suspend TX.
465815516c77SSepherosa Ziehau 	 */
465915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
466025641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
466115516c77SSepherosa Ziehau 
466215516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
466315516c77SSepherosa Ziehau 		txr->hn_suspended = 1;
466415516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
466515516c77SSepherosa Ziehau 		/* No one is able send more packets now. */
466615516c77SSepherosa Ziehau 
466725641fc7SSepherosa Ziehau 		/*
466825641fc7SSepherosa Ziehau 		 * Wait for all pending sends to finish.
466925641fc7SSepherosa Ziehau 		 *
467025641fc7SSepherosa Ziehau 		 * NOTE:
467125641fc7SSepherosa Ziehau 		 * We will _not_ receive all pending send-done, if the
467225641fc7SSepherosa Ziehau 		 * primary channel is revoked.
467325641fc7SSepherosa Ziehau 		 */
467425641fc7SSepherosa Ziehau 		while (hn_tx_ring_pending(txr) &&
467525641fc7SSepherosa Ziehau 		    !vmbus_chan_is_revoked(sc->hn_prichan))
467615516c77SSepherosa Ziehau 			pause("hnwtx", 1 /* 1 tick */);
467715516c77SSepherosa Ziehau 	}
467815516c77SSepherosa Ziehau 
467915516c77SSepherosa Ziehau 	/*
468015516c77SSepherosa Ziehau 	 * Disable RX by clearing RX filter.
468115516c77SSepherosa Ziehau 	 */
468215516c77SSepherosa Ziehau 	sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE;
468315516c77SSepherosa Ziehau 	hn_rndis_set_rxfilter(sc, sc->hn_rx_filter);
468415516c77SSepherosa Ziehau 
468515516c77SSepherosa Ziehau 	/*
468615516c77SSepherosa Ziehau 	 * Give RNDIS enough time to flush all pending data packets.
468715516c77SSepherosa Ziehau 	 */
468815516c77SSepherosa Ziehau 	pause("waitrx", (200 * hz) / 1000);
468915516c77SSepherosa Ziehau 
469015516c77SSepherosa Ziehau 	/*
469115516c77SSepherosa Ziehau 	 * Drain RX/TX bufrings and interrupts.
469215516c77SSepherosa Ziehau 	 */
469315516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_inuse - 1;
469415516c77SSepherosa Ziehau 	if (nsubch > 0)
469515516c77SSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
469615516c77SSepherosa Ziehau 
469715516c77SSepherosa Ziehau 	if (subch != NULL) {
469815516c77SSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
469925641fc7SSepherosa Ziehau 			hn_chan_drain(sc, subch[i]);
470015516c77SSepherosa Ziehau 	}
470125641fc7SSepherosa Ziehau 	hn_chan_drain(sc, sc->hn_prichan);
470215516c77SSepherosa Ziehau 
470315516c77SSepherosa Ziehau 	if (subch != NULL)
470415516c77SSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
470525641fc7SSepherosa Ziehau 
470625641fc7SSepherosa Ziehau 	/*
470725641fc7SSepherosa Ziehau 	 * Drain any pending TX tasks.
470825641fc7SSepherosa Ziehau 	 *
470925641fc7SSepherosa Ziehau 	 * NOTE:
471025641fc7SSepherosa Ziehau 	 * The above hn_chan_drain() can dispatch TX tasks, so the TX
471125641fc7SSepherosa Ziehau 	 * tasks will have to be drained _after_ the above hn_chan_drain()
471225641fc7SSepherosa Ziehau 	 * calls.
471325641fc7SSepherosa Ziehau 	 */
471425641fc7SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
471525641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
471625641fc7SSepherosa Ziehau 
471725641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task);
471825641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task);
471925641fc7SSepherosa Ziehau 	}
472015516c77SSepherosa Ziehau }
472115516c77SSepherosa Ziehau 
472215516c77SSepherosa Ziehau static void
472315516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused)
472415516c77SSepherosa Ziehau {
472515516c77SSepherosa Ziehau 
472615516c77SSepherosa Ziehau 	((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL;
472715516c77SSepherosa Ziehau }
472815516c77SSepherosa Ziehau 
472915516c77SSepherosa Ziehau static void
473015516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc)
473115516c77SSepherosa Ziehau {
473215516c77SSepherosa Ziehau 	struct task task;
473315516c77SSepherosa Ziehau 
473415516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
473515516c77SSepherosa Ziehau 
473615516c77SSepherosa Ziehau 	/*
473715516c77SSepherosa Ziehau 	 * Make sure that hn_mgmt_taskq0 can nolonger be accessed
473815516c77SSepherosa Ziehau 	 * through hn_mgmt_taskq.
473915516c77SSepherosa Ziehau 	 */
474015516c77SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc);
474115516c77SSepherosa Ziehau 	vmbus_chan_run_task(sc->hn_prichan, &task);
474215516c77SSepherosa Ziehau 
474315516c77SSepherosa Ziehau 	/*
474415516c77SSepherosa Ziehau 	 * Make sure that all pending management tasks are completed.
474515516c77SSepherosa Ziehau 	 */
474615516c77SSepherosa Ziehau 	taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init);
474715516c77SSepherosa Ziehau 	taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status);
474815516c77SSepherosa Ziehau 	taskqueue_drain_all(sc->hn_mgmt_taskq0);
474915516c77SSepherosa Ziehau }
475015516c77SSepherosa Ziehau 
475115516c77SSepherosa Ziehau static void
475215516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc)
475315516c77SSepherosa Ziehau {
475415516c77SSepherosa Ziehau 
475515516c77SSepherosa Ziehau 	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
475615516c77SSepherosa Ziehau 		hn_suspend_data(sc);
475715516c77SSepherosa Ziehau 	hn_suspend_mgmt(sc);
475815516c77SSepherosa Ziehau }
475915516c77SSepherosa Ziehau 
476015516c77SSepherosa Ziehau static void
476115516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt)
476215516c77SSepherosa Ziehau {
476315516c77SSepherosa Ziehau 	int i;
476415516c77SSepherosa Ziehau 
476515516c77SSepherosa Ziehau 	KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt,
476615516c77SSepherosa Ziehau 	    ("invalid TX ring count %d", tx_ring_cnt));
476715516c77SSepherosa Ziehau 
476815516c77SSepherosa Ziehau 	for (i = 0; i < tx_ring_cnt; ++i) {
476915516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
477015516c77SSepherosa Ziehau 
477115516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
477215516c77SSepherosa Ziehau 		txr->hn_suspended = 0;
477315516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
477415516c77SSepherosa Ziehau 	}
477515516c77SSepherosa Ziehau }
477615516c77SSepherosa Ziehau 
477715516c77SSepherosa Ziehau static void
477815516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc)
477915516c77SSepherosa Ziehau {
478015516c77SSepherosa Ziehau 	int i;
478115516c77SSepherosa Ziehau 
478215516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
478315516c77SSepherosa Ziehau 
478415516c77SSepherosa Ziehau 	/*
478515516c77SSepherosa Ziehau 	 * Re-enable RX.
478615516c77SSepherosa Ziehau 	 */
478715516c77SSepherosa Ziehau 	hn_set_rxfilter(sc);
478815516c77SSepherosa Ziehau 
478915516c77SSepherosa Ziehau 	/*
479015516c77SSepherosa Ziehau 	 * Make sure to clear suspend status on "all" TX rings,
479115516c77SSepherosa Ziehau 	 * since hn_tx_ring_inuse can be changed after
479215516c77SSepherosa Ziehau 	 * hn_suspend_data().
479315516c77SSepherosa Ziehau 	 */
479415516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_cnt);
479515516c77SSepherosa Ziehau 
479623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
479723bf9e15SSepherosa Ziehau 	if (!hn_use_if_start)
479823bf9e15SSepherosa Ziehau #endif
479923bf9e15SSepherosa Ziehau 	{
480015516c77SSepherosa Ziehau 		/*
480115516c77SSepherosa Ziehau 		 * Flush unused drbrs, since hn_tx_ring_inuse may be
480215516c77SSepherosa Ziehau 		 * reduced.
480315516c77SSepherosa Ziehau 		 */
480415516c77SSepherosa Ziehau 		for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i)
480515516c77SSepherosa Ziehau 			hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
480615516c77SSepherosa Ziehau 	}
480715516c77SSepherosa Ziehau 
480815516c77SSepherosa Ziehau 	/*
480915516c77SSepherosa Ziehau 	 * Kick start TX.
481015516c77SSepherosa Ziehau 	 */
481115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
481215516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
481315516c77SSepherosa Ziehau 
481415516c77SSepherosa Ziehau 		/*
481515516c77SSepherosa Ziehau 		 * Use txeof task, so that any pending oactive can be
481615516c77SSepherosa Ziehau 		 * cleared properly.
481715516c77SSepherosa Ziehau 		 */
481815516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
481915516c77SSepherosa Ziehau 	}
482015516c77SSepherosa Ziehau }
482115516c77SSepherosa Ziehau 
482215516c77SSepherosa Ziehau static void
482315516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc)
482415516c77SSepherosa Ziehau {
482515516c77SSepherosa Ziehau 
482615516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
482715516c77SSepherosa Ziehau 
482815516c77SSepherosa Ziehau 	/*
482915516c77SSepherosa Ziehau 	 * Kick off network change detection, if it was pending.
483015516c77SSepherosa Ziehau 	 * If no network change was pending, start link status
483115516c77SSepherosa Ziehau 	 * checks, which is more lightweight than network change
483215516c77SSepherosa Ziehau 	 * detection.
483315516c77SSepherosa Ziehau 	 */
483415516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
483515516c77SSepherosa Ziehau 		hn_change_network(sc);
483615516c77SSepherosa Ziehau 	else
483715516c77SSepherosa Ziehau 		hn_update_link_status(sc);
483815516c77SSepherosa Ziehau }
483915516c77SSepherosa Ziehau 
484015516c77SSepherosa Ziehau static void
484115516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc)
484215516c77SSepherosa Ziehau {
484315516c77SSepherosa Ziehau 
484415516c77SSepherosa Ziehau 	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
484515516c77SSepherosa Ziehau 		hn_resume_data(sc);
484615516c77SSepherosa Ziehau 	hn_resume_mgmt(sc);
484715516c77SSepherosa Ziehau }
484815516c77SSepherosa Ziehau 
484915516c77SSepherosa Ziehau static void
485015516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen)
485115516c77SSepherosa Ziehau {
485215516c77SSepherosa Ziehau 	const struct rndis_status_msg *msg;
485315516c77SSepherosa Ziehau 	int ofs;
485415516c77SSepherosa Ziehau 
485515516c77SSepherosa Ziehau 	if (dlen < sizeof(*msg)) {
485615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid RNDIS status\n");
485715516c77SSepherosa Ziehau 		return;
485815516c77SSepherosa Ziehau 	}
485915516c77SSepherosa Ziehau 	msg = data;
486015516c77SSepherosa Ziehau 
486115516c77SSepherosa Ziehau 	switch (msg->rm_status) {
486215516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_CONNECT:
486315516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_DISCONNECT:
486415516c77SSepherosa Ziehau 		hn_update_link_status(sc);
486515516c77SSepherosa Ziehau 		break;
486615516c77SSepherosa Ziehau 
486715516c77SSepherosa Ziehau 	case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
486815516c77SSepherosa Ziehau 		/* Not really useful; ignore. */
486915516c77SSepherosa Ziehau 		break;
487015516c77SSepherosa Ziehau 
487115516c77SSepherosa Ziehau 	case RNDIS_STATUS_NETWORK_CHANGE:
487215516c77SSepherosa Ziehau 		ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
487315516c77SSepherosa Ziehau 		if (dlen < ofs + msg->rm_stbuflen ||
487415516c77SSepherosa Ziehau 		    msg->rm_stbuflen < sizeof(uint32_t)) {
487515516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed\n");
487615516c77SSepherosa Ziehau 		} else {
487715516c77SSepherosa Ziehau 			uint32_t change;
487815516c77SSepherosa Ziehau 
487915516c77SSepherosa Ziehau 			memcpy(&change, ((const uint8_t *)msg) + ofs,
488015516c77SSepherosa Ziehau 			    sizeof(change));
488115516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed, change %u\n",
488215516c77SSepherosa Ziehau 			    change);
488315516c77SSepherosa Ziehau 		}
488415516c77SSepherosa Ziehau 		hn_change_network(sc);
488515516c77SSepherosa Ziehau 		break;
488615516c77SSepherosa Ziehau 
488715516c77SSepherosa Ziehau 	default:
488815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
488915516c77SSepherosa Ziehau 		    msg->rm_status);
489015516c77SSepherosa Ziehau 		break;
489115516c77SSepherosa Ziehau 	}
489215516c77SSepherosa Ziehau }
489315516c77SSepherosa Ziehau 
489415516c77SSepherosa Ziehau static int
489515516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info)
489615516c77SSepherosa Ziehau {
489715516c77SSepherosa Ziehau 	const struct rndis_pktinfo *pi = info_data;
489815516c77SSepherosa Ziehau 	uint32_t mask = 0;
489915516c77SSepherosa Ziehau 
490015516c77SSepherosa Ziehau 	while (info_dlen != 0) {
490115516c77SSepherosa Ziehau 		const void *data;
490215516c77SSepherosa Ziehau 		uint32_t dlen;
490315516c77SSepherosa Ziehau 
490415516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < sizeof(*pi)))
490515516c77SSepherosa Ziehau 			return (EINVAL);
490615516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < pi->rm_size))
490715516c77SSepherosa Ziehau 			return (EINVAL);
490815516c77SSepherosa Ziehau 		info_dlen -= pi->rm_size;
490915516c77SSepherosa Ziehau 
491015516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
491115516c77SSepherosa Ziehau 			return (EINVAL);
491215516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
491315516c77SSepherosa Ziehau 			return (EINVAL);
491415516c77SSepherosa Ziehau 		dlen = pi->rm_size - pi->rm_pktinfooffset;
491515516c77SSepherosa Ziehau 		data = pi->rm_data;
491615516c77SSepherosa Ziehau 
491715516c77SSepherosa Ziehau 		switch (pi->rm_type) {
491815516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_VLAN:
491915516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
492015516c77SSepherosa Ziehau 				return (EINVAL);
492115516c77SSepherosa Ziehau 			info->vlan_info = *((const uint32_t *)data);
492215516c77SSepherosa Ziehau 			mask |= HN_RXINFO_VLAN;
492315516c77SSepherosa Ziehau 			break;
492415516c77SSepherosa Ziehau 
492515516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_CSUM:
492615516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
492715516c77SSepherosa Ziehau 				return (EINVAL);
492815516c77SSepherosa Ziehau 			info->csum_info = *((const uint32_t *)data);
492915516c77SSepherosa Ziehau 			mask |= HN_RXINFO_CSUM;
493015516c77SSepherosa Ziehau 			break;
493115516c77SSepherosa Ziehau 
493215516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHVAL:
493315516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
493415516c77SSepherosa Ziehau 				return (EINVAL);
493515516c77SSepherosa Ziehau 			info->hash_value = *((const uint32_t *)data);
493615516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHVAL;
493715516c77SSepherosa Ziehau 			break;
493815516c77SSepherosa Ziehau 
493915516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHINF:
494015516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
494115516c77SSepherosa Ziehau 				return (EINVAL);
494215516c77SSepherosa Ziehau 			info->hash_info = *((const uint32_t *)data);
494315516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHINF;
494415516c77SSepherosa Ziehau 			break;
494515516c77SSepherosa Ziehau 
494615516c77SSepherosa Ziehau 		default:
494715516c77SSepherosa Ziehau 			goto next;
494815516c77SSepherosa Ziehau 		}
494915516c77SSepherosa Ziehau 
495015516c77SSepherosa Ziehau 		if (mask == HN_RXINFO_ALL) {
495115516c77SSepherosa Ziehau 			/* All found; done */
495215516c77SSepherosa Ziehau 			break;
495315516c77SSepherosa Ziehau 		}
495415516c77SSepherosa Ziehau next:
495515516c77SSepherosa Ziehau 		pi = (const struct rndis_pktinfo *)
495615516c77SSepherosa Ziehau 		    ((const uint8_t *)pi + pi->rm_size);
495715516c77SSepherosa Ziehau 	}
495815516c77SSepherosa Ziehau 
495915516c77SSepherosa Ziehau 	/*
496015516c77SSepherosa Ziehau 	 * Final fixup.
496115516c77SSepherosa Ziehau 	 * - If there is no hash value, invalidate the hash info.
496215516c77SSepherosa Ziehau 	 */
496315516c77SSepherosa Ziehau 	if ((mask & HN_RXINFO_HASHVAL) == 0)
496415516c77SSepherosa Ziehau 		info->hash_info = HN_NDIS_HASH_INFO_INVALID;
496515516c77SSepherosa Ziehau 	return (0);
496615516c77SSepherosa Ziehau }
496715516c77SSepherosa Ziehau 
496815516c77SSepherosa Ziehau static __inline bool
496915516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
497015516c77SSepherosa Ziehau {
497115516c77SSepherosa Ziehau 
497215516c77SSepherosa Ziehau 	if (off < check_off) {
497315516c77SSepherosa Ziehau 		if (__predict_true(off + len <= check_off))
497415516c77SSepherosa Ziehau 			return (false);
497515516c77SSepherosa Ziehau 	} else if (off > check_off) {
497615516c77SSepherosa Ziehau 		if (__predict_true(check_off + check_len <= off))
497715516c77SSepherosa Ziehau 			return (false);
497815516c77SSepherosa Ziehau 	}
497915516c77SSepherosa Ziehau 	return (true);
498015516c77SSepherosa Ziehau }
498115516c77SSepherosa Ziehau 
498215516c77SSepherosa Ziehau static void
498315516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen)
498415516c77SSepherosa Ziehau {
498515516c77SSepherosa Ziehau 	const struct rndis_packet_msg *pkt;
498615516c77SSepherosa Ziehau 	struct hn_rxinfo info;
498715516c77SSepherosa Ziehau 	int data_off, pktinfo_off, data_len, pktinfo_len;
498815516c77SSepherosa Ziehau 
498915516c77SSepherosa Ziehau 	/*
499015516c77SSepherosa Ziehau 	 * Check length.
499115516c77SSepherosa Ziehau 	 */
499215516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*pkt))) {
499315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
499415516c77SSepherosa Ziehau 		return;
499515516c77SSepherosa Ziehau 	}
499615516c77SSepherosa Ziehau 	pkt = data;
499715516c77SSepherosa Ziehau 
499815516c77SSepherosa Ziehau 	if (__predict_false(dlen < pkt->rm_len)) {
499915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
500015516c77SSepherosa Ziehau 		    "dlen %d, msglen %u\n", dlen, pkt->rm_len);
500115516c77SSepherosa Ziehau 		return;
500215516c77SSepherosa Ziehau 	}
500315516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_len <
500415516c77SSepherosa Ziehau 	    pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
500515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
500615516c77SSepherosa Ziehau 		    "msglen %u, data %u, oob %u, pktinfo %u\n",
500715516c77SSepherosa Ziehau 		    pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
500815516c77SSepherosa Ziehau 		    pkt->rm_pktinfolen);
500915516c77SSepherosa Ziehau 		return;
501015516c77SSepherosa Ziehau 	}
501115516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_datalen == 0)) {
501215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
501315516c77SSepherosa Ziehau 		return;
501415516c77SSepherosa Ziehau 	}
501515516c77SSepherosa Ziehau 
501615516c77SSepherosa Ziehau 	/*
501715516c77SSepherosa Ziehau 	 * Check offests.
501815516c77SSepherosa Ziehau 	 */
501915516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs)			\
502015516c77SSepherosa Ziehau 	((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN ||	\
502115516c77SSepherosa Ziehau 	 ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
502215516c77SSepherosa Ziehau 
502315516c77SSepherosa Ziehau 	/* XXX Hyper-V does not meet data offset alignment requirement */
502415516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
502515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
502615516c77SSepherosa Ziehau 		    "data offset %u\n", pkt->rm_dataoffset);
502715516c77SSepherosa Ziehau 		return;
502815516c77SSepherosa Ziehau 	}
502915516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdataoffset > 0 &&
503015516c77SSepherosa Ziehau 	    IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
503115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
503215516c77SSepherosa Ziehau 		    "oob offset %u\n", pkt->rm_oobdataoffset);
503315516c77SSepherosa Ziehau 		return;
503415516c77SSepherosa Ziehau 	}
503515516c77SSepherosa Ziehau 	if (__predict_true(pkt->rm_pktinfooffset > 0) &&
503615516c77SSepherosa Ziehau 	    __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
503715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
503815516c77SSepherosa Ziehau 		    "pktinfo offset %u\n", pkt->rm_pktinfooffset);
503915516c77SSepherosa Ziehau 		return;
504015516c77SSepherosa Ziehau 	}
504115516c77SSepherosa Ziehau 
504215516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID
504315516c77SSepherosa Ziehau 
504415516c77SSepherosa Ziehau 	data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
504515516c77SSepherosa Ziehau 	data_len = pkt->rm_datalen;
504615516c77SSepherosa Ziehau 	pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
504715516c77SSepherosa Ziehau 	pktinfo_len = pkt->rm_pktinfolen;
504815516c77SSepherosa Ziehau 
504915516c77SSepherosa Ziehau 	/*
505015516c77SSepherosa Ziehau 	 * Check OOB coverage.
505115516c77SSepherosa Ziehau 	 */
505215516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdatalen != 0)) {
505315516c77SSepherosa Ziehau 		int oob_off, oob_len;
505415516c77SSepherosa Ziehau 
505515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "got oobdata\n");
505615516c77SSepherosa Ziehau 		oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
505715516c77SSepherosa Ziehau 		oob_len = pkt->rm_oobdatalen;
505815516c77SSepherosa Ziehau 
505915516c77SSepherosa Ziehau 		if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
506015516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
506115516c77SSepherosa Ziehau 			    "oob overflow, msglen %u, oob abs %d len %d\n",
506215516c77SSepherosa Ziehau 			    pkt->rm_len, oob_off, oob_len);
506315516c77SSepherosa Ziehau 			return;
506415516c77SSepherosa Ziehau 		}
506515516c77SSepherosa Ziehau 
506615516c77SSepherosa Ziehau 		/*
506715516c77SSepherosa Ziehau 		 * Check against data.
506815516c77SSepherosa Ziehau 		 */
506915516c77SSepherosa Ziehau 		if (hn_rndis_check_overlap(oob_off, oob_len,
507015516c77SSepherosa Ziehau 		    data_off, data_len)) {
507115516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
507215516c77SSepherosa Ziehau 			    "oob overlaps data, oob abs %d len %d, "
507315516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
507415516c77SSepherosa Ziehau 			    oob_off, oob_len, data_off, data_len);
507515516c77SSepherosa Ziehau 			return;
507615516c77SSepherosa Ziehau 		}
507715516c77SSepherosa Ziehau 
507815516c77SSepherosa Ziehau 		/*
507915516c77SSepherosa Ziehau 		 * Check against pktinfo.
508015516c77SSepherosa Ziehau 		 */
508115516c77SSepherosa Ziehau 		if (pktinfo_len != 0 &&
508215516c77SSepherosa Ziehau 		    hn_rndis_check_overlap(oob_off, oob_len,
508315516c77SSepherosa Ziehau 		    pktinfo_off, pktinfo_len)) {
508415516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
508515516c77SSepherosa Ziehau 			    "oob overlaps pktinfo, oob abs %d len %d, "
508615516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
508715516c77SSepherosa Ziehau 			    oob_off, oob_len, pktinfo_off, pktinfo_len);
508815516c77SSepherosa Ziehau 			return;
508915516c77SSepherosa Ziehau 		}
509015516c77SSepherosa Ziehau 	}
509115516c77SSepherosa Ziehau 
509215516c77SSepherosa Ziehau 	/*
509315516c77SSepherosa Ziehau 	 * Check per-packet-info coverage and find useful per-packet-info.
509415516c77SSepherosa Ziehau 	 */
509515516c77SSepherosa Ziehau 	info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
509615516c77SSepherosa Ziehau 	info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
509715516c77SSepherosa Ziehau 	info.hash_info = HN_NDIS_HASH_INFO_INVALID;
509815516c77SSepherosa Ziehau 	if (__predict_true(pktinfo_len != 0)) {
509915516c77SSepherosa Ziehau 		bool overlap;
510015516c77SSepherosa Ziehau 		int error;
510115516c77SSepherosa Ziehau 
510215516c77SSepherosa Ziehau 		if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
510315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
510415516c77SSepherosa Ziehau 			    "pktinfo overflow, msglen %u, "
510515516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
510615516c77SSepherosa Ziehau 			    pkt->rm_len, pktinfo_off, pktinfo_len);
510715516c77SSepherosa Ziehau 			return;
510815516c77SSepherosa Ziehau 		}
510915516c77SSepherosa Ziehau 
511015516c77SSepherosa Ziehau 		/*
511115516c77SSepherosa Ziehau 		 * Check packet info coverage.
511215516c77SSepherosa Ziehau 		 */
511315516c77SSepherosa Ziehau 		overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
511415516c77SSepherosa Ziehau 		    data_off, data_len);
511515516c77SSepherosa Ziehau 		if (__predict_false(overlap)) {
511615516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
511715516c77SSepherosa Ziehau 			    "pktinfo overlap data, pktinfo abs %d len %d, "
511815516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
511915516c77SSepherosa Ziehau 			    pktinfo_off, pktinfo_len, data_off, data_len);
512015516c77SSepherosa Ziehau 			return;
512115516c77SSepherosa Ziehau 		}
512215516c77SSepherosa Ziehau 
512315516c77SSepherosa Ziehau 		/*
512415516c77SSepherosa Ziehau 		 * Find useful per-packet-info.
512515516c77SSepherosa Ziehau 		 */
512615516c77SSepherosa Ziehau 		error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
512715516c77SSepherosa Ziehau 		    pktinfo_len, &info);
512815516c77SSepherosa Ziehau 		if (__predict_false(error)) {
512915516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
513015516c77SSepherosa Ziehau 			    "pktinfo\n");
513115516c77SSepherosa Ziehau 			return;
513215516c77SSepherosa Ziehau 		}
513315516c77SSepherosa Ziehau 	}
513415516c77SSepherosa Ziehau 
513515516c77SSepherosa Ziehau 	if (__predict_false(data_off + data_len > pkt->rm_len)) {
513615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
513715516c77SSepherosa Ziehau 		    "data overflow, msglen %u, data abs %d len %d\n",
513815516c77SSepherosa Ziehau 		    pkt->rm_len, data_off, data_len);
513915516c77SSepherosa Ziehau 		return;
514015516c77SSepherosa Ziehau 	}
514115516c77SSepherosa Ziehau 	hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
514215516c77SSepherosa Ziehau }
514315516c77SSepherosa Ziehau 
514415516c77SSepherosa Ziehau static __inline void
514515516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen)
514615516c77SSepherosa Ziehau {
514715516c77SSepherosa Ziehau 	const struct rndis_msghdr *hdr;
514815516c77SSepherosa Ziehau 
514915516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*hdr))) {
515015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
515115516c77SSepherosa Ziehau 		return;
515215516c77SSepherosa Ziehau 	}
515315516c77SSepherosa Ziehau 	hdr = data;
515415516c77SSepherosa Ziehau 
515515516c77SSepherosa Ziehau 	if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) {
515615516c77SSepherosa Ziehau 		/* Hot data path. */
515715516c77SSepherosa Ziehau 		hn_rndis_rx_data(rxr, data, dlen);
515815516c77SSepherosa Ziehau 		/* Done! */
515915516c77SSepherosa Ziehau 		return;
516015516c77SSepherosa Ziehau 	}
516115516c77SSepherosa Ziehau 
516215516c77SSepherosa Ziehau 	if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG)
516315516c77SSepherosa Ziehau 		hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen);
516415516c77SSepherosa Ziehau 	else
516515516c77SSepherosa Ziehau 		hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen);
516615516c77SSepherosa Ziehau }
516715516c77SSepherosa Ziehau 
516815516c77SSepherosa Ziehau static void
516915516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
517015516c77SSepherosa Ziehau {
517115516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *hdr;
517215516c77SSepherosa Ziehau 
517315516c77SSepherosa Ziehau 	if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) {
517415516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid nvs notify\n");
517515516c77SSepherosa Ziehau 		return;
517615516c77SSepherosa Ziehau 	}
517715516c77SSepherosa Ziehau 	hdr = VMBUS_CHANPKT_CONST_DATA(pkt);
517815516c77SSepherosa Ziehau 
517915516c77SSepherosa Ziehau 	if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) {
518015516c77SSepherosa Ziehau 		/* Useless; ignore */
518115516c77SSepherosa Ziehau 		return;
518215516c77SSepherosa Ziehau 	}
518315516c77SSepherosa Ziehau 	if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type);
518415516c77SSepherosa Ziehau }
518515516c77SSepherosa Ziehau 
518615516c77SSepherosa Ziehau static void
518715516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan,
518815516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkt)
518915516c77SSepherosa Ziehau {
519015516c77SSepherosa Ziehau 	struct hn_nvs_sendctx *sndc;
519115516c77SSepherosa Ziehau 
519215516c77SSepherosa Ziehau 	sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid;
519315516c77SSepherosa Ziehau 	sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt),
519415516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_DATALEN(pkt));
519515516c77SSepherosa Ziehau 	/*
519615516c77SSepherosa Ziehau 	 * NOTE:
519715516c77SSepherosa Ziehau 	 * 'sndc' CAN NOT be accessed anymore, since it can be freed by
519815516c77SSepherosa Ziehau 	 * its callback.
519915516c77SSepherosa Ziehau 	 */
520015516c77SSepherosa Ziehau }
520115516c77SSepherosa Ziehau 
520215516c77SSepherosa Ziehau static void
520315516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
520415516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkthdr)
520515516c77SSepherosa Ziehau {
520615516c77SSepherosa Ziehau 	const struct vmbus_chanpkt_rxbuf *pkt;
520715516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *nvs_hdr;
520815516c77SSepherosa Ziehau 	int count, i, hlen;
520915516c77SSepherosa Ziehau 
521015516c77SSepherosa Ziehau 	if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) {
521115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n");
521215516c77SSepherosa Ziehau 		return;
521315516c77SSepherosa Ziehau 	}
521415516c77SSepherosa Ziehau 	nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr);
521515516c77SSepherosa Ziehau 
521615516c77SSepherosa Ziehau 	/* Make sure that this is a RNDIS message. */
521715516c77SSepherosa Ziehau 	if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) {
521815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n",
521915516c77SSepherosa Ziehau 		    nvs_hdr->nvs_type);
522015516c77SSepherosa Ziehau 		return;
522115516c77SSepherosa Ziehau 	}
522215516c77SSepherosa Ziehau 
522315516c77SSepherosa Ziehau 	hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen);
522415516c77SSepherosa Ziehau 	if (__predict_false(hlen < sizeof(*pkt))) {
522515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n");
522615516c77SSepherosa Ziehau 		return;
522715516c77SSepherosa Ziehau 	}
522815516c77SSepherosa Ziehau 	pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
522915516c77SSepherosa Ziehau 
523015516c77SSepherosa Ziehau 	if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) {
523115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n",
523215516c77SSepherosa Ziehau 		    pkt->cp_rxbuf_id);
523315516c77SSepherosa Ziehau 		return;
523415516c77SSepherosa Ziehau 	}
523515516c77SSepherosa Ziehau 
523615516c77SSepherosa Ziehau 	count = pkt->cp_rxbuf_cnt;
523715516c77SSepherosa Ziehau 	if (__predict_false(hlen <
523815516c77SSepherosa Ziehau 	    __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) {
523915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count);
524015516c77SSepherosa Ziehau 		return;
524115516c77SSepherosa Ziehau 	}
524215516c77SSepherosa Ziehau 
524315516c77SSepherosa Ziehau 	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
524415516c77SSepherosa Ziehau 	for (i = 0; i < count; ++i) {
524515516c77SSepherosa Ziehau 		int ofs, len;
524615516c77SSepherosa Ziehau 
524715516c77SSepherosa Ziehau 		ofs = pkt->cp_rxbuf[i].rb_ofs;
524815516c77SSepherosa Ziehau 		len = pkt->cp_rxbuf[i].rb_len;
524915516c77SSepherosa Ziehau 		if (__predict_false(ofs + len > HN_RXBUF_SIZE)) {
525015516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, "
525115516c77SSepherosa Ziehau 			    "ofs %d, len %d\n", i, ofs, len);
525215516c77SSepherosa Ziehau 			continue;
525315516c77SSepherosa Ziehau 		}
525415516c77SSepherosa Ziehau 		hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len);
525515516c77SSepherosa Ziehau 	}
525615516c77SSepherosa Ziehau 
525715516c77SSepherosa Ziehau 	/*
525815516c77SSepherosa Ziehau 	 * Ack the consumed RXBUF associated w/ this channel packet,
525915516c77SSepherosa Ziehau 	 * so that this RXBUF can be recycled by the hypervisor.
526015516c77SSepherosa Ziehau 	 */
526115516c77SSepherosa Ziehau 	hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid);
526215516c77SSepherosa Ziehau }
526315516c77SSepherosa Ziehau 
526415516c77SSepherosa Ziehau static void
526515516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
526615516c77SSepherosa Ziehau     uint64_t tid)
526715516c77SSepherosa Ziehau {
526815516c77SSepherosa Ziehau 	struct hn_nvs_rndis_ack ack;
526915516c77SSepherosa Ziehau 	int retries, error;
527015516c77SSepherosa Ziehau 
527115516c77SSepherosa Ziehau 	ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK;
527215516c77SSepherosa Ziehau 	ack.nvs_status = HN_NVS_STATUS_OK;
527315516c77SSepherosa Ziehau 
527415516c77SSepherosa Ziehau 	retries = 0;
527515516c77SSepherosa Ziehau again:
527615516c77SSepherosa Ziehau 	error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP,
527715516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid);
527815516c77SSepherosa Ziehau 	if (__predict_false(error == EAGAIN)) {
527915516c77SSepherosa Ziehau 		/*
528015516c77SSepherosa Ziehau 		 * NOTE:
528115516c77SSepherosa Ziehau 		 * This should _not_ happen in real world, since the
528215516c77SSepherosa Ziehau 		 * consumption of the TX bufring from the TX path is
528315516c77SSepherosa Ziehau 		 * controlled.
528415516c77SSepherosa Ziehau 		 */
528515516c77SSepherosa Ziehau 		if (rxr->hn_ack_failed == 0)
528615516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "RXBUF ack retry\n");
528715516c77SSepherosa Ziehau 		rxr->hn_ack_failed++;
528815516c77SSepherosa Ziehau 		retries++;
528915516c77SSepherosa Ziehau 		if (retries < 10) {
529015516c77SSepherosa Ziehau 			DELAY(100);
529115516c77SSepherosa Ziehau 			goto again;
529215516c77SSepherosa Ziehau 		}
529315516c77SSepherosa Ziehau 		/* RXBUF leaks! */
529415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "RXBUF ack failed\n");
529515516c77SSepherosa Ziehau 	}
529615516c77SSepherosa Ziehau }
529715516c77SSepherosa Ziehau 
529815516c77SSepherosa Ziehau static void
529915516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr)
530015516c77SSepherosa Ziehau {
530115516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr = xrxr;
530215516c77SSepherosa Ziehau 	struct hn_softc *sc = rxr->hn_ifp->if_softc;
530315516c77SSepherosa Ziehau 
530415516c77SSepherosa Ziehau 	for (;;) {
530515516c77SSepherosa Ziehau 		struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf;
530615516c77SSepherosa Ziehau 		int error, pktlen;
530715516c77SSepherosa Ziehau 
530815516c77SSepherosa Ziehau 		pktlen = rxr->hn_pktbuf_len;
530915516c77SSepherosa Ziehau 		error = vmbus_chan_recv_pkt(chan, pkt, &pktlen);
531015516c77SSepherosa Ziehau 		if (__predict_false(error == ENOBUFS)) {
531115516c77SSepherosa Ziehau 			void *nbuf;
531215516c77SSepherosa Ziehau 			int nlen;
531315516c77SSepherosa Ziehau 
531415516c77SSepherosa Ziehau 			/*
531515516c77SSepherosa Ziehau 			 * Expand channel packet buffer.
531615516c77SSepherosa Ziehau 			 *
531715516c77SSepherosa Ziehau 			 * XXX
531815516c77SSepherosa Ziehau 			 * Use M_WAITOK here, since allocation failure
531915516c77SSepherosa Ziehau 			 * is fatal.
532015516c77SSepherosa Ziehau 			 */
532115516c77SSepherosa Ziehau 			nlen = rxr->hn_pktbuf_len * 2;
532215516c77SSepherosa Ziehau 			while (nlen < pktlen)
532315516c77SSepherosa Ziehau 				nlen *= 2;
532415516c77SSepherosa Ziehau 			nbuf = malloc(nlen, M_DEVBUF, M_WAITOK);
532515516c77SSepherosa Ziehau 
532615516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n",
532715516c77SSepherosa Ziehau 			    rxr->hn_pktbuf_len, nlen);
532815516c77SSepherosa Ziehau 
532915516c77SSepherosa Ziehau 			free(rxr->hn_pktbuf, M_DEVBUF);
533015516c77SSepherosa Ziehau 			rxr->hn_pktbuf = nbuf;
533115516c77SSepherosa Ziehau 			rxr->hn_pktbuf_len = nlen;
533215516c77SSepherosa Ziehau 			/* Retry! */
533315516c77SSepherosa Ziehau 			continue;
533415516c77SSepherosa Ziehau 		} else if (__predict_false(error == EAGAIN)) {
533515516c77SSepherosa Ziehau 			/* No more channel packets; done! */
533615516c77SSepherosa Ziehau 			break;
533715516c77SSepherosa Ziehau 		}
533815516c77SSepherosa Ziehau 		KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error));
533915516c77SSepherosa Ziehau 
534015516c77SSepherosa Ziehau 		switch (pkt->cph_type) {
534115516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_COMP:
534215516c77SSepherosa Ziehau 			hn_nvs_handle_comp(sc, chan, pkt);
534315516c77SSepherosa Ziehau 			break;
534415516c77SSepherosa Ziehau 
534515516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_RXBUF:
534615516c77SSepherosa Ziehau 			hn_nvs_handle_rxbuf(rxr, chan, pkt);
534715516c77SSepherosa Ziehau 			break;
534815516c77SSepherosa Ziehau 
534915516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_INBAND:
535015516c77SSepherosa Ziehau 			hn_nvs_handle_notify(sc, pkt);
535115516c77SSepherosa Ziehau 			break;
535215516c77SSepherosa Ziehau 
535315516c77SSepherosa Ziehau 		default:
535415516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "unknown chan pkt %u\n",
535515516c77SSepherosa Ziehau 			    pkt->cph_type);
535615516c77SSepherosa Ziehau 			break;
535715516c77SSepherosa Ziehau 		}
535815516c77SSepherosa Ziehau 	}
535915516c77SSepherosa Ziehau 	hn_chan_rollup(rxr, rxr->hn_txr);
536015516c77SSepherosa Ziehau }
536115516c77SSepherosa Ziehau 
536215516c77SSepherosa Ziehau static void
536315516c77SSepherosa Ziehau hn_tx_taskq_create(void *arg __unused)
536415516c77SSepherosa Ziehau {
5365fdd0222aSSepherosa Ziehau 	int i;
5366fdd0222aSSepherosa Ziehau 
5367fdd0222aSSepherosa Ziehau 	/*
5368fdd0222aSSepherosa Ziehau 	 * Fix the # of TX taskqueues.
5369fdd0222aSSepherosa Ziehau 	 */
5370fdd0222aSSepherosa Ziehau 	if (hn_tx_taskq_cnt <= 0)
5371fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = 1;
5372fdd0222aSSepherosa Ziehau 	else if (hn_tx_taskq_cnt > mp_ncpus)
5373fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = mp_ncpus;
537415516c77SSepherosa Ziehau 
5375*0e11868dSSepherosa Ziehau 	/*
5376*0e11868dSSepherosa Ziehau 	 * Fix the TX taskqueue mode.
5377*0e11868dSSepherosa Ziehau 	 */
5378*0e11868dSSepherosa Ziehau 	switch (hn_tx_taskq_mode) {
5379*0e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_INDEP:
5380*0e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_GLOBAL:
5381*0e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_EVTTQ:
5382*0e11868dSSepherosa Ziehau 		break;
5383*0e11868dSSepherosa Ziehau 	default:
5384*0e11868dSSepherosa Ziehau 		hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
5385*0e11868dSSepherosa Ziehau 		break;
5386*0e11868dSSepherosa Ziehau 	}
5387*0e11868dSSepherosa Ziehau 
538815516c77SSepherosa Ziehau 	if (vm_guest != VM_GUEST_HV)
538915516c77SSepherosa Ziehau 		return;
539015516c77SSepherosa Ziehau 
5391*0e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode != HN_TX_TASKQ_M_GLOBAL)
539215516c77SSepherosa Ziehau 		return;
539315516c77SSepherosa Ziehau 
5394fdd0222aSSepherosa Ziehau 	hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
5395fdd0222aSSepherosa Ziehau 	    M_DEVBUF, M_WAITOK);
5396fdd0222aSSepherosa Ziehau 	for (i = 0; i < hn_tx_taskq_cnt; ++i) {
5397fdd0222aSSepherosa Ziehau 		hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK,
5398fdd0222aSSepherosa Ziehau 		    taskqueue_thread_enqueue, &hn_tx_taskque[i]);
5399fdd0222aSSepherosa Ziehau 		taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET,
5400fdd0222aSSepherosa Ziehau 		    "hn tx%d", i);
5401fdd0222aSSepherosa Ziehau 	}
540215516c77SSepherosa Ziehau }
540315516c77SSepherosa Ziehau SYSINIT(hn_txtq_create, SI_SUB_DRIVERS, SI_ORDER_SECOND,
540415516c77SSepherosa Ziehau     hn_tx_taskq_create, NULL);
540515516c77SSepherosa Ziehau 
540615516c77SSepherosa Ziehau static void
540715516c77SSepherosa Ziehau hn_tx_taskq_destroy(void *arg __unused)
540815516c77SSepherosa Ziehau {
540915516c77SSepherosa Ziehau 
5410fdd0222aSSepherosa Ziehau 	if (hn_tx_taskque != NULL) {
5411fdd0222aSSepherosa Ziehau 		int i;
5412fdd0222aSSepherosa Ziehau 
5413fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
5414fdd0222aSSepherosa Ziehau 			taskqueue_free(hn_tx_taskque[i]);
5415fdd0222aSSepherosa Ziehau 		free(hn_tx_taskque, M_DEVBUF);
5416fdd0222aSSepherosa Ziehau 	}
541715516c77SSepherosa Ziehau }
541815516c77SSepherosa Ziehau SYSUNINIT(hn_txtq_destroy, SI_SUB_DRIVERS, SI_ORDER_SECOND,
541915516c77SSepherosa Ziehau     hn_tx_taskq_destroy, NULL);
5420