xref: /freebsd/sys/dev/hyperv/netvsc/if_hn.c (revision fdd0222a048ff961110d308c99c2c9096fb0ec58)
115516c77SSepherosa Ziehau /*-
215516c77SSepherosa Ziehau  * Copyright (c) 2010-2012 Citrix Inc.
315516c77SSepherosa Ziehau  * Copyright (c) 2009-2012,2016 Microsoft Corp.
415516c77SSepherosa Ziehau  * Copyright (c) 2012 NetApp Inc.
515516c77SSepherosa Ziehau  * All rights reserved.
615516c77SSepherosa Ziehau  *
715516c77SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
815516c77SSepherosa Ziehau  * modification, are permitted provided that the following conditions
915516c77SSepherosa Ziehau  * are met:
1015516c77SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
1115516c77SSepherosa Ziehau  *    notice unmodified, this list of conditions, and the following
1215516c77SSepherosa Ziehau  *    disclaimer.
1315516c77SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
1415516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
1515516c77SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
1615516c77SSepherosa Ziehau  *
1715516c77SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1815516c77SSepherosa Ziehau  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1915516c77SSepherosa Ziehau  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2015516c77SSepherosa Ziehau  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2115516c77SSepherosa Ziehau  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2215516c77SSepherosa Ziehau  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2315516c77SSepherosa Ziehau  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2415516c77SSepherosa Ziehau  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2515516c77SSepherosa Ziehau  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2615516c77SSepherosa Ziehau  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2715516c77SSepherosa Ziehau  */
2815516c77SSepherosa Ziehau 
2915516c77SSepherosa Ziehau /*-
3015516c77SSepherosa Ziehau  * Copyright (c) 2004-2006 Kip Macy
3115516c77SSepherosa Ziehau  * All rights reserved.
3215516c77SSepherosa Ziehau  *
3315516c77SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
3415516c77SSepherosa Ziehau  * modification, are permitted provided that the following conditions
3515516c77SSepherosa Ziehau  * are met:
3615516c77SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
3715516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer.
3815516c77SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
3915516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
4015516c77SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
4115516c77SSepherosa Ziehau  *
4215516c77SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
4315516c77SSepherosa Ziehau  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4415516c77SSepherosa Ziehau  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4515516c77SSepherosa Ziehau  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4615516c77SSepherosa Ziehau  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4715516c77SSepherosa Ziehau  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4815516c77SSepherosa Ziehau  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4915516c77SSepherosa Ziehau  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5015516c77SSepherosa Ziehau  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5115516c77SSepherosa Ziehau  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5215516c77SSepherosa Ziehau  * SUCH DAMAGE.
5315516c77SSepherosa Ziehau  */
5415516c77SSepherosa Ziehau 
5515516c77SSepherosa Ziehau #include <sys/cdefs.h>
5615516c77SSepherosa Ziehau __FBSDID("$FreeBSD$");
5715516c77SSepherosa Ziehau 
5815516c77SSepherosa Ziehau #include "opt_inet6.h"
5915516c77SSepherosa Ziehau #include "opt_inet.h"
6015516c77SSepherosa Ziehau 
6115516c77SSepherosa Ziehau #include <sys/param.h>
6215516c77SSepherosa Ziehau #include <sys/bus.h>
6315516c77SSepherosa Ziehau #include <sys/kernel.h>
6415516c77SSepherosa Ziehau #include <sys/limits.h>
6515516c77SSepherosa Ziehau #include <sys/malloc.h>
6615516c77SSepherosa Ziehau #include <sys/mbuf.h>
6715516c77SSepherosa Ziehau #include <sys/module.h>
6815516c77SSepherosa Ziehau #include <sys/queue.h>
6915516c77SSepherosa Ziehau #include <sys/lock.h>
7015516c77SSepherosa Ziehau #include <sys/smp.h>
7115516c77SSepherosa Ziehau #include <sys/socket.h>
7215516c77SSepherosa Ziehau #include <sys/sockio.h>
7315516c77SSepherosa Ziehau #include <sys/sx.h>
7415516c77SSepherosa Ziehau #include <sys/sysctl.h>
7515516c77SSepherosa Ziehau #include <sys/systm.h>
7615516c77SSepherosa Ziehau #include <sys/taskqueue.h>
7715516c77SSepherosa Ziehau #include <sys/buf_ring.h>
7815516c77SSepherosa Ziehau 
7915516c77SSepherosa Ziehau #include <machine/atomic.h>
8015516c77SSepherosa Ziehau #include <machine/in_cksum.h>
8115516c77SSepherosa Ziehau 
8215516c77SSepherosa Ziehau #include <net/bpf.h>
8315516c77SSepherosa Ziehau #include <net/ethernet.h>
8415516c77SSepherosa Ziehau #include <net/if.h>
8515516c77SSepherosa Ziehau #include <net/if_media.h>
8615516c77SSepherosa Ziehau #include <net/if_types.h>
8715516c77SSepherosa Ziehau #include <net/if_var.h>
8815516c77SSepherosa Ziehau #include <net/rndis.h>
8915516c77SSepherosa Ziehau 
9015516c77SSepherosa Ziehau #include <netinet/in_systm.h>
9115516c77SSepherosa Ziehau #include <netinet/in.h>
9215516c77SSepherosa Ziehau #include <netinet/ip.h>
9315516c77SSepherosa Ziehau #include <netinet/ip6.h>
9415516c77SSepherosa Ziehau #include <netinet/tcp.h>
9515516c77SSepherosa Ziehau #include <netinet/tcp_lro.h>
9615516c77SSepherosa Ziehau #include <netinet/udp.h>
9715516c77SSepherosa Ziehau 
9815516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h>
9915516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv_busdma.h>
10015516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus.h>
10115516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus_xact.h>
10215516c77SSepherosa Ziehau 
10315516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/ndis.h>
10415516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnreg.h>
10515516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnvar.h>
10615516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_nvs.h>
10715516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_rndis.h>
10815516c77SSepherosa Ziehau 
10915516c77SSepherosa Ziehau #include "vmbus_if.h"
11015516c77SSepherosa Ziehau 
11123bf9e15SSepherosa Ziehau #define HN_IFSTART_SUPPORT
11223bf9e15SSepherosa Ziehau 
11315516c77SSepherosa Ziehau #define HN_RING_CNT_DEF_MAX		8
11415516c77SSepherosa Ziehau 
11515516c77SSepherosa Ziehau /* YYY should get it from the underlying channel */
11615516c77SSepherosa Ziehau #define HN_TX_DESC_CNT			512
11715516c77SSepherosa Ziehau 
11815516c77SSepherosa Ziehau #define HN_RNDIS_PKT_LEN					\
11915516c77SSepherosa Ziehau 	(sizeof(struct rndis_packet_msg) +			\
12015516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) +	\
12115516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) +		\
12215516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) +		\
12315516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_TXCSUM_INFO_SIZE))
12415516c77SSepherosa Ziehau #define HN_RNDIS_PKT_BOUNDARY		PAGE_SIZE
12515516c77SSepherosa Ziehau #define HN_RNDIS_PKT_ALIGN		CACHE_LINE_SIZE
12615516c77SSepherosa Ziehau 
12715516c77SSepherosa Ziehau #define HN_TX_DATA_BOUNDARY		PAGE_SIZE
12815516c77SSepherosa Ziehau #define HN_TX_DATA_MAXSIZE		IP_MAXPACKET
12915516c77SSepherosa Ziehau #define HN_TX_DATA_SEGSIZE		PAGE_SIZE
13015516c77SSepherosa Ziehau /* -1 for RNDIS packet message */
13115516c77SSepherosa Ziehau #define HN_TX_DATA_SEGCNT_MAX		(HN_GPACNT_MAX - 1)
13215516c77SSepherosa Ziehau 
13315516c77SSepherosa Ziehau #define HN_DIRECT_TX_SIZE_DEF		128
13415516c77SSepherosa Ziehau 
13515516c77SSepherosa Ziehau #define HN_EARLY_TXEOF_THRESH		8
13615516c77SSepherosa Ziehau 
13715516c77SSepherosa Ziehau #define HN_PKTBUF_LEN_DEF		(16 * 1024)
13815516c77SSepherosa Ziehau 
13915516c77SSepherosa Ziehau #define HN_LROENT_CNT_DEF		128
14015516c77SSepherosa Ziehau 
14115516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MULTIRX_DEF	(12 * ETHERMTU)
14215516c77SSepherosa Ziehau #define HN_LRO_LENLIM_DEF		(25 * ETHERMTU)
14315516c77SSepherosa Ziehau /* YYY 2*MTU is a bit rough, but should be good enough. */
14415516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MIN(ifp)		(2 * (ifp)->if_mtu)
14515516c77SSepherosa Ziehau 
14615516c77SSepherosa Ziehau #define HN_LRO_ACKCNT_DEF		1
14715516c77SSepherosa Ziehau 
14815516c77SSepherosa Ziehau #define HN_LOCK_INIT(sc)		\
14915516c77SSepherosa Ziehau 	sx_init(&(sc)->hn_lock, device_get_nameunit((sc)->hn_dev))
15015516c77SSepherosa Ziehau #define HN_LOCK_DESTROY(sc)		sx_destroy(&(sc)->hn_lock)
15115516c77SSepherosa Ziehau #define HN_LOCK_ASSERT(sc)		sx_assert(&(sc)->hn_lock, SA_XLOCKED)
152fdc4f478SSepherosa Ziehau #define HN_LOCK(sc)					\
153fdc4f478SSepherosa Ziehau do {							\
154fdc4f478SSepherosa Ziehau 	while (sx_try_xlock(&(sc)->hn_lock) == 0)	\
155fdc4f478SSepherosa Ziehau 		DELAY(1000);				\
156fdc4f478SSepherosa Ziehau } while (0)
15715516c77SSepherosa Ziehau #define HN_UNLOCK(sc)			sx_xunlock(&(sc)->hn_lock)
15815516c77SSepherosa Ziehau 
15915516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK			(CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP)
16015516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK		(CSUM_IP6_TCP | CSUM_IP6_UDP)
16115516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc)		\
16215516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK)
16315516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc)	\
16415516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK)
16515516c77SSepherosa Ziehau 
166dc13fee6SSepherosa Ziehau #define HN_PKTSIZE_MIN(align)		\
167dc13fee6SSepherosa Ziehau 	roundup2(ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN + \
168dc13fee6SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN, (align))
169dc13fee6SSepherosa Ziehau #define HN_PKTSIZE(m, align)		\
170dc13fee6SSepherosa Ziehau 	roundup2((m)->m_pkthdr.len + HN_RNDIS_PKT_LEN, (align))
171dc13fee6SSepherosa Ziehau 
17215516c77SSepherosa Ziehau struct hn_txdesc {
17315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
17415516c77SSepherosa Ziehau 	SLIST_ENTRY(hn_txdesc)		link;
17515516c77SSepherosa Ziehau #endif
176dc13fee6SSepherosa Ziehau 	STAILQ_ENTRY(hn_txdesc)		agg_link;
177dc13fee6SSepherosa Ziehau 
178dc13fee6SSepherosa Ziehau 	/* Aggregated txdescs, in sending order. */
179dc13fee6SSepherosa Ziehau 	STAILQ_HEAD(, hn_txdesc)	agg_list;
180dc13fee6SSepherosa Ziehau 
181dc13fee6SSepherosa Ziehau 	/* The oldest packet, if transmission aggregation happens. */
18215516c77SSepherosa Ziehau 	struct mbuf			*m;
18315516c77SSepherosa Ziehau 	struct hn_tx_ring		*txr;
18415516c77SSepherosa Ziehau 	int				refs;
18515516c77SSepherosa Ziehau 	uint32_t			flags;	/* HN_TXD_FLAG_ */
18615516c77SSepherosa Ziehau 	struct hn_nvs_sendctx		send_ctx;
18715516c77SSepherosa Ziehau 	uint32_t			chim_index;
18815516c77SSepherosa Ziehau 	int				chim_size;
18915516c77SSepherosa Ziehau 
19015516c77SSepherosa Ziehau 	bus_dmamap_t			data_dmap;
19115516c77SSepherosa Ziehau 
19215516c77SSepherosa Ziehau 	bus_addr_t			rndis_pkt_paddr;
19315516c77SSepherosa Ziehau 	struct rndis_packet_msg		*rndis_pkt;
19415516c77SSepherosa Ziehau 	bus_dmamap_t			rndis_pkt_dmap;
19515516c77SSepherosa Ziehau };
19615516c77SSepherosa Ziehau 
19715516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST		0x0001
19815516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP		0x0002
199dc13fee6SSepherosa Ziehau #define HN_TXD_FLAG_ONAGG		0x0004
20015516c77SSepherosa Ziehau 
20115516c77SSepherosa Ziehau struct hn_rxinfo {
20215516c77SSepherosa Ziehau 	uint32_t			vlan_info;
20315516c77SSepherosa Ziehau 	uint32_t			csum_info;
20415516c77SSepherosa Ziehau 	uint32_t			hash_info;
20515516c77SSepherosa Ziehau 	uint32_t			hash_value;
20615516c77SSepherosa Ziehau };
20715516c77SSepherosa Ziehau 
20815516c77SSepherosa Ziehau #define HN_RXINFO_VLAN			0x0001
20915516c77SSepherosa Ziehau #define HN_RXINFO_CSUM			0x0002
21015516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF		0x0004
21115516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL		0x0008
21215516c77SSepherosa Ziehau #define HN_RXINFO_ALL			\
21315516c77SSepherosa Ziehau 	(HN_RXINFO_VLAN |		\
21415516c77SSepherosa Ziehau 	 HN_RXINFO_CSUM |		\
21515516c77SSepherosa Ziehau 	 HN_RXINFO_HASHINF |		\
21615516c77SSepherosa Ziehau 	 HN_RXINFO_HASHVAL)
21715516c77SSepherosa Ziehau 
21815516c77SSepherosa Ziehau #define HN_NDIS_VLAN_INFO_INVALID	0xffffffff
21915516c77SSepherosa Ziehau #define HN_NDIS_RXCSUM_INFO_INVALID	0
22015516c77SSepherosa Ziehau #define HN_NDIS_HASH_INFO_INVALID	0
22115516c77SSepherosa Ziehau 
22215516c77SSepherosa Ziehau static int			hn_probe(device_t);
22315516c77SSepherosa Ziehau static int			hn_attach(device_t);
22415516c77SSepherosa Ziehau static int			hn_detach(device_t);
22515516c77SSepherosa Ziehau static int			hn_shutdown(device_t);
22615516c77SSepherosa Ziehau static void			hn_chan_callback(struct vmbus_channel *,
22715516c77SSepherosa Ziehau 				    void *);
22815516c77SSepherosa Ziehau 
22915516c77SSepherosa Ziehau static void			hn_init(void *);
23015516c77SSepherosa Ziehau static int			hn_ioctl(struct ifnet *, u_long, caddr_t);
23123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
23215516c77SSepherosa Ziehau static void			hn_start(struct ifnet *);
23323bf9e15SSepherosa Ziehau #endif
23415516c77SSepherosa Ziehau static int			hn_transmit(struct ifnet *, struct mbuf *);
23515516c77SSepherosa Ziehau static void			hn_xmit_qflush(struct ifnet *);
23615516c77SSepherosa Ziehau static int			hn_ifmedia_upd(struct ifnet *);
23715516c77SSepherosa Ziehau static void			hn_ifmedia_sts(struct ifnet *,
23815516c77SSepherosa Ziehau 				    struct ifmediareq *);
23915516c77SSepherosa Ziehau 
24015516c77SSepherosa Ziehau static int			hn_rndis_rxinfo(const void *, int,
24115516c77SSepherosa Ziehau 				    struct hn_rxinfo *);
24215516c77SSepherosa Ziehau static void			hn_rndis_rx_data(struct hn_rx_ring *,
24315516c77SSepherosa Ziehau 				    const void *, int);
24415516c77SSepherosa Ziehau static void			hn_rndis_rx_status(struct hn_softc *,
24515516c77SSepherosa Ziehau 				    const void *, int);
24615516c77SSepherosa Ziehau 
24715516c77SSepherosa Ziehau static void			hn_nvs_handle_notify(struct hn_softc *,
24815516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
24915516c77SSepherosa Ziehau static void			hn_nvs_handle_comp(struct hn_softc *,
25015516c77SSepherosa Ziehau 				    struct vmbus_channel *,
25115516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
25215516c77SSepherosa Ziehau static void			hn_nvs_handle_rxbuf(struct hn_rx_ring *,
25315516c77SSepherosa Ziehau 				    struct vmbus_channel *,
25415516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
25515516c77SSepherosa Ziehau static void			hn_nvs_ack_rxbuf(struct hn_rx_ring *,
25615516c77SSepherosa Ziehau 				    struct vmbus_channel *, uint64_t);
25715516c77SSepherosa Ziehau 
25815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
25915516c77SSepherosa Ziehau static int			hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS);
26015516c77SSepherosa Ziehau static int			hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS);
26115516c77SSepherosa Ziehau #endif
26215516c77SSepherosa Ziehau static int			hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS);
26315516c77SSepherosa Ziehau static int			hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS);
26415516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
26515516c77SSepherosa Ziehau static int			hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS);
26615516c77SSepherosa Ziehau #else
26715516c77SSepherosa Ziehau static int			hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS);
26815516c77SSepherosa Ziehau #endif
26915516c77SSepherosa Ziehau static int			hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
27015516c77SSepherosa Ziehau static int			hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
27115516c77SSepherosa Ziehau static int			hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS);
27215516c77SSepherosa Ziehau static int			hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS);
27315516c77SSepherosa Ziehau static int			hn_caps_sysctl(SYSCTL_HANDLER_ARGS);
27415516c77SSepherosa Ziehau static int			hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS);
27515516c77SSepherosa Ziehau static int			hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS);
27615516c77SSepherosa Ziehau static int			hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS);
27715516c77SSepherosa Ziehau static int			hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS);
27815516c77SSepherosa Ziehau static int			hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS);
279dc13fee6SSepherosa Ziehau static int			hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS);
280dc13fee6SSepherosa Ziehau static int			hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS);
281dc13fee6SSepherosa Ziehau static int			hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS);
282dc13fee6SSepherosa Ziehau static int			hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS);
28315516c77SSepherosa Ziehau 
28415516c77SSepherosa Ziehau static void			hn_stop(struct hn_softc *);
28515516c77SSepherosa Ziehau static void			hn_init_locked(struct hn_softc *);
28615516c77SSepherosa Ziehau static int			hn_chan_attach(struct hn_softc *,
28715516c77SSepherosa Ziehau 				    struct vmbus_channel *);
28815516c77SSepherosa Ziehau static void			hn_chan_detach(struct hn_softc *,
28915516c77SSepherosa Ziehau 				    struct vmbus_channel *);
29015516c77SSepherosa Ziehau static int			hn_attach_subchans(struct hn_softc *);
29115516c77SSepherosa Ziehau static void			hn_detach_allchans(struct hn_softc *);
29215516c77SSepherosa Ziehau static void			hn_chan_rollup(struct hn_rx_ring *,
29315516c77SSepherosa Ziehau 				    struct hn_tx_ring *);
29415516c77SSepherosa Ziehau static void			hn_set_ring_inuse(struct hn_softc *, int);
29515516c77SSepherosa Ziehau static int			hn_synth_attach(struct hn_softc *, int);
29615516c77SSepherosa Ziehau static void			hn_synth_detach(struct hn_softc *);
29715516c77SSepherosa Ziehau static int			hn_synth_alloc_subchans(struct hn_softc *,
29815516c77SSepherosa Ziehau 				    int *);
2992494d735SSepherosa Ziehau static bool			hn_synth_attachable(const struct hn_softc *);
30015516c77SSepherosa Ziehau static void			hn_suspend(struct hn_softc *);
30115516c77SSepherosa Ziehau static void			hn_suspend_data(struct hn_softc *);
30215516c77SSepherosa Ziehau static void			hn_suspend_mgmt(struct hn_softc *);
30315516c77SSepherosa Ziehau static void			hn_resume(struct hn_softc *);
30415516c77SSepherosa Ziehau static void			hn_resume_data(struct hn_softc *);
30515516c77SSepherosa Ziehau static void			hn_resume_mgmt(struct hn_softc *);
30615516c77SSepherosa Ziehau static void			hn_suspend_mgmt_taskfunc(void *, int);
30725641fc7SSepherosa Ziehau static void			hn_chan_drain(struct hn_softc *,
30825641fc7SSepherosa Ziehau 				    struct vmbus_channel *);
30915516c77SSepherosa Ziehau 
31015516c77SSepherosa Ziehau static void			hn_update_link_status(struct hn_softc *);
31115516c77SSepherosa Ziehau static void			hn_change_network(struct hn_softc *);
31215516c77SSepherosa Ziehau static void			hn_link_taskfunc(void *, int);
31315516c77SSepherosa Ziehau static void			hn_netchg_init_taskfunc(void *, int);
31415516c77SSepherosa Ziehau static void			hn_netchg_status_taskfunc(void *, int);
31515516c77SSepherosa Ziehau static void			hn_link_status(struct hn_softc *);
31615516c77SSepherosa Ziehau 
31715516c77SSepherosa Ziehau static int			hn_create_rx_data(struct hn_softc *, int);
31815516c77SSepherosa Ziehau static void			hn_destroy_rx_data(struct hn_softc *);
31915516c77SSepherosa Ziehau static int			hn_check_iplen(const struct mbuf *, int);
32015516c77SSepherosa Ziehau static int			hn_set_rxfilter(struct hn_softc *);
32115516c77SSepherosa Ziehau static int			hn_rss_reconfig(struct hn_softc *);
322afd4971bSSepherosa Ziehau static void			hn_rss_ind_fixup(struct hn_softc *);
32315516c77SSepherosa Ziehau static int			hn_rxpkt(struct hn_rx_ring *, const void *,
32415516c77SSepherosa Ziehau 				    int, const struct hn_rxinfo *);
32515516c77SSepherosa Ziehau 
32615516c77SSepherosa Ziehau static int			hn_tx_ring_create(struct hn_softc *, int);
32715516c77SSepherosa Ziehau static void			hn_tx_ring_destroy(struct hn_tx_ring *);
32815516c77SSepherosa Ziehau static int			hn_create_tx_data(struct hn_softc *, int);
32915516c77SSepherosa Ziehau static void			hn_fixup_tx_data(struct hn_softc *);
33015516c77SSepherosa Ziehau static void			hn_destroy_tx_data(struct hn_softc *);
33115516c77SSepherosa Ziehau static void			hn_txdesc_dmamap_destroy(struct hn_txdesc *);
33225641fc7SSepherosa Ziehau static void			hn_txdesc_gc(struct hn_tx_ring *,
33325641fc7SSepherosa Ziehau 				    struct hn_txdesc *);
334dc13fee6SSepherosa Ziehau static int			hn_encap(struct ifnet *, struct hn_tx_ring *,
33515516c77SSepherosa Ziehau 				    struct hn_txdesc *, struct mbuf **);
33615516c77SSepherosa Ziehau static int			hn_txpkt(struct ifnet *, struct hn_tx_ring *,
33715516c77SSepherosa Ziehau 				    struct hn_txdesc *);
33815516c77SSepherosa Ziehau static void			hn_set_chim_size(struct hn_softc *, int);
33915516c77SSepherosa Ziehau static void			hn_set_tso_maxsize(struct hn_softc *, int, int);
34015516c77SSepherosa Ziehau static bool			hn_tx_ring_pending(struct hn_tx_ring *);
34115516c77SSepherosa Ziehau static void			hn_tx_ring_qflush(struct hn_tx_ring *);
34215516c77SSepherosa Ziehau static void			hn_resume_tx(struct hn_softc *, int);
343dc13fee6SSepherosa Ziehau static void			hn_set_txagg(struct hn_softc *);
344dc13fee6SSepherosa Ziehau static void			*hn_try_txagg(struct ifnet *,
345dc13fee6SSepherosa Ziehau 				    struct hn_tx_ring *, struct hn_txdesc *,
346dc13fee6SSepherosa Ziehau 				    int);
34715516c77SSepherosa Ziehau static int			hn_get_txswq_depth(const struct hn_tx_ring *);
34815516c77SSepherosa Ziehau static void			hn_txpkt_done(struct hn_nvs_sendctx *,
34915516c77SSepherosa Ziehau 				    struct hn_softc *, struct vmbus_channel *,
35015516c77SSepherosa Ziehau 				    const void *, int);
35115516c77SSepherosa Ziehau static int			hn_txpkt_sglist(struct hn_tx_ring *,
35215516c77SSepherosa Ziehau 				    struct hn_txdesc *);
35315516c77SSepherosa Ziehau static int			hn_txpkt_chim(struct hn_tx_ring *,
35415516c77SSepherosa Ziehau 				    struct hn_txdesc *);
35515516c77SSepherosa Ziehau static int			hn_xmit(struct hn_tx_ring *, int);
35615516c77SSepherosa Ziehau static void			hn_xmit_taskfunc(void *, int);
35715516c77SSepherosa Ziehau static void			hn_xmit_txeof(struct hn_tx_ring *);
35815516c77SSepherosa Ziehau static void			hn_xmit_txeof_taskfunc(void *, int);
35923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
36015516c77SSepherosa Ziehau static int			hn_start_locked(struct hn_tx_ring *, int);
36115516c77SSepherosa Ziehau static void			hn_start_taskfunc(void *, int);
36215516c77SSepherosa Ziehau static void			hn_start_txeof(struct hn_tx_ring *);
36315516c77SSepherosa Ziehau static void			hn_start_txeof_taskfunc(void *, int);
36423bf9e15SSepherosa Ziehau #endif
36515516c77SSepherosa Ziehau 
36615516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
36715516c77SSepherosa Ziehau     "Hyper-V network interface");
36815516c77SSepherosa Ziehau 
36915516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */
37015516c77SSepherosa Ziehau static int			hn_trust_hosttcp = 1;
37115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN,
37215516c77SSepherosa Ziehau     &hn_trust_hosttcp, 0,
37315516c77SSepherosa Ziehau     "Trust tcp segement verification on host side, "
37415516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
37515516c77SSepherosa Ziehau 
37615516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */
37715516c77SSepherosa Ziehau static int			hn_trust_hostudp = 1;
37815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN,
37915516c77SSepherosa Ziehau     &hn_trust_hostudp, 0,
38015516c77SSepherosa Ziehau     "Trust udp datagram verification on host side, "
38115516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
38215516c77SSepherosa Ziehau 
38315516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */
38415516c77SSepherosa Ziehau static int			hn_trust_hostip = 1;
38515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN,
38615516c77SSepherosa Ziehau     &hn_trust_hostip, 0,
38715516c77SSepherosa Ziehau     "Trust ip packet verification on host side, "
38815516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
38915516c77SSepherosa Ziehau 
39015516c77SSepherosa Ziehau /* Limit TSO burst size */
39115516c77SSepherosa Ziehau static int			hn_tso_maxlen = IP_MAXPACKET;
39215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN,
39315516c77SSepherosa Ziehau     &hn_tso_maxlen, 0, "TSO burst limit");
39415516c77SSepherosa Ziehau 
39515516c77SSepherosa Ziehau /* Limit chimney send size */
39615516c77SSepherosa Ziehau static int			hn_tx_chimney_size = 0;
39715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN,
39815516c77SSepherosa Ziehau     &hn_tx_chimney_size, 0, "Chimney send packet size limit");
39915516c77SSepherosa Ziehau 
40015516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */
40115516c77SSepherosa Ziehau static int			hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF;
40215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN,
40315516c77SSepherosa Ziehau     &hn_direct_tx_size, 0, "Size of the packet for direct transmission");
40415516c77SSepherosa Ziehau 
40515516c77SSepherosa Ziehau /* # of LRO entries per RX ring */
40615516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
40715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
40815516c77SSepherosa Ziehau static int			hn_lro_entry_count = HN_LROENT_CNT_DEF;
40915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN,
41015516c77SSepherosa Ziehau     &hn_lro_entry_count, 0, "LRO entry count");
41115516c77SSepherosa Ziehau #endif
41215516c77SSepherosa Ziehau #endif
41315516c77SSepherosa Ziehau 
41415516c77SSepherosa Ziehau /* Use shared TX taskqueue */
41515516c77SSepherosa Ziehau static int			hn_share_tx_taskq = 0;
41615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, share_tx_taskq, CTLFLAG_RDTUN,
41715516c77SSepherosa Ziehau     &hn_share_tx_taskq, 0, "Enable shared TX taskqueue");
41815516c77SSepherosa Ziehau 
419*fdd0222aSSepherosa Ziehau static int			hn_tx_taskq_cnt = 1;
420*fdd0222aSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_cnt, CTLFLAG_RDTUN,
421*fdd0222aSSepherosa Ziehau     &hn_tx_taskq_cnt, 0, "# of TX taskqueues");
422*fdd0222aSSepherosa Ziehau 
42315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
42415516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 0;
42515516c77SSepherosa Ziehau #else
42615516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 1;
42715516c77SSepherosa Ziehau #endif
42815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD,
42915516c77SSepherosa Ziehau     &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors");
43015516c77SSepherosa Ziehau 
43123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
43215516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */
43315516c77SSepherosa Ziehau static int			hn_use_if_start = 0;
43415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN,
43515516c77SSepherosa Ziehau     &hn_use_if_start, 0, "Use if_start TX method");
43623bf9e15SSepherosa Ziehau #endif
43715516c77SSepherosa Ziehau 
43815516c77SSepherosa Ziehau /* # of channels to use */
43915516c77SSepherosa Ziehau static int			hn_chan_cnt = 0;
44015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN,
44115516c77SSepherosa Ziehau     &hn_chan_cnt, 0,
44215516c77SSepherosa Ziehau     "# of channels to use; each channel has one RX ring and one TX ring");
44315516c77SSepherosa Ziehau 
44415516c77SSepherosa Ziehau /* # of transmit rings to use */
44515516c77SSepherosa Ziehau static int			hn_tx_ring_cnt = 0;
44615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN,
44715516c77SSepherosa Ziehau     &hn_tx_ring_cnt, 0, "# of TX rings to use");
44815516c77SSepherosa Ziehau 
44915516c77SSepherosa Ziehau /* Software TX ring deptch */
45015516c77SSepherosa Ziehau static int			hn_tx_swq_depth = 0;
45115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN,
45215516c77SSepherosa Ziehau     &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING");
45315516c77SSepherosa Ziehau 
45415516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */
45515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
45615516c77SSepherosa Ziehau static u_int			hn_lro_mbufq_depth = 0;
45715516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN,
45815516c77SSepherosa Ziehau     &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue");
45915516c77SSepherosa Ziehau #endif
46015516c77SSepherosa Ziehau 
461dc13fee6SSepherosa Ziehau /* Packet transmission aggregation size limit */
462dc13fee6SSepherosa Ziehau static int			hn_tx_agg_size = -1;
463dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN,
464dc13fee6SSepherosa Ziehau     &hn_tx_agg_size, 0, "Packet transmission aggregation size limit");
465dc13fee6SSepherosa Ziehau 
466dc13fee6SSepherosa Ziehau /* Packet transmission aggregation count limit */
467fa915c4dSSepherosa Ziehau static int			hn_tx_agg_pkts = -1;
468dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN,
469dc13fee6SSepherosa Ziehau     &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit");
470dc13fee6SSepherosa Ziehau 
47115516c77SSepherosa Ziehau static u_int			hn_cpu_index;	/* next CPU for channel */
472*fdd0222aSSepherosa Ziehau static struct taskqueue		**hn_tx_taskque;/* shared TX taskqueues */
47315516c77SSepherosa Ziehau 
47415516c77SSepherosa Ziehau static const uint8_t
47515516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
47615516c77SSepherosa Ziehau 	0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
47715516c77SSepherosa Ziehau 	0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
47815516c77SSepherosa Ziehau 	0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
47915516c77SSepherosa Ziehau 	0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
48015516c77SSepherosa Ziehau 	0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
48115516c77SSepherosa Ziehau };
48215516c77SSepherosa Ziehau 
48315516c77SSepherosa Ziehau static device_method_t hn_methods[] = {
48415516c77SSepherosa Ziehau 	/* Device interface */
48515516c77SSepherosa Ziehau 	DEVMETHOD(device_probe,		hn_probe),
48615516c77SSepherosa Ziehau 	DEVMETHOD(device_attach,	hn_attach),
48715516c77SSepherosa Ziehau 	DEVMETHOD(device_detach,	hn_detach),
48815516c77SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	hn_shutdown),
48915516c77SSepherosa Ziehau 	DEVMETHOD_END
49015516c77SSepherosa Ziehau };
49115516c77SSepherosa Ziehau 
49215516c77SSepherosa Ziehau static driver_t hn_driver = {
49315516c77SSepherosa Ziehau 	"hn",
49415516c77SSepherosa Ziehau 	hn_methods,
49515516c77SSepherosa Ziehau 	sizeof(struct hn_softc)
49615516c77SSepherosa Ziehau };
49715516c77SSepherosa Ziehau 
49815516c77SSepherosa Ziehau static devclass_t hn_devclass;
49915516c77SSepherosa Ziehau 
50015516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0);
50115516c77SSepherosa Ziehau MODULE_VERSION(hn, 1);
50215516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1);
50315516c77SSepherosa Ziehau 
50415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
50515516c77SSepherosa Ziehau static void
50615516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim)
50715516c77SSepherosa Ziehau {
50815516c77SSepherosa Ziehau 	int i;
50915516c77SSepherosa Ziehau 
510a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
51115516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim;
51215516c77SSepherosa Ziehau }
51315516c77SSepherosa Ziehau #endif
51415516c77SSepherosa Ziehau 
51515516c77SSepherosa Ziehau static int
51615516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd)
51715516c77SSepherosa Ziehau {
51815516c77SSepherosa Ziehau 
51915516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
52015516c77SSepherosa Ziehau 	    txd->chim_size == 0, ("invalid rndis sglist txd"));
52115516c77SSepherosa Ziehau 	return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA,
52215516c77SSepherosa Ziehau 	    &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt));
52315516c77SSepherosa Ziehau }
52415516c77SSepherosa Ziehau 
52515516c77SSepherosa Ziehau static int
52615516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd)
52715516c77SSepherosa Ziehau {
52815516c77SSepherosa Ziehau 	struct hn_nvs_rndis rndis;
52915516c77SSepherosa Ziehau 
53015516c77SSepherosa Ziehau 	KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID &&
53115516c77SSepherosa Ziehau 	    txd->chim_size > 0, ("invalid rndis chim txd"));
53215516c77SSepherosa Ziehau 
53315516c77SSepherosa Ziehau 	rndis.nvs_type = HN_NVS_TYPE_RNDIS;
53415516c77SSepherosa Ziehau 	rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA;
53515516c77SSepherosa Ziehau 	rndis.nvs_chim_idx = txd->chim_index;
53615516c77SSepherosa Ziehau 	rndis.nvs_chim_sz = txd->chim_size;
53715516c77SSepherosa Ziehau 
53815516c77SSepherosa Ziehau 	return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC,
53915516c77SSepherosa Ziehau 	    &rndis, sizeof(rndis), &txd->send_ctx));
54015516c77SSepherosa Ziehau }
54115516c77SSepherosa Ziehau 
54215516c77SSepherosa Ziehau static __inline uint32_t
54315516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc)
54415516c77SSepherosa Ziehau {
54515516c77SSepherosa Ziehau 	int i, bmap_cnt = sc->hn_chim_bmap_cnt;
54615516c77SSepherosa Ziehau 	u_long *bmap = sc->hn_chim_bmap;
54715516c77SSepherosa Ziehau 	uint32_t ret = HN_NVS_CHIM_IDX_INVALID;
54815516c77SSepherosa Ziehau 
54915516c77SSepherosa Ziehau 	for (i = 0; i < bmap_cnt; ++i) {
55015516c77SSepherosa Ziehau 		int idx;
55115516c77SSepherosa Ziehau 
55215516c77SSepherosa Ziehau 		idx = ffsl(~bmap[i]);
55315516c77SSepherosa Ziehau 		if (idx == 0)
55415516c77SSepherosa Ziehau 			continue;
55515516c77SSepherosa Ziehau 
55615516c77SSepherosa Ziehau 		--idx; /* ffsl is 1-based */
55715516c77SSepherosa Ziehau 		KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt,
55815516c77SSepherosa Ziehau 		    ("invalid i %d and idx %d", i, idx));
55915516c77SSepherosa Ziehau 
56015516c77SSepherosa Ziehau 		if (atomic_testandset_long(&bmap[i], idx))
56115516c77SSepherosa Ziehau 			continue;
56215516c77SSepherosa Ziehau 
56315516c77SSepherosa Ziehau 		ret = i * LONG_BIT + idx;
56415516c77SSepherosa Ziehau 		break;
56515516c77SSepherosa Ziehau 	}
56615516c77SSepherosa Ziehau 	return (ret);
56715516c77SSepherosa Ziehau }
56815516c77SSepherosa Ziehau 
56915516c77SSepherosa Ziehau static __inline void
57015516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx)
57115516c77SSepherosa Ziehau {
57215516c77SSepherosa Ziehau 	u_long mask;
57315516c77SSepherosa Ziehau 	uint32_t idx;
57415516c77SSepherosa Ziehau 
57515516c77SSepherosa Ziehau 	idx = chim_idx / LONG_BIT;
57615516c77SSepherosa Ziehau 	KASSERT(idx < sc->hn_chim_bmap_cnt,
57715516c77SSepherosa Ziehau 	    ("invalid chimney index 0x%x", chim_idx));
57815516c77SSepherosa Ziehau 
57915516c77SSepherosa Ziehau 	mask = 1UL << (chim_idx % LONG_BIT);
58015516c77SSepherosa Ziehau 	KASSERT(sc->hn_chim_bmap[idx] & mask,
58115516c77SSepherosa Ziehau 	    ("index bitmap 0x%lx, chimney index %u, "
58215516c77SSepherosa Ziehau 	     "bitmap idx %d, bitmask 0x%lx",
58315516c77SSepherosa Ziehau 	     sc->hn_chim_bmap[idx], chim_idx, idx, mask));
58415516c77SSepherosa Ziehau 
58515516c77SSepherosa Ziehau 	atomic_clear_long(&sc->hn_chim_bmap[idx], mask);
58615516c77SSepherosa Ziehau }
58715516c77SSepherosa Ziehau 
588edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
589edd3f315SSepherosa Ziehau /*
590edd3f315SSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
591edd3f315SSepherosa Ziehau  */
592edd3f315SSepherosa Ziehau static __inline struct mbuf *
593edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head)
594edd3f315SSepherosa Ziehau {
595edd3f315SSepherosa Ziehau 	struct ether_vlan_header *evl;
596edd3f315SSepherosa Ziehau 	struct tcphdr *th;
597edd3f315SSepherosa Ziehau 	int ehlen;
598edd3f315SSepherosa Ziehau 
599edd3f315SSepherosa Ziehau 	KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable"));
600edd3f315SSepherosa Ziehau 
601edd3f315SSepherosa Ziehau #define PULLUP_HDR(m, len)				\
602edd3f315SSepherosa Ziehau do {							\
603edd3f315SSepherosa Ziehau 	if (__predict_false((m)->m_len < (len))) {	\
604edd3f315SSepherosa Ziehau 		(m) = m_pullup((m), (len));		\
605edd3f315SSepherosa Ziehau 		if ((m) == NULL)			\
606edd3f315SSepherosa Ziehau 			return (NULL);			\
607edd3f315SSepherosa Ziehau 	}						\
608edd3f315SSepherosa Ziehau } while (0)
609edd3f315SSepherosa Ziehau 
610edd3f315SSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
611edd3f315SSepherosa Ziehau 	evl = mtod(m_head, struct ether_vlan_header *);
612edd3f315SSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
613edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
614edd3f315SSepherosa Ziehau 	else
615edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
616edd3f315SSepherosa Ziehau 
617edd3f315SSepherosa Ziehau #ifdef INET
618edd3f315SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
619edd3f315SSepherosa Ziehau 		struct ip *ip;
620edd3f315SSepherosa Ziehau 		int iphlen;
621edd3f315SSepherosa Ziehau 
622edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
623edd3f315SSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
624edd3f315SSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
625edd3f315SSepherosa Ziehau 
626edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
627edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + iphlen);
628edd3f315SSepherosa Ziehau 
629edd3f315SSepherosa Ziehau 		ip->ip_len = 0;
630edd3f315SSepherosa Ziehau 		ip->ip_sum = 0;
631edd3f315SSepherosa Ziehau 		th->th_sum = in_pseudo(ip->ip_src.s_addr,
632edd3f315SSepherosa Ziehau 		    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
633edd3f315SSepherosa Ziehau 	}
634edd3f315SSepherosa Ziehau #endif
635edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET)
636edd3f315SSepherosa Ziehau 	else
637edd3f315SSepherosa Ziehau #endif
638edd3f315SSepherosa Ziehau #ifdef INET6
639edd3f315SSepherosa Ziehau 	{
640edd3f315SSepherosa Ziehau 		struct ip6_hdr *ip6;
641edd3f315SSepherosa Ziehau 
642edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
643edd3f315SSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
644edd3f315SSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP) {
645edd3f315SSepherosa Ziehau 			m_freem(m_head);
646edd3f315SSepherosa Ziehau 			return (NULL);
647edd3f315SSepherosa Ziehau 		}
648edd3f315SSepherosa Ziehau 
649edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
650edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + sizeof(*ip6));
651edd3f315SSepherosa Ziehau 
652edd3f315SSepherosa Ziehau 		ip6->ip6_plen = 0;
653edd3f315SSepherosa Ziehau 		th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
654edd3f315SSepherosa Ziehau 	}
655edd3f315SSepherosa Ziehau #endif
656edd3f315SSepherosa Ziehau 	return (m_head);
657edd3f315SSepherosa Ziehau 
658edd3f315SSepherosa Ziehau #undef PULLUP_HDR
659edd3f315SSepherosa Ziehau }
660edd3f315SSepherosa Ziehau #endif	/* INET6 || INET */
661edd3f315SSepherosa Ziehau 
66215516c77SSepherosa Ziehau static int
66315516c77SSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc)
66415516c77SSepherosa Ziehau {
66515516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
66615516c77SSepherosa Ziehau 	uint32_t filter;
66715516c77SSepherosa Ziehau 	int error = 0;
66815516c77SSepherosa Ziehau 
66915516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
67015516c77SSepherosa Ziehau 
67115516c77SSepherosa Ziehau 	if (ifp->if_flags & IFF_PROMISC) {
67215516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_PROMISCUOUS;
67315516c77SSepherosa Ziehau 	} else {
67415516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_DIRECTED;
67515516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_BROADCAST)
67615516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_BROADCAST;
67715516c77SSepherosa Ziehau 		/* TODO: support multicast list */
67815516c77SSepherosa Ziehau 		if ((ifp->if_flags & IFF_ALLMULTI) ||
67915516c77SSepherosa Ziehau 		    !TAILQ_EMPTY(&ifp->if_multiaddrs))
68015516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
68115516c77SSepherosa Ziehau 	}
68215516c77SSepherosa Ziehau 
68315516c77SSepherosa Ziehau 	if (sc->hn_rx_filter != filter) {
68415516c77SSepherosa Ziehau 		error = hn_rndis_set_rxfilter(sc, filter);
68515516c77SSepherosa Ziehau 		if (!error)
68615516c77SSepherosa Ziehau 			sc->hn_rx_filter = filter;
68715516c77SSepherosa Ziehau 	}
68815516c77SSepherosa Ziehau 	return (error);
68915516c77SSepherosa Ziehau }
69015516c77SSepherosa Ziehau 
691dc13fee6SSepherosa Ziehau static void
692dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc)
693dc13fee6SSepherosa Ziehau {
694dc13fee6SSepherosa Ziehau 	uint32_t size, pkts;
695dc13fee6SSepherosa Ziehau 	int i;
696dc13fee6SSepherosa Ziehau 
697dc13fee6SSepherosa Ziehau 	/*
698dc13fee6SSepherosa Ziehau 	 * Setup aggregation size.
699dc13fee6SSepherosa Ziehau 	 */
700dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_size < 0)
701dc13fee6SSepherosa Ziehau 		size = UINT32_MAX;
702dc13fee6SSepherosa Ziehau 	else
703dc13fee6SSepherosa Ziehau 		size = sc->hn_agg_size;
704dc13fee6SSepherosa Ziehau 
705dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_size < size)
706dc13fee6SSepherosa Ziehau 		size = sc->hn_rndis_agg_size;
707dc13fee6SSepherosa Ziehau 
708a4364cfeSSepherosa Ziehau 	/* NOTE: We only aggregate packets using chimney sending buffers. */
709a4364cfeSSepherosa Ziehau 	if (size > (uint32_t)sc->hn_chim_szmax)
710a4364cfeSSepherosa Ziehau 		size = sc->hn_chim_szmax;
711a4364cfeSSepherosa Ziehau 
712dc13fee6SSepherosa Ziehau 	if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) {
713dc13fee6SSepherosa Ziehau 		/* Disable */
714dc13fee6SSepherosa Ziehau 		size = 0;
715dc13fee6SSepherosa Ziehau 		pkts = 0;
716dc13fee6SSepherosa Ziehau 		goto done;
717dc13fee6SSepherosa Ziehau 	}
718dc13fee6SSepherosa Ziehau 
719dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'int'. */
720dc13fee6SSepherosa Ziehau 	if (size > INT_MAX)
721dc13fee6SSepherosa Ziehau 		size = INT_MAX;
722dc13fee6SSepherosa Ziehau 
723dc13fee6SSepherosa Ziehau 	/*
724dc13fee6SSepherosa Ziehau 	 * Setup aggregation packet count.
725dc13fee6SSepherosa Ziehau 	 */
726dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_pkts < 0)
727dc13fee6SSepherosa Ziehau 		pkts = UINT32_MAX;
728dc13fee6SSepherosa Ziehau 	else
729dc13fee6SSepherosa Ziehau 		pkts = sc->hn_agg_pkts;
730dc13fee6SSepherosa Ziehau 
731dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_pkts < pkts)
732dc13fee6SSepherosa Ziehau 		pkts = sc->hn_rndis_agg_pkts;
733dc13fee6SSepherosa Ziehau 
734dc13fee6SSepherosa Ziehau 	if (pkts <= 1) {
735dc13fee6SSepherosa Ziehau 		/* Disable */
736dc13fee6SSepherosa Ziehau 		size = 0;
737dc13fee6SSepherosa Ziehau 		pkts = 0;
738dc13fee6SSepherosa Ziehau 		goto done;
739dc13fee6SSepherosa Ziehau 	}
740dc13fee6SSepherosa Ziehau 
741dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
742dc13fee6SSepherosa Ziehau 	if (pkts > SHRT_MAX)
743dc13fee6SSepherosa Ziehau 		pkts = SHRT_MAX;
744dc13fee6SSepherosa Ziehau 
745dc13fee6SSepherosa Ziehau done:
746dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
747dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_align > SHRT_MAX) {
748dc13fee6SSepherosa Ziehau 		/* Disable */
749dc13fee6SSepherosa Ziehau 		size = 0;
750dc13fee6SSepherosa Ziehau 		pkts = 0;
751dc13fee6SSepherosa Ziehau 	}
752dc13fee6SSepherosa Ziehau 
753dc13fee6SSepherosa Ziehau 	if (bootverbose) {
754dc13fee6SSepherosa Ziehau 		if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n",
755dc13fee6SSepherosa Ziehau 		    size, pkts, sc->hn_rndis_agg_align);
756dc13fee6SSepherosa Ziehau 	}
757dc13fee6SSepherosa Ziehau 
758dc13fee6SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
759dc13fee6SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
760dc13fee6SSepherosa Ziehau 
761dc13fee6SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
762dc13fee6SSepherosa Ziehau 		txr->hn_agg_szmax = size;
763dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktmax = pkts;
764dc13fee6SSepherosa Ziehau 		txr->hn_agg_align = sc->hn_rndis_agg_align;
765dc13fee6SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
766dc13fee6SSepherosa Ziehau 	}
767dc13fee6SSepherosa Ziehau }
768dc13fee6SSepherosa Ziehau 
76915516c77SSepherosa Ziehau static int
77015516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr)
77115516c77SSepherosa Ziehau {
77215516c77SSepherosa Ziehau 
77315516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet"));
77415516c77SSepherosa Ziehau 	if (hn_tx_swq_depth < txr->hn_txdesc_cnt)
77515516c77SSepherosa Ziehau 		return txr->hn_txdesc_cnt;
77615516c77SSepherosa Ziehau 	return hn_tx_swq_depth;
77715516c77SSepherosa Ziehau }
77815516c77SSepherosa Ziehau 
77915516c77SSepherosa Ziehau static int
78015516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc)
78115516c77SSepherosa Ziehau {
78215516c77SSepherosa Ziehau 	int error;
78315516c77SSepherosa Ziehau 
78415516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
78515516c77SSepherosa Ziehau 
78615516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
78715516c77SSepherosa Ziehau 		return (ENXIO);
78815516c77SSepherosa Ziehau 
78915516c77SSepherosa Ziehau 	/*
79015516c77SSepherosa Ziehau 	 * Disable RSS first.
79115516c77SSepherosa Ziehau 	 *
79215516c77SSepherosa Ziehau 	 * NOTE:
79315516c77SSepherosa Ziehau 	 * Direct reconfiguration by setting the UNCHG flags does
79415516c77SSepherosa Ziehau 	 * _not_ work properly.
79515516c77SSepherosa Ziehau 	 */
79615516c77SSepherosa Ziehau 	if (bootverbose)
79715516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "disable RSS\n");
79815516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE);
79915516c77SSepherosa Ziehau 	if (error) {
80015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS disable failed\n");
80115516c77SSepherosa Ziehau 		return (error);
80215516c77SSepherosa Ziehau 	}
80315516c77SSepherosa Ziehau 
80415516c77SSepherosa Ziehau 	/*
80515516c77SSepherosa Ziehau 	 * Reenable the RSS w/ the updated RSS key or indirect
80615516c77SSepherosa Ziehau 	 * table.
80715516c77SSepherosa Ziehau 	 */
80815516c77SSepherosa Ziehau 	if (bootverbose)
80915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "reconfig RSS\n");
81015516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
81115516c77SSepherosa Ziehau 	if (error) {
81215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS reconfig failed\n");
81315516c77SSepherosa Ziehau 		return (error);
81415516c77SSepherosa Ziehau 	}
81515516c77SSepherosa Ziehau 	return (0);
81615516c77SSepherosa Ziehau }
81715516c77SSepherosa Ziehau 
81815516c77SSepherosa Ziehau static void
819afd4971bSSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc)
82015516c77SSepherosa Ziehau {
82115516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
822afd4971bSSepherosa Ziehau 	int i, nchan;
82315516c77SSepherosa Ziehau 
824afd4971bSSepherosa Ziehau 	nchan = sc->hn_rx_ring_inuse;
82515516c77SSepherosa Ziehau 	KASSERT(nchan > 1, ("invalid # of channels %d", nchan));
82615516c77SSepherosa Ziehau 
82715516c77SSepherosa Ziehau 	/*
82815516c77SSepherosa Ziehau 	 * Check indirect table to make sure that all channels in it
82915516c77SSepherosa Ziehau 	 * can be used.
83015516c77SSepherosa Ziehau 	 */
83115516c77SSepherosa Ziehau 	for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
83215516c77SSepherosa Ziehau 		if (rss->rss_ind[i] >= nchan) {
83315516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp,
83415516c77SSepherosa Ziehau 			    "RSS indirect table %d fixup: %u -> %d\n",
83515516c77SSepherosa Ziehau 			    i, rss->rss_ind[i], nchan - 1);
83615516c77SSepherosa Ziehau 			rss->rss_ind[i] = nchan - 1;
83715516c77SSepherosa Ziehau 		}
83815516c77SSepherosa Ziehau 	}
83915516c77SSepherosa Ziehau }
84015516c77SSepherosa Ziehau 
84115516c77SSepherosa Ziehau static int
84215516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused)
84315516c77SSepherosa Ziehau {
84415516c77SSepherosa Ziehau 
84515516c77SSepherosa Ziehau 	return EOPNOTSUPP;
84615516c77SSepherosa Ziehau }
84715516c77SSepherosa Ziehau 
84815516c77SSepherosa Ziehau static void
84915516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
85015516c77SSepherosa Ziehau {
85115516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
85215516c77SSepherosa Ziehau 
85315516c77SSepherosa Ziehau 	ifmr->ifm_status = IFM_AVALID;
85415516c77SSepherosa Ziehau 	ifmr->ifm_active = IFM_ETHER;
85515516c77SSepherosa Ziehau 
85615516c77SSepherosa Ziehau 	if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) {
85715516c77SSepherosa Ziehau 		ifmr->ifm_active |= IFM_NONE;
85815516c77SSepherosa Ziehau 		return;
85915516c77SSepherosa Ziehau 	}
86015516c77SSepherosa Ziehau 	ifmr->ifm_status |= IFM_ACTIVE;
86115516c77SSepherosa Ziehau 	ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
86215516c77SSepherosa Ziehau }
86315516c77SSepherosa Ziehau 
86415516c77SSepherosa Ziehau /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
86515516c77SSepherosa Ziehau static const struct hyperv_guid g_net_vsc_device_type = {
86615516c77SSepherosa Ziehau 	.hv_guid = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
86715516c77SSepherosa Ziehau 		0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E}
86815516c77SSepherosa Ziehau };
86915516c77SSepherosa Ziehau 
87015516c77SSepherosa Ziehau static int
87115516c77SSepherosa Ziehau hn_probe(device_t dev)
87215516c77SSepherosa Ziehau {
87315516c77SSepherosa Ziehau 
87415516c77SSepherosa Ziehau 	if (VMBUS_PROBE_GUID(device_get_parent(dev), dev,
87515516c77SSepherosa Ziehau 	    &g_net_vsc_device_type) == 0) {
87615516c77SSepherosa Ziehau 		device_set_desc(dev, "Hyper-V Network Interface");
87715516c77SSepherosa Ziehau 		return BUS_PROBE_DEFAULT;
87815516c77SSepherosa Ziehau 	}
87915516c77SSepherosa Ziehau 	return ENXIO;
88015516c77SSepherosa Ziehau }
88115516c77SSepherosa Ziehau 
88215516c77SSepherosa Ziehau static int
88315516c77SSepherosa Ziehau hn_attach(device_t dev)
88415516c77SSepherosa Ziehau {
88515516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
88615516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
88715516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
88815516c77SSepherosa Ziehau 	uint8_t eaddr[ETHER_ADDR_LEN];
88915516c77SSepherosa Ziehau 	struct ifnet *ifp = NULL;
89015516c77SSepherosa Ziehau 	int error, ring_cnt, tx_ring_cnt;
89115516c77SSepherosa Ziehau 
89215516c77SSepherosa Ziehau 	sc->hn_dev = dev;
89315516c77SSepherosa Ziehau 	sc->hn_prichan = vmbus_get_channel(dev);
89415516c77SSepherosa Ziehau 	HN_LOCK_INIT(sc);
89515516c77SSepherosa Ziehau 
89615516c77SSepherosa Ziehau 	/*
897dc13fee6SSepherosa Ziehau 	 * Initialize these tunables once.
898dc13fee6SSepherosa Ziehau 	 */
899dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = hn_tx_agg_size;
900dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = hn_tx_agg_pkts;
901dc13fee6SSepherosa Ziehau 
902dc13fee6SSepherosa Ziehau 	/*
90315516c77SSepherosa Ziehau 	 * Setup taskqueue for transmission.
90415516c77SSepherosa Ziehau 	 */
905*fdd0222aSSepherosa Ziehau 	if (hn_tx_taskque == NULL) {
906*fdd0222aSSepherosa Ziehau 		int i;
907*fdd0222aSSepherosa Ziehau 
908*fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs =
909*fdd0222aSSepherosa Ziehau 		    malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
910*fdd0222aSSepherosa Ziehau 		    M_DEVBUF, M_WAITOK);
911*fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i) {
912*fdd0222aSSepherosa Ziehau 			sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx",
913*fdd0222aSSepherosa Ziehau 			    M_WAITOK, taskqueue_thread_enqueue,
914*fdd0222aSSepherosa Ziehau 			    &sc->hn_tx_taskqs[i]);
915*fdd0222aSSepherosa Ziehau 			taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET,
916*fdd0222aSSepherosa Ziehau 			    "%s tx%d", device_get_nameunit(dev), i);
917*fdd0222aSSepherosa Ziehau 		}
91815516c77SSepherosa Ziehau 	} else {
919*fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs = hn_tx_taskque;
92015516c77SSepherosa Ziehau 	}
92115516c77SSepherosa Ziehau 
92215516c77SSepherosa Ziehau 	/*
92315516c77SSepherosa Ziehau 	 * Setup taskqueue for mangement tasks, e.g. link status.
92415516c77SSepherosa Ziehau 	 */
92515516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK,
92615516c77SSepherosa Ziehau 	    taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0);
92715516c77SSepherosa Ziehau 	taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
92815516c77SSepherosa Ziehau 	    device_get_nameunit(dev));
92915516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
93015516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc);
93115516c77SSepherosa Ziehau 	TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0,
93215516c77SSepherosa Ziehau 	    hn_netchg_status_taskfunc, sc);
93315516c77SSepherosa Ziehau 
93415516c77SSepherosa Ziehau 	/*
93515516c77SSepherosa Ziehau 	 * Allocate ifnet and setup its name earlier, so that if_printf
93615516c77SSepherosa Ziehau 	 * can be used by functions, which will be called after
93715516c77SSepherosa Ziehau 	 * ether_ifattach().
93815516c77SSepherosa Ziehau 	 */
93915516c77SSepherosa Ziehau 	ifp = sc->hn_ifp = if_alloc(IFT_ETHER);
94015516c77SSepherosa Ziehau 	ifp->if_softc = sc;
94115516c77SSepherosa Ziehau 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
94215516c77SSepherosa Ziehau 
94315516c77SSepherosa Ziehau 	/*
94415516c77SSepherosa Ziehau 	 * Initialize ifmedia earlier so that it can be unconditionally
94515516c77SSepherosa Ziehau 	 * destroyed, if error happened later on.
94615516c77SSepherosa Ziehau 	 */
94715516c77SSepherosa Ziehau 	ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts);
94815516c77SSepherosa Ziehau 
94915516c77SSepherosa Ziehau 	/*
95015516c77SSepherosa Ziehau 	 * Figure out the # of RX rings (ring_cnt) and the # of TX rings
95115516c77SSepherosa Ziehau 	 * to use (tx_ring_cnt).
95215516c77SSepherosa Ziehau 	 *
95315516c77SSepherosa Ziehau 	 * NOTE:
95415516c77SSepherosa Ziehau 	 * The # of RX rings to use is same as the # of channels to use.
95515516c77SSepherosa Ziehau 	 */
95615516c77SSepherosa Ziehau 	ring_cnt = hn_chan_cnt;
95715516c77SSepherosa Ziehau 	if (ring_cnt <= 0) {
95815516c77SSepherosa Ziehau 		/* Default */
95915516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
96015516c77SSepherosa Ziehau 		if (ring_cnt > HN_RING_CNT_DEF_MAX)
96115516c77SSepherosa Ziehau 			ring_cnt = HN_RING_CNT_DEF_MAX;
96215516c77SSepherosa Ziehau 	} else if (ring_cnt > mp_ncpus) {
96315516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
96415516c77SSepherosa Ziehau 	}
96515516c77SSepherosa Ziehau 
96615516c77SSepherosa Ziehau 	tx_ring_cnt = hn_tx_ring_cnt;
96715516c77SSepherosa Ziehau 	if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt)
96815516c77SSepherosa Ziehau 		tx_ring_cnt = ring_cnt;
96923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
97015516c77SSepherosa Ziehau 	if (hn_use_if_start) {
97115516c77SSepherosa Ziehau 		/* ifnet.if_start only needs one TX ring. */
97215516c77SSepherosa Ziehau 		tx_ring_cnt = 1;
97315516c77SSepherosa Ziehau 	}
97423bf9e15SSepherosa Ziehau #endif
97515516c77SSepherosa Ziehau 
97615516c77SSepherosa Ziehau 	/*
97715516c77SSepherosa Ziehau 	 * Set the leader CPU for channels.
97815516c77SSepherosa Ziehau 	 */
97915516c77SSepherosa Ziehau 	sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus;
98015516c77SSepherosa Ziehau 
98115516c77SSepherosa Ziehau 	/*
98215516c77SSepherosa Ziehau 	 * Create enough TX/RX rings, even if only limited number of
98315516c77SSepherosa Ziehau 	 * channels can be allocated.
98415516c77SSepherosa Ziehau 	 */
98515516c77SSepherosa Ziehau 	error = hn_create_tx_data(sc, tx_ring_cnt);
98615516c77SSepherosa Ziehau 	if (error)
98715516c77SSepherosa Ziehau 		goto failed;
98815516c77SSepherosa Ziehau 	error = hn_create_rx_data(sc, ring_cnt);
98915516c77SSepherosa Ziehau 	if (error)
99015516c77SSepherosa Ziehau 		goto failed;
99115516c77SSepherosa Ziehau 
99215516c77SSepherosa Ziehau 	/*
99315516c77SSepherosa Ziehau 	 * Create transaction context for NVS and RNDIS transactions.
99415516c77SSepherosa Ziehau 	 */
99515516c77SSepherosa Ziehau 	sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
99615516c77SSepherosa Ziehau 	    HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
99725641fc7SSepherosa Ziehau 	if (sc->hn_xact == NULL) {
99825641fc7SSepherosa Ziehau 		error = ENXIO;
99915516c77SSepherosa Ziehau 		goto failed;
100025641fc7SSepherosa Ziehau 	}
100125641fc7SSepherosa Ziehau 
100225641fc7SSepherosa Ziehau 	/*
100325641fc7SSepherosa Ziehau 	 * Install orphan handler for the revocation of this device's
100425641fc7SSepherosa Ziehau 	 * primary channel.
100525641fc7SSepherosa Ziehau 	 *
100625641fc7SSepherosa Ziehau 	 * NOTE:
100725641fc7SSepherosa Ziehau 	 * The processing order is critical here:
100825641fc7SSepherosa Ziehau 	 * Install the orphan handler, _before_ testing whether this
100925641fc7SSepherosa Ziehau 	 * device's primary channel has been revoked or not.
101025641fc7SSepherosa Ziehau 	 */
101125641fc7SSepherosa Ziehau 	vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact);
101225641fc7SSepherosa Ziehau 	if (vmbus_chan_is_revoked(sc->hn_prichan)) {
101325641fc7SSepherosa Ziehau 		error = ENXIO;
101425641fc7SSepherosa Ziehau 		goto failed;
101525641fc7SSepherosa Ziehau 	}
101615516c77SSepherosa Ziehau 
101715516c77SSepherosa Ziehau 	/*
101815516c77SSepherosa Ziehau 	 * Attach the synthetic parts, i.e. NVS and RNDIS.
101915516c77SSepherosa Ziehau 	 */
102015516c77SSepherosa Ziehau 	error = hn_synth_attach(sc, ETHERMTU);
102115516c77SSepherosa Ziehau 	if (error)
102215516c77SSepherosa Ziehau 		goto failed;
102315516c77SSepherosa Ziehau 
102415516c77SSepherosa Ziehau 	error = hn_rndis_get_eaddr(sc, eaddr);
102515516c77SSepherosa Ziehau 	if (error)
102615516c77SSepherosa Ziehau 		goto failed;
102715516c77SSepherosa Ziehau 
102815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
102915516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
103015516c77SSepherosa Ziehau 		/*
103115516c77SSepherosa Ziehau 		 * Reduce TCP segment aggregation limit for multiple
103215516c77SSepherosa Ziehau 		 * RX rings to increase ACK timeliness.
103315516c77SSepherosa Ziehau 		 */
103415516c77SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF);
103515516c77SSepherosa Ziehau 	}
103615516c77SSepherosa Ziehau #endif
103715516c77SSepherosa Ziehau 
103815516c77SSepherosa Ziehau 	/*
103915516c77SSepherosa Ziehau 	 * Fixup TX stuffs after synthetic parts are attached.
104015516c77SSepherosa Ziehau 	 */
104115516c77SSepherosa Ziehau 	hn_fixup_tx_data(sc);
104215516c77SSepherosa Ziehau 
104315516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
104415516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
104515516c77SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD,
104615516c77SSepherosa Ziehau 	    &sc->hn_nvs_ver, 0, "NVS version");
104715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version",
104815516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
104915516c77SSepherosa Ziehau 	    hn_ndis_version_sysctl, "A", "NDIS version");
105015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps",
105115516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
105215516c77SSepherosa Ziehau 	    hn_caps_sysctl, "A", "capabilities");
105315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist",
105415516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
105515516c77SSepherosa Ziehau 	    hn_hwassist_sysctl, "A", "hwassist");
105615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter",
105715516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
105815516c77SSepherosa Ziehau 	    hn_rxfilter_sysctl, "A", "rxfilter");
105915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash",
106015516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
106115516c77SSepherosa Ziehau 	    hn_rss_hash_sysctl, "A", "RSS hash");
106215516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size",
106315516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count");
106415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key",
106515516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
106615516c77SSepherosa Ziehau 	    hn_rss_key_sysctl, "IU", "RSS key");
106715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind",
106815516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
106915516c77SSepherosa Ziehau 	    hn_rss_ind_sysctl, "IU", "RSS indirect table");
1070dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size",
1071dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_size, 0,
1072dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation size limit");
1073dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts",
1074dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0,
1075dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation count limit");
1076dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align",
1077dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_align, 0,
1078dc13fee6SSepherosa Ziehau 	    "RNDIS packet transmission aggregation alignment");
1079dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size",
1080dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
1081dc13fee6SSepherosa Ziehau 	    hn_txagg_size_sysctl, "I",
1082dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation size, 0 -- disable, -1 -- auto");
1083dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts",
1084dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
1085dc13fee6SSepherosa Ziehau 	    hn_txagg_pkts_sysctl, "I",
1086dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation packets, "
1087dc13fee6SSepherosa Ziehau 	    "0 -- disable, -1 -- auto");
108815516c77SSepherosa Ziehau 
108915516c77SSepherosa Ziehau 	/*
109015516c77SSepherosa Ziehau 	 * Setup the ifmedia, which has been initialized earlier.
109115516c77SSepherosa Ziehau 	 */
109215516c77SSepherosa Ziehau 	ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL);
109315516c77SSepherosa Ziehau 	ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO);
109415516c77SSepherosa Ziehau 	/* XXX ifmedia_set really should do this for us */
109515516c77SSepherosa Ziehau 	sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media;
109615516c77SSepherosa Ziehau 
109715516c77SSepherosa Ziehau 	/*
109815516c77SSepherosa Ziehau 	 * Setup the ifnet for this interface.
109915516c77SSepherosa Ziehau 	 */
110015516c77SSepherosa Ziehau 
110115516c77SSepherosa Ziehau 	ifp->if_baudrate = IF_Gbps(10);
110215516c77SSepherosa Ziehau 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
110315516c77SSepherosa Ziehau 	ifp->if_ioctl = hn_ioctl;
110415516c77SSepherosa Ziehau 	ifp->if_init = hn_init;
110523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
110615516c77SSepherosa Ziehau 	if (hn_use_if_start) {
110715516c77SSepherosa Ziehau 		int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]);
110815516c77SSepherosa Ziehau 
110915516c77SSepherosa Ziehau 		ifp->if_start = hn_start;
111015516c77SSepherosa Ziehau 		IFQ_SET_MAXLEN(&ifp->if_snd, qdepth);
111115516c77SSepherosa Ziehau 		ifp->if_snd.ifq_drv_maxlen = qdepth - 1;
111215516c77SSepherosa Ziehau 		IFQ_SET_READY(&ifp->if_snd);
111323bf9e15SSepherosa Ziehau 	} else
111423bf9e15SSepherosa Ziehau #endif
111523bf9e15SSepherosa Ziehau 	{
111615516c77SSepherosa Ziehau 		ifp->if_transmit = hn_transmit;
111715516c77SSepherosa Ziehau 		ifp->if_qflush = hn_xmit_qflush;
111815516c77SSepherosa Ziehau 	}
111915516c77SSepherosa Ziehau 
112015516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO;
112115516c77SSepherosa Ziehau #ifdef foo
112215516c77SSepherosa Ziehau 	/* We can't diff IPv6 packets from IPv4 packets on RX path. */
112315516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM_IPV6;
112415516c77SSepherosa Ziehau #endif
112515516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_VLAN) {
112615516c77SSepherosa Ziehau 		/* XXX not sure about VLAN_MTU. */
112715516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
112815516c77SSepherosa Ziehau 	}
112915516c77SSepherosa Ziehau 
113015516c77SSepherosa Ziehau 	ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist;
113115516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP_MASK)
113215516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM;
113315516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP6_MASK)
113415516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM_IPV6;
113515516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO4) {
113615516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO4;
113715516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP_TSO;
113815516c77SSepherosa Ziehau 	}
113915516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO6) {
114015516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO6;
114115516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP6_TSO;
114215516c77SSepherosa Ziehau 	}
114315516c77SSepherosa Ziehau 
114415516c77SSepherosa Ziehau 	/* Enable all available capabilities by default. */
114515516c77SSepherosa Ziehau 	ifp->if_capenable = ifp->if_capabilities;
114615516c77SSepherosa Ziehau 
11477960e6baSSepherosa Ziehau 	/*
11487960e6baSSepherosa Ziehau 	 * Disable IPv6 TSO and TXCSUM by default, they still can
11497960e6baSSepherosa Ziehau 	 * be enabled through SIOCSIFCAP.
11507960e6baSSepherosa Ziehau 	 */
11517960e6baSSepherosa Ziehau 	ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
11527960e6baSSepherosa Ziehau 	ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO);
11537960e6baSSepherosa Ziehau 
115415516c77SSepherosa Ziehau 	if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) {
115515516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU);
115615516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX;
115715516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = PAGE_SIZE;
115815516c77SSepherosa Ziehau 	}
115915516c77SSepherosa Ziehau 
116015516c77SSepherosa Ziehau 	ether_ifattach(ifp, eaddr);
116115516c77SSepherosa Ziehau 
116215516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) {
116315516c77SSepherosa Ziehau 		if_printf(ifp, "TSO segcnt %u segsz %u\n",
116415516c77SSepherosa Ziehau 		    ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize);
116515516c77SSepherosa Ziehau 	}
116615516c77SSepherosa Ziehau 
116715516c77SSepherosa Ziehau 	/* Inform the upper layer about the long frame support. */
116815516c77SSepherosa Ziehau 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
116915516c77SSepherosa Ziehau 
117015516c77SSepherosa Ziehau 	/*
117115516c77SSepherosa Ziehau 	 * Kick off link status check.
117215516c77SSepherosa Ziehau 	 */
117315516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
117415516c77SSepherosa Ziehau 	hn_update_link_status(sc);
117515516c77SSepherosa Ziehau 
117615516c77SSepherosa Ziehau 	return (0);
117715516c77SSepherosa Ziehau failed:
117815516c77SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)
117915516c77SSepherosa Ziehau 		hn_synth_detach(sc);
118015516c77SSepherosa Ziehau 	hn_detach(dev);
118115516c77SSepherosa Ziehau 	return (error);
118215516c77SSepherosa Ziehau }
118315516c77SSepherosa Ziehau 
118415516c77SSepherosa Ziehau static int
118515516c77SSepherosa Ziehau hn_detach(device_t dev)
118615516c77SSepherosa Ziehau {
118715516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
118815516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
118915516c77SSepherosa Ziehau 
119025641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) {
119125641fc7SSepherosa Ziehau 		/*
119225641fc7SSepherosa Ziehau 		 * In case that the vmbus missed the orphan handler
119325641fc7SSepherosa Ziehau 		 * installation.
119425641fc7SSepherosa Ziehau 		 */
119525641fc7SSepherosa Ziehau 		vmbus_xact_ctx_orphan(sc->hn_xact);
119625641fc7SSepherosa Ziehau 	}
119725641fc7SSepherosa Ziehau 
119815516c77SSepherosa Ziehau 	if (device_is_attached(dev)) {
119915516c77SSepherosa Ziehau 		HN_LOCK(sc);
120015516c77SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
120115516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
120215516c77SSepherosa Ziehau 				hn_stop(sc);
120315516c77SSepherosa Ziehau 			/*
120415516c77SSepherosa Ziehau 			 * NOTE:
120515516c77SSepherosa Ziehau 			 * hn_stop() only suspends data, so managment
120615516c77SSepherosa Ziehau 			 * stuffs have to be suspended manually here.
120715516c77SSepherosa Ziehau 			 */
120815516c77SSepherosa Ziehau 			hn_suspend_mgmt(sc);
120915516c77SSepherosa Ziehau 			hn_synth_detach(sc);
121015516c77SSepherosa Ziehau 		}
121115516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
121215516c77SSepherosa Ziehau 		ether_ifdetach(ifp);
121315516c77SSepherosa Ziehau 	}
121415516c77SSepherosa Ziehau 
121515516c77SSepherosa Ziehau 	ifmedia_removeall(&sc->hn_media);
121615516c77SSepherosa Ziehau 	hn_destroy_rx_data(sc);
121715516c77SSepherosa Ziehau 	hn_destroy_tx_data(sc);
121815516c77SSepherosa Ziehau 
1219*fdd0222aSSepherosa Ziehau 	if (sc->hn_tx_taskqs != hn_tx_taskque) {
1220*fdd0222aSSepherosa Ziehau 		int i;
1221*fdd0222aSSepherosa Ziehau 
1222*fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
1223*fdd0222aSSepherosa Ziehau 			taskqueue_free(sc->hn_tx_taskqs[i]);
1224*fdd0222aSSepherosa Ziehau 		free(sc->hn_tx_taskqs, M_DEVBUF);
1225*fdd0222aSSepherosa Ziehau 	}
122615516c77SSepherosa Ziehau 	taskqueue_free(sc->hn_mgmt_taskq0);
122715516c77SSepherosa Ziehau 
122825641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL) {
122925641fc7SSepherosa Ziehau 		/*
123025641fc7SSepherosa Ziehau 		 * Uninstall the orphan handler _before_ the xact is
123125641fc7SSepherosa Ziehau 		 * destructed.
123225641fc7SSepherosa Ziehau 		 */
123325641fc7SSepherosa Ziehau 		vmbus_chan_unset_orphan(sc->hn_prichan);
123415516c77SSepherosa Ziehau 		vmbus_xact_ctx_destroy(sc->hn_xact);
123525641fc7SSepherosa Ziehau 	}
123615516c77SSepherosa Ziehau 
123715516c77SSepherosa Ziehau 	if_free(ifp);
123815516c77SSepherosa Ziehau 
123915516c77SSepherosa Ziehau 	HN_LOCK_DESTROY(sc);
124015516c77SSepherosa Ziehau 	return (0);
124115516c77SSepherosa Ziehau }
124215516c77SSepherosa Ziehau 
124315516c77SSepherosa Ziehau static int
124415516c77SSepherosa Ziehau hn_shutdown(device_t dev)
124515516c77SSepherosa Ziehau {
124615516c77SSepherosa Ziehau 
124715516c77SSepherosa Ziehau 	return (0);
124815516c77SSepherosa Ziehau }
124915516c77SSepherosa Ziehau 
125015516c77SSepherosa Ziehau static void
125115516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc)
125215516c77SSepherosa Ziehau {
125315516c77SSepherosa Ziehau 	uint32_t link_status;
125415516c77SSepherosa Ziehau 	int error;
125515516c77SSepherosa Ziehau 
125615516c77SSepherosa Ziehau 	error = hn_rndis_get_linkstatus(sc, &link_status);
125715516c77SSepherosa Ziehau 	if (error) {
125815516c77SSepherosa Ziehau 		/* XXX what to do? */
125915516c77SSepherosa Ziehau 		return;
126015516c77SSepherosa Ziehau 	}
126115516c77SSepherosa Ziehau 
126215516c77SSepherosa Ziehau 	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
126315516c77SSepherosa Ziehau 		sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
126415516c77SSepherosa Ziehau 	else
126515516c77SSepherosa Ziehau 		sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
126615516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp,
126715516c77SSepherosa Ziehau 	    (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ?
126815516c77SSepherosa Ziehau 	    LINK_STATE_UP : LINK_STATE_DOWN);
126915516c77SSepherosa Ziehau }
127015516c77SSepherosa Ziehau 
127115516c77SSepherosa Ziehau static void
127215516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused)
127315516c77SSepherosa Ziehau {
127415516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
127515516c77SSepherosa Ziehau 
127615516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
127715516c77SSepherosa Ziehau 		return;
127815516c77SSepherosa Ziehau 	hn_link_status(sc);
127915516c77SSepherosa Ziehau }
128015516c77SSepherosa Ziehau 
128115516c77SSepherosa Ziehau static void
128215516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused)
128315516c77SSepherosa Ziehau {
128415516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
128515516c77SSepherosa Ziehau 
128615516c77SSepherosa Ziehau 	/* Prevent any link status checks from running. */
128715516c77SSepherosa Ziehau 	sc->hn_link_flags |= HN_LINK_FLAG_NETCHG;
128815516c77SSepherosa Ziehau 
128915516c77SSepherosa Ziehau 	/*
129015516c77SSepherosa Ziehau 	 * Fake up a [link down --> link up] state change; 5 seconds
129115516c77SSepherosa Ziehau 	 * delay is used, which closely simulates miibus reaction
129215516c77SSepherosa Ziehau 	 * upon link down event.
129315516c77SSepherosa Ziehau 	 */
129415516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
129515516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
129615516c77SSepherosa Ziehau 	taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0,
129715516c77SSepherosa Ziehau 	    &sc->hn_netchg_status, 5 * hz);
129815516c77SSepherosa Ziehau }
129915516c77SSepherosa Ziehau 
130015516c77SSepherosa Ziehau static void
130115516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused)
130215516c77SSepherosa Ziehau {
130315516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
130415516c77SSepherosa Ziehau 
130515516c77SSepherosa Ziehau 	/* Re-allow link status checks. */
130615516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG;
130715516c77SSepherosa Ziehau 	hn_link_status(sc);
130815516c77SSepherosa Ziehau }
130915516c77SSepherosa Ziehau 
131015516c77SSepherosa Ziehau static void
131115516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc)
131215516c77SSepherosa Ziehau {
131315516c77SSepherosa Ziehau 
131415516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
131515516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
131615516c77SSepherosa Ziehau }
131715516c77SSepherosa Ziehau 
131815516c77SSepherosa Ziehau static void
131915516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc)
132015516c77SSepherosa Ziehau {
132115516c77SSepherosa Ziehau 
132215516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
132315516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init);
132415516c77SSepherosa Ziehau }
132515516c77SSepherosa Ziehau 
132615516c77SSepherosa Ziehau static __inline int
132715516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
132815516c77SSepherosa Ziehau     struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
132915516c77SSepherosa Ziehau {
133015516c77SSepherosa Ziehau 	struct mbuf *m = *m_head;
133115516c77SSepherosa Ziehau 	int error;
133215516c77SSepherosa Ziehau 
133315516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim"));
133415516c77SSepherosa Ziehau 
133515516c77SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap,
133615516c77SSepherosa Ziehau 	    m, segs, nsegs, BUS_DMA_NOWAIT);
133715516c77SSepherosa Ziehau 	if (error == EFBIG) {
133815516c77SSepherosa Ziehau 		struct mbuf *m_new;
133915516c77SSepherosa Ziehau 
134015516c77SSepherosa Ziehau 		m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX);
134115516c77SSepherosa Ziehau 		if (m_new == NULL)
134215516c77SSepherosa Ziehau 			return ENOBUFS;
134315516c77SSepherosa Ziehau 		else
134415516c77SSepherosa Ziehau 			*m_head = m = m_new;
134515516c77SSepherosa Ziehau 		txr->hn_tx_collapsed++;
134615516c77SSepherosa Ziehau 
134715516c77SSepherosa Ziehau 		error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag,
134815516c77SSepherosa Ziehau 		    txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT);
134915516c77SSepherosa Ziehau 	}
135015516c77SSepherosa Ziehau 	if (!error) {
135115516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap,
135215516c77SSepherosa Ziehau 		    BUS_DMASYNC_PREWRITE);
135315516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_DMAMAP;
135415516c77SSepherosa Ziehau 	}
135515516c77SSepherosa Ziehau 	return error;
135615516c77SSepherosa Ziehau }
135715516c77SSepherosa Ziehau 
135815516c77SSepherosa Ziehau static __inline int
135915516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd)
136015516c77SSepherosa Ziehau {
136115516c77SSepherosa Ziehau 
136215516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0,
136315516c77SSepherosa Ziehau 	    ("put an onlist txd %#x", txd->flags));
1364dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1365dc13fee6SSepherosa Ziehau 	    ("put an onagg txd %#x", txd->flags));
136615516c77SSepherosa Ziehau 
136715516c77SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
136815516c77SSepherosa Ziehau 	if (atomic_fetchadd_int(&txd->refs, -1) != 1)
136915516c77SSepherosa Ziehau 		return 0;
137015516c77SSepherosa Ziehau 
1371dc13fee6SSepherosa Ziehau 	if (!STAILQ_EMPTY(&txd->agg_list)) {
1372dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tmp_txd;
1373dc13fee6SSepherosa Ziehau 
1374dc13fee6SSepherosa Ziehau 		while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) {
1375dc13fee6SSepherosa Ziehau 			int freed;
1376dc13fee6SSepherosa Ziehau 
1377dc13fee6SSepherosa Ziehau 			KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list),
1378dc13fee6SSepherosa Ziehau 			    ("resursive aggregation on aggregated txdesc"));
1379dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG),
1380dc13fee6SSepherosa Ziehau 			    ("not aggregated txdesc"));
1381dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
1382dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc uses dmamap"));
1383dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
1384dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc consumes "
1385dc13fee6SSepherosa Ziehau 			     "chimney sending buffer"));
1386dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_size == 0,
1387dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc has non-zero "
1388dc13fee6SSepherosa Ziehau 			     "chimney sending size"));
1389dc13fee6SSepherosa Ziehau 
1390dc13fee6SSepherosa Ziehau 			STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link);
1391dc13fee6SSepherosa Ziehau 			tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG;
1392dc13fee6SSepherosa Ziehau 			freed = hn_txdesc_put(txr, tmp_txd);
1393dc13fee6SSepherosa Ziehau 			KASSERT(freed, ("failed to free aggregated txdesc"));
1394dc13fee6SSepherosa Ziehau 		}
1395dc13fee6SSepherosa Ziehau 	}
1396dc13fee6SSepherosa Ziehau 
139715516c77SSepherosa Ziehau 	if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) {
139815516c77SSepherosa Ziehau 		KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
139915516c77SSepherosa Ziehau 		    ("chim txd uses dmamap"));
140015516c77SSepherosa Ziehau 		hn_chim_free(txr->hn_sc, txd->chim_index);
140115516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
1402dc13fee6SSepherosa Ziehau 		txd->chim_size = 0;
140315516c77SSepherosa Ziehau 	} else if (txd->flags & HN_TXD_FLAG_DMAMAP) {
140415516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag,
140515516c77SSepherosa Ziehau 		    txd->data_dmap, BUS_DMASYNC_POSTWRITE);
140615516c77SSepherosa Ziehau 		bus_dmamap_unload(txr->hn_tx_data_dtag,
140715516c77SSepherosa Ziehau 		    txd->data_dmap);
140815516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_DMAMAP;
140915516c77SSepherosa Ziehau 	}
141015516c77SSepherosa Ziehau 
141115516c77SSepherosa Ziehau 	if (txd->m != NULL) {
141215516c77SSepherosa Ziehau 		m_freem(txd->m);
141315516c77SSepherosa Ziehau 		txd->m = NULL;
141415516c77SSepherosa Ziehau 	}
141515516c77SSepherosa Ziehau 
141615516c77SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONLIST;
141715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
141815516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
141915516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_avail >= 0 &&
142015516c77SSepherosa Ziehau 	    txr->hn_txdesc_avail < txr->hn_txdesc_cnt,
142115516c77SSepherosa Ziehau 	    ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail));
142215516c77SSepherosa Ziehau 	txr->hn_txdesc_avail++;
142315516c77SSepherosa Ziehau 	SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
142415516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
142515516c77SSepherosa Ziehau #else
142615516c77SSepherosa Ziehau 	atomic_add_int(&txr->hn_txdesc_avail, 1);
142715516c77SSepherosa Ziehau 	buf_ring_enqueue(txr->hn_txdesc_br, txd);
142815516c77SSepherosa Ziehau #endif
142915516c77SSepherosa Ziehau 
143015516c77SSepherosa Ziehau 	return 1;
143115516c77SSepherosa Ziehau }
143215516c77SSepherosa Ziehau 
143315516c77SSepherosa Ziehau static __inline struct hn_txdesc *
143415516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr)
143515516c77SSepherosa Ziehau {
143615516c77SSepherosa Ziehau 	struct hn_txdesc *txd;
143715516c77SSepherosa Ziehau 
143815516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
143915516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
144015516c77SSepherosa Ziehau 	txd = SLIST_FIRST(&txr->hn_txlist);
144115516c77SSepherosa Ziehau 	if (txd != NULL) {
144215516c77SSepherosa Ziehau 		KASSERT(txr->hn_txdesc_avail > 0,
144315516c77SSepherosa Ziehau 		    ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail));
144415516c77SSepherosa Ziehau 		txr->hn_txdesc_avail--;
144515516c77SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&txr->hn_txlist, link);
144615516c77SSepherosa Ziehau 	}
144715516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
144815516c77SSepherosa Ziehau #else
144915516c77SSepherosa Ziehau 	txd = buf_ring_dequeue_sc(txr->hn_txdesc_br);
145015516c77SSepherosa Ziehau #endif
145115516c77SSepherosa Ziehau 
145215516c77SSepherosa Ziehau 	if (txd != NULL) {
145315516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
145415516c77SSepherosa Ziehau 		atomic_subtract_int(&txr->hn_txdesc_avail, 1);
145515516c77SSepherosa Ziehau #endif
145615516c77SSepherosa Ziehau 		KASSERT(txd->m == NULL && txd->refs == 0 &&
1457dc13fee6SSepherosa Ziehau 		    STAILQ_EMPTY(&txd->agg_list) &&
145815516c77SSepherosa Ziehau 		    txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
1459dc13fee6SSepherosa Ziehau 		    txd->chim_size == 0 &&
146015516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONLIST) &&
1461dc13fee6SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONAGG) == 0 &&
146215516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd"));
146315516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_ONLIST;
146415516c77SSepherosa Ziehau 		txd->refs = 1;
146515516c77SSepherosa Ziehau 	}
146615516c77SSepherosa Ziehau 	return txd;
146715516c77SSepherosa Ziehau }
146815516c77SSepherosa Ziehau 
146915516c77SSepherosa Ziehau static __inline void
147015516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd)
147115516c77SSepherosa Ziehau {
147215516c77SSepherosa Ziehau 
147315516c77SSepherosa Ziehau 	/* 0->1 transition will never work */
147425641fc7SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
147515516c77SSepherosa Ziehau 	atomic_add_int(&txd->refs, 1);
147615516c77SSepherosa Ziehau }
147715516c77SSepherosa Ziehau 
1478dc13fee6SSepherosa Ziehau static __inline void
1479dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd)
1480dc13fee6SSepherosa Ziehau {
1481dc13fee6SSepherosa Ziehau 
1482dc13fee6SSepherosa Ziehau 	KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1483dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on aggregating txdesc"));
1484dc13fee6SSepherosa Ziehau 
1485dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1486dc13fee6SSepherosa Ziehau 	    ("already aggregated"));
1487dc13fee6SSepherosa Ziehau 	KASSERT(STAILQ_EMPTY(&txd->agg_list),
1488dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on to-be-aggregated txdesc"));
1489dc13fee6SSepherosa Ziehau 
1490dc13fee6SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONAGG;
1491dc13fee6SSepherosa Ziehau 	STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link);
1492dc13fee6SSepherosa Ziehau }
1493dc13fee6SSepherosa Ziehau 
149415516c77SSepherosa Ziehau static bool
149515516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr)
149615516c77SSepherosa Ziehau {
149715516c77SSepherosa Ziehau 	bool pending = false;
149815516c77SSepherosa Ziehau 
149915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
150015516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
150115516c77SSepherosa Ziehau 	if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt)
150215516c77SSepherosa Ziehau 		pending = true;
150315516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
150415516c77SSepherosa Ziehau #else
150515516c77SSepherosa Ziehau 	if (!buf_ring_full(txr->hn_txdesc_br))
150615516c77SSepherosa Ziehau 		pending = true;
150715516c77SSepherosa Ziehau #endif
150815516c77SSepherosa Ziehau 	return (pending);
150915516c77SSepherosa Ziehau }
151015516c77SSepherosa Ziehau 
151115516c77SSepherosa Ziehau static __inline void
151215516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr)
151315516c77SSepherosa Ziehau {
151415516c77SSepherosa Ziehau 	txr->hn_has_txeof = 0;
151515516c77SSepherosa Ziehau 	txr->hn_txeof(txr);
151615516c77SSepherosa Ziehau }
151715516c77SSepherosa Ziehau 
151815516c77SSepherosa Ziehau static void
151915516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc,
152015516c77SSepherosa Ziehau     struct vmbus_channel *chan, const void *data __unused, int dlen __unused)
152115516c77SSepherosa Ziehau {
152215516c77SSepherosa Ziehau 	struct hn_txdesc *txd = sndc->hn_cbarg;
152315516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
152415516c77SSepherosa Ziehau 
152515516c77SSepherosa Ziehau 	txr = txd->txr;
152615516c77SSepherosa Ziehau 	KASSERT(txr->hn_chan == chan,
152715516c77SSepherosa Ziehau 	    ("channel mismatch, on chan%u, should be chan%u",
1528aa1a2adcSSepherosa Ziehau 	     vmbus_chan_id(chan), vmbus_chan_id(txr->hn_chan)));
152915516c77SSepherosa Ziehau 
153015516c77SSepherosa Ziehau 	txr->hn_has_txeof = 1;
153115516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
153215516c77SSepherosa Ziehau 
153315516c77SSepherosa Ziehau 	++txr->hn_txdone_cnt;
153415516c77SSepherosa Ziehau 	if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) {
153515516c77SSepherosa Ziehau 		txr->hn_txdone_cnt = 0;
153615516c77SSepherosa Ziehau 		if (txr->hn_oactive)
153715516c77SSepherosa Ziehau 			hn_txeof(txr);
153815516c77SSepherosa Ziehau 	}
153915516c77SSepherosa Ziehau }
154015516c77SSepherosa Ziehau 
154115516c77SSepherosa Ziehau static void
154215516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
154315516c77SSepherosa Ziehau {
154415516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
154515516c77SSepherosa Ziehau 	tcp_lro_flush_all(&rxr->hn_lro);
154615516c77SSepherosa Ziehau #endif
154715516c77SSepherosa Ziehau 
154815516c77SSepherosa Ziehau 	/*
154915516c77SSepherosa Ziehau 	 * NOTE:
155015516c77SSepherosa Ziehau 	 * 'txr' could be NULL, if multiple channels and
155115516c77SSepherosa Ziehau 	 * ifnet.if_start method are enabled.
155215516c77SSepherosa Ziehau 	 */
155315516c77SSepherosa Ziehau 	if (txr == NULL || !txr->hn_has_txeof)
155415516c77SSepherosa Ziehau 		return;
155515516c77SSepherosa Ziehau 
155615516c77SSepherosa Ziehau 	txr->hn_txdone_cnt = 0;
155715516c77SSepherosa Ziehau 	hn_txeof(txr);
155815516c77SSepherosa Ziehau }
155915516c77SSepherosa Ziehau 
156015516c77SSepherosa Ziehau static __inline uint32_t
156115516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs)
156215516c77SSepherosa Ziehau {
156315516c77SSepherosa Ziehau 
156415516c77SSepherosa Ziehau 	KASSERT(ofs >= sizeof(struct rndis_packet_msg),
156515516c77SSepherosa Ziehau 	    ("invalid RNDIS packet msg offset %u", ofs));
156615516c77SSepherosa Ziehau 	return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset));
156715516c77SSepherosa Ziehau }
156815516c77SSepherosa Ziehau 
156915516c77SSepherosa Ziehau static __inline void *
157015516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
157115516c77SSepherosa Ziehau     size_t pi_dlen, uint32_t pi_type)
157215516c77SSepherosa Ziehau {
157315516c77SSepherosa Ziehau 	const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
157415516c77SSepherosa Ziehau 	struct rndis_pktinfo *pi;
157515516c77SSepherosa Ziehau 
157615516c77SSepherosa Ziehau 	KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
157715516c77SSepherosa Ziehau 	    ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
157815516c77SSepherosa Ziehau 
157915516c77SSepherosa Ziehau 	/*
158015516c77SSepherosa Ziehau 	 * Per-packet-info does not move; it only grows.
158115516c77SSepherosa Ziehau 	 *
158215516c77SSepherosa Ziehau 	 * NOTE:
158315516c77SSepherosa Ziehau 	 * rm_pktinfooffset in this phase counts from the beginning
158415516c77SSepherosa Ziehau 	 * of rndis_packet_msg.
158515516c77SSepherosa Ziehau 	 */
158615516c77SSepherosa Ziehau 	KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
158715516c77SSepherosa Ziehau 	    ("%u pktinfo overflows RNDIS packet msg", pi_type));
158815516c77SSepherosa Ziehau 	pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
158915516c77SSepherosa Ziehau 	    pkt->rm_pktinfolen);
159015516c77SSepherosa Ziehau 	pkt->rm_pktinfolen += pi_size;
159115516c77SSepherosa Ziehau 
159215516c77SSepherosa Ziehau 	pi->rm_size = pi_size;
159315516c77SSepherosa Ziehau 	pi->rm_type = pi_type;
159415516c77SSepherosa Ziehau 	pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
159515516c77SSepherosa Ziehau 
159615516c77SSepherosa Ziehau 	/* Data immediately follow per-packet-info. */
159715516c77SSepherosa Ziehau 	pkt->rm_dataoffset += pi_size;
159815516c77SSepherosa Ziehau 
159915516c77SSepherosa Ziehau 	/* Update RNDIS packet msg length */
160015516c77SSepherosa Ziehau 	pkt->rm_len += pi_size;
160115516c77SSepherosa Ziehau 
160215516c77SSepherosa Ziehau 	return (pi->rm_data);
160315516c77SSepherosa Ziehau }
160415516c77SSepherosa Ziehau 
1605dc13fee6SSepherosa Ziehau static __inline int
1606dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr)
1607dc13fee6SSepherosa Ziehau {
1608dc13fee6SSepherosa Ziehau 	struct hn_txdesc *txd;
1609dc13fee6SSepherosa Ziehau 	struct mbuf *m;
1610dc13fee6SSepherosa Ziehau 	int error, pkts;
1611dc13fee6SSepherosa Ziehau 
1612dc13fee6SSepherosa Ziehau 	txd = txr->hn_agg_txd;
1613dc13fee6SSepherosa Ziehau 	KASSERT(txd != NULL, ("no aggregate txdesc"));
1614dc13fee6SSepherosa Ziehau 
1615dc13fee6SSepherosa Ziehau 	/*
1616dc13fee6SSepherosa Ziehau 	 * Since hn_txpkt() will reset this temporary stat, save
1617dc13fee6SSepherosa Ziehau 	 * it now, so that oerrors can be updated properly, if
1618dc13fee6SSepherosa Ziehau 	 * hn_txpkt() ever fails.
1619dc13fee6SSepherosa Ziehau 	 */
1620dc13fee6SSepherosa Ziehau 	pkts = txr->hn_stat_pkts;
1621dc13fee6SSepherosa Ziehau 
1622dc13fee6SSepherosa Ziehau 	/*
1623dc13fee6SSepherosa Ziehau 	 * Since txd's mbuf will _not_ be freed upon hn_txpkt()
1624dc13fee6SSepherosa Ziehau 	 * failure, save it for later freeing, if hn_txpkt() ever
1625dc13fee6SSepherosa Ziehau 	 * fails.
1626dc13fee6SSepherosa Ziehau 	 */
1627dc13fee6SSepherosa Ziehau 	m = txd->m;
1628dc13fee6SSepherosa Ziehau 	error = hn_txpkt(ifp, txr, txd);
1629dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
1630dc13fee6SSepherosa Ziehau 		/* txd is freed, but m is not. */
1631dc13fee6SSepherosa Ziehau 		m_freem(m);
1632dc13fee6SSepherosa Ziehau 
1633dc13fee6SSepherosa Ziehau 		txr->hn_flush_failed++;
1634dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts);
1635dc13fee6SSepherosa Ziehau 	}
1636dc13fee6SSepherosa Ziehau 
1637dc13fee6SSepherosa Ziehau 	/* Reset all aggregation states. */
1638dc13fee6SSepherosa Ziehau 	txr->hn_agg_txd = NULL;
1639dc13fee6SSepherosa Ziehau 	txr->hn_agg_szleft = 0;
1640dc13fee6SSepherosa Ziehau 	txr->hn_agg_pktleft = 0;
1641dc13fee6SSepherosa Ziehau 	txr->hn_agg_prevpkt = NULL;
1642dc13fee6SSepherosa Ziehau 
1643dc13fee6SSepherosa Ziehau 	return (error);
1644dc13fee6SSepherosa Ziehau }
1645dc13fee6SSepherosa Ziehau 
1646dc13fee6SSepherosa Ziehau static void *
1647dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
1648dc13fee6SSepherosa Ziehau     int pktsize)
1649dc13fee6SSepherosa Ziehau {
1650dc13fee6SSepherosa Ziehau 	void *chim;
1651dc13fee6SSepherosa Ziehau 
1652dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL) {
1653dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) {
1654dc13fee6SSepherosa Ziehau 			struct hn_txdesc *agg_txd = txr->hn_agg_txd;
1655dc13fee6SSepherosa Ziehau 			struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt;
1656dc13fee6SSepherosa Ziehau 			int olen;
1657dc13fee6SSepherosa Ziehau 
1658dc13fee6SSepherosa Ziehau 			/*
1659dc13fee6SSepherosa Ziehau 			 * Update the previous RNDIS packet's total length,
1660dc13fee6SSepherosa Ziehau 			 * it can be increased due to the mandatory alignment
1661dc13fee6SSepherosa Ziehau 			 * padding for this RNDIS packet.  And update the
1662dc13fee6SSepherosa Ziehau 			 * aggregating txdesc's chimney sending buffer size
1663dc13fee6SSepherosa Ziehau 			 * accordingly.
1664dc13fee6SSepherosa Ziehau 			 *
1665dc13fee6SSepherosa Ziehau 			 * XXX
1666dc13fee6SSepherosa Ziehau 			 * Zero-out the padding, as required by the RNDIS spec.
1667dc13fee6SSepherosa Ziehau 			 */
1668dc13fee6SSepherosa Ziehau 			olen = pkt->rm_len;
1669dc13fee6SSepherosa Ziehau 			pkt->rm_len = roundup2(olen, txr->hn_agg_align);
1670dc13fee6SSepherosa Ziehau 			agg_txd->chim_size += pkt->rm_len - olen;
1671dc13fee6SSepherosa Ziehau 
1672dc13fee6SSepherosa Ziehau 			/* Link this txdesc to the parent. */
1673dc13fee6SSepherosa Ziehau 			hn_txdesc_agg(agg_txd, txd);
1674dc13fee6SSepherosa Ziehau 
1675dc13fee6SSepherosa Ziehau 			chim = (uint8_t *)pkt + pkt->rm_len;
1676dc13fee6SSepherosa Ziehau 			/* Save the current packet for later fixup. */
1677dc13fee6SSepherosa Ziehau 			txr->hn_agg_prevpkt = chim;
1678dc13fee6SSepherosa Ziehau 
1679dc13fee6SSepherosa Ziehau 			txr->hn_agg_pktleft--;
1680dc13fee6SSepherosa Ziehau 			txr->hn_agg_szleft -= pktsize;
1681dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_szleft <=
1682dc13fee6SSepherosa Ziehau 			    HN_PKTSIZE_MIN(txr->hn_agg_align)) {
1683dc13fee6SSepherosa Ziehau 				/*
1684dc13fee6SSepherosa Ziehau 				 * Probably can't aggregate more packets,
1685dc13fee6SSepherosa Ziehau 				 * flush this aggregating txdesc proactively.
1686dc13fee6SSepherosa Ziehau 				 */
1687dc13fee6SSepherosa Ziehau 				txr->hn_agg_pktleft = 0;
1688dc13fee6SSepherosa Ziehau 			}
1689dc13fee6SSepherosa Ziehau 			/* Done! */
1690dc13fee6SSepherosa Ziehau 			return (chim);
1691dc13fee6SSepherosa Ziehau 		}
1692dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
1693dc13fee6SSepherosa Ziehau 	}
1694dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
1695dc13fee6SSepherosa Ziehau 
1696dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney_tried++;
1697dc13fee6SSepherosa Ziehau 	txd->chim_index = hn_chim_alloc(txr->hn_sc);
1698dc13fee6SSepherosa Ziehau 	if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID)
1699dc13fee6SSepherosa Ziehau 		return (NULL);
1700dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney++;
1701dc13fee6SSepherosa Ziehau 
1702dc13fee6SSepherosa Ziehau 	chim = txr->hn_sc->hn_chim +
1703dc13fee6SSepherosa Ziehau 	    (txd->chim_index * txr->hn_sc->hn_chim_szmax);
1704dc13fee6SSepherosa Ziehau 
1705dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_pktmax > 1 &&
1706dc13fee6SSepherosa Ziehau 	    txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) {
1707dc13fee6SSepherosa Ziehau 		txr->hn_agg_txd = txd;
1708dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1;
1709dc13fee6SSepherosa Ziehau 		txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize;
1710dc13fee6SSepherosa Ziehau 		txr->hn_agg_prevpkt = chim;
1711dc13fee6SSepherosa Ziehau 	}
1712dc13fee6SSepherosa Ziehau 	return (chim);
1713dc13fee6SSepherosa Ziehau }
1714dc13fee6SSepherosa Ziehau 
171515516c77SSepherosa Ziehau /*
171615516c77SSepherosa Ziehau  * NOTE:
171715516c77SSepherosa Ziehau  * If this function fails, then both txd and m_head0 will be freed.
171815516c77SSepherosa Ziehau  */
171915516c77SSepherosa Ziehau static int
1720dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
1721dc13fee6SSepherosa Ziehau     struct mbuf **m_head0)
172215516c77SSepherosa Ziehau {
172315516c77SSepherosa Ziehau 	bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX];
172415516c77SSepherosa Ziehau 	int error, nsegs, i;
172515516c77SSepherosa Ziehau 	struct mbuf *m_head = *m_head0;
172615516c77SSepherosa Ziehau 	struct rndis_packet_msg *pkt;
172715516c77SSepherosa Ziehau 	uint32_t *pi_data;
17288966e5d5SSepherosa Ziehau 	void *chim = NULL;
1729dc13fee6SSepherosa Ziehau 	int pkt_hlen, pkt_size;
173015516c77SSepherosa Ziehau 
173115516c77SSepherosa Ziehau 	pkt = txd->rndis_pkt;
1732dc13fee6SSepherosa Ziehau 	pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align);
1733dc13fee6SSepherosa Ziehau 	if (pkt_size < txr->hn_chim_size) {
1734dc13fee6SSepherosa Ziehau 		chim = hn_try_txagg(ifp, txr, txd, pkt_size);
1735dc13fee6SSepherosa Ziehau 		if (chim != NULL)
17368966e5d5SSepherosa Ziehau 			pkt = chim;
1737dc13fee6SSepherosa Ziehau 	} else {
1738dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL)
1739dc13fee6SSepherosa Ziehau 			hn_flush_txagg(ifp, txr);
17408966e5d5SSepherosa Ziehau 	}
17418966e5d5SSepherosa Ziehau 
174215516c77SSepherosa Ziehau 	pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
174315516c77SSepherosa Ziehau 	pkt->rm_len = sizeof(*pkt) + m_head->m_pkthdr.len;
174415516c77SSepherosa Ziehau 	pkt->rm_dataoffset = sizeof(*pkt);
174515516c77SSepherosa Ziehau 	pkt->rm_datalen = m_head->m_pkthdr.len;
1746dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataoffset = 0;
1747dc13fee6SSepherosa Ziehau 	pkt->rm_oobdatalen = 0;
1748dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataelements = 0;
174915516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = sizeof(*pkt);
175015516c77SSepherosa Ziehau 	pkt->rm_pktinfolen = 0;
1751dc13fee6SSepherosa Ziehau 	pkt->rm_vchandle = 0;
1752dc13fee6SSepherosa Ziehau 	pkt->rm_reserved = 0;
175315516c77SSepherosa Ziehau 
175415516c77SSepherosa Ziehau 	if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) {
175515516c77SSepherosa Ziehau 		/*
175615516c77SSepherosa Ziehau 		 * Set the hash value for this packet, so that the host could
175715516c77SSepherosa Ziehau 		 * dispatch the TX done event for this packet back to this TX
175815516c77SSepherosa Ziehau 		 * ring's channel.
175915516c77SSepherosa Ziehau 		 */
176015516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
176115516c77SSepherosa Ziehau 		    HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL);
176215516c77SSepherosa Ziehau 		*pi_data = txr->hn_tx_idx;
176315516c77SSepherosa Ziehau 	}
176415516c77SSepherosa Ziehau 
176515516c77SSepherosa Ziehau 	if (m_head->m_flags & M_VLANTAG) {
176615516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
176715516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
176815516c77SSepherosa Ziehau 		*pi_data = NDIS_VLAN_INFO_MAKE(
176915516c77SSepherosa Ziehau 		    EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag),
177015516c77SSepherosa Ziehau 		    EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag),
177115516c77SSepherosa Ziehau 		    EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag));
177215516c77SSepherosa Ziehau 	}
177315516c77SSepherosa Ziehau 
177415516c77SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
177515516c77SSepherosa Ziehau #if defined(INET6) || defined(INET)
177615516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
177715516c77SSepherosa Ziehau 		    NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO);
177815516c77SSepherosa Ziehau #ifdef INET
177915516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
178015516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV4(0,
178115516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
178215516c77SSepherosa Ziehau 		}
178315516c77SSepherosa Ziehau #endif
178415516c77SSepherosa Ziehau #if defined(INET6) && defined(INET)
178515516c77SSepherosa Ziehau 		else
178615516c77SSepherosa Ziehau #endif
178715516c77SSepherosa Ziehau #ifdef INET6
178815516c77SSepherosa Ziehau 		{
178915516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV6(0,
179015516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
179115516c77SSepherosa Ziehau 		}
179215516c77SSepherosa Ziehau #endif
179315516c77SSepherosa Ziehau #endif	/* INET6 || INET */
179415516c77SSepherosa Ziehau 	} else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) {
179515516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
179615516c77SSepherosa Ziehau 		    NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
179715516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
179815516c77SSepherosa Ziehau 		    (CSUM_IP6_TCP | CSUM_IP6_UDP)) {
179915516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV6;
180015516c77SSepherosa Ziehau 		} else {
180115516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV4;
180215516c77SSepherosa Ziehau 			if (m_head->m_pkthdr.csum_flags & CSUM_IP)
180315516c77SSepherosa Ziehau 				*pi_data |= NDIS_TXCSUM_INFO_IPCS;
180415516c77SSepherosa Ziehau 		}
180515516c77SSepherosa Ziehau 
180615516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP))
180715516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_TCPCS;
180815516c77SSepherosa Ziehau 		else if (m_head->m_pkthdr.csum_flags &
180915516c77SSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP6_UDP))
181015516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_UDPCS;
181115516c77SSepherosa Ziehau 	}
181215516c77SSepherosa Ziehau 
1813dc13fee6SSepherosa Ziehau 	pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
181415516c77SSepherosa Ziehau 	/* Convert RNDIS packet message offsets */
181515516c77SSepherosa Ziehau 	pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt->rm_dataoffset);
181615516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset);
181715516c77SSepherosa Ziehau 
181815516c77SSepherosa Ziehau 	/*
18198966e5d5SSepherosa Ziehau 	 * Fast path: Chimney sending.
182015516c77SSepherosa Ziehau 	 */
18218966e5d5SSepherosa Ziehau 	if (chim != NULL) {
1822dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tgt_txd = txd;
1823dc13fee6SSepherosa Ziehau 
1824dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL) {
1825dc13fee6SSepherosa Ziehau 			tgt_txd = txr->hn_agg_txd;
1826dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
1827dc13fee6SSepherosa Ziehau 			*m_head0 = NULL;
1828dc13fee6SSepherosa Ziehau #endif
1829dc13fee6SSepherosa Ziehau 		}
1830dc13fee6SSepherosa Ziehau 
1831dc13fee6SSepherosa Ziehau 		KASSERT(pkt == chim,
1832dc13fee6SSepherosa Ziehau 		    ("RNDIS pkt not in chimney sending buffer"));
1833dc13fee6SSepherosa Ziehau 		KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID,
1834dc13fee6SSepherosa Ziehau 		    ("chimney sending buffer is not used"));
1835dc13fee6SSepherosa Ziehau 		tgt_txd->chim_size += pkt->rm_len;
183615516c77SSepherosa Ziehau 
18378966e5d5SSepherosa Ziehau 		m_copydata(m_head, 0, m_head->m_pkthdr.len,
1838dc13fee6SSepherosa Ziehau 		    ((uint8_t *)chim) + pkt_hlen);
183915516c77SSepherosa Ziehau 
184015516c77SSepherosa Ziehau 		txr->hn_gpa_cnt = 0;
184115516c77SSepherosa Ziehau 		txr->hn_sendpkt = hn_txpkt_chim;
184215516c77SSepherosa Ziehau 		goto done;
184315516c77SSepherosa Ziehau 	}
1844dc13fee6SSepherosa Ziehau 
1845dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc"));
18468966e5d5SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
18478966e5d5SSepherosa Ziehau 	    ("chimney buffer is used"));
18488966e5d5SSepherosa Ziehau 	KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc"));
184915516c77SSepherosa Ziehau 
185015516c77SSepherosa Ziehau 	error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs);
1851dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
185215516c77SSepherosa Ziehau 		int freed;
185315516c77SSepherosa Ziehau 
185415516c77SSepherosa Ziehau 		/*
185515516c77SSepherosa Ziehau 		 * This mbuf is not linked w/ the txd yet, so free it now.
185615516c77SSepherosa Ziehau 		 */
185715516c77SSepherosa Ziehau 		m_freem(m_head);
185815516c77SSepherosa Ziehau 		*m_head0 = NULL;
185915516c77SSepherosa Ziehau 
186015516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
186115516c77SSepherosa Ziehau 		KASSERT(freed != 0,
186215516c77SSepherosa Ziehau 		    ("fail to free txd upon txdma error"));
186315516c77SSepherosa Ziehau 
186415516c77SSepherosa Ziehau 		txr->hn_txdma_failed++;
1865dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
186615516c77SSepherosa Ziehau 		return error;
186715516c77SSepherosa Ziehau 	}
186815516c77SSepherosa Ziehau 	*m_head0 = m_head;
186915516c77SSepherosa Ziehau 
187015516c77SSepherosa Ziehau 	/* +1 RNDIS packet message */
187115516c77SSepherosa Ziehau 	txr->hn_gpa_cnt = nsegs + 1;
187215516c77SSepherosa Ziehau 
187315516c77SSepherosa Ziehau 	/* send packet with page buffer */
187415516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr);
187515516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK;
1876dc13fee6SSepherosa Ziehau 	txr->hn_gpa[0].gpa_len = pkt_hlen;
187715516c77SSepherosa Ziehau 
187815516c77SSepherosa Ziehau 	/*
187915516c77SSepherosa Ziehau 	 * Fill the page buffers with mbuf info after the page
188015516c77SSepherosa Ziehau 	 * buffer for RNDIS packet message.
188115516c77SSepherosa Ziehau 	 */
188215516c77SSepherosa Ziehau 	for (i = 0; i < nsegs; ++i) {
188315516c77SSepherosa Ziehau 		struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1];
188415516c77SSepherosa Ziehau 
188515516c77SSepherosa Ziehau 		gpa->gpa_page = atop(segs[i].ds_addr);
188615516c77SSepherosa Ziehau 		gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK;
188715516c77SSepherosa Ziehau 		gpa->gpa_len = segs[i].ds_len;
188815516c77SSepherosa Ziehau 	}
188915516c77SSepherosa Ziehau 
189015516c77SSepherosa Ziehau 	txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
189115516c77SSepherosa Ziehau 	txd->chim_size = 0;
189215516c77SSepherosa Ziehau 	txr->hn_sendpkt = hn_txpkt_sglist;
189315516c77SSepherosa Ziehau done:
189415516c77SSepherosa Ziehau 	txd->m = m_head;
189515516c77SSepherosa Ziehau 
189615516c77SSepherosa Ziehau 	/* Set the completion routine */
189715516c77SSepherosa Ziehau 	hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd);
189815516c77SSepherosa Ziehau 
1899dc13fee6SSepherosa Ziehau 	/* Update temporary stats for later use. */
1900dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts++;
1901dc13fee6SSepherosa Ziehau 	txr->hn_stat_size += m_head->m_pkthdr.len;
1902dc13fee6SSepherosa Ziehau 	if (m_head->m_flags & M_MCAST)
1903dc13fee6SSepherosa Ziehau 		txr->hn_stat_mcasts++;
1904dc13fee6SSepherosa Ziehau 
190515516c77SSepherosa Ziehau 	return 0;
190615516c77SSepherosa Ziehau }
190715516c77SSepherosa Ziehau 
190815516c77SSepherosa Ziehau /*
190915516c77SSepherosa Ziehau  * NOTE:
191015516c77SSepherosa Ziehau  * If this function fails, then txd will be freed, but the mbuf
191115516c77SSepherosa Ziehau  * associated w/ the txd will _not_ be freed.
191215516c77SSepherosa Ziehau  */
191315516c77SSepherosa Ziehau static int
191415516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd)
191515516c77SSepherosa Ziehau {
191615516c77SSepherosa Ziehau 	int error, send_failed = 0;
191715516c77SSepherosa Ziehau 
191815516c77SSepherosa Ziehau again:
191915516c77SSepherosa Ziehau 	/*
1920dc13fee6SSepherosa Ziehau 	 * Make sure that this txd and any aggregated txds are not freed
1921dc13fee6SSepherosa Ziehau 	 * before ETHER_BPF_MTAP.
192215516c77SSepherosa Ziehau 	 */
192315516c77SSepherosa Ziehau 	hn_txdesc_hold(txd);
192415516c77SSepherosa Ziehau 	error = txr->hn_sendpkt(txr, txd);
192515516c77SSepherosa Ziehau 	if (!error) {
1926dc13fee6SSepherosa Ziehau 		if (bpf_peers_present(ifp->if_bpf)) {
1927dc13fee6SSepherosa Ziehau 			const struct hn_txdesc *tmp_txd;
1928dc13fee6SSepherosa Ziehau 
192915516c77SSepherosa Ziehau 			ETHER_BPF_MTAP(ifp, txd->m);
1930dc13fee6SSepherosa Ziehau 			STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link)
1931dc13fee6SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, tmp_txd->m);
1932dc13fee6SSepherosa Ziehau 		}
1933dc13fee6SSepherosa Ziehau 
1934dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts);
193523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
193623bf9e15SSepherosa Ziehau 		if (!hn_use_if_start)
193723bf9e15SSepherosa Ziehau #endif
193823bf9e15SSepherosa Ziehau 		{
193915516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OBYTES,
1940dc13fee6SSepherosa Ziehau 			    txr->hn_stat_size);
1941dc13fee6SSepherosa Ziehau 			if (txr->hn_stat_mcasts != 0) {
1942dc13fee6SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OMCASTS,
1943dc13fee6SSepherosa Ziehau 				    txr->hn_stat_mcasts);
194415516c77SSepherosa Ziehau 			}
1945dc13fee6SSepherosa Ziehau 		}
1946dc13fee6SSepherosa Ziehau 		txr->hn_pkts += txr->hn_stat_pkts;
1947dc13fee6SSepherosa Ziehau 		txr->hn_sends++;
194815516c77SSepherosa Ziehau 	}
194915516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
195015516c77SSepherosa Ziehau 
195115516c77SSepherosa Ziehau 	if (__predict_false(error)) {
195215516c77SSepherosa Ziehau 		int freed;
195315516c77SSepherosa Ziehau 
195415516c77SSepherosa Ziehau 		/*
195515516c77SSepherosa Ziehau 		 * This should "really rarely" happen.
195615516c77SSepherosa Ziehau 		 *
195715516c77SSepherosa Ziehau 		 * XXX Too many RX to be acked or too many sideband
195815516c77SSepherosa Ziehau 		 * commands to run?  Ask netvsc_channel_rollup()
195915516c77SSepherosa Ziehau 		 * to kick start later.
196015516c77SSepherosa Ziehau 		 */
196115516c77SSepherosa Ziehau 		txr->hn_has_txeof = 1;
196215516c77SSepherosa Ziehau 		if (!send_failed) {
196315516c77SSepherosa Ziehau 			txr->hn_send_failed++;
196415516c77SSepherosa Ziehau 			send_failed = 1;
196515516c77SSepherosa Ziehau 			/*
196615516c77SSepherosa Ziehau 			 * Try sending again after set hn_has_txeof;
196715516c77SSepherosa Ziehau 			 * in case that we missed the last
196815516c77SSepherosa Ziehau 			 * netvsc_channel_rollup().
196915516c77SSepherosa Ziehau 			 */
197015516c77SSepherosa Ziehau 			goto again;
197115516c77SSepherosa Ziehau 		}
197215516c77SSepherosa Ziehau 		if_printf(ifp, "send failed\n");
197315516c77SSepherosa Ziehau 
197415516c77SSepherosa Ziehau 		/*
197515516c77SSepherosa Ziehau 		 * Caller will perform further processing on the
197615516c77SSepherosa Ziehau 		 * associated mbuf, so don't free it in hn_txdesc_put();
197715516c77SSepherosa Ziehau 		 * only unload it from the DMA map in hn_txdesc_put(),
197815516c77SSepherosa Ziehau 		 * if it was loaded.
197915516c77SSepherosa Ziehau 		 */
198015516c77SSepherosa Ziehau 		txd->m = NULL;
198115516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
198215516c77SSepherosa Ziehau 		KASSERT(freed != 0,
198315516c77SSepherosa Ziehau 		    ("fail to free txd upon send error"));
198415516c77SSepherosa Ziehau 
198515516c77SSepherosa Ziehau 		txr->hn_send_failed++;
198615516c77SSepherosa Ziehau 	}
1987dc13fee6SSepherosa Ziehau 
1988dc13fee6SSepherosa Ziehau 	/* Reset temporary stats, after this sending is done. */
1989dc13fee6SSepherosa Ziehau 	txr->hn_stat_size = 0;
1990dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts = 0;
1991dc13fee6SSepherosa Ziehau 	txr->hn_stat_mcasts = 0;
1992dc13fee6SSepherosa Ziehau 
1993dc13fee6SSepherosa Ziehau 	return (error);
199415516c77SSepherosa Ziehau }
199515516c77SSepherosa Ziehau 
199615516c77SSepherosa Ziehau /*
199715516c77SSepherosa Ziehau  * Append the specified data to the indicated mbuf chain,
199815516c77SSepherosa Ziehau  * Extend the mbuf chain if the new data does not fit in
199915516c77SSepherosa Ziehau  * existing space.
200015516c77SSepherosa Ziehau  *
200115516c77SSepherosa Ziehau  * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c.
200215516c77SSepherosa Ziehau  * There should be an equivalent in the kernel mbuf code,
200315516c77SSepherosa Ziehau  * but there does not appear to be one yet.
200415516c77SSepherosa Ziehau  *
200515516c77SSepherosa Ziehau  * Differs from m_append() in that additional mbufs are
200615516c77SSepherosa Ziehau  * allocated with cluster size MJUMPAGESIZE, and filled
200715516c77SSepherosa Ziehau  * accordingly.
200815516c77SSepherosa Ziehau  *
200915516c77SSepherosa Ziehau  * Return 1 if able to complete the job; otherwise 0.
201015516c77SSepherosa Ziehau  */
201115516c77SSepherosa Ziehau static int
201215516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp)
201315516c77SSepherosa Ziehau {
201415516c77SSepherosa Ziehau 	struct mbuf *m, *n;
201515516c77SSepherosa Ziehau 	int remainder, space;
201615516c77SSepherosa Ziehau 
201715516c77SSepherosa Ziehau 	for (m = m0; m->m_next != NULL; m = m->m_next)
201815516c77SSepherosa Ziehau 		;
201915516c77SSepherosa Ziehau 	remainder = len;
202015516c77SSepherosa Ziehau 	space = M_TRAILINGSPACE(m);
202115516c77SSepherosa Ziehau 	if (space > 0) {
202215516c77SSepherosa Ziehau 		/*
202315516c77SSepherosa Ziehau 		 * Copy into available space.
202415516c77SSepherosa Ziehau 		 */
202515516c77SSepherosa Ziehau 		if (space > remainder)
202615516c77SSepherosa Ziehau 			space = remainder;
202715516c77SSepherosa Ziehau 		bcopy(cp, mtod(m, caddr_t) + m->m_len, space);
202815516c77SSepherosa Ziehau 		m->m_len += space;
202915516c77SSepherosa Ziehau 		cp += space;
203015516c77SSepherosa Ziehau 		remainder -= space;
203115516c77SSepherosa Ziehau 	}
203215516c77SSepherosa Ziehau 	while (remainder > 0) {
203315516c77SSepherosa Ziehau 		/*
203415516c77SSepherosa Ziehau 		 * Allocate a new mbuf; could check space
203515516c77SSepherosa Ziehau 		 * and allocate a cluster instead.
203615516c77SSepherosa Ziehau 		 */
203715516c77SSepherosa Ziehau 		n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE);
203815516c77SSepherosa Ziehau 		if (n == NULL)
203915516c77SSepherosa Ziehau 			break;
204015516c77SSepherosa Ziehau 		n->m_len = min(MJUMPAGESIZE, remainder);
204115516c77SSepherosa Ziehau 		bcopy(cp, mtod(n, caddr_t), n->m_len);
204215516c77SSepherosa Ziehau 		cp += n->m_len;
204315516c77SSepherosa Ziehau 		remainder -= n->m_len;
204415516c77SSepherosa Ziehau 		m->m_next = n;
204515516c77SSepherosa Ziehau 		m = n;
204615516c77SSepherosa Ziehau 	}
204715516c77SSepherosa Ziehau 	if (m0->m_flags & M_PKTHDR)
204815516c77SSepherosa Ziehau 		m0->m_pkthdr.len += len - remainder;
204915516c77SSepherosa Ziehau 
205015516c77SSepherosa Ziehau 	return (remainder == 0);
205115516c77SSepherosa Ziehau }
205215516c77SSepherosa Ziehau 
205315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
205415516c77SSepherosa Ziehau static __inline int
205515516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m)
205615516c77SSepherosa Ziehau {
205715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
205815516c77SSepherosa Ziehau 	if (hn_lro_mbufq_depth) {
205915516c77SSepherosa Ziehau 		tcp_lro_queue_mbuf(lc, m);
206015516c77SSepherosa Ziehau 		return 0;
206115516c77SSepherosa Ziehau 	}
206215516c77SSepherosa Ziehau #endif
206315516c77SSepherosa Ziehau 	return tcp_lro_rx(lc, m, 0);
206415516c77SSepherosa Ziehau }
206515516c77SSepherosa Ziehau #endif
206615516c77SSepherosa Ziehau 
206715516c77SSepherosa Ziehau static int
206815516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
206915516c77SSepherosa Ziehau     const struct hn_rxinfo *info)
207015516c77SSepherosa Ziehau {
207115516c77SSepherosa Ziehau 	struct ifnet *ifp = rxr->hn_ifp;
207215516c77SSepherosa Ziehau 	struct mbuf *m_new;
207315516c77SSepherosa Ziehau 	int size, do_lro = 0, do_csum = 1;
207415516c77SSepherosa Ziehau 	int hash_type;
207515516c77SSepherosa Ziehau 
207615516c77SSepherosa Ziehau 	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
207715516c77SSepherosa Ziehau 		return (0);
207815516c77SSepherosa Ziehau 
207915516c77SSepherosa Ziehau 	/*
208015516c77SSepherosa Ziehau 	 * Bail out if packet contains more data than configured MTU.
208115516c77SSepherosa Ziehau 	 */
208215516c77SSepherosa Ziehau 	if (dlen > (ifp->if_mtu + ETHER_HDR_LEN)) {
208315516c77SSepherosa Ziehau 		return (0);
208415516c77SSepherosa Ziehau 	} else if (dlen <= MHLEN) {
208515516c77SSepherosa Ziehau 		m_new = m_gethdr(M_NOWAIT, MT_DATA);
208615516c77SSepherosa Ziehau 		if (m_new == NULL) {
208715516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
208815516c77SSepherosa Ziehau 			return (0);
208915516c77SSepherosa Ziehau 		}
209015516c77SSepherosa Ziehau 		memcpy(mtod(m_new, void *), data, dlen);
209115516c77SSepherosa Ziehau 		m_new->m_pkthdr.len = m_new->m_len = dlen;
209215516c77SSepherosa Ziehau 		rxr->hn_small_pkts++;
209315516c77SSepherosa Ziehau 	} else {
209415516c77SSepherosa Ziehau 		/*
209515516c77SSepherosa Ziehau 		 * Get an mbuf with a cluster.  For packets 2K or less,
209615516c77SSepherosa Ziehau 		 * get a standard 2K cluster.  For anything larger, get a
209715516c77SSepherosa Ziehau 		 * 4K cluster.  Any buffers larger than 4K can cause problems
209815516c77SSepherosa Ziehau 		 * if looped around to the Hyper-V TX channel, so avoid them.
209915516c77SSepherosa Ziehau 		 */
210015516c77SSepherosa Ziehau 		size = MCLBYTES;
210115516c77SSepherosa Ziehau 		if (dlen > MCLBYTES) {
210215516c77SSepherosa Ziehau 			/* 4096 */
210315516c77SSepherosa Ziehau 			size = MJUMPAGESIZE;
210415516c77SSepherosa Ziehau 		}
210515516c77SSepherosa Ziehau 
210615516c77SSepherosa Ziehau 		m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size);
210715516c77SSepherosa Ziehau 		if (m_new == NULL) {
210815516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
210915516c77SSepherosa Ziehau 			return (0);
211015516c77SSepherosa Ziehau 		}
211115516c77SSepherosa Ziehau 
211215516c77SSepherosa Ziehau 		hv_m_append(m_new, dlen, data);
211315516c77SSepherosa Ziehau 	}
211415516c77SSepherosa Ziehau 	m_new->m_pkthdr.rcvif = ifp;
211515516c77SSepherosa Ziehau 
211615516c77SSepherosa Ziehau 	if (__predict_false((ifp->if_capenable & IFCAP_RXCSUM) == 0))
211715516c77SSepherosa Ziehau 		do_csum = 0;
211815516c77SSepherosa Ziehau 
211915516c77SSepherosa Ziehau 	/* receive side checksum offload */
212015516c77SSepherosa Ziehau 	if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) {
212115516c77SSepherosa Ziehau 		/* IP csum offload */
212215516c77SSepherosa Ziehau 		if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) {
212315516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
212415516c77SSepherosa Ziehau 			    (CSUM_IP_CHECKED | CSUM_IP_VALID);
212515516c77SSepherosa Ziehau 			rxr->hn_csum_ip++;
212615516c77SSepherosa Ziehau 		}
212715516c77SSepherosa Ziehau 
212815516c77SSepherosa Ziehau 		/* TCP/UDP csum offload */
212915516c77SSepherosa Ziehau 		if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK |
213015516c77SSepherosa Ziehau 		     NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) {
213115516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
213215516c77SSepherosa Ziehau 			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
213315516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_data = 0xffff;
213415516c77SSepherosa Ziehau 			if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK)
213515516c77SSepherosa Ziehau 				rxr->hn_csum_tcp++;
213615516c77SSepherosa Ziehau 			else
213715516c77SSepherosa Ziehau 				rxr->hn_csum_udp++;
213815516c77SSepherosa Ziehau 		}
213915516c77SSepherosa Ziehau 
214015516c77SSepherosa Ziehau 		/*
214115516c77SSepherosa Ziehau 		 * XXX
214215516c77SSepherosa Ziehau 		 * As of this write (Oct 28th, 2016), host side will turn
214315516c77SSepherosa Ziehau 		 * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so
214415516c77SSepherosa Ziehau 		 * the do_lro setting here is actually _not_ accurate.  We
214515516c77SSepherosa Ziehau 		 * depend on the RSS hash type check to reset do_lro.
214615516c77SSepherosa Ziehau 		 */
214715516c77SSepherosa Ziehau 		if ((info->csum_info &
214815516c77SSepherosa Ziehau 		     (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) ==
214915516c77SSepherosa Ziehau 		    (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK))
215015516c77SSepherosa Ziehau 			do_lro = 1;
215115516c77SSepherosa Ziehau 	} else {
215215516c77SSepherosa Ziehau 		const struct ether_header *eh;
215315516c77SSepherosa Ziehau 		uint16_t etype;
215415516c77SSepherosa Ziehau 		int hoff;
215515516c77SSepherosa Ziehau 
215615516c77SSepherosa Ziehau 		hoff = sizeof(*eh);
215715516c77SSepherosa Ziehau 		if (m_new->m_len < hoff)
215815516c77SSepherosa Ziehau 			goto skip;
215915516c77SSepherosa Ziehau 		eh = mtod(m_new, struct ether_header *);
216015516c77SSepherosa Ziehau 		etype = ntohs(eh->ether_type);
216115516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_VLAN) {
216215516c77SSepherosa Ziehau 			const struct ether_vlan_header *evl;
216315516c77SSepherosa Ziehau 
216415516c77SSepherosa Ziehau 			hoff = sizeof(*evl);
216515516c77SSepherosa Ziehau 			if (m_new->m_len < hoff)
216615516c77SSepherosa Ziehau 				goto skip;
216715516c77SSepherosa Ziehau 			evl = mtod(m_new, struct ether_vlan_header *);
216815516c77SSepherosa Ziehau 			etype = ntohs(evl->evl_proto);
216915516c77SSepherosa Ziehau 		}
217015516c77SSepherosa Ziehau 
217115516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_IP) {
217215516c77SSepherosa Ziehau 			int pr;
217315516c77SSepherosa Ziehau 
217415516c77SSepherosa Ziehau 			pr = hn_check_iplen(m_new, hoff);
217515516c77SSepherosa Ziehau 			if (pr == IPPROTO_TCP) {
217615516c77SSepherosa Ziehau 				if (do_csum &&
217715516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
217815516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_TCP)) {
217915516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
218015516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
218115516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
218215516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
218315516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
218415516c77SSepherosa Ziehau 				}
218515516c77SSepherosa Ziehau 				do_lro = 1;
218615516c77SSepherosa Ziehau 			} else if (pr == IPPROTO_UDP) {
218715516c77SSepherosa Ziehau 				if (do_csum &&
218815516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
218915516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_UDP)) {
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 			} else if (pr != IPPROTO_DONE && do_csum &&
219715516c77SSepherosa Ziehau 			    (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) {
219815516c77SSepherosa Ziehau 				rxr->hn_csum_trusted++;
219915516c77SSepherosa Ziehau 				m_new->m_pkthdr.csum_flags |=
220015516c77SSepherosa Ziehau 				    (CSUM_IP_CHECKED | CSUM_IP_VALID);
220115516c77SSepherosa Ziehau 			}
220215516c77SSepherosa Ziehau 		}
220315516c77SSepherosa Ziehau 	}
220415516c77SSepherosa Ziehau skip:
220515516c77SSepherosa Ziehau 	if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) {
220615516c77SSepherosa Ziehau 		m_new->m_pkthdr.ether_vtag = EVL_MAKETAG(
220715516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_ID(info->vlan_info),
220815516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_PRI(info->vlan_info),
220915516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_CFI(info->vlan_info));
221015516c77SSepherosa Ziehau 		m_new->m_flags |= M_VLANTAG;
221115516c77SSepherosa Ziehau 	}
221215516c77SSepherosa Ziehau 
221315516c77SSepherosa Ziehau 	if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) {
221415516c77SSepherosa Ziehau 		rxr->hn_rss_pkts++;
221515516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = info->hash_value;
221615516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE_HASH;
221715516c77SSepherosa Ziehau 		if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) ==
221815516c77SSepherosa Ziehau 		    NDIS_HASH_FUNCTION_TOEPLITZ) {
221915516c77SSepherosa Ziehau 			uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK);
222015516c77SSepherosa Ziehau 
222115516c77SSepherosa Ziehau 			/*
222215516c77SSepherosa Ziehau 			 * NOTE:
222315516c77SSepherosa Ziehau 			 * do_lro is resetted, if the hash types are not TCP
222415516c77SSepherosa Ziehau 			 * related.  See the comment in the above csum_flags
222515516c77SSepherosa Ziehau 			 * setup section.
222615516c77SSepherosa Ziehau 			 */
222715516c77SSepherosa Ziehau 			switch (type) {
222815516c77SSepherosa Ziehau 			case NDIS_HASH_IPV4:
222915516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV4;
223015516c77SSepherosa Ziehau 				do_lro = 0;
223115516c77SSepherosa Ziehau 				break;
223215516c77SSepherosa Ziehau 
223315516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV4:
223415516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV4;
223515516c77SSepherosa Ziehau 				break;
223615516c77SSepherosa Ziehau 
223715516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6:
223815516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6;
223915516c77SSepherosa Ziehau 				do_lro = 0;
224015516c77SSepherosa Ziehau 				break;
224115516c77SSepherosa Ziehau 
224215516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6_EX:
224315516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6_EX;
224415516c77SSepherosa Ziehau 				do_lro = 0;
224515516c77SSepherosa Ziehau 				break;
224615516c77SSepherosa Ziehau 
224715516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6:
224815516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6;
224915516c77SSepherosa Ziehau 				break;
225015516c77SSepherosa Ziehau 
225115516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6_EX:
225215516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX;
225315516c77SSepherosa Ziehau 				break;
225415516c77SSepherosa Ziehau 			}
225515516c77SSepherosa Ziehau 		}
225615516c77SSepherosa Ziehau 	} else {
225715516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
225815516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE;
225915516c77SSepherosa Ziehau 	}
226015516c77SSepherosa Ziehau 	M_HASHTYPE_SET(m_new, hash_type);
226115516c77SSepherosa Ziehau 
226215516c77SSepherosa Ziehau 	/*
226315516c77SSepherosa Ziehau 	 * Note:  Moved RX completion back to hv_nv_on_receive() so all
226415516c77SSepherosa Ziehau 	 * messages (not just data messages) will trigger a response.
226515516c77SSepherosa Ziehau 	 */
226615516c77SSepherosa Ziehau 
226715516c77SSepherosa Ziehau 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
226815516c77SSepherosa Ziehau 	rxr->hn_pkts++;
226915516c77SSepherosa Ziehau 
227015516c77SSepherosa Ziehau 	if ((ifp->if_capenable & IFCAP_LRO) && do_lro) {
227115516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
227215516c77SSepherosa Ziehau 		struct lro_ctrl *lro = &rxr->hn_lro;
227315516c77SSepherosa Ziehau 
227415516c77SSepherosa Ziehau 		if (lro->lro_cnt) {
227515516c77SSepherosa Ziehau 			rxr->hn_lro_tried++;
227615516c77SSepherosa Ziehau 			if (hn_lro_rx(lro, m_new) == 0) {
227715516c77SSepherosa Ziehau 				/* DONE! */
227815516c77SSepherosa Ziehau 				return 0;
227915516c77SSepherosa Ziehau 			}
228015516c77SSepherosa Ziehau 		}
228115516c77SSepherosa Ziehau #endif
228215516c77SSepherosa Ziehau 	}
228315516c77SSepherosa Ziehau 
228415516c77SSepherosa Ziehau 	/* We're not holding the lock here, so don't release it */
228515516c77SSepherosa Ziehau 	(*ifp->if_input)(ifp, m_new);
228615516c77SSepherosa Ziehau 
228715516c77SSepherosa Ziehau 	return (0);
228815516c77SSepherosa Ziehau }
228915516c77SSepherosa Ziehau 
229015516c77SSepherosa Ziehau static int
229115516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
229215516c77SSepherosa Ziehau {
229315516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
229415516c77SSepherosa Ziehau 	struct ifreq *ifr = (struct ifreq *)data;
229515516c77SSepherosa Ziehau 	int mask, error = 0;
229615516c77SSepherosa Ziehau 
229715516c77SSepherosa Ziehau 	switch (cmd) {
229815516c77SSepherosa Ziehau 	case SIOCSIFMTU:
229915516c77SSepherosa Ziehau 		if (ifr->ifr_mtu > HN_MTU_MAX) {
230015516c77SSepherosa Ziehau 			error = EINVAL;
230115516c77SSepherosa Ziehau 			break;
230215516c77SSepherosa Ziehau 		}
230315516c77SSepherosa Ziehau 
230415516c77SSepherosa Ziehau 		HN_LOCK(sc);
230515516c77SSepherosa Ziehau 
230615516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
230715516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
230815516c77SSepherosa Ziehau 			break;
230915516c77SSepherosa Ziehau 		}
231015516c77SSepherosa Ziehau 
231115516c77SSepherosa Ziehau 		if ((sc->hn_caps & HN_CAP_MTU) == 0) {
231215516c77SSepherosa Ziehau 			/* Can't change MTU */
231315516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
231415516c77SSepherosa Ziehau 			error = EOPNOTSUPP;
231515516c77SSepherosa Ziehau 			break;
231615516c77SSepherosa Ziehau 		}
231715516c77SSepherosa Ziehau 
231815516c77SSepherosa Ziehau 		if (ifp->if_mtu == ifr->ifr_mtu) {
231915516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
232015516c77SSepherosa Ziehau 			break;
232115516c77SSepherosa Ziehau 		}
232215516c77SSepherosa Ziehau 
232315516c77SSepherosa Ziehau 		/*
232415516c77SSepherosa Ziehau 		 * Suspend this interface before the synthetic parts
232515516c77SSepherosa Ziehau 		 * are ripped.
232615516c77SSepherosa Ziehau 		 */
232715516c77SSepherosa Ziehau 		hn_suspend(sc);
232815516c77SSepherosa Ziehau 
232915516c77SSepherosa Ziehau 		/*
233015516c77SSepherosa Ziehau 		 * Detach the synthetics parts, i.e. NVS and RNDIS.
233115516c77SSepherosa Ziehau 		 */
233215516c77SSepherosa Ziehau 		hn_synth_detach(sc);
233315516c77SSepherosa Ziehau 
233415516c77SSepherosa Ziehau 		/*
233515516c77SSepherosa Ziehau 		 * Reattach the synthetic parts, i.e. NVS and RNDIS,
233615516c77SSepherosa Ziehau 		 * with the new MTU setting.
233715516c77SSepherosa Ziehau 		 */
233815516c77SSepherosa Ziehau 		error = hn_synth_attach(sc, ifr->ifr_mtu);
233915516c77SSepherosa Ziehau 		if (error) {
234015516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
234115516c77SSepherosa Ziehau 			break;
234215516c77SSepherosa Ziehau 		}
234315516c77SSepherosa Ziehau 
234415516c77SSepherosa Ziehau 		/*
234515516c77SSepherosa Ziehau 		 * Commit the requested MTU, after the synthetic parts
234615516c77SSepherosa Ziehau 		 * have been successfully attached.
234715516c77SSepherosa Ziehau 		 */
234815516c77SSepherosa Ziehau 		ifp->if_mtu = ifr->ifr_mtu;
234915516c77SSepherosa Ziehau 
235015516c77SSepherosa Ziehau 		/*
235115516c77SSepherosa Ziehau 		 * Make sure that various parameters based on MTU are
235215516c77SSepherosa Ziehau 		 * still valid, after the MTU change.
235315516c77SSepherosa Ziehau 		 */
235415516c77SSepherosa Ziehau 		if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax)
235515516c77SSepherosa Ziehau 			hn_set_chim_size(sc, sc->hn_chim_szmax);
235615516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu);
235715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
235815516c77SSepherosa Ziehau 		if (sc->hn_rx_ring[0].hn_lro.lro_length_lim <
235915516c77SSepherosa Ziehau 		    HN_LRO_LENLIM_MIN(ifp))
236015516c77SSepherosa Ziehau 			hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
236115516c77SSepherosa Ziehau #endif
236215516c77SSepherosa Ziehau 
236315516c77SSepherosa Ziehau 		/*
236415516c77SSepherosa Ziehau 		 * All done!  Resume the interface now.
236515516c77SSepherosa Ziehau 		 */
236615516c77SSepherosa Ziehau 		hn_resume(sc);
236715516c77SSepherosa Ziehau 
236815516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
236915516c77SSepherosa Ziehau 		break;
237015516c77SSepherosa Ziehau 
237115516c77SSepherosa Ziehau 	case SIOCSIFFLAGS:
237215516c77SSepherosa Ziehau 		HN_LOCK(sc);
237315516c77SSepherosa Ziehau 
237415516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
237515516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
237615516c77SSepherosa Ziehau 			break;
237715516c77SSepherosa Ziehau 		}
237815516c77SSepherosa Ziehau 
237915516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_UP) {
2380fdc4f478SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2381fdc4f478SSepherosa Ziehau 				/*
2382fdc4f478SSepherosa Ziehau 				 * Caller meight hold mutex, e.g.
2383fdc4f478SSepherosa Ziehau 				 * bpf; use busy-wait for the RNDIS
2384fdc4f478SSepherosa Ziehau 				 * reply.
2385fdc4f478SSepherosa Ziehau 				 */
2386fdc4f478SSepherosa Ziehau 				HN_NO_SLEEPING(sc);
238715516c77SSepherosa Ziehau 				hn_set_rxfilter(sc);
2388fdc4f478SSepherosa Ziehau 				HN_SLEEPING_OK(sc);
2389fdc4f478SSepherosa Ziehau 			} else {
239015516c77SSepherosa Ziehau 				hn_init_locked(sc);
2391fdc4f478SSepherosa Ziehau 			}
239215516c77SSepherosa Ziehau 		} else {
239315516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
239415516c77SSepherosa Ziehau 				hn_stop(sc);
239515516c77SSepherosa Ziehau 		}
239615516c77SSepherosa Ziehau 		sc->hn_if_flags = ifp->if_flags;
239715516c77SSepherosa Ziehau 
239815516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
239915516c77SSepherosa Ziehau 		break;
240015516c77SSepherosa Ziehau 
240115516c77SSepherosa Ziehau 	case SIOCSIFCAP:
240215516c77SSepherosa Ziehau 		HN_LOCK(sc);
240315516c77SSepherosa Ziehau 		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
240415516c77SSepherosa Ziehau 
240515516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM) {
240615516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM;
240715516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM)
240815516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc);
240915516c77SSepherosa Ziehau 			else
241015516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc);
241115516c77SSepherosa Ziehau 		}
241215516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM_IPV6) {
241315516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
241415516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
241515516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc);
241615516c77SSepherosa Ziehau 			else
241715516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc);
241815516c77SSepherosa Ziehau 		}
241915516c77SSepherosa Ziehau 
242015516c77SSepherosa Ziehau 		/* TODO: flip RNDIS offload parameters for RXCSUM. */
242115516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM)
242215516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM;
242315516c77SSepherosa Ziehau #ifdef foo
242415516c77SSepherosa Ziehau 		/* We can't diff IPv6 packets from IPv4 packets on RX path. */
242515516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM_IPV6)
242615516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
242715516c77SSepherosa Ziehau #endif
242815516c77SSepherosa Ziehau 
242915516c77SSepherosa Ziehau 		if (mask & IFCAP_LRO)
243015516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_LRO;
243115516c77SSepherosa Ziehau 
243215516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO4) {
243315516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO4;
243415516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO4)
243515516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP_TSO;
243615516c77SSepherosa Ziehau 			else
243715516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP_TSO;
243815516c77SSepherosa Ziehau 		}
243915516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO6) {
244015516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO6;
244115516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO6)
244215516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP6_TSO;
244315516c77SSepherosa Ziehau 			else
244415516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP6_TSO;
244515516c77SSepherosa Ziehau 		}
244615516c77SSepherosa Ziehau 
244715516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
244815516c77SSepherosa Ziehau 		break;
244915516c77SSepherosa Ziehau 
245015516c77SSepherosa Ziehau 	case SIOCADDMULTI:
245115516c77SSepherosa Ziehau 	case SIOCDELMULTI:
245215516c77SSepherosa Ziehau 		HN_LOCK(sc);
245315516c77SSepherosa Ziehau 
245415516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
245515516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
245615516c77SSepherosa Ziehau 			break;
245715516c77SSepherosa Ziehau 		}
2458fdc4f478SSepherosa Ziehau 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2459fdc4f478SSepherosa Ziehau 			/*
2460fdc4f478SSepherosa Ziehau 			 * Multicast uses mutex; use busy-wait for
2461fdc4f478SSepherosa Ziehau 			 * the RNDIS reply.
2462fdc4f478SSepherosa Ziehau 			 */
2463fdc4f478SSepherosa Ziehau 			HN_NO_SLEEPING(sc);
246415516c77SSepherosa Ziehau 			hn_set_rxfilter(sc);
2465fdc4f478SSepherosa Ziehau 			HN_SLEEPING_OK(sc);
2466fdc4f478SSepherosa Ziehau 		}
246715516c77SSepherosa Ziehau 
246815516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
246915516c77SSepherosa Ziehau 		break;
247015516c77SSepherosa Ziehau 
247115516c77SSepherosa Ziehau 	case SIOCSIFMEDIA:
247215516c77SSepherosa Ziehau 	case SIOCGIFMEDIA:
247315516c77SSepherosa Ziehau 		error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd);
247415516c77SSepherosa Ziehau 		break;
247515516c77SSepherosa Ziehau 
247615516c77SSepherosa Ziehau 	default:
247715516c77SSepherosa Ziehau 		error = ether_ioctl(ifp, cmd, data);
247815516c77SSepherosa Ziehau 		break;
247915516c77SSepherosa Ziehau 	}
248015516c77SSepherosa Ziehau 	return (error);
248115516c77SSepherosa Ziehau }
248215516c77SSepherosa Ziehau 
248315516c77SSepherosa Ziehau static void
248415516c77SSepherosa Ziehau hn_stop(struct hn_softc *sc)
248515516c77SSepherosa Ziehau {
248615516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
248715516c77SSepherosa Ziehau 	int i;
248815516c77SSepherosa Ziehau 
248915516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
249015516c77SSepherosa Ziehau 
249115516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
249215516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
249315516c77SSepherosa Ziehau 
249415516c77SSepherosa Ziehau 	/* Clear RUNNING bit _before_ hn_suspend_data() */
249515516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
249615516c77SSepherosa Ziehau 	hn_suspend_data(sc);
249715516c77SSepherosa Ziehau 
249815516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
249915516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
250015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
250115516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
250215516c77SSepherosa Ziehau }
250315516c77SSepherosa Ziehau 
250415516c77SSepherosa Ziehau static void
250515516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc)
250615516c77SSepherosa Ziehau {
250715516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
250815516c77SSepherosa Ziehau 	int i;
250915516c77SSepherosa Ziehau 
251015516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
251115516c77SSepherosa Ziehau 
251215516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
251315516c77SSepherosa Ziehau 		return;
251415516c77SSepherosa Ziehau 
251515516c77SSepherosa Ziehau 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
251615516c77SSepherosa Ziehau 		return;
251715516c77SSepherosa Ziehau 
251815516c77SSepherosa Ziehau 	/* Configure RX filter */
251915516c77SSepherosa Ziehau 	hn_set_rxfilter(sc);
252015516c77SSepherosa Ziehau 
252115516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
252215516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
252315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
252415516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
252515516c77SSepherosa Ziehau 
252615516c77SSepherosa Ziehau 	/* Clear TX 'suspended' bit. */
252715516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_inuse);
252815516c77SSepherosa Ziehau 
252915516c77SSepherosa Ziehau 	/* Everything is ready; unleash! */
253015516c77SSepherosa Ziehau 	atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
253115516c77SSepherosa Ziehau }
253215516c77SSepherosa Ziehau 
253315516c77SSepherosa Ziehau static void
253415516c77SSepherosa Ziehau hn_init(void *xsc)
253515516c77SSepherosa Ziehau {
253615516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
253715516c77SSepherosa Ziehau 
253815516c77SSepherosa Ziehau 	HN_LOCK(sc);
253915516c77SSepherosa Ziehau 	hn_init_locked(sc);
254015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
254115516c77SSepherosa Ziehau }
254215516c77SSepherosa Ziehau 
254315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
254415516c77SSepherosa Ziehau 
254515516c77SSepherosa Ziehau static int
254615516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
254715516c77SSepherosa Ziehau {
254815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
254915516c77SSepherosa Ziehau 	unsigned int lenlim;
255015516c77SSepherosa Ziehau 	int error;
255115516c77SSepherosa Ziehau 
255215516c77SSepherosa Ziehau 	lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim;
255315516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &lenlim, 0, req);
255415516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
255515516c77SSepherosa Ziehau 		return error;
255615516c77SSepherosa Ziehau 
255715516c77SSepherosa Ziehau 	HN_LOCK(sc);
255815516c77SSepherosa Ziehau 	if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) ||
255915516c77SSepherosa Ziehau 	    lenlim > TCP_LRO_LENGTH_MAX) {
256015516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
256115516c77SSepherosa Ziehau 		return EINVAL;
256215516c77SSepherosa Ziehau 	}
256315516c77SSepherosa Ziehau 	hn_set_lro_lenlim(sc, lenlim);
256415516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
256515516c77SSepherosa Ziehau 
256615516c77SSepherosa Ziehau 	return 0;
256715516c77SSepherosa Ziehau }
256815516c77SSepherosa Ziehau 
256915516c77SSepherosa Ziehau static int
257015516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS)
257115516c77SSepherosa Ziehau {
257215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
257315516c77SSepherosa Ziehau 	int ackcnt, error, i;
257415516c77SSepherosa Ziehau 
257515516c77SSepherosa Ziehau 	/*
257615516c77SSepherosa Ziehau 	 * lro_ackcnt_lim is append count limit,
257715516c77SSepherosa Ziehau 	 * +1 to turn it into aggregation limit.
257815516c77SSepherosa Ziehau 	 */
257915516c77SSepherosa Ziehau 	ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1;
258015516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &ackcnt, 0, req);
258115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
258215516c77SSepherosa Ziehau 		return error;
258315516c77SSepherosa Ziehau 
258415516c77SSepherosa Ziehau 	if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1))
258515516c77SSepherosa Ziehau 		return EINVAL;
258615516c77SSepherosa Ziehau 
258715516c77SSepherosa Ziehau 	/*
258815516c77SSepherosa Ziehau 	 * Convert aggregation limit back to append
258915516c77SSepherosa Ziehau 	 * count limit.
259015516c77SSepherosa Ziehau 	 */
259115516c77SSepherosa Ziehau 	--ackcnt;
259215516c77SSepherosa Ziehau 	HN_LOCK(sc);
2593a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
259415516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt;
259515516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
259615516c77SSepherosa Ziehau 	return 0;
259715516c77SSepherosa Ziehau }
259815516c77SSepherosa Ziehau 
259915516c77SSepherosa Ziehau #endif
260015516c77SSepherosa Ziehau 
260115516c77SSepherosa Ziehau static int
260215516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS)
260315516c77SSepherosa Ziehau {
260415516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
260515516c77SSepherosa Ziehau 	int hcsum = arg2;
260615516c77SSepherosa Ziehau 	int on, error, i;
260715516c77SSepherosa Ziehau 
260815516c77SSepherosa Ziehau 	on = 0;
260915516c77SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum)
261015516c77SSepherosa Ziehau 		on = 1;
261115516c77SSepherosa Ziehau 
261215516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &on, 0, req);
261315516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
261415516c77SSepherosa Ziehau 		return error;
261515516c77SSepherosa Ziehau 
261615516c77SSepherosa Ziehau 	HN_LOCK(sc);
2617a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
261815516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
261915516c77SSepherosa Ziehau 
262015516c77SSepherosa Ziehau 		if (on)
262115516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= hcsum;
262215516c77SSepherosa Ziehau 		else
262315516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum &= ~hcsum;
262415516c77SSepherosa Ziehau 	}
262515516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
262615516c77SSepherosa Ziehau 	return 0;
262715516c77SSepherosa Ziehau }
262815516c77SSepherosa Ziehau 
262915516c77SSepherosa Ziehau static int
263015516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS)
263115516c77SSepherosa Ziehau {
263215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
263315516c77SSepherosa Ziehau 	int chim_size, error;
263415516c77SSepherosa Ziehau 
263515516c77SSepherosa Ziehau 	chim_size = sc->hn_tx_ring[0].hn_chim_size;
263615516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &chim_size, 0, req);
263715516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
263815516c77SSepherosa Ziehau 		return error;
263915516c77SSepherosa Ziehau 
264015516c77SSepherosa Ziehau 	if (chim_size > sc->hn_chim_szmax || chim_size <= 0)
264115516c77SSepherosa Ziehau 		return EINVAL;
264215516c77SSepherosa Ziehau 
264315516c77SSepherosa Ziehau 	HN_LOCK(sc);
264415516c77SSepherosa Ziehau 	hn_set_chim_size(sc, chim_size);
264515516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
264615516c77SSepherosa Ziehau 	return 0;
264715516c77SSepherosa Ziehau }
264815516c77SSepherosa Ziehau 
264915516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
265015516c77SSepherosa Ziehau static int
265115516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS)
265215516c77SSepherosa Ziehau {
265315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
265415516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
265515516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
265615516c77SSepherosa Ziehau 	uint64_t stat;
265715516c77SSepherosa Ziehau 
265815516c77SSepherosa Ziehau 	stat = 0;
265915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
266015516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
266115516c77SSepherosa Ziehau 		stat += *((int *)((uint8_t *)rxr + ofs));
266215516c77SSepherosa Ziehau 	}
266315516c77SSepherosa Ziehau 
266415516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
266515516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
266615516c77SSepherosa Ziehau 		return error;
266715516c77SSepherosa Ziehau 
266815516c77SSepherosa Ziehau 	/* Zero out this stat. */
266915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
267015516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
267115516c77SSepherosa Ziehau 		*((int *)((uint8_t *)rxr + ofs)) = 0;
267215516c77SSepherosa Ziehau 	}
267315516c77SSepherosa Ziehau 	return 0;
267415516c77SSepherosa Ziehau }
267515516c77SSepherosa Ziehau #else
267615516c77SSepherosa Ziehau static int
267715516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS)
267815516c77SSepherosa Ziehau {
267915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
268015516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
268115516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
268215516c77SSepherosa Ziehau 	uint64_t stat;
268315516c77SSepherosa Ziehau 
268415516c77SSepherosa Ziehau 	stat = 0;
2685a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
268615516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
268715516c77SSepherosa Ziehau 		stat += *((uint64_t *)((uint8_t *)rxr + ofs));
268815516c77SSepherosa Ziehau 	}
268915516c77SSepherosa Ziehau 
269015516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
269115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
269215516c77SSepherosa Ziehau 		return error;
269315516c77SSepherosa Ziehau 
269415516c77SSepherosa Ziehau 	/* Zero out this stat. */
2695a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
269615516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
269715516c77SSepherosa Ziehau 		*((uint64_t *)((uint8_t *)rxr + ofs)) = 0;
269815516c77SSepherosa Ziehau 	}
269915516c77SSepherosa Ziehau 	return 0;
270015516c77SSepherosa Ziehau }
270115516c77SSepherosa Ziehau 
270215516c77SSepherosa Ziehau #endif
270315516c77SSepherosa Ziehau 
270415516c77SSepherosa Ziehau static int
270515516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
270615516c77SSepherosa Ziehau {
270715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
270815516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
270915516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
271015516c77SSepherosa Ziehau 	u_long stat;
271115516c77SSepherosa Ziehau 
271215516c77SSepherosa Ziehau 	stat = 0;
2713a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
271415516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
271515516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)rxr + ofs));
271615516c77SSepherosa Ziehau 	}
271715516c77SSepherosa Ziehau 
271815516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
271915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
272015516c77SSepherosa Ziehau 		return error;
272115516c77SSepherosa Ziehau 
272215516c77SSepherosa Ziehau 	/* Zero out this stat. */
2723a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
272415516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
272515516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)rxr + ofs)) = 0;
272615516c77SSepherosa Ziehau 	}
272715516c77SSepherosa Ziehau 	return 0;
272815516c77SSepherosa Ziehau }
272915516c77SSepherosa Ziehau 
273015516c77SSepherosa Ziehau static int
273115516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
273215516c77SSepherosa Ziehau {
273315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
273415516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
273515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
273615516c77SSepherosa Ziehau 	u_long stat;
273715516c77SSepherosa Ziehau 
273815516c77SSepherosa Ziehau 	stat = 0;
2739a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
274015516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
274115516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)txr + ofs));
274215516c77SSepherosa Ziehau 	}
274315516c77SSepherosa Ziehau 
274415516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
274515516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
274615516c77SSepherosa Ziehau 		return error;
274715516c77SSepherosa Ziehau 
274815516c77SSepherosa Ziehau 	/* Zero out this stat. */
2749a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
275015516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
275115516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)txr + ofs)) = 0;
275215516c77SSepherosa Ziehau 	}
275315516c77SSepherosa Ziehau 	return 0;
275415516c77SSepherosa Ziehau }
275515516c77SSepherosa Ziehau 
275615516c77SSepherosa Ziehau static int
275715516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS)
275815516c77SSepherosa Ziehau {
275915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
276015516c77SSepherosa Ziehau 	int ofs = arg2, i, error, conf;
276115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
276215516c77SSepherosa Ziehau 
276315516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[0];
276415516c77SSepherosa Ziehau 	conf = *((int *)((uint8_t *)txr + ofs));
276515516c77SSepherosa Ziehau 
276615516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &conf, 0, req);
276715516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
276815516c77SSepherosa Ziehau 		return error;
276915516c77SSepherosa Ziehau 
277015516c77SSepherosa Ziehau 	HN_LOCK(sc);
2771a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
277215516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
277315516c77SSepherosa Ziehau 		*((int *)((uint8_t *)txr + ofs)) = conf;
277415516c77SSepherosa Ziehau 	}
277515516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
277615516c77SSepherosa Ziehau 
277715516c77SSepherosa Ziehau 	return 0;
277815516c77SSepherosa Ziehau }
277915516c77SSepherosa Ziehau 
278015516c77SSepherosa Ziehau static int
2781dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS)
2782dc13fee6SSepherosa Ziehau {
2783dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2784dc13fee6SSepherosa Ziehau 	int error, size;
2785dc13fee6SSepherosa Ziehau 
2786dc13fee6SSepherosa Ziehau 	size = sc->hn_agg_size;
2787dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &size, 0, req);
2788dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
2789dc13fee6SSepherosa Ziehau 		return (error);
2790dc13fee6SSepherosa Ziehau 
2791dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
2792dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = size;
2793dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
2794dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
2795dc13fee6SSepherosa Ziehau 
2796dc13fee6SSepherosa Ziehau 	return (0);
2797dc13fee6SSepherosa Ziehau }
2798dc13fee6SSepherosa Ziehau 
2799dc13fee6SSepherosa Ziehau static int
2800dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS)
2801dc13fee6SSepherosa Ziehau {
2802dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2803dc13fee6SSepherosa Ziehau 	int error, pkts;
2804dc13fee6SSepherosa Ziehau 
2805dc13fee6SSepherosa Ziehau 	pkts = sc->hn_agg_pkts;
2806dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pkts, 0, req);
2807dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
2808dc13fee6SSepherosa Ziehau 		return (error);
2809dc13fee6SSepherosa Ziehau 
2810dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
2811dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = pkts;
2812dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
2813dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
2814dc13fee6SSepherosa Ziehau 
2815dc13fee6SSepherosa Ziehau 	return (0);
2816dc13fee6SSepherosa Ziehau }
2817dc13fee6SSepherosa Ziehau 
2818dc13fee6SSepherosa Ziehau static int
2819dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS)
2820dc13fee6SSepherosa Ziehau {
2821dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2822dc13fee6SSepherosa Ziehau 	int pkts;
2823dc13fee6SSepherosa Ziehau 
2824dc13fee6SSepherosa Ziehau 	pkts = sc->hn_tx_ring[0].hn_agg_pktmax;
2825dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &pkts, 0, req));
2826dc13fee6SSepherosa Ziehau }
2827dc13fee6SSepherosa Ziehau 
2828dc13fee6SSepherosa Ziehau static int
2829dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS)
2830dc13fee6SSepherosa Ziehau {
2831dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2832dc13fee6SSepherosa Ziehau 	int align;
2833dc13fee6SSepherosa Ziehau 
2834dc13fee6SSepherosa Ziehau 	align = sc->hn_tx_ring[0].hn_agg_align;
2835dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &align, 0, req));
2836dc13fee6SSepherosa Ziehau }
2837dc13fee6SSepherosa Ziehau 
2838dc13fee6SSepherosa Ziehau static int
283915516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS)
284015516c77SSepherosa Ziehau {
284115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
284215516c77SSepherosa Ziehau 	char verstr[16];
284315516c77SSepherosa Ziehau 
284415516c77SSepherosa Ziehau 	snprintf(verstr, sizeof(verstr), "%u.%u",
284515516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
284615516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
284715516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
284815516c77SSepherosa Ziehau }
284915516c77SSepherosa Ziehau 
285015516c77SSepherosa Ziehau static int
285115516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS)
285215516c77SSepherosa Ziehau {
285315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
285415516c77SSepherosa Ziehau 	char caps_str[128];
285515516c77SSepherosa Ziehau 	uint32_t caps;
285615516c77SSepherosa Ziehau 
285715516c77SSepherosa Ziehau 	HN_LOCK(sc);
285815516c77SSepherosa Ziehau 	caps = sc->hn_caps;
285915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
286015516c77SSepherosa Ziehau 	snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS);
286115516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req);
286215516c77SSepherosa Ziehau }
286315516c77SSepherosa Ziehau 
286415516c77SSepherosa Ziehau static int
286515516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS)
286615516c77SSepherosa Ziehau {
286715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
286815516c77SSepherosa Ziehau 	char assist_str[128];
286915516c77SSepherosa Ziehau 	uint32_t hwassist;
287015516c77SSepherosa Ziehau 
287115516c77SSepherosa Ziehau 	HN_LOCK(sc);
287215516c77SSepherosa Ziehau 	hwassist = sc->hn_ifp->if_hwassist;
287315516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
287415516c77SSepherosa Ziehau 	snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS);
287515516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req);
287615516c77SSepherosa Ziehau }
287715516c77SSepherosa Ziehau 
287815516c77SSepherosa Ziehau static int
287915516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS)
288015516c77SSepherosa Ziehau {
288115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
288215516c77SSepherosa Ziehau 	char filter_str[128];
288315516c77SSepherosa Ziehau 	uint32_t filter;
288415516c77SSepherosa Ziehau 
288515516c77SSepherosa Ziehau 	HN_LOCK(sc);
288615516c77SSepherosa Ziehau 	filter = sc->hn_rx_filter;
288715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
288815516c77SSepherosa Ziehau 	snprintf(filter_str, sizeof(filter_str), "%b", filter,
288915516c77SSepherosa Ziehau 	    NDIS_PACKET_TYPES);
289015516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req);
289115516c77SSepherosa Ziehau }
289215516c77SSepherosa Ziehau 
289315516c77SSepherosa Ziehau static int
289415516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
289515516c77SSepherosa Ziehau {
289615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
289715516c77SSepherosa Ziehau 	int error;
289815516c77SSepherosa Ziehau 
289915516c77SSepherosa Ziehau 	HN_LOCK(sc);
290015516c77SSepherosa Ziehau 
290115516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
290215516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
290315516c77SSepherosa Ziehau 		goto back;
290415516c77SSepherosa Ziehau 
290515516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
290615516c77SSepherosa Ziehau 	if (error)
290715516c77SSepherosa Ziehau 		goto back;
290815516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
290915516c77SSepherosa Ziehau 
291015516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
291115516c77SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
291215516c77SSepherosa Ziehau 	} else {
291315516c77SSepherosa Ziehau 		/* Not RSS capable, at least for now; just save the RSS key. */
291415516c77SSepherosa Ziehau 		error = 0;
291515516c77SSepherosa Ziehau 	}
291615516c77SSepherosa Ziehau back:
291715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
291815516c77SSepherosa Ziehau 	return (error);
291915516c77SSepherosa Ziehau }
292015516c77SSepherosa Ziehau 
292115516c77SSepherosa Ziehau static int
292215516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS)
292315516c77SSepherosa Ziehau {
292415516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
292515516c77SSepherosa Ziehau 	int error;
292615516c77SSepherosa Ziehau 
292715516c77SSepherosa Ziehau 	HN_LOCK(sc);
292815516c77SSepherosa Ziehau 
292915516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
293015516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
293115516c77SSepherosa Ziehau 		goto back;
293215516c77SSepherosa Ziehau 
293315516c77SSepherosa Ziehau 	/*
293415516c77SSepherosa Ziehau 	 * Don't allow RSS indirect table change, if this interface is not
293515516c77SSepherosa Ziehau 	 * RSS capable currently.
293615516c77SSepherosa Ziehau 	 */
293715516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
293815516c77SSepherosa Ziehau 		error = EOPNOTSUPP;
293915516c77SSepherosa Ziehau 		goto back;
294015516c77SSepherosa Ziehau 	}
294115516c77SSepherosa Ziehau 
294215516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
294315516c77SSepherosa Ziehau 	if (error)
294415516c77SSepherosa Ziehau 		goto back;
294515516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSIND;
294615516c77SSepherosa Ziehau 
2947afd4971bSSepherosa Ziehau 	hn_rss_ind_fixup(sc);
294815516c77SSepherosa Ziehau 	error = hn_rss_reconfig(sc);
294915516c77SSepherosa Ziehau back:
295015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
295115516c77SSepherosa Ziehau 	return (error);
295215516c77SSepherosa Ziehau }
295315516c77SSepherosa Ziehau 
295415516c77SSepherosa Ziehau static int
295515516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS)
295615516c77SSepherosa Ziehau {
295715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
295815516c77SSepherosa Ziehau 	char hash_str[128];
295915516c77SSepherosa Ziehau 	uint32_t hash;
296015516c77SSepherosa Ziehau 
296115516c77SSepherosa Ziehau 	HN_LOCK(sc);
296215516c77SSepherosa Ziehau 	hash = sc->hn_rss_hash;
296315516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
296415516c77SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
296515516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
296615516c77SSepherosa Ziehau }
296715516c77SSepherosa Ziehau 
296815516c77SSepherosa Ziehau static int
296915516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff)
297015516c77SSepherosa Ziehau {
297115516c77SSepherosa Ziehau 	const struct ip *ip;
297215516c77SSepherosa Ziehau 	int len, iphlen, iplen;
297315516c77SSepherosa Ziehau 	const struct tcphdr *th;
297415516c77SSepherosa Ziehau 	int thoff;				/* TCP data offset */
297515516c77SSepherosa Ziehau 
297615516c77SSepherosa Ziehau 	len = hoff + sizeof(struct ip);
297715516c77SSepherosa Ziehau 
297815516c77SSepherosa Ziehau 	/* The packet must be at least the size of an IP header. */
297915516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < len)
298015516c77SSepherosa Ziehau 		return IPPROTO_DONE;
298115516c77SSepherosa Ziehau 
298215516c77SSepherosa Ziehau 	/* The fixed IP header must reside completely in the first mbuf. */
298315516c77SSepherosa Ziehau 	if (m->m_len < len)
298415516c77SSepherosa Ziehau 		return IPPROTO_DONE;
298515516c77SSepherosa Ziehau 
298615516c77SSepherosa Ziehau 	ip = mtodo(m, hoff);
298715516c77SSepherosa Ziehau 
298815516c77SSepherosa Ziehau 	/* Bound check the packet's stated IP header length. */
298915516c77SSepherosa Ziehau 	iphlen = ip->ip_hl << 2;
299015516c77SSepherosa Ziehau 	if (iphlen < sizeof(struct ip))		/* minimum header length */
299115516c77SSepherosa Ziehau 		return IPPROTO_DONE;
299215516c77SSepherosa Ziehau 
299315516c77SSepherosa Ziehau 	/* The full IP header must reside completely in the one mbuf. */
299415516c77SSepherosa Ziehau 	if (m->m_len < hoff + iphlen)
299515516c77SSepherosa Ziehau 		return IPPROTO_DONE;
299615516c77SSepherosa Ziehau 
299715516c77SSepherosa Ziehau 	iplen = ntohs(ip->ip_len);
299815516c77SSepherosa Ziehau 
299915516c77SSepherosa Ziehau 	/*
300015516c77SSepherosa Ziehau 	 * Check that the amount of data in the buffers is as
300115516c77SSepherosa Ziehau 	 * at least much as the IP header would have us expect.
300215516c77SSepherosa Ziehau 	 */
300315516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < hoff + iplen)
300415516c77SSepherosa Ziehau 		return IPPROTO_DONE;
300515516c77SSepherosa Ziehau 
300615516c77SSepherosa Ziehau 	/*
300715516c77SSepherosa Ziehau 	 * Ignore IP fragments.
300815516c77SSepherosa Ziehau 	 */
300915516c77SSepherosa Ziehau 	if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF))
301015516c77SSepherosa Ziehau 		return IPPROTO_DONE;
301115516c77SSepherosa Ziehau 
301215516c77SSepherosa Ziehau 	/*
301315516c77SSepherosa Ziehau 	 * The TCP/IP or UDP/IP header must be entirely contained within
301415516c77SSepherosa Ziehau 	 * the first fragment of a packet.
301515516c77SSepherosa Ziehau 	 */
301615516c77SSepherosa Ziehau 	switch (ip->ip_p) {
301715516c77SSepherosa Ziehau 	case IPPROTO_TCP:
301815516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct tcphdr))
301915516c77SSepherosa Ziehau 			return IPPROTO_DONE;
302015516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct tcphdr))
302115516c77SSepherosa Ziehau 			return IPPROTO_DONE;
302215516c77SSepherosa Ziehau 		th = (const struct tcphdr *)((const uint8_t *)ip + iphlen);
302315516c77SSepherosa Ziehau 		thoff = th->th_off << 2;
302415516c77SSepherosa Ziehau 		if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen)
302515516c77SSepherosa Ziehau 			return IPPROTO_DONE;
302615516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + thoff)
302715516c77SSepherosa Ziehau 			return IPPROTO_DONE;
302815516c77SSepherosa Ziehau 		break;
302915516c77SSepherosa Ziehau 	case IPPROTO_UDP:
303015516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct udphdr))
303115516c77SSepherosa Ziehau 			return IPPROTO_DONE;
303215516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct udphdr))
303315516c77SSepherosa Ziehau 			return IPPROTO_DONE;
303415516c77SSepherosa Ziehau 		break;
303515516c77SSepherosa Ziehau 	default:
303615516c77SSepherosa Ziehau 		if (iplen < iphlen)
303715516c77SSepherosa Ziehau 			return IPPROTO_DONE;
303815516c77SSepherosa Ziehau 		break;
303915516c77SSepherosa Ziehau 	}
304015516c77SSepherosa Ziehau 	return ip->ip_p;
304115516c77SSepherosa Ziehau }
304215516c77SSepherosa Ziehau 
304315516c77SSepherosa Ziehau static int
304415516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt)
304515516c77SSepherosa Ziehau {
304615516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
304715516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
304815516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
304915516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
305015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
305115516c77SSepherosa Ziehau 	int lroent_cnt;
305215516c77SSepherosa Ziehau #endif
305315516c77SSepherosa Ziehau #endif
305415516c77SSepherosa Ziehau 	int i;
305515516c77SSepherosa Ziehau 
305615516c77SSepherosa Ziehau 	/*
305715516c77SSepherosa Ziehau 	 * Create RXBUF for reception.
305815516c77SSepherosa Ziehau 	 *
305915516c77SSepherosa Ziehau 	 * NOTE:
306015516c77SSepherosa Ziehau 	 * - It is shared by all channels.
306115516c77SSepherosa Ziehau 	 * - A large enough buffer is allocated, certain version of NVSes
306215516c77SSepherosa Ziehau 	 *   may further limit the usable space.
306315516c77SSepherosa Ziehau 	 */
306415516c77SSepherosa Ziehau 	sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
306515516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma,
306615516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
306715516c77SSepherosa Ziehau 	if (sc->hn_rxbuf == NULL) {
306815516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate rxbuf failed\n");
306915516c77SSepherosa Ziehau 		return (ENOMEM);
307015516c77SSepherosa Ziehau 	}
307115516c77SSepherosa Ziehau 
307215516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = ring_cnt;
307315516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt;
307415516c77SSepherosa Ziehau 
307515516c77SSepherosa Ziehau 	sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt,
307615516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
307715516c77SSepherosa Ziehau 
307815516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
307915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
308015516c77SSepherosa Ziehau 	lroent_cnt = hn_lro_entry_count;
308115516c77SSepherosa Ziehau 	if (lroent_cnt < TCP_LRO_ENTRIES)
308215516c77SSepherosa Ziehau 		lroent_cnt = TCP_LRO_ENTRIES;
308315516c77SSepherosa Ziehau 	if (bootverbose)
308415516c77SSepherosa Ziehau 		device_printf(dev, "LRO: entry count %d\n", lroent_cnt);
308515516c77SSepherosa Ziehau #endif
308615516c77SSepherosa Ziehau #endif	/* INET || INET6 */
308715516c77SSepherosa Ziehau 
308815516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
308915516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
309015516c77SSepherosa Ziehau 
309115516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.rx sysctl tree */
309215516c77SSepherosa Ziehau 	sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx",
309315516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
309415516c77SSepherosa Ziehau 
309515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
309615516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
309715516c77SSepherosa Ziehau 
309815516c77SSepherosa Ziehau 		rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
309915516c77SSepherosa Ziehau 		    PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE,
310015516c77SSepherosa Ziehau 		    &rxr->hn_br_dma, BUS_DMA_WAITOK);
310115516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL) {
310215516c77SSepherosa Ziehau 			device_printf(dev, "allocate bufring failed\n");
310315516c77SSepherosa Ziehau 			return (ENOMEM);
310415516c77SSepherosa Ziehau 		}
310515516c77SSepherosa Ziehau 
310615516c77SSepherosa Ziehau 		if (hn_trust_hosttcp)
310715516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP;
310815516c77SSepherosa Ziehau 		if (hn_trust_hostudp)
310915516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP;
311015516c77SSepherosa Ziehau 		if (hn_trust_hostip)
311115516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP;
311215516c77SSepherosa Ziehau 		rxr->hn_ifp = sc->hn_ifp;
311315516c77SSepherosa Ziehau 		if (i < sc->hn_tx_ring_cnt)
311415516c77SSepherosa Ziehau 			rxr->hn_txr = &sc->hn_tx_ring[i];
311515516c77SSepherosa Ziehau 		rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF;
311615516c77SSepherosa Ziehau 		rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK);
311715516c77SSepherosa Ziehau 		rxr->hn_rx_idx = i;
311815516c77SSepherosa Ziehau 		rxr->hn_rxbuf = sc->hn_rxbuf;
311915516c77SSepherosa Ziehau 
312015516c77SSepherosa Ziehau 		/*
312115516c77SSepherosa Ziehau 		 * Initialize LRO.
312215516c77SSepherosa Ziehau 		 */
312315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
312415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
312515516c77SSepherosa Ziehau 		tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt,
312615516c77SSepherosa Ziehau 		    hn_lro_mbufq_depth);
312715516c77SSepherosa Ziehau #else
312815516c77SSepherosa Ziehau 		tcp_lro_init(&rxr->hn_lro);
312915516c77SSepherosa Ziehau 		rxr->hn_lro.ifp = sc->hn_ifp;
313015516c77SSepherosa Ziehau #endif
313115516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
313215516c77SSepherosa Ziehau 		rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF;
313315516c77SSepherosa Ziehau 		rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF;
313415516c77SSepherosa Ziehau #endif
313515516c77SSepherosa Ziehau #endif	/* INET || INET6 */
313615516c77SSepherosa Ziehau 
313715516c77SSepherosa Ziehau 		if (sc->hn_rx_sysctl_tree != NULL) {
313815516c77SSepherosa Ziehau 			char name[16];
313915516c77SSepherosa Ziehau 
314015516c77SSepherosa Ziehau 			/*
314115516c77SSepherosa Ziehau 			 * Create per RX ring sysctl tree:
314215516c77SSepherosa Ziehau 			 * dev.hn.UNIT.rx.RINGID
314315516c77SSepherosa Ziehau 			 */
314415516c77SSepherosa Ziehau 			snprintf(name, sizeof(name), "%d", i);
314515516c77SSepherosa Ziehau 			rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx,
314615516c77SSepherosa Ziehau 			    SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree),
314715516c77SSepherosa Ziehau 			    OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
314815516c77SSepherosa Ziehau 
314915516c77SSepherosa Ziehau 			if (rxr->hn_rx_sysctl_tree != NULL) {
315015516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
315115516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
315215516c77SSepherosa Ziehau 				    OID_AUTO, "packets", CTLFLAG_RW,
315315516c77SSepherosa Ziehau 				    &rxr->hn_pkts, "# of packets received");
315415516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
315515516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
315615516c77SSepherosa Ziehau 				    OID_AUTO, "rss_pkts", CTLFLAG_RW,
315715516c77SSepherosa Ziehau 				    &rxr->hn_rss_pkts,
315815516c77SSepherosa Ziehau 				    "# of packets w/ RSS info received");
315915516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx,
316015516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
316115516c77SSepherosa Ziehau 				    OID_AUTO, "pktbuf_len", CTLFLAG_RD,
316215516c77SSepherosa Ziehau 				    &rxr->hn_pktbuf_len, 0,
316315516c77SSepherosa Ziehau 				    "Temporary channel packet buffer length");
316415516c77SSepherosa Ziehau 			}
316515516c77SSepherosa Ziehau 		}
316615516c77SSepherosa Ziehau 	}
316715516c77SSepherosa Ziehau 
316815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued",
316915516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
317015516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_queued),
317115516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
317215516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
317315516c77SSepherosa Ziehau #else
317415516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
317515516c77SSepherosa Ziehau #endif
317615516c77SSepherosa Ziehau 	    "LU", "LRO queued");
317715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed",
317815516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
317915516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_flushed),
318015516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
318115516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
318215516c77SSepherosa Ziehau #else
318315516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
318415516c77SSepherosa Ziehau #endif
318515516c77SSepherosa Ziehau 	    "LU", "LRO flushed");
318615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried",
318715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
318815516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro_tried),
318915516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries");
319015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
319115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim",
319215516c77SSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
319315516c77SSepherosa Ziehau 	    hn_lro_lenlim_sysctl, "IU",
319415516c77SSepherosa Ziehau 	    "Max # of data bytes to be aggregated by LRO");
319515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim",
319615516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
319715516c77SSepherosa Ziehau 	    hn_lro_ackcnt_sysctl, "I",
319815516c77SSepherosa Ziehau 	    "Max # of ACKs to be aggregated by LRO");
319915516c77SSepherosa Ziehau #endif
320015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp",
320115516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP,
320215516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
320315516c77SSepherosa Ziehau 	    "Trust tcp segement verification on host side, "
320415516c77SSepherosa Ziehau 	    "when csum info is missing");
320515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp",
320615516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP,
320715516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
320815516c77SSepherosa Ziehau 	    "Trust udp datagram verification on host side, "
320915516c77SSepherosa Ziehau 	    "when csum info is missing");
321015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip",
321115516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP,
321215516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
321315516c77SSepherosa Ziehau 	    "Trust ip packet verification on host side, "
321415516c77SSepherosa Ziehau 	    "when csum info is missing");
321515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip",
321615516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
321715516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_ip),
321815516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP");
321915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp",
322015516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
322115516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_tcp),
322215516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP");
322315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp",
322415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
322515516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_udp),
322615516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP");
322715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted",
322815516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
322915516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_trusted),
323015516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU",
323115516c77SSepherosa Ziehau 	    "# of packets that we trust host's csum verification");
323215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts",
323315516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
323415516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_small_pkts),
323515516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of small packets received");
323615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed",
323715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
323815516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_ack_failed),
323915516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures");
324015516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt",
324115516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings");
324215516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse",
324315516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings");
324415516c77SSepherosa Ziehau 
324515516c77SSepherosa Ziehau 	return (0);
324615516c77SSepherosa Ziehau }
324715516c77SSepherosa Ziehau 
324815516c77SSepherosa Ziehau static void
324915516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc)
325015516c77SSepherosa Ziehau {
325115516c77SSepherosa Ziehau 	int i;
325215516c77SSepherosa Ziehau 
325315516c77SSepherosa Ziehau 	if (sc->hn_rxbuf != NULL) {
32542494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0)
325515516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf);
32562494d735SSepherosa Ziehau 		else
32572494d735SSepherosa Ziehau 			device_printf(sc->hn_dev, "RXBUF is referenced\n");
325815516c77SSepherosa Ziehau 		sc->hn_rxbuf = NULL;
325915516c77SSepherosa Ziehau 	}
326015516c77SSepherosa Ziehau 
326115516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_cnt == 0)
326215516c77SSepherosa Ziehau 		return;
326315516c77SSepherosa Ziehau 
326415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
326515516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
326615516c77SSepherosa Ziehau 
326715516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL)
326815516c77SSepherosa Ziehau 			continue;
32692494d735SSepherosa Ziehau 		if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) {
327015516c77SSepherosa Ziehau 			hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br);
32712494d735SSepherosa Ziehau 		} else {
32722494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
32732494d735SSepherosa Ziehau 			    "%dth channel bufring is referenced", i);
32742494d735SSepherosa Ziehau 		}
327515516c77SSepherosa Ziehau 		rxr->hn_br = NULL;
327615516c77SSepherosa Ziehau 
327715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
327815516c77SSepherosa Ziehau 		tcp_lro_free(&rxr->hn_lro);
327915516c77SSepherosa Ziehau #endif
328015516c77SSepherosa Ziehau 		free(rxr->hn_pktbuf, M_DEVBUF);
328115516c77SSepherosa Ziehau 	}
328215516c77SSepherosa Ziehau 	free(sc->hn_rx_ring, M_DEVBUF);
328315516c77SSepherosa Ziehau 	sc->hn_rx_ring = NULL;
328415516c77SSepherosa Ziehau 
328515516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = 0;
328615516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = 0;
328715516c77SSepherosa Ziehau }
328815516c77SSepherosa Ziehau 
328915516c77SSepherosa Ziehau static int
329015516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id)
329115516c77SSepherosa Ziehau {
329215516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[id];
329315516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
329415516c77SSepherosa Ziehau 	bus_dma_tag_t parent_dtag;
329515516c77SSepherosa Ziehau 	int error, i;
329615516c77SSepherosa Ziehau 
329715516c77SSepherosa Ziehau 	txr->hn_sc = sc;
329815516c77SSepherosa Ziehau 	txr->hn_tx_idx = id;
329915516c77SSepherosa Ziehau 
330015516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
330115516c77SSepherosa Ziehau 	mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN);
330215516c77SSepherosa Ziehau #endif
330315516c77SSepherosa Ziehau 	mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF);
330415516c77SSepherosa Ziehau 
330515516c77SSepherosa Ziehau 	txr->hn_txdesc_cnt = HN_TX_DESC_CNT;
330615516c77SSepherosa Ziehau 	txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt,
330715516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
330815516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
330915516c77SSepherosa Ziehau 	SLIST_INIT(&txr->hn_txlist);
331015516c77SSepherosa Ziehau #else
331115516c77SSepherosa Ziehau 	txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF,
331215516c77SSepherosa Ziehau 	    M_WAITOK, &txr->hn_tx_lock);
331315516c77SSepherosa Ziehau #endif
331415516c77SSepherosa Ziehau 
3315*fdd0222aSSepherosa Ziehau 	txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt];
331615516c77SSepherosa Ziehau 
331723bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
331815516c77SSepherosa Ziehau 	if (hn_use_if_start) {
331915516c77SSepherosa Ziehau 		txr->hn_txeof = hn_start_txeof;
332015516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr);
332115516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr);
332223bf9e15SSepherosa Ziehau 	} else
332323bf9e15SSepherosa Ziehau #endif
332423bf9e15SSepherosa Ziehau 	{
332515516c77SSepherosa Ziehau 		int br_depth;
332615516c77SSepherosa Ziehau 
332715516c77SSepherosa Ziehau 		txr->hn_txeof = hn_xmit_txeof;
332815516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr);
332915516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr);
333015516c77SSepherosa Ziehau 
333115516c77SSepherosa Ziehau 		br_depth = hn_get_txswq_depth(txr);
333215516c77SSepherosa Ziehau 		txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF,
333315516c77SSepherosa Ziehau 		    M_WAITOK, &txr->hn_tx_lock);
333415516c77SSepherosa Ziehau 	}
333515516c77SSepherosa Ziehau 
333615516c77SSepherosa Ziehau 	txr->hn_direct_tx_size = hn_direct_tx_size;
333715516c77SSepherosa Ziehau 
333815516c77SSepherosa Ziehau 	/*
333915516c77SSepherosa Ziehau 	 * Always schedule transmission instead of trying to do direct
334015516c77SSepherosa Ziehau 	 * transmission.  This one gives the best performance so far.
334115516c77SSepherosa Ziehau 	 */
334215516c77SSepherosa Ziehau 	txr->hn_sched_tx = 1;
334315516c77SSepherosa Ziehau 
334415516c77SSepherosa Ziehau 	parent_dtag = bus_get_dma_tag(dev);
334515516c77SSepherosa Ziehau 
334615516c77SSepherosa Ziehau 	/* DMA tag for RNDIS packet messages. */
334715516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
334815516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_ALIGN,		/* alignment */
334915516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_BOUNDARY,	/* boundary */
335015516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
335115516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
335215516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
335315516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsize */
335415516c77SSepherosa Ziehau 	    1,				/* nsegments */
335515516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsegsize */
335615516c77SSepherosa Ziehau 	    0,				/* flags */
335715516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
335815516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
335915516c77SSepherosa Ziehau 	    &txr->hn_tx_rndis_dtag);
336015516c77SSepherosa Ziehau 	if (error) {
336115516c77SSepherosa Ziehau 		device_printf(dev, "failed to create rndis dmatag\n");
336215516c77SSepherosa Ziehau 		return error;
336315516c77SSepherosa Ziehau 	}
336415516c77SSepherosa Ziehau 
336515516c77SSepherosa Ziehau 	/* DMA tag for data. */
336615516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
336715516c77SSepherosa Ziehau 	    1,				/* alignment */
336815516c77SSepherosa Ziehau 	    HN_TX_DATA_BOUNDARY,	/* boundary */
336915516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
337015516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
337115516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
337215516c77SSepherosa Ziehau 	    HN_TX_DATA_MAXSIZE,		/* maxsize */
337315516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGCNT_MAX,	/* nsegments */
337415516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGSIZE,		/* maxsegsize */
337515516c77SSepherosa Ziehau 	    0,				/* flags */
337615516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
337715516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
337815516c77SSepherosa Ziehau 	    &txr->hn_tx_data_dtag);
337915516c77SSepherosa Ziehau 	if (error) {
338015516c77SSepherosa Ziehau 		device_printf(dev, "failed to create data dmatag\n");
338115516c77SSepherosa Ziehau 		return error;
338215516c77SSepherosa Ziehau 	}
338315516c77SSepherosa Ziehau 
338415516c77SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i) {
338515516c77SSepherosa Ziehau 		struct hn_txdesc *txd = &txr->hn_txdesc[i];
338615516c77SSepherosa Ziehau 
338715516c77SSepherosa Ziehau 		txd->txr = txr;
338815516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
3389dc13fee6SSepherosa Ziehau 		STAILQ_INIT(&txd->agg_list);
339015516c77SSepherosa Ziehau 
339115516c77SSepherosa Ziehau 		/*
339215516c77SSepherosa Ziehau 		 * Allocate and load RNDIS packet message.
339315516c77SSepherosa Ziehau 		 */
339415516c77SSepherosa Ziehau         	error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag,
339515516c77SSepherosa Ziehau 		    (void **)&txd->rndis_pkt,
339615516c77SSepherosa Ziehau 		    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
339715516c77SSepherosa Ziehau 		    &txd->rndis_pkt_dmap);
339815516c77SSepherosa Ziehau 		if (error) {
339915516c77SSepherosa Ziehau 			device_printf(dev,
340015516c77SSepherosa Ziehau 			    "failed to allocate rndis_packet_msg, %d\n", i);
340115516c77SSepherosa Ziehau 			return error;
340215516c77SSepherosa Ziehau 		}
340315516c77SSepherosa Ziehau 
340415516c77SSepherosa Ziehau 		error = bus_dmamap_load(txr->hn_tx_rndis_dtag,
340515516c77SSepherosa Ziehau 		    txd->rndis_pkt_dmap,
340615516c77SSepherosa Ziehau 		    txd->rndis_pkt, HN_RNDIS_PKT_LEN,
340715516c77SSepherosa Ziehau 		    hyperv_dma_map_paddr, &txd->rndis_pkt_paddr,
340815516c77SSepherosa Ziehau 		    BUS_DMA_NOWAIT);
340915516c77SSepherosa Ziehau 		if (error) {
341015516c77SSepherosa Ziehau 			device_printf(dev,
341115516c77SSepherosa Ziehau 			    "failed to load rndis_packet_msg, %d\n", i);
341215516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
341315516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
341415516c77SSepherosa Ziehau 			return error;
341515516c77SSepherosa Ziehau 		}
341615516c77SSepherosa Ziehau 
341715516c77SSepherosa Ziehau 		/* DMA map for TX data. */
341815516c77SSepherosa Ziehau 		error = bus_dmamap_create(txr->hn_tx_data_dtag, 0,
341915516c77SSepherosa Ziehau 		    &txd->data_dmap);
342015516c77SSepherosa Ziehau 		if (error) {
342115516c77SSepherosa Ziehau 			device_printf(dev,
342215516c77SSepherosa Ziehau 			    "failed to allocate tx data dmamap\n");
342315516c77SSepherosa Ziehau 			bus_dmamap_unload(txr->hn_tx_rndis_dtag,
342415516c77SSepherosa Ziehau 			    txd->rndis_pkt_dmap);
342515516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
342615516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
342715516c77SSepherosa Ziehau 			return error;
342815516c77SSepherosa Ziehau 		}
342915516c77SSepherosa Ziehau 
343015516c77SSepherosa Ziehau 		/* All set, put it to list */
343115516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_ONLIST;
343215516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
343315516c77SSepherosa Ziehau 		SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
343415516c77SSepherosa Ziehau #else
343515516c77SSepherosa Ziehau 		buf_ring_enqueue(txr->hn_txdesc_br, txd);
343615516c77SSepherosa Ziehau #endif
343715516c77SSepherosa Ziehau 	}
343815516c77SSepherosa Ziehau 	txr->hn_txdesc_avail = txr->hn_txdesc_cnt;
343915516c77SSepherosa Ziehau 
344015516c77SSepherosa Ziehau 	if (sc->hn_tx_sysctl_tree != NULL) {
344115516c77SSepherosa Ziehau 		struct sysctl_oid_list *child;
344215516c77SSepherosa Ziehau 		struct sysctl_ctx_list *ctx;
344315516c77SSepherosa Ziehau 		char name[16];
344415516c77SSepherosa Ziehau 
344515516c77SSepherosa Ziehau 		/*
344615516c77SSepherosa Ziehau 		 * Create per TX ring sysctl tree:
344715516c77SSepherosa Ziehau 		 * dev.hn.UNIT.tx.RINGID
344815516c77SSepherosa Ziehau 		 */
344915516c77SSepherosa Ziehau 		ctx = device_get_sysctl_ctx(dev);
345015516c77SSepherosa Ziehau 		child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree);
345115516c77SSepherosa Ziehau 
345215516c77SSepherosa Ziehau 		snprintf(name, sizeof(name), "%d", id);
345315516c77SSepherosa Ziehau 		txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
345415516c77SSepherosa Ziehau 		    name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
345515516c77SSepherosa Ziehau 
345615516c77SSepherosa Ziehau 		if (txr->hn_tx_sysctl_tree != NULL) {
345715516c77SSepherosa Ziehau 			child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree);
345815516c77SSepherosa Ziehau 
345915516c77SSepherosa Ziehau 			SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail",
346015516c77SSepherosa Ziehau 			    CTLFLAG_RD, &txr->hn_txdesc_avail, 0,
346115516c77SSepherosa Ziehau 			    "# of available TX descs");
346223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
346323bf9e15SSepherosa Ziehau 			if (!hn_use_if_start)
346423bf9e15SSepherosa Ziehau #endif
346523bf9e15SSepherosa Ziehau 			{
346615516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive",
346715516c77SSepherosa Ziehau 				    CTLFLAG_RD, &txr->hn_oactive, 0,
346815516c77SSepherosa Ziehau 				    "over active");
346915516c77SSepherosa Ziehau 			}
347015516c77SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets",
347115516c77SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_pkts,
347215516c77SSepherosa Ziehau 			    "# of packets transmitted");
3473dc13fee6SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends",
3474dc13fee6SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_sends, "# of sends");
347515516c77SSepherosa Ziehau 		}
347615516c77SSepherosa Ziehau 	}
347715516c77SSepherosa Ziehau 
347815516c77SSepherosa Ziehau 	return 0;
347915516c77SSepherosa Ziehau }
348015516c77SSepherosa Ziehau 
348115516c77SSepherosa Ziehau static void
348215516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd)
348315516c77SSepherosa Ziehau {
348415516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = txd->txr;
348515516c77SSepherosa Ziehau 
348615516c77SSepherosa Ziehau 	KASSERT(txd->m == NULL, ("still has mbuf installed"));
348715516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped"));
348815516c77SSepherosa Ziehau 
348915516c77SSepherosa Ziehau 	bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap);
349015516c77SSepherosa Ziehau 	bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt,
349115516c77SSepherosa Ziehau 	    txd->rndis_pkt_dmap);
349215516c77SSepherosa Ziehau 	bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap);
349315516c77SSepherosa Ziehau }
349415516c77SSepherosa Ziehau 
349515516c77SSepherosa Ziehau static void
349625641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd)
349725641fc7SSepherosa Ziehau {
349825641fc7SSepherosa Ziehau 
349925641fc7SSepherosa Ziehau 	KASSERT(txd->refs == 0 || txd->refs == 1,
350025641fc7SSepherosa Ziehau 	    ("invalid txd refs %d", txd->refs));
350125641fc7SSepherosa Ziehau 
350225641fc7SSepherosa Ziehau 	/* Aggregated txds will be freed by their aggregating txd. */
350325641fc7SSepherosa Ziehau 	if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) {
350425641fc7SSepherosa Ziehau 		int freed;
350525641fc7SSepherosa Ziehau 
350625641fc7SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
350725641fc7SSepherosa Ziehau 		KASSERT(freed, ("can't free txdesc"));
350825641fc7SSepherosa Ziehau 	}
350925641fc7SSepherosa Ziehau }
351025641fc7SSepherosa Ziehau 
351125641fc7SSepherosa Ziehau static void
351215516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr)
351315516c77SSepherosa Ziehau {
351425641fc7SSepherosa Ziehau 	int i;
351515516c77SSepherosa Ziehau 
351615516c77SSepherosa Ziehau 	if (txr->hn_txdesc == NULL)
351715516c77SSepherosa Ziehau 		return;
351815516c77SSepherosa Ziehau 
351925641fc7SSepherosa Ziehau 	/*
352025641fc7SSepherosa Ziehau 	 * NOTE:
352125641fc7SSepherosa Ziehau 	 * Because the freeing of aggregated txds will be deferred
352225641fc7SSepherosa Ziehau 	 * to the aggregating txd, two passes are used here:
352325641fc7SSepherosa Ziehau 	 * - The first pass GCes any pending txds.  This GC is necessary,
352425641fc7SSepherosa Ziehau 	 *   since if the channels are revoked, hypervisor will not
352525641fc7SSepherosa Ziehau 	 *   deliver send-done for all pending txds.
352625641fc7SSepherosa Ziehau 	 * - The second pass frees the busdma stuffs, i.e. after all txds
352725641fc7SSepherosa Ziehau 	 *   were freed.
352825641fc7SSepherosa Ziehau 	 */
352925641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
353025641fc7SSepherosa Ziehau 		hn_txdesc_gc(txr, &txr->hn_txdesc[i]);
353125641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
353225641fc7SSepherosa Ziehau 		hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]);
353315516c77SSepherosa Ziehau 
353415516c77SSepherosa Ziehau 	if (txr->hn_tx_data_dtag != NULL)
353515516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_data_dtag);
353615516c77SSepherosa Ziehau 	if (txr->hn_tx_rndis_dtag != NULL)
353715516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_rndis_dtag);
353815516c77SSepherosa Ziehau 
353915516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
354015516c77SSepherosa Ziehau 	buf_ring_free(txr->hn_txdesc_br, M_DEVBUF);
354115516c77SSepherosa Ziehau #endif
354215516c77SSepherosa Ziehau 
354315516c77SSepherosa Ziehau 	free(txr->hn_txdesc, M_DEVBUF);
354415516c77SSepherosa Ziehau 	txr->hn_txdesc = NULL;
354515516c77SSepherosa Ziehau 
354615516c77SSepherosa Ziehau 	if (txr->hn_mbuf_br != NULL)
354715516c77SSepherosa Ziehau 		buf_ring_free(txr->hn_mbuf_br, M_DEVBUF);
354815516c77SSepherosa Ziehau 
354915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
355015516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_txlist_spin);
355115516c77SSepherosa Ziehau #endif
355215516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_tx_lock);
355315516c77SSepherosa Ziehau }
355415516c77SSepherosa Ziehau 
355515516c77SSepherosa Ziehau static int
355615516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt)
355715516c77SSepherosa Ziehau {
355815516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
355915516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
356015516c77SSepherosa Ziehau 	int i;
356115516c77SSepherosa Ziehau 
356215516c77SSepherosa Ziehau 	/*
356315516c77SSepherosa Ziehau 	 * Create TXBUF for chimney sending.
356415516c77SSepherosa Ziehau 	 *
356515516c77SSepherosa Ziehau 	 * NOTE: It is shared by all channels.
356615516c77SSepherosa Ziehau 	 */
356715516c77SSepherosa Ziehau 	sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev),
356815516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma,
356915516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
357015516c77SSepherosa Ziehau 	if (sc->hn_chim == NULL) {
357115516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate txbuf failed\n");
357215516c77SSepherosa Ziehau 		return (ENOMEM);
357315516c77SSepherosa Ziehau 	}
357415516c77SSepherosa Ziehau 
357515516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = ring_cnt;
357615516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
357715516c77SSepherosa Ziehau 
357815516c77SSepherosa Ziehau 	sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt,
357915516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
358015516c77SSepherosa Ziehau 
358115516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(sc->hn_dev);
358215516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev));
358315516c77SSepherosa Ziehau 
358415516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.tx sysctl tree */
358515516c77SSepherosa Ziehau 	sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx",
358615516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
358715516c77SSepherosa Ziehau 
358815516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
358915516c77SSepherosa Ziehau 		int error;
359015516c77SSepherosa Ziehau 
359115516c77SSepherosa Ziehau 		error = hn_tx_ring_create(sc, i);
359215516c77SSepherosa Ziehau 		if (error)
359315516c77SSepherosa Ziehau 			return error;
359415516c77SSepherosa Ziehau 	}
359515516c77SSepherosa Ziehau 
359615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs",
359715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
359815516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_no_txdescs),
359915516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs");
360015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed",
360115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
360215516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_send_failed),
360315516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure");
360415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed",
360515516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
360615516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_txdma_failed),
360715516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure");
3608dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed",
3609dc13fee6SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
3610dc13fee6SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_flush_failed),
3611dc13fee6SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU",
3612dc13fee6SSepherosa Ziehau 	    "# of packet transmission aggregation flush failure");
361315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed",
361415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
361515516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_collapsed),
361615516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed");
361715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney",
361815516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
361915516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney),
362015516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send");
362115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried",
362215516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
362315516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney_tried),
362415516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries");
362515516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt",
362615516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0,
362715516c77SSepherosa Ziehau 	    "# of total TX descs");
362815516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max",
362915516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_chim_szmax, 0,
363015516c77SSepherosa Ziehau 	    "Chimney send packet size upper boundary");
363115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size",
363215516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
363315516c77SSepherosa Ziehau 	    hn_chim_size_sysctl, "I", "Chimney send packet size limit");
363415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size",
363515516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
363615516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_direct_tx_size),
363715516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
363815516c77SSepherosa Ziehau 	    "Size of the packet for direct transmission");
363915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx",
364015516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
364115516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_sched_tx),
364215516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
364315516c77SSepherosa Ziehau 	    "Always schedule transmission "
364415516c77SSepherosa Ziehau 	    "instead of doing direct transmission");
364515516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt",
364615516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings");
364715516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse",
364815516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings");
3649dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax",
3650dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0,
3651dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation size");
3652dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax",
3653dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
3654dc13fee6SSepherosa Ziehau 	    hn_txagg_pktmax_sysctl, "I",
3655dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation packets");
3656dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align",
3657dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
3658dc13fee6SSepherosa Ziehau 	    hn_txagg_align_sysctl, "I",
3659dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation alignment");
366015516c77SSepherosa Ziehau 
366115516c77SSepherosa Ziehau 	return 0;
366215516c77SSepherosa Ziehau }
366315516c77SSepherosa Ziehau 
366415516c77SSepherosa Ziehau static void
366515516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size)
366615516c77SSepherosa Ziehau {
366715516c77SSepherosa Ziehau 	int i;
366815516c77SSepherosa Ziehau 
3669a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
367015516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_chim_size = chim_size;
367115516c77SSepherosa Ziehau }
367215516c77SSepherosa Ziehau 
367315516c77SSepherosa Ziehau static void
367415516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu)
367515516c77SSepherosa Ziehau {
367615516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
367715516c77SSepherosa Ziehau 	int tso_minlen;
367815516c77SSepherosa Ziehau 
367915516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0)
368015516c77SSepherosa Ziehau 		return;
368115516c77SSepherosa Ziehau 
368215516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_sgmin >= 2,
368315516c77SSepherosa Ziehau 	    ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin));
368415516c77SSepherosa Ziehau 	tso_minlen = sc->hn_ndis_tso_sgmin * mtu;
368515516c77SSepherosa Ziehau 
368615516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen &&
368715516c77SSepherosa Ziehau 	    sc->hn_ndis_tso_szmax <= IP_MAXPACKET,
368815516c77SSepherosa Ziehau 	    ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax));
368915516c77SSepherosa Ziehau 
369015516c77SSepherosa Ziehau 	if (tso_maxlen < tso_minlen)
369115516c77SSepherosa Ziehau 		tso_maxlen = tso_minlen;
369215516c77SSepherosa Ziehau 	else if (tso_maxlen > IP_MAXPACKET)
369315516c77SSepherosa Ziehau 		tso_maxlen = IP_MAXPACKET;
369415516c77SSepherosa Ziehau 	if (tso_maxlen > sc->hn_ndis_tso_szmax)
369515516c77SSepherosa Ziehau 		tso_maxlen = sc->hn_ndis_tso_szmax;
369615516c77SSepherosa Ziehau 	ifp->if_hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
369715516c77SSepherosa Ziehau 	if (bootverbose)
369815516c77SSepherosa Ziehau 		if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax);
369915516c77SSepherosa Ziehau }
370015516c77SSepherosa Ziehau 
370115516c77SSepherosa Ziehau static void
370215516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc)
370315516c77SSepherosa Ziehau {
370415516c77SSepherosa Ziehau 	uint64_t csum_assist;
370515516c77SSepherosa Ziehau 	int i;
370615516c77SSepherosa Ziehau 
370715516c77SSepherosa Ziehau 	hn_set_chim_size(sc, sc->hn_chim_szmax);
370815516c77SSepherosa Ziehau 	if (hn_tx_chimney_size > 0 &&
370915516c77SSepherosa Ziehau 	    hn_tx_chimney_size < sc->hn_chim_szmax)
371015516c77SSepherosa Ziehau 		hn_set_chim_size(sc, hn_tx_chimney_size);
371115516c77SSepherosa Ziehau 
371215516c77SSepherosa Ziehau 	csum_assist = 0;
371315516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_IPCS)
371415516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP;
371515516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP4CS)
371615516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_TCP;
371715516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP4CS)
371815516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_UDP;
371915516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP6CS)
372015516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_TCP;
372115516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP6CS)
372215516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_UDP;
372315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
372415516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_csum_assist = csum_assist;
372515516c77SSepherosa Ziehau 
372615516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_HASHVAL) {
372715516c77SSepherosa Ziehau 		/*
372815516c77SSepherosa Ziehau 		 * Support HASHVAL pktinfo on TX path.
372915516c77SSepherosa Ziehau 		 */
373015516c77SSepherosa Ziehau 		if (bootverbose)
373115516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n");
373215516c77SSepherosa Ziehau 		for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
373315516c77SSepherosa Ziehau 			sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL;
373415516c77SSepherosa Ziehau 	}
373515516c77SSepherosa Ziehau }
373615516c77SSepherosa Ziehau 
373715516c77SSepherosa Ziehau static void
373815516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc)
373915516c77SSepherosa Ziehau {
374015516c77SSepherosa Ziehau 	int i;
374115516c77SSepherosa Ziehau 
374215516c77SSepherosa Ziehau 	if (sc->hn_chim != NULL) {
37432494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) {
374415516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim);
37452494d735SSepherosa Ziehau 		} else {
37462494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
37472494d735SSepherosa Ziehau 			    "chimney sending buffer is referenced");
37482494d735SSepherosa Ziehau 		}
374915516c77SSepherosa Ziehau 		sc->hn_chim = NULL;
375015516c77SSepherosa Ziehau 	}
375115516c77SSepherosa Ziehau 
375215516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt == 0)
375315516c77SSepherosa Ziehau 		return;
375415516c77SSepherosa Ziehau 
375515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
375615516c77SSepherosa Ziehau 		hn_tx_ring_destroy(&sc->hn_tx_ring[i]);
375715516c77SSepherosa Ziehau 
375815516c77SSepherosa Ziehau 	free(sc->hn_tx_ring, M_DEVBUF);
375915516c77SSepherosa Ziehau 	sc->hn_tx_ring = NULL;
376015516c77SSepherosa Ziehau 
376115516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = 0;
376215516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = 0;
376315516c77SSepherosa Ziehau }
376415516c77SSepherosa Ziehau 
376523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
376623bf9e15SSepherosa Ziehau 
376715516c77SSepherosa Ziehau static void
376815516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused)
376915516c77SSepherosa Ziehau {
377015516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
377115516c77SSepherosa Ziehau 
377215516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
377315516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
377415516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
377515516c77SSepherosa Ziehau }
377615516c77SSepherosa Ziehau 
377723bf9e15SSepherosa Ziehau static int
377823bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len)
377923bf9e15SSepherosa Ziehau {
378023bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
378123bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
3782dc13fee6SSepherosa Ziehau 	int sched = 0;
378323bf9e15SSepherosa Ziehau 
378423bf9e15SSepherosa Ziehau 	KASSERT(hn_use_if_start,
378523bf9e15SSepherosa Ziehau 	    ("hn_start_locked is called, when if_start is disabled"));
378623bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
378723bf9e15SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
3788dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
378923bf9e15SSepherosa Ziehau 
379023bf9e15SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
3791dc13fee6SSepherosa Ziehau 		return (0);
379223bf9e15SSepherosa Ziehau 
379323bf9e15SSepherosa Ziehau 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
379423bf9e15SSepherosa Ziehau 	    IFF_DRV_RUNNING)
3795dc13fee6SSepherosa Ziehau 		return (0);
379623bf9e15SSepherosa Ziehau 
379723bf9e15SSepherosa Ziehau 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
379823bf9e15SSepherosa Ziehau 		struct hn_txdesc *txd;
379923bf9e15SSepherosa Ziehau 		struct mbuf *m_head;
380023bf9e15SSepherosa Ziehau 		int error;
380123bf9e15SSepherosa Ziehau 
380223bf9e15SSepherosa Ziehau 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
380323bf9e15SSepherosa Ziehau 		if (m_head == NULL)
380423bf9e15SSepherosa Ziehau 			break;
380523bf9e15SSepherosa Ziehau 
380623bf9e15SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
380723bf9e15SSepherosa Ziehau 			/*
380823bf9e15SSepherosa Ziehau 			 * This sending could be time consuming; let callers
380923bf9e15SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
381023bf9e15SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
381123bf9e15SSepherosa Ziehau 			 */
381223bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
3813dc13fee6SSepherosa Ziehau 			sched = 1;
3814dc13fee6SSepherosa Ziehau 			break;
381523bf9e15SSepherosa Ziehau 		}
381623bf9e15SSepherosa Ziehau 
3817edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
3818edd3f315SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
3819edd3f315SSepherosa Ziehau 			m_head = hn_tso_fixup(m_head);
3820edd3f315SSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
3821edd3f315SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
3822edd3f315SSepherosa Ziehau 				continue;
3823edd3f315SSepherosa Ziehau 			}
3824edd3f315SSepherosa Ziehau 		}
3825edd3f315SSepherosa Ziehau #endif
3826edd3f315SSepherosa Ziehau 
382723bf9e15SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
382823bf9e15SSepherosa Ziehau 		if (txd == NULL) {
382923bf9e15SSepherosa Ziehau 			txr->hn_no_txdescs++;
383023bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
383123bf9e15SSepherosa Ziehau 			atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
383223bf9e15SSepherosa Ziehau 			break;
383323bf9e15SSepherosa Ziehau 		}
383423bf9e15SSepherosa Ziehau 
3835dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
383623bf9e15SSepherosa Ziehau 		if (error) {
383723bf9e15SSepherosa Ziehau 			/* Both txd and m_head are freed */
3838dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
3839dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
384023bf9e15SSepherosa Ziehau 			continue;
384123bf9e15SSepherosa Ziehau 		}
384223bf9e15SSepherosa Ziehau 
3843dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
3844dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
3845dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
3846dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
3847dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
3848dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
3849dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
3850dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
3851dc13fee6SSepherosa Ziehau 					break;
3852dc13fee6SSepherosa Ziehau 				}
3853dc13fee6SSepherosa Ziehau 			} else {
3854dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
385523bf9e15SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
385623bf9e15SSepherosa Ziehau 				if (__predict_false(error)) {
385723bf9e15SSepherosa Ziehau 					/* txd is freed, but m_head is not */
385823bf9e15SSepherosa Ziehau 					IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
3859dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
3860dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
386123bf9e15SSepherosa Ziehau 					break;
386223bf9e15SSepherosa Ziehau 				}
386323bf9e15SSepherosa Ziehau 			}
3864dc13fee6SSepherosa Ziehau 		}
3865dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
3866dc13fee6SSepherosa Ziehau 		else {
3867dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
3868dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
3869dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
3870dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
3871dc13fee6SSepherosa Ziehau 		}
3872dc13fee6SSepherosa Ziehau #endif
3873dc13fee6SSepherosa Ziehau 	}
3874dc13fee6SSepherosa Ziehau 
3875dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
3876dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
3877dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
3878dc13fee6SSepherosa Ziehau 	return (sched);
387923bf9e15SSepherosa Ziehau }
388023bf9e15SSepherosa Ziehau 
388123bf9e15SSepherosa Ziehau static void
388223bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp)
388323bf9e15SSepherosa Ziehau {
388423bf9e15SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
388523bf9e15SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[0];
388623bf9e15SSepherosa Ziehau 
388723bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
388823bf9e15SSepherosa Ziehau 		goto do_sched;
388923bf9e15SSepherosa Ziehau 
389023bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
389123bf9e15SSepherosa Ziehau 		int sched;
389223bf9e15SSepherosa Ziehau 
389323bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
389423bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
389523bf9e15SSepherosa Ziehau 		if (!sched)
389623bf9e15SSepherosa Ziehau 			return;
389723bf9e15SSepherosa Ziehau 	}
389823bf9e15SSepherosa Ziehau do_sched:
389923bf9e15SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
390023bf9e15SSepherosa Ziehau }
390123bf9e15SSepherosa Ziehau 
390215516c77SSepherosa Ziehau static void
390315516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused)
390415516c77SSepherosa Ziehau {
390515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
390615516c77SSepherosa Ziehau 
390715516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
390815516c77SSepherosa Ziehau 	atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE);
390915516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
391015516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
391115516c77SSepherosa Ziehau }
391215516c77SSepherosa Ziehau 
391323bf9e15SSepherosa Ziehau static void
391423bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr)
391523bf9e15SSepherosa Ziehau {
391623bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
391723bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
391823bf9e15SSepherosa Ziehau 
391923bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
392023bf9e15SSepherosa Ziehau 
392123bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
392223bf9e15SSepherosa Ziehau 		goto do_sched;
392323bf9e15SSepherosa Ziehau 
392423bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
392523bf9e15SSepherosa Ziehau 		int sched;
392623bf9e15SSepherosa Ziehau 
392723bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
392823bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
392923bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
393023bf9e15SSepherosa Ziehau 		if (sched) {
393123bf9e15SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
393223bf9e15SSepherosa Ziehau 			    &txr->hn_tx_task);
393323bf9e15SSepherosa Ziehau 		}
393423bf9e15SSepherosa Ziehau 	} else {
393523bf9e15SSepherosa Ziehau do_sched:
393623bf9e15SSepherosa Ziehau 		/*
393723bf9e15SSepherosa Ziehau 		 * Release the OACTIVE earlier, with the hope, that
393823bf9e15SSepherosa Ziehau 		 * others could catch up.  The task will clear the
393923bf9e15SSepherosa Ziehau 		 * flag again with the hn_tx_lock to avoid possible
394023bf9e15SSepherosa Ziehau 		 * races.
394123bf9e15SSepherosa Ziehau 		 */
394223bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
394323bf9e15SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
394423bf9e15SSepherosa Ziehau 	}
394523bf9e15SSepherosa Ziehau }
394623bf9e15SSepherosa Ziehau 
394723bf9e15SSepherosa Ziehau #endif	/* HN_IFSTART_SUPPORT */
394823bf9e15SSepherosa Ziehau 
394915516c77SSepherosa Ziehau static int
395015516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len)
395115516c77SSepherosa Ziehau {
395215516c77SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
395315516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
395415516c77SSepherosa Ziehau 	struct mbuf *m_head;
3955dc13fee6SSepherosa Ziehau 	int sched = 0;
395615516c77SSepherosa Ziehau 
395715516c77SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
395823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
395915516c77SSepherosa Ziehau 	KASSERT(hn_use_if_start == 0,
396015516c77SSepherosa Ziehau 	    ("hn_xmit is called, when if_start is enabled"));
396123bf9e15SSepherosa Ziehau #endif
3962dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
396315516c77SSepherosa Ziehau 
396415516c77SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
3965dc13fee6SSepherosa Ziehau 		return (0);
396615516c77SSepherosa Ziehau 
396715516c77SSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive)
3968dc13fee6SSepherosa Ziehau 		return (0);
396915516c77SSepherosa Ziehau 
397015516c77SSepherosa Ziehau 	while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) {
397115516c77SSepherosa Ziehau 		struct hn_txdesc *txd;
397215516c77SSepherosa Ziehau 		int error;
397315516c77SSepherosa Ziehau 
397415516c77SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
397515516c77SSepherosa Ziehau 			/*
397615516c77SSepherosa Ziehau 			 * This sending could be time consuming; let callers
397715516c77SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
397815516c77SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
397915516c77SSepherosa Ziehau 			 */
398015516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
3981dc13fee6SSepherosa Ziehau 			sched = 1;
3982dc13fee6SSepherosa Ziehau 			break;
398315516c77SSepherosa Ziehau 		}
398415516c77SSepherosa Ziehau 
398515516c77SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
398615516c77SSepherosa Ziehau 		if (txd == NULL) {
398715516c77SSepherosa Ziehau 			txr->hn_no_txdescs++;
398815516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
398915516c77SSepherosa Ziehau 			txr->hn_oactive = 1;
399015516c77SSepherosa Ziehau 			break;
399115516c77SSepherosa Ziehau 		}
399215516c77SSepherosa Ziehau 
3993dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
399415516c77SSepherosa Ziehau 		if (error) {
399515516c77SSepherosa Ziehau 			/* Both txd and m_head are freed; discard */
3996dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
3997dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
399815516c77SSepherosa Ziehau 			drbr_advance(ifp, txr->hn_mbuf_br);
399915516c77SSepherosa Ziehau 			continue;
400015516c77SSepherosa Ziehau 		}
400115516c77SSepherosa Ziehau 
4002dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
4003dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
4004dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
4005dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
4006dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
400715516c77SSepherosa Ziehau 				if (__predict_false(error)) {
400815516c77SSepherosa Ziehau 					txr->hn_oactive = 1;
400915516c77SSepherosa Ziehau 					break;
401015516c77SSepherosa Ziehau 				}
4011dc13fee6SSepherosa Ziehau 			} else {
4012dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
4013dc13fee6SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
4014dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
4015dc13fee6SSepherosa Ziehau 					/* txd is freed, but m_head is not */
4016dc13fee6SSepherosa Ziehau 					drbr_putback(ifp, txr->hn_mbuf_br,
4017dc13fee6SSepherosa Ziehau 					    m_head);
4018dc13fee6SSepherosa Ziehau 					txr->hn_oactive = 1;
4019dc13fee6SSepherosa Ziehau 					break;
4020dc13fee6SSepherosa Ziehau 				}
4021dc13fee6SSepherosa Ziehau 			}
4022dc13fee6SSepherosa Ziehau 		}
4023dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
4024dc13fee6SSepherosa Ziehau 		else {
4025dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
4026dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
4027dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
4028dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
4029dc13fee6SSepherosa Ziehau 		}
4030dc13fee6SSepherosa Ziehau #endif
403115516c77SSepherosa Ziehau 
403215516c77SSepherosa Ziehau 		/* Sent */
403315516c77SSepherosa Ziehau 		drbr_advance(ifp, txr->hn_mbuf_br);
403415516c77SSepherosa Ziehau 	}
4035dc13fee6SSepherosa Ziehau 
4036dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
4037dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
4038dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
4039dc13fee6SSepherosa Ziehau 	return (sched);
404015516c77SSepherosa Ziehau }
404115516c77SSepherosa Ziehau 
404215516c77SSepherosa Ziehau static int
404315516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m)
404415516c77SSepherosa Ziehau {
404515516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
404615516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
404715516c77SSepherosa Ziehau 	int error, idx = 0;
404815516c77SSepherosa Ziehau 
4049edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
4050edd3f315SSepherosa Ziehau 	/*
4051edd3f315SSepherosa Ziehau 	 * Perform TSO packet header fixup now, since the TSO
4052edd3f315SSepherosa Ziehau 	 * packet header should be cache-hot.
4053edd3f315SSepherosa Ziehau 	 */
4054edd3f315SSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
4055edd3f315SSepherosa Ziehau 		m = hn_tso_fixup(m);
4056edd3f315SSepherosa Ziehau 		if (__predict_false(m == NULL)) {
4057edd3f315SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
4058edd3f315SSepherosa Ziehau 			return EIO;
4059edd3f315SSepherosa Ziehau 		}
4060edd3f315SSepherosa Ziehau 	}
4061edd3f315SSepherosa Ziehau #endif
4062edd3f315SSepherosa Ziehau 
406315516c77SSepherosa Ziehau 	/*
406415516c77SSepherosa Ziehau 	 * Select the TX ring based on flowid
406515516c77SSepherosa Ziehau 	 */
406615516c77SSepherosa Ziehau 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
406715516c77SSepherosa Ziehau 		idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse;
406815516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[idx];
406915516c77SSepherosa Ziehau 
407015516c77SSepherosa Ziehau 	error = drbr_enqueue(ifp, txr->hn_mbuf_br, m);
407115516c77SSepherosa Ziehau 	if (error) {
407215516c77SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
407315516c77SSepherosa Ziehau 		return error;
407415516c77SSepherosa Ziehau 	}
407515516c77SSepherosa Ziehau 
407615516c77SSepherosa Ziehau 	if (txr->hn_oactive)
407715516c77SSepherosa Ziehau 		return 0;
407815516c77SSepherosa Ziehau 
407915516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
408015516c77SSepherosa Ziehau 		goto do_sched;
408115516c77SSepherosa Ziehau 
408215516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
408315516c77SSepherosa Ziehau 		int sched;
408415516c77SSepherosa Ziehau 
408515516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
408615516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
408715516c77SSepherosa Ziehau 		if (!sched)
408815516c77SSepherosa Ziehau 			return 0;
408915516c77SSepherosa Ziehau 	}
409015516c77SSepherosa Ziehau do_sched:
409115516c77SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
409215516c77SSepherosa Ziehau 	return 0;
409315516c77SSepherosa Ziehau }
409415516c77SSepherosa Ziehau 
409515516c77SSepherosa Ziehau static void
409615516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr)
409715516c77SSepherosa Ziehau {
409815516c77SSepherosa Ziehau 	struct mbuf *m;
409915516c77SSepherosa Ziehau 
410015516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
410115516c77SSepherosa Ziehau 	while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL)
410215516c77SSepherosa Ziehau 		m_freem(m);
410315516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
410415516c77SSepherosa Ziehau }
410515516c77SSepherosa Ziehau 
410615516c77SSepherosa Ziehau static void
410715516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp)
410815516c77SSepherosa Ziehau {
410915516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
411015516c77SSepherosa Ziehau 	int i;
411115516c77SSepherosa Ziehau 
411215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
411315516c77SSepherosa Ziehau 		hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
411415516c77SSepherosa Ziehau 	if_qflush(ifp);
411515516c77SSepherosa Ziehau }
411615516c77SSepherosa Ziehau 
411715516c77SSepherosa Ziehau static void
411815516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr)
411915516c77SSepherosa Ziehau {
412015516c77SSepherosa Ziehau 
412115516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
412215516c77SSepherosa Ziehau 		goto do_sched;
412315516c77SSepherosa Ziehau 
412415516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
412515516c77SSepherosa Ziehau 		int sched;
412615516c77SSepherosa Ziehau 
412715516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
412815516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
412915516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
413015516c77SSepherosa Ziehau 		if (sched) {
413115516c77SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
413215516c77SSepherosa Ziehau 			    &txr->hn_tx_task);
413315516c77SSepherosa Ziehau 		}
413415516c77SSepherosa Ziehau 	} else {
413515516c77SSepherosa Ziehau do_sched:
413615516c77SSepherosa Ziehau 		/*
413715516c77SSepherosa Ziehau 		 * Release the oactive earlier, with the hope, that
413815516c77SSepherosa Ziehau 		 * others could catch up.  The task will clear the
413915516c77SSepherosa Ziehau 		 * oactive again with the hn_tx_lock to avoid possible
414015516c77SSepherosa Ziehau 		 * races.
414115516c77SSepherosa Ziehau 		 */
414215516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
414315516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
414415516c77SSepherosa Ziehau 	}
414515516c77SSepherosa Ziehau }
414615516c77SSepherosa Ziehau 
414715516c77SSepherosa Ziehau static void
414815516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused)
414915516c77SSepherosa Ziehau {
415015516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
415115516c77SSepherosa Ziehau 
415215516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
415315516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
415415516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
415515516c77SSepherosa Ziehau }
415615516c77SSepherosa Ziehau 
415715516c77SSepherosa Ziehau static void
415815516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused)
415915516c77SSepherosa Ziehau {
416015516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
416115516c77SSepherosa Ziehau 
416215516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
416315516c77SSepherosa Ziehau 	txr->hn_oactive = 0;
416415516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
416515516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
416615516c77SSepherosa Ziehau }
416715516c77SSepherosa Ziehau 
416815516c77SSepherosa Ziehau static int
416915516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan)
417015516c77SSepherosa Ziehau {
417115516c77SSepherosa Ziehau 	struct vmbus_chan_br cbr;
417215516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
417315516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = NULL;
417415516c77SSepherosa Ziehau 	int idx, error;
417515516c77SSepherosa Ziehau 
417615516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
417715516c77SSepherosa Ziehau 
417815516c77SSepherosa Ziehau 	/*
417915516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
418015516c77SSepherosa Ziehau 	 */
418115516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
418215516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
418315516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
418415516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
418515516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0,
418615516c77SSepherosa Ziehau 	    ("RX ring %d already attached", idx));
418715516c77SSepherosa Ziehau 	rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED;
418815516c77SSepherosa Ziehau 
418915516c77SSepherosa Ziehau 	if (bootverbose) {
419015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n",
419115516c77SSepherosa Ziehau 		    idx, vmbus_chan_id(chan));
419215516c77SSepherosa Ziehau 	}
419315516c77SSepherosa Ziehau 
419415516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
419515516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[idx];
419615516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0,
419715516c77SSepherosa Ziehau 		    ("TX ring %d already attached", idx));
419815516c77SSepherosa Ziehau 		txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED;
419915516c77SSepherosa Ziehau 
420015516c77SSepherosa Ziehau 		txr->hn_chan = chan;
420115516c77SSepherosa Ziehau 		if (bootverbose) {
420215516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n",
420315516c77SSepherosa Ziehau 			    idx, vmbus_chan_id(chan));
420415516c77SSepherosa Ziehau 		}
420515516c77SSepherosa Ziehau 	}
420615516c77SSepherosa Ziehau 
420715516c77SSepherosa Ziehau 	/* Bind this channel to a proper CPU. */
420815516c77SSepherosa Ziehau 	vmbus_chan_cpu_set(chan, (sc->hn_cpu + idx) % mp_ncpus);
420915516c77SSepherosa Ziehau 
421015516c77SSepherosa Ziehau 	/*
421115516c77SSepherosa Ziehau 	 * Open this channel
421215516c77SSepherosa Ziehau 	 */
421315516c77SSepherosa Ziehau 	cbr.cbr = rxr->hn_br;
421415516c77SSepherosa Ziehau 	cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr;
421515516c77SSepherosa Ziehau 	cbr.cbr_txsz = HN_TXBR_SIZE;
421615516c77SSepherosa Ziehau 	cbr.cbr_rxsz = HN_RXBR_SIZE;
421715516c77SSepherosa Ziehau 	error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr);
421815516c77SSepherosa Ziehau 	if (error) {
421971e8ac56SSepherosa Ziehau 		if (error == EISCONN) {
422071e8ac56SSepherosa Ziehau 			if_printf(sc->hn_ifp, "bufring is connected after "
422171e8ac56SSepherosa Ziehau 			    "chan%u open failure\n", vmbus_chan_id(chan));
422271e8ac56SSepherosa Ziehau 			rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
422371e8ac56SSepherosa Ziehau 		} else {
422415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "open chan%u failed: %d\n",
422515516c77SSepherosa Ziehau 			    vmbus_chan_id(chan), error);
422671e8ac56SSepherosa Ziehau 		}
422715516c77SSepherosa Ziehau 	}
422815516c77SSepherosa Ziehau 	return (error);
422915516c77SSepherosa Ziehau }
423015516c77SSepherosa Ziehau 
423115516c77SSepherosa Ziehau static void
423215516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan)
423315516c77SSepherosa Ziehau {
423415516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
42352494d735SSepherosa Ziehau 	int idx, error;
423615516c77SSepherosa Ziehau 
423715516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
423815516c77SSepherosa Ziehau 
423915516c77SSepherosa Ziehau 	/*
424015516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
424115516c77SSepherosa Ziehau 	 */
424215516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
424315516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
424415516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
424515516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
424615516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED),
424715516c77SSepherosa Ziehau 	    ("RX ring %d is not attached", idx));
424815516c77SSepherosa Ziehau 	rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
424915516c77SSepherosa Ziehau 
425015516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
425115516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[idx];
425215516c77SSepherosa Ziehau 
425315516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED),
425415516c77SSepherosa Ziehau 		    ("TX ring %d is not attached attached", idx));
425515516c77SSepherosa Ziehau 		txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
425615516c77SSepherosa Ziehau 	}
425715516c77SSepherosa Ziehau 
425815516c77SSepherosa Ziehau 	/*
425915516c77SSepherosa Ziehau 	 * Close this channel.
426015516c77SSepherosa Ziehau 	 *
426115516c77SSepherosa Ziehau 	 * NOTE:
426215516c77SSepherosa Ziehau 	 * Channel closing does _not_ destroy the target channel.
426315516c77SSepherosa Ziehau 	 */
42642494d735SSepherosa Ziehau 	error = vmbus_chan_close_direct(chan);
42652494d735SSepherosa Ziehau 	if (error == EISCONN) {
4266aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u bufring is connected "
4267aa1a2adcSSepherosa Ziehau 		    "after being closed\n", vmbus_chan_id(chan));
42682494d735SSepherosa Ziehau 		rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
42692494d735SSepherosa Ziehau 	} else if (error) {
4270aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u close failed: %d\n",
4271aa1a2adcSSepherosa Ziehau 		    vmbus_chan_id(chan), error);
42722494d735SSepherosa Ziehau 	}
427315516c77SSepherosa Ziehau }
427415516c77SSepherosa Ziehau 
427515516c77SSepherosa Ziehau static int
427615516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc)
427715516c77SSepherosa Ziehau {
427815516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
427915516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
428015516c77SSepherosa Ziehau 	int i, error = 0;
428115516c77SSepherosa Ziehau 
428271e8ac56SSepherosa Ziehau 	KASSERT(subchan_cnt > 0, ("no sub-channels"));
428315516c77SSepherosa Ziehau 
428415516c77SSepherosa Ziehau 	/* Attach the sub-channels. */
428515516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
428615516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i) {
428771e8ac56SSepherosa Ziehau 		int error1;
428871e8ac56SSepherosa Ziehau 
428971e8ac56SSepherosa Ziehau 		error1 = hn_chan_attach(sc, subchans[i]);
429071e8ac56SSepherosa Ziehau 		if (error1) {
429171e8ac56SSepherosa Ziehau 			error = error1;
429271e8ac56SSepherosa Ziehau 			/* Move on; all channels will be detached later. */
429371e8ac56SSepherosa Ziehau 		}
429415516c77SSepherosa Ziehau 	}
429515516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
429615516c77SSepherosa Ziehau 
429715516c77SSepherosa Ziehau 	if (error) {
429815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error);
429915516c77SSepherosa Ziehau 	} else {
430015516c77SSepherosa Ziehau 		if (bootverbose) {
430115516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "%d sub-channels attached\n",
430215516c77SSepherosa Ziehau 			    subchan_cnt);
430315516c77SSepherosa Ziehau 		}
430415516c77SSepherosa Ziehau 	}
430515516c77SSepherosa Ziehau 	return (error);
430615516c77SSepherosa Ziehau }
430715516c77SSepherosa Ziehau 
430815516c77SSepherosa Ziehau static void
430915516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc)
431015516c77SSepherosa Ziehau {
431115516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
431215516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
431315516c77SSepherosa Ziehau 	int i;
431415516c77SSepherosa Ziehau 
431515516c77SSepherosa Ziehau 	if (subchan_cnt == 0)
431615516c77SSepherosa Ziehau 		goto back;
431715516c77SSepherosa Ziehau 
431815516c77SSepherosa Ziehau 	/* Detach the sub-channels. */
431915516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
432015516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i)
432115516c77SSepherosa Ziehau 		hn_chan_detach(sc, subchans[i]);
432215516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
432315516c77SSepherosa Ziehau 
432415516c77SSepherosa Ziehau back:
432515516c77SSepherosa Ziehau 	/*
432615516c77SSepherosa Ziehau 	 * Detach the primary channel, _after_ all sub-channels
432715516c77SSepherosa Ziehau 	 * are detached.
432815516c77SSepherosa Ziehau 	 */
432915516c77SSepherosa Ziehau 	hn_chan_detach(sc, sc->hn_prichan);
433015516c77SSepherosa Ziehau 
433115516c77SSepherosa Ziehau 	/* Wait for sub-channels to be destroyed, if any. */
433215516c77SSepherosa Ziehau 	vmbus_subchan_drain(sc->hn_prichan);
433315516c77SSepherosa Ziehau 
433415516c77SSepherosa Ziehau #ifdef INVARIANTS
433515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
433615516c77SSepherosa Ziehau 		KASSERT((sc->hn_rx_ring[i].hn_rx_flags &
433715516c77SSepherosa Ziehau 		    HN_RX_FLAG_ATTACHED) == 0,
433815516c77SSepherosa Ziehau 		    ("%dth RX ring is still attached", i));
433915516c77SSepherosa Ziehau 	}
434015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
434115516c77SSepherosa Ziehau 		KASSERT((sc->hn_tx_ring[i].hn_tx_flags &
434215516c77SSepherosa Ziehau 		    HN_TX_FLAG_ATTACHED) == 0,
434315516c77SSepherosa Ziehau 		    ("%dth TX ring is still attached", i));
434415516c77SSepherosa Ziehau 	}
434515516c77SSepherosa Ziehau #endif
434615516c77SSepherosa Ziehau }
434715516c77SSepherosa Ziehau 
434815516c77SSepherosa Ziehau static int
434915516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch)
435015516c77SSepherosa Ziehau {
435115516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
435215516c77SSepherosa Ziehau 	int nchan, rxr_cnt, error;
435315516c77SSepherosa Ziehau 
435415516c77SSepherosa Ziehau 	nchan = *nsubch + 1;
435515516c77SSepherosa Ziehau 	if (nchan == 1) {
435615516c77SSepherosa Ziehau 		/*
435715516c77SSepherosa Ziehau 		 * Multiple RX/TX rings are not requested.
435815516c77SSepherosa Ziehau 		 */
435915516c77SSepherosa Ziehau 		*nsubch = 0;
436015516c77SSepherosa Ziehau 		return (0);
436115516c77SSepherosa Ziehau 	}
436215516c77SSepherosa Ziehau 
436315516c77SSepherosa Ziehau 	/*
436415516c77SSepherosa Ziehau 	 * Query RSS capabilities, e.g. # of RX rings, and # of indirect
436515516c77SSepherosa Ziehau 	 * table entries.
436615516c77SSepherosa Ziehau 	 */
436715516c77SSepherosa Ziehau 	error = hn_rndis_query_rsscaps(sc, &rxr_cnt);
436815516c77SSepherosa Ziehau 	if (error) {
436915516c77SSepherosa Ziehau 		/* No RSS; this is benign. */
437015516c77SSepherosa Ziehau 		*nsubch = 0;
437115516c77SSepherosa Ziehau 		return (0);
437215516c77SSepherosa Ziehau 	}
437315516c77SSepherosa Ziehau 	if (bootverbose) {
437415516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
437515516c77SSepherosa Ziehau 		    rxr_cnt, nchan);
437615516c77SSepherosa Ziehau 	}
437715516c77SSepherosa Ziehau 
437815516c77SSepherosa Ziehau 	if (nchan > rxr_cnt)
437915516c77SSepherosa Ziehau 		nchan = rxr_cnt;
438015516c77SSepherosa Ziehau 	if (nchan == 1) {
438115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n");
438215516c77SSepherosa Ziehau 		*nsubch = 0;
438315516c77SSepherosa Ziehau 		return (0);
438415516c77SSepherosa Ziehau 	}
438515516c77SSepherosa Ziehau 
438615516c77SSepherosa Ziehau 	/*
438715516c77SSepherosa Ziehau 	 * Allocate sub-channels from NVS.
438815516c77SSepherosa Ziehau 	 */
438915516c77SSepherosa Ziehau 	*nsubch = nchan - 1;
439015516c77SSepherosa Ziehau 	error = hn_nvs_alloc_subchans(sc, nsubch);
439115516c77SSepherosa Ziehau 	if (error || *nsubch == 0) {
439215516c77SSepherosa Ziehau 		/* Failed to allocate sub-channels. */
439315516c77SSepherosa Ziehau 		*nsubch = 0;
439415516c77SSepherosa Ziehau 		return (0);
439515516c77SSepherosa Ziehau 	}
439615516c77SSepherosa Ziehau 
439715516c77SSepherosa Ziehau 	/*
439815516c77SSepherosa Ziehau 	 * Wait for all sub-channels to become ready before moving on.
439915516c77SSepherosa Ziehau 	 */
440015516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch);
440115516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, *nsubch);
440215516c77SSepherosa Ziehau 	return (0);
440315516c77SSepherosa Ziehau }
440415516c77SSepherosa Ziehau 
44052494d735SSepherosa Ziehau static bool
44062494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc)
44072494d735SSepherosa Ziehau {
44082494d735SSepherosa Ziehau 	int i;
44092494d735SSepherosa Ziehau 
44102494d735SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_ERRORS)
44112494d735SSepherosa Ziehau 		return (false);
44122494d735SSepherosa Ziehau 
44132494d735SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
44142494d735SSepherosa Ziehau 		const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
44152494d735SSepherosa Ziehau 
44162494d735SSepherosa Ziehau 		if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF)
44172494d735SSepherosa Ziehau 			return (false);
44182494d735SSepherosa Ziehau 	}
44192494d735SSepherosa Ziehau 	return (true);
44202494d735SSepherosa Ziehau }
44212494d735SSepherosa Ziehau 
442215516c77SSepherosa Ziehau static int
442315516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu)
442415516c77SSepherosa Ziehau {
442571e8ac56SSepherosa Ziehau #define ATTACHED_NVS		0x0002
442671e8ac56SSepherosa Ziehau #define ATTACHED_RNDIS		0x0004
442771e8ac56SSepherosa Ziehau 
442815516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
442915516c77SSepherosa Ziehau 	int error, nsubch, nchan, i;
443071e8ac56SSepherosa Ziehau 	uint32_t old_caps, attached = 0;
443115516c77SSepherosa Ziehau 
443215516c77SSepherosa Ziehau 	KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0,
443315516c77SSepherosa Ziehau 	    ("synthetic parts were attached"));
443415516c77SSepherosa Ziehau 
44352494d735SSepherosa Ziehau 	if (!hn_synth_attachable(sc))
44362494d735SSepherosa Ziehau 		return (ENXIO);
44372494d735SSepherosa Ziehau 
443815516c77SSepherosa Ziehau 	/* Save capabilities for later verification. */
443915516c77SSepherosa Ziehau 	old_caps = sc->hn_caps;
444015516c77SSepherosa Ziehau 	sc->hn_caps = 0;
444115516c77SSepherosa Ziehau 
444215516c77SSepherosa Ziehau 	/* Clear RSS stuffs. */
444315516c77SSepherosa Ziehau 	sc->hn_rss_ind_size = 0;
444415516c77SSepherosa Ziehau 	sc->hn_rss_hash = 0;
444515516c77SSepherosa Ziehau 
444615516c77SSepherosa Ziehau 	/*
444715516c77SSepherosa Ziehau 	 * Attach the primary channel _before_ attaching NVS and RNDIS.
444815516c77SSepherosa Ziehau 	 */
444915516c77SSepherosa Ziehau 	error = hn_chan_attach(sc, sc->hn_prichan);
445015516c77SSepherosa Ziehau 	if (error)
445171e8ac56SSepherosa Ziehau 		goto failed;
445215516c77SSepherosa Ziehau 
445315516c77SSepherosa Ziehau 	/*
445415516c77SSepherosa Ziehau 	 * Attach NVS.
445515516c77SSepherosa Ziehau 	 */
445615516c77SSepherosa Ziehau 	error = hn_nvs_attach(sc, mtu);
445715516c77SSepherosa Ziehau 	if (error)
445871e8ac56SSepherosa Ziehau 		goto failed;
445971e8ac56SSepherosa Ziehau 	attached |= ATTACHED_NVS;
446015516c77SSepherosa Ziehau 
446115516c77SSepherosa Ziehau 	/*
446215516c77SSepherosa Ziehau 	 * Attach RNDIS _after_ NVS is attached.
446315516c77SSepherosa Ziehau 	 */
446415516c77SSepherosa Ziehau 	error = hn_rndis_attach(sc, mtu);
446515516c77SSepherosa Ziehau 	if (error)
446671e8ac56SSepherosa Ziehau 		goto failed;
446771e8ac56SSepherosa Ziehau 	attached |= ATTACHED_RNDIS;
446815516c77SSepherosa Ziehau 
446915516c77SSepherosa Ziehau 	/*
447015516c77SSepherosa Ziehau 	 * Make sure capabilities are not changed.
447115516c77SSepherosa Ziehau 	 */
447215516c77SSepherosa Ziehau 	if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) {
447315516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n",
447415516c77SSepherosa Ziehau 		    old_caps, sc->hn_caps);
447571e8ac56SSepherosa Ziehau 		error = ENXIO;
447671e8ac56SSepherosa Ziehau 		goto failed;
447715516c77SSepherosa Ziehau 	}
447815516c77SSepherosa Ziehau 
447915516c77SSepherosa Ziehau 	/*
448015516c77SSepherosa Ziehau 	 * Allocate sub-channels for multi-TX/RX rings.
448115516c77SSepherosa Ziehau 	 *
448215516c77SSepherosa Ziehau 	 * NOTE:
448315516c77SSepherosa Ziehau 	 * The # of RX rings that can be used is equivalent to the # of
448415516c77SSepherosa Ziehau 	 * channels to be requested.
448515516c77SSepherosa Ziehau 	 */
448615516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_cnt - 1;
448715516c77SSepherosa Ziehau 	error = hn_synth_alloc_subchans(sc, &nsubch);
448815516c77SSepherosa Ziehau 	if (error)
448971e8ac56SSepherosa Ziehau 		goto failed;
449071e8ac56SSepherosa Ziehau 	/* NOTE: _Full_ synthetic parts detach is required now. */
449171e8ac56SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED;
449215516c77SSepherosa Ziehau 
449371e8ac56SSepherosa Ziehau 	/*
449471e8ac56SSepherosa Ziehau 	 * Set the # of TX/RX rings that could be used according to
449571e8ac56SSepherosa Ziehau 	 * the # of channels that NVS offered.
449671e8ac56SSepherosa Ziehau 	 */
449715516c77SSepherosa Ziehau 	nchan = nsubch + 1;
449871e8ac56SSepherosa Ziehau 	hn_set_ring_inuse(sc, nchan);
449915516c77SSepherosa Ziehau 	if (nchan == 1) {
450015516c77SSepherosa Ziehau 		/* Only the primary channel can be used; done */
450115516c77SSepherosa Ziehau 		goto back;
450215516c77SSepherosa Ziehau 	}
450315516c77SSepherosa Ziehau 
450415516c77SSepherosa Ziehau 	/*
450571e8ac56SSepherosa Ziehau 	 * Attach the sub-channels.
4506afd4971bSSepherosa Ziehau 	 *
4507afd4971bSSepherosa Ziehau 	 * NOTE: hn_set_ring_inuse() _must_ have been called.
450815516c77SSepherosa Ziehau 	 */
450971e8ac56SSepherosa Ziehau 	error = hn_attach_subchans(sc);
451071e8ac56SSepherosa Ziehau 	if (error)
451171e8ac56SSepherosa Ziehau 		goto failed;
451215516c77SSepherosa Ziehau 
451371e8ac56SSepherosa Ziehau 	/*
451471e8ac56SSepherosa Ziehau 	 * Configure RSS key and indirect table _after_ all sub-channels
451571e8ac56SSepherosa Ziehau 	 * are attached.
451671e8ac56SSepherosa Ziehau 	 */
451715516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) {
451815516c77SSepherosa Ziehau 		/*
451915516c77SSepherosa Ziehau 		 * RSS key is not set yet; set it to the default RSS key.
452015516c77SSepherosa Ziehau 		 */
452115516c77SSepherosa Ziehau 		if (bootverbose)
452215516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS key\n");
452315516c77SSepherosa Ziehau 		memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key));
452415516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
452515516c77SSepherosa Ziehau 	}
452615516c77SSepherosa Ziehau 
452715516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) {
452815516c77SSepherosa Ziehau 		/*
452915516c77SSepherosa Ziehau 		 * RSS indirect table is not set yet; set it up in round-
453015516c77SSepherosa Ziehau 		 * robin fashion.
453115516c77SSepherosa Ziehau 		 */
453215516c77SSepherosa Ziehau 		if (bootverbose) {
453315516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS indirect "
453415516c77SSepherosa Ziehau 			    "table\n");
453515516c77SSepherosa Ziehau 		}
453615516c77SSepherosa Ziehau 		for (i = 0; i < NDIS_HASH_INDCNT; ++i)
453715516c77SSepherosa Ziehau 			rss->rss_ind[i] = i % nchan;
453815516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSIND;
453915516c77SSepherosa Ziehau 	} else {
454015516c77SSepherosa Ziehau 		/*
454115516c77SSepherosa Ziehau 		 * # of usable channels may be changed, so we have to
454215516c77SSepherosa Ziehau 		 * make sure that all entries in RSS indirect table
454315516c77SSepherosa Ziehau 		 * are valid.
4544afd4971bSSepherosa Ziehau 		 *
4545afd4971bSSepherosa Ziehau 		 * NOTE: hn_set_ring_inuse() _must_ have been called.
454615516c77SSepherosa Ziehau 		 */
4547afd4971bSSepherosa Ziehau 		hn_rss_ind_fixup(sc);
454815516c77SSepherosa Ziehau 	}
454915516c77SSepherosa Ziehau 
455015516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
455115516c77SSepherosa Ziehau 	if (error)
455271e8ac56SSepherosa Ziehau 		goto failed;
455371e8ac56SSepherosa Ziehau back:
4554dc13fee6SSepherosa Ziehau 	/*
4555dc13fee6SSepherosa Ziehau 	 * Fixup transmission aggregation setup.
4556dc13fee6SSepherosa Ziehau 	 */
4557dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
455815516c77SSepherosa Ziehau 	return (0);
455971e8ac56SSepherosa Ziehau 
456071e8ac56SSepherosa Ziehau failed:
456171e8ac56SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
456271e8ac56SSepherosa Ziehau 		hn_synth_detach(sc);
456371e8ac56SSepherosa Ziehau 	} else {
456471e8ac56SSepherosa Ziehau 		if (attached & ATTACHED_RNDIS)
456571e8ac56SSepherosa Ziehau 			hn_rndis_detach(sc);
456671e8ac56SSepherosa Ziehau 		if (attached & ATTACHED_NVS)
456771e8ac56SSepherosa Ziehau 			hn_nvs_detach(sc);
456871e8ac56SSepherosa Ziehau 		hn_chan_detach(sc, sc->hn_prichan);
456971e8ac56SSepherosa Ziehau 		/* Restore old capabilities. */
457071e8ac56SSepherosa Ziehau 		sc->hn_caps = old_caps;
457171e8ac56SSepherosa Ziehau 	}
457271e8ac56SSepherosa Ziehau 	return (error);
457371e8ac56SSepherosa Ziehau 
457471e8ac56SSepherosa Ziehau #undef ATTACHED_RNDIS
457571e8ac56SSepherosa Ziehau #undef ATTACHED_NVS
457615516c77SSepherosa Ziehau }
457715516c77SSepherosa Ziehau 
457815516c77SSepherosa Ziehau /*
457915516c77SSepherosa Ziehau  * NOTE:
458015516c77SSepherosa Ziehau  * The interface must have been suspended though hn_suspend(), before
458115516c77SSepherosa Ziehau  * this function get called.
458215516c77SSepherosa Ziehau  */
458315516c77SSepherosa Ziehau static void
458415516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc)
458515516c77SSepherosa Ziehau {
458615516c77SSepherosa Ziehau 
458715516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
458815516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
458915516c77SSepherosa Ziehau 
459015516c77SSepherosa Ziehau 	/* Detach the RNDIS first. */
459115516c77SSepherosa Ziehau 	hn_rndis_detach(sc);
459215516c77SSepherosa Ziehau 
459315516c77SSepherosa Ziehau 	/* Detach NVS. */
459415516c77SSepherosa Ziehau 	hn_nvs_detach(sc);
459515516c77SSepherosa Ziehau 
459615516c77SSepherosa Ziehau 	/* Detach all of the channels. */
459715516c77SSepherosa Ziehau 	hn_detach_allchans(sc);
459815516c77SSepherosa Ziehau 
459915516c77SSepherosa Ziehau 	sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED;
460015516c77SSepherosa Ziehau }
460115516c77SSepherosa Ziehau 
460215516c77SSepherosa Ziehau static void
460315516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt)
460415516c77SSepherosa Ziehau {
460515516c77SSepherosa Ziehau 	KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt,
460615516c77SSepherosa Ziehau 	    ("invalid ring count %d", ring_cnt));
460715516c77SSepherosa Ziehau 
460815516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt > ring_cnt)
460915516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = ring_cnt;
461015516c77SSepherosa Ziehau 	else
461115516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
461215516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = ring_cnt;
461315516c77SSepherosa Ziehau 
461415516c77SSepherosa Ziehau 	if (bootverbose) {
461515516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n",
461615516c77SSepherosa Ziehau 		    sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
461715516c77SSepherosa Ziehau 	}
461815516c77SSepherosa Ziehau }
461915516c77SSepherosa Ziehau 
462015516c77SSepherosa Ziehau static void
462125641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan)
462215516c77SSepherosa Ziehau {
462315516c77SSepherosa Ziehau 
462425641fc7SSepherosa Ziehau 	/*
462525641fc7SSepherosa Ziehau 	 * NOTE:
462625641fc7SSepherosa Ziehau 	 * The TX bufring will not be drained by the hypervisor,
462725641fc7SSepherosa Ziehau 	 * if the primary channel is revoked.
462825641fc7SSepherosa Ziehau 	 */
462925641fc7SSepherosa Ziehau 	while (!vmbus_chan_rx_empty(chan) ||
463025641fc7SSepherosa Ziehau 	    (!vmbus_chan_is_revoked(sc->hn_prichan) &&
463125641fc7SSepherosa Ziehau 	     !vmbus_chan_tx_empty(chan)))
463215516c77SSepherosa Ziehau 		pause("waitch", 1);
463315516c77SSepherosa Ziehau 	vmbus_chan_intr_drain(chan);
463415516c77SSepherosa Ziehau }
463515516c77SSepherosa Ziehau 
463615516c77SSepherosa Ziehau static void
463715516c77SSepherosa Ziehau hn_suspend_data(struct hn_softc *sc)
463815516c77SSepherosa Ziehau {
463915516c77SSepherosa Ziehau 	struct vmbus_channel **subch = NULL;
464025641fc7SSepherosa Ziehau 	struct hn_tx_ring *txr;
464115516c77SSepherosa Ziehau 	int i, nsubch;
464215516c77SSepherosa Ziehau 
464315516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
464415516c77SSepherosa Ziehau 
464515516c77SSepherosa Ziehau 	/*
464615516c77SSepherosa Ziehau 	 * Suspend TX.
464715516c77SSepherosa Ziehau 	 */
464815516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
464925641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
465015516c77SSepherosa Ziehau 
465115516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
465215516c77SSepherosa Ziehau 		txr->hn_suspended = 1;
465315516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
465415516c77SSepherosa Ziehau 		/* No one is able send more packets now. */
465515516c77SSepherosa Ziehau 
465625641fc7SSepherosa Ziehau 		/*
465725641fc7SSepherosa Ziehau 		 * Wait for all pending sends to finish.
465825641fc7SSepherosa Ziehau 		 *
465925641fc7SSepherosa Ziehau 		 * NOTE:
466025641fc7SSepherosa Ziehau 		 * We will _not_ receive all pending send-done, if the
466125641fc7SSepherosa Ziehau 		 * primary channel is revoked.
466225641fc7SSepherosa Ziehau 		 */
466325641fc7SSepherosa Ziehau 		while (hn_tx_ring_pending(txr) &&
466425641fc7SSepherosa Ziehau 		    !vmbus_chan_is_revoked(sc->hn_prichan))
466515516c77SSepherosa Ziehau 			pause("hnwtx", 1 /* 1 tick */);
466615516c77SSepherosa Ziehau 	}
466715516c77SSepherosa Ziehau 
466815516c77SSepherosa Ziehau 	/*
466915516c77SSepherosa Ziehau 	 * Disable RX by clearing RX filter.
467015516c77SSepherosa Ziehau 	 */
467115516c77SSepherosa Ziehau 	sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE;
467215516c77SSepherosa Ziehau 	hn_rndis_set_rxfilter(sc, sc->hn_rx_filter);
467315516c77SSepherosa Ziehau 
467415516c77SSepherosa Ziehau 	/*
467515516c77SSepherosa Ziehau 	 * Give RNDIS enough time to flush all pending data packets.
467615516c77SSepherosa Ziehau 	 */
467715516c77SSepherosa Ziehau 	pause("waitrx", (200 * hz) / 1000);
467815516c77SSepherosa Ziehau 
467915516c77SSepherosa Ziehau 	/*
468015516c77SSepherosa Ziehau 	 * Drain RX/TX bufrings and interrupts.
468115516c77SSepherosa Ziehau 	 */
468215516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_inuse - 1;
468315516c77SSepherosa Ziehau 	if (nsubch > 0)
468415516c77SSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
468515516c77SSepherosa Ziehau 
468615516c77SSepherosa Ziehau 	if (subch != NULL) {
468715516c77SSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
468825641fc7SSepherosa Ziehau 			hn_chan_drain(sc, subch[i]);
468915516c77SSepherosa Ziehau 	}
469025641fc7SSepherosa Ziehau 	hn_chan_drain(sc, sc->hn_prichan);
469115516c77SSepherosa Ziehau 
469215516c77SSepherosa Ziehau 	if (subch != NULL)
469315516c77SSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
469425641fc7SSepherosa Ziehau 
469525641fc7SSepherosa Ziehau 	/*
469625641fc7SSepherosa Ziehau 	 * Drain any pending TX tasks.
469725641fc7SSepherosa Ziehau 	 *
469825641fc7SSepherosa Ziehau 	 * NOTE:
469925641fc7SSepherosa Ziehau 	 * The above hn_chan_drain() can dispatch TX tasks, so the TX
470025641fc7SSepherosa Ziehau 	 * tasks will have to be drained _after_ the above hn_chan_drain()
470125641fc7SSepherosa Ziehau 	 * calls.
470225641fc7SSepherosa Ziehau 	 */
470325641fc7SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
470425641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
470525641fc7SSepherosa Ziehau 
470625641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task);
470725641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task);
470825641fc7SSepherosa Ziehau 	}
470915516c77SSepherosa Ziehau }
471015516c77SSepherosa Ziehau 
471115516c77SSepherosa Ziehau static void
471215516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused)
471315516c77SSepherosa Ziehau {
471415516c77SSepherosa Ziehau 
471515516c77SSepherosa Ziehau 	((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL;
471615516c77SSepherosa Ziehau }
471715516c77SSepherosa Ziehau 
471815516c77SSepherosa Ziehau static void
471915516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc)
472015516c77SSepherosa Ziehau {
472115516c77SSepherosa Ziehau 	struct task task;
472215516c77SSepherosa Ziehau 
472315516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
472415516c77SSepherosa Ziehau 
472515516c77SSepherosa Ziehau 	/*
472615516c77SSepherosa Ziehau 	 * Make sure that hn_mgmt_taskq0 can nolonger be accessed
472715516c77SSepherosa Ziehau 	 * through hn_mgmt_taskq.
472815516c77SSepherosa Ziehau 	 */
472915516c77SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc);
473015516c77SSepherosa Ziehau 	vmbus_chan_run_task(sc->hn_prichan, &task);
473115516c77SSepherosa Ziehau 
473215516c77SSepherosa Ziehau 	/*
473315516c77SSepherosa Ziehau 	 * Make sure that all pending management tasks are completed.
473415516c77SSepherosa Ziehau 	 */
473515516c77SSepherosa Ziehau 	taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init);
473615516c77SSepherosa Ziehau 	taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status);
473715516c77SSepherosa Ziehau 	taskqueue_drain_all(sc->hn_mgmt_taskq0);
473815516c77SSepherosa Ziehau }
473915516c77SSepherosa Ziehau 
474015516c77SSepherosa Ziehau static void
474115516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc)
474215516c77SSepherosa Ziehau {
474315516c77SSepherosa Ziehau 
474415516c77SSepherosa Ziehau 	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
474515516c77SSepherosa Ziehau 		hn_suspend_data(sc);
474615516c77SSepherosa Ziehau 	hn_suspend_mgmt(sc);
474715516c77SSepherosa Ziehau }
474815516c77SSepherosa Ziehau 
474915516c77SSepherosa Ziehau static void
475015516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt)
475115516c77SSepherosa Ziehau {
475215516c77SSepherosa Ziehau 	int i;
475315516c77SSepherosa Ziehau 
475415516c77SSepherosa Ziehau 	KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt,
475515516c77SSepherosa Ziehau 	    ("invalid TX ring count %d", tx_ring_cnt));
475615516c77SSepherosa Ziehau 
475715516c77SSepherosa Ziehau 	for (i = 0; i < tx_ring_cnt; ++i) {
475815516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
475915516c77SSepherosa Ziehau 
476015516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
476115516c77SSepherosa Ziehau 		txr->hn_suspended = 0;
476215516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
476315516c77SSepherosa Ziehau 	}
476415516c77SSepherosa Ziehau }
476515516c77SSepherosa Ziehau 
476615516c77SSepherosa Ziehau static void
476715516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc)
476815516c77SSepherosa Ziehau {
476915516c77SSepherosa Ziehau 	int i;
477015516c77SSepherosa Ziehau 
477115516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
477215516c77SSepherosa Ziehau 
477315516c77SSepherosa Ziehau 	/*
477415516c77SSepherosa Ziehau 	 * Re-enable RX.
477515516c77SSepherosa Ziehau 	 */
477615516c77SSepherosa Ziehau 	hn_set_rxfilter(sc);
477715516c77SSepherosa Ziehau 
477815516c77SSepherosa Ziehau 	/*
477915516c77SSepherosa Ziehau 	 * Make sure to clear suspend status on "all" TX rings,
478015516c77SSepherosa Ziehau 	 * since hn_tx_ring_inuse can be changed after
478115516c77SSepherosa Ziehau 	 * hn_suspend_data().
478215516c77SSepherosa Ziehau 	 */
478315516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_cnt);
478415516c77SSepherosa Ziehau 
478523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
478623bf9e15SSepherosa Ziehau 	if (!hn_use_if_start)
478723bf9e15SSepherosa Ziehau #endif
478823bf9e15SSepherosa Ziehau 	{
478915516c77SSepherosa Ziehau 		/*
479015516c77SSepherosa Ziehau 		 * Flush unused drbrs, since hn_tx_ring_inuse may be
479115516c77SSepherosa Ziehau 		 * reduced.
479215516c77SSepherosa Ziehau 		 */
479315516c77SSepherosa Ziehau 		for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i)
479415516c77SSepherosa Ziehau 			hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
479515516c77SSepherosa Ziehau 	}
479615516c77SSepherosa Ziehau 
479715516c77SSepherosa Ziehau 	/*
479815516c77SSepherosa Ziehau 	 * Kick start TX.
479915516c77SSepherosa Ziehau 	 */
480015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
480115516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
480215516c77SSepherosa Ziehau 
480315516c77SSepherosa Ziehau 		/*
480415516c77SSepherosa Ziehau 		 * Use txeof task, so that any pending oactive can be
480515516c77SSepherosa Ziehau 		 * cleared properly.
480615516c77SSepherosa Ziehau 		 */
480715516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
480815516c77SSepherosa Ziehau 	}
480915516c77SSepherosa Ziehau }
481015516c77SSepherosa Ziehau 
481115516c77SSepherosa Ziehau static void
481215516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc)
481315516c77SSepherosa Ziehau {
481415516c77SSepherosa Ziehau 
481515516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
481615516c77SSepherosa Ziehau 
481715516c77SSepherosa Ziehau 	/*
481815516c77SSepherosa Ziehau 	 * Kick off network change detection, if it was pending.
481915516c77SSepherosa Ziehau 	 * If no network change was pending, start link status
482015516c77SSepherosa Ziehau 	 * checks, which is more lightweight than network change
482115516c77SSepherosa Ziehau 	 * detection.
482215516c77SSepherosa Ziehau 	 */
482315516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
482415516c77SSepherosa Ziehau 		hn_change_network(sc);
482515516c77SSepherosa Ziehau 	else
482615516c77SSepherosa Ziehau 		hn_update_link_status(sc);
482715516c77SSepherosa Ziehau }
482815516c77SSepherosa Ziehau 
482915516c77SSepherosa Ziehau static void
483015516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc)
483115516c77SSepherosa Ziehau {
483215516c77SSepherosa Ziehau 
483315516c77SSepherosa Ziehau 	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
483415516c77SSepherosa Ziehau 		hn_resume_data(sc);
483515516c77SSepherosa Ziehau 	hn_resume_mgmt(sc);
483615516c77SSepherosa Ziehau }
483715516c77SSepherosa Ziehau 
483815516c77SSepherosa Ziehau static void
483915516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen)
484015516c77SSepherosa Ziehau {
484115516c77SSepherosa Ziehau 	const struct rndis_status_msg *msg;
484215516c77SSepherosa Ziehau 	int ofs;
484315516c77SSepherosa Ziehau 
484415516c77SSepherosa Ziehau 	if (dlen < sizeof(*msg)) {
484515516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid RNDIS status\n");
484615516c77SSepherosa Ziehau 		return;
484715516c77SSepherosa Ziehau 	}
484815516c77SSepherosa Ziehau 	msg = data;
484915516c77SSepherosa Ziehau 
485015516c77SSepherosa Ziehau 	switch (msg->rm_status) {
485115516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_CONNECT:
485215516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_DISCONNECT:
485315516c77SSepherosa Ziehau 		hn_update_link_status(sc);
485415516c77SSepherosa Ziehau 		break;
485515516c77SSepherosa Ziehau 
485615516c77SSepherosa Ziehau 	case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
485715516c77SSepherosa Ziehau 		/* Not really useful; ignore. */
485815516c77SSepherosa Ziehau 		break;
485915516c77SSepherosa Ziehau 
486015516c77SSepherosa Ziehau 	case RNDIS_STATUS_NETWORK_CHANGE:
486115516c77SSepherosa Ziehau 		ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
486215516c77SSepherosa Ziehau 		if (dlen < ofs + msg->rm_stbuflen ||
486315516c77SSepherosa Ziehau 		    msg->rm_stbuflen < sizeof(uint32_t)) {
486415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed\n");
486515516c77SSepherosa Ziehau 		} else {
486615516c77SSepherosa Ziehau 			uint32_t change;
486715516c77SSepherosa Ziehau 
486815516c77SSepherosa Ziehau 			memcpy(&change, ((const uint8_t *)msg) + ofs,
486915516c77SSepherosa Ziehau 			    sizeof(change));
487015516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed, change %u\n",
487115516c77SSepherosa Ziehau 			    change);
487215516c77SSepherosa Ziehau 		}
487315516c77SSepherosa Ziehau 		hn_change_network(sc);
487415516c77SSepherosa Ziehau 		break;
487515516c77SSepherosa Ziehau 
487615516c77SSepherosa Ziehau 	default:
487715516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
487815516c77SSepherosa Ziehau 		    msg->rm_status);
487915516c77SSepherosa Ziehau 		break;
488015516c77SSepherosa Ziehau 	}
488115516c77SSepherosa Ziehau }
488215516c77SSepherosa Ziehau 
488315516c77SSepherosa Ziehau static int
488415516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info)
488515516c77SSepherosa Ziehau {
488615516c77SSepherosa Ziehau 	const struct rndis_pktinfo *pi = info_data;
488715516c77SSepherosa Ziehau 	uint32_t mask = 0;
488815516c77SSepherosa Ziehau 
488915516c77SSepherosa Ziehau 	while (info_dlen != 0) {
489015516c77SSepherosa Ziehau 		const void *data;
489115516c77SSepherosa Ziehau 		uint32_t dlen;
489215516c77SSepherosa Ziehau 
489315516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < sizeof(*pi)))
489415516c77SSepherosa Ziehau 			return (EINVAL);
489515516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < pi->rm_size))
489615516c77SSepherosa Ziehau 			return (EINVAL);
489715516c77SSepherosa Ziehau 		info_dlen -= pi->rm_size;
489815516c77SSepherosa Ziehau 
489915516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
490015516c77SSepherosa Ziehau 			return (EINVAL);
490115516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
490215516c77SSepherosa Ziehau 			return (EINVAL);
490315516c77SSepherosa Ziehau 		dlen = pi->rm_size - pi->rm_pktinfooffset;
490415516c77SSepherosa Ziehau 		data = pi->rm_data;
490515516c77SSepherosa Ziehau 
490615516c77SSepherosa Ziehau 		switch (pi->rm_type) {
490715516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_VLAN:
490815516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
490915516c77SSepherosa Ziehau 				return (EINVAL);
491015516c77SSepherosa Ziehau 			info->vlan_info = *((const uint32_t *)data);
491115516c77SSepherosa Ziehau 			mask |= HN_RXINFO_VLAN;
491215516c77SSepherosa Ziehau 			break;
491315516c77SSepherosa Ziehau 
491415516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_CSUM:
491515516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
491615516c77SSepherosa Ziehau 				return (EINVAL);
491715516c77SSepherosa Ziehau 			info->csum_info = *((const uint32_t *)data);
491815516c77SSepherosa Ziehau 			mask |= HN_RXINFO_CSUM;
491915516c77SSepherosa Ziehau 			break;
492015516c77SSepherosa Ziehau 
492115516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHVAL:
492215516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
492315516c77SSepherosa Ziehau 				return (EINVAL);
492415516c77SSepherosa Ziehau 			info->hash_value = *((const uint32_t *)data);
492515516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHVAL;
492615516c77SSepherosa Ziehau 			break;
492715516c77SSepherosa Ziehau 
492815516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHINF:
492915516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
493015516c77SSepherosa Ziehau 				return (EINVAL);
493115516c77SSepherosa Ziehau 			info->hash_info = *((const uint32_t *)data);
493215516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHINF;
493315516c77SSepherosa Ziehau 			break;
493415516c77SSepherosa Ziehau 
493515516c77SSepherosa Ziehau 		default:
493615516c77SSepherosa Ziehau 			goto next;
493715516c77SSepherosa Ziehau 		}
493815516c77SSepherosa Ziehau 
493915516c77SSepherosa Ziehau 		if (mask == HN_RXINFO_ALL) {
494015516c77SSepherosa Ziehau 			/* All found; done */
494115516c77SSepherosa Ziehau 			break;
494215516c77SSepherosa Ziehau 		}
494315516c77SSepherosa Ziehau next:
494415516c77SSepherosa Ziehau 		pi = (const struct rndis_pktinfo *)
494515516c77SSepherosa Ziehau 		    ((const uint8_t *)pi + pi->rm_size);
494615516c77SSepherosa Ziehau 	}
494715516c77SSepherosa Ziehau 
494815516c77SSepherosa Ziehau 	/*
494915516c77SSepherosa Ziehau 	 * Final fixup.
495015516c77SSepherosa Ziehau 	 * - If there is no hash value, invalidate the hash info.
495115516c77SSepherosa Ziehau 	 */
495215516c77SSepherosa Ziehau 	if ((mask & HN_RXINFO_HASHVAL) == 0)
495315516c77SSepherosa Ziehau 		info->hash_info = HN_NDIS_HASH_INFO_INVALID;
495415516c77SSepherosa Ziehau 	return (0);
495515516c77SSepherosa Ziehau }
495615516c77SSepherosa Ziehau 
495715516c77SSepherosa Ziehau static __inline bool
495815516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
495915516c77SSepherosa Ziehau {
496015516c77SSepherosa Ziehau 
496115516c77SSepherosa Ziehau 	if (off < check_off) {
496215516c77SSepherosa Ziehau 		if (__predict_true(off + len <= check_off))
496315516c77SSepherosa Ziehau 			return (false);
496415516c77SSepherosa Ziehau 	} else if (off > check_off) {
496515516c77SSepherosa Ziehau 		if (__predict_true(check_off + check_len <= off))
496615516c77SSepherosa Ziehau 			return (false);
496715516c77SSepherosa Ziehau 	}
496815516c77SSepherosa Ziehau 	return (true);
496915516c77SSepherosa Ziehau }
497015516c77SSepherosa Ziehau 
497115516c77SSepherosa Ziehau static void
497215516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen)
497315516c77SSepherosa Ziehau {
497415516c77SSepherosa Ziehau 	const struct rndis_packet_msg *pkt;
497515516c77SSepherosa Ziehau 	struct hn_rxinfo info;
497615516c77SSepherosa Ziehau 	int data_off, pktinfo_off, data_len, pktinfo_len;
497715516c77SSepherosa Ziehau 
497815516c77SSepherosa Ziehau 	/*
497915516c77SSepherosa Ziehau 	 * Check length.
498015516c77SSepherosa Ziehau 	 */
498115516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*pkt))) {
498215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
498315516c77SSepherosa Ziehau 		return;
498415516c77SSepherosa Ziehau 	}
498515516c77SSepherosa Ziehau 	pkt = data;
498615516c77SSepherosa Ziehau 
498715516c77SSepherosa Ziehau 	if (__predict_false(dlen < pkt->rm_len)) {
498815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
498915516c77SSepherosa Ziehau 		    "dlen %d, msglen %u\n", dlen, pkt->rm_len);
499015516c77SSepherosa Ziehau 		return;
499115516c77SSepherosa Ziehau 	}
499215516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_len <
499315516c77SSepherosa Ziehau 	    pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
499415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
499515516c77SSepherosa Ziehau 		    "msglen %u, data %u, oob %u, pktinfo %u\n",
499615516c77SSepherosa Ziehau 		    pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
499715516c77SSepherosa Ziehau 		    pkt->rm_pktinfolen);
499815516c77SSepherosa Ziehau 		return;
499915516c77SSepherosa Ziehau 	}
500015516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_datalen == 0)) {
500115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
500215516c77SSepherosa Ziehau 		return;
500315516c77SSepherosa Ziehau 	}
500415516c77SSepherosa Ziehau 
500515516c77SSepherosa Ziehau 	/*
500615516c77SSepherosa Ziehau 	 * Check offests.
500715516c77SSepherosa Ziehau 	 */
500815516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs)			\
500915516c77SSepherosa Ziehau 	((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN ||	\
501015516c77SSepherosa Ziehau 	 ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
501115516c77SSepherosa Ziehau 
501215516c77SSepherosa Ziehau 	/* XXX Hyper-V does not meet data offset alignment requirement */
501315516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
501415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
501515516c77SSepherosa Ziehau 		    "data offset %u\n", pkt->rm_dataoffset);
501615516c77SSepherosa Ziehau 		return;
501715516c77SSepherosa Ziehau 	}
501815516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdataoffset > 0 &&
501915516c77SSepherosa Ziehau 	    IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
502015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
502115516c77SSepherosa Ziehau 		    "oob offset %u\n", pkt->rm_oobdataoffset);
502215516c77SSepherosa Ziehau 		return;
502315516c77SSepherosa Ziehau 	}
502415516c77SSepherosa Ziehau 	if (__predict_true(pkt->rm_pktinfooffset > 0) &&
502515516c77SSepherosa Ziehau 	    __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
502615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
502715516c77SSepherosa Ziehau 		    "pktinfo offset %u\n", pkt->rm_pktinfooffset);
502815516c77SSepherosa Ziehau 		return;
502915516c77SSepherosa Ziehau 	}
503015516c77SSepherosa Ziehau 
503115516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID
503215516c77SSepherosa Ziehau 
503315516c77SSepherosa Ziehau 	data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
503415516c77SSepherosa Ziehau 	data_len = pkt->rm_datalen;
503515516c77SSepherosa Ziehau 	pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
503615516c77SSepherosa Ziehau 	pktinfo_len = pkt->rm_pktinfolen;
503715516c77SSepherosa Ziehau 
503815516c77SSepherosa Ziehau 	/*
503915516c77SSepherosa Ziehau 	 * Check OOB coverage.
504015516c77SSepherosa Ziehau 	 */
504115516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdatalen != 0)) {
504215516c77SSepherosa Ziehau 		int oob_off, oob_len;
504315516c77SSepherosa Ziehau 
504415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "got oobdata\n");
504515516c77SSepherosa Ziehau 		oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
504615516c77SSepherosa Ziehau 		oob_len = pkt->rm_oobdatalen;
504715516c77SSepherosa Ziehau 
504815516c77SSepherosa Ziehau 		if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
504915516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
505015516c77SSepherosa Ziehau 			    "oob overflow, msglen %u, oob abs %d len %d\n",
505115516c77SSepherosa Ziehau 			    pkt->rm_len, oob_off, oob_len);
505215516c77SSepherosa Ziehau 			return;
505315516c77SSepherosa Ziehau 		}
505415516c77SSepherosa Ziehau 
505515516c77SSepherosa Ziehau 		/*
505615516c77SSepherosa Ziehau 		 * Check against data.
505715516c77SSepherosa Ziehau 		 */
505815516c77SSepherosa Ziehau 		if (hn_rndis_check_overlap(oob_off, oob_len,
505915516c77SSepherosa Ziehau 		    data_off, data_len)) {
506015516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
506115516c77SSepherosa Ziehau 			    "oob overlaps data, oob abs %d len %d, "
506215516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
506315516c77SSepherosa Ziehau 			    oob_off, oob_len, data_off, data_len);
506415516c77SSepherosa Ziehau 			return;
506515516c77SSepherosa Ziehau 		}
506615516c77SSepherosa Ziehau 
506715516c77SSepherosa Ziehau 		/*
506815516c77SSepherosa Ziehau 		 * Check against pktinfo.
506915516c77SSepherosa Ziehau 		 */
507015516c77SSepherosa Ziehau 		if (pktinfo_len != 0 &&
507115516c77SSepherosa Ziehau 		    hn_rndis_check_overlap(oob_off, oob_len,
507215516c77SSepherosa Ziehau 		    pktinfo_off, pktinfo_len)) {
507315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
507415516c77SSepherosa Ziehau 			    "oob overlaps pktinfo, oob abs %d len %d, "
507515516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
507615516c77SSepherosa Ziehau 			    oob_off, oob_len, pktinfo_off, pktinfo_len);
507715516c77SSepherosa Ziehau 			return;
507815516c77SSepherosa Ziehau 		}
507915516c77SSepherosa Ziehau 	}
508015516c77SSepherosa Ziehau 
508115516c77SSepherosa Ziehau 	/*
508215516c77SSepherosa Ziehau 	 * Check per-packet-info coverage and find useful per-packet-info.
508315516c77SSepherosa Ziehau 	 */
508415516c77SSepherosa Ziehau 	info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
508515516c77SSepherosa Ziehau 	info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
508615516c77SSepherosa Ziehau 	info.hash_info = HN_NDIS_HASH_INFO_INVALID;
508715516c77SSepherosa Ziehau 	if (__predict_true(pktinfo_len != 0)) {
508815516c77SSepherosa Ziehau 		bool overlap;
508915516c77SSepherosa Ziehau 		int error;
509015516c77SSepherosa Ziehau 
509115516c77SSepherosa Ziehau 		if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
509215516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
509315516c77SSepherosa Ziehau 			    "pktinfo overflow, msglen %u, "
509415516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
509515516c77SSepherosa Ziehau 			    pkt->rm_len, pktinfo_off, pktinfo_len);
509615516c77SSepherosa Ziehau 			return;
509715516c77SSepherosa Ziehau 		}
509815516c77SSepherosa Ziehau 
509915516c77SSepherosa Ziehau 		/*
510015516c77SSepherosa Ziehau 		 * Check packet info coverage.
510115516c77SSepherosa Ziehau 		 */
510215516c77SSepherosa Ziehau 		overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
510315516c77SSepherosa Ziehau 		    data_off, data_len);
510415516c77SSepherosa Ziehau 		if (__predict_false(overlap)) {
510515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
510615516c77SSepherosa Ziehau 			    "pktinfo overlap data, pktinfo abs %d len %d, "
510715516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
510815516c77SSepherosa Ziehau 			    pktinfo_off, pktinfo_len, data_off, data_len);
510915516c77SSepherosa Ziehau 			return;
511015516c77SSepherosa Ziehau 		}
511115516c77SSepherosa Ziehau 
511215516c77SSepherosa Ziehau 		/*
511315516c77SSepherosa Ziehau 		 * Find useful per-packet-info.
511415516c77SSepherosa Ziehau 		 */
511515516c77SSepherosa Ziehau 		error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
511615516c77SSepherosa Ziehau 		    pktinfo_len, &info);
511715516c77SSepherosa Ziehau 		if (__predict_false(error)) {
511815516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
511915516c77SSepherosa Ziehau 			    "pktinfo\n");
512015516c77SSepherosa Ziehau 			return;
512115516c77SSepherosa Ziehau 		}
512215516c77SSepherosa Ziehau 	}
512315516c77SSepherosa Ziehau 
512415516c77SSepherosa Ziehau 	if (__predict_false(data_off + data_len > pkt->rm_len)) {
512515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
512615516c77SSepherosa Ziehau 		    "data overflow, msglen %u, data abs %d len %d\n",
512715516c77SSepherosa Ziehau 		    pkt->rm_len, data_off, data_len);
512815516c77SSepherosa Ziehau 		return;
512915516c77SSepherosa Ziehau 	}
513015516c77SSepherosa Ziehau 	hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
513115516c77SSepherosa Ziehau }
513215516c77SSepherosa Ziehau 
513315516c77SSepherosa Ziehau static __inline void
513415516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen)
513515516c77SSepherosa Ziehau {
513615516c77SSepherosa Ziehau 	const struct rndis_msghdr *hdr;
513715516c77SSepherosa Ziehau 
513815516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*hdr))) {
513915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
514015516c77SSepherosa Ziehau 		return;
514115516c77SSepherosa Ziehau 	}
514215516c77SSepherosa Ziehau 	hdr = data;
514315516c77SSepherosa Ziehau 
514415516c77SSepherosa Ziehau 	if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) {
514515516c77SSepherosa Ziehau 		/* Hot data path. */
514615516c77SSepherosa Ziehau 		hn_rndis_rx_data(rxr, data, dlen);
514715516c77SSepherosa Ziehau 		/* Done! */
514815516c77SSepherosa Ziehau 		return;
514915516c77SSepherosa Ziehau 	}
515015516c77SSepherosa Ziehau 
515115516c77SSepherosa Ziehau 	if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG)
515215516c77SSepherosa Ziehau 		hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen);
515315516c77SSepherosa Ziehau 	else
515415516c77SSepherosa Ziehau 		hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen);
515515516c77SSepherosa Ziehau }
515615516c77SSepherosa Ziehau 
515715516c77SSepherosa Ziehau static void
515815516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
515915516c77SSepherosa Ziehau {
516015516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *hdr;
516115516c77SSepherosa Ziehau 
516215516c77SSepherosa Ziehau 	if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) {
516315516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid nvs notify\n");
516415516c77SSepherosa Ziehau 		return;
516515516c77SSepherosa Ziehau 	}
516615516c77SSepherosa Ziehau 	hdr = VMBUS_CHANPKT_CONST_DATA(pkt);
516715516c77SSepherosa Ziehau 
516815516c77SSepherosa Ziehau 	if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) {
516915516c77SSepherosa Ziehau 		/* Useless; ignore */
517015516c77SSepherosa Ziehau 		return;
517115516c77SSepherosa Ziehau 	}
517215516c77SSepherosa Ziehau 	if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type);
517315516c77SSepherosa Ziehau }
517415516c77SSepherosa Ziehau 
517515516c77SSepherosa Ziehau static void
517615516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan,
517715516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkt)
517815516c77SSepherosa Ziehau {
517915516c77SSepherosa Ziehau 	struct hn_nvs_sendctx *sndc;
518015516c77SSepherosa Ziehau 
518115516c77SSepherosa Ziehau 	sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid;
518215516c77SSepherosa Ziehau 	sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt),
518315516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_DATALEN(pkt));
518415516c77SSepherosa Ziehau 	/*
518515516c77SSepherosa Ziehau 	 * NOTE:
518615516c77SSepherosa Ziehau 	 * 'sndc' CAN NOT be accessed anymore, since it can be freed by
518715516c77SSepherosa Ziehau 	 * its callback.
518815516c77SSepherosa Ziehau 	 */
518915516c77SSepherosa Ziehau }
519015516c77SSepherosa Ziehau 
519115516c77SSepherosa Ziehau static void
519215516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
519315516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkthdr)
519415516c77SSepherosa Ziehau {
519515516c77SSepherosa Ziehau 	const struct vmbus_chanpkt_rxbuf *pkt;
519615516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *nvs_hdr;
519715516c77SSepherosa Ziehau 	int count, i, hlen;
519815516c77SSepherosa Ziehau 
519915516c77SSepherosa Ziehau 	if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) {
520015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n");
520115516c77SSepherosa Ziehau 		return;
520215516c77SSepherosa Ziehau 	}
520315516c77SSepherosa Ziehau 	nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr);
520415516c77SSepherosa Ziehau 
520515516c77SSepherosa Ziehau 	/* Make sure that this is a RNDIS message. */
520615516c77SSepherosa Ziehau 	if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) {
520715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n",
520815516c77SSepherosa Ziehau 		    nvs_hdr->nvs_type);
520915516c77SSepherosa Ziehau 		return;
521015516c77SSepherosa Ziehau 	}
521115516c77SSepherosa Ziehau 
521215516c77SSepherosa Ziehau 	hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen);
521315516c77SSepherosa Ziehau 	if (__predict_false(hlen < sizeof(*pkt))) {
521415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n");
521515516c77SSepherosa Ziehau 		return;
521615516c77SSepherosa Ziehau 	}
521715516c77SSepherosa Ziehau 	pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
521815516c77SSepherosa Ziehau 
521915516c77SSepherosa Ziehau 	if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) {
522015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n",
522115516c77SSepherosa Ziehau 		    pkt->cp_rxbuf_id);
522215516c77SSepherosa Ziehau 		return;
522315516c77SSepherosa Ziehau 	}
522415516c77SSepherosa Ziehau 
522515516c77SSepherosa Ziehau 	count = pkt->cp_rxbuf_cnt;
522615516c77SSepherosa Ziehau 	if (__predict_false(hlen <
522715516c77SSepherosa Ziehau 	    __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) {
522815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count);
522915516c77SSepherosa Ziehau 		return;
523015516c77SSepherosa Ziehau 	}
523115516c77SSepherosa Ziehau 
523215516c77SSepherosa Ziehau 	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
523315516c77SSepherosa Ziehau 	for (i = 0; i < count; ++i) {
523415516c77SSepherosa Ziehau 		int ofs, len;
523515516c77SSepherosa Ziehau 
523615516c77SSepherosa Ziehau 		ofs = pkt->cp_rxbuf[i].rb_ofs;
523715516c77SSepherosa Ziehau 		len = pkt->cp_rxbuf[i].rb_len;
523815516c77SSepherosa Ziehau 		if (__predict_false(ofs + len > HN_RXBUF_SIZE)) {
523915516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, "
524015516c77SSepherosa Ziehau 			    "ofs %d, len %d\n", i, ofs, len);
524115516c77SSepherosa Ziehau 			continue;
524215516c77SSepherosa Ziehau 		}
524315516c77SSepherosa Ziehau 		hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len);
524415516c77SSepherosa Ziehau 	}
524515516c77SSepherosa Ziehau 
524615516c77SSepherosa Ziehau 	/*
524715516c77SSepherosa Ziehau 	 * Ack the consumed RXBUF associated w/ this channel packet,
524815516c77SSepherosa Ziehau 	 * so that this RXBUF can be recycled by the hypervisor.
524915516c77SSepherosa Ziehau 	 */
525015516c77SSepherosa Ziehau 	hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid);
525115516c77SSepherosa Ziehau }
525215516c77SSepherosa Ziehau 
525315516c77SSepherosa Ziehau static void
525415516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
525515516c77SSepherosa Ziehau     uint64_t tid)
525615516c77SSepherosa Ziehau {
525715516c77SSepherosa Ziehau 	struct hn_nvs_rndis_ack ack;
525815516c77SSepherosa Ziehau 	int retries, error;
525915516c77SSepherosa Ziehau 
526015516c77SSepherosa Ziehau 	ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK;
526115516c77SSepherosa Ziehau 	ack.nvs_status = HN_NVS_STATUS_OK;
526215516c77SSepherosa Ziehau 
526315516c77SSepherosa Ziehau 	retries = 0;
526415516c77SSepherosa Ziehau again:
526515516c77SSepherosa Ziehau 	error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP,
526615516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid);
526715516c77SSepherosa Ziehau 	if (__predict_false(error == EAGAIN)) {
526815516c77SSepherosa Ziehau 		/*
526915516c77SSepherosa Ziehau 		 * NOTE:
527015516c77SSepherosa Ziehau 		 * This should _not_ happen in real world, since the
527115516c77SSepherosa Ziehau 		 * consumption of the TX bufring from the TX path is
527215516c77SSepherosa Ziehau 		 * controlled.
527315516c77SSepherosa Ziehau 		 */
527415516c77SSepherosa Ziehau 		if (rxr->hn_ack_failed == 0)
527515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "RXBUF ack retry\n");
527615516c77SSepherosa Ziehau 		rxr->hn_ack_failed++;
527715516c77SSepherosa Ziehau 		retries++;
527815516c77SSepherosa Ziehau 		if (retries < 10) {
527915516c77SSepherosa Ziehau 			DELAY(100);
528015516c77SSepherosa Ziehau 			goto again;
528115516c77SSepherosa Ziehau 		}
528215516c77SSepherosa Ziehau 		/* RXBUF leaks! */
528315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "RXBUF ack failed\n");
528415516c77SSepherosa Ziehau 	}
528515516c77SSepherosa Ziehau }
528615516c77SSepherosa Ziehau 
528715516c77SSepherosa Ziehau static void
528815516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr)
528915516c77SSepherosa Ziehau {
529015516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr = xrxr;
529115516c77SSepherosa Ziehau 	struct hn_softc *sc = rxr->hn_ifp->if_softc;
529215516c77SSepherosa Ziehau 
529315516c77SSepherosa Ziehau 	for (;;) {
529415516c77SSepherosa Ziehau 		struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf;
529515516c77SSepherosa Ziehau 		int error, pktlen;
529615516c77SSepherosa Ziehau 
529715516c77SSepherosa Ziehau 		pktlen = rxr->hn_pktbuf_len;
529815516c77SSepherosa Ziehau 		error = vmbus_chan_recv_pkt(chan, pkt, &pktlen);
529915516c77SSepherosa Ziehau 		if (__predict_false(error == ENOBUFS)) {
530015516c77SSepherosa Ziehau 			void *nbuf;
530115516c77SSepherosa Ziehau 			int nlen;
530215516c77SSepherosa Ziehau 
530315516c77SSepherosa Ziehau 			/*
530415516c77SSepherosa Ziehau 			 * Expand channel packet buffer.
530515516c77SSepherosa Ziehau 			 *
530615516c77SSepherosa Ziehau 			 * XXX
530715516c77SSepherosa Ziehau 			 * Use M_WAITOK here, since allocation failure
530815516c77SSepherosa Ziehau 			 * is fatal.
530915516c77SSepherosa Ziehau 			 */
531015516c77SSepherosa Ziehau 			nlen = rxr->hn_pktbuf_len * 2;
531115516c77SSepherosa Ziehau 			while (nlen < pktlen)
531215516c77SSepherosa Ziehau 				nlen *= 2;
531315516c77SSepherosa Ziehau 			nbuf = malloc(nlen, M_DEVBUF, M_WAITOK);
531415516c77SSepherosa Ziehau 
531515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n",
531615516c77SSepherosa Ziehau 			    rxr->hn_pktbuf_len, nlen);
531715516c77SSepherosa Ziehau 
531815516c77SSepherosa Ziehau 			free(rxr->hn_pktbuf, M_DEVBUF);
531915516c77SSepherosa Ziehau 			rxr->hn_pktbuf = nbuf;
532015516c77SSepherosa Ziehau 			rxr->hn_pktbuf_len = nlen;
532115516c77SSepherosa Ziehau 			/* Retry! */
532215516c77SSepherosa Ziehau 			continue;
532315516c77SSepherosa Ziehau 		} else if (__predict_false(error == EAGAIN)) {
532415516c77SSepherosa Ziehau 			/* No more channel packets; done! */
532515516c77SSepherosa Ziehau 			break;
532615516c77SSepherosa Ziehau 		}
532715516c77SSepherosa Ziehau 		KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error));
532815516c77SSepherosa Ziehau 
532915516c77SSepherosa Ziehau 		switch (pkt->cph_type) {
533015516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_COMP:
533115516c77SSepherosa Ziehau 			hn_nvs_handle_comp(sc, chan, pkt);
533215516c77SSepherosa Ziehau 			break;
533315516c77SSepherosa Ziehau 
533415516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_RXBUF:
533515516c77SSepherosa Ziehau 			hn_nvs_handle_rxbuf(rxr, chan, pkt);
533615516c77SSepherosa Ziehau 			break;
533715516c77SSepherosa Ziehau 
533815516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_INBAND:
533915516c77SSepherosa Ziehau 			hn_nvs_handle_notify(sc, pkt);
534015516c77SSepherosa Ziehau 			break;
534115516c77SSepherosa Ziehau 
534215516c77SSepherosa Ziehau 		default:
534315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "unknown chan pkt %u\n",
534415516c77SSepherosa Ziehau 			    pkt->cph_type);
534515516c77SSepherosa Ziehau 			break;
534615516c77SSepherosa Ziehau 		}
534715516c77SSepherosa Ziehau 	}
534815516c77SSepherosa Ziehau 	hn_chan_rollup(rxr, rxr->hn_txr);
534915516c77SSepherosa Ziehau }
535015516c77SSepherosa Ziehau 
535115516c77SSepherosa Ziehau static void
535215516c77SSepherosa Ziehau hn_tx_taskq_create(void *arg __unused)
535315516c77SSepherosa Ziehau {
5354*fdd0222aSSepherosa Ziehau 	int i;
5355*fdd0222aSSepherosa Ziehau 
5356*fdd0222aSSepherosa Ziehau 	/*
5357*fdd0222aSSepherosa Ziehau 	 * Fix the # of TX taskqueues.
5358*fdd0222aSSepherosa Ziehau 	 */
5359*fdd0222aSSepherosa Ziehau 	if (hn_tx_taskq_cnt <= 0)
5360*fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = 1;
5361*fdd0222aSSepherosa Ziehau 	else if (hn_tx_taskq_cnt > mp_ncpus)
5362*fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = mp_ncpus;
536315516c77SSepherosa Ziehau 
536415516c77SSepherosa Ziehau 	if (vm_guest != VM_GUEST_HV)
536515516c77SSepherosa Ziehau 		return;
536615516c77SSepherosa Ziehau 
536715516c77SSepherosa Ziehau 	if (!hn_share_tx_taskq)
536815516c77SSepherosa Ziehau 		return;
536915516c77SSepherosa Ziehau 
5370*fdd0222aSSepherosa Ziehau 	hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
5371*fdd0222aSSepherosa Ziehau 	    M_DEVBUF, M_WAITOK);
5372*fdd0222aSSepherosa Ziehau 	for (i = 0; i < hn_tx_taskq_cnt; ++i) {
5373*fdd0222aSSepherosa Ziehau 		hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK,
5374*fdd0222aSSepherosa Ziehau 		    taskqueue_thread_enqueue, &hn_tx_taskque[i]);
5375*fdd0222aSSepherosa Ziehau 		taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET,
5376*fdd0222aSSepherosa Ziehau 		    "hn tx%d", i);
5377*fdd0222aSSepherosa Ziehau 	}
537815516c77SSepherosa Ziehau }
537915516c77SSepherosa Ziehau SYSINIT(hn_txtq_create, SI_SUB_DRIVERS, SI_ORDER_SECOND,
538015516c77SSepherosa Ziehau     hn_tx_taskq_create, NULL);
538115516c77SSepherosa Ziehau 
538215516c77SSepherosa Ziehau static void
538315516c77SSepherosa Ziehau hn_tx_taskq_destroy(void *arg __unused)
538415516c77SSepherosa Ziehau {
538515516c77SSepherosa Ziehau 
5386*fdd0222aSSepherosa Ziehau 	if (hn_tx_taskque != NULL) {
5387*fdd0222aSSepherosa Ziehau 		int i;
5388*fdd0222aSSepherosa Ziehau 
5389*fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
5390*fdd0222aSSepherosa Ziehau 			taskqueue_free(hn_tx_taskque[i]);
5391*fdd0222aSSepherosa Ziehau 		free(hn_tx_taskque, M_DEVBUF);
5392*fdd0222aSSepherosa Ziehau 	}
539315516c77SSepherosa Ziehau }
539415516c77SSepherosa Ziehau SYSUNINIT(hn_txtq_destroy, SI_SUB_DRIVERS, SI_ORDER_SECOND,
539515516c77SSepherosa Ziehau     hn_tx_taskq_destroy, NULL);
5396