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