xref: /freebsd/sys/dev/hyperv/netvsc/if_hn.c (revision 6c1204df36ac61e01a12c770d46a0acbd905e502)
115516c77SSepherosa Ziehau /*-
215516c77SSepherosa Ziehau  * Copyright (c) 2010-2012 Citrix Inc.
315516c77SSepherosa Ziehau  * Copyright (c) 2009-2012,2016 Microsoft Corp.
415516c77SSepherosa Ziehau  * Copyright (c) 2012 NetApp Inc.
515516c77SSepherosa Ziehau  * All rights reserved.
615516c77SSepherosa Ziehau  *
715516c77SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
815516c77SSepherosa Ziehau  * modification, are permitted provided that the following conditions
915516c77SSepherosa Ziehau  * are met:
1015516c77SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
1115516c77SSepherosa Ziehau  *    notice unmodified, this list of conditions, and the following
1215516c77SSepherosa Ziehau  *    disclaimer.
1315516c77SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
1415516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
1515516c77SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
1615516c77SSepherosa Ziehau  *
1715516c77SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1815516c77SSepherosa Ziehau  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1915516c77SSepherosa Ziehau  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2015516c77SSepherosa Ziehau  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2115516c77SSepherosa Ziehau  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2215516c77SSepherosa Ziehau  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2315516c77SSepherosa Ziehau  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2415516c77SSepherosa Ziehau  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2515516c77SSepherosa Ziehau  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2615516c77SSepherosa Ziehau  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2715516c77SSepherosa Ziehau  */
2815516c77SSepherosa Ziehau 
2915516c77SSepherosa Ziehau /*-
3015516c77SSepherosa Ziehau  * Copyright (c) 2004-2006 Kip Macy
3115516c77SSepherosa Ziehau  * All rights reserved.
3215516c77SSepherosa Ziehau  *
3315516c77SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
3415516c77SSepherosa Ziehau  * modification, are permitted provided that the following conditions
3515516c77SSepherosa Ziehau  * are met:
3615516c77SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
3715516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer.
3815516c77SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
3915516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
4015516c77SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
4115516c77SSepherosa Ziehau  *
4215516c77SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
4315516c77SSepherosa Ziehau  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4415516c77SSepherosa Ziehau  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4515516c77SSepherosa Ziehau  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4615516c77SSepherosa Ziehau  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4715516c77SSepherosa Ziehau  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4815516c77SSepherosa Ziehau  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4915516c77SSepherosa Ziehau  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5015516c77SSepherosa Ziehau  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5115516c77SSepherosa Ziehau  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5215516c77SSepherosa Ziehau  * SUCH DAMAGE.
5315516c77SSepherosa Ziehau  */
5415516c77SSepherosa Ziehau 
5515516c77SSepherosa Ziehau #include <sys/cdefs.h>
5615516c77SSepherosa Ziehau __FBSDID("$FreeBSD$");
5715516c77SSepherosa Ziehau 
5834d68912SSepherosa Ziehau #include "opt_hn.h"
5915516c77SSepherosa Ziehau #include "opt_inet6.h"
6015516c77SSepherosa Ziehau #include "opt_inet.h"
6134d68912SSepherosa Ziehau #include "opt_rss.h"
6215516c77SSepherosa Ziehau 
6315516c77SSepherosa Ziehau #include <sys/param.h>
6415516c77SSepherosa Ziehau #include <sys/bus.h>
6515516c77SSepherosa Ziehau #include <sys/kernel.h>
6615516c77SSepherosa Ziehau #include <sys/limits.h>
6715516c77SSepherosa Ziehau #include <sys/malloc.h>
6815516c77SSepherosa Ziehau #include <sys/mbuf.h>
6915516c77SSepherosa Ziehau #include <sys/module.h>
7015516c77SSepherosa Ziehau #include <sys/queue.h>
7115516c77SSepherosa Ziehau #include <sys/lock.h>
7215516c77SSepherosa Ziehau #include <sys/smp.h>
7315516c77SSepherosa Ziehau #include <sys/socket.h>
7415516c77SSepherosa Ziehau #include <sys/sockio.h>
7515516c77SSepherosa Ziehau #include <sys/sx.h>
7615516c77SSepherosa Ziehau #include <sys/sysctl.h>
7715516c77SSepherosa Ziehau #include <sys/systm.h>
7815516c77SSepherosa Ziehau #include <sys/taskqueue.h>
7915516c77SSepherosa Ziehau #include <sys/buf_ring.h>
8015516c77SSepherosa Ziehau 
8115516c77SSepherosa Ziehau #include <machine/atomic.h>
8215516c77SSepherosa Ziehau #include <machine/in_cksum.h>
8315516c77SSepherosa Ziehau 
8415516c77SSepherosa Ziehau #include <net/bpf.h>
8515516c77SSepherosa Ziehau #include <net/ethernet.h>
8615516c77SSepherosa Ziehau #include <net/if.h>
8715516c77SSepherosa Ziehau #include <net/if_media.h>
8815516c77SSepherosa Ziehau #include <net/if_types.h>
8915516c77SSepherosa Ziehau #include <net/if_var.h>
9015516c77SSepherosa Ziehau #include <net/rndis.h>
9134d68912SSepherosa Ziehau #ifdef RSS
9234d68912SSepherosa Ziehau #include <net/rss_config.h>
9334d68912SSepherosa Ziehau #endif
9415516c77SSepherosa Ziehau 
9515516c77SSepherosa Ziehau #include <netinet/in_systm.h>
9615516c77SSepherosa Ziehau #include <netinet/in.h>
9715516c77SSepherosa Ziehau #include <netinet/ip.h>
9815516c77SSepherosa Ziehau #include <netinet/ip6.h>
9915516c77SSepherosa Ziehau #include <netinet/tcp.h>
10015516c77SSepherosa Ziehau #include <netinet/tcp_lro.h>
10115516c77SSepherosa Ziehau #include <netinet/udp.h>
10215516c77SSepherosa Ziehau 
10315516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h>
10415516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv_busdma.h>
10515516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus.h>
10615516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus_xact.h>
10715516c77SSepherosa Ziehau 
10815516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/ndis.h>
10915516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnreg.h>
11015516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnvar.h>
11115516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_nvs.h>
11215516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_rndis.h>
11315516c77SSepherosa Ziehau 
11415516c77SSepherosa Ziehau #include "vmbus_if.h"
11515516c77SSepherosa Ziehau 
11623bf9e15SSepherosa Ziehau #define HN_IFSTART_SUPPORT
11723bf9e15SSepherosa Ziehau 
11815516c77SSepherosa Ziehau #define HN_RING_CNT_DEF_MAX		8
11915516c77SSepherosa Ziehau 
12015516c77SSepherosa Ziehau /* YYY should get it from the underlying channel */
12115516c77SSepherosa Ziehau #define HN_TX_DESC_CNT			512
12215516c77SSepherosa Ziehau 
12315516c77SSepherosa Ziehau #define HN_RNDIS_PKT_LEN					\
12415516c77SSepherosa Ziehau 	(sizeof(struct rndis_packet_msg) +			\
12515516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) +	\
12615516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) +		\
12715516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) +		\
12815516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_TXCSUM_INFO_SIZE))
12915516c77SSepherosa Ziehau #define HN_RNDIS_PKT_BOUNDARY		PAGE_SIZE
13015516c77SSepherosa Ziehau #define HN_RNDIS_PKT_ALIGN		CACHE_LINE_SIZE
13115516c77SSepherosa Ziehau 
13215516c77SSepherosa Ziehau #define HN_TX_DATA_BOUNDARY		PAGE_SIZE
13315516c77SSepherosa Ziehau #define HN_TX_DATA_MAXSIZE		IP_MAXPACKET
13415516c77SSepherosa Ziehau #define HN_TX_DATA_SEGSIZE		PAGE_SIZE
13515516c77SSepherosa Ziehau /* -1 for RNDIS packet message */
13615516c77SSepherosa Ziehau #define HN_TX_DATA_SEGCNT_MAX		(HN_GPACNT_MAX - 1)
13715516c77SSepherosa Ziehau 
13815516c77SSepherosa Ziehau #define HN_DIRECT_TX_SIZE_DEF		128
13915516c77SSepherosa Ziehau 
14015516c77SSepherosa Ziehau #define HN_EARLY_TXEOF_THRESH		8
14115516c77SSepherosa Ziehau 
14215516c77SSepherosa Ziehau #define HN_PKTBUF_LEN_DEF		(16 * 1024)
14315516c77SSepherosa Ziehau 
14415516c77SSepherosa Ziehau #define HN_LROENT_CNT_DEF		128
14515516c77SSepherosa Ziehau 
14615516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MULTIRX_DEF	(12 * ETHERMTU)
14715516c77SSepherosa Ziehau #define HN_LRO_LENLIM_DEF		(25 * ETHERMTU)
14815516c77SSepherosa Ziehau /* YYY 2*MTU is a bit rough, but should be good enough. */
14915516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MIN(ifp)		(2 * (ifp)->if_mtu)
15015516c77SSepherosa Ziehau 
15115516c77SSepherosa Ziehau #define HN_LRO_ACKCNT_DEF		1
15215516c77SSepherosa Ziehau 
15315516c77SSepherosa Ziehau #define HN_LOCK_INIT(sc)		\
15415516c77SSepherosa Ziehau 	sx_init(&(sc)->hn_lock, device_get_nameunit((sc)->hn_dev))
15515516c77SSepherosa Ziehau #define HN_LOCK_DESTROY(sc)		sx_destroy(&(sc)->hn_lock)
15615516c77SSepherosa Ziehau #define HN_LOCK_ASSERT(sc)		sx_assert(&(sc)->hn_lock, SA_XLOCKED)
157fdc4f478SSepherosa Ziehau #define HN_LOCK(sc)					\
158fdc4f478SSepherosa Ziehau do {							\
159fdc4f478SSepherosa Ziehau 	while (sx_try_xlock(&(sc)->hn_lock) == 0)	\
160fdc4f478SSepherosa Ziehau 		DELAY(1000);				\
161fdc4f478SSepherosa Ziehau } while (0)
16215516c77SSepherosa Ziehau #define HN_UNLOCK(sc)			sx_xunlock(&(sc)->hn_lock)
16315516c77SSepherosa Ziehau 
16415516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK			(CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP)
16515516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK		(CSUM_IP6_TCP | CSUM_IP6_UDP)
16615516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc)		\
16715516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK)
16815516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc)	\
16915516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK)
17015516c77SSepherosa Ziehau 
171dc13fee6SSepherosa Ziehau #define HN_PKTSIZE_MIN(align)		\
172dc13fee6SSepherosa Ziehau 	roundup2(ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN + \
173dc13fee6SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN, (align))
174dc13fee6SSepherosa Ziehau #define HN_PKTSIZE(m, align)		\
175dc13fee6SSepherosa Ziehau 	roundup2((m)->m_pkthdr.len + HN_RNDIS_PKT_LEN, (align))
176dc13fee6SSepherosa Ziehau 
17734d68912SSepherosa Ziehau #ifdef RSS
17834d68912SSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx)	rss_getcpu((idx) % rss_getnumbuckets())
17934d68912SSepherosa Ziehau #else
1800e11868dSSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx)	(((sc)->hn_cpu + (idx)) % mp_ncpus)
18134d68912SSepherosa Ziehau #endif
1820e11868dSSepherosa Ziehau 
18315516c77SSepherosa Ziehau struct hn_txdesc {
18415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
18515516c77SSepherosa Ziehau 	SLIST_ENTRY(hn_txdesc)		link;
18615516c77SSepherosa Ziehau #endif
187dc13fee6SSepherosa Ziehau 	STAILQ_ENTRY(hn_txdesc)		agg_link;
188dc13fee6SSepherosa Ziehau 
189dc13fee6SSepherosa Ziehau 	/* Aggregated txdescs, in sending order. */
190dc13fee6SSepherosa Ziehau 	STAILQ_HEAD(, hn_txdesc)	agg_list;
191dc13fee6SSepherosa Ziehau 
192dc13fee6SSepherosa Ziehau 	/* The oldest packet, if transmission aggregation happens. */
19315516c77SSepherosa Ziehau 	struct mbuf			*m;
19415516c77SSepherosa Ziehau 	struct hn_tx_ring		*txr;
19515516c77SSepherosa Ziehau 	int				refs;
19615516c77SSepherosa Ziehau 	uint32_t			flags;	/* HN_TXD_FLAG_ */
19715516c77SSepherosa Ziehau 	struct hn_nvs_sendctx		send_ctx;
19815516c77SSepherosa Ziehau 	uint32_t			chim_index;
19915516c77SSepherosa Ziehau 	int				chim_size;
20015516c77SSepherosa Ziehau 
20115516c77SSepherosa Ziehau 	bus_dmamap_t			data_dmap;
20215516c77SSepherosa Ziehau 
20315516c77SSepherosa Ziehau 	bus_addr_t			rndis_pkt_paddr;
20415516c77SSepherosa Ziehau 	struct rndis_packet_msg		*rndis_pkt;
20515516c77SSepherosa Ziehau 	bus_dmamap_t			rndis_pkt_dmap;
20615516c77SSepherosa Ziehau };
20715516c77SSepherosa Ziehau 
20815516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST		0x0001
20915516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP		0x0002
210dc13fee6SSepherosa Ziehau #define HN_TXD_FLAG_ONAGG		0x0004
21115516c77SSepherosa Ziehau 
21215516c77SSepherosa Ziehau struct hn_rxinfo {
21315516c77SSepherosa Ziehau 	uint32_t			vlan_info;
21415516c77SSepherosa Ziehau 	uint32_t			csum_info;
21515516c77SSepherosa Ziehau 	uint32_t			hash_info;
21615516c77SSepherosa Ziehau 	uint32_t			hash_value;
21715516c77SSepherosa Ziehau };
21815516c77SSepherosa Ziehau 
21915516c77SSepherosa Ziehau #define HN_RXINFO_VLAN			0x0001
22015516c77SSepherosa Ziehau #define HN_RXINFO_CSUM			0x0002
22115516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF		0x0004
22215516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL		0x0008
22315516c77SSepherosa Ziehau #define HN_RXINFO_ALL			\
22415516c77SSepherosa Ziehau 	(HN_RXINFO_VLAN |		\
22515516c77SSepherosa Ziehau 	 HN_RXINFO_CSUM |		\
22615516c77SSepherosa Ziehau 	 HN_RXINFO_HASHINF |		\
22715516c77SSepherosa Ziehau 	 HN_RXINFO_HASHVAL)
22815516c77SSepherosa Ziehau 
22915516c77SSepherosa Ziehau #define HN_NDIS_VLAN_INFO_INVALID	0xffffffff
23015516c77SSepherosa Ziehau #define HN_NDIS_RXCSUM_INFO_INVALID	0
23115516c77SSepherosa Ziehau #define HN_NDIS_HASH_INFO_INVALID	0
23215516c77SSepherosa Ziehau 
23315516c77SSepherosa Ziehau static int			hn_probe(device_t);
23415516c77SSepherosa Ziehau static int			hn_attach(device_t);
23515516c77SSepherosa Ziehau static int			hn_detach(device_t);
23615516c77SSepherosa Ziehau static int			hn_shutdown(device_t);
23715516c77SSepherosa Ziehau static void			hn_chan_callback(struct vmbus_channel *,
23815516c77SSepherosa Ziehau 				    void *);
23915516c77SSepherosa Ziehau 
24015516c77SSepherosa Ziehau static void			hn_init(void *);
24115516c77SSepherosa Ziehau static int			hn_ioctl(struct ifnet *, u_long, caddr_t);
24223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
24315516c77SSepherosa Ziehau static void			hn_start(struct ifnet *);
24423bf9e15SSepherosa Ziehau #endif
24515516c77SSepherosa Ziehau static int			hn_transmit(struct ifnet *, struct mbuf *);
24615516c77SSepherosa Ziehau static void			hn_xmit_qflush(struct ifnet *);
24715516c77SSepherosa Ziehau static int			hn_ifmedia_upd(struct ifnet *);
24815516c77SSepherosa Ziehau static void			hn_ifmedia_sts(struct ifnet *,
24915516c77SSepherosa Ziehau 				    struct ifmediareq *);
25015516c77SSepherosa Ziehau 
25115516c77SSepherosa Ziehau static int			hn_rndis_rxinfo(const void *, int,
25215516c77SSepherosa Ziehau 				    struct hn_rxinfo *);
25315516c77SSepherosa Ziehau static void			hn_rndis_rx_data(struct hn_rx_ring *,
25415516c77SSepherosa Ziehau 				    const void *, int);
25515516c77SSepherosa Ziehau static void			hn_rndis_rx_status(struct hn_softc *,
25615516c77SSepherosa Ziehau 				    const void *, int);
25715516c77SSepherosa Ziehau 
25815516c77SSepherosa Ziehau static void			hn_nvs_handle_notify(struct hn_softc *,
25915516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
26015516c77SSepherosa Ziehau static void			hn_nvs_handle_comp(struct hn_softc *,
26115516c77SSepherosa Ziehau 				    struct vmbus_channel *,
26215516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
26315516c77SSepherosa Ziehau static void			hn_nvs_handle_rxbuf(struct hn_rx_ring *,
26415516c77SSepherosa Ziehau 				    struct vmbus_channel *,
26515516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
26615516c77SSepherosa Ziehau static void			hn_nvs_ack_rxbuf(struct hn_rx_ring *,
26715516c77SSepherosa Ziehau 				    struct vmbus_channel *, uint64_t);
26815516c77SSepherosa Ziehau 
26915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
27015516c77SSepherosa Ziehau static int			hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS);
27115516c77SSepherosa Ziehau static int			hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS);
27215516c77SSepherosa Ziehau #endif
27315516c77SSepherosa Ziehau static int			hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS);
27415516c77SSepherosa Ziehau static int			hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS);
27515516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
27615516c77SSepherosa Ziehau static int			hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS);
27715516c77SSepherosa Ziehau #else
27815516c77SSepherosa Ziehau static int			hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS);
27915516c77SSepherosa Ziehau #endif
28015516c77SSepherosa Ziehau static int			hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
28115516c77SSepherosa Ziehau static int			hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
28215516c77SSepherosa Ziehau static int			hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS);
28315516c77SSepherosa Ziehau static int			hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS);
28415516c77SSepherosa Ziehau static int			hn_caps_sysctl(SYSCTL_HANDLER_ARGS);
28515516c77SSepherosa Ziehau static int			hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS);
28615516c77SSepherosa Ziehau static int			hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS);
28734d68912SSepherosa Ziehau #ifndef RSS
28815516c77SSepherosa Ziehau static int			hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS);
28915516c77SSepherosa Ziehau static int			hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS);
29034d68912SSepherosa Ziehau #endif
29115516c77SSepherosa Ziehau static int			hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS);
292dc13fee6SSepherosa Ziehau static int			hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS);
293dc13fee6SSepherosa Ziehau static int			hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS);
294dc13fee6SSepherosa Ziehau static int			hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS);
295dc13fee6SSepherosa Ziehau static int			hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS);
296*6c1204dfSSepherosa Ziehau static int			hn_polling_sysctl(SYSCTL_HANDLER_ARGS);
29715516c77SSepherosa Ziehau 
29815516c77SSepherosa Ziehau static void			hn_stop(struct hn_softc *);
29915516c77SSepherosa Ziehau static void			hn_init_locked(struct hn_softc *);
30015516c77SSepherosa Ziehau static int			hn_chan_attach(struct hn_softc *,
30115516c77SSepherosa Ziehau 				    struct vmbus_channel *);
30215516c77SSepherosa Ziehau static void			hn_chan_detach(struct hn_softc *,
30315516c77SSepherosa Ziehau 				    struct vmbus_channel *);
30415516c77SSepherosa Ziehau static int			hn_attach_subchans(struct hn_softc *);
30515516c77SSepherosa Ziehau static void			hn_detach_allchans(struct hn_softc *);
30615516c77SSepherosa Ziehau static void			hn_chan_rollup(struct hn_rx_ring *,
30715516c77SSepherosa Ziehau 				    struct hn_tx_ring *);
30815516c77SSepherosa Ziehau static void			hn_set_ring_inuse(struct hn_softc *, int);
30915516c77SSepherosa Ziehau static int			hn_synth_attach(struct hn_softc *, int);
31015516c77SSepherosa Ziehau static void			hn_synth_detach(struct hn_softc *);
31115516c77SSepherosa Ziehau static int			hn_synth_alloc_subchans(struct hn_softc *,
31215516c77SSepherosa Ziehau 				    int *);
3132494d735SSepherosa Ziehau static bool			hn_synth_attachable(const struct hn_softc *);
31415516c77SSepherosa Ziehau static void			hn_suspend(struct hn_softc *);
31515516c77SSepherosa Ziehau static void			hn_suspend_data(struct hn_softc *);
31615516c77SSepherosa Ziehau static void			hn_suspend_mgmt(struct hn_softc *);
31715516c77SSepherosa Ziehau static void			hn_resume(struct hn_softc *);
31815516c77SSepherosa Ziehau static void			hn_resume_data(struct hn_softc *);
31915516c77SSepherosa Ziehau static void			hn_resume_mgmt(struct hn_softc *);
32015516c77SSepherosa Ziehau static void			hn_suspend_mgmt_taskfunc(void *, int);
32125641fc7SSepherosa Ziehau static void			hn_chan_drain(struct hn_softc *,
32225641fc7SSepherosa Ziehau 				    struct vmbus_channel *);
323*6c1204dfSSepherosa Ziehau static void			hn_polling(struct hn_softc *, u_int);
324*6c1204dfSSepherosa Ziehau static void			hn_chan_polling(struct vmbus_channel *, u_int);
32515516c77SSepherosa Ziehau 
32615516c77SSepherosa Ziehau static void			hn_update_link_status(struct hn_softc *);
32715516c77SSepherosa Ziehau static void			hn_change_network(struct hn_softc *);
32815516c77SSepherosa Ziehau static void			hn_link_taskfunc(void *, int);
32915516c77SSepherosa Ziehau static void			hn_netchg_init_taskfunc(void *, int);
33015516c77SSepherosa Ziehau static void			hn_netchg_status_taskfunc(void *, int);
33115516c77SSepherosa Ziehau static void			hn_link_status(struct hn_softc *);
33215516c77SSepherosa Ziehau 
33315516c77SSepherosa Ziehau static int			hn_create_rx_data(struct hn_softc *, int);
33415516c77SSepherosa Ziehau static void			hn_destroy_rx_data(struct hn_softc *);
33515516c77SSepherosa Ziehau static int			hn_check_iplen(const struct mbuf *, int);
33615516c77SSepherosa Ziehau static int			hn_set_rxfilter(struct hn_softc *);
33734d68912SSepherosa Ziehau #ifndef RSS
33815516c77SSepherosa Ziehau static int			hn_rss_reconfig(struct hn_softc *);
33934d68912SSepherosa Ziehau #endif
340afd4971bSSepherosa Ziehau static void			hn_rss_ind_fixup(struct hn_softc *);
34115516c77SSepherosa Ziehau static int			hn_rxpkt(struct hn_rx_ring *, const void *,
34215516c77SSepherosa Ziehau 				    int, const struct hn_rxinfo *);
34315516c77SSepherosa Ziehau 
34415516c77SSepherosa Ziehau static int			hn_tx_ring_create(struct hn_softc *, int);
34515516c77SSepherosa Ziehau static void			hn_tx_ring_destroy(struct hn_tx_ring *);
34615516c77SSepherosa Ziehau static int			hn_create_tx_data(struct hn_softc *, int);
34715516c77SSepherosa Ziehau static void			hn_fixup_tx_data(struct hn_softc *);
34815516c77SSepherosa Ziehau static void			hn_destroy_tx_data(struct hn_softc *);
34915516c77SSepherosa Ziehau static void			hn_txdesc_dmamap_destroy(struct hn_txdesc *);
35025641fc7SSepherosa Ziehau static void			hn_txdesc_gc(struct hn_tx_ring *,
35125641fc7SSepherosa Ziehau 				    struct hn_txdesc *);
352dc13fee6SSepherosa Ziehau static int			hn_encap(struct ifnet *, struct hn_tx_ring *,
35315516c77SSepherosa Ziehau 				    struct hn_txdesc *, struct mbuf **);
35415516c77SSepherosa Ziehau static int			hn_txpkt(struct ifnet *, struct hn_tx_ring *,
35515516c77SSepherosa Ziehau 				    struct hn_txdesc *);
35615516c77SSepherosa Ziehau static void			hn_set_chim_size(struct hn_softc *, int);
35715516c77SSepherosa Ziehau static void			hn_set_tso_maxsize(struct hn_softc *, int, int);
35815516c77SSepherosa Ziehau static bool			hn_tx_ring_pending(struct hn_tx_ring *);
35915516c77SSepherosa Ziehau static void			hn_tx_ring_qflush(struct hn_tx_ring *);
36015516c77SSepherosa Ziehau static void			hn_resume_tx(struct hn_softc *, int);
361dc13fee6SSepherosa Ziehau static void			hn_set_txagg(struct hn_softc *);
362dc13fee6SSepherosa Ziehau static void			*hn_try_txagg(struct ifnet *,
363dc13fee6SSepherosa Ziehau 				    struct hn_tx_ring *, struct hn_txdesc *,
364dc13fee6SSepherosa Ziehau 				    int);
36515516c77SSepherosa Ziehau static int			hn_get_txswq_depth(const struct hn_tx_ring *);
36615516c77SSepherosa Ziehau static void			hn_txpkt_done(struct hn_nvs_sendctx *,
36715516c77SSepherosa Ziehau 				    struct hn_softc *, struct vmbus_channel *,
36815516c77SSepherosa Ziehau 				    const void *, int);
36915516c77SSepherosa Ziehau static int			hn_txpkt_sglist(struct hn_tx_ring *,
37015516c77SSepherosa Ziehau 				    struct hn_txdesc *);
37115516c77SSepherosa Ziehau static int			hn_txpkt_chim(struct hn_tx_ring *,
37215516c77SSepherosa Ziehau 				    struct hn_txdesc *);
37315516c77SSepherosa Ziehau static int			hn_xmit(struct hn_tx_ring *, int);
37415516c77SSepherosa Ziehau static void			hn_xmit_taskfunc(void *, int);
37515516c77SSepherosa Ziehau static void			hn_xmit_txeof(struct hn_tx_ring *);
37615516c77SSepherosa Ziehau static void			hn_xmit_txeof_taskfunc(void *, int);
37723bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
37815516c77SSepherosa Ziehau static int			hn_start_locked(struct hn_tx_ring *, int);
37915516c77SSepherosa Ziehau static void			hn_start_taskfunc(void *, int);
38015516c77SSepherosa Ziehau static void			hn_start_txeof(struct hn_tx_ring *);
38115516c77SSepherosa Ziehau static void			hn_start_txeof_taskfunc(void *, int);
38223bf9e15SSepherosa Ziehau #endif
38315516c77SSepherosa Ziehau 
38415516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
38515516c77SSepherosa Ziehau     "Hyper-V network interface");
38615516c77SSepherosa Ziehau 
38715516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */
38815516c77SSepherosa Ziehau static int			hn_trust_hosttcp = 1;
38915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN,
39015516c77SSepherosa Ziehau     &hn_trust_hosttcp, 0,
39115516c77SSepherosa Ziehau     "Trust tcp segement verification on host side, "
39215516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
39315516c77SSepherosa Ziehau 
39415516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */
39515516c77SSepherosa Ziehau static int			hn_trust_hostudp = 1;
39615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN,
39715516c77SSepherosa Ziehau     &hn_trust_hostudp, 0,
39815516c77SSepherosa Ziehau     "Trust udp datagram verification on host side, "
39915516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
40015516c77SSepherosa Ziehau 
40115516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */
40215516c77SSepherosa Ziehau static int			hn_trust_hostip = 1;
40315516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN,
40415516c77SSepherosa Ziehau     &hn_trust_hostip, 0,
40515516c77SSepherosa Ziehau     "Trust ip packet verification on host side, "
40615516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
40715516c77SSepherosa Ziehau 
40815516c77SSepherosa Ziehau /* Limit TSO burst size */
40915516c77SSepherosa Ziehau static int			hn_tso_maxlen = IP_MAXPACKET;
41015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN,
41115516c77SSepherosa Ziehau     &hn_tso_maxlen, 0, "TSO burst limit");
41215516c77SSepherosa Ziehau 
41315516c77SSepherosa Ziehau /* Limit chimney send size */
41415516c77SSepherosa Ziehau static int			hn_tx_chimney_size = 0;
41515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN,
41615516c77SSepherosa Ziehau     &hn_tx_chimney_size, 0, "Chimney send packet size limit");
41715516c77SSepherosa Ziehau 
41815516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */
41915516c77SSepherosa Ziehau static int			hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF;
42015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN,
42115516c77SSepherosa Ziehau     &hn_direct_tx_size, 0, "Size of the packet for direct transmission");
42215516c77SSepherosa Ziehau 
42315516c77SSepherosa Ziehau /* # of LRO entries per RX ring */
42415516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
42515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
42615516c77SSepherosa Ziehau static int			hn_lro_entry_count = HN_LROENT_CNT_DEF;
42715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN,
42815516c77SSepherosa Ziehau     &hn_lro_entry_count, 0, "LRO entry count");
42915516c77SSepherosa Ziehau #endif
43015516c77SSepherosa Ziehau #endif
43115516c77SSepherosa Ziehau 
432fdd0222aSSepherosa Ziehau static int			hn_tx_taskq_cnt = 1;
433fdd0222aSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_cnt, CTLFLAG_RDTUN,
434fdd0222aSSepherosa Ziehau     &hn_tx_taskq_cnt, 0, "# of TX taskqueues");
435fdd0222aSSepherosa Ziehau 
4360e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_INDEP	0
4370e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_GLOBAL	1
4380e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_EVTTQ	2
4390e11868dSSepherosa Ziehau 
4400e11868dSSepherosa Ziehau static int			hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
4410e11868dSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_mode, CTLFLAG_RDTUN,
4420e11868dSSepherosa Ziehau     &hn_tx_taskq_mode, 0, "TX taskqueue modes: "
4430e11868dSSepherosa Ziehau     "0 - independent, 1 - share global tx taskqs, 2 - share event taskqs");
4440e11868dSSepherosa Ziehau 
44515516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
44615516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 0;
44715516c77SSepherosa Ziehau #else
44815516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 1;
44915516c77SSepherosa Ziehau #endif
45015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD,
45115516c77SSepherosa Ziehau     &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors");
45215516c77SSepherosa Ziehau 
45323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
45415516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */
45515516c77SSepherosa Ziehau static int			hn_use_if_start = 0;
45615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN,
45715516c77SSepherosa Ziehau     &hn_use_if_start, 0, "Use if_start TX method");
45823bf9e15SSepherosa Ziehau #endif
45915516c77SSepherosa Ziehau 
46015516c77SSepherosa Ziehau /* # of channels to use */
46115516c77SSepherosa Ziehau static int			hn_chan_cnt = 0;
46215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN,
46315516c77SSepherosa Ziehau     &hn_chan_cnt, 0,
46415516c77SSepherosa Ziehau     "# of channels to use; each channel has one RX ring and one TX ring");
46515516c77SSepherosa Ziehau 
46615516c77SSepherosa Ziehau /* # of transmit rings to use */
46715516c77SSepherosa Ziehau static int			hn_tx_ring_cnt = 0;
46815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN,
46915516c77SSepherosa Ziehau     &hn_tx_ring_cnt, 0, "# of TX rings to use");
47015516c77SSepherosa Ziehau 
47115516c77SSepherosa Ziehau /* Software TX ring deptch */
47215516c77SSepherosa Ziehau static int			hn_tx_swq_depth = 0;
47315516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN,
47415516c77SSepherosa Ziehau     &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING");
47515516c77SSepherosa Ziehau 
47615516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */
47715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
47815516c77SSepherosa Ziehau static u_int			hn_lro_mbufq_depth = 0;
47915516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN,
48015516c77SSepherosa Ziehau     &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue");
48115516c77SSepherosa Ziehau #endif
48215516c77SSepherosa Ziehau 
483dc13fee6SSepherosa Ziehau /* Packet transmission aggregation size limit */
484dc13fee6SSepherosa Ziehau static int			hn_tx_agg_size = -1;
485dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN,
486dc13fee6SSepherosa Ziehau     &hn_tx_agg_size, 0, "Packet transmission aggregation size limit");
487dc13fee6SSepherosa Ziehau 
488dc13fee6SSepherosa Ziehau /* Packet transmission aggregation count limit */
489fa915c4dSSepherosa Ziehau static int			hn_tx_agg_pkts = -1;
490dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN,
491dc13fee6SSepherosa Ziehau     &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit");
492dc13fee6SSepherosa Ziehau 
49315516c77SSepherosa Ziehau static u_int			hn_cpu_index;	/* next CPU for channel */
494fdd0222aSSepherosa Ziehau static struct taskqueue		**hn_tx_taskque;/* shared TX taskqueues */
49515516c77SSepherosa Ziehau 
49634d68912SSepherosa Ziehau #ifndef RSS
49715516c77SSepherosa Ziehau static const uint8_t
49815516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
49915516c77SSepherosa Ziehau 	0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
50015516c77SSepherosa Ziehau 	0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
50115516c77SSepherosa Ziehau 	0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
50215516c77SSepherosa Ziehau 	0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
50315516c77SSepherosa Ziehau 	0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
50415516c77SSepherosa Ziehau };
50534d68912SSepherosa Ziehau #endif	/* !RSS */
50615516c77SSepherosa Ziehau 
50715516c77SSepherosa Ziehau static device_method_t hn_methods[] = {
50815516c77SSepherosa Ziehau 	/* Device interface */
50915516c77SSepherosa Ziehau 	DEVMETHOD(device_probe,		hn_probe),
51015516c77SSepherosa Ziehau 	DEVMETHOD(device_attach,	hn_attach),
51115516c77SSepherosa Ziehau 	DEVMETHOD(device_detach,	hn_detach),
51215516c77SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	hn_shutdown),
51315516c77SSepherosa Ziehau 	DEVMETHOD_END
51415516c77SSepherosa Ziehau };
51515516c77SSepherosa Ziehau 
51615516c77SSepherosa Ziehau static driver_t hn_driver = {
51715516c77SSepherosa Ziehau 	"hn",
51815516c77SSepherosa Ziehau 	hn_methods,
51915516c77SSepherosa Ziehau 	sizeof(struct hn_softc)
52015516c77SSepherosa Ziehau };
52115516c77SSepherosa Ziehau 
52215516c77SSepherosa Ziehau static devclass_t hn_devclass;
52315516c77SSepherosa Ziehau 
52415516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0);
52515516c77SSepherosa Ziehau MODULE_VERSION(hn, 1);
52615516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1);
52715516c77SSepherosa Ziehau 
52815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
52915516c77SSepherosa Ziehau static void
53015516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim)
53115516c77SSepherosa Ziehau {
53215516c77SSepherosa Ziehau 	int i;
53315516c77SSepherosa Ziehau 
534a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
53515516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim;
53615516c77SSepherosa Ziehau }
53715516c77SSepherosa Ziehau #endif
53815516c77SSepherosa Ziehau 
53915516c77SSepherosa Ziehau static int
54015516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd)
54115516c77SSepherosa Ziehau {
54215516c77SSepherosa Ziehau 
54315516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
54415516c77SSepherosa Ziehau 	    txd->chim_size == 0, ("invalid rndis sglist txd"));
54515516c77SSepherosa Ziehau 	return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA,
54615516c77SSepherosa Ziehau 	    &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt));
54715516c77SSepherosa Ziehau }
54815516c77SSepherosa Ziehau 
54915516c77SSepherosa Ziehau static int
55015516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd)
55115516c77SSepherosa Ziehau {
55215516c77SSepherosa Ziehau 	struct hn_nvs_rndis rndis;
55315516c77SSepherosa Ziehau 
55415516c77SSepherosa Ziehau 	KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID &&
55515516c77SSepherosa Ziehau 	    txd->chim_size > 0, ("invalid rndis chim txd"));
55615516c77SSepherosa Ziehau 
55715516c77SSepherosa Ziehau 	rndis.nvs_type = HN_NVS_TYPE_RNDIS;
55815516c77SSepherosa Ziehau 	rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA;
55915516c77SSepherosa Ziehau 	rndis.nvs_chim_idx = txd->chim_index;
56015516c77SSepherosa Ziehau 	rndis.nvs_chim_sz = txd->chim_size;
56115516c77SSepherosa Ziehau 
56215516c77SSepherosa Ziehau 	return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC,
56315516c77SSepherosa Ziehau 	    &rndis, sizeof(rndis), &txd->send_ctx));
56415516c77SSepherosa Ziehau }
56515516c77SSepherosa Ziehau 
56615516c77SSepherosa Ziehau static __inline uint32_t
56715516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc)
56815516c77SSepherosa Ziehau {
56915516c77SSepherosa Ziehau 	int i, bmap_cnt = sc->hn_chim_bmap_cnt;
57015516c77SSepherosa Ziehau 	u_long *bmap = sc->hn_chim_bmap;
57115516c77SSepherosa Ziehau 	uint32_t ret = HN_NVS_CHIM_IDX_INVALID;
57215516c77SSepherosa Ziehau 
57315516c77SSepherosa Ziehau 	for (i = 0; i < bmap_cnt; ++i) {
57415516c77SSepherosa Ziehau 		int idx;
57515516c77SSepherosa Ziehau 
57615516c77SSepherosa Ziehau 		idx = ffsl(~bmap[i]);
57715516c77SSepherosa Ziehau 		if (idx == 0)
57815516c77SSepherosa Ziehau 			continue;
57915516c77SSepherosa Ziehau 
58015516c77SSepherosa Ziehau 		--idx; /* ffsl is 1-based */
58115516c77SSepherosa Ziehau 		KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt,
58215516c77SSepherosa Ziehau 		    ("invalid i %d and idx %d", i, idx));
58315516c77SSepherosa Ziehau 
58415516c77SSepherosa Ziehau 		if (atomic_testandset_long(&bmap[i], idx))
58515516c77SSepherosa Ziehau 			continue;
58615516c77SSepherosa Ziehau 
58715516c77SSepherosa Ziehau 		ret = i * LONG_BIT + idx;
58815516c77SSepherosa Ziehau 		break;
58915516c77SSepherosa Ziehau 	}
59015516c77SSepherosa Ziehau 	return (ret);
59115516c77SSepherosa Ziehau }
59215516c77SSepherosa Ziehau 
59315516c77SSepherosa Ziehau static __inline void
59415516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx)
59515516c77SSepherosa Ziehau {
59615516c77SSepherosa Ziehau 	u_long mask;
59715516c77SSepherosa Ziehau 	uint32_t idx;
59815516c77SSepherosa Ziehau 
59915516c77SSepherosa Ziehau 	idx = chim_idx / LONG_BIT;
60015516c77SSepherosa Ziehau 	KASSERT(idx < sc->hn_chim_bmap_cnt,
60115516c77SSepherosa Ziehau 	    ("invalid chimney index 0x%x", chim_idx));
60215516c77SSepherosa Ziehau 
60315516c77SSepherosa Ziehau 	mask = 1UL << (chim_idx % LONG_BIT);
60415516c77SSepherosa Ziehau 	KASSERT(sc->hn_chim_bmap[idx] & mask,
60515516c77SSepherosa Ziehau 	    ("index bitmap 0x%lx, chimney index %u, "
60615516c77SSepherosa Ziehau 	     "bitmap idx %d, bitmask 0x%lx",
60715516c77SSepherosa Ziehau 	     sc->hn_chim_bmap[idx], chim_idx, idx, mask));
60815516c77SSepherosa Ziehau 
60915516c77SSepherosa Ziehau 	atomic_clear_long(&sc->hn_chim_bmap[idx], mask);
61015516c77SSepherosa Ziehau }
61115516c77SSepherosa Ziehau 
612edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
613edd3f315SSepherosa Ziehau /*
614edd3f315SSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
615edd3f315SSepherosa Ziehau  */
616edd3f315SSepherosa Ziehau static __inline struct mbuf *
617edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head)
618edd3f315SSepherosa Ziehau {
619edd3f315SSepherosa Ziehau 	struct ether_vlan_header *evl;
620edd3f315SSepherosa Ziehau 	struct tcphdr *th;
621edd3f315SSepherosa Ziehau 	int ehlen;
622edd3f315SSepherosa Ziehau 
623edd3f315SSepherosa Ziehau 	KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable"));
624edd3f315SSepherosa Ziehau 
625edd3f315SSepherosa Ziehau #define PULLUP_HDR(m, len)				\
626edd3f315SSepherosa Ziehau do {							\
627edd3f315SSepherosa Ziehau 	if (__predict_false((m)->m_len < (len))) {	\
628edd3f315SSepherosa Ziehau 		(m) = m_pullup((m), (len));		\
629edd3f315SSepherosa Ziehau 		if ((m) == NULL)			\
630edd3f315SSepherosa Ziehau 			return (NULL);			\
631edd3f315SSepherosa Ziehau 	}						\
632edd3f315SSepherosa Ziehau } while (0)
633edd3f315SSepherosa Ziehau 
634edd3f315SSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
635edd3f315SSepherosa Ziehau 	evl = mtod(m_head, struct ether_vlan_header *);
636edd3f315SSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
637edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
638edd3f315SSepherosa Ziehau 	else
639edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
640edd3f315SSepherosa Ziehau 
641edd3f315SSepherosa Ziehau #ifdef INET
642edd3f315SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
643edd3f315SSepherosa Ziehau 		struct ip *ip;
644edd3f315SSepherosa Ziehau 		int iphlen;
645edd3f315SSepherosa Ziehau 
646edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
647edd3f315SSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
648edd3f315SSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
649edd3f315SSepherosa Ziehau 
650edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
651edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + iphlen);
652edd3f315SSepherosa Ziehau 
653edd3f315SSepherosa Ziehau 		ip->ip_len = 0;
654edd3f315SSepherosa Ziehau 		ip->ip_sum = 0;
655edd3f315SSepherosa Ziehau 		th->th_sum = in_pseudo(ip->ip_src.s_addr,
656edd3f315SSepherosa Ziehau 		    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
657edd3f315SSepherosa Ziehau 	}
658edd3f315SSepherosa Ziehau #endif
659edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET)
660edd3f315SSepherosa Ziehau 	else
661edd3f315SSepherosa Ziehau #endif
662edd3f315SSepherosa Ziehau #ifdef INET6
663edd3f315SSepherosa Ziehau 	{
664edd3f315SSepherosa Ziehau 		struct ip6_hdr *ip6;
665edd3f315SSepherosa Ziehau 
666edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
667edd3f315SSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
668edd3f315SSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP) {
669edd3f315SSepherosa Ziehau 			m_freem(m_head);
670edd3f315SSepherosa Ziehau 			return (NULL);
671edd3f315SSepherosa Ziehau 		}
672edd3f315SSepherosa Ziehau 
673edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
674edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + sizeof(*ip6));
675edd3f315SSepherosa Ziehau 
676edd3f315SSepherosa Ziehau 		ip6->ip6_plen = 0;
677edd3f315SSepherosa Ziehau 		th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
678edd3f315SSepherosa Ziehau 	}
679edd3f315SSepherosa Ziehau #endif
680edd3f315SSepherosa Ziehau 	return (m_head);
681edd3f315SSepherosa Ziehau 
682edd3f315SSepherosa Ziehau #undef PULLUP_HDR
683edd3f315SSepherosa Ziehau }
684edd3f315SSepherosa Ziehau #endif	/* INET6 || INET */
685edd3f315SSepherosa Ziehau 
68615516c77SSepherosa Ziehau static int
68715516c77SSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc)
68815516c77SSepherosa Ziehau {
68915516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
69015516c77SSepherosa Ziehau 	uint32_t filter;
69115516c77SSepherosa Ziehau 	int error = 0;
69215516c77SSepherosa Ziehau 
69315516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
69415516c77SSepherosa Ziehau 
69515516c77SSepherosa Ziehau 	if (ifp->if_flags & IFF_PROMISC) {
69615516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_PROMISCUOUS;
69715516c77SSepherosa Ziehau 	} else {
69815516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_DIRECTED;
69915516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_BROADCAST)
70015516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_BROADCAST;
70115516c77SSepherosa Ziehau 		/* TODO: support multicast list */
70215516c77SSepherosa Ziehau 		if ((ifp->if_flags & IFF_ALLMULTI) ||
70315516c77SSepherosa Ziehau 		    !TAILQ_EMPTY(&ifp->if_multiaddrs))
70415516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
70515516c77SSepherosa Ziehau 	}
70615516c77SSepherosa Ziehau 
70715516c77SSepherosa Ziehau 	if (sc->hn_rx_filter != filter) {
70815516c77SSepherosa Ziehau 		error = hn_rndis_set_rxfilter(sc, filter);
70915516c77SSepherosa Ziehau 		if (!error)
71015516c77SSepherosa Ziehau 			sc->hn_rx_filter = filter;
71115516c77SSepherosa Ziehau 	}
71215516c77SSepherosa Ziehau 	return (error);
71315516c77SSepherosa Ziehau }
71415516c77SSepherosa Ziehau 
715dc13fee6SSepherosa Ziehau static void
716dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc)
717dc13fee6SSepherosa Ziehau {
718dc13fee6SSepherosa Ziehau 	uint32_t size, pkts;
719dc13fee6SSepherosa Ziehau 	int i;
720dc13fee6SSepherosa Ziehau 
721dc13fee6SSepherosa Ziehau 	/*
722dc13fee6SSepherosa Ziehau 	 * Setup aggregation size.
723dc13fee6SSepherosa Ziehau 	 */
724dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_size < 0)
725dc13fee6SSepherosa Ziehau 		size = UINT32_MAX;
726dc13fee6SSepherosa Ziehau 	else
727dc13fee6SSepherosa Ziehau 		size = sc->hn_agg_size;
728dc13fee6SSepherosa Ziehau 
729dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_size < size)
730dc13fee6SSepherosa Ziehau 		size = sc->hn_rndis_agg_size;
731dc13fee6SSepherosa Ziehau 
732a4364cfeSSepherosa Ziehau 	/* NOTE: We only aggregate packets using chimney sending buffers. */
733a4364cfeSSepherosa Ziehau 	if (size > (uint32_t)sc->hn_chim_szmax)
734a4364cfeSSepherosa Ziehau 		size = sc->hn_chim_szmax;
735a4364cfeSSepherosa Ziehau 
736dc13fee6SSepherosa Ziehau 	if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) {
737dc13fee6SSepherosa Ziehau 		/* Disable */
738dc13fee6SSepherosa Ziehau 		size = 0;
739dc13fee6SSepherosa Ziehau 		pkts = 0;
740dc13fee6SSepherosa Ziehau 		goto done;
741dc13fee6SSepherosa Ziehau 	}
742dc13fee6SSepherosa Ziehau 
743dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'int'. */
744dc13fee6SSepherosa Ziehau 	if (size > INT_MAX)
745dc13fee6SSepherosa Ziehau 		size = INT_MAX;
746dc13fee6SSepherosa Ziehau 
747dc13fee6SSepherosa Ziehau 	/*
748dc13fee6SSepherosa Ziehau 	 * Setup aggregation packet count.
749dc13fee6SSepherosa Ziehau 	 */
750dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_pkts < 0)
751dc13fee6SSepherosa Ziehau 		pkts = UINT32_MAX;
752dc13fee6SSepherosa Ziehau 	else
753dc13fee6SSepherosa Ziehau 		pkts = sc->hn_agg_pkts;
754dc13fee6SSepherosa Ziehau 
755dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_pkts < pkts)
756dc13fee6SSepherosa Ziehau 		pkts = sc->hn_rndis_agg_pkts;
757dc13fee6SSepherosa Ziehau 
758dc13fee6SSepherosa Ziehau 	if (pkts <= 1) {
759dc13fee6SSepherosa Ziehau 		/* Disable */
760dc13fee6SSepherosa Ziehau 		size = 0;
761dc13fee6SSepherosa Ziehau 		pkts = 0;
762dc13fee6SSepherosa Ziehau 		goto done;
763dc13fee6SSepherosa Ziehau 	}
764dc13fee6SSepherosa Ziehau 
765dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
766dc13fee6SSepherosa Ziehau 	if (pkts > SHRT_MAX)
767dc13fee6SSepherosa Ziehau 		pkts = SHRT_MAX;
768dc13fee6SSepherosa Ziehau 
769dc13fee6SSepherosa Ziehau done:
770dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
771dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_align > SHRT_MAX) {
772dc13fee6SSepherosa Ziehau 		/* Disable */
773dc13fee6SSepherosa Ziehau 		size = 0;
774dc13fee6SSepherosa Ziehau 		pkts = 0;
775dc13fee6SSepherosa Ziehau 	}
776dc13fee6SSepherosa Ziehau 
777dc13fee6SSepherosa Ziehau 	if (bootverbose) {
778dc13fee6SSepherosa Ziehau 		if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n",
779dc13fee6SSepherosa Ziehau 		    size, pkts, sc->hn_rndis_agg_align);
780dc13fee6SSepherosa Ziehau 	}
781dc13fee6SSepherosa Ziehau 
782dc13fee6SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
783dc13fee6SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
784dc13fee6SSepherosa Ziehau 
785dc13fee6SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
786dc13fee6SSepherosa Ziehau 		txr->hn_agg_szmax = size;
787dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktmax = pkts;
788dc13fee6SSepherosa Ziehau 		txr->hn_agg_align = sc->hn_rndis_agg_align;
789dc13fee6SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
790dc13fee6SSepherosa Ziehau 	}
791dc13fee6SSepherosa Ziehau }
792dc13fee6SSepherosa Ziehau 
79315516c77SSepherosa Ziehau static int
79415516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr)
79515516c77SSepherosa Ziehau {
79615516c77SSepherosa Ziehau 
79715516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet"));
79815516c77SSepherosa Ziehau 	if (hn_tx_swq_depth < txr->hn_txdesc_cnt)
79915516c77SSepherosa Ziehau 		return txr->hn_txdesc_cnt;
80015516c77SSepherosa Ziehau 	return hn_tx_swq_depth;
80115516c77SSepherosa Ziehau }
80215516c77SSepherosa Ziehau 
80334d68912SSepherosa Ziehau #ifndef RSS
80415516c77SSepherosa Ziehau static int
80515516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc)
80615516c77SSepherosa Ziehau {
80715516c77SSepherosa Ziehau 	int error;
80815516c77SSepherosa Ziehau 
80915516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
81015516c77SSepherosa Ziehau 
81115516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
81215516c77SSepherosa Ziehau 		return (ENXIO);
81315516c77SSepherosa Ziehau 
81415516c77SSepherosa Ziehau 	/*
81515516c77SSepherosa Ziehau 	 * Disable RSS first.
81615516c77SSepherosa Ziehau 	 *
81715516c77SSepherosa Ziehau 	 * NOTE:
81815516c77SSepherosa Ziehau 	 * Direct reconfiguration by setting the UNCHG flags does
81915516c77SSepherosa Ziehau 	 * _not_ work properly.
82015516c77SSepherosa Ziehau 	 */
82115516c77SSepherosa Ziehau 	if (bootverbose)
82215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "disable RSS\n");
82315516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE);
82415516c77SSepherosa Ziehau 	if (error) {
82515516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS disable failed\n");
82615516c77SSepherosa Ziehau 		return (error);
82715516c77SSepherosa Ziehau 	}
82815516c77SSepherosa Ziehau 
82915516c77SSepherosa Ziehau 	/*
83015516c77SSepherosa Ziehau 	 * Reenable the RSS w/ the updated RSS key or indirect
83115516c77SSepherosa Ziehau 	 * table.
83215516c77SSepherosa Ziehau 	 */
83315516c77SSepherosa Ziehau 	if (bootverbose)
83415516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "reconfig RSS\n");
83515516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
83615516c77SSepherosa Ziehau 	if (error) {
83715516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS reconfig failed\n");
83815516c77SSepherosa Ziehau 		return (error);
83915516c77SSepherosa Ziehau 	}
84015516c77SSepherosa Ziehau 	return (0);
84115516c77SSepherosa Ziehau }
84234d68912SSepherosa Ziehau #endif	/* !RSS */
84315516c77SSepherosa Ziehau 
84415516c77SSepherosa Ziehau static void
845afd4971bSSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc)
84615516c77SSepherosa Ziehau {
84715516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
848afd4971bSSepherosa Ziehau 	int i, nchan;
84915516c77SSepherosa Ziehau 
850afd4971bSSepherosa Ziehau 	nchan = sc->hn_rx_ring_inuse;
85115516c77SSepherosa Ziehau 	KASSERT(nchan > 1, ("invalid # of channels %d", nchan));
85215516c77SSepherosa Ziehau 
85315516c77SSepherosa Ziehau 	/*
85415516c77SSepherosa Ziehau 	 * Check indirect table to make sure that all channels in it
85515516c77SSepherosa Ziehau 	 * can be used.
85615516c77SSepherosa Ziehau 	 */
85715516c77SSepherosa Ziehau 	for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
85815516c77SSepherosa Ziehau 		if (rss->rss_ind[i] >= nchan) {
85915516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp,
86015516c77SSepherosa Ziehau 			    "RSS indirect table %d fixup: %u -> %d\n",
86115516c77SSepherosa Ziehau 			    i, rss->rss_ind[i], nchan - 1);
86215516c77SSepherosa Ziehau 			rss->rss_ind[i] = nchan - 1;
86315516c77SSepherosa Ziehau 		}
86415516c77SSepherosa Ziehau 	}
86515516c77SSepherosa Ziehau }
86615516c77SSepherosa Ziehau 
86715516c77SSepherosa Ziehau static int
86815516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused)
86915516c77SSepherosa Ziehau {
87015516c77SSepherosa Ziehau 
87115516c77SSepherosa Ziehau 	return EOPNOTSUPP;
87215516c77SSepherosa Ziehau }
87315516c77SSepherosa Ziehau 
87415516c77SSepherosa Ziehau static void
87515516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
87615516c77SSepherosa Ziehau {
87715516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
87815516c77SSepherosa Ziehau 
87915516c77SSepherosa Ziehau 	ifmr->ifm_status = IFM_AVALID;
88015516c77SSepherosa Ziehau 	ifmr->ifm_active = IFM_ETHER;
88115516c77SSepherosa Ziehau 
88215516c77SSepherosa Ziehau 	if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) {
88315516c77SSepherosa Ziehau 		ifmr->ifm_active |= IFM_NONE;
88415516c77SSepherosa Ziehau 		return;
88515516c77SSepherosa Ziehau 	}
88615516c77SSepherosa Ziehau 	ifmr->ifm_status |= IFM_ACTIVE;
88715516c77SSepherosa Ziehau 	ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
88815516c77SSepherosa Ziehau }
88915516c77SSepherosa Ziehau 
89015516c77SSepherosa Ziehau /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
89115516c77SSepherosa Ziehau static const struct hyperv_guid g_net_vsc_device_type = {
89215516c77SSepherosa Ziehau 	.hv_guid = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
89315516c77SSepherosa Ziehau 		0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E}
89415516c77SSepherosa Ziehau };
89515516c77SSepherosa Ziehau 
89615516c77SSepherosa Ziehau static int
89715516c77SSepherosa Ziehau hn_probe(device_t dev)
89815516c77SSepherosa Ziehau {
89915516c77SSepherosa Ziehau 
90015516c77SSepherosa Ziehau 	if (VMBUS_PROBE_GUID(device_get_parent(dev), dev,
90115516c77SSepherosa Ziehau 	    &g_net_vsc_device_type) == 0) {
90215516c77SSepherosa Ziehau 		device_set_desc(dev, "Hyper-V Network Interface");
90315516c77SSepherosa Ziehau 		return BUS_PROBE_DEFAULT;
90415516c77SSepherosa Ziehau 	}
90515516c77SSepherosa Ziehau 	return ENXIO;
90615516c77SSepherosa Ziehau }
90715516c77SSepherosa Ziehau 
90815516c77SSepherosa Ziehau static int
90915516c77SSepherosa Ziehau hn_attach(device_t dev)
91015516c77SSepherosa Ziehau {
91115516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
91215516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
91315516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
91415516c77SSepherosa Ziehau 	uint8_t eaddr[ETHER_ADDR_LEN];
91515516c77SSepherosa Ziehau 	struct ifnet *ifp = NULL;
91615516c77SSepherosa Ziehau 	int error, ring_cnt, tx_ring_cnt;
91715516c77SSepherosa Ziehau 
91815516c77SSepherosa Ziehau 	sc->hn_dev = dev;
91915516c77SSepherosa Ziehau 	sc->hn_prichan = vmbus_get_channel(dev);
92015516c77SSepherosa Ziehau 	HN_LOCK_INIT(sc);
92115516c77SSepherosa Ziehau 
92215516c77SSepherosa Ziehau 	/*
923dc13fee6SSepherosa Ziehau 	 * Initialize these tunables once.
924dc13fee6SSepherosa Ziehau 	 */
925dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = hn_tx_agg_size;
926dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = hn_tx_agg_pkts;
927dc13fee6SSepherosa Ziehau 
928dc13fee6SSepherosa Ziehau 	/*
92915516c77SSepherosa Ziehau 	 * Setup taskqueue for transmission.
93015516c77SSepherosa Ziehau 	 */
9310e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_INDEP) {
932fdd0222aSSepherosa Ziehau 		int i;
933fdd0222aSSepherosa Ziehau 
934fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs =
935fdd0222aSSepherosa Ziehau 		    malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
936fdd0222aSSepherosa Ziehau 		    M_DEVBUF, M_WAITOK);
937fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i) {
938fdd0222aSSepherosa Ziehau 			sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx",
939fdd0222aSSepherosa Ziehau 			    M_WAITOK, taskqueue_thread_enqueue,
940fdd0222aSSepherosa Ziehau 			    &sc->hn_tx_taskqs[i]);
941fdd0222aSSepherosa Ziehau 			taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET,
942fdd0222aSSepherosa Ziehau 			    "%s tx%d", device_get_nameunit(dev), i);
943fdd0222aSSepherosa Ziehau 		}
9440e11868dSSepherosa Ziehau 	} else if (hn_tx_taskq_mode == HN_TX_TASKQ_M_GLOBAL) {
945fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs = hn_tx_taskque;
94615516c77SSepherosa Ziehau 	}
94715516c77SSepherosa Ziehau 
94815516c77SSepherosa Ziehau 	/*
94915516c77SSepherosa Ziehau 	 * Setup taskqueue for mangement tasks, e.g. link status.
95015516c77SSepherosa Ziehau 	 */
95115516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK,
95215516c77SSepherosa Ziehau 	    taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0);
95315516c77SSepherosa Ziehau 	taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
95415516c77SSepherosa Ziehau 	    device_get_nameunit(dev));
95515516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
95615516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc);
95715516c77SSepherosa Ziehau 	TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0,
95815516c77SSepherosa Ziehau 	    hn_netchg_status_taskfunc, sc);
95915516c77SSepherosa Ziehau 
96015516c77SSepherosa Ziehau 	/*
96115516c77SSepherosa Ziehau 	 * Allocate ifnet and setup its name earlier, so that if_printf
96215516c77SSepherosa Ziehau 	 * can be used by functions, which will be called after
96315516c77SSepherosa Ziehau 	 * ether_ifattach().
96415516c77SSepherosa Ziehau 	 */
96515516c77SSepherosa Ziehau 	ifp = sc->hn_ifp = if_alloc(IFT_ETHER);
96615516c77SSepherosa Ziehau 	ifp->if_softc = sc;
96715516c77SSepherosa Ziehau 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
96815516c77SSepherosa Ziehau 
96915516c77SSepherosa Ziehau 	/*
97015516c77SSepherosa Ziehau 	 * Initialize ifmedia earlier so that it can be unconditionally
97115516c77SSepherosa Ziehau 	 * destroyed, if error happened later on.
97215516c77SSepherosa Ziehau 	 */
97315516c77SSepherosa Ziehau 	ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts);
97415516c77SSepherosa Ziehau 
97515516c77SSepherosa Ziehau 	/*
97615516c77SSepherosa Ziehau 	 * Figure out the # of RX rings (ring_cnt) and the # of TX rings
97715516c77SSepherosa Ziehau 	 * to use (tx_ring_cnt).
97815516c77SSepherosa Ziehau 	 *
97915516c77SSepherosa Ziehau 	 * NOTE:
98015516c77SSepherosa Ziehau 	 * The # of RX rings to use is same as the # of channels to use.
98115516c77SSepherosa Ziehau 	 */
98215516c77SSepherosa Ziehau 	ring_cnt = hn_chan_cnt;
98315516c77SSepherosa Ziehau 	if (ring_cnt <= 0) {
98415516c77SSepherosa Ziehau 		/* Default */
98515516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
98615516c77SSepherosa Ziehau 		if (ring_cnt > HN_RING_CNT_DEF_MAX)
98715516c77SSepherosa Ziehau 			ring_cnt = HN_RING_CNT_DEF_MAX;
98815516c77SSepherosa Ziehau 	} else if (ring_cnt > mp_ncpus) {
98915516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
99015516c77SSepherosa Ziehau 	}
99134d68912SSepherosa Ziehau #ifdef RSS
99234d68912SSepherosa Ziehau 	if (ring_cnt > rss_getnumbuckets())
99334d68912SSepherosa Ziehau 		ring_cnt = rss_getnumbuckets();
99434d68912SSepherosa Ziehau #endif
99515516c77SSepherosa Ziehau 
99615516c77SSepherosa Ziehau 	tx_ring_cnt = hn_tx_ring_cnt;
99715516c77SSepherosa Ziehau 	if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt)
99815516c77SSepherosa Ziehau 		tx_ring_cnt = ring_cnt;
99923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
100015516c77SSepherosa Ziehau 	if (hn_use_if_start) {
100115516c77SSepherosa Ziehau 		/* ifnet.if_start only needs one TX ring. */
100215516c77SSepherosa Ziehau 		tx_ring_cnt = 1;
100315516c77SSepherosa Ziehau 	}
100423bf9e15SSepherosa Ziehau #endif
100515516c77SSepherosa Ziehau 
100615516c77SSepherosa Ziehau 	/*
100715516c77SSepherosa Ziehau 	 * Set the leader CPU for channels.
100815516c77SSepherosa Ziehau 	 */
100915516c77SSepherosa Ziehau 	sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus;
101015516c77SSepherosa Ziehau 
101115516c77SSepherosa Ziehau 	/*
101215516c77SSepherosa Ziehau 	 * Create enough TX/RX rings, even if only limited number of
101315516c77SSepherosa Ziehau 	 * channels can be allocated.
101415516c77SSepherosa Ziehau 	 */
101515516c77SSepherosa Ziehau 	error = hn_create_tx_data(sc, tx_ring_cnt);
101615516c77SSepherosa Ziehau 	if (error)
101715516c77SSepherosa Ziehau 		goto failed;
101815516c77SSepherosa Ziehau 	error = hn_create_rx_data(sc, ring_cnt);
101915516c77SSepherosa Ziehau 	if (error)
102015516c77SSepherosa Ziehau 		goto failed;
102115516c77SSepherosa Ziehau 
102215516c77SSepherosa Ziehau 	/*
102315516c77SSepherosa Ziehau 	 * Create transaction context for NVS and RNDIS transactions.
102415516c77SSepherosa Ziehau 	 */
102515516c77SSepherosa Ziehau 	sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
102615516c77SSepherosa Ziehau 	    HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
102725641fc7SSepherosa Ziehau 	if (sc->hn_xact == NULL) {
102825641fc7SSepherosa Ziehau 		error = ENXIO;
102915516c77SSepherosa Ziehau 		goto failed;
103025641fc7SSepherosa Ziehau 	}
103125641fc7SSepherosa Ziehau 
103225641fc7SSepherosa Ziehau 	/*
103325641fc7SSepherosa Ziehau 	 * Install orphan handler for the revocation of this device's
103425641fc7SSepherosa Ziehau 	 * primary channel.
103525641fc7SSepherosa Ziehau 	 *
103625641fc7SSepherosa Ziehau 	 * NOTE:
103725641fc7SSepherosa Ziehau 	 * The processing order is critical here:
103825641fc7SSepherosa Ziehau 	 * Install the orphan handler, _before_ testing whether this
103925641fc7SSepherosa Ziehau 	 * device's primary channel has been revoked or not.
104025641fc7SSepherosa Ziehau 	 */
104125641fc7SSepherosa Ziehau 	vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact);
104225641fc7SSepherosa Ziehau 	if (vmbus_chan_is_revoked(sc->hn_prichan)) {
104325641fc7SSepherosa Ziehau 		error = ENXIO;
104425641fc7SSepherosa Ziehau 		goto failed;
104525641fc7SSepherosa Ziehau 	}
104615516c77SSepherosa Ziehau 
104715516c77SSepherosa Ziehau 	/*
104815516c77SSepherosa Ziehau 	 * Attach the synthetic parts, i.e. NVS and RNDIS.
104915516c77SSepherosa Ziehau 	 */
105015516c77SSepherosa Ziehau 	error = hn_synth_attach(sc, ETHERMTU);
105115516c77SSepherosa Ziehau 	if (error)
105215516c77SSepherosa Ziehau 		goto failed;
105315516c77SSepherosa Ziehau 
105415516c77SSepherosa Ziehau 	error = hn_rndis_get_eaddr(sc, eaddr);
105515516c77SSepherosa Ziehau 	if (error)
105615516c77SSepherosa Ziehau 		goto failed;
105715516c77SSepherosa Ziehau 
105815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
105915516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
106015516c77SSepherosa Ziehau 		/*
106115516c77SSepherosa Ziehau 		 * Reduce TCP segment aggregation limit for multiple
106215516c77SSepherosa Ziehau 		 * RX rings to increase ACK timeliness.
106315516c77SSepherosa Ziehau 		 */
106415516c77SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF);
106515516c77SSepherosa Ziehau 	}
106615516c77SSepherosa Ziehau #endif
106715516c77SSepherosa Ziehau 
106815516c77SSepherosa Ziehau 	/*
106915516c77SSepherosa Ziehau 	 * Fixup TX stuffs after synthetic parts are attached.
107015516c77SSepherosa Ziehau 	 */
107115516c77SSepherosa Ziehau 	hn_fixup_tx_data(sc);
107215516c77SSepherosa Ziehau 
107315516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
107415516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
107515516c77SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD,
107615516c77SSepherosa Ziehau 	    &sc->hn_nvs_ver, 0, "NVS version");
107715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version",
107815516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
107915516c77SSepherosa Ziehau 	    hn_ndis_version_sysctl, "A", "NDIS version");
108015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps",
108115516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
108215516c77SSepherosa Ziehau 	    hn_caps_sysctl, "A", "capabilities");
108315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist",
108415516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
108515516c77SSepherosa Ziehau 	    hn_hwassist_sysctl, "A", "hwassist");
108615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter",
108715516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
108815516c77SSepherosa Ziehau 	    hn_rxfilter_sysctl, "A", "rxfilter");
108915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash",
109015516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
109115516c77SSepherosa Ziehau 	    hn_rss_hash_sysctl, "A", "RSS hash");
109215516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size",
109315516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count");
109434d68912SSepherosa Ziehau #ifndef RSS
109534d68912SSepherosa Ziehau 	/*
109634d68912SSepherosa Ziehau 	 * Don't allow RSS key/indirect table changes, if RSS is defined.
109734d68912SSepherosa Ziehau 	 */
109815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key",
109915516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
110015516c77SSepherosa Ziehau 	    hn_rss_key_sysctl, "IU", "RSS key");
110115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind",
110215516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
110315516c77SSepherosa Ziehau 	    hn_rss_ind_sysctl, "IU", "RSS indirect table");
110434d68912SSepherosa Ziehau #endif
1105dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size",
1106dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_size, 0,
1107dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation size limit");
1108dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts",
1109dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0,
1110dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation count limit");
1111dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align",
1112dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_align, 0,
1113dc13fee6SSepherosa Ziehau 	    "RNDIS packet transmission aggregation alignment");
1114dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size",
1115dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
1116dc13fee6SSepherosa Ziehau 	    hn_txagg_size_sysctl, "I",
1117dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation size, 0 -- disable, -1 -- auto");
1118dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts",
1119dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
1120dc13fee6SSepherosa Ziehau 	    hn_txagg_pkts_sysctl, "I",
1121dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation packets, "
1122dc13fee6SSepherosa Ziehau 	    "0 -- disable, -1 -- auto");
1123*6c1204dfSSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "polling",
1124*6c1204dfSSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
1125*6c1204dfSSepherosa Ziehau 	    hn_polling_sysctl, "I",
1126*6c1204dfSSepherosa Ziehau 	    "Polling frequency: [100,1000000], 0 disable polling");
112715516c77SSepherosa Ziehau 
112815516c77SSepherosa Ziehau 	/*
112915516c77SSepherosa Ziehau 	 * Setup the ifmedia, which has been initialized earlier.
113015516c77SSepherosa Ziehau 	 */
113115516c77SSepherosa Ziehau 	ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL);
113215516c77SSepherosa Ziehau 	ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO);
113315516c77SSepherosa Ziehau 	/* XXX ifmedia_set really should do this for us */
113415516c77SSepherosa Ziehau 	sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media;
113515516c77SSepherosa Ziehau 
113615516c77SSepherosa Ziehau 	/*
113715516c77SSepherosa Ziehau 	 * Setup the ifnet for this interface.
113815516c77SSepherosa Ziehau 	 */
113915516c77SSepherosa Ziehau 
114015516c77SSepherosa Ziehau 	ifp->if_baudrate = IF_Gbps(10);
114115516c77SSepherosa Ziehau 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
114215516c77SSepherosa Ziehau 	ifp->if_ioctl = hn_ioctl;
114315516c77SSepherosa Ziehau 	ifp->if_init = hn_init;
114423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
114515516c77SSepherosa Ziehau 	if (hn_use_if_start) {
114615516c77SSepherosa Ziehau 		int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]);
114715516c77SSepherosa Ziehau 
114815516c77SSepherosa Ziehau 		ifp->if_start = hn_start;
114915516c77SSepherosa Ziehau 		IFQ_SET_MAXLEN(&ifp->if_snd, qdepth);
115015516c77SSepherosa Ziehau 		ifp->if_snd.ifq_drv_maxlen = qdepth - 1;
115115516c77SSepherosa Ziehau 		IFQ_SET_READY(&ifp->if_snd);
115223bf9e15SSepherosa Ziehau 	} else
115323bf9e15SSepherosa Ziehau #endif
115423bf9e15SSepherosa Ziehau 	{
115515516c77SSepherosa Ziehau 		ifp->if_transmit = hn_transmit;
115615516c77SSepherosa Ziehau 		ifp->if_qflush = hn_xmit_qflush;
115715516c77SSepherosa Ziehau 	}
115815516c77SSepherosa Ziehau 
115915516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO;
116015516c77SSepherosa Ziehau #ifdef foo
116115516c77SSepherosa Ziehau 	/* We can't diff IPv6 packets from IPv4 packets on RX path. */
116215516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM_IPV6;
116315516c77SSepherosa Ziehau #endif
116415516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_VLAN) {
116515516c77SSepherosa Ziehau 		/* XXX not sure about VLAN_MTU. */
116615516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
116715516c77SSepherosa Ziehau 	}
116815516c77SSepherosa Ziehau 
116915516c77SSepherosa Ziehau 	ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist;
117015516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP_MASK)
117115516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM;
117215516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP6_MASK)
117315516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM_IPV6;
117415516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO4) {
117515516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO4;
117615516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP_TSO;
117715516c77SSepherosa Ziehau 	}
117815516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO6) {
117915516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO6;
118015516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP6_TSO;
118115516c77SSepherosa Ziehau 	}
118215516c77SSepherosa Ziehau 
118315516c77SSepherosa Ziehau 	/* Enable all available capabilities by default. */
118415516c77SSepherosa Ziehau 	ifp->if_capenable = ifp->if_capabilities;
118515516c77SSepherosa Ziehau 
11867960e6baSSepherosa Ziehau 	/*
11877960e6baSSepherosa Ziehau 	 * Disable IPv6 TSO and TXCSUM by default, they still can
11887960e6baSSepherosa Ziehau 	 * be enabled through SIOCSIFCAP.
11897960e6baSSepherosa Ziehau 	 */
11907960e6baSSepherosa Ziehau 	ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
11917960e6baSSepherosa Ziehau 	ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO);
11927960e6baSSepherosa Ziehau 
119315516c77SSepherosa Ziehau 	if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) {
119415516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU);
119515516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX;
119615516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = PAGE_SIZE;
119715516c77SSepherosa Ziehau 	}
119815516c77SSepherosa Ziehau 
119915516c77SSepherosa Ziehau 	ether_ifattach(ifp, eaddr);
120015516c77SSepherosa Ziehau 
120115516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) {
120215516c77SSepherosa Ziehau 		if_printf(ifp, "TSO segcnt %u segsz %u\n",
120315516c77SSepherosa Ziehau 		    ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize);
120415516c77SSepherosa Ziehau 	}
120515516c77SSepherosa Ziehau 
120615516c77SSepherosa Ziehau 	/* Inform the upper layer about the long frame support. */
120715516c77SSepherosa Ziehau 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
120815516c77SSepherosa Ziehau 
120915516c77SSepherosa Ziehau 	/*
121015516c77SSepherosa Ziehau 	 * Kick off link status check.
121115516c77SSepherosa Ziehau 	 */
121215516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
121315516c77SSepherosa Ziehau 	hn_update_link_status(sc);
121415516c77SSepherosa Ziehau 
121515516c77SSepherosa Ziehau 	return (0);
121615516c77SSepherosa Ziehau failed:
121715516c77SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)
121815516c77SSepherosa Ziehau 		hn_synth_detach(sc);
121915516c77SSepherosa Ziehau 	hn_detach(dev);
122015516c77SSepherosa Ziehau 	return (error);
122115516c77SSepherosa Ziehau }
122215516c77SSepherosa Ziehau 
122315516c77SSepherosa Ziehau static int
122415516c77SSepherosa Ziehau hn_detach(device_t dev)
122515516c77SSepherosa Ziehau {
122615516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
122715516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
122815516c77SSepherosa Ziehau 
122925641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) {
123025641fc7SSepherosa Ziehau 		/*
123125641fc7SSepherosa Ziehau 		 * In case that the vmbus missed the orphan handler
123225641fc7SSepherosa Ziehau 		 * installation.
123325641fc7SSepherosa Ziehau 		 */
123425641fc7SSepherosa Ziehau 		vmbus_xact_ctx_orphan(sc->hn_xact);
123525641fc7SSepherosa Ziehau 	}
123625641fc7SSepherosa Ziehau 
123715516c77SSepherosa Ziehau 	if (device_is_attached(dev)) {
123815516c77SSepherosa Ziehau 		HN_LOCK(sc);
123915516c77SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
124015516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
124115516c77SSepherosa Ziehau 				hn_stop(sc);
124215516c77SSepherosa Ziehau 			/*
124315516c77SSepherosa Ziehau 			 * NOTE:
124415516c77SSepherosa Ziehau 			 * hn_stop() only suspends data, so managment
124515516c77SSepherosa Ziehau 			 * stuffs have to be suspended manually here.
124615516c77SSepherosa Ziehau 			 */
124715516c77SSepherosa Ziehau 			hn_suspend_mgmt(sc);
124815516c77SSepherosa Ziehau 			hn_synth_detach(sc);
124915516c77SSepherosa Ziehau 		}
125015516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
125115516c77SSepherosa Ziehau 		ether_ifdetach(ifp);
125215516c77SSepherosa Ziehau 	}
125315516c77SSepherosa Ziehau 
125415516c77SSepherosa Ziehau 	ifmedia_removeall(&sc->hn_media);
125515516c77SSepherosa Ziehau 	hn_destroy_rx_data(sc);
125615516c77SSepherosa Ziehau 	hn_destroy_tx_data(sc);
125715516c77SSepherosa Ziehau 
12580e11868dSSepherosa Ziehau 	if (sc->hn_tx_taskqs != NULL && sc->hn_tx_taskqs != hn_tx_taskque) {
1259fdd0222aSSepherosa Ziehau 		int i;
1260fdd0222aSSepherosa Ziehau 
1261fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
1262fdd0222aSSepherosa Ziehau 			taskqueue_free(sc->hn_tx_taskqs[i]);
1263fdd0222aSSepherosa Ziehau 		free(sc->hn_tx_taskqs, M_DEVBUF);
1264fdd0222aSSepherosa Ziehau 	}
126515516c77SSepherosa Ziehau 	taskqueue_free(sc->hn_mgmt_taskq0);
126615516c77SSepherosa Ziehau 
126725641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL) {
126825641fc7SSepherosa Ziehau 		/*
126925641fc7SSepherosa Ziehau 		 * Uninstall the orphan handler _before_ the xact is
127025641fc7SSepherosa Ziehau 		 * destructed.
127125641fc7SSepherosa Ziehau 		 */
127225641fc7SSepherosa Ziehau 		vmbus_chan_unset_orphan(sc->hn_prichan);
127315516c77SSepherosa Ziehau 		vmbus_xact_ctx_destroy(sc->hn_xact);
127425641fc7SSepherosa Ziehau 	}
127515516c77SSepherosa Ziehau 
127615516c77SSepherosa Ziehau 	if_free(ifp);
127715516c77SSepherosa Ziehau 
127815516c77SSepherosa Ziehau 	HN_LOCK_DESTROY(sc);
127915516c77SSepherosa Ziehau 	return (0);
128015516c77SSepherosa Ziehau }
128115516c77SSepherosa Ziehau 
128215516c77SSepherosa Ziehau static int
128315516c77SSepherosa Ziehau hn_shutdown(device_t dev)
128415516c77SSepherosa Ziehau {
128515516c77SSepherosa Ziehau 
128615516c77SSepherosa Ziehau 	return (0);
128715516c77SSepherosa Ziehau }
128815516c77SSepherosa Ziehau 
128915516c77SSepherosa Ziehau static void
129015516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc)
129115516c77SSepherosa Ziehau {
129215516c77SSepherosa Ziehau 	uint32_t link_status;
129315516c77SSepherosa Ziehau 	int error;
129415516c77SSepherosa Ziehau 
129515516c77SSepherosa Ziehau 	error = hn_rndis_get_linkstatus(sc, &link_status);
129615516c77SSepherosa Ziehau 	if (error) {
129715516c77SSepherosa Ziehau 		/* XXX what to do? */
129815516c77SSepherosa Ziehau 		return;
129915516c77SSepherosa Ziehau 	}
130015516c77SSepherosa Ziehau 
130115516c77SSepherosa Ziehau 	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
130215516c77SSepherosa Ziehau 		sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
130315516c77SSepherosa Ziehau 	else
130415516c77SSepherosa Ziehau 		sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
130515516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp,
130615516c77SSepherosa Ziehau 	    (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ?
130715516c77SSepherosa Ziehau 	    LINK_STATE_UP : LINK_STATE_DOWN);
130815516c77SSepherosa Ziehau }
130915516c77SSepherosa Ziehau 
131015516c77SSepherosa Ziehau static void
131115516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused)
131215516c77SSepherosa Ziehau {
131315516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
131415516c77SSepherosa Ziehau 
131515516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
131615516c77SSepherosa Ziehau 		return;
131715516c77SSepherosa Ziehau 	hn_link_status(sc);
131815516c77SSepherosa Ziehau }
131915516c77SSepherosa Ziehau 
132015516c77SSepherosa Ziehau static void
132115516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused)
132215516c77SSepherosa Ziehau {
132315516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
132415516c77SSepherosa Ziehau 
132515516c77SSepherosa Ziehau 	/* Prevent any link status checks from running. */
132615516c77SSepherosa Ziehau 	sc->hn_link_flags |= HN_LINK_FLAG_NETCHG;
132715516c77SSepherosa Ziehau 
132815516c77SSepherosa Ziehau 	/*
132915516c77SSepherosa Ziehau 	 * Fake up a [link down --> link up] state change; 5 seconds
133015516c77SSepherosa Ziehau 	 * delay is used, which closely simulates miibus reaction
133115516c77SSepherosa Ziehau 	 * upon link down event.
133215516c77SSepherosa Ziehau 	 */
133315516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
133415516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
133515516c77SSepherosa Ziehau 	taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0,
133615516c77SSepherosa Ziehau 	    &sc->hn_netchg_status, 5 * hz);
133715516c77SSepherosa Ziehau }
133815516c77SSepherosa Ziehau 
133915516c77SSepherosa Ziehau static void
134015516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused)
134115516c77SSepherosa Ziehau {
134215516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
134315516c77SSepherosa Ziehau 
134415516c77SSepherosa Ziehau 	/* Re-allow link status checks. */
134515516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG;
134615516c77SSepherosa Ziehau 	hn_link_status(sc);
134715516c77SSepherosa Ziehau }
134815516c77SSepherosa Ziehau 
134915516c77SSepherosa Ziehau static void
135015516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc)
135115516c77SSepherosa Ziehau {
135215516c77SSepherosa Ziehau 
135315516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
135415516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
135515516c77SSepherosa Ziehau }
135615516c77SSepherosa Ziehau 
135715516c77SSepherosa Ziehau static void
135815516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc)
135915516c77SSepherosa Ziehau {
136015516c77SSepherosa Ziehau 
136115516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
136215516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init);
136315516c77SSepherosa Ziehau }
136415516c77SSepherosa Ziehau 
136515516c77SSepherosa Ziehau static __inline int
136615516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
136715516c77SSepherosa Ziehau     struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
136815516c77SSepherosa Ziehau {
136915516c77SSepherosa Ziehau 	struct mbuf *m = *m_head;
137015516c77SSepherosa Ziehau 	int error;
137115516c77SSepherosa Ziehau 
137215516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim"));
137315516c77SSepherosa Ziehau 
137415516c77SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap,
137515516c77SSepherosa Ziehau 	    m, segs, nsegs, BUS_DMA_NOWAIT);
137615516c77SSepherosa Ziehau 	if (error == EFBIG) {
137715516c77SSepherosa Ziehau 		struct mbuf *m_new;
137815516c77SSepherosa Ziehau 
137915516c77SSepherosa Ziehau 		m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX);
138015516c77SSepherosa Ziehau 		if (m_new == NULL)
138115516c77SSepherosa Ziehau 			return ENOBUFS;
138215516c77SSepherosa Ziehau 		else
138315516c77SSepherosa Ziehau 			*m_head = m = m_new;
138415516c77SSepherosa Ziehau 		txr->hn_tx_collapsed++;
138515516c77SSepherosa Ziehau 
138615516c77SSepherosa Ziehau 		error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag,
138715516c77SSepherosa Ziehau 		    txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT);
138815516c77SSepherosa Ziehau 	}
138915516c77SSepherosa Ziehau 	if (!error) {
139015516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap,
139115516c77SSepherosa Ziehau 		    BUS_DMASYNC_PREWRITE);
139215516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_DMAMAP;
139315516c77SSepherosa Ziehau 	}
139415516c77SSepherosa Ziehau 	return error;
139515516c77SSepherosa Ziehau }
139615516c77SSepherosa Ziehau 
139715516c77SSepherosa Ziehau static __inline int
139815516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd)
139915516c77SSepherosa Ziehau {
140015516c77SSepherosa Ziehau 
140115516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0,
140215516c77SSepherosa Ziehau 	    ("put an onlist txd %#x", txd->flags));
1403dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1404dc13fee6SSepherosa Ziehau 	    ("put an onagg txd %#x", txd->flags));
140515516c77SSepherosa Ziehau 
140615516c77SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
140715516c77SSepherosa Ziehau 	if (atomic_fetchadd_int(&txd->refs, -1) != 1)
140815516c77SSepherosa Ziehau 		return 0;
140915516c77SSepherosa Ziehau 
1410dc13fee6SSepherosa Ziehau 	if (!STAILQ_EMPTY(&txd->agg_list)) {
1411dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tmp_txd;
1412dc13fee6SSepherosa Ziehau 
1413dc13fee6SSepherosa Ziehau 		while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) {
1414dc13fee6SSepherosa Ziehau 			int freed;
1415dc13fee6SSepherosa Ziehau 
1416dc13fee6SSepherosa Ziehau 			KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list),
1417dc13fee6SSepherosa Ziehau 			    ("resursive aggregation on aggregated txdesc"));
1418dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG),
1419dc13fee6SSepherosa Ziehau 			    ("not aggregated txdesc"));
1420dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
1421dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc uses dmamap"));
1422dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
1423dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc consumes "
1424dc13fee6SSepherosa Ziehau 			     "chimney sending buffer"));
1425dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_size == 0,
1426dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc has non-zero "
1427dc13fee6SSepherosa Ziehau 			     "chimney sending size"));
1428dc13fee6SSepherosa Ziehau 
1429dc13fee6SSepherosa Ziehau 			STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link);
1430dc13fee6SSepherosa Ziehau 			tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG;
1431dc13fee6SSepherosa Ziehau 			freed = hn_txdesc_put(txr, tmp_txd);
1432dc13fee6SSepherosa Ziehau 			KASSERT(freed, ("failed to free aggregated txdesc"));
1433dc13fee6SSepherosa Ziehau 		}
1434dc13fee6SSepherosa Ziehau 	}
1435dc13fee6SSepherosa Ziehau 
143615516c77SSepherosa Ziehau 	if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) {
143715516c77SSepherosa Ziehau 		KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
143815516c77SSepherosa Ziehau 		    ("chim txd uses dmamap"));
143915516c77SSepherosa Ziehau 		hn_chim_free(txr->hn_sc, txd->chim_index);
144015516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
1441dc13fee6SSepherosa Ziehau 		txd->chim_size = 0;
144215516c77SSepherosa Ziehau 	} else if (txd->flags & HN_TXD_FLAG_DMAMAP) {
144315516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag,
144415516c77SSepherosa Ziehau 		    txd->data_dmap, BUS_DMASYNC_POSTWRITE);
144515516c77SSepherosa Ziehau 		bus_dmamap_unload(txr->hn_tx_data_dtag,
144615516c77SSepherosa Ziehau 		    txd->data_dmap);
144715516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_DMAMAP;
144815516c77SSepherosa Ziehau 	}
144915516c77SSepherosa Ziehau 
145015516c77SSepherosa Ziehau 	if (txd->m != NULL) {
145115516c77SSepherosa Ziehau 		m_freem(txd->m);
145215516c77SSepherosa Ziehau 		txd->m = NULL;
145315516c77SSepherosa Ziehau 	}
145415516c77SSepherosa Ziehau 
145515516c77SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONLIST;
145615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
145715516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
145815516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_avail >= 0 &&
145915516c77SSepherosa Ziehau 	    txr->hn_txdesc_avail < txr->hn_txdesc_cnt,
146015516c77SSepherosa Ziehau 	    ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail));
146115516c77SSepherosa Ziehau 	txr->hn_txdesc_avail++;
146215516c77SSepherosa Ziehau 	SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
146315516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
146485e4ae1eSSepherosa Ziehau #else	/* HN_USE_TXDESC_BUFRING */
146585e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
146615516c77SSepherosa Ziehau 	atomic_add_int(&txr->hn_txdesc_avail, 1);
146715516c77SSepherosa Ziehau #endif
146885e4ae1eSSepherosa Ziehau 	buf_ring_enqueue(txr->hn_txdesc_br, txd);
146985e4ae1eSSepherosa Ziehau #endif	/* !HN_USE_TXDESC_BUFRING */
147015516c77SSepherosa Ziehau 
147115516c77SSepherosa Ziehau 	return 1;
147215516c77SSepherosa Ziehau }
147315516c77SSepherosa Ziehau 
147415516c77SSepherosa Ziehau static __inline struct hn_txdesc *
147515516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr)
147615516c77SSepherosa Ziehau {
147715516c77SSepherosa Ziehau 	struct hn_txdesc *txd;
147815516c77SSepherosa Ziehau 
147915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
148015516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
148115516c77SSepherosa Ziehau 	txd = SLIST_FIRST(&txr->hn_txlist);
148215516c77SSepherosa Ziehau 	if (txd != NULL) {
148315516c77SSepherosa Ziehau 		KASSERT(txr->hn_txdesc_avail > 0,
148415516c77SSepherosa Ziehau 		    ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail));
148515516c77SSepherosa Ziehau 		txr->hn_txdesc_avail--;
148615516c77SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&txr->hn_txlist, link);
148715516c77SSepherosa Ziehau 	}
148815516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
148915516c77SSepherosa Ziehau #else
149015516c77SSepherosa Ziehau 	txd = buf_ring_dequeue_sc(txr->hn_txdesc_br);
149115516c77SSepherosa Ziehau #endif
149215516c77SSepherosa Ziehau 
149315516c77SSepherosa Ziehau 	if (txd != NULL) {
149415516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
149585e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
149615516c77SSepherosa Ziehau 		atomic_subtract_int(&txr->hn_txdesc_avail, 1);
149715516c77SSepherosa Ziehau #endif
149885e4ae1eSSepherosa Ziehau #endif	/* HN_USE_TXDESC_BUFRING */
149915516c77SSepherosa Ziehau 		KASSERT(txd->m == NULL && txd->refs == 0 &&
1500dc13fee6SSepherosa Ziehau 		    STAILQ_EMPTY(&txd->agg_list) &&
150115516c77SSepherosa Ziehau 		    txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
1502dc13fee6SSepherosa Ziehau 		    txd->chim_size == 0 &&
150315516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONLIST) &&
1504dc13fee6SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONAGG) == 0 &&
150515516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd"));
150615516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_ONLIST;
150715516c77SSepherosa Ziehau 		txd->refs = 1;
150815516c77SSepherosa Ziehau 	}
150915516c77SSepherosa Ziehau 	return txd;
151015516c77SSepherosa Ziehau }
151115516c77SSepherosa Ziehau 
151215516c77SSepherosa Ziehau static __inline void
151315516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd)
151415516c77SSepherosa Ziehau {
151515516c77SSepherosa Ziehau 
151615516c77SSepherosa Ziehau 	/* 0->1 transition will never work */
151725641fc7SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
151815516c77SSepherosa Ziehau 	atomic_add_int(&txd->refs, 1);
151915516c77SSepherosa Ziehau }
152015516c77SSepherosa Ziehau 
1521dc13fee6SSepherosa Ziehau static __inline void
1522dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd)
1523dc13fee6SSepherosa Ziehau {
1524dc13fee6SSepherosa Ziehau 
1525dc13fee6SSepherosa Ziehau 	KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1526dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on aggregating txdesc"));
1527dc13fee6SSepherosa Ziehau 
1528dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1529dc13fee6SSepherosa Ziehau 	    ("already aggregated"));
1530dc13fee6SSepherosa Ziehau 	KASSERT(STAILQ_EMPTY(&txd->agg_list),
1531dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on to-be-aggregated txdesc"));
1532dc13fee6SSepherosa Ziehau 
1533dc13fee6SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONAGG;
1534dc13fee6SSepherosa Ziehau 	STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link);
1535dc13fee6SSepherosa Ziehau }
1536dc13fee6SSepherosa Ziehau 
153715516c77SSepherosa Ziehau static bool
153815516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr)
153915516c77SSepherosa Ziehau {
154015516c77SSepherosa Ziehau 	bool pending = false;
154115516c77SSepherosa Ziehau 
154215516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
154315516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
154415516c77SSepherosa Ziehau 	if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt)
154515516c77SSepherosa Ziehau 		pending = true;
154615516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
154715516c77SSepherosa Ziehau #else
154815516c77SSepherosa Ziehau 	if (!buf_ring_full(txr->hn_txdesc_br))
154915516c77SSepherosa Ziehau 		pending = true;
155015516c77SSepherosa Ziehau #endif
155115516c77SSepherosa Ziehau 	return (pending);
155215516c77SSepherosa Ziehau }
155315516c77SSepherosa Ziehau 
155415516c77SSepherosa Ziehau static __inline void
155515516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr)
155615516c77SSepherosa Ziehau {
155715516c77SSepherosa Ziehau 	txr->hn_has_txeof = 0;
155815516c77SSepherosa Ziehau 	txr->hn_txeof(txr);
155915516c77SSepherosa Ziehau }
156015516c77SSepherosa Ziehau 
156115516c77SSepherosa Ziehau static void
156215516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc,
156315516c77SSepherosa Ziehau     struct vmbus_channel *chan, const void *data __unused, int dlen __unused)
156415516c77SSepherosa Ziehau {
156515516c77SSepherosa Ziehau 	struct hn_txdesc *txd = sndc->hn_cbarg;
156615516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
156715516c77SSepherosa Ziehau 
156815516c77SSepherosa Ziehau 	txr = txd->txr;
156915516c77SSepherosa Ziehau 	KASSERT(txr->hn_chan == chan,
157015516c77SSepherosa Ziehau 	    ("channel mismatch, on chan%u, should be chan%u",
1571aa1a2adcSSepherosa Ziehau 	     vmbus_chan_id(chan), vmbus_chan_id(txr->hn_chan)));
157215516c77SSepherosa Ziehau 
157315516c77SSepherosa Ziehau 	txr->hn_has_txeof = 1;
157415516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
157515516c77SSepherosa Ziehau 
157615516c77SSepherosa Ziehau 	++txr->hn_txdone_cnt;
157715516c77SSepherosa Ziehau 	if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) {
157815516c77SSepherosa Ziehau 		txr->hn_txdone_cnt = 0;
157915516c77SSepherosa Ziehau 		if (txr->hn_oactive)
158015516c77SSepherosa Ziehau 			hn_txeof(txr);
158115516c77SSepherosa Ziehau 	}
158215516c77SSepherosa Ziehau }
158315516c77SSepherosa Ziehau 
158415516c77SSepherosa Ziehau static void
158515516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
158615516c77SSepherosa Ziehau {
158715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
158815516c77SSepherosa Ziehau 	tcp_lro_flush_all(&rxr->hn_lro);
158915516c77SSepherosa Ziehau #endif
159015516c77SSepherosa Ziehau 
159115516c77SSepherosa Ziehau 	/*
159215516c77SSepherosa Ziehau 	 * NOTE:
159315516c77SSepherosa Ziehau 	 * 'txr' could be NULL, if multiple channels and
159415516c77SSepherosa Ziehau 	 * ifnet.if_start method are enabled.
159515516c77SSepherosa Ziehau 	 */
159615516c77SSepherosa Ziehau 	if (txr == NULL || !txr->hn_has_txeof)
159715516c77SSepherosa Ziehau 		return;
159815516c77SSepherosa Ziehau 
159915516c77SSepherosa Ziehau 	txr->hn_txdone_cnt = 0;
160015516c77SSepherosa Ziehau 	hn_txeof(txr);
160115516c77SSepherosa Ziehau }
160215516c77SSepherosa Ziehau 
160315516c77SSepherosa Ziehau static __inline uint32_t
160415516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs)
160515516c77SSepherosa Ziehau {
160615516c77SSepherosa Ziehau 
160715516c77SSepherosa Ziehau 	KASSERT(ofs >= sizeof(struct rndis_packet_msg),
160815516c77SSepherosa Ziehau 	    ("invalid RNDIS packet msg offset %u", ofs));
160915516c77SSepherosa Ziehau 	return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset));
161015516c77SSepherosa Ziehau }
161115516c77SSepherosa Ziehau 
161215516c77SSepherosa Ziehau static __inline void *
161315516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
161415516c77SSepherosa Ziehau     size_t pi_dlen, uint32_t pi_type)
161515516c77SSepherosa Ziehau {
161615516c77SSepherosa Ziehau 	const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
161715516c77SSepherosa Ziehau 	struct rndis_pktinfo *pi;
161815516c77SSepherosa Ziehau 
161915516c77SSepherosa Ziehau 	KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
162015516c77SSepherosa Ziehau 	    ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
162115516c77SSepherosa Ziehau 
162215516c77SSepherosa Ziehau 	/*
162315516c77SSepherosa Ziehau 	 * Per-packet-info does not move; it only grows.
162415516c77SSepherosa Ziehau 	 *
162515516c77SSepherosa Ziehau 	 * NOTE:
162615516c77SSepherosa Ziehau 	 * rm_pktinfooffset in this phase counts from the beginning
162715516c77SSepherosa Ziehau 	 * of rndis_packet_msg.
162815516c77SSepherosa Ziehau 	 */
162915516c77SSepherosa Ziehau 	KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
163015516c77SSepherosa Ziehau 	    ("%u pktinfo overflows RNDIS packet msg", pi_type));
163115516c77SSepherosa Ziehau 	pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
163215516c77SSepherosa Ziehau 	    pkt->rm_pktinfolen);
163315516c77SSepherosa Ziehau 	pkt->rm_pktinfolen += pi_size;
163415516c77SSepherosa Ziehau 
163515516c77SSepherosa Ziehau 	pi->rm_size = pi_size;
163615516c77SSepherosa Ziehau 	pi->rm_type = pi_type;
163715516c77SSepherosa Ziehau 	pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
163815516c77SSepherosa Ziehau 
163915516c77SSepherosa Ziehau 	/* Data immediately follow per-packet-info. */
164015516c77SSepherosa Ziehau 	pkt->rm_dataoffset += pi_size;
164115516c77SSepherosa Ziehau 
164215516c77SSepherosa Ziehau 	/* Update RNDIS packet msg length */
164315516c77SSepherosa Ziehau 	pkt->rm_len += pi_size;
164415516c77SSepherosa Ziehau 
164515516c77SSepherosa Ziehau 	return (pi->rm_data);
164615516c77SSepherosa Ziehau }
164715516c77SSepherosa Ziehau 
1648dc13fee6SSepherosa Ziehau static __inline int
1649dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr)
1650dc13fee6SSepherosa Ziehau {
1651dc13fee6SSepherosa Ziehau 	struct hn_txdesc *txd;
1652dc13fee6SSepherosa Ziehau 	struct mbuf *m;
1653dc13fee6SSepherosa Ziehau 	int error, pkts;
1654dc13fee6SSepherosa Ziehau 
1655dc13fee6SSepherosa Ziehau 	txd = txr->hn_agg_txd;
1656dc13fee6SSepherosa Ziehau 	KASSERT(txd != NULL, ("no aggregate txdesc"));
1657dc13fee6SSepherosa Ziehau 
1658dc13fee6SSepherosa Ziehau 	/*
1659dc13fee6SSepherosa Ziehau 	 * Since hn_txpkt() will reset this temporary stat, save
1660dc13fee6SSepherosa Ziehau 	 * it now, so that oerrors can be updated properly, if
1661dc13fee6SSepherosa Ziehau 	 * hn_txpkt() ever fails.
1662dc13fee6SSepherosa Ziehau 	 */
1663dc13fee6SSepherosa Ziehau 	pkts = txr->hn_stat_pkts;
1664dc13fee6SSepherosa Ziehau 
1665dc13fee6SSepherosa Ziehau 	/*
1666dc13fee6SSepherosa Ziehau 	 * Since txd's mbuf will _not_ be freed upon hn_txpkt()
1667dc13fee6SSepherosa Ziehau 	 * failure, save it for later freeing, if hn_txpkt() ever
1668dc13fee6SSepherosa Ziehau 	 * fails.
1669dc13fee6SSepherosa Ziehau 	 */
1670dc13fee6SSepherosa Ziehau 	m = txd->m;
1671dc13fee6SSepherosa Ziehau 	error = hn_txpkt(ifp, txr, txd);
1672dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
1673dc13fee6SSepherosa Ziehau 		/* txd is freed, but m is not. */
1674dc13fee6SSepherosa Ziehau 		m_freem(m);
1675dc13fee6SSepherosa Ziehau 
1676dc13fee6SSepherosa Ziehau 		txr->hn_flush_failed++;
1677dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts);
1678dc13fee6SSepherosa Ziehau 	}
1679dc13fee6SSepherosa Ziehau 
1680dc13fee6SSepherosa Ziehau 	/* Reset all aggregation states. */
1681dc13fee6SSepherosa Ziehau 	txr->hn_agg_txd = NULL;
1682dc13fee6SSepherosa Ziehau 	txr->hn_agg_szleft = 0;
1683dc13fee6SSepherosa Ziehau 	txr->hn_agg_pktleft = 0;
1684dc13fee6SSepherosa Ziehau 	txr->hn_agg_prevpkt = NULL;
1685dc13fee6SSepherosa Ziehau 
1686dc13fee6SSepherosa Ziehau 	return (error);
1687dc13fee6SSepherosa Ziehau }
1688dc13fee6SSepherosa Ziehau 
1689dc13fee6SSepherosa Ziehau static void *
1690dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
1691dc13fee6SSepherosa Ziehau     int pktsize)
1692dc13fee6SSepherosa Ziehau {
1693dc13fee6SSepherosa Ziehau 	void *chim;
1694dc13fee6SSepherosa Ziehau 
1695dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL) {
1696dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) {
1697dc13fee6SSepherosa Ziehau 			struct hn_txdesc *agg_txd = txr->hn_agg_txd;
1698dc13fee6SSepherosa Ziehau 			struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt;
1699dc13fee6SSepherosa Ziehau 			int olen;
1700dc13fee6SSepherosa Ziehau 
1701dc13fee6SSepherosa Ziehau 			/*
1702dc13fee6SSepherosa Ziehau 			 * Update the previous RNDIS packet's total length,
1703dc13fee6SSepherosa Ziehau 			 * it can be increased due to the mandatory alignment
1704dc13fee6SSepherosa Ziehau 			 * padding for this RNDIS packet.  And update the
1705dc13fee6SSepherosa Ziehau 			 * aggregating txdesc's chimney sending buffer size
1706dc13fee6SSepherosa Ziehau 			 * accordingly.
1707dc13fee6SSepherosa Ziehau 			 *
1708dc13fee6SSepherosa Ziehau 			 * XXX
1709dc13fee6SSepherosa Ziehau 			 * Zero-out the padding, as required by the RNDIS spec.
1710dc13fee6SSepherosa Ziehau 			 */
1711dc13fee6SSepherosa Ziehau 			olen = pkt->rm_len;
1712dc13fee6SSepherosa Ziehau 			pkt->rm_len = roundup2(olen, txr->hn_agg_align);
1713dc13fee6SSepherosa Ziehau 			agg_txd->chim_size += pkt->rm_len - olen;
1714dc13fee6SSepherosa Ziehau 
1715dc13fee6SSepherosa Ziehau 			/* Link this txdesc to the parent. */
1716dc13fee6SSepherosa Ziehau 			hn_txdesc_agg(agg_txd, txd);
1717dc13fee6SSepherosa Ziehau 
1718dc13fee6SSepherosa Ziehau 			chim = (uint8_t *)pkt + pkt->rm_len;
1719dc13fee6SSepherosa Ziehau 			/* Save the current packet for later fixup. */
1720dc13fee6SSepherosa Ziehau 			txr->hn_agg_prevpkt = chim;
1721dc13fee6SSepherosa Ziehau 
1722dc13fee6SSepherosa Ziehau 			txr->hn_agg_pktleft--;
1723dc13fee6SSepherosa Ziehau 			txr->hn_agg_szleft -= pktsize;
1724dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_szleft <=
1725dc13fee6SSepherosa Ziehau 			    HN_PKTSIZE_MIN(txr->hn_agg_align)) {
1726dc13fee6SSepherosa Ziehau 				/*
1727dc13fee6SSepherosa Ziehau 				 * Probably can't aggregate more packets,
1728dc13fee6SSepherosa Ziehau 				 * flush this aggregating txdesc proactively.
1729dc13fee6SSepherosa Ziehau 				 */
1730dc13fee6SSepherosa Ziehau 				txr->hn_agg_pktleft = 0;
1731dc13fee6SSepherosa Ziehau 			}
1732dc13fee6SSepherosa Ziehau 			/* Done! */
1733dc13fee6SSepherosa Ziehau 			return (chim);
1734dc13fee6SSepherosa Ziehau 		}
1735dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
1736dc13fee6SSepherosa Ziehau 	}
1737dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
1738dc13fee6SSepherosa Ziehau 
1739dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney_tried++;
1740dc13fee6SSepherosa Ziehau 	txd->chim_index = hn_chim_alloc(txr->hn_sc);
1741dc13fee6SSepherosa Ziehau 	if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID)
1742dc13fee6SSepherosa Ziehau 		return (NULL);
1743dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney++;
1744dc13fee6SSepherosa Ziehau 
1745dc13fee6SSepherosa Ziehau 	chim = txr->hn_sc->hn_chim +
1746dc13fee6SSepherosa Ziehau 	    (txd->chim_index * txr->hn_sc->hn_chim_szmax);
1747dc13fee6SSepherosa Ziehau 
1748dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_pktmax > 1 &&
1749dc13fee6SSepherosa Ziehau 	    txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) {
1750dc13fee6SSepherosa Ziehau 		txr->hn_agg_txd = txd;
1751dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1;
1752dc13fee6SSepherosa Ziehau 		txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize;
1753dc13fee6SSepherosa Ziehau 		txr->hn_agg_prevpkt = chim;
1754dc13fee6SSepherosa Ziehau 	}
1755dc13fee6SSepherosa Ziehau 	return (chim);
1756dc13fee6SSepherosa Ziehau }
1757dc13fee6SSepherosa Ziehau 
175815516c77SSepherosa Ziehau /*
175915516c77SSepherosa Ziehau  * NOTE:
176015516c77SSepherosa Ziehau  * If this function fails, then both txd and m_head0 will be freed.
176115516c77SSepherosa Ziehau  */
176215516c77SSepherosa Ziehau static int
1763dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
1764dc13fee6SSepherosa Ziehau     struct mbuf **m_head0)
176515516c77SSepherosa Ziehau {
176615516c77SSepherosa Ziehau 	bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX];
176715516c77SSepherosa Ziehau 	int error, nsegs, i;
176815516c77SSepherosa Ziehau 	struct mbuf *m_head = *m_head0;
176915516c77SSepherosa Ziehau 	struct rndis_packet_msg *pkt;
177015516c77SSepherosa Ziehau 	uint32_t *pi_data;
17718966e5d5SSepherosa Ziehau 	void *chim = NULL;
1772dc13fee6SSepherosa Ziehau 	int pkt_hlen, pkt_size;
177315516c77SSepherosa Ziehau 
177415516c77SSepherosa Ziehau 	pkt = txd->rndis_pkt;
1775dc13fee6SSepherosa Ziehau 	pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align);
1776dc13fee6SSepherosa Ziehau 	if (pkt_size < txr->hn_chim_size) {
1777dc13fee6SSepherosa Ziehau 		chim = hn_try_txagg(ifp, txr, txd, pkt_size);
1778dc13fee6SSepherosa Ziehau 		if (chim != NULL)
17798966e5d5SSepherosa Ziehau 			pkt = chim;
1780dc13fee6SSepherosa Ziehau 	} else {
1781dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL)
1782dc13fee6SSepherosa Ziehau 			hn_flush_txagg(ifp, txr);
17838966e5d5SSepherosa Ziehau 	}
17848966e5d5SSepherosa Ziehau 
178515516c77SSepherosa Ziehau 	pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
178615516c77SSepherosa Ziehau 	pkt->rm_len = sizeof(*pkt) + m_head->m_pkthdr.len;
178715516c77SSepherosa Ziehau 	pkt->rm_dataoffset = sizeof(*pkt);
178815516c77SSepherosa Ziehau 	pkt->rm_datalen = m_head->m_pkthdr.len;
1789dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataoffset = 0;
1790dc13fee6SSepherosa Ziehau 	pkt->rm_oobdatalen = 0;
1791dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataelements = 0;
179215516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = sizeof(*pkt);
179315516c77SSepherosa Ziehau 	pkt->rm_pktinfolen = 0;
1794dc13fee6SSepherosa Ziehau 	pkt->rm_vchandle = 0;
1795dc13fee6SSepherosa Ziehau 	pkt->rm_reserved = 0;
179615516c77SSepherosa Ziehau 
179715516c77SSepherosa Ziehau 	if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) {
179815516c77SSepherosa Ziehau 		/*
179915516c77SSepherosa Ziehau 		 * Set the hash value for this packet, so that the host could
180015516c77SSepherosa Ziehau 		 * dispatch the TX done event for this packet back to this TX
180115516c77SSepherosa Ziehau 		 * ring's channel.
180215516c77SSepherosa Ziehau 		 */
180315516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
180415516c77SSepherosa Ziehau 		    HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL);
180515516c77SSepherosa Ziehau 		*pi_data = txr->hn_tx_idx;
180615516c77SSepherosa Ziehau 	}
180715516c77SSepherosa Ziehau 
180815516c77SSepherosa Ziehau 	if (m_head->m_flags & M_VLANTAG) {
180915516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
181015516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
181115516c77SSepherosa Ziehau 		*pi_data = NDIS_VLAN_INFO_MAKE(
181215516c77SSepherosa Ziehau 		    EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag),
181315516c77SSepherosa Ziehau 		    EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag),
181415516c77SSepherosa Ziehau 		    EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag));
181515516c77SSepherosa Ziehau 	}
181615516c77SSepherosa Ziehau 
181715516c77SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
181815516c77SSepherosa Ziehau #if defined(INET6) || defined(INET)
181915516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
182015516c77SSepherosa Ziehau 		    NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO);
182115516c77SSepherosa Ziehau #ifdef INET
182215516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
182315516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV4(0,
182415516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
182515516c77SSepherosa Ziehau 		}
182615516c77SSepherosa Ziehau #endif
182715516c77SSepherosa Ziehau #if defined(INET6) && defined(INET)
182815516c77SSepherosa Ziehau 		else
182915516c77SSepherosa Ziehau #endif
183015516c77SSepherosa Ziehau #ifdef INET6
183115516c77SSepherosa Ziehau 		{
183215516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV6(0,
183315516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
183415516c77SSepherosa Ziehau 		}
183515516c77SSepherosa Ziehau #endif
183615516c77SSepherosa Ziehau #endif	/* INET6 || INET */
183715516c77SSepherosa Ziehau 	} else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) {
183815516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
183915516c77SSepherosa Ziehau 		    NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
184015516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
184115516c77SSepherosa Ziehau 		    (CSUM_IP6_TCP | CSUM_IP6_UDP)) {
184215516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV6;
184315516c77SSepherosa Ziehau 		} else {
184415516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV4;
184515516c77SSepherosa Ziehau 			if (m_head->m_pkthdr.csum_flags & CSUM_IP)
184615516c77SSepherosa Ziehau 				*pi_data |= NDIS_TXCSUM_INFO_IPCS;
184715516c77SSepherosa Ziehau 		}
184815516c77SSepherosa Ziehau 
184915516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP))
185015516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_TCPCS;
185115516c77SSepherosa Ziehau 		else if (m_head->m_pkthdr.csum_flags &
185215516c77SSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP6_UDP))
185315516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_UDPCS;
185415516c77SSepherosa Ziehau 	}
185515516c77SSepherosa Ziehau 
1856dc13fee6SSepherosa Ziehau 	pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
185715516c77SSepherosa Ziehau 	/* Convert RNDIS packet message offsets */
185815516c77SSepherosa Ziehau 	pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt->rm_dataoffset);
185915516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset);
186015516c77SSepherosa Ziehau 
186115516c77SSepherosa Ziehau 	/*
18628966e5d5SSepherosa Ziehau 	 * Fast path: Chimney sending.
186315516c77SSepherosa Ziehau 	 */
18648966e5d5SSepherosa Ziehau 	if (chim != NULL) {
1865dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tgt_txd = txd;
1866dc13fee6SSepherosa Ziehau 
1867dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL) {
1868dc13fee6SSepherosa Ziehau 			tgt_txd = txr->hn_agg_txd;
1869dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
1870dc13fee6SSepherosa Ziehau 			*m_head0 = NULL;
1871dc13fee6SSepherosa Ziehau #endif
1872dc13fee6SSepherosa Ziehau 		}
1873dc13fee6SSepherosa Ziehau 
1874dc13fee6SSepherosa Ziehau 		KASSERT(pkt == chim,
1875dc13fee6SSepherosa Ziehau 		    ("RNDIS pkt not in chimney sending buffer"));
1876dc13fee6SSepherosa Ziehau 		KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID,
1877dc13fee6SSepherosa Ziehau 		    ("chimney sending buffer is not used"));
1878dc13fee6SSepherosa Ziehau 		tgt_txd->chim_size += pkt->rm_len;
187915516c77SSepherosa Ziehau 
18808966e5d5SSepherosa Ziehau 		m_copydata(m_head, 0, m_head->m_pkthdr.len,
1881dc13fee6SSepherosa Ziehau 		    ((uint8_t *)chim) + pkt_hlen);
188215516c77SSepherosa Ziehau 
188315516c77SSepherosa Ziehau 		txr->hn_gpa_cnt = 0;
188415516c77SSepherosa Ziehau 		txr->hn_sendpkt = hn_txpkt_chim;
188515516c77SSepherosa Ziehau 		goto done;
188615516c77SSepherosa Ziehau 	}
1887dc13fee6SSepherosa Ziehau 
1888dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc"));
18898966e5d5SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
18908966e5d5SSepherosa Ziehau 	    ("chimney buffer is used"));
18918966e5d5SSepherosa Ziehau 	KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc"));
189215516c77SSepherosa Ziehau 
189315516c77SSepherosa Ziehau 	error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs);
1894dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
189515516c77SSepherosa Ziehau 		int freed;
189615516c77SSepherosa Ziehau 
189715516c77SSepherosa Ziehau 		/*
189815516c77SSepherosa Ziehau 		 * This mbuf is not linked w/ the txd yet, so free it now.
189915516c77SSepherosa Ziehau 		 */
190015516c77SSepherosa Ziehau 		m_freem(m_head);
190115516c77SSepherosa Ziehau 		*m_head0 = NULL;
190215516c77SSepherosa Ziehau 
190315516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
190415516c77SSepherosa Ziehau 		KASSERT(freed != 0,
190515516c77SSepherosa Ziehau 		    ("fail to free txd upon txdma error"));
190615516c77SSepherosa Ziehau 
190715516c77SSepherosa Ziehau 		txr->hn_txdma_failed++;
1908dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
190915516c77SSepherosa Ziehau 		return error;
191015516c77SSepherosa Ziehau 	}
191115516c77SSepherosa Ziehau 	*m_head0 = m_head;
191215516c77SSepherosa Ziehau 
191315516c77SSepherosa Ziehau 	/* +1 RNDIS packet message */
191415516c77SSepherosa Ziehau 	txr->hn_gpa_cnt = nsegs + 1;
191515516c77SSepherosa Ziehau 
191615516c77SSepherosa Ziehau 	/* send packet with page buffer */
191715516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr);
191815516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK;
1919dc13fee6SSepherosa Ziehau 	txr->hn_gpa[0].gpa_len = pkt_hlen;
192015516c77SSepherosa Ziehau 
192115516c77SSepherosa Ziehau 	/*
192215516c77SSepherosa Ziehau 	 * Fill the page buffers with mbuf info after the page
192315516c77SSepherosa Ziehau 	 * buffer for RNDIS packet message.
192415516c77SSepherosa Ziehau 	 */
192515516c77SSepherosa Ziehau 	for (i = 0; i < nsegs; ++i) {
192615516c77SSepherosa Ziehau 		struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1];
192715516c77SSepherosa Ziehau 
192815516c77SSepherosa Ziehau 		gpa->gpa_page = atop(segs[i].ds_addr);
192915516c77SSepherosa Ziehau 		gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK;
193015516c77SSepherosa Ziehau 		gpa->gpa_len = segs[i].ds_len;
193115516c77SSepherosa Ziehau 	}
193215516c77SSepherosa Ziehau 
193315516c77SSepherosa Ziehau 	txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
193415516c77SSepherosa Ziehau 	txd->chim_size = 0;
193515516c77SSepherosa Ziehau 	txr->hn_sendpkt = hn_txpkt_sglist;
193615516c77SSepherosa Ziehau done:
193715516c77SSepherosa Ziehau 	txd->m = m_head;
193815516c77SSepherosa Ziehau 
193915516c77SSepherosa Ziehau 	/* Set the completion routine */
194015516c77SSepherosa Ziehau 	hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd);
194115516c77SSepherosa Ziehau 
1942dc13fee6SSepherosa Ziehau 	/* Update temporary stats for later use. */
1943dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts++;
1944dc13fee6SSepherosa Ziehau 	txr->hn_stat_size += m_head->m_pkthdr.len;
1945dc13fee6SSepherosa Ziehau 	if (m_head->m_flags & M_MCAST)
1946dc13fee6SSepherosa Ziehau 		txr->hn_stat_mcasts++;
1947dc13fee6SSepherosa Ziehau 
194815516c77SSepherosa Ziehau 	return 0;
194915516c77SSepherosa Ziehau }
195015516c77SSepherosa Ziehau 
195115516c77SSepherosa Ziehau /*
195215516c77SSepherosa Ziehau  * NOTE:
195315516c77SSepherosa Ziehau  * If this function fails, then txd will be freed, but the mbuf
195415516c77SSepherosa Ziehau  * associated w/ the txd will _not_ be freed.
195515516c77SSepherosa Ziehau  */
195615516c77SSepherosa Ziehau static int
195715516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd)
195815516c77SSepherosa Ziehau {
19598e7d3136SSepherosa Ziehau 	int error, send_failed = 0, has_bpf;
196015516c77SSepherosa Ziehau 
196115516c77SSepherosa Ziehau again:
19628e7d3136SSepherosa Ziehau 	has_bpf = bpf_peers_present(ifp->if_bpf);
19638e7d3136SSepherosa Ziehau 	if (has_bpf) {
196415516c77SSepherosa Ziehau 		/*
19658e7d3136SSepherosa Ziehau 		 * Make sure that this txd and any aggregated txds are not
19668e7d3136SSepherosa Ziehau 		 * freed before ETHER_BPF_MTAP.
196715516c77SSepherosa Ziehau 		 */
196815516c77SSepherosa Ziehau 		hn_txdesc_hold(txd);
19698e7d3136SSepherosa Ziehau 	}
197015516c77SSepherosa Ziehau 	error = txr->hn_sendpkt(txr, txd);
197115516c77SSepherosa Ziehau 	if (!error) {
19728e7d3136SSepherosa Ziehau 		if (has_bpf) {
1973dc13fee6SSepherosa Ziehau 			const struct hn_txdesc *tmp_txd;
1974dc13fee6SSepherosa Ziehau 
197515516c77SSepherosa Ziehau 			ETHER_BPF_MTAP(ifp, txd->m);
1976dc13fee6SSepherosa Ziehau 			STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link)
1977dc13fee6SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, tmp_txd->m);
1978dc13fee6SSepherosa Ziehau 		}
1979dc13fee6SSepherosa Ziehau 
1980dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts);
198123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
198223bf9e15SSepherosa Ziehau 		if (!hn_use_if_start)
198323bf9e15SSepherosa Ziehau #endif
198423bf9e15SSepherosa Ziehau 		{
198515516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OBYTES,
1986dc13fee6SSepherosa Ziehau 			    txr->hn_stat_size);
1987dc13fee6SSepherosa Ziehau 			if (txr->hn_stat_mcasts != 0) {
1988dc13fee6SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OMCASTS,
1989dc13fee6SSepherosa Ziehau 				    txr->hn_stat_mcasts);
199015516c77SSepherosa Ziehau 			}
1991dc13fee6SSepherosa Ziehau 		}
1992dc13fee6SSepherosa Ziehau 		txr->hn_pkts += txr->hn_stat_pkts;
1993dc13fee6SSepherosa Ziehau 		txr->hn_sends++;
199415516c77SSepherosa Ziehau 	}
19958e7d3136SSepherosa Ziehau 	if (has_bpf)
199615516c77SSepherosa Ziehau 		hn_txdesc_put(txr, txd);
199715516c77SSepherosa Ziehau 
199815516c77SSepherosa Ziehau 	if (__predict_false(error)) {
199915516c77SSepherosa Ziehau 		int freed;
200015516c77SSepherosa Ziehau 
200115516c77SSepherosa Ziehau 		/*
200215516c77SSepherosa Ziehau 		 * This should "really rarely" happen.
200315516c77SSepherosa Ziehau 		 *
200415516c77SSepherosa Ziehau 		 * XXX Too many RX to be acked or too many sideband
200515516c77SSepherosa Ziehau 		 * commands to run?  Ask netvsc_channel_rollup()
200615516c77SSepherosa Ziehau 		 * to kick start later.
200715516c77SSepherosa Ziehau 		 */
200815516c77SSepherosa Ziehau 		txr->hn_has_txeof = 1;
200915516c77SSepherosa Ziehau 		if (!send_failed) {
201015516c77SSepherosa Ziehau 			txr->hn_send_failed++;
201115516c77SSepherosa Ziehau 			send_failed = 1;
201215516c77SSepherosa Ziehau 			/*
201315516c77SSepherosa Ziehau 			 * Try sending again after set hn_has_txeof;
201415516c77SSepherosa Ziehau 			 * in case that we missed the last
201515516c77SSepherosa Ziehau 			 * netvsc_channel_rollup().
201615516c77SSepherosa Ziehau 			 */
201715516c77SSepherosa Ziehau 			goto again;
201815516c77SSepherosa Ziehau 		}
201915516c77SSepherosa Ziehau 		if_printf(ifp, "send failed\n");
202015516c77SSepherosa Ziehau 
202115516c77SSepherosa Ziehau 		/*
202215516c77SSepherosa Ziehau 		 * Caller will perform further processing on the
202315516c77SSepherosa Ziehau 		 * associated mbuf, so don't free it in hn_txdesc_put();
202415516c77SSepherosa Ziehau 		 * only unload it from the DMA map in hn_txdesc_put(),
202515516c77SSepherosa Ziehau 		 * if it was loaded.
202615516c77SSepherosa Ziehau 		 */
202715516c77SSepherosa Ziehau 		txd->m = NULL;
202815516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
202915516c77SSepherosa Ziehau 		KASSERT(freed != 0,
203015516c77SSepherosa Ziehau 		    ("fail to free txd upon send error"));
203115516c77SSepherosa Ziehau 
203215516c77SSepherosa Ziehau 		txr->hn_send_failed++;
203315516c77SSepherosa Ziehau 	}
2034dc13fee6SSepherosa Ziehau 
2035dc13fee6SSepherosa Ziehau 	/* Reset temporary stats, after this sending is done. */
2036dc13fee6SSepherosa Ziehau 	txr->hn_stat_size = 0;
2037dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts = 0;
2038dc13fee6SSepherosa Ziehau 	txr->hn_stat_mcasts = 0;
2039dc13fee6SSepherosa Ziehau 
2040dc13fee6SSepherosa Ziehau 	return (error);
204115516c77SSepherosa Ziehau }
204215516c77SSepherosa Ziehau 
204315516c77SSepherosa Ziehau /*
204415516c77SSepherosa Ziehau  * Append the specified data to the indicated mbuf chain,
204515516c77SSepherosa Ziehau  * Extend the mbuf chain if the new data does not fit in
204615516c77SSepherosa Ziehau  * existing space.
204715516c77SSepherosa Ziehau  *
204815516c77SSepherosa Ziehau  * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c.
204915516c77SSepherosa Ziehau  * There should be an equivalent in the kernel mbuf code,
205015516c77SSepherosa Ziehau  * but there does not appear to be one yet.
205115516c77SSepherosa Ziehau  *
205215516c77SSepherosa Ziehau  * Differs from m_append() in that additional mbufs are
205315516c77SSepherosa Ziehau  * allocated with cluster size MJUMPAGESIZE, and filled
205415516c77SSepherosa Ziehau  * accordingly.
205515516c77SSepherosa Ziehau  *
205615516c77SSepherosa Ziehau  * Return 1 if able to complete the job; otherwise 0.
205715516c77SSepherosa Ziehau  */
205815516c77SSepherosa Ziehau static int
205915516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp)
206015516c77SSepherosa Ziehau {
206115516c77SSepherosa Ziehau 	struct mbuf *m, *n;
206215516c77SSepherosa Ziehau 	int remainder, space;
206315516c77SSepherosa Ziehau 
206415516c77SSepherosa Ziehau 	for (m = m0; m->m_next != NULL; m = m->m_next)
206515516c77SSepherosa Ziehau 		;
206615516c77SSepherosa Ziehau 	remainder = len;
206715516c77SSepherosa Ziehau 	space = M_TRAILINGSPACE(m);
206815516c77SSepherosa Ziehau 	if (space > 0) {
206915516c77SSepherosa Ziehau 		/*
207015516c77SSepherosa Ziehau 		 * Copy into available space.
207115516c77SSepherosa Ziehau 		 */
207215516c77SSepherosa Ziehau 		if (space > remainder)
207315516c77SSepherosa Ziehau 			space = remainder;
207415516c77SSepherosa Ziehau 		bcopy(cp, mtod(m, caddr_t) + m->m_len, space);
207515516c77SSepherosa Ziehau 		m->m_len += space;
207615516c77SSepherosa Ziehau 		cp += space;
207715516c77SSepherosa Ziehau 		remainder -= space;
207815516c77SSepherosa Ziehau 	}
207915516c77SSepherosa Ziehau 	while (remainder > 0) {
208015516c77SSepherosa Ziehau 		/*
208115516c77SSepherosa Ziehau 		 * Allocate a new mbuf; could check space
208215516c77SSepherosa Ziehau 		 * and allocate a cluster instead.
208315516c77SSepherosa Ziehau 		 */
208415516c77SSepherosa Ziehau 		n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE);
208515516c77SSepherosa Ziehau 		if (n == NULL)
208615516c77SSepherosa Ziehau 			break;
208715516c77SSepherosa Ziehau 		n->m_len = min(MJUMPAGESIZE, remainder);
208815516c77SSepherosa Ziehau 		bcopy(cp, mtod(n, caddr_t), n->m_len);
208915516c77SSepherosa Ziehau 		cp += n->m_len;
209015516c77SSepherosa Ziehau 		remainder -= n->m_len;
209115516c77SSepherosa Ziehau 		m->m_next = n;
209215516c77SSepherosa Ziehau 		m = n;
209315516c77SSepherosa Ziehau 	}
209415516c77SSepherosa Ziehau 	if (m0->m_flags & M_PKTHDR)
209515516c77SSepherosa Ziehau 		m0->m_pkthdr.len += len - remainder;
209615516c77SSepherosa Ziehau 
209715516c77SSepherosa Ziehau 	return (remainder == 0);
209815516c77SSepherosa Ziehau }
209915516c77SSepherosa Ziehau 
210015516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
210115516c77SSepherosa Ziehau static __inline int
210215516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m)
210315516c77SSepherosa Ziehau {
210415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
210515516c77SSepherosa Ziehau 	if (hn_lro_mbufq_depth) {
210615516c77SSepherosa Ziehau 		tcp_lro_queue_mbuf(lc, m);
210715516c77SSepherosa Ziehau 		return 0;
210815516c77SSepherosa Ziehau 	}
210915516c77SSepherosa Ziehau #endif
211015516c77SSepherosa Ziehau 	return tcp_lro_rx(lc, m, 0);
211115516c77SSepherosa Ziehau }
211215516c77SSepherosa Ziehau #endif
211315516c77SSepherosa Ziehau 
211415516c77SSepherosa Ziehau static int
211515516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
211615516c77SSepherosa Ziehau     const struct hn_rxinfo *info)
211715516c77SSepherosa Ziehau {
211815516c77SSepherosa Ziehau 	struct ifnet *ifp = rxr->hn_ifp;
211915516c77SSepherosa Ziehau 	struct mbuf *m_new;
212015516c77SSepherosa Ziehau 	int size, do_lro = 0, do_csum = 1;
212115516c77SSepherosa Ziehau 	int hash_type;
212215516c77SSepherosa Ziehau 
212315516c77SSepherosa Ziehau 	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
212415516c77SSepherosa Ziehau 		return (0);
212515516c77SSepherosa Ziehau 
212615516c77SSepherosa Ziehau 	/*
212715516c77SSepherosa Ziehau 	 * Bail out if packet contains more data than configured MTU.
212815516c77SSepherosa Ziehau 	 */
212915516c77SSepherosa Ziehau 	if (dlen > (ifp->if_mtu + ETHER_HDR_LEN)) {
213015516c77SSepherosa Ziehau 		return (0);
213115516c77SSepherosa Ziehau 	} else if (dlen <= MHLEN) {
213215516c77SSepherosa Ziehau 		m_new = m_gethdr(M_NOWAIT, MT_DATA);
213315516c77SSepherosa Ziehau 		if (m_new == NULL) {
213415516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
213515516c77SSepherosa Ziehau 			return (0);
213615516c77SSepherosa Ziehau 		}
213715516c77SSepherosa Ziehau 		memcpy(mtod(m_new, void *), data, dlen);
213815516c77SSepherosa Ziehau 		m_new->m_pkthdr.len = m_new->m_len = dlen;
213915516c77SSepherosa Ziehau 		rxr->hn_small_pkts++;
214015516c77SSepherosa Ziehau 	} else {
214115516c77SSepherosa Ziehau 		/*
214215516c77SSepherosa Ziehau 		 * Get an mbuf with a cluster.  For packets 2K or less,
214315516c77SSepherosa Ziehau 		 * get a standard 2K cluster.  For anything larger, get a
214415516c77SSepherosa Ziehau 		 * 4K cluster.  Any buffers larger than 4K can cause problems
214515516c77SSepherosa Ziehau 		 * if looped around to the Hyper-V TX channel, so avoid them.
214615516c77SSepherosa Ziehau 		 */
214715516c77SSepherosa Ziehau 		size = MCLBYTES;
214815516c77SSepherosa Ziehau 		if (dlen > MCLBYTES) {
214915516c77SSepherosa Ziehau 			/* 4096 */
215015516c77SSepherosa Ziehau 			size = MJUMPAGESIZE;
215115516c77SSepherosa Ziehau 		}
215215516c77SSepherosa Ziehau 
215315516c77SSepherosa Ziehau 		m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size);
215415516c77SSepherosa Ziehau 		if (m_new == NULL) {
215515516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
215615516c77SSepherosa Ziehau 			return (0);
215715516c77SSepherosa Ziehau 		}
215815516c77SSepherosa Ziehau 
215915516c77SSepherosa Ziehau 		hv_m_append(m_new, dlen, data);
216015516c77SSepherosa Ziehau 	}
216115516c77SSepherosa Ziehau 	m_new->m_pkthdr.rcvif = ifp;
216215516c77SSepherosa Ziehau 
216315516c77SSepherosa Ziehau 	if (__predict_false((ifp->if_capenable & IFCAP_RXCSUM) == 0))
216415516c77SSepherosa Ziehau 		do_csum = 0;
216515516c77SSepherosa Ziehau 
216615516c77SSepherosa Ziehau 	/* receive side checksum offload */
216715516c77SSepherosa Ziehau 	if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) {
216815516c77SSepherosa Ziehau 		/* IP csum offload */
216915516c77SSepherosa Ziehau 		if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) {
217015516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
217115516c77SSepherosa Ziehau 			    (CSUM_IP_CHECKED | CSUM_IP_VALID);
217215516c77SSepherosa Ziehau 			rxr->hn_csum_ip++;
217315516c77SSepherosa Ziehau 		}
217415516c77SSepherosa Ziehau 
217515516c77SSepherosa Ziehau 		/* TCP/UDP csum offload */
217615516c77SSepherosa Ziehau 		if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK |
217715516c77SSepherosa Ziehau 		     NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) {
217815516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
217915516c77SSepherosa Ziehau 			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
218015516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_data = 0xffff;
218115516c77SSepherosa Ziehau 			if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK)
218215516c77SSepherosa Ziehau 				rxr->hn_csum_tcp++;
218315516c77SSepherosa Ziehau 			else
218415516c77SSepherosa Ziehau 				rxr->hn_csum_udp++;
218515516c77SSepherosa Ziehau 		}
218615516c77SSepherosa Ziehau 
218715516c77SSepherosa Ziehau 		/*
218815516c77SSepherosa Ziehau 		 * XXX
218915516c77SSepherosa Ziehau 		 * As of this write (Oct 28th, 2016), host side will turn
219015516c77SSepherosa Ziehau 		 * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so
219115516c77SSepherosa Ziehau 		 * the do_lro setting here is actually _not_ accurate.  We
219215516c77SSepherosa Ziehau 		 * depend on the RSS hash type check to reset do_lro.
219315516c77SSepherosa Ziehau 		 */
219415516c77SSepherosa Ziehau 		if ((info->csum_info &
219515516c77SSepherosa Ziehau 		     (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) ==
219615516c77SSepherosa Ziehau 		    (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK))
219715516c77SSepherosa Ziehau 			do_lro = 1;
219815516c77SSepherosa Ziehau 	} else {
219915516c77SSepherosa Ziehau 		const struct ether_header *eh;
220015516c77SSepherosa Ziehau 		uint16_t etype;
220115516c77SSepherosa Ziehau 		int hoff;
220215516c77SSepherosa Ziehau 
220315516c77SSepherosa Ziehau 		hoff = sizeof(*eh);
220415516c77SSepherosa Ziehau 		if (m_new->m_len < hoff)
220515516c77SSepherosa Ziehau 			goto skip;
220615516c77SSepherosa Ziehau 		eh = mtod(m_new, struct ether_header *);
220715516c77SSepherosa Ziehau 		etype = ntohs(eh->ether_type);
220815516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_VLAN) {
220915516c77SSepherosa Ziehau 			const struct ether_vlan_header *evl;
221015516c77SSepherosa Ziehau 
221115516c77SSepherosa Ziehau 			hoff = sizeof(*evl);
221215516c77SSepherosa Ziehau 			if (m_new->m_len < hoff)
221315516c77SSepherosa Ziehau 				goto skip;
221415516c77SSepherosa Ziehau 			evl = mtod(m_new, struct ether_vlan_header *);
221515516c77SSepherosa Ziehau 			etype = ntohs(evl->evl_proto);
221615516c77SSepherosa Ziehau 		}
221715516c77SSepherosa Ziehau 
221815516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_IP) {
221915516c77SSepherosa Ziehau 			int pr;
222015516c77SSepherosa Ziehau 
222115516c77SSepherosa Ziehau 			pr = hn_check_iplen(m_new, hoff);
222215516c77SSepherosa Ziehau 			if (pr == IPPROTO_TCP) {
222315516c77SSepherosa Ziehau 				if (do_csum &&
222415516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
222515516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_TCP)) {
222615516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
222715516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
222815516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
222915516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
223015516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
223115516c77SSepherosa Ziehau 				}
223215516c77SSepherosa Ziehau 				do_lro = 1;
223315516c77SSepherosa Ziehau 			} else if (pr == IPPROTO_UDP) {
223415516c77SSepherosa Ziehau 				if (do_csum &&
223515516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
223615516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_UDP)) {
223715516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
223815516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
223915516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
224015516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
224115516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
224215516c77SSepherosa Ziehau 				}
224315516c77SSepherosa Ziehau 			} else if (pr != IPPROTO_DONE && do_csum &&
224415516c77SSepherosa Ziehau 			    (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) {
224515516c77SSepherosa Ziehau 				rxr->hn_csum_trusted++;
224615516c77SSepherosa Ziehau 				m_new->m_pkthdr.csum_flags |=
224715516c77SSepherosa Ziehau 				    (CSUM_IP_CHECKED | CSUM_IP_VALID);
224815516c77SSepherosa Ziehau 			}
224915516c77SSepherosa Ziehau 		}
225015516c77SSepherosa Ziehau 	}
225115516c77SSepherosa Ziehau skip:
225215516c77SSepherosa Ziehau 	if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) {
225315516c77SSepherosa Ziehau 		m_new->m_pkthdr.ether_vtag = EVL_MAKETAG(
225415516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_ID(info->vlan_info),
225515516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_PRI(info->vlan_info),
225615516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_CFI(info->vlan_info));
225715516c77SSepherosa Ziehau 		m_new->m_flags |= M_VLANTAG;
225815516c77SSepherosa Ziehau 	}
225915516c77SSepherosa Ziehau 
226015516c77SSepherosa Ziehau 	if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) {
226115516c77SSepherosa Ziehau 		rxr->hn_rss_pkts++;
226215516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = info->hash_value;
226315516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE_HASH;
226415516c77SSepherosa Ziehau 		if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) ==
226515516c77SSepherosa Ziehau 		    NDIS_HASH_FUNCTION_TOEPLITZ) {
226615516c77SSepherosa Ziehau 			uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK);
226715516c77SSepherosa Ziehau 
226815516c77SSepherosa Ziehau 			/*
226915516c77SSepherosa Ziehau 			 * NOTE:
227015516c77SSepherosa Ziehau 			 * do_lro is resetted, if the hash types are not TCP
227115516c77SSepherosa Ziehau 			 * related.  See the comment in the above csum_flags
227215516c77SSepherosa Ziehau 			 * setup section.
227315516c77SSepherosa Ziehau 			 */
227415516c77SSepherosa Ziehau 			switch (type) {
227515516c77SSepherosa Ziehau 			case NDIS_HASH_IPV4:
227615516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV4;
227715516c77SSepherosa Ziehau 				do_lro = 0;
227815516c77SSepherosa Ziehau 				break;
227915516c77SSepherosa Ziehau 
228015516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV4:
228115516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV4;
228215516c77SSepherosa Ziehau 				break;
228315516c77SSepherosa Ziehau 
228415516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6:
228515516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6;
228615516c77SSepherosa Ziehau 				do_lro = 0;
228715516c77SSepherosa Ziehau 				break;
228815516c77SSepherosa Ziehau 
228915516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6_EX:
229015516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6_EX;
229115516c77SSepherosa Ziehau 				do_lro = 0;
229215516c77SSepherosa Ziehau 				break;
229315516c77SSepherosa Ziehau 
229415516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6:
229515516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6;
229615516c77SSepherosa Ziehau 				break;
229715516c77SSepherosa Ziehau 
229815516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6_EX:
229915516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX;
230015516c77SSepherosa Ziehau 				break;
230115516c77SSepherosa Ziehau 			}
230215516c77SSepherosa Ziehau 		}
230315516c77SSepherosa Ziehau 	} else {
230415516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
230515516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE;
230615516c77SSepherosa Ziehau 	}
230715516c77SSepherosa Ziehau 	M_HASHTYPE_SET(m_new, hash_type);
230815516c77SSepherosa Ziehau 
230915516c77SSepherosa Ziehau 	/*
231015516c77SSepherosa Ziehau 	 * Note:  Moved RX completion back to hv_nv_on_receive() so all
231115516c77SSepherosa Ziehau 	 * messages (not just data messages) will trigger a response.
231215516c77SSepherosa Ziehau 	 */
231315516c77SSepherosa Ziehau 
231415516c77SSepherosa Ziehau 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
231515516c77SSepherosa Ziehau 	rxr->hn_pkts++;
231615516c77SSepherosa Ziehau 
231715516c77SSepherosa Ziehau 	if ((ifp->if_capenable & IFCAP_LRO) && do_lro) {
231815516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
231915516c77SSepherosa Ziehau 		struct lro_ctrl *lro = &rxr->hn_lro;
232015516c77SSepherosa Ziehau 
232115516c77SSepherosa Ziehau 		if (lro->lro_cnt) {
232215516c77SSepherosa Ziehau 			rxr->hn_lro_tried++;
232315516c77SSepherosa Ziehau 			if (hn_lro_rx(lro, m_new) == 0) {
232415516c77SSepherosa Ziehau 				/* DONE! */
232515516c77SSepherosa Ziehau 				return 0;
232615516c77SSepherosa Ziehau 			}
232715516c77SSepherosa Ziehau 		}
232815516c77SSepherosa Ziehau #endif
232915516c77SSepherosa Ziehau 	}
233015516c77SSepherosa Ziehau 
233115516c77SSepherosa Ziehau 	/* We're not holding the lock here, so don't release it */
233215516c77SSepherosa Ziehau 	(*ifp->if_input)(ifp, m_new);
233315516c77SSepherosa Ziehau 
233415516c77SSepherosa Ziehau 	return (0);
233515516c77SSepherosa Ziehau }
233615516c77SSepherosa Ziehau 
233715516c77SSepherosa Ziehau static int
233815516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
233915516c77SSepherosa Ziehau {
234015516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
234115516c77SSepherosa Ziehau 	struct ifreq *ifr = (struct ifreq *)data;
234215516c77SSepherosa Ziehau 	int mask, error = 0;
234315516c77SSepherosa Ziehau 
234415516c77SSepherosa Ziehau 	switch (cmd) {
234515516c77SSepherosa Ziehau 	case SIOCSIFMTU:
234615516c77SSepherosa Ziehau 		if (ifr->ifr_mtu > HN_MTU_MAX) {
234715516c77SSepherosa Ziehau 			error = EINVAL;
234815516c77SSepherosa Ziehau 			break;
234915516c77SSepherosa Ziehau 		}
235015516c77SSepherosa Ziehau 
235115516c77SSepherosa Ziehau 		HN_LOCK(sc);
235215516c77SSepherosa Ziehau 
235315516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
235415516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
235515516c77SSepherosa Ziehau 			break;
235615516c77SSepherosa Ziehau 		}
235715516c77SSepherosa Ziehau 
235815516c77SSepherosa Ziehau 		if ((sc->hn_caps & HN_CAP_MTU) == 0) {
235915516c77SSepherosa Ziehau 			/* Can't change MTU */
236015516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
236115516c77SSepherosa Ziehau 			error = EOPNOTSUPP;
236215516c77SSepherosa Ziehau 			break;
236315516c77SSepherosa Ziehau 		}
236415516c77SSepherosa Ziehau 
236515516c77SSepherosa Ziehau 		if (ifp->if_mtu == ifr->ifr_mtu) {
236615516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
236715516c77SSepherosa Ziehau 			break;
236815516c77SSepherosa Ziehau 		}
236915516c77SSepherosa Ziehau 
2370*6c1204dfSSepherosa Ziehau 		/* Disable polling. */
2371*6c1204dfSSepherosa Ziehau 		hn_polling(sc, 0);
2372*6c1204dfSSepherosa Ziehau 
237315516c77SSepherosa Ziehau 		/*
237415516c77SSepherosa Ziehau 		 * Suspend this interface before the synthetic parts
237515516c77SSepherosa Ziehau 		 * are ripped.
237615516c77SSepherosa Ziehau 		 */
237715516c77SSepherosa Ziehau 		hn_suspend(sc);
237815516c77SSepherosa Ziehau 
237915516c77SSepherosa Ziehau 		/*
238015516c77SSepherosa Ziehau 		 * Detach the synthetics parts, i.e. NVS and RNDIS.
238115516c77SSepherosa Ziehau 		 */
238215516c77SSepherosa Ziehau 		hn_synth_detach(sc);
238315516c77SSepherosa Ziehau 
238415516c77SSepherosa Ziehau 		/*
238515516c77SSepherosa Ziehau 		 * Reattach the synthetic parts, i.e. NVS and RNDIS,
238615516c77SSepherosa Ziehau 		 * with the new MTU setting.
238715516c77SSepherosa Ziehau 		 */
238815516c77SSepherosa Ziehau 		error = hn_synth_attach(sc, ifr->ifr_mtu);
238915516c77SSepherosa Ziehau 		if (error) {
239015516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
239115516c77SSepherosa Ziehau 			break;
239215516c77SSepherosa Ziehau 		}
239315516c77SSepherosa Ziehau 
239415516c77SSepherosa Ziehau 		/*
239515516c77SSepherosa Ziehau 		 * Commit the requested MTU, after the synthetic parts
239615516c77SSepherosa Ziehau 		 * have been successfully attached.
239715516c77SSepherosa Ziehau 		 */
239815516c77SSepherosa Ziehau 		ifp->if_mtu = ifr->ifr_mtu;
239915516c77SSepherosa Ziehau 
240015516c77SSepherosa Ziehau 		/*
240115516c77SSepherosa Ziehau 		 * Make sure that various parameters based on MTU are
240215516c77SSepherosa Ziehau 		 * still valid, after the MTU change.
240315516c77SSepherosa Ziehau 		 */
240415516c77SSepherosa Ziehau 		if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax)
240515516c77SSepherosa Ziehau 			hn_set_chim_size(sc, sc->hn_chim_szmax);
240615516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu);
240715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
240815516c77SSepherosa Ziehau 		if (sc->hn_rx_ring[0].hn_lro.lro_length_lim <
240915516c77SSepherosa Ziehau 		    HN_LRO_LENLIM_MIN(ifp))
241015516c77SSepherosa Ziehau 			hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
241115516c77SSepherosa Ziehau #endif
241215516c77SSepherosa Ziehau 
241315516c77SSepherosa Ziehau 		/*
241415516c77SSepherosa Ziehau 		 * All done!  Resume the interface now.
241515516c77SSepherosa Ziehau 		 */
241615516c77SSepherosa Ziehau 		hn_resume(sc);
241715516c77SSepherosa Ziehau 
2418*6c1204dfSSepherosa Ziehau 		/*
2419*6c1204dfSSepherosa Ziehau 		 * Re-enable polling if this interface is running and
2420*6c1204dfSSepherosa Ziehau 		 * the polling is requested.
2421*6c1204dfSSepherosa Ziehau 		 */
2422*6c1204dfSSepherosa Ziehau 		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->hn_pollhz > 0)
2423*6c1204dfSSepherosa Ziehau 			hn_polling(sc, sc->hn_pollhz);
2424*6c1204dfSSepherosa Ziehau 
242515516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
242615516c77SSepherosa Ziehau 		break;
242715516c77SSepherosa Ziehau 
242815516c77SSepherosa Ziehau 	case SIOCSIFFLAGS:
242915516c77SSepherosa Ziehau 		HN_LOCK(sc);
243015516c77SSepherosa Ziehau 
243115516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
243215516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
243315516c77SSepherosa Ziehau 			break;
243415516c77SSepherosa Ziehau 		}
243515516c77SSepherosa Ziehau 
243615516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_UP) {
2437fdc4f478SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2438fdc4f478SSepherosa Ziehau 				/*
2439fdc4f478SSepherosa Ziehau 				 * Caller meight hold mutex, e.g.
2440fdc4f478SSepherosa Ziehau 				 * bpf; use busy-wait for the RNDIS
2441fdc4f478SSepherosa Ziehau 				 * reply.
2442fdc4f478SSepherosa Ziehau 				 */
2443fdc4f478SSepherosa Ziehau 				HN_NO_SLEEPING(sc);
244415516c77SSepherosa Ziehau 				hn_set_rxfilter(sc);
2445fdc4f478SSepherosa Ziehau 				HN_SLEEPING_OK(sc);
2446fdc4f478SSepherosa Ziehau 			} else {
244715516c77SSepherosa Ziehau 				hn_init_locked(sc);
2448fdc4f478SSepherosa Ziehau 			}
244915516c77SSepherosa Ziehau 		} else {
245015516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
245115516c77SSepherosa Ziehau 				hn_stop(sc);
245215516c77SSepherosa Ziehau 		}
245315516c77SSepherosa Ziehau 		sc->hn_if_flags = ifp->if_flags;
245415516c77SSepherosa Ziehau 
245515516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
245615516c77SSepherosa Ziehau 		break;
245715516c77SSepherosa Ziehau 
245815516c77SSepherosa Ziehau 	case SIOCSIFCAP:
245915516c77SSepherosa Ziehau 		HN_LOCK(sc);
246015516c77SSepherosa Ziehau 		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
246115516c77SSepherosa Ziehau 
246215516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM) {
246315516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM;
246415516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM)
246515516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc);
246615516c77SSepherosa Ziehau 			else
246715516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc);
246815516c77SSepherosa Ziehau 		}
246915516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM_IPV6) {
247015516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
247115516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
247215516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc);
247315516c77SSepherosa Ziehau 			else
247415516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc);
247515516c77SSepherosa Ziehau 		}
247615516c77SSepherosa Ziehau 
247715516c77SSepherosa Ziehau 		/* TODO: flip RNDIS offload parameters for RXCSUM. */
247815516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM)
247915516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM;
248015516c77SSepherosa Ziehau #ifdef foo
248115516c77SSepherosa Ziehau 		/* We can't diff IPv6 packets from IPv4 packets on RX path. */
248215516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM_IPV6)
248315516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
248415516c77SSepherosa Ziehau #endif
248515516c77SSepherosa Ziehau 
248615516c77SSepherosa Ziehau 		if (mask & IFCAP_LRO)
248715516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_LRO;
248815516c77SSepherosa Ziehau 
248915516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO4) {
249015516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO4;
249115516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO4)
249215516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP_TSO;
249315516c77SSepherosa Ziehau 			else
249415516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP_TSO;
249515516c77SSepherosa Ziehau 		}
249615516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO6) {
249715516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO6;
249815516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO6)
249915516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP6_TSO;
250015516c77SSepherosa Ziehau 			else
250115516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP6_TSO;
250215516c77SSepherosa Ziehau 		}
250315516c77SSepherosa Ziehau 
250415516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
250515516c77SSepherosa Ziehau 		break;
250615516c77SSepherosa Ziehau 
250715516c77SSepherosa Ziehau 	case SIOCADDMULTI:
250815516c77SSepherosa Ziehau 	case SIOCDELMULTI:
250915516c77SSepherosa Ziehau 		HN_LOCK(sc);
251015516c77SSepherosa Ziehau 
251115516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
251215516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
251315516c77SSepherosa Ziehau 			break;
251415516c77SSepherosa Ziehau 		}
2515fdc4f478SSepherosa Ziehau 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2516fdc4f478SSepherosa Ziehau 			/*
2517fdc4f478SSepherosa Ziehau 			 * Multicast uses mutex; use busy-wait for
2518fdc4f478SSepherosa Ziehau 			 * the RNDIS reply.
2519fdc4f478SSepherosa Ziehau 			 */
2520fdc4f478SSepherosa Ziehau 			HN_NO_SLEEPING(sc);
252115516c77SSepherosa Ziehau 			hn_set_rxfilter(sc);
2522fdc4f478SSepherosa Ziehau 			HN_SLEEPING_OK(sc);
2523fdc4f478SSepherosa Ziehau 		}
252415516c77SSepherosa Ziehau 
252515516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
252615516c77SSepherosa Ziehau 		break;
252715516c77SSepherosa Ziehau 
252815516c77SSepherosa Ziehau 	case SIOCSIFMEDIA:
252915516c77SSepherosa Ziehau 	case SIOCGIFMEDIA:
253015516c77SSepherosa Ziehau 		error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd);
253115516c77SSepherosa Ziehau 		break;
253215516c77SSepherosa Ziehau 
253315516c77SSepherosa Ziehau 	default:
253415516c77SSepherosa Ziehau 		error = ether_ioctl(ifp, cmd, data);
253515516c77SSepherosa Ziehau 		break;
253615516c77SSepherosa Ziehau 	}
253715516c77SSepherosa Ziehau 	return (error);
253815516c77SSepherosa Ziehau }
253915516c77SSepherosa Ziehau 
254015516c77SSepherosa Ziehau static void
254115516c77SSepherosa Ziehau hn_stop(struct hn_softc *sc)
254215516c77SSepherosa Ziehau {
254315516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
254415516c77SSepherosa Ziehau 	int i;
254515516c77SSepherosa Ziehau 
254615516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
254715516c77SSepherosa Ziehau 
254815516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
254915516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
255015516c77SSepherosa Ziehau 
2551*6c1204dfSSepherosa Ziehau 	/* Disable polling. */
2552*6c1204dfSSepherosa Ziehau 	hn_polling(sc, 0);
2553*6c1204dfSSepherosa Ziehau 
255415516c77SSepherosa Ziehau 	/* Clear RUNNING bit _before_ hn_suspend_data() */
255515516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
255615516c77SSepherosa Ziehau 	hn_suspend_data(sc);
255715516c77SSepherosa Ziehau 
255815516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
255915516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
256015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
256115516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
256215516c77SSepherosa Ziehau }
256315516c77SSepherosa Ziehau 
256415516c77SSepherosa Ziehau static void
256515516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc)
256615516c77SSepherosa Ziehau {
256715516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
256815516c77SSepherosa Ziehau 	int i;
256915516c77SSepherosa Ziehau 
257015516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
257115516c77SSepherosa Ziehau 
257215516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
257315516c77SSepherosa Ziehau 		return;
257415516c77SSepherosa Ziehau 
257515516c77SSepherosa Ziehau 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
257615516c77SSepherosa Ziehau 		return;
257715516c77SSepherosa Ziehau 
257815516c77SSepherosa Ziehau 	/* Configure RX filter */
257915516c77SSepherosa Ziehau 	hn_set_rxfilter(sc);
258015516c77SSepherosa Ziehau 
258115516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
258215516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
258315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
258415516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
258515516c77SSepherosa Ziehau 
258615516c77SSepherosa Ziehau 	/* Clear TX 'suspended' bit. */
258715516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_inuse);
258815516c77SSepherosa Ziehau 
258915516c77SSepherosa Ziehau 	/* Everything is ready; unleash! */
259015516c77SSepherosa Ziehau 	atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
2591*6c1204dfSSepherosa Ziehau 
2592*6c1204dfSSepherosa Ziehau 	/* Re-enable polling if requested. */
2593*6c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz > 0)
2594*6c1204dfSSepherosa Ziehau 		hn_polling(sc, sc->hn_pollhz);
259515516c77SSepherosa Ziehau }
259615516c77SSepherosa Ziehau 
259715516c77SSepherosa Ziehau static void
259815516c77SSepherosa Ziehau hn_init(void *xsc)
259915516c77SSepherosa Ziehau {
260015516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
260115516c77SSepherosa Ziehau 
260215516c77SSepherosa Ziehau 	HN_LOCK(sc);
260315516c77SSepherosa Ziehau 	hn_init_locked(sc);
260415516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
260515516c77SSepherosa Ziehau }
260615516c77SSepherosa Ziehau 
260715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
260815516c77SSepherosa Ziehau 
260915516c77SSepherosa Ziehau static int
261015516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
261115516c77SSepherosa Ziehau {
261215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
261315516c77SSepherosa Ziehau 	unsigned int lenlim;
261415516c77SSepherosa Ziehau 	int error;
261515516c77SSepherosa Ziehau 
261615516c77SSepherosa Ziehau 	lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim;
261715516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &lenlim, 0, req);
261815516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
261915516c77SSepherosa Ziehau 		return error;
262015516c77SSepherosa Ziehau 
262115516c77SSepherosa Ziehau 	HN_LOCK(sc);
262215516c77SSepherosa Ziehau 	if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) ||
262315516c77SSepherosa Ziehau 	    lenlim > TCP_LRO_LENGTH_MAX) {
262415516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
262515516c77SSepherosa Ziehau 		return EINVAL;
262615516c77SSepherosa Ziehau 	}
262715516c77SSepherosa Ziehau 	hn_set_lro_lenlim(sc, lenlim);
262815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
262915516c77SSepherosa Ziehau 
263015516c77SSepherosa Ziehau 	return 0;
263115516c77SSepherosa Ziehau }
263215516c77SSepherosa Ziehau 
263315516c77SSepherosa Ziehau static int
263415516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS)
263515516c77SSepherosa Ziehau {
263615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
263715516c77SSepherosa Ziehau 	int ackcnt, error, i;
263815516c77SSepherosa Ziehau 
263915516c77SSepherosa Ziehau 	/*
264015516c77SSepherosa Ziehau 	 * lro_ackcnt_lim is append count limit,
264115516c77SSepherosa Ziehau 	 * +1 to turn it into aggregation limit.
264215516c77SSepherosa Ziehau 	 */
264315516c77SSepherosa Ziehau 	ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1;
264415516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &ackcnt, 0, req);
264515516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
264615516c77SSepherosa Ziehau 		return error;
264715516c77SSepherosa Ziehau 
264815516c77SSepherosa Ziehau 	if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1))
264915516c77SSepherosa Ziehau 		return EINVAL;
265015516c77SSepherosa Ziehau 
265115516c77SSepherosa Ziehau 	/*
265215516c77SSepherosa Ziehau 	 * Convert aggregation limit back to append
265315516c77SSepherosa Ziehau 	 * count limit.
265415516c77SSepherosa Ziehau 	 */
265515516c77SSepherosa Ziehau 	--ackcnt;
265615516c77SSepherosa Ziehau 	HN_LOCK(sc);
2657a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
265815516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt;
265915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
266015516c77SSepherosa Ziehau 	return 0;
266115516c77SSepherosa Ziehau }
266215516c77SSepherosa Ziehau 
266315516c77SSepherosa Ziehau #endif
266415516c77SSepherosa Ziehau 
266515516c77SSepherosa Ziehau static int
266615516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS)
266715516c77SSepherosa Ziehau {
266815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
266915516c77SSepherosa Ziehau 	int hcsum = arg2;
267015516c77SSepherosa Ziehau 	int on, error, i;
267115516c77SSepherosa Ziehau 
267215516c77SSepherosa Ziehau 	on = 0;
267315516c77SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum)
267415516c77SSepherosa Ziehau 		on = 1;
267515516c77SSepherosa Ziehau 
267615516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &on, 0, req);
267715516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
267815516c77SSepherosa Ziehau 		return error;
267915516c77SSepherosa Ziehau 
268015516c77SSepherosa Ziehau 	HN_LOCK(sc);
2681a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
268215516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
268315516c77SSepherosa Ziehau 
268415516c77SSepherosa Ziehau 		if (on)
268515516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= hcsum;
268615516c77SSepherosa Ziehau 		else
268715516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum &= ~hcsum;
268815516c77SSepherosa Ziehau 	}
268915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
269015516c77SSepherosa Ziehau 	return 0;
269115516c77SSepherosa Ziehau }
269215516c77SSepherosa Ziehau 
269315516c77SSepherosa Ziehau static int
269415516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS)
269515516c77SSepherosa Ziehau {
269615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
269715516c77SSepherosa Ziehau 	int chim_size, error;
269815516c77SSepherosa Ziehau 
269915516c77SSepherosa Ziehau 	chim_size = sc->hn_tx_ring[0].hn_chim_size;
270015516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &chim_size, 0, req);
270115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
270215516c77SSepherosa Ziehau 		return error;
270315516c77SSepherosa Ziehau 
270415516c77SSepherosa Ziehau 	if (chim_size > sc->hn_chim_szmax || chim_size <= 0)
270515516c77SSepherosa Ziehau 		return EINVAL;
270615516c77SSepherosa Ziehau 
270715516c77SSepherosa Ziehau 	HN_LOCK(sc);
270815516c77SSepherosa Ziehau 	hn_set_chim_size(sc, chim_size);
270915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
271015516c77SSepherosa Ziehau 	return 0;
271115516c77SSepherosa Ziehau }
271215516c77SSepherosa Ziehau 
271315516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
271415516c77SSepherosa Ziehau static int
271515516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS)
271615516c77SSepherosa Ziehau {
271715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
271815516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
271915516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
272015516c77SSepherosa Ziehau 	uint64_t stat;
272115516c77SSepherosa Ziehau 
272215516c77SSepherosa Ziehau 	stat = 0;
272315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
272415516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
272515516c77SSepherosa Ziehau 		stat += *((int *)((uint8_t *)rxr + ofs));
272615516c77SSepherosa Ziehau 	}
272715516c77SSepherosa Ziehau 
272815516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
272915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
273015516c77SSepherosa Ziehau 		return error;
273115516c77SSepherosa Ziehau 
273215516c77SSepherosa Ziehau 	/* Zero out this stat. */
273315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
273415516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
273515516c77SSepherosa Ziehau 		*((int *)((uint8_t *)rxr + ofs)) = 0;
273615516c77SSepherosa Ziehau 	}
273715516c77SSepherosa Ziehau 	return 0;
273815516c77SSepherosa Ziehau }
273915516c77SSepherosa Ziehau #else
274015516c77SSepherosa Ziehau static int
274115516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS)
274215516c77SSepherosa Ziehau {
274315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
274415516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
274515516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
274615516c77SSepherosa Ziehau 	uint64_t stat;
274715516c77SSepherosa Ziehau 
274815516c77SSepherosa Ziehau 	stat = 0;
2749a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
275015516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
275115516c77SSepherosa Ziehau 		stat += *((uint64_t *)((uint8_t *)rxr + ofs));
275215516c77SSepherosa Ziehau 	}
275315516c77SSepherosa Ziehau 
275415516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
275515516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
275615516c77SSepherosa Ziehau 		return error;
275715516c77SSepherosa Ziehau 
275815516c77SSepherosa Ziehau 	/* Zero out this stat. */
2759a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
276015516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
276115516c77SSepherosa Ziehau 		*((uint64_t *)((uint8_t *)rxr + ofs)) = 0;
276215516c77SSepherosa Ziehau 	}
276315516c77SSepherosa Ziehau 	return 0;
276415516c77SSepherosa Ziehau }
276515516c77SSepherosa Ziehau 
276615516c77SSepherosa Ziehau #endif
276715516c77SSepherosa Ziehau 
276815516c77SSepherosa Ziehau static int
276915516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
277015516c77SSepherosa Ziehau {
277115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
277215516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
277315516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
277415516c77SSepherosa Ziehau 	u_long stat;
277515516c77SSepherosa Ziehau 
277615516c77SSepherosa Ziehau 	stat = 0;
2777a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
277815516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
277915516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)rxr + ofs));
278015516c77SSepherosa Ziehau 	}
278115516c77SSepherosa Ziehau 
278215516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
278315516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
278415516c77SSepherosa Ziehau 		return error;
278515516c77SSepherosa Ziehau 
278615516c77SSepherosa Ziehau 	/* Zero out this stat. */
2787a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
278815516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
278915516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)rxr + ofs)) = 0;
279015516c77SSepherosa Ziehau 	}
279115516c77SSepherosa Ziehau 	return 0;
279215516c77SSepherosa Ziehau }
279315516c77SSepherosa Ziehau 
279415516c77SSepherosa Ziehau static int
279515516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
279615516c77SSepherosa Ziehau {
279715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
279815516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
279915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
280015516c77SSepherosa Ziehau 	u_long stat;
280115516c77SSepherosa Ziehau 
280215516c77SSepherosa Ziehau 	stat = 0;
2803a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
280415516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
280515516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)txr + ofs));
280615516c77SSepherosa Ziehau 	}
280715516c77SSepherosa Ziehau 
280815516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
280915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
281015516c77SSepherosa Ziehau 		return error;
281115516c77SSepherosa Ziehau 
281215516c77SSepherosa Ziehau 	/* Zero out this stat. */
2813a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
281415516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
281515516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)txr + ofs)) = 0;
281615516c77SSepherosa Ziehau 	}
281715516c77SSepherosa Ziehau 	return 0;
281815516c77SSepherosa Ziehau }
281915516c77SSepherosa Ziehau 
282015516c77SSepherosa Ziehau static int
282115516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS)
282215516c77SSepherosa Ziehau {
282315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
282415516c77SSepherosa Ziehau 	int ofs = arg2, i, error, conf;
282515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
282615516c77SSepherosa Ziehau 
282715516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[0];
282815516c77SSepherosa Ziehau 	conf = *((int *)((uint8_t *)txr + ofs));
282915516c77SSepherosa Ziehau 
283015516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &conf, 0, req);
283115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
283215516c77SSepherosa Ziehau 		return error;
283315516c77SSepherosa Ziehau 
283415516c77SSepherosa Ziehau 	HN_LOCK(sc);
2835a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
283615516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
283715516c77SSepherosa Ziehau 		*((int *)((uint8_t *)txr + ofs)) = conf;
283815516c77SSepherosa Ziehau 	}
283915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
284015516c77SSepherosa Ziehau 
284115516c77SSepherosa Ziehau 	return 0;
284215516c77SSepherosa Ziehau }
284315516c77SSepherosa Ziehau 
284415516c77SSepherosa Ziehau static int
2845dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS)
2846dc13fee6SSepherosa Ziehau {
2847dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2848dc13fee6SSepherosa Ziehau 	int error, size;
2849dc13fee6SSepherosa Ziehau 
2850dc13fee6SSepherosa Ziehau 	size = sc->hn_agg_size;
2851dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &size, 0, req);
2852dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
2853dc13fee6SSepherosa Ziehau 		return (error);
2854dc13fee6SSepherosa Ziehau 
2855dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
2856dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = size;
2857dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
2858dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
2859dc13fee6SSepherosa Ziehau 
2860dc13fee6SSepherosa Ziehau 	return (0);
2861dc13fee6SSepherosa Ziehau }
2862dc13fee6SSepherosa Ziehau 
2863dc13fee6SSepherosa Ziehau static int
2864dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS)
2865dc13fee6SSepherosa Ziehau {
2866dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2867dc13fee6SSepherosa Ziehau 	int error, pkts;
2868dc13fee6SSepherosa Ziehau 
2869dc13fee6SSepherosa Ziehau 	pkts = sc->hn_agg_pkts;
2870dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pkts, 0, req);
2871dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
2872dc13fee6SSepherosa Ziehau 		return (error);
2873dc13fee6SSepherosa Ziehau 
2874dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
2875dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = pkts;
2876dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
2877dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
2878dc13fee6SSepherosa Ziehau 
2879dc13fee6SSepherosa Ziehau 	return (0);
2880dc13fee6SSepherosa Ziehau }
2881dc13fee6SSepherosa Ziehau 
2882dc13fee6SSepherosa Ziehau static int
2883dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS)
2884dc13fee6SSepherosa Ziehau {
2885dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2886dc13fee6SSepherosa Ziehau 	int pkts;
2887dc13fee6SSepherosa Ziehau 
2888dc13fee6SSepherosa Ziehau 	pkts = sc->hn_tx_ring[0].hn_agg_pktmax;
2889dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &pkts, 0, req));
2890dc13fee6SSepherosa Ziehau }
2891dc13fee6SSepherosa Ziehau 
2892dc13fee6SSepherosa Ziehau static int
2893dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS)
2894dc13fee6SSepherosa Ziehau {
2895dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2896dc13fee6SSepherosa Ziehau 	int align;
2897dc13fee6SSepherosa Ziehau 
2898dc13fee6SSepherosa Ziehau 	align = sc->hn_tx_ring[0].hn_agg_align;
2899dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &align, 0, req));
2900dc13fee6SSepherosa Ziehau }
2901dc13fee6SSepherosa Ziehau 
2902*6c1204dfSSepherosa Ziehau static void
2903*6c1204dfSSepherosa Ziehau hn_chan_polling(struct vmbus_channel *chan, u_int pollhz)
2904*6c1204dfSSepherosa Ziehau {
2905*6c1204dfSSepherosa Ziehau 	if (pollhz == 0)
2906*6c1204dfSSepherosa Ziehau 		vmbus_chan_poll_disable(chan);
2907*6c1204dfSSepherosa Ziehau 	else
2908*6c1204dfSSepherosa Ziehau 		vmbus_chan_poll_enable(chan, pollhz);
2909*6c1204dfSSepherosa Ziehau }
2910*6c1204dfSSepherosa Ziehau 
2911*6c1204dfSSepherosa Ziehau static void
2912*6c1204dfSSepherosa Ziehau hn_polling(struct hn_softc *sc, u_int pollhz)
2913*6c1204dfSSepherosa Ziehau {
2914*6c1204dfSSepherosa Ziehau 	int nsubch = sc->hn_rx_ring_inuse - 1;
2915*6c1204dfSSepherosa Ziehau 
2916*6c1204dfSSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
2917*6c1204dfSSepherosa Ziehau 
2918*6c1204dfSSepherosa Ziehau 	if (nsubch > 0) {
2919*6c1204dfSSepherosa Ziehau 		struct vmbus_channel **subch;
2920*6c1204dfSSepherosa Ziehau 		int i;
2921*6c1204dfSSepherosa Ziehau 
2922*6c1204dfSSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
2923*6c1204dfSSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
2924*6c1204dfSSepherosa Ziehau 			hn_chan_polling(subch[i], pollhz);
2925*6c1204dfSSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
2926*6c1204dfSSepherosa Ziehau 	}
2927*6c1204dfSSepherosa Ziehau 	hn_chan_polling(sc->hn_prichan, pollhz);
2928*6c1204dfSSepherosa Ziehau }
2929*6c1204dfSSepherosa Ziehau 
2930*6c1204dfSSepherosa Ziehau static int
2931*6c1204dfSSepherosa Ziehau hn_polling_sysctl(SYSCTL_HANDLER_ARGS)
2932*6c1204dfSSepherosa Ziehau {
2933*6c1204dfSSepherosa Ziehau 	struct hn_softc *sc = arg1;
2934*6c1204dfSSepherosa Ziehau 	int pollhz, error;
2935*6c1204dfSSepherosa Ziehau 
2936*6c1204dfSSepherosa Ziehau 	pollhz = sc->hn_pollhz;
2937*6c1204dfSSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pollhz, 0, req);
2938*6c1204dfSSepherosa Ziehau 	if (error || req->newptr == NULL)
2939*6c1204dfSSepherosa Ziehau 		return (error);
2940*6c1204dfSSepherosa Ziehau 
2941*6c1204dfSSepherosa Ziehau 	if (pollhz != 0 &&
2942*6c1204dfSSepherosa Ziehau 	    (pollhz < VMBUS_CHAN_POLLHZ_MIN || pollhz > VMBUS_CHAN_POLLHZ_MAX))
2943*6c1204dfSSepherosa Ziehau 		return (EINVAL);
2944*6c1204dfSSepherosa Ziehau 
2945*6c1204dfSSepherosa Ziehau 	HN_LOCK(sc);
2946*6c1204dfSSepherosa Ziehau 	if (sc->hn_pollhz != pollhz) {
2947*6c1204dfSSepherosa Ziehau 		sc->hn_pollhz = pollhz;
2948*6c1204dfSSepherosa Ziehau 		if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) &&
2949*6c1204dfSSepherosa Ziehau 		    (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
2950*6c1204dfSSepherosa Ziehau 			hn_polling(sc, sc->hn_pollhz);
2951*6c1204dfSSepherosa Ziehau 	}
2952*6c1204dfSSepherosa Ziehau 	HN_UNLOCK(sc);
2953*6c1204dfSSepherosa Ziehau 
2954*6c1204dfSSepherosa Ziehau 	return (0);
2955*6c1204dfSSepherosa Ziehau }
2956*6c1204dfSSepherosa Ziehau 
2957dc13fee6SSepherosa Ziehau static int
295815516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS)
295915516c77SSepherosa Ziehau {
296015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
296115516c77SSepherosa Ziehau 	char verstr[16];
296215516c77SSepherosa Ziehau 
296315516c77SSepherosa Ziehau 	snprintf(verstr, sizeof(verstr), "%u.%u",
296415516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
296515516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
296615516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
296715516c77SSepherosa Ziehau }
296815516c77SSepherosa Ziehau 
296915516c77SSepherosa Ziehau static int
297015516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS)
297115516c77SSepherosa Ziehau {
297215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
297315516c77SSepherosa Ziehau 	char caps_str[128];
297415516c77SSepherosa Ziehau 	uint32_t caps;
297515516c77SSepherosa Ziehau 
297615516c77SSepherosa Ziehau 	HN_LOCK(sc);
297715516c77SSepherosa Ziehau 	caps = sc->hn_caps;
297815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
297915516c77SSepherosa Ziehau 	snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS);
298015516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req);
298115516c77SSepherosa Ziehau }
298215516c77SSepherosa Ziehau 
298315516c77SSepherosa Ziehau static int
298415516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS)
298515516c77SSepherosa Ziehau {
298615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
298715516c77SSepherosa Ziehau 	char assist_str[128];
298815516c77SSepherosa Ziehau 	uint32_t hwassist;
298915516c77SSepherosa Ziehau 
299015516c77SSepherosa Ziehau 	HN_LOCK(sc);
299115516c77SSepherosa Ziehau 	hwassist = sc->hn_ifp->if_hwassist;
299215516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
299315516c77SSepherosa Ziehau 	snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS);
299415516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req);
299515516c77SSepherosa Ziehau }
299615516c77SSepherosa Ziehau 
299715516c77SSepherosa Ziehau static int
299815516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS)
299915516c77SSepherosa Ziehau {
300015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
300115516c77SSepherosa Ziehau 	char filter_str[128];
300215516c77SSepherosa Ziehau 	uint32_t filter;
300315516c77SSepherosa Ziehau 
300415516c77SSepherosa Ziehau 	HN_LOCK(sc);
300515516c77SSepherosa Ziehau 	filter = sc->hn_rx_filter;
300615516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
300715516c77SSepherosa Ziehau 	snprintf(filter_str, sizeof(filter_str), "%b", filter,
300815516c77SSepherosa Ziehau 	    NDIS_PACKET_TYPES);
300915516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req);
301015516c77SSepherosa Ziehau }
301115516c77SSepherosa Ziehau 
301234d68912SSepherosa Ziehau #ifndef RSS
301334d68912SSepherosa Ziehau 
301415516c77SSepherosa Ziehau static int
301515516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
301615516c77SSepherosa Ziehau {
301715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
301815516c77SSepherosa Ziehau 	int error;
301915516c77SSepherosa Ziehau 
302015516c77SSepherosa Ziehau 	HN_LOCK(sc);
302115516c77SSepherosa Ziehau 
302215516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
302315516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
302415516c77SSepherosa Ziehau 		goto back;
302515516c77SSepherosa Ziehau 
302615516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
302715516c77SSepherosa Ziehau 	if (error)
302815516c77SSepherosa Ziehau 		goto back;
302915516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
303015516c77SSepherosa Ziehau 
303115516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
303215516c77SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
303315516c77SSepherosa Ziehau 	} else {
303415516c77SSepherosa Ziehau 		/* Not RSS capable, at least for now; just save the RSS key. */
303515516c77SSepherosa Ziehau 		error = 0;
303615516c77SSepherosa Ziehau 	}
303715516c77SSepherosa Ziehau back:
303815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
303915516c77SSepherosa Ziehau 	return (error);
304015516c77SSepherosa Ziehau }
304115516c77SSepherosa Ziehau 
304215516c77SSepherosa Ziehau static int
304315516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS)
304415516c77SSepherosa Ziehau {
304515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
304615516c77SSepherosa Ziehau 	int error;
304715516c77SSepherosa Ziehau 
304815516c77SSepherosa Ziehau 	HN_LOCK(sc);
304915516c77SSepherosa Ziehau 
305015516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
305115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
305215516c77SSepherosa Ziehau 		goto back;
305315516c77SSepherosa Ziehau 
305415516c77SSepherosa Ziehau 	/*
305515516c77SSepherosa Ziehau 	 * Don't allow RSS indirect table change, if this interface is not
305615516c77SSepherosa Ziehau 	 * RSS capable currently.
305715516c77SSepherosa Ziehau 	 */
305815516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
305915516c77SSepherosa Ziehau 		error = EOPNOTSUPP;
306015516c77SSepherosa Ziehau 		goto back;
306115516c77SSepherosa Ziehau 	}
306215516c77SSepherosa Ziehau 
306315516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
306415516c77SSepherosa Ziehau 	if (error)
306515516c77SSepherosa Ziehau 		goto back;
306615516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSIND;
306715516c77SSepherosa Ziehau 
3068afd4971bSSepherosa Ziehau 	hn_rss_ind_fixup(sc);
306915516c77SSepherosa Ziehau 	error = hn_rss_reconfig(sc);
307015516c77SSepherosa Ziehau back:
307115516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
307215516c77SSepherosa Ziehau 	return (error);
307315516c77SSepherosa Ziehau }
307415516c77SSepherosa Ziehau 
307534d68912SSepherosa Ziehau #endif	/* !RSS */
307634d68912SSepherosa Ziehau 
307715516c77SSepherosa Ziehau static int
307815516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS)
307915516c77SSepherosa Ziehau {
308015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
308115516c77SSepherosa Ziehau 	char hash_str[128];
308215516c77SSepherosa Ziehau 	uint32_t hash;
308315516c77SSepherosa Ziehau 
308415516c77SSepherosa Ziehau 	HN_LOCK(sc);
308515516c77SSepherosa Ziehau 	hash = sc->hn_rss_hash;
308615516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
308715516c77SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
308815516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
308915516c77SSepherosa Ziehau }
309015516c77SSepherosa Ziehau 
309115516c77SSepherosa Ziehau static int
309215516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff)
309315516c77SSepherosa Ziehau {
309415516c77SSepherosa Ziehau 	const struct ip *ip;
309515516c77SSepherosa Ziehau 	int len, iphlen, iplen;
309615516c77SSepherosa Ziehau 	const struct tcphdr *th;
309715516c77SSepherosa Ziehau 	int thoff;				/* TCP data offset */
309815516c77SSepherosa Ziehau 
309915516c77SSepherosa Ziehau 	len = hoff + sizeof(struct ip);
310015516c77SSepherosa Ziehau 
310115516c77SSepherosa Ziehau 	/* The packet must be at least the size of an IP header. */
310215516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < len)
310315516c77SSepherosa Ziehau 		return IPPROTO_DONE;
310415516c77SSepherosa Ziehau 
310515516c77SSepherosa Ziehau 	/* The fixed IP header must reside completely in the first mbuf. */
310615516c77SSepherosa Ziehau 	if (m->m_len < len)
310715516c77SSepherosa Ziehau 		return IPPROTO_DONE;
310815516c77SSepherosa Ziehau 
310915516c77SSepherosa Ziehau 	ip = mtodo(m, hoff);
311015516c77SSepherosa Ziehau 
311115516c77SSepherosa Ziehau 	/* Bound check the packet's stated IP header length. */
311215516c77SSepherosa Ziehau 	iphlen = ip->ip_hl << 2;
311315516c77SSepherosa Ziehau 	if (iphlen < sizeof(struct ip))		/* minimum header length */
311415516c77SSepherosa Ziehau 		return IPPROTO_DONE;
311515516c77SSepherosa Ziehau 
311615516c77SSepherosa Ziehau 	/* The full IP header must reside completely in the one mbuf. */
311715516c77SSepherosa Ziehau 	if (m->m_len < hoff + iphlen)
311815516c77SSepherosa Ziehau 		return IPPROTO_DONE;
311915516c77SSepherosa Ziehau 
312015516c77SSepherosa Ziehau 	iplen = ntohs(ip->ip_len);
312115516c77SSepherosa Ziehau 
312215516c77SSepherosa Ziehau 	/*
312315516c77SSepherosa Ziehau 	 * Check that the amount of data in the buffers is as
312415516c77SSepherosa Ziehau 	 * at least much as the IP header would have us expect.
312515516c77SSepherosa Ziehau 	 */
312615516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < hoff + iplen)
312715516c77SSepherosa Ziehau 		return IPPROTO_DONE;
312815516c77SSepherosa Ziehau 
312915516c77SSepherosa Ziehau 	/*
313015516c77SSepherosa Ziehau 	 * Ignore IP fragments.
313115516c77SSepherosa Ziehau 	 */
313215516c77SSepherosa Ziehau 	if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF))
313315516c77SSepherosa Ziehau 		return IPPROTO_DONE;
313415516c77SSepherosa Ziehau 
313515516c77SSepherosa Ziehau 	/*
313615516c77SSepherosa Ziehau 	 * The TCP/IP or UDP/IP header must be entirely contained within
313715516c77SSepherosa Ziehau 	 * the first fragment of a packet.
313815516c77SSepherosa Ziehau 	 */
313915516c77SSepherosa Ziehau 	switch (ip->ip_p) {
314015516c77SSepherosa Ziehau 	case IPPROTO_TCP:
314115516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct tcphdr))
314215516c77SSepherosa Ziehau 			return IPPROTO_DONE;
314315516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct tcphdr))
314415516c77SSepherosa Ziehau 			return IPPROTO_DONE;
314515516c77SSepherosa Ziehau 		th = (const struct tcphdr *)((const uint8_t *)ip + iphlen);
314615516c77SSepherosa Ziehau 		thoff = th->th_off << 2;
314715516c77SSepherosa Ziehau 		if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen)
314815516c77SSepherosa Ziehau 			return IPPROTO_DONE;
314915516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + thoff)
315015516c77SSepherosa Ziehau 			return IPPROTO_DONE;
315115516c77SSepherosa Ziehau 		break;
315215516c77SSepherosa Ziehau 	case IPPROTO_UDP:
315315516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct udphdr))
315415516c77SSepherosa Ziehau 			return IPPROTO_DONE;
315515516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct udphdr))
315615516c77SSepherosa Ziehau 			return IPPROTO_DONE;
315715516c77SSepherosa Ziehau 		break;
315815516c77SSepherosa Ziehau 	default:
315915516c77SSepherosa Ziehau 		if (iplen < iphlen)
316015516c77SSepherosa Ziehau 			return IPPROTO_DONE;
316115516c77SSepherosa Ziehau 		break;
316215516c77SSepherosa Ziehau 	}
316315516c77SSepherosa Ziehau 	return ip->ip_p;
316415516c77SSepherosa Ziehau }
316515516c77SSepherosa Ziehau 
316615516c77SSepherosa Ziehau static int
316715516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt)
316815516c77SSepherosa Ziehau {
316915516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
317015516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
317115516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
317215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
317315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
317415516c77SSepherosa Ziehau 	int lroent_cnt;
317515516c77SSepherosa Ziehau #endif
317615516c77SSepherosa Ziehau #endif
317715516c77SSepherosa Ziehau 	int i;
317815516c77SSepherosa Ziehau 
317915516c77SSepherosa Ziehau 	/*
318015516c77SSepherosa Ziehau 	 * Create RXBUF for reception.
318115516c77SSepherosa Ziehau 	 *
318215516c77SSepherosa Ziehau 	 * NOTE:
318315516c77SSepherosa Ziehau 	 * - It is shared by all channels.
318415516c77SSepherosa Ziehau 	 * - A large enough buffer is allocated, certain version of NVSes
318515516c77SSepherosa Ziehau 	 *   may further limit the usable space.
318615516c77SSepherosa Ziehau 	 */
318715516c77SSepherosa Ziehau 	sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
318815516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma,
318915516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
319015516c77SSepherosa Ziehau 	if (sc->hn_rxbuf == NULL) {
319115516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate rxbuf failed\n");
319215516c77SSepherosa Ziehau 		return (ENOMEM);
319315516c77SSepherosa Ziehau 	}
319415516c77SSepherosa Ziehau 
319515516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = ring_cnt;
319615516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt;
319715516c77SSepherosa Ziehau 
319815516c77SSepherosa Ziehau 	sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt,
319915516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
320015516c77SSepherosa Ziehau 
320115516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
320215516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
320315516c77SSepherosa Ziehau 	lroent_cnt = hn_lro_entry_count;
320415516c77SSepherosa Ziehau 	if (lroent_cnt < TCP_LRO_ENTRIES)
320515516c77SSepherosa Ziehau 		lroent_cnt = TCP_LRO_ENTRIES;
320615516c77SSepherosa Ziehau 	if (bootverbose)
320715516c77SSepherosa Ziehau 		device_printf(dev, "LRO: entry count %d\n", lroent_cnt);
320815516c77SSepherosa Ziehau #endif
320915516c77SSepherosa Ziehau #endif	/* INET || INET6 */
321015516c77SSepherosa Ziehau 
321115516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
321215516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
321315516c77SSepherosa Ziehau 
321415516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.rx sysctl tree */
321515516c77SSepherosa Ziehau 	sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx",
321615516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
321715516c77SSepherosa Ziehau 
321815516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
321915516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
322015516c77SSepherosa Ziehau 
322115516c77SSepherosa Ziehau 		rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
322215516c77SSepherosa Ziehau 		    PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE,
322315516c77SSepherosa Ziehau 		    &rxr->hn_br_dma, BUS_DMA_WAITOK);
322415516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL) {
322515516c77SSepherosa Ziehau 			device_printf(dev, "allocate bufring failed\n");
322615516c77SSepherosa Ziehau 			return (ENOMEM);
322715516c77SSepherosa Ziehau 		}
322815516c77SSepherosa Ziehau 
322915516c77SSepherosa Ziehau 		if (hn_trust_hosttcp)
323015516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP;
323115516c77SSepherosa Ziehau 		if (hn_trust_hostudp)
323215516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP;
323315516c77SSepherosa Ziehau 		if (hn_trust_hostip)
323415516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP;
323515516c77SSepherosa Ziehau 		rxr->hn_ifp = sc->hn_ifp;
323615516c77SSepherosa Ziehau 		if (i < sc->hn_tx_ring_cnt)
323715516c77SSepherosa Ziehau 			rxr->hn_txr = &sc->hn_tx_ring[i];
323815516c77SSepherosa Ziehau 		rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF;
323915516c77SSepherosa Ziehau 		rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK);
324015516c77SSepherosa Ziehau 		rxr->hn_rx_idx = i;
324115516c77SSepherosa Ziehau 		rxr->hn_rxbuf = sc->hn_rxbuf;
324215516c77SSepherosa Ziehau 
324315516c77SSepherosa Ziehau 		/*
324415516c77SSepherosa Ziehau 		 * Initialize LRO.
324515516c77SSepherosa Ziehau 		 */
324615516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
324715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
324815516c77SSepherosa Ziehau 		tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt,
324915516c77SSepherosa Ziehau 		    hn_lro_mbufq_depth);
325015516c77SSepherosa Ziehau #else
325115516c77SSepherosa Ziehau 		tcp_lro_init(&rxr->hn_lro);
325215516c77SSepherosa Ziehau 		rxr->hn_lro.ifp = sc->hn_ifp;
325315516c77SSepherosa Ziehau #endif
325415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
325515516c77SSepherosa Ziehau 		rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF;
325615516c77SSepherosa Ziehau 		rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF;
325715516c77SSepherosa Ziehau #endif
325815516c77SSepherosa Ziehau #endif	/* INET || INET6 */
325915516c77SSepherosa Ziehau 
326015516c77SSepherosa Ziehau 		if (sc->hn_rx_sysctl_tree != NULL) {
326115516c77SSepherosa Ziehau 			char name[16];
326215516c77SSepherosa Ziehau 
326315516c77SSepherosa Ziehau 			/*
326415516c77SSepherosa Ziehau 			 * Create per RX ring sysctl tree:
326515516c77SSepherosa Ziehau 			 * dev.hn.UNIT.rx.RINGID
326615516c77SSepherosa Ziehau 			 */
326715516c77SSepherosa Ziehau 			snprintf(name, sizeof(name), "%d", i);
326815516c77SSepherosa Ziehau 			rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx,
326915516c77SSepherosa Ziehau 			    SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree),
327015516c77SSepherosa Ziehau 			    OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
327115516c77SSepherosa Ziehau 
327215516c77SSepherosa Ziehau 			if (rxr->hn_rx_sysctl_tree != NULL) {
327315516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
327415516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
327515516c77SSepherosa Ziehau 				    OID_AUTO, "packets", CTLFLAG_RW,
327615516c77SSepherosa Ziehau 				    &rxr->hn_pkts, "# of packets received");
327715516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
327815516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
327915516c77SSepherosa Ziehau 				    OID_AUTO, "rss_pkts", CTLFLAG_RW,
328015516c77SSepherosa Ziehau 				    &rxr->hn_rss_pkts,
328115516c77SSepherosa Ziehau 				    "# of packets w/ RSS info received");
328215516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx,
328315516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
328415516c77SSepherosa Ziehau 				    OID_AUTO, "pktbuf_len", CTLFLAG_RD,
328515516c77SSepherosa Ziehau 				    &rxr->hn_pktbuf_len, 0,
328615516c77SSepherosa Ziehau 				    "Temporary channel packet buffer length");
328715516c77SSepherosa Ziehau 			}
328815516c77SSepherosa Ziehau 		}
328915516c77SSepherosa Ziehau 	}
329015516c77SSepherosa Ziehau 
329115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued",
329215516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
329315516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_queued),
329415516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
329515516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
329615516c77SSepherosa Ziehau #else
329715516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
329815516c77SSepherosa Ziehau #endif
329915516c77SSepherosa Ziehau 	    "LU", "LRO queued");
330015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed",
330115516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
330215516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_flushed),
330315516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
330415516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
330515516c77SSepherosa Ziehau #else
330615516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
330715516c77SSepherosa Ziehau #endif
330815516c77SSepherosa Ziehau 	    "LU", "LRO flushed");
330915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried",
331015516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
331115516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro_tried),
331215516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries");
331315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
331415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim",
331515516c77SSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
331615516c77SSepherosa Ziehau 	    hn_lro_lenlim_sysctl, "IU",
331715516c77SSepherosa Ziehau 	    "Max # of data bytes to be aggregated by LRO");
331815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim",
331915516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
332015516c77SSepherosa Ziehau 	    hn_lro_ackcnt_sysctl, "I",
332115516c77SSepherosa Ziehau 	    "Max # of ACKs to be aggregated by LRO");
332215516c77SSepherosa Ziehau #endif
332315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp",
332415516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP,
332515516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
332615516c77SSepherosa Ziehau 	    "Trust tcp segement verification on host side, "
332715516c77SSepherosa Ziehau 	    "when csum info is missing");
332815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp",
332915516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP,
333015516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
333115516c77SSepherosa Ziehau 	    "Trust udp datagram verification on host side, "
333215516c77SSepherosa Ziehau 	    "when csum info is missing");
333315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip",
333415516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP,
333515516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
333615516c77SSepherosa Ziehau 	    "Trust ip packet verification on host side, "
333715516c77SSepherosa Ziehau 	    "when csum info is missing");
333815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip",
333915516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
334015516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_ip),
334115516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP");
334215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp",
334315516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
334415516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_tcp),
334515516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP");
334615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp",
334715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
334815516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_udp),
334915516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP");
335015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted",
335115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
335215516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_trusted),
335315516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU",
335415516c77SSepherosa Ziehau 	    "# of packets that we trust host's csum verification");
335515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts",
335615516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
335715516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_small_pkts),
335815516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of small packets received");
335915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed",
336015516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
336115516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_ack_failed),
336215516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures");
336315516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt",
336415516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings");
336515516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse",
336615516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings");
336715516c77SSepherosa Ziehau 
336815516c77SSepherosa Ziehau 	return (0);
336915516c77SSepherosa Ziehau }
337015516c77SSepherosa Ziehau 
337115516c77SSepherosa Ziehau static void
337215516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc)
337315516c77SSepherosa Ziehau {
337415516c77SSepherosa Ziehau 	int i;
337515516c77SSepherosa Ziehau 
337615516c77SSepherosa Ziehau 	if (sc->hn_rxbuf != NULL) {
33772494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0)
337815516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf);
33792494d735SSepherosa Ziehau 		else
33802494d735SSepherosa Ziehau 			device_printf(sc->hn_dev, "RXBUF is referenced\n");
338115516c77SSepherosa Ziehau 		sc->hn_rxbuf = NULL;
338215516c77SSepherosa Ziehau 	}
338315516c77SSepherosa Ziehau 
338415516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_cnt == 0)
338515516c77SSepherosa Ziehau 		return;
338615516c77SSepherosa Ziehau 
338715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
338815516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
338915516c77SSepherosa Ziehau 
339015516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL)
339115516c77SSepherosa Ziehau 			continue;
33922494d735SSepherosa Ziehau 		if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) {
339315516c77SSepherosa Ziehau 			hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br);
33942494d735SSepherosa Ziehau 		} else {
33952494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
33962494d735SSepherosa Ziehau 			    "%dth channel bufring is referenced", i);
33972494d735SSepherosa Ziehau 		}
339815516c77SSepherosa Ziehau 		rxr->hn_br = NULL;
339915516c77SSepherosa Ziehau 
340015516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
340115516c77SSepherosa Ziehau 		tcp_lro_free(&rxr->hn_lro);
340215516c77SSepherosa Ziehau #endif
340315516c77SSepherosa Ziehau 		free(rxr->hn_pktbuf, M_DEVBUF);
340415516c77SSepherosa Ziehau 	}
340515516c77SSepherosa Ziehau 	free(sc->hn_rx_ring, M_DEVBUF);
340615516c77SSepherosa Ziehau 	sc->hn_rx_ring = NULL;
340715516c77SSepherosa Ziehau 
340815516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = 0;
340915516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = 0;
341015516c77SSepherosa Ziehau }
341115516c77SSepherosa Ziehau 
341215516c77SSepherosa Ziehau static int
341315516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id)
341415516c77SSepherosa Ziehau {
341515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[id];
341615516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
341715516c77SSepherosa Ziehau 	bus_dma_tag_t parent_dtag;
341815516c77SSepherosa Ziehau 	int error, i;
341915516c77SSepherosa Ziehau 
342015516c77SSepherosa Ziehau 	txr->hn_sc = sc;
342115516c77SSepherosa Ziehau 	txr->hn_tx_idx = id;
342215516c77SSepherosa Ziehau 
342315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
342415516c77SSepherosa Ziehau 	mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN);
342515516c77SSepherosa Ziehau #endif
342615516c77SSepherosa Ziehau 	mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF);
342715516c77SSepherosa Ziehau 
342815516c77SSepherosa Ziehau 	txr->hn_txdesc_cnt = HN_TX_DESC_CNT;
342915516c77SSepherosa Ziehau 	txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt,
343015516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
343115516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
343215516c77SSepherosa Ziehau 	SLIST_INIT(&txr->hn_txlist);
343315516c77SSepherosa Ziehau #else
343415516c77SSepherosa Ziehau 	txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF,
343515516c77SSepherosa Ziehau 	    M_WAITOK, &txr->hn_tx_lock);
343615516c77SSepherosa Ziehau #endif
343715516c77SSepherosa Ziehau 
34380e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_EVTTQ) {
34390e11868dSSepherosa Ziehau 		txr->hn_tx_taskq = VMBUS_GET_EVENT_TASKQ(
34400e11868dSSepherosa Ziehau 		    device_get_parent(dev), dev, HN_RING_IDX2CPU(sc, id));
34410e11868dSSepherosa Ziehau 	} else {
3442fdd0222aSSepherosa Ziehau 		txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt];
34430e11868dSSepherosa Ziehau 	}
344415516c77SSepherosa Ziehau 
344523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
344615516c77SSepherosa Ziehau 	if (hn_use_if_start) {
344715516c77SSepherosa Ziehau 		txr->hn_txeof = hn_start_txeof;
344815516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr);
344915516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr);
345023bf9e15SSepherosa Ziehau 	} else
345123bf9e15SSepherosa Ziehau #endif
345223bf9e15SSepherosa Ziehau 	{
345315516c77SSepherosa Ziehau 		int br_depth;
345415516c77SSepherosa Ziehau 
345515516c77SSepherosa Ziehau 		txr->hn_txeof = hn_xmit_txeof;
345615516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr);
345715516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr);
345815516c77SSepherosa Ziehau 
345915516c77SSepherosa Ziehau 		br_depth = hn_get_txswq_depth(txr);
346015516c77SSepherosa Ziehau 		txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF,
346115516c77SSepherosa Ziehau 		    M_WAITOK, &txr->hn_tx_lock);
346215516c77SSepherosa Ziehau 	}
346315516c77SSepherosa Ziehau 
346415516c77SSepherosa Ziehau 	txr->hn_direct_tx_size = hn_direct_tx_size;
346515516c77SSepherosa Ziehau 
346615516c77SSepherosa Ziehau 	/*
346715516c77SSepherosa Ziehau 	 * Always schedule transmission instead of trying to do direct
346815516c77SSepherosa Ziehau 	 * transmission.  This one gives the best performance so far.
346915516c77SSepherosa Ziehau 	 */
347015516c77SSepherosa Ziehau 	txr->hn_sched_tx = 1;
347115516c77SSepherosa Ziehau 
347215516c77SSepherosa Ziehau 	parent_dtag = bus_get_dma_tag(dev);
347315516c77SSepherosa Ziehau 
347415516c77SSepherosa Ziehau 	/* DMA tag for RNDIS packet messages. */
347515516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
347615516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_ALIGN,		/* alignment */
347715516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_BOUNDARY,	/* boundary */
347815516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
347915516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
348015516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
348115516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsize */
348215516c77SSepherosa Ziehau 	    1,				/* nsegments */
348315516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsegsize */
348415516c77SSepherosa Ziehau 	    0,				/* flags */
348515516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
348615516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
348715516c77SSepherosa Ziehau 	    &txr->hn_tx_rndis_dtag);
348815516c77SSepherosa Ziehau 	if (error) {
348915516c77SSepherosa Ziehau 		device_printf(dev, "failed to create rndis dmatag\n");
349015516c77SSepherosa Ziehau 		return error;
349115516c77SSepherosa Ziehau 	}
349215516c77SSepherosa Ziehau 
349315516c77SSepherosa Ziehau 	/* DMA tag for data. */
349415516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
349515516c77SSepherosa Ziehau 	    1,				/* alignment */
349615516c77SSepherosa Ziehau 	    HN_TX_DATA_BOUNDARY,	/* boundary */
349715516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
349815516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
349915516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
350015516c77SSepherosa Ziehau 	    HN_TX_DATA_MAXSIZE,		/* maxsize */
350115516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGCNT_MAX,	/* nsegments */
350215516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGSIZE,		/* maxsegsize */
350315516c77SSepherosa Ziehau 	    0,				/* flags */
350415516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
350515516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
350615516c77SSepherosa Ziehau 	    &txr->hn_tx_data_dtag);
350715516c77SSepherosa Ziehau 	if (error) {
350815516c77SSepherosa Ziehau 		device_printf(dev, "failed to create data dmatag\n");
350915516c77SSepherosa Ziehau 		return error;
351015516c77SSepherosa Ziehau 	}
351115516c77SSepherosa Ziehau 
351215516c77SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i) {
351315516c77SSepherosa Ziehau 		struct hn_txdesc *txd = &txr->hn_txdesc[i];
351415516c77SSepherosa Ziehau 
351515516c77SSepherosa Ziehau 		txd->txr = txr;
351615516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
3517dc13fee6SSepherosa Ziehau 		STAILQ_INIT(&txd->agg_list);
351815516c77SSepherosa Ziehau 
351915516c77SSepherosa Ziehau 		/*
352015516c77SSepherosa Ziehau 		 * Allocate and load RNDIS packet message.
352115516c77SSepherosa Ziehau 		 */
352215516c77SSepherosa Ziehau         	error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag,
352315516c77SSepherosa Ziehau 		    (void **)&txd->rndis_pkt,
352415516c77SSepherosa Ziehau 		    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
352515516c77SSepherosa Ziehau 		    &txd->rndis_pkt_dmap);
352615516c77SSepherosa Ziehau 		if (error) {
352715516c77SSepherosa Ziehau 			device_printf(dev,
352815516c77SSepherosa Ziehau 			    "failed to allocate rndis_packet_msg, %d\n", i);
352915516c77SSepherosa Ziehau 			return error;
353015516c77SSepherosa Ziehau 		}
353115516c77SSepherosa Ziehau 
353215516c77SSepherosa Ziehau 		error = bus_dmamap_load(txr->hn_tx_rndis_dtag,
353315516c77SSepherosa Ziehau 		    txd->rndis_pkt_dmap,
353415516c77SSepherosa Ziehau 		    txd->rndis_pkt, HN_RNDIS_PKT_LEN,
353515516c77SSepherosa Ziehau 		    hyperv_dma_map_paddr, &txd->rndis_pkt_paddr,
353615516c77SSepherosa Ziehau 		    BUS_DMA_NOWAIT);
353715516c77SSepherosa Ziehau 		if (error) {
353815516c77SSepherosa Ziehau 			device_printf(dev,
353915516c77SSepherosa Ziehau 			    "failed to load rndis_packet_msg, %d\n", i);
354015516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
354115516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
354215516c77SSepherosa Ziehau 			return error;
354315516c77SSepherosa Ziehau 		}
354415516c77SSepherosa Ziehau 
354515516c77SSepherosa Ziehau 		/* DMA map for TX data. */
354615516c77SSepherosa Ziehau 		error = bus_dmamap_create(txr->hn_tx_data_dtag, 0,
354715516c77SSepherosa Ziehau 		    &txd->data_dmap);
354815516c77SSepherosa Ziehau 		if (error) {
354915516c77SSepherosa Ziehau 			device_printf(dev,
355015516c77SSepherosa Ziehau 			    "failed to allocate tx data dmamap\n");
355115516c77SSepherosa Ziehau 			bus_dmamap_unload(txr->hn_tx_rndis_dtag,
355215516c77SSepherosa Ziehau 			    txd->rndis_pkt_dmap);
355315516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
355415516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
355515516c77SSepherosa Ziehau 			return error;
355615516c77SSepherosa Ziehau 		}
355715516c77SSepherosa Ziehau 
355815516c77SSepherosa Ziehau 		/* All set, put it to list */
355915516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_ONLIST;
356015516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
356115516c77SSepherosa Ziehau 		SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
356215516c77SSepherosa Ziehau #else
356315516c77SSepherosa Ziehau 		buf_ring_enqueue(txr->hn_txdesc_br, txd);
356415516c77SSepherosa Ziehau #endif
356515516c77SSepherosa Ziehau 	}
356615516c77SSepherosa Ziehau 	txr->hn_txdesc_avail = txr->hn_txdesc_cnt;
356715516c77SSepherosa Ziehau 
356815516c77SSepherosa Ziehau 	if (sc->hn_tx_sysctl_tree != NULL) {
356915516c77SSepherosa Ziehau 		struct sysctl_oid_list *child;
357015516c77SSepherosa Ziehau 		struct sysctl_ctx_list *ctx;
357115516c77SSepherosa Ziehau 		char name[16];
357215516c77SSepherosa Ziehau 
357315516c77SSepherosa Ziehau 		/*
357415516c77SSepherosa Ziehau 		 * Create per TX ring sysctl tree:
357515516c77SSepherosa Ziehau 		 * dev.hn.UNIT.tx.RINGID
357615516c77SSepherosa Ziehau 		 */
357715516c77SSepherosa Ziehau 		ctx = device_get_sysctl_ctx(dev);
357815516c77SSepherosa Ziehau 		child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree);
357915516c77SSepherosa Ziehau 
358015516c77SSepherosa Ziehau 		snprintf(name, sizeof(name), "%d", id);
358115516c77SSepherosa Ziehau 		txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
358215516c77SSepherosa Ziehau 		    name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
358315516c77SSepherosa Ziehau 
358415516c77SSepherosa Ziehau 		if (txr->hn_tx_sysctl_tree != NULL) {
358515516c77SSepherosa Ziehau 			child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree);
358615516c77SSepherosa Ziehau 
358785e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
358815516c77SSepherosa Ziehau 			SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail",
358915516c77SSepherosa Ziehau 			    CTLFLAG_RD, &txr->hn_txdesc_avail, 0,
359015516c77SSepherosa Ziehau 			    "# of available TX descs");
359185e4ae1eSSepherosa Ziehau #endif
359223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
359323bf9e15SSepherosa Ziehau 			if (!hn_use_if_start)
359423bf9e15SSepherosa Ziehau #endif
359523bf9e15SSepherosa Ziehau 			{
359615516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive",
359715516c77SSepherosa Ziehau 				    CTLFLAG_RD, &txr->hn_oactive, 0,
359815516c77SSepherosa Ziehau 				    "over active");
359915516c77SSepherosa Ziehau 			}
360015516c77SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets",
360115516c77SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_pkts,
360215516c77SSepherosa Ziehau 			    "# of packets transmitted");
3603dc13fee6SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends",
3604dc13fee6SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_sends, "# of sends");
360515516c77SSepherosa Ziehau 		}
360615516c77SSepherosa Ziehau 	}
360715516c77SSepherosa Ziehau 
360815516c77SSepherosa Ziehau 	return 0;
360915516c77SSepherosa Ziehau }
361015516c77SSepherosa Ziehau 
361115516c77SSepherosa Ziehau static void
361215516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd)
361315516c77SSepherosa Ziehau {
361415516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = txd->txr;
361515516c77SSepherosa Ziehau 
361615516c77SSepherosa Ziehau 	KASSERT(txd->m == NULL, ("still has mbuf installed"));
361715516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped"));
361815516c77SSepherosa Ziehau 
361915516c77SSepherosa Ziehau 	bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap);
362015516c77SSepherosa Ziehau 	bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt,
362115516c77SSepherosa Ziehau 	    txd->rndis_pkt_dmap);
362215516c77SSepherosa Ziehau 	bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap);
362315516c77SSepherosa Ziehau }
362415516c77SSepherosa Ziehau 
362515516c77SSepherosa Ziehau static void
362625641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd)
362725641fc7SSepherosa Ziehau {
362825641fc7SSepherosa Ziehau 
362925641fc7SSepherosa Ziehau 	KASSERT(txd->refs == 0 || txd->refs == 1,
363025641fc7SSepherosa Ziehau 	    ("invalid txd refs %d", txd->refs));
363125641fc7SSepherosa Ziehau 
363225641fc7SSepherosa Ziehau 	/* Aggregated txds will be freed by their aggregating txd. */
363325641fc7SSepherosa Ziehau 	if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) {
363425641fc7SSepherosa Ziehau 		int freed;
363525641fc7SSepherosa Ziehau 
363625641fc7SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
363725641fc7SSepherosa Ziehau 		KASSERT(freed, ("can't free txdesc"));
363825641fc7SSepherosa Ziehau 	}
363925641fc7SSepherosa Ziehau }
364025641fc7SSepherosa Ziehau 
364125641fc7SSepherosa Ziehau static void
364215516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr)
364315516c77SSepherosa Ziehau {
364425641fc7SSepherosa Ziehau 	int i;
364515516c77SSepherosa Ziehau 
364615516c77SSepherosa Ziehau 	if (txr->hn_txdesc == NULL)
364715516c77SSepherosa Ziehau 		return;
364815516c77SSepherosa Ziehau 
364925641fc7SSepherosa Ziehau 	/*
365025641fc7SSepherosa Ziehau 	 * NOTE:
365125641fc7SSepherosa Ziehau 	 * Because the freeing of aggregated txds will be deferred
365225641fc7SSepherosa Ziehau 	 * to the aggregating txd, two passes are used here:
365325641fc7SSepherosa Ziehau 	 * - The first pass GCes any pending txds.  This GC is necessary,
365425641fc7SSepherosa Ziehau 	 *   since if the channels are revoked, hypervisor will not
365525641fc7SSepherosa Ziehau 	 *   deliver send-done for all pending txds.
365625641fc7SSepherosa Ziehau 	 * - The second pass frees the busdma stuffs, i.e. after all txds
365725641fc7SSepherosa Ziehau 	 *   were freed.
365825641fc7SSepherosa Ziehau 	 */
365925641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
366025641fc7SSepherosa Ziehau 		hn_txdesc_gc(txr, &txr->hn_txdesc[i]);
366125641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
366225641fc7SSepherosa Ziehau 		hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]);
366315516c77SSepherosa Ziehau 
366415516c77SSepherosa Ziehau 	if (txr->hn_tx_data_dtag != NULL)
366515516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_data_dtag);
366615516c77SSepherosa Ziehau 	if (txr->hn_tx_rndis_dtag != NULL)
366715516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_rndis_dtag);
366815516c77SSepherosa Ziehau 
366915516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
367015516c77SSepherosa Ziehau 	buf_ring_free(txr->hn_txdesc_br, M_DEVBUF);
367115516c77SSepherosa Ziehau #endif
367215516c77SSepherosa Ziehau 
367315516c77SSepherosa Ziehau 	free(txr->hn_txdesc, M_DEVBUF);
367415516c77SSepherosa Ziehau 	txr->hn_txdesc = NULL;
367515516c77SSepherosa Ziehau 
367615516c77SSepherosa Ziehau 	if (txr->hn_mbuf_br != NULL)
367715516c77SSepherosa Ziehau 		buf_ring_free(txr->hn_mbuf_br, M_DEVBUF);
367815516c77SSepherosa Ziehau 
367915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
368015516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_txlist_spin);
368115516c77SSepherosa Ziehau #endif
368215516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_tx_lock);
368315516c77SSepherosa Ziehau }
368415516c77SSepherosa Ziehau 
368515516c77SSepherosa Ziehau static int
368615516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt)
368715516c77SSepherosa Ziehau {
368815516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
368915516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
369015516c77SSepherosa Ziehau 	int i;
369115516c77SSepherosa Ziehau 
369215516c77SSepherosa Ziehau 	/*
369315516c77SSepherosa Ziehau 	 * Create TXBUF for chimney sending.
369415516c77SSepherosa Ziehau 	 *
369515516c77SSepherosa Ziehau 	 * NOTE: It is shared by all channels.
369615516c77SSepherosa Ziehau 	 */
369715516c77SSepherosa Ziehau 	sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev),
369815516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma,
369915516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
370015516c77SSepherosa Ziehau 	if (sc->hn_chim == NULL) {
370115516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate txbuf failed\n");
370215516c77SSepherosa Ziehau 		return (ENOMEM);
370315516c77SSepherosa Ziehau 	}
370415516c77SSepherosa Ziehau 
370515516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = ring_cnt;
370615516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
370715516c77SSepherosa Ziehau 
370815516c77SSepherosa Ziehau 	sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt,
370915516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
371015516c77SSepherosa Ziehau 
371115516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(sc->hn_dev);
371215516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev));
371315516c77SSepherosa Ziehau 
371415516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.tx sysctl tree */
371515516c77SSepherosa Ziehau 	sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx",
371615516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
371715516c77SSepherosa Ziehau 
371815516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
371915516c77SSepherosa Ziehau 		int error;
372015516c77SSepherosa Ziehau 
372115516c77SSepherosa Ziehau 		error = hn_tx_ring_create(sc, i);
372215516c77SSepherosa Ziehau 		if (error)
372315516c77SSepherosa Ziehau 			return error;
372415516c77SSepherosa Ziehau 	}
372515516c77SSepherosa Ziehau 
372615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs",
372715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
372815516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_no_txdescs),
372915516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs");
373015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed",
373115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
373215516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_send_failed),
373315516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure");
373415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed",
373515516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
373615516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_txdma_failed),
373715516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure");
3738dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed",
3739dc13fee6SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
3740dc13fee6SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_flush_failed),
3741dc13fee6SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU",
3742dc13fee6SSepherosa Ziehau 	    "# of packet transmission aggregation flush failure");
374315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed",
374415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
374515516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_collapsed),
374615516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed");
374715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney",
374815516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
374915516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney),
375015516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send");
375115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried",
375215516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
375315516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney_tried),
375415516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries");
375515516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt",
375615516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0,
375715516c77SSepherosa Ziehau 	    "# of total TX descs");
375815516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max",
375915516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_chim_szmax, 0,
376015516c77SSepherosa Ziehau 	    "Chimney send packet size upper boundary");
376115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size",
376215516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
376315516c77SSepherosa Ziehau 	    hn_chim_size_sysctl, "I", "Chimney send packet size limit");
376415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size",
376515516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
376615516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_direct_tx_size),
376715516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
376815516c77SSepherosa Ziehau 	    "Size of the packet for direct transmission");
376915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx",
377015516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
377115516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_sched_tx),
377215516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
377315516c77SSepherosa Ziehau 	    "Always schedule transmission "
377415516c77SSepherosa Ziehau 	    "instead of doing direct transmission");
377515516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt",
377615516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings");
377715516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse",
377815516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings");
3779dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax",
3780dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0,
3781dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation size");
3782dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax",
3783dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
3784dc13fee6SSepherosa Ziehau 	    hn_txagg_pktmax_sysctl, "I",
3785dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation packets");
3786dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align",
3787dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
3788dc13fee6SSepherosa Ziehau 	    hn_txagg_align_sysctl, "I",
3789dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation alignment");
379015516c77SSepherosa Ziehau 
379115516c77SSepherosa Ziehau 	return 0;
379215516c77SSepherosa Ziehau }
379315516c77SSepherosa Ziehau 
379415516c77SSepherosa Ziehau static void
379515516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size)
379615516c77SSepherosa Ziehau {
379715516c77SSepherosa Ziehau 	int i;
379815516c77SSepherosa Ziehau 
3799a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
380015516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_chim_size = chim_size;
380115516c77SSepherosa Ziehau }
380215516c77SSepherosa Ziehau 
380315516c77SSepherosa Ziehau static void
380415516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu)
380515516c77SSepherosa Ziehau {
380615516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
380715516c77SSepherosa Ziehau 	int tso_minlen;
380815516c77SSepherosa Ziehau 
380915516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0)
381015516c77SSepherosa Ziehau 		return;
381115516c77SSepherosa Ziehau 
381215516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_sgmin >= 2,
381315516c77SSepherosa Ziehau 	    ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin));
381415516c77SSepherosa Ziehau 	tso_minlen = sc->hn_ndis_tso_sgmin * mtu;
381515516c77SSepherosa Ziehau 
381615516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen &&
381715516c77SSepherosa Ziehau 	    sc->hn_ndis_tso_szmax <= IP_MAXPACKET,
381815516c77SSepherosa Ziehau 	    ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax));
381915516c77SSepherosa Ziehau 
382015516c77SSepherosa Ziehau 	if (tso_maxlen < tso_minlen)
382115516c77SSepherosa Ziehau 		tso_maxlen = tso_minlen;
382215516c77SSepherosa Ziehau 	else if (tso_maxlen > IP_MAXPACKET)
382315516c77SSepherosa Ziehau 		tso_maxlen = IP_MAXPACKET;
382415516c77SSepherosa Ziehau 	if (tso_maxlen > sc->hn_ndis_tso_szmax)
382515516c77SSepherosa Ziehau 		tso_maxlen = sc->hn_ndis_tso_szmax;
382615516c77SSepherosa Ziehau 	ifp->if_hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
382715516c77SSepherosa Ziehau 	if (bootverbose)
382815516c77SSepherosa Ziehau 		if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax);
382915516c77SSepherosa Ziehau }
383015516c77SSepherosa Ziehau 
383115516c77SSepherosa Ziehau static void
383215516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc)
383315516c77SSepherosa Ziehau {
383415516c77SSepherosa Ziehau 	uint64_t csum_assist;
383515516c77SSepherosa Ziehau 	int i;
383615516c77SSepherosa Ziehau 
383715516c77SSepherosa Ziehau 	hn_set_chim_size(sc, sc->hn_chim_szmax);
383815516c77SSepherosa Ziehau 	if (hn_tx_chimney_size > 0 &&
383915516c77SSepherosa Ziehau 	    hn_tx_chimney_size < sc->hn_chim_szmax)
384015516c77SSepherosa Ziehau 		hn_set_chim_size(sc, hn_tx_chimney_size);
384115516c77SSepherosa Ziehau 
384215516c77SSepherosa Ziehau 	csum_assist = 0;
384315516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_IPCS)
384415516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP;
384515516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP4CS)
384615516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_TCP;
384715516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP4CS)
384815516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_UDP;
384915516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP6CS)
385015516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_TCP;
385115516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP6CS)
385215516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_UDP;
385315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
385415516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_csum_assist = csum_assist;
385515516c77SSepherosa Ziehau 
385615516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_HASHVAL) {
385715516c77SSepherosa Ziehau 		/*
385815516c77SSepherosa Ziehau 		 * Support HASHVAL pktinfo on TX path.
385915516c77SSepherosa Ziehau 		 */
386015516c77SSepherosa Ziehau 		if (bootverbose)
386115516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n");
386215516c77SSepherosa Ziehau 		for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
386315516c77SSepherosa Ziehau 			sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL;
386415516c77SSepherosa Ziehau 	}
386515516c77SSepherosa Ziehau }
386615516c77SSepherosa Ziehau 
386715516c77SSepherosa Ziehau static void
386815516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc)
386915516c77SSepherosa Ziehau {
387015516c77SSepherosa Ziehau 	int i;
387115516c77SSepherosa Ziehau 
387215516c77SSepherosa Ziehau 	if (sc->hn_chim != NULL) {
38732494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) {
387415516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim);
38752494d735SSepherosa Ziehau 		} else {
38762494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
38772494d735SSepherosa Ziehau 			    "chimney sending buffer is referenced");
38782494d735SSepherosa Ziehau 		}
387915516c77SSepherosa Ziehau 		sc->hn_chim = NULL;
388015516c77SSepherosa Ziehau 	}
388115516c77SSepherosa Ziehau 
388215516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt == 0)
388315516c77SSepherosa Ziehau 		return;
388415516c77SSepherosa Ziehau 
388515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
388615516c77SSepherosa Ziehau 		hn_tx_ring_destroy(&sc->hn_tx_ring[i]);
388715516c77SSepherosa Ziehau 
388815516c77SSepherosa Ziehau 	free(sc->hn_tx_ring, M_DEVBUF);
388915516c77SSepherosa Ziehau 	sc->hn_tx_ring = NULL;
389015516c77SSepherosa Ziehau 
389115516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = 0;
389215516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = 0;
389315516c77SSepherosa Ziehau }
389415516c77SSepherosa Ziehau 
389523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
389623bf9e15SSepherosa Ziehau 
389715516c77SSepherosa Ziehau static void
389815516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused)
389915516c77SSepherosa Ziehau {
390015516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
390115516c77SSepherosa Ziehau 
390215516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
390315516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
390415516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
390515516c77SSepherosa Ziehau }
390615516c77SSepherosa Ziehau 
390723bf9e15SSepherosa Ziehau static int
390823bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len)
390923bf9e15SSepherosa Ziehau {
391023bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
391123bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
3912dc13fee6SSepherosa Ziehau 	int sched = 0;
391323bf9e15SSepherosa Ziehau 
391423bf9e15SSepherosa Ziehau 	KASSERT(hn_use_if_start,
391523bf9e15SSepherosa Ziehau 	    ("hn_start_locked is called, when if_start is disabled"));
391623bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
391723bf9e15SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
3918dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
391923bf9e15SSepherosa Ziehau 
392023bf9e15SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
3921dc13fee6SSepherosa Ziehau 		return (0);
392223bf9e15SSepherosa Ziehau 
392323bf9e15SSepherosa Ziehau 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
392423bf9e15SSepherosa Ziehau 	    IFF_DRV_RUNNING)
3925dc13fee6SSepherosa Ziehau 		return (0);
392623bf9e15SSepherosa Ziehau 
392723bf9e15SSepherosa Ziehau 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
392823bf9e15SSepherosa Ziehau 		struct hn_txdesc *txd;
392923bf9e15SSepherosa Ziehau 		struct mbuf *m_head;
393023bf9e15SSepherosa Ziehau 		int error;
393123bf9e15SSepherosa Ziehau 
393223bf9e15SSepherosa Ziehau 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
393323bf9e15SSepherosa Ziehau 		if (m_head == NULL)
393423bf9e15SSepherosa Ziehau 			break;
393523bf9e15SSepherosa Ziehau 
393623bf9e15SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
393723bf9e15SSepherosa Ziehau 			/*
393823bf9e15SSepherosa Ziehau 			 * This sending could be time consuming; let callers
393923bf9e15SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
394023bf9e15SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
394123bf9e15SSepherosa Ziehau 			 */
394223bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
3943dc13fee6SSepherosa Ziehau 			sched = 1;
3944dc13fee6SSepherosa Ziehau 			break;
394523bf9e15SSepherosa Ziehau 		}
394623bf9e15SSepherosa Ziehau 
3947edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
3948edd3f315SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
3949edd3f315SSepherosa Ziehau 			m_head = hn_tso_fixup(m_head);
3950edd3f315SSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
3951edd3f315SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
3952edd3f315SSepherosa Ziehau 				continue;
3953edd3f315SSepherosa Ziehau 			}
3954edd3f315SSepherosa Ziehau 		}
3955edd3f315SSepherosa Ziehau #endif
3956edd3f315SSepherosa Ziehau 
395723bf9e15SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
395823bf9e15SSepherosa Ziehau 		if (txd == NULL) {
395923bf9e15SSepherosa Ziehau 			txr->hn_no_txdescs++;
396023bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
396123bf9e15SSepherosa Ziehau 			atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
396223bf9e15SSepherosa Ziehau 			break;
396323bf9e15SSepherosa Ziehau 		}
396423bf9e15SSepherosa Ziehau 
3965dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
396623bf9e15SSepherosa Ziehau 		if (error) {
396723bf9e15SSepherosa Ziehau 			/* Both txd and m_head are freed */
3968dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
3969dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
397023bf9e15SSepherosa Ziehau 			continue;
397123bf9e15SSepherosa Ziehau 		}
397223bf9e15SSepherosa Ziehau 
3973dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
3974dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
3975dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
3976dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
3977dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
3978dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
3979dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
3980dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
3981dc13fee6SSepherosa Ziehau 					break;
3982dc13fee6SSepherosa Ziehau 				}
3983dc13fee6SSepherosa Ziehau 			} else {
3984dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
398523bf9e15SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
398623bf9e15SSepherosa Ziehau 				if (__predict_false(error)) {
398723bf9e15SSepherosa Ziehau 					/* txd is freed, but m_head is not */
398823bf9e15SSepherosa Ziehau 					IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
3989dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
3990dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
399123bf9e15SSepherosa Ziehau 					break;
399223bf9e15SSepherosa Ziehau 				}
399323bf9e15SSepherosa Ziehau 			}
3994dc13fee6SSepherosa Ziehau 		}
3995dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
3996dc13fee6SSepherosa Ziehau 		else {
3997dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
3998dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
3999dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
4000dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
4001dc13fee6SSepherosa Ziehau 		}
4002dc13fee6SSepherosa Ziehau #endif
4003dc13fee6SSepherosa Ziehau 	}
4004dc13fee6SSepherosa Ziehau 
4005dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
4006dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
4007dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
4008dc13fee6SSepherosa Ziehau 	return (sched);
400923bf9e15SSepherosa Ziehau }
401023bf9e15SSepherosa Ziehau 
401123bf9e15SSepherosa Ziehau static void
401223bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp)
401323bf9e15SSepherosa Ziehau {
401423bf9e15SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
401523bf9e15SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[0];
401623bf9e15SSepherosa Ziehau 
401723bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
401823bf9e15SSepherosa Ziehau 		goto do_sched;
401923bf9e15SSepherosa Ziehau 
402023bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
402123bf9e15SSepherosa Ziehau 		int sched;
402223bf9e15SSepherosa Ziehau 
402323bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
402423bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
402523bf9e15SSepherosa Ziehau 		if (!sched)
402623bf9e15SSepherosa Ziehau 			return;
402723bf9e15SSepherosa Ziehau 	}
402823bf9e15SSepherosa Ziehau do_sched:
402923bf9e15SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
403023bf9e15SSepherosa Ziehau }
403123bf9e15SSepherosa Ziehau 
403215516c77SSepherosa Ziehau static void
403315516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused)
403415516c77SSepherosa Ziehau {
403515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
403615516c77SSepherosa Ziehau 
403715516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
403815516c77SSepherosa Ziehau 	atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE);
403915516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
404015516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
404115516c77SSepherosa Ziehau }
404215516c77SSepherosa Ziehau 
404323bf9e15SSepherosa Ziehau static void
404423bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr)
404523bf9e15SSepherosa Ziehau {
404623bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
404723bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
404823bf9e15SSepherosa Ziehau 
404923bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
405023bf9e15SSepherosa Ziehau 
405123bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
405223bf9e15SSepherosa Ziehau 		goto do_sched;
405323bf9e15SSepherosa Ziehau 
405423bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
405523bf9e15SSepherosa Ziehau 		int sched;
405623bf9e15SSepherosa Ziehau 
405723bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
405823bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
405923bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
406023bf9e15SSepherosa Ziehau 		if (sched) {
406123bf9e15SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
406223bf9e15SSepherosa Ziehau 			    &txr->hn_tx_task);
406323bf9e15SSepherosa Ziehau 		}
406423bf9e15SSepherosa Ziehau 	} else {
406523bf9e15SSepherosa Ziehau do_sched:
406623bf9e15SSepherosa Ziehau 		/*
406723bf9e15SSepherosa Ziehau 		 * Release the OACTIVE earlier, with the hope, that
406823bf9e15SSepherosa Ziehau 		 * others could catch up.  The task will clear the
406923bf9e15SSepherosa Ziehau 		 * flag again with the hn_tx_lock to avoid possible
407023bf9e15SSepherosa Ziehau 		 * races.
407123bf9e15SSepherosa Ziehau 		 */
407223bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
407323bf9e15SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
407423bf9e15SSepherosa Ziehau 	}
407523bf9e15SSepherosa Ziehau }
407623bf9e15SSepherosa Ziehau 
407723bf9e15SSepherosa Ziehau #endif	/* HN_IFSTART_SUPPORT */
407823bf9e15SSepherosa Ziehau 
407915516c77SSepherosa Ziehau static int
408015516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len)
408115516c77SSepherosa Ziehau {
408215516c77SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
408315516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
408415516c77SSepherosa Ziehau 	struct mbuf *m_head;
4085dc13fee6SSepherosa Ziehau 	int sched = 0;
408615516c77SSepherosa Ziehau 
408715516c77SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
408823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
408915516c77SSepherosa Ziehau 	KASSERT(hn_use_if_start == 0,
409015516c77SSepherosa Ziehau 	    ("hn_xmit is called, when if_start is enabled"));
409123bf9e15SSepherosa Ziehau #endif
4092dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
409315516c77SSepherosa Ziehau 
409415516c77SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
4095dc13fee6SSepherosa Ziehau 		return (0);
409615516c77SSepherosa Ziehau 
409715516c77SSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive)
4098dc13fee6SSepherosa Ziehau 		return (0);
409915516c77SSepherosa Ziehau 
410015516c77SSepherosa Ziehau 	while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) {
410115516c77SSepherosa Ziehau 		struct hn_txdesc *txd;
410215516c77SSepherosa Ziehau 		int error;
410315516c77SSepherosa Ziehau 
410415516c77SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
410515516c77SSepherosa Ziehau 			/*
410615516c77SSepherosa Ziehau 			 * This sending could be time consuming; let callers
410715516c77SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
410815516c77SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
410915516c77SSepherosa Ziehau 			 */
411015516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
4111dc13fee6SSepherosa Ziehau 			sched = 1;
4112dc13fee6SSepherosa Ziehau 			break;
411315516c77SSepherosa Ziehau 		}
411415516c77SSepherosa Ziehau 
411515516c77SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
411615516c77SSepherosa Ziehau 		if (txd == NULL) {
411715516c77SSepherosa Ziehau 			txr->hn_no_txdescs++;
411815516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
411915516c77SSepherosa Ziehau 			txr->hn_oactive = 1;
412015516c77SSepherosa Ziehau 			break;
412115516c77SSepherosa Ziehau 		}
412215516c77SSepherosa Ziehau 
4123dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
412415516c77SSepherosa Ziehau 		if (error) {
412515516c77SSepherosa Ziehau 			/* Both txd and m_head are freed; discard */
4126dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
4127dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
412815516c77SSepherosa Ziehau 			drbr_advance(ifp, txr->hn_mbuf_br);
412915516c77SSepherosa Ziehau 			continue;
413015516c77SSepherosa Ziehau 		}
413115516c77SSepherosa Ziehau 
4132dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
4133dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
4134dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
4135dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
4136dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
413715516c77SSepherosa Ziehau 				if (__predict_false(error)) {
413815516c77SSepherosa Ziehau 					txr->hn_oactive = 1;
413915516c77SSepherosa Ziehau 					break;
414015516c77SSepherosa Ziehau 				}
4141dc13fee6SSepherosa Ziehau 			} else {
4142dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
4143dc13fee6SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
4144dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
4145dc13fee6SSepherosa Ziehau 					/* txd is freed, but m_head is not */
4146dc13fee6SSepherosa Ziehau 					drbr_putback(ifp, txr->hn_mbuf_br,
4147dc13fee6SSepherosa Ziehau 					    m_head);
4148dc13fee6SSepherosa Ziehau 					txr->hn_oactive = 1;
4149dc13fee6SSepherosa Ziehau 					break;
4150dc13fee6SSepherosa Ziehau 				}
4151dc13fee6SSepherosa Ziehau 			}
4152dc13fee6SSepherosa Ziehau 		}
4153dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
4154dc13fee6SSepherosa Ziehau 		else {
4155dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
4156dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
4157dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
4158dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
4159dc13fee6SSepherosa Ziehau 		}
4160dc13fee6SSepherosa Ziehau #endif
416115516c77SSepherosa Ziehau 
416215516c77SSepherosa Ziehau 		/* Sent */
416315516c77SSepherosa Ziehau 		drbr_advance(ifp, txr->hn_mbuf_br);
416415516c77SSepherosa Ziehau 	}
4165dc13fee6SSepherosa Ziehau 
4166dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
4167dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
4168dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
4169dc13fee6SSepherosa Ziehau 	return (sched);
417015516c77SSepherosa Ziehau }
417115516c77SSepherosa Ziehau 
417215516c77SSepherosa Ziehau static int
417315516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m)
417415516c77SSepherosa Ziehau {
417515516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
417615516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
417715516c77SSepherosa Ziehau 	int error, idx = 0;
417815516c77SSepherosa Ziehau 
4179edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
4180edd3f315SSepherosa Ziehau 	/*
4181edd3f315SSepherosa Ziehau 	 * Perform TSO packet header fixup now, since the TSO
4182edd3f315SSepherosa Ziehau 	 * packet header should be cache-hot.
4183edd3f315SSepherosa Ziehau 	 */
4184edd3f315SSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
4185edd3f315SSepherosa Ziehau 		m = hn_tso_fixup(m);
4186edd3f315SSepherosa Ziehau 		if (__predict_false(m == NULL)) {
4187edd3f315SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
4188edd3f315SSepherosa Ziehau 			return EIO;
4189edd3f315SSepherosa Ziehau 		}
4190edd3f315SSepherosa Ziehau 	}
4191edd3f315SSepherosa Ziehau #endif
4192edd3f315SSepherosa Ziehau 
419315516c77SSepherosa Ziehau 	/*
419415516c77SSepherosa Ziehau 	 * Select the TX ring based on flowid
419515516c77SSepherosa Ziehau 	 */
419634d68912SSepherosa Ziehau 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
419734d68912SSepherosa Ziehau #ifdef RSS
419834d68912SSepherosa Ziehau 		uint32_t bid;
419934d68912SSepherosa Ziehau 
420034d68912SSepherosa Ziehau 		if (rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m),
420134d68912SSepherosa Ziehau 		    &bid) == 0)
420234d68912SSepherosa Ziehau 			idx = bid % sc->hn_tx_ring_inuse;
420334d68912SSepherosa Ziehau 		else
420434d68912SSepherosa Ziehau #endif
420515516c77SSepherosa Ziehau 			idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse;
420634d68912SSepherosa Ziehau 	}
420715516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[idx];
420815516c77SSepherosa Ziehau 
420915516c77SSepherosa Ziehau 	error = drbr_enqueue(ifp, txr->hn_mbuf_br, m);
421015516c77SSepherosa Ziehau 	if (error) {
421115516c77SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
421215516c77SSepherosa Ziehau 		return error;
421315516c77SSepherosa Ziehau 	}
421415516c77SSepherosa Ziehau 
421515516c77SSepherosa Ziehau 	if (txr->hn_oactive)
421615516c77SSepherosa Ziehau 		return 0;
421715516c77SSepherosa Ziehau 
421815516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
421915516c77SSepherosa Ziehau 		goto do_sched;
422015516c77SSepherosa Ziehau 
422115516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
422215516c77SSepherosa Ziehau 		int sched;
422315516c77SSepherosa Ziehau 
422415516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
422515516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
422615516c77SSepherosa Ziehau 		if (!sched)
422715516c77SSepherosa Ziehau 			return 0;
422815516c77SSepherosa Ziehau 	}
422915516c77SSepherosa Ziehau do_sched:
423015516c77SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
423115516c77SSepherosa Ziehau 	return 0;
423215516c77SSepherosa Ziehau }
423315516c77SSepherosa Ziehau 
423415516c77SSepherosa Ziehau static void
423515516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr)
423615516c77SSepherosa Ziehau {
423715516c77SSepherosa Ziehau 	struct mbuf *m;
423815516c77SSepherosa Ziehau 
423915516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
424015516c77SSepherosa Ziehau 	while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL)
424115516c77SSepherosa Ziehau 		m_freem(m);
424215516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
424315516c77SSepherosa Ziehau }
424415516c77SSepherosa Ziehau 
424515516c77SSepherosa Ziehau static void
424615516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp)
424715516c77SSepherosa Ziehau {
424815516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
424915516c77SSepherosa Ziehau 	int i;
425015516c77SSepherosa Ziehau 
425115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
425215516c77SSepherosa Ziehau 		hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
425315516c77SSepherosa Ziehau 	if_qflush(ifp);
425415516c77SSepherosa Ziehau }
425515516c77SSepherosa Ziehau 
425615516c77SSepherosa Ziehau static void
425715516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr)
425815516c77SSepherosa Ziehau {
425915516c77SSepherosa Ziehau 
426015516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
426115516c77SSepherosa Ziehau 		goto do_sched;
426215516c77SSepherosa Ziehau 
426315516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
426415516c77SSepherosa Ziehau 		int sched;
426515516c77SSepherosa Ziehau 
426615516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
426715516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
426815516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
426915516c77SSepherosa Ziehau 		if (sched) {
427015516c77SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
427115516c77SSepherosa Ziehau 			    &txr->hn_tx_task);
427215516c77SSepherosa Ziehau 		}
427315516c77SSepherosa Ziehau 	} else {
427415516c77SSepherosa Ziehau do_sched:
427515516c77SSepherosa Ziehau 		/*
427615516c77SSepherosa Ziehau 		 * Release the oactive earlier, with the hope, that
427715516c77SSepherosa Ziehau 		 * others could catch up.  The task will clear the
427815516c77SSepherosa Ziehau 		 * oactive again with the hn_tx_lock to avoid possible
427915516c77SSepherosa Ziehau 		 * races.
428015516c77SSepherosa Ziehau 		 */
428115516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
428215516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
428315516c77SSepherosa Ziehau 	}
428415516c77SSepherosa Ziehau }
428515516c77SSepherosa Ziehau 
428615516c77SSepherosa Ziehau static void
428715516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused)
428815516c77SSepherosa Ziehau {
428915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
429015516c77SSepherosa Ziehau 
429115516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
429215516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
429315516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
429415516c77SSepherosa Ziehau }
429515516c77SSepherosa Ziehau 
429615516c77SSepherosa Ziehau static void
429715516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused)
429815516c77SSepherosa Ziehau {
429915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
430015516c77SSepherosa Ziehau 
430115516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
430215516c77SSepherosa Ziehau 	txr->hn_oactive = 0;
430315516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
430415516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
430515516c77SSepherosa Ziehau }
430615516c77SSepherosa Ziehau 
430715516c77SSepherosa Ziehau static int
430815516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan)
430915516c77SSepherosa Ziehau {
431015516c77SSepherosa Ziehau 	struct vmbus_chan_br cbr;
431115516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
431215516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = NULL;
431315516c77SSepherosa Ziehau 	int idx, error;
431415516c77SSepherosa Ziehau 
431515516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
431615516c77SSepherosa Ziehau 
431715516c77SSepherosa Ziehau 	/*
431815516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
431915516c77SSepherosa Ziehau 	 */
432015516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
432115516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
432215516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
432315516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
432415516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0,
432515516c77SSepherosa Ziehau 	    ("RX ring %d already attached", idx));
432615516c77SSepherosa Ziehau 	rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED;
432715516c77SSepherosa Ziehau 
432815516c77SSepherosa Ziehau 	if (bootverbose) {
432915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n",
433015516c77SSepherosa Ziehau 		    idx, vmbus_chan_id(chan));
433115516c77SSepherosa Ziehau 	}
433215516c77SSepherosa Ziehau 
433315516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
433415516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[idx];
433515516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0,
433615516c77SSepherosa Ziehau 		    ("TX ring %d already attached", idx));
433715516c77SSepherosa Ziehau 		txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED;
433815516c77SSepherosa Ziehau 
433915516c77SSepherosa Ziehau 		txr->hn_chan = chan;
434015516c77SSepherosa Ziehau 		if (bootverbose) {
434115516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n",
434215516c77SSepherosa Ziehau 			    idx, vmbus_chan_id(chan));
434315516c77SSepherosa Ziehau 		}
434415516c77SSepherosa Ziehau 	}
434515516c77SSepherosa Ziehau 
434615516c77SSepherosa Ziehau 	/* Bind this channel to a proper CPU. */
43470e11868dSSepherosa Ziehau 	vmbus_chan_cpu_set(chan, HN_RING_IDX2CPU(sc, idx));
434815516c77SSepherosa Ziehau 
434915516c77SSepherosa Ziehau 	/*
435015516c77SSepherosa Ziehau 	 * Open this channel
435115516c77SSepherosa Ziehau 	 */
435215516c77SSepherosa Ziehau 	cbr.cbr = rxr->hn_br;
435315516c77SSepherosa Ziehau 	cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr;
435415516c77SSepherosa Ziehau 	cbr.cbr_txsz = HN_TXBR_SIZE;
435515516c77SSepherosa Ziehau 	cbr.cbr_rxsz = HN_RXBR_SIZE;
435615516c77SSepherosa Ziehau 	error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr);
435715516c77SSepherosa Ziehau 	if (error) {
435871e8ac56SSepherosa Ziehau 		if (error == EISCONN) {
435971e8ac56SSepherosa Ziehau 			if_printf(sc->hn_ifp, "bufring is connected after "
436071e8ac56SSepherosa Ziehau 			    "chan%u open failure\n", vmbus_chan_id(chan));
436171e8ac56SSepherosa Ziehau 			rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
436271e8ac56SSepherosa Ziehau 		} else {
436315516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "open chan%u failed: %d\n",
436415516c77SSepherosa Ziehau 			    vmbus_chan_id(chan), error);
436571e8ac56SSepherosa Ziehau 		}
436615516c77SSepherosa Ziehau 	}
436715516c77SSepherosa Ziehau 	return (error);
436815516c77SSepherosa Ziehau }
436915516c77SSepherosa Ziehau 
437015516c77SSepherosa Ziehau static void
437115516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan)
437215516c77SSepherosa Ziehau {
437315516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
43742494d735SSepherosa Ziehau 	int idx, error;
437515516c77SSepherosa Ziehau 
437615516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
437715516c77SSepherosa Ziehau 
437815516c77SSepherosa Ziehau 	/*
437915516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
438015516c77SSepherosa Ziehau 	 */
438115516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
438215516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
438315516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
438415516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
438515516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED),
438615516c77SSepherosa Ziehau 	    ("RX ring %d is not attached", idx));
438715516c77SSepherosa Ziehau 	rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
438815516c77SSepherosa Ziehau 
438915516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
439015516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[idx];
439115516c77SSepherosa Ziehau 
439215516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED),
439315516c77SSepherosa Ziehau 		    ("TX ring %d is not attached attached", idx));
439415516c77SSepherosa Ziehau 		txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
439515516c77SSepherosa Ziehau 	}
439615516c77SSepherosa Ziehau 
439715516c77SSepherosa Ziehau 	/*
439815516c77SSepherosa Ziehau 	 * Close this channel.
439915516c77SSepherosa Ziehau 	 *
440015516c77SSepherosa Ziehau 	 * NOTE:
440115516c77SSepherosa Ziehau 	 * Channel closing does _not_ destroy the target channel.
440215516c77SSepherosa Ziehau 	 */
44032494d735SSepherosa Ziehau 	error = vmbus_chan_close_direct(chan);
44042494d735SSepherosa Ziehau 	if (error == EISCONN) {
4405aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u bufring is connected "
4406aa1a2adcSSepherosa Ziehau 		    "after being closed\n", vmbus_chan_id(chan));
44072494d735SSepherosa Ziehau 		rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
44082494d735SSepherosa Ziehau 	} else if (error) {
4409aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u close failed: %d\n",
4410aa1a2adcSSepherosa Ziehau 		    vmbus_chan_id(chan), error);
44112494d735SSepherosa Ziehau 	}
441215516c77SSepherosa Ziehau }
441315516c77SSepherosa Ziehau 
441415516c77SSepherosa Ziehau static int
441515516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc)
441615516c77SSepherosa Ziehau {
441715516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
441815516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
441915516c77SSepherosa Ziehau 	int i, error = 0;
442015516c77SSepherosa Ziehau 
442171e8ac56SSepherosa Ziehau 	KASSERT(subchan_cnt > 0, ("no sub-channels"));
442215516c77SSepherosa Ziehau 
442315516c77SSepherosa Ziehau 	/* Attach the sub-channels. */
442415516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
442515516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i) {
442671e8ac56SSepherosa Ziehau 		int error1;
442771e8ac56SSepherosa Ziehau 
442871e8ac56SSepherosa Ziehau 		error1 = hn_chan_attach(sc, subchans[i]);
442971e8ac56SSepherosa Ziehau 		if (error1) {
443071e8ac56SSepherosa Ziehau 			error = error1;
443171e8ac56SSepherosa Ziehau 			/* Move on; all channels will be detached later. */
443271e8ac56SSepherosa Ziehau 		}
443315516c77SSepherosa Ziehau 	}
443415516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
443515516c77SSepherosa Ziehau 
443615516c77SSepherosa Ziehau 	if (error) {
443715516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error);
443815516c77SSepherosa Ziehau 	} else {
443915516c77SSepherosa Ziehau 		if (bootverbose) {
444015516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "%d sub-channels attached\n",
444115516c77SSepherosa Ziehau 			    subchan_cnt);
444215516c77SSepherosa Ziehau 		}
444315516c77SSepherosa Ziehau 	}
444415516c77SSepherosa Ziehau 	return (error);
444515516c77SSepherosa Ziehau }
444615516c77SSepherosa Ziehau 
444715516c77SSepherosa Ziehau static void
444815516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc)
444915516c77SSepherosa Ziehau {
445015516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
445115516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
445215516c77SSepherosa Ziehau 	int i;
445315516c77SSepherosa Ziehau 
445415516c77SSepherosa Ziehau 	if (subchan_cnt == 0)
445515516c77SSepherosa Ziehau 		goto back;
445615516c77SSepherosa Ziehau 
445715516c77SSepherosa Ziehau 	/* Detach the sub-channels. */
445815516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
445915516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i)
446015516c77SSepherosa Ziehau 		hn_chan_detach(sc, subchans[i]);
446115516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
446215516c77SSepherosa Ziehau 
446315516c77SSepherosa Ziehau back:
446415516c77SSepherosa Ziehau 	/*
446515516c77SSepherosa Ziehau 	 * Detach the primary channel, _after_ all sub-channels
446615516c77SSepherosa Ziehau 	 * are detached.
446715516c77SSepherosa Ziehau 	 */
446815516c77SSepherosa Ziehau 	hn_chan_detach(sc, sc->hn_prichan);
446915516c77SSepherosa Ziehau 
447015516c77SSepherosa Ziehau 	/* Wait for sub-channels to be destroyed, if any. */
447115516c77SSepherosa Ziehau 	vmbus_subchan_drain(sc->hn_prichan);
447215516c77SSepherosa Ziehau 
447315516c77SSepherosa Ziehau #ifdef INVARIANTS
447415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
447515516c77SSepherosa Ziehau 		KASSERT((sc->hn_rx_ring[i].hn_rx_flags &
447615516c77SSepherosa Ziehau 		    HN_RX_FLAG_ATTACHED) == 0,
447715516c77SSepherosa Ziehau 		    ("%dth RX ring is still attached", i));
447815516c77SSepherosa Ziehau 	}
447915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
448015516c77SSepherosa Ziehau 		KASSERT((sc->hn_tx_ring[i].hn_tx_flags &
448115516c77SSepherosa Ziehau 		    HN_TX_FLAG_ATTACHED) == 0,
448215516c77SSepherosa Ziehau 		    ("%dth TX ring is still attached", i));
448315516c77SSepherosa Ziehau 	}
448415516c77SSepherosa Ziehau #endif
448515516c77SSepherosa Ziehau }
448615516c77SSepherosa Ziehau 
448715516c77SSepherosa Ziehau static int
448815516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch)
448915516c77SSepherosa Ziehau {
449015516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
449115516c77SSepherosa Ziehau 	int nchan, rxr_cnt, error;
449215516c77SSepherosa Ziehau 
449315516c77SSepherosa Ziehau 	nchan = *nsubch + 1;
449415516c77SSepherosa Ziehau 	if (nchan == 1) {
449515516c77SSepherosa Ziehau 		/*
449615516c77SSepherosa Ziehau 		 * Multiple RX/TX rings are not requested.
449715516c77SSepherosa Ziehau 		 */
449815516c77SSepherosa Ziehau 		*nsubch = 0;
449915516c77SSepherosa Ziehau 		return (0);
450015516c77SSepherosa Ziehau 	}
450115516c77SSepherosa Ziehau 
450215516c77SSepherosa Ziehau 	/*
450315516c77SSepherosa Ziehau 	 * Query RSS capabilities, e.g. # of RX rings, and # of indirect
450415516c77SSepherosa Ziehau 	 * table entries.
450515516c77SSepherosa Ziehau 	 */
450615516c77SSepherosa Ziehau 	error = hn_rndis_query_rsscaps(sc, &rxr_cnt);
450715516c77SSepherosa Ziehau 	if (error) {
450815516c77SSepherosa Ziehau 		/* No RSS; this is benign. */
450915516c77SSepherosa Ziehau 		*nsubch = 0;
451015516c77SSepherosa Ziehau 		return (0);
451115516c77SSepherosa Ziehau 	}
451215516c77SSepherosa Ziehau 	if (bootverbose) {
451315516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
451415516c77SSepherosa Ziehau 		    rxr_cnt, nchan);
451515516c77SSepherosa Ziehau 	}
451615516c77SSepherosa Ziehau 
451715516c77SSepherosa Ziehau 	if (nchan > rxr_cnt)
451815516c77SSepherosa Ziehau 		nchan = rxr_cnt;
451915516c77SSepherosa Ziehau 	if (nchan == 1) {
452015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n");
452115516c77SSepherosa Ziehau 		*nsubch = 0;
452215516c77SSepherosa Ziehau 		return (0);
452315516c77SSepherosa Ziehau 	}
452415516c77SSepherosa Ziehau 
452515516c77SSepherosa Ziehau 	/*
452615516c77SSepherosa Ziehau 	 * Allocate sub-channels from NVS.
452715516c77SSepherosa Ziehau 	 */
452815516c77SSepherosa Ziehau 	*nsubch = nchan - 1;
452915516c77SSepherosa Ziehau 	error = hn_nvs_alloc_subchans(sc, nsubch);
453015516c77SSepherosa Ziehau 	if (error || *nsubch == 0) {
453115516c77SSepherosa Ziehau 		/* Failed to allocate sub-channels. */
453215516c77SSepherosa Ziehau 		*nsubch = 0;
453315516c77SSepherosa Ziehau 		return (0);
453415516c77SSepherosa Ziehau 	}
453515516c77SSepherosa Ziehau 
453615516c77SSepherosa Ziehau 	/*
453715516c77SSepherosa Ziehau 	 * Wait for all sub-channels to become ready before moving on.
453815516c77SSepherosa Ziehau 	 */
453915516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch);
454015516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, *nsubch);
454115516c77SSepherosa Ziehau 	return (0);
454215516c77SSepherosa Ziehau }
454315516c77SSepherosa Ziehau 
45442494d735SSepherosa Ziehau static bool
45452494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc)
45462494d735SSepherosa Ziehau {
45472494d735SSepherosa Ziehau 	int i;
45482494d735SSepherosa Ziehau 
45492494d735SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_ERRORS)
45502494d735SSepherosa Ziehau 		return (false);
45512494d735SSepherosa Ziehau 
45522494d735SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
45532494d735SSepherosa Ziehau 		const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
45542494d735SSepherosa Ziehau 
45552494d735SSepherosa Ziehau 		if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF)
45562494d735SSepherosa Ziehau 			return (false);
45572494d735SSepherosa Ziehau 	}
45582494d735SSepherosa Ziehau 	return (true);
45592494d735SSepherosa Ziehau }
45602494d735SSepherosa Ziehau 
456115516c77SSepherosa Ziehau static int
456215516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu)
456315516c77SSepherosa Ziehau {
456471e8ac56SSepherosa Ziehau #define ATTACHED_NVS		0x0002
456571e8ac56SSepherosa Ziehau #define ATTACHED_RNDIS		0x0004
456671e8ac56SSepherosa Ziehau 
456715516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
456815516c77SSepherosa Ziehau 	int error, nsubch, nchan, i;
456971e8ac56SSepherosa Ziehau 	uint32_t old_caps, attached = 0;
457015516c77SSepherosa Ziehau 
457115516c77SSepherosa Ziehau 	KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0,
457215516c77SSepherosa Ziehau 	    ("synthetic parts were attached"));
457315516c77SSepherosa Ziehau 
45742494d735SSepherosa Ziehau 	if (!hn_synth_attachable(sc))
45752494d735SSepherosa Ziehau 		return (ENXIO);
45762494d735SSepherosa Ziehau 
457715516c77SSepherosa Ziehau 	/* Save capabilities for later verification. */
457815516c77SSepherosa Ziehau 	old_caps = sc->hn_caps;
457915516c77SSepherosa Ziehau 	sc->hn_caps = 0;
458015516c77SSepherosa Ziehau 
458115516c77SSepherosa Ziehau 	/* Clear RSS stuffs. */
458215516c77SSepherosa Ziehau 	sc->hn_rss_ind_size = 0;
458315516c77SSepherosa Ziehau 	sc->hn_rss_hash = 0;
458415516c77SSepherosa Ziehau 
458515516c77SSepherosa Ziehau 	/*
458615516c77SSepherosa Ziehau 	 * Attach the primary channel _before_ attaching NVS and RNDIS.
458715516c77SSepherosa Ziehau 	 */
458815516c77SSepherosa Ziehau 	error = hn_chan_attach(sc, sc->hn_prichan);
458915516c77SSepherosa Ziehau 	if (error)
459071e8ac56SSepherosa Ziehau 		goto failed;
459115516c77SSepherosa Ziehau 
459215516c77SSepherosa Ziehau 	/*
459315516c77SSepherosa Ziehau 	 * Attach NVS.
459415516c77SSepherosa Ziehau 	 */
459515516c77SSepherosa Ziehau 	error = hn_nvs_attach(sc, mtu);
459615516c77SSepherosa Ziehau 	if (error)
459771e8ac56SSepherosa Ziehau 		goto failed;
459871e8ac56SSepherosa Ziehau 	attached |= ATTACHED_NVS;
459915516c77SSepherosa Ziehau 
460015516c77SSepherosa Ziehau 	/*
460115516c77SSepherosa Ziehau 	 * Attach RNDIS _after_ NVS is attached.
460215516c77SSepherosa Ziehau 	 */
460315516c77SSepherosa Ziehau 	error = hn_rndis_attach(sc, mtu);
460415516c77SSepherosa Ziehau 	if (error)
460571e8ac56SSepherosa Ziehau 		goto failed;
460671e8ac56SSepherosa Ziehau 	attached |= ATTACHED_RNDIS;
460715516c77SSepherosa Ziehau 
460815516c77SSepherosa Ziehau 	/*
460915516c77SSepherosa Ziehau 	 * Make sure capabilities are not changed.
461015516c77SSepherosa Ziehau 	 */
461115516c77SSepherosa Ziehau 	if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) {
461215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n",
461315516c77SSepherosa Ziehau 		    old_caps, sc->hn_caps);
461471e8ac56SSepherosa Ziehau 		error = ENXIO;
461571e8ac56SSepherosa Ziehau 		goto failed;
461615516c77SSepherosa Ziehau 	}
461715516c77SSepherosa Ziehau 
461815516c77SSepherosa Ziehau 	/*
461915516c77SSepherosa Ziehau 	 * Allocate sub-channels for multi-TX/RX rings.
462015516c77SSepherosa Ziehau 	 *
462115516c77SSepherosa Ziehau 	 * NOTE:
462215516c77SSepherosa Ziehau 	 * The # of RX rings that can be used is equivalent to the # of
462315516c77SSepherosa Ziehau 	 * channels to be requested.
462415516c77SSepherosa Ziehau 	 */
462515516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_cnt - 1;
462615516c77SSepherosa Ziehau 	error = hn_synth_alloc_subchans(sc, &nsubch);
462715516c77SSepherosa Ziehau 	if (error)
462871e8ac56SSepherosa Ziehau 		goto failed;
462971e8ac56SSepherosa Ziehau 	/* NOTE: _Full_ synthetic parts detach is required now. */
463071e8ac56SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED;
463115516c77SSepherosa Ziehau 
463271e8ac56SSepherosa Ziehau 	/*
463371e8ac56SSepherosa Ziehau 	 * Set the # of TX/RX rings that could be used according to
463471e8ac56SSepherosa Ziehau 	 * the # of channels that NVS offered.
463571e8ac56SSepherosa Ziehau 	 */
463615516c77SSepherosa Ziehau 	nchan = nsubch + 1;
463771e8ac56SSepherosa Ziehau 	hn_set_ring_inuse(sc, nchan);
463815516c77SSepherosa Ziehau 	if (nchan == 1) {
463915516c77SSepherosa Ziehau 		/* Only the primary channel can be used; done */
464015516c77SSepherosa Ziehau 		goto back;
464115516c77SSepherosa Ziehau 	}
464215516c77SSepherosa Ziehau 
464315516c77SSepherosa Ziehau 	/*
464471e8ac56SSepherosa Ziehau 	 * Attach the sub-channels.
4645afd4971bSSepherosa Ziehau 	 *
4646afd4971bSSepherosa Ziehau 	 * NOTE: hn_set_ring_inuse() _must_ have been called.
464715516c77SSepherosa Ziehau 	 */
464871e8ac56SSepherosa Ziehau 	error = hn_attach_subchans(sc);
464971e8ac56SSepherosa Ziehau 	if (error)
465071e8ac56SSepherosa Ziehau 		goto failed;
465115516c77SSepherosa Ziehau 
465271e8ac56SSepherosa Ziehau 	/*
465371e8ac56SSepherosa Ziehau 	 * Configure RSS key and indirect table _after_ all sub-channels
465471e8ac56SSepherosa Ziehau 	 * are attached.
465571e8ac56SSepherosa Ziehau 	 */
465615516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) {
465715516c77SSepherosa Ziehau 		/*
465815516c77SSepherosa Ziehau 		 * RSS key is not set yet; set it to the default RSS key.
465915516c77SSepherosa Ziehau 		 */
466015516c77SSepherosa Ziehau 		if (bootverbose)
466115516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS key\n");
466234d68912SSepherosa Ziehau #ifdef RSS
466334d68912SSepherosa Ziehau 		rss_getkey(rss->rss_key);
466434d68912SSepherosa Ziehau #else
466515516c77SSepherosa Ziehau 		memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key));
466634d68912SSepherosa Ziehau #endif
466715516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
466815516c77SSepherosa Ziehau 	}
466915516c77SSepherosa Ziehau 
467015516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) {
467115516c77SSepherosa Ziehau 		/*
467215516c77SSepherosa Ziehau 		 * RSS indirect table is not set yet; set it up in round-
467315516c77SSepherosa Ziehau 		 * robin fashion.
467415516c77SSepherosa Ziehau 		 */
467515516c77SSepherosa Ziehau 		if (bootverbose) {
467615516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS indirect "
467715516c77SSepherosa Ziehau 			    "table\n");
467815516c77SSepherosa Ziehau 		}
467934d68912SSepherosa Ziehau 		for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
468034d68912SSepherosa Ziehau 			uint32_t subidx;
468134d68912SSepherosa Ziehau 
468234d68912SSepherosa Ziehau #ifdef RSS
468334d68912SSepherosa Ziehau 			subidx = rss_get_indirection_to_bucket(i);
468434d68912SSepherosa Ziehau #else
468534d68912SSepherosa Ziehau 			subidx = i;
468634d68912SSepherosa Ziehau #endif
468734d68912SSepherosa Ziehau 			rss->rss_ind[i] = subidx % nchan;
468834d68912SSepherosa Ziehau 		}
468915516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSIND;
469015516c77SSepherosa Ziehau 	} else {
469115516c77SSepherosa Ziehau 		/*
469215516c77SSepherosa Ziehau 		 * # of usable channels may be changed, so we have to
469315516c77SSepherosa Ziehau 		 * make sure that all entries in RSS indirect table
469415516c77SSepherosa Ziehau 		 * are valid.
4695afd4971bSSepherosa Ziehau 		 *
4696afd4971bSSepherosa Ziehau 		 * NOTE: hn_set_ring_inuse() _must_ have been called.
469715516c77SSepherosa Ziehau 		 */
4698afd4971bSSepherosa Ziehau 		hn_rss_ind_fixup(sc);
469915516c77SSepherosa Ziehau 	}
470015516c77SSepherosa Ziehau 
470115516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
470215516c77SSepherosa Ziehau 	if (error)
470371e8ac56SSepherosa Ziehau 		goto failed;
470471e8ac56SSepherosa Ziehau back:
4705dc13fee6SSepherosa Ziehau 	/*
4706dc13fee6SSepherosa Ziehau 	 * Fixup transmission aggregation setup.
4707dc13fee6SSepherosa Ziehau 	 */
4708dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
470915516c77SSepherosa Ziehau 	return (0);
471071e8ac56SSepherosa Ziehau 
471171e8ac56SSepherosa Ziehau failed:
471271e8ac56SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
471371e8ac56SSepherosa Ziehau 		hn_synth_detach(sc);
471471e8ac56SSepherosa Ziehau 	} else {
471571e8ac56SSepherosa Ziehau 		if (attached & ATTACHED_RNDIS)
471671e8ac56SSepherosa Ziehau 			hn_rndis_detach(sc);
471771e8ac56SSepherosa Ziehau 		if (attached & ATTACHED_NVS)
471871e8ac56SSepherosa Ziehau 			hn_nvs_detach(sc);
471971e8ac56SSepherosa Ziehau 		hn_chan_detach(sc, sc->hn_prichan);
472071e8ac56SSepherosa Ziehau 		/* Restore old capabilities. */
472171e8ac56SSepherosa Ziehau 		sc->hn_caps = old_caps;
472271e8ac56SSepherosa Ziehau 	}
472371e8ac56SSepherosa Ziehau 	return (error);
472471e8ac56SSepherosa Ziehau 
472571e8ac56SSepherosa Ziehau #undef ATTACHED_RNDIS
472671e8ac56SSepherosa Ziehau #undef ATTACHED_NVS
472715516c77SSepherosa Ziehau }
472815516c77SSepherosa Ziehau 
472915516c77SSepherosa Ziehau /*
473015516c77SSepherosa Ziehau  * NOTE:
473115516c77SSepherosa Ziehau  * The interface must have been suspended though hn_suspend(), before
473215516c77SSepherosa Ziehau  * this function get called.
473315516c77SSepherosa Ziehau  */
473415516c77SSepherosa Ziehau static void
473515516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc)
473615516c77SSepherosa Ziehau {
473715516c77SSepherosa Ziehau 
473815516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
473915516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
474015516c77SSepherosa Ziehau 
474115516c77SSepherosa Ziehau 	/* Detach the RNDIS first. */
474215516c77SSepherosa Ziehau 	hn_rndis_detach(sc);
474315516c77SSepherosa Ziehau 
474415516c77SSepherosa Ziehau 	/* Detach NVS. */
474515516c77SSepherosa Ziehau 	hn_nvs_detach(sc);
474615516c77SSepherosa Ziehau 
474715516c77SSepherosa Ziehau 	/* Detach all of the channels. */
474815516c77SSepherosa Ziehau 	hn_detach_allchans(sc);
474915516c77SSepherosa Ziehau 
475015516c77SSepherosa Ziehau 	sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED;
475115516c77SSepherosa Ziehau }
475215516c77SSepherosa Ziehau 
475315516c77SSepherosa Ziehau static void
475415516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt)
475515516c77SSepherosa Ziehau {
475615516c77SSepherosa Ziehau 	KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt,
475715516c77SSepherosa Ziehau 	    ("invalid ring count %d", ring_cnt));
475815516c77SSepherosa Ziehau 
475915516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt > ring_cnt)
476015516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = ring_cnt;
476115516c77SSepherosa Ziehau 	else
476215516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
476315516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = ring_cnt;
476415516c77SSepherosa Ziehau 
476534d68912SSepherosa Ziehau #ifdef RSS
476634d68912SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse != rss_getnumbuckets()) {
476734d68912SSepherosa Ziehau 		if_printf(sc->hn_ifp, "# of RX rings (%d) does not match "
476834d68912SSepherosa Ziehau 		    "# of RSS buckets (%d)\n", sc->hn_rx_ring_inuse,
476934d68912SSepherosa Ziehau 		    rss_getnumbuckets());
477034d68912SSepherosa Ziehau 	}
477134d68912SSepherosa Ziehau #endif
477234d68912SSepherosa Ziehau 
477315516c77SSepherosa Ziehau 	if (bootverbose) {
477415516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n",
477515516c77SSepherosa Ziehau 		    sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
477615516c77SSepherosa Ziehau 	}
477715516c77SSepherosa Ziehau }
477815516c77SSepherosa Ziehau 
477915516c77SSepherosa Ziehau static void
478025641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan)
478115516c77SSepherosa Ziehau {
478215516c77SSepherosa Ziehau 
478325641fc7SSepherosa Ziehau 	/*
478425641fc7SSepherosa Ziehau 	 * NOTE:
478525641fc7SSepherosa Ziehau 	 * The TX bufring will not be drained by the hypervisor,
478625641fc7SSepherosa Ziehau 	 * if the primary channel is revoked.
478725641fc7SSepherosa Ziehau 	 */
478825641fc7SSepherosa Ziehau 	while (!vmbus_chan_rx_empty(chan) ||
478925641fc7SSepherosa Ziehau 	    (!vmbus_chan_is_revoked(sc->hn_prichan) &&
479025641fc7SSepherosa Ziehau 	     !vmbus_chan_tx_empty(chan)))
479115516c77SSepherosa Ziehau 		pause("waitch", 1);
479215516c77SSepherosa Ziehau 	vmbus_chan_intr_drain(chan);
479315516c77SSepherosa Ziehau }
479415516c77SSepherosa Ziehau 
479515516c77SSepherosa Ziehau static void
479615516c77SSepherosa Ziehau hn_suspend_data(struct hn_softc *sc)
479715516c77SSepherosa Ziehau {
479815516c77SSepherosa Ziehau 	struct vmbus_channel **subch = NULL;
479925641fc7SSepherosa Ziehau 	struct hn_tx_ring *txr;
480015516c77SSepherosa Ziehau 	int i, nsubch;
480115516c77SSepherosa Ziehau 
480215516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
480315516c77SSepherosa Ziehau 
480415516c77SSepherosa Ziehau 	/*
480515516c77SSepherosa Ziehau 	 * Suspend TX.
480615516c77SSepherosa Ziehau 	 */
480715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
480825641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
480915516c77SSepherosa Ziehau 
481015516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
481115516c77SSepherosa Ziehau 		txr->hn_suspended = 1;
481215516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
481315516c77SSepherosa Ziehau 		/* No one is able send more packets now. */
481415516c77SSepherosa Ziehau 
481525641fc7SSepherosa Ziehau 		/*
481625641fc7SSepherosa Ziehau 		 * Wait for all pending sends to finish.
481725641fc7SSepherosa Ziehau 		 *
481825641fc7SSepherosa Ziehau 		 * NOTE:
481925641fc7SSepherosa Ziehau 		 * We will _not_ receive all pending send-done, if the
482025641fc7SSepherosa Ziehau 		 * primary channel is revoked.
482125641fc7SSepherosa Ziehau 		 */
482225641fc7SSepherosa Ziehau 		while (hn_tx_ring_pending(txr) &&
482325641fc7SSepherosa Ziehau 		    !vmbus_chan_is_revoked(sc->hn_prichan))
482415516c77SSepherosa Ziehau 			pause("hnwtx", 1 /* 1 tick */);
482515516c77SSepherosa Ziehau 	}
482615516c77SSepherosa Ziehau 
482715516c77SSepherosa Ziehau 	/*
482815516c77SSepherosa Ziehau 	 * Disable RX by clearing RX filter.
482915516c77SSepherosa Ziehau 	 */
483015516c77SSepherosa Ziehau 	sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE;
483115516c77SSepherosa Ziehau 	hn_rndis_set_rxfilter(sc, sc->hn_rx_filter);
483215516c77SSepherosa Ziehau 
483315516c77SSepherosa Ziehau 	/*
483415516c77SSepherosa Ziehau 	 * Give RNDIS enough time to flush all pending data packets.
483515516c77SSepherosa Ziehau 	 */
483615516c77SSepherosa Ziehau 	pause("waitrx", (200 * hz) / 1000);
483715516c77SSepherosa Ziehau 
483815516c77SSepherosa Ziehau 	/*
483915516c77SSepherosa Ziehau 	 * Drain RX/TX bufrings and interrupts.
484015516c77SSepherosa Ziehau 	 */
484115516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_inuse - 1;
484215516c77SSepherosa Ziehau 	if (nsubch > 0)
484315516c77SSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
484415516c77SSepherosa Ziehau 
484515516c77SSepherosa Ziehau 	if (subch != NULL) {
484615516c77SSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
484725641fc7SSepherosa Ziehau 			hn_chan_drain(sc, subch[i]);
484815516c77SSepherosa Ziehau 	}
484925641fc7SSepherosa Ziehau 	hn_chan_drain(sc, sc->hn_prichan);
485015516c77SSepherosa Ziehau 
485115516c77SSepherosa Ziehau 	if (subch != NULL)
485215516c77SSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
485325641fc7SSepherosa Ziehau 
485425641fc7SSepherosa Ziehau 	/*
485525641fc7SSepherosa Ziehau 	 * Drain any pending TX tasks.
485625641fc7SSepherosa Ziehau 	 *
485725641fc7SSepherosa Ziehau 	 * NOTE:
485825641fc7SSepherosa Ziehau 	 * The above hn_chan_drain() can dispatch TX tasks, so the TX
485925641fc7SSepherosa Ziehau 	 * tasks will have to be drained _after_ the above hn_chan_drain()
486025641fc7SSepherosa Ziehau 	 * calls.
486125641fc7SSepherosa Ziehau 	 */
486225641fc7SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
486325641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
486425641fc7SSepherosa Ziehau 
486525641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task);
486625641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task);
486725641fc7SSepherosa Ziehau 	}
486815516c77SSepherosa Ziehau }
486915516c77SSepherosa Ziehau 
487015516c77SSepherosa Ziehau static void
487115516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused)
487215516c77SSepherosa Ziehau {
487315516c77SSepherosa Ziehau 
487415516c77SSepherosa Ziehau 	((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL;
487515516c77SSepherosa Ziehau }
487615516c77SSepherosa Ziehau 
487715516c77SSepherosa Ziehau static void
487815516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc)
487915516c77SSepherosa Ziehau {
488015516c77SSepherosa Ziehau 	struct task task;
488115516c77SSepherosa Ziehau 
488215516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
488315516c77SSepherosa Ziehau 
488415516c77SSepherosa Ziehau 	/*
488515516c77SSepherosa Ziehau 	 * Make sure that hn_mgmt_taskq0 can nolonger be accessed
488615516c77SSepherosa Ziehau 	 * through hn_mgmt_taskq.
488715516c77SSepherosa Ziehau 	 */
488815516c77SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc);
488915516c77SSepherosa Ziehau 	vmbus_chan_run_task(sc->hn_prichan, &task);
489015516c77SSepherosa Ziehau 
489115516c77SSepherosa Ziehau 	/*
489215516c77SSepherosa Ziehau 	 * Make sure that all pending management tasks are completed.
489315516c77SSepherosa Ziehau 	 */
489415516c77SSepherosa Ziehau 	taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init);
489515516c77SSepherosa Ziehau 	taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status);
489615516c77SSepherosa Ziehau 	taskqueue_drain_all(sc->hn_mgmt_taskq0);
489715516c77SSepherosa Ziehau }
489815516c77SSepherosa Ziehau 
489915516c77SSepherosa Ziehau static void
490015516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc)
490115516c77SSepherosa Ziehau {
490215516c77SSepherosa Ziehau 
490315516c77SSepherosa Ziehau 	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
490415516c77SSepherosa Ziehau 		hn_suspend_data(sc);
490515516c77SSepherosa Ziehau 	hn_suspend_mgmt(sc);
490615516c77SSepherosa Ziehau }
490715516c77SSepherosa Ziehau 
490815516c77SSepherosa Ziehau static void
490915516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt)
491015516c77SSepherosa Ziehau {
491115516c77SSepherosa Ziehau 	int i;
491215516c77SSepherosa Ziehau 
491315516c77SSepherosa Ziehau 	KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt,
491415516c77SSepherosa Ziehau 	    ("invalid TX ring count %d", tx_ring_cnt));
491515516c77SSepherosa Ziehau 
491615516c77SSepherosa Ziehau 	for (i = 0; i < tx_ring_cnt; ++i) {
491715516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
491815516c77SSepherosa Ziehau 
491915516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
492015516c77SSepherosa Ziehau 		txr->hn_suspended = 0;
492115516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
492215516c77SSepherosa Ziehau 	}
492315516c77SSepherosa Ziehau }
492415516c77SSepherosa Ziehau 
492515516c77SSepherosa Ziehau static void
492615516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc)
492715516c77SSepherosa Ziehau {
492815516c77SSepherosa Ziehau 	int i;
492915516c77SSepherosa Ziehau 
493015516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
493115516c77SSepherosa Ziehau 
493215516c77SSepherosa Ziehau 	/*
493315516c77SSepherosa Ziehau 	 * Re-enable RX.
493415516c77SSepherosa Ziehau 	 */
493515516c77SSepherosa Ziehau 	hn_set_rxfilter(sc);
493615516c77SSepherosa Ziehau 
493715516c77SSepherosa Ziehau 	/*
493815516c77SSepherosa Ziehau 	 * Make sure to clear suspend status on "all" TX rings,
493915516c77SSepherosa Ziehau 	 * since hn_tx_ring_inuse can be changed after
494015516c77SSepherosa Ziehau 	 * hn_suspend_data().
494115516c77SSepherosa Ziehau 	 */
494215516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_cnt);
494315516c77SSepherosa Ziehau 
494423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
494523bf9e15SSepherosa Ziehau 	if (!hn_use_if_start)
494623bf9e15SSepherosa Ziehau #endif
494723bf9e15SSepherosa Ziehau 	{
494815516c77SSepherosa Ziehau 		/*
494915516c77SSepherosa Ziehau 		 * Flush unused drbrs, since hn_tx_ring_inuse may be
495015516c77SSepherosa Ziehau 		 * reduced.
495115516c77SSepherosa Ziehau 		 */
495215516c77SSepherosa Ziehau 		for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i)
495315516c77SSepherosa Ziehau 			hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
495415516c77SSepherosa Ziehau 	}
495515516c77SSepherosa Ziehau 
495615516c77SSepherosa Ziehau 	/*
495715516c77SSepherosa Ziehau 	 * Kick start TX.
495815516c77SSepherosa Ziehau 	 */
495915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
496015516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
496115516c77SSepherosa Ziehau 
496215516c77SSepherosa Ziehau 		/*
496315516c77SSepherosa Ziehau 		 * Use txeof task, so that any pending oactive can be
496415516c77SSepherosa Ziehau 		 * cleared properly.
496515516c77SSepherosa Ziehau 		 */
496615516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
496715516c77SSepherosa Ziehau 	}
496815516c77SSepherosa Ziehau }
496915516c77SSepherosa Ziehau 
497015516c77SSepherosa Ziehau static void
497115516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc)
497215516c77SSepherosa Ziehau {
497315516c77SSepherosa Ziehau 
497415516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
497515516c77SSepherosa Ziehau 
497615516c77SSepherosa Ziehau 	/*
497715516c77SSepherosa Ziehau 	 * Kick off network change detection, if it was pending.
497815516c77SSepherosa Ziehau 	 * If no network change was pending, start link status
497915516c77SSepherosa Ziehau 	 * checks, which is more lightweight than network change
498015516c77SSepherosa Ziehau 	 * detection.
498115516c77SSepherosa Ziehau 	 */
498215516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
498315516c77SSepherosa Ziehau 		hn_change_network(sc);
498415516c77SSepherosa Ziehau 	else
498515516c77SSepherosa Ziehau 		hn_update_link_status(sc);
498615516c77SSepherosa Ziehau }
498715516c77SSepherosa Ziehau 
498815516c77SSepherosa Ziehau static void
498915516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc)
499015516c77SSepherosa Ziehau {
499115516c77SSepherosa Ziehau 
499215516c77SSepherosa Ziehau 	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
499315516c77SSepherosa Ziehau 		hn_resume_data(sc);
499415516c77SSepherosa Ziehau 	hn_resume_mgmt(sc);
499515516c77SSepherosa Ziehau }
499615516c77SSepherosa Ziehau 
499715516c77SSepherosa Ziehau static void
499815516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen)
499915516c77SSepherosa Ziehau {
500015516c77SSepherosa Ziehau 	const struct rndis_status_msg *msg;
500115516c77SSepherosa Ziehau 	int ofs;
500215516c77SSepherosa Ziehau 
500315516c77SSepherosa Ziehau 	if (dlen < sizeof(*msg)) {
500415516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid RNDIS status\n");
500515516c77SSepherosa Ziehau 		return;
500615516c77SSepherosa Ziehau 	}
500715516c77SSepherosa Ziehau 	msg = data;
500815516c77SSepherosa Ziehau 
500915516c77SSepherosa Ziehau 	switch (msg->rm_status) {
501015516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_CONNECT:
501115516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_DISCONNECT:
501215516c77SSepherosa Ziehau 		hn_update_link_status(sc);
501315516c77SSepherosa Ziehau 		break;
501415516c77SSepherosa Ziehau 
501515516c77SSepherosa Ziehau 	case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
501615516c77SSepherosa Ziehau 		/* Not really useful; ignore. */
501715516c77SSepherosa Ziehau 		break;
501815516c77SSepherosa Ziehau 
501915516c77SSepherosa Ziehau 	case RNDIS_STATUS_NETWORK_CHANGE:
502015516c77SSepherosa Ziehau 		ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
502115516c77SSepherosa Ziehau 		if (dlen < ofs + msg->rm_stbuflen ||
502215516c77SSepherosa Ziehau 		    msg->rm_stbuflen < sizeof(uint32_t)) {
502315516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed\n");
502415516c77SSepherosa Ziehau 		} else {
502515516c77SSepherosa Ziehau 			uint32_t change;
502615516c77SSepherosa Ziehau 
502715516c77SSepherosa Ziehau 			memcpy(&change, ((const uint8_t *)msg) + ofs,
502815516c77SSepherosa Ziehau 			    sizeof(change));
502915516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed, change %u\n",
503015516c77SSepherosa Ziehau 			    change);
503115516c77SSepherosa Ziehau 		}
503215516c77SSepherosa Ziehau 		hn_change_network(sc);
503315516c77SSepherosa Ziehau 		break;
503415516c77SSepherosa Ziehau 
503515516c77SSepherosa Ziehau 	default:
503615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
503715516c77SSepherosa Ziehau 		    msg->rm_status);
503815516c77SSepherosa Ziehau 		break;
503915516c77SSepherosa Ziehau 	}
504015516c77SSepherosa Ziehau }
504115516c77SSepherosa Ziehau 
504215516c77SSepherosa Ziehau static int
504315516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info)
504415516c77SSepherosa Ziehau {
504515516c77SSepherosa Ziehau 	const struct rndis_pktinfo *pi = info_data;
504615516c77SSepherosa Ziehau 	uint32_t mask = 0;
504715516c77SSepherosa Ziehau 
504815516c77SSepherosa Ziehau 	while (info_dlen != 0) {
504915516c77SSepherosa Ziehau 		const void *data;
505015516c77SSepherosa Ziehau 		uint32_t dlen;
505115516c77SSepherosa Ziehau 
505215516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < sizeof(*pi)))
505315516c77SSepherosa Ziehau 			return (EINVAL);
505415516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < pi->rm_size))
505515516c77SSepherosa Ziehau 			return (EINVAL);
505615516c77SSepherosa Ziehau 		info_dlen -= pi->rm_size;
505715516c77SSepherosa Ziehau 
505815516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
505915516c77SSepherosa Ziehau 			return (EINVAL);
506015516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
506115516c77SSepherosa Ziehau 			return (EINVAL);
506215516c77SSepherosa Ziehau 		dlen = pi->rm_size - pi->rm_pktinfooffset;
506315516c77SSepherosa Ziehau 		data = pi->rm_data;
506415516c77SSepherosa Ziehau 
506515516c77SSepherosa Ziehau 		switch (pi->rm_type) {
506615516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_VLAN:
506715516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
506815516c77SSepherosa Ziehau 				return (EINVAL);
506915516c77SSepherosa Ziehau 			info->vlan_info = *((const uint32_t *)data);
507015516c77SSepherosa Ziehau 			mask |= HN_RXINFO_VLAN;
507115516c77SSepherosa Ziehau 			break;
507215516c77SSepherosa Ziehau 
507315516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_CSUM:
507415516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
507515516c77SSepherosa Ziehau 				return (EINVAL);
507615516c77SSepherosa Ziehau 			info->csum_info = *((const uint32_t *)data);
507715516c77SSepherosa Ziehau 			mask |= HN_RXINFO_CSUM;
507815516c77SSepherosa Ziehau 			break;
507915516c77SSepherosa Ziehau 
508015516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHVAL:
508115516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
508215516c77SSepherosa Ziehau 				return (EINVAL);
508315516c77SSepherosa Ziehau 			info->hash_value = *((const uint32_t *)data);
508415516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHVAL;
508515516c77SSepherosa Ziehau 			break;
508615516c77SSepherosa Ziehau 
508715516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHINF:
508815516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
508915516c77SSepherosa Ziehau 				return (EINVAL);
509015516c77SSepherosa Ziehau 			info->hash_info = *((const uint32_t *)data);
509115516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHINF;
509215516c77SSepherosa Ziehau 			break;
509315516c77SSepherosa Ziehau 
509415516c77SSepherosa Ziehau 		default:
509515516c77SSepherosa Ziehau 			goto next;
509615516c77SSepherosa Ziehau 		}
509715516c77SSepherosa Ziehau 
509815516c77SSepherosa Ziehau 		if (mask == HN_RXINFO_ALL) {
509915516c77SSepherosa Ziehau 			/* All found; done */
510015516c77SSepherosa Ziehau 			break;
510115516c77SSepherosa Ziehau 		}
510215516c77SSepherosa Ziehau next:
510315516c77SSepherosa Ziehau 		pi = (const struct rndis_pktinfo *)
510415516c77SSepherosa Ziehau 		    ((const uint8_t *)pi + pi->rm_size);
510515516c77SSepherosa Ziehau 	}
510615516c77SSepherosa Ziehau 
510715516c77SSepherosa Ziehau 	/*
510815516c77SSepherosa Ziehau 	 * Final fixup.
510915516c77SSepherosa Ziehau 	 * - If there is no hash value, invalidate the hash info.
511015516c77SSepherosa Ziehau 	 */
511115516c77SSepherosa Ziehau 	if ((mask & HN_RXINFO_HASHVAL) == 0)
511215516c77SSepherosa Ziehau 		info->hash_info = HN_NDIS_HASH_INFO_INVALID;
511315516c77SSepherosa Ziehau 	return (0);
511415516c77SSepherosa Ziehau }
511515516c77SSepherosa Ziehau 
511615516c77SSepherosa Ziehau static __inline bool
511715516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
511815516c77SSepherosa Ziehau {
511915516c77SSepherosa Ziehau 
512015516c77SSepherosa Ziehau 	if (off < check_off) {
512115516c77SSepherosa Ziehau 		if (__predict_true(off + len <= check_off))
512215516c77SSepherosa Ziehau 			return (false);
512315516c77SSepherosa Ziehau 	} else if (off > check_off) {
512415516c77SSepherosa Ziehau 		if (__predict_true(check_off + check_len <= off))
512515516c77SSepherosa Ziehau 			return (false);
512615516c77SSepherosa Ziehau 	}
512715516c77SSepherosa Ziehau 	return (true);
512815516c77SSepherosa Ziehau }
512915516c77SSepherosa Ziehau 
513015516c77SSepherosa Ziehau static void
513115516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen)
513215516c77SSepherosa Ziehau {
513315516c77SSepherosa Ziehau 	const struct rndis_packet_msg *pkt;
513415516c77SSepherosa Ziehau 	struct hn_rxinfo info;
513515516c77SSepherosa Ziehau 	int data_off, pktinfo_off, data_len, pktinfo_len;
513615516c77SSepherosa Ziehau 
513715516c77SSepherosa Ziehau 	/*
513815516c77SSepherosa Ziehau 	 * Check length.
513915516c77SSepherosa Ziehau 	 */
514015516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*pkt))) {
514115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
514215516c77SSepherosa Ziehau 		return;
514315516c77SSepherosa Ziehau 	}
514415516c77SSepherosa Ziehau 	pkt = data;
514515516c77SSepherosa Ziehau 
514615516c77SSepherosa Ziehau 	if (__predict_false(dlen < pkt->rm_len)) {
514715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
514815516c77SSepherosa Ziehau 		    "dlen %d, msglen %u\n", dlen, pkt->rm_len);
514915516c77SSepherosa Ziehau 		return;
515015516c77SSepherosa Ziehau 	}
515115516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_len <
515215516c77SSepherosa Ziehau 	    pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
515315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
515415516c77SSepherosa Ziehau 		    "msglen %u, data %u, oob %u, pktinfo %u\n",
515515516c77SSepherosa Ziehau 		    pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
515615516c77SSepherosa Ziehau 		    pkt->rm_pktinfolen);
515715516c77SSepherosa Ziehau 		return;
515815516c77SSepherosa Ziehau 	}
515915516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_datalen == 0)) {
516015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
516115516c77SSepherosa Ziehau 		return;
516215516c77SSepherosa Ziehau 	}
516315516c77SSepherosa Ziehau 
516415516c77SSepherosa Ziehau 	/*
516515516c77SSepherosa Ziehau 	 * Check offests.
516615516c77SSepherosa Ziehau 	 */
516715516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs)			\
516815516c77SSepherosa Ziehau 	((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN ||	\
516915516c77SSepherosa Ziehau 	 ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
517015516c77SSepherosa Ziehau 
517115516c77SSepherosa Ziehau 	/* XXX Hyper-V does not meet data offset alignment requirement */
517215516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
517315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
517415516c77SSepherosa Ziehau 		    "data offset %u\n", pkt->rm_dataoffset);
517515516c77SSepherosa Ziehau 		return;
517615516c77SSepherosa Ziehau 	}
517715516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdataoffset > 0 &&
517815516c77SSepherosa Ziehau 	    IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
517915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
518015516c77SSepherosa Ziehau 		    "oob offset %u\n", pkt->rm_oobdataoffset);
518115516c77SSepherosa Ziehau 		return;
518215516c77SSepherosa Ziehau 	}
518315516c77SSepherosa Ziehau 	if (__predict_true(pkt->rm_pktinfooffset > 0) &&
518415516c77SSepherosa Ziehau 	    __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
518515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
518615516c77SSepherosa Ziehau 		    "pktinfo offset %u\n", pkt->rm_pktinfooffset);
518715516c77SSepherosa Ziehau 		return;
518815516c77SSepherosa Ziehau 	}
518915516c77SSepherosa Ziehau 
519015516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID
519115516c77SSepherosa Ziehau 
519215516c77SSepherosa Ziehau 	data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
519315516c77SSepherosa Ziehau 	data_len = pkt->rm_datalen;
519415516c77SSepherosa Ziehau 	pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
519515516c77SSepherosa Ziehau 	pktinfo_len = pkt->rm_pktinfolen;
519615516c77SSepherosa Ziehau 
519715516c77SSepherosa Ziehau 	/*
519815516c77SSepherosa Ziehau 	 * Check OOB coverage.
519915516c77SSepherosa Ziehau 	 */
520015516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdatalen != 0)) {
520115516c77SSepherosa Ziehau 		int oob_off, oob_len;
520215516c77SSepherosa Ziehau 
520315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "got oobdata\n");
520415516c77SSepherosa Ziehau 		oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
520515516c77SSepherosa Ziehau 		oob_len = pkt->rm_oobdatalen;
520615516c77SSepherosa Ziehau 
520715516c77SSepherosa Ziehau 		if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
520815516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
520915516c77SSepherosa Ziehau 			    "oob overflow, msglen %u, oob abs %d len %d\n",
521015516c77SSepherosa Ziehau 			    pkt->rm_len, oob_off, oob_len);
521115516c77SSepherosa Ziehau 			return;
521215516c77SSepherosa Ziehau 		}
521315516c77SSepherosa Ziehau 
521415516c77SSepherosa Ziehau 		/*
521515516c77SSepherosa Ziehau 		 * Check against data.
521615516c77SSepherosa Ziehau 		 */
521715516c77SSepherosa Ziehau 		if (hn_rndis_check_overlap(oob_off, oob_len,
521815516c77SSepherosa Ziehau 		    data_off, data_len)) {
521915516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
522015516c77SSepherosa Ziehau 			    "oob overlaps data, oob abs %d len %d, "
522115516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
522215516c77SSepherosa Ziehau 			    oob_off, oob_len, data_off, data_len);
522315516c77SSepherosa Ziehau 			return;
522415516c77SSepherosa Ziehau 		}
522515516c77SSepherosa Ziehau 
522615516c77SSepherosa Ziehau 		/*
522715516c77SSepherosa Ziehau 		 * Check against pktinfo.
522815516c77SSepherosa Ziehau 		 */
522915516c77SSepherosa Ziehau 		if (pktinfo_len != 0 &&
523015516c77SSepherosa Ziehau 		    hn_rndis_check_overlap(oob_off, oob_len,
523115516c77SSepherosa Ziehau 		    pktinfo_off, pktinfo_len)) {
523215516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
523315516c77SSepherosa Ziehau 			    "oob overlaps pktinfo, oob abs %d len %d, "
523415516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
523515516c77SSepherosa Ziehau 			    oob_off, oob_len, pktinfo_off, pktinfo_len);
523615516c77SSepherosa Ziehau 			return;
523715516c77SSepherosa Ziehau 		}
523815516c77SSepherosa Ziehau 	}
523915516c77SSepherosa Ziehau 
524015516c77SSepherosa Ziehau 	/*
524115516c77SSepherosa Ziehau 	 * Check per-packet-info coverage and find useful per-packet-info.
524215516c77SSepherosa Ziehau 	 */
524315516c77SSepherosa Ziehau 	info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
524415516c77SSepherosa Ziehau 	info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
524515516c77SSepherosa Ziehau 	info.hash_info = HN_NDIS_HASH_INFO_INVALID;
524615516c77SSepherosa Ziehau 	if (__predict_true(pktinfo_len != 0)) {
524715516c77SSepherosa Ziehau 		bool overlap;
524815516c77SSepherosa Ziehau 		int error;
524915516c77SSepherosa Ziehau 
525015516c77SSepherosa Ziehau 		if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
525115516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
525215516c77SSepherosa Ziehau 			    "pktinfo overflow, msglen %u, "
525315516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
525415516c77SSepherosa Ziehau 			    pkt->rm_len, pktinfo_off, pktinfo_len);
525515516c77SSepherosa Ziehau 			return;
525615516c77SSepherosa Ziehau 		}
525715516c77SSepherosa Ziehau 
525815516c77SSepherosa Ziehau 		/*
525915516c77SSepherosa Ziehau 		 * Check packet info coverage.
526015516c77SSepherosa Ziehau 		 */
526115516c77SSepherosa Ziehau 		overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
526215516c77SSepherosa Ziehau 		    data_off, data_len);
526315516c77SSepherosa Ziehau 		if (__predict_false(overlap)) {
526415516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
526515516c77SSepherosa Ziehau 			    "pktinfo overlap data, pktinfo abs %d len %d, "
526615516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
526715516c77SSepherosa Ziehau 			    pktinfo_off, pktinfo_len, data_off, data_len);
526815516c77SSepherosa Ziehau 			return;
526915516c77SSepherosa Ziehau 		}
527015516c77SSepherosa Ziehau 
527115516c77SSepherosa Ziehau 		/*
527215516c77SSepherosa Ziehau 		 * Find useful per-packet-info.
527315516c77SSepherosa Ziehau 		 */
527415516c77SSepherosa Ziehau 		error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
527515516c77SSepherosa Ziehau 		    pktinfo_len, &info);
527615516c77SSepherosa Ziehau 		if (__predict_false(error)) {
527715516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
527815516c77SSepherosa Ziehau 			    "pktinfo\n");
527915516c77SSepherosa Ziehau 			return;
528015516c77SSepherosa Ziehau 		}
528115516c77SSepherosa Ziehau 	}
528215516c77SSepherosa Ziehau 
528315516c77SSepherosa Ziehau 	if (__predict_false(data_off + data_len > pkt->rm_len)) {
528415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
528515516c77SSepherosa Ziehau 		    "data overflow, msglen %u, data abs %d len %d\n",
528615516c77SSepherosa Ziehau 		    pkt->rm_len, data_off, data_len);
528715516c77SSepherosa Ziehau 		return;
528815516c77SSepherosa Ziehau 	}
528915516c77SSepherosa Ziehau 	hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
529015516c77SSepherosa Ziehau }
529115516c77SSepherosa Ziehau 
529215516c77SSepherosa Ziehau static __inline void
529315516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen)
529415516c77SSepherosa Ziehau {
529515516c77SSepherosa Ziehau 	const struct rndis_msghdr *hdr;
529615516c77SSepherosa Ziehau 
529715516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*hdr))) {
529815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
529915516c77SSepherosa Ziehau 		return;
530015516c77SSepherosa Ziehau 	}
530115516c77SSepherosa Ziehau 	hdr = data;
530215516c77SSepherosa Ziehau 
530315516c77SSepherosa Ziehau 	if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) {
530415516c77SSepherosa Ziehau 		/* Hot data path. */
530515516c77SSepherosa Ziehau 		hn_rndis_rx_data(rxr, data, dlen);
530615516c77SSepherosa Ziehau 		/* Done! */
530715516c77SSepherosa Ziehau 		return;
530815516c77SSepherosa Ziehau 	}
530915516c77SSepherosa Ziehau 
531015516c77SSepherosa Ziehau 	if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG)
531115516c77SSepherosa Ziehau 		hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen);
531215516c77SSepherosa Ziehau 	else
531315516c77SSepherosa Ziehau 		hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen);
531415516c77SSepherosa Ziehau }
531515516c77SSepherosa Ziehau 
531615516c77SSepherosa Ziehau static void
531715516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
531815516c77SSepherosa Ziehau {
531915516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *hdr;
532015516c77SSepherosa Ziehau 
532115516c77SSepherosa Ziehau 	if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) {
532215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid nvs notify\n");
532315516c77SSepherosa Ziehau 		return;
532415516c77SSepherosa Ziehau 	}
532515516c77SSepherosa Ziehau 	hdr = VMBUS_CHANPKT_CONST_DATA(pkt);
532615516c77SSepherosa Ziehau 
532715516c77SSepherosa Ziehau 	if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) {
532815516c77SSepherosa Ziehau 		/* Useless; ignore */
532915516c77SSepherosa Ziehau 		return;
533015516c77SSepherosa Ziehau 	}
533115516c77SSepherosa Ziehau 	if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type);
533215516c77SSepherosa Ziehau }
533315516c77SSepherosa Ziehau 
533415516c77SSepherosa Ziehau static void
533515516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan,
533615516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkt)
533715516c77SSepherosa Ziehau {
533815516c77SSepherosa Ziehau 	struct hn_nvs_sendctx *sndc;
533915516c77SSepherosa Ziehau 
534015516c77SSepherosa Ziehau 	sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid;
534115516c77SSepherosa Ziehau 	sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt),
534215516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_DATALEN(pkt));
534315516c77SSepherosa Ziehau 	/*
534415516c77SSepherosa Ziehau 	 * NOTE:
534515516c77SSepherosa Ziehau 	 * 'sndc' CAN NOT be accessed anymore, since it can be freed by
534615516c77SSepherosa Ziehau 	 * its callback.
534715516c77SSepherosa Ziehau 	 */
534815516c77SSepherosa Ziehau }
534915516c77SSepherosa Ziehau 
535015516c77SSepherosa Ziehau static void
535115516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
535215516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkthdr)
535315516c77SSepherosa Ziehau {
535415516c77SSepherosa Ziehau 	const struct vmbus_chanpkt_rxbuf *pkt;
535515516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *nvs_hdr;
535615516c77SSepherosa Ziehau 	int count, i, hlen;
535715516c77SSepherosa Ziehau 
535815516c77SSepherosa Ziehau 	if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) {
535915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n");
536015516c77SSepherosa Ziehau 		return;
536115516c77SSepherosa Ziehau 	}
536215516c77SSepherosa Ziehau 	nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr);
536315516c77SSepherosa Ziehau 
536415516c77SSepherosa Ziehau 	/* Make sure that this is a RNDIS message. */
536515516c77SSepherosa Ziehau 	if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) {
536615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n",
536715516c77SSepherosa Ziehau 		    nvs_hdr->nvs_type);
536815516c77SSepherosa Ziehau 		return;
536915516c77SSepherosa Ziehau 	}
537015516c77SSepherosa Ziehau 
537115516c77SSepherosa Ziehau 	hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen);
537215516c77SSepherosa Ziehau 	if (__predict_false(hlen < sizeof(*pkt))) {
537315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n");
537415516c77SSepherosa Ziehau 		return;
537515516c77SSepherosa Ziehau 	}
537615516c77SSepherosa Ziehau 	pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
537715516c77SSepherosa Ziehau 
537815516c77SSepherosa Ziehau 	if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) {
537915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n",
538015516c77SSepherosa Ziehau 		    pkt->cp_rxbuf_id);
538115516c77SSepherosa Ziehau 		return;
538215516c77SSepherosa Ziehau 	}
538315516c77SSepherosa Ziehau 
538415516c77SSepherosa Ziehau 	count = pkt->cp_rxbuf_cnt;
538515516c77SSepherosa Ziehau 	if (__predict_false(hlen <
538615516c77SSepherosa Ziehau 	    __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) {
538715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count);
538815516c77SSepherosa Ziehau 		return;
538915516c77SSepherosa Ziehau 	}
539015516c77SSepherosa Ziehau 
539115516c77SSepherosa Ziehau 	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
539215516c77SSepherosa Ziehau 	for (i = 0; i < count; ++i) {
539315516c77SSepherosa Ziehau 		int ofs, len;
539415516c77SSepherosa Ziehau 
539515516c77SSepherosa Ziehau 		ofs = pkt->cp_rxbuf[i].rb_ofs;
539615516c77SSepherosa Ziehau 		len = pkt->cp_rxbuf[i].rb_len;
539715516c77SSepherosa Ziehau 		if (__predict_false(ofs + len > HN_RXBUF_SIZE)) {
539815516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, "
539915516c77SSepherosa Ziehau 			    "ofs %d, len %d\n", i, ofs, len);
540015516c77SSepherosa Ziehau 			continue;
540115516c77SSepherosa Ziehau 		}
540215516c77SSepherosa Ziehau 		hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len);
540315516c77SSepherosa Ziehau 	}
540415516c77SSepherosa Ziehau 
540515516c77SSepherosa Ziehau 	/*
540615516c77SSepherosa Ziehau 	 * Ack the consumed RXBUF associated w/ this channel packet,
540715516c77SSepherosa Ziehau 	 * so that this RXBUF can be recycled by the hypervisor.
540815516c77SSepherosa Ziehau 	 */
540915516c77SSepherosa Ziehau 	hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid);
541015516c77SSepherosa Ziehau }
541115516c77SSepherosa Ziehau 
541215516c77SSepherosa Ziehau static void
541315516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
541415516c77SSepherosa Ziehau     uint64_t tid)
541515516c77SSepherosa Ziehau {
541615516c77SSepherosa Ziehau 	struct hn_nvs_rndis_ack ack;
541715516c77SSepherosa Ziehau 	int retries, error;
541815516c77SSepherosa Ziehau 
541915516c77SSepherosa Ziehau 	ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK;
542015516c77SSepherosa Ziehau 	ack.nvs_status = HN_NVS_STATUS_OK;
542115516c77SSepherosa Ziehau 
542215516c77SSepherosa Ziehau 	retries = 0;
542315516c77SSepherosa Ziehau again:
542415516c77SSepherosa Ziehau 	error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP,
542515516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid);
542615516c77SSepherosa Ziehau 	if (__predict_false(error == EAGAIN)) {
542715516c77SSepherosa Ziehau 		/*
542815516c77SSepherosa Ziehau 		 * NOTE:
542915516c77SSepherosa Ziehau 		 * This should _not_ happen in real world, since the
543015516c77SSepherosa Ziehau 		 * consumption of the TX bufring from the TX path is
543115516c77SSepherosa Ziehau 		 * controlled.
543215516c77SSepherosa Ziehau 		 */
543315516c77SSepherosa Ziehau 		if (rxr->hn_ack_failed == 0)
543415516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "RXBUF ack retry\n");
543515516c77SSepherosa Ziehau 		rxr->hn_ack_failed++;
543615516c77SSepherosa Ziehau 		retries++;
543715516c77SSepherosa Ziehau 		if (retries < 10) {
543815516c77SSepherosa Ziehau 			DELAY(100);
543915516c77SSepherosa Ziehau 			goto again;
544015516c77SSepherosa Ziehau 		}
544115516c77SSepherosa Ziehau 		/* RXBUF leaks! */
544215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "RXBUF ack failed\n");
544315516c77SSepherosa Ziehau 	}
544415516c77SSepherosa Ziehau }
544515516c77SSepherosa Ziehau 
544615516c77SSepherosa Ziehau static void
544715516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr)
544815516c77SSepherosa Ziehau {
544915516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr = xrxr;
545015516c77SSepherosa Ziehau 	struct hn_softc *sc = rxr->hn_ifp->if_softc;
545115516c77SSepherosa Ziehau 
545215516c77SSepherosa Ziehau 	for (;;) {
545315516c77SSepherosa Ziehau 		struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf;
545415516c77SSepherosa Ziehau 		int error, pktlen;
545515516c77SSepherosa Ziehau 
545615516c77SSepherosa Ziehau 		pktlen = rxr->hn_pktbuf_len;
545715516c77SSepherosa Ziehau 		error = vmbus_chan_recv_pkt(chan, pkt, &pktlen);
545815516c77SSepherosa Ziehau 		if (__predict_false(error == ENOBUFS)) {
545915516c77SSepherosa Ziehau 			void *nbuf;
546015516c77SSepherosa Ziehau 			int nlen;
546115516c77SSepherosa Ziehau 
546215516c77SSepherosa Ziehau 			/*
546315516c77SSepherosa Ziehau 			 * Expand channel packet buffer.
546415516c77SSepherosa Ziehau 			 *
546515516c77SSepherosa Ziehau 			 * XXX
546615516c77SSepherosa Ziehau 			 * Use M_WAITOK here, since allocation failure
546715516c77SSepherosa Ziehau 			 * is fatal.
546815516c77SSepherosa Ziehau 			 */
546915516c77SSepherosa Ziehau 			nlen = rxr->hn_pktbuf_len * 2;
547015516c77SSepherosa Ziehau 			while (nlen < pktlen)
547115516c77SSepherosa Ziehau 				nlen *= 2;
547215516c77SSepherosa Ziehau 			nbuf = malloc(nlen, M_DEVBUF, M_WAITOK);
547315516c77SSepherosa Ziehau 
547415516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n",
547515516c77SSepherosa Ziehau 			    rxr->hn_pktbuf_len, nlen);
547615516c77SSepherosa Ziehau 
547715516c77SSepherosa Ziehau 			free(rxr->hn_pktbuf, M_DEVBUF);
547815516c77SSepherosa Ziehau 			rxr->hn_pktbuf = nbuf;
547915516c77SSepherosa Ziehau 			rxr->hn_pktbuf_len = nlen;
548015516c77SSepherosa Ziehau 			/* Retry! */
548115516c77SSepherosa Ziehau 			continue;
548215516c77SSepherosa Ziehau 		} else if (__predict_false(error == EAGAIN)) {
548315516c77SSepherosa Ziehau 			/* No more channel packets; done! */
548415516c77SSepherosa Ziehau 			break;
548515516c77SSepherosa Ziehau 		}
548615516c77SSepherosa Ziehau 		KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error));
548715516c77SSepherosa Ziehau 
548815516c77SSepherosa Ziehau 		switch (pkt->cph_type) {
548915516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_COMP:
549015516c77SSepherosa Ziehau 			hn_nvs_handle_comp(sc, chan, pkt);
549115516c77SSepherosa Ziehau 			break;
549215516c77SSepherosa Ziehau 
549315516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_RXBUF:
549415516c77SSepherosa Ziehau 			hn_nvs_handle_rxbuf(rxr, chan, pkt);
549515516c77SSepherosa Ziehau 			break;
549615516c77SSepherosa Ziehau 
549715516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_INBAND:
549815516c77SSepherosa Ziehau 			hn_nvs_handle_notify(sc, pkt);
549915516c77SSepherosa Ziehau 			break;
550015516c77SSepherosa Ziehau 
550115516c77SSepherosa Ziehau 		default:
550215516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "unknown chan pkt %u\n",
550315516c77SSepherosa Ziehau 			    pkt->cph_type);
550415516c77SSepherosa Ziehau 			break;
550515516c77SSepherosa Ziehau 		}
550615516c77SSepherosa Ziehau 	}
550715516c77SSepherosa Ziehau 	hn_chan_rollup(rxr, rxr->hn_txr);
550815516c77SSepherosa Ziehau }
550915516c77SSepherosa Ziehau 
551015516c77SSepherosa Ziehau static void
551115516c77SSepherosa Ziehau hn_tx_taskq_create(void *arg __unused)
551215516c77SSepherosa Ziehau {
5513fdd0222aSSepherosa Ziehau 	int i;
5514fdd0222aSSepherosa Ziehau 
5515fdd0222aSSepherosa Ziehau 	/*
5516fdd0222aSSepherosa Ziehau 	 * Fix the # of TX taskqueues.
5517fdd0222aSSepherosa Ziehau 	 */
5518fdd0222aSSepherosa Ziehau 	if (hn_tx_taskq_cnt <= 0)
5519fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = 1;
5520fdd0222aSSepherosa Ziehau 	else if (hn_tx_taskq_cnt > mp_ncpus)
5521fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = mp_ncpus;
552215516c77SSepherosa Ziehau 
55230e11868dSSepherosa Ziehau 	/*
55240e11868dSSepherosa Ziehau 	 * Fix the TX taskqueue mode.
55250e11868dSSepherosa Ziehau 	 */
55260e11868dSSepherosa Ziehau 	switch (hn_tx_taskq_mode) {
55270e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_INDEP:
55280e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_GLOBAL:
55290e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_EVTTQ:
55300e11868dSSepherosa Ziehau 		break;
55310e11868dSSepherosa Ziehau 	default:
55320e11868dSSepherosa Ziehau 		hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
55330e11868dSSepherosa Ziehau 		break;
55340e11868dSSepherosa Ziehau 	}
55350e11868dSSepherosa Ziehau 
553615516c77SSepherosa Ziehau 	if (vm_guest != VM_GUEST_HV)
553715516c77SSepherosa Ziehau 		return;
553815516c77SSepherosa Ziehau 
55390e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode != HN_TX_TASKQ_M_GLOBAL)
554015516c77SSepherosa Ziehau 		return;
554115516c77SSepherosa Ziehau 
5542fdd0222aSSepherosa Ziehau 	hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
5543fdd0222aSSepherosa Ziehau 	    M_DEVBUF, M_WAITOK);
5544fdd0222aSSepherosa Ziehau 	for (i = 0; i < hn_tx_taskq_cnt; ++i) {
5545fdd0222aSSepherosa Ziehau 		hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK,
5546fdd0222aSSepherosa Ziehau 		    taskqueue_thread_enqueue, &hn_tx_taskque[i]);
5547fdd0222aSSepherosa Ziehau 		taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET,
5548fdd0222aSSepherosa Ziehau 		    "hn tx%d", i);
5549fdd0222aSSepherosa Ziehau 	}
555015516c77SSepherosa Ziehau }
555115516c77SSepherosa Ziehau SYSINIT(hn_txtq_create, SI_SUB_DRIVERS, SI_ORDER_SECOND,
555215516c77SSepherosa Ziehau     hn_tx_taskq_create, NULL);
555315516c77SSepherosa Ziehau 
555415516c77SSepherosa Ziehau static void
555515516c77SSepherosa Ziehau hn_tx_taskq_destroy(void *arg __unused)
555615516c77SSepherosa Ziehau {
555715516c77SSepherosa Ziehau 
5558fdd0222aSSepherosa Ziehau 	if (hn_tx_taskque != NULL) {
5559fdd0222aSSepherosa Ziehau 		int i;
5560fdd0222aSSepherosa Ziehau 
5561fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
5562fdd0222aSSepherosa Ziehau 			taskqueue_free(hn_tx_taskque[i]);
5563fdd0222aSSepherosa Ziehau 		free(hn_tx_taskque, M_DEVBUF);
5564fdd0222aSSepherosa Ziehau 	}
556515516c77SSepherosa Ziehau }
556615516c77SSepherosa Ziehau SYSUNINIT(hn_txtq_destroy, SI_SUB_DRIVERS, SI_ORDER_SECOND,
556715516c77SSepherosa Ziehau     hn_tx_taskq_destroy, NULL);
5568