xref: /freebsd/sys/dev/hyperv/netvsc/if_hn.c (revision 7960e6ba99d5edacb94b87b4f60be4b0eecd3e5f)
115516c77SSepherosa Ziehau /*-
215516c77SSepherosa Ziehau  * Copyright (c) 2010-2012 Citrix Inc.
315516c77SSepherosa Ziehau  * Copyright (c) 2009-2012,2016 Microsoft Corp.
415516c77SSepherosa Ziehau  * Copyright (c) 2012 NetApp Inc.
515516c77SSepherosa Ziehau  * All rights reserved.
615516c77SSepherosa Ziehau  *
715516c77SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
815516c77SSepherosa Ziehau  * modification, are permitted provided that the following conditions
915516c77SSepherosa Ziehau  * are met:
1015516c77SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
1115516c77SSepherosa Ziehau  *    notice unmodified, this list of conditions, and the following
1215516c77SSepherosa Ziehau  *    disclaimer.
1315516c77SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
1415516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
1515516c77SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
1615516c77SSepherosa Ziehau  *
1715516c77SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1815516c77SSepherosa Ziehau  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1915516c77SSepherosa Ziehau  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2015516c77SSepherosa Ziehau  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2115516c77SSepherosa Ziehau  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2215516c77SSepherosa Ziehau  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2315516c77SSepherosa Ziehau  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2415516c77SSepherosa Ziehau  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2515516c77SSepherosa Ziehau  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2615516c77SSepherosa Ziehau  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2715516c77SSepherosa Ziehau  */
2815516c77SSepherosa Ziehau 
2915516c77SSepherosa Ziehau /*-
3015516c77SSepherosa Ziehau  * Copyright (c) 2004-2006 Kip Macy
3115516c77SSepherosa Ziehau  * All rights reserved.
3215516c77SSepherosa Ziehau  *
3315516c77SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
3415516c77SSepherosa Ziehau  * modification, are permitted provided that the following conditions
3515516c77SSepherosa Ziehau  * are met:
3615516c77SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
3715516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer.
3815516c77SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
3915516c77SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
4015516c77SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
4115516c77SSepherosa Ziehau  *
4215516c77SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
4315516c77SSepherosa Ziehau  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4415516c77SSepherosa Ziehau  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4515516c77SSepherosa Ziehau  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4615516c77SSepherosa Ziehau  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4715516c77SSepherosa Ziehau  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4815516c77SSepherosa Ziehau  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4915516c77SSepherosa Ziehau  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5015516c77SSepherosa Ziehau  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5115516c77SSepherosa Ziehau  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5215516c77SSepherosa Ziehau  * SUCH DAMAGE.
5315516c77SSepherosa Ziehau  */
5415516c77SSepherosa Ziehau 
5515516c77SSepherosa Ziehau #include <sys/cdefs.h>
5615516c77SSepherosa Ziehau __FBSDID("$FreeBSD$");
5715516c77SSepherosa Ziehau 
5815516c77SSepherosa Ziehau #include "opt_inet6.h"
5915516c77SSepherosa Ziehau #include "opt_inet.h"
6015516c77SSepherosa Ziehau 
6115516c77SSepherosa Ziehau #include <sys/param.h>
6215516c77SSepherosa Ziehau #include <sys/bus.h>
6315516c77SSepherosa Ziehau #include <sys/kernel.h>
6415516c77SSepherosa Ziehau #include <sys/limits.h>
6515516c77SSepherosa Ziehau #include <sys/malloc.h>
6615516c77SSepherosa Ziehau #include <sys/mbuf.h>
6715516c77SSepherosa Ziehau #include <sys/module.h>
6815516c77SSepherosa Ziehau #include <sys/queue.h>
6915516c77SSepherosa Ziehau #include <sys/lock.h>
7015516c77SSepherosa Ziehau #include <sys/smp.h>
7115516c77SSepherosa Ziehau #include <sys/socket.h>
7215516c77SSepherosa Ziehau #include <sys/sockio.h>
7315516c77SSepherosa Ziehau #include <sys/sx.h>
7415516c77SSepherosa Ziehau #include <sys/sysctl.h>
7515516c77SSepherosa Ziehau #include <sys/systm.h>
7615516c77SSepherosa Ziehau #include <sys/taskqueue.h>
7715516c77SSepherosa Ziehau #include <sys/buf_ring.h>
7815516c77SSepherosa Ziehau 
7915516c77SSepherosa Ziehau #include <machine/atomic.h>
8015516c77SSepherosa Ziehau #include <machine/in_cksum.h>
8115516c77SSepherosa Ziehau 
8215516c77SSepherosa Ziehau #include <net/bpf.h>
8315516c77SSepherosa Ziehau #include <net/ethernet.h>
8415516c77SSepherosa Ziehau #include <net/if.h>
8515516c77SSepherosa Ziehau #include <net/if_media.h>
8615516c77SSepherosa Ziehau #include <net/if_types.h>
8715516c77SSepherosa Ziehau #include <net/if_var.h>
8815516c77SSepherosa Ziehau #include <net/rndis.h>
8915516c77SSepherosa Ziehau 
9015516c77SSepherosa Ziehau #include <netinet/in_systm.h>
9115516c77SSepherosa Ziehau #include <netinet/in.h>
9215516c77SSepherosa Ziehau #include <netinet/ip.h>
9315516c77SSepherosa Ziehau #include <netinet/ip6.h>
9415516c77SSepherosa Ziehau #include <netinet/tcp.h>
9515516c77SSepherosa Ziehau #include <netinet/tcp_lro.h>
9615516c77SSepherosa Ziehau #include <netinet/udp.h>
9715516c77SSepherosa Ziehau 
9815516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h>
9915516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv_busdma.h>
10015516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus.h>
10115516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus_xact.h>
10215516c77SSepherosa Ziehau 
10315516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/ndis.h>
10415516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnreg.h>
10515516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnvar.h>
10615516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_nvs.h>
10715516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_rndis.h>
10815516c77SSepherosa Ziehau 
10915516c77SSepherosa Ziehau #include "vmbus_if.h"
11015516c77SSepherosa Ziehau 
11123bf9e15SSepherosa Ziehau #define HN_IFSTART_SUPPORT
11223bf9e15SSepherosa Ziehau 
11315516c77SSepherosa Ziehau #define HN_RING_CNT_DEF_MAX		8
11415516c77SSepherosa Ziehau 
11515516c77SSepherosa Ziehau /* YYY should get it from the underlying channel */
11615516c77SSepherosa Ziehau #define HN_TX_DESC_CNT			512
11715516c77SSepherosa Ziehau 
11815516c77SSepherosa Ziehau #define HN_RNDIS_PKT_LEN					\
11915516c77SSepherosa Ziehau 	(sizeof(struct rndis_packet_msg) +			\
12015516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) +	\
12115516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) +		\
12215516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) +		\
12315516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_TXCSUM_INFO_SIZE))
12415516c77SSepherosa Ziehau #define HN_RNDIS_PKT_BOUNDARY		PAGE_SIZE
12515516c77SSepherosa Ziehau #define HN_RNDIS_PKT_ALIGN		CACHE_LINE_SIZE
12615516c77SSepherosa Ziehau 
12715516c77SSepherosa Ziehau #define HN_TX_DATA_BOUNDARY		PAGE_SIZE
12815516c77SSepherosa Ziehau #define HN_TX_DATA_MAXSIZE		IP_MAXPACKET
12915516c77SSepherosa Ziehau #define HN_TX_DATA_SEGSIZE		PAGE_SIZE
13015516c77SSepherosa Ziehau /* -1 for RNDIS packet message */
13115516c77SSepherosa Ziehau #define HN_TX_DATA_SEGCNT_MAX		(HN_GPACNT_MAX - 1)
13215516c77SSepherosa Ziehau 
13315516c77SSepherosa Ziehau #define HN_DIRECT_TX_SIZE_DEF		128
13415516c77SSepherosa Ziehau 
13515516c77SSepherosa Ziehau #define HN_EARLY_TXEOF_THRESH		8
13615516c77SSepherosa Ziehau 
13715516c77SSepherosa Ziehau #define HN_PKTBUF_LEN_DEF		(16 * 1024)
13815516c77SSepherosa Ziehau 
13915516c77SSepherosa Ziehau #define HN_LROENT_CNT_DEF		128
14015516c77SSepherosa Ziehau 
14115516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MULTIRX_DEF	(12 * ETHERMTU)
14215516c77SSepherosa Ziehau #define HN_LRO_LENLIM_DEF		(25 * ETHERMTU)
14315516c77SSepherosa Ziehau /* YYY 2*MTU is a bit rough, but should be good enough. */
14415516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MIN(ifp)		(2 * (ifp)->if_mtu)
14515516c77SSepherosa Ziehau 
14615516c77SSepherosa Ziehau #define HN_LRO_ACKCNT_DEF		1
14715516c77SSepherosa Ziehau 
14815516c77SSepherosa Ziehau #define HN_LOCK_INIT(sc)		\
14915516c77SSepherosa Ziehau 	sx_init(&(sc)->hn_lock, device_get_nameunit((sc)->hn_dev))
15015516c77SSepherosa Ziehau #define HN_LOCK_DESTROY(sc)		sx_destroy(&(sc)->hn_lock)
15115516c77SSepherosa Ziehau #define HN_LOCK_ASSERT(sc)		sx_assert(&(sc)->hn_lock, SA_XLOCKED)
152fdc4f478SSepherosa Ziehau #define HN_LOCK(sc)					\
153fdc4f478SSepherosa Ziehau do {							\
154fdc4f478SSepherosa Ziehau 	while (sx_try_xlock(&(sc)->hn_lock) == 0)	\
155fdc4f478SSepherosa Ziehau 		DELAY(1000);				\
156fdc4f478SSepherosa Ziehau } while (0)
15715516c77SSepherosa Ziehau #define HN_UNLOCK(sc)			sx_xunlock(&(sc)->hn_lock)
15815516c77SSepherosa Ziehau 
15915516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK			(CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP)
16015516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK		(CSUM_IP6_TCP | CSUM_IP6_UDP)
16115516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc)		\
16215516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK)
16315516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc)	\
16415516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK)
16515516c77SSepherosa Ziehau 
166dc13fee6SSepherosa Ziehau #define HN_PKTSIZE_MIN(align)		\
167dc13fee6SSepherosa Ziehau 	roundup2(ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN + \
168dc13fee6SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN, (align))
169dc13fee6SSepherosa Ziehau #define HN_PKTSIZE(m, align)		\
170dc13fee6SSepherosa Ziehau 	roundup2((m)->m_pkthdr.len + HN_RNDIS_PKT_LEN, (align))
171dc13fee6SSepherosa Ziehau 
17215516c77SSepherosa Ziehau struct hn_txdesc {
17315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
17415516c77SSepherosa Ziehau 	SLIST_ENTRY(hn_txdesc)		link;
17515516c77SSepherosa Ziehau #endif
176dc13fee6SSepherosa Ziehau 	STAILQ_ENTRY(hn_txdesc)		agg_link;
177dc13fee6SSepherosa Ziehau 
178dc13fee6SSepherosa Ziehau 	/* Aggregated txdescs, in sending order. */
179dc13fee6SSepherosa Ziehau 	STAILQ_HEAD(, hn_txdesc)	agg_list;
180dc13fee6SSepherosa Ziehau 
181dc13fee6SSepherosa Ziehau 	/* The oldest packet, if transmission aggregation happens. */
18215516c77SSepherosa Ziehau 	struct mbuf			*m;
18315516c77SSepherosa Ziehau 	struct hn_tx_ring		*txr;
18415516c77SSepherosa Ziehau 	int				refs;
18515516c77SSepherosa Ziehau 	uint32_t			flags;	/* HN_TXD_FLAG_ */
18615516c77SSepherosa Ziehau 	struct hn_nvs_sendctx		send_ctx;
18715516c77SSepherosa Ziehau 	uint32_t			chim_index;
18815516c77SSepherosa Ziehau 	int				chim_size;
18915516c77SSepherosa Ziehau 
19015516c77SSepherosa Ziehau 	bus_dmamap_t			data_dmap;
19115516c77SSepherosa Ziehau 
19215516c77SSepherosa Ziehau 	bus_addr_t			rndis_pkt_paddr;
19315516c77SSepherosa Ziehau 	struct rndis_packet_msg		*rndis_pkt;
19415516c77SSepherosa Ziehau 	bus_dmamap_t			rndis_pkt_dmap;
19515516c77SSepherosa Ziehau };
19615516c77SSepherosa Ziehau 
19715516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST		0x0001
19815516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP		0x0002
199dc13fee6SSepherosa Ziehau #define HN_TXD_FLAG_ONAGG		0x0004
20015516c77SSepherosa Ziehau 
20115516c77SSepherosa Ziehau struct hn_rxinfo {
20215516c77SSepherosa Ziehau 	uint32_t			vlan_info;
20315516c77SSepherosa Ziehau 	uint32_t			csum_info;
20415516c77SSepherosa Ziehau 	uint32_t			hash_info;
20515516c77SSepherosa Ziehau 	uint32_t			hash_value;
20615516c77SSepherosa Ziehau };
20715516c77SSepherosa Ziehau 
20815516c77SSepherosa Ziehau #define HN_RXINFO_VLAN			0x0001
20915516c77SSepherosa Ziehau #define HN_RXINFO_CSUM			0x0002
21015516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF		0x0004
21115516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL		0x0008
21215516c77SSepherosa Ziehau #define HN_RXINFO_ALL			\
21315516c77SSepherosa Ziehau 	(HN_RXINFO_VLAN |		\
21415516c77SSepherosa Ziehau 	 HN_RXINFO_CSUM |		\
21515516c77SSepherosa Ziehau 	 HN_RXINFO_HASHINF |		\
21615516c77SSepherosa Ziehau 	 HN_RXINFO_HASHVAL)
21715516c77SSepherosa Ziehau 
21815516c77SSepherosa Ziehau #define HN_NDIS_VLAN_INFO_INVALID	0xffffffff
21915516c77SSepherosa Ziehau #define HN_NDIS_RXCSUM_INFO_INVALID	0
22015516c77SSepherosa Ziehau #define HN_NDIS_HASH_INFO_INVALID	0
22115516c77SSepherosa Ziehau 
22215516c77SSepherosa Ziehau static int			hn_probe(device_t);
22315516c77SSepherosa Ziehau static int			hn_attach(device_t);
22415516c77SSepherosa Ziehau static int			hn_detach(device_t);
22515516c77SSepherosa Ziehau static int			hn_shutdown(device_t);
22615516c77SSepherosa Ziehau static void			hn_chan_callback(struct vmbus_channel *,
22715516c77SSepherosa Ziehau 				    void *);
22815516c77SSepherosa Ziehau 
22915516c77SSepherosa Ziehau static void			hn_init(void *);
23015516c77SSepherosa Ziehau static int			hn_ioctl(struct ifnet *, u_long, caddr_t);
23123bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
23215516c77SSepherosa Ziehau static void			hn_start(struct ifnet *);
23323bf9e15SSepherosa Ziehau #endif
23415516c77SSepherosa Ziehau static int			hn_transmit(struct ifnet *, struct mbuf *);
23515516c77SSepherosa Ziehau static void			hn_xmit_qflush(struct ifnet *);
23615516c77SSepherosa Ziehau static int			hn_ifmedia_upd(struct ifnet *);
23715516c77SSepherosa Ziehau static void			hn_ifmedia_sts(struct ifnet *,
23815516c77SSepherosa Ziehau 				    struct ifmediareq *);
23915516c77SSepherosa Ziehau 
24015516c77SSepherosa Ziehau static int			hn_rndis_rxinfo(const void *, int,
24115516c77SSepherosa Ziehau 				    struct hn_rxinfo *);
24215516c77SSepherosa Ziehau static void			hn_rndis_rx_data(struct hn_rx_ring *,
24315516c77SSepherosa Ziehau 				    const void *, int);
24415516c77SSepherosa Ziehau static void			hn_rndis_rx_status(struct hn_softc *,
24515516c77SSepherosa Ziehau 				    const void *, int);
24615516c77SSepherosa Ziehau 
24715516c77SSepherosa Ziehau static void			hn_nvs_handle_notify(struct hn_softc *,
24815516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
24915516c77SSepherosa Ziehau static void			hn_nvs_handle_comp(struct hn_softc *,
25015516c77SSepherosa Ziehau 				    struct vmbus_channel *,
25115516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
25215516c77SSepherosa Ziehau static void			hn_nvs_handle_rxbuf(struct hn_rx_ring *,
25315516c77SSepherosa Ziehau 				    struct vmbus_channel *,
25415516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
25515516c77SSepherosa Ziehau static void			hn_nvs_ack_rxbuf(struct hn_rx_ring *,
25615516c77SSepherosa Ziehau 				    struct vmbus_channel *, uint64_t);
25715516c77SSepherosa Ziehau 
25815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
25915516c77SSepherosa Ziehau static int			hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS);
26015516c77SSepherosa Ziehau static int			hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS);
26115516c77SSepherosa Ziehau #endif
26215516c77SSepherosa Ziehau static int			hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS);
26315516c77SSepherosa Ziehau static int			hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS);
26415516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
26515516c77SSepherosa Ziehau static int			hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS);
26615516c77SSepherosa Ziehau #else
26715516c77SSepherosa Ziehau static int			hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS);
26815516c77SSepherosa Ziehau #endif
26915516c77SSepherosa Ziehau static int			hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
27015516c77SSepherosa Ziehau static int			hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
27115516c77SSepherosa Ziehau static int			hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS);
27215516c77SSepherosa Ziehau static int			hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS);
27315516c77SSepherosa Ziehau static int			hn_caps_sysctl(SYSCTL_HANDLER_ARGS);
27415516c77SSepherosa Ziehau static int			hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS);
27515516c77SSepherosa Ziehau static int			hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS);
27615516c77SSepherosa Ziehau static int			hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS);
27715516c77SSepherosa Ziehau static int			hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS);
27815516c77SSepherosa Ziehau static int			hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS);
279dc13fee6SSepherosa Ziehau static int			hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS);
280dc13fee6SSepherosa Ziehau static int			hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS);
281dc13fee6SSepherosa Ziehau static int			hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS);
282dc13fee6SSepherosa Ziehau static int			hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS);
28315516c77SSepherosa Ziehau 
28415516c77SSepherosa Ziehau static void			hn_stop(struct hn_softc *);
28515516c77SSepherosa Ziehau static void			hn_init_locked(struct hn_softc *);
28615516c77SSepherosa Ziehau static int			hn_chan_attach(struct hn_softc *,
28715516c77SSepherosa Ziehau 				    struct vmbus_channel *);
28815516c77SSepherosa Ziehau static void			hn_chan_detach(struct hn_softc *,
28915516c77SSepherosa Ziehau 				    struct vmbus_channel *);
29015516c77SSepherosa Ziehau static int			hn_attach_subchans(struct hn_softc *);
29115516c77SSepherosa Ziehau static void			hn_detach_allchans(struct hn_softc *);
29215516c77SSepherosa Ziehau static void			hn_chan_rollup(struct hn_rx_ring *,
29315516c77SSepherosa Ziehau 				    struct hn_tx_ring *);
29415516c77SSepherosa Ziehau static void			hn_set_ring_inuse(struct hn_softc *, int);
29515516c77SSepherosa Ziehau static int			hn_synth_attach(struct hn_softc *, int);
29615516c77SSepherosa Ziehau static void			hn_synth_detach(struct hn_softc *);
29715516c77SSepherosa Ziehau static int			hn_synth_alloc_subchans(struct hn_softc *,
29815516c77SSepherosa Ziehau 				    int *);
29915516c77SSepherosa Ziehau static void			hn_suspend(struct hn_softc *);
30015516c77SSepherosa Ziehau static void			hn_suspend_data(struct hn_softc *);
30115516c77SSepherosa Ziehau static void			hn_suspend_mgmt(struct hn_softc *);
30215516c77SSepherosa Ziehau static void			hn_resume(struct hn_softc *);
30315516c77SSepherosa Ziehau static void			hn_resume_data(struct hn_softc *);
30415516c77SSepherosa Ziehau static void			hn_resume_mgmt(struct hn_softc *);
30515516c77SSepherosa Ziehau static void			hn_suspend_mgmt_taskfunc(void *, int);
30615516c77SSepherosa Ziehau static void			hn_chan_drain(struct vmbus_channel *);
30715516c77SSepherosa Ziehau 
30815516c77SSepherosa Ziehau static void			hn_update_link_status(struct hn_softc *);
30915516c77SSepherosa Ziehau static void			hn_change_network(struct hn_softc *);
31015516c77SSepherosa Ziehau static void			hn_link_taskfunc(void *, int);
31115516c77SSepherosa Ziehau static void			hn_netchg_init_taskfunc(void *, int);
31215516c77SSepherosa Ziehau static void			hn_netchg_status_taskfunc(void *, int);
31315516c77SSepherosa Ziehau static void			hn_link_status(struct hn_softc *);
31415516c77SSepherosa Ziehau 
31515516c77SSepherosa Ziehau static int			hn_create_rx_data(struct hn_softc *, int);
31615516c77SSepherosa Ziehau static void			hn_destroy_rx_data(struct hn_softc *);
31715516c77SSepherosa Ziehau static int			hn_check_iplen(const struct mbuf *, int);
31815516c77SSepherosa Ziehau static int			hn_set_rxfilter(struct hn_softc *);
31915516c77SSepherosa Ziehau static int			hn_rss_reconfig(struct hn_softc *);
32015516c77SSepherosa Ziehau static void			hn_rss_ind_fixup(struct hn_softc *, int);
32115516c77SSepherosa Ziehau static int			hn_rxpkt(struct hn_rx_ring *, const void *,
32215516c77SSepherosa Ziehau 				    int, const struct hn_rxinfo *);
32315516c77SSepherosa Ziehau 
32415516c77SSepherosa Ziehau static int			hn_tx_ring_create(struct hn_softc *, int);
32515516c77SSepherosa Ziehau static void			hn_tx_ring_destroy(struct hn_tx_ring *);
32615516c77SSepherosa Ziehau static int			hn_create_tx_data(struct hn_softc *, int);
32715516c77SSepherosa Ziehau static void			hn_fixup_tx_data(struct hn_softc *);
32815516c77SSepherosa Ziehau static void			hn_destroy_tx_data(struct hn_softc *);
32915516c77SSepherosa Ziehau static void			hn_txdesc_dmamap_destroy(struct hn_txdesc *);
330dc13fee6SSepherosa Ziehau static int			hn_encap(struct ifnet *, struct hn_tx_ring *,
33115516c77SSepherosa Ziehau 				    struct hn_txdesc *, struct mbuf **);
33215516c77SSepherosa Ziehau static int			hn_txpkt(struct ifnet *, struct hn_tx_ring *,
33315516c77SSepherosa Ziehau 				    struct hn_txdesc *);
33415516c77SSepherosa Ziehau static void			hn_set_chim_size(struct hn_softc *, int);
33515516c77SSepherosa Ziehau static void			hn_set_tso_maxsize(struct hn_softc *, int, int);
33615516c77SSepherosa Ziehau static bool			hn_tx_ring_pending(struct hn_tx_ring *);
33715516c77SSepherosa Ziehau static void			hn_tx_ring_qflush(struct hn_tx_ring *);
33815516c77SSepherosa Ziehau static void			hn_resume_tx(struct hn_softc *, int);
339dc13fee6SSepherosa Ziehau static void			hn_set_txagg(struct hn_softc *);
340dc13fee6SSepherosa Ziehau static void			*hn_try_txagg(struct ifnet *,
341dc13fee6SSepherosa Ziehau 				    struct hn_tx_ring *, struct hn_txdesc *,
342dc13fee6SSepherosa Ziehau 				    int);
34315516c77SSepherosa Ziehau static int			hn_get_txswq_depth(const struct hn_tx_ring *);
34415516c77SSepherosa Ziehau static void			hn_txpkt_done(struct hn_nvs_sendctx *,
34515516c77SSepherosa Ziehau 				    struct hn_softc *, struct vmbus_channel *,
34615516c77SSepherosa Ziehau 				    const void *, int);
34715516c77SSepherosa Ziehau static int			hn_txpkt_sglist(struct hn_tx_ring *,
34815516c77SSepherosa Ziehau 				    struct hn_txdesc *);
34915516c77SSepherosa Ziehau static int			hn_txpkt_chim(struct hn_tx_ring *,
35015516c77SSepherosa Ziehau 				    struct hn_txdesc *);
35115516c77SSepherosa Ziehau static int			hn_xmit(struct hn_tx_ring *, int);
35215516c77SSepherosa Ziehau static void			hn_xmit_taskfunc(void *, int);
35315516c77SSepherosa Ziehau static void			hn_xmit_txeof(struct hn_tx_ring *);
35415516c77SSepherosa Ziehau static void			hn_xmit_txeof_taskfunc(void *, int);
35523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
35615516c77SSepherosa Ziehau static int			hn_start_locked(struct hn_tx_ring *, int);
35715516c77SSepherosa Ziehau static void			hn_start_taskfunc(void *, int);
35815516c77SSepherosa Ziehau static void			hn_start_txeof(struct hn_tx_ring *);
35915516c77SSepherosa Ziehau static void			hn_start_txeof_taskfunc(void *, int);
36023bf9e15SSepherosa Ziehau #endif
36115516c77SSepherosa Ziehau 
36215516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
36315516c77SSepherosa Ziehau     "Hyper-V network interface");
36415516c77SSepherosa Ziehau 
36515516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */
36615516c77SSepherosa Ziehau static int			hn_trust_hosttcp = 1;
36715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN,
36815516c77SSepherosa Ziehau     &hn_trust_hosttcp, 0,
36915516c77SSepherosa Ziehau     "Trust tcp segement verification on host side, "
37015516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
37115516c77SSepherosa Ziehau 
37215516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */
37315516c77SSepherosa Ziehau static int			hn_trust_hostudp = 1;
37415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN,
37515516c77SSepherosa Ziehau     &hn_trust_hostudp, 0,
37615516c77SSepherosa Ziehau     "Trust udp datagram verification on host side, "
37715516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
37815516c77SSepherosa Ziehau 
37915516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */
38015516c77SSepherosa Ziehau static int			hn_trust_hostip = 1;
38115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN,
38215516c77SSepherosa Ziehau     &hn_trust_hostip, 0,
38315516c77SSepherosa Ziehau     "Trust ip packet verification on host side, "
38415516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
38515516c77SSepherosa Ziehau 
38615516c77SSepherosa Ziehau /* Limit TSO burst size */
38715516c77SSepherosa Ziehau static int			hn_tso_maxlen = IP_MAXPACKET;
38815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN,
38915516c77SSepherosa Ziehau     &hn_tso_maxlen, 0, "TSO burst limit");
39015516c77SSepherosa Ziehau 
39115516c77SSepherosa Ziehau /* Limit chimney send size */
39215516c77SSepherosa Ziehau static int			hn_tx_chimney_size = 0;
39315516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN,
39415516c77SSepherosa Ziehau     &hn_tx_chimney_size, 0, "Chimney send packet size limit");
39515516c77SSepherosa Ziehau 
39615516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */
39715516c77SSepherosa Ziehau static int			hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF;
39815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN,
39915516c77SSepherosa Ziehau     &hn_direct_tx_size, 0, "Size of the packet for direct transmission");
40015516c77SSepherosa Ziehau 
40115516c77SSepherosa Ziehau /* # of LRO entries per RX ring */
40215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
40315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
40415516c77SSepherosa Ziehau static int			hn_lro_entry_count = HN_LROENT_CNT_DEF;
40515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN,
40615516c77SSepherosa Ziehau     &hn_lro_entry_count, 0, "LRO entry count");
40715516c77SSepherosa Ziehau #endif
40815516c77SSepherosa Ziehau #endif
40915516c77SSepherosa Ziehau 
41015516c77SSepherosa Ziehau /* Use shared TX taskqueue */
41115516c77SSepherosa Ziehau static int			hn_share_tx_taskq = 0;
41215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, share_tx_taskq, CTLFLAG_RDTUN,
41315516c77SSepherosa Ziehau     &hn_share_tx_taskq, 0, "Enable shared TX taskqueue");
41415516c77SSepherosa Ziehau 
41515516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
41615516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 0;
41715516c77SSepherosa Ziehau #else
41815516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 1;
41915516c77SSepherosa Ziehau #endif
42015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD,
42115516c77SSepherosa Ziehau     &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors");
42215516c77SSepherosa Ziehau 
42315516c77SSepherosa Ziehau /* Bind TX taskqueue to the target CPU */
42415516c77SSepherosa Ziehau static int			hn_bind_tx_taskq = -1;
42515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, bind_tx_taskq, CTLFLAG_RDTUN,
42615516c77SSepherosa Ziehau     &hn_bind_tx_taskq, 0, "Bind TX taskqueue to the specified cpu");
42715516c77SSepherosa Ziehau 
42823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
42915516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */
43015516c77SSepherosa Ziehau static int			hn_use_if_start = 0;
43115516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN,
43215516c77SSepherosa Ziehau     &hn_use_if_start, 0, "Use if_start TX method");
43323bf9e15SSepherosa Ziehau #endif
43415516c77SSepherosa Ziehau 
43515516c77SSepherosa Ziehau /* # of channels to use */
43615516c77SSepherosa Ziehau static int			hn_chan_cnt = 0;
43715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN,
43815516c77SSepherosa Ziehau     &hn_chan_cnt, 0,
43915516c77SSepherosa Ziehau     "# of channels to use; each channel has one RX ring and one TX ring");
44015516c77SSepherosa Ziehau 
44115516c77SSepherosa Ziehau /* # of transmit rings to use */
44215516c77SSepherosa Ziehau static int			hn_tx_ring_cnt = 0;
44315516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN,
44415516c77SSepherosa Ziehau     &hn_tx_ring_cnt, 0, "# of TX rings to use");
44515516c77SSepherosa Ziehau 
44615516c77SSepherosa Ziehau /* Software TX ring deptch */
44715516c77SSepherosa Ziehau static int			hn_tx_swq_depth = 0;
44815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN,
44915516c77SSepherosa Ziehau     &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING");
45015516c77SSepherosa Ziehau 
45115516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */
45215516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
45315516c77SSepherosa Ziehau static u_int			hn_lro_mbufq_depth = 0;
45415516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN,
45515516c77SSepherosa Ziehau     &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue");
45615516c77SSepherosa Ziehau #endif
45715516c77SSepherosa Ziehau 
458dc13fee6SSepherosa Ziehau /* Packet transmission aggregation size limit */
459dc13fee6SSepherosa Ziehau static int			hn_tx_agg_size = -1;
460dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN,
461dc13fee6SSepherosa Ziehau     &hn_tx_agg_size, 0, "Packet transmission aggregation size limit");
462dc13fee6SSepherosa Ziehau 
463dc13fee6SSepherosa Ziehau /* Packet transmission aggregation count limit */
464dc13fee6SSepherosa Ziehau static int			hn_tx_agg_pkts = 0;
465dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN,
466dc13fee6SSepherosa Ziehau     &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit");
467dc13fee6SSepherosa Ziehau 
46815516c77SSepherosa Ziehau static u_int			hn_cpu_index;	/* next CPU for channel */
46915516c77SSepherosa Ziehau static struct taskqueue		*hn_tx_taskq;	/* shared TX taskqueue */
47015516c77SSepherosa Ziehau 
47115516c77SSepherosa Ziehau static const uint8_t
47215516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
47315516c77SSepherosa Ziehau 	0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
47415516c77SSepherosa Ziehau 	0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
47515516c77SSepherosa Ziehau 	0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
47615516c77SSepherosa Ziehau 	0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
47715516c77SSepherosa Ziehau 	0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
47815516c77SSepherosa Ziehau };
47915516c77SSepherosa Ziehau 
48015516c77SSepherosa Ziehau static device_method_t hn_methods[] = {
48115516c77SSepherosa Ziehau 	/* Device interface */
48215516c77SSepherosa Ziehau 	DEVMETHOD(device_probe,		hn_probe),
48315516c77SSepherosa Ziehau 	DEVMETHOD(device_attach,	hn_attach),
48415516c77SSepherosa Ziehau 	DEVMETHOD(device_detach,	hn_detach),
48515516c77SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	hn_shutdown),
48615516c77SSepherosa Ziehau 	DEVMETHOD_END
48715516c77SSepherosa Ziehau };
48815516c77SSepherosa Ziehau 
48915516c77SSepherosa Ziehau static driver_t hn_driver = {
49015516c77SSepherosa Ziehau 	"hn",
49115516c77SSepherosa Ziehau 	hn_methods,
49215516c77SSepherosa Ziehau 	sizeof(struct hn_softc)
49315516c77SSepherosa Ziehau };
49415516c77SSepherosa Ziehau 
49515516c77SSepherosa Ziehau static devclass_t hn_devclass;
49615516c77SSepherosa Ziehau 
49715516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0);
49815516c77SSepherosa Ziehau MODULE_VERSION(hn, 1);
49915516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1);
50015516c77SSepherosa Ziehau 
50115516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
50215516c77SSepherosa Ziehau static void
50315516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim)
50415516c77SSepherosa Ziehau {
50515516c77SSepherosa Ziehau 	int i;
50615516c77SSepherosa Ziehau 
50715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_inuse; ++i)
50815516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim;
50915516c77SSepherosa Ziehau }
51015516c77SSepherosa Ziehau #endif
51115516c77SSepherosa Ziehau 
51215516c77SSepherosa Ziehau static int
51315516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd)
51415516c77SSepherosa Ziehau {
51515516c77SSepherosa Ziehau 
51615516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
51715516c77SSepherosa Ziehau 	    txd->chim_size == 0, ("invalid rndis sglist txd"));
51815516c77SSepherosa Ziehau 	return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA,
51915516c77SSepherosa Ziehau 	    &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt));
52015516c77SSepherosa Ziehau }
52115516c77SSepherosa Ziehau 
52215516c77SSepherosa Ziehau static int
52315516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd)
52415516c77SSepherosa Ziehau {
52515516c77SSepherosa Ziehau 	struct hn_nvs_rndis rndis;
52615516c77SSepherosa Ziehau 
52715516c77SSepherosa Ziehau 	KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID &&
52815516c77SSepherosa Ziehau 	    txd->chim_size > 0, ("invalid rndis chim txd"));
52915516c77SSepherosa Ziehau 
53015516c77SSepherosa Ziehau 	rndis.nvs_type = HN_NVS_TYPE_RNDIS;
53115516c77SSepherosa Ziehau 	rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA;
53215516c77SSepherosa Ziehau 	rndis.nvs_chim_idx = txd->chim_index;
53315516c77SSepherosa Ziehau 	rndis.nvs_chim_sz = txd->chim_size;
53415516c77SSepherosa Ziehau 
53515516c77SSepherosa Ziehau 	return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC,
53615516c77SSepherosa Ziehau 	    &rndis, sizeof(rndis), &txd->send_ctx));
53715516c77SSepherosa Ziehau }
53815516c77SSepherosa Ziehau 
53915516c77SSepherosa Ziehau static __inline uint32_t
54015516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc)
54115516c77SSepherosa Ziehau {
54215516c77SSepherosa Ziehau 	int i, bmap_cnt = sc->hn_chim_bmap_cnt;
54315516c77SSepherosa Ziehau 	u_long *bmap = sc->hn_chim_bmap;
54415516c77SSepherosa Ziehau 	uint32_t ret = HN_NVS_CHIM_IDX_INVALID;
54515516c77SSepherosa Ziehau 
54615516c77SSepherosa Ziehau 	for (i = 0; i < bmap_cnt; ++i) {
54715516c77SSepherosa Ziehau 		int idx;
54815516c77SSepherosa Ziehau 
54915516c77SSepherosa Ziehau 		idx = ffsl(~bmap[i]);
55015516c77SSepherosa Ziehau 		if (idx == 0)
55115516c77SSepherosa Ziehau 			continue;
55215516c77SSepherosa Ziehau 
55315516c77SSepherosa Ziehau 		--idx; /* ffsl is 1-based */
55415516c77SSepherosa Ziehau 		KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt,
55515516c77SSepherosa Ziehau 		    ("invalid i %d and idx %d", i, idx));
55615516c77SSepherosa Ziehau 
55715516c77SSepherosa Ziehau 		if (atomic_testandset_long(&bmap[i], idx))
55815516c77SSepherosa Ziehau 			continue;
55915516c77SSepherosa Ziehau 
56015516c77SSepherosa Ziehau 		ret = i * LONG_BIT + idx;
56115516c77SSepherosa Ziehau 		break;
56215516c77SSepherosa Ziehau 	}
56315516c77SSepherosa Ziehau 	return (ret);
56415516c77SSepherosa Ziehau }
56515516c77SSepherosa Ziehau 
56615516c77SSepherosa Ziehau static __inline void
56715516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx)
56815516c77SSepherosa Ziehau {
56915516c77SSepherosa Ziehau 	u_long mask;
57015516c77SSepherosa Ziehau 	uint32_t idx;
57115516c77SSepherosa Ziehau 
57215516c77SSepherosa Ziehau 	idx = chim_idx / LONG_BIT;
57315516c77SSepherosa Ziehau 	KASSERT(idx < sc->hn_chim_bmap_cnt,
57415516c77SSepherosa Ziehau 	    ("invalid chimney index 0x%x", chim_idx));
57515516c77SSepherosa Ziehau 
57615516c77SSepherosa Ziehau 	mask = 1UL << (chim_idx % LONG_BIT);
57715516c77SSepherosa Ziehau 	KASSERT(sc->hn_chim_bmap[idx] & mask,
57815516c77SSepherosa Ziehau 	    ("index bitmap 0x%lx, chimney index %u, "
57915516c77SSepherosa Ziehau 	     "bitmap idx %d, bitmask 0x%lx",
58015516c77SSepherosa Ziehau 	     sc->hn_chim_bmap[idx], chim_idx, idx, mask));
58115516c77SSepherosa Ziehau 
58215516c77SSepherosa Ziehau 	atomic_clear_long(&sc->hn_chim_bmap[idx], mask);
58315516c77SSepherosa Ziehau }
58415516c77SSepherosa Ziehau 
585edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
586edd3f315SSepherosa Ziehau /*
587edd3f315SSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
588edd3f315SSepherosa Ziehau  */
589edd3f315SSepherosa Ziehau static __inline struct mbuf *
590edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head)
591edd3f315SSepherosa Ziehau {
592edd3f315SSepherosa Ziehau 	struct ether_vlan_header *evl;
593edd3f315SSepherosa Ziehau 	struct tcphdr *th;
594edd3f315SSepherosa Ziehau 	int ehlen;
595edd3f315SSepherosa Ziehau 
596edd3f315SSepherosa Ziehau 	KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable"));
597edd3f315SSepherosa Ziehau 
598edd3f315SSepherosa Ziehau #define PULLUP_HDR(m, len)				\
599edd3f315SSepherosa Ziehau do {							\
600edd3f315SSepherosa Ziehau 	if (__predict_false((m)->m_len < (len))) {	\
601edd3f315SSepherosa Ziehau 		(m) = m_pullup((m), (len));		\
602edd3f315SSepherosa Ziehau 		if ((m) == NULL)			\
603edd3f315SSepherosa Ziehau 			return (NULL);			\
604edd3f315SSepherosa Ziehau 	}						\
605edd3f315SSepherosa Ziehau } while (0)
606edd3f315SSepherosa Ziehau 
607edd3f315SSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
608edd3f315SSepherosa Ziehau 	evl = mtod(m_head, struct ether_vlan_header *);
609edd3f315SSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
610edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
611edd3f315SSepherosa Ziehau 	else
612edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
613edd3f315SSepherosa Ziehau 
614edd3f315SSepherosa Ziehau #ifdef INET
615edd3f315SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
616edd3f315SSepherosa Ziehau 		struct ip *ip;
617edd3f315SSepherosa Ziehau 		int iphlen;
618edd3f315SSepherosa Ziehau 
619edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
620edd3f315SSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
621edd3f315SSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
622edd3f315SSepherosa Ziehau 
623edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
624edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + iphlen);
625edd3f315SSepherosa Ziehau 
626edd3f315SSepherosa Ziehau 		ip->ip_len = 0;
627edd3f315SSepherosa Ziehau 		ip->ip_sum = 0;
628edd3f315SSepherosa Ziehau 		th->th_sum = in_pseudo(ip->ip_src.s_addr,
629edd3f315SSepherosa Ziehau 		    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
630edd3f315SSepherosa Ziehau 	}
631edd3f315SSepherosa Ziehau #endif
632edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET)
633edd3f315SSepherosa Ziehau 	else
634edd3f315SSepherosa Ziehau #endif
635edd3f315SSepherosa Ziehau #ifdef INET6
636edd3f315SSepherosa Ziehau 	{
637edd3f315SSepherosa Ziehau 		struct ip6_hdr *ip6;
638edd3f315SSepherosa Ziehau 
639edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
640edd3f315SSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
641edd3f315SSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP) {
642edd3f315SSepherosa Ziehau 			m_freem(m_head);
643edd3f315SSepherosa Ziehau 			return (NULL);
644edd3f315SSepherosa Ziehau 		}
645edd3f315SSepherosa Ziehau 
646edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
647edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + sizeof(*ip6));
648edd3f315SSepherosa Ziehau 
649edd3f315SSepherosa Ziehau 		ip6->ip6_plen = 0;
650edd3f315SSepherosa Ziehau 		th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
651edd3f315SSepherosa Ziehau 	}
652edd3f315SSepherosa Ziehau #endif
653edd3f315SSepherosa Ziehau 	return (m_head);
654edd3f315SSepherosa Ziehau 
655edd3f315SSepherosa Ziehau #undef PULLUP_HDR
656edd3f315SSepherosa Ziehau }
657edd3f315SSepherosa Ziehau #endif	/* INET6 || INET */
658edd3f315SSepherosa Ziehau 
65915516c77SSepherosa Ziehau static int
66015516c77SSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc)
66115516c77SSepherosa Ziehau {
66215516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
66315516c77SSepherosa Ziehau 	uint32_t filter;
66415516c77SSepherosa Ziehau 	int error = 0;
66515516c77SSepherosa Ziehau 
66615516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
66715516c77SSepherosa Ziehau 
66815516c77SSepherosa Ziehau 	if (ifp->if_flags & IFF_PROMISC) {
66915516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_PROMISCUOUS;
67015516c77SSepherosa Ziehau 	} else {
67115516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_DIRECTED;
67215516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_BROADCAST)
67315516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_BROADCAST;
67415516c77SSepherosa Ziehau 		/* TODO: support multicast list */
67515516c77SSepherosa Ziehau 		if ((ifp->if_flags & IFF_ALLMULTI) ||
67615516c77SSepherosa Ziehau 		    !TAILQ_EMPTY(&ifp->if_multiaddrs))
67715516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
67815516c77SSepherosa Ziehau 	}
67915516c77SSepherosa Ziehau 
68015516c77SSepherosa Ziehau 	if (sc->hn_rx_filter != filter) {
68115516c77SSepherosa Ziehau 		error = hn_rndis_set_rxfilter(sc, filter);
68215516c77SSepherosa Ziehau 		if (!error)
68315516c77SSepherosa Ziehau 			sc->hn_rx_filter = filter;
68415516c77SSepherosa Ziehau 	}
68515516c77SSepherosa Ziehau 	return (error);
68615516c77SSepherosa Ziehau }
68715516c77SSepherosa Ziehau 
688dc13fee6SSepherosa Ziehau static void
689dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc)
690dc13fee6SSepherosa Ziehau {
691dc13fee6SSepherosa Ziehau 	uint32_t size, pkts;
692dc13fee6SSepherosa Ziehau 	int i;
693dc13fee6SSepherosa Ziehau 
694dc13fee6SSepherosa Ziehau 	/*
695dc13fee6SSepherosa Ziehau 	 * Setup aggregation size.
696dc13fee6SSepherosa Ziehau 	 */
697dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_size < 0)
698dc13fee6SSepherosa Ziehau 		size = UINT32_MAX;
699dc13fee6SSepherosa Ziehau 	else
700dc13fee6SSepherosa Ziehau 		size = sc->hn_agg_size;
701dc13fee6SSepherosa Ziehau 
702dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_size < size)
703dc13fee6SSepherosa Ziehau 		size = sc->hn_rndis_agg_size;
704dc13fee6SSepherosa Ziehau 
705dc13fee6SSepherosa Ziehau 	if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) {
706dc13fee6SSepherosa Ziehau 		/* Disable */
707dc13fee6SSepherosa Ziehau 		size = 0;
708dc13fee6SSepherosa Ziehau 		pkts = 0;
709dc13fee6SSepherosa Ziehau 		goto done;
710dc13fee6SSepherosa Ziehau 	}
711dc13fee6SSepherosa Ziehau 
712dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'int'. */
713dc13fee6SSepherosa Ziehau 	if (size > INT_MAX)
714dc13fee6SSepherosa Ziehau 		size = INT_MAX;
715dc13fee6SSepherosa Ziehau 
716dc13fee6SSepherosa Ziehau 	/* NOTE: We only aggregate packets using chimney sending buffers. */
717dc13fee6SSepherosa Ziehau 	if (size > (uint32_t)sc->hn_chim_szmax)
718dc13fee6SSepherosa Ziehau 		size = sc->hn_chim_szmax;
719dc13fee6SSepherosa Ziehau 
720dc13fee6SSepherosa Ziehau 	/*
721dc13fee6SSepherosa Ziehau 	 * Setup aggregation packet count.
722dc13fee6SSepherosa Ziehau 	 */
723dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_pkts < 0)
724dc13fee6SSepherosa Ziehau 		pkts = UINT32_MAX;
725dc13fee6SSepherosa Ziehau 	else
726dc13fee6SSepherosa Ziehau 		pkts = sc->hn_agg_pkts;
727dc13fee6SSepherosa Ziehau 
728dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_pkts < pkts)
729dc13fee6SSepherosa Ziehau 		pkts = sc->hn_rndis_agg_pkts;
730dc13fee6SSepherosa Ziehau 
731dc13fee6SSepherosa Ziehau 	if (pkts <= 1) {
732dc13fee6SSepherosa Ziehau 		/* Disable */
733dc13fee6SSepherosa Ziehau 		size = 0;
734dc13fee6SSepherosa Ziehau 		pkts = 0;
735dc13fee6SSepherosa Ziehau 		goto done;
736dc13fee6SSepherosa Ziehau 	}
737dc13fee6SSepherosa Ziehau 
738dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
739dc13fee6SSepherosa Ziehau 	if (pkts > SHRT_MAX)
740dc13fee6SSepherosa Ziehau 		pkts = SHRT_MAX;
741dc13fee6SSepherosa Ziehau 
742dc13fee6SSepherosa Ziehau done:
743dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
744dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_align > SHRT_MAX) {
745dc13fee6SSepherosa Ziehau 		/* Disable */
746dc13fee6SSepherosa Ziehau 		size = 0;
747dc13fee6SSepherosa Ziehau 		pkts = 0;
748dc13fee6SSepherosa Ziehau 	}
749dc13fee6SSepherosa Ziehau 
750dc13fee6SSepherosa Ziehau 	if (bootverbose) {
751dc13fee6SSepherosa Ziehau 		if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n",
752dc13fee6SSepherosa Ziehau 		    size, pkts, sc->hn_rndis_agg_align);
753dc13fee6SSepherosa Ziehau 	}
754dc13fee6SSepherosa Ziehau 
755dc13fee6SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
756dc13fee6SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
757dc13fee6SSepherosa Ziehau 
758dc13fee6SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
759dc13fee6SSepherosa Ziehau 		txr->hn_agg_szmax = size;
760dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktmax = pkts;
761dc13fee6SSepherosa Ziehau 		txr->hn_agg_align = sc->hn_rndis_agg_align;
762dc13fee6SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
763dc13fee6SSepherosa Ziehau 	}
764dc13fee6SSepherosa Ziehau }
765dc13fee6SSepherosa Ziehau 
76615516c77SSepherosa Ziehau static int
76715516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr)
76815516c77SSepherosa Ziehau {
76915516c77SSepherosa Ziehau 
77015516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet"));
77115516c77SSepherosa Ziehau 	if (hn_tx_swq_depth < txr->hn_txdesc_cnt)
77215516c77SSepherosa Ziehau 		return txr->hn_txdesc_cnt;
77315516c77SSepherosa Ziehau 	return hn_tx_swq_depth;
77415516c77SSepherosa Ziehau }
77515516c77SSepherosa Ziehau 
77615516c77SSepherosa Ziehau static int
77715516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc)
77815516c77SSepherosa Ziehau {
77915516c77SSepherosa Ziehau 	int error;
78015516c77SSepherosa Ziehau 
78115516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
78215516c77SSepherosa Ziehau 
78315516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
78415516c77SSepherosa Ziehau 		return (ENXIO);
78515516c77SSepherosa Ziehau 
78615516c77SSepherosa Ziehau 	/*
78715516c77SSepherosa Ziehau 	 * Disable RSS first.
78815516c77SSepherosa Ziehau 	 *
78915516c77SSepherosa Ziehau 	 * NOTE:
79015516c77SSepherosa Ziehau 	 * Direct reconfiguration by setting the UNCHG flags does
79115516c77SSepherosa Ziehau 	 * _not_ work properly.
79215516c77SSepherosa Ziehau 	 */
79315516c77SSepherosa Ziehau 	if (bootverbose)
79415516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "disable RSS\n");
79515516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE);
79615516c77SSepherosa Ziehau 	if (error) {
79715516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS disable failed\n");
79815516c77SSepherosa Ziehau 		return (error);
79915516c77SSepherosa Ziehau 	}
80015516c77SSepherosa Ziehau 
80115516c77SSepherosa Ziehau 	/*
80215516c77SSepherosa Ziehau 	 * Reenable the RSS w/ the updated RSS key or indirect
80315516c77SSepherosa Ziehau 	 * table.
80415516c77SSepherosa Ziehau 	 */
80515516c77SSepherosa Ziehau 	if (bootverbose)
80615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "reconfig RSS\n");
80715516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
80815516c77SSepherosa Ziehau 	if (error) {
80915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS reconfig failed\n");
81015516c77SSepherosa Ziehau 		return (error);
81115516c77SSepherosa Ziehau 	}
81215516c77SSepherosa Ziehau 	return (0);
81315516c77SSepherosa Ziehau }
81415516c77SSepherosa Ziehau 
81515516c77SSepherosa Ziehau static void
81615516c77SSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc, int nchan)
81715516c77SSepherosa Ziehau {
81815516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
81915516c77SSepherosa Ziehau 	int i;
82015516c77SSepherosa Ziehau 
82115516c77SSepherosa Ziehau 	KASSERT(nchan > 1, ("invalid # of channels %d", nchan));
82215516c77SSepherosa Ziehau 
82315516c77SSepherosa Ziehau 	/*
82415516c77SSepherosa Ziehau 	 * Check indirect table to make sure that all channels in it
82515516c77SSepherosa Ziehau 	 * can be used.
82615516c77SSepherosa Ziehau 	 */
82715516c77SSepherosa Ziehau 	for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
82815516c77SSepherosa Ziehau 		if (rss->rss_ind[i] >= nchan) {
82915516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp,
83015516c77SSepherosa Ziehau 			    "RSS indirect table %d fixup: %u -> %d\n",
83115516c77SSepherosa Ziehau 			    i, rss->rss_ind[i], nchan - 1);
83215516c77SSepherosa Ziehau 			rss->rss_ind[i] = nchan - 1;
83315516c77SSepherosa Ziehau 		}
83415516c77SSepherosa Ziehau 	}
83515516c77SSepherosa Ziehau }
83615516c77SSepherosa Ziehau 
83715516c77SSepherosa Ziehau static int
83815516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused)
83915516c77SSepherosa Ziehau {
84015516c77SSepherosa Ziehau 
84115516c77SSepherosa Ziehau 	return EOPNOTSUPP;
84215516c77SSepherosa Ziehau }
84315516c77SSepherosa Ziehau 
84415516c77SSepherosa Ziehau static void
84515516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
84615516c77SSepherosa Ziehau {
84715516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
84815516c77SSepherosa Ziehau 
84915516c77SSepherosa Ziehau 	ifmr->ifm_status = IFM_AVALID;
85015516c77SSepherosa Ziehau 	ifmr->ifm_active = IFM_ETHER;
85115516c77SSepherosa Ziehau 
85215516c77SSepherosa Ziehau 	if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) {
85315516c77SSepherosa Ziehau 		ifmr->ifm_active |= IFM_NONE;
85415516c77SSepherosa Ziehau 		return;
85515516c77SSepherosa Ziehau 	}
85615516c77SSepherosa Ziehau 	ifmr->ifm_status |= IFM_ACTIVE;
85715516c77SSepherosa Ziehau 	ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
85815516c77SSepherosa Ziehau }
85915516c77SSepherosa Ziehau 
86015516c77SSepherosa Ziehau /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
86115516c77SSepherosa Ziehau static const struct hyperv_guid g_net_vsc_device_type = {
86215516c77SSepherosa Ziehau 	.hv_guid = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
86315516c77SSepherosa Ziehau 		0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E}
86415516c77SSepherosa Ziehau };
86515516c77SSepherosa Ziehau 
86615516c77SSepherosa Ziehau static int
86715516c77SSepherosa Ziehau hn_probe(device_t dev)
86815516c77SSepherosa Ziehau {
86915516c77SSepherosa Ziehau 
87015516c77SSepherosa Ziehau 	if (VMBUS_PROBE_GUID(device_get_parent(dev), dev,
87115516c77SSepherosa Ziehau 	    &g_net_vsc_device_type) == 0) {
87215516c77SSepherosa Ziehau 		device_set_desc(dev, "Hyper-V Network Interface");
87315516c77SSepherosa Ziehau 		return BUS_PROBE_DEFAULT;
87415516c77SSepherosa Ziehau 	}
87515516c77SSepherosa Ziehau 	return ENXIO;
87615516c77SSepherosa Ziehau }
87715516c77SSepherosa Ziehau 
87815516c77SSepherosa Ziehau static int
87915516c77SSepherosa Ziehau hn_attach(device_t dev)
88015516c77SSepherosa Ziehau {
88115516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
88215516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
88315516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
88415516c77SSepherosa Ziehau 	uint8_t eaddr[ETHER_ADDR_LEN];
88515516c77SSepherosa Ziehau 	struct ifnet *ifp = NULL;
88615516c77SSepherosa Ziehau 	int error, ring_cnt, tx_ring_cnt;
88715516c77SSepherosa Ziehau 
88815516c77SSepherosa Ziehau 	sc->hn_dev = dev;
88915516c77SSepherosa Ziehau 	sc->hn_prichan = vmbus_get_channel(dev);
89015516c77SSepherosa Ziehau 	HN_LOCK_INIT(sc);
89115516c77SSepherosa Ziehau 
89215516c77SSepherosa Ziehau 	/*
893dc13fee6SSepherosa Ziehau 	 * Initialize these tunables once.
894dc13fee6SSepherosa Ziehau 	 */
895dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = hn_tx_agg_size;
896dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = hn_tx_agg_pkts;
897dc13fee6SSepherosa Ziehau 
898dc13fee6SSepherosa Ziehau 	/*
89915516c77SSepherosa Ziehau 	 * Setup taskqueue for transmission.
90015516c77SSepherosa Ziehau 	 */
90115516c77SSepherosa Ziehau 	if (hn_tx_taskq == NULL) {
90215516c77SSepherosa Ziehau 		sc->hn_tx_taskq = taskqueue_create("hn_tx", M_WAITOK,
90315516c77SSepherosa Ziehau 		    taskqueue_thread_enqueue, &sc->hn_tx_taskq);
90415516c77SSepherosa Ziehau 		if (hn_bind_tx_taskq >= 0) {
90515516c77SSepherosa Ziehau 			int cpu = hn_bind_tx_taskq;
90615516c77SSepherosa Ziehau 			cpuset_t cpu_set;
90715516c77SSepherosa Ziehau 
90815516c77SSepherosa Ziehau 			if (cpu > mp_ncpus - 1)
90915516c77SSepherosa Ziehau 				cpu = mp_ncpus - 1;
91015516c77SSepherosa Ziehau 			CPU_SETOF(cpu, &cpu_set);
91115516c77SSepherosa Ziehau 			taskqueue_start_threads_cpuset(&sc->hn_tx_taskq, 1,
91215516c77SSepherosa Ziehau 			    PI_NET, &cpu_set, "%s tx",
91315516c77SSepherosa Ziehau 			    device_get_nameunit(dev));
91415516c77SSepherosa Ziehau 		} else {
91515516c77SSepherosa Ziehau 			taskqueue_start_threads(&sc->hn_tx_taskq, 1, PI_NET,
91615516c77SSepherosa Ziehau 			    "%s tx", device_get_nameunit(dev));
91715516c77SSepherosa Ziehau 		}
91815516c77SSepherosa Ziehau 	} else {
91915516c77SSepherosa Ziehau 		sc->hn_tx_taskq = hn_tx_taskq;
92015516c77SSepherosa Ziehau 	}
92115516c77SSepherosa Ziehau 
92215516c77SSepherosa Ziehau 	/*
92315516c77SSepherosa Ziehau 	 * Setup taskqueue for mangement tasks, e.g. link status.
92415516c77SSepherosa Ziehau 	 */
92515516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK,
92615516c77SSepherosa Ziehau 	    taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0);
92715516c77SSepherosa Ziehau 	taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
92815516c77SSepherosa Ziehau 	    device_get_nameunit(dev));
92915516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
93015516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc);
93115516c77SSepherosa Ziehau 	TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0,
93215516c77SSepherosa Ziehau 	    hn_netchg_status_taskfunc, sc);
93315516c77SSepherosa Ziehau 
93415516c77SSepherosa Ziehau 	/*
93515516c77SSepherosa Ziehau 	 * Allocate ifnet and setup its name earlier, so that if_printf
93615516c77SSepherosa Ziehau 	 * can be used by functions, which will be called after
93715516c77SSepherosa Ziehau 	 * ether_ifattach().
93815516c77SSepherosa Ziehau 	 */
93915516c77SSepherosa Ziehau 	ifp = sc->hn_ifp = if_alloc(IFT_ETHER);
94015516c77SSepherosa Ziehau 	ifp->if_softc = sc;
94115516c77SSepherosa Ziehau 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
94215516c77SSepherosa Ziehau 
94315516c77SSepherosa Ziehau 	/*
94415516c77SSepherosa Ziehau 	 * Initialize ifmedia earlier so that it can be unconditionally
94515516c77SSepherosa Ziehau 	 * destroyed, if error happened later on.
94615516c77SSepherosa Ziehau 	 */
94715516c77SSepherosa Ziehau 	ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts);
94815516c77SSepherosa Ziehau 
94915516c77SSepherosa Ziehau 	/*
95015516c77SSepherosa Ziehau 	 * Figure out the # of RX rings (ring_cnt) and the # of TX rings
95115516c77SSepherosa Ziehau 	 * to use (tx_ring_cnt).
95215516c77SSepherosa Ziehau 	 *
95315516c77SSepherosa Ziehau 	 * NOTE:
95415516c77SSepherosa Ziehau 	 * The # of RX rings to use is same as the # of channels to use.
95515516c77SSepherosa Ziehau 	 */
95615516c77SSepherosa Ziehau 	ring_cnt = hn_chan_cnt;
95715516c77SSepherosa Ziehau 	if (ring_cnt <= 0) {
95815516c77SSepherosa Ziehau 		/* Default */
95915516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
96015516c77SSepherosa Ziehau 		if (ring_cnt > HN_RING_CNT_DEF_MAX)
96115516c77SSepherosa Ziehau 			ring_cnt = HN_RING_CNT_DEF_MAX;
96215516c77SSepherosa Ziehau 	} else if (ring_cnt > mp_ncpus) {
96315516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
96415516c77SSepherosa Ziehau 	}
96515516c77SSepherosa Ziehau 
96615516c77SSepherosa Ziehau 	tx_ring_cnt = hn_tx_ring_cnt;
96715516c77SSepherosa Ziehau 	if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt)
96815516c77SSepherosa Ziehau 		tx_ring_cnt = ring_cnt;
96923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
97015516c77SSepherosa Ziehau 	if (hn_use_if_start) {
97115516c77SSepherosa Ziehau 		/* ifnet.if_start only needs one TX ring. */
97215516c77SSepherosa Ziehau 		tx_ring_cnt = 1;
97315516c77SSepherosa Ziehau 	}
97423bf9e15SSepherosa Ziehau #endif
97515516c77SSepherosa Ziehau 
97615516c77SSepherosa Ziehau 	/*
97715516c77SSepherosa Ziehau 	 * Set the leader CPU for channels.
97815516c77SSepherosa Ziehau 	 */
97915516c77SSepherosa Ziehau 	sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus;
98015516c77SSepherosa Ziehau 
98115516c77SSepherosa Ziehau 	/*
98215516c77SSepherosa Ziehau 	 * Create enough TX/RX rings, even if only limited number of
98315516c77SSepherosa Ziehau 	 * channels can be allocated.
98415516c77SSepherosa Ziehau 	 */
98515516c77SSepherosa Ziehau 	error = hn_create_tx_data(sc, tx_ring_cnt);
98615516c77SSepherosa Ziehau 	if (error)
98715516c77SSepherosa Ziehau 		goto failed;
98815516c77SSepherosa Ziehau 	error = hn_create_rx_data(sc, ring_cnt);
98915516c77SSepherosa Ziehau 	if (error)
99015516c77SSepherosa Ziehau 		goto failed;
99115516c77SSepherosa Ziehau 
99215516c77SSepherosa Ziehau 	/*
99315516c77SSepherosa Ziehau 	 * Create transaction context for NVS and RNDIS transactions.
99415516c77SSepherosa Ziehau 	 */
99515516c77SSepherosa Ziehau 	sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
99615516c77SSepherosa Ziehau 	    HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
99715516c77SSepherosa Ziehau 	if (sc->hn_xact == NULL)
99815516c77SSepherosa Ziehau 		goto failed;
99915516c77SSepherosa Ziehau 
100015516c77SSepherosa Ziehau 	/*
100115516c77SSepherosa Ziehau 	 * Attach the synthetic parts, i.e. NVS and RNDIS.
100215516c77SSepherosa Ziehau 	 */
100315516c77SSepherosa Ziehau 	error = hn_synth_attach(sc, ETHERMTU);
100415516c77SSepherosa Ziehau 	if (error)
100515516c77SSepherosa Ziehau 		goto failed;
100615516c77SSepherosa Ziehau 
100715516c77SSepherosa Ziehau 	error = hn_rndis_get_eaddr(sc, eaddr);
100815516c77SSepherosa Ziehau 	if (error)
100915516c77SSepherosa Ziehau 		goto failed;
101015516c77SSepherosa Ziehau 
101115516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
101215516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
101315516c77SSepherosa Ziehau 		/*
101415516c77SSepherosa Ziehau 		 * Reduce TCP segment aggregation limit for multiple
101515516c77SSepherosa Ziehau 		 * RX rings to increase ACK timeliness.
101615516c77SSepherosa Ziehau 		 */
101715516c77SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF);
101815516c77SSepherosa Ziehau 	}
101915516c77SSepherosa Ziehau #endif
102015516c77SSepherosa Ziehau 
102115516c77SSepherosa Ziehau 	/*
102215516c77SSepherosa Ziehau 	 * Fixup TX stuffs after synthetic parts are attached.
102315516c77SSepherosa Ziehau 	 */
102415516c77SSepherosa Ziehau 	hn_fixup_tx_data(sc);
102515516c77SSepherosa Ziehau 
102615516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
102715516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
102815516c77SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD,
102915516c77SSepherosa Ziehau 	    &sc->hn_nvs_ver, 0, "NVS version");
103015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version",
103115516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
103215516c77SSepherosa Ziehau 	    hn_ndis_version_sysctl, "A", "NDIS version");
103315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps",
103415516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
103515516c77SSepherosa Ziehau 	    hn_caps_sysctl, "A", "capabilities");
103615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist",
103715516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
103815516c77SSepherosa Ziehau 	    hn_hwassist_sysctl, "A", "hwassist");
103915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter",
104015516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
104115516c77SSepherosa Ziehau 	    hn_rxfilter_sysctl, "A", "rxfilter");
104215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash",
104315516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
104415516c77SSepherosa Ziehau 	    hn_rss_hash_sysctl, "A", "RSS hash");
104515516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size",
104615516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count");
104715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key",
104815516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
104915516c77SSepherosa Ziehau 	    hn_rss_key_sysctl, "IU", "RSS key");
105015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind",
105115516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
105215516c77SSepherosa Ziehau 	    hn_rss_ind_sysctl, "IU", "RSS indirect table");
1053dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size",
1054dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_size, 0,
1055dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation size limit");
1056dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts",
1057dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0,
1058dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation count limit");
1059dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align",
1060dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_align, 0,
1061dc13fee6SSepherosa Ziehau 	    "RNDIS packet transmission aggregation alignment");
1062dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size",
1063dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
1064dc13fee6SSepherosa Ziehau 	    hn_txagg_size_sysctl, "I",
1065dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation size, 0 -- disable, -1 -- auto");
1066dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts",
1067dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
1068dc13fee6SSepherosa Ziehau 	    hn_txagg_pkts_sysctl, "I",
1069dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation packets, "
1070dc13fee6SSepherosa Ziehau 	    "0 -- disable, -1 -- auto");
107115516c77SSepherosa Ziehau 
107215516c77SSepherosa Ziehau 	/*
107315516c77SSepherosa Ziehau 	 * Setup the ifmedia, which has been initialized earlier.
107415516c77SSepherosa Ziehau 	 */
107515516c77SSepherosa Ziehau 	ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL);
107615516c77SSepherosa Ziehau 	ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO);
107715516c77SSepherosa Ziehau 	/* XXX ifmedia_set really should do this for us */
107815516c77SSepherosa Ziehau 	sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media;
107915516c77SSepherosa Ziehau 
108015516c77SSepherosa Ziehau 	/*
108115516c77SSepherosa Ziehau 	 * Setup the ifnet for this interface.
108215516c77SSepherosa Ziehau 	 */
108315516c77SSepherosa Ziehau 
108415516c77SSepherosa Ziehau 	ifp->if_baudrate = IF_Gbps(10);
108515516c77SSepherosa Ziehau 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
108615516c77SSepherosa Ziehau 	ifp->if_ioctl = hn_ioctl;
108715516c77SSepherosa Ziehau 	ifp->if_init = hn_init;
108823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
108915516c77SSepherosa Ziehau 	if (hn_use_if_start) {
109015516c77SSepherosa Ziehau 		int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]);
109115516c77SSepherosa Ziehau 
109215516c77SSepherosa Ziehau 		ifp->if_start = hn_start;
109315516c77SSepherosa Ziehau 		IFQ_SET_MAXLEN(&ifp->if_snd, qdepth);
109415516c77SSepherosa Ziehau 		ifp->if_snd.ifq_drv_maxlen = qdepth - 1;
109515516c77SSepherosa Ziehau 		IFQ_SET_READY(&ifp->if_snd);
109623bf9e15SSepherosa Ziehau 	} else
109723bf9e15SSepherosa Ziehau #endif
109823bf9e15SSepherosa Ziehau 	{
109915516c77SSepherosa Ziehau 		ifp->if_transmit = hn_transmit;
110015516c77SSepherosa Ziehau 		ifp->if_qflush = hn_xmit_qflush;
110115516c77SSepherosa Ziehau 	}
110215516c77SSepherosa Ziehau 
110315516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO;
110415516c77SSepherosa Ziehau #ifdef foo
110515516c77SSepherosa Ziehau 	/* We can't diff IPv6 packets from IPv4 packets on RX path. */
110615516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM_IPV6;
110715516c77SSepherosa Ziehau #endif
110815516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_VLAN) {
110915516c77SSepherosa Ziehau 		/* XXX not sure about VLAN_MTU. */
111015516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
111115516c77SSepherosa Ziehau 	}
111215516c77SSepherosa Ziehau 
111315516c77SSepherosa Ziehau 	ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist;
111415516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP_MASK)
111515516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM;
111615516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP6_MASK)
111715516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM_IPV6;
111815516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO4) {
111915516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO4;
112015516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP_TSO;
112115516c77SSepherosa Ziehau 	}
112215516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO6) {
112315516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO6;
112415516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP6_TSO;
112515516c77SSepherosa Ziehau 	}
112615516c77SSepherosa Ziehau 
112715516c77SSepherosa Ziehau 	/* Enable all available capabilities by default. */
112815516c77SSepherosa Ziehau 	ifp->if_capenable = ifp->if_capabilities;
112915516c77SSepherosa Ziehau 
1130*7960e6baSSepherosa Ziehau 	/*
1131*7960e6baSSepherosa Ziehau 	 * Disable IPv6 TSO and TXCSUM by default, they still can
1132*7960e6baSSepherosa Ziehau 	 * be enabled through SIOCSIFCAP.
1133*7960e6baSSepherosa Ziehau 	 */
1134*7960e6baSSepherosa Ziehau 	ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
1135*7960e6baSSepherosa Ziehau 	ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO);
1136*7960e6baSSepherosa Ziehau 
113715516c77SSepherosa Ziehau 	if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) {
113815516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU);
113915516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX;
114015516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = PAGE_SIZE;
114115516c77SSepherosa Ziehau 	}
114215516c77SSepherosa Ziehau 
114315516c77SSepherosa Ziehau 	ether_ifattach(ifp, eaddr);
114415516c77SSepherosa Ziehau 
114515516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) {
114615516c77SSepherosa Ziehau 		if_printf(ifp, "TSO segcnt %u segsz %u\n",
114715516c77SSepherosa Ziehau 		    ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize);
114815516c77SSepherosa Ziehau 	}
114915516c77SSepherosa Ziehau 
115015516c77SSepherosa Ziehau 	/* Inform the upper layer about the long frame support. */
115115516c77SSepherosa Ziehau 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
115215516c77SSepherosa Ziehau 
115315516c77SSepherosa Ziehau 	/*
115415516c77SSepherosa Ziehau 	 * Kick off link status check.
115515516c77SSepherosa Ziehau 	 */
115615516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
115715516c77SSepherosa Ziehau 	hn_update_link_status(sc);
115815516c77SSepherosa Ziehau 
115915516c77SSepherosa Ziehau 	return (0);
116015516c77SSepherosa Ziehau failed:
116115516c77SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)
116215516c77SSepherosa Ziehau 		hn_synth_detach(sc);
116315516c77SSepherosa Ziehau 	hn_detach(dev);
116415516c77SSepherosa Ziehau 	return (error);
116515516c77SSepherosa Ziehau }
116615516c77SSepherosa Ziehau 
116715516c77SSepherosa Ziehau static int
116815516c77SSepherosa Ziehau hn_detach(device_t dev)
116915516c77SSepherosa Ziehau {
117015516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
117115516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
117215516c77SSepherosa Ziehau 
117315516c77SSepherosa Ziehau 	if (device_is_attached(dev)) {
117415516c77SSepherosa Ziehau 		HN_LOCK(sc);
117515516c77SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
117615516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
117715516c77SSepherosa Ziehau 				hn_stop(sc);
117815516c77SSepherosa Ziehau 			/*
117915516c77SSepherosa Ziehau 			 * NOTE:
118015516c77SSepherosa Ziehau 			 * hn_stop() only suspends data, so managment
118115516c77SSepherosa Ziehau 			 * stuffs have to be suspended manually here.
118215516c77SSepherosa Ziehau 			 */
118315516c77SSepherosa Ziehau 			hn_suspend_mgmt(sc);
118415516c77SSepherosa Ziehau 			hn_synth_detach(sc);
118515516c77SSepherosa Ziehau 		}
118615516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
118715516c77SSepherosa Ziehau 		ether_ifdetach(ifp);
118815516c77SSepherosa Ziehau 	}
118915516c77SSepherosa Ziehau 
119015516c77SSepherosa Ziehau 	ifmedia_removeall(&sc->hn_media);
119115516c77SSepherosa Ziehau 	hn_destroy_rx_data(sc);
119215516c77SSepherosa Ziehau 	hn_destroy_tx_data(sc);
119315516c77SSepherosa Ziehau 
119415516c77SSepherosa Ziehau 	if (sc->hn_tx_taskq != hn_tx_taskq)
119515516c77SSepherosa Ziehau 		taskqueue_free(sc->hn_tx_taskq);
119615516c77SSepherosa Ziehau 	taskqueue_free(sc->hn_mgmt_taskq0);
119715516c77SSepherosa Ziehau 
119815516c77SSepherosa Ziehau 	if (sc->hn_xact != NULL)
119915516c77SSepherosa Ziehau 		vmbus_xact_ctx_destroy(sc->hn_xact);
120015516c77SSepherosa Ziehau 
120115516c77SSepherosa Ziehau 	if_free(ifp);
120215516c77SSepherosa Ziehau 
120315516c77SSepherosa Ziehau 	HN_LOCK_DESTROY(sc);
120415516c77SSepherosa Ziehau 	return (0);
120515516c77SSepherosa Ziehau }
120615516c77SSepherosa Ziehau 
120715516c77SSepherosa Ziehau static int
120815516c77SSepherosa Ziehau hn_shutdown(device_t dev)
120915516c77SSepherosa Ziehau {
121015516c77SSepherosa Ziehau 
121115516c77SSepherosa Ziehau 	return (0);
121215516c77SSepherosa Ziehau }
121315516c77SSepherosa Ziehau 
121415516c77SSepherosa Ziehau static void
121515516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc)
121615516c77SSepherosa Ziehau {
121715516c77SSepherosa Ziehau 	uint32_t link_status;
121815516c77SSepherosa Ziehau 	int error;
121915516c77SSepherosa Ziehau 
122015516c77SSepherosa Ziehau 	error = hn_rndis_get_linkstatus(sc, &link_status);
122115516c77SSepherosa Ziehau 	if (error) {
122215516c77SSepherosa Ziehau 		/* XXX what to do? */
122315516c77SSepherosa Ziehau 		return;
122415516c77SSepherosa Ziehau 	}
122515516c77SSepherosa Ziehau 
122615516c77SSepherosa Ziehau 	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
122715516c77SSepherosa Ziehau 		sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
122815516c77SSepherosa Ziehau 	else
122915516c77SSepherosa Ziehau 		sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
123015516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp,
123115516c77SSepherosa Ziehau 	    (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ?
123215516c77SSepherosa Ziehau 	    LINK_STATE_UP : LINK_STATE_DOWN);
123315516c77SSepherosa Ziehau }
123415516c77SSepherosa Ziehau 
123515516c77SSepherosa Ziehau static void
123615516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused)
123715516c77SSepherosa Ziehau {
123815516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
123915516c77SSepherosa Ziehau 
124015516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
124115516c77SSepherosa Ziehau 		return;
124215516c77SSepherosa Ziehau 	hn_link_status(sc);
124315516c77SSepherosa Ziehau }
124415516c77SSepherosa Ziehau 
124515516c77SSepherosa Ziehau static void
124615516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused)
124715516c77SSepherosa Ziehau {
124815516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
124915516c77SSepherosa Ziehau 
125015516c77SSepherosa Ziehau 	/* Prevent any link status checks from running. */
125115516c77SSepherosa Ziehau 	sc->hn_link_flags |= HN_LINK_FLAG_NETCHG;
125215516c77SSepherosa Ziehau 
125315516c77SSepherosa Ziehau 	/*
125415516c77SSepherosa Ziehau 	 * Fake up a [link down --> link up] state change; 5 seconds
125515516c77SSepherosa Ziehau 	 * delay is used, which closely simulates miibus reaction
125615516c77SSepherosa Ziehau 	 * upon link down event.
125715516c77SSepherosa Ziehau 	 */
125815516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
125915516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
126015516c77SSepherosa Ziehau 	taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0,
126115516c77SSepherosa Ziehau 	    &sc->hn_netchg_status, 5 * hz);
126215516c77SSepherosa Ziehau }
126315516c77SSepherosa Ziehau 
126415516c77SSepherosa Ziehau static void
126515516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused)
126615516c77SSepherosa Ziehau {
126715516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
126815516c77SSepherosa Ziehau 
126915516c77SSepherosa Ziehau 	/* Re-allow link status checks. */
127015516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG;
127115516c77SSepherosa Ziehau 	hn_link_status(sc);
127215516c77SSepherosa Ziehau }
127315516c77SSepherosa Ziehau 
127415516c77SSepherosa Ziehau static void
127515516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc)
127615516c77SSepherosa Ziehau {
127715516c77SSepherosa Ziehau 
127815516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
127915516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
128015516c77SSepherosa Ziehau }
128115516c77SSepherosa Ziehau 
128215516c77SSepherosa Ziehau static void
128315516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc)
128415516c77SSepherosa Ziehau {
128515516c77SSepherosa Ziehau 
128615516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
128715516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init);
128815516c77SSepherosa Ziehau }
128915516c77SSepherosa Ziehau 
129015516c77SSepherosa Ziehau static __inline int
129115516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
129215516c77SSepherosa Ziehau     struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
129315516c77SSepherosa Ziehau {
129415516c77SSepherosa Ziehau 	struct mbuf *m = *m_head;
129515516c77SSepherosa Ziehau 	int error;
129615516c77SSepherosa Ziehau 
129715516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim"));
129815516c77SSepherosa Ziehau 
129915516c77SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap,
130015516c77SSepherosa Ziehau 	    m, segs, nsegs, BUS_DMA_NOWAIT);
130115516c77SSepherosa Ziehau 	if (error == EFBIG) {
130215516c77SSepherosa Ziehau 		struct mbuf *m_new;
130315516c77SSepherosa Ziehau 
130415516c77SSepherosa Ziehau 		m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX);
130515516c77SSepherosa Ziehau 		if (m_new == NULL)
130615516c77SSepherosa Ziehau 			return ENOBUFS;
130715516c77SSepherosa Ziehau 		else
130815516c77SSepherosa Ziehau 			*m_head = m = m_new;
130915516c77SSepherosa Ziehau 		txr->hn_tx_collapsed++;
131015516c77SSepherosa Ziehau 
131115516c77SSepherosa Ziehau 		error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag,
131215516c77SSepherosa Ziehau 		    txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT);
131315516c77SSepherosa Ziehau 	}
131415516c77SSepherosa Ziehau 	if (!error) {
131515516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap,
131615516c77SSepherosa Ziehau 		    BUS_DMASYNC_PREWRITE);
131715516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_DMAMAP;
131815516c77SSepherosa Ziehau 	}
131915516c77SSepherosa Ziehau 	return error;
132015516c77SSepherosa Ziehau }
132115516c77SSepherosa Ziehau 
132215516c77SSepherosa Ziehau static __inline int
132315516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd)
132415516c77SSepherosa Ziehau {
132515516c77SSepherosa Ziehau 
132615516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0,
132715516c77SSepherosa Ziehau 	    ("put an onlist txd %#x", txd->flags));
1328dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1329dc13fee6SSepherosa Ziehau 	    ("put an onagg txd %#x", txd->flags));
133015516c77SSepherosa Ziehau 
133115516c77SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
133215516c77SSepherosa Ziehau 	if (atomic_fetchadd_int(&txd->refs, -1) != 1)
133315516c77SSepherosa Ziehau 		return 0;
133415516c77SSepherosa Ziehau 
1335dc13fee6SSepherosa Ziehau 	if (!STAILQ_EMPTY(&txd->agg_list)) {
1336dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tmp_txd;
1337dc13fee6SSepherosa Ziehau 
1338dc13fee6SSepherosa Ziehau 		while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) {
1339dc13fee6SSepherosa Ziehau 			int freed;
1340dc13fee6SSepherosa Ziehau 
1341dc13fee6SSepherosa Ziehau 			KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list),
1342dc13fee6SSepherosa Ziehau 			    ("resursive aggregation on aggregated txdesc"));
1343dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG),
1344dc13fee6SSepherosa Ziehau 			    ("not aggregated txdesc"));
1345dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
1346dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc uses dmamap"));
1347dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
1348dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc consumes "
1349dc13fee6SSepherosa Ziehau 			     "chimney sending buffer"));
1350dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_size == 0,
1351dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc has non-zero "
1352dc13fee6SSepherosa Ziehau 			     "chimney sending size"));
1353dc13fee6SSepherosa Ziehau 
1354dc13fee6SSepherosa Ziehau 			STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link);
1355dc13fee6SSepherosa Ziehau 			tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG;
1356dc13fee6SSepherosa Ziehau 			freed = hn_txdesc_put(txr, tmp_txd);
1357dc13fee6SSepherosa Ziehau 			KASSERT(freed, ("failed to free aggregated txdesc"));
1358dc13fee6SSepherosa Ziehau 		}
1359dc13fee6SSepherosa Ziehau 	}
1360dc13fee6SSepherosa Ziehau 
136115516c77SSepherosa Ziehau 	if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) {
136215516c77SSepherosa Ziehau 		KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
136315516c77SSepherosa Ziehau 		    ("chim txd uses dmamap"));
136415516c77SSepherosa Ziehau 		hn_chim_free(txr->hn_sc, txd->chim_index);
136515516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
1366dc13fee6SSepherosa Ziehau 		txd->chim_size = 0;
136715516c77SSepherosa Ziehau 	} else if (txd->flags & HN_TXD_FLAG_DMAMAP) {
136815516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag,
136915516c77SSepherosa Ziehau 		    txd->data_dmap, BUS_DMASYNC_POSTWRITE);
137015516c77SSepherosa Ziehau 		bus_dmamap_unload(txr->hn_tx_data_dtag,
137115516c77SSepherosa Ziehau 		    txd->data_dmap);
137215516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_DMAMAP;
137315516c77SSepherosa Ziehau 	}
137415516c77SSepherosa Ziehau 
137515516c77SSepherosa Ziehau 	if (txd->m != NULL) {
137615516c77SSepherosa Ziehau 		m_freem(txd->m);
137715516c77SSepherosa Ziehau 		txd->m = NULL;
137815516c77SSepherosa Ziehau 	}
137915516c77SSepherosa Ziehau 
138015516c77SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONLIST;
138115516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
138215516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
138315516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_avail >= 0 &&
138415516c77SSepherosa Ziehau 	    txr->hn_txdesc_avail < txr->hn_txdesc_cnt,
138515516c77SSepherosa Ziehau 	    ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail));
138615516c77SSepherosa Ziehau 	txr->hn_txdesc_avail++;
138715516c77SSepherosa Ziehau 	SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
138815516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
138915516c77SSepherosa Ziehau #else
139015516c77SSepherosa Ziehau 	atomic_add_int(&txr->hn_txdesc_avail, 1);
139115516c77SSepherosa Ziehau 	buf_ring_enqueue(txr->hn_txdesc_br, txd);
139215516c77SSepherosa Ziehau #endif
139315516c77SSepherosa Ziehau 
139415516c77SSepherosa Ziehau 	return 1;
139515516c77SSepherosa Ziehau }
139615516c77SSepherosa Ziehau 
139715516c77SSepherosa Ziehau static __inline struct hn_txdesc *
139815516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr)
139915516c77SSepherosa Ziehau {
140015516c77SSepherosa Ziehau 	struct hn_txdesc *txd;
140115516c77SSepherosa Ziehau 
140215516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
140315516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
140415516c77SSepherosa Ziehau 	txd = SLIST_FIRST(&txr->hn_txlist);
140515516c77SSepherosa Ziehau 	if (txd != NULL) {
140615516c77SSepherosa Ziehau 		KASSERT(txr->hn_txdesc_avail > 0,
140715516c77SSepherosa Ziehau 		    ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail));
140815516c77SSepherosa Ziehau 		txr->hn_txdesc_avail--;
140915516c77SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&txr->hn_txlist, link);
141015516c77SSepherosa Ziehau 	}
141115516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
141215516c77SSepherosa Ziehau #else
141315516c77SSepherosa Ziehau 	txd = buf_ring_dequeue_sc(txr->hn_txdesc_br);
141415516c77SSepherosa Ziehau #endif
141515516c77SSepherosa Ziehau 
141615516c77SSepherosa Ziehau 	if (txd != NULL) {
141715516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
141815516c77SSepherosa Ziehau 		atomic_subtract_int(&txr->hn_txdesc_avail, 1);
141915516c77SSepherosa Ziehau #endif
142015516c77SSepherosa Ziehau 		KASSERT(txd->m == NULL && txd->refs == 0 &&
1421dc13fee6SSepherosa Ziehau 		    STAILQ_EMPTY(&txd->agg_list) &&
142215516c77SSepherosa Ziehau 		    txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
1423dc13fee6SSepherosa Ziehau 		    txd->chim_size == 0 &&
142415516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONLIST) &&
1425dc13fee6SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONAGG) == 0 &&
142615516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd"));
142715516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_ONLIST;
142815516c77SSepherosa Ziehau 		txd->refs = 1;
142915516c77SSepherosa Ziehau 	}
143015516c77SSepherosa Ziehau 	return txd;
143115516c77SSepherosa Ziehau }
143215516c77SSepherosa Ziehau 
143315516c77SSepherosa Ziehau static __inline void
143415516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd)
143515516c77SSepherosa Ziehau {
143615516c77SSepherosa Ziehau 
143715516c77SSepherosa Ziehau 	/* 0->1 transition will never work */
143815516c77SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid refs %d", txd->refs));
143915516c77SSepherosa Ziehau 	atomic_add_int(&txd->refs, 1);
144015516c77SSepherosa Ziehau }
144115516c77SSepherosa Ziehau 
1442dc13fee6SSepherosa Ziehau static __inline void
1443dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd)
1444dc13fee6SSepherosa Ziehau {
1445dc13fee6SSepherosa Ziehau 
1446dc13fee6SSepherosa Ziehau 	KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1447dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on aggregating txdesc"));
1448dc13fee6SSepherosa Ziehau 
1449dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1450dc13fee6SSepherosa Ziehau 	    ("already aggregated"));
1451dc13fee6SSepherosa Ziehau 	KASSERT(STAILQ_EMPTY(&txd->agg_list),
1452dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on to-be-aggregated txdesc"));
1453dc13fee6SSepherosa Ziehau 
1454dc13fee6SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONAGG;
1455dc13fee6SSepherosa Ziehau 	STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link);
1456dc13fee6SSepherosa Ziehau }
1457dc13fee6SSepherosa Ziehau 
145815516c77SSepherosa Ziehau static bool
145915516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr)
146015516c77SSepherosa Ziehau {
146115516c77SSepherosa Ziehau 	bool pending = false;
146215516c77SSepherosa Ziehau 
146315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
146415516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
146515516c77SSepherosa Ziehau 	if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt)
146615516c77SSepherosa Ziehau 		pending = true;
146715516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
146815516c77SSepherosa Ziehau #else
146915516c77SSepherosa Ziehau 	if (!buf_ring_full(txr->hn_txdesc_br))
147015516c77SSepherosa Ziehau 		pending = true;
147115516c77SSepherosa Ziehau #endif
147215516c77SSepherosa Ziehau 	return (pending);
147315516c77SSepherosa Ziehau }
147415516c77SSepherosa Ziehau 
147515516c77SSepherosa Ziehau static __inline void
147615516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr)
147715516c77SSepherosa Ziehau {
147815516c77SSepherosa Ziehau 	txr->hn_has_txeof = 0;
147915516c77SSepherosa Ziehau 	txr->hn_txeof(txr);
148015516c77SSepherosa Ziehau }
148115516c77SSepherosa Ziehau 
148215516c77SSepherosa Ziehau static void
148315516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc,
148415516c77SSepherosa Ziehau     struct vmbus_channel *chan, const void *data __unused, int dlen __unused)
148515516c77SSepherosa Ziehau {
148615516c77SSepherosa Ziehau 	struct hn_txdesc *txd = sndc->hn_cbarg;
148715516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
148815516c77SSepherosa Ziehau 
148915516c77SSepherosa Ziehau 	txr = txd->txr;
149015516c77SSepherosa Ziehau 	KASSERT(txr->hn_chan == chan,
149115516c77SSepherosa Ziehau 	    ("channel mismatch, on chan%u, should be chan%u",
149215516c77SSepherosa Ziehau 	     vmbus_chan_subidx(chan), vmbus_chan_subidx(txr->hn_chan)));
149315516c77SSepherosa Ziehau 
149415516c77SSepherosa Ziehau 	txr->hn_has_txeof = 1;
149515516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
149615516c77SSepherosa Ziehau 
149715516c77SSepherosa Ziehau 	++txr->hn_txdone_cnt;
149815516c77SSepherosa Ziehau 	if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) {
149915516c77SSepherosa Ziehau 		txr->hn_txdone_cnt = 0;
150015516c77SSepherosa Ziehau 		if (txr->hn_oactive)
150115516c77SSepherosa Ziehau 			hn_txeof(txr);
150215516c77SSepherosa Ziehau 	}
150315516c77SSepherosa Ziehau }
150415516c77SSepherosa Ziehau 
150515516c77SSepherosa Ziehau static void
150615516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
150715516c77SSepherosa Ziehau {
150815516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
150915516c77SSepherosa Ziehau 	tcp_lro_flush_all(&rxr->hn_lro);
151015516c77SSepherosa Ziehau #endif
151115516c77SSepherosa Ziehau 
151215516c77SSepherosa Ziehau 	/*
151315516c77SSepherosa Ziehau 	 * NOTE:
151415516c77SSepherosa Ziehau 	 * 'txr' could be NULL, if multiple channels and
151515516c77SSepherosa Ziehau 	 * ifnet.if_start method are enabled.
151615516c77SSepherosa Ziehau 	 */
151715516c77SSepherosa Ziehau 	if (txr == NULL || !txr->hn_has_txeof)
151815516c77SSepherosa Ziehau 		return;
151915516c77SSepherosa Ziehau 
152015516c77SSepherosa Ziehau 	txr->hn_txdone_cnt = 0;
152115516c77SSepherosa Ziehau 	hn_txeof(txr);
152215516c77SSepherosa Ziehau }
152315516c77SSepherosa Ziehau 
152415516c77SSepherosa Ziehau static __inline uint32_t
152515516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs)
152615516c77SSepherosa Ziehau {
152715516c77SSepherosa Ziehau 
152815516c77SSepherosa Ziehau 	KASSERT(ofs >= sizeof(struct rndis_packet_msg),
152915516c77SSepherosa Ziehau 	    ("invalid RNDIS packet msg offset %u", ofs));
153015516c77SSepherosa Ziehau 	return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset));
153115516c77SSepherosa Ziehau }
153215516c77SSepherosa Ziehau 
153315516c77SSepherosa Ziehau static __inline void *
153415516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
153515516c77SSepherosa Ziehau     size_t pi_dlen, uint32_t pi_type)
153615516c77SSepherosa Ziehau {
153715516c77SSepherosa Ziehau 	const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
153815516c77SSepherosa Ziehau 	struct rndis_pktinfo *pi;
153915516c77SSepherosa Ziehau 
154015516c77SSepherosa Ziehau 	KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
154115516c77SSepherosa Ziehau 	    ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
154215516c77SSepherosa Ziehau 
154315516c77SSepherosa Ziehau 	/*
154415516c77SSepherosa Ziehau 	 * Per-packet-info does not move; it only grows.
154515516c77SSepherosa Ziehau 	 *
154615516c77SSepherosa Ziehau 	 * NOTE:
154715516c77SSepherosa Ziehau 	 * rm_pktinfooffset in this phase counts from the beginning
154815516c77SSepherosa Ziehau 	 * of rndis_packet_msg.
154915516c77SSepherosa Ziehau 	 */
155015516c77SSepherosa Ziehau 	KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
155115516c77SSepherosa Ziehau 	    ("%u pktinfo overflows RNDIS packet msg", pi_type));
155215516c77SSepherosa Ziehau 	pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
155315516c77SSepherosa Ziehau 	    pkt->rm_pktinfolen);
155415516c77SSepherosa Ziehau 	pkt->rm_pktinfolen += pi_size;
155515516c77SSepherosa Ziehau 
155615516c77SSepherosa Ziehau 	pi->rm_size = pi_size;
155715516c77SSepherosa Ziehau 	pi->rm_type = pi_type;
155815516c77SSepherosa Ziehau 	pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
155915516c77SSepherosa Ziehau 
156015516c77SSepherosa Ziehau 	/* Data immediately follow per-packet-info. */
156115516c77SSepherosa Ziehau 	pkt->rm_dataoffset += pi_size;
156215516c77SSepherosa Ziehau 
156315516c77SSepherosa Ziehau 	/* Update RNDIS packet msg length */
156415516c77SSepherosa Ziehau 	pkt->rm_len += pi_size;
156515516c77SSepherosa Ziehau 
156615516c77SSepherosa Ziehau 	return (pi->rm_data);
156715516c77SSepherosa Ziehau }
156815516c77SSepherosa Ziehau 
1569dc13fee6SSepherosa Ziehau static __inline int
1570dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr)
1571dc13fee6SSepherosa Ziehau {
1572dc13fee6SSepherosa Ziehau 	struct hn_txdesc *txd;
1573dc13fee6SSepherosa Ziehau 	struct mbuf *m;
1574dc13fee6SSepherosa Ziehau 	int error, pkts;
1575dc13fee6SSepherosa Ziehau 
1576dc13fee6SSepherosa Ziehau 	txd = txr->hn_agg_txd;
1577dc13fee6SSepherosa Ziehau 	KASSERT(txd != NULL, ("no aggregate txdesc"));
1578dc13fee6SSepherosa Ziehau 
1579dc13fee6SSepherosa Ziehau 	/*
1580dc13fee6SSepherosa Ziehau 	 * Since hn_txpkt() will reset this temporary stat, save
1581dc13fee6SSepherosa Ziehau 	 * it now, so that oerrors can be updated properly, if
1582dc13fee6SSepherosa Ziehau 	 * hn_txpkt() ever fails.
1583dc13fee6SSepherosa Ziehau 	 */
1584dc13fee6SSepherosa Ziehau 	pkts = txr->hn_stat_pkts;
1585dc13fee6SSepherosa Ziehau 
1586dc13fee6SSepherosa Ziehau 	/*
1587dc13fee6SSepherosa Ziehau 	 * Since txd's mbuf will _not_ be freed upon hn_txpkt()
1588dc13fee6SSepherosa Ziehau 	 * failure, save it for later freeing, if hn_txpkt() ever
1589dc13fee6SSepherosa Ziehau 	 * fails.
1590dc13fee6SSepherosa Ziehau 	 */
1591dc13fee6SSepherosa Ziehau 	m = txd->m;
1592dc13fee6SSepherosa Ziehau 	error = hn_txpkt(ifp, txr, txd);
1593dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
1594dc13fee6SSepherosa Ziehau 		/* txd is freed, but m is not. */
1595dc13fee6SSepherosa Ziehau 		m_freem(m);
1596dc13fee6SSepherosa Ziehau 
1597dc13fee6SSepherosa Ziehau 		txr->hn_flush_failed++;
1598dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts);
1599dc13fee6SSepherosa Ziehau 	}
1600dc13fee6SSepherosa Ziehau 
1601dc13fee6SSepherosa Ziehau 	/* Reset all aggregation states. */
1602dc13fee6SSepherosa Ziehau 	txr->hn_agg_txd = NULL;
1603dc13fee6SSepherosa Ziehau 	txr->hn_agg_szleft = 0;
1604dc13fee6SSepherosa Ziehau 	txr->hn_agg_pktleft = 0;
1605dc13fee6SSepherosa Ziehau 	txr->hn_agg_prevpkt = NULL;
1606dc13fee6SSepherosa Ziehau 
1607dc13fee6SSepherosa Ziehau 	return (error);
1608dc13fee6SSepherosa Ziehau }
1609dc13fee6SSepherosa Ziehau 
1610dc13fee6SSepherosa Ziehau static void *
1611dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
1612dc13fee6SSepherosa Ziehau     int pktsize)
1613dc13fee6SSepherosa Ziehau {
1614dc13fee6SSepherosa Ziehau 	void *chim;
1615dc13fee6SSepherosa Ziehau 
1616dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL) {
1617dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) {
1618dc13fee6SSepherosa Ziehau 			struct hn_txdesc *agg_txd = txr->hn_agg_txd;
1619dc13fee6SSepherosa Ziehau 			struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt;
1620dc13fee6SSepherosa Ziehau 			int olen;
1621dc13fee6SSepherosa Ziehau 
1622dc13fee6SSepherosa Ziehau 			/*
1623dc13fee6SSepherosa Ziehau 			 * Update the previous RNDIS packet's total length,
1624dc13fee6SSepherosa Ziehau 			 * it can be increased due to the mandatory alignment
1625dc13fee6SSepherosa Ziehau 			 * padding for this RNDIS packet.  And update the
1626dc13fee6SSepherosa Ziehau 			 * aggregating txdesc's chimney sending buffer size
1627dc13fee6SSepherosa Ziehau 			 * accordingly.
1628dc13fee6SSepherosa Ziehau 			 *
1629dc13fee6SSepherosa Ziehau 			 * XXX
1630dc13fee6SSepherosa Ziehau 			 * Zero-out the padding, as required by the RNDIS spec.
1631dc13fee6SSepherosa Ziehau 			 */
1632dc13fee6SSepherosa Ziehau 			olen = pkt->rm_len;
1633dc13fee6SSepherosa Ziehau 			pkt->rm_len = roundup2(olen, txr->hn_agg_align);
1634dc13fee6SSepherosa Ziehau 			agg_txd->chim_size += pkt->rm_len - olen;
1635dc13fee6SSepherosa Ziehau 
1636dc13fee6SSepherosa Ziehau 			/* Link this txdesc to the parent. */
1637dc13fee6SSepherosa Ziehau 			hn_txdesc_agg(agg_txd, txd);
1638dc13fee6SSepherosa Ziehau 
1639dc13fee6SSepherosa Ziehau 			chim = (uint8_t *)pkt + pkt->rm_len;
1640dc13fee6SSepherosa Ziehau 			/* Save the current packet for later fixup. */
1641dc13fee6SSepherosa Ziehau 			txr->hn_agg_prevpkt = chim;
1642dc13fee6SSepherosa Ziehau 
1643dc13fee6SSepherosa Ziehau 			txr->hn_agg_pktleft--;
1644dc13fee6SSepherosa Ziehau 			txr->hn_agg_szleft -= pktsize;
1645dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_szleft <=
1646dc13fee6SSepherosa Ziehau 			    HN_PKTSIZE_MIN(txr->hn_agg_align)) {
1647dc13fee6SSepherosa Ziehau 				/*
1648dc13fee6SSepherosa Ziehau 				 * Probably can't aggregate more packets,
1649dc13fee6SSepherosa Ziehau 				 * flush this aggregating txdesc proactively.
1650dc13fee6SSepherosa Ziehau 				 */
1651dc13fee6SSepherosa Ziehau 				txr->hn_agg_pktleft = 0;
1652dc13fee6SSepherosa Ziehau 			}
1653dc13fee6SSepherosa Ziehau 			/* Done! */
1654dc13fee6SSepherosa Ziehau 			return (chim);
1655dc13fee6SSepherosa Ziehau 		}
1656dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
1657dc13fee6SSepherosa Ziehau 	}
1658dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
1659dc13fee6SSepherosa Ziehau 
1660dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney_tried++;
1661dc13fee6SSepherosa Ziehau 	txd->chim_index = hn_chim_alloc(txr->hn_sc);
1662dc13fee6SSepherosa Ziehau 	if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID)
1663dc13fee6SSepherosa Ziehau 		return (NULL);
1664dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney++;
1665dc13fee6SSepherosa Ziehau 
1666dc13fee6SSepherosa Ziehau 	chim = txr->hn_sc->hn_chim +
1667dc13fee6SSepherosa Ziehau 	    (txd->chim_index * txr->hn_sc->hn_chim_szmax);
1668dc13fee6SSepherosa Ziehau 
1669dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_pktmax > 1 &&
1670dc13fee6SSepherosa Ziehau 	    txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) {
1671dc13fee6SSepherosa Ziehau 		txr->hn_agg_txd = txd;
1672dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1;
1673dc13fee6SSepherosa Ziehau 		txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize;
1674dc13fee6SSepherosa Ziehau 		txr->hn_agg_prevpkt = chim;
1675dc13fee6SSepherosa Ziehau 	}
1676dc13fee6SSepherosa Ziehau 	return (chim);
1677dc13fee6SSepherosa Ziehau }
1678dc13fee6SSepherosa Ziehau 
167915516c77SSepherosa Ziehau /*
168015516c77SSepherosa Ziehau  * NOTE:
168115516c77SSepherosa Ziehau  * If this function fails, then both txd and m_head0 will be freed.
168215516c77SSepherosa Ziehau  */
168315516c77SSepherosa Ziehau static int
1684dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
1685dc13fee6SSepherosa Ziehau     struct mbuf **m_head0)
168615516c77SSepherosa Ziehau {
168715516c77SSepherosa Ziehau 	bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX];
168815516c77SSepherosa Ziehau 	int error, nsegs, i;
168915516c77SSepherosa Ziehau 	struct mbuf *m_head = *m_head0;
169015516c77SSepherosa Ziehau 	struct rndis_packet_msg *pkt;
169115516c77SSepherosa Ziehau 	uint32_t *pi_data;
16928966e5d5SSepherosa Ziehau 	void *chim = NULL;
1693dc13fee6SSepherosa Ziehau 	int pkt_hlen, pkt_size;
169415516c77SSepherosa Ziehau 
169515516c77SSepherosa Ziehau 	pkt = txd->rndis_pkt;
1696dc13fee6SSepherosa Ziehau 	pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align);
1697dc13fee6SSepherosa Ziehau 	if (pkt_size < txr->hn_chim_size) {
1698dc13fee6SSepherosa Ziehau 		chim = hn_try_txagg(ifp, txr, txd, pkt_size);
1699dc13fee6SSepherosa Ziehau 		if (chim != NULL)
17008966e5d5SSepherosa Ziehau 			pkt = chim;
1701dc13fee6SSepherosa Ziehau 	} else {
1702dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL)
1703dc13fee6SSepherosa Ziehau 			hn_flush_txagg(ifp, txr);
17048966e5d5SSepherosa Ziehau 	}
17058966e5d5SSepherosa Ziehau 
170615516c77SSepherosa Ziehau 	pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
170715516c77SSepherosa Ziehau 	pkt->rm_len = sizeof(*pkt) + m_head->m_pkthdr.len;
170815516c77SSepherosa Ziehau 	pkt->rm_dataoffset = sizeof(*pkt);
170915516c77SSepherosa Ziehau 	pkt->rm_datalen = m_head->m_pkthdr.len;
1710dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataoffset = 0;
1711dc13fee6SSepherosa Ziehau 	pkt->rm_oobdatalen = 0;
1712dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataelements = 0;
171315516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = sizeof(*pkt);
171415516c77SSepherosa Ziehau 	pkt->rm_pktinfolen = 0;
1715dc13fee6SSepherosa Ziehau 	pkt->rm_vchandle = 0;
1716dc13fee6SSepherosa Ziehau 	pkt->rm_reserved = 0;
171715516c77SSepherosa Ziehau 
171815516c77SSepherosa Ziehau 	if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) {
171915516c77SSepherosa Ziehau 		/*
172015516c77SSepherosa Ziehau 		 * Set the hash value for this packet, so that the host could
172115516c77SSepherosa Ziehau 		 * dispatch the TX done event for this packet back to this TX
172215516c77SSepherosa Ziehau 		 * ring's channel.
172315516c77SSepherosa Ziehau 		 */
172415516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
172515516c77SSepherosa Ziehau 		    HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL);
172615516c77SSepherosa Ziehau 		*pi_data = txr->hn_tx_idx;
172715516c77SSepherosa Ziehau 	}
172815516c77SSepherosa Ziehau 
172915516c77SSepherosa Ziehau 	if (m_head->m_flags & M_VLANTAG) {
173015516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
173115516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
173215516c77SSepherosa Ziehau 		*pi_data = NDIS_VLAN_INFO_MAKE(
173315516c77SSepherosa Ziehau 		    EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag),
173415516c77SSepherosa Ziehau 		    EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag),
173515516c77SSepherosa Ziehau 		    EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag));
173615516c77SSepherosa Ziehau 	}
173715516c77SSepherosa Ziehau 
173815516c77SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
173915516c77SSepherosa Ziehau #if defined(INET6) || defined(INET)
174015516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
174115516c77SSepherosa Ziehau 		    NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO);
174215516c77SSepherosa Ziehau #ifdef INET
174315516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
174415516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV4(0,
174515516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
174615516c77SSepherosa Ziehau 		}
174715516c77SSepherosa Ziehau #endif
174815516c77SSepherosa Ziehau #if defined(INET6) && defined(INET)
174915516c77SSepherosa Ziehau 		else
175015516c77SSepherosa Ziehau #endif
175115516c77SSepherosa Ziehau #ifdef INET6
175215516c77SSepherosa Ziehau 		{
175315516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV6(0,
175415516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
175515516c77SSepherosa Ziehau 		}
175615516c77SSepherosa Ziehau #endif
175715516c77SSepherosa Ziehau #endif	/* INET6 || INET */
175815516c77SSepherosa Ziehau 	} else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) {
175915516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
176015516c77SSepherosa Ziehau 		    NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
176115516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
176215516c77SSepherosa Ziehau 		    (CSUM_IP6_TCP | CSUM_IP6_UDP)) {
176315516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV6;
176415516c77SSepherosa Ziehau 		} else {
176515516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV4;
176615516c77SSepherosa Ziehau 			if (m_head->m_pkthdr.csum_flags & CSUM_IP)
176715516c77SSepherosa Ziehau 				*pi_data |= NDIS_TXCSUM_INFO_IPCS;
176815516c77SSepherosa Ziehau 		}
176915516c77SSepherosa Ziehau 
177015516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP))
177115516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_TCPCS;
177215516c77SSepherosa Ziehau 		else if (m_head->m_pkthdr.csum_flags &
177315516c77SSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP6_UDP))
177415516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_UDPCS;
177515516c77SSepherosa Ziehau 	}
177615516c77SSepherosa Ziehau 
1777dc13fee6SSepherosa Ziehau 	pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
177815516c77SSepherosa Ziehau 	/* Convert RNDIS packet message offsets */
177915516c77SSepherosa Ziehau 	pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt->rm_dataoffset);
178015516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset);
178115516c77SSepherosa Ziehau 
178215516c77SSepherosa Ziehau 	/*
17838966e5d5SSepherosa Ziehau 	 * Fast path: Chimney sending.
178415516c77SSepherosa Ziehau 	 */
17858966e5d5SSepherosa Ziehau 	if (chim != NULL) {
1786dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tgt_txd = txd;
1787dc13fee6SSepherosa Ziehau 
1788dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL) {
1789dc13fee6SSepherosa Ziehau 			tgt_txd = txr->hn_agg_txd;
1790dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
1791dc13fee6SSepherosa Ziehau 			*m_head0 = NULL;
1792dc13fee6SSepherosa Ziehau #endif
1793dc13fee6SSepherosa Ziehau 		}
1794dc13fee6SSepherosa Ziehau 
1795dc13fee6SSepherosa Ziehau 		KASSERT(pkt == chim,
1796dc13fee6SSepherosa Ziehau 		    ("RNDIS pkt not in chimney sending buffer"));
1797dc13fee6SSepherosa Ziehau 		KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID,
1798dc13fee6SSepherosa Ziehau 		    ("chimney sending buffer is not used"));
1799dc13fee6SSepherosa Ziehau 		tgt_txd->chim_size += pkt->rm_len;
180015516c77SSepherosa Ziehau 
18018966e5d5SSepherosa Ziehau 		m_copydata(m_head, 0, m_head->m_pkthdr.len,
1802dc13fee6SSepherosa Ziehau 		    ((uint8_t *)chim) + pkt_hlen);
180315516c77SSepherosa Ziehau 
180415516c77SSepherosa Ziehau 		txr->hn_gpa_cnt = 0;
180515516c77SSepherosa Ziehau 		txr->hn_sendpkt = hn_txpkt_chim;
180615516c77SSepherosa Ziehau 		goto done;
180715516c77SSepherosa Ziehau 	}
1808dc13fee6SSepherosa Ziehau 
1809dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc"));
18108966e5d5SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
18118966e5d5SSepherosa Ziehau 	    ("chimney buffer is used"));
18128966e5d5SSepherosa Ziehau 	KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc"));
181315516c77SSepherosa Ziehau 
181415516c77SSepherosa Ziehau 	error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs);
1815dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
181615516c77SSepherosa Ziehau 		int freed;
181715516c77SSepherosa Ziehau 
181815516c77SSepherosa Ziehau 		/*
181915516c77SSepherosa Ziehau 		 * This mbuf is not linked w/ the txd yet, so free it now.
182015516c77SSepherosa Ziehau 		 */
182115516c77SSepherosa Ziehau 		m_freem(m_head);
182215516c77SSepherosa Ziehau 		*m_head0 = NULL;
182315516c77SSepherosa Ziehau 
182415516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
182515516c77SSepherosa Ziehau 		KASSERT(freed != 0,
182615516c77SSepherosa Ziehau 		    ("fail to free txd upon txdma error"));
182715516c77SSepherosa Ziehau 
182815516c77SSepherosa Ziehau 		txr->hn_txdma_failed++;
1829dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
183015516c77SSepherosa Ziehau 		return error;
183115516c77SSepherosa Ziehau 	}
183215516c77SSepherosa Ziehau 	*m_head0 = m_head;
183315516c77SSepherosa Ziehau 
183415516c77SSepherosa Ziehau 	/* +1 RNDIS packet message */
183515516c77SSepherosa Ziehau 	txr->hn_gpa_cnt = nsegs + 1;
183615516c77SSepherosa Ziehau 
183715516c77SSepherosa Ziehau 	/* send packet with page buffer */
183815516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr);
183915516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK;
1840dc13fee6SSepherosa Ziehau 	txr->hn_gpa[0].gpa_len = pkt_hlen;
184115516c77SSepherosa Ziehau 
184215516c77SSepherosa Ziehau 	/*
184315516c77SSepherosa Ziehau 	 * Fill the page buffers with mbuf info after the page
184415516c77SSepherosa Ziehau 	 * buffer for RNDIS packet message.
184515516c77SSepherosa Ziehau 	 */
184615516c77SSepherosa Ziehau 	for (i = 0; i < nsegs; ++i) {
184715516c77SSepherosa Ziehau 		struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1];
184815516c77SSepherosa Ziehau 
184915516c77SSepherosa Ziehau 		gpa->gpa_page = atop(segs[i].ds_addr);
185015516c77SSepherosa Ziehau 		gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK;
185115516c77SSepherosa Ziehau 		gpa->gpa_len = segs[i].ds_len;
185215516c77SSepherosa Ziehau 	}
185315516c77SSepherosa Ziehau 
185415516c77SSepherosa Ziehau 	txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
185515516c77SSepherosa Ziehau 	txd->chim_size = 0;
185615516c77SSepherosa Ziehau 	txr->hn_sendpkt = hn_txpkt_sglist;
185715516c77SSepherosa Ziehau done:
185815516c77SSepherosa Ziehau 	txd->m = m_head;
185915516c77SSepherosa Ziehau 
186015516c77SSepherosa Ziehau 	/* Set the completion routine */
186115516c77SSepherosa Ziehau 	hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd);
186215516c77SSepherosa Ziehau 
1863dc13fee6SSepherosa Ziehau 	/* Update temporary stats for later use. */
1864dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts++;
1865dc13fee6SSepherosa Ziehau 	txr->hn_stat_size += m_head->m_pkthdr.len;
1866dc13fee6SSepherosa Ziehau 	if (m_head->m_flags & M_MCAST)
1867dc13fee6SSepherosa Ziehau 		txr->hn_stat_mcasts++;
1868dc13fee6SSepherosa Ziehau 
186915516c77SSepherosa Ziehau 	return 0;
187015516c77SSepherosa Ziehau }
187115516c77SSepherosa Ziehau 
187215516c77SSepherosa Ziehau /*
187315516c77SSepherosa Ziehau  * NOTE:
187415516c77SSepherosa Ziehau  * If this function fails, then txd will be freed, but the mbuf
187515516c77SSepherosa Ziehau  * associated w/ the txd will _not_ be freed.
187615516c77SSepherosa Ziehau  */
187715516c77SSepherosa Ziehau static int
187815516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd)
187915516c77SSepherosa Ziehau {
188015516c77SSepherosa Ziehau 	int error, send_failed = 0;
188115516c77SSepherosa Ziehau 
188215516c77SSepherosa Ziehau again:
188315516c77SSepherosa Ziehau 	/*
1884dc13fee6SSepherosa Ziehau 	 * Make sure that this txd and any aggregated txds are not freed
1885dc13fee6SSepherosa Ziehau 	 * before ETHER_BPF_MTAP.
188615516c77SSepherosa Ziehau 	 */
188715516c77SSepherosa Ziehau 	hn_txdesc_hold(txd);
188815516c77SSepherosa Ziehau 	error = txr->hn_sendpkt(txr, txd);
188915516c77SSepherosa Ziehau 	if (!error) {
1890dc13fee6SSepherosa Ziehau 		if (bpf_peers_present(ifp->if_bpf)) {
1891dc13fee6SSepherosa Ziehau 			const struct hn_txdesc *tmp_txd;
1892dc13fee6SSepherosa Ziehau 
189315516c77SSepherosa Ziehau 			ETHER_BPF_MTAP(ifp, txd->m);
1894dc13fee6SSepherosa Ziehau 			STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link)
1895dc13fee6SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, tmp_txd->m);
1896dc13fee6SSepherosa Ziehau 		}
1897dc13fee6SSepherosa Ziehau 
1898dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts);
189923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
190023bf9e15SSepherosa Ziehau 		if (!hn_use_if_start)
190123bf9e15SSepherosa Ziehau #endif
190223bf9e15SSepherosa Ziehau 		{
190315516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OBYTES,
1904dc13fee6SSepherosa Ziehau 			    txr->hn_stat_size);
1905dc13fee6SSepherosa Ziehau 			if (txr->hn_stat_mcasts != 0) {
1906dc13fee6SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OMCASTS,
1907dc13fee6SSepherosa Ziehau 				    txr->hn_stat_mcasts);
190815516c77SSepherosa Ziehau 			}
1909dc13fee6SSepherosa Ziehau 		}
1910dc13fee6SSepherosa Ziehau 		txr->hn_pkts += txr->hn_stat_pkts;
1911dc13fee6SSepherosa Ziehau 		txr->hn_sends++;
191215516c77SSepherosa Ziehau 	}
191315516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
191415516c77SSepherosa Ziehau 
191515516c77SSepherosa Ziehau 	if (__predict_false(error)) {
191615516c77SSepherosa Ziehau 		int freed;
191715516c77SSepherosa Ziehau 
191815516c77SSepherosa Ziehau 		/*
191915516c77SSepherosa Ziehau 		 * This should "really rarely" happen.
192015516c77SSepherosa Ziehau 		 *
192115516c77SSepherosa Ziehau 		 * XXX Too many RX to be acked or too many sideband
192215516c77SSepherosa Ziehau 		 * commands to run?  Ask netvsc_channel_rollup()
192315516c77SSepherosa Ziehau 		 * to kick start later.
192415516c77SSepherosa Ziehau 		 */
192515516c77SSepherosa Ziehau 		txr->hn_has_txeof = 1;
192615516c77SSepherosa Ziehau 		if (!send_failed) {
192715516c77SSepherosa Ziehau 			txr->hn_send_failed++;
192815516c77SSepherosa Ziehau 			send_failed = 1;
192915516c77SSepherosa Ziehau 			/*
193015516c77SSepherosa Ziehau 			 * Try sending again after set hn_has_txeof;
193115516c77SSepherosa Ziehau 			 * in case that we missed the last
193215516c77SSepherosa Ziehau 			 * netvsc_channel_rollup().
193315516c77SSepherosa Ziehau 			 */
193415516c77SSepherosa Ziehau 			goto again;
193515516c77SSepherosa Ziehau 		}
193615516c77SSepherosa Ziehau 		if_printf(ifp, "send failed\n");
193715516c77SSepherosa Ziehau 
193815516c77SSepherosa Ziehau 		/*
193915516c77SSepherosa Ziehau 		 * Caller will perform further processing on the
194015516c77SSepherosa Ziehau 		 * associated mbuf, so don't free it in hn_txdesc_put();
194115516c77SSepherosa Ziehau 		 * only unload it from the DMA map in hn_txdesc_put(),
194215516c77SSepherosa Ziehau 		 * if it was loaded.
194315516c77SSepherosa Ziehau 		 */
194415516c77SSepherosa Ziehau 		txd->m = NULL;
194515516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
194615516c77SSepherosa Ziehau 		KASSERT(freed != 0,
194715516c77SSepherosa Ziehau 		    ("fail to free txd upon send error"));
194815516c77SSepherosa Ziehau 
194915516c77SSepherosa Ziehau 		txr->hn_send_failed++;
195015516c77SSepherosa Ziehau 	}
1951dc13fee6SSepherosa Ziehau 
1952dc13fee6SSepherosa Ziehau 	/* Reset temporary stats, after this sending is done. */
1953dc13fee6SSepherosa Ziehau 	txr->hn_stat_size = 0;
1954dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts = 0;
1955dc13fee6SSepherosa Ziehau 	txr->hn_stat_mcasts = 0;
1956dc13fee6SSepherosa Ziehau 
1957dc13fee6SSepherosa Ziehau 	return (error);
195815516c77SSepherosa Ziehau }
195915516c77SSepherosa Ziehau 
196015516c77SSepherosa Ziehau /*
196115516c77SSepherosa Ziehau  * Append the specified data to the indicated mbuf chain,
196215516c77SSepherosa Ziehau  * Extend the mbuf chain if the new data does not fit in
196315516c77SSepherosa Ziehau  * existing space.
196415516c77SSepherosa Ziehau  *
196515516c77SSepherosa Ziehau  * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c.
196615516c77SSepherosa Ziehau  * There should be an equivalent in the kernel mbuf code,
196715516c77SSepherosa Ziehau  * but there does not appear to be one yet.
196815516c77SSepherosa Ziehau  *
196915516c77SSepherosa Ziehau  * Differs from m_append() in that additional mbufs are
197015516c77SSepherosa Ziehau  * allocated with cluster size MJUMPAGESIZE, and filled
197115516c77SSepherosa Ziehau  * accordingly.
197215516c77SSepherosa Ziehau  *
197315516c77SSepherosa Ziehau  * Return 1 if able to complete the job; otherwise 0.
197415516c77SSepherosa Ziehau  */
197515516c77SSepherosa Ziehau static int
197615516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp)
197715516c77SSepherosa Ziehau {
197815516c77SSepherosa Ziehau 	struct mbuf *m, *n;
197915516c77SSepherosa Ziehau 	int remainder, space;
198015516c77SSepherosa Ziehau 
198115516c77SSepherosa Ziehau 	for (m = m0; m->m_next != NULL; m = m->m_next)
198215516c77SSepherosa Ziehau 		;
198315516c77SSepherosa Ziehau 	remainder = len;
198415516c77SSepherosa Ziehau 	space = M_TRAILINGSPACE(m);
198515516c77SSepherosa Ziehau 	if (space > 0) {
198615516c77SSepherosa Ziehau 		/*
198715516c77SSepherosa Ziehau 		 * Copy into available space.
198815516c77SSepherosa Ziehau 		 */
198915516c77SSepherosa Ziehau 		if (space > remainder)
199015516c77SSepherosa Ziehau 			space = remainder;
199115516c77SSepherosa Ziehau 		bcopy(cp, mtod(m, caddr_t) + m->m_len, space);
199215516c77SSepherosa Ziehau 		m->m_len += space;
199315516c77SSepherosa Ziehau 		cp += space;
199415516c77SSepherosa Ziehau 		remainder -= space;
199515516c77SSepherosa Ziehau 	}
199615516c77SSepherosa Ziehau 	while (remainder > 0) {
199715516c77SSepherosa Ziehau 		/*
199815516c77SSepherosa Ziehau 		 * Allocate a new mbuf; could check space
199915516c77SSepherosa Ziehau 		 * and allocate a cluster instead.
200015516c77SSepherosa Ziehau 		 */
200115516c77SSepherosa Ziehau 		n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE);
200215516c77SSepherosa Ziehau 		if (n == NULL)
200315516c77SSepherosa Ziehau 			break;
200415516c77SSepherosa Ziehau 		n->m_len = min(MJUMPAGESIZE, remainder);
200515516c77SSepherosa Ziehau 		bcopy(cp, mtod(n, caddr_t), n->m_len);
200615516c77SSepherosa Ziehau 		cp += n->m_len;
200715516c77SSepherosa Ziehau 		remainder -= n->m_len;
200815516c77SSepherosa Ziehau 		m->m_next = n;
200915516c77SSepherosa Ziehau 		m = n;
201015516c77SSepherosa Ziehau 	}
201115516c77SSepherosa Ziehau 	if (m0->m_flags & M_PKTHDR)
201215516c77SSepherosa Ziehau 		m0->m_pkthdr.len += len - remainder;
201315516c77SSepherosa Ziehau 
201415516c77SSepherosa Ziehau 	return (remainder == 0);
201515516c77SSepherosa Ziehau }
201615516c77SSepherosa Ziehau 
201715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
201815516c77SSepherosa Ziehau static __inline int
201915516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m)
202015516c77SSepherosa Ziehau {
202115516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
202215516c77SSepherosa Ziehau 	if (hn_lro_mbufq_depth) {
202315516c77SSepherosa Ziehau 		tcp_lro_queue_mbuf(lc, m);
202415516c77SSepherosa Ziehau 		return 0;
202515516c77SSepherosa Ziehau 	}
202615516c77SSepherosa Ziehau #endif
202715516c77SSepherosa Ziehau 	return tcp_lro_rx(lc, m, 0);
202815516c77SSepherosa Ziehau }
202915516c77SSepherosa Ziehau #endif
203015516c77SSepherosa Ziehau 
203115516c77SSepherosa Ziehau static int
203215516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
203315516c77SSepherosa Ziehau     const struct hn_rxinfo *info)
203415516c77SSepherosa Ziehau {
203515516c77SSepherosa Ziehau 	struct ifnet *ifp = rxr->hn_ifp;
203615516c77SSepherosa Ziehau 	struct mbuf *m_new;
203715516c77SSepherosa Ziehau 	int size, do_lro = 0, do_csum = 1;
203815516c77SSepherosa Ziehau 	int hash_type;
203915516c77SSepherosa Ziehau 
204015516c77SSepherosa Ziehau 	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
204115516c77SSepherosa Ziehau 		return (0);
204215516c77SSepherosa Ziehau 
204315516c77SSepherosa Ziehau 	/*
204415516c77SSepherosa Ziehau 	 * Bail out if packet contains more data than configured MTU.
204515516c77SSepherosa Ziehau 	 */
204615516c77SSepherosa Ziehau 	if (dlen > (ifp->if_mtu + ETHER_HDR_LEN)) {
204715516c77SSepherosa Ziehau 		return (0);
204815516c77SSepherosa Ziehau 	} else if (dlen <= MHLEN) {
204915516c77SSepherosa Ziehau 		m_new = m_gethdr(M_NOWAIT, MT_DATA);
205015516c77SSepherosa Ziehau 		if (m_new == NULL) {
205115516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
205215516c77SSepherosa Ziehau 			return (0);
205315516c77SSepherosa Ziehau 		}
205415516c77SSepherosa Ziehau 		memcpy(mtod(m_new, void *), data, dlen);
205515516c77SSepherosa Ziehau 		m_new->m_pkthdr.len = m_new->m_len = dlen;
205615516c77SSepherosa Ziehau 		rxr->hn_small_pkts++;
205715516c77SSepherosa Ziehau 	} else {
205815516c77SSepherosa Ziehau 		/*
205915516c77SSepherosa Ziehau 		 * Get an mbuf with a cluster.  For packets 2K or less,
206015516c77SSepherosa Ziehau 		 * get a standard 2K cluster.  For anything larger, get a
206115516c77SSepherosa Ziehau 		 * 4K cluster.  Any buffers larger than 4K can cause problems
206215516c77SSepherosa Ziehau 		 * if looped around to the Hyper-V TX channel, so avoid them.
206315516c77SSepherosa Ziehau 		 */
206415516c77SSepherosa Ziehau 		size = MCLBYTES;
206515516c77SSepherosa Ziehau 		if (dlen > MCLBYTES) {
206615516c77SSepherosa Ziehau 			/* 4096 */
206715516c77SSepherosa Ziehau 			size = MJUMPAGESIZE;
206815516c77SSepherosa Ziehau 		}
206915516c77SSepherosa Ziehau 
207015516c77SSepherosa Ziehau 		m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size);
207115516c77SSepherosa Ziehau 		if (m_new == NULL) {
207215516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
207315516c77SSepherosa Ziehau 			return (0);
207415516c77SSepherosa Ziehau 		}
207515516c77SSepherosa Ziehau 
207615516c77SSepherosa Ziehau 		hv_m_append(m_new, dlen, data);
207715516c77SSepherosa Ziehau 	}
207815516c77SSepherosa Ziehau 	m_new->m_pkthdr.rcvif = ifp;
207915516c77SSepherosa Ziehau 
208015516c77SSepherosa Ziehau 	if (__predict_false((ifp->if_capenable & IFCAP_RXCSUM) == 0))
208115516c77SSepherosa Ziehau 		do_csum = 0;
208215516c77SSepherosa Ziehau 
208315516c77SSepherosa Ziehau 	/* receive side checksum offload */
208415516c77SSepherosa Ziehau 	if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) {
208515516c77SSepherosa Ziehau 		/* IP csum offload */
208615516c77SSepherosa Ziehau 		if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) {
208715516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
208815516c77SSepherosa Ziehau 			    (CSUM_IP_CHECKED | CSUM_IP_VALID);
208915516c77SSepherosa Ziehau 			rxr->hn_csum_ip++;
209015516c77SSepherosa Ziehau 		}
209115516c77SSepherosa Ziehau 
209215516c77SSepherosa Ziehau 		/* TCP/UDP csum offload */
209315516c77SSepherosa Ziehau 		if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK |
209415516c77SSepherosa Ziehau 		     NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) {
209515516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
209615516c77SSepherosa Ziehau 			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
209715516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_data = 0xffff;
209815516c77SSepherosa Ziehau 			if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK)
209915516c77SSepherosa Ziehau 				rxr->hn_csum_tcp++;
210015516c77SSepherosa Ziehau 			else
210115516c77SSepherosa Ziehau 				rxr->hn_csum_udp++;
210215516c77SSepherosa Ziehau 		}
210315516c77SSepherosa Ziehau 
210415516c77SSepherosa Ziehau 		/*
210515516c77SSepherosa Ziehau 		 * XXX
210615516c77SSepherosa Ziehau 		 * As of this write (Oct 28th, 2016), host side will turn
210715516c77SSepherosa Ziehau 		 * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so
210815516c77SSepherosa Ziehau 		 * the do_lro setting here is actually _not_ accurate.  We
210915516c77SSepherosa Ziehau 		 * depend on the RSS hash type check to reset do_lro.
211015516c77SSepherosa Ziehau 		 */
211115516c77SSepherosa Ziehau 		if ((info->csum_info &
211215516c77SSepherosa Ziehau 		     (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) ==
211315516c77SSepherosa Ziehau 		    (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK))
211415516c77SSepherosa Ziehau 			do_lro = 1;
211515516c77SSepherosa Ziehau 	} else {
211615516c77SSepherosa Ziehau 		const struct ether_header *eh;
211715516c77SSepherosa Ziehau 		uint16_t etype;
211815516c77SSepherosa Ziehau 		int hoff;
211915516c77SSepherosa Ziehau 
212015516c77SSepherosa Ziehau 		hoff = sizeof(*eh);
212115516c77SSepherosa Ziehau 		if (m_new->m_len < hoff)
212215516c77SSepherosa Ziehau 			goto skip;
212315516c77SSepherosa Ziehau 		eh = mtod(m_new, struct ether_header *);
212415516c77SSepherosa Ziehau 		etype = ntohs(eh->ether_type);
212515516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_VLAN) {
212615516c77SSepherosa Ziehau 			const struct ether_vlan_header *evl;
212715516c77SSepherosa Ziehau 
212815516c77SSepherosa Ziehau 			hoff = sizeof(*evl);
212915516c77SSepherosa Ziehau 			if (m_new->m_len < hoff)
213015516c77SSepherosa Ziehau 				goto skip;
213115516c77SSepherosa Ziehau 			evl = mtod(m_new, struct ether_vlan_header *);
213215516c77SSepherosa Ziehau 			etype = ntohs(evl->evl_proto);
213315516c77SSepherosa Ziehau 		}
213415516c77SSepherosa Ziehau 
213515516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_IP) {
213615516c77SSepherosa Ziehau 			int pr;
213715516c77SSepherosa Ziehau 
213815516c77SSepherosa Ziehau 			pr = hn_check_iplen(m_new, hoff);
213915516c77SSepherosa Ziehau 			if (pr == IPPROTO_TCP) {
214015516c77SSepherosa Ziehau 				if (do_csum &&
214115516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
214215516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_TCP)) {
214315516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
214415516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
214515516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
214615516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
214715516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
214815516c77SSepherosa Ziehau 				}
214915516c77SSepherosa Ziehau 				do_lro = 1;
215015516c77SSepherosa Ziehau 			} else if (pr == IPPROTO_UDP) {
215115516c77SSepherosa Ziehau 				if (do_csum &&
215215516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
215315516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_UDP)) {
215415516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
215515516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
215615516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
215715516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
215815516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
215915516c77SSepherosa Ziehau 				}
216015516c77SSepherosa Ziehau 			} else if (pr != IPPROTO_DONE && do_csum &&
216115516c77SSepherosa Ziehau 			    (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) {
216215516c77SSepherosa Ziehau 				rxr->hn_csum_trusted++;
216315516c77SSepherosa Ziehau 				m_new->m_pkthdr.csum_flags |=
216415516c77SSepherosa Ziehau 				    (CSUM_IP_CHECKED | CSUM_IP_VALID);
216515516c77SSepherosa Ziehau 			}
216615516c77SSepherosa Ziehau 		}
216715516c77SSepherosa Ziehau 	}
216815516c77SSepherosa Ziehau skip:
216915516c77SSepherosa Ziehau 	if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) {
217015516c77SSepherosa Ziehau 		m_new->m_pkthdr.ether_vtag = EVL_MAKETAG(
217115516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_ID(info->vlan_info),
217215516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_PRI(info->vlan_info),
217315516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_CFI(info->vlan_info));
217415516c77SSepherosa Ziehau 		m_new->m_flags |= M_VLANTAG;
217515516c77SSepherosa Ziehau 	}
217615516c77SSepherosa Ziehau 
217715516c77SSepherosa Ziehau 	if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) {
217815516c77SSepherosa Ziehau 		rxr->hn_rss_pkts++;
217915516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = info->hash_value;
218015516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE_HASH;
218115516c77SSepherosa Ziehau 		if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) ==
218215516c77SSepherosa Ziehau 		    NDIS_HASH_FUNCTION_TOEPLITZ) {
218315516c77SSepherosa Ziehau 			uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK);
218415516c77SSepherosa Ziehau 
218515516c77SSepherosa Ziehau 			/*
218615516c77SSepherosa Ziehau 			 * NOTE:
218715516c77SSepherosa Ziehau 			 * do_lro is resetted, if the hash types are not TCP
218815516c77SSepherosa Ziehau 			 * related.  See the comment in the above csum_flags
218915516c77SSepherosa Ziehau 			 * setup section.
219015516c77SSepherosa Ziehau 			 */
219115516c77SSepherosa Ziehau 			switch (type) {
219215516c77SSepherosa Ziehau 			case NDIS_HASH_IPV4:
219315516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV4;
219415516c77SSepherosa Ziehau 				do_lro = 0;
219515516c77SSepherosa Ziehau 				break;
219615516c77SSepherosa Ziehau 
219715516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV4:
219815516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV4;
219915516c77SSepherosa Ziehau 				break;
220015516c77SSepherosa Ziehau 
220115516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6:
220215516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6;
220315516c77SSepherosa Ziehau 				do_lro = 0;
220415516c77SSepherosa Ziehau 				break;
220515516c77SSepherosa Ziehau 
220615516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6_EX:
220715516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6_EX;
220815516c77SSepherosa Ziehau 				do_lro = 0;
220915516c77SSepherosa Ziehau 				break;
221015516c77SSepherosa Ziehau 
221115516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6:
221215516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6;
221315516c77SSepherosa Ziehau 				break;
221415516c77SSepherosa Ziehau 
221515516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6_EX:
221615516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX;
221715516c77SSepherosa Ziehau 				break;
221815516c77SSepherosa Ziehau 			}
221915516c77SSepherosa Ziehau 		}
222015516c77SSepherosa Ziehau 	} else {
222115516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
222215516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE;
222315516c77SSepherosa Ziehau 	}
222415516c77SSepherosa Ziehau 	M_HASHTYPE_SET(m_new, hash_type);
222515516c77SSepherosa Ziehau 
222615516c77SSepherosa Ziehau 	/*
222715516c77SSepherosa Ziehau 	 * Note:  Moved RX completion back to hv_nv_on_receive() so all
222815516c77SSepherosa Ziehau 	 * messages (not just data messages) will trigger a response.
222915516c77SSepherosa Ziehau 	 */
223015516c77SSepherosa Ziehau 
223115516c77SSepherosa Ziehau 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
223215516c77SSepherosa Ziehau 	rxr->hn_pkts++;
223315516c77SSepherosa Ziehau 
223415516c77SSepherosa Ziehau 	if ((ifp->if_capenable & IFCAP_LRO) && do_lro) {
223515516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
223615516c77SSepherosa Ziehau 		struct lro_ctrl *lro = &rxr->hn_lro;
223715516c77SSepherosa Ziehau 
223815516c77SSepherosa Ziehau 		if (lro->lro_cnt) {
223915516c77SSepherosa Ziehau 			rxr->hn_lro_tried++;
224015516c77SSepherosa Ziehau 			if (hn_lro_rx(lro, m_new) == 0) {
224115516c77SSepherosa Ziehau 				/* DONE! */
224215516c77SSepherosa Ziehau 				return 0;
224315516c77SSepherosa Ziehau 			}
224415516c77SSepherosa Ziehau 		}
224515516c77SSepherosa Ziehau #endif
224615516c77SSepherosa Ziehau 	}
224715516c77SSepherosa Ziehau 
224815516c77SSepherosa Ziehau 	/* We're not holding the lock here, so don't release it */
224915516c77SSepherosa Ziehau 	(*ifp->if_input)(ifp, m_new);
225015516c77SSepherosa Ziehau 
225115516c77SSepherosa Ziehau 	return (0);
225215516c77SSepherosa Ziehau }
225315516c77SSepherosa Ziehau 
225415516c77SSepherosa Ziehau static int
225515516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
225615516c77SSepherosa Ziehau {
225715516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
225815516c77SSepherosa Ziehau 	struct ifreq *ifr = (struct ifreq *)data;
225915516c77SSepherosa Ziehau 	int mask, error = 0;
226015516c77SSepherosa Ziehau 
226115516c77SSepherosa Ziehau 	switch (cmd) {
226215516c77SSepherosa Ziehau 	case SIOCSIFMTU:
226315516c77SSepherosa Ziehau 		if (ifr->ifr_mtu > HN_MTU_MAX) {
226415516c77SSepherosa Ziehau 			error = EINVAL;
226515516c77SSepherosa Ziehau 			break;
226615516c77SSepherosa Ziehau 		}
226715516c77SSepherosa Ziehau 
226815516c77SSepherosa Ziehau 		HN_LOCK(sc);
226915516c77SSepherosa Ziehau 
227015516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
227115516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
227215516c77SSepherosa Ziehau 			break;
227315516c77SSepherosa Ziehau 		}
227415516c77SSepherosa Ziehau 
227515516c77SSepherosa Ziehau 		if ((sc->hn_caps & HN_CAP_MTU) == 0) {
227615516c77SSepherosa Ziehau 			/* Can't change MTU */
227715516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
227815516c77SSepherosa Ziehau 			error = EOPNOTSUPP;
227915516c77SSepherosa Ziehau 			break;
228015516c77SSepherosa Ziehau 		}
228115516c77SSepherosa Ziehau 
228215516c77SSepherosa Ziehau 		if (ifp->if_mtu == ifr->ifr_mtu) {
228315516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
228415516c77SSepherosa Ziehau 			break;
228515516c77SSepherosa Ziehau 		}
228615516c77SSepherosa Ziehau 
228715516c77SSepherosa Ziehau 		/*
228815516c77SSepherosa Ziehau 		 * Suspend this interface before the synthetic parts
228915516c77SSepherosa Ziehau 		 * are ripped.
229015516c77SSepherosa Ziehau 		 */
229115516c77SSepherosa Ziehau 		hn_suspend(sc);
229215516c77SSepherosa Ziehau 
229315516c77SSepherosa Ziehau 		/*
229415516c77SSepherosa Ziehau 		 * Detach the synthetics parts, i.e. NVS and RNDIS.
229515516c77SSepherosa Ziehau 		 */
229615516c77SSepherosa Ziehau 		hn_synth_detach(sc);
229715516c77SSepherosa Ziehau 
229815516c77SSepherosa Ziehau 		/*
229915516c77SSepherosa Ziehau 		 * Reattach the synthetic parts, i.e. NVS and RNDIS,
230015516c77SSepherosa Ziehau 		 * with the new MTU setting.
230115516c77SSepherosa Ziehau 		 */
230215516c77SSepherosa Ziehau 		error = hn_synth_attach(sc, ifr->ifr_mtu);
230315516c77SSepherosa Ziehau 		if (error) {
230415516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
230515516c77SSepherosa Ziehau 			break;
230615516c77SSepherosa Ziehau 		}
230715516c77SSepherosa Ziehau 
230815516c77SSepherosa Ziehau 		/*
230915516c77SSepherosa Ziehau 		 * Commit the requested MTU, after the synthetic parts
231015516c77SSepherosa Ziehau 		 * have been successfully attached.
231115516c77SSepherosa Ziehau 		 */
231215516c77SSepherosa Ziehau 		ifp->if_mtu = ifr->ifr_mtu;
231315516c77SSepherosa Ziehau 
231415516c77SSepherosa Ziehau 		/*
231515516c77SSepherosa Ziehau 		 * Make sure that various parameters based on MTU are
231615516c77SSepherosa Ziehau 		 * still valid, after the MTU change.
231715516c77SSepherosa Ziehau 		 */
231815516c77SSepherosa Ziehau 		if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax)
231915516c77SSepherosa Ziehau 			hn_set_chim_size(sc, sc->hn_chim_szmax);
232015516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu);
232115516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
232215516c77SSepherosa Ziehau 		if (sc->hn_rx_ring[0].hn_lro.lro_length_lim <
232315516c77SSepherosa Ziehau 		    HN_LRO_LENLIM_MIN(ifp))
232415516c77SSepherosa Ziehau 			hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
232515516c77SSepherosa Ziehau #endif
232615516c77SSepherosa Ziehau 
232715516c77SSepherosa Ziehau 		/*
232815516c77SSepherosa Ziehau 		 * All done!  Resume the interface now.
232915516c77SSepherosa Ziehau 		 */
233015516c77SSepherosa Ziehau 		hn_resume(sc);
233115516c77SSepherosa Ziehau 
233215516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
233315516c77SSepherosa Ziehau 		break;
233415516c77SSepherosa Ziehau 
233515516c77SSepherosa Ziehau 	case SIOCSIFFLAGS:
233615516c77SSepherosa Ziehau 		HN_LOCK(sc);
233715516c77SSepherosa Ziehau 
233815516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
233915516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
234015516c77SSepherosa Ziehau 			break;
234115516c77SSepherosa Ziehau 		}
234215516c77SSepherosa Ziehau 
234315516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_UP) {
2344fdc4f478SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2345fdc4f478SSepherosa Ziehau 				/*
2346fdc4f478SSepherosa Ziehau 				 * Caller meight hold mutex, e.g.
2347fdc4f478SSepherosa Ziehau 				 * bpf; use busy-wait for the RNDIS
2348fdc4f478SSepherosa Ziehau 				 * reply.
2349fdc4f478SSepherosa Ziehau 				 */
2350fdc4f478SSepherosa Ziehau 				HN_NO_SLEEPING(sc);
235115516c77SSepherosa Ziehau 				hn_set_rxfilter(sc);
2352fdc4f478SSepherosa Ziehau 				HN_SLEEPING_OK(sc);
2353fdc4f478SSepherosa Ziehau 			} else {
235415516c77SSepherosa Ziehau 				hn_init_locked(sc);
2355fdc4f478SSepherosa Ziehau 			}
235615516c77SSepherosa Ziehau 		} else {
235715516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
235815516c77SSepherosa Ziehau 				hn_stop(sc);
235915516c77SSepherosa Ziehau 		}
236015516c77SSepherosa Ziehau 		sc->hn_if_flags = ifp->if_flags;
236115516c77SSepherosa Ziehau 
236215516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
236315516c77SSepherosa Ziehau 		break;
236415516c77SSepherosa Ziehau 
236515516c77SSepherosa Ziehau 	case SIOCSIFCAP:
236615516c77SSepherosa Ziehau 		HN_LOCK(sc);
236715516c77SSepherosa Ziehau 		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
236815516c77SSepherosa Ziehau 
236915516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM) {
237015516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM;
237115516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM)
237215516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc);
237315516c77SSepherosa Ziehau 			else
237415516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc);
237515516c77SSepherosa Ziehau 		}
237615516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM_IPV6) {
237715516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
237815516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
237915516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc);
238015516c77SSepherosa Ziehau 			else
238115516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc);
238215516c77SSepherosa Ziehau 		}
238315516c77SSepherosa Ziehau 
238415516c77SSepherosa Ziehau 		/* TODO: flip RNDIS offload parameters for RXCSUM. */
238515516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM)
238615516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM;
238715516c77SSepherosa Ziehau #ifdef foo
238815516c77SSepherosa Ziehau 		/* We can't diff IPv6 packets from IPv4 packets on RX path. */
238915516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM_IPV6)
239015516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
239115516c77SSepherosa Ziehau #endif
239215516c77SSepherosa Ziehau 
239315516c77SSepherosa Ziehau 		if (mask & IFCAP_LRO)
239415516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_LRO;
239515516c77SSepherosa Ziehau 
239615516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO4) {
239715516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO4;
239815516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO4)
239915516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP_TSO;
240015516c77SSepherosa Ziehau 			else
240115516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP_TSO;
240215516c77SSepherosa Ziehau 		}
240315516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO6) {
240415516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO6;
240515516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO6)
240615516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP6_TSO;
240715516c77SSepherosa Ziehau 			else
240815516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP6_TSO;
240915516c77SSepherosa Ziehau 		}
241015516c77SSepherosa Ziehau 
241115516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
241215516c77SSepherosa Ziehau 		break;
241315516c77SSepherosa Ziehau 
241415516c77SSepherosa Ziehau 	case SIOCADDMULTI:
241515516c77SSepherosa Ziehau 	case SIOCDELMULTI:
241615516c77SSepherosa Ziehau 		HN_LOCK(sc);
241715516c77SSepherosa Ziehau 
241815516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
241915516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
242015516c77SSepherosa Ziehau 			break;
242115516c77SSepherosa Ziehau 		}
2422fdc4f478SSepherosa Ziehau 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2423fdc4f478SSepherosa Ziehau 			/*
2424fdc4f478SSepherosa Ziehau 			 * Multicast uses mutex; use busy-wait for
2425fdc4f478SSepherosa Ziehau 			 * the RNDIS reply.
2426fdc4f478SSepherosa Ziehau 			 */
2427fdc4f478SSepherosa Ziehau 			HN_NO_SLEEPING(sc);
242815516c77SSepherosa Ziehau 			hn_set_rxfilter(sc);
2429fdc4f478SSepherosa Ziehau 			HN_SLEEPING_OK(sc);
2430fdc4f478SSepherosa Ziehau 		}
243115516c77SSepherosa Ziehau 
243215516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
243315516c77SSepherosa Ziehau 		break;
243415516c77SSepherosa Ziehau 
243515516c77SSepherosa Ziehau 	case SIOCSIFMEDIA:
243615516c77SSepherosa Ziehau 	case SIOCGIFMEDIA:
243715516c77SSepherosa Ziehau 		error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd);
243815516c77SSepherosa Ziehau 		break;
243915516c77SSepherosa Ziehau 
244015516c77SSepherosa Ziehau 	default:
244115516c77SSepherosa Ziehau 		error = ether_ioctl(ifp, cmd, data);
244215516c77SSepherosa Ziehau 		break;
244315516c77SSepherosa Ziehau 	}
244415516c77SSepherosa Ziehau 	return (error);
244515516c77SSepherosa Ziehau }
244615516c77SSepherosa Ziehau 
244715516c77SSepherosa Ziehau static void
244815516c77SSepherosa Ziehau hn_stop(struct hn_softc *sc)
244915516c77SSepherosa Ziehau {
245015516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
245115516c77SSepherosa Ziehau 	int i;
245215516c77SSepherosa Ziehau 
245315516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
245415516c77SSepherosa Ziehau 
245515516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
245615516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
245715516c77SSepherosa Ziehau 
245815516c77SSepherosa Ziehau 	/* Clear RUNNING bit _before_ hn_suspend_data() */
245915516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
246015516c77SSepherosa Ziehau 	hn_suspend_data(sc);
246115516c77SSepherosa Ziehau 
246215516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
246315516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
246415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
246515516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
246615516c77SSepherosa Ziehau }
246715516c77SSepherosa Ziehau 
246815516c77SSepherosa Ziehau static void
246915516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc)
247015516c77SSepherosa Ziehau {
247115516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
247215516c77SSepherosa Ziehau 	int i;
247315516c77SSepherosa Ziehau 
247415516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
247515516c77SSepherosa Ziehau 
247615516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
247715516c77SSepherosa Ziehau 		return;
247815516c77SSepherosa Ziehau 
247915516c77SSepherosa Ziehau 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
248015516c77SSepherosa Ziehau 		return;
248115516c77SSepherosa Ziehau 
248215516c77SSepherosa Ziehau 	/* Configure RX filter */
248315516c77SSepherosa Ziehau 	hn_set_rxfilter(sc);
248415516c77SSepherosa Ziehau 
248515516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
248615516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
248715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
248815516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
248915516c77SSepherosa Ziehau 
249015516c77SSepherosa Ziehau 	/* Clear TX 'suspended' bit. */
249115516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_inuse);
249215516c77SSepherosa Ziehau 
249315516c77SSepherosa Ziehau 	/* Everything is ready; unleash! */
249415516c77SSepherosa Ziehau 	atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
249515516c77SSepherosa Ziehau }
249615516c77SSepherosa Ziehau 
249715516c77SSepherosa Ziehau static void
249815516c77SSepherosa Ziehau hn_init(void *xsc)
249915516c77SSepherosa Ziehau {
250015516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
250115516c77SSepherosa Ziehau 
250215516c77SSepherosa Ziehau 	HN_LOCK(sc);
250315516c77SSepherosa Ziehau 	hn_init_locked(sc);
250415516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
250515516c77SSepherosa Ziehau }
250615516c77SSepherosa Ziehau 
250715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
250815516c77SSepherosa Ziehau 
250915516c77SSepherosa Ziehau static int
251015516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
251115516c77SSepherosa Ziehau {
251215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
251315516c77SSepherosa Ziehau 	unsigned int lenlim;
251415516c77SSepherosa Ziehau 	int error;
251515516c77SSepherosa Ziehau 
251615516c77SSepherosa Ziehau 	lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim;
251715516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &lenlim, 0, req);
251815516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
251915516c77SSepherosa Ziehau 		return error;
252015516c77SSepherosa Ziehau 
252115516c77SSepherosa Ziehau 	HN_LOCK(sc);
252215516c77SSepherosa Ziehau 	if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) ||
252315516c77SSepherosa Ziehau 	    lenlim > TCP_LRO_LENGTH_MAX) {
252415516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
252515516c77SSepherosa Ziehau 		return EINVAL;
252615516c77SSepherosa Ziehau 	}
252715516c77SSepherosa Ziehau 	hn_set_lro_lenlim(sc, lenlim);
252815516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
252915516c77SSepherosa Ziehau 
253015516c77SSepherosa Ziehau 	return 0;
253115516c77SSepherosa Ziehau }
253215516c77SSepherosa Ziehau 
253315516c77SSepherosa Ziehau static int
253415516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS)
253515516c77SSepherosa Ziehau {
253615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
253715516c77SSepherosa Ziehau 	int ackcnt, error, i;
253815516c77SSepherosa Ziehau 
253915516c77SSepherosa Ziehau 	/*
254015516c77SSepherosa Ziehau 	 * lro_ackcnt_lim is append count limit,
254115516c77SSepherosa Ziehau 	 * +1 to turn it into aggregation limit.
254215516c77SSepherosa Ziehau 	 */
254315516c77SSepherosa Ziehau 	ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1;
254415516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &ackcnt, 0, req);
254515516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
254615516c77SSepherosa Ziehau 		return error;
254715516c77SSepherosa Ziehau 
254815516c77SSepherosa Ziehau 	if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1))
254915516c77SSepherosa Ziehau 		return EINVAL;
255015516c77SSepherosa Ziehau 
255115516c77SSepherosa Ziehau 	/*
255215516c77SSepherosa Ziehau 	 * Convert aggregation limit back to append
255315516c77SSepherosa Ziehau 	 * count limit.
255415516c77SSepherosa Ziehau 	 */
255515516c77SSepherosa Ziehau 	--ackcnt;
255615516c77SSepherosa Ziehau 	HN_LOCK(sc);
255715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_inuse; ++i)
255815516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt;
255915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
256015516c77SSepherosa Ziehau 	return 0;
256115516c77SSepherosa Ziehau }
256215516c77SSepherosa Ziehau 
256315516c77SSepherosa Ziehau #endif
256415516c77SSepherosa Ziehau 
256515516c77SSepherosa Ziehau static int
256615516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS)
256715516c77SSepherosa Ziehau {
256815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
256915516c77SSepherosa Ziehau 	int hcsum = arg2;
257015516c77SSepherosa Ziehau 	int on, error, i;
257115516c77SSepherosa Ziehau 
257215516c77SSepherosa Ziehau 	on = 0;
257315516c77SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum)
257415516c77SSepherosa Ziehau 		on = 1;
257515516c77SSepherosa Ziehau 
257615516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &on, 0, req);
257715516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
257815516c77SSepherosa Ziehau 		return error;
257915516c77SSepherosa Ziehau 
258015516c77SSepherosa Ziehau 	HN_LOCK(sc);
258115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_inuse; ++i) {
258215516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
258315516c77SSepherosa Ziehau 
258415516c77SSepherosa Ziehau 		if (on)
258515516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= hcsum;
258615516c77SSepherosa Ziehau 		else
258715516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum &= ~hcsum;
258815516c77SSepherosa Ziehau 	}
258915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
259015516c77SSepherosa Ziehau 	return 0;
259115516c77SSepherosa Ziehau }
259215516c77SSepherosa Ziehau 
259315516c77SSepherosa Ziehau static int
259415516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS)
259515516c77SSepherosa Ziehau {
259615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
259715516c77SSepherosa Ziehau 	int chim_size, error;
259815516c77SSepherosa Ziehau 
259915516c77SSepherosa Ziehau 	chim_size = sc->hn_tx_ring[0].hn_chim_size;
260015516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &chim_size, 0, req);
260115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
260215516c77SSepherosa Ziehau 		return error;
260315516c77SSepherosa Ziehau 
260415516c77SSepherosa Ziehau 	if (chim_size > sc->hn_chim_szmax || chim_size <= 0)
260515516c77SSepherosa Ziehau 		return EINVAL;
260615516c77SSepherosa Ziehau 
260715516c77SSepherosa Ziehau 	HN_LOCK(sc);
260815516c77SSepherosa Ziehau 	hn_set_chim_size(sc, chim_size);
260915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
261015516c77SSepherosa Ziehau 	return 0;
261115516c77SSepherosa Ziehau }
261215516c77SSepherosa Ziehau 
261315516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
261415516c77SSepherosa Ziehau static int
261515516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS)
261615516c77SSepherosa Ziehau {
261715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
261815516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
261915516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
262015516c77SSepherosa Ziehau 	uint64_t stat;
262115516c77SSepherosa Ziehau 
262215516c77SSepherosa Ziehau 	stat = 0;
262315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
262415516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
262515516c77SSepherosa Ziehau 		stat += *((int *)((uint8_t *)rxr + ofs));
262615516c77SSepherosa Ziehau 	}
262715516c77SSepherosa Ziehau 
262815516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
262915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
263015516c77SSepherosa Ziehau 		return error;
263115516c77SSepherosa Ziehau 
263215516c77SSepherosa Ziehau 	/* Zero out this stat. */
263315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
263415516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
263515516c77SSepherosa Ziehau 		*((int *)((uint8_t *)rxr + ofs)) = 0;
263615516c77SSepherosa Ziehau 	}
263715516c77SSepherosa Ziehau 	return 0;
263815516c77SSepherosa Ziehau }
263915516c77SSepherosa Ziehau #else
264015516c77SSepherosa Ziehau static int
264115516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS)
264215516c77SSepherosa Ziehau {
264315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
264415516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
264515516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
264615516c77SSepherosa Ziehau 	uint64_t stat;
264715516c77SSepherosa Ziehau 
264815516c77SSepherosa Ziehau 	stat = 0;
264915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_inuse; ++i) {
265015516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
265115516c77SSepherosa Ziehau 		stat += *((uint64_t *)((uint8_t *)rxr + ofs));
265215516c77SSepherosa Ziehau 	}
265315516c77SSepherosa Ziehau 
265415516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
265515516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
265615516c77SSepherosa Ziehau 		return error;
265715516c77SSepherosa Ziehau 
265815516c77SSepherosa Ziehau 	/* Zero out this stat. */
265915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_inuse; ++i) {
266015516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
266115516c77SSepherosa Ziehau 		*((uint64_t *)((uint8_t *)rxr + ofs)) = 0;
266215516c77SSepherosa Ziehau 	}
266315516c77SSepherosa Ziehau 	return 0;
266415516c77SSepherosa Ziehau }
266515516c77SSepherosa Ziehau 
266615516c77SSepherosa Ziehau #endif
266715516c77SSepherosa Ziehau 
266815516c77SSepherosa Ziehau static int
266915516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
267015516c77SSepherosa Ziehau {
267115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
267215516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
267315516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
267415516c77SSepherosa Ziehau 	u_long stat;
267515516c77SSepherosa Ziehau 
267615516c77SSepherosa Ziehau 	stat = 0;
267715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_inuse; ++i) {
267815516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
267915516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)rxr + ofs));
268015516c77SSepherosa Ziehau 	}
268115516c77SSepherosa Ziehau 
268215516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
268315516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
268415516c77SSepherosa Ziehau 		return error;
268515516c77SSepherosa Ziehau 
268615516c77SSepherosa Ziehau 	/* Zero out this stat. */
268715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_inuse; ++i) {
268815516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
268915516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)rxr + ofs)) = 0;
269015516c77SSepherosa Ziehau 	}
269115516c77SSepherosa Ziehau 	return 0;
269215516c77SSepherosa Ziehau }
269315516c77SSepherosa Ziehau 
269415516c77SSepherosa Ziehau static int
269515516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
269615516c77SSepherosa Ziehau {
269715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
269815516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
269915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
270015516c77SSepherosa Ziehau 	u_long stat;
270115516c77SSepherosa Ziehau 
270215516c77SSepherosa Ziehau 	stat = 0;
270315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
270415516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
270515516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)txr + ofs));
270615516c77SSepherosa Ziehau 	}
270715516c77SSepherosa Ziehau 
270815516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
270915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
271015516c77SSepherosa Ziehau 		return error;
271115516c77SSepherosa Ziehau 
271215516c77SSepherosa Ziehau 	/* Zero out this stat. */
271315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
271415516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
271515516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)txr + ofs)) = 0;
271615516c77SSepherosa Ziehau 	}
271715516c77SSepherosa Ziehau 	return 0;
271815516c77SSepherosa Ziehau }
271915516c77SSepherosa Ziehau 
272015516c77SSepherosa Ziehau static int
272115516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS)
272215516c77SSepherosa Ziehau {
272315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
272415516c77SSepherosa Ziehau 	int ofs = arg2, i, error, conf;
272515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
272615516c77SSepherosa Ziehau 
272715516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[0];
272815516c77SSepherosa Ziehau 	conf = *((int *)((uint8_t *)txr + ofs));
272915516c77SSepherosa Ziehau 
273015516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &conf, 0, req);
273115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
273215516c77SSepherosa Ziehau 		return error;
273315516c77SSepherosa Ziehau 
273415516c77SSepherosa Ziehau 	HN_LOCK(sc);
273515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
273615516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
273715516c77SSepherosa Ziehau 		*((int *)((uint8_t *)txr + ofs)) = conf;
273815516c77SSepherosa Ziehau 	}
273915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
274015516c77SSepherosa Ziehau 
274115516c77SSepherosa Ziehau 	return 0;
274215516c77SSepherosa Ziehau }
274315516c77SSepherosa Ziehau 
274415516c77SSepherosa Ziehau static int
2745dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS)
2746dc13fee6SSepherosa Ziehau {
2747dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2748dc13fee6SSepherosa Ziehau 	int error, size;
2749dc13fee6SSepherosa Ziehau 
2750dc13fee6SSepherosa Ziehau 	size = sc->hn_agg_size;
2751dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &size, 0, req);
2752dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
2753dc13fee6SSepherosa Ziehau 		return (error);
2754dc13fee6SSepherosa Ziehau 
2755dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
2756dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = size;
2757dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
2758dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
2759dc13fee6SSepherosa Ziehau 
2760dc13fee6SSepherosa Ziehau 	return (0);
2761dc13fee6SSepherosa Ziehau }
2762dc13fee6SSepherosa Ziehau 
2763dc13fee6SSepherosa Ziehau static int
2764dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS)
2765dc13fee6SSepherosa Ziehau {
2766dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2767dc13fee6SSepherosa Ziehau 	int error, pkts;
2768dc13fee6SSepherosa Ziehau 
2769dc13fee6SSepherosa Ziehau 	pkts = sc->hn_agg_pkts;
2770dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pkts, 0, req);
2771dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
2772dc13fee6SSepherosa Ziehau 		return (error);
2773dc13fee6SSepherosa Ziehau 
2774dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
2775dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = pkts;
2776dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
2777dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
2778dc13fee6SSepherosa Ziehau 
2779dc13fee6SSepherosa Ziehau 	return (0);
2780dc13fee6SSepherosa Ziehau }
2781dc13fee6SSepherosa Ziehau 
2782dc13fee6SSepherosa Ziehau static int
2783dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS)
2784dc13fee6SSepherosa Ziehau {
2785dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2786dc13fee6SSepherosa Ziehau 	int pkts;
2787dc13fee6SSepherosa Ziehau 
2788dc13fee6SSepherosa Ziehau 	pkts = sc->hn_tx_ring[0].hn_agg_pktmax;
2789dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &pkts, 0, req));
2790dc13fee6SSepherosa Ziehau }
2791dc13fee6SSepherosa Ziehau 
2792dc13fee6SSepherosa Ziehau static int
2793dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS)
2794dc13fee6SSepherosa Ziehau {
2795dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2796dc13fee6SSepherosa Ziehau 	int align;
2797dc13fee6SSepherosa Ziehau 
2798dc13fee6SSepherosa Ziehau 	align = sc->hn_tx_ring[0].hn_agg_align;
2799dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &align, 0, req));
2800dc13fee6SSepherosa Ziehau }
2801dc13fee6SSepherosa Ziehau 
2802dc13fee6SSepherosa Ziehau static int
280315516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS)
280415516c77SSepherosa Ziehau {
280515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
280615516c77SSepherosa Ziehau 	char verstr[16];
280715516c77SSepherosa Ziehau 
280815516c77SSepherosa Ziehau 	snprintf(verstr, sizeof(verstr), "%u.%u",
280915516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
281015516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
281115516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
281215516c77SSepherosa Ziehau }
281315516c77SSepherosa Ziehau 
281415516c77SSepherosa Ziehau static int
281515516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS)
281615516c77SSepherosa Ziehau {
281715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
281815516c77SSepherosa Ziehau 	char caps_str[128];
281915516c77SSepherosa Ziehau 	uint32_t caps;
282015516c77SSepherosa Ziehau 
282115516c77SSepherosa Ziehau 	HN_LOCK(sc);
282215516c77SSepherosa Ziehau 	caps = sc->hn_caps;
282315516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
282415516c77SSepherosa Ziehau 	snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS);
282515516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req);
282615516c77SSepherosa Ziehau }
282715516c77SSepherosa Ziehau 
282815516c77SSepherosa Ziehau static int
282915516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS)
283015516c77SSepherosa Ziehau {
283115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
283215516c77SSepherosa Ziehau 	char assist_str[128];
283315516c77SSepherosa Ziehau 	uint32_t hwassist;
283415516c77SSepherosa Ziehau 
283515516c77SSepherosa Ziehau 	HN_LOCK(sc);
283615516c77SSepherosa Ziehau 	hwassist = sc->hn_ifp->if_hwassist;
283715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
283815516c77SSepherosa Ziehau 	snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS);
283915516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req);
284015516c77SSepherosa Ziehau }
284115516c77SSepherosa Ziehau 
284215516c77SSepherosa Ziehau static int
284315516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS)
284415516c77SSepherosa Ziehau {
284515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
284615516c77SSepherosa Ziehau 	char filter_str[128];
284715516c77SSepherosa Ziehau 	uint32_t filter;
284815516c77SSepherosa Ziehau 
284915516c77SSepherosa Ziehau 	HN_LOCK(sc);
285015516c77SSepherosa Ziehau 	filter = sc->hn_rx_filter;
285115516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
285215516c77SSepherosa Ziehau 	snprintf(filter_str, sizeof(filter_str), "%b", filter,
285315516c77SSepherosa Ziehau 	    NDIS_PACKET_TYPES);
285415516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req);
285515516c77SSepherosa Ziehau }
285615516c77SSepherosa Ziehau 
285715516c77SSepherosa Ziehau static int
285815516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
285915516c77SSepherosa Ziehau {
286015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
286115516c77SSepherosa Ziehau 	int error;
286215516c77SSepherosa Ziehau 
286315516c77SSepherosa Ziehau 	HN_LOCK(sc);
286415516c77SSepherosa Ziehau 
286515516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
286615516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
286715516c77SSepherosa Ziehau 		goto back;
286815516c77SSepherosa Ziehau 
286915516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
287015516c77SSepherosa Ziehau 	if (error)
287115516c77SSepherosa Ziehau 		goto back;
287215516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
287315516c77SSepherosa Ziehau 
287415516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
287515516c77SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
287615516c77SSepherosa Ziehau 	} else {
287715516c77SSepherosa Ziehau 		/* Not RSS capable, at least for now; just save the RSS key. */
287815516c77SSepherosa Ziehau 		error = 0;
287915516c77SSepherosa Ziehau 	}
288015516c77SSepherosa Ziehau back:
288115516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
288215516c77SSepherosa Ziehau 	return (error);
288315516c77SSepherosa Ziehau }
288415516c77SSepherosa Ziehau 
288515516c77SSepherosa Ziehau static int
288615516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS)
288715516c77SSepherosa Ziehau {
288815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
288915516c77SSepherosa Ziehau 	int error;
289015516c77SSepherosa Ziehau 
289115516c77SSepherosa Ziehau 	HN_LOCK(sc);
289215516c77SSepherosa Ziehau 
289315516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
289415516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
289515516c77SSepherosa Ziehau 		goto back;
289615516c77SSepherosa Ziehau 
289715516c77SSepherosa Ziehau 	/*
289815516c77SSepherosa Ziehau 	 * Don't allow RSS indirect table change, if this interface is not
289915516c77SSepherosa Ziehau 	 * RSS capable currently.
290015516c77SSepherosa Ziehau 	 */
290115516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
290215516c77SSepherosa Ziehau 		error = EOPNOTSUPP;
290315516c77SSepherosa Ziehau 		goto back;
290415516c77SSepherosa Ziehau 	}
290515516c77SSepherosa Ziehau 
290615516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
290715516c77SSepherosa Ziehau 	if (error)
290815516c77SSepherosa Ziehau 		goto back;
290915516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSIND;
291015516c77SSepherosa Ziehau 
291115516c77SSepherosa Ziehau 	hn_rss_ind_fixup(sc, sc->hn_rx_ring_inuse);
291215516c77SSepherosa Ziehau 	error = hn_rss_reconfig(sc);
291315516c77SSepherosa Ziehau back:
291415516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
291515516c77SSepherosa Ziehau 	return (error);
291615516c77SSepherosa Ziehau }
291715516c77SSepherosa Ziehau 
291815516c77SSepherosa Ziehau static int
291915516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS)
292015516c77SSepherosa Ziehau {
292115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
292215516c77SSepherosa Ziehau 	char hash_str[128];
292315516c77SSepherosa Ziehau 	uint32_t hash;
292415516c77SSepherosa Ziehau 
292515516c77SSepherosa Ziehau 	HN_LOCK(sc);
292615516c77SSepherosa Ziehau 	hash = sc->hn_rss_hash;
292715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
292815516c77SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
292915516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
293015516c77SSepherosa Ziehau }
293115516c77SSepherosa Ziehau 
293215516c77SSepherosa Ziehau static int
293315516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff)
293415516c77SSepherosa Ziehau {
293515516c77SSepherosa Ziehau 	const struct ip *ip;
293615516c77SSepherosa Ziehau 	int len, iphlen, iplen;
293715516c77SSepherosa Ziehau 	const struct tcphdr *th;
293815516c77SSepherosa Ziehau 	int thoff;				/* TCP data offset */
293915516c77SSepherosa Ziehau 
294015516c77SSepherosa Ziehau 	len = hoff + sizeof(struct ip);
294115516c77SSepherosa Ziehau 
294215516c77SSepherosa Ziehau 	/* The packet must be at least the size of an IP header. */
294315516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < len)
294415516c77SSepherosa Ziehau 		return IPPROTO_DONE;
294515516c77SSepherosa Ziehau 
294615516c77SSepherosa Ziehau 	/* The fixed IP header must reside completely in the first mbuf. */
294715516c77SSepherosa Ziehau 	if (m->m_len < len)
294815516c77SSepherosa Ziehau 		return IPPROTO_DONE;
294915516c77SSepherosa Ziehau 
295015516c77SSepherosa Ziehau 	ip = mtodo(m, hoff);
295115516c77SSepherosa Ziehau 
295215516c77SSepherosa Ziehau 	/* Bound check the packet's stated IP header length. */
295315516c77SSepherosa Ziehau 	iphlen = ip->ip_hl << 2;
295415516c77SSepherosa Ziehau 	if (iphlen < sizeof(struct ip))		/* minimum header length */
295515516c77SSepherosa Ziehau 		return IPPROTO_DONE;
295615516c77SSepherosa Ziehau 
295715516c77SSepherosa Ziehau 	/* The full IP header must reside completely in the one mbuf. */
295815516c77SSepherosa Ziehau 	if (m->m_len < hoff + iphlen)
295915516c77SSepherosa Ziehau 		return IPPROTO_DONE;
296015516c77SSepherosa Ziehau 
296115516c77SSepherosa Ziehau 	iplen = ntohs(ip->ip_len);
296215516c77SSepherosa Ziehau 
296315516c77SSepherosa Ziehau 	/*
296415516c77SSepherosa Ziehau 	 * Check that the amount of data in the buffers is as
296515516c77SSepherosa Ziehau 	 * at least much as the IP header would have us expect.
296615516c77SSepherosa Ziehau 	 */
296715516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < hoff + iplen)
296815516c77SSepherosa Ziehau 		return IPPROTO_DONE;
296915516c77SSepherosa Ziehau 
297015516c77SSepherosa Ziehau 	/*
297115516c77SSepherosa Ziehau 	 * Ignore IP fragments.
297215516c77SSepherosa Ziehau 	 */
297315516c77SSepherosa Ziehau 	if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF))
297415516c77SSepherosa Ziehau 		return IPPROTO_DONE;
297515516c77SSepherosa Ziehau 
297615516c77SSepherosa Ziehau 	/*
297715516c77SSepherosa Ziehau 	 * The TCP/IP or UDP/IP header must be entirely contained within
297815516c77SSepherosa Ziehau 	 * the first fragment of a packet.
297915516c77SSepherosa Ziehau 	 */
298015516c77SSepherosa Ziehau 	switch (ip->ip_p) {
298115516c77SSepherosa Ziehau 	case IPPROTO_TCP:
298215516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct tcphdr))
298315516c77SSepherosa Ziehau 			return IPPROTO_DONE;
298415516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct tcphdr))
298515516c77SSepherosa Ziehau 			return IPPROTO_DONE;
298615516c77SSepherosa Ziehau 		th = (const struct tcphdr *)((const uint8_t *)ip + iphlen);
298715516c77SSepherosa Ziehau 		thoff = th->th_off << 2;
298815516c77SSepherosa Ziehau 		if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen)
298915516c77SSepherosa Ziehau 			return IPPROTO_DONE;
299015516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + thoff)
299115516c77SSepherosa Ziehau 			return IPPROTO_DONE;
299215516c77SSepherosa Ziehau 		break;
299315516c77SSepherosa Ziehau 	case IPPROTO_UDP:
299415516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct udphdr))
299515516c77SSepherosa Ziehau 			return IPPROTO_DONE;
299615516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct udphdr))
299715516c77SSepherosa Ziehau 			return IPPROTO_DONE;
299815516c77SSepherosa Ziehau 		break;
299915516c77SSepherosa Ziehau 	default:
300015516c77SSepherosa Ziehau 		if (iplen < iphlen)
300115516c77SSepherosa Ziehau 			return IPPROTO_DONE;
300215516c77SSepherosa Ziehau 		break;
300315516c77SSepherosa Ziehau 	}
300415516c77SSepherosa Ziehau 	return ip->ip_p;
300515516c77SSepherosa Ziehau }
300615516c77SSepherosa Ziehau 
300715516c77SSepherosa Ziehau static int
300815516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt)
300915516c77SSepherosa Ziehau {
301015516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
301115516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
301215516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
301315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
301415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
301515516c77SSepherosa Ziehau 	int lroent_cnt;
301615516c77SSepherosa Ziehau #endif
301715516c77SSepherosa Ziehau #endif
301815516c77SSepherosa Ziehau 	int i;
301915516c77SSepherosa Ziehau 
302015516c77SSepherosa Ziehau 	/*
302115516c77SSepherosa Ziehau 	 * Create RXBUF for reception.
302215516c77SSepherosa Ziehau 	 *
302315516c77SSepherosa Ziehau 	 * NOTE:
302415516c77SSepherosa Ziehau 	 * - It is shared by all channels.
302515516c77SSepherosa Ziehau 	 * - A large enough buffer is allocated, certain version of NVSes
302615516c77SSepherosa Ziehau 	 *   may further limit the usable space.
302715516c77SSepherosa Ziehau 	 */
302815516c77SSepherosa Ziehau 	sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
302915516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma,
303015516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
303115516c77SSepherosa Ziehau 	if (sc->hn_rxbuf == NULL) {
303215516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate rxbuf failed\n");
303315516c77SSepherosa Ziehau 		return (ENOMEM);
303415516c77SSepherosa Ziehau 	}
303515516c77SSepherosa Ziehau 
303615516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = ring_cnt;
303715516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt;
303815516c77SSepherosa Ziehau 
303915516c77SSepherosa Ziehau 	sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt,
304015516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
304115516c77SSepherosa Ziehau 
304215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
304315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
304415516c77SSepherosa Ziehau 	lroent_cnt = hn_lro_entry_count;
304515516c77SSepherosa Ziehau 	if (lroent_cnt < TCP_LRO_ENTRIES)
304615516c77SSepherosa Ziehau 		lroent_cnt = TCP_LRO_ENTRIES;
304715516c77SSepherosa Ziehau 	if (bootverbose)
304815516c77SSepherosa Ziehau 		device_printf(dev, "LRO: entry count %d\n", lroent_cnt);
304915516c77SSepherosa Ziehau #endif
305015516c77SSepherosa Ziehau #endif	/* INET || INET6 */
305115516c77SSepherosa Ziehau 
305215516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
305315516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
305415516c77SSepherosa Ziehau 
305515516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.rx sysctl tree */
305615516c77SSepherosa Ziehau 	sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx",
305715516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
305815516c77SSepherosa Ziehau 
305915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
306015516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
306115516c77SSepherosa Ziehau 
306215516c77SSepherosa Ziehau 		rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
306315516c77SSepherosa Ziehau 		    PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE,
306415516c77SSepherosa Ziehau 		    &rxr->hn_br_dma, BUS_DMA_WAITOK);
306515516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL) {
306615516c77SSepherosa Ziehau 			device_printf(dev, "allocate bufring failed\n");
306715516c77SSepherosa Ziehau 			return (ENOMEM);
306815516c77SSepherosa Ziehau 		}
306915516c77SSepherosa Ziehau 
307015516c77SSepherosa Ziehau 		if (hn_trust_hosttcp)
307115516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP;
307215516c77SSepherosa Ziehau 		if (hn_trust_hostudp)
307315516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP;
307415516c77SSepherosa Ziehau 		if (hn_trust_hostip)
307515516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP;
307615516c77SSepherosa Ziehau 		rxr->hn_ifp = sc->hn_ifp;
307715516c77SSepherosa Ziehau 		if (i < sc->hn_tx_ring_cnt)
307815516c77SSepherosa Ziehau 			rxr->hn_txr = &sc->hn_tx_ring[i];
307915516c77SSepherosa Ziehau 		rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF;
308015516c77SSepherosa Ziehau 		rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK);
308115516c77SSepherosa Ziehau 		rxr->hn_rx_idx = i;
308215516c77SSepherosa Ziehau 		rxr->hn_rxbuf = sc->hn_rxbuf;
308315516c77SSepherosa Ziehau 
308415516c77SSepherosa Ziehau 		/*
308515516c77SSepherosa Ziehau 		 * Initialize LRO.
308615516c77SSepherosa Ziehau 		 */
308715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
308815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
308915516c77SSepherosa Ziehau 		tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt,
309015516c77SSepherosa Ziehau 		    hn_lro_mbufq_depth);
309115516c77SSepherosa Ziehau #else
309215516c77SSepherosa Ziehau 		tcp_lro_init(&rxr->hn_lro);
309315516c77SSepherosa Ziehau 		rxr->hn_lro.ifp = sc->hn_ifp;
309415516c77SSepherosa Ziehau #endif
309515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
309615516c77SSepherosa Ziehau 		rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF;
309715516c77SSepherosa Ziehau 		rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF;
309815516c77SSepherosa Ziehau #endif
309915516c77SSepherosa Ziehau #endif	/* INET || INET6 */
310015516c77SSepherosa Ziehau 
310115516c77SSepherosa Ziehau 		if (sc->hn_rx_sysctl_tree != NULL) {
310215516c77SSepherosa Ziehau 			char name[16];
310315516c77SSepherosa Ziehau 
310415516c77SSepherosa Ziehau 			/*
310515516c77SSepherosa Ziehau 			 * Create per RX ring sysctl tree:
310615516c77SSepherosa Ziehau 			 * dev.hn.UNIT.rx.RINGID
310715516c77SSepherosa Ziehau 			 */
310815516c77SSepherosa Ziehau 			snprintf(name, sizeof(name), "%d", i);
310915516c77SSepherosa Ziehau 			rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx,
311015516c77SSepherosa Ziehau 			    SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree),
311115516c77SSepherosa Ziehau 			    OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
311215516c77SSepherosa Ziehau 
311315516c77SSepherosa Ziehau 			if (rxr->hn_rx_sysctl_tree != NULL) {
311415516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
311515516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
311615516c77SSepherosa Ziehau 				    OID_AUTO, "packets", CTLFLAG_RW,
311715516c77SSepherosa Ziehau 				    &rxr->hn_pkts, "# of packets received");
311815516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
311915516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
312015516c77SSepherosa Ziehau 				    OID_AUTO, "rss_pkts", CTLFLAG_RW,
312115516c77SSepherosa Ziehau 				    &rxr->hn_rss_pkts,
312215516c77SSepherosa Ziehau 				    "# of packets w/ RSS info received");
312315516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx,
312415516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
312515516c77SSepherosa Ziehau 				    OID_AUTO, "pktbuf_len", CTLFLAG_RD,
312615516c77SSepherosa Ziehau 				    &rxr->hn_pktbuf_len, 0,
312715516c77SSepherosa Ziehau 				    "Temporary channel packet buffer length");
312815516c77SSepherosa Ziehau 			}
312915516c77SSepherosa Ziehau 		}
313015516c77SSepherosa Ziehau 	}
313115516c77SSepherosa Ziehau 
313215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued",
313315516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
313415516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_queued),
313515516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
313615516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
313715516c77SSepherosa Ziehau #else
313815516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
313915516c77SSepherosa Ziehau #endif
314015516c77SSepherosa Ziehau 	    "LU", "LRO queued");
314115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed",
314215516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
314315516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_flushed),
314415516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
314515516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
314615516c77SSepherosa Ziehau #else
314715516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
314815516c77SSepherosa Ziehau #endif
314915516c77SSepherosa Ziehau 	    "LU", "LRO flushed");
315015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried",
315115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
315215516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro_tried),
315315516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries");
315415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
315515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim",
315615516c77SSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
315715516c77SSepherosa Ziehau 	    hn_lro_lenlim_sysctl, "IU",
315815516c77SSepherosa Ziehau 	    "Max # of data bytes to be aggregated by LRO");
315915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim",
316015516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
316115516c77SSepherosa Ziehau 	    hn_lro_ackcnt_sysctl, "I",
316215516c77SSepherosa Ziehau 	    "Max # of ACKs to be aggregated by LRO");
316315516c77SSepherosa Ziehau #endif
316415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp",
316515516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP,
316615516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
316715516c77SSepherosa Ziehau 	    "Trust tcp segement verification on host side, "
316815516c77SSepherosa Ziehau 	    "when csum info is missing");
316915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp",
317015516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP,
317115516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
317215516c77SSepherosa Ziehau 	    "Trust udp datagram verification on host side, "
317315516c77SSepherosa Ziehau 	    "when csum info is missing");
317415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip",
317515516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP,
317615516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
317715516c77SSepherosa Ziehau 	    "Trust ip packet verification on host side, "
317815516c77SSepherosa Ziehau 	    "when csum info is missing");
317915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip",
318015516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
318115516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_ip),
318215516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP");
318315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp",
318415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
318515516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_tcp),
318615516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP");
318715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp",
318815516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
318915516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_udp),
319015516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP");
319115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted",
319215516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
319315516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_trusted),
319415516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU",
319515516c77SSepherosa Ziehau 	    "# of packets that we trust host's csum verification");
319615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts",
319715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
319815516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_small_pkts),
319915516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of small packets received");
320015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed",
320115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
320215516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_ack_failed),
320315516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures");
320415516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt",
320515516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings");
320615516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse",
320715516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings");
320815516c77SSepherosa Ziehau 
320915516c77SSepherosa Ziehau 	return (0);
321015516c77SSepherosa Ziehau }
321115516c77SSepherosa Ziehau 
321215516c77SSepherosa Ziehau static void
321315516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc)
321415516c77SSepherosa Ziehau {
321515516c77SSepherosa Ziehau 	int i;
321615516c77SSepherosa Ziehau 
321715516c77SSepherosa Ziehau 	if (sc->hn_rxbuf != NULL) {
321815516c77SSepherosa Ziehau 		hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf);
321915516c77SSepherosa Ziehau 		sc->hn_rxbuf = NULL;
322015516c77SSepherosa Ziehau 	}
322115516c77SSepherosa Ziehau 
322215516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_cnt == 0)
322315516c77SSepherosa Ziehau 		return;
322415516c77SSepherosa Ziehau 
322515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
322615516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
322715516c77SSepherosa Ziehau 
322815516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL)
322915516c77SSepherosa Ziehau 			continue;
323015516c77SSepherosa Ziehau 		hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br);
323115516c77SSepherosa Ziehau 		rxr->hn_br = NULL;
323215516c77SSepherosa Ziehau 
323315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
323415516c77SSepherosa Ziehau 		tcp_lro_free(&rxr->hn_lro);
323515516c77SSepherosa Ziehau #endif
323615516c77SSepherosa Ziehau 		free(rxr->hn_pktbuf, M_DEVBUF);
323715516c77SSepherosa Ziehau 	}
323815516c77SSepherosa Ziehau 	free(sc->hn_rx_ring, M_DEVBUF);
323915516c77SSepherosa Ziehau 	sc->hn_rx_ring = NULL;
324015516c77SSepherosa Ziehau 
324115516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = 0;
324215516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = 0;
324315516c77SSepherosa Ziehau }
324415516c77SSepherosa Ziehau 
324515516c77SSepherosa Ziehau static int
324615516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id)
324715516c77SSepherosa Ziehau {
324815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[id];
324915516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
325015516c77SSepherosa Ziehau 	bus_dma_tag_t parent_dtag;
325115516c77SSepherosa Ziehau 	int error, i;
325215516c77SSepherosa Ziehau 
325315516c77SSepherosa Ziehau 	txr->hn_sc = sc;
325415516c77SSepherosa Ziehau 	txr->hn_tx_idx = id;
325515516c77SSepherosa Ziehau 
325615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
325715516c77SSepherosa Ziehau 	mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN);
325815516c77SSepherosa Ziehau #endif
325915516c77SSepherosa Ziehau 	mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF);
326015516c77SSepherosa Ziehau 
326115516c77SSepherosa Ziehau 	txr->hn_txdesc_cnt = HN_TX_DESC_CNT;
326215516c77SSepherosa Ziehau 	txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt,
326315516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
326415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
326515516c77SSepherosa Ziehau 	SLIST_INIT(&txr->hn_txlist);
326615516c77SSepherosa Ziehau #else
326715516c77SSepherosa Ziehau 	txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF,
326815516c77SSepherosa Ziehau 	    M_WAITOK, &txr->hn_tx_lock);
326915516c77SSepherosa Ziehau #endif
327015516c77SSepherosa Ziehau 
327115516c77SSepherosa Ziehau 	txr->hn_tx_taskq = sc->hn_tx_taskq;
327215516c77SSepherosa Ziehau 
327323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
327415516c77SSepherosa Ziehau 	if (hn_use_if_start) {
327515516c77SSepherosa Ziehau 		txr->hn_txeof = hn_start_txeof;
327615516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr);
327715516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr);
327823bf9e15SSepherosa Ziehau 	} else
327923bf9e15SSepherosa Ziehau #endif
328023bf9e15SSepherosa Ziehau 	{
328115516c77SSepherosa Ziehau 		int br_depth;
328215516c77SSepherosa Ziehau 
328315516c77SSepherosa Ziehau 		txr->hn_txeof = hn_xmit_txeof;
328415516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr);
328515516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr);
328615516c77SSepherosa Ziehau 
328715516c77SSepherosa Ziehau 		br_depth = hn_get_txswq_depth(txr);
328815516c77SSepherosa Ziehau 		txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF,
328915516c77SSepherosa Ziehau 		    M_WAITOK, &txr->hn_tx_lock);
329015516c77SSepherosa Ziehau 	}
329115516c77SSepherosa Ziehau 
329215516c77SSepherosa Ziehau 	txr->hn_direct_tx_size = hn_direct_tx_size;
329315516c77SSepherosa Ziehau 
329415516c77SSepherosa Ziehau 	/*
329515516c77SSepherosa Ziehau 	 * Always schedule transmission instead of trying to do direct
329615516c77SSepherosa Ziehau 	 * transmission.  This one gives the best performance so far.
329715516c77SSepherosa Ziehau 	 */
329815516c77SSepherosa Ziehau 	txr->hn_sched_tx = 1;
329915516c77SSepherosa Ziehau 
330015516c77SSepherosa Ziehau 	parent_dtag = bus_get_dma_tag(dev);
330115516c77SSepherosa Ziehau 
330215516c77SSepherosa Ziehau 	/* DMA tag for RNDIS packet messages. */
330315516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
330415516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_ALIGN,		/* alignment */
330515516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_BOUNDARY,	/* boundary */
330615516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
330715516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
330815516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
330915516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsize */
331015516c77SSepherosa Ziehau 	    1,				/* nsegments */
331115516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsegsize */
331215516c77SSepherosa Ziehau 	    0,				/* flags */
331315516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
331415516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
331515516c77SSepherosa Ziehau 	    &txr->hn_tx_rndis_dtag);
331615516c77SSepherosa Ziehau 	if (error) {
331715516c77SSepherosa Ziehau 		device_printf(dev, "failed to create rndis dmatag\n");
331815516c77SSepherosa Ziehau 		return error;
331915516c77SSepherosa Ziehau 	}
332015516c77SSepherosa Ziehau 
332115516c77SSepherosa Ziehau 	/* DMA tag for data. */
332215516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
332315516c77SSepherosa Ziehau 	    1,				/* alignment */
332415516c77SSepherosa Ziehau 	    HN_TX_DATA_BOUNDARY,	/* boundary */
332515516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
332615516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
332715516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
332815516c77SSepherosa Ziehau 	    HN_TX_DATA_MAXSIZE,		/* maxsize */
332915516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGCNT_MAX,	/* nsegments */
333015516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGSIZE,		/* maxsegsize */
333115516c77SSepherosa Ziehau 	    0,				/* flags */
333215516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
333315516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
333415516c77SSepherosa Ziehau 	    &txr->hn_tx_data_dtag);
333515516c77SSepherosa Ziehau 	if (error) {
333615516c77SSepherosa Ziehau 		device_printf(dev, "failed to create data dmatag\n");
333715516c77SSepherosa Ziehau 		return error;
333815516c77SSepherosa Ziehau 	}
333915516c77SSepherosa Ziehau 
334015516c77SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i) {
334115516c77SSepherosa Ziehau 		struct hn_txdesc *txd = &txr->hn_txdesc[i];
334215516c77SSepherosa Ziehau 
334315516c77SSepherosa Ziehau 		txd->txr = txr;
334415516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
3345dc13fee6SSepherosa Ziehau 		STAILQ_INIT(&txd->agg_list);
334615516c77SSepherosa Ziehau 
334715516c77SSepherosa Ziehau 		/*
334815516c77SSepherosa Ziehau 		 * Allocate and load RNDIS packet message.
334915516c77SSepherosa Ziehau 		 */
335015516c77SSepherosa Ziehau         	error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag,
335115516c77SSepherosa Ziehau 		    (void **)&txd->rndis_pkt,
335215516c77SSepherosa Ziehau 		    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
335315516c77SSepherosa Ziehau 		    &txd->rndis_pkt_dmap);
335415516c77SSepherosa Ziehau 		if (error) {
335515516c77SSepherosa Ziehau 			device_printf(dev,
335615516c77SSepherosa Ziehau 			    "failed to allocate rndis_packet_msg, %d\n", i);
335715516c77SSepherosa Ziehau 			return error;
335815516c77SSepherosa Ziehau 		}
335915516c77SSepherosa Ziehau 
336015516c77SSepherosa Ziehau 		error = bus_dmamap_load(txr->hn_tx_rndis_dtag,
336115516c77SSepherosa Ziehau 		    txd->rndis_pkt_dmap,
336215516c77SSepherosa Ziehau 		    txd->rndis_pkt, HN_RNDIS_PKT_LEN,
336315516c77SSepherosa Ziehau 		    hyperv_dma_map_paddr, &txd->rndis_pkt_paddr,
336415516c77SSepherosa Ziehau 		    BUS_DMA_NOWAIT);
336515516c77SSepherosa Ziehau 		if (error) {
336615516c77SSepherosa Ziehau 			device_printf(dev,
336715516c77SSepherosa Ziehau 			    "failed to load rndis_packet_msg, %d\n", i);
336815516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
336915516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
337015516c77SSepherosa Ziehau 			return error;
337115516c77SSepherosa Ziehau 		}
337215516c77SSepherosa Ziehau 
337315516c77SSepherosa Ziehau 		/* DMA map for TX data. */
337415516c77SSepherosa Ziehau 		error = bus_dmamap_create(txr->hn_tx_data_dtag, 0,
337515516c77SSepherosa Ziehau 		    &txd->data_dmap);
337615516c77SSepherosa Ziehau 		if (error) {
337715516c77SSepherosa Ziehau 			device_printf(dev,
337815516c77SSepherosa Ziehau 			    "failed to allocate tx data dmamap\n");
337915516c77SSepherosa Ziehau 			bus_dmamap_unload(txr->hn_tx_rndis_dtag,
338015516c77SSepherosa Ziehau 			    txd->rndis_pkt_dmap);
338115516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
338215516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
338315516c77SSepherosa Ziehau 			return error;
338415516c77SSepherosa Ziehau 		}
338515516c77SSepherosa Ziehau 
338615516c77SSepherosa Ziehau 		/* All set, put it to list */
338715516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_ONLIST;
338815516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
338915516c77SSepherosa Ziehau 		SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
339015516c77SSepherosa Ziehau #else
339115516c77SSepherosa Ziehau 		buf_ring_enqueue(txr->hn_txdesc_br, txd);
339215516c77SSepherosa Ziehau #endif
339315516c77SSepherosa Ziehau 	}
339415516c77SSepherosa Ziehau 	txr->hn_txdesc_avail = txr->hn_txdesc_cnt;
339515516c77SSepherosa Ziehau 
339615516c77SSepherosa Ziehau 	if (sc->hn_tx_sysctl_tree != NULL) {
339715516c77SSepherosa Ziehau 		struct sysctl_oid_list *child;
339815516c77SSepherosa Ziehau 		struct sysctl_ctx_list *ctx;
339915516c77SSepherosa Ziehau 		char name[16];
340015516c77SSepherosa Ziehau 
340115516c77SSepherosa Ziehau 		/*
340215516c77SSepherosa Ziehau 		 * Create per TX ring sysctl tree:
340315516c77SSepherosa Ziehau 		 * dev.hn.UNIT.tx.RINGID
340415516c77SSepherosa Ziehau 		 */
340515516c77SSepherosa Ziehau 		ctx = device_get_sysctl_ctx(dev);
340615516c77SSepherosa Ziehau 		child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree);
340715516c77SSepherosa Ziehau 
340815516c77SSepherosa Ziehau 		snprintf(name, sizeof(name), "%d", id);
340915516c77SSepherosa Ziehau 		txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
341015516c77SSepherosa Ziehau 		    name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
341115516c77SSepherosa Ziehau 
341215516c77SSepherosa Ziehau 		if (txr->hn_tx_sysctl_tree != NULL) {
341315516c77SSepherosa Ziehau 			child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree);
341415516c77SSepherosa Ziehau 
341515516c77SSepherosa Ziehau 			SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail",
341615516c77SSepherosa Ziehau 			    CTLFLAG_RD, &txr->hn_txdesc_avail, 0,
341715516c77SSepherosa Ziehau 			    "# of available TX descs");
341823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
341923bf9e15SSepherosa Ziehau 			if (!hn_use_if_start)
342023bf9e15SSepherosa Ziehau #endif
342123bf9e15SSepherosa Ziehau 			{
342215516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive",
342315516c77SSepherosa Ziehau 				    CTLFLAG_RD, &txr->hn_oactive, 0,
342415516c77SSepherosa Ziehau 				    "over active");
342515516c77SSepherosa Ziehau 			}
342615516c77SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets",
342715516c77SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_pkts,
342815516c77SSepherosa Ziehau 			    "# of packets transmitted");
3429dc13fee6SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends",
3430dc13fee6SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_sends, "# of sends");
343115516c77SSepherosa Ziehau 		}
343215516c77SSepherosa Ziehau 	}
343315516c77SSepherosa Ziehau 
343415516c77SSepherosa Ziehau 	return 0;
343515516c77SSepherosa Ziehau }
343615516c77SSepherosa Ziehau 
343715516c77SSepherosa Ziehau static void
343815516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd)
343915516c77SSepherosa Ziehau {
344015516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = txd->txr;
344115516c77SSepherosa Ziehau 
344215516c77SSepherosa Ziehau 	KASSERT(txd->m == NULL, ("still has mbuf installed"));
344315516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped"));
344415516c77SSepherosa Ziehau 
344515516c77SSepherosa Ziehau 	bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap);
344615516c77SSepherosa Ziehau 	bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt,
344715516c77SSepherosa Ziehau 	    txd->rndis_pkt_dmap);
344815516c77SSepherosa Ziehau 	bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap);
344915516c77SSepherosa Ziehau }
345015516c77SSepherosa Ziehau 
345115516c77SSepherosa Ziehau static void
345215516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr)
345315516c77SSepherosa Ziehau {
345415516c77SSepherosa Ziehau 	struct hn_txdesc *txd;
345515516c77SSepherosa Ziehau 
345615516c77SSepherosa Ziehau 	if (txr->hn_txdesc == NULL)
345715516c77SSepherosa Ziehau 		return;
345815516c77SSepherosa Ziehau 
345915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
346015516c77SSepherosa Ziehau 	while ((txd = SLIST_FIRST(&txr->hn_txlist)) != NULL) {
346115516c77SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&txr->hn_txlist, link);
346215516c77SSepherosa Ziehau 		hn_txdesc_dmamap_destroy(txd);
346315516c77SSepherosa Ziehau 	}
346415516c77SSepherosa Ziehau #else
346515516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
346615516c77SSepherosa Ziehau 	while ((txd = buf_ring_dequeue_sc(txr->hn_txdesc_br)) != NULL)
346715516c77SSepherosa Ziehau 		hn_txdesc_dmamap_destroy(txd);
346815516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
346915516c77SSepherosa Ziehau #endif
347015516c77SSepherosa Ziehau 
347115516c77SSepherosa Ziehau 	if (txr->hn_tx_data_dtag != NULL)
347215516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_data_dtag);
347315516c77SSepherosa Ziehau 	if (txr->hn_tx_rndis_dtag != NULL)
347415516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_rndis_dtag);
347515516c77SSepherosa Ziehau 
347615516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
347715516c77SSepherosa Ziehau 	buf_ring_free(txr->hn_txdesc_br, M_DEVBUF);
347815516c77SSepherosa Ziehau #endif
347915516c77SSepherosa Ziehau 
348015516c77SSepherosa Ziehau 	free(txr->hn_txdesc, M_DEVBUF);
348115516c77SSepherosa Ziehau 	txr->hn_txdesc = NULL;
348215516c77SSepherosa Ziehau 
348315516c77SSepherosa Ziehau 	if (txr->hn_mbuf_br != NULL)
348415516c77SSepherosa Ziehau 		buf_ring_free(txr->hn_mbuf_br, M_DEVBUF);
348515516c77SSepherosa Ziehau 
348615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
348715516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_txlist_spin);
348815516c77SSepherosa Ziehau #endif
348915516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_tx_lock);
349015516c77SSepherosa Ziehau }
349115516c77SSepherosa Ziehau 
349215516c77SSepherosa Ziehau static int
349315516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt)
349415516c77SSepherosa Ziehau {
349515516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
349615516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
349715516c77SSepherosa Ziehau 	int i;
349815516c77SSepherosa Ziehau 
349915516c77SSepherosa Ziehau 	/*
350015516c77SSepherosa Ziehau 	 * Create TXBUF for chimney sending.
350115516c77SSepherosa Ziehau 	 *
350215516c77SSepherosa Ziehau 	 * NOTE: It is shared by all channels.
350315516c77SSepherosa Ziehau 	 */
350415516c77SSepherosa Ziehau 	sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev),
350515516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma,
350615516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
350715516c77SSepherosa Ziehau 	if (sc->hn_chim == NULL) {
350815516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate txbuf failed\n");
350915516c77SSepherosa Ziehau 		return (ENOMEM);
351015516c77SSepherosa Ziehau 	}
351115516c77SSepherosa Ziehau 
351215516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = ring_cnt;
351315516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
351415516c77SSepherosa Ziehau 
351515516c77SSepherosa Ziehau 	sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt,
351615516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
351715516c77SSepherosa Ziehau 
351815516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(sc->hn_dev);
351915516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev));
352015516c77SSepherosa Ziehau 
352115516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.tx sysctl tree */
352215516c77SSepherosa Ziehau 	sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx",
352315516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
352415516c77SSepherosa Ziehau 
352515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
352615516c77SSepherosa Ziehau 		int error;
352715516c77SSepherosa Ziehau 
352815516c77SSepherosa Ziehau 		error = hn_tx_ring_create(sc, i);
352915516c77SSepherosa Ziehau 		if (error)
353015516c77SSepherosa Ziehau 			return error;
353115516c77SSepherosa Ziehau 	}
353215516c77SSepherosa Ziehau 
353315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs",
353415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
353515516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_no_txdescs),
353615516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs");
353715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed",
353815516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
353915516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_send_failed),
354015516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure");
354115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed",
354215516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
354315516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_txdma_failed),
354415516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure");
3545dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed",
3546dc13fee6SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
3547dc13fee6SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_flush_failed),
3548dc13fee6SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU",
3549dc13fee6SSepherosa Ziehau 	    "# of packet transmission aggregation flush failure");
355015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed",
355115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
355215516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_collapsed),
355315516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed");
355415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney",
355515516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
355615516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney),
355715516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send");
355815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried",
355915516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
356015516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney_tried),
356115516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries");
356215516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt",
356315516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0,
356415516c77SSepherosa Ziehau 	    "# of total TX descs");
356515516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max",
356615516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_chim_szmax, 0,
356715516c77SSepherosa Ziehau 	    "Chimney send packet size upper boundary");
356815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size",
356915516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
357015516c77SSepherosa Ziehau 	    hn_chim_size_sysctl, "I", "Chimney send packet size limit");
357115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size",
357215516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
357315516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_direct_tx_size),
357415516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
357515516c77SSepherosa Ziehau 	    "Size of the packet for direct transmission");
357615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx",
357715516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
357815516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_sched_tx),
357915516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
358015516c77SSepherosa Ziehau 	    "Always schedule transmission "
358115516c77SSepherosa Ziehau 	    "instead of doing direct transmission");
358215516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt",
358315516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings");
358415516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse",
358515516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings");
3586dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax",
3587dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0,
3588dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation size");
3589dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax",
3590dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
3591dc13fee6SSepherosa Ziehau 	    hn_txagg_pktmax_sysctl, "I",
3592dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation packets");
3593dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align",
3594dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
3595dc13fee6SSepherosa Ziehau 	    hn_txagg_align_sysctl, "I",
3596dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation alignment");
359715516c77SSepherosa Ziehau 
359815516c77SSepherosa Ziehau 	return 0;
359915516c77SSepherosa Ziehau }
360015516c77SSepherosa Ziehau 
360115516c77SSepherosa Ziehau static void
360215516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size)
360315516c77SSepherosa Ziehau {
360415516c77SSepherosa Ziehau 	int i;
360515516c77SSepherosa Ziehau 
360615516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
360715516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_chim_size = chim_size;
360815516c77SSepherosa Ziehau }
360915516c77SSepherosa Ziehau 
361015516c77SSepherosa Ziehau static void
361115516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu)
361215516c77SSepherosa Ziehau {
361315516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
361415516c77SSepherosa Ziehau 	int tso_minlen;
361515516c77SSepherosa Ziehau 
361615516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0)
361715516c77SSepherosa Ziehau 		return;
361815516c77SSepherosa Ziehau 
361915516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_sgmin >= 2,
362015516c77SSepherosa Ziehau 	    ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin));
362115516c77SSepherosa Ziehau 	tso_minlen = sc->hn_ndis_tso_sgmin * mtu;
362215516c77SSepherosa Ziehau 
362315516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen &&
362415516c77SSepherosa Ziehau 	    sc->hn_ndis_tso_szmax <= IP_MAXPACKET,
362515516c77SSepherosa Ziehau 	    ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax));
362615516c77SSepherosa Ziehau 
362715516c77SSepherosa Ziehau 	if (tso_maxlen < tso_minlen)
362815516c77SSepherosa Ziehau 		tso_maxlen = tso_minlen;
362915516c77SSepherosa Ziehau 	else if (tso_maxlen > IP_MAXPACKET)
363015516c77SSepherosa Ziehau 		tso_maxlen = IP_MAXPACKET;
363115516c77SSepherosa Ziehau 	if (tso_maxlen > sc->hn_ndis_tso_szmax)
363215516c77SSepherosa Ziehau 		tso_maxlen = sc->hn_ndis_tso_szmax;
363315516c77SSepherosa Ziehau 	ifp->if_hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
363415516c77SSepherosa Ziehau 	if (bootverbose)
363515516c77SSepherosa Ziehau 		if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax);
363615516c77SSepherosa Ziehau }
363715516c77SSepherosa Ziehau 
363815516c77SSepherosa Ziehau static void
363915516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc)
364015516c77SSepherosa Ziehau {
364115516c77SSepherosa Ziehau 	uint64_t csum_assist;
364215516c77SSepherosa Ziehau 	int i;
364315516c77SSepherosa Ziehau 
364415516c77SSepherosa Ziehau 	hn_set_chim_size(sc, sc->hn_chim_szmax);
364515516c77SSepherosa Ziehau 	if (hn_tx_chimney_size > 0 &&
364615516c77SSepherosa Ziehau 	    hn_tx_chimney_size < sc->hn_chim_szmax)
364715516c77SSepherosa Ziehau 		hn_set_chim_size(sc, hn_tx_chimney_size);
364815516c77SSepherosa Ziehau 
364915516c77SSepherosa Ziehau 	csum_assist = 0;
365015516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_IPCS)
365115516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP;
365215516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP4CS)
365315516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_TCP;
365415516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP4CS)
365515516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_UDP;
365615516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP6CS)
365715516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_TCP;
365815516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP6CS)
365915516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_UDP;
366015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
366115516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_csum_assist = csum_assist;
366215516c77SSepherosa Ziehau 
366315516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_HASHVAL) {
366415516c77SSepherosa Ziehau 		/*
366515516c77SSepherosa Ziehau 		 * Support HASHVAL pktinfo on TX path.
366615516c77SSepherosa Ziehau 		 */
366715516c77SSepherosa Ziehau 		if (bootverbose)
366815516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n");
366915516c77SSepherosa Ziehau 		for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
367015516c77SSepherosa Ziehau 			sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL;
367115516c77SSepherosa Ziehau 	}
367215516c77SSepherosa Ziehau }
367315516c77SSepherosa Ziehau 
367415516c77SSepherosa Ziehau static void
367515516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc)
367615516c77SSepherosa Ziehau {
367715516c77SSepherosa Ziehau 	int i;
367815516c77SSepherosa Ziehau 
367915516c77SSepherosa Ziehau 	if (sc->hn_chim != NULL) {
368015516c77SSepherosa Ziehau 		hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim);
368115516c77SSepherosa Ziehau 		sc->hn_chim = NULL;
368215516c77SSepherosa Ziehau 	}
368315516c77SSepherosa Ziehau 
368415516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt == 0)
368515516c77SSepherosa Ziehau 		return;
368615516c77SSepherosa Ziehau 
368715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
368815516c77SSepherosa Ziehau 		hn_tx_ring_destroy(&sc->hn_tx_ring[i]);
368915516c77SSepherosa Ziehau 
369015516c77SSepherosa Ziehau 	free(sc->hn_tx_ring, M_DEVBUF);
369115516c77SSepherosa Ziehau 	sc->hn_tx_ring = NULL;
369215516c77SSepherosa Ziehau 
369315516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = 0;
369415516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = 0;
369515516c77SSepherosa Ziehau }
369615516c77SSepherosa Ziehau 
369723bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
369823bf9e15SSepherosa Ziehau 
369915516c77SSepherosa Ziehau static void
370015516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused)
370115516c77SSepherosa Ziehau {
370215516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
370315516c77SSepherosa Ziehau 
370415516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
370515516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
370615516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
370715516c77SSepherosa Ziehau }
370815516c77SSepherosa Ziehau 
370923bf9e15SSepherosa Ziehau static int
371023bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len)
371123bf9e15SSepherosa Ziehau {
371223bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
371323bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
3714dc13fee6SSepherosa Ziehau 	int sched = 0;
371523bf9e15SSepherosa Ziehau 
371623bf9e15SSepherosa Ziehau 	KASSERT(hn_use_if_start,
371723bf9e15SSepherosa Ziehau 	    ("hn_start_locked is called, when if_start is disabled"));
371823bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
371923bf9e15SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
3720dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
372123bf9e15SSepherosa Ziehau 
372223bf9e15SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
3723dc13fee6SSepherosa Ziehau 		return (0);
372423bf9e15SSepherosa Ziehau 
372523bf9e15SSepherosa Ziehau 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
372623bf9e15SSepherosa Ziehau 	    IFF_DRV_RUNNING)
3727dc13fee6SSepherosa Ziehau 		return (0);
372823bf9e15SSepherosa Ziehau 
372923bf9e15SSepherosa Ziehau 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
373023bf9e15SSepherosa Ziehau 		struct hn_txdesc *txd;
373123bf9e15SSepherosa Ziehau 		struct mbuf *m_head;
373223bf9e15SSepherosa Ziehau 		int error;
373323bf9e15SSepherosa Ziehau 
373423bf9e15SSepherosa Ziehau 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
373523bf9e15SSepherosa Ziehau 		if (m_head == NULL)
373623bf9e15SSepherosa Ziehau 			break;
373723bf9e15SSepherosa Ziehau 
373823bf9e15SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
373923bf9e15SSepherosa Ziehau 			/*
374023bf9e15SSepherosa Ziehau 			 * This sending could be time consuming; let callers
374123bf9e15SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
374223bf9e15SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
374323bf9e15SSepherosa Ziehau 			 */
374423bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
3745dc13fee6SSepherosa Ziehau 			sched = 1;
3746dc13fee6SSepherosa Ziehau 			break;
374723bf9e15SSepherosa Ziehau 		}
374823bf9e15SSepherosa Ziehau 
3749edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
3750edd3f315SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
3751edd3f315SSepherosa Ziehau 			m_head = hn_tso_fixup(m_head);
3752edd3f315SSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
3753edd3f315SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
3754edd3f315SSepherosa Ziehau 				continue;
3755edd3f315SSepherosa Ziehau 			}
3756edd3f315SSepherosa Ziehau 		}
3757edd3f315SSepherosa Ziehau #endif
3758edd3f315SSepherosa Ziehau 
375923bf9e15SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
376023bf9e15SSepherosa Ziehau 		if (txd == NULL) {
376123bf9e15SSepherosa Ziehau 			txr->hn_no_txdescs++;
376223bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
376323bf9e15SSepherosa Ziehau 			atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
376423bf9e15SSepherosa Ziehau 			break;
376523bf9e15SSepherosa Ziehau 		}
376623bf9e15SSepherosa Ziehau 
3767dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
376823bf9e15SSepherosa Ziehau 		if (error) {
376923bf9e15SSepherosa Ziehau 			/* Both txd and m_head are freed */
3770dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
3771dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
377223bf9e15SSepherosa Ziehau 			continue;
377323bf9e15SSepherosa Ziehau 		}
377423bf9e15SSepherosa Ziehau 
3775dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
3776dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
3777dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
3778dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
3779dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
3780dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
3781dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
3782dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
3783dc13fee6SSepherosa Ziehau 					break;
3784dc13fee6SSepherosa Ziehau 				}
3785dc13fee6SSepherosa Ziehau 			} else {
3786dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
378723bf9e15SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
378823bf9e15SSepherosa Ziehau 				if (__predict_false(error)) {
378923bf9e15SSepherosa Ziehau 					/* txd is freed, but m_head is not */
379023bf9e15SSepherosa Ziehau 					IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
3791dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
3792dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
379323bf9e15SSepherosa Ziehau 					break;
379423bf9e15SSepherosa Ziehau 				}
379523bf9e15SSepherosa Ziehau 			}
3796dc13fee6SSepherosa Ziehau 		}
3797dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
3798dc13fee6SSepherosa Ziehau 		else {
3799dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
3800dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
3801dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
3802dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
3803dc13fee6SSepherosa Ziehau 		}
3804dc13fee6SSepherosa Ziehau #endif
3805dc13fee6SSepherosa Ziehau 	}
3806dc13fee6SSepherosa Ziehau 
3807dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
3808dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
3809dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
3810dc13fee6SSepherosa Ziehau 	return (sched);
381123bf9e15SSepherosa Ziehau }
381223bf9e15SSepherosa Ziehau 
381323bf9e15SSepherosa Ziehau static void
381423bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp)
381523bf9e15SSepherosa Ziehau {
381623bf9e15SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
381723bf9e15SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[0];
381823bf9e15SSepherosa Ziehau 
381923bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
382023bf9e15SSepherosa Ziehau 		goto do_sched;
382123bf9e15SSepherosa Ziehau 
382223bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
382323bf9e15SSepherosa Ziehau 		int sched;
382423bf9e15SSepherosa Ziehau 
382523bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
382623bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
382723bf9e15SSepherosa Ziehau 		if (!sched)
382823bf9e15SSepherosa Ziehau 			return;
382923bf9e15SSepherosa Ziehau 	}
383023bf9e15SSepherosa Ziehau do_sched:
383123bf9e15SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
383223bf9e15SSepherosa Ziehau }
383323bf9e15SSepherosa Ziehau 
383415516c77SSepherosa Ziehau static void
383515516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused)
383615516c77SSepherosa Ziehau {
383715516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
383815516c77SSepherosa Ziehau 
383915516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
384015516c77SSepherosa Ziehau 	atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE);
384115516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
384215516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
384315516c77SSepherosa Ziehau }
384415516c77SSepherosa Ziehau 
384523bf9e15SSepherosa Ziehau static void
384623bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr)
384723bf9e15SSepherosa Ziehau {
384823bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
384923bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
385023bf9e15SSepherosa Ziehau 
385123bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
385223bf9e15SSepherosa Ziehau 
385323bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
385423bf9e15SSepherosa Ziehau 		goto do_sched;
385523bf9e15SSepherosa Ziehau 
385623bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
385723bf9e15SSepherosa Ziehau 		int sched;
385823bf9e15SSepherosa Ziehau 
385923bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
386023bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
386123bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
386223bf9e15SSepherosa Ziehau 		if (sched) {
386323bf9e15SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
386423bf9e15SSepherosa Ziehau 			    &txr->hn_tx_task);
386523bf9e15SSepherosa Ziehau 		}
386623bf9e15SSepherosa Ziehau 	} else {
386723bf9e15SSepherosa Ziehau do_sched:
386823bf9e15SSepherosa Ziehau 		/*
386923bf9e15SSepherosa Ziehau 		 * Release the OACTIVE earlier, with the hope, that
387023bf9e15SSepherosa Ziehau 		 * others could catch up.  The task will clear the
387123bf9e15SSepherosa Ziehau 		 * flag again with the hn_tx_lock to avoid possible
387223bf9e15SSepherosa Ziehau 		 * races.
387323bf9e15SSepherosa Ziehau 		 */
387423bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
387523bf9e15SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
387623bf9e15SSepherosa Ziehau 	}
387723bf9e15SSepherosa Ziehau }
387823bf9e15SSepherosa Ziehau 
387923bf9e15SSepherosa Ziehau #endif	/* HN_IFSTART_SUPPORT */
388023bf9e15SSepherosa Ziehau 
388115516c77SSepherosa Ziehau static int
388215516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len)
388315516c77SSepherosa Ziehau {
388415516c77SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
388515516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
388615516c77SSepherosa Ziehau 	struct mbuf *m_head;
3887dc13fee6SSepherosa Ziehau 	int sched = 0;
388815516c77SSepherosa Ziehau 
388915516c77SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
389023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
389115516c77SSepherosa Ziehau 	KASSERT(hn_use_if_start == 0,
389215516c77SSepherosa Ziehau 	    ("hn_xmit is called, when if_start is enabled"));
389323bf9e15SSepherosa Ziehau #endif
3894dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
389515516c77SSepherosa Ziehau 
389615516c77SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
3897dc13fee6SSepherosa Ziehau 		return (0);
389815516c77SSepherosa Ziehau 
389915516c77SSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive)
3900dc13fee6SSepherosa Ziehau 		return (0);
390115516c77SSepherosa Ziehau 
390215516c77SSepherosa Ziehau 	while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) {
390315516c77SSepherosa Ziehau 		struct hn_txdesc *txd;
390415516c77SSepherosa Ziehau 		int error;
390515516c77SSepherosa Ziehau 
390615516c77SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
390715516c77SSepherosa Ziehau 			/*
390815516c77SSepherosa Ziehau 			 * This sending could be time consuming; let callers
390915516c77SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
391015516c77SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
391115516c77SSepherosa Ziehau 			 */
391215516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
3913dc13fee6SSepherosa Ziehau 			sched = 1;
3914dc13fee6SSepherosa Ziehau 			break;
391515516c77SSepherosa Ziehau 		}
391615516c77SSepherosa Ziehau 
391715516c77SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
391815516c77SSepherosa Ziehau 		if (txd == NULL) {
391915516c77SSepherosa Ziehau 			txr->hn_no_txdescs++;
392015516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
392115516c77SSepherosa Ziehau 			txr->hn_oactive = 1;
392215516c77SSepherosa Ziehau 			break;
392315516c77SSepherosa Ziehau 		}
392415516c77SSepherosa Ziehau 
3925dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
392615516c77SSepherosa Ziehau 		if (error) {
392715516c77SSepherosa Ziehau 			/* Both txd and m_head are freed; discard */
3928dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
3929dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
393015516c77SSepherosa Ziehau 			drbr_advance(ifp, txr->hn_mbuf_br);
393115516c77SSepherosa Ziehau 			continue;
393215516c77SSepherosa Ziehau 		}
393315516c77SSepherosa Ziehau 
3934dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
3935dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
3936dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
3937dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
3938dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
393915516c77SSepherosa Ziehau 				if (__predict_false(error)) {
394015516c77SSepherosa Ziehau 					txr->hn_oactive = 1;
394115516c77SSepherosa Ziehau 					break;
394215516c77SSepherosa Ziehau 				}
3943dc13fee6SSepherosa Ziehau 			} else {
3944dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
3945dc13fee6SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
3946dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
3947dc13fee6SSepherosa Ziehau 					/* txd is freed, but m_head is not */
3948dc13fee6SSepherosa Ziehau 					drbr_putback(ifp, txr->hn_mbuf_br,
3949dc13fee6SSepherosa Ziehau 					    m_head);
3950dc13fee6SSepherosa Ziehau 					txr->hn_oactive = 1;
3951dc13fee6SSepherosa Ziehau 					break;
3952dc13fee6SSepherosa Ziehau 				}
3953dc13fee6SSepherosa Ziehau 			}
3954dc13fee6SSepherosa Ziehau 		}
3955dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
3956dc13fee6SSepherosa Ziehau 		else {
3957dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
3958dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
3959dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
3960dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
3961dc13fee6SSepherosa Ziehau 		}
3962dc13fee6SSepherosa Ziehau #endif
396315516c77SSepherosa Ziehau 
396415516c77SSepherosa Ziehau 		/* Sent */
396515516c77SSepherosa Ziehau 		drbr_advance(ifp, txr->hn_mbuf_br);
396615516c77SSepherosa Ziehau 	}
3967dc13fee6SSepherosa Ziehau 
3968dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
3969dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
3970dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
3971dc13fee6SSepherosa Ziehau 	return (sched);
397215516c77SSepherosa Ziehau }
397315516c77SSepherosa Ziehau 
397415516c77SSepherosa Ziehau static int
397515516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m)
397615516c77SSepherosa Ziehau {
397715516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
397815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
397915516c77SSepherosa Ziehau 	int error, idx = 0;
398015516c77SSepherosa Ziehau 
3981edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
3982edd3f315SSepherosa Ziehau 	/*
3983edd3f315SSepherosa Ziehau 	 * Perform TSO packet header fixup now, since the TSO
3984edd3f315SSepherosa Ziehau 	 * packet header should be cache-hot.
3985edd3f315SSepherosa Ziehau 	 */
3986edd3f315SSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
3987edd3f315SSepherosa Ziehau 		m = hn_tso_fixup(m);
3988edd3f315SSepherosa Ziehau 		if (__predict_false(m == NULL)) {
3989edd3f315SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
3990edd3f315SSepherosa Ziehau 			return EIO;
3991edd3f315SSepherosa Ziehau 		}
3992edd3f315SSepherosa Ziehau 	}
3993edd3f315SSepherosa Ziehau #endif
3994edd3f315SSepherosa Ziehau 
399515516c77SSepherosa Ziehau 	/*
399615516c77SSepherosa Ziehau 	 * Select the TX ring based on flowid
399715516c77SSepherosa Ziehau 	 */
399815516c77SSepherosa Ziehau 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
399915516c77SSepherosa Ziehau 		idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse;
400015516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[idx];
400115516c77SSepherosa Ziehau 
400215516c77SSepherosa Ziehau 	error = drbr_enqueue(ifp, txr->hn_mbuf_br, m);
400315516c77SSepherosa Ziehau 	if (error) {
400415516c77SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
400515516c77SSepherosa Ziehau 		return error;
400615516c77SSepherosa Ziehau 	}
400715516c77SSepherosa Ziehau 
400815516c77SSepherosa Ziehau 	if (txr->hn_oactive)
400915516c77SSepherosa Ziehau 		return 0;
401015516c77SSepherosa Ziehau 
401115516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
401215516c77SSepherosa Ziehau 		goto do_sched;
401315516c77SSepherosa Ziehau 
401415516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
401515516c77SSepherosa Ziehau 		int sched;
401615516c77SSepherosa Ziehau 
401715516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
401815516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
401915516c77SSepherosa Ziehau 		if (!sched)
402015516c77SSepherosa Ziehau 			return 0;
402115516c77SSepherosa Ziehau 	}
402215516c77SSepherosa Ziehau do_sched:
402315516c77SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
402415516c77SSepherosa Ziehau 	return 0;
402515516c77SSepherosa Ziehau }
402615516c77SSepherosa Ziehau 
402715516c77SSepherosa Ziehau static void
402815516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr)
402915516c77SSepherosa Ziehau {
403015516c77SSepherosa Ziehau 	struct mbuf *m;
403115516c77SSepherosa Ziehau 
403215516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
403315516c77SSepherosa Ziehau 	while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL)
403415516c77SSepherosa Ziehau 		m_freem(m);
403515516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
403615516c77SSepherosa Ziehau }
403715516c77SSepherosa Ziehau 
403815516c77SSepherosa Ziehau static void
403915516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp)
404015516c77SSepherosa Ziehau {
404115516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
404215516c77SSepherosa Ziehau 	int i;
404315516c77SSepherosa Ziehau 
404415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
404515516c77SSepherosa Ziehau 		hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
404615516c77SSepherosa Ziehau 	if_qflush(ifp);
404715516c77SSepherosa Ziehau }
404815516c77SSepherosa Ziehau 
404915516c77SSepherosa Ziehau static void
405015516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr)
405115516c77SSepherosa Ziehau {
405215516c77SSepherosa Ziehau 
405315516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
405415516c77SSepherosa Ziehau 		goto do_sched;
405515516c77SSepherosa Ziehau 
405615516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
405715516c77SSepherosa Ziehau 		int sched;
405815516c77SSepherosa Ziehau 
405915516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
406015516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
406115516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
406215516c77SSepherosa Ziehau 		if (sched) {
406315516c77SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
406415516c77SSepherosa Ziehau 			    &txr->hn_tx_task);
406515516c77SSepherosa Ziehau 		}
406615516c77SSepherosa Ziehau 	} else {
406715516c77SSepherosa Ziehau do_sched:
406815516c77SSepherosa Ziehau 		/*
406915516c77SSepherosa Ziehau 		 * Release the oactive earlier, with the hope, that
407015516c77SSepherosa Ziehau 		 * others could catch up.  The task will clear the
407115516c77SSepherosa Ziehau 		 * oactive again with the hn_tx_lock to avoid possible
407215516c77SSepherosa Ziehau 		 * races.
407315516c77SSepherosa Ziehau 		 */
407415516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
407515516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
407615516c77SSepherosa Ziehau 	}
407715516c77SSepherosa Ziehau }
407815516c77SSepherosa Ziehau 
407915516c77SSepherosa Ziehau static void
408015516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused)
408115516c77SSepherosa Ziehau {
408215516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
408315516c77SSepherosa Ziehau 
408415516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
408515516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
408615516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
408715516c77SSepherosa Ziehau }
408815516c77SSepherosa Ziehau 
408915516c77SSepherosa Ziehau static void
409015516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused)
409115516c77SSepherosa Ziehau {
409215516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
409315516c77SSepherosa Ziehau 
409415516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
409515516c77SSepherosa Ziehau 	txr->hn_oactive = 0;
409615516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
409715516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
409815516c77SSepherosa Ziehau }
409915516c77SSepherosa Ziehau 
410015516c77SSepherosa Ziehau static int
410115516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan)
410215516c77SSepherosa Ziehau {
410315516c77SSepherosa Ziehau 	struct vmbus_chan_br cbr;
410415516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
410515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = NULL;
410615516c77SSepherosa Ziehau 	int idx, error;
410715516c77SSepherosa Ziehau 
410815516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
410915516c77SSepherosa Ziehau 
411015516c77SSepherosa Ziehau 	/*
411115516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
411215516c77SSepherosa Ziehau 	 */
411315516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
411415516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
411515516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
411615516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
411715516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0,
411815516c77SSepherosa Ziehau 	    ("RX ring %d already attached", idx));
411915516c77SSepherosa Ziehau 	rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED;
412015516c77SSepherosa Ziehau 
412115516c77SSepherosa Ziehau 	if (bootverbose) {
412215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n",
412315516c77SSepherosa Ziehau 		    idx, vmbus_chan_id(chan));
412415516c77SSepherosa Ziehau 	}
412515516c77SSepherosa Ziehau 
412615516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
412715516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[idx];
412815516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0,
412915516c77SSepherosa Ziehau 		    ("TX ring %d already attached", idx));
413015516c77SSepherosa Ziehau 		txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED;
413115516c77SSepherosa Ziehau 
413215516c77SSepherosa Ziehau 		txr->hn_chan = chan;
413315516c77SSepherosa Ziehau 		if (bootverbose) {
413415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n",
413515516c77SSepherosa Ziehau 			    idx, vmbus_chan_id(chan));
413615516c77SSepherosa Ziehau 		}
413715516c77SSepherosa Ziehau 	}
413815516c77SSepherosa Ziehau 
413915516c77SSepherosa Ziehau 	/* Bind this channel to a proper CPU. */
414015516c77SSepherosa Ziehau 	vmbus_chan_cpu_set(chan, (sc->hn_cpu + idx) % mp_ncpus);
414115516c77SSepherosa Ziehau 
414215516c77SSepherosa Ziehau 	/*
414315516c77SSepherosa Ziehau 	 * Open this channel
414415516c77SSepherosa Ziehau 	 */
414515516c77SSepherosa Ziehau 	cbr.cbr = rxr->hn_br;
414615516c77SSepherosa Ziehau 	cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr;
414715516c77SSepherosa Ziehau 	cbr.cbr_txsz = HN_TXBR_SIZE;
414815516c77SSepherosa Ziehau 	cbr.cbr_rxsz = HN_RXBR_SIZE;
414915516c77SSepherosa Ziehau 	error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr);
415015516c77SSepherosa Ziehau 	if (error) {
415115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "open chan%u failed: %d\n",
415215516c77SSepherosa Ziehau 		    vmbus_chan_id(chan), error);
415315516c77SSepherosa Ziehau 		rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
415415516c77SSepherosa Ziehau 		if (txr != NULL)
415515516c77SSepherosa Ziehau 			txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
415615516c77SSepherosa Ziehau 	}
415715516c77SSepherosa Ziehau 	return (error);
415815516c77SSepherosa Ziehau }
415915516c77SSepherosa Ziehau 
416015516c77SSepherosa Ziehau static void
416115516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan)
416215516c77SSepherosa Ziehau {
416315516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
416415516c77SSepherosa Ziehau 	int idx;
416515516c77SSepherosa Ziehau 
416615516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
416715516c77SSepherosa Ziehau 
416815516c77SSepherosa Ziehau 	/*
416915516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
417015516c77SSepherosa Ziehau 	 */
417115516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
417215516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
417315516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
417415516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
417515516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED),
417615516c77SSepherosa Ziehau 	    ("RX ring %d is not attached", idx));
417715516c77SSepherosa Ziehau 	rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
417815516c77SSepherosa Ziehau 
417915516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
418015516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[idx];
418115516c77SSepherosa Ziehau 
418215516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED),
418315516c77SSepherosa Ziehau 		    ("TX ring %d is not attached attached", idx));
418415516c77SSepherosa Ziehau 		txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
418515516c77SSepherosa Ziehau 	}
418615516c77SSepherosa Ziehau 
418715516c77SSepherosa Ziehau 	/*
418815516c77SSepherosa Ziehau 	 * Close this channel.
418915516c77SSepherosa Ziehau 	 *
419015516c77SSepherosa Ziehau 	 * NOTE:
419115516c77SSepherosa Ziehau 	 * Channel closing does _not_ destroy the target channel.
419215516c77SSepherosa Ziehau 	 */
419315516c77SSepherosa Ziehau 	vmbus_chan_close(chan);
419415516c77SSepherosa Ziehau }
419515516c77SSepherosa Ziehau 
419615516c77SSepherosa Ziehau static int
419715516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc)
419815516c77SSepherosa Ziehau {
419915516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
420015516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
420115516c77SSepherosa Ziehau 	int i, error = 0;
420215516c77SSepherosa Ziehau 
420315516c77SSepherosa Ziehau 	if (subchan_cnt == 0)
420415516c77SSepherosa Ziehau 		return (0);
420515516c77SSepherosa Ziehau 
420615516c77SSepherosa Ziehau 	/* Attach the sub-channels. */
420715516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
420815516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i) {
420915516c77SSepherosa Ziehau 		error = hn_chan_attach(sc, subchans[i]);
421015516c77SSepherosa Ziehau 		if (error)
421115516c77SSepherosa Ziehau 			break;
421215516c77SSepherosa Ziehau 	}
421315516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
421415516c77SSepherosa Ziehau 
421515516c77SSepherosa Ziehau 	if (error) {
421615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error);
421715516c77SSepherosa Ziehau 	} else {
421815516c77SSepherosa Ziehau 		if (bootverbose) {
421915516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "%d sub-channels attached\n",
422015516c77SSepherosa Ziehau 			    subchan_cnt);
422115516c77SSepherosa Ziehau 		}
422215516c77SSepherosa Ziehau 	}
422315516c77SSepherosa Ziehau 	return (error);
422415516c77SSepherosa Ziehau }
422515516c77SSepherosa Ziehau 
422615516c77SSepherosa Ziehau static void
422715516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc)
422815516c77SSepherosa Ziehau {
422915516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
423015516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
423115516c77SSepherosa Ziehau 	int i;
423215516c77SSepherosa Ziehau 
423315516c77SSepherosa Ziehau 	if (subchan_cnt == 0)
423415516c77SSepherosa Ziehau 		goto back;
423515516c77SSepherosa Ziehau 
423615516c77SSepherosa Ziehau 	/* Detach the sub-channels. */
423715516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
423815516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i)
423915516c77SSepherosa Ziehau 		hn_chan_detach(sc, subchans[i]);
424015516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
424115516c77SSepherosa Ziehau 
424215516c77SSepherosa Ziehau back:
424315516c77SSepherosa Ziehau 	/*
424415516c77SSepherosa Ziehau 	 * Detach the primary channel, _after_ all sub-channels
424515516c77SSepherosa Ziehau 	 * are detached.
424615516c77SSepherosa Ziehau 	 */
424715516c77SSepherosa Ziehau 	hn_chan_detach(sc, sc->hn_prichan);
424815516c77SSepherosa Ziehau 
424915516c77SSepherosa Ziehau 	/* Wait for sub-channels to be destroyed, if any. */
425015516c77SSepherosa Ziehau 	vmbus_subchan_drain(sc->hn_prichan);
425115516c77SSepherosa Ziehau 
425215516c77SSepherosa Ziehau #ifdef INVARIANTS
425315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
425415516c77SSepherosa Ziehau 		KASSERT((sc->hn_rx_ring[i].hn_rx_flags &
425515516c77SSepherosa Ziehau 		    HN_RX_FLAG_ATTACHED) == 0,
425615516c77SSepherosa Ziehau 		    ("%dth RX ring is still attached", i));
425715516c77SSepherosa Ziehau 	}
425815516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
425915516c77SSepherosa Ziehau 		KASSERT((sc->hn_tx_ring[i].hn_tx_flags &
426015516c77SSepherosa Ziehau 		    HN_TX_FLAG_ATTACHED) == 0,
426115516c77SSepherosa Ziehau 		    ("%dth TX ring is still attached", i));
426215516c77SSepherosa Ziehau 	}
426315516c77SSepherosa Ziehau #endif
426415516c77SSepherosa Ziehau }
426515516c77SSepherosa Ziehau 
426615516c77SSepherosa Ziehau static int
426715516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch)
426815516c77SSepherosa Ziehau {
426915516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
427015516c77SSepherosa Ziehau 	int nchan, rxr_cnt, error;
427115516c77SSepherosa Ziehau 
427215516c77SSepherosa Ziehau 	nchan = *nsubch + 1;
427315516c77SSepherosa Ziehau 	if (nchan == 1) {
427415516c77SSepherosa Ziehau 		/*
427515516c77SSepherosa Ziehau 		 * Multiple RX/TX rings are not requested.
427615516c77SSepherosa Ziehau 		 */
427715516c77SSepherosa Ziehau 		*nsubch = 0;
427815516c77SSepherosa Ziehau 		return (0);
427915516c77SSepherosa Ziehau 	}
428015516c77SSepherosa Ziehau 
428115516c77SSepherosa Ziehau 	/*
428215516c77SSepherosa Ziehau 	 * Query RSS capabilities, e.g. # of RX rings, and # of indirect
428315516c77SSepherosa Ziehau 	 * table entries.
428415516c77SSepherosa Ziehau 	 */
428515516c77SSepherosa Ziehau 	error = hn_rndis_query_rsscaps(sc, &rxr_cnt);
428615516c77SSepherosa Ziehau 	if (error) {
428715516c77SSepherosa Ziehau 		/* No RSS; this is benign. */
428815516c77SSepherosa Ziehau 		*nsubch = 0;
428915516c77SSepherosa Ziehau 		return (0);
429015516c77SSepherosa Ziehau 	}
429115516c77SSepherosa Ziehau 	if (bootverbose) {
429215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
429315516c77SSepherosa Ziehau 		    rxr_cnt, nchan);
429415516c77SSepherosa Ziehau 	}
429515516c77SSepherosa Ziehau 
429615516c77SSepherosa Ziehau 	if (nchan > rxr_cnt)
429715516c77SSepherosa Ziehau 		nchan = rxr_cnt;
429815516c77SSepherosa Ziehau 	if (nchan == 1) {
429915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n");
430015516c77SSepherosa Ziehau 		*nsubch = 0;
430115516c77SSepherosa Ziehau 		return (0);
430215516c77SSepherosa Ziehau 	}
430315516c77SSepherosa Ziehau 
430415516c77SSepherosa Ziehau 	/*
430515516c77SSepherosa Ziehau 	 * Allocate sub-channels from NVS.
430615516c77SSepherosa Ziehau 	 */
430715516c77SSepherosa Ziehau 	*nsubch = nchan - 1;
430815516c77SSepherosa Ziehau 	error = hn_nvs_alloc_subchans(sc, nsubch);
430915516c77SSepherosa Ziehau 	if (error || *nsubch == 0) {
431015516c77SSepherosa Ziehau 		/* Failed to allocate sub-channels. */
431115516c77SSepherosa Ziehau 		*nsubch = 0;
431215516c77SSepherosa Ziehau 		return (0);
431315516c77SSepherosa Ziehau 	}
431415516c77SSepherosa Ziehau 
431515516c77SSepherosa Ziehau 	/*
431615516c77SSepherosa Ziehau 	 * Wait for all sub-channels to become ready before moving on.
431715516c77SSepherosa Ziehau 	 */
431815516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch);
431915516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, *nsubch);
432015516c77SSepherosa Ziehau 	return (0);
432115516c77SSepherosa Ziehau }
432215516c77SSepherosa Ziehau 
432315516c77SSepherosa Ziehau static int
432415516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu)
432515516c77SSepherosa Ziehau {
432615516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
432715516c77SSepherosa Ziehau 	int error, nsubch, nchan, i;
432815516c77SSepherosa Ziehau 	uint32_t old_caps;
432915516c77SSepherosa Ziehau 
433015516c77SSepherosa Ziehau 	KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0,
433115516c77SSepherosa Ziehau 	    ("synthetic parts were attached"));
433215516c77SSepherosa Ziehau 
433315516c77SSepherosa Ziehau 	/* Save capabilities for later verification. */
433415516c77SSepherosa Ziehau 	old_caps = sc->hn_caps;
433515516c77SSepherosa Ziehau 	sc->hn_caps = 0;
433615516c77SSepherosa Ziehau 
433715516c77SSepherosa Ziehau 	/* Clear RSS stuffs. */
433815516c77SSepherosa Ziehau 	sc->hn_rss_ind_size = 0;
433915516c77SSepherosa Ziehau 	sc->hn_rss_hash = 0;
434015516c77SSepherosa Ziehau 
434115516c77SSepherosa Ziehau 	/*
434215516c77SSepherosa Ziehau 	 * Attach the primary channel _before_ attaching NVS and RNDIS.
434315516c77SSepherosa Ziehau 	 */
434415516c77SSepherosa Ziehau 	error = hn_chan_attach(sc, sc->hn_prichan);
434515516c77SSepherosa Ziehau 	if (error)
434615516c77SSepherosa Ziehau 		return (error);
434715516c77SSepherosa Ziehau 
434815516c77SSepherosa Ziehau 	/*
434915516c77SSepherosa Ziehau 	 * Attach NVS.
435015516c77SSepherosa Ziehau 	 */
435115516c77SSepherosa Ziehau 	error = hn_nvs_attach(sc, mtu);
435215516c77SSepherosa Ziehau 	if (error)
435315516c77SSepherosa Ziehau 		return (error);
435415516c77SSepherosa Ziehau 
435515516c77SSepherosa Ziehau 	/*
435615516c77SSepherosa Ziehau 	 * Attach RNDIS _after_ NVS is attached.
435715516c77SSepherosa Ziehau 	 */
435815516c77SSepherosa Ziehau 	error = hn_rndis_attach(sc, mtu);
435915516c77SSepherosa Ziehau 	if (error)
436015516c77SSepherosa Ziehau 		return (error);
436115516c77SSepherosa Ziehau 
436215516c77SSepherosa Ziehau 	/*
436315516c77SSepherosa Ziehau 	 * Make sure capabilities are not changed.
436415516c77SSepherosa Ziehau 	 */
436515516c77SSepherosa Ziehau 	if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) {
436615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n",
436715516c77SSepherosa Ziehau 		    old_caps, sc->hn_caps);
436815516c77SSepherosa Ziehau 		/* Restore old capabilities and abort. */
436915516c77SSepherosa Ziehau 		sc->hn_caps = old_caps;
437015516c77SSepherosa Ziehau 		return ENXIO;
437115516c77SSepherosa Ziehau 	}
437215516c77SSepherosa Ziehau 
437315516c77SSepherosa Ziehau 	/*
437415516c77SSepherosa Ziehau 	 * Allocate sub-channels for multi-TX/RX rings.
437515516c77SSepherosa Ziehau 	 *
437615516c77SSepherosa Ziehau 	 * NOTE:
437715516c77SSepherosa Ziehau 	 * The # of RX rings that can be used is equivalent to the # of
437815516c77SSepherosa Ziehau 	 * channels to be requested.
437915516c77SSepherosa Ziehau 	 */
438015516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_cnt - 1;
438115516c77SSepherosa Ziehau 	error = hn_synth_alloc_subchans(sc, &nsubch);
438215516c77SSepherosa Ziehau 	if (error)
438315516c77SSepherosa Ziehau 		return (error);
438415516c77SSepherosa Ziehau 
438515516c77SSepherosa Ziehau 	nchan = nsubch + 1;
438615516c77SSepherosa Ziehau 	if (nchan == 1) {
438715516c77SSepherosa Ziehau 		/* Only the primary channel can be used; done */
438815516c77SSepherosa Ziehau 		goto back;
438915516c77SSepherosa Ziehau 	}
439015516c77SSepherosa Ziehau 
439115516c77SSepherosa Ziehau 	/*
439215516c77SSepherosa Ziehau 	 * Configure RSS key and indirect table _after_ all sub-channels
439315516c77SSepherosa Ziehau 	 * are allocated.
439415516c77SSepherosa Ziehau 	 */
439515516c77SSepherosa Ziehau 
439615516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) {
439715516c77SSepherosa Ziehau 		/*
439815516c77SSepherosa Ziehau 		 * RSS key is not set yet; set it to the default RSS key.
439915516c77SSepherosa Ziehau 		 */
440015516c77SSepherosa Ziehau 		if (bootverbose)
440115516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS key\n");
440215516c77SSepherosa Ziehau 		memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key));
440315516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
440415516c77SSepherosa Ziehau 	}
440515516c77SSepherosa Ziehau 
440615516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) {
440715516c77SSepherosa Ziehau 		/*
440815516c77SSepherosa Ziehau 		 * RSS indirect table is not set yet; set it up in round-
440915516c77SSepherosa Ziehau 		 * robin fashion.
441015516c77SSepherosa Ziehau 		 */
441115516c77SSepherosa Ziehau 		if (bootverbose) {
441215516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS indirect "
441315516c77SSepherosa Ziehau 			    "table\n");
441415516c77SSepherosa Ziehau 		}
441515516c77SSepherosa Ziehau 		for (i = 0; i < NDIS_HASH_INDCNT; ++i)
441615516c77SSepherosa Ziehau 			rss->rss_ind[i] = i % nchan;
441715516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSIND;
441815516c77SSepherosa Ziehau 	} else {
441915516c77SSepherosa Ziehau 		/*
442015516c77SSepherosa Ziehau 		 * # of usable channels may be changed, so we have to
442115516c77SSepherosa Ziehau 		 * make sure that all entries in RSS indirect table
442215516c77SSepherosa Ziehau 		 * are valid.
442315516c77SSepherosa Ziehau 		 */
442415516c77SSepherosa Ziehau 		hn_rss_ind_fixup(sc, nchan);
442515516c77SSepherosa Ziehau 	}
442615516c77SSepherosa Ziehau 
442715516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
442815516c77SSepherosa Ziehau 	if (error) {
442915516c77SSepherosa Ziehau 		/*
443015516c77SSepherosa Ziehau 		 * Failed to configure RSS key or indirect table; only
443115516c77SSepherosa Ziehau 		 * the primary channel can be used.
443215516c77SSepherosa Ziehau 		 */
443315516c77SSepherosa Ziehau 		nchan = 1;
443415516c77SSepherosa Ziehau 	}
443515516c77SSepherosa Ziehau back:
443615516c77SSepherosa Ziehau 	/*
443715516c77SSepherosa Ziehau 	 * Set the # of TX/RX rings that could be used according to
443815516c77SSepherosa Ziehau 	 * the # of channels that NVS offered.
443915516c77SSepherosa Ziehau 	 */
444015516c77SSepherosa Ziehau 	hn_set_ring_inuse(sc, nchan);
444115516c77SSepherosa Ziehau 
444215516c77SSepherosa Ziehau 	/*
444315516c77SSepherosa Ziehau 	 * Attach the sub-channels, if any.
444415516c77SSepherosa Ziehau 	 */
444515516c77SSepherosa Ziehau 	error = hn_attach_subchans(sc);
444615516c77SSepherosa Ziehau 	if (error)
444715516c77SSepherosa Ziehau 		return (error);
444815516c77SSepherosa Ziehau 
4449dc13fee6SSepherosa Ziehau 	/*
4450dc13fee6SSepherosa Ziehau 	 * Fixup transmission aggregation setup.
4451dc13fee6SSepherosa Ziehau 	 */
4452dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
4453dc13fee6SSepherosa Ziehau 
445415516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED;
445515516c77SSepherosa Ziehau 	return (0);
445615516c77SSepherosa Ziehau }
445715516c77SSepherosa Ziehau 
445815516c77SSepherosa Ziehau /*
445915516c77SSepherosa Ziehau  * NOTE:
446015516c77SSepherosa Ziehau  * The interface must have been suspended though hn_suspend(), before
446115516c77SSepherosa Ziehau  * this function get called.
446215516c77SSepherosa Ziehau  */
446315516c77SSepherosa Ziehau static void
446415516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc)
446515516c77SSepherosa Ziehau {
446615516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
446715516c77SSepherosa Ziehau 
446815516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
446915516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
447015516c77SSepherosa Ziehau 
447115516c77SSepherosa Ziehau 	/* Detach the RNDIS first. */
447215516c77SSepherosa Ziehau 	hn_rndis_detach(sc);
447315516c77SSepherosa Ziehau 
447415516c77SSepherosa Ziehau 	/* Detach NVS. */
447515516c77SSepherosa Ziehau 	hn_nvs_detach(sc);
447615516c77SSepherosa Ziehau 
447715516c77SSepherosa Ziehau 	/* Detach all of the channels. */
447815516c77SSepherosa Ziehau 	hn_detach_allchans(sc);
447915516c77SSepherosa Ziehau 
448015516c77SSepherosa Ziehau 	sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED;
448115516c77SSepherosa Ziehau }
448215516c77SSepherosa Ziehau 
448315516c77SSepherosa Ziehau static void
448415516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt)
448515516c77SSepherosa Ziehau {
448615516c77SSepherosa Ziehau 	KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt,
448715516c77SSepherosa Ziehau 	    ("invalid ring count %d", ring_cnt));
448815516c77SSepherosa Ziehau 
448915516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt > ring_cnt)
449015516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = ring_cnt;
449115516c77SSepherosa Ziehau 	else
449215516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
449315516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = ring_cnt;
449415516c77SSepherosa Ziehau 
449515516c77SSepherosa Ziehau 	if (bootverbose) {
449615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n",
449715516c77SSepherosa Ziehau 		    sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
449815516c77SSepherosa Ziehau 	}
449915516c77SSepherosa Ziehau }
450015516c77SSepherosa Ziehau 
450115516c77SSepherosa Ziehau static void
450215516c77SSepherosa Ziehau hn_chan_drain(struct vmbus_channel *chan)
450315516c77SSepherosa Ziehau {
450415516c77SSepherosa Ziehau 
450515516c77SSepherosa Ziehau 	while (!vmbus_chan_rx_empty(chan) || !vmbus_chan_tx_empty(chan))
450615516c77SSepherosa Ziehau 		pause("waitch", 1);
450715516c77SSepherosa Ziehau 	vmbus_chan_intr_drain(chan);
450815516c77SSepherosa Ziehau }
450915516c77SSepherosa Ziehau 
451015516c77SSepherosa Ziehau static void
451115516c77SSepherosa Ziehau hn_suspend_data(struct hn_softc *sc)
451215516c77SSepherosa Ziehau {
451315516c77SSepherosa Ziehau 	struct vmbus_channel **subch = NULL;
451415516c77SSepherosa Ziehau 	int i, nsubch;
451515516c77SSepherosa Ziehau 
451615516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
451715516c77SSepherosa Ziehau 
451815516c77SSepherosa Ziehau 	/*
451915516c77SSepherosa Ziehau 	 * Suspend TX.
452015516c77SSepherosa Ziehau 	 */
452115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
452215516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
452315516c77SSepherosa Ziehau 
452415516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
452515516c77SSepherosa Ziehau 		txr->hn_suspended = 1;
452615516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
452715516c77SSepherosa Ziehau 		/* No one is able send more packets now. */
452815516c77SSepherosa Ziehau 
452915516c77SSepherosa Ziehau 		/* Wait for all pending sends to finish. */
453015516c77SSepherosa Ziehau 		while (hn_tx_ring_pending(txr))
453115516c77SSepherosa Ziehau 			pause("hnwtx", 1 /* 1 tick */);
453215516c77SSepherosa Ziehau 
453315516c77SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task);
453415516c77SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task);
453515516c77SSepherosa Ziehau 	}
453615516c77SSepherosa Ziehau 
453715516c77SSepherosa Ziehau 	/*
453815516c77SSepherosa Ziehau 	 * Disable RX by clearing RX filter.
453915516c77SSepherosa Ziehau 	 */
454015516c77SSepherosa Ziehau 	sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE;
454115516c77SSepherosa Ziehau 	hn_rndis_set_rxfilter(sc, sc->hn_rx_filter);
454215516c77SSepherosa Ziehau 
454315516c77SSepherosa Ziehau 	/*
454415516c77SSepherosa Ziehau 	 * Give RNDIS enough time to flush all pending data packets.
454515516c77SSepherosa Ziehau 	 */
454615516c77SSepherosa Ziehau 	pause("waitrx", (200 * hz) / 1000);
454715516c77SSepherosa Ziehau 
454815516c77SSepherosa Ziehau 	/*
454915516c77SSepherosa Ziehau 	 * Drain RX/TX bufrings and interrupts.
455015516c77SSepherosa Ziehau 	 */
455115516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_inuse - 1;
455215516c77SSepherosa Ziehau 	if (nsubch > 0)
455315516c77SSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
455415516c77SSepherosa Ziehau 
455515516c77SSepherosa Ziehau 	if (subch != NULL) {
455615516c77SSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
455715516c77SSepherosa Ziehau 			hn_chan_drain(subch[i]);
455815516c77SSepherosa Ziehau 	}
455915516c77SSepherosa Ziehau 	hn_chan_drain(sc->hn_prichan);
456015516c77SSepherosa Ziehau 
456115516c77SSepherosa Ziehau 	if (subch != NULL)
456215516c77SSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
456315516c77SSepherosa Ziehau }
456415516c77SSepherosa Ziehau 
456515516c77SSepherosa Ziehau static void
456615516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused)
456715516c77SSepherosa Ziehau {
456815516c77SSepherosa Ziehau 
456915516c77SSepherosa Ziehau 	((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL;
457015516c77SSepherosa Ziehau }
457115516c77SSepherosa Ziehau 
457215516c77SSepherosa Ziehau static void
457315516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc)
457415516c77SSepherosa Ziehau {
457515516c77SSepherosa Ziehau 	struct task task;
457615516c77SSepherosa Ziehau 
457715516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
457815516c77SSepherosa Ziehau 
457915516c77SSepherosa Ziehau 	/*
458015516c77SSepherosa Ziehau 	 * Make sure that hn_mgmt_taskq0 can nolonger be accessed
458115516c77SSepherosa Ziehau 	 * through hn_mgmt_taskq.
458215516c77SSepherosa Ziehau 	 */
458315516c77SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc);
458415516c77SSepherosa Ziehau 	vmbus_chan_run_task(sc->hn_prichan, &task);
458515516c77SSepherosa Ziehau 
458615516c77SSepherosa Ziehau 	/*
458715516c77SSepherosa Ziehau 	 * Make sure that all pending management tasks are completed.
458815516c77SSepherosa Ziehau 	 */
458915516c77SSepherosa Ziehau 	taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init);
459015516c77SSepherosa Ziehau 	taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status);
459115516c77SSepherosa Ziehau 	taskqueue_drain_all(sc->hn_mgmt_taskq0);
459215516c77SSepherosa Ziehau }
459315516c77SSepherosa Ziehau 
459415516c77SSepherosa Ziehau static void
459515516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc)
459615516c77SSepherosa Ziehau {
459715516c77SSepherosa Ziehau 
459815516c77SSepherosa Ziehau 	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
459915516c77SSepherosa Ziehau 		hn_suspend_data(sc);
460015516c77SSepherosa Ziehau 	hn_suspend_mgmt(sc);
460115516c77SSepherosa Ziehau }
460215516c77SSepherosa Ziehau 
460315516c77SSepherosa Ziehau static void
460415516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt)
460515516c77SSepherosa Ziehau {
460615516c77SSepherosa Ziehau 	int i;
460715516c77SSepherosa Ziehau 
460815516c77SSepherosa Ziehau 	KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt,
460915516c77SSepherosa Ziehau 	    ("invalid TX ring count %d", tx_ring_cnt));
461015516c77SSepherosa Ziehau 
461115516c77SSepherosa Ziehau 	for (i = 0; i < tx_ring_cnt; ++i) {
461215516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
461315516c77SSepherosa Ziehau 
461415516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
461515516c77SSepherosa Ziehau 		txr->hn_suspended = 0;
461615516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
461715516c77SSepherosa Ziehau 	}
461815516c77SSepherosa Ziehau }
461915516c77SSepherosa Ziehau 
462015516c77SSepherosa Ziehau static void
462115516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc)
462215516c77SSepherosa Ziehau {
462315516c77SSepherosa Ziehau 	int i;
462415516c77SSepherosa Ziehau 
462515516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
462615516c77SSepherosa Ziehau 
462715516c77SSepherosa Ziehau 	/*
462815516c77SSepherosa Ziehau 	 * Re-enable RX.
462915516c77SSepherosa Ziehau 	 */
463015516c77SSepherosa Ziehau 	hn_set_rxfilter(sc);
463115516c77SSepherosa Ziehau 
463215516c77SSepherosa Ziehau 	/*
463315516c77SSepherosa Ziehau 	 * Make sure to clear suspend status on "all" TX rings,
463415516c77SSepherosa Ziehau 	 * since hn_tx_ring_inuse can be changed after
463515516c77SSepherosa Ziehau 	 * hn_suspend_data().
463615516c77SSepherosa Ziehau 	 */
463715516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_cnt);
463815516c77SSepherosa Ziehau 
463923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
464023bf9e15SSepherosa Ziehau 	if (!hn_use_if_start)
464123bf9e15SSepherosa Ziehau #endif
464223bf9e15SSepherosa Ziehau 	{
464315516c77SSepherosa Ziehau 		/*
464415516c77SSepherosa Ziehau 		 * Flush unused drbrs, since hn_tx_ring_inuse may be
464515516c77SSepherosa Ziehau 		 * reduced.
464615516c77SSepherosa Ziehau 		 */
464715516c77SSepherosa Ziehau 		for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i)
464815516c77SSepherosa Ziehau 			hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
464915516c77SSepherosa Ziehau 	}
465015516c77SSepherosa Ziehau 
465115516c77SSepherosa Ziehau 	/*
465215516c77SSepherosa Ziehau 	 * Kick start TX.
465315516c77SSepherosa Ziehau 	 */
465415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
465515516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
465615516c77SSepherosa Ziehau 
465715516c77SSepherosa Ziehau 		/*
465815516c77SSepherosa Ziehau 		 * Use txeof task, so that any pending oactive can be
465915516c77SSepherosa Ziehau 		 * cleared properly.
466015516c77SSepherosa Ziehau 		 */
466115516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
466215516c77SSepherosa Ziehau 	}
466315516c77SSepherosa Ziehau }
466415516c77SSepherosa Ziehau 
466515516c77SSepherosa Ziehau static void
466615516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc)
466715516c77SSepherosa Ziehau {
466815516c77SSepherosa Ziehau 
466915516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
467015516c77SSepherosa Ziehau 
467115516c77SSepherosa Ziehau 	/*
467215516c77SSepherosa Ziehau 	 * Kick off network change detection, if it was pending.
467315516c77SSepherosa Ziehau 	 * If no network change was pending, start link status
467415516c77SSepherosa Ziehau 	 * checks, which is more lightweight than network change
467515516c77SSepherosa Ziehau 	 * detection.
467615516c77SSepherosa Ziehau 	 */
467715516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
467815516c77SSepherosa Ziehau 		hn_change_network(sc);
467915516c77SSepherosa Ziehau 	else
468015516c77SSepherosa Ziehau 		hn_update_link_status(sc);
468115516c77SSepherosa Ziehau }
468215516c77SSepherosa Ziehau 
468315516c77SSepherosa Ziehau static void
468415516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc)
468515516c77SSepherosa Ziehau {
468615516c77SSepherosa Ziehau 
468715516c77SSepherosa Ziehau 	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
468815516c77SSepherosa Ziehau 		hn_resume_data(sc);
468915516c77SSepherosa Ziehau 	hn_resume_mgmt(sc);
469015516c77SSepherosa Ziehau }
469115516c77SSepherosa Ziehau 
469215516c77SSepherosa Ziehau static void
469315516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen)
469415516c77SSepherosa Ziehau {
469515516c77SSepherosa Ziehau 	const struct rndis_status_msg *msg;
469615516c77SSepherosa Ziehau 	int ofs;
469715516c77SSepherosa Ziehau 
469815516c77SSepherosa Ziehau 	if (dlen < sizeof(*msg)) {
469915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid RNDIS status\n");
470015516c77SSepherosa Ziehau 		return;
470115516c77SSepherosa Ziehau 	}
470215516c77SSepherosa Ziehau 	msg = data;
470315516c77SSepherosa Ziehau 
470415516c77SSepherosa Ziehau 	switch (msg->rm_status) {
470515516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_CONNECT:
470615516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_DISCONNECT:
470715516c77SSepherosa Ziehau 		hn_update_link_status(sc);
470815516c77SSepherosa Ziehau 		break;
470915516c77SSepherosa Ziehau 
471015516c77SSepherosa Ziehau 	case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
471115516c77SSepherosa Ziehau 		/* Not really useful; ignore. */
471215516c77SSepherosa Ziehau 		break;
471315516c77SSepherosa Ziehau 
471415516c77SSepherosa Ziehau 	case RNDIS_STATUS_NETWORK_CHANGE:
471515516c77SSepherosa Ziehau 		ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
471615516c77SSepherosa Ziehau 		if (dlen < ofs + msg->rm_stbuflen ||
471715516c77SSepherosa Ziehau 		    msg->rm_stbuflen < sizeof(uint32_t)) {
471815516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed\n");
471915516c77SSepherosa Ziehau 		} else {
472015516c77SSepherosa Ziehau 			uint32_t change;
472115516c77SSepherosa Ziehau 
472215516c77SSepherosa Ziehau 			memcpy(&change, ((const uint8_t *)msg) + ofs,
472315516c77SSepherosa Ziehau 			    sizeof(change));
472415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed, change %u\n",
472515516c77SSepherosa Ziehau 			    change);
472615516c77SSepherosa Ziehau 		}
472715516c77SSepherosa Ziehau 		hn_change_network(sc);
472815516c77SSepherosa Ziehau 		break;
472915516c77SSepherosa Ziehau 
473015516c77SSepherosa Ziehau 	default:
473115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
473215516c77SSepherosa Ziehau 		    msg->rm_status);
473315516c77SSepherosa Ziehau 		break;
473415516c77SSepherosa Ziehau 	}
473515516c77SSepherosa Ziehau }
473615516c77SSepherosa Ziehau 
473715516c77SSepherosa Ziehau static int
473815516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info)
473915516c77SSepherosa Ziehau {
474015516c77SSepherosa Ziehau 	const struct rndis_pktinfo *pi = info_data;
474115516c77SSepherosa Ziehau 	uint32_t mask = 0;
474215516c77SSepherosa Ziehau 
474315516c77SSepherosa Ziehau 	while (info_dlen != 0) {
474415516c77SSepherosa Ziehau 		const void *data;
474515516c77SSepherosa Ziehau 		uint32_t dlen;
474615516c77SSepherosa Ziehau 
474715516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < sizeof(*pi)))
474815516c77SSepherosa Ziehau 			return (EINVAL);
474915516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < pi->rm_size))
475015516c77SSepherosa Ziehau 			return (EINVAL);
475115516c77SSepherosa Ziehau 		info_dlen -= pi->rm_size;
475215516c77SSepherosa Ziehau 
475315516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
475415516c77SSepherosa Ziehau 			return (EINVAL);
475515516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
475615516c77SSepherosa Ziehau 			return (EINVAL);
475715516c77SSepherosa Ziehau 		dlen = pi->rm_size - pi->rm_pktinfooffset;
475815516c77SSepherosa Ziehau 		data = pi->rm_data;
475915516c77SSepherosa Ziehau 
476015516c77SSepherosa Ziehau 		switch (pi->rm_type) {
476115516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_VLAN:
476215516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
476315516c77SSepherosa Ziehau 				return (EINVAL);
476415516c77SSepherosa Ziehau 			info->vlan_info = *((const uint32_t *)data);
476515516c77SSepherosa Ziehau 			mask |= HN_RXINFO_VLAN;
476615516c77SSepherosa Ziehau 			break;
476715516c77SSepherosa Ziehau 
476815516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_CSUM:
476915516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
477015516c77SSepherosa Ziehau 				return (EINVAL);
477115516c77SSepherosa Ziehau 			info->csum_info = *((const uint32_t *)data);
477215516c77SSepherosa Ziehau 			mask |= HN_RXINFO_CSUM;
477315516c77SSepherosa Ziehau 			break;
477415516c77SSepherosa Ziehau 
477515516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHVAL:
477615516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
477715516c77SSepherosa Ziehau 				return (EINVAL);
477815516c77SSepherosa Ziehau 			info->hash_value = *((const uint32_t *)data);
477915516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHVAL;
478015516c77SSepherosa Ziehau 			break;
478115516c77SSepherosa Ziehau 
478215516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHINF:
478315516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
478415516c77SSepherosa Ziehau 				return (EINVAL);
478515516c77SSepherosa Ziehau 			info->hash_info = *((const uint32_t *)data);
478615516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHINF;
478715516c77SSepherosa Ziehau 			break;
478815516c77SSepherosa Ziehau 
478915516c77SSepherosa Ziehau 		default:
479015516c77SSepherosa Ziehau 			goto next;
479115516c77SSepherosa Ziehau 		}
479215516c77SSepherosa Ziehau 
479315516c77SSepherosa Ziehau 		if (mask == HN_RXINFO_ALL) {
479415516c77SSepherosa Ziehau 			/* All found; done */
479515516c77SSepherosa Ziehau 			break;
479615516c77SSepherosa Ziehau 		}
479715516c77SSepherosa Ziehau next:
479815516c77SSepherosa Ziehau 		pi = (const struct rndis_pktinfo *)
479915516c77SSepherosa Ziehau 		    ((const uint8_t *)pi + pi->rm_size);
480015516c77SSepherosa Ziehau 	}
480115516c77SSepherosa Ziehau 
480215516c77SSepherosa Ziehau 	/*
480315516c77SSepherosa Ziehau 	 * Final fixup.
480415516c77SSepherosa Ziehau 	 * - If there is no hash value, invalidate the hash info.
480515516c77SSepherosa Ziehau 	 */
480615516c77SSepherosa Ziehau 	if ((mask & HN_RXINFO_HASHVAL) == 0)
480715516c77SSepherosa Ziehau 		info->hash_info = HN_NDIS_HASH_INFO_INVALID;
480815516c77SSepherosa Ziehau 	return (0);
480915516c77SSepherosa Ziehau }
481015516c77SSepherosa Ziehau 
481115516c77SSepherosa Ziehau static __inline bool
481215516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
481315516c77SSepherosa Ziehau {
481415516c77SSepherosa Ziehau 
481515516c77SSepherosa Ziehau 	if (off < check_off) {
481615516c77SSepherosa Ziehau 		if (__predict_true(off + len <= check_off))
481715516c77SSepherosa Ziehau 			return (false);
481815516c77SSepherosa Ziehau 	} else if (off > check_off) {
481915516c77SSepherosa Ziehau 		if (__predict_true(check_off + check_len <= off))
482015516c77SSepherosa Ziehau 			return (false);
482115516c77SSepherosa Ziehau 	}
482215516c77SSepherosa Ziehau 	return (true);
482315516c77SSepherosa Ziehau }
482415516c77SSepherosa Ziehau 
482515516c77SSepherosa Ziehau static void
482615516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen)
482715516c77SSepherosa Ziehau {
482815516c77SSepherosa Ziehau 	const struct rndis_packet_msg *pkt;
482915516c77SSepherosa Ziehau 	struct hn_rxinfo info;
483015516c77SSepherosa Ziehau 	int data_off, pktinfo_off, data_len, pktinfo_len;
483115516c77SSepherosa Ziehau 
483215516c77SSepherosa Ziehau 	/*
483315516c77SSepherosa Ziehau 	 * Check length.
483415516c77SSepherosa Ziehau 	 */
483515516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*pkt))) {
483615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
483715516c77SSepherosa Ziehau 		return;
483815516c77SSepherosa Ziehau 	}
483915516c77SSepherosa Ziehau 	pkt = data;
484015516c77SSepherosa Ziehau 
484115516c77SSepherosa Ziehau 	if (__predict_false(dlen < pkt->rm_len)) {
484215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
484315516c77SSepherosa Ziehau 		    "dlen %d, msglen %u\n", dlen, pkt->rm_len);
484415516c77SSepherosa Ziehau 		return;
484515516c77SSepherosa Ziehau 	}
484615516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_len <
484715516c77SSepherosa Ziehau 	    pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
484815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
484915516c77SSepherosa Ziehau 		    "msglen %u, data %u, oob %u, pktinfo %u\n",
485015516c77SSepherosa Ziehau 		    pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
485115516c77SSepherosa Ziehau 		    pkt->rm_pktinfolen);
485215516c77SSepherosa Ziehau 		return;
485315516c77SSepherosa Ziehau 	}
485415516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_datalen == 0)) {
485515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
485615516c77SSepherosa Ziehau 		return;
485715516c77SSepherosa Ziehau 	}
485815516c77SSepherosa Ziehau 
485915516c77SSepherosa Ziehau 	/*
486015516c77SSepherosa Ziehau 	 * Check offests.
486115516c77SSepherosa Ziehau 	 */
486215516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs)			\
486315516c77SSepherosa Ziehau 	((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN ||	\
486415516c77SSepherosa Ziehau 	 ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
486515516c77SSepherosa Ziehau 
486615516c77SSepherosa Ziehau 	/* XXX Hyper-V does not meet data offset alignment requirement */
486715516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
486815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
486915516c77SSepherosa Ziehau 		    "data offset %u\n", pkt->rm_dataoffset);
487015516c77SSepherosa Ziehau 		return;
487115516c77SSepherosa Ziehau 	}
487215516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdataoffset > 0 &&
487315516c77SSepherosa Ziehau 	    IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
487415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
487515516c77SSepherosa Ziehau 		    "oob offset %u\n", pkt->rm_oobdataoffset);
487615516c77SSepherosa Ziehau 		return;
487715516c77SSepherosa Ziehau 	}
487815516c77SSepherosa Ziehau 	if (__predict_true(pkt->rm_pktinfooffset > 0) &&
487915516c77SSepherosa Ziehau 	    __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
488015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
488115516c77SSepherosa Ziehau 		    "pktinfo offset %u\n", pkt->rm_pktinfooffset);
488215516c77SSepherosa Ziehau 		return;
488315516c77SSepherosa Ziehau 	}
488415516c77SSepherosa Ziehau 
488515516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID
488615516c77SSepherosa Ziehau 
488715516c77SSepherosa Ziehau 	data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
488815516c77SSepherosa Ziehau 	data_len = pkt->rm_datalen;
488915516c77SSepherosa Ziehau 	pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
489015516c77SSepherosa Ziehau 	pktinfo_len = pkt->rm_pktinfolen;
489115516c77SSepherosa Ziehau 
489215516c77SSepherosa Ziehau 	/*
489315516c77SSepherosa Ziehau 	 * Check OOB coverage.
489415516c77SSepherosa Ziehau 	 */
489515516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdatalen != 0)) {
489615516c77SSepherosa Ziehau 		int oob_off, oob_len;
489715516c77SSepherosa Ziehau 
489815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "got oobdata\n");
489915516c77SSepherosa Ziehau 		oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
490015516c77SSepherosa Ziehau 		oob_len = pkt->rm_oobdatalen;
490115516c77SSepherosa Ziehau 
490215516c77SSepherosa Ziehau 		if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
490315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
490415516c77SSepherosa Ziehau 			    "oob overflow, msglen %u, oob abs %d len %d\n",
490515516c77SSepherosa Ziehau 			    pkt->rm_len, oob_off, oob_len);
490615516c77SSepherosa Ziehau 			return;
490715516c77SSepherosa Ziehau 		}
490815516c77SSepherosa Ziehau 
490915516c77SSepherosa Ziehau 		/*
491015516c77SSepherosa Ziehau 		 * Check against data.
491115516c77SSepherosa Ziehau 		 */
491215516c77SSepherosa Ziehau 		if (hn_rndis_check_overlap(oob_off, oob_len,
491315516c77SSepherosa Ziehau 		    data_off, data_len)) {
491415516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
491515516c77SSepherosa Ziehau 			    "oob overlaps data, oob abs %d len %d, "
491615516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
491715516c77SSepherosa Ziehau 			    oob_off, oob_len, data_off, data_len);
491815516c77SSepherosa Ziehau 			return;
491915516c77SSepherosa Ziehau 		}
492015516c77SSepherosa Ziehau 
492115516c77SSepherosa Ziehau 		/*
492215516c77SSepherosa Ziehau 		 * Check against pktinfo.
492315516c77SSepherosa Ziehau 		 */
492415516c77SSepherosa Ziehau 		if (pktinfo_len != 0 &&
492515516c77SSepherosa Ziehau 		    hn_rndis_check_overlap(oob_off, oob_len,
492615516c77SSepherosa Ziehau 		    pktinfo_off, pktinfo_len)) {
492715516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
492815516c77SSepherosa Ziehau 			    "oob overlaps pktinfo, oob abs %d len %d, "
492915516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
493015516c77SSepherosa Ziehau 			    oob_off, oob_len, pktinfo_off, pktinfo_len);
493115516c77SSepherosa Ziehau 			return;
493215516c77SSepherosa Ziehau 		}
493315516c77SSepherosa Ziehau 	}
493415516c77SSepherosa Ziehau 
493515516c77SSepherosa Ziehau 	/*
493615516c77SSepherosa Ziehau 	 * Check per-packet-info coverage and find useful per-packet-info.
493715516c77SSepherosa Ziehau 	 */
493815516c77SSepherosa Ziehau 	info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
493915516c77SSepherosa Ziehau 	info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
494015516c77SSepherosa Ziehau 	info.hash_info = HN_NDIS_HASH_INFO_INVALID;
494115516c77SSepherosa Ziehau 	if (__predict_true(pktinfo_len != 0)) {
494215516c77SSepherosa Ziehau 		bool overlap;
494315516c77SSepherosa Ziehau 		int error;
494415516c77SSepherosa Ziehau 
494515516c77SSepherosa Ziehau 		if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
494615516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
494715516c77SSepherosa Ziehau 			    "pktinfo overflow, msglen %u, "
494815516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
494915516c77SSepherosa Ziehau 			    pkt->rm_len, pktinfo_off, pktinfo_len);
495015516c77SSepherosa Ziehau 			return;
495115516c77SSepherosa Ziehau 		}
495215516c77SSepherosa Ziehau 
495315516c77SSepherosa Ziehau 		/*
495415516c77SSepherosa Ziehau 		 * Check packet info coverage.
495515516c77SSepherosa Ziehau 		 */
495615516c77SSepherosa Ziehau 		overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
495715516c77SSepherosa Ziehau 		    data_off, data_len);
495815516c77SSepherosa Ziehau 		if (__predict_false(overlap)) {
495915516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
496015516c77SSepherosa Ziehau 			    "pktinfo overlap data, pktinfo abs %d len %d, "
496115516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
496215516c77SSepherosa Ziehau 			    pktinfo_off, pktinfo_len, data_off, data_len);
496315516c77SSepherosa Ziehau 			return;
496415516c77SSepherosa Ziehau 		}
496515516c77SSepherosa Ziehau 
496615516c77SSepherosa Ziehau 		/*
496715516c77SSepherosa Ziehau 		 * Find useful per-packet-info.
496815516c77SSepherosa Ziehau 		 */
496915516c77SSepherosa Ziehau 		error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
497015516c77SSepherosa Ziehau 		    pktinfo_len, &info);
497115516c77SSepherosa Ziehau 		if (__predict_false(error)) {
497215516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
497315516c77SSepherosa Ziehau 			    "pktinfo\n");
497415516c77SSepherosa Ziehau 			return;
497515516c77SSepherosa Ziehau 		}
497615516c77SSepherosa Ziehau 	}
497715516c77SSepherosa Ziehau 
497815516c77SSepherosa Ziehau 	if (__predict_false(data_off + data_len > pkt->rm_len)) {
497915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
498015516c77SSepherosa Ziehau 		    "data overflow, msglen %u, data abs %d len %d\n",
498115516c77SSepherosa Ziehau 		    pkt->rm_len, data_off, data_len);
498215516c77SSepherosa Ziehau 		return;
498315516c77SSepherosa Ziehau 	}
498415516c77SSepherosa Ziehau 	hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
498515516c77SSepherosa Ziehau }
498615516c77SSepherosa Ziehau 
498715516c77SSepherosa Ziehau static __inline void
498815516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen)
498915516c77SSepherosa Ziehau {
499015516c77SSepherosa Ziehau 	const struct rndis_msghdr *hdr;
499115516c77SSepherosa Ziehau 
499215516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*hdr))) {
499315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
499415516c77SSepherosa Ziehau 		return;
499515516c77SSepherosa Ziehau 	}
499615516c77SSepherosa Ziehau 	hdr = data;
499715516c77SSepherosa Ziehau 
499815516c77SSepherosa Ziehau 	if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) {
499915516c77SSepherosa Ziehau 		/* Hot data path. */
500015516c77SSepherosa Ziehau 		hn_rndis_rx_data(rxr, data, dlen);
500115516c77SSepherosa Ziehau 		/* Done! */
500215516c77SSepherosa Ziehau 		return;
500315516c77SSepherosa Ziehau 	}
500415516c77SSepherosa Ziehau 
500515516c77SSepherosa Ziehau 	if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG)
500615516c77SSepherosa Ziehau 		hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen);
500715516c77SSepherosa Ziehau 	else
500815516c77SSepherosa Ziehau 		hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen);
500915516c77SSepherosa Ziehau }
501015516c77SSepherosa Ziehau 
501115516c77SSepherosa Ziehau static void
501215516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
501315516c77SSepherosa Ziehau {
501415516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *hdr;
501515516c77SSepherosa Ziehau 
501615516c77SSepherosa Ziehau 	if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) {
501715516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid nvs notify\n");
501815516c77SSepherosa Ziehau 		return;
501915516c77SSepherosa Ziehau 	}
502015516c77SSepherosa Ziehau 	hdr = VMBUS_CHANPKT_CONST_DATA(pkt);
502115516c77SSepherosa Ziehau 
502215516c77SSepherosa Ziehau 	if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) {
502315516c77SSepherosa Ziehau 		/* Useless; ignore */
502415516c77SSepherosa Ziehau 		return;
502515516c77SSepherosa Ziehau 	}
502615516c77SSepherosa Ziehau 	if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type);
502715516c77SSepherosa Ziehau }
502815516c77SSepherosa Ziehau 
502915516c77SSepherosa Ziehau static void
503015516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan,
503115516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkt)
503215516c77SSepherosa Ziehau {
503315516c77SSepherosa Ziehau 	struct hn_nvs_sendctx *sndc;
503415516c77SSepherosa Ziehau 
503515516c77SSepherosa Ziehau 	sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid;
503615516c77SSepherosa Ziehau 	sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt),
503715516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_DATALEN(pkt));
503815516c77SSepherosa Ziehau 	/*
503915516c77SSepherosa Ziehau 	 * NOTE:
504015516c77SSepherosa Ziehau 	 * 'sndc' CAN NOT be accessed anymore, since it can be freed by
504115516c77SSepherosa Ziehau 	 * its callback.
504215516c77SSepherosa Ziehau 	 */
504315516c77SSepherosa Ziehau }
504415516c77SSepherosa Ziehau 
504515516c77SSepherosa Ziehau static void
504615516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
504715516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkthdr)
504815516c77SSepherosa Ziehau {
504915516c77SSepherosa Ziehau 	const struct vmbus_chanpkt_rxbuf *pkt;
505015516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *nvs_hdr;
505115516c77SSepherosa Ziehau 	int count, i, hlen;
505215516c77SSepherosa Ziehau 
505315516c77SSepherosa Ziehau 	if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) {
505415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n");
505515516c77SSepherosa Ziehau 		return;
505615516c77SSepherosa Ziehau 	}
505715516c77SSepherosa Ziehau 	nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr);
505815516c77SSepherosa Ziehau 
505915516c77SSepherosa Ziehau 	/* Make sure that this is a RNDIS message. */
506015516c77SSepherosa Ziehau 	if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) {
506115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n",
506215516c77SSepherosa Ziehau 		    nvs_hdr->nvs_type);
506315516c77SSepherosa Ziehau 		return;
506415516c77SSepherosa Ziehau 	}
506515516c77SSepherosa Ziehau 
506615516c77SSepherosa Ziehau 	hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen);
506715516c77SSepherosa Ziehau 	if (__predict_false(hlen < sizeof(*pkt))) {
506815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n");
506915516c77SSepherosa Ziehau 		return;
507015516c77SSepherosa Ziehau 	}
507115516c77SSepherosa Ziehau 	pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
507215516c77SSepherosa Ziehau 
507315516c77SSepherosa Ziehau 	if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) {
507415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n",
507515516c77SSepherosa Ziehau 		    pkt->cp_rxbuf_id);
507615516c77SSepherosa Ziehau 		return;
507715516c77SSepherosa Ziehau 	}
507815516c77SSepherosa Ziehau 
507915516c77SSepherosa Ziehau 	count = pkt->cp_rxbuf_cnt;
508015516c77SSepherosa Ziehau 	if (__predict_false(hlen <
508115516c77SSepherosa Ziehau 	    __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) {
508215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count);
508315516c77SSepherosa Ziehau 		return;
508415516c77SSepherosa Ziehau 	}
508515516c77SSepherosa Ziehau 
508615516c77SSepherosa Ziehau 	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
508715516c77SSepherosa Ziehau 	for (i = 0; i < count; ++i) {
508815516c77SSepherosa Ziehau 		int ofs, len;
508915516c77SSepherosa Ziehau 
509015516c77SSepherosa Ziehau 		ofs = pkt->cp_rxbuf[i].rb_ofs;
509115516c77SSepherosa Ziehau 		len = pkt->cp_rxbuf[i].rb_len;
509215516c77SSepherosa Ziehau 		if (__predict_false(ofs + len > HN_RXBUF_SIZE)) {
509315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, "
509415516c77SSepherosa Ziehau 			    "ofs %d, len %d\n", i, ofs, len);
509515516c77SSepherosa Ziehau 			continue;
509615516c77SSepherosa Ziehau 		}
509715516c77SSepherosa Ziehau 		hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len);
509815516c77SSepherosa Ziehau 	}
509915516c77SSepherosa Ziehau 
510015516c77SSepherosa Ziehau 	/*
510115516c77SSepherosa Ziehau 	 * Ack the consumed RXBUF associated w/ this channel packet,
510215516c77SSepherosa Ziehau 	 * so that this RXBUF can be recycled by the hypervisor.
510315516c77SSepherosa Ziehau 	 */
510415516c77SSepherosa Ziehau 	hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid);
510515516c77SSepherosa Ziehau }
510615516c77SSepherosa Ziehau 
510715516c77SSepherosa Ziehau static void
510815516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
510915516c77SSepherosa Ziehau     uint64_t tid)
511015516c77SSepherosa Ziehau {
511115516c77SSepherosa Ziehau 	struct hn_nvs_rndis_ack ack;
511215516c77SSepherosa Ziehau 	int retries, error;
511315516c77SSepherosa Ziehau 
511415516c77SSepherosa Ziehau 	ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK;
511515516c77SSepherosa Ziehau 	ack.nvs_status = HN_NVS_STATUS_OK;
511615516c77SSepherosa Ziehau 
511715516c77SSepherosa Ziehau 	retries = 0;
511815516c77SSepherosa Ziehau again:
511915516c77SSepherosa Ziehau 	error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP,
512015516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid);
512115516c77SSepherosa Ziehau 	if (__predict_false(error == EAGAIN)) {
512215516c77SSepherosa Ziehau 		/*
512315516c77SSepherosa Ziehau 		 * NOTE:
512415516c77SSepherosa Ziehau 		 * This should _not_ happen in real world, since the
512515516c77SSepherosa Ziehau 		 * consumption of the TX bufring from the TX path is
512615516c77SSepherosa Ziehau 		 * controlled.
512715516c77SSepherosa Ziehau 		 */
512815516c77SSepherosa Ziehau 		if (rxr->hn_ack_failed == 0)
512915516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "RXBUF ack retry\n");
513015516c77SSepherosa Ziehau 		rxr->hn_ack_failed++;
513115516c77SSepherosa Ziehau 		retries++;
513215516c77SSepherosa Ziehau 		if (retries < 10) {
513315516c77SSepherosa Ziehau 			DELAY(100);
513415516c77SSepherosa Ziehau 			goto again;
513515516c77SSepherosa Ziehau 		}
513615516c77SSepherosa Ziehau 		/* RXBUF leaks! */
513715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "RXBUF ack failed\n");
513815516c77SSepherosa Ziehau 	}
513915516c77SSepherosa Ziehau }
514015516c77SSepherosa Ziehau 
514115516c77SSepherosa Ziehau static void
514215516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr)
514315516c77SSepherosa Ziehau {
514415516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr = xrxr;
514515516c77SSepherosa Ziehau 	struct hn_softc *sc = rxr->hn_ifp->if_softc;
514615516c77SSepherosa Ziehau 
514715516c77SSepherosa Ziehau 	for (;;) {
514815516c77SSepherosa Ziehau 		struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf;
514915516c77SSepherosa Ziehau 		int error, pktlen;
515015516c77SSepherosa Ziehau 
515115516c77SSepherosa Ziehau 		pktlen = rxr->hn_pktbuf_len;
515215516c77SSepherosa Ziehau 		error = vmbus_chan_recv_pkt(chan, pkt, &pktlen);
515315516c77SSepherosa Ziehau 		if (__predict_false(error == ENOBUFS)) {
515415516c77SSepherosa Ziehau 			void *nbuf;
515515516c77SSepherosa Ziehau 			int nlen;
515615516c77SSepherosa Ziehau 
515715516c77SSepherosa Ziehau 			/*
515815516c77SSepherosa Ziehau 			 * Expand channel packet buffer.
515915516c77SSepherosa Ziehau 			 *
516015516c77SSepherosa Ziehau 			 * XXX
516115516c77SSepherosa Ziehau 			 * Use M_WAITOK here, since allocation failure
516215516c77SSepherosa Ziehau 			 * is fatal.
516315516c77SSepherosa Ziehau 			 */
516415516c77SSepherosa Ziehau 			nlen = rxr->hn_pktbuf_len * 2;
516515516c77SSepherosa Ziehau 			while (nlen < pktlen)
516615516c77SSepherosa Ziehau 				nlen *= 2;
516715516c77SSepherosa Ziehau 			nbuf = malloc(nlen, M_DEVBUF, M_WAITOK);
516815516c77SSepherosa Ziehau 
516915516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n",
517015516c77SSepherosa Ziehau 			    rxr->hn_pktbuf_len, nlen);
517115516c77SSepherosa Ziehau 
517215516c77SSepherosa Ziehau 			free(rxr->hn_pktbuf, M_DEVBUF);
517315516c77SSepherosa Ziehau 			rxr->hn_pktbuf = nbuf;
517415516c77SSepherosa Ziehau 			rxr->hn_pktbuf_len = nlen;
517515516c77SSepherosa Ziehau 			/* Retry! */
517615516c77SSepherosa Ziehau 			continue;
517715516c77SSepherosa Ziehau 		} else if (__predict_false(error == EAGAIN)) {
517815516c77SSepherosa Ziehau 			/* No more channel packets; done! */
517915516c77SSepherosa Ziehau 			break;
518015516c77SSepherosa Ziehau 		}
518115516c77SSepherosa Ziehau 		KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error));
518215516c77SSepherosa Ziehau 
518315516c77SSepherosa Ziehau 		switch (pkt->cph_type) {
518415516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_COMP:
518515516c77SSepherosa Ziehau 			hn_nvs_handle_comp(sc, chan, pkt);
518615516c77SSepherosa Ziehau 			break;
518715516c77SSepherosa Ziehau 
518815516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_RXBUF:
518915516c77SSepherosa Ziehau 			hn_nvs_handle_rxbuf(rxr, chan, pkt);
519015516c77SSepherosa Ziehau 			break;
519115516c77SSepherosa Ziehau 
519215516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_INBAND:
519315516c77SSepherosa Ziehau 			hn_nvs_handle_notify(sc, pkt);
519415516c77SSepherosa Ziehau 			break;
519515516c77SSepherosa Ziehau 
519615516c77SSepherosa Ziehau 		default:
519715516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "unknown chan pkt %u\n",
519815516c77SSepherosa Ziehau 			    pkt->cph_type);
519915516c77SSepherosa Ziehau 			break;
520015516c77SSepherosa Ziehau 		}
520115516c77SSepherosa Ziehau 	}
520215516c77SSepherosa Ziehau 	hn_chan_rollup(rxr, rxr->hn_txr);
520315516c77SSepherosa Ziehau }
520415516c77SSepherosa Ziehau 
520515516c77SSepherosa Ziehau static void
520615516c77SSepherosa Ziehau hn_tx_taskq_create(void *arg __unused)
520715516c77SSepherosa Ziehau {
520815516c77SSepherosa Ziehau 
520915516c77SSepherosa Ziehau 	if (vm_guest != VM_GUEST_HV)
521015516c77SSepherosa Ziehau 		return;
521115516c77SSepherosa Ziehau 
521215516c77SSepherosa Ziehau 	if (!hn_share_tx_taskq)
521315516c77SSepherosa Ziehau 		return;
521415516c77SSepherosa Ziehau 
521515516c77SSepherosa Ziehau 	hn_tx_taskq = taskqueue_create("hn_tx", M_WAITOK,
521615516c77SSepherosa Ziehau 	    taskqueue_thread_enqueue, &hn_tx_taskq);
521715516c77SSepherosa Ziehau 	if (hn_bind_tx_taskq >= 0) {
521815516c77SSepherosa Ziehau 		int cpu = hn_bind_tx_taskq;
521915516c77SSepherosa Ziehau 		cpuset_t cpu_set;
522015516c77SSepherosa Ziehau 
522115516c77SSepherosa Ziehau 		if (cpu > mp_ncpus - 1)
522215516c77SSepherosa Ziehau 			cpu = mp_ncpus - 1;
522315516c77SSepherosa Ziehau 		CPU_SETOF(cpu, &cpu_set);
522415516c77SSepherosa Ziehau 		taskqueue_start_threads_cpuset(&hn_tx_taskq, 1, PI_NET,
522515516c77SSepherosa Ziehau 		    &cpu_set, "hn tx");
522615516c77SSepherosa Ziehau 	} else {
522715516c77SSepherosa Ziehau 		taskqueue_start_threads(&hn_tx_taskq, 1, PI_NET, "hn tx");
522815516c77SSepherosa Ziehau 	}
522915516c77SSepherosa Ziehau }
523015516c77SSepherosa Ziehau SYSINIT(hn_txtq_create, SI_SUB_DRIVERS, SI_ORDER_SECOND,
523115516c77SSepherosa Ziehau     hn_tx_taskq_create, NULL);
523215516c77SSepherosa Ziehau 
523315516c77SSepherosa Ziehau static void
523415516c77SSepherosa Ziehau hn_tx_taskq_destroy(void *arg __unused)
523515516c77SSepherosa Ziehau {
523615516c77SSepherosa Ziehau 
523715516c77SSepherosa Ziehau 	if (hn_tx_taskq != NULL)
523815516c77SSepherosa Ziehau 		taskqueue_free(hn_tx_taskq);
523915516c77SSepherosa Ziehau }
524015516c77SSepherosa Ziehau SYSUNINIT(hn_txtq_destroy, SI_SUB_DRIVERS, SI_ORDER_SECOND,
524115516c77SSepherosa Ziehau     hn_tx_taskq_destroy, NULL);
5242