xref: /freebsd/sys/dev/hyperv/netvsc/if_hn.c (revision edd3f31541d8a0a5365b0cbe0f48db8535a838c8)
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)
15215516c77SSepherosa Ziehau #define HN_LOCK(sc)			sx_xlock(&(sc)->hn_lock)
15315516c77SSepherosa Ziehau #define HN_UNLOCK(sc)			sx_xunlock(&(sc)->hn_lock)
15415516c77SSepherosa Ziehau 
15515516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK			(CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP)
15615516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK		(CSUM_IP6_TCP | CSUM_IP6_UDP)
15715516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc)		\
15815516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK)
15915516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc)	\
16015516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK)
16115516c77SSepherosa Ziehau 
16215516c77SSepherosa Ziehau struct hn_txdesc {
16315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
16415516c77SSepherosa Ziehau 	SLIST_ENTRY(hn_txdesc)		link;
16515516c77SSepherosa Ziehau #endif
16615516c77SSepherosa Ziehau 	struct mbuf			*m;
16715516c77SSepherosa Ziehau 	struct hn_tx_ring		*txr;
16815516c77SSepherosa Ziehau 	int				refs;
16915516c77SSepherosa Ziehau 	uint32_t			flags;	/* HN_TXD_FLAG_ */
17015516c77SSepherosa Ziehau 	struct hn_nvs_sendctx		send_ctx;
17115516c77SSepherosa Ziehau 	uint32_t			chim_index;
17215516c77SSepherosa Ziehau 	int				chim_size;
17315516c77SSepherosa Ziehau 
17415516c77SSepherosa Ziehau 	bus_dmamap_t			data_dmap;
17515516c77SSepherosa Ziehau 
17615516c77SSepherosa Ziehau 	bus_addr_t			rndis_pkt_paddr;
17715516c77SSepherosa Ziehau 	struct rndis_packet_msg		*rndis_pkt;
17815516c77SSepherosa Ziehau 	bus_dmamap_t			rndis_pkt_dmap;
17915516c77SSepherosa Ziehau };
18015516c77SSepherosa Ziehau 
18115516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST		0x0001
18215516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP		0x0002
18315516c77SSepherosa Ziehau 
18415516c77SSepherosa Ziehau struct hn_rxinfo {
18515516c77SSepherosa Ziehau 	uint32_t			vlan_info;
18615516c77SSepherosa Ziehau 	uint32_t			csum_info;
18715516c77SSepherosa Ziehau 	uint32_t			hash_info;
18815516c77SSepherosa Ziehau 	uint32_t			hash_value;
18915516c77SSepherosa Ziehau };
19015516c77SSepherosa Ziehau 
19115516c77SSepherosa Ziehau #define HN_RXINFO_VLAN			0x0001
19215516c77SSepherosa Ziehau #define HN_RXINFO_CSUM			0x0002
19315516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF		0x0004
19415516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL		0x0008
19515516c77SSepherosa Ziehau #define HN_RXINFO_ALL			\
19615516c77SSepherosa Ziehau 	(HN_RXINFO_VLAN |		\
19715516c77SSepherosa Ziehau 	 HN_RXINFO_CSUM |		\
19815516c77SSepherosa Ziehau 	 HN_RXINFO_HASHINF |		\
19915516c77SSepherosa Ziehau 	 HN_RXINFO_HASHVAL)
20015516c77SSepherosa Ziehau 
20115516c77SSepherosa Ziehau #define HN_NDIS_VLAN_INFO_INVALID	0xffffffff
20215516c77SSepherosa Ziehau #define HN_NDIS_RXCSUM_INFO_INVALID	0
20315516c77SSepherosa Ziehau #define HN_NDIS_HASH_INFO_INVALID	0
20415516c77SSepherosa Ziehau 
20515516c77SSepherosa Ziehau static int			hn_probe(device_t);
20615516c77SSepherosa Ziehau static int			hn_attach(device_t);
20715516c77SSepherosa Ziehau static int			hn_detach(device_t);
20815516c77SSepherosa Ziehau static int			hn_shutdown(device_t);
20915516c77SSepherosa Ziehau static void			hn_chan_callback(struct vmbus_channel *,
21015516c77SSepherosa Ziehau 				    void *);
21115516c77SSepherosa Ziehau 
21215516c77SSepherosa Ziehau static void			hn_init(void *);
21315516c77SSepherosa Ziehau static int			hn_ioctl(struct ifnet *, u_long, caddr_t);
21423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
21515516c77SSepherosa Ziehau static void			hn_start(struct ifnet *);
21623bf9e15SSepherosa Ziehau #endif
21715516c77SSepherosa Ziehau static int			hn_transmit(struct ifnet *, struct mbuf *);
21815516c77SSepherosa Ziehau static void			hn_xmit_qflush(struct ifnet *);
21915516c77SSepherosa Ziehau static int			hn_ifmedia_upd(struct ifnet *);
22015516c77SSepherosa Ziehau static void			hn_ifmedia_sts(struct ifnet *,
22115516c77SSepherosa Ziehau 				    struct ifmediareq *);
22215516c77SSepherosa Ziehau 
22315516c77SSepherosa Ziehau static int			hn_rndis_rxinfo(const void *, int,
22415516c77SSepherosa Ziehau 				    struct hn_rxinfo *);
22515516c77SSepherosa Ziehau static void			hn_rndis_rx_data(struct hn_rx_ring *,
22615516c77SSepherosa Ziehau 				    const void *, int);
22715516c77SSepherosa Ziehau static void			hn_rndis_rx_status(struct hn_softc *,
22815516c77SSepherosa Ziehau 				    const void *, int);
22915516c77SSepherosa Ziehau 
23015516c77SSepherosa Ziehau static void			hn_nvs_handle_notify(struct hn_softc *,
23115516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
23215516c77SSepherosa Ziehau static void			hn_nvs_handle_comp(struct hn_softc *,
23315516c77SSepherosa Ziehau 				    struct vmbus_channel *,
23415516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
23515516c77SSepherosa Ziehau static void			hn_nvs_handle_rxbuf(struct hn_rx_ring *,
23615516c77SSepherosa Ziehau 				    struct vmbus_channel *,
23715516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
23815516c77SSepherosa Ziehau static void			hn_nvs_ack_rxbuf(struct hn_rx_ring *,
23915516c77SSepherosa Ziehau 				    struct vmbus_channel *, uint64_t);
24015516c77SSepherosa Ziehau 
24115516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
24215516c77SSepherosa Ziehau static int			hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS);
24315516c77SSepherosa Ziehau static int			hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS);
24415516c77SSepherosa Ziehau #endif
24515516c77SSepherosa Ziehau static int			hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS);
24615516c77SSepherosa Ziehau static int			hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS);
24715516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
24815516c77SSepherosa Ziehau static int			hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS);
24915516c77SSepherosa Ziehau #else
25015516c77SSepherosa Ziehau static int			hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS);
25115516c77SSepherosa Ziehau #endif
25215516c77SSepherosa Ziehau static int			hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
25315516c77SSepherosa Ziehau static int			hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
25415516c77SSepherosa Ziehau static int			hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS);
25515516c77SSepherosa Ziehau static int			hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS);
25615516c77SSepherosa Ziehau static int			hn_caps_sysctl(SYSCTL_HANDLER_ARGS);
25715516c77SSepherosa Ziehau static int			hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS);
25815516c77SSepherosa Ziehau static int			hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS);
25915516c77SSepherosa Ziehau static int			hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS);
26015516c77SSepherosa Ziehau static int			hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS);
26115516c77SSepherosa Ziehau static int			hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS);
26215516c77SSepherosa Ziehau 
26315516c77SSepherosa Ziehau static void			hn_stop(struct hn_softc *);
26415516c77SSepherosa Ziehau static void			hn_init_locked(struct hn_softc *);
26515516c77SSepherosa Ziehau static int			hn_chan_attach(struct hn_softc *,
26615516c77SSepherosa Ziehau 				    struct vmbus_channel *);
26715516c77SSepherosa Ziehau static void			hn_chan_detach(struct hn_softc *,
26815516c77SSepherosa Ziehau 				    struct vmbus_channel *);
26915516c77SSepherosa Ziehau static int			hn_attach_subchans(struct hn_softc *);
27015516c77SSepherosa Ziehau static void			hn_detach_allchans(struct hn_softc *);
27115516c77SSepherosa Ziehau static void			hn_chan_rollup(struct hn_rx_ring *,
27215516c77SSepherosa Ziehau 				    struct hn_tx_ring *);
27315516c77SSepherosa Ziehau static void			hn_set_ring_inuse(struct hn_softc *, int);
27415516c77SSepherosa Ziehau static int			hn_synth_attach(struct hn_softc *, int);
27515516c77SSepherosa Ziehau static void			hn_synth_detach(struct hn_softc *);
27615516c77SSepherosa Ziehau static int			hn_synth_alloc_subchans(struct hn_softc *,
27715516c77SSepherosa Ziehau 				    int *);
27815516c77SSepherosa Ziehau static void			hn_suspend(struct hn_softc *);
27915516c77SSepherosa Ziehau static void			hn_suspend_data(struct hn_softc *);
28015516c77SSepherosa Ziehau static void			hn_suspend_mgmt(struct hn_softc *);
28115516c77SSepherosa Ziehau static void			hn_resume(struct hn_softc *);
28215516c77SSepherosa Ziehau static void			hn_resume_data(struct hn_softc *);
28315516c77SSepherosa Ziehau static void			hn_resume_mgmt(struct hn_softc *);
28415516c77SSepherosa Ziehau static void			hn_suspend_mgmt_taskfunc(void *, int);
28515516c77SSepherosa Ziehau static void			hn_chan_drain(struct vmbus_channel *);
28615516c77SSepherosa Ziehau 
28715516c77SSepherosa Ziehau static void			hn_update_link_status(struct hn_softc *);
28815516c77SSepherosa Ziehau static void			hn_change_network(struct hn_softc *);
28915516c77SSepherosa Ziehau static void			hn_link_taskfunc(void *, int);
29015516c77SSepherosa Ziehau static void			hn_netchg_init_taskfunc(void *, int);
29115516c77SSepherosa Ziehau static void			hn_netchg_status_taskfunc(void *, int);
29215516c77SSepherosa Ziehau static void			hn_link_status(struct hn_softc *);
29315516c77SSepherosa Ziehau 
29415516c77SSepherosa Ziehau static int			hn_create_rx_data(struct hn_softc *, int);
29515516c77SSepherosa Ziehau static void			hn_destroy_rx_data(struct hn_softc *);
29615516c77SSepherosa Ziehau static int			hn_check_iplen(const struct mbuf *, int);
29715516c77SSepherosa Ziehau static int			hn_set_rxfilter(struct hn_softc *);
29815516c77SSepherosa Ziehau static int			hn_rss_reconfig(struct hn_softc *);
29915516c77SSepherosa Ziehau static void			hn_rss_ind_fixup(struct hn_softc *, int);
30015516c77SSepherosa Ziehau static int			hn_rxpkt(struct hn_rx_ring *, const void *,
30115516c77SSepherosa Ziehau 				    int, const struct hn_rxinfo *);
30215516c77SSepherosa Ziehau 
30315516c77SSepherosa Ziehau static int			hn_tx_ring_create(struct hn_softc *, int);
30415516c77SSepherosa Ziehau static void			hn_tx_ring_destroy(struct hn_tx_ring *);
30515516c77SSepherosa Ziehau static int			hn_create_tx_data(struct hn_softc *, int);
30615516c77SSepherosa Ziehau static void			hn_fixup_tx_data(struct hn_softc *);
30715516c77SSepherosa Ziehau static void			hn_destroy_tx_data(struct hn_softc *);
30815516c77SSepherosa Ziehau static void			hn_txdesc_dmamap_destroy(struct hn_txdesc *);
30915516c77SSepherosa Ziehau static int			hn_encap(struct hn_tx_ring *,
31015516c77SSepherosa Ziehau 				    struct hn_txdesc *, struct mbuf **);
31115516c77SSepherosa Ziehau static int			hn_txpkt(struct ifnet *, struct hn_tx_ring *,
31215516c77SSepherosa Ziehau 				    struct hn_txdesc *);
31315516c77SSepherosa Ziehau static void			hn_set_chim_size(struct hn_softc *, int);
31415516c77SSepherosa Ziehau static void			hn_set_tso_maxsize(struct hn_softc *, int, int);
31515516c77SSepherosa Ziehau static bool			hn_tx_ring_pending(struct hn_tx_ring *);
31615516c77SSepherosa Ziehau static void			hn_tx_ring_qflush(struct hn_tx_ring *);
31715516c77SSepherosa Ziehau static void			hn_resume_tx(struct hn_softc *, int);
31815516c77SSepherosa Ziehau static int			hn_get_txswq_depth(const struct hn_tx_ring *);
31915516c77SSepherosa Ziehau static void			hn_txpkt_done(struct hn_nvs_sendctx *,
32015516c77SSepherosa Ziehau 				    struct hn_softc *, struct vmbus_channel *,
32115516c77SSepherosa Ziehau 				    const void *, int);
32215516c77SSepherosa Ziehau static int			hn_txpkt_sglist(struct hn_tx_ring *,
32315516c77SSepherosa Ziehau 				    struct hn_txdesc *);
32415516c77SSepherosa Ziehau static int			hn_txpkt_chim(struct hn_tx_ring *,
32515516c77SSepherosa Ziehau 				    struct hn_txdesc *);
32615516c77SSepherosa Ziehau static int			hn_xmit(struct hn_tx_ring *, int);
32715516c77SSepherosa Ziehau static void			hn_xmit_taskfunc(void *, int);
32815516c77SSepherosa Ziehau static void			hn_xmit_txeof(struct hn_tx_ring *);
32915516c77SSepherosa Ziehau static void			hn_xmit_txeof_taskfunc(void *, int);
33023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
33115516c77SSepherosa Ziehau static int			hn_start_locked(struct hn_tx_ring *, int);
33215516c77SSepherosa Ziehau static void			hn_start_taskfunc(void *, int);
33315516c77SSepherosa Ziehau static void			hn_start_txeof(struct hn_tx_ring *);
33415516c77SSepherosa Ziehau static void			hn_start_txeof_taskfunc(void *, int);
33523bf9e15SSepherosa Ziehau #endif
33615516c77SSepherosa Ziehau 
33715516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
33815516c77SSepherosa Ziehau     "Hyper-V network interface");
33915516c77SSepherosa Ziehau 
34015516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */
34115516c77SSepherosa Ziehau static int			hn_trust_hosttcp = 1;
34215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN,
34315516c77SSepherosa Ziehau     &hn_trust_hosttcp, 0,
34415516c77SSepherosa Ziehau     "Trust tcp segement verification on host side, "
34515516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
34615516c77SSepherosa Ziehau 
34715516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */
34815516c77SSepherosa Ziehau static int			hn_trust_hostudp = 1;
34915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN,
35015516c77SSepherosa Ziehau     &hn_trust_hostudp, 0,
35115516c77SSepherosa Ziehau     "Trust udp datagram verification on host side, "
35215516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
35315516c77SSepherosa Ziehau 
35415516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */
35515516c77SSepherosa Ziehau static int			hn_trust_hostip = 1;
35615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN,
35715516c77SSepherosa Ziehau     &hn_trust_hostip, 0,
35815516c77SSepherosa Ziehau     "Trust ip packet verification on host side, "
35915516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
36015516c77SSepherosa Ziehau 
36115516c77SSepherosa Ziehau /* Limit TSO burst size */
36215516c77SSepherosa Ziehau static int			hn_tso_maxlen = IP_MAXPACKET;
36315516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN,
36415516c77SSepherosa Ziehau     &hn_tso_maxlen, 0, "TSO burst limit");
36515516c77SSepherosa Ziehau 
36615516c77SSepherosa Ziehau /* Limit chimney send size */
36715516c77SSepherosa Ziehau static int			hn_tx_chimney_size = 0;
36815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN,
36915516c77SSepherosa Ziehau     &hn_tx_chimney_size, 0, "Chimney send packet size limit");
37015516c77SSepherosa Ziehau 
37115516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */
37215516c77SSepherosa Ziehau static int			hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF;
37315516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN,
37415516c77SSepherosa Ziehau     &hn_direct_tx_size, 0, "Size of the packet for direct transmission");
37515516c77SSepherosa Ziehau 
37615516c77SSepherosa Ziehau /* # of LRO entries per RX ring */
37715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
37815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
37915516c77SSepherosa Ziehau static int			hn_lro_entry_count = HN_LROENT_CNT_DEF;
38015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN,
38115516c77SSepherosa Ziehau     &hn_lro_entry_count, 0, "LRO entry count");
38215516c77SSepherosa Ziehau #endif
38315516c77SSepherosa Ziehau #endif
38415516c77SSepherosa Ziehau 
38515516c77SSepherosa Ziehau /* Use shared TX taskqueue */
38615516c77SSepherosa Ziehau static int			hn_share_tx_taskq = 0;
38715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, share_tx_taskq, CTLFLAG_RDTUN,
38815516c77SSepherosa Ziehau     &hn_share_tx_taskq, 0, "Enable shared TX taskqueue");
38915516c77SSepherosa Ziehau 
39015516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
39115516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 0;
39215516c77SSepherosa Ziehau #else
39315516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 1;
39415516c77SSepherosa Ziehau #endif
39515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD,
39615516c77SSepherosa Ziehau     &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors");
39715516c77SSepherosa Ziehau 
39815516c77SSepherosa Ziehau /* Bind TX taskqueue to the target CPU */
39915516c77SSepherosa Ziehau static int			hn_bind_tx_taskq = -1;
40015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, bind_tx_taskq, CTLFLAG_RDTUN,
40115516c77SSepherosa Ziehau     &hn_bind_tx_taskq, 0, "Bind TX taskqueue to the specified cpu");
40215516c77SSepherosa Ziehau 
40323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
40415516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */
40515516c77SSepherosa Ziehau static int			hn_use_if_start = 0;
40615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN,
40715516c77SSepherosa Ziehau     &hn_use_if_start, 0, "Use if_start TX method");
40823bf9e15SSepherosa Ziehau #endif
40915516c77SSepherosa Ziehau 
41015516c77SSepherosa Ziehau /* # of channels to use */
41115516c77SSepherosa Ziehau static int			hn_chan_cnt = 0;
41215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN,
41315516c77SSepherosa Ziehau     &hn_chan_cnt, 0,
41415516c77SSepherosa Ziehau     "# of channels to use; each channel has one RX ring and one TX ring");
41515516c77SSepherosa Ziehau 
41615516c77SSepherosa Ziehau /* # of transmit rings to use */
41715516c77SSepherosa Ziehau static int			hn_tx_ring_cnt = 0;
41815516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN,
41915516c77SSepherosa Ziehau     &hn_tx_ring_cnt, 0, "# of TX rings to use");
42015516c77SSepherosa Ziehau 
42115516c77SSepherosa Ziehau /* Software TX ring deptch */
42215516c77SSepherosa Ziehau static int			hn_tx_swq_depth = 0;
42315516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN,
42415516c77SSepherosa Ziehau     &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING");
42515516c77SSepherosa Ziehau 
42615516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */
42715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
42815516c77SSepherosa Ziehau static u_int			hn_lro_mbufq_depth = 0;
42915516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN,
43015516c77SSepherosa Ziehau     &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue");
43115516c77SSepherosa Ziehau #endif
43215516c77SSepherosa Ziehau 
43315516c77SSepherosa Ziehau static u_int			hn_cpu_index;	/* next CPU for channel */
43415516c77SSepherosa Ziehau static struct taskqueue		*hn_tx_taskq;	/* shared TX taskqueue */
43515516c77SSepherosa Ziehau 
43615516c77SSepherosa Ziehau static const uint8_t
43715516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
43815516c77SSepherosa Ziehau 	0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
43915516c77SSepherosa Ziehau 	0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
44015516c77SSepherosa Ziehau 	0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
44115516c77SSepherosa Ziehau 	0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
44215516c77SSepherosa Ziehau 	0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
44315516c77SSepherosa Ziehau };
44415516c77SSepherosa Ziehau 
44515516c77SSepherosa Ziehau static device_method_t hn_methods[] = {
44615516c77SSepherosa Ziehau 	/* Device interface */
44715516c77SSepherosa Ziehau 	DEVMETHOD(device_probe,		hn_probe),
44815516c77SSepherosa Ziehau 	DEVMETHOD(device_attach,	hn_attach),
44915516c77SSepherosa Ziehau 	DEVMETHOD(device_detach,	hn_detach),
45015516c77SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	hn_shutdown),
45115516c77SSepherosa Ziehau 	DEVMETHOD_END
45215516c77SSepherosa Ziehau };
45315516c77SSepherosa Ziehau 
45415516c77SSepherosa Ziehau static driver_t hn_driver = {
45515516c77SSepherosa Ziehau 	"hn",
45615516c77SSepherosa Ziehau 	hn_methods,
45715516c77SSepherosa Ziehau 	sizeof(struct hn_softc)
45815516c77SSepherosa Ziehau };
45915516c77SSepherosa Ziehau 
46015516c77SSepherosa Ziehau static devclass_t hn_devclass;
46115516c77SSepherosa Ziehau 
46215516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0);
46315516c77SSepherosa Ziehau MODULE_VERSION(hn, 1);
46415516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1);
46515516c77SSepherosa Ziehau 
46615516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
46715516c77SSepherosa Ziehau static void
46815516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim)
46915516c77SSepherosa Ziehau {
47015516c77SSepherosa Ziehau 	int i;
47115516c77SSepherosa Ziehau 
47215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_inuse; ++i)
47315516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim;
47415516c77SSepherosa Ziehau }
47515516c77SSepherosa Ziehau #endif
47615516c77SSepherosa Ziehau 
47715516c77SSepherosa Ziehau static int
47815516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd)
47915516c77SSepherosa Ziehau {
48015516c77SSepherosa Ziehau 
48115516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
48215516c77SSepherosa Ziehau 	    txd->chim_size == 0, ("invalid rndis sglist txd"));
48315516c77SSepherosa Ziehau 	return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA,
48415516c77SSepherosa Ziehau 	    &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt));
48515516c77SSepherosa Ziehau }
48615516c77SSepherosa Ziehau 
48715516c77SSepherosa Ziehau static int
48815516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd)
48915516c77SSepherosa Ziehau {
49015516c77SSepherosa Ziehau 	struct hn_nvs_rndis rndis;
49115516c77SSepherosa Ziehau 
49215516c77SSepherosa Ziehau 	KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID &&
49315516c77SSepherosa Ziehau 	    txd->chim_size > 0, ("invalid rndis chim txd"));
49415516c77SSepherosa Ziehau 
49515516c77SSepherosa Ziehau 	rndis.nvs_type = HN_NVS_TYPE_RNDIS;
49615516c77SSepherosa Ziehau 	rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA;
49715516c77SSepherosa Ziehau 	rndis.nvs_chim_idx = txd->chim_index;
49815516c77SSepherosa Ziehau 	rndis.nvs_chim_sz = txd->chim_size;
49915516c77SSepherosa Ziehau 
50015516c77SSepherosa Ziehau 	return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC,
50115516c77SSepherosa Ziehau 	    &rndis, sizeof(rndis), &txd->send_ctx));
50215516c77SSepherosa Ziehau }
50315516c77SSepherosa Ziehau 
50415516c77SSepherosa Ziehau static __inline uint32_t
50515516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc)
50615516c77SSepherosa Ziehau {
50715516c77SSepherosa Ziehau 	int i, bmap_cnt = sc->hn_chim_bmap_cnt;
50815516c77SSepherosa Ziehau 	u_long *bmap = sc->hn_chim_bmap;
50915516c77SSepherosa Ziehau 	uint32_t ret = HN_NVS_CHIM_IDX_INVALID;
51015516c77SSepherosa Ziehau 
51115516c77SSepherosa Ziehau 	for (i = 0; i < bmap_cnt; ++i) {
51215516c77SSepherosa Ziehau 		int idx;
51315516c77SSepherosa Ziehau 
51415516c77SSepherosa Ziehau 		idx = ffsl(~bmap[i]);
51515516c77SSepherosa Ziehau 		if (idx == 0)
51615516c77SSepherosa Ziehau 			continue;
51715516c77SSepherosa Ziehau 
51815516c77SSepherosa Ziehau 		--idx; /* ffsl is 1-based */
51915516c77SSepherosa Ziehau 		KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt,
52015516c77SSepherosa Ziehau 		    ("invalid i %d and idx %d", i, idx));
52115516c77SSepherosa Ziehau 
52215516c77SSepherosa Ziehau 		if (atomic_testandset_long(&bmap[i], idx))
52315516c77SSepherosa Ziehau 			continue;
52415516c77SSepherosa Ziehau 
52515516c77SSepherosa Ziehau 		ret = i * LONG_BIT + idx;
52615516c77SSepherosa Ziehau 		break;
52715516c77SSepherosa Ziehau 	}
52815516c77SSepherosa Ziehau 	return (ret);
52915516c77SSepherosa Ziehau }
53015516c77SSepherosa Ziehau 
53115516c77SSepherosa Ziehau static __inline void
53215516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx)
53315516c77SSepherosa Ziehau {
53415516c77SSepherosa Ziehau 	u_long mask;
53515516c77SSepherosa Ziehau 	uint32_t idx;
53615516c77SSepherosa Ziehau 
53715516c77SSepherosa Ziehau 	idx = chim_idx / LONG_BIT;
53815516c77SSepherosa Ziehau 	KASSERT(idx < sc->hn_chim_bmap_cnt,
53915516c77SSepherosa Ziehau 	    ("invalid chimney index 0x%x", chim_idx));
54015516c77SSepherosa Ziehau 
54115516c77SSepherosa Ziehau 	mask = 1UL << (chim_idx % LONG_BIT);
54215516c77SSepherosa Ziehau 	KASSERT(sc->hn_chim_bmap[idx] & mask,
54315516c77SSepherosa Ziehau 	    ("index bitmap 0x%lx, chimney index %u, "
54415516c77SSepherosa Ziehau 	     "bitmap idx %d, bitmask 0x%lx",
54515516c77SSepherosa Ziehau 	     sc->hn_chim_bmap[idx], chim_idx, idx, mask));
54615516c77SSepherosa Ziehau 
54715516c77SSepherosa Ziehau 	atomic_clear_long(&sc->hn_chim_bmap[idx], mask);
54815516c77SSepherosa Ziehau }
54915516c77SSepherosa Ziehau 
550*edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
551*edd3f315SSepherosa Ziehau /*
552*edd3f315SSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
553*edd3f315SSepherosa Ziehau  */
554*edd3f315SSepherosa Ziehau static __inline struct mbuf *
555*edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head)
556*edd3f315SSepherosa Ziehau {
557*edd3f315SSepherosa Ziehau 	struct ether_vlan_header *evl;
558*edd3f315SSepherosa Ziehau 	struct tcphdr *th;
559*edd3f315SSepherosa Ziehau 	int ehlen;
560*edd3f315SSepherosa Ziehau 
561*edd3f315SSepherosa Ziehau 	KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable"));
562*edd3f315SSepherosa Ziehau 
563*edd3f315SSepherosa Ziehau #define PULLUP_HDR(m, len)				\
564*edd3f315SSepherosa Ziehau do {							\
565*edd3f315SSepherosa Ziehau 	if (__predict_false((m)->m_len < (len))) {	\
566*edd3f315SSepherosa Ziehau 		(m) = m_pullup((m), (len));		\
567*edd3f315SSepherosa Ziehau 		if ((m) == NULL)			\
568*edd3f315SSepherosa Ziehau 			return (NULL);			\
569*edd3f315SSepherosa Ziehau 	}						\
570*edd3f315SSepherosa Ziehau } while (0)
571*edd3f315SSepherosa Ziehau 
572*edd3f315SSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
573*edd3f315SSepherosa Ziehau 	evl = mtod(m_head, struct ether_vlan_header *);
574*edd3f315SSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
575*edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
576*edd3f315SSepherosa Ziehau 	else
577*edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
578*edd3f315SSepherosa Ziehau 
579*edd3f315SSepherosa Ziehau #ifdef INET
580*edd3f315SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
581*edd3f315SSepherosa Ziehau 		struct ip *ip;
582*edd3f315SSepherosa Ziehau 		int iphlen;
583*edd3f315SSepherosa Ziehau 
584*edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
585*edd3f315SSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
586*edd3f315SSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
587*edd3f315SSepherosa Ziehau 
588*edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
589*edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + iphlen);
590*edd3f315SSepherosa Ziehau 
591*edd3f315SSepherosa Ziehau 		ip->ip_len = 0;
592*edd3f315SSepherosa Ziehau 		ip->ip_sum = 0;
593*edd3f315SSepherosa Ziehau 		th->th_sum = in_pseudo(ip->ip_src.s_addr,
594*edd3f315SSepherosa Ziehau 		    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
595*edd3f315SSepherosa Ziehau 	}
596*edd3f315SSepherosa Ziehau #endif
597*edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET)
598*edd3f315SSepherosa Ziehau 	else
599*edd3f315SSepherosa Ziehau #endif
600*edd3f315SSepherosa Ziehau #ifdef INET6
601*edd3f315SSepherosa Ziehau 	{
602*edd3f315SSepherosa Ziehau 		struct ip6_hdr *ip6;
603*edd3f315SSepherosa Ziehau 
604*edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
605*edd3f315SSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
606*edd3f315SSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP) {
607*edd3f315SSepherosa Ziehau 			m_freem(m_head);
608*edd3f315SSepherosa Ziehau 			return (NULL);
609*edd3f315SSepherosa Ziehau 		}
610*edd3f315SSepherosa Ziehau 
611*edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
612*edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + sizeof(*ip6));
613*edd3f315SSepherosa Ziehau 
614*edd3f315SSepherosa Ziehau 		ip6->ip6_plen = 0;
615*edd3f315SSepherosa Ziehau 		th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
616*edd3f315SSepherosa Ziehau 	}
617*edd3f315SSepherosa Ziehau #endif
618*edd3f315SSepherosa Ziehau 	return (m_head);
619*edd3f315SSepherosa Ziehau 
620*edd3f315SSepherosa Ziehau #undef PULLUP_HDR
621*edd3f315SSepherosa Ziehau }
622*edd3f315SSepherosa Ziehau #endif	/* INET6 || INET */
623*edd3f315SSepherosa Ziehau 
62415516c77SSepherosa Ziehau static int
62515516c77SSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc)
62615516c77SSepherosa Ziehau {
62715516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
62815516c77SSepherosa Ziehau 	uint32_t filter;
62915516c77SSepherosa Ziehau 	int error = 0;
63015516c77SSepherosa Ziehau 
63115516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
63215516c77SSepherosa Ziehau 
63315516c77SSepherosa Ziehau 	if (ifp->if_flags & IFF_PROMISC) {
63415516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_PROMISCUOUS;
63515516c77SSepherosa Ziehau 	} else {
63615516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_DIRECTED;
63715516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_BROADCAST)
63815516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_BROADCAST;
63915516c77SSepherosa Ziehau #ifdef notyet
64015516c77SSepherosa Ziehau 		/*
64115516c77SSepherosa Ziehau 		 * See the comment in SIOCADDMULTI/SIOCDELMULTI.
64215516c77SSepherosa Ziehau 		 */
64315516c77SSepherosa Ziehau 		/* TODO: support multicast list */
64415516c77SSepherosa Ziehau 		if ((ifp->if_flags & IFF_ALLMULTI) ||
64515516c77SSepherosa Ziehau 		    !TAILQ_EMPTY(&ifp->if_multiaddrs))
64615516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
64715516c77SSepherosa Ziehau #else
64815516c77SSepherosa Ziehau 		/* Always enable ALLMULTI */
64915516c77SSepherosa Ziehau 		filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
65015516c77SSepherosa Ziehau #endif
65115516c77SSepherosa Ziehau 	}
65215516c77SSepherosa Ziehau 
65315516c77SSepherosa Ziehau 	if (sc->hn_rx_filter != filter) {
65415516c77SSepherosa Ziehau 		error = hn_rndis_set_rxfilter(sc, filter);
65515516c77SSepherosa Ziehau 		if (!error)
65615516c77SSepherosa Ziehau 			sc->hn_rx_filter = filter;
65715516c77SSepherosa Ziehau 	}
65815516c77SSepherosa Ziehau 	return (error);
65915516c77SSepherosa Ziehau }
66015516c77SSepherosa Ziehau 
66115516c77SSepherosa Ziehau static int
66215516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr)
66315516c77SSepherosa Ziehau {
66415516c77SSepherosa Ziehau 
66515516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet"));
66615516c77SSepherosa Ziehau 	if (hn_tx_swq_depth < txr->hn_txdesc_cnt)
66715516c77SSepherosa Ziehau 		return txr->hn_txdesc_cnt;
66815516c77SSepherosa Ziehau 	return hn_tx_swq_depth;
66915516c77SSepherosa Ziehau }
67015516c77SSepherosa Ziehau 
67115516c77SSepherosa Ziehau static int
67215516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc)
67315516c77SSepherosa Ziehau {
67415516c77SSepherosa Ziehau 	int error;
67515516c77SSepherosa Ziehau 
67615516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
67715516c77SSepherosa Ziehau 
67815516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
67915516c77SSepherosa Ziehau 		return (ENXIO);
68015516c77SSepherosa Ziehau 
68115516c77SSepherosa Ziehau 	/*
68215516c77SSepherosa Ziehau 	 * Disable RSS first.
68315516c77SSepherosa Ziehau 	 *
68415516c77SSepherosa Ziehau 	 * NOTE:
68515516c77SSepherosa Ziehau 	 * Direct reconfiguration by setting the UNCHG flags does
68615516c77SSepherosa Ziehau 	 * _not_ work properly.
68715516c77SSepherosa Ziehau 	 */
68815516c77SSepherosa Ziehau 	if (bootverbose)
68915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "disable RSS\n");
69015516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE);
69115516c77SSepherosa Ziehau 	if (error) {
69215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS disable failed\n");
69315516c77SSepherosa Ziehau 		return (error);
69415516c77SSepherosa Ziehau 	}
69515516c77SSepherosa Ziehau 
69615516c77SSepherosa Ziehau 	/*
69715516c77SSepherosa Ziehau 	 * Reenable the RSS w/ the updated RSS key or indirect
69815516c77SSepherosa Ziehau 	 * table.
69915516c77SSepherosa Ziehau 	 */
70015516c77SSepherosa Ziehau 	if (bootverbose)
70115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "reconfig RSS\n");
70215516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
70315516c77SSepherosa Ziehau 	if (error) {
70415516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS reconfig failed\n");
70515516c77SSepherosa Ziehau 		return (error);
70615516c77SSepherosa Ziehau 	}
70715516c77SSepherosa Ziehau 	return (0);
70815516c77SSepherosa Ziehau }
70915516c77SSepherosa Ziehau 
71015516c77SSepherosa Ziehau static void
71115516c77SSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc, int nchan)
71215516c77SSepherosa Ziehau {
71315516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
71415516c77SSepherosa Ziehau 	int i;
71515516c77SSepherosa Ziehau 
71615516c77SSepherosa Ziehau 	KASSERT(nchan > 1, ("invalid # of channels %d", nchan));
71715516c77SSepherosa Ziehau 
71815516c77SSepherosa Ziehau 	/*
71915516c77SSepherosa Ziehau 	 * Check indirect table to make sure that all channels in it
72015516c77SSepherosa Ziehau 	 * can be used.
72115516c77SSepherosa Ziehau 	 */
72215516c77SSepherosa Ziehau 	for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
72315516c77SSepherosa Ziehau 		if (rss->rss_ind[i] >= nchan) {
72415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp,
72515516c77SSepherosa Ziehau 			    "RSS indirect table %d fixup: %u -> %d\n",
72615516c77SSepherosa Ziehau 			    i, rss->rss_ind[i], nchan - 1);
72715516c77SSepherosa Ziehau 			rss->rss_ind[i] = nchan - 1;
72815516c77SSepherosa Ziehau 		}
72915516c77SSepherosa Ziehau 	}
73015516c77SSepherosa Ziehau }
73115516c77SSepherosa Ziehau 
73215516c77SSepherosa Ziehau static int
73315516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused)
73415516c77SSepherosa Ziehau {
73515516c77SSepherosa Ziehau 
73615516c77SSepherosa Ziehau 	return EOPNOTSUPP;
73715516c77SSepherosa Ziehau }
73815516c77SSepherosa Ziehau 
73915516c77SSepherosa Ziehau static void
74015516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
74115516c77SSepherosa Ziehau {
74215516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
74315516c77SSepherosa Ziehau 
74415516c77SSepherosa Ziehau 	ifmr->ifm_status = IFM_AVALID;
74515516c77SSepherosa Ziehau 	ifmr->ifm_active = IFM_ETHER;
74615516c77SSepherosa Ziehau 
74715516c77SSepherosa Ziehau 	if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) {
74815516c77SSepherosa Ziehau 		ifmr->ifm_active |= IFM_NONE;
74915516c77SSepherosa Ziehau 		return;
75015516c77SSepherosa Ziehau 	}
75115516c77SSepherosa Ziehau 	ifmr->ifm_status |= IFM_ACTIVE;
75215516c77SSepherosa Ziehau 	ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
75315516c77SSepherosa Ziehau }
75415516c77SSepherosa Ziehau 
75515516c77SSepherosa Ziehau /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
75615516c77SSepherosa Ziehau static const struct hyperv_guid g_net_vsc_device_type = {
75715516c77SSepherosa Ziehau 	.hv_guid = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
75815516c77SSepherosa Ziehau 		0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E}
75915516c77SSepherosa Ziehau };
76015516c77SSepherosa Ziehau 
76115516c77SSepherosa Ziehau static int
76215516c77SSepherosa Ziehau hn_probe(device_t dev)
76315516c77SSepherosa Ziehau {
76415516c77SSepherosa Ziehau 
76515516c77SSepherosa Ziehau 	if (VMBUS_PROBE_GUID(device_get_parent(dev), dev,
76615516c77SSepherosa Ziehau 	    &g_net_vsc_device_type) == 0) {
76715516c77SSepherosa Ziehau 		device_set_desc(dev, "Hyper-V Network Interface");
76815516c77SSepherosa Ziehau 		return BUS_PROBE_DEFAULT;
76915516c77SSepherosa Ziehau 	}
77015516c77SSepherosa Ziehau 	return ENXIO;
77115516c77SSepherosa Ziehau }
77215516c77SSepherosa Ziehau 
77315516c77SSepherosa Ziehau static int
77415516c77SSepherosa Ziehau hn_attach(device_t dev)
77515516c77SSepherosa Ziehau {
77615516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
77715516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
77815516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
77915516c77SSepherosa Ziehau 	uint8_t eaddr[ETHER_ADDR_LEN];
78015516c77SSepherosa Ziehau 	struct ifnet *ifp = NULL;
78115516c77SSepherosa Ziehau 	int error, ring_cnt, tx_ring_cnt;
78215516c77SSepherosa Ziehau 
78315516c77SSepherosa Ziehau 	sc->hn_dev = dev;
78415516c77SSepherosa Ziehau 	sc->hn_prichan = vmbus_get_channel(dev);
78515516c77SSepherosa Ziehau 	HN_LOCK_INIT(sc);
78615516c77SSepherosa Ziehau 
78715516c77SSepherosa Ziehau 	/*
78815516c77SSepherosa Ziehau 	 * Setup taskqueue for transmission.
78915516c77SSepherosa Ziehau 	 */
79015516c77SSepherosa Ziehau 	if (hn_tx_taskq == NULL) {
79115516c77SSepherosa Ziehau 		sc->hn_tx_taskq = taskqueue_create("hn_tx", M_WAITOK,
79215516c77SSepherosa Ziehau 		    taskqueue_thread_enqueue, &sc->hn_tx_taskq);
79315516c77SSepherosa Ziehau 		if (hn_bind_tx_taskq >= 0) {
79415516c77SSepherosa Ziehau 			int cpu = hn_bind_tx_taskq;
79515516c77SSepherosa Ziehau 			cpuset_t cpu_set;
79615516c77SSepherosa Ziehau 
79715516c77SSepherosa Ziehau 			if (cpu > mp_ncpus - 1)
79815516c77SSepherosa Ziehau 				cpu = mp_ncpus - 1;
79915516c77SSepherosa Ziehau 			CPU_SETOF(cpu, &cpu_set);
80015516c77SSepherosa Ziehau 			taskqueue_start_threads_cpuset(&sc->hn_tx_taskq, 1,
80115516c77SSepherosa Ziehau 			    PI_NET, &cpu_set, "%s tx",
80215516c77SSepherosa Ziehau 			    device_get_nameunit(dev));
80315516c77SSepherosa Ziehau 		} else {
80415516c77SSepherosa Ziehau 			taskqueue_start_threads(&sc->hn_tx_taskq, 1, PI_NET,
80515516c77SSepherosa Ziehau 			    "%s tx", device_get_nameunit(dev));
80615516c77SSepherosa Ziehau 		}
80715516c77SSepherosa Ziehau 	} else {
80815516c77SSepherosa Ziehau 		sc->hn_tx_taskq = hn_tx_taskq;
80915516c77SSepherosa Ziehau 	}
81015516c77SSepherosa Ziehau 
81115516c77SSepherosa Ziehau 	/*
81215516c77SSepherosa Ziehau 	 * Setup taskqueue for mangement tasks, e.g. link status.
81315516c77SSepherosa Ziehau 	 */
81415516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK,
81515516c77SSepherosa Ziehau 	    taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0);
81615516c77SSepherosa Ziehau 	taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
81715516c77SSepherosa Ziehau 	    device_get_nameunit(dev));
81815516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
81915516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc);
82015516c77SSepherosa Ziehau 	TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0,
82115516c77SSepherosa Ziehau 	    hn_netchg_status_taskfunc, sc);
82215516c77SSepherosa Ziehau 
82315516c77SSepherosa Ziehau 	/*
82415516c77SSepherosa Ziehau 	 * Allocate ifnet and setup its name earlier, so that if_printf
82515516c77SSepherosa Ziehau 	 * can be used by functions, which will be called after
82615516c77SSepherosa Ziehau 	 * ether_ifattach().
82715516c77SSepherosa Ziehau 	 */
82815516c77SSepherosa Ziehau 	ifp = sc->hn_ifp = if_alloc(IFT_ETHER);
82915516c77SSepherosa Ziehau 	ifp->if_softc = sc;
83015516c77SSepherosa Ziehau 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
83115516c77SSepherosa Ziehau 
83215516c77SSepherosa Ziehau 	/*
83315516c77SSepherosa Ziehau 	 * Initialize ifmedia earlier so that it can be unconditionally
83415516c77SSepherosa Ziehau 	 * destroyed, if error happened later on.
83515516c77SSepherosa Ziehau 	 */
83615516c77SSepherosa Ziehau 	ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts);
83715516c77SSepherosa Ziehau 
83815516c77SSepherosa Ziehau 	/*
83915516c77SSepherosa Ziehau 	 * Figure out the # of RX rings (ring_cnt) and the # of TX rings
84015516c77SSepherosa Ziehau 	 * to use (tx_ring_cnt).
84115516c77SSepherosa Ziehau 	 *
84215516c77SSepherosa Ziehau 	 * NOTE:
84315516c77SSepherosa Ziehau 	 * The # of RX rings to use is same as the # of channels to use.
84415516c77SSepherosa Ziehau 	 */
84515516c77SSepherosa Ziehau 	ring_cnt = hn_chan_cnt;
84615516c77SSepherosa Ziehau 	if (ring_cnt <= 0) {
84715516c77SSepherosa Ziehau 		/* Default */
84815516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
84915516c77SSepherosa Ziehau 		if (ring_cnt > HN_RING_CNT_DEF_MAX)
85015516c77SSepherosa Ziehau 			ring_cnt = HN_RING_CNT_DEF_MAX;
85115516c77SSepherosa Ziehau 	} else if (ring_cnt > mp_ncpus) {
85215516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
85315516c77SSepherosa Ziehau 	}
85415516c77SSepherosa Ziehau 
85515516c77SSepherosa Ziehau 	tx_ring_cnt = hn_tx_ring_cnt;
85615516c77SSepherosa Ziehau 	if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt)
85715516c77SSepherosa Ziehau 		tx_ring_cnt = ring_cnt;
85823bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
85915516c77SSepherosa Ziehau 	if (hn_use_if_start) {
86015516c77SSepherosa Ziehau 		/* ifnet.if_start only needs one TX ring. */
86115516c77SSepherosa Ziehau 		tx_ring_cnt = 1;
86215516c77SSepherosa Ziehau 	}
86323bf9e15SSepherosa Ziehau #endif
86415516c77SSepherosa Ziehau 
86515516c77SSepherosa Ziehau 	/*
86615516c77SSepherosa Ziehau 	 * Set the leader CPU for channels.
86715516c77SSepherosa Ziehau 	 */
86815516c77SSepherosa Ziehau 	sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus;
86915516c77SSepherosa Ziehau 
87015516c77SSepherosa Ziehau 	/*
87115516c77SSepherosa Ziehau 	 * Create enough TX/RX rings, even if only limited number of
87215516c77SSepherosa Ziehau 	 * channels can be allocated.
87315516c77SSepherosa Ziehau 	 */
87415516c77SSepherosa Ziehau 	error = hn_create_tx_data(sc, tx_ring_cnt);
87515516c77SSepherosa Ziehau 	if (error)
87615516c77SSepherosa Ziehau 		goto failed;
87715516c77SSepherosa Ziehau 	error = hn_create_rx_data(sc, ring_cnt);
87815516c77SSepherosa Ziehau 	if (error)
87915516c77SSepherosa Ziehau 		goto failed;
88015516c77SSepherosa Ziehau 
88115516c77SSepherosa Ziehau 	/*
88215516c77SSepherosa Ziehau 	 * Create transaction context for NVS and RNDIS transactions.
88315516c77SSepherosa Ziehau 	 */
88415516c77SSepherosa Ziehau 	sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
88515516c77SSepherosa Ziehau 	    HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
88615516c77SSepherosa Ziehau 	if (sc->hn_xact == NULL)
88715516c77SSepherosa Ziehau 		goto failed;
88815516c77SSepherosa Ziehau 
88915516c77SSepherosa Ziehau 	/*
89015516c77SSepherosa Ziehau 	 * Attach the synthetic parts, i.e. NVS and RNDIS.
89115516c77SSepherosa Ziehau 	 */
89215516c77SSepherosa Ziehau 	error = hn_synth_attach(sc, ETHERMTU);
89315516c77SSepherosa Ziehau 	if (error)
89415516c77SSepherosa Ziehau 		goto failed;
89515516c77SSepherosa Ziehau 
89615516c77SSepherosa Ziehau 	error = hn_rndis_get_eaddr(sc, eaddr);
89715516c77SSepherosa Ziehau 	if (error)
89815516c77SSepherosa Ziehau 		goto failed;
89915516c77SSepherosa Ziehau 
90015516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
90115516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
90215516c77SSepherosa Ziehau 		/*
90315516c77SSepherosa Ziehau 		 * Reduce TCP segment aggregation limit for multiple
90415516c77SSepherosa Ziehau 		 * RX rings to increase ACK timeliness.
90515516c77SSepherosa Ziehau 		 */
90615516c77SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF);
90715516c77SSepherosa Ziehau 	}
90815516c77SSepherosa Ziehau #endif
90915516c77SSepherosa Ziehau 
91015516c77SSepherosa Ziehau 	/*
91115516c77SSepherosa Ziehau 	 * Fixup TX stuffs after synthetic parts are attached.
91215516c77SSepherosa Ziehau 	 */
91315516c77SSepherosa Ziehau 	hn_fixup_tx_data(sc);
91415516c77SSepherosa Ziehau 
91515516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
91615516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
91715516c77SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD,
91815516c77SSepherosa Ziehau 	    &sc->hn_nvs_ver, 0, "NVS version");
91915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version",
92015516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
92115516c77SSepherosa Ziehau 	    hn_ndis_version_sysctl, "A", "NDIS version");
92215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps",
92315516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
92415516c77SSepherosa Ziehau 	    hn_caps_sysctl, "A", "capabilities");
92515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist",
92615516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
92715516c77SSepherosa Ziehau 	    hn_hwassist_sysctl, "A", "hwassist");
92815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter",
92915516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
93015516c77SSepherosa Ziehau 	    hn_rxfilter_sysctl, "A", "rxfilter");
93115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash",
93215516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
93315516c77SSepherosa Ziehau 	    hn_rss_hash_sysctl, "A", "RSS hash");
93415516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size",
93515516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count");
93615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key",
93715516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
93815516c77SSepherosa Ziehau 	    hn_rss_key_sysctl, "IU", "RSS key");
93915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind",
94015516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
94115516c77SSepherosa Ziehau 	    hn_rss_ind_sysctl, "IU", "RSS indirect table");
94215516c77SSepherosa Ziehau 
94315516c77SSepherosa Ziehau 	/*
94415516c77SSepherosa Ziehau 	 * Setup the ifmedia, which has been initialized earlier.
94515516c77SSepherosa Ziehau 	 */
94615516c77SSepherosa Ziehau 	ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL);
94715516c77SSepherosa Ziehau 	ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO);
94815516c77SSepherosa Ziehau 	/* XXX ifmedia_set really should do this for us */
94915516c77SSepherosa Ziehau 	sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media;
95015516c77SSepherosa Ziehau 
95115516c77SSepherosa Ziehau 	/*
95215516c77SSepherosa Ziehau 	 * Setup the ifnet for this interface.
95315516c77SSepherosa Ziehau 	 */
95415516c77SSepherosa Ziehau 
95515516c77SSepherosa Ziehau 	ifp->if_baudrate = IF_Gbps(10);
95615516c77SSepherosa Ziehau 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
95715516c77SSepherosa Ziehau 	ifp->if_ioctl = hn_ioctl;
95815516c77SSepherosa Ziehau 	ifp->if_init = hn_init;
95923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
96015516c77SSepherosa Ziehau 	if (hn_use_if_start) {
96115516c77SSepherosa Ziehau 		int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]);
96215516c77SSepherosa Ziehau 
96315516c77SSepherosa Ziehau 		ifp->if_start = hn_start;
96415516c77SSepherosa Ziehau 		IFQ_SET_MAXLEN(&ifp->if_snd, qdepth);
96515516c77SSepherosa Ziehau 		ifp->if_snd.ifq_drv_maxlen = qdepth - 1;
96615516c77SSepherosa Ziehau 		IFQ_SET_READY(&ifp->if_snd);
96723bf9e15SSepherosa Ziehau 	} else
96823bf9e15SSepherosa Ziehau #endif
96923bf9e15SSepherosa Ziehau 	{
97015516c77SSepherosa Ziehau 		ifp->if_transmit = hn_transmit;
97115516c77SSepherosa Ziehau 		ifp->if_qflush = hn_xmit_qflush;
97215516c77SSepherosa Ziehau 	}
97315516c77SSepherosa Ziehau 
97415516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO;
97515516c77SSepherosa Ziehau #ifdef foo
97615516c77SSepherosa Ziehau 	/* We can't diff IPv6 packets from IPv4 packets on RX path. */
97715516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM_IPV6;
97815516c77SSepherosa Ziehau #endif
97915516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_VLAN) {
98015516c77SSepherosa Ziehau 		/* XXX not sure about VLAN_MTU. */
98115516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
98215516c77SSepherosa Ziehau 	}
98315516c77SSepherosa Ziehau 
98415516c77SSepherosa Ziehau 	ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist;
98515516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP_MASK)
98615516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM;
98715516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP6_MASK)
98815516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM_IPV6;
98915516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO4) {
99015516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO4;
99115516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP_TSO;
99215516c77SSepherosa Ziehau 	}
99315516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO6) {
99415516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO6;
99515516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP6_TSO;
99615516c77SSepherosa Ziehau 	}
99715516c77SSepherosa Ziehau 
99815516c77SSepherosa Ziehau 	/* Enable all available capabilities by default. */
99915516c77SSepherosa Ziehau 	ifp->if_capenable = ifp->if_capabilities;
100015516c77SSepherosa Ziehau 
100115516c77SSepherosa Ziehau 	if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) {
100215516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU);
100315516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX;
100415516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = PAGE_SIZE;
100515516c77SSepherosa Ziehau 	}
100615516c77SSepherosa Ziehau 
100715516c77SSepherosa Ziehau 	ether_ifattach(ifp, eaddr);
100815516c77SSepherosa Ziehau 
100915516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) {
101015516c77SSepherosa Ziehau 		if_printf(ifp, "TSO segcnt %u segsz %u\n",
101115516c77SSepherosa Ziehau 		    ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize);
101215516c77SSepherosa Ziehau 	}
101315516c77SSepherosa Ziehau 
101415516c77SSepherosa Ziehau 	/* Inform the upper layer about the long frame support. */
101515516c77SSepherosa Ziehau 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
101615516c77SSepherosa Ziehau 
101715516c77SSepherosa Ziehau 	/*
101815516c77SSepherosa Ziehau 	 * Kick off link status check.
101915516c77SSepherosa Ziehau 	 */
102015516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
102115516c77SSepherosa Ziehau 	hn_update_link_status(sc);
102215516c77SSepherosa Ziehau 
102315516c77SSepherosa Ziehau 	return (0);
102415516c77SSepherosa Ziehau failed:
102515516c77SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)
102615516c77SSepherosa Ziehau 		hn_synth_detach(sc);
102715516c77SSepherosa Ziehau 	hn_detach(dev);
102815516c77SSepherosa Ziehau 	return (error);
102915516c77SSepherosa Ziehau }
103015516c77SSepherosa Ziehau 
103115516c77SSepherosa Ziehau static int
103215516c77SSepherosa Ziehau hn_detach(device_t dev)
103315516c77SSepherosa Ziehau {
103415516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
103515516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
103615516c77SSepherosa Ziehau 
103715516c77SSepherosa Ziehau 	if (device_is_attached(dev)) {
103815516c77SSepherosa Ziehau 		HN_LOCK(sc);
103915516c77SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
104015516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
104115516c77SSepherosa Ziehau 				hn_stop(sc);
104215516c77SSepherosa Ziehau 			/*
104315516c77SSepherosa Ziehau 			 * NOTE:
104415516c77SSepherosa Ziehau 			 * hn_stop() only suspends data, so managment
104515516c77SSepherosa Ziehau 			 * stuffs have to be suspended manually here.
104615516c77SSepherosa Ziehau 			 */
104715516c77SSepherosa Ziehau 			hn_suspend_mgmt(sc);
104815516c77SSepherosa Ziehau 			hn_synth_detach(sc);
104915516c77SSepherosa Ziehau 		}
105015516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
105115516c77SSepherosa Ziehau 		ether_ifdetach(ifp);
105215516c77SSepherosa Ziehau 	}
105315516c77SSepherosa Ziehau 
105415516c77SSepherosa Ziehau 	ifmedia_removeall(&sc->hn_media);
105515516c77SSepherosa Ziehau 	hn_destroy_rx_data(sc);
105615516c77SSepherosa Ziehau 	hn_destroy_tx_data(sc);
105715516c77SSepherosa Ziehau 
105815516c77SSepherosa Ziehau 	if (sc->hn_tx_taskq != hn_tx_taskq)
105915516c77SSepherosa Ziehau 		taskqueue_free(sc->hn_tx_taskq);
106015516c77SSepherosa Ziehau 	taskqueue_free(sc->hn_mgmt_taskq0);
106115516c77SSepherosa Ziehau 
106215516c77SSepherosa Ziehau 	if (sc->hn_xact != NULL)
106315516c77SSepherosa Ziehau 		vmbus_xact_ctx_destroy(sc->hn_xact);
106415516c77SSepherosa Ziehau 
106515516c77SSepherosa Ziehau 	if_free(ifp);
106615516c77SSepherosa Ziehau 
106715516c77SSepherosa Ziehau 	HN_LOCK_DESTROY(sc);
106815516c77SSepherosa Ziehau 	return (0);
106915516c77SSepherosa Ziehau }
107015516c77SSepherosa Ziehau 
107115516c77SSepherosa Ziehau static int
107215516c77SSepherosa Ziehau hn_shutdown(device_t dev)
107315516c77SSepherosa Ziehau {
107415516c77SSepherosa Ziehau 
107515516c77SSepherosa Ziehau 	return (0);
107615516c77SSepherosa Ziehau }
107715516c77SSepherosa Ziehau 
107815516c77SSepherosa Ziehau static void
107915516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc)
108015516c77SSepherosa Ziehau {
108115516c77SSepherosa Ziehau 	uint32_t link_status;
108215516c77SSepherosa Ziehau 	int error;
108315516c77SSepherosa Ziehau 
108415516c77SSepherosa Ziehau 	error = hn_rndis_get_linkstatus(sc, &link_status);
108515516c77SSepherosa Ziehau 	if (error) {
108615516c77SSepherosa Ziehau 		/* XXX what to do? */
108715516c77SSepherosa Ziehau 		return;
108815516c77SSepherosa Ziehau 	}
108915516c77SSepherosa Ziehau 
109015516c77SSepherosa Ziehau 	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
109115516c77SSepherosa Ziehau 		sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
109215516c77SSepherosa Ziehau 	else
109315516c77SSepherosa Ziehau 		sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
109415516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp,
109515516c77SSepherosa Ziehau 	    (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ?
109615516c77SSepherosa Ziehau 	    LINK_STATE_UP : LINK_STATE_DOWN);
109715516c77SSepherosa Ziehau }
109815516c77SSepherosa Ziehau 
109915516c77SSepherosa Ziehau static void
110015516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused)
110115516c77SSepherosa Ziehau {
110215516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
110315516c77SSepherosa Ziehau 
110415516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
110515516c77SSepherosa Ziehau 		return;
110615516c77SSepherosa Ziehau 	hn_link_status(sc);
110715516c77SSepherosa Ziehau }
110815516c77SSepherosa Ziehau 
110915516c77SSepherosa Ziehau static void
111015516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused)
111115516c77SSepherosa Ziehau {
111215516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
111315516c77SSepherosa Ziehau 
111415516c77SSepherosa Ziehau 	/* Prevent any link status checks from running. */
111515516c77SSepherosa Ziehau 	sc->hn_link_flags |= HN_LINK_FLAG_NETCHG;
111615516c77SSepherosa Ziehau 
111715516c77SSepherosa Ziehau 	/*
111815516c77SSepherosa Ziehau 	 * Fake up a [link down --> link up] state change; 5 seconds
111915516c77SSepherosa Ziehau 	 * delay is used, which closely simulates miibus reaction
112015516c77SSepherosa Ziehau 	 * upon link down event.
112115516c77SSepherosa Ziehau 	 */
112215516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
112315516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
112415516c77SSepherosa Ziehau 	taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0,
112515516c77SSepherosa Ziehau 	    &sc->hn_netchg_status, 5 * hz);
112615516c77SSepherosa Ziehau }
112715516c77SSepherosa Ziehau 
112815516c77SSepherosa Ziehau static void
112915516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused)
113015516c77SSepherosa Ziehau {
113115516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
113215516c77SSepherosa Ziehau 
113315516c77SSepherosa Ziehau 	/* Re-allow link status checks. */
113415516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG;
113515516c77SSepherosa Ziehau 	hn_link_status(sc);
113615516c77SSepherosa Ziehau }
113715516c77SSepherosa Ziehau 
113815516c77SSepherosa Ziehau static void
113915516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc)
114015516c77SSepherosa Ziehau {
114115516c77SSepherosa Ziehau 
114215516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
114315516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
114415516c77SSepherosa Ziehau }
114515516c77SSepherosa Ziehau 
114615516c77SSepherosa Ziehau static void
114715516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc)
114815516c77SSepherosa Ziehau {
114915516c77SSepherosa Ziehau 
115015516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
115115516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init);
115215516c77SSepherosa Ziehau }
115315516c77SSepherosa Ziehau 
115415516c77SSepherosa Ziehau static __inline int
115515516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
115615516c77SSepherosa Ziehau     struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
115715516c77SSepherosa Ziehau {
115815516c77SSepherosa Ziehau 	struct mbuf *m = *m_head;
115915516c77SSepherosa Ziehau 	int error;
116015516c77SSepherosa Ziehau 
116115516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim"));
116215516c77SSepherosa Ziehau 
116315516c77SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap,
116415516c77SSepherosa Ziehau 	    m, segs, nsegs, BUS_DMA_NOWAIT);
116515516c77SSepherosa Ziehau 	if (error == EFBIG) {
116615516c77SSepherosa Ziehau 		struct mbuf *m_new;
116715516c77SSepherosa Ziehau 
116815516c77SSepherosa Ziehau 		m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX);
116915516c77SSepherosa Ziehau 		if (m_new == NULL)
117015516c77SSepherosa Ziehau 			return ENOBUFS;
117115516c77SSepherosa Ziehau 		else
117215516c77SSepherosa Ziehau 			*m_head = m = m_new;
117315516c77SSepherosa Ziehau 		txr->hn_tx_collapsed++;
117415516c77SSepherosa Ziehau 
117515516c77SSepherosa Ziehau 		error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag,
117615516c77SSepherosa Ziehau 		    txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT);
117715516c77SSepherosa Ziehau 	}
117815516c77SSepherosa Ziehau 	if (!error) {
117915516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap,
118015516c77SSepherosa Ziehau 		    BUS_DMASYNC_PREWRITE);
118115516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_DMAMAP;
118215516c77SSepherosa Ziehau 	}
118315516c77SSepherosa Ziehau 	return error;
118415516c77SSepherosa Ziehau }
118515516c77SSepherosa Ziehau 
118615516c77SSepherosa Ziehau static __inline int
118715516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd)
118815516c77SSepherosa Ziehau {
118915516c77SSepherosa Ziehau 
119015516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0,
119115516c77SSepherosa Ziehau 	    ("put an onlist txd %#x", txd->flags));
119215516c77SSepherosa Ziehau 
119315516c77SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
119415516c77SSepherosa Ziehau 	if (atomic_fetchadd_int(&txd->refs, -1) != 1)
119515516c77SSepherosa Ziehau 		return 0;
119615516c77SSepherosa Ziehau 
119715516c77SSepherosa Ziehau 	if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) {
119815516c77SSepherosa Ziehau 		KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
119915516c77SSepherosa Ziehau 		    ("chim txd uses dmamap"));
120015516c77SSepherosa Ziehau 		hn_chim_free(txr->hn_sc, txd->chim_index);
120115516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
120215516c77SSepherosa Ziehau 	} else if (txd->flags & HN_TXD_FLAG_DMAMAP) {
120315516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag,
120415516c77SSepherosa Ziehau 		    txd->data_dmap, BUS_DMASYNC_POSTWRITE);
120515516c77SSepherosa Ziehau 		bus_dmamap_unload(txr->hn_tx_data_dtag,
120615516c77SSepherosa Ziehau 		    txd->data_dmap);
120715516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_DMAMAP;
120815516c77SSepherosa Ziehau 	}
120915516c77SSepherosa Ziehau 
121015516c77SSepherosa Ziehau 	if (txd->m != NULL) {
121115516c77SSepherosa Ziehau 		m_freem(txd->m);
121215516c77SSepherosa Ziehau 		txd->m = NULL;
121315516c77SSepherosa Ziehau 	}
121415516c77SSepherosa Ziehau 
121515516c77SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONLIST;
121615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
121715516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
121815516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_avail >= 0 &&
121915516c77SSepherosa Ziehau 	    txr->hn_txdesc_avail < txr->hn_txdesc_cnt,
122015516c77SSepherosa Ziehau 	    ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail));
122115516c77SSepherosa Ziehau 	txr->hn_txdesc_avail++;
122215516c77SSepherosa Ziehau 	SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
122315516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
122415516c77SSepherosa Ziehau #else
122515516c77SSepherosa Ziehau 	atomic_add_int(&txr->hn_txdesc_avail, 1);
122615516c77SSepherosa Ziehau 	buf_ring_enqueue(txr->hn_txdesc_br, txd);
122715516c77SSepherosa Ziehau #endif
122815516c77SSepherosa Ziehau 
122915516c77SSepherosa Ziehau 	return 1;
123015516c77SSepherosa Ziehau }
123115516c77SSepherosa Ziehau 
123215516c77SSepherosa Ziehau static __inline struct hn_txdesc *
123315516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr)
123415516c77SSepherosa Ziehau {
123515516c77SSepherosa Ziehau 	struct hn_txdesc *txd;
123615516c77SSepherosa Ziehau 
123715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
123815516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
123915516c77SSepherosa Ziehau 	txd = SLIST_FIRST(&txr->hn_txlist);
124015516c77SSepherosa Ziehau 	if (txd != NULL) {
124115516c77SSepherosa Ziehau 		KASSERT(txr->hn_txdesc_avail > 0,
124215516c77SSepherosa Ziehau 		    ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail));
124315516c77SSepherosa Ziehau 		txr->hn_txdesc_avail--;
124415516c77SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&txr->hn_txlist, link);
124515516c77SSepherosa Ziehau 	}
124615516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
124715516c77SSepherosa Ziehau #else
124815516c77SSepherosa Ziehau 	txd = buf_ring_dequeue_sc(txr->hn_txdesc_br);
124915516c77SSepherosa Ziehau #endif
125015516c77SSepherosa Ziehau 
125115516c77SSepherosa Ziehau 	if (txd != NULL) {
125215516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
125315516c77SSepherosa Ziehau 		atomic_subtract_int(&txr->hn_txdesc_avail, 1);
125415516c77SSepherosa Ziehau #endif
125515516c77SSepherosa Ziehau 		KASSERT(txd->m == NULL && txd->refs == 0 &&
125615516c77SSepherosa Ziehau 		    txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
125715516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONLIST) &&
125815516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd"));
125915516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_ONLIST;
126015516c77SSepherosa Ziehau 		txd->refs = 1;
126115516c77SSepherosa Ziehau 	}
126215516c77SSepherosa Ziehau 	return txd;
126315516c77SSepherosa Ziehau }
126415516c77SSepherosa Ziehau 
126515516c77SSepherosa Ziehau static __inline void
126615516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd)
126715516c77SSepherosa Ziehau {
126815516c77SSepherosa Ziehau 
126915516c77SSepherosa Ziehau 	/* 0->1 transition will never work */
127015516c77SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid refs %d", txd->refs));
127115516c77SSepherosa Ziehau 	atomic_add_int(&txd->refs, 1);
127215516c77SSepherosa Ziehau }
127315516c77SSepherosa Ziehau 
127415516c77SSepherosa Ziehau static bool
127515516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr)
127615516c77SSepherosa Ziehau {
127715516c77SSepherosa Ziehau 	bool pending = false;
127815516c77SSepherosa Ziehau 
127915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
128015516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
128115516c77SSepherosa Ziehau 	if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt)
128215516c77SSepherosa Ziehau 		pending = true;
128315516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
128415516c77SSepherosa Ziehau #else
128515516c77SSepherosa Ziehau 	if (!buf_ring_full(txr->hn_txdesc_br))
128615516c77SSepherosa Ziehau 		pending = true;
128715516c77SSepherosa Ziehau #endif
128815516c77SSepherosa Ziehau 	return (pending);
128915516c77SSepherosa Ziehau }
129015516c77SSepherosa Ziehau 
129115516c77SSepherosa Ziehau static __inline void
129215516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr)
129315516c77SSepherosa Ziehau {
129415516c77SSepherosa Ziehau 	txr->hn_has_txeof = 0;
129515516c77SSepherosa Ziehau 	txr->hn_txeof(txr);
129615516c77SSepherosa Ziehau }
129715516c77SSepherosa Ziehau 
129815516c77SSepherosa Ziehau static void
129915516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc,
130015516c77SSepherosa Ziehau     struct vmbus_channel *chan, const void *data __unused, int dlen __unused)
130115516c77SSepherosa Ziehau {
130215516c77SSepherosa Ziehau 	struct hn_txdesc *txd = sndc->hn_cbarg;
130315516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
130415516c77SSepherosa Ziehau 
130515516c77SSepherosa Ziehau 	txr = txd->txr;
130615516c77SSepherosa Ziehau 	KASSERT(txr->hn_chan == chan,
130715516c77SSepherosa Ziehau 	    ("channel mismatch, on chan%u, should be chan%u",
130815516c77SSepherosa Ziehau 	     vmbus_chan_subidx(chan), vmbus_chan_subidx(txr->hn_chan)));
130915516c77SSepherosa Ziehau 
131015516c77SSepherosa Ziehau 	txr->hn_has_txeof = 1;
131115516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
131215516c77SSepherosa Ziehau 
131315516c77SSepherosa Ziehau 	++txr->hn_txdone_cnt;
131415516c77SSepherosa Ziehau 	if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) {
131515516c77SSepherosa Ziehau 		txr->hn_txdone_cnt = 0;
131615516c77SSepherosa Ziehau 		if (txr->hn_oactive)
131715516c77SSepherosa Ziehau 			hn_txeof(txr);
131815516c77SSepherosa Ziehau 	}
131915516c77SSepherosa Ziehau }
132015516c77SSepherosa Ziehau 
132115516c77SSepherosa Ziehau static void
132215516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
132315516c77SSepherosa Ziehau {
132415516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
132515516c77SSepherosa Ziehau 	tcp_lro_flush_all(&rxr->hn_lro);
132615516c77SSepherosa Ziehau #endif
132715516c77SSepherosa Ziehau 
132815516c77SSepherosa Ziehau 	/*
132915516c77SSepherosa Ziehau 	 * NOTE:
133015516c77SSepherosa Ziehau 	 * 'txr' could be NULL, if multiple channels and
133115516c77SSepherosa Ziehau 	 * ifnet.if_start method are enabled.
133215516c77SSepherosa Ziehau 	 */
133315516c77SSepherosa Ziehau 	if (txr == NULL || !txr->hn_has_txeof)
133415516c77SSepherosa Ziehau 		return;
133515516c77SSepherosa Ziehau 
133615516c77SSepherosa Ziehau 	txr->hn_txdone_cnt = 0;
133715516c77SSepherosa Ziehau 	hn_txeof(txr);
133815516c77SSepherosa Ziehau }
133915516c77SSepherosa Ziehau 
134015516c77SSepherosa Ziehau static __inline uint32_t
134115516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs)
134215516c77SSepherosa Ziehau {
134315516c77SSepherosa Ziehau 
134415516c77SSepherosa Ziehau 	KASSERT(ofs >= sizeof(struct rndis_packet_msg),
134515516c77SSepherosa Ziehau 	    ("invalid RNDIS packet msg offset %u", ofs));
134615516c77SSepherosa Ziehau 	return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset));
134715516c77SSepherosa Ziehau }
134815516c77SSepherosa Ziehau 
134915516c77SSepherosa Ziehau static __inline void *
135015516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
135115516c77SSepherosa Ziehau     size_t pi_dlen, uint32_t pi_type)
135215516c77SSepherosa Ziehau {
135315516c77SSepherosa Ziehau 	const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
135415516c77SSepherosa Ziehau 	struct rndis_pktinfo *pi;
135515516c77SSepherosa Ziehau 
135615516c77SSepherosa Ziehau 	KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
135715516c77SSepherosa Ziehau 	    ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
135815516c77SSepherosa Ziehau 
135915516c77SSepherosa Ziehau 	/*
136015516c77SSepherosa Ziehau 	 * Per-packet-info does not move; it only grows.
136115516c77SSepherosa Ziehau 	 *
136215516c77SSepherosa Ziehau 	 * NOTE:
136315516c77SSepherosa Ziehau 	 * rm_pktinfooffset in this phase counts from the beginning
136415516c77SSepherosa Ziehau 	 * of rndis_packet_msg.
136515516c77SSepherosa Ziehau 	 */
136615516c77SSepherosa Ziehau 	KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
136715516c77SSepherosa Ziehau 	    ("%u pktinfo overflows RNDIS packet msg", pi_type));
136815516c77SSepherosa Ziehau 	pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
136915516c77SSepherosa Ziehau 	    pkt->rm_pktinfolen);
137015516c77SSepherosa Ziehau 	pkt->rm_pktinfolen += pi_size;
137115516c77SSepherosa Ziehau 
137215516c77SSepherosa Ziehau 	pi->rm_size = pi_size;
137315516c77SSepherosa Ziehau 	pi->rm_type = pi_type;
137415516c77SSepherosa Ziehau 	pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
137515516c77SSepherosa Ziehau 
137615516c77SSepherosa Ziehau 	/* Data immediately follow per-packet-info. */
137715516c77SSepherosa Ziehau 	pkt->rm_dataoffset += pi_size;
137815516c77SSepherosa Ziehau 
137915516c77SSepherosa Ziehau 	/* Update RNDIS packet msg length */
138015516c77SSepherosa Ziehau 	pkt->rm_len += pi_size;
138115516c77SSepherosa Ziehau 
138215516c77SSepherosa Ziehau 	return (pi->rm_data);
138315516c77SSepherosa Ziehau }
138415516c77SSepherosa Ziehau 
138515516c77SSepherosa Ziehau /*
138615516c77SSepherosa Ziehau  * NOTE:
138715516c77SSepherosa Ziehau  * If this function fails, then both txd and m_head0 will be freed.
138815516c77SSepherosa Ziehau  */
138915516c77SSepherosa Ziehau static int
139015516c77SSepherosa Ziehau hn_encap(struct hn_tx_ring *txr, struct hn_txdesc *txd, struct mbuf **m_head0)
139115516c77SSepherosa Ziehau {
139215516c77SSepherosa Ziehau 	bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX];
139315516c77SSepherosa Ziehau 	int error, nsegs, i;
139415516c77SSepherosa Ziehau 	struct mbuf *m_head = *m_head0;
139515516c77SSepherosa Ziehau 	struct rndis_packet_msg *pkt;
139615516c77SSepherosa Ziehau 	uint32_t *pi_data;
139715516c77SSepherosa Ziehau 	int pktlen;
139815516c77SSepherosa Ziehau 
139915516c77SSepherosa Ziehau 	/*
140015516c77SSepherosa Ziehau 	 * extension points to the area reserved for the
140115516c77SSepherosa Ziehau 	 * rndis_filter_packet, which is placed just after
140215516c77SSepherosa Ziehau 	 * the netvsc_packet (and rppi struct, if present;
140315516c77SSepherosa Ziehau 	 * length is updated later).
140415516c77SSepherosa Ziehau 	 */
140515516c77SSepherosa Ziehau 	pkt = txd->rndis_pkt;
140615516c77SSepherosa Ziehau 	pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
140715516c77SSepherosa Ziehau 	pkt->rm_len = sizeof(*pkt) + m_head->m_pkthdr.len;
140815516c77SSepherosa Ziehau 	pkt->rm_dataoffset = sizeof(*pkt);
140915516c77SSepherosa Ziehau 	pkt->rm_datalen = m_head->m_pkthdr.len;
141015516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = sizeof(*pkt);
141115516c77SSepherosa Ziehau 	pkt->rm_pktinfolen = 0;
141215516c77SSepherosa Ziehau 
141315516c77SSepherosa Ziehau 	if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) {
141415516c77SSepherosa Ziehau 		/*
141515516c77SSepherosa Ziehau 		 * Set the hash value for this packet, so that the host could
141615516c77SSepherosa Ziehau 		 * dispatch the TX done event for this packet back to this TX
141715516c77SSepherosa Ziehau 		 * ring's channel.
141815516c77SSepherosa Ziehau 		 */
141915516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
142015516c77SSepherosa Ziehau 		    HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL);
142115516c77SSepherosa Ziehau 		*pi_data = txr->hn_tx_idx;
142215516c77SSepherosa Ziehau 	}
142315516c77SSepherosa Ziehau 
142415516c77SSepherosa Ziehau 	if (m_head->m_flags & M_VLANTAG) {
142515516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
142615516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
142715516c77SSepherosa Ziehau 		*pi_data = NDIS_VLAN_INFO_MAKE(
142815516c77SSepherosa Ziehau 		    EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag),
142915516c77SSepherosa Ziehau 		    EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag),
143015516c77SSepherosa Ziehau 		    EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag));
143115516c77SSepherosa Ziehau 	}
143215516c77SSepherosa Ziehau 
143315516c77SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
143415516c77SSepherosa Ziehau #if defined(INET6) || defined(INET)
143515516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
143615516c77SSepherosa Ziehau 		    NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO);
143715516c77SSepherosa Ziehau #ifdef INET
143815516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
143915516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV4(0,
144015516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
144115516c77SSepherosa Ziehau 		}
144215516c77SSepherosa Ziehau #endif
144315516c77SSepherosa Ziehau #if defined(INET6) && defined(INET)
144415516c77SSepherosa Ziehau 		else
144515516c77SSepherosa Ziehau #endif
144615516c77SSepherosa Ziehau #ifdef INET6
144715516c77SSepherosa Ziehau 		{
144815516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV6(0,
144915516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
145015516c77SSepherosa Ziehau 		}
145115516c77SSepherosa Ziehau #endif
145215516c77SSepherosa Ziehau #endif	/* INET6 || INET */
145315516c77SSepherosa Ziehau 	} else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) {
145415516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
145515516c77SSepherosa Ziehau 		    NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
145615516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
145715516c77SSepherosa Ziehau 		    (CSUM_IP6_TCP | CSUM_IP6_UDP)) {
145815516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV6;
145915516c77SSepherosa Ziehau 		} else {
146015516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV4;
146115516c77SSepherosa Ziehau 			if (m_head->m_pkthdr.csum_flags & CSUM_IP)
146215516c77SSepherosa Ziehau 				*pi_data |= NDIS_TXCSUM_INFO_IPCS;
146315516c77SSepherosa Ziehau 		}
146415516c77SSepherosa Ziehau 
146515516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP))
146615516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_TCPCS;
146715516c77SSepherosa Ziehau 		else if (m_head->m_pkthdr.csum_flags &
146815516c77SSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP6_UDP))
146915516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_UDPCS;
147015516c77SSepherosa Ziehau 	}
147115516c77SSepherosa Ziehau 
147215516c77SSepherosa Ziehau 	pktlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
147315516c77SSepherosa Ziehau 	/* Convert RNDIS packet message offsets */
147415516c77SSepherosa Ziehau 	pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt->rm_dataoffset);
147515516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset);
147615516c77SSepherosa Ziehau 
147715516c77SSepherosa Ziehau 	/*
147815516c77SSepherosa Ziehau 	 * Chimney send, if the packet could fit into one chimney buffer.
147915516c77SSepherosa Ziehau 	 */
148015516c77SSepherosa Ziehau 	if (pkt->rm_len < txr->hn_chim_size) {
148115516c77SSepherosa Ziehau 		txr->hn_tx_chimney_tried++;
148215516c77SSepherosa Ziehau 		txd->chim_index = hn_chim_alloc(txr->hn_sc);
148315516c77SSepherosa Ziehau 		if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) {
148415516c77SSepherosa Ziehau 			uint8_t *dest = txr->hn_sc->hn_chim +
148515516c77SSepherosa Ziehau 			    (txd->chim_index * txr->hn_sc->hn_chim_szmax);
148615516c77SSepherosa Ziehau 
148715516c77SSepherosa Ziehau 			memcpy(dest, pkt, pktlen);
148815516c77SSepherosa Ziehau 			dest += pktlen;
148915516c77SSepherosa Ziehau 			m_copydata(m_head, 0, m_head->m_pkthdr.len, dest);
149015516c77SSepherosa Ziehau 
149115516c77SSepherosa Ziehau 			txd->chim_size = pkt->rm_len;
149215516c77SSepherosa Ziehau 			txr->hn_gpa_cnt = 0;
149315516c77SSepherosa Ziehau 			txr->hn_tx_chimney++;
149415516c77SSepherosa Ziehau 			txr->hn_sendpkt = hn_txpkt_chim;
149515516c77SSepherosa Ziehau 			goto done;
149615516c77SSepherosa Ziehau 		}
149715516c77SSepherosa Ziehau 	}
149815516c77SSepherosa Ziehau 
149915516c77SSepherosa Ziehau 	error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs);
150015516c77SSepherosa Ziehau 	if (error) {
150115516c77SSepherosa Ziehau 		int freed;
150215516c77SSepherosa Ziehau 
150315516c77SSepherosa Ziehau 		/*
150415516c77SSepherosa Ziehau 		 * This mbuf is not linked w/ the txd yet, so free it now.
150515516c77SSepherosa Ziehau 		 */
150615516c77SSepherosa Ziehau 		m_freem(m_head);
150715516c77SSepherosa Ziehau 		*m_head0 = NULL;
150815516c77SSepherosa Ziehau 
150915516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
151015516c77SSepherosa Ziehau 		KASSERT(freed != 0,
151115516c77SSepherosa Ziehau 		    ("fail to free txd upon txdma error"));
151215516c77SSepherosa Ziehau 
151315516c77SSepherosa Ziehau 		txr->hn_txdma_failed++;
151415516c77SSepherosa Ziehau 		if_inc_counter(txr->hn_sc->hn_ifp, IFCOUNTER_OERRORS, 1);
151515516c77SSepherosa Ziehau 		return error;
151615516c77SSepherosa Ziehau 	}
151715516c77SSepherosa Ziehau 	*m_head0 = m_head;
151815516c77SSepherosa Ziehau 
151915516c77SSepherosa Ziehau 	/* +1 RNDIS packet message */
152015516c77SSepherosa Ziehau 	txr->hn_gpa_cnt = nsegs + 1;
152115516c77SSepherosa Ziehau 
152215516c77SSepherosa Ziehau 	/* send packet with page buffer */
152315516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr);
152415516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK;
152515516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_len = pktlen;
152615516c77SSepherosa Ziehau 
152715516c77SSepherosa Ziehau 	/*
152815516c77SSepherosa Ziehau 	 * Fill the page buffers with mbuf info after the page
152915516c77SSepherosa Ziehau 	 * buffer for RNDIS packet message.
153015516c77SSepherosa Ziehau 	 */
153115516c77SSepherosa Ziehau 	for (i = 0; i < nsegs; ++i) {
153215516c77SSepherosa Ziehau 		struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1];
153315516c77SSepherosa Ziehau 
153415516c77SSepherosa Ziehau 		gpa->gpa_page = atop(segs[i].ds_addr);
153515516c77SSepherosa Ziehau 		gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK;
153615516c77SSepherosa Ziehau 		gpa->gpa_len = segs[i].ds_len;
153715516c77SSepherosa Ziehau 	}
153815516c77SSepherosa Ziehau 
153915516c77SSepherosa Ziehau 	txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
154015516c77SSepherosa Ziehau 	txd->chim_size = 0;
154115516c77SSepherosa Ziehau 	txr->hn_sendpkt = hn_txpkt_sglist;
154215516c77SSepherosa Ziehau done:
154315516c77SSepherosa Ziehau 	txd->m = m_head;
154415516c77SSepherosa Ziehau 
154515516c77SSepherosa Ziehau 	/* Set the completion routine */
154615516c77SSepherosa Ziehau 	hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd);
154715516c77SSepherosa Ziehau 
154815516c77SSepherosa Ziehau 	return 0;
154915516c77SSepherosa Ziehau }
155015516c77SSepherosa Ziehau 
155115516c77SSepherosa Ziehau /*
155215516c77SSepherosa Ziehau  * NOTE:
155315516c77SSepherosa Ziehau  * If this function fails, then txd will be freed, but the mbuf
155415516c77SSepherosa Ziehau  * associated w/ the txd will _not_ be freed.
155515516c77SSepherosa Ziehau  */
155615516c77SSepherosa Ziehau static int
155715516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd)
155815516c77SSepherosa Ziehau {
155915516c77SSepherosa Ziehau 	int error, send_failed = 0;
156015516c77SSepherosa Ziehau 
156115516c77SSepherosa Ziehau again:
156215516c77SSepherosa Ziehau 	/*
156315516c77SSepherosa Ziehau 	 * Make sure that txd is not freed before ETHER_BPF_MTAP.
156415516c77SSepherosa Ziehau 	 */
156515516c77SSepherosa Ziehau 	hn_txdesc_hold(txd);
156615516c77SSepherosa Ziehau 	error = txr->hn_sendpkt(txr, txd);
156715516c77SSepherosa Ziehau 	if (!error) {
156815516c77SSepherosa Ziehau 		ETHER_BPF_MTAP(ifp, txd->m);
156915516c77SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
157023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
157123bf9e15SSepherosa Ziehau 		if (!hn_use_if_start)
157223bf9e15SSepherosa Ziehau #endif
157323bf9e15SSepherosa Ziehau 		{
157415516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OBYTES,
157515516c77SSepherosa Ziehau 			    txd->m->m_pkthdr.len);
157615516c77SSepherosa Ziehau 			if (txd->m->m_flags & M_MCAST)
157715516c77SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
157815516c77SSepherosa Ziehau 		}
157915516c77SSepherosa Ziehau 		txr->hn_pkts++;
158015516c77SSepherosa Ziehau 	}
158115516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
158215516c77SSepherosa Ziehau 
158315516c77SSepherosa Ziehau 	if (__predict_false(error)) {
158415516c77SSepherosa Ziehau 		int freed;
158515516c77SSepherosa Ziehau 
158615516c77SSepherosa Ziehau 		/*
158715516c77SSepherosa Ziehau 		 * This should "really rarely" happen.
158815516c77SSepherosa Ziehau 		 *
158915516c77SSepherosa Ziehau 		 * XXX Too many RX to be acked or too many sideband
159015516c77SSepherosa Ziehau 		 * commands to run?  Ask netvsc_channel_rollup()
159115516c77SSepherosa Ziehau 		 * to kick start later.
159215516c77SSepherosa Ziehau 		 */
159315516c77SSepherosa Ziehau 		txr->hn_has_txeof = 1;
159415516c77SSepherosa Ziehau 		if (!send_failed) {
159515516c77SSepherosa Ziehau 			txr->hn_send_failed++;
159615516c77SSepherosa Ziehau 			send_failed = 1;
159715516c77SSepherosa Ziehau 			/*
159815516c77SSepherosa Ziehau 			 * Try sending again after set hn_has_txeof;
159915516c77SSepherosa Ziehau 			 * in case that we missed the last
160015516c77SSepherosa Ziehau 			 * netvsc_channel_rollup().
160115516c77SSepherosa Ziehau 			 */
160215516c77SSepherosa Ziehau 			goto again;
160315516c77SSepherosa Ziehau 		}
160415516c77SSepherosa Ziehau 		if_printf(ifp, "send failed\n");
160515516c77SSepherosa Ziehau 
160615516c77SSepherosa Ziehau 		/*
160715516c77SSepherosa Ziehau 		 * Caller will perform further processing on the
160815516c77SSepherosa Ziehau 		 * associated mbuf, so don't free it in hn_txdesc_put();
160915516c77SSepherosa Ziehau 		 * only unload it from the DMA map in hn_txdesc_put(),
161015516c77SSepherosa Ziehau 		 * if it was loaded.
161115516c77SSepherosa Ziehau 		 */
161215516c77SSepherosa Ziehau 		txd->m = NULL;
161315516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
161415516c77SSepherosa Ziehau 		KASSERT(freed != 0,
161515516c77SSepherosa Ziehau 		    ("fail to free txd upon send error"));
161615516c77SSepherosa Ziehau 
161715516c77SSepherosa Ziehau 		txr->hn_send_failed++;
161815516c77SSepherosa Ziehau 	}
161915516c77SSepherosa Ziehau 	return error;
162015516c77SSepherosa Ziehau }
162115516c77SSepherosa Ziehau 
162215516c77SSepherosa Ziehau /*
162315516c77SSepherosa Ziehau  * Append the specified data to the indicated mbuf chain,
162415516c77SSepherosa Ziehau  * Extend the mbuf chain if the new data does not fit in
162515516c77SSepherosa Ziehau  * existing space.
162615516c77SSepherosa Ziehau  *
162715516c77SSepherosa Ziehau  * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c.
162815516c77SSepherosa Ziehau  * There should be an equivalent in the kernel mbuf code,
162915516c77SSepherosa Ziehau  * but there does not appear to be one yet.
163015516c77SSepherosa Ziehau  *
163115516c77SSepherosa Ziehau  * Differs from m_append() in that additional mbufs are
163215516c77SSepherosa Ziehau  * allocated with cluster size MJUMPAGESIZE, and filled
163315516c77SSepherosa Ziehau  * accordingly.
163415516c77SSepherosa Ziehau  *
163515516c77SSepherosa Ziehau  * Return 1 if able to complete the job; otherwise 0.
163615516c77SSepherosa Ziehau  */
163715516c77SSepherosa Ziehau static int
163815516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp)
163915516c77SSepherosa Ziehau {
164015516c77SSepherosa Ziehau 	struct mbuf *m, *n;
164115516c77SSepherosa Ziehau 	int remainder, space;
164215516c77SSepherosa Ziehau 
164315516c77SSepherosa Ziehau 	for (m = m0; m->m_next != NULL; m = m->m_next)
164415516c77SSepherosa Ziehau 		;
164515516c77SSepherosa Ziehau 	remainder = len;
164615516c77SSepherosa Ziehau 	space = M_TRAILINGSPACE(m);
164715516c77SSepherosa Ziehau 	if (space > 0) {
164815516c77SSepherosa Ziehau 		/*
164915516c77SSepherosa Ziehau 		 * Copy into available space.
165015516c77SSepherosa Ziehau 		 */
165115516c77SSepherosa Ziehau 		if (space > remainder)
165215516c77SSepherosa Ziehau 			space = remainder;
165315516c77SSepherosa Ziehau 		bcopy(cp, mtod(m, caddr_t) + m->m_len, space);
165415516c77SSepherosa Ziehau 		m->m_len += space;
165515516c77SSepherosa Ziehau 		cp += space;
165615516c77SSepherosa Ziehau 		remainder -= space;
165715516c77SSepherosa Ziehau 	}
165815516c77SSepherosa Ziehau 	while (remainder > 0) {
165915516c77SSepherosa Ziehau 		/*
166015516c77SSepherosa Ziehau 		 * Allocate a new mbuf; could check space
166115516c77SSepherosa Ziehau 		 * and allocate a cluster instead.
166215516c77SSepherosa Ziehau 		 */
166315516c77SSepherosa Ziehau 		n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE);
166415516c77SSepherosa Ziehau 		if (n == NULL)
166515516c77SSepherosa Ziehau 			break;
166615516c77SSepherosa Ziehau 		n->m_len = min(MJUMPAGESIZE, remainder);
166715516c77SSepherosa Ziehau 		bcopy(cp, mtod(n, caddr_t), n->m_len);
166815516c77SSepherosa Ziehau 		cp += n->m_len;
166915516c77SSepherosa Ziehau 		remainder -= n->m_len;
167015516c77SSepherosa Ziehau 		m->m_next = n;
167115516c77SSepherosa Ziehau 		m = n;
167215516c77SSepherosa Ziehau 	}
167315516c77SSepherosa Ziehau 	if (m0->m_flags & M_PKTHDR)
167415516c77SSepherosa Ziehau 		m0->m_pkthdr.len += len - remainder;
167515516c77SSepherosa Ziehau 
167615516c77SSepherosa Ziehau 	return (remainder == 0);
167715516c77SSepherosa Ziehau }
167815516c77SSepherosa Ziehau 
167915516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
168015516c77SSepherosa Ziehau static __inline int
168115516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m)
168215516c77SSepherosa Ziehau {
168315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
168415516c77SSepherosa Ziehau 	if (hn_lro_mbufq_depth) {
168515516c77SSepherosa Ziehau 		tcp_lro_queue_mbuf(lc, m);
168615516c77SSepherosa Ziehau 		return 0;
168715516c77SSepherosa Ziehau 	}
168815516c77SSepherosa Ziehau #endif
168915516c77SSepherosa Ziehau 	return tcp_lro_rx(lc, m, 0);
169015516c77SSepherosa Ziehau }
169115516c77SSepherosa Ziehau #endif
169215516c77SSepherosa Ziehau 
169315516c77SSepherosa Ziehau static int
169415516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
169515516c77SSepherosa Ziehau     const struct hn_rxinfo *info)
169615516c77SSepherosa Ziehau {
169715516c77SSepherosa Ziehau 	struct ifnet *ifp = rxr->hn_ifp;
169815516c77SSepherosa Ziehau 	struct mbuf *m_new;
169915516c77SSepherosa Ziehau 	int size, do_lro = 0, do_csum = 1;
170015516c77SSepherosa Ziehau 	int hash_type;
170115516c77SSepherosa Ziehau 
170215516c77SSepherosa Ziehau 	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
170315516c77SSepherosa Ziehau 		return (0);
170415516c77SSepherosa Ziehau 
170515516c77SSepherosa Ziehau 	/*
170615516c77SSepherosa Ziehau 	 * Bail out if packet contains more data than configured MTU.
170715516c77SSepherosa Ziehau 	 */
170815516c77SSepherosa Ziehau 	if (dlen > (ifp->if_mtu + ETHER_HDR_LEN)) {
170915516c77SSepherosa Ziehau 		return (0);
171015516c77SSepherosa Ziehau 	} else if (dlen <= MHLEN) {
171115516c77SSepherosa Ziehau 		m_new = m_gethdr(M_NOWAIT, MT_DATA);
171215516c77SSepherosa Ziehau 		if (m_new == NULL) {
171315516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
171415516c77SSepherosa Ziehau 			return (0);
171515516c77SSepherosa Ziehau 		}
171615516c77SSepherosa Ziehau 		memcpy(mtod(m_new, void *), data, dlen);
171715516c77SSepherosa Ziehau 		m_new->m_pkthdr.len = m_new->m_len = dlen;
171815516c77SSepherosa Ziehau 		rxr->hn_small_pkts++;
171915516c77SSepherosa Ziehau 	} else {
172015516c77SSepherosa Ziehau 		/*
172115516c77SSepherosa Ziehau 		 * Get an mbuf with a cluster.  For packets 2K or less,
172215516c77SSepherosa Ziehau 		 * get a standard 2K cluster.  For anything larger, get a
172315516c77SSepherosa Ziehau 		 * 4K cluster.  Any buffers larger than 4K can cause problems
172415516c77SSepherosa Ziehau 		 * if looped around to the Hyper-V TX channel, so avoid them.
172515516c77SSepherosa Ziehau 		 */
172615516c77SSepherosa Ziehau 		size = MCLBYTES;
172715516c77SSepherosa Ziehau 		if (dlen > MCLBYTES) {
172815516c77SSepherosa Ziehau 			/* 4096 */
172915516c77SSepherosa Ziehau 			size = MJUMPAGESIZE;
173015516c77SSepherosa Ziehau 		}
173115516c77SSepherosa Ziehau 
173215516c77SSepherosa Ziehau 		m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size);
173315516c77SSepherosa Ziehau 		if (m_new == NULL) {
173415516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
173515516c77SSepherosa Ziehau 			return (0);
173615516c77SSepherosa Ziehau 		}
173715516c77SSepherosa Ziehau 
173815516c77SSepherosa Ziehau 		hv_m_append(m_new, dlen, data);
173915516c77SSepherosa Ziehau 	}
174015516c77SSepherosa Ziehau 	m_new->m_pkthdr.rcvif = ifp;
174115516c77SSepherosa Ziehau 
174215516c77SSepherosa Ziehau 	if (__predict_false((ifp->if_capenable & IFCAP_RXCSUM) == 0))
174315516c77SSepherosa Ziehau 		do_csum = 0;
174415516c77SSepherosa Ziehau 
174515516c77SSepherosa Ziehau 	/* receive side checksum offload */
174615516c77SSepherosa Ziehau 	if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) {
174715516c77SSepherosa Ziehau 		/* IP csum offload */
174815516c77SSepherosa Ziehau 		if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) {
174915516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
175015516c77SSepherosa Ziehau 			    (CSUM_IP_CHECKED | CSUM_IP_VALID);
175115516c77SSepherosa Ziehau 			rxr->hn_csum_ip++;
175215516c77SSepherosa Ziehau 		}
175315516c77SSepherosa Ziehau 
175415516c77SSepherosa Ziehau 		/* TCP/UDP csum offload */
175515516c77SSepherosa Ziehau 		if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK |
175615516c77SSepherosa Ziehau 		     NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) {
175715516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
175815516c77SSepherosa Ziehau 			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
175915516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_data = 0xffff;
176015516c77SSepherosa Ziehau 			if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK)
176115516c77SSepherosa Ziehau 				rxr->hn_csum_tcp++;
176215516c77SSepherosa Ziehau 			else
176315516c77SSepherosa Ziehau 				rxr->hn_csum_udp++;
176415516c77SSepherosa Ziehau 		}
176515516c77SSepherosa Ziehau 
176615516c77SSepherosa Ziehau 		/*
176715516c77SSepherosa Ziehau 		 * XXX
176815516c77SSepherosa Ziehau 		 * As of this write (Oct 28th, 2016), host side will turn
176915516c77SSepherosa Ziehau 		 * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so
177015516c77SSepherosa Ziehau 		 * the do_lro setting here is actually _not_ accurate.  We
177115516c77SSepherosa Ziehau 		 * depend on the RSS hash type check to reset do_lro.
177215516c77SSepherosa Ziehau 		 */
177315516c77SSepherosa Ziehau 		if ((info->csum_info &
177415516c77SSepherosa Ziehau 		     (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) ==
177515516c77SSepherosa Ziehau 		    (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK))
177615516c77SSepherosa Ziehau 			do_lro = 1;
177715516c77SSepherosa Ziehau 	} else {
177815516c77SSepherosa Ziehau 		const struct ether_header *eh;
177915516c77SSepherosa Ziehau 		uint16_t etype;
178015516c77SSepherosa Ziehau 		int hoff;
178115516c77SSepherosa Ziehau 
178215516c77SSepherosa Ziehau 		hoff = sizeof(*eh);
178315516c77SSepherosa Ziehau 		if (m_new->m_len < hoff)
178415516c77SSepherosa Ziehau 			goto skip;
178515516c77SSepherosa Ziehau 		eh = mtod(m_new, struct ether_header *);
178615516c77SSepherosa Ziehau 		etype = ntohs(eh->ether_type);
178715516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_VLAN) {
178815516c77SSepherosa Ziehau 			const struct ether_vlan_header *evl;
178915516c77SSepherosa Ziehau 
179015516c77SSepherosa Ziehau 			hoff = sizeof(*evl);
179115516c77SSepherosa Ziehau 			if (m_new->m_len < hoff)
179215516c77SSepherosa Ziehau 				goto skip;
179315516c77SSepherosa Ziehau 			evl = mtod(m_new, struct ether_vlan_header *);
179415516c77SSepherosa Ziehau 			etype = ntohs(evl->evl_proto);
179515516c77SSepherosa Ziehau 		}
179615516c77SSepherosa Ziehau 
179715516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_IP) {
179815516c77SSepherosa Ziehau 			int pr;
179915516c77SSepherosa Ziehau 
180015516c77SSepherosa Ziehau 			pr = hn_check_iplen(m_new, hoff);
180115516c77SSepherosa Ziehau 			if (pr == IPPROTO_TCP) {
180215516c77SSepherosa Ziehau 				if (do_csum &&
180315516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
180415516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_TCP)) {
180515516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
180615516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
180715516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
180815516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
180915516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
181015516c77SSepherosa Ziehau 				}
181115516c77SSepherosa Ziehau 				do_lro = 1;
181215516c77SSepherosa Ziehau 			} else if (pr == IPPROTO_UDP) {
181315516c77SSepherosa Ziehau 				if (do_csum &&
181415516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
181515516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_UDP)) {
181615516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
181715516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
181815516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
181915516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
182015516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
182115516c77SSepherosa Ziehau 				}
182215516c77SSepherosa Ziehau 			} else if (pr != IPPROTO_DONE && do_csum &&
182315516c77SSepherosa Ziehau 			    (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) {
182415516c77SSepherosa Ziehau 				rxr->hn_csum_trusted++;
182515516c77SSepherosa Ziehau 				m_new->m_pkthdr.csum_flags |=
182615516c77SSepherosa Ziehau 				    (CSUM_IP_CHECKED | CSUM_IP_VALID);
182715516c77SSepherosa Ziehau 			}
182815516c77SSepherosa Ziehau 		}
182915516c77SSepherosa Ziehau 	}
183015516c77SSepherosa Ziehau skip:
183115516c77SSepherosa Ziehau 	if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) {
183215516c77SSepherosa Ziehau 		m_new->m_pkthdr.ether_vtag = EVL_MAKETAG(
183315516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_ID(info->vlan_info),
183415516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_PRI(info->vlan_info),
183515516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_CFI(info->vlan_info));
183615516c77SSepherosa Ziehau 		m_new->m_flags |= M_VLANTAG;
183715516c77SSepherosa Ziehau 	}
183815516c77SSepherosa Ziehau 
183915516c77SSepherosa Ziehau 	if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) {
184015516c77SSepherosa Ziehau 		rxr->hn_rss_pkts++;
184115516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = info->hash_value;
184215516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE_HASH;
184315516c77SSepherosa Ziehau 		if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) ==
184415516c77SSepherosa Ziehau 		    NDIS_HASH_FUNCTION_TOEPLITZ) {
184515516c77SSepherosa Ziehau 			uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK);
184615516c77SSepherosa Ziehau 
184715516c77SSepherosa Ziehau 			/*
184815516c77SSepherosa Ziehau 			 * NOTE:
184915516c77SSepherosa Ziehau 			 * do_lro is resetted, if the hash types are not TCP
185015516c77SSepherosa Ziehau 			 * related.  See the comment in the above csum_flags
185115516c77SSepherosa Ziehau 			 * setup section.
185215516c77SSepherosa Ziehau 			 */
185315516c77SSepherosa Ziehau 			switch (type) {
185415516c77SSepherosa Ziehau 			case NDIS_HASH_IPV4:
185515516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV4;
185615516c77SSepherosa Ziehau 				do_lro = 0;
185715516c77SSepherosa Ziehau 				break;
185815516c77SSepherosa Ziehau 
185915516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV4:
186015516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV4;
186115516c77SSepherosa Ziehau 				break;
186215516c77SSepherosa Ziehau 
186315516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6:
186415516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6;
186515516c77SSepherosa Ziehau 				do_lro = 0;
186615516c77SSepherosa Ziehau 				break;
186715516c77SSepherosa Ziehau 
186815516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6_EX:
186915516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6_EX;
187015516c77SSepherosa Ziehau 				do_lro = 0;
187115516c77SSepherosa Ziehau 				break;
187215516c77SSepherosa Ziehau 
187315516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6:
187415516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6;
187515516c77SSepherosa Ziehau 				break;
187615516c77SSepherosa Ziehau 
187715516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6_EX:
187815516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX;
187915516c77SSepherosa Ziehau 				break;
188015516c77SSepherosa Ziehau 			}
188115516c77SSepherosa Ziehau 		}
188215516c77SSepherosa Ziehau 	} else {
188315516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
188415516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE;
188515516c77SSepherosa Ziehau 	}
188615516c77SSepherosa Ziehau 	M_HASHTYPE_SET(m_new, hash_type);
188715516c77SSepherosa Ziehau 
188815516c77SSepherosa Ziehau 	/*
188915516c77SSepherosa Ziehau 	 * Note:  Moved RX completion back to hv_nv_on_receive() so all
189015516c77SSepherosa Ziehau 	 * messages (not just data messages) will trigger a response.
189115516c77SSepherosa Ziehau 	 */
189215516c77SSepherosa Ziehau 
189315516c77SSepherosa Ziehau 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
189415516c77SSepherosa Ziehau 	rxr->hn_pkts++;
189515516c77SSepherosa Ziehau 
189615516c77SSepherosa Ziehau 	if ((ifp->if_capenable & IFCAP_LRO) && do_lro) {
189715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
189815516c77SSepherosa Ziehau 		struct lro_ctrl *lro = &rxr->hn_lro;
189915516c77SSepherosa Ziehau 
190015516c77SSepherosa Ziehau 		if (lro->lro_cnt) {
190115516c77SSepherosa Ziehau 			rxr->hn_lro_tried++;
190215516c77SSepherosa Ziehau 			if (hn_lro_rx(lro, m_new) == 0) {
190315516c77SSepherosa Ziehau 				/* DONE! */
190415516c77SSepherosa Ziehau 				return 0;
190515516c77SSepherosa Ziehau 			}
190615516c77SSepherosa Ziehau 		}
190715516c77SSepherosa Ziehau #endif
190815516c77SSepherosa Ziehau 	}
190915516c77SSepherosa Ziehau 
191015516c77SSepherosa Ziehau 	/* We're not holding the lock here, so don't release it */
191115516c77SSepherosa Ziehau 	(*ifp->if_input)(ifp, m_new);
191215516c77SSepherosa Ziehau 
191315516c77SSepherosa Ziehau 	return (0);
191415516c77SSepherosa Ziehau }
191515516c77SSepherosa Ziehau 
191615516c77SSepherosa Ziehau static int
191715516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
191815516c77SSepherosa Ziehau {
191915516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
192015516c77SSepherosa Ziehau 	struct ifreq *ifr = (struct ifreq *)data;
192115516c77SSepherosa Ziehau 	int mask, error = 0;
192215516c77SSepherosa Ziehau 
192315516c77SSepherosa Ziehau 	switch (cmd) {
192415516c77SSepherosa Ziehau 	case SIOCSIFMTU:
192515516c77SSepherosa Ziehau 		if (ifr->ifr_mtu > HN_MTU_MAX) {
192615516c77SSepherosa Ziehau 			error = EINVAL;
192715516c77SSepherosa Ziehau 			break;
192815516c77SSepherosa Ziehau 		}
192915516c77SSepherosa Ziehau 
193015516c77SSepherosa Ziehau 		HN_LOCK(sc);
193115516c77SSepherosa Ziehau 
193215516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
193315516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
193415516c77SSepherosa Ziehau 			break;
193515516c77SSepherosa Ziehau 		}
193615516c77SSepherosa Ziehau 
193715516c77SSepherosa Ziehau 		if ((sc->hn_caps & HN_CAP_MTU) == 0) {
193815516c77SSepherosa Ziehau 			/* Can't change MTU */
193915516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
194015516c77SSepherosa Ziehau 			error = EOPNOTSUPP;
194115516c77SSepherosa Ziehau 			break;
194215516c77SSepherosa Ziehau 		}
194315516c77SSepherosa Ziehau 
194415516c77SSepherosa Ziehau 		if (ifp->if_mtu == ifr->ifr_mtu) {
194515516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
194615516c77SSepherosa Ziehau 			break;
194715516c77SSepherosa Ziehau 		}
194815516c77SSepherosa Ziehau 
194915516c77SSepherosa Ziehau 		/*
195015516c77SSepherosa Ziehau 		 * Suspend this interface before the synthetic parts
195115516c77SSepherosa Ziehau 		 * are ripped.
195215516c77SSepherosa Ziehau 		 */
195315516c77SSepherosa Ziehau 		hn_suspend(sc);
195415516c77SSepherosa Ziehau 
195515516c77SSepherosa Ziehau 		/*
195615516c77SSepherosa Ziehau 		 * Detach the synthetics parts, i.e. NVS and RNDIS.
195715516c77SSepherosa Ziehau 		 */
195815516c77SSepherosa Ziehau 		hn_synth_detach(sc);
195915516c77SSepherosa Ziehau 
196015516c77SSepherosa Ziehau 		/*
196115516c77SSepherosa Ziehau 		 * Reattach the synthetic parts, i.e. NVS and RNDIS,
196215516c77SSepherosa Ziehau 		 * with the new MTU setting.
196315516c77SSepherosa Ziehau 		 */
196415516c77SSepherosa Ziehau 		error = hn_synth_attach(sc, ifr->ifr_mtu);
196515516c77SSepherosa Ziehau 		if (error) {
196615516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
196715516c77SSepherosa Ziehau 			break;
196815516c77SSepherosa Ziehau 		}
196915516c77SSepherosa Ziehau 
197015516c77SSepherosa Ziehau 		/*
197115516c77SSepherosa Ziehau 		 * Commit the requested MTU, after the synthetic parts
197215516c77SSepherosa Ziehau 		 * have been successfully attached.
197315516c77SSepherosa Ziehau 		 */
197415516c77SSepherosa Ziehau 		ifp->if_mtu = ifr->ifr_mtu;
197515516c77SSepherosa Ziehau 
197615516c77SSepherosa Ziehau 		/*
197715516c77SSepherosa Ziehau 		 * Make sure that various parameters based on MTU are
197815516c77SSepherosa Ziehau 		 * still valid, after the MTU change.
197915516c77SSepherosa Ziehau 		 */
198015516c77SSepherosa Ziehau 		if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax)
198115516c77SSepherosa Ziehau 			hn_set_chim_size(sc, sc->hn_chim_szmax);
198215516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu);
198315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
198415516c77SSepherosa Ziehau 		if (sc->hn_rx_ring[0].hn_lro.lro_length_lim <
198515516c77SSepherosa Ziehau 		    HN_LRO_LENLIM_MIN(ifp))
198615516c77SSepherosa Ziehau 			hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
198715516c77SSepherosa Ziehau #endif
198815516c77SSepherosa Ziehau 
198915516c77SSepherosa Ziehau 		/*
199015516c77SSepherosa Ziehau 		 * All done!  Resume the interface now.
199115516c77SSepherosa Ziehau 		 */
199215516c77SSepherosa Ziehau 		hn_resume(sc);
199315516c77SSepherosa Ziehau 
199415516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
199515516c77SSepherosa Ziehau 		break;
199615516c77SSepherosa Ziehau 
199715516c77SSepherosa Ziehau 	case SIOCSIFFLAGS:
199815516c77SSepherosa Ziehau 		HN_LOCK(sc);
199915516c77SSepherosa Ziehau 
200015516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
200115516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
200215516c77SSepherosa Ziehau 			break;
200315516c77SSepherosa Ziehau 		}
200415516c77SSepherosa Ziehau 
200515516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_UP) {
200615516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
200715516c77SSepherosa Ziehau 				hn_set_rxfilter(sc);
200815516c77SSepherosa Ziehau 			else
200915516c77SSepherosa Ziehau 				hn_init_locked(sc);
201015516c77SSepherosa Ziehau 		} else {
201115516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
201215516c77SSepherosa Ziehau 				hn_stop(sc);
201315516c77SSepherosa Ziehau 		}
201415516c77SSepherosa Ziehau 		sc->hn_if_flags = ifp->if_flags;
201515516c77SSepherosa Ziehau 
201615516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
201715516c77SSepherosa Ziehau 		break;
201815516c77SSepherosa Ziehau 
201915516c77SSepherosa Ziehau 	case SIOCSIFCAP:
202015516c77SSepherosa Ziehau 		HN_LOCK(sc);
202115516c77SSepherosa Ziehau 		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
202215516c77SSepherosa Ziehau 
202315516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM) {
202415516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM;
202515516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM)
202615516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc);
202715516c77SSepherosa Ziehau 			else
202815516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc);
202915516c77SSepherosa Ziehau 		}
203015516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM_IPV6) {
203115516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
203215516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
203315516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc);
203415516c77SSepherosa Ziehau 			else
203515516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc);
203615516c77SSepherosa Ziehau 		}
203715516c77SSepherosa Ziehau 
203815516c77SSepherosa Ziehau 		/* TODO: flip RNDIS offload parameters for RXCSUM. */
203915516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM)
204015516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM;
204115516c77SSepherosa Ziehau #ifdef foo
204215516c77SSepherosa Ziehau 		/* We can't diff IPv6 packets from IPv4 packets on RX path. */
204315516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM_IPV6)
204415516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
204515516c77SSepherosa Ziehau #endif
204615516c77SSepherosa Ziehau 
204715516c77SSepherosa Ziehau 		if (mask & IFCAP_LRO)
204815516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_LRO;
204915516c77SSepherosa Ziehau 
205015516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO4) {
205115516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO4;
205215516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO4)
205315516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP_TSO;
205415516c77SSepherosa Ziehau 			else
205515516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP_TSO;
205615516c77SSepherosa Ziehau 		}
205715516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO6) {
205815516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO6;
205915516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO6)
206015516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP6_TSO;
206115516c77SSepherosa Ziehau 			else
206215516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP6_TSO;
206315516c77SSepherosa Ziehau 		}
206415516c77SSepherosa Ziehau 
206515516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
206615516c77SSepherosa Ziehau 		break;
206715516c77SSepherosa Ziehau 
206815516c77SSepherosa Ziehau 	case SIOCADDMULTI:
206915516c77SSepherosa Ziehau 	case SIOCDELMULTI:
207015516c77SSepherosa Ziehau #ifdef notyet
207115516c77SSepherosa Ziehau 		/*
207215516c77SSepherosa Ziehau 		 * XXX
207315516c77SSepherosa Ziehau 		 * Multicast uses mutex, while RNDIS RX filter setting
207415516c77SSepherosa Ziehau 		 * sleeps.  We workaround this by always enabling
207515516c77SSepherosa Ziehau 		 * ALLMULTI.  ALLMULTI would actually always be on, even
207615516c77SSepherosa Ziehau 		 * if we supported the SIOCADDMULTI/SIOCDELMULTI, since
207715516c77SSepherosa Ziehau 		 * we don't support multicast address list configuration
207815516c77SSepherosa Ziehau 		 * for this driver.
207915516c77SSepherosa Ziehau 		 */
208015516c77SSepherosa Ziehau 		HN_LOCK(sc);
208115516c77SSepherosa Ziehau 
208215516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
208315516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
208415516c77SSepherosa Ziehau 			break;
208515516c77SSepherosa Ziehau 		}
208615516c77SSepherosa Ziehau 		if (ifp->if_drv_flags & IFF_DRV_RUNNING)
208715516c77SSepherosa Ziehau 			hn_set_rxfilter(sc);
208815516c77SSepherosa Ziehau 
208915516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
209015516c77SSepherosa Ziehau #endif
209115516c77SSepherosa Ziehau 		break;
209215516c77SSepherosa Ziehau 
209315516c77SSepherosa Ziehau 	case SIOCSIFMEDIA:
209415516c77SSepherosa Ziehau 	case SIOCGIFMEDIA:
209515516c77SSepherosa Ziehau 		error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd);
209615516c77SSepherosa Ziehau 		break;
209715516c77SSepherosa Ziehau 
209815516c77SSepherosa Ziehau 	default:
209915516c77SSepherosa Ziehau 		error = ether_ioctl(ifp, cmd, data);
210015516c77SSepherosa Ziehau 		break;
210115516c77SSepherosa Ziehau 	}
210215516c77SSepherosa Ziehau 	return (error);
210315516c77SSepherosa Ziehau }
210415516c77SSepherosa Ziehau 
210515516c77SSepherosa Ziehau static void
210615516c77SSepherosa Ziehau hn_stop(struct hn_softc *sc)
210715516c77SSepherosa Ziehau {
210815516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
210915516c77SSepherosa Ziehau 	int i;
211015516c77SSepherosa Ziehau 
211115516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
211215516c77SSepherosa Ziehau 
211315516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
211415516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
211515516c77SSepherosa Ziehau 
211615516c77SSepherosa Ziehau 	/* Clear RUNNING bit _before_ hn_suspend_data() */
211715516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
211815516c77SSepherosa Ziehau 	hn_suspend_data(sc);
211915516c77SSepherosa Ziehau 
212015516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
212115516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
212215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
212315516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
212415516c77SSepherosa Ziehau }
212515516c77SSepherosa Ziehau 
212615516c77SSepherosa Ziehau static void
212715516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc)
212815516c77SSepherosa Ziehau {
212915516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
213015516c77SSepherosa Ziehau 	int i;
213115516c77SSepherosa Ziehau 
213215516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
213315516c77SSepherosa Ziehau 
213415516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
213515516c77SSepherosa Ziehau 		return;
213615516c77SSepherosa Ziehau 
213715516c77SSepherosa Ziehau 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
213815516c77SSepherosa Ziehau 		return;
213915516c77SSepherosa Ziehau 
214015516c77SSepherosa Ziehau 	/* Configure RX filter */
214115516c77SSepherosa Ziehau 	hn_set_rxfilter(sc);
214215516c77SSepherosa Ziehau 
214315516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
214415516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
214515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
214615516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
214715516c77SSepherosa Ziehau 
214815516c77SSepherosa Ziehau 	/* Clear TX 'suspended' bit. */
214915516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_inuse);
215015516c77SSepherosa Ziehau 
215115516c77SSepherosa Ziehau 	/* Everything is ready; unleash! */
215215516c77SSepherosa Ziehau 	atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
215315516c77SSepherosa Ziehau }
215415516c77SSepherosa Ziehau 
215515516c77SSepherosa Ziehau static void
215615516c77SSepherosa Ziehau hn_init(void *xsc)
215715516c77SSepherosa Ziehau {
215815516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
215915516c77SSepherosa Ziehau 
216015516c77SSepherosa Ziehau 	HN_LOCK(sc);
216115516c77SSepherosa Ziehau 	hn_init_locked(sc);
216215516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
216315516c77SSepherosa Ziehau }
216415516c77SSepherosa Ziehau 
216515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
216615516c77SSepherosa Ziehau 
216715516c77SSepherosa Ziehau static int
216815516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
216915516c77SSepherosa Ziehau {
217015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
217115516c77SSepherosa Ziehau 	unsigned int lenlim;
217215516c77SSepherosa Ziehau 	int error;
217315516c77SSepherosa Ziehau 
217415516c77SSepherosa Ziehau 	lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim;
217515516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &lenlim, 0, req);
217615516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
217715516c77SSepherosa Ziehau 		return error;
217815516c77SSepherosa Ziehau 
217915516c77SSepherosa Ziehau 	HN_LOCK(sc);
218015516c77SSepherosa Ziehau 	if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) ||
218115516c77SSepherosa Ziehau 	    lenlim > TCP_LRO_LENGTH_MAX) {
218215516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
218315516c77SSepherosa Ziehau 		return EINVAL;
218415516c77SSepherosa Ziehau 	}
218515516c77SSepherosa Ziehau 	hn_set_lro_lenlim(sc, lenlim);
218615516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
218715516c77SSepherosa Ziehau 
218815516c77SSepherosa Ziehau 	return 0;
218915516c77SSepherosa Ziehau }
219015516c77SSepherosa Ziehau 
219115516c77SSepherosa Ziehau static int
219215516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS)
219315516c77SSepherosa Ziehau {
219415516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
219515516c77SSepherosa Ziehau 	int ackcnt, error, i;
219615516c77SSepherosa Ziehau 
219715516c77SSepherosa Ziehau 	/*
219815516c77SSepherosa Ziehau 	 * lro_ackcnt_lim is append count limit,
219915516c77SSepherosa Ziehau 	 * +1 to turn it into aggregation limit.
220015516c77SSepherosa Ziehau 	 */
220115516c77SSepherosa Ziehau 	ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1;
220215516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &ackcnt, 0, req);
220315516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
220415516c77SSepherosa Ziehau 		return error;
220515516c77SSepherosa Ziehau 
220615516c77SSepherosa Ziehau 	if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1))
220715516c77SSepherosa Ziehau 		return EINVAL;
220815516c77SSepherosa Ziehau 
220915516c77SSepherosa Ziehau 	/*
221015516c77SSepherosa Ziehau 	 * Convert aggregation limit back to append
221115516c77SSepherosa Ziehau 	 * count limit.
221215516c77SSepherosa Ziehau 	 */
221315516c77SSepherosa Ziehau 	--ackcnt;
221415516c77SSepherosa Ziehau 	HN_LOCK(sc);
221515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_inuse; ++i)
221615516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt;
221715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
221815516c77SSepherosa Ziehau 	return 0;
221915516c77SSepherosa Ziehau }
222015516c77SSepherosa Ziehau 
222115516c77SSepherosa Ziehau #endif
222215516c77SSepherosa Ziehau 
222315516c77SSepherosa Ziehau static int
222415516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS)
222515516c77SSepherosa Ziehau {
222615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
222715516c77SSepherosa Ziehau 	int hcsum = arg2;
222815516c77SSepherosa Ziehau 	int on, error, i;
222915516c77SSepherosa Ziehau 
223015516c77SSepherosa Ziehau 	on = 0;
223115516c77SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum)
223215516c77SSepherosa Ziehau 		on = 1;
223315516c77SSepherosa Ziehau 
223415516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &on, 0, req);
223515516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
223615516c77SSepherosa Ziehau 		return error;
223715516c77SSepherosa Ziehau 
223815516c77SSepherosa Ziehau 	HN_LOCK(sc);
223915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_inuse; ++i) {
224015516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
224115516c77SSepherosa Ziehau 
224215516c77SSepherosa Ziehau 		if (on)
224315516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= hcsum;
224415516c77SSepherosa Ziehau 		else
224515516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum &= ~hcsum;
224615516c77SSepherosa Ziehau 	}
224715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
224815516c77SSepherosa Ziehau 	return 0;
224915516c77SSepherosa Ziehau }
225015516c77SSepherosa Ziehau 
225115516c77SSepherosa Ziehau static int
225215516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS)
225315516c77SSepherosa Ziehau {
225415516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
225515516c77SSepherosa Ziehau 	int chim_size, error;
225615516c77SSepherosa Ziehau 
225715516c77SSepherosa Ziehau 	chim_size = sc->hn_tx_ring[0].hn_chim_size;
225815516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &chim_size, 0, req);
225915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
226015516c77SSepherosa Ziehau 		return error;
226115516c77SSepherosa Ziehau 
226215516c77SSepherosa Ziehau 	if (chim_size > sc->hn_chim_szmax || chim_size <= 0)
226315516c77SSepherosa Ziehau 		return EINVAL;
226415516c77SSepherosa Ziehau 
226515516c77SSepherosa Ziehau 	HN_LOCK(sc);
226615516c77SSepherosa Ziehau 	hn_set_chim_size(sc, chim_size);
226715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
226815516c77SSepherosa Ziehau 	return 0;
226915516c77SSepherosa Ziehau }
227015516c77SSepherosa Ziehau 
227115516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
227215516c77SSepherosa Ziehau static int
227315516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS)
227415516c77SSepherosa Ziehau {
227515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
227615516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
227715516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
227815516c77SSepherosa Ziehau 	uint64_t stat;
227915516c77SSepherosa Ziehau 
228015516c77SSepherosa Ziehau 	stat = 0;
228115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
228215516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
228315516c77SSepherosa Ziehau 		stat += *((int *)((uint8_t *)rxr + ofs));
228415516c77SSepherosa Ziehau 	}
228515516c77SSepherosa Ziehau 
228615516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
228715516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
228815516c77SSepherosa Ziehau 		return error;
228915516c77SSepherosa Ziehau 
229015516c77SSepherosa Ziehau 	/* Zero out this stat. */
229115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
229215516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
229315516c77SSepherosa Ziehau 		*((int *)((uint8_t *)rxr + ofs)) = 0;
229415516c77SSepherosa Ziehau 	}
229515516c77SSepherosa Ziehau 	return 0;
229615516c77SSepherosa Ziehau }
229715516c77SSepherosa Ziehau #else
229815516c77SSepherosa Ziehau static int
229915516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS)
230015516c77SSepherosa Ziehau {
230115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
230215516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
230315516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
230415516c77SSepherosa Ziehau 	uint64_t stat;
230515516c77SSepherosa Ziehau 
230615516c77SSepherosa Ziehau 	stat = 0;
230715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_inuse; ++i) {
230815516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
230915516c77SSepherosa Ziehau 		stat += *((uint64_t *)((uint8_t *)rxr + ofs));
231015516c77SSepherosa Ziehau 	}
231115516c77SSepherosa Ziehau 
231215516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
231315516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
231415516c77SSepherosa Ziehau 		return error;
231515516c77SSepherosa Ziehau 
231615516c77SSepherosa Ziehau 	/* Zero out this stat. */
231715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_inuse; ++i) {
231815516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
231915516c77SSepherosa Ziehau 		*((uint64_t *)((uint8_t *)rxr + ofs)) = 0;
232015516c77SSepherosa Ziehau 	}
232115516c77SSepherosa Ziehau 	return 0;
232215516c77SSepherosa Ziehau }
232315516c77SSepherosa Ziehau 
232415516c77SSepherosa Ziehau #endif
232515516c77SSepherosa Ziehau 
232615516c77SSepherosa Ziehau static int
232715516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
232815516c77SSepherosa Ziehau {
232915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
233015516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
233115516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
233215516c77SSepherosa Ziehau 	u_long stat;
233315516c77SSepherosa Ziehau 
233415516c77SSepherosa Ziehau 	stat = 0;
233515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_inuse; ++i) {
233615516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
233715516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)rxr + ofs));
233815516c77SSepherosa Ziehau 	}
233915516c77SSepherosa Ziehau 
234015516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
234115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
234215516c77SSepherosa Ziehau 		return error;
234315516c77SSepherosa Ziehau 
234415516c77SSepherosa Ziehau 	/* Zero out this stat. */
234515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_inuse; ++i) {
234615516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
234715516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)rxr + ofs)) = 0;
234815516c77SSepherosa Ziehau 	}
234915516c77SSepherosa Ziehau 	return 0;
235015516c77SSepherosa Ziehau }
235115516c77SSepherosa Ziehau 
235215516c77SSepherosa Ziehau static int
235315516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
235415516c77SSepherosa Ziehau {
235515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
235615516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
235715516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
235815516c77SSepherosa Ziehau 	u_long stat;
235915516c77SSepherosa Ziehau 
236015516c77SSepherosa Ziehau 	stat = 0;
236115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
236215516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
236315516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)txr + ofs));
236415516c77SSepherosa Ziehau 	}
236515516c77SSepherosa Ziehau 
236615516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
236715516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
236815516c77SSepherosa Ziehau 		return error;
236915516c77SSepherosa Ziehau 
237015516c77SSepherosa Ziehau 	/* Zero out this stat. */
237115516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
237215516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
237315516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)txr + ofs)) = 0;
237415516c77SSepherosa Ziehau 	}
237515516c77SSepherosa Ziehau 	return 0;
237615516c77SSepherosa Ziehau }
237715516c77SSepherosa Ziehau 
237815516c77SSepherosa Ziehau static int
237915516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS)
238015516c77SSepherosa Ziehau {
238115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
238215516c77SSepherosa Ziehau 	int ofs = arg2, i, error, conf;
238315516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
238415516c77SSepherosa Ziehau 
238515516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[0];
238615516c77SSepherosa Ziehau 	conf = *((int *)((uint8_t *)txr + ofs));
238715516c77SSepherosa Ziehau 
238815516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &conf, 0, req);
238915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
239015516c77SSepherosa Ziehau 		return error;
239115516c77SSepherosa Ziehau 
239215516c77SSepherosa Ziehau 	HN_LOCK(sc);
239315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
239415516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
239515516c77SSepherosa Ziehau 		*((int *)((uint8_t *)txr + ofs)) = conf;
239615516c77SSepherosa Ziehau 	}
239715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
239815516c77SSepherosa Ziehau 
239915516c77SSepherosa Ziehau 	return 0;
240015516c77SSepherosa Ziehau }
240115516c77SSepherosa Ziehau 
240215516c77SSepherosa Ziehau static int
240315516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS)
240415516c77SSepherosa Ziehau {
240515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
240615516c77SSepherosa Ziehau 	char verstr[16];
240715516c77SSepherosa Ziehau 
240815516c77SSepherosa Ziehau 	snprintf(verstr, sizeof(verstr), "%u.%u",
240915516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
241015516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
241115516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
241215516c77SSepherosa Ziehau }
241315516c77SSepherosa Ziehau 
241415516c77SSepherosa Ziehau static int
241515516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS)
241615516c77SSepherosa Ziehau {
241715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
241815516c77SSepherosa Ziehau 	char caps_str[128];
241915516c77SSepherosa Ziehau 	uint32_t caps;
242015516c77SSepherosa Ziehau 
242115516c77SSepherosa Ziehau 	HN_LOCK(sc);
242215516c77SSepherosa Ziehau 	caps = sc->hn_caps;
242315516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
242415516c77SSepherosa Ziehau 	snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS);
242515516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req);
242615516c77SSepherosa Ziehau }
242715516c77SSepherosa Ziehau 
242815516c77SSepherosa Ziehau static int
242915516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS)
243015516c77SSepherosa Ziehau {
243115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
243215516c77SSepherosa Ziehau 	char assist_str[128];
243315516c77SSepherosa Ziehau 	uint32_t hwassist;
243415516c77SSepherosa Ziehau 
243515516c77SSepherosa Ziehau 	HN_LOCK(sc);
243615516c77SSepherosa Ziehau 	hwassist = sc->hn_ifp->if_hwassist;
243715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
243815516c77SSepherosa Ziehau 	snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS);
243915516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req);
244015516c77SSepherosa Ziehau }
244115516c77SSepherosa Ziehau 
244215516c77SSepherosa Ziehau static int
244315516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS)
244415516c77SSepherosa Ziehau {
244515516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
244615516c77SSepherosa Ziehau 	char filter_str[128];
244715516c77SSepherosa Ziehau 	uint32_t filter;
244815516c77SSepherosa Ziehau 
244915516c77SSepherosa Ziehau 	HN_LOCK(sc);
245015516c77SSepherosa Ziehau 	filter = sc->hn_rx_filter;
245115516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
245215516c77SSepherosa Ziehau 	snprintf(filter_str, sizeof(filter_str), "%b", filter,
245315516c77SSepherosa Ziehau 	    NDIS_PACKET_TYPES);
245415516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req);
245515516c77SSepherosa Ziehau }
245615516c77SSepherosa Ziehau 
245715516c77SSepherosa Ziehau static int
245815516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
245915516c77SSepherosa Ziehau {
246015516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
246115516c77SSepherosa Ziehau 	int error;
246215516c77SSepherosa Ziehau 
246315516c77SSepherosa Ziehau 	HN_LOCK(sc);
246415516c77SSepherosa Ziehau 
246515516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
246615516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
246715516c77SSepherosa Ziehau 		goto back;
246815516c77SSepherosa Ziehau 
246915516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
247015516c77SSepherosa Ziehau 	if (error)
247115516c77SSepherosa Ziehau 		goto back;
247215516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
247315516c77SSepherosa Ziehau 
247415516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
247515516c77SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
247615516c77SSepherosa Ziehau 	} else {
247715516c77SSepherosa Ziehau 		/* Not RSS capable, at least for now; just save the RSS key. */
247815516c77SSepherosa Ziehau 		error = 0;
247915516c77SSepherosa Ziehau 	}
248015516c77SSepherosa Ziehau back:
248115516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
248215516c77SSepherosa Ziehau 	return (error);
248315516c77SSepherosa Ziehau }
248415516c77SSepherosa Ziehau 
248515516c77SSepherosa Ziehau static int
248615516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS)
248715516c77SSepherosa Ziehau {
248815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
248915516c77SSepherosa Ziehau 	int error;
249015516c77SSepherosa Ziehau 
249115516c77SSepherosa Ziehau 	HN_LOCK(sc);
249215516c77SSepherosa Ziehau 
249315516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
249415516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
249515516c77SSepherosa Ziehau 		goto back;
249615516c77SSepherosa Ziehau 
249715516c77SSepherosa Ziehau 	/*
249815516c77SSepherosa Ziehau 	 * Don't allow RSS indirect table change, if this interface is not
249915516c77SSepherosa Ziehau 	 * RSS capable currently.
250015516c77SSepherosa Ziehau 	 */
250115516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
250215516c77SSepherosa Ziehau 		error = EOPNOTSUPP;
250315516c77SSepherosa Ziehau 		goto back;
250415516c77SSepherosa Ziehau 	}
250515516c77SSepherosa Ziehau 
250615516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
250715516c77SSepherosa Ziehau 	if (error)
250815516c77SSepherosa Ziehau 		goto back;
250915516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSIND;
251015516c77SSepherosa Ziehau 
251115516c77SSepherosa Ziehau 	hn_rss_ind_fixup(sc, sc->hn_rx_ring_inuse);
251215516c77SSepherosa Ziehau 	error = hn_rss_reconfig(sc);
251315516c77SSepherosa Ziehau back:
251415516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
251515516c77SSepherosa Ziehau 	return (error);
251615516c77SSepherosa Ziehau }
251715516c77SSepherosa Ziehau 
251815516c77SSepherosa Ziehau static int
251915516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS)
252015516c77SSepherosa Ziehau {
252115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
252215516c77SSepherosa Ziehau 	char hash_str[128];
252315516c77SSepherosa Ziehau 	uint32_t hash;
252415516c77SSepherosa Ziehau 
252515516c77SSepherosa Ziehau 	HN_LOCK(sc);
252615516c77SSepherosa Ziehau 	hash = sc->hn_rss_hash;
252715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
252815516c77SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
252915516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
253015516c77SSepherosa Ziehau }
253115516c77SSepherosa Ziehau 
253215516c77SSepherosa Ziehau static int
253315516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff)
253415516c77SSepherosa Ziehau {
253515516c77SSepherosa Ziehau 	const struct ip *ip;
253615516c77SSepherosa Ziehau 	int len, iphlen, iplen;
253715516c77SSepherosa Ziehau 	const struct tcphdr *th;
253815516c77SSepherosa Ziehau 	int thoff;				/* TCP data offset */
253915516c77SSepherosa Ziehau 
254015516c77SSepherosa Ziehau 	len = hoff + sizeof(struct ip);
254115516c77SSepherosa Ziehau 
254215516c77SSepherosa Ziehau 	/* The packet must be at least the size of an IP header. */
254315516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < len)
254415516c77SSepherosa Ziehau 		return IPPROTO_DONE;
254515516c77SSepherosa Ziehau 
254615516c77SSepherosa Ziehau 	/* The fixed IP header must reside completely in the first mbuf. */
254715516c77SSepherosa Ziehau 	if (m->m_len < len)
254815516c77SSepherosa Ziehau 		return IPPROTO_DONE;
254915516c77SSepherosa Ziehau 
255015516c77SSepherosa Ziehau 	ip = mtodo(m, hoff);
255115516c77SSepherosa Ziehau 
255215516c77SSepherosa Ziehau 	/* Bound check the packet's stated IP header length. */
255315516c77SSepherosa Ziehau 	iphlen = ip->ip_hl << 2;
255415516c77SSepherosa Ziehau 	if (iphlen < sizeof(struct ip))		/* minimum header length */
255515516c77SSepherosa Ziehau 		return IPPROTO_DONE;
255615516c77SSepherosa Ziehau 
255715516c77SSepherosa Ziehau 	/* The full IP header must reside completely in the one mbuf. */
255815516c77SSepherosa Ziehau 	if (m->m_len < hoff + iphlen)
255915516c77SSepherosa Ziehau 		return IPPROTO_DONE;
256015516c77SSepherosa Ziehau 
256115516c77SSepherosa Ziehau 	iplen = ntohs(ip->ip_len);
256215516c77SSepherosa Ziehau 
256315516c77SSepherosa Ziehau 	/*
256415516c77SSepherosa Ziehau 	 * Check that the amount of data in the buffers is as
256515516c77SSepherosa Ziehau 	 * at least much as the IP header would have us expect.
256615516c77SSepherosa Ziehau 	 */
256715516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < hoff + iplen)
256815516c77SSepherosa Ziehau 		return IPPROTO_DONE;
256915516c77SSepherosa Ziehau 
257015516c77SSepherosa Ziehau 	/*
257115516c77SSepherosa Ziehau 	 * Ignore IP fragments.
257215516c77SSepherosa Ziehau 	 */
257315516c77SSepherosa Ziehau 	if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF))
257415516c77SSepherosa Ziehau 		return IPPROTO_DONE;
257515516c77SSepherosa Ziehau 
257615516c77SSepherosa Ziehau 	/*
257715516c77SSepherosa Ziehau 	 * The TCP/IP or UDP/IP header must be entirely contained within
257815516c77SSepherosa Ziehau 	 * the first fragment of a packet.
257915516c77SSepherosa Ziehau 	 */
258015516c77SSepherosa Ziehau 	switch (ip->ip_p) {
258115516c77SSepherosa Ziehau 	case IPPROTO_TCP:
258215516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct tcphdr))
258315516c77SSepherosa Ziehau 			return IPPROTO_DONE;
258415516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct tcphdr))
258515516c77SSepherosa Ziehau 			return IPPROTO_DONE;
258615516c77SSepherosa Ziehau 		th = (const struct tcphdr *)((const uint8_t *)ip + iphlen);
258715516c77SSepherosa Ziehau 		thoff = th->th_off << 2;
258815516c77SSepherosa Ziehau 		if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen)
258915516c77SSepherosa Ziehau 			return IPPROTO_DONE;
259015516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + thoff)
259115516c77SSepherosa Ziehau 			return IPPROTO_DONE;
259215516c77SSepherosa Ziehau 		break;
259315516c77SSepherosa Ziehau 	case IPPROTO_UDP:
259415516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct udphdr))
259515516c77SSepherosa Ziehau 			return IPPROTO_DONE;
259615516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct udphdr))
259715516c77SSepherosa Ziehau 			return IPPROTO_DONE;
259815516c77SSepherosa Ziehau 		break;
259915516c77SSepherosa Ziehau 	default:
260015516c77SSepherosa Ziehau 		if (iplen < iphlen)
260115516c77SSepherosa Ziehau 			return IPPROTO_DONE;
260215516c77SSepherosa Ziehau 		break;
260315516c77SSepherosa Ziehau 	}
260415516c77SSepherosa Ziehau 	return ip->ip_p;
260515516c77SSepherosa Ziehau }
260615516c77SSepherosa Ziehau 
260715516c77SSepherosa Ziehau static int
260815516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt)
260915516c77SSepherosa Ziehau {
261015516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
261115516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
261215516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
261315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
261415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
261515516c77SSepherosa Ziehau 	int lroent_cnt;
261615516c77SSepherosa Ziehau #endif
261715516c77SSepherosa Ziehau #endif
261815516c77SSepherosa Ziehau 	int i;
261915516c77SSepherosa Ziehau 
262015516c77SSepherosa Ziehau 	/*
262115516c77SSepherosa Ziehau 	 * Create RXBUF for reception.
262215516c77SSepherosa Ziehau 	 *
262315516c77SSepherosa Ziehau 	 * NOTE:
262415516c77SSepherosa Ziehau 	 * - It is shared by all channels.
262515516c77SSepherosa Ziehau 	 * - A large enough buffer is allocated, certain version of NVSes
262615516c77SSepherosa Ziehau 	 *   may further limit the usable space.
262715516c77SSepherosa Ziehau 	 */
262815516c77SSepherosa Ziehau 	sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
262915516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma,
263015516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
263115516c77SSepherosa Ziehau 	if (sc->hn_rxbuf == NULL) {
263215516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate rxbuf failed\n");
263315516c77SSepherosa Ziehau 		return (ENOMEM);
263415516c77SSepherosa Ziehau 	}
263515516c77SSepherosa Ziehau 
263615516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = ring_cnt;
263715516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt;
263815516c77SSepherosa Ziehau 
263915516c77SSepherosa Ziehau 	sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt,
264015516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
264115516c77SSepherosa Ziehau 
264215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
264315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
264415516c77SSepherosa Ziehau 	lroent_cnt = hn_lro_entry_count;
264515516c77SSepherosa Ziehau 	if (lroent_cnt < TCP_LRO_ENTRIES)
264615516c77SSepherosa Ziehau 		lroent_cnt = TCP_LRO_ENTRIES;
264715516c77SSepherosa Ziehau 	if (bootverbose)
264815516c77SSepherosa Ziehau 		device_printf(dev, "LRO: entry count %d\n", lroent_cnt);
264915516c77SSepherosa Ziehau #endif
265015516c77SSepherosa Ziehau #endif	/* INET || INET6 */
265115516c77SSepherosa Ziehau 
265215516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
265315516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
265415516c77SSepherosa Ziehau 
265515516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.rx sysctl tree */
265615516c77SSepherosa Ziehau 	sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx",
265715516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
265815516c77SSepherosa Ziehau 
265915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
266015516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
266115516c77SSepherosa Ziehau 
266215516c77SSepherosa Ziehau 		rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
266315516c77SSepherosa Ziehau 		    PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE,
266415516c77SSepherosa Ziehau 		    &rxr->hn_br_dma, BUS_DMA_WAITOK);
266515516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL) {
266615516c77SSepherosa Ziehau 			device_printf(dev, "allocate bufring failed\n");
266715516c77SSepherosa Ziehau 			return (ENOMEM);
266815516c77SSepherosa Ziehau 		}
266915516c77SSepherosa Ziehau 
267015516c77SSepherosa Ziehau 		if (hn_trust_hosttcp)
267115516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP;
267215516c77SSepherosa Ziehau 		if (hn_trust_hostudp)
267315516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP;
267415516c77SSepherosa Ziehau 		if (hn_trust_hostip)
267515516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP;
267615516c77SSepherosa Ziehau 		rxr->hn_ifp = sc->hn_ifp;
267715516c77SSepherosa Ziehau 		if (i < sc->hn_tx_ring_cnt)
267815516c77SSepherosa Ziehau 			rxr->hn_txr = &sc->hn_tx_ring[i];
267915516c77SSepherosa Ziehau 		rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF;
268015516c77SSepherosa Ziehau 		rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK);
268115516c77SSepherosa Ziehau 		rxr->hn_rx_idx = i;
268215516c77SSepherosa Ziehau 		rxr->hn_rxbuf = sc->hn_rxbuf;
268315516c77SSepherosa Ziehau 
268415516c77SSepherosa Ziehau 		/*
268515516c77SSepherosa Ziehau 		 * Initialize LRO.
268615516c77SSepherosa Ziehau 		 */
268715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
268815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
268915516c77SSepherosa Ziehau 		tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt,
269015516c77SSepherosa Ziehau 		    hn_lro_mbufq_depth);
269115516c77SSepherosa Ziehau #else
269215516c77SSepherosa Ziehau 		tcp_lro_init(&rxr->hn_lro);
269315516c77SSepherosa Ziehau 		rxr->hn_lro.ifp = sc->hn_ifp;
269415516c77SSepherosa Ziehau #endif
269515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
269615516c77SSepherosa Ziehau 		rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF;
269715516c77SSepherosa Ziehau 		rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF;
269815516c77SSepherosa Ziehau #endif
269915516c77SSepherosa Ziehau #endif	/* INET || INET6 */
270015516c77SSepherosa Ziehau 
270115516c77SSepherosa Ziehau 		if (sc->hn_rx_sysctl_tree != NULL) {
270215516c77SSepherosa Ziehau 			char name[16];
270315516c77SSepherosa Ziehau 
270415516c77SSepherosa Ziehau 			/*
270515516c77SSepherosa Ziehau 			 * Create per RX ring sysctl tree:
270615516c77SSepherosa Ziehau 			 * dev.hn.UNIT.rx.RINGID
270715516c77SSepherosa Ziehau 			 */
270815516c77SSepherosa Ziehau 			snprintf(name, sizeof(name), "%d", i);
270915516c77SSepherosa Ziehau 			rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx,
271015516c77SSepherosa Ziehau 			    SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree),
271115516c77SSepherosa Ziehau 			    OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
271215516c77SSepherosa Ziehau 
271315516c77SSepherosa Ziehau 			if (rxr->hn_rx_sysctl_tree != NULL) {
271415516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
271515516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
271615516c77SSepherosa Ziehau 				    OID_AUTO, "packets", CTLFLAG_RW,
271715516c77SSepherosa Ziehau 				    &rxr->hn_pkts, "# of packets received");
271815516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
271915516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
272015516c77SSepherosa Ziehau 				    OID_AUTO, "rss_pkts", CTLFLAG_RW,
272115516c77SSepherosa Ziehau 				    &rxr->hn_rss_pkts,
272215516c77SSepherosa Ziehau 				    "# of packets w/ RSS info received");
272315516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx,
272415516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
272515516c77SSepherosa Ziehau 				    OID_AUTO, "pktbuf_len", CTLFLAG_RD,
272615516c77SSepherosa Ziehau 				    &rxr->hn_pktbuf_len, 0,
272715516c77SSepherosa Ziehau 				    "Temporary channel packet buffer length");
272815516c77SSepherosa Ziehau 			}
272915516c77SSepherosa Ziehau 		}
273015516c77SSepherosa Ziehau 	}
273115516c77SSepherosa Ziehau 
273215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued",
273315516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
273415516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_queued),
273515516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
273615516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
273715516c77SSepherosa Ziehau #else
273815516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
273915516c77SSepherosa Ziehau #endif
274015516c77SSepherosa Ziehau 	    "LU", "LRO queued");
274115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed",
274215516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
274315516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_flushed),
274415516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
274515516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
274615516c77SSepherosa Ziehau #else
274715516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
274815516c77SSepherosa Ziehau #endif
274915516c77SSepherosa Ziehau 	    "LU", "LRO flushed");
275015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried",
275115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
275215516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro_tried),
275315516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries");
275415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
275515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim",
275615516c77SSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
275715516c77SSepherosa Ziehau 	    hn_lro_lenlim_sysctl, "IU",
275815516c77SSepherosa Ziehau 	    "Max # of data bytes to be aggregated by LRO");
275915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim",
276015516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
276115516c77SSepherosa Ziehau 	    hn_lro_ackcnt_sysctl, "I",
276215516c77SSepherosa Ziehau 	    "Max # of ACKs to be aggregated by LRO");
276315516c77SSepherosa Ziehau #endif
276415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp",
276515516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP,
276615516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
276715516c77SSepherosa Ziehau 	    "Trust tcp segement verification on host side, "
276815516c77SSepherosa Ziehau 	    "when csum info is missing");
276915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp",
277015516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP,
277115516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
277215516c77SSepherosa Ziehau 	    "Trust udp datagram verification on host side, "
277315516c77SSepherosa Ziehau 	    "when csum info is missing");
277415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip",
277515516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP,
277615516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
277715516c77SSepherosa Ziehau 	    "Trust ip packet verification on host side, "
277815516c77SSepherosa Ziehau 	    "when csum info is missing");
277915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip",
278015516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
278115516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_ip),
278215516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP");
278315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp",
278415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
278515516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_tcp),
278615516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP");
278715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp",
278815516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
278915516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_udp),
279015516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP");
279115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted",
279215516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
279315516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_trusted),
279415516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU",
279515516c77SSepherosa Ziehau 	    "# of packets that we trust host's csum verification");
279615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts",
279715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
279815516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_small_pkts),
279915516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of small packets received");
280015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed",
280115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
280215516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_ack_failed),
280315516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures");
280415516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt",
280515516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings");
280615516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse",
280715516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings");
280815516c77SSepherosa Ziehau 
280915516c77SSepherosa Ziehau 	return (0);
281015516c77SSepherosa Ziehau }
281115516c77SSepherosa Ziehau 
281215516c77SSepherosa Ziehau static void
281315516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc)
281415516c77SSepherosa Ziehau {
281515516c77SSepherosa Ziehau 	int i;
281615516c77SSepherosa Ziehau 
281715516c77SSepherosa Ziehau 	if (sc->hn_rxbuf != NULL) {
281815516c77SSepherosa Ziehau 		hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf);
281915516c77SSepherosa Ziehau 		sc->hn_rxbuf = NULL;
282015516c77SSepherosa Ziehau 	}
282115516c77SSepherosa Ziehau 
282215516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_cnt == 0)
282315516c77SSepherosa Ziehau 		return;
282415516c77SSepherosa Ziehau 
282515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
282615516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
282715516c77SSepherosa Ziehau 
282815516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL)
282915516c77SSepherosa Ziehau 			continue;
283015516c77SSepherosa Ziehau 		hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br);
283115516c77SSepherosa Ziehau 		rxr->hn_br = NULL;
283215516c77SSepherosa Ziehau 
283315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
283415516c77SSepherosa Ziehau 		tcp_lro_free(&rxr->hn_lro);
283515516c77SSepherosa Ziehau #endif
283615516c77SSepherosa Ziehau 		free(rxr->hn_pktbuf, M_DEVBUF);
283715516c77SSepherosa Ziehau 	}
283815516c77SSepherosa Ziehau 	free(sc->hn_rx_ring, M_DEVBUF);
283915516c77SSepherosa Ziehau 	sc->hn_rx_ring = NULL;
284015516c77SSepherosa Ziehau 
284115516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = 0;
284215516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = 0;
284315516c77SSepherosa Ziehau }
284415516c77SSepherosa Ziehau 
284515516c77SSepherosa Ziehau static int
284615516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id)
284715516c77SSepherosa Ziehau {
284815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[id];
284915516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
285015516c77SSepherosa Ziehau 	bus_dma_tag_t parent_dtag;
285115516c77SSepherosa Ziehau 	int error, i;
285215516c77SSepherosa Ziehau 
285315516c77SSepherosa Ziehau 	txr->hn_sc = sc;
285415516c77SSepherosa Ziehau 	txr->hn_tx_idx = id;
285515516c77SSepherosa Ziehau 
285615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
285715516c77SSepherosa Ziehau 	mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN);
285815516c77SSepherosa Ziehau #endif
285915516c77SSepherosa Ziehau 	mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF);
286015516c77SSepherosa Ziehau 
286115516c77SSepherosa Ziehau 	txr->hn_txdesc_cnt = HN_TX_DESC_CNT;
286215516c77SSepherosa Ziehau 	txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt,
286315516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
286415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
286515516c77SSepherosa Ziehau 	SLIST_INIT(&txr->hn_txlist);
286615516c77SSepherosa Ziehau #else
286715516c77SSepherosa Ziehau 	txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF,
286815516c77SSepherosa Ziehau 	    M_WAITOK, &txr->hn_tx_lock);
286915516c77SSepherosa Ziehau #endif
287015516c77SSepherosa Ziehau 
287115516c77SSepherosa Ziehau 	txr->hn_tx_taskq = sc->hn_tx_taskq;
287215516c77SSepherosa Ziehau 
287323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
287415516c77SSepherosa Ziehau 	if (hn_use_if_start) {
287515516c77SSepherosa Ziehau 		txr->hn_txeof = hn_start_txeof;
287615516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr);
287715516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr);
287823bf9e15SSepherosa Ziehau 	} else
287923bf9e15SSepherosa Ziehau #endif
288023bf9e15SSepherosa Ziehau 	{
288115516c77SSepherosa Ziehau 		int br_depth;
288215516c77SSepherosa Ziehau 
288315516c77SSepherosa Ziehau 		txr->hn_txeof = hn_xmit_txeof;
288415516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr);
288515516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr);
288615516c77SSepherosa Ziehau 
288715516c77SSepherosa Ziehau 		br_depth = hn_get_txswq_depth(txr);
288815516c77SSepherosa Ziehau 		txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF,
288915516c77SSepherosa Ziehau 		    M_WAITOK, &txr->hn_tx_lock);
289015516c77SSepherosa Ziehau 	}
289115516c77SSepherosa Ziehau 
289215516c77SSepherosa Ziehau 	txr->hn_direct_tx_size = hn_direct_tx_size;
289315516c77SSepherosa Ziehau 
289415516c77SSepherosa Ziehau 	/*
289515516c77SSepherosa Ziehau 	 * Always schedule transmission instead of trying to do direct
289615516c77SSepherosa Ziehau 	 * transmission.  This one gives the best performance so far.
289715516c77SSepherosa Ziehau 	 */
289815516c77SSepherosa Ziehau 	txr->hn_sched_tx = 1;
289915516c77SSepherosa Ziehau 
290015516c77SSepherosa Ziehau 	parent_dtag = bus_get_dma_tag(dev);
290115516c77SSepherosa Ziehau 
290215516c77SSepherosa Ziehau 	/* DMA tag for RNDIS packet messages. */
290315516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
290415516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_ALIGN,		/* alignment */
290515516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_BOUNDARY,	/* boundary */
290615516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
290715516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
290815516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
290915516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsize */
291015516c77SSepherosa Ziehau 	    1,				/* nsegments */
291115516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsegsize */
291215516c77SSepherosa Ziehau 	    0,				/* flags */
291315516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
291415516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
291515516c77SSepherosa Ziehau 	    &txr->hn_tx_rndis_dtag);
291615516c77SSepherosa Ziehau 	if (error) {
291715516c77SSepherosa Ziehau 		device_printf(dev, "failed to create rndis dmatag\n");
291815516c77SSepherosa Ziehau 		return error;
291915516c77SSepherosa Ziehau 	}
292015516c77SSepherosa Ziehau 
292115516c77SSepherosa Ziehau 	/* DMA tag for data. */
292215516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
292315516c77SSepherosa Ziehau 	    1,				/* alignment */
292415516c77SSepherosa Ziehau 	    HN_TX_DATA_BOUNDARY,	/* boundary */
292515516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
292615516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
292715516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
292815516c77SSepherosa Ziehau 	    HN_TX_DATA_MAXSIZE,		/* maxsize */
292915516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGCNT_MAX,	/* nsegments */
293015516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGSIZE,		/* maxsegsize */
293115516c77SSepherosa Ziehau 	    0,				/* flags */
293215516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
293315516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
293415516c77SSepherosa Ziehau 	    &txr->hn_tx_data_dtag);
293515516c77SSepherosa Ziehau 	if (error) {
293615516c77SSepherosa Ziehau 		device_printf(dev, "failed to create data dmatag\n");
293715516c77SSepherosa Ziehau 		return error;
293815516c77SSepherosa Ziehau 	}
293915516c77SSepherosa Ziehau 
294015516c77SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i) {
294115516c77SSepherosa Ziehau 		struct hn_txdesc *txd = &txr->hn_txdesc[i];
294215516c77SSepherosa Ziehau 
294315516c77SSepherosa Ziehau 		txd->txr = txr;
294415516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
294515516c77SSepherosa Ziehau 
294615516c77SSepherosa Ziehau 		/*
294715516c77SSepherosa Ziehau 		 * Allocate and load RNDIS packet message.
294815516c77SSepherosa Ziehau 		 */
294915516c77SSepherosa Ziehau         	error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag,
295015516c77SSepherosa Ziehau 		    (void **)&txd->rndis_pkt,
295115516c77SSepherosa Ziehau 		    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
295215516c77SSepherosa Ziehau 		    &txd->rndis_pkt_dmap);
295315516c77SSepherosa Ziehau 		if (error) {
295415516c77SSepherosa Ziehau 			device_printf(dev,
295515516c77SSepherosa Ziehau 			    "failed to allocate rndis_packet_msg, %d\n", i);
295615516c77SSepherosa Ziehau 			return error;
295715516c77SSepherosa Ziehau 		}
295815516c77SSepherosa Ziehau 
295915516c77SSepherosa Ziehau 		error = bus_dmamap_load(txr->hn_tx_rndis_dtag,
296015516c77SSepherosa Ziehau 		    txd->rndis_pkt_dmap,
296115516c77SSepherosa Ziehau 		    txd->rndis_pkt, HN_RNDIS_PKT_LEN,
296215516c77SSepherosa Ziehau 		    hyperv_dma_map_paddr, &txd->rndis_pkt_paddr,
296315516c77SSepherosa Ziehau 		    BUS_DMA_NOWAIT);
296415516c77SSepherosa Ziehau 		if (error) {
296515516c77SSepherosa Ziehau 			device_printf(dev,
296615516c77SSepherosa Ziehau 			    "failed to load rndis_packet_msg, %d\n", i);
296715516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
296815516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
296915516c77SSepherosa Ziehau 			return error;
297015516c77SSepherosa Ziehau 		}
297115516c77SSepherosa Ziehau 
297215516c77SSepherosa Ziehau 		/* DMA map for TX data. */
297315516c77SSepherosa Ziehau 		error = bus_dmamap_create(txr->hn_tx_data_dtag, 0,
297415516c77SSepherosa Ziehau 		    &txd->data_dmap);
297515516c77SSepherosa Ziehau 		if (error) {
297615516c77SSepherosa Ziehau 			device_printf(dev,
297715516c77SSepherosa Ziehau 			    "failed to allocate tx data dmamap\n");
297815516c77SSepherosa Ziehau 			bus_dmamap_unload(txr->hn_tx_rndis_dtag,
297915516c77SSepherosa Ziehau 			    txd->rndis_pkt_dmap);
298015516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
298115516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
298215516c77SSepherosa Ziehau 			return error;
298315516c77SSepherosa Ziehau 		}
298415516c77SSepherosa Ziehau 
298515516c77SSepherosa Ziehau 		/* All set, put it to list */
298615516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_ONLIST;
298715516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
298815516c77SSepherosa Ziehau 		SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
298915516c77SSepherosa Ziehau #else
299015516c77SSepherosa Ziehau 		buf_ring_enqueue(txr->hn_txdesc_br, txd);
299115516c77SSepherosa Ziehau #endif
299215516c77SSepherosa Ziehau 	}
299315516c77SSepherosa Ziehau 	txr->hn_txdesc_avail = txr->hn_txdesc_cnt;
299415516c77SSepherosa Ziehau 
299515516c77SSepherosa Ziehau 	if (sc->hn_tx_sysctl_tree != NULL) {
299615516c77SSepherosa Ziehau 		struct sysctl_oid_list *child;
299715516c77SSepherosa Ziehau 		struct sysctl_ctx_list *ctx;
299815516c77SSepherosa Ziehau 		char name[16];
299915516c77SSepherosa Ziehau 
300015516c77SSepherosa Ziehau 		/*
300115516c77SSepherosa Ziehau 		 * Create per TX ring sysctl tree:
300215516c77SSepherosa Ziehau 		 * dev.hn.UNIT.tx.RINGID
300315516c77SSepherosa Ziehau 		 */
300415516c77SSepherosa Ziehau 		ctx = device_get_sysctl_ctx(dev);
300515516c77SSepherosa Ziehau 		child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree);
300615516c77SSepherosa Ziehau 
300715516c77SSepherosa Ziehau 		snprintf(name, sizeof(name), "%d", id);
300815516c77SSepherosa Ziehau 		txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
300915516c77SSepherosa Ziehau 		    name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
301015516c77SSepherosa Ziehau 
301115516c77SSepherosa Ziehau 		if (txr->hn_tx_sysctl_tree != NULL) {
301215516c77SSepherosa Ziehau 			child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree);
301315516c77SSepherosa Ziehau 
301415516c77SSepherosa Ziehau 			SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail",
301515516c77SSepherosa Ziehau 			    CTLFLAG_RD, &txr->hn_txdesc_avail, 0,
301615516c77SSepherosa Ziehau 			    "# of available TX descs");
301723bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
301823bf9e15SSepherosa Ziehau 			if (!hn_use_if_start)
301923bf9e15SSepherosa Ziehau #endif
302023bf9e15SSepherosa Ziehau 			{
302115516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive",
302215516c77SSepherosa Ziehau 				    CTLFLAG_RD, &txr->hn_oactive, 0,
302315516c77SSepherosa Ziehau 				    "over active");
302415516c77SSepherosa Ziehau 			}
302515516c77SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets",
302615516c77SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_pkts,
302715516c77SSepherosa Ziehau 			    "# of packets transmitted");
302815516c77SSepherosa Ziehau 		}
302915516c77SSepherosa Ziehau 	}
303015516c77SSepherosa Ziehau 
303115516c77SSepherosa Ziehau 	return 0;
303215516c77SSepherosa Ziehau }
303315516c77SSepherosa Ziehau 
303415516c77SSepherosa Ziehau static void
303515516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd)
303615516c77SSepherosa Ziehau {
303715516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = txd->txr;
303815516c77SSepherosa Ziehau 
303915516c77SSepherosa Ziehau 	KASSERT(txd->m == NULL, ("still has mbuf installed"));
304015516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped"));
304115516c77SSepherosa Ziehau 
304215516c77SSepherosa Ziehau 	bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap);
304315516c77SSepherosa Ziehau 	bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt,
304415516c77SSepherosa Ziehau 	    txd->rndis_pkt_dmap);
304515516c77SSepherosa Ziehau 	bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap);
304615516c77SSepherosa Ziehau }
304715516c77SSepherosa Ziehau 
304815516c77SSepherosa Ziehau static void
304915516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr)
305015516c77SSepherosa Ziehau {
305115516c77SSepherosa Ziehau 	struct hn_txdesc *txd;
305215516c77SSepherosa Ziehau 
305315516c77SSepherosa Ziehau 	if (txr->hn_txdesc == NULL)
305415516c77SSepherosa Ziehau 		return;
305515516c77SSepherosa Ziehau 
305615516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
305715516c77SSepherosa Ziehau 	while ((txd = SLIST_FIRST(&txr->hn_txlist)) != NULL) {
305815516c77SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&txr->hn_txlist, link);
305915516c77SSepherosa Ziehau 		hn_txdesc_dmamap_destroy(txd);
306015516c77SSepherosa Ziehau 	}
306115516c77SSepherosa Ziehau #else
306215516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
306315516c77SSepherosa Ziehau 	while ((txd = buf_ring_dequeue_sc(txr->hn_txdesc_br)) != NULL)
306415516c77SSepherosa Ziehau 		hn_txdesc_dmamap_destroy(txd);
306515516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
306615516c77SSepherosa Ziehau #endif
306715516c77SSepherosa Ziehau 
306815516c77SSepherosa Ziehau 	if (txr->hn_tx_data_dtag != NULL)
306915516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_data_dtag);
307015516c77SSepherosa Ziehau 	if (txr->hn_tx_rndis_dtag != NULL)
307115516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_rndis_dtag);
307215516c77SSepherosa Ziehau 
307315516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
307415516c77SSepherosa Ziehau 	buf_ring_free(txr->hn_txdesc_br, M_DEVBUF);
307515516c77SSepherosa Ziehau #endif
307615516c77SSepherosa Ziehau 
307715516c77SSepherosa Ziehau 	free(txr->hn_txdesc, M_DEVBUF);
307815516c77SSepherosa Ziehau 	txr->hn_txdesc = NULL;
307915516c77SSepherosa Ziehau 
308015516c77SSepherosa Ziehau 	if (txr->hn_mbuf_br != NULL)
308115516c77SSepherosa Ziehau 		buf_ring_free(txr->hn_mbuf_br, M_DEVBUF);
308215516c77SSepherosa Ziehau 
308315516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
308415516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_txlist_spin);
308515516c77SSepherosa Ziehau #endif
308615516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_tx_lock);
308715516c77SSepherosa Ziehau }
308815516c77SSepherosa Ziehau 
308915516c77SSepherosa Ziehau static int
309015516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt)
309115516c77SSepherosa Ziehau {
309215516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
309315516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
309415516c77SSepherosa Ziehau 	int i;
309515516c77SSepherosa Ziehau 
309615516c77SSepherosa Ziehau 	/*
309715516c77SSepherosa Ziehau 	 * Create TXBUF for chimney sending.
309815516c77SSepherosa Ziehau 	 *
309915516c77SSepherosa Ziehau 	 * NOTE: It is shared by all channels.
310015516c77SSepherosa Ziehau 	 */
310115516c77SSepherosa Ziehau 	sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev),
310215516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma,
310315516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
310415516c77SSepherosa Ziehau 	if (sc->hn_chim == NULL) {
310515516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate txbuf failed\n");
310615516c77SSepherosa Ziehau 		return (ENOMEM);
310715516c77SSepherosa Ziehau 	}
310815516c77SSepherosa Ziehau 
310915516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = ring_cnt;
311015516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
311115516c77SSepherosa Ziehau 
311215516c77SSepherosa Ziehau 	sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt,
311315516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
311415516c77SSepherosa Ziehau 
311515516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(sc->hn_dev);
311615516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev));
311715516c77SSepherosa Ziehau 
311815516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.tx sysctl tree */
311915516c77SSepherosa Ziehau 	sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx",
312015516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
312115516c77SSepherosa Ziehau 
312215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
312315516c77SSepherosa Ziehau 		int error;
312415516c77SSepherosa Ziehau 
312515516c77SSepherosa Ziehau 		error = hn_tx_ring_create(sc, i);
312615516c77SSepherosa Ziehau 		if (error)
312715516c77SSepherosa Ziehau 			return error;
312815516c77SSepherosa Ziehau 	}
312915516c77SSepherosa Ziehau 
313015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs",
313115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
313215516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_no_txdescs),
313315516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs");
313415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed",
313515516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
313615516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_send_failed),
313715516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure");
313815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed",
313915516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
314015516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_txdma_failed),
314115516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure");
314215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed",
314315516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
314415516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_collapsed),
314515516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed");
314615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney",
314715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
314815516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney),
314915516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send");
315015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried",
315115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
315215516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney_tried),
315315516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries");
315415516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt",
315515516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0,
315615516c77SSepherosa Ziehau 	    "# of total TX descs");
315715516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max",
315815516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_chim_szmax, 0,
315915516c77SSepherosa Ziehau 	    "Chimney send packet size upper boundary");
316015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size",
316115516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
316215516c77SSepherosa Ziehau 	    hn_chim_size_sysctl, "I", "Chimney send packet size limit");
316315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size",
316415516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
316515516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_direct_tx_size),
316615516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
316715516c77SSepherosa Ziehau 	    "Size of the packet for direct transmission");
316815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx",
316915516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
317015516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_sched_tx),
317115516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
317215516c77SSepherosa Ziehau 	    "Always schedule transmission "
317315516c77SSepherosa Ziehau 	    "instead of doing direct transmission");
317415516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt",
317515516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings");
317615516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse",
317715516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings");
317815516c77SSepherosa Ziehau 
317915516c77SSepherosa Ziehau 	return 0;
318015516c77SSepherosa Ziehau }
318115516c77SSepherosa Ziehau 
318215516c77SSepherosa Ziehau static void
318315516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size)
318415516c77SSepherosa Ziehau {
318515516c77SSepherosa Ziehau 	int i;
318615516c77SSepherosa Ziehau 
318715516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
318815516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_chim_size = chim_size;
318915516c77SSepherosa Ziehau }
319015516c77SSepherosa Ziehau 
319115516c77SSepherosa Ziehau static void
319215516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu)
319315516c77SSepherosa Ziehau {
319415516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
319515516c77SSepherosa Ziehau 	int tso_minlen;
319615516c77SSepherosa Ziehau 
319715516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0)
319815516c77SSepherosa Ziehau 		return;
319915516c77SSepherosa Ziehau 
320015516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_sgmin >= 2,
320115516c77SSepherosa Ziehau 	    ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin));
320215516c77SSepherosa Ziehau 	tso_minlen = sc->hn_ndis_tso_sgmin * mtu;
320315516c77SSepherosa Ziehau 
320415516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen &&
320515516c77SSepherosa Ziehau 	    sc->hn_ndis_tso_szmax <= IP_MAXPACKET,
320615516c77SSepherosa Ziehau 	    ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax));
320715516c77SSepherosa Ziehau 
320815516c77SSepherosa Ziehau 	if (tso_maxlen < tso_minlen)
320915516c77SSepherosa Ziehau 		tso_maxlen = tso_minlen;
321015516c77SSepherosa Ziehau 	else if (tso_maxlen > IP_MAXPACKET)
321115516c77SSepherosa Ziehau 		tso_maxlen = IP_MAXPACKET;
321215516c77SSepherosa Ziehau 	if (tso_maxlen > sc->hn_ndis_tso_szmax)
321315516c77SSepherosa Ziehau 		tso_maxlen = sc->hn_ndis_tso_szmax;
321415516c77SSepherosa Ziehau 	ifp->if_hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
321515516c77SSepherosa Ziehau 	if (bootverbose)
321615516c77SSepherosa Ziehau 		if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax);
321715516c77SSepherosa Ziehau }
321815516c77SSepherosa Ziehau 
321915516c77SSepherosa Ziehau static void
322015516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc)
322115516c77SSepherosa Ziehau {
322215516c77SSepherosa Ziehau 	uint64_t csum_assist;
322315516c77SSepherosa Ziehau 	int i;
322415516c77SSepherosa Ziehau 
322515516c77SSepherosa Ziehau 	hn_set_chim_size(sc, sc->hn_chim_szmax);
322615516c77SSepherosa Ziehau 	if (hn_tx_chimney_size > 0 &&
322715516c77SSepherosa Ziehau 	    hn_tx_chimney_size < sc->hn_chim_szmax)
322815516c77SSepherosa Ziehau 		hn_set_chim_size(sc, hn_tx_chimney_size);
322915516c77SSepherosa Ziehau 
323015516c77SSepherosa Ziehau 	csum_assist = 0;
323115516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_IPCS)
323215516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP;
323315516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP4CS)
323415516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_TCP;
323515516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP4CS)
323615516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_UDP;
323715516c77SSepherosa Ziehau #ifdef notyet
323815516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP6CS)
323915516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_TCP;
324015516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP6CS)
324115516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_UDP;
324215516c77SSepherosa Ziehau #endif
324315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
324415516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_csum_assist = csum_assist;
324515516c77SSepherosa Ziehau 
324615516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_HASHVAL) {
324715516c77SSepherosa Ziehau 		/*
324815516c77SSepherosa Ziehau 		 * Support HASHVAL pktinfo on TX path.
324915516c77SSepherosa Ziehau 		 */
325015516c77SSepherosa Ziehau 		if (bootverbose)
325115516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n");
325215516c77SSepherosa Ziehau 		for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
325315516c77SSepherosa Ziehau 			sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL;
325415516c77SSepherosa Ziehau 	}
325515516c77SSepherosa Ziehau }
325615516c77SSepherosa Ziehau 
325715516c77SSepherosa Ziehau static void
325815516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc)
325915516c77SSepherosa Ziehau {
326015516c77SSepherosa Ziehau 	int i;
326115516c77SSepherosa Ziehau 
326215516c77SSepherosa Ziehau 	if (sc->hn_chim != NULL) {
326315516c77SSepherosa Ziehau 		hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim);
326415516c77SSepherosa Ziehau 		sc->hn_chim = NULL;
326515516c77SSepherosa Ziehau 	}
326615516c77SSepherosa Ziehau 
326715516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt == 0)
326815516c77SSepherosa Ziehau 		return;
326915516c77SSepherosa Ziehau 
327015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
327115516c77SSepherosa Ziehau 		hn_tx_ring_destroy(&sc->hn_tx_ring[i]);
327215516c77SSepherosa Ziehau 
327315516c77SSepherosa Ziehau 	free(sc->hn_tx_ring, M_DEVBUF);
327415516c77SSepherosa Ziehau 	sc->hn_tx_ring = NULL;
327515516c77SSepherosa Ziehau 
327615516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = 0;
327715516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = 0;
327815516c77SSepherosa Ziehau }
327915516c77SSepherosa Ziehau 
328023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
328123bf9e15SSepherosa Ziehau 
328215516c77SSepherosa Ziehau static void
328315516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused)
328415516c77SSepherosa Ziehau {
328515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
328615516c77SSepherosa Ziehau 
328715516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
328815516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
328915516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
329015516c77SSepherosa Ziehau }
329115516c77SSepherosa Ziehau 
329223bf9e15SSepherosa Ziehau static int
329323bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len)
329423bf9e15SSepherosa Ziehau {
329523bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
329623bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
329723bf9e15SSepherosa Ziehau 
329823bf9e15SSepherosa Ziehau 	KASSERT(hn_use_if_start,
329923bf9e15SSepherosa Ziehau 	    ("hn_start_locked is called, when if_start is disabled"));
330023bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
330123bf9e15SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
330223bf9e15SSepherosa Ziehau 
330323bf9e15SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
330423bf9e15SSepherosa Ziehau 		return 0;
330523bf9e15SSepherosa Ziehau 
330623bf9e15SSepherosa Ziehau 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
330723bf9e15SSepherosa Ziehau 	    IFF_DRV_RUNNING)
330823bf9e15SSepherosa Ziehau 		return 0;
330923bf9e15SSepherosa Ziehau 
331023bf9e15SSepherosa Ziehau 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
331123bf9e15SSepherosa Ziehau 		struct hn_txdesc *txd;
331223bf9e15SSepherosa Ziehau 		struct mbuf *m_head;
331323bf9e15SSepherosa Ziehau 		int error;
331423bf9e15SSepherosa Ziehau 
331523bf9e15SSepherosa Ziehau 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
331623bf9e15SSepherosa Ziehau 		if (m_head == NULL)
331723bf9e15SSepherosa Ziehau 			break;
331823bf9e15SSepherosa Ziehau 
331923bf9e15SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
332023bf9e15SSepherosa Ziehau 			/*
332123bf9e15SSepherosa Ziehau 			 * This sending could be time consuming; let callers
332223bf9e15SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
332323bf9e15SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
332423bf9e15SSepherosa Ziehau 			 */
332523bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
332623bf9e15SSepherosa Ziehau 			return 1;
332723bf9e15SSepherosa Ziehau 		}
332823bf9e15SSepherosa Ziehau 
3329*edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
3330*edd3f315SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
3331*edd3f315SSepherosa Ziehau 			m_head = hn_tso_fixup(m_head);
3332*edd3f315SSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
3333*edd3f315SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
3334*edd3f315SSepherosa Ziehau 				continue;
3335*edd3f315SSepherosa Ziehau 			}
3336*edd3f315SSepherosa Ziehau 		}
3337*edd3f315SSepherosa Ziehau #endif
3338*edd3f315SSepherosa Ziehau 
333923bf9e15SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
334023bf9e15SSepherosa Ziehau 		if (txd == NULL) {
334123bf9e15SSepherosa Ziehau 			txr->hn_no_txdescs++;
334223bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
334323bf9e15SSepherosa Ziehau 			atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
334423bf9e15SSepherosa Ziehau 			break;
334523bf9e15SSepherosa Ziehau 		}
334623bf9e15SSepherosa Ziehau 
334723bf9e15SSepherosa Ziehau 		error = hn_encap(txr, txd, &m_head);
334823bf9e15SSepherosa Ziehau 		if (error) {
334923bf9e15SSepherosa Ziehau 			/* Both txd and m_head are freed */
335023bf9e15SSepherosa Ziehau 			continue;
335123bf9e15SSepherosa Ziehau 		}
335223bf9e15SSepherosa Ziehau 
335323bf9e15SSepherosa Ziehau 		error = hn_txpkt(ifp, txr, txd);
335423bf9e15SSepherosa Ziehau 		if (__predict_false(error)) {
335523bf9e15SSepherosa Ziehau 			/* txd is freed, but m_head is not */
335623bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
335723bf9e15SSepherosa Ziehau 			atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
335823bf9e15SSepherosa Ziehau 			break;
335923bf9e15SSepherosa Ziehau 		}
336023bf9e15SSepherosa Ziehau 	}
336123bf9e15SSepherosa Ziehau 	return 0;
336223bf9e15SSepherosa Ziehau }
336323bf9e15SSepherosa Ziehau 
336423bf9e15SSepherosa Ziehau static void
336523bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp)
336623bf9e15SSepherosa Ziehau {
336723bf9e15SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
336823bf9e15SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[0];
336923bf9e15SSepherosa Ziehau 
337023bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
337123bf9e15SSepherosa Ziehau 		goto do_sched;
337223bf9e15SSepherosa Ziehau 
337323bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
337423bf9e15SSepherosa Ziehau 		int sched;
337523bf9e15SSepherosa Ziehau 
337623bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
337723bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
337823bf9e15SSepherosa Ziehau 		if (!sched)
337923bf9e15SSepherosa Ziehau 			return;
338023bf9e15SSepherosa Ziehau 	}
338123bf9e15SSepherosa Ziehau do_sched:
338223bf9e15SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
338323bf9e15SSepherosa Ziehau }
338423bf9e15SSepherosa Ziehau 
338515516c77SSepherosa Ziehau static void
338615516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused)
338715516c77SSepherosa Ziehau {
338815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
338915516c77SSepherosa Ziehau 
339015516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
339115516c77SSepherosa Ziehau 	atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE);
339215516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
339315516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
339415516c77SSepherosa Ziehau }
339515516c77SSepherosa Ziehau 
339623bf9e15SSepherosa Ziehau static void
339723bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr)
339823bf9e15SSepherosa Ziehau {
339923bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
340023bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
340123bf9e15SSepherosa Ziehau 
340223bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
340323bf9e15SSepherosa Ziehau 
340423bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
340523bf9e15SSepherosa Ziehau 		goto do_sched;
340623bf9e15SSepherosa Ziehau 
340723bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
340823bf9e15SSepherosa Ziehau 		int sched;
340923bf9e15SSepherosa Ziehau 
341023bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
341123bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
341223bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
341323bf9e15SSepherosa Ziehau 		if (sched) {
341423bf9e15SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
341523bf9e15SSepherosa Ziehau 			    &txr->hn_tx_task);
341623bf9e15SSepherosa Ziehau 		}
341723bf9e15SSepherosa Ziehau 	} else {
341823bf9e15SSepherosa Ziehau do_sched:
341923bf9e15SSepherosa Ziehau 		/*
342023bf9e15SSepherosa Ziehau 		 * Release the OACTIVE earlier, with the hope, that
342123bf9e15SSepherosa Ziehau 		 * others could catch up.  The task will clear the
342223bf9e15SSepherosa Ziehau 		 * flag again with the hn_tx_lock to avoid possible
342323bf9e15SSepherosa Ziehau 		 * races.
342423bf9e15SSepherosa Ziehau 		 */
342523bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
342623bf9e15SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
342723bf9e15SSepherosa Ziehau 	}
342823bf9e15SSepherosa Ziehau }
342923bf9e15SSepherosa Ziehau 
343023bf9e15SSepherosa Ziehau #endif	/* HN_IFSTART_SUPPORT */
343123bf9e15SSepherosa Ziehau 
343215516c77SSepherosa Ziehau static int
343315516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len)
343415516c77SSepherosa Ziehau {
343515516c77SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
343615516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
343715516c77SSepherosa Ziehau 	struct mbuf *m_head;
343815516c77SSepherosa Ziehau 
343915516c77SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
344023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
344115516c77SSepherosa Ziehau 	KASSERT(hn_use_if_start == 0,
344215516c77SSepherosa Ziehau 	    ("hn_xmit is called, when if_start is enabled"));
344323bf9e15SSepherosa Ziehau #endif
344415516c77SSepherosa Ziehau 
344515516c77SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
344615516c77SSepherosa Ziehau 		return 0;
344715516c77SSepherosa Ziehau 
344815516c77SSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive)
344915516c77SSepherosa Ziehau 		return 0;
345015516c77SSepherosa Ziehau 
345115516c77SSepherosa Ziehau 	while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) {
345215516c77SSepherosa Ziehau 		struct hn_txdesc *txd;
345315516c77SSepherosa Ziehau 		int error;
345415516c77SSepherosa Ziehau 
345515516c77SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
345615516c77SSepherosa Ziehau 			/*
345715516c77SSepherosa Ziehau 			 * This sending could be time consuming; let callers
345815516c77SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
345915516c77SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
346015516c77SSepherosa Ziehau 			 */
346115516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
346215516c77SSepherosa Ziehau 			return 1;
346315516c77SSepherosa Ziehau 		}
346415516c77SSepherosa Ziehau 
346515516c77SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
346615516c77SSepherosa Ziehau 		if (txd == NULL) {
346715516c77SSepherosa Ziehau 			txr->hn_no_txdescs++;
346815516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
346915516c77SSepherosa Ziehau 			txr->hn_oactive = 1;
347015516c77SSepherosa Ziehau 			break;
347115516c77SSepherosa Ziehau 		}
347215516c77SSepherosa Ziehau 
347315516c77SSepherosa Ziehau 		error = hn_encap(txr, txd, &m_head);
347415516c77SSepherosa Ziehau 		if (error) {
347515516c77SSepherosa Ziehau 			/* Both txd and m_head are freed; discard */
347615516c77SSepherosa Ziehau 			drbr_advance(ifp, txr->hn_mbuf_br);
347715516c77SSepherosa Ziehau 			continue;
347815516c77SSepherosa Ziehau 		}
347915516c77SSepherosa Ziehau 
348015516c77SSepherosa Ziehau 		error = hn_txpkt(ifp, txr, txd);
348115516c77SSepherosa Ziehau 		if (__predict_false(error)) {
348215516c77SSepherosa Ziehau 			/* txd is freed, but m_head is not */
348315516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
348415516c77SSepherosa Ziehau 			txr->hn_oactive = 1;
348515516c77SSepherosa Ziehau 			break;
348615516c77SSepherosa Ziehau 		}
348715516c77SSepherosa Ziehau 
348815516c77SSepherosa Ziehau 		/* Sent */
348915516c77SSepherosa Ziehau 		drbr_advance(ifp, txr->hn_mbuf_br);
349015516c77SSepherosa Ziehau 	}
349115516c77SSepherosa Ziehau 	return 0;
349215516c77SSepherosa Ziehau }
349315516c77SSepherosa Ziehau 
349415516c77SSepherosa Ziehau static int
349515516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m)
349615516c77SSepherosa Ziehau {
349715516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
349815516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
349915516c77SSepherosa Ziehau 	int error, idx = 0;
350015516c77SSepherosa Ziehau 
3501*edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
3502*edd3f315SSepherosa Ziehau 	/*
3503*edd3f315SSepherosa Ziehau 	 * Perform TSO packet header fixup now, since the TSO
3504*edd3f315SSepherosa Ziehau 	 * packet header should be cache-hot.
3505*edd3f315SSepherosa Ziehau 	 */
3506*edd3f315SSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
3507*edd3f315SSepherosa Ziehau 		m = hn_tso_fixup(m);
3508*edd3f315SSepherosa Ziehau 		if (__predict_false(m == NULL)) {
3509*edd3f315SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
3510*edd3f315SSepherosa Ziehau 			return EIO;
3511*edd3f315SSepherosa Ziehau 		}
3512*edd3f315SSepherosa Ziehau 	}
3513*edd3f315SSepherosa Ziehau #endif
3514*edd3f315SSepherosa Ziehau 
351515516c77SSepherosa Ziehau 	/*
351615516c77SSepherosa Ziehau 	 * Select the TX ring based on flowid
351715516c77SSepherosa Ziehau 	 */
351815516c77SSepherosa Ziehau 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
351915516c77SSepherosa Ziehau 		idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse;
352015516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[idx];
352115516c77SSepherosa Ziehau 
352215516c77SSepherosa Ziehau 	error = drbr_enqueue(ifp, txr->hn_mbuf_br, m);
352315516c77SSepherosa Ziehau 	if (error) {
352415516c77SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
352515516c77SSepherosa Ziehau 		return error;
352615516c77SSepherosa Ziehau 	}
352715516c77SSepherosa Ziehau 
352815516c77SSepherosa Ziehau 	if (txr->hn_oactive)
352915516c77SSepherosa Ziehau 		return 0;
353015516c77SSepherosa Ziehau 
353115516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
353215516c77SSepherosa Ziehau 		goto do_sched;
353315516c77SSepherosa Ziehau 
353415516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
353515516c77SSepherosa Ziehau 		int sched;
353615516c77SSepherosa Ziehau 
353715516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
353815516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
353915516c77SSepherosa Ziehau 		if (!sched)
354015516c77SSepherosa Ziehau 			return 0;
354115516c77SSepherosa Ziehau 	}
354215516c77SSepherosa Ziehau do_sched:
354315516c77SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
354415516c77SSepherosa Ziehau 	return 0;
354515516c77SSepherosa Ziehau }
354615516c77SSepherosa Ziehau 
354715516c77SSepherosa Ziehau static void
354815516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr)
354915516c77SSepherosa Ziehau {
355015516c77SSepherosa Ziehau 	struct mbuf *m;
355115516c77SSepherosa Ziehau 
355215516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
355315516c77SSepherosa Ziehau 	while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL)
355415516c77SSepherosa Ziehau 		m_freem(m);
355515516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
355615516c77SSepherosa Ziehau }
355715516c77SSepherosa Ziehau 
355815516c77SSepherosa Ziehau static void
355915516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp)
356015516c77SSepherosa Ziehau {
356115516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
356215516c77SSepherosa Ziehau 	int i;
356315516c77SSepherosa Ziehau 
356415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
356515516c77SSepherosa Ziehau 		hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
356615516c77SSepherosa Ziehau 	if_qflush(ifp);
356715516c77SSepherosa Ziehau }
356815516c77SSepherosa Ziehau 
356915516c77SSepherosa Ziehau static void
357015516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr)
357115516c77SSepherosa Ziehau {
357215516c77SSepherosa Ziehau 
357315516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
357415516c77SSepherosa Ziehau 		goto do_sched;
357515516c77SSepherosa Ziehau 
357615516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
357715516c77SSepherosa Ziehau 		int sched;
357815516c77SSepherosa Ziehau 
357915516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
358015516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
358115516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
358215516c77SSepherosa Ziehau 		if (sched) {
358315516c77SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
358415516c77SSepherosa Ziehau 			    &txr->hn_tx_task);
358515516c77SSepherosa Ziehau 		}
358615516c77SSepherosa Ziehau 	} else {
358715516c77SSepherosa Ziehau do_sched:
358815516c77SSepherosa Ziehau 		/*
358915516c77SSepherosa Ziehau 		 * Release the oactive earlier, with the hope, that
359015516c77SSepherosa Ziehau 		 * others could catch up.  The task will clear the
359115516c77SSepherosa Ziehau 		 * oactive again with the hn_tx_lock to avoid possible
359215516c77SSepherosa Ziehau 		 * races.
359315516c77SSepherosa Ziehau 		 */
359415516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
359515516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
359615516c77SSepherosa Ziehau 	}
359715516c77SSepherosa Ziehau }
359815516c77SSepherosa Ziehau 
359915516c77SSepherosa Ziehau static void
360015516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused)
360115516c77SSepherosa Ziehau {
360215516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
360315516c77SSepherosa Ziehau 
360415516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
360515516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
360615516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
360715516c77SSepherosa Ziehau }
360815516c77SSepherosa Ziehau 
360915516c77SSepherosa Ziehau static void
361015516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused)
361115516c77SSepherosa Ziehau {
361215516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
361315516c77SSepherosa Ziehau 
361415516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
361515516c77SSepherosa Ziehau 	txr->hn_oactive = 0;
361615516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
361715516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
361815516c77SSepherosa Ziehau }
361915516c77SSepherosa Ziehau 
362015516c77SSepherosa Ziehau static int
362115516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan)
362215516c77SSepherosa Ziehau {
362315516c77SSepherosa Ziehau 	struct vmbus_chan_br cbr;
362415516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
362515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = NULL;
362615516c77SSepherosa Ziehau 	int idx, error;
362715516c77SSepherosa Ziehau 
362815516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
362915516c77SSepherosa Ziehau 
363015516c77SSepherosa Ziehau 	/*
363115516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
363215516c77SSepherosa Ziehau 	 */
363315516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
363415516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
363515516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
363615516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
363715516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0,
363815516c77SSepherosa Ziehau 	    ("RX ring %d already attached", idx));
363915516c77SSepherosa Ziehau 	rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED;
364015516c77SSepherosa Ziehau 
364115516c77SSepherosa Ziehau 	if (bootverbose) {
364215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n",
364315516c77SSepherosa Ziehau 		    idx, vmbus_chan_id(chan));
364415516c77SSepherosa Ziehau 	}
364515516c77SSepherosa Ziehau 
364615516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
364715516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[idx];
364815516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0,
364915516c77SSepherosa Ziehau 		    ("TX ring %d already attached", idx));
365015516c77SSepherosa Ziehau 		txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED;
365115516c77SSepherosa Ziehau 
365215516c77SSepherosa Ziehau 		txr->hn_chan = chan;
365315516c77SSepherosa Ziehau 		if (bootverbose) {
365415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n",
365515516c77SSepherosa Ziehau 			    idx, vmbus_chan_id(chan));
365615516c77SSepherosa Ziehau 		}
365715516c77SSepherosa Ziehau 	}
365815516c77SSepherosa Ziehau 
365915516c77SSepherosa Ziehau 	/* Bind this channel to a proper CPU. */
366015516c77SSepherosa Ziehau 	vmbus_chan_cpu_set(chan, (sc->hn_cpu + idx) % mp_ncpus);
366115516c77SSepherosa Ziehau 
366215516c77SSepherosa Ziehau 	/*
366315516c77SSepherosa Ziehau 	 * Open this channel
366415516c77SSepherosa Ziehau 	 */
366515516c77SSepherosa Ziehau 	cbr.cbr = rxr->hn_br;
366615516c77SSepherosa Ziehau 	cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr;
366715516c77SSepherosa Ziehau 	cbr.cbr_txsz = HN_TXBR_SIZE;
366815516c77SSepherosa Ziehau 	cbr.cbr_rxsz = HN_RXBR_SIZE;
366915516c77SSepherosa Ziehau 	error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr);
367015516c77SSepherosa Ziehau 	if (error) {
367115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "open chan%u failed: %d\n",
367215516c77SSepherosa Ziehau 		    vmbus_chan_id(chan), error);
367315516c77SSepherosa Ziehau 		rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
367415516c77SSepherosa Ziehau 		if (txr != NULL)
367515516c77SSepherosa Ziehau 			txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
367615516c77SSepherosa Ziehau 	}
367715516c77SSepherosa Ziehau 	return (error);
367815516c77SSepherosa Ziehau }
367915516c77SSepherosa Ziehau 
368015516c77SSepherosa Ziehau static void
368115516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan)
368215516c77SSepherosa Ziehau {
368315516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
368415516c77SSepherosa Ziehau 	int idx;
368515516c77SSepherosa Ziehau 
368615516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
368715516c77SSepherosa Ziehau 
368815516c77SSepherosa Ziehau 	/*
368915516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
369015516c77SSepherosa Ziehau 	 */
369115516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
369215516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
369315516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
369415516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
369515516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED),
369615516c77SSepherosa Ziehau 	    ("RX ring %d is not attached", idx));
369715516c77SSepherosa Ziehau 	rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
369815516c77SSepherosa Ziehau 
369915516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
370015516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[idx];
370115516c77SSepherosa Ziehau 
370215516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED),
370315516c77SSepherosa Ziehau 		    ("TX ring %d is not attached attached", idx));
370415516c77SSepherosa Ziehau 		txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
370515516c77SSepherosa Ziehau 	}
370615516c77SSepherosa Ziehau 
370715516c77SSepherosa Ziehau 	/*
370815516c77SSepherosa Ziehau 	 * Close this channel.
370915516c77SSepherosa Ziehau 	 *
371015516c77SSepherosa Ziehau 	 * NOTE:
371115516c77SSepherosa Ziehau 	 * Channel closing does _not_ destroy the target channel.
371215516c77SSepherosa Ziehau 	 */
371315516c77SSepherosa Ziehau 	vmbus_chan_close(chan);
371415516c77SSepherosa Ziehau }
371515516c77SSepherosa Ziehau 
371615516c77SSepherosa Ziehau static int
371715516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc)
371815516c77SSepherosa Ziehau {
371915516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
372015516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
372115516c77SSepherosa Ziehau 	int i, error = 0;
372215516c77SSepherosa Ziehau 
372315516c77SSepherosa Ziehau 	if (subchan_cnt == 0)
372415516c77SSepherosa Ziehau 		return (0);
372515516c77SSepherosa Ziehau 
372615516c77SSepherosa Ziehau 	/* Attach the sub-channels. */
372715516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
372815516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i) {
372915516c77SSepherosa Ziehau 		error = hn_chan_attach(sc, subchans[i]);
373015516c77SSepherosa Ziehau 		if (error)
373115516c77SSepherosa Ziehau 			break;
373215516c77SSepherosa Ziehau 	}
373315516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
373415516c77SSepherosa Ziehau 
373515516c77SSepherosa Ziehau 	if (error) {
373615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error);
373715516c77SSepherosa Ziehau 	} else {
373815516c77SSepherosa Ziehau 		if (bootverbose) {
373915516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "%d sub-channels attached\n",
374015516c77SSepherosa Ziehau 			    subchan_cnt);
374115516c77SSepherosa Ziehau 		}
374215516c77SSepherosa Ziehau 	}
374315516c77SSepherosa Ziehau 	return (error);
374415516c77SSepherosa Ziehau }
374515516c77SSepherosa Ziehau 
374615516c77SSepherosa Ziehau static void
374715516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc)
374815516c77SSepherosa Ziehau {
374915516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
375015516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
375115516c77SSepherosa Ziehau 	int i;
375215516c77SSepherosa Ziehau 
375315516c77SSepherosa Ziehau 	if (subchan_cnt == 0)
375415516c77SSepherosa Ziehau 		goto back;
375515516c77SSepherosa Ziehau 
375615516c77SSepherosa Ziehau 	/* Detach the sub-channels. */
375715516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
375815516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i)
375915516c77SSepherosa Ziehau 		hn_chan_detach(sc, subchans[i]);
376015516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
376115516c77SSepherosa Ziehau 
376215516c77SSepherosa Ziehau back:
376315516c77SSepherosa Ziehau 	/*
376415516c77SSepherosa Ziehau 	 * Detach the primary channel, _after_ all sub-channels
376515516c77SSepherosa Ziehau 	 * are detached.
376615516c77SSepherosa Ziehau 	 */
376715516c77SSepherosa Ziehau 	hn_chan_detach(sc, sc->hn_prichan);
376815516c77SSepherosa Ziehau 
376915516c77SSepherosa Ziehau 	/* Wait for sub-channels to be destroyed, if any. */
377015516c77SSepherosa Ziehau 	vmbus_subchan_drain(sc->hn_prichan);
377115516c77SSepherosa Ziehau 
377215516c77SSepherosa Ziehau #ifdef INVARIANTS
377315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
377415516c77SSepherosa Ziehau 		KASSERT((sc->hn_rx_ring[i].hn_rx_flags &
377515516c77SSepherosa Ziehau 		    HN_RX_FLAG_ATTACHED) == 0,
377615516c77SSepherosa Ziehau 		    ("%dth RX ring is still attached", i));
377715516c77SSepherosa Ziehau 	}
377815516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
377915516c77SSepherosa Ziehau 		KASSERT((sc->hn_tx_ring[i].hn_tx_flags &
378015516c77SSepherosa Ziehau 		    HN_TX_FLAG_ATTACHED) == 0,
378115516c77SSepherosa Ziehau 		    ("%dth TX ring is still attached", i));
378215516c77SSepherosa Ziehau 	}
378315516c77SSepherosa Ziehau #endif
378415516c77SSepherosa Ziehau }
378515516c77SSepherosa Ziehau 
378615516c77SSepherosa Ziehau static int
378715516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch)
378815516c77SSepherosa Ziehau {
378915516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
379015516c77SSepherosa Ziehau 	int nchan, rxr_cnt, error;
379115516c77SSepherosa Ziehau 
379215516c77SSepherosa Ziehau 	nchan = *nsubch + 1;
379315516c77SSepherosa Ziehau 	if (nchan == 1) {
379415516c77SSepherosa Ziehau 		/*
379515516c77SSepherosa Ziehau 		 * Multiple RX/TX rings are not requested.
379615516c77SSepherosa Ziehau 		 */
379715516c77SSepherosa Ziehau 		*nsubch = 0;
379815516c77SSepherosa Ziehau 		return (0);
379915516c77SSepherosa Ziehau 	}
380015516c77SSepherosa Ziehau 
380115516c77SSepherosa Ziehau 	/*
380215516c77SSepherosa Ziehau 	 * Query RSS capabilities, e.g. # of RX rings, and # of indirect
380315516c77SSepherosa Ziehau 	 * table entries.
380415516c77SSepherosa Ziehau 	 */
380515516c77SSepherosa Ziehau 	error = hn_rndis_query_rsscaps(sc, &rxr_cnt);
380615516c77SSepherosa Ziehau 	if (error) {
380715516c77SSepherosa Ziehau 		/* No RSS; this is benign. */
380815516c77SSepherosa Ziehau 		*nsubch = 0;
380915516c77SSepherosa Ziehau 		return (0);
381015516c77SSepherosa Ziehau 	}
381115516c77SSepherosa Ziehau 	if (bootverbose) {
381215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
381315516c77SSepherosa Ziehau 		    rxr_cnt, nchan);
381415516c77SSepherosa Ziehau 	}
381515516c77SSepherosa Ziehau 
381615516c77SSepherosa Ziehau 	if (nchan > rxr_cnt)
381715516c77SSepherosa Ziehau 		nchan = rxr_cnt;
381815516c77SSepherosa Ziehau 	if (nchan == 1) {
381915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n");
382015516c77SSepherosa Ziehau 		*nsubch = 0;
382115516c77SSepherosa Ziehau 		return (0);
382215516c77SSepherosa Ziehau 	}
382315516c77SSepherosa Ziehau 
382415516c77SSepherosa Ziehau 	/*
382515516c77SSepherosa Ziehau 	 * Allocate sub-channels from NVS.
382615516c77SSepherosa Ziehau 	 */
382715516c77SSepherosa Ziehau 	*nsubch = nchan - 1;
382815516c77SSepherosa Ziehau 	error = hn_nvs_alloc_subchans(sc, nsubch);
382915516c77SSepherosa Ziehau 	if (error || *nsubch == 0) {
383015516c77SSepherosa Ziehau 		/* Failed to allocate sub-channels. */
383115516c77SSepherosa Ziehau 		*nsubch = 0;
383215516c77SSepherosa Ziehau 		return (0);
383315516c77SSepherosa Ziehau 	}
383415516c77SSepherosa Ziehau 
383515516c77SSepherosa Ziehau 	/*
383615516c77SSepherosa Ziehau 	 * Wait for all sub-channels to become ready before moving on.
383715516c77SSepherosa Ziehau 	 */
383815516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch);
383915516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, *nsubch);
384015516c77SSepherosa Ziehau 	return (0);
384115516c77SSepherosa Ziehau }
384215516c77SSepherosa Ziehau 
384315516c77SSepherosa Ziehau static int
384415516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu)
384515516c77SSepherosa Ziehau {
384615516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
384715516c77SSepherosa Ziehau 	int error, nsubch, nchan, i;
384815516c77SSepherosa Ziehau 	uint32_t old_caps;
384915516c77SSepherosa Ziehau 
385015516c77SSepherosa Ziehau 	KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0,
385115516c77SSepherosa Ziehau 	    ("synthetic parts were attached"));
385215516c77SSepherosa Ziehau 
385315516c77SSepherosa Ziehau 	/* Save capabilities for later verification. */
385415516c77SSepherosa Ziehau 	old_caps = sc->hn_caps;
385515516c77SSepherosa Ziehau 	sc->hn_caps = 0;
385615516c77SSepherosa Ziehau 
385715516c77SSepherosa Ziehau 	/* Clear RSS stuffs. */
385815516c77SSepherosa Ziehau 	sc->hn_rss_ind_size = 0;
385915516c77SSepherosa Ziehau 	sc->hn_rss_hash = 0;
386015516c77SSepherosa Ziehau 
386115516c77SSepherosa Ziehau 	/*
386215516c77SSepherosa Ziehau 	 * Attach the primary channel _before_ attaching NVS and RNDIS.
386315516c77SSepherosa Ziehau 	 */
386415516c77SSepherosa Ziehau 	error = hn_chan_attach(sc, sc->hn_prichan);
386515516c77SSepherosa Ziehau 	if (error)
386615516c77SSepherosa Ziehau 		return (error);
386715516c77SSepherosa Ziehau 
386815516c77SSepherosa Ziehau 	/*
386915516c77SSepherosa Ziehau 	 * Attach NVS.
387015516c77SSepherosa Ziehau 	 */
387115516c77SSepherosa Ziehau 	error = hn_nvs_attach(sc, mtu);
387215516c77SSepherosa Ziehau 	if (error)
387315516c77SSepherosa Ziehau 		return (error);
387415516c77SSepherosa Ziehau 
387515516c77SSepherosa Ziehau 	/*
387615516c77SSepherosa Ziehau 	 * Attach RNDIS _after_ NVS is attached.
387715516c77SSepherosa Ziehau 	 */
387815516c77SSepherosa Ziehau 	error = hn_rndis_attach(sc, mtu);
387915516c77SSepherosa Ziehau 	if (error)
388015516c77SSepherosa Ziehau 		return (error);
388115516c77SSepherosa Ziehau 
388215516c77SSepherosa Ziehau 	/*
388315516c77SSepherosa Ziehau 	 * Make sure capabilities are not changed.
388415516c77SSepherosa Ziehau 	 */
388515516c77SSepherosa Ziehau 	if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) {
388615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n",
388715516c77SSepherosa Ziehau 		    old_caps, sc->hn_caps);
388815516c77SSepherosa Ziehau 		/* Restore old capabilities and abort. */
388915516c77SSepherosa Ziehau 		sc->hn_caps = old_caps;
389015516c77SSepherosa Ziehau 		return ENXIO;
389115516c77SSepherosa Ziehau 	}
389215516c77SSepherosa Ziehau 
389315516c77SSepherosa Ziehau 	/*
389415516c77SSepherosa Ziehau 	 * Allocate sub-channels for multi-TX/RX rings.
389515516c77SSepherosa Ziehau 	 *
389615516c77SSepherosa Ziehau 	 * NOTE:
389715516c77SSepherosa Ziehau 	 * The # of RX rings that can be used is equivalent to the # of
389815516c77SSepherosa Ziehau 	 * channels to be requested.
389915516c77SSepherosa Ziehau 	 */
390015516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_cnt - 1;
390115516c77SSepherosa Ziehau 	error = hn_synth_alloc_subchans(sc, &nsubch);
390215516c77SSepherosa Ziehau 	if (error)
390315516c77SSepherosa Ziehau 		return (error);
390415516c77SSepherosa Ziehau 
390515516c77SSepherosa Ziehau 	nchan = nsubch + 1;
390615516c77SSepherosa Ziehau 	if (nchan == 1) {
390715516c77SSepherosa Ziehau 		/* Only the primary channel can be used; done */
390815516c77SSepherosa Ziehau 		goto back;
390915516c77SSepherosa Ziehau 	}
391015516c77SSepherosa Ziehau 
391115516c77SSepherosa Ziehau 	/*
391215516c77SSepherosa Ziehau 	 * Configure RSS key and indirect table _after_ all sub-channels
391315516c77SSepherosa Ziehau 	 * are allocated.
391415516c77SSepherosa Ziehau 	 */
391515516c77SSepherosa Ziehau 
391615516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) {
391715516c77SSepherosa Ziehau 		/*
391815516c77SSepherosa Ziehau 		 * RSS key is not set yet; set it to the default RSS key.
391915516c77SSepherosa Ziehau 		 */
392015516c77SSepherosa Ziehau 		if (bootverbose)
392115516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS key\n");
392215516c77SSepherosa Ziehau 		memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key));
392315516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
392415516c77SSepherosa Ziehau 	}
392515516c77SSepherosa Ziehau 
392615516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) {
392715516c77SSepherosa Ziehau 		/*
392815516c77SSepherosa Ziehau 		 * RSS indirect table is not set yet; set it up in round-
392915516c77SSepherosa Ziehau 		 * robin fashion.
393015516c77SSepherosa Ziehau 		 */
393115516c77SSepherosa Ziehau 		if (bootverbose) {
393215516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS indirect "
393315516c77SSepherosa Ziehau 			    "table\n");
393415516c77SSepherosa Ziehau 		}
393515516c77SSepherosa Ziehau 		for (i = 0; i < NDIS_HASH_INDCNT; ++i)
393615516c77SSepherosa Ziehau 			rss->rss_ind[i] = i % nchan;
393715516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSIND;
393815516c77SSepherosa Ziehau 	} else {
393915516c77SSepherosa Ziehau 		/*
394015516c77SSepherosa Ziehau 		 * # of usable channels may be changed, so we have to
394115516c77SSepherosa Ziehau 		 * make sure that all entries in RSS indirect table
394215516c77SSepherosa Ziehau 		 * are valid.
394315516c77SSepherosa Ziehau 		 */
394415516c77SSepherosa Ziehau 		hn_rss_ind_fixup(sc, nchan);
394515516c77SSepherosa Ziehau 	}
394615516c77SSepherosa Ziehau 
394715516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
394815516c77SSepherosa Ziehau 	if (error) {
394915516c77SSepherosa Ziehau 		/*
395015516c77SSepherosa Ziehau 		 * Failed to configure RSS key or indirect table; only
395115516c77SSepherosa Ziehau 		 * the primary channel can be used.
395215516c77SSepherosa Ziehau 		 */
395315516c77SSepherosa Ziehau 		nchan = 1;
395415516c77SSepherosa Ziehau 	}
395515516c77SSepherosa Ziehau back:
395615516c77SSepherosa Ziehau 	/*
395715516c77SSepherosa Ziehau 	 * Set the # of TX/RX rings that could be used according to
395815516c77SSepherosa Ziehau 	 * the # of channels that NVS offered.
395915516c77SSepherosa Ziehau 	 */
396015516c77SSepherosa Ziehau 	hn_set_ring_inuse(sc, nchan);
396115516c77SSepherosa Ziehau 
396215516c77SSepherosa Ziehau 	/*
396315516c77SSepherosa Ziehau 	 * Attach the sub-channels, if any.
396415516c77SSepherosa Ziehau 	 */
396515516c77SSepherosa Ziehau 	error = hn_attach_subchans(sc);
396615516c77SSepherosa Ziehau 	if (error)
396715516c77SSepherosa Ziehau 		return (error);
396815516c77SSepherosa Ziehau 
396915516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED;
397015516c77SSepherosa Ziehau 	return (0);
397115516c77SSepherosa Ziehau }
397215516c77SSepherosa Ziehau 
397315516c77SSepherosa Ziehau /*
397415516c77SSepherosa Ziehau  * NOTE:
397515516c77SSepherosa Ziehau  * The interface must have been suspended though hn_suspend(), before
397615516c77SSepherosa Ziehau  * this function get called.
397715516c77SSepherosa Ziehau  */
397815516c77SSepherosa Ziehau static void
397915516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc)
398015516c77SSepherosa Ziehau {
398115516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
398215516c77SSepherosa Ziehau 
398315516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
398415516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
398515516c77SSepherosa Ziehau 
398615516c77SSepherosa Ziehau 	/* Detach the RNDIS first. */
398715516c77SSepherosa Ziehau 	hn_rndis_detach(sc);
398815516c77SSepherosa Ziehau 
398915516c77SSepherosa Ziehau 	/* Detach NVS. */
399015516c77SSepherosa Ziehau 	hn_nvs_detach(sc);
399115516c77SSepherosa Ziehau 
399215516c77SSepherosa Ziehau 	/* Detach all of the channels. */
399315516c77SSepherosa Ziehau 	hn_detach_allchans(sc);
399415516c77SSepherosa Ziehau 
399515516c77SSepherosa Ziehau 	sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED;
399615516c77SSepherosa Ziehau }
399715516c77SSepherosa Ziehau 
399815516c77SSepherosa Ziehau static void
399915516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt)
400015516c77SSepherosa Ziehau {
400115516c77SSepherosa Ziehau 	KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt,
400215516c77SSepherosa Ziehau 	    ("invalid ring count %d", ring_cnt));
400315516c77SSepherosa Ziehau 
400415516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt > ring_cnt)
400515516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = ring_cnt;
400615516c77SSepherosa Ziehau 	else
400715516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
400815516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = ring_cnt;
400915516c77SSepherosa Ziehau 
401015516c77SSepherosa Ziehau 	if (bootverbose) {
401115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n",
401215516c77SSepherosa Ziehau 		    sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
401315516c77SSepherosa Ziehau 	}
401415516c77SSepherosa Ziehau }
401515516c77SSepherosa Ziehau 
401615516c77SSepherosa Ziehau static void
401715516c77SSepherosa Ziehau hn_chan_drain(struct vmbus_channel *chan)
401815516c77SSepherosa Ziehau {
401915516c77SSepherosa Ziehau 
402015516c77SSepherosa Ziehau 	while (!vmbus_chan_rx_empty(chan) || !vmbus_chan_tx_empty(chan))
402115516c77SSepherosa Ziehau 		pause("waitch", 1);
402215516c77SSepherosa Ziehau 	vmbus_chan_intr_drain(chan);
402315516c77SSepherosa Ziehau }
402415516c77SSepherosa Ziehau 
402515516c77SSepherosa Ziehau static void
402615516c77SSepherosa Ziehau hn_suspend_data(struct hn_softc *sc)
402715516c77SSepherosa Ziehau {
402815516c77SSepherosa Ziehau 	struct vmbus_channel **subch = NULL;
402915516c77SSepherosa Ziehau 	int i, nsubch;
403015516c77SSepherosa Ziehau 
403115516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
403215516c77SSepherosa Ziehau 
403315516c77SSepherosa Ziehau 	/*
403415516c77SSepherosa Ziehau 	 * Suspend TX.
403515516c77SSepherosa Ziehau 	 */
403615516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
403715516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
403815516c77SSepherosa Ziehau 
403915516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
404015516c77SSepherosa Ziehau 		txr->hn_suspended = 1;
404115516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
404215516c77SSepherosa Ziehau 		/* No one is able send more packets now. */
404315516c77SSepherosa Ziehau 
404415516c77SSepherosa Ziehau 		/* Wait for all pending sends to finish. */
404515516c77SSepherosa Ziehau 		while (hn_tx_ring_pending(txr))
404615516c77SSepherosa Ziehau 			pause("hnwtx", 1 /* 1 tick */);
404715516c77SSepherosa Ziehau 
404815516c77SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task);
404915516c77SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task);
405015516c77SSepherosa Ziehau 	}
405115516c77SSepherosa Ziehau 
405215516c77SSepherosa Ziehau 	/*
405315516c77SSepherosa Ziehau 	 * Disable RX by clearing RX filter.
405415516c77SSepherosa Ziehau 	 */
405515516c77SSepherosa Ziehau 	sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE;
405615516c77SSepherosa Ziehau 	hn_rndis_set_rxfilter(sc, sc->hn_rx_filter);
405715516c77SSepherosa Ziehau 
405815516c77SSepherosa Ziehau 	/*
405915516c77SSepherosa Ziehau 	 * Give RNDIS enough time to flush all pending data packets.
406015516c77SSepherosa Ziehau 	 */
406115516c77SSepherosa Ziehau 	pause("waitrx", (200 * hz) / 1000);
406215516c77SSepherosa Ziehau 
406315516c77SSepherosa Ziehau 	/*
406415516c77SSepherosa Ziehau 	 * Drain RX/TX bufrings and interrupts.
406515516c77SSepherosa Ziehau 	 */
406615516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_inuse - 1;
406715516c77SSepherosa Ziehau 	if (nsubch > 0)
406815516c77SSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
406915516c77SSepherosa Ziehau 
407015516c77SSepherosa Ziehau 	if (subch != NULL) {
407115516c77SSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
407215516c77SSepherosa Ziehau 			hn_chan_drain(subch[i]);
407315516c77SSepherosa Ziehau 	}
407415516c77SSepherosa Ziehau 	hn_chan_drain(sc->hn_prichan);
407515516c77SSepherosa Ziehau 
407615516c77SSepherosa Ziehau 	if (subch != NULL)
407715516c77SSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
407815516c77SSepherosa Ziehau }
407915516c77SSepherosa Ziehau 
408015516c77SSepherosa Ziehau static void
408115516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused)
408215516c77SSepherosa Ziehau {
408315516c77SSepherosa Ziehau 
408415516c77SSepherosa Ziehau 	((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL;
408515516c77SSepherosa Ziehau }
408615516c77SSepherosa Ziehau 
408715516c77SSepherosa Ziehau static void
408815516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc)
408915516c77SSepherosa Ziehau {
409015516c77SSepherosa Ziehau 	struct task task;
409115516c77SSepherosa Ziehau 
409215516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
409315516c77SSepherosa Ziehau 
409415516c77SSepherosa Ziehau 	/*
409515516c77SSepherosa Ziehau 	 * Make sure that hn_mgmt_taskq0 can nolonger be accessed
409615516c77SSepherosa Ziehau 	 * through hn_mgmt_taskq.
409715516c77SSepherosa Ziehau 	 */
409815516c77SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc);
409915516c77SSepherosa Ziehau 	vmbus_chan_run_task(sc->hn_prichan, &task);
410015516c77SSepherosa Ziehau 
410115516c77SSepherosa Ziehau 	/*
410215516c77SSepherosa Ziehau 	 * Make sure that all pending management tasks are completed.
410315516c77SSepherosa Ziehau 	 */
410415516c77SSepherosa Ziehau 	taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init);
410515516c77SSepherosa Ziehau 	taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status);
410615516c77SSepherosa Ziehau 	taskqueue_drain_all(sc->hn_mgmt_taskq0);
410715516c77SSepherosa Ziehau }
410815516c77SSepherosa Ziehau 
410915516c77SSepherosa Ziehau static void
411015516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc)
411115516c77SSepherosa Ziehau {
411215516c77SSepherosa Ziehau 
411315516c77SSepherosa Ziehau 	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
411415516c77SSepherosa Ziehau 		hn_suspend_data(sc);
411515516c77SSepherosa Ziehau 	hn_suspend_mgmt(sc);
411615516c77SSepherosa Ziehau }
411715516c77SSepherosa Ziehau 
411815516c77SSepherosa Ziehau static void
411915516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt)
412015516c77SSepherosa Ziehau {
412115516c77SSepherosa Ziehau 	int i;
412215516c77SSepherosa Ziehau 
412315516c77SSepherosa Ziehau 	KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt,
412415516c77SSepherosa Ziehau 	    ("invalid TX ring count %d", tx_ring_cnt));
412515516c77SSepherosa Ziehau 
412615516c77SSepherosa Ziehau 	for (i = 0; i < tx_ring_cnt; ++i) {
412715516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
412815516c77SSepherosa Ziehau 
412915516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
413015516c77SSepherosa Ziehau 		txr->hn_suspended = 0;
413115516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
413215516c77SSepherosa Ziehau 	}
413315516c77SSepherosa Ziehau }
413415516c77SSepherosa Ziehau 
413515516c77SSepherosa Ziehau static void
413615516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc)
413715516c77SSepherosa Ziehau {
413815516c77SSepherosa Ziehau 	int i;
413915516c77SSepherosa Ziehau 
414015516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
414115516c77SSepherosa Ziehau 
414215516c77SSepherosa Ziehau 	/*
414315516c77SSepherosa Ziehau 	 * Re-enable RX.
414415516c77SSepherosa Ziehau 	 */
414515516c77SSepherosa Ziehau 	hn_set_rxfilter(sc);
414615516c77SSepherosa Ziehau 
414715516c77SSepherosa Ziehau 	/*
414815516c77SSepherosa Ziehau 	 * Make sure to clear suspend status on "all" TX rings,
414915516c77SSepherosa Ziehau 	 * since hn_tx_ring_inuse can be changed after
415015516c77SSepherosa Ziehau 	 * hn_suspend_data().
415115516c77SSepherosa Ziehau 	 */
415215516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_cnt);
415315516c77SSepherosa Ziehau 
415423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
415523bf9e15SSepherosa Ziehau 	if (!hn_use_if_start)
415623bf9e15SSepherosa Ziehau #endif
415723bf9e15SSepherosa Ziehau 	{
415815516c77SSepherosa Ziehau 		/*
415915516c77SSepherosa Ziehau 		 * Flush unused drbrs, since hn_tx_ring_inuse may be
416015516c77SSepherosa Ziehau 		 * reduced.
416115516c77SSepherosa Ziehau 		 */
416215516c77SSepherosa Ziehau 		for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i)
416315516c77SSepherosa Ziehau 			hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
416415516c77SSepherosa Ziehau 	}
416515516c77SSepherosa Ziehau 
416615516c77SSepherosa Ziehau 	/*
416715516c77SSepherosa Ziehau 	 * Kick start TX.
416815516c77SSepherosa Ziehau 	 */
416915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
417015516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
417115516c77SSepherosa Ziehau 
417215516c77SSepherosa Ziehau 		/*
417315516c77SSepherosa Ziehau 		 * Use txeof task, so that any pending oactive can be
417415516c77SSepherosa Ziehau 		 * cleared properly.
417515516c77SSepherosa Ziehau 		 */
417615516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
417715516c77SSepherosa Ziehau 	}
417815516c77SSepherosa Ziehau }
417915516c77SSepherosa Ziehau 
418015516c77SSepherosa Ziehau static void
418115516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc)
418215516c77SSepherosa Ziehau {
418315516c77SSepherosa Ziehau 
418415516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
418515516c77SSepherosa Ziehau 
418615516c77SSepherosa Ziehau 	/*
418715516c77SSepherosa Ziehau 	 * Kick off network change detection, if it was pending.
418815516c77SSepherosa Ziehau 	 * If no network change was pending, start link status
418915516c77SSepherosa Ziehau 	 * checks, which is more lightweight than network change
419015516c77SSepherosa Ziehau 	 * detection.
419115516c77SSepherosa Ziehau 	 */
419215516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
419315516c77SSepherosa Ziehau 		hn_change_network(sc);
419415516c77SSepherosa Ziehau 	else
419515516c77SSepherosa Ziehau 		hn_update_link_status(sc);
419615516c77SSepherosa Ziehau }
419715516c77SSepherosa Ziehau 
419815516c77SSepherosa Ziehau static void
419915516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc)
420015516c77SSepherosa Ziehau {
420115516c77SSepherosa Ziehau 
420215516c77SSepherosa Ziehau 	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
420315516c77SSepherosa Ziehau 		hn_resume_data(sc);
420415516c77SSepherosa Ziehau 	hn_resume_mgmt(sc);
420515516c77SSepherosa Ziehau }
420615516c77SSepherosa Ziehau 
420715516c77SSepherosa Ziehau static void
420815516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen)
420915516c77SSepherosa Ziehau {
421015516c77SSepherosa Ziehau 	const struct rndis_status_msg *msg;
421115516c77SSepherosa Ziehau 	int ofs;
421215516c77SSepherosa Ziehau 
421315516c77SSepherosa Ziehau 	if (dlen < sizeof(*msg)) {
421415516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid RNDIS status\n");
421515516c77SSepherosa Ziehau 		return;
421615516c77SSepherosa Ziehau 	}
421715516c77SSepherosa Ziehau 	msg = data;
421815516c77SSepherosa Ziehau 
421915516c77SSepherosa Ziehau 	switch (msg->rm_status) {
422015516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_CONNECT:
422115516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_DISCONNECT:
422215516c77SSepherosa Ziehau 		hn_update_link_status(sc);
422315516c77SSepherosa Ziehau 		break;
422415516c77SSepherosa Ziehau 
422515516c77SSepherosa Ziehau 	case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
422615516c77SSepherosa Ziehau 		/* Not really useful; ignore. */
422715516c77SSepherosa Ziehau 		break;
422815516c77SSepherosa Ziehau 
422915516c77SSepherosa Ziehau 	case RNDIS_STATUS_NETWORK_CHANGE:
423015516c77SSepherosa Ziehau 		ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
423115516c77SSepherosa Ziehau 		if (dlen < ofs + msg->rm_stbuflen ||
423215516c77SSepherosa Ziehau 		    msg->rm_stbuflen < sizeof(uint32_t)) {
423315516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed\n");
423415516c77SSepherosa Ziehau 		} else {
423515516c77SSepherosa Ziehau 			uint32_t change;
423615516c77SSepherosa Ziehau 
423715516c77SSepherosa Ziehau 			memcpy(&change, ((const uint8_t *)msg) + ofs,
423815516c77SSepherosa Ziehau 			    sizeof(change));
423915516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed, change %u\n",
424015516c77SSepherosa Ziehau 			    change);
424115516c77SSepherosa Ziehau 		}
424215516c77SSepherosa Ziehau 		hn_change_network(sc);
424315516c77SSepherosa Ziehau 		break;
424415516c77SSepherosa Ziehau 
424515516c77SSepherosa Ziehau 	default:
424615516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
424715516c77SSepherosa Ziehau 		    msg->rm_status);
424815516c77SSepherosa Ziehau 		break;
424915516c77SSepherosa Ziehau 	}
425015516c77SSepherosa Ziehau }
425115516c77SSepherosa Ziehau 
425215516c77SSepherosa Ziehau static int
425315516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info)
425415516c77SSepherosa Ziehau {
425515516c77SSepherosa Ziehau 	const struct rndis_pktinfo *pi = info_data;
425615516c77SSepherosa Ziehau 	uint32_t mask = 0;
425715516c77SSepherosa Ziehau 
425815516c77SSepherosa Ziehau 	while (info_dlen != 0) {
425915516c77SSepherosa Ziehau 		const void *data;
426015516c77SSepherosa Ziehau 		uint32_t dlen;
426115516c77SSepherosa Ziehau 
426215516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < sizeof(*pi)))
426315516c77SSepherosa Ziehau 			return (EINVAL);
426415516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < pi->rm_size))
426515516c77SSepherosa Ziehau 			return (EINVAL);
426615516c77SSepherosa Ziehau 		info_dlen -= pi->rm_size;
426715516c77SSepherosa Ziehau 
426815516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
426915516c77SSepherosa Ziehau 			return (EINVAL);
427015516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
427115516c77SSepherosa Ziehau 			return (EINVAL);
427215516c77SSepherosa Ziehau 		dlen = pi->rm_size - pi->rm_pktinfooffset;
427315516c77SSepherosa Ziehau 		data = pi->rm_data;
427415516c77SSepherosa Ziehau 
427515516c77SSepherosa Ziehau 		switch (pi->rm_type) {
427615516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_VLAN:
427715516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
427815516c77SSepherosa Ziehau 				return (EINVAL);
427915516c77SSepherosa Ziehau 			info->vlan_info = *((const uint32_t *)data);
428015516c77SSepherosa Ziehau 			mask |= HN_RXINFO_VLAN;
428115516c77SSepherosa Ziehau 			break;
428215516c77SSepherosa Ziehau 
428315516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_CSUM:
428415516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
428515516c77SSepherosa Ziehau 				return (EINVAL);
428615516c77SSepherosa Ziehau 			info->csum_info = *((const uint32_t *)data);
428715516c77SSepherosa Ziehau 			mask |= HN_RXINFO_CSUM;
428815516c77SSepherosa Ziehau 			break;
428915516c77SSepherosa Ziehau 
429015516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHVAL:
429115516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
429215516c77SSepherosa Ziehau 				return (EINVAL);
429315516c77SSepherosa Ziehau 			info->hash_value = *((const uint32_t *)data);
429415516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHVAL;
429515516c77SSepherosa Ziehau 			break;
429615516c77SSepherosa Ziehau 
429715516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHINF:
429815516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
429915516c77SSepherosa Ziehau 				return (EINVAL);
430015516c77SSepherosa Ziehau 			info->hash_info = *((const uint32_t *)data);
430115516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHINF;
430215516c77SSepherosa Ziehau 			break;
430315516c77SSepherosa Ziehau 
430415516c77SSepherosa Ziehau 		default:
430515516c77SSepherosa Ziehau 			goto next;
430615516c77SSepherosa Ziehau 		}
430715516c77SSepherosa Ziehau 
430815516c77SSepherosa Ziehau 		if (mask == HN_RXINFO_ALL) {
430915516c77SSepherosa Ziehau 			/* All found; done */
431015516c77SSepherosa Ziehau 			break;
431115516c77SSepherosa Ziehau 		}
431215516c77SSepherosa Ziehau next:
431315516c77SSepherosa Ziehau 		pi = (const struct rndis_pktinfo *)
431415516c77SSepherosa Ziehau 		    ((const uint8_t *)pi + pi->rm_size);
431515516c77SSepherosa Ziehau 	}
431615516c77SSepherosa Ziehau 
431715516c77SSepherosa Ziehau 	/*
431815516c77SSepherosa Ziehau 	 * Final fixup.
431915516c77SSepherosa Ziehau 	 * - If there is no hash value, invalidate the hash info.
432015516c77SSepherosa Ziehau 	 */
432115516c77SSepherosa Ziehau 	if ((mask & HN_RXINFO_HASHVAL) == 0)
432215516c77SSepherosa Ziehau 		info->hash_info = HN_NDIS_HASH_INFO_INVALID;
432315516c77SSepherosa Ziehau 	return (0);
432415516c77SSepherosa Ziehau }
432515516c77SSepherosa Ziehau 
432615516c77SSepherosa Ziehau static __inline bool
432715516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
432815516c77SSepherosa Ziehau {
432915516c77SSepherosa Ziehau 
433015516c77SSepherosa Ziehau 	if (off < check_off) {
433115516c77SSepherosa Ziehau 		if (__predict_true(off + len <= check_off))
433215516c77SSepherosa Ziehau 			return (false);
433315516c77SSepherosa Ziehau 	} else if (off > check_off) {
433415516c77SSepherosa Ziehau 		if (__predict_true(check_off + check_len <= off))
433515516c77SSepherosa Ziehau 			return (false);
433615516c77SSepherosa Ziehau 	}
433715516c77SSepherosa Ziehau 	return (true);
433815516c77SSepherosa Ziehau }
433915516c77SSepherosa Ziehau 
434015516c77SSepherosa Ziehau static void
434115516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen)
434215516c77SSepherosa Ziehau {
434315516c77SSepherosa Ziehau 	const struct rndis_packet_msg *pkt;
434415516c77SSepherosa Ziehau 	struct hn_rxinfo info;
434515516c77SSepherosa Ziehau 	int data_off, pktinfo_off, data_len, pktinfo_len;
434615516c77SSepherosa Ziehau 
434715516c77SSepherosa Ziehau 	/*
434815516c77SSepherosa Ziehau 	 * Check length.
434915516c77SSepherosa Ziehau 	 */
435015516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*pkt))) {
435115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
435215516c77SSepherosa Ziehau 		return;
435315516c77SSepherosa Ziehau 	}
435415516c77SSepherosa Ziehau 	pkt = data;
435515516c77SSepherosa Ziehau 
435615516c77SSepherosa Ziehau 	if (__predict_false(dlen < pkt->rm_len)) {
435715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
435815516c77SSepherosa Ziehau 		    "dlen %d, msglen %u\n", dlen, pkt->rm_len);
435915516c77SSepherosa Ziehau 		return;
436015516c77SSepherosa Ziehau 	}
436115516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_len <
436215516c77SSepherosa Ziehau 	    pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
436315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
436415516c77SSepherosa Ziehau 		    "msglen %u, data %u, oob %u, pktinfo %u\n",
436515516c77SSepherosa Ziehau 		    pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
436615516c77SSepherosa Ziehau 		    pkt->rm_pktinfolen);
436715516c77SSepherosa Ziehau 		return;
436815516c77SSepherosa Ziehau 	}
436915516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_datalen == 0)) {
437015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
437115516c77SSepherosa Ziehau 		return;
437215516c77SSepherosa Ziehau 	}
437315516c77SSepherosa Ziehau 
437415516c77SSepherosa Ziehau 	/*
437515516c77SSepherosa Ziehau 	 * Check offests.
437615516c77SSepherosa Ziehau 	 */
437715516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs)			\
437815516c77SSepherosa Ziehau 	((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN ||	\
437915516c77SSepherosa Ziehau 	 ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
438015516c77SSepherosa Ziehau 
438115516c77SSepherosa Ziehau 	/* XXX Hyper-V does not meet data offset alignment requirement */
438215516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
438315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
438415516c77SSepherosa Ziehau 		    "data offset %u\n", pkt->rm_dataoffset);
438515516c77SSepherosa Ziehau 		return;
438615516c77SSepherosa Ziehau 	}
438715516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdataoffset > 0 &&
438815516c77SSepherosa Ziehau 	    IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
438915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
439015516c77SSepherosa Ziehau 		    "oob offset %u\n", pkt->rm_oobdataoffset);
439115516c77SSepherosa Ziehau 		return;
439215516c77SSepherosa Ziehau 	}
439315516c77SSepherosa Ziehau 	if (__predict_true(pkt->rm_pktinfooffset > 0) &&
439415516c77SSepherosa Ziehau 	    __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
439515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
439615516c77SSepherosa Ziehau 		    "pktinfo offset %u\n", pkt->rm_pktinfooffset);
439715516c77SSepherosa Ziehau 		return;
439815516c77SSepherosa Ziehau 	}
439915516c77SSepherosa Ziehau 
440015516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID
440115516c77SSepherosa Ziehau 
440215516c77SSepherosa Ziehau 	data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
440315516c77SSepherosa Ziehau 	data_len = pkt->rm_datalen;
440415516c77SSepherosa Ziehau 	pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
440515516c77SSepherosa Ziehau 	pktinfo_len = pkt->rm_pktinfolen;
440615516c77SSepherosa Ziehau 
440715516c77SSepherosa Ziehau 	/*
440815516c77SSepherosa Ziehau 	 * Check OOB coverage.
440915516c77SSepherosa Ziehau 	 */
441015516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdatalen != 0)) {
441115516c77SSepherosa Ziehau 		int oob_off, oob_len;
441215516c77SSepherosa Ziehau 
441315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "got oobdata\n");
441415516c77SSepherosa Ziehau 		oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
441515516c77SSepherosa Ziehau 		oob_len = pkt->rm_oobdatalen;
441615516c77SSepherosa Ziehau 
441715516c77SSepherosa Ziehau 		if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
441815516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
441915516c77SSepherosa Ziehau 			    "oob overflow, msglen %u, oob abs %d len %d\n",
442015516c77SSepherosa Ziehau 			    pkt->rm_len, oob_off, oob_len);
442115516c77SSepherosa Ziehau 			return;
442215516c77SSepherosa Ziehau 		}
442315516c77SSepherosa Ziehau 
442415516c77SSepherosa Ziehau 		/*
442515516c77SSepherosa Ziehau 		 * Check against data.
442615516c77SSepherosa Ziehau 		 */
442715516c77SSepherosa Ziehau 		if (hn_rndis_check_overlap(oob_off, oob_len,
442815516c77SSepherosa Ziehau 		    data_off, data_len)) {
442915516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
443015516c77SSepherosa Ziehau 			    "oob overlaps data, oob abs %d len %d, "
443115516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
443215516c77SSepherosa Ziehau 			    oob_off, oob_len, data_off, data_len);
443315516c77SSepherosa Ziehau 			return;
443415516c77SSepherosa Ziehau 		}
443515516c77SSepherosa Ziehau 
443615516c77SSepherosa Ziehau 		/*
443715516c77SSepherosa Ziehau 		 * Check against pktinfo.
443815516c77SSepherosa Ziehau 		 */
443915516c77SSepherosa Ziehau 		if (pktinfo_len != 0 &&
444015516c77SSepherosa Ziehau 		    hn_rndis_check_overlap(oob_off, oob_len,
444115516c77SSepherosa Ziehau 		    pktinfo_off, pktinfo_len)) {
444215516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
444315516c77SSepherosa Ziehau 			    "oob overlaps pktinfo, oob abs %d len %d, "
444415516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
444515516c77SSepherosa Ziehau 			    oob_off, oob_len, pktinfo_off, pktinfo_len);
444615516c77SSepherosa Ziehau 			return;
444715516c77SSepherosa Ziehau 		}
444815516c77SSepherosa Ziehau 	}
444915516c77SSepherosa Ziehau 
445015516c77SSepherosa Ziehau 	/*
445115516c77SSepherosa Ziehau 	 * Check per-packet-info coverage and find useful per-packet-info.
445215516c77SSepherosa Ziehau 	 */
445315516c77SSepherosa Ziehau 	info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
445415516c77SSepherosa Ziehau 	info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
445515516c77SSepherosa Ziehau 	info.hash_info = HN_NDIS_HASH_INFO_INVALID;
445615516c77SSepherosa Ziehau 	if (__predict_true(pktinfo_len != 0)) {
445715516c77SSepherosa Ziehau 		bool overlap;
445815516c77SSepherosa Ziehau 		int error;
445915516c77SSepherosa Ziehau 
446015516c77SSepherosa Ziehau 		if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
446115516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
446215516c77SSepherosa Ziehau 			    "pktinfo overflow, msglen %u, "
446315516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
446415516c77SSepherosa Ziehau 			    pkt->rm_len, pktinfo_off, pktinfo_len);
446515516c77SSepherosa Ziehau 			return;
446615516c77SSepherosa Ziehau 		}
446715516c77SSepherosa Ziehau 
446815516c77SSepherosa Ziehau 		/*
446915516c77SSepherosa Ziehau 		 * Check packet info coverage.
447015516c77SSepherosa Ziehau 		 */
447115516c77SSepherosa Ziehau 		overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
447215516c77SSepherosa Ziehau 		    data_off, data_len);
447315516c77SSepherosa Ziehau 		if (__predict_false(overlap)) {
447415516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
447515516c77SSepherosa Ziehau 			    "pktinfo overlap data, pktinfo abs %d len %d, "
447615516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
447715516c77SSepherosa Ziehau 			    pktinfo_off, pktinfo_len, data_off, data_len);
447815516c77SSepherosa Ziehau 			return;
447915516c77SSepherosa Ziehau 		}
448015516c77SSepherosa Ziehau 
448115516c77SSepherosa Ziehau 		/*
448215516c77SSepherosa Ziehau 		 * Find useful per-packet-info.
448315516c77SSepherosa Ziehau 		 */
448415516c77SSepherosa Ziehau 		error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
448515516c77SSepherosa Ziehau 		    pktinfo_len, &info);
448615516c77SSepherosa Ziehau 		if (__predict_false(error)) {
448715516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
448815516c77SSepherosa Ziehau 			    "pktinfo\n");
448915516c77SSepherosa Ziehau 			return;
449015516c77SSepherosa Ziehau 		}
449115516c77SSepherosa Ziehau 	}
449215516c77SSepherosa Ziehau 
449315516c77SSepherosa Ziehau 	if (__predict_false(data_off + data_len > pkt->rm_len)) {
449415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
449515516c77SSepherosa Ziehau 		    "data overflow, msglen %u, data abs %d len %d\n",
449615516c77SSepherosa Ziehau 		    pkt->rm_len, data_off, data_len);
449715516c77SSepherosa Ziehau 		return;
449815516c77SSepherosa Ziehau 	}
449915516c77SSepherosa Ziehau 	hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
450015516c77SSepherosa Ziehau }
450115516c77SSepherosa Ziehau 
450215516c77SSepherosa Ziehau static __inline void
450315516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen)
450415516c77SSepherosa Ziehau {
450515516c77SSepherosa Ziehau 	const struct rndis_msghdr *hdr;
450615516c77SSepherosa Ziehau 
450715516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*hdr))) {
450815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
450915516c77SSepherosa Ziehau 		return;
451015516c77SSepherosa Ziehau 	}
451115516c77SSepherosa Ziehau 	hdr = data;
451215516c77SSepherosa Ziehau 
451315516c77SSepherosa Ziehau 	if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) {
451415516c77SSepherosa Ziehau 		/* Hot data path. */
451515516c77SSepherosa Ziehau 		hn_rndis_rx_data(rxr, data, dlen);
451615516c77SSepherosa Ziehau 		/* Done! */
451715516c77SSepherosa Ziehau 		return;
451815516c77SSepherosa Ziehau 	}
451915516c77SSepherosa Ziehau 
452015516c77SSepherosa Ziehau 	if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG)
452115516c77SSepherosa Ziehau 		hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen);
452215516c77SSepherosa Ziehau 	else
452315516c77SSepherosa Ziehau 		hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen);
452415516c77SSepherosa Ziehau }
452515516c77SSepherosa Ziehau 
452615516c77SSepherosa Ziehau static void
452715516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
452815516c77SSepherosa Ziehau {
452915516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *hdr;
453015516c77SSepherosa Ziehau 
453115516c77SSepherosa Ziehau 	if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) {
453215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid nvs notify\n");
453315516c77SSepherosa Ziehau 		return;
453415516c77SSepherosa Ziehau 	}
453515516c77SSepherosa Ziehau 	hdr = VMBUS_CHANPKT_CONST_DATA(pkt);
453615516c77SSepherosa Ziehau 
453715516c77SSepherosa Ziehau 	if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) {
453815516c77SSepherosa Ziehau 		/* Useless; ignore */
453915516c77SSepherosa Ziehau 		return;
454015516c77SSepherosa Ziehau 	}
454115516c77SSepherosa Ziehau 	if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type);
454215516c77SSepherosa Ziehau }
454315516c77SSepherosa Ziehau 
454415516c77SSepherosa Ziehau static void
454515516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan,
454615516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkt)
454715516c77SSepherosa Ziehau {
454815516c77SSepherosa Ziehau 	struct hn_nvs_sendctx *sndc;
454915516c77SSepherosa Ziehau 
455015516c77SSepherosa Ziehau 	sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid;
455115516c77SSepherosa Ziehau 	sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt),
455215516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_DATALEN(pkt));
455315516c77SSepherosa Ziehau 	/*
455415516c77SSepherosa Ziehau 	 * NOTE:
455515516c77SSepherosa Ziehau 	 * 'sndc' CAN NOT be accessed anymore, since it can be freed by
455615516c77SSepherosa Ziehau 	 * its callback.
455715516c77SSepherosa Ziehau 	 */
455815516c77SSepherosa Ziehau }
455915516c77SSepherosa Ziehau 
456015516c77SSepherosa Ziehau static void
456115516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
456215516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkthdr)
456315516c77SSepherosa Ziehau {
456415516c77SSepherosa Ziehau 	const struct vmbus_chanpkt_rxbuf *pkt;
456515516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *nvs_hdr;
456615516c77SSepherosa Ziehau 	int count, i, hlen;
456715516c77SSepherosa Ziehau 
456815516c77SSepherosa Ziehau 	if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) {
456915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n");
457015516c77SSepherosa Ziehau 		return;
457115516c77SSepherosa Ziehau 	}
457215516c77SSepherosa Ziehau 	nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr);
457315516c77SSepherosa Ziehau 
457415516c77SSepherosa Ziehau 	/* Make sure that this is a RNDIS message. */
457515516c77SSepherosa Ziehau 	if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) {
457615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n",
457715516c77SSepherosa Ziehau 		    nvs_hdr->nvs_type);
457815516c77SSepherosa Ziehau 		return;
457915516c77SSepherosa Ziehau 	}
458015516c77SSepherosa Ziehau 
458115516c77SSepherosa Ziehau 	hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen);
458215516c77SSepherosa Ziehau 	if (__predict_false(hlen < sizeof(*pkt))) {
458315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n");
458415516c77SSepherosa Ziehau 		return;
458515516c77SSepherosa Ziehau 	}
458615516c77SSepherosa Ziehau 	pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
458715516c77SSepherosa Ziehau 
458815516c77SSepherosa Ziehau 	if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) {
458915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n",
459015516c77SSepherosa Ziehau 		    pkt->cp_rxbuf_id);
459115516c77SSepherosa Ziehau 		return;
459215516c77SSepherosa Ziehau 	}
459315516c77SSepherosa Ziehau 
459415516c77SSepherosa Ziehau 	count = pkt->cp_rxbuf_cnt;
459515516c77SSepherosa Ziehau 	if (__predict_false(hlen <
459615516c77SSepherosa Ziehau 	    __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) {
459715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count);
459815516c77SSepherosa Ziehau 		return;
459915516c77SSepherosa Ziehau 	}
460015516c77SSepherosa Ziehau 
460115516c77SSepherosa Ziehau 	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
460215516c77SSepherosa Ziehau 	for (i = 0; i < count; ++i) {
460315516c77SSepherosa Ziehau 		int ofs, len;
460415516c77SSepherosa Ziehau 
460515516c77SSepherosa Ziehau 		ofs = pkt->cp_rxbuf[i].rb_ofs;
460615516c77SSepherosa Ziehau 		len = pkt->cp_rxbuf[i].rb_len;
460715516c77SSepherosa Ziehau 		if (__predict_false(ofs + len > HN_RXBUF_SIZE)) {
460815516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, "
460915516c77SSepherosa Ziehau 			    "ofs %d, len %d\n", i, ofs, len);
461015516c77SSepherosa Ziehau 			continue;
461115516c77SSepherosa Ziehau 		}
461215516c77SSepherosa Ziehau 		hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len);
461315516c77SSepherosa Ziehau 	}
461415516c77SSepherosa Ziehau 
461515516c77SSepherosa Ziehau 	/*
461615516c77SSepherosa Ziehau 	 * Ack the consumed RXBUF associated w/ this channel packet,
461715516c77SSepherosa Ziehau 	 * so that this RXBUF can be recycled by the hypervisor.
461815516c77SSepherosa Ziehau 	 */
461915516c77SSepherosa Ziehau 	hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid);
462015516c77SSepherosa Ziehau }
462115516c77SSepherosa Ziehau 
462215516c77SSepherosa Ziehau static void
462315516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
462415516c77SSepherosa Ziehau     uint64_t tid)
462515516c77SSepherosa Ziehau {
462615516c77SSepherosa Ziehau 	struct hn_nvs_rndis_ack ack;
462715516c77SSepherosa Ziehau 	int retries, error;
462815516c77SSepherosa Ziehau 
462915516c77SSepherosa Ziehau 	ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK;
463015516c77SSepherosa Ziehau 	ack.nvs_status = HN_NVS_STATUS_OK;
463115516c77SSepherosa Ziehau 
463215516c77SSepherosa Ziehau 	retries = 0;
463315516c77SSepherosa Ziehau again:
463415516c77SSepherosa Ziehau 	error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP,
463515516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid);
463615516c77SSepherosa Ziehau 	if (__predict_false(error == EAGAIN)) {
463715516c77SSepherosa Ziehau 		/*
463815516c77SSepherosa Ziehau 		 * NOTE:
463915516c77SSepherosa Ziehau 		 * This should _not_ happen in real world, since the
464015516c77SSepherosa Ziehau 		 * consumption of the TX bufring from the TX path is
464115516c77SSepherosa Ziehau 		 * controlled.
464215516c77SSepherosa Ziehau 		 */
464315516c77SSepherosa Ziehau 		if (rxr->hn_ack_failed == 0)
464415516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "RXBUF ack retry\n");
464515516c77SSepherosa Ziehau 		rxr->hn_ack_failed++;
464615516c77SSepherosa Ziehau 		retries++;
464715516c77SSepherosa Ziehau 		if (retries < 10) {
464815516c77SSepherosa Ziehau 			DELAY(100);
464915516c77SSepherosa Ziehau 			goto again;
465015516c77SSepherosa Ziehau 		}
465115516c77SSepherosa Ziehau 		/* RXBUF leaks! */
465215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "RXBUF ack failed\n");
465315516c77SSepherosa Ziehau 	}
465415516c77SSepherosa Ziehau }
465515516c77SSepherosa Ziehau 
465615516c77SSepherosa Ziehau static void
465715516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr)
465815516c77SSepherosa Ziehau {
465915516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr = xrxr;
466015516c77SSepherosa Ziehau 	struct hn_softc *sc = rxr->hn_ifp->if_softc;
466115516c77SSepherosa Ziehau 
466215516c77SSepherosa Ziehau 	for (;;) {
466315516c77SSepherosa Ziehau 		struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf;
466415516c77SSepherosa Ziehau 		int error, pktlen;
466515516c77SSepherosa Ziehau 
466615516c77SSepherosa Ziehau 		pktlen = rxr->hn_pktbuf_len;
466715516c77SSepherosa Ziehau 		error = vmbus_chan_recv_pkt(chan, pkt, &pktlen);
466815516c77SSepherosa Ziehau 		if (__predict_false(error == ENOBUFS)) {
466915516c77SSepherosa Ziehau 			void *nbuf;
467015516c77SSepherosa Ziehau 			int nlen;
467115516c77SSepherosa Ziehau 
467215516c77SSepherosa Ziehau 			/*
467315516c77SSepherosa Ziehau 			 * Expand channel packet buffer.
467415516c77SSepherosa Ziehau 			 *
467515516c77SSepherosa Ziehau 			 * XXX
467615516c77SSepherosa Ziehau 			 * Use M_WAITOK here, since allocation failure
467715516c77SSepherosa Ziehau 			 * is fatal.
467815516c77SSepherosa Ziehau 			 */
467915516c77SSepherosa Ziehau 			nlen = rxr->hn_pktbuf_len * 2;
468015516c77SSepherosa Ziehau 			while (nlen < pktlen)
468115516c77SSepherosa Ziehau 				nlen *= 2;
468215516c77SSepherosa Ziehau 			nbuf = malloc(nlen, M_DEVBUF, M_WAITOK);
468315516c77SSepherosa Ziehau 
468415516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n",
468515516c77SSepherosa Ziehau 			    rxr->hn_pktbuf_len, nlen);
468615516c77SSepherosa Ziehau 
468715516c77SSepherosa Ziehau 			free(rxr->hn_pktbuf, M_DEVBUF);
468815516c77SSepherosa Ziehau 			rxr->hn_pktbuf = nbuf;
468915516c77SSepherosa Ziehau 			rxr->hn_pktbuf_len = nlen;
469015516c77SSepherosa Ziehau 			/* Retry! */
469115516c77SSepherosa Ziehau 			continue;
469215516c77SSepherosa Ziehau 		} else if (__predict_false(error == EAGAIN)) {
469315516c77SSepherosa Ziehau 			/* No more channel packets; done! */
469415516c77SSepherosa Ziehau 			break;
469515516c77SSepherosa Ziehau 		}
469615516c77SSepherosa Ziehau 		KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error));
469715516c77SSepherosa Ziehau 
469815516c77SSepherosa Ziehau 		switch (pkt->cph_type) {
469915516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_COMP:
470015516c77SSepherosa Ziehau 			hn_nvs_handle_comp(sc, chan, pkt);
470115516c77SSepherosa Ziehau 			break;
470215516c77SSepherosa Ziehau 
470315516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_RXBUF:
470415516c77SSepherosa Ziehau 			hn_nvs_handle_rxbuf(rxr, chan, pkt);
470515516c77SSepherosa Ziehau 			break;
470615516c77SSepherosa Ziehau 
470715516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_INBAND:
470815516c77SSepherosa Ziehau 			hn_nvs_handle_notify(sc, pkt);
470915516c77SSepherosa Ziehau 			break;
471015516c77SSepherosa Ziehau 
471115516c77SSepherosa Ziehau 		default:
471215516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "unknown chan pkt %u\n",
471315516c77SSepherosa Ziehau 			    pkt->cph_type);
471415516c77SSepherosa Ziehau 			break;
471515516c77SSepherosa Ziehau 		}
471615516c77SSepherosa Ziehau 	}
471715516c77SSepherosa Ziehau 	hn_chan_rollup(rxr, rxr->hn_txr);
471815516c77SSepherosa Ziehau }
471915516c77SSepherosa Ziehau 
472015516c77SSepherosa Ziehau static void
472115516c77SSepherosa Ziehau hn_tx_taskq_create(void *arg __unused)
472215516c77SSepherosa Ziehau {
472315516c77SSepherosa Ziehau 
472415516c77SSepherosa Ziehau 	if (vm_guest != VM_GUEST_HV)
472515516c77SSepherosa Ziehau 		return;
472615516c77SSepherosa Ziehau 
472715516c77SSepherosa Ziehau 	if (!hn_share_tx_taskq)
472815516c77SSepherosa Ziehau 		return;
472915516c77SSepherosa Ziehau 
473015516c77SSepherosa Ziehau 	hn_tx_taskq = taskqueue_create("hn_tx", M_WAITOK,
473115516c77SSepherosa Ziehau 	    taskqueue_thread_enqueue, &hn_tx_taskq);
473215516c77SSepherosa Ziehau 	if (hn_bind_tx_taskq >= 0) {
473315516c77SSepherosa Ziehau 		int cpu = hn_bind_tx_taskq;
473415516c77SSepherosa Ziehau 		cpuset_t cpu_set;
473515516c77SSepherosa Ziehau 
473615516c77SSepherosa Ziehau 		if (cpu > mp_ncpus - 1)
473715516c77SSepherosa Ziehau 			cpu = mp_ncpus - 1;
473815516c77SSepherosa Ziehau 		CPU_SETOF(cpu, &cpu_set);
473915516c77SSepherosa Ziehau 		taskqueue_start_threads_cpuset(&hn_tx_taskq, 1, PI_NET,
474015516c77SSepherosa Ziehau 		    &cpu_set, "hn tx");
474115516c77SSepherosa Ziehau 	} else {
474215516c77SSepherosa Ziehau 		taskqueue_start_threads(&hn_tx_taskq, 1, PI_NET, "hn tx");
474315516c77SSepherosa Ziehau 	}
474415516c77SSepherosa Ziehau }
474515516c77SSepherosa Ziehau SYSINIT(hn_txtq_create, SI_SUB_DRIVERS, SI_ORDER_SECOND,
474615516c77SSepherosa Ziehau     hn_tx_taskq_create, NULL);
474715516c77SSepherosa Ziehau 
474815516c77SSepherosa Ziehau static void
474915516c77SSepherosa Ziehau hn_tx_taskq_destroy(void *arg __unused)
475015516c77SSepherosa Ziehau {
475115516c77SSepherosa Ziehau 
475215516c77SSepherosa Ziehau 	if (hn_tx_taskq != NULL)
475315516c77SSepherosa Ziehau 		taskqueue_free(hn_tx_taskq);
475415516c77SSepherosa Ziehau }
475515516c77SSepherosa Ziehau SYSUNINIT(hn_txtq_destroy, SI_SUB_DRIVERS, SI_ORDER_SECOND,
475615516c77SSepherosa Ziehau     hn_tx_taskq_destroy, NULL);
4757