xref: /freebsd/sys/dev/hyperv/netvsc/if_hn.c (revision 34d68912be15861a2f30b224fc353dd0e5830664)
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 
58*34d68912SSepherosa Ziehau #include "opt_hn.h"
5915516c77SSepherosa Ziehau #include "opt_inet6.h"
6015516c77SSepherosa Ziehau #include "opt_inet.h"
61*34d68912SSepherosa Ziehau #include "opt_rss.h"
6215516c77SSepherosa Ziehau 
6315516c77SSepherosa Ziehau #include <sys/param.h>
6415516c77SSepherosa Ziehau #include <sys/bus.h>
6515516c77SSepherosa Ziehau #include <sys/kernel.h>
6615516c77SSepherosa Ziehau #include <sys/limits.h>
6715516c77SSepherosa Ziehau #include <sys/malloc.h>
6815516c77SSepherosa Ziehau #include <sys/mbuf.h>
6915516c77SSepherosa Ziehau #include <sys/module.h>
7015516c77SSepherosa Ziehau #include <sys/queue.h>
7115516c77SSepherosa Ziehau #include <sys/lock.h>
7215516c77SSepherosa Ziehau #include <sys/smp.h>
7315516c77SSepherosa Ziehau #include <sys/socket.h>
7415516c77SSepherosa Ziehau #include <sys/sockio.h>
7515516c77SSepherosa Ziehau #include <sys/sx.h>
7615516c77SSepherosa Ziehau #include <sys/sysctl.h>
7715516c77SSepherosa Ziehau #include <sys/systm.h>
7815516c77SSepherosa Ziehau #include <sys/taskqueue.h>
7915516c77SSepherosa Ziehau #include <sys/buf_ring.h>
8015516c77SSepherosa Ziehau 
8115516c77SSepherosa Ziehau #include <machine/atomic.h>
8215516c77SSepherosa Ziehau #include <machine/in_cksum.h>
8315516c77SSepherosa Ziehau 
8415516c77SSepherosa Ziehau #include <net/bpf.h>
8515516c77SSepherosa Ziehau #include <net/ethernet.h>
8615516c77SSepherosa Ziehau #include <net/if.h>
8715516c77SSepherosa Ziehau #include <net/if_media.h>
8815516c77SSepherosa Ziehau #include <net/if_types.h>
8915516c77SSepherosa Ziehau #include <net/if_var.h>
9015516c77SSepherosa Ziehau #include <net/rndis.h>
91*34d68912SSepherosa Ziehau #ifdef RSS
92*34d68912SSepherosa Ziehau #include <net/rss_config.h>
93*34d68912SSepherosa Ziehau #endif
9415516c77SSepherosa Ziehau 
9515516c77SSepherosa Ziehau #include <netinet/in_systm.h>
9615516c77SSepherosa Ziehau #include <netinet/in.h>
9715516c77SSepherosa Ziehau #include <netinet/ip.h>
9815516c77SSepherosa Ziehau #include <netinet/ip6.h>
9915516c77SSepherosa Ziehau #include <netinet/tcp.h>
10015516c77SSepherosa Ziehau #include <netinet/tcp_lro.h>
10115516c77SSepherosa Ziehau #include <netinet/udp.h>
10215516c77SSepherosa Ziehau 
10315516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h>
10415516c77SSepherosa Ziehau #include <dev/hyperv/include/hyperv_busdma.h>
10515516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus.h>
10615516c77SSepherosa Ziehau #include <dev/hyperv/include/vmbus_xact.h>
10715516c77SSepherosa Ziehau 
10815516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/ndis.h>
10915516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnreg.h>
11015516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/if_hnvar.h>
11115516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_nvs.h>
11215516c77SSepherosa Ziehau #include <dev/hyperv/netvsc/hn_rndis.h>
11315516c77SSepherosa Ziehau 
11415516c77SSepherosa Ziehau #include "vmbus_if.h"
11515516c77SSepherosa Ziehau 
11623bf9e15SSepherosa Ziehau #define HN_IFSTART_SUPPORT
11723bf9e15SSepherosa Ziehau 
11815516c77SSepherosa Ziehau #define HN_RING_CNT_DEF_MAX		8
11915516c77SSepherosa Ziehau 
12015516c77SSepherosa Ziehau /* YYY should get it from the underlying channel */
12115516c77SSepherosa Ziehau #define HN_TX_DESC_CNT			512
12215516c77SSepherosa Ziehau 
12315516c77SSepherosa Ziehau #define HN_RNDIS_PKT_LEN					\
12415516c77SSepherosa Ziehau 	(sizeof(struct rndis_packet_msg) +			\
12515516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) +	\
12615516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) +		\
12715516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) +		\
12815516c77SSepherosa Ziehau 	 HN_RNDIS_PKTINFO_SIZE(NDIS_TXCSUM_INFO_SIZE))
12915516c77SSepherosa Ziehau #define HN_RNDIS_PKT_BOUNDARY		PAGE_SIZE
13015516c77SSepherosa Ziehau #define HN_RNDIS_PKT_ALIGN		CACHE_LINE_SIZE
13115516c77SSepherosa Ziehau 
13215516c77SSepherosa Ziehau #define HN_TX_DATA_BOUNDARY		PAGE_SIZE
13315516c77SSepherosa Ziehau #define HN_TX_DATA_MAXSIZE		IP_MAXPACKET
13415516c77SSepherosa Ziehau #define HN_TX_DATA_SEGSIZE		PAGE_SIZE
13515516c77SSepherosa Ziehau /* -1 for RNDIS packet message */
13615516c77SSepherosa Ziehau #define HN_TX_DATA_SEGCNT_MAX		(HN_GPACNT_MAX - 1)
13715516c77SSepherosa Ziehau 
13815516c77SSepherosa Ziehau #define HN_DIRECT_TX_SIZE_DEF		128
13915516c77SSepherosa Ziehau 
14015516c77SSepherosa Ziehau #define HN_EARLY_TXEOF_THRESH		8
14115516c77SSepherosa Ziehau 
14215516c77SSepherosa Ziehau #define HN_PKTBUF_LEN_DEF		(16 * 1024)
14315516c77SSepherosa Ziehau 
14415516c77SSepherosa Ziehau #define HN_LROENT_CNT_DEF		128
14515516c77SSepherosa Ziehau 
14615516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MULTIRX_DEF	(12 * ETHERMTU)
14715516c77SSepherosa Ziehau #define HN_LRO_LENLIM_DEF		(25 * ETHERMTU)
14815516c77SSepherosa Ziehau /* YYY 2*MTU is a bit rough, but should be good enough. */
14915516c77SSepherosa Ziehau #define HN_LRO_LENLIM_MIN(ifp)		(2 * (ifp)->if_mtu)
15015516c77SSepherosa Ziehau 
15115516c77SSepherosa Ziehau #define HN_LRO_ACKCNT_DEF		1
15215516c77SSepherosa Ziehau 
15315516c77SSepherosa Ziehau #define HN_LOCK_INIT(sc)		\
15415516c77SSepherosa Ziehau 	sx_init(&(sc)->hn_lock, device_get_nameunit((sc)->hn_dev))
15515516c77SSepherosa Ziehau #define HN_LOCK_DESTROY(sc)		sx_destroy(&(sc)->hn_lock)
15615516c77SSepherosa Ziehau #define HN_LOCK_ASSERT(sc)		sx_assert(&(sc)->hn_lock, SA_XLOCKED)
157fdc4f478SSepherosa Ziehau #define HN_LOCK(sc)					\
158fdc4f478SSepherosa Ziehau do {							\
159fdc4f478SSepherosa Ziehau 	while (sx_try_xlock(&(sc)->hn_lock) == 0)	\
160fdc4f478SSepherosa Ziehau 		DELAY(1000);				\
161fdc4f478SSepherosa Ziehau } while (0)
16215516c77SSepherosa Ziehau #define HN_UNLOCK(sc)			sx_xunlock(&(sc)->hn_lock)
16315516c77SSepherosa Ziehau 
16415516c77SSepherosa Ziehau #define HN_CSUM_IP_MASK			(CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP)
16515516c77SSepherosa Ziehau #define HN_CSUM_IP6_MASK		(CSUM_IP6_TCP | CSUM_IP6_UDP)
16615516c77SSepherosa Ziehau #define HN_CSUM_IP_HWASSIST(sc)		\
16715516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP_MASK)
16815516c77SSepherosa Ziehau #define HN_CSUM_IP6_HWASSIST(sc)	\
16915516c77SSepherosa Ziehau 	((sc)->hn_tx_ring[0].hn_csum_assist & HN_CSUM_IP6_MASK)
17015516c77SSepherosa Ziehau 
171dc13fee6SSepherosa Ziehau #define HN_PKTSIZE_MIN(align)		\
172dc13fee6SSepherosa Ziehau 	roundup2(ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN + \
173dc13fee6SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN, (align))
174dc13fee6SSepherosa Ziehau #define HN_PKTSIZE(m, align)		\
175dc13fee6SSepherosa Ziehau 	roundup2((m)->m_pkthdr.len + HN_RNDIS_PKT_LEN, (align))
176dc13fee6SSepherosa Ziehau 
177*34d68912SSepherosa Ziehau #ifdef RSS
178*34d68912SSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx)	rss_getcpu((idx) % rss_getnumbuckets())
179*34d68912SSepherosa Ziehau #else
1800e11868dSSepherosa Ziehau #define HN_RING_IDX2CPU(sc, idx)	(((sc)->hn_cpu + (idx)) % mp_ncpus)
181*34d68912SSepherosa Ziehau #endif
1820e11868dSSepherosa Ziehau 
18315516c77SSepherosa Ziehau struct hn_txdesc {
18415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
18515516c77SSepherosa Ziehau 	SLIST_ENTRY(hn_txdesc)		link;
18615516c77SSepherosa Ziehau #endif
187dc13fee6SSepherosa Ziehau 	STAILQ_ENTRY(hn_txdesc)		agg_link;
188dc13fee6SSepherosa Ziehau 
189dc13fee6SSepherosa Ziehau 	/* Aggregated txdescs, in sending order. */
190dc13fee6SSepherosa Ziehau 	STAILQ_HEAD(, hn_txdesc)	agg_list;
191dc13fee6SSepherosa Ziehau 
192dc13fee6SSepherosa Ziehau 	/* The oldest packet, if transmission aggregation happens. */
19315516c77SSepherosa Ziehau 	struct mbuf			*m;
19415516c77SSepherosa Ziehau 	struct hn_tx_ring		*txr;
19515516c77SSepherosa Ziehau 	int				refs;
19615516c77SSepherosa Ziehau 	uint32_t			flags;	/* HN_TXD_FLAG_ */
19715516c77SSepherosa Ziehau 	struct hn_nvs_sendctx		send_ctx;
19815516c77SSepherosa Ziehau 	uint32_t			chim_index;
19915516c77SSepherosa Ziehau 	int				chim_size;
20015516c77SSepherosa Ziehau 
20115516c77SSepherosa Ziehau 	bus_dmamap_t			data_dmap;
20215516c77SSepherosa Ziehau 
20315516c77SSepherosa Ziehau 	bus_addr_t			rndis_pkt_paddr;
20415516c77SSepherosa Ziehau 	struct rndis_packet_msg		*rndis_pkt;
20515516c77SSepherosa Ziehau 	bus_dmamap_t			rndis_pkt_dmap;
20615516c77SSepherosa Ziehau };
20715516c77SSepherosa Ziehau 
20815516c77SSepherosa Ziehau #define HN_TXD_FLAG_ONLIST		0x0001
20915516c77SSepherosa Ziehau #define HN_TXD_FLAG_DMAMAP		0x0002
210dc13fee6SSepherosa Ziehau #define HN_TXD_FLAG_ONAGG		0x0004
21115516c77SSepherosa Ziehau 
21215516c77SSepherosa Ziehau struct hn_rxinfo {
21315516c77SSepherosa Ziehau 	uint32_t			vlan_info;
21415516c77SSepherosa Ziehau 	uint32_t			csum_info;
21515516c77SSepherosa Ziehau 	uint32_t			hash_info;
21615516c77SSepherosa Ziehau 	uint32_t			hash_value;
21715516c77SSepherosa Ziehau };
21815516c77SSepherosa Ziehau 
21915516c77SSepherosa Ziehau #define HN_RXINFO_VLAN			0x0001
22015516c77SSepherosa Ziehau #define HN_RXINFO_CSUM			0x0002
22115516c77SSepherosa Ziehau #define HN_RXINFO_HASHINF		0x0004
22215516c77SSepherosa Ziehau #define HN_RXINFO_HASHVAL		0x0008
22315516c77SSepherosa Ziehau #define HN_RXINFO_ALL			\
22415516c77SSepherosa Ziehau 	(HN_RXINFO_VLAN |		\
22515516c77SSepherosa Ziehau 	 HN_RXINFO_CSUM |		\
22615516c77SSepherosa Ziehau 	 HN_RXINFO_HASHINF |		\
22715516c77SSepherosa Ziehau 	 HN_RXINFO_HASHVAL)
22815516c77SSepherosa Ziehau 
22915516c77SSepherosa Ziehau #define HN_NDIS_VLAN_INFO_INVALID	0xffffffff
23015516c77SSepherosa Ziehau #define HN_NDIS_RXCSUM_INFO_INVALID	0
23115516c77SSepherosa Ziehau #define HN_NDIS_HASH_INFO_INVALID	0
23215516c77SSepherosa Ziehau 
23315516c77SSepherosa Ziehau static int			hn_probe(device_t);
23415516c77SSepherosa Ziehau static int			hn_attach(device_t);
23515516c77SSepherosa Ziehau static int			hn_detach(device_t);
23615516c77SSepherosa Ziehau static int			hn_shutdown(device_t);
23715516c77SSepherosa Ziehau static void			hn_chan_callback(struct vmbus_channel *,
23815516c77SSepherosa Ziehau 				    void *);
23915516c77SSepherosa Ziehau 
24015516c77SSepherosa Ziehau static void			hn_init(void *);
24115516c77SSepherosa Ziehau static int			hn_ioctl(struct ifnet *, u_long, caddr_t);
24223bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
24315516c77SSepherosa Ziehau static void			hn_start(struct ifnet *);
24423bf9e15SSepherosa Ziehau #endif
24515516c77SSepherosa Ziehau static int			hn_transmit(struct ifnet *, struct mbuf *);
24615516c77SSepherosa Ziehau static void			hn_xmit_qflush(struct ifnet *);
24715516c77SSepherosa Ziehau static int			hn_ifmedia_upd(struct ifnet *);
24815516c77SSepherosa Ziehau static void			hn_ifmedia_sts(struct ifnet *,
24915516c77SSepherosa Ziehau 				    struct ifmediareq *);
25015516c77SSepherosa Ziehau 
25115516c77SSepherosa Ziehau static int			hn_rndis_rxinfo(const void *, int,
25215516c77SSepherosa Ziehau 				    struct hn_rxinfo *);
25315516c77SSepherosa Ziehau static void			hn_rndis_rx_data(struct hn_rx_ring *,
25415516c77SSepherosa Ziehau 				    const void *, int);
25515516c77SSepherosa Ziehau static void			hn_rndis_rx_status(struct hn_softc *,
25615516c77SSepherosa Ziehau 				    const void *, int);
25715516c77SSepherosa Ziehau 
25815516c77SSepherosa Ziehau static void			hn_nvs_handle_notify(struct hn_softc *,
25915516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
26015516c77SSepherosa Ziehau static void			hn_nvs_handle_comp(struct hn_softc *,
26115516c77SSepherosa Ziehau 				    struct vmbus_channel *,
26215516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
26315516c77SSepherosa Ziehau static void			hn_nvs_handle_rxbuf(struct hn_rx_ring *,
26415516c77SSepherosa Ziehau 				    struct vmbus_channel *,
26515516c77SSepherosa Ziehau 				    const struct vmbus_chanpkt_hdr *);
26615516c77SSepherosa Ziehau static void			hn_nvs_ack_rxbuf(struct hn_rx_ring *,
26715516c77SSepherosa Ziehau 				    struct vmbus_channel *, uint64_t);
26815516c77SSepherosa Ziehau 
26915516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
27015516c77SSepherosa Ziehau static int			hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS);
27115516c77SSepherosa Ziehau static int			hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS);
27215516c77SSepherosa Ziehau #endif
27315516c77SSepherosa Ziehau static int			hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS);
27415516c77SSepherosa Ziehau static int			hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS);
27515516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
27615516c77SSepherosa Ziehau static int			hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS);
27715516c77SSepherosa Ziehau #else
27815516c77SSepherosa Ziehau static int			hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS);
27915516c77SSepherosa Ziehau #endif
28015516c77SSepherosa Ziehau static int			hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
28115516c77SSepherosa Ziehau static int			hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS);
28215516c77SSepherosa Ziehau static int			hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS);
28315516c77SSepherosa Ziehau static int			hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS);
28415516c77SSepherosa Ziehau static int			hn_caps_sysctl(SYSCTL_HANDLER_ARGS);
28515516c77SSepherosa Ziehau static int			hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS);
28615516c77SSepherosa Ziehau static int			hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS);
287*34d68912SSepherosa Ziehau #ifndef RSS
28815516c77SSepherosa Ziehau static int			hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS);
28915516c77SSepherosa Ziehau static int			hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS);
290*34d68912SSepherosa Ziehau #endif
29115516c77SSepherosa Ziehau static int			hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS);
292dc13fee6SSepherosa Ziehau static int			hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS);
293dc13fee6SSepherosa Ziehau static int			hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS);
294dc13fee6SSepherosa Ziehau static int			hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS);
295dc13fee6SSepherosa Ziehau static int			hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS);
29615516c77SSepherosa Ziehau 
29715516c77SSepherosa Ziehau static void			hn_stop(struct hn_softc *);
29815516c77SSepherosa Ziehau static void			hn_init_locked(struct hn_softc *);
29915516c77SSepherosa Ziehau static int			hn_chan_attach(struct hn_softc *,
30015516c77SSepherosa Ziehau 				    struct vmbus_channel *);
30115516c77SSepherosa Ziehau static void			hn_chan_detach(struct hn_softc *,
30215516c77SSepherosa Ziehau 				    struct vmbus_channel *);
30315516c77SSepherosa Ziehau static int			hn_attach_subchans(struct hn_softc *);
30415516c77SSepherosa Ziehau static void			hn_detach_allchans(struct hn_softc *);
30515516c77SSepherosa Ziehau static void			hn_chan_rollup(struct hn_rx_ring *,
30615516c77SSepherosa Ziehau 				    struct hn_tx_ring *);
30715516c77SSepherosa Ziehau static void			hn_set_ring_inuse(struct hn_softc *, int);
30815516c77SSepherosa Ziehau static int			hn_synth_attach(struct hn_softc *, int);
30915516c77SSepherosa Ziehau static void			hn_synth_detach(struct hn_softc *);
31015516c77SSepherosa Ziehau static int			hn_synth_alloc_subchans(struct hn_softc *,
31115516c77SSepherosa Ziehau 				    int *);
3122494d735SSepherosa Ziehau static bool			hn_synth_attachable(const struct hn_softc *);
31315516c77SSepherosa Ziehau static void			hn_suspend(struct hn_softc *);
31415516c77SSepherosa Ziehau static void			hn_suspend_data(struct hn_softc *);
31515516c77SSepherosa Ziehau static void			hn_suspend_mgmt(struct hn_softc *);
31615516c77SSepherosa Ziehau static void			hn_resume(struct hn_softc *);
31715516c77SSepherosa Ziehau static void			hn_resume_data(struct hn_softc *);
31815516c77SSepherosa Ziehau static void			hn_resume_mgmt(struct hn_softc *);
31915516c77SSepherosa Ziehau static void			hn_suspend_mgmt_taskfunc(void *, int);
32025641fc7SSepherosa Ziehau static void			hn_chan_drain(struct hn_softc *,
32125641fc7SSepherosa Ziehau 				    struct vmbus_channel *);
32215516c77SSepherosa Ziehau 
32315516c77SSepherosa Ziehau static void			hn_update_link_status(struct hn_softc *);
32415516c77SSepherosa Ziehau static void			hn_change_network(struct hn_softc *);
32515516c77SSepherosa Ziehau static void			hn_link_taskfunc(void *, int);
32615516c77SSepherosa Ziehau static void			hn_netchg_init_taskfunc(void *, int);
32715516c77SSepherosa Ziehau static void			hn_netchg_status_taskfunc(void *, int);
32815516c77SSepherosa Ziehau static void			hn_link_status(struct hn_softc *);
32915516c77SSepherosa Ziehau 
33015516c77SSepherosa Ziehau static int			hn_create_rx_data(struct hn_softc *, int);
33115516c77SSepherosa Ziehau static void			hn_destroy_rx_data(struct hn_softc *);
33215516c77SSepherosa Ziehau static int			hn_check_iplen(const struct mbuf *, int);
33315516c77SSepherosa Ziehau static int			hn_set_rxfilter(struct hn_softc *);
334*34d68912SSepherosa Ziehau #ifndef RSS
33515516c77SSepherosa Ziehau static int			hn_rss_reconfig(struct hn_softc *);
336*34d68912SSepherosa Ziehau #endif
337afd4971bSSepherosa Ziehau static void			hn_rss_ind_fixup(struct hn_softc *);
33815516c77SSepherosa Ziehau static int			hn_rxpkt(struct hn_rx_ring *, const void *,
33915516c77SSepherosa Ziehau 				    int, const struct hn_rxinfo *);
34015516c77SSepherosa Ziehau 
34115516c77SSepherosa Ziehau static int			hn_tx_ring_create(struct hn_softc *, int);
34215516c77SSepherosa Ziehau static void			hn_tx_ring_destroy(struct hn_tx_ring *);
34315516c77SSepherosa Ziehau static int			hn_create_tx_data(struct hn_softc *, int);
34415516c77SSepherosa Ziehau static void			hn_fixup_tx_data(struct hn_softc *);
34515516c77SSepherosa Ziehau static void			hn_destroy_tx_data(struct hn_softc *);
34615516c77SSepherosa Ziehau static void			hn_txdesc_dmamap_destroy(struct hn_txdesc *);
34725641fc7SSepherosa Ziehau static void			hn_txdesc_gc(struct hn_tx_ring *,
34825641fc7SSepherosa Ziehau 				    struct hn_txdesc *);
349dc13fee6SSepherosa Ziehau static int			hn_encap(struct ifnet *, struct hn_tx_ring *,
35015516c77SSepherosa Ziehau 				    struct hn_txdesc *, struct mbuf **);
35115516c77SSepherosa Ziehau static int			hn_txpkt(struct ifnet *, struct hn_tx_ring *,
35215516c77SSepherosa Ziehau 				    struct hn_txdesc *);
35315516c77SSepherosa Ziehau static void			hn_set_chim_size(struct hn_softc *, int);
35415516c77SSepherosa Ziehau static void			hn_set_tso_maxsize(struct hn_softc *, int, int);
35515516c77SSepherosa Ziehau static bool			hn_tx_ring_pending(struct hn_tx_ring *);
35615516c77SSepherosa Ziehau static void			hn_tx_ring_qflush(struct hn_tx_ring *);
35715516c77SSepherosa Ziehau static void			hn_resume_tx(struct hn_softc *, int);
358dc13fee6SSepherosa Ziehau static void			hn_set_txagg(struct hn_softc *);
359dc13fee6SSepherosa Ziehau static void			*hn_try_txagg(struct ifnet *,
360dc13fee6SSepherosa Ziehau 				    struct hn_tx_ring *, struct hn_txdesc *,
361dc13fee6SSepherosa Ziehau 				    int);
36215516c77SSepherosa Ziehau static int			hn_get_txswq_depth(const struct hn_tx_ring *);
36315516c77SSepherosa Ziehau static void			hn_txpkt_done(struct hn_nvs_sendctx *,
36415516c77SSepherosa Ziehau 				    struct hn_softc *, struct vmbus_channel *,
36515516c77SSepherosa Ziehau 				    const void *, int);
36615516c77SSepherosa Ziehau static int			hn_txpkt_sglist(struct hn_tx_ring *,
36715516c77SSepherosa Ziehau 				    struct hn_txdesc *);
36815516c77SSepherosa Ziehau static int			hn_txpkt_chim(struct hn_tx_ring *,
36915516c77SSepherosa Ziehau 				    struct hn_txdesc *);
37015516c77SSepherosa Ziehau static int			hn_xmit(struct hn_tx_ring *, int);
37115516c77SSepherosa Ziehau static void			hn_xmit_taskfunc(void *, int);
37215516c77SSepherosa Ziehau static void			hn_xmit_txeof(struct hn_tx_ring *);
37315516c77SSepherosa Ziehau static void			hn_xmit_txeof_taskfunc(void *, int);
37423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
37515516c77SSepherosa Ziehau static int			hn_start_locked(struct hn_tx_ring *, int);
37615516c77SSepherosa Ziehau static void			hn_start_taskfunc(void *, int);
37715516c77SSepherosa Ziehau static void			hn_start_txeof(struct hn_tx_ring *);
37815516c77SSepherosa Ziehau static void			hn_start_txeof_taskfunc(void *, int);
37923bf9e15SSepherosa Ziehau #endif
38015516c77SSepherosa Ziehau 
38115516c77SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
38215516c77SSepherosa Ziehau     "Hyper-V network interface");
38315516c77SSepherosa Ziehau 
38415516c77SSepherosa Ziehau /* Trust tcp segements verification on host side. */
38515516c77SSepherosa Ziehau static int			hn_trust_hosttcp = 1;
38615516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosttcp, CTLFLAG_RDTUN,
38715516c77SSepherosa Ziehau     &hn_trust_hosttcp, 0,
38815516c77SSepherosa Ziehau     "Trust tcp segement verification on host side, "
38915516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
39015516c77SSepherosa Ziehau 
39115516c77SSepherosa Ziehau /* Trust udp datagrams verification on host side. */
39215516c77SSepherosa Ziehau static int			hn_trust_hostudp = 1;
39315516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostudp, CTLFLAG_RDTUN,
39415516c77SSepherosa Ziehau     &hn_trust_hostudp, 0,
39515516c77SSepherosa Ziehau     "Trust udp datagram verification on host side, "
39615516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
39715516c77SSepherosa Ziehau 
39815516c77SSepherosa Ziehau /* Trust ip packets verification on host side. */
39915516c77SSepherosa Ziehau static int			hn_trust_hostip = 1;
40015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN,
40115516c77SSepherosa Ziehau     &hn_trust_hostip, 0,
40215516c77SSepherosa Ziehau     "Trust ip packet verification on host side, "
40315516c77SSepherosa Ziehau     "when csum info is missing (global setting)");
40415516c77SSepherosa Ziehau 
40515516c77SSepherosa Ziehau /* Limit TSO burst size */
40615516c77SSepherosa Ziehau static int			hn_tso_maxlen = IP_MAXPACKET;
40715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN,
40815516c77SSepherosa Ziehau     &hn_tso_maxlen, 0, "TSO burst limit");
40915516c77SSepherosa Ziehau 
41015516c77SSepherosa Ziehau /* Limit chimney send size */
41115516c77SSepherosa Ziehau static int			hn_tx_chimney_size = 0;
41215516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_chimney_size, CTLFLAG_RDTUN,
41315516c77SSepherosa Ziehau     &hn_tx_chimney_size, 0, "Chimney send packet size limit");
41415516c77SSepherosa Ziehau 
41515516c77SSepherosa Ziehau /* Limit the size of packet for direct transmission */
41615516c77SSepherosa Ziehau static int			hn_direct_tx_size = HN_DIRECT_TX_SIZE_DEF;
41715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, direct_tx_size, CTLFLAG_RDTUN,
41815516c77SSepherosa Ziehau     &hn_direct_tx_size, 0, "Size of the packet for direct transmission");
41915516c77SSepherosa Ziehau 
42015516c77SSepherosa Ziehau /* # of LRO entries per RX ring */
42115516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
42215516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
42315516c77SSepherosa Ziehau static int			hn_lro_entry_count = HN_LROENT_CNT_DEF;
42415516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, lro_entry_count, CTLFLAG_RDTUN,
42515516c77SSepherosa Ziehau     &hn_lro_entry_count, 0, "LRO entry count");
42615516c77SSepherosa Ziehau #endif
42715516c77SSepherosa Ziehau #endif
42815516c77SSepherosa Ziehau 
429fdd0222aSSepherosa Ziehau static int			hn_tx_taskq_cnt = 1;
430fdd0222aSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_cnt, CTLFLAG_RDTUN,
431fdd0222aSSepherosa Ziehau     &hn_tx_taskq_cnt, 0, "# of TX taskqueues");
432fdd0222aSSepherosa Ziehau 
4330e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_INDEP	0
4340e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_GLOBAL	1
4350e11868dSSepherosa Ziehau #define HN_TX_TASKQ_M_EVTTQ	2
4360e11868dSSepherosa Ziehau 
4370e11868dSSepherosa Ziehau static int			hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
4380e11868dSSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_mode, CTLFLAG_RDTUN,
4390e11868dSSepherosa Ziehau     &hn_tx_taskq_mode, 0, "TX taskqueue modes: "
4400e11868dSSepherosa Ziehau     "0 - independent, 1 - share global tx taskqs, 2 - share event taskqs");
4410e11868dSSepherosa Ziehau 
44215516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
44315516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 0;
44415516c77SSepherosa Ziehau #else
44515516c77SSepherosa Ziehau static int			hn_use_txdesc_bufring = 1;
44615516c77SSepherosa Ziehau #endif
44715516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD,
44815516c77SSepherosa Ziehau     &hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors");
44915516c77SSepherosa Ziehau 
45023bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
45115516c77SSepherosa Ziehau /* Use ifnet.if_start instead of ifnet.if_transmit */
45215516c77SSepherosa Ziehau static int			hn_use_if_start = 0;
45315516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN,
45415516c77SSepherosa Ziehau     &hn_use_if_start, 0, "Use if_start TX method");
45523bf9e15SSepherosa Ziehau #endif
45615516c77SSepherosa Ziehau 
45715516c77SSepherosa Ziehau /* # of channels to use */
45815516c77SSepherosa Ziehau static int			hn_chan_cnt = 0;
45915516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN,
46015516c77SSepherosa Ziehau     &hn_chan_cnt, 0,
46115516c77SSepherosa Ziehau     "# of channels to use; each channel has one RX ring and one TX ring");
46215516c77SSepherosa Ziehau 
46315516c77SSepherosa Ziehau /* # of transmit rings to use */
46415516c77SSepherosa Ziehau static int			hn_tx_ring_cnt = 0;
46515516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN,
46615516c77SSepherosa Ziehau     &hn_tx_ring_cnt, 0, "# of TX rings to use");
46715516c77SSepherosa Ziehau 
46815516c77SSepherosa Ziehau /* Software TX ring deptch */
46915516c77SSepherosa Ziehau static int			hn_tx_swq_depth = 0;
47015516c77SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN,
47115516c77SSepherosa Ziehau     &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING");
47215516c77SSepherosa Ziehau 
47315516c77SSepherosa Ziehau /* Enable sorted LRO, and the depth of the per-channel mbuf queue */
47415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
47515516c77SSepherosa Ziehau static u_int			hn_lro_mbufq_depth = 0;
47615516c77SSepherosa Ziehau SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN,
47715516c77SSepherosa Ziehau     &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue");
47815516c77SSepherosa Ziehau #endif
47915516c77SSepherosa Ziehau 
480dc13fee6SSepherosa Ziehau /* Packet transmission aggregation size limit */
481dc13fee6SSepherosa Ziehau static int			hn_tx_agg_size = -1;
482dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN,
483dc13fee6SSepherosa Ziehau     &hn_tx_agg_size, 0, "Packet transmission aggregation size limit");
484dc13fee6SSepherosa Ziehau 
485dc13fee6SSepherosa Ziehau /* Packet transmission aggregation count limit */
486fa915c4dSSepherosa Ziehau static int			hn_tx_agg_pkts = -1;
487dc13fee6SSepherosa Ziehau SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN,
488dc13fee6SSepherosa Ziehau     &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit");
489dc13fee6SSepherosa Ziehau 
49015516c77SSepherosa Ziehau static u_int			hn_cpu_index;	/* next CPU for channel */
491fdd0222aSSepherosa Ziehau static struct taskqueue		**hn_tx_taskque;/* shared TX taskqueues */
49215516c77SSepherosa Ziehau 
493*34d68912SSepherosa Ziehau #ifndef RSS
49415516c77SSepherosa Ziehau static const uint8_t
49515516c77SSepherosa Ziehau hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
49615516c77SSepherosa Ziehau 	0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
49715516c77SSepherosa Ziehau 	0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
49815516c77SSepherosa Ziehau 	0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
49915516c77SSepherosa Ziehau 	0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
50015516c77SSepherosa Ziehau 	0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
50115516c77SSepherosa Ziehau };
502*34d68912SSepherosa Ziehau #endif	/* !RSS */
50315516c77SSepherosa Ziehau 
50415516c77SSepherosa Ziehau static device_method_t hn_methods[] = {
50515516c77SSepherosa Ziehau 	/* Device interface */
50615516c77SSepherosa Ziehau 	DEVMETHOD(device_probe,		hn_probe),
50715516c77SSepherosa Ziehau 	DEVMETHOD(device_attach,	hn_attach),
50815516c77SSepherosa Ziehau 	DEVMETHOD(device_detach,	hn_detach),
50915516c77SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	hn_shutdown),
51015516c77SSepherosa Ziehau 	DEVMETHOD_END
51115516c77SSepherosa Ziehau };
51215516c77SSepherosa Ziehau 
51315516c77SSepherosa Ziehau static driver_t hn_driver = {
51415516c77SSepherosa Ziehau 	"hn",
51515516c77SSepherosa Ziehau 	hn_methods,
51615516c77SSepherosa Ziehau 	sizeof(struct hn_softc)
51715516c77SSepherosa Ziehau };
51815516c77SSepherosa Ziehau 
51915516c77SSepherosa Ziehau static devclass_t hn_devclass;
52015516c77SSepherosa Ziehau 
52115516c77SSepherosa Ziehau DRIVER_MODULE(hn, vmbus, hn_driver, hn_devclass, 0, 0);
52215516c77SSepherosa Ziehau MODULE_VERSION(hn, 1);
52315516c77SSepherosa Ziehau MODULE_DEPEND(hn, vmbus, 1, 1, 1);
52415516c77SSepherosa Ziehau 
52515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
52615516c77SSepherosa Ziehau static void
52715516c77SSepherosa Ziehau hn_set_lro_lenlim(struct hn_softc *sc, int lenlim)
52815516c77SSepherosa Ziehau {
52915516c77SSepherosa Ziehau 	int i;
53015516c77SSepherosa Ziehau 
531a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
53215516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim;
53315516c77SSepherosa Ziehau }
53415516c77SSepherosa Ziehau #endif
53515516c77SSepherosa Ziehau 
53615516c77SSepherosa Ziehau static int
53715516c77SSepherosa Ziehau hn_txpkt_sglist(struct hn_tx_ring *txr, struct hn_txdesc *txd)
53815516c77SSepherosa Ziehau {
53915516c77SSepherosa Ziehau 
54015516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
54115516c77SSepherosa Ziehau 	    txd->chim_size == 0, ("invalid rndis sglist txd"));
54215516c77SSepherosa Ziehau 	return (hn_nvs_send_rndis_sglist(txr->hn_chan, HN_NVS_RNDIS_MTYPE_DATA,
54315516c77SSepherosa Ziehau 	    &txd->send_ctx, txr->hn_gpa, txr->hn_gpa_cnt));
54415516c77SSepherosa Ziehau }
54515516c77SSepherosa Ziehau 
54615516c77SSepherosa Ziehau static int
54715516c77SSepherosa Ziehau hn_txpkt_chim(struct hn_tx_ring *txr, struct hn_txdesc *txd)
54815516c77SSepherosa Ziehau {
54915516c77SSepherosa Ziehau 	struct hn_nvs_rndis rndis;
55015516c77SSepherosa Ziehau 
55115516c77SSepherosa Ziehau 	KASSERT(txd->chim_index != HN_NVS_CHIM_IDX_INVALID &&
55215516c77SSepherosa Ziehau 	    txd->chim_size > 0, ("invalid rndis chim txd"));
55315516c77SSepherosa Ziehau 
55415516c77SSepherosa Ziehau 	rndis.nvs_type = HN_NVS_TYPE_RNDIS;
55515516c77SSepherosa Ziehau 	rndis.nvs_rndis_mtype = HN_NVS_RNDIS_MTYPE_DATA;
55615516c77SSepherosa Ziehau 	rndis.nvs_chim_idx = txd->chim_index;
55715516c77SSepherosa Ziehau 	rndis.nvs_chim_sz = txd->chim_size;
55815516c77SSepherosa Ziehau 
55915516c77SSepherosa Ziehau 	return (hn_nvs_send(txr->hn_chan, VMBUS_CHANPKT_FLAG_RC,
56015516c77SSepherosa Ziehau 	    &rndis, sizeof(rndis), &txd->send_ctx));
56115516c77SSepherosa Ziehau }
56215516c77SSepherosa Ziehau 
56315516c77SSepherosa Ziehau static __inline uint32_t
56415516c77SSepherosa Ziehau hn_chim_alloc(struct hn_softc *sc)
56515516c77SSepherosa Ziehau {
56615516c77SSepherosa Ziehau 	int i, bmap_cnt = sc->hn_chim_bmap_cnt;
56715516c77SSepherosa Ziehau 	u_long *bmap = sc->hn_chim_bmap;
56815516c77SSepherosa Ziehau 	uint32_t ret = HN_NVS_CHIM_IDX_INVALID;
56915516c77SSepherosa Ziehau 
57015516c77SSepherosa Ziehau 	for (i = 0; i < bmap_cnt; ++i) {
57115516c77SSepherosa Ziehau 		int idx;
57215516c77SSepherosa Ziehau 
57315516c77SSepherosa Ziehau 		idx = ffsl(~bmap[i]);
57415516c77SSepherosa Ziehau 		if (idx == 0)
57515516c77SSepherosa Ziehau 			continue;
57615516c77SSepherosa Ziehau 
57715516c77SSepherosa Ziehau 		--idx; /* ffsl is 1-based */
57815516c77SSepherosa Ziehau 		KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt,
57915516c77SSepherosa Ziehau 		    ("invalid i %d and idx %d", i, idx));
58015516c77SSepherosa Ziehau 
58115516c77SSepherosa Ziehau 		if (atomic_testandset_long(&bmap[i], idx))
58215516c77SSepherosa Ziehau 			continue;
58315516c77SSepherosa Ziehau 
58415516c77SSepherosa Ziehau 		ret = i * LONG_BIT + idx;
58515516c77SSepherosa Ziehau 		break;
58615516c77SSepherosa Ziehau 	}
58715516c77SSepherosa Ziehau 	return (ret);
58815516c77SSepherosa Ziehau }
58915516c77SSepherosa Ziehau 
59015516c77SSepherosa Ziehau static __inline void
59115516c77SSepherosa Ziehau hn_chim_free(struct hn_softc *sc, uint32_t chim_idx)
59215516c77SSepherosa Ziehau {
59315516c77SSepherosa Ziehau 	u_long mask;
59415516c77SSepherosa Ziehau 	uint32_t idx;
59515516c77SSepherosa Ziehau 
59615516c77SSepherosa Ziehau 	idx = chim_idx / LONG_BIT;
59715516c77SSepherosa Ziehau 	KASSERT(idx < sc->hn_chim_bmap_cnt,
59815516c77SSepherosa Ziehau 	    ("invalid chimney index 0x%x", chim_idx));
59915516c77SSepherosa Ziehau 
60015516c77SSepherosa Ziehau 	mask = 1UL << (chim_idx % LONG_BIT);
60115516c77SSepherosa Ziehau 	KASSERT(sc->hn_chim_bmap[idx] & mask,
60215516c77SSepherosa Ziehau 	    ("index bitmap 0x%lx, chimney index %u, "
60315516c77SSepherosa Ziehau 	     "bitmap idx %d, bitmask 0x%lx",
60415516c77SSepherosa Ziehau 	     sc->hn_chim_bmap[idx], chim_idx, idx, mask));
60515516c77SSepherosa Ziehau 
60615516c77SSepherosa Ziehau 	atomic_clear_long(&sc->hn_chim_bmap[idx], mask);
60715516c77SSepherosa Ziehau }
60815516c77SSepherosa Ziehau 
609edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
610edd3f315SSepherosa Ziehau /*
611edd3f315SSepherosa Ziehau  * NOTE: If this function failed, the m_head would be freed.
612edd3f315SSepherosa Ziehau  */
613edd3f315SSepherosa Ziehau static __inline struct mbuf *
614edd3f315SSepherosa Ziehau hn_tso_fixup(struct mbuf *m_head)
615edd3f315SSepherosa Ziehau {
616edd3f315SSepherosa Ziehau 	struct ether_vlan_header *evl;
617edd3f315SSepherosa Ziehau 	struct tcphdr *th;
618edd3f315SSepherosa Ziehau 	int ehlen;
619edd3f315SSepherosa Ziehau 
620edd3f315SSepherosa Ziehau 	KASSERT(M_WRITABLE(m_head), ("TSO mbuf not writable"));
621edd3f315SSepherosa Ziehau 
622edd3f315SSepherosa Ziehau #define PULLUP_HDR(m, len)				\
623edd3f315SSepherosa Ziehau do {							\
624edd3f315SSepherosa Ziehau 	if (__predict_false((m)->m_len < (len))) {	\
625edd3f315SSepherosa Ziehau 		(m) = m_pullup((m), (len));		\
626edd3f315SSepherosa Ziehau 		if ((m) == NULL)			\
627edd3f315SSepherosa Ziehau 			return (NULL);			\
628edd3f315SSepherosa Ziehau 	}						\
629edd3f315SSepherosa Ziehau } while (0)
630edd3f315SSepherosa Ziehau 
631edd3f315SSepherosa Ziehau 	PULLUP_HDR(m_head, sizeof(*evl));
632edd3f315SSepherosa Ziehau 	evl = mtod(m_head, struct ether_vlan_header *);
633edd3f315SSepherosa Ziehau 	if (evl->evl_encap_proto == ntohs(ETHERTYPE_VLAN))
634edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
635edd3f315SSepherosa Ziehau 	else
636edd3f315SSepherosa Ziehau 		ehlen = ETHER_HDR_LEN;
637edd3f315SSepherosa Ziehau 
638edd3f315SSepherosa Ziehau #ifdef INET
639edd3f315SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
640edd3f315SSepherosa Ziehau 		struct ip *ip;
641edd3f315SSepherosa Ziehau 		int iphlen;
642edd3f315SSepherosa Ziehau 
643edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip));
644edd3f315SSepherosa Ziehau 		ip = mtodo(m_head, ehlen);
645edd3f315SSepherosa Ziehau 		iphlen = ip->ip_hl << 2;
646edd3f315SSepherosa Ziehau 
647edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + iphlen + sizeof(*th));
648edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + iphlen);
649edd3f315SSepherosa Ziehau 
650edd3f315SSepherosa Ziehau 		ip->ip_len = 0;
651edd3f315SSepherosa Ziehau 		ip->ip_sum = 0;
652edd3f315SSepherosa Ziehau 		th->th_sum = in_pseudo(ip->ip_src.s_addr,
653edd3f315SSepherosa Ziehau 		    ip->ip_dst.s_addr, htons(IPPROTO_TCP));
654edd3f315SSepherosa Ziehau 	}
655edd3f315SSepherosa Ziehau #endif
656edd3f315SSepherosa Ziehau #if defined(INET6) && defined(INET)
657edd3f315SSepherosa Ziehau 	else
658edd3f315SSepherosa Ziehau #endif
659edd3f315SSepherosa Ziehau #ifdef INET6
660edd3f315SSepherosa Ziehau 	{
661edd3f315SSepherosa Ziehau 		struct ip6_hdr *ip6;
662edd3f315SSepherosa Ziehau 
663edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6));
664edd3f315SSepherosa Ziehau 		ip6 = mtodo(m_head, ehlen);
665edd3f315SSepherosa Ziehau 		if (ip6->ip6_nxt != IPPROTO_TCP) {
666edd3f315SSepherosa Ziehau 			m_freem(m_head);
667edd3f315SSepherosa Ziehau 			return (NULL);
668edd3f315SSepherosa Ziehau 		}
669edd3f315SSepherosa Ziehau 
670edd3f315SSepherosa Ziehau 		PULLUP_HDR(m_head, ehlen + sizeof(*ip6) + sizeof(*th));
671edd3f315SSepherosa Ziehau 		th = mtodo(m_head, ehlen + sizeof(*ip6));
672edd3f315SSepherosa Ziehau 
673edd3f315SSepherosa Ziehau 		ip6->ip6_plen = 0;
674edd3f315SSepherosa Ziehau 		th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0);
675edd3f315SSepherosa Ziehau 	}
676edd3f315SSepherosa Ziehau #endif
677edd3f315SSepherosa Ziehau 	return (m_head);
678edd3f315SSepherosa Ziehau 
679edd3f315SSepherosa Ziehau #undef PULLUP_HDR
680edd3f315SSepherosa Ziehau }
681edd3f315SSepherosa Ziehau #endif	/* INET6 || INET */
682edd3f315SSepherosa Ziehau 
68315516c77SSepherosa Ziehau static int
68415516c77SSepherosa Ziehau hn_set_rxfilter(struct hn_softc *sc)
68515516c77SSepherosa Ziehau {
68615516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
68715516c77SSepherosa Ziehau 	uint32_t filter;
68815516c77SSepherosa Ziehau 	int error = 0;
68915516c77SSepherosa Ziehau 
69015516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
69115516c77SSepherosa Ziehau 
69215516c77SSepherosa Ziehau 	if (ifp->if_flags & IFF_PROMISC) {
69315516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_PROMISCUOUS;
69415516c77SSepherosa Ziehau 	} else {
69515516c77SSepherosa Ziehau 		filter = NDIS_PACKET_TYPE_DIRECTED;
69615516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_BROADCAST)
69715516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_BROADCAST;
69815516c77SSepherosa Ziehau 		/* TODO: support multicast list */
69915516c77SSepherosa Ziehau 		if ((ifp->if_flags & IFF_ALLMULTI) ||
70015516c77SSepherosa Ziehau 		    !TAILQ_EMPTY(&ifp->if_multiaddrs))
70115516c77SSepherosa Ziehau 			filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
70215516c77SSepherosa Ziehau 	}
70315516c77SSepherosa Ziehau 
70415516c77SSepherosa Ziehau 	if (sc->hn_rx_filter != filter) {
70515516c77SSepherosa Ziehau 		error = hn_rndis_set_rxfilter(sc, filter);
70615516c77SSepherosa Ziehau 		if (!error)
70715516c77SSepherosa Ziehau 			sc->hn_rx_filter = filter;
70815516c77SSepherosa Ziehau 	}
70915516c77SSepherosa Ziehau 	return (error);
71015516c77SSepherosa Ziehau }
71115516c77SSepherosa Ziehau 
712dc13fee6SSepherosa Ziehau static void
713dc13fee6SSepherosa Ziehau hn_set_txagg(struct hn_softc *sc)
714dc13fee6SSepherosa Ziehau {
715dc13fee6SSepherosa Ziehau 	uint32_t size, pkts;
716dc13fee6SSepherosa Ziehau 	int i;
717dc13fee6SSepherosa Ziehau 
718dc13fee6SSepherosa Ziehau 	/*
719dc13fee6SSepherosa Ziehau 	 * Setup aggregation size.
720dc13fee6SSepherosa Ziehau 	 */
721dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_size < 0)
722dc13fee6SSepherosa Ziehau 		size = UINT32_MAX;
723dc13fee6SSepherosa Ziehau 	else
724dc13fee6SSepherosa Ziehau 		size = sc->hn_agg_size;
725dc13fee6SSepherosa Ziehau 
726dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_size < size)
727dc13fee6SSepherosa Ziehau 		size = sc->hn_rndis_agg_size;
728dc13fee6SSepherosa Ziehau 
729a4364cfeSSepherosa Ziehau 	/* NOTE: We only aggregate packets using chimney sending buffers. */
730a4364cfeSSepherosa Ziehau 	if (size > (uint32_t)sc->hn_chim_szmax)
731a4364cfeSSepherosa Ziehau 		size = sc->hn_chim_szmax;
732a4364cfeSSepherosa Ziehau 
733dc13fee6SSepherosa Ziehau 	if (size <= 2 * HN_PKTSIZE_MIN(sc->hn_rndis_agg_align)) {
734dc13fee6SSepherosa Ziehau 		/* Disable */
735dc13fee6SSepherosa Ziehau 		size = 0;
736dc13fee6SSepherosa Ziehau 		pkts = 0;
737dc13fee6SSepherosa Ziehau 		goto done;
738dc13fee6SSepherosa Ziehau 	}
739dc13fee6SSepherosa Ziehau 
740dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'int'. */
741dc13fee6SSepherosa Ziehau 	if (size > INT_MAX)
742dc13fee6SSepherosa Ziehau 		size = INT_MAX;
743dc13fee6SSepherosa Ziehau 
744dc13fee6SSepherosa Ziehau 	/*
745dc13fee6SSepherosa Ziehau 	 * Setup aggregation packet count.
746dc13fee6SSepherosa Ziehau 	 */
747dc13fee6SSepherosa Ziehau 	if (sc->hn_agg_pkts < 0)
748dc13fee6SSepherosa Ziehau 		pkts = UINT32_MAX;
749dc13fee6SSepherosa Ziehau 	else
750dc13fee6SSepherosa Ziehau 		pkts = sc->hn_agg_pkts;
751dc13fee6SSepherosa Ziehau 
752dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_pkts < pkts)
753dc13fee6SSepherosa Ziehau 		pkts = sc->hn_rndis_agg_pkts;
754dc13fee6SSepherosa Ziehau 
755dc13fee6SSepherosa Ziehau 	if (pkts <= 1) {
756dc13fee6SSepherosa Ziehau 		/* Disable */
757dc13fee6SSepherosa Ziehau 		size = 0;
758dc13fee6SSepherosa Ziehau 		pkts = 0;
759dc13fee6SSepherosa Ziehau 		goto done;
760dc13fee6SSepherosa Ziehau 	}
761dc13fee6SSepherosa Ziehau 
762dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
763dc13fee6SSepherosa Ziehau 	if (pkts > SHRT_MAX)
764dc13fee6SSepherosa Ziehau 		pkts = SHRT_MAX;
765dc13fee6SSepherosa Ziehau 
766dc13fee6SSepherosa Ziehau done:
767dc13fee6SSepherosa Ziehau 	/* NOTE: Type of the per TX ring setting is 'short'. */
768dc13fee6SSepherosa Ziehau 	if (sc->hn_rndis_agg_align > SHRT_MAX) {
769dc13fee6SSepherosa Ziehau 		/* Disable */
770dc13fee6SSepherosa Ziehau 		size = 0;
771dc13fee6SSepherosa Ziehau 		pkts = 0;
772dc13fee6SSepherosa Ziehau 	}
773dc13fee6SSepherosa Ziehau 
774dc13fee6SSepherosa Ziehau 	if (bootverbose) {
775dc13fee6SSepherosa Ziehau 		if_printf(sc->hn_ifp, "TX agg size %u, pkts %u, align %u\n",
776dc13fee6SSepherosa Ziehau 		    size, pkts, sc->hn_rndis_agg_align);
777dc13fee6SSepherosa Ziehau 	}
778dc13fee6SSepherosa Ziehau 
779dc13fee6SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
780dc13fee6SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
781dc13fee6SSepherosa Ziehau 
782dc13fee6SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
783dc13fee6SSepherosa Ziehau 		txr->hn_agg_szmax = size;
784dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktmax = pkts;
785dc13fee6SSepherosa Ziehau 		txr->hn_agg_align = sc->hn_rndis_agg_align;
786dc13fee6SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
787dc13fee6SSepherosa Ziehau 	}
788dc13fee6SSepherosa Ziehau }
789dc13fee6SSepherosa Ziehau 
79015516c77SSepherosa Ziehau static int
79115516c77SSepherosa Ziehau hn_get_txswq_depth(const struct hn_tx_ring *txr)
79215516c77SSepherosa Ziehau {
79315516c77SSepherosa Ziehau 
79415516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_cnt > 0, ("tx ring is not setup yet"));
79515516c77SSepherosa Ziehau 	if (hn_tx_swq_depth < txr->hn_txdesc_cnt)
79615516c77SSepherosa Ziehau 		return txr->hn_txdesc_cnt;
79715516c77SSepherosa Ziehau 	return hn_tx_swq_depth;
79815516c77SSepherosa Ziehau }
79915516c77SSepherosa Ziehau 
800*34d68912SSepherosa Ziehau #ifndef RSS
80115516c77SSepherosa Ziehau static int
80215516c77SSepherosa Ziehau hn_rss_reconfig(struct hn_softc *sc)
80315516c77SSepherosa Ziehau {
80415516c77SSepherosa Ziehau 	int error;
80515516c77SSepherosa Ziehau 
80615516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
80715516c77SSepherosa Ziehau 
80815516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
80915516c77SSepherosa Ziehau 		return (ENXIO);
81015516c77SSepherosa Ziehau 
81115516c77SSepherosa Ziehau 	/*
81215516c77SSepherosa Ziehau 	 * Disable RSS first.
81315516c77SSepherosa Ziehau 	 *
81415516c77SSepherosa Ziehau 	 * NOTE:
81515516c77SSepherosa Ziehau 	 * Direct reconfiguration by setting the UNCHG flags does
81615516c77SSepherosa Ziehau 	 * _not_ work properly.
81715516c77SSepherosa Ziehau 	 */
81815516c77SSepherosa Ziehau 	if (bootverbose)
81915516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "disable RSS\n");
82015516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE);
82115516c77SSepherosa Ziehau 	if (error) {
82215516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS disable failed\n");
82315516c77SSepherosa Ziehau 		return (error);
82415516c77SSepherosa Ziehau 	}
82515516c77SSepherosa Ziehau 
82615516c77SSepherosa Ziehau 	/*
82715516c77SSepherosa Ziehau 	 * Reenable the RSS w/ the updated RSS key or indirect
82815516c77SSepherosa Ziehau 	 * table.
82915516c77SSepherosa Ziehau 	 */
83015516c77SSepherosa Ziehau 	if (bootverbose)
83115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "reconfig RSS\n");
83215516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
83315516c77SSepherosa Ziehau 	if (error) {
83415516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RSS reconfig failed\n");
83515516c77SSepherosa Ziehau 		return (error);
83615516c77SSepherosa Ziehau 	}
83715516c77SSepherosa Ziehau 	return (0);
83815516c77SSepherosa Ziehau }
839*34d68912SSepherosa Ziehau #endif	/* !RSS */
84015516c77SSepherosa Ziehau 
84115516c77SSepherosa Ziehau static void
842afd4971bSSepherosa Ziehau hn_rss_ind_fixup(struct hn_softc *sc)
84315516c77SSepherosa Ziehau {
84415516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
845afd4971bSSepherosa Ziehau 	int i, nchan;
84615516c77SSepherosa Ziehau 
847afd4971bSSepherosa Ziehau 	nchan = sc->hn_rx_ring_inuse;
84815516c77SSepherosa Ziehau 	KASSERT(nchan > 1, ("invalid # of channels %d", nchan));
84915516c77SSepherosa Ziehau 
85015516c77SSepherosa Ziehau 	/*
85115516c77SSepherosa Ziehau 	 * Check indirect table to make sure that all channels in it
85215516c77SSepherosa Ziehau 	 * can be used.
85315516c77SSepherosa Ziehau 	 */
85415516c77SSepherosa Ziehau 	for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
85515516c77SSepherosa Ziehau 		if (rss->rss_ind[i] >= nchan) {
85615516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp,
85715516c77SSepherosa Ziehau 			    "RSS indirect table %d fixup: %u -> %d\n",
85815516c77SSepherosa Ziehau 			    i, rss->rss_ind[i], nchan - 1);
85915516c77SSepherosa Ziehau 			rss->rss_ind[i] = nchan - 1;
86015516c77SSepherosa Ziehau 		}
86115516c77SSepherosa Ziehau 	}
86215516c77SSepherosa Ziehau }
86315516c77SSepherosa Ziehau 
86415516c77SSepherosa Ziehau static int
86515516c77SSepherosa Ziehau hn_ifmedia_upd(struct ifnet *ifp __unused)
86615516c77SSepherosa Ziehau {
86715516c77SSepherosa Ziehau 
86815516c77SSepherosa Ziehau 	return EOPNOTSUPP;
86915516c77SSepherosa Ziehau }
87015516c77SSepherosa Ziehau 
87115516c77SSepherosa Ziehau static void
87215516c77SSepherosa Ziehau hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
87315516c77SSepherosa Ziehau {
87415516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
87515516c77SSepherosa Ziehau 
87615516c77SSepherosa Ziehau 	ifmr->ifm_status = IFM_AVALID;
87715516c77SSepherosa Ziehau 	ifmr->ifm_active = IFM_ETHER;
87815516c77SSepherosa Ziehau 
87915516c77SSepherosa Ziehau 	if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) {
88015516c77SSepherosa Ziehau 		ifmr->ifm_active |= IFM_NONE;
88115516c77SSepherosa Ziehau 		return;
88215516c77SSepherosa Ziehau 	}
88315516c77SSepherosa Ziehau 	ifmr->ifm_status |= IFM_ACTIVE;
88415516c77SSepherosa Ziehau 	ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
88515516c77SSepherosa Ziehau }
88615516c77SSepherosa Ziehau 
88715516c77SSepherosa Ziehau /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
88815516c77SSepherosa Ziehau static const struct hyperv_guid g_net_vsc_device_type = {
88915516c77SSepherosa Ziehau 	.hv_guid = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
89015516c77SSepherosa Ziehau 		0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E}
89115516c77SSepherosa Ziehau };
89215516c77SSepherosa Ziehau 
89315516c77SSepherosa Ziehau static int
89415516c77SSepherosa Ziehau hn_probe(device_t dev)
89515516c77SSepherosa Ziehau {
89615516c77SSepherosa Ziehau 
89715516c77SSepherosa Ziehau 	if (VMBUS_PROBE_GUID(device_get_parent(dev), dev,
89815516c77SSepherosa Ziehau 	    &g_net_vsc_device_type) == 0) {
89915516c77SSepherosa Ziehau 		device_set_desc(dev, "Hyper-V Network Interface");
90015516c77SSepherosa Ziehau 		return BUS_PROBE_DEFAULT;
90115516c77SSepherosa Ziehau 	}
90215516c77SSepherosa Ziehau 	return ENXIO;
90315516c77SSepherosa Ziehau }
90415516c77SSepherosa Ziehau 
90515516c77SSepherosa Ziehau static int
90615516c77SSepherosa Ziehau hn_attach(device_t dev)
90715516c77SSepherosa Ziehau {
90815516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
90915516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
91015516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
91115516c77SSepherosa Ziehau 	uint8_t eaddr[ETHER_ADDR_LEN];
91215516c77SSepherosa Ziehau 	struct ifnet *ifp = NULL;
91315516c77SSepherosa Ziehau 	int error, ring_cnt, tx_ring_cnt;
91415516c77SSepherosa Ziehau 
91515516c77SSepherosa Ziehau 	sc->hn_dev = dev;
91615516c77SSepherosa Ziehau 	sc->hn_prichan = vmbus_get_channel(dev);
91715516c77SSepherosa Ziehau 	HN_LOCK_INIT(sc);
91815516c77SSepherosa Ziehau 
91915516c77SSepherosa Ziehau 	/*
920dc13fee6SSepherosa Ziehau 	 * Initialize these tunables once.
921dc13fee6SSepherosa Ziehau 	 */
922dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = hn_tx_agg_size;
923dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = hn_tx_agg_pkts;
924dc13fee6SSepherosa Ziehau 
925dc13fee6SSepherosa Ziehau 	/*
92615516c77SSepherosa Ziehau 	 * Setup taskqueue for transmission.
92715516c77SSepherosa Ziehau 	 */
9280e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_INDEP) {
929fdd0222aSSepherosa Ziehau 		int i;
930fdd0222aSSepherosa Ziehau 
931fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs =
932fdd0222aSSepherosa Ziehau 		    malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
933fdd0222aSSepherosa Ziehau 		    M_DEVBUF, M_WAITOK);
934fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i) {
935fdd0222aSSepherosa Ziehau 			sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx",
936fdd0222aSSepherosa Ziehau 			    M_WAITOK, taskqueue_thread_enqueue,
937fdd0222aSSepherosa Ziehau 			    &sc->hn_tx_taskqs[i]);
938fdd0222aSSepherosa Ziehau 			taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET,
939fdd0222aSSepherosa Ziehau 			    "%s tx%d", device_get_nameunit(dev), i);
940fdd0222aSSepherosa Ziehau 		}
9410e11868dSSepherosa Ziehau 	} else if (hn_tx_taskq_mode == HN_TX_TASKQ_M_GLOBAL) {
942fdd0222aSSepherosa Ziehau 		sc->hn_tx_taskqs = hn_tx_taskque;
94315516c77SSepherosa Ziehau 	}
94415516c77SSepherosa Ziehau 
94515516c77SSepherosa Ziehau 	/*
94615516c77SSepherosa Ziehau 	 * Setup taskqueue for mangement tasks, e.g. link status.
94715516c77SSepherosa Ziehau 	 */
94815516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK,
94915516c77SSepherosa Ziehau 	    taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0);
95015516c77SSepherosa Ziehau 	taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
95115516c77SSepherosa Ziehau 	    device_get_nameunit(dev));
95215516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
95315516c77SSepherosa Ziehau 	TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc);
95415516c77SSepherosa Ziehau 	TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0,
95515516c77SSepherosa Ziehau 	    hn_netchg_status_taskfunc, sc);
95615516c77SSepherosa Ziehau 
95715516c77SSepherosa Ziehau 	/*
95815516c77SSepherosa Ziehau 	 * Allocate ifnet and setup its name earlier, so that if_printf
95915516c77SSepherosa Ziehau 	 * can be used by functions, which will be called after
96015516c77SSepherosa Ziehau 	 * ether_ifattach().
96115516c77SSepherosa Ziehau 	 */
96215516c77SSepherosa Ziehau 	ifp = sc->hn_ifp = if_alloc(IFT_ETHER);
96315516c77SSepherosa Ziehau 	ifp->if_softc = sc;
96415516c77SSepherosa Ziehau 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
96515516c77SSepherosa Ziehau 
96615516c77SSepherosa Ziehau 	/*
96715516c77SSepherosa Ziehau 	 * Initialize ifmedia earlier so that it can be unconditionally
96815516c77SSepherosa Ziehau 	 * destroyed, if error happened later on.
96915516c77SSepherosa Ziehau 	 */
97015516c77SSepherosa Ziehau 	ifmedia_init(&sc->hn_media, 0, hn_ifmedia_upd, hn_ifmedia_sts);
97115516c77SSepherosa Ziehau 
97215516c77SSepherosa Ziehau 	/*
97315516c77SSepherosa Ziehau 	 * Figure out the # of RX rings (ring_cnt) and the # of TX rings
97415516c77SSepherosa Ziehau 	 * to use (tx_ring_cnt).
97515516c77SSepherosa Ziehau 	 *
97615516c77SSepherosa Ziehau 	 * NOTE:
97715516c77SSepherosa Ziehau 	 * The # of RX rings to use is same as the # of channels to use.
97815516c77SSepherosa Ziehau 	 */
97915516c77SSepherosa Ziehau 	ring_cnt = hn_chan_cnt;
98015516c77SSepherosa Ziehau 	if (ring_cnt <= 0) {
98115516c77SSepherosa Ziehau 		/* Default */
98215516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
98315516c77SSepherosa Ziehau 		if (ring_cnt > HN_RING_CNT_DEF_MAX)
98415516c77SSepherosa Ziehau 			ring_cnt = HN_RING_CNT_DEF_MAX;
98515516c77SSepherosa Ziehau 	} else if (ring_cnt > mp_ncpus) {
98615516c77SSepherosa Ziehau 		ring_cnt = mp_ncpus;
98715516c77SSepherosa Ziehau 	}
988*34d68912SSepherosa Ziehau #ifdef RSS
989*34d68912SSepherosa Ziehau 	if (ring_cnt > rss_getnumbuckets())
990*34d68912SSepherosa Ziehau 		ring_cnt = rss_getnumbuckets();
991*34d68912SSepherosa Ziehau #endif
99215516c77SSepherosa Ziehau 
99315516c77SSepherosa Ziehau 	tx_ring_cnt = hn_tx_ring_cnt;
99415516c77SSepherosa Ziehau 	if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt)
99515516c77SSepherosa Ziehau 		tx_ring_cnt = ring_cnt;
99623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
99715516c77SSepherosa Ziehau 	if (hn_use_if_start) {
99815516c77SSepherosa Ziehau 		/* ifnet.if_start only needs one TX ring. */
99915516c77SSepherosa Ziehau 		tx_ring_cnt = 1;
100015516c77SSepherosa Ziehau 	}
100123bf9e15SSepherosa Ziehau #endif
100215516c77SSepherosa Ziehau 
100315516c77SSepherosa Ziehau 	/*
100415516c77SSepherosa Ziehau 	 * Set the leader CPU for channels.
100515516c77SSepherosa Ziehau 	 */
100615516c77SSepherosa Ziehau 	sc->hn_cpu = atomic_fetchadd_int(&hn_cpu_index, ring_cnt) % mp_ncpus;
100715516c77SSepherosa Ziehau 
100815516c77SSepherosa Ziehau 	/*
100915516c77SSepherosa Ziehau 	 * Create enough TX/RX rings, even if only limited number of
101015516c77SSepherosa Ziehau 	 * channels can be allocated.
101115516c77SSepherosa Ziehau 	 */
101215516c77SSepherosa Ziehau 	error = hn_create_tx_data(sc, tx_ring_cnt);
101315516c77SSepherosa Ziehau 	if (error)
101415516c77SSepherosa Ziehau 		goto failed;
101515516c77SSepherosa Ziehau 	error = hn_create_rx_data(sc, ring_cnt);
101615516c77SSepherosa Ziehau 	if (error)
101715516c77SSepherosa Ziehau 		goto failed;
101815516c77SSepherosa Ziehau 
101915516c77SSepherosa Ziehau 	/*
102015516c77SSepherosa Ziehau 	 * Create transaction context for NVS and RNDIS transactions.
102115516c77SSepherosa Ziehau 	 */
102215516c77SSepherosa Ziehau 	sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
102315516c77SSepherosa Ziehau 	    HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
102425641fc7SSepherosa Ziehau 	if (sc->hn_xact == NULL) {
102525641fc7SSepherosa Ziehau 		error = ENXIO;
102615516c77SSepherosa Ziehau 		goto failed;
102725641fc7SSepherosa Ziehau 	}
102825641fc7SSepherosa Ziehau 
102925641fc7SSepherosa Ziehau 	/*
103025641fc7SSepherosa Ziehau 	 * Install orphan handler for the revocation of this device's
103125641fc7SSepherosa Ziehau 	 * primary channel.
103225641fc7SSepherosa Ziehau 	 *
103325641fc7SSepherosa Ziehau 	 * NOTE:
103425641fc7SSepherosa Ziehau 	 * The processing order is critical here:
103525641fc7SSepherosa Ziehau 	 * Install the orphan handler, _before_ testing whether this
103625641fc7SSepherosa Ziehau 	 * device's primary channel has been revoked or not.
103725641fc7SSepherosa Ziehau 	 */
103825641fc7SSepherosa Ziehau 	vmbus_chan_set_orphan(sc->hn_prichan, sc->hn_xact);
103925641fc7SSepherosa Ziehau 	if (vmbus_chan_is_revoked(sc->hn_prichan)) {
104025641fc7SSepherosa Ziehau 		error = ENXIO;
104125641fc7SSepherosa Ziehau 		goto failed;
104225641fc7SSepherosa Ziehau 	}
104315516c77SSepherosa Ziehau 
104415516c77SSepherosa Ziehau 	/*
104515516c77SSepherosa Ziehau 	 * Attach the synthetic parts, i.e. NVS and RNDIS.
104615516c77SSepherosa Ziehau 	 */
104715516c77SSepherosa Ziehau 	error = hn_synth_attach(sc, ETHERMTU);
104815516c77SSepherosa Ziehau 	if (error)
104915516c77SSepherosa Ziehau 		goto failed;
105015516c77SSepherosa Ziehau 
105115516c77SSepherosa Ziehau 	error = hn_rndis_get_eaddr(sc, eaddr);
105215516c77SSepherosa Ziehau 	if (error)
105315516c77SSepherosa Ziehau 		goto failed;
105415516c77SSepherosa Ziehau 
105515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
105615516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
105715516c77SSepherosa Ziehau 		/*
105815516c77SSepherosa Ziehau 		 * Reduce TCP segment aggregation limit for multiple
105915516c77SSepherosa Ziehau 		 * RX rings to increase ACK timeliness.
106015516c77SSepherosa Ziehau 		 */
106115516c77SSepherosa Ziehau 		hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF);
106215516c77SSepherosa Ziehau 	}
106315516c77SSepherosa Ziehau #endif
106415516c77SSepherosa Ziehau 
106515516c77SSepherosa Ziehau 	/*
106615516c77SSepherosa Ziehau 	 * Fixup TX stuffs after synthetic parts are attached.
106715516c77SSepherosa Ziehau 	 */
106815516c77SSepherosa Ziehau 	hn_fixup_tx_data(sc);
106915516c77SSepherosa Ziehau 
107015516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
107115516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
107215516c77SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "nvs_version", CTLFLAG_RD,
107315516c77SSepherosa Ziehau 	    &sc->hn_nvs_ver, 0, "NVS version");
107415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version",
107515516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
107615516c77SSepherosa Ziehau 	    hn_ndis_version_sysctl, "A", "NDIS version");
107715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "caps",
107815516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
107915516c77SSepherosa Ziehau 	    hn_caps_sysctl, "A", "capabilities");
108015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "hwassist",
108115516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
108215516c77SSepherosa Ziehau 	    hn_hwassist_sysctl, "A", "hwassist");
108315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter",
108415516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
108515516c77SSepherosa Ziehau 	    hn_rxfilter_sysctl, "A", "rxfilter");
108615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash",
108715516c77SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
108815516c77SSepherosa Ziehau 	    hn_rss_hash_sysctl, "A", "RSS hash");
108915516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size",
109015516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count");
1091*34d68912SSepherosa Ziehau #ifndef RSS
1092*34d68912SSepherosa Ziehau 	/*
1093*34d68912SSepherosa Ziehau 	 * Don't allow RSS key/indirect table changes, if RSS is defined.
1094*34d68912SSepherosa Ziehau 	 */
109515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key",
109615516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
109715516c77SSepherosa Ziehau 	    hn_rss_key_sysctl, "IU", "RSS key");
109815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind",
109915516c77SSepherosa Ziehau 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
110015516c77SSepherosa Ziehau 	    hn_rss_ind_sysctl, "IU", "RSS indirect table");
1101*34d68912SSepherosa Ziehau #endif
1102dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_size",
1103dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_size, 0,
1104dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation size limit");
1105dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_pkts",
1106dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_pkts, 0,
1107dc13fee6SSepherosa Ziehau 	    "RNDIS offered packet transmission aggregation count limit");
1108dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rndis_agg_align",
1109dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rndis_agg_align, 0,
1110dc13fee6SSepherosa Ziehau 	    "RNDIS packet transmission aggregation alignment");
1111dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_size",
1112dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
1113dc13fee6SSepherosa Ziehau 	    hn_txagg_size_sysctl, "I",
1114dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation size, 0 -- disable, -1 -- auto");
1115dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts",
1116dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
1117dc13fee6SSepherosa Ziehau 	    hn_txagg_pkts_sysctl, "I",
1118dc13fee6SSepherosa Ziehau 	    "Packet transmission aggregation packets, "
1119dc13fee6SSepherosa Ziehau 	    "0 -- disable, -1 -- auto");
112015516c77SSepherosa Ziehau 
112115516c77SSepherosa Ziehau 	/*
112215516c77SSepherosa Ziehau 	 * Setup the ifmedia, which has been initialized earlier.
112315516c77SSepherosa Ziehau 	 */
112415516c77SSepherosa Ziehau 	ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL);
112515516c77SSepherosa Ziehau 	ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO);
112615516c77SSepherosa Ziehau 	/* XXX ifmedia_set really should do this for us */
112715516c77SSepherosa Ziehau 	sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media;
112815516c77SSepherosa Ziehau 
112915516c77SSepherosa Ziehau 	/*
113015516c77SSepherosa Ziehau 	 * Setup the ifnet for this interface.
113115516c77SSepherosa Ziehau 	 */
113215516c77SSepherosa Ziehau 
113315516c77SSepherosa Ziehau 	ifp->if_baudrate = IF_Gbps(10);
113415516c77SSepherosa Ziehau 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
113515516c77SSepherosa Ziehau 	ifp->if_ioctl = hn_ioctl;
113615516c77SSepherosa Ziehau 	ifp->if_init = hn_init;
113723bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
113815516c77SSepherosa Ziehau 	if (hn_use_if_start) {
113915516c77SSepherosa Ziehau 		int qdepth = hn_get_txswq_depth(&sc->hn_tx_ring[0]);
114015516c77SSepherosa Ziehau 
114115516c77SSepherosa Ziehau 		ifp->if_start = hn_start;
114215516c77SSepherosa Ziehau 		IFQ_SET_MAXLEN(&ifp->if_snd, qdepth);
114315516c77SSepherosa Ziehau 		ifp->if_snd.ifq_drv_maxlen = qdepth - 1;
114415516c77SSepherosa Ziehau 		IFQ_SET_READY(&ifp->if_snd);
114523bf9e15SSepherosa Ziehau 	} else
114623bf9e15SSepherosa Ziehau #endif
114723bf9e15SSepherosa Ziehau 	{
114815516c77SSepherosa Ziehau 		ifp->if_transmit = hn_transmit;
114915516c77SSepherosa Ziehau 		ifp->if_qflush = hn_xmit_qflush;
115015516c77SSepherosa Ziehau 	}
115115516c77SSepherosa Ziehau 
115215516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_LRO;
115315516c77SSepherosa Ziehau #ifdef foo
115415516c77SSepherosa Ziehau 	/* We can't diff IPv6 packets from IPv4 packets on RX path. */
115515516c77SSepherosa Ziehau 	ifp->if_capabilities |= IFCAP_RXCSUM_IPV6;
115615516c77SSepherosa Ziehau #endif
115715516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_VLAN) {
115815516c77SSepherosa Ziehau 		/* XXX not sure about VLAN_MTU. */
115915516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
116015516c77SSepherosa Ziehau 	}
116115516c77SSepherosa Ziehau 
116215516c77SSepherosa Ziehau 	ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist;
116315516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP_MASK)
116415516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM;
116515516c77SSepherosa Ziehau 	if (ifp->if_hwassist & HN_CSUM_IP6_MASK)
116615516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TXCSUM_IPV6;
116715516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO4) {
116815516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO4;
116915516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP_TSO;
117015516c77SSepherosa Ziehau 	}
117115516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TSO6) {
117215516c77SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_TSO6;
117315516c77SSepherosa Ziehau 		ifp->if_hwassist |= CSUM_IP6_TSO;
117415516c77SSepherosa Ziehau 	}
117515516c77SSepherosa Ziehau 
117615516c77SSepherosa Ziehau 	/* Enable all available capabilities by default. */
117715516c77SSepherosa Ziehau 	ifp->if_capenable = ifp->if_capabilities;
117815516c77SSepherosa Ziehau 
11797960e6baSSepherosa Ziehau 	/*
11807960e6baSSepherosa Ziehau 	 * Disable IPv6 TSO and TXCSUM by default, they still can
11817960e6baSSepherosa Ziehau 	 * be enabled through SIOCSIFCAP.
11827960e6baSSepherosa Ziehau 	 */
11837960e6baSSepherosa Ziehau 	ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6);
11847960e6baSSepherosa Ziehau 	ifp->if_hwassist &= ~(HN_CSUM_IP6_MASK | CSUM_IP6_TSO);
11857960e6baSSepherosa Ziehau 
118615516c77SSepherosa Ziehau 	if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) {
118715516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU);
118815516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX;
118915516c77SSepherosa Ziehau 		ifp->if_hw_tsomaxsegsize = PAGE_SIZE;
119015516c77SSepherosa Ziehau 	}
119115516c77SSepherosa Ziehau 
119215516c77SSepherosa Ziehau 	ether_ifattach(ifp, eaddr);
119315516c77SSepherosa Ziehau 
119415516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) {
119515516c77SSepherosa Ziehau 		if_printf(ifp, "TSO segcnt %u segsz %u\n",
119615516c77SSepherosa Ziehau 		    ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize);
119715516c77SSepherosa Ziehau 	}
119815516c77SSepherosa Ziehau 
119915516c77SSepherosa Ziehau 	/* Inform the upper layer about the long frame support. */
120015516c77SSepherosa Ziehau 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
120115516c77SSepherosa Ziehau 
120215516c77SSepherosa Ziehau 	/*
120315516c77SSepherosa Ziehau 	 * Kick off link status check.
120415516c77SSepherosa Ziehau 	 */
120515516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
120615516c77SSepherosa Ziehau 	hn_update_link_status(sc);
120715516c77SSepherosa Ziehau 
120815516c77SSepherosa Ziehau 	return (0);
120915516c77SSepherosa Ziehau failed:
121015516c77SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)
121115516c77SSepherosa Ziehau 		hn_synth_detach(sc);
121215516c77SSepherosa Ziehau 	hn_detach(dev);
121315516c77SSepherosa Ziehau 	return (error);
121415516c77SSepherosa Ziehau }
121515516c77SSepherosa Ziehau 
121615516c77SSepherosa Ziehau static int
121715516c77SSepherosa Ziehau hn_detach(device_t dev)
121815516c77SSepherosa Ziehau {
121915516c77SSepherosa Ziehau 	struct hn_softc *sc = device_get_softc(dev);
122015516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
122115516c77SSepherosa Ziehau 
122225641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) {
122325641fc7SSepherosa Ziehau 		/*
122425641fc7SSepherosa Ziehau 		 * In case that the vmbus missed the orphan handler
122525641fc7SSepherosa Ziehau 		 * installation.
122625641fc7SSepherosa Ziehau 		 */
122725641fc7SSepherosa Ziehau 		vmbus_xact_ctx_orphan(sc->hn_xact);
122825641fc7SSepherosa Ziehau 	}
122925641fc7SSepherosa Ziehau 
123015516c77SSepherosa Ziehau 	if (device_is_attached(dev)) {
123115516c77SSepherosa Ziehau 		HN_LOCK(sc);
123215516c77SSepherosa Ziehau 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
123315516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
123415516c77SSepherosa Ziehau 				hn_stop(sc);
123515516c77SSepherosa Ziehau 			/*
123615516c77SSepherosa Ziehau 			 * NOTE:
123715516c77SSepherosa Ziehau 			 * hn_stop() only suspends data, so managment
123815516c77SSepherosa Ziehau 			 * stuffs have to be suspended manually here.
123915516c77SSepherosa Ziehau 			 */
124015516c77SSepherosa Ziehau 			hn_suspend_mgmt(sc);
124115516c77SSepherosa Ziehau 			hn_synth_detach(sc);
124215516c77SSepherosa Ziehau 		}
124315516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
124415516c77SSepherosa Ziehau 		ether_ifdetach(ifp);
124515516c77SSepherosa Ziehau 	}
124615516c77SSepherosa Ziehau 
124715516c77SSepherosa Ziehau 	ifmedia_removeall(&sc->hn_media);
124815516c77SSepherosa Ziehau 	hn_destroy_rx_data(sc);
124915516c77SSepherosa Ziehau 	hn_destroy_tx_data(sc);
125015516c77SSepherosa Ziehau 
12510e11868dSSepherosa Ziehau 	if (sc->hn_tx_taskqs != NULL && sc->hn_tx_taskqs != hn_tx_taskque) {
1252fdd0222aSSepherosa Ziehau 		int i;
1253fdd0222aSSepherosa Ziehau 
1254fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
1255fdd0222aSSepherosa Ziehau 			taskqueue_free(sc->hn_tx_taskqs[i]);
1256fdd0222aSSepherosa Ziehau 		free(sc->hn_tx_taskqs, M_DEVBUF);
1257fdd0222aSSepherosa Ziehau 	}
125815516c77SSepherosa Ziehau 	taskqueue_free(sc->hn_mgmt_taskq0);
125915516c77SSepherosa Ziehau 
126025641fc7SSepherosa Ziehau 	if (sc->hn_xact != NULL) {
126125641fc7SSepherosa Ziehau 		/*
126225641fc7SSepherosa Ziehau 		 * Uninstall the orphan handler _before_ the xact is
126325641fc7SSepherosa Ziehau 		 * destructed.
126425641fc7SSepherosa Ziehau 		 */
126525641fc7SSepherosa Ziehau 		vmbus_chan_unset_orphan(sc->hn_prichan);
126615516c77SSepherosa Ziehau 		vmbus_xact_ctx_destroy(sc->hn_xact);
126725641fc7SSepherosa Ziehau 	}
126815516c77SSepherosa Ziehau 
126915516c77SSepherosa Ziehau 	if_free(ifp);
127015516c77SSepherosa Ziehau 
127115516c77SSepherosa Ziehau 	HN_LOCK_DESTROY(sc);
127215516c77SSepherosa Ziehau 	return (0);
127315516c77SSepherosa Ziehau }
127415516c77SSepherosa Ziehau 
127515516c77SSepherosa Ziehau static int
127615516c77SSepherosa Ziehau hn_shutdown(device_t dev)
127715516c77SSepherosa Ziehau {
127815516c77SSepherosa Ziehau 
127915516c77SSepherosa Ziehau 	return (0);
128015516c77SSepherosa Ziehau }
128115516c77SSepherosa Ziehau 
128215516c77SSepherosa Ziehau static void
128315516c77SSepherosa Ziehau hn_link_status(struct hn_softc *sc)
128415516c77SSepherosa Ziehau {
128515516c77SSepherosa Ziehau 	uint32_t link_status;
128615516c77SSepherosa Ziehau 	int error;
128715516c77SSepherosa Ziehau 
128815516c77SSepherosa Ziehau 	error = hn_rndis_get_linkstatus(sc, &link_status);
128915516c77SSepherosa Ziehau 	if (error) {
129015516c77SSepherosa Ziehau 		/* XXX what to do? */
129115516c77SSepherosa Ziehau 		return;
129215516c77SSepherosa Ziehau 	}
129315516c77SSepherosa Ziehau 
129415516c77SSepherosa Ziehau 	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
129515516c77SSepherosa Ziehau 		sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
129615516c77SSepherosa Ziehau 	else
129715516c77SSepherosa Ziehau 		sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
129815516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp,
129915516c77SSepherosa Ziehau 	    (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ?
130015516c77SSepherosa Ziehau 	    LINK_STATE_UP : LINK_STATE_DOWN);
130115516c77SSepherosa Ziehau }
130215516c77SSepherosa Ziehau 
130315516c77SSepherosa Ziehau static void
130415516c77SSepherosa Ziehau hn_link_taskfunc(void *xsc, int pending __unused)
130515516c77SSepherosa Ziehau {
130615516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
130715516c77SSepherosa Ziehau 
130815516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
130915516c77SSepherosa Ziehau 		return;
131015516c77SSepherosa Ziehau 	hn_link_status(sc);
131115516c77SSepherosa Ziehau }
131215516c77SSepherosa Ziehau 
131315516c77SSepherosa Ziehau static void
131415516c77SSepherosa Ziehau hn_netchg_init_taskfunc(void *xsc, int pending __unused)
131515516c77SSepherosa Ziehau {
131615516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
131715516c77SSepherosa Ziehau 
131815516c77SSepherosa Ziehau 	/* Prevent any link status checks from running. */
131915516c77SSepherosa Ziehau 	sc->hn_link_flags |= HN_LINK_FLAG_NETCHG;
132015516c77SSepherosa Ziehau 
132115516c77SSepherosa Ziehau 	/*
132215516c77SSepherosa Ziehau 	 * Fake up a [link down --> link up] state change; 5 seconds
132315516c77SSepherosa Ziehau 	 * delay is used, which closely simulates miibus reaction
132415516c77SSepherosa Ziehau 	 * upon link down event.
132515516c77SSepherosa Ziehau 	 */
132615516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
132715516c77SSepherosa Ziehau 	if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
132815516c77SSepherosa Ziehau 	taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0,
132915516c77SSepherosa Ziehau 	    &sc->hn_netchg_status, 5 * hz);
133015516c77SSepherosa Ziehau }
133115516c77SSepherosa Ziehau 
133215516c77SSepherosa Ziehau static void
133315516c77SSepherosa Ziehau hn_netchg_status_taskfunc(void *xsc, int pending __unused)
133415516c77SSepherosa Ziehau {
133515516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
133615516c77SSepherosa Ziehau 
133715516c77SSepherosa Ziehau 	/* Re-allow link status checks. */
133815516c77SSepherosa Ziehau 	sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG;
133915516c77SSepherosa Ziehau 	hn_link_status(sc);
134015516c77SSepherosa Ziehau }
134115516c77SSepherosa Ziehau 
134215516c77SSepherosa Ziehau static void
134315516c77SSepherosa Ziehau hn_update_link_status(struct hn_softc *sc)
134415516c77SSepherosa Ziehau {
134515516c77SSepherosa Ziehau 
134615516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
134715516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
134815516c77SSepherosa Ziehau }
134915516c77SSepherosa Ziehau 
135015516c77SSepherosa Ziehau static void
135115516c77SSepherosa Ziehau hn_change_network(struct hn_softc *sc)
135215516c77SSepherosa Ziehau {
135315516c77SSepherosa Ziehau 
135415516c77SSepherosa Ziehau 	if (sc->hn_mgmt_taskq != NULL)
135515516c77SSepherosa Ziehau 		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init);
135615516c77SSepherosa Ziehau }
135715516c77SSepherosa Ziehau 
135815516c77SSepherosa Ziehau static __inline int
135915516c77SSepherosa Ziehau hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
136015516c77SSepherosa Ziehau     struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
136115516c77SSepherosa Ziehau {
136215516c77SSepherosa Ziehau 	struct mbuf *m = *m_head;
136315516c77SSepherosa Ziehau 	int error;
136415516c77SSepherosa Ziehau 
136515516c77SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID, ("txd uses chim"));
136615516c77SSepherosa Ziehau 
136715516c77SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag, txd->data_dmap,
136815516c77SSepherosa Ziehau 	    m, segs, nsegs, BUS_DMA_NOWAIT);
136915516c77SSepherosa Ziehau 	if (error == EFBIG) {
137015516c77SSepherosa Ziehau 		struct mbuf *m_new;
137115516c77SSepherosa Ziehau 
137215516c77SSepherosa Ziehau 		m_new = m_collapse(m, M_NOWAIT, HN_TX_DATA_SEGCNT_MAX);
137315516c77SSepherosa Ziehau 		if (m_new == NULL)
137415516c77SSepherosa Ziehau 			return ENOBUFS;
137515516c77SSepherosa Ziehau 		else
137615516c77SSepherosa Ziehau 			*m_head = m = m_new;
137715516c77SSepherosa Ziehau 		txr->hn_tx_collapsed++;
137815516c77SSepherosa Ziehau 
137915516c77SSepherosa Ziehau 		error = bus_dmamap_load_mbuf_sg(txr->hn_tx_data_dtag,
138015516c77SSepherosa Ziehau 		    txd->data_dmap, m, segs, nsegs, BUS_DMA_NOWAIT);
138115516c77SSepherosa Ziehau 	}
138215516c77SSepherosa Ziehau 	if (!error) {
138315516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag, txd->data_dmap,
138415516c77SSepherosa Ziehau 		    BUS_DMASYNC_PREWRITE);
138515516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_DMAMAP;
138615516c77SSepherosa Ziehau 	}
138715516c77SSepherosa Ziehau 	return error;
138815516c77SSepherosa Ziehau }
138915516c77SSepherosa Ziehau 
139015516c77SSepherosa Ziehau static __inline int
139115516c77SSepherosa Ziehau hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd)
139215516c77SSepherosa Ziehau {
139315516c77SSepherosa Ziehau 
139415516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONLIST) == 0,
139515516c77SSepherosa Ziehau 	    ("put an onlist txd %#x", txd->flags));
1396dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1397dc13fee6SSepherosa Ziehau 	    ("put an onagg txd %#x", txd->flags));
139815516c77SSepherosa Ziehau 
139915516c77SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
140015516c77SSepherosa Ziehau 	if (atomic_fetchadd_int(&txd->refs, -1) != 1)
140115516c77SSepherosa Ziehau 		return 0;
140215516c77SSepherosa Ziehau 
1403dc13fee6SSepherosa Ziehau 	if (!STAILQ_EMPTY(&txd->agg_list)) {
1404dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tmp_txd;
1405dc13fee6SSepherosa Ziehau 
1406dc13fee6SSepherosa Ziehau 		while ((tmp_txd = STAILQ_FIRST(&txd->agg_list)) != NULL) {
1407dc13fee6SSepherosa Ziehau 			int freed;
1408dc13fee6SSepherosa Ziehau 
1409dc13fee6SSepherosa Ziehau 			KASSERT(STAILQ_EMPTY(&tmp_txd->agg_list),
1410dc13fee6SSepherosa Ziehau 			    ("resursive aggregation on aggregated txdesc"));
1411dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_ONAGG),
1412dc13fee6SSepherosa Ziehau 			    ("not aggregated txdesc"));
1413dc13fee6SSepherosa Ziehau 			KASSERT((tmp_txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
1414dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc uses dmamap"));
1415dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
1416dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc consumes "
1417dc13fee6SSepherosa Ziehau 			     "chimney sending buffer"));
1418dc13fee6SSepherosa Ziehau 			KASSERT(tmp_txd->chim_size == 0,
1419dc13fee6SSepherosa Ziehau 			    ("aggregated txdesc has non-zero "
1420dc13fee6SSepherosa Ziehau 			     "chimney sending size"));
1421dc13fee6SSepherosa Ziehau 
1422dc13fee6SSepherosa Ziehau 			STAILQ_REMOVE_HEAD(&txd->agg_list, agg_link);
1423dc13fee6SSepherosa Ziehau 			tmp_txd->flags &= ~HN_TXD_FLAG_ONAGG;
1424dc13fee6SSepherosa Ziehau 			freed = hn_txdesc_put(txr, tmp_txd);
1425dc13fee6SSepherosa Ziehau 			KASSERT(freed, ("failed to free aggregated txdesc"));
1426dc13fee6SSepherosa Ziehau 		}
1427dc13fee6SSepherosa Ziehau 	}
1428dc13fee6SSepherosa Ziehau 
142915516c77SSepherosa Ziehau 	if (txd->chim_index != HN_NVS_CHIM_IDX_INVALID) {
143015516c77SSepherosa Ziehau 		KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0,
143115516c77SSepherosa Ziehau 		    ("chim txd uses dmamap"));
143215516c77SSepherosa Ziehau 		hn_chim_free(txr->hn_sc, txd->chim_index);
143315516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
1434dc13fee6SSepherosa Ziehau 		txd->chim_size = 0;
143515516c77SSepherosa Ziehau 	} else if (txd->flags & HN_TXD_FLAG_DMAMAP) {
143615516c77SSepherosa Ziehau 		bus_dmamap_sync(txr->hn_tx_data_dtag,
143715516c77SSepherosa Ziehau 		    txd->data_dmap, BUS_DMASYNC_POSTWRITE);
143815516c77SSepherosa Ziehau 		bus_dmamap_unload(txr->hn_tx_data_dtag,
143915516c77SSepherosa Ziehau 		    txd->data_dmap);
144015516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_DMAMAP;
144115516c77SSepherosa Ziehau 	}
144215516c77SSepherosa Ziehau 
144315516c77SSepherosa Ziehau 	if (txd->m != NULL) {
144415516c77SSepherosa Ziehau 		m_freem(txd->m);
144515516c77SSepherosa Ziehau 		txd->m = NULL;
144615516c77SSepherosa Ziehau 	}
144715516c77SSepherosa Ziehau 
144815516c77SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONLIST;
144915516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
145015516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
145115516c77SSepherosa Ziehau 	KASSERT(txr->hn_txdesc_avail >= 0 &&
145215516c77SSepherosa Ziehau 	    txr->hn_txdesc_avail < txr->hn_txdesc_cnt,
145315516c77SSepherosa Ziehau 	    ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail));
145415516c77SSepherosa Ziehau 	txr->hn_txdesc_avail++;
145515516c77SSepherosa Ziehau 	SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
145615516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
145785e4ae1eSSepherosa Ziehau #else	/* HN_USE_TXDESC_BUFRING */
145885e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
145915516c77SSepherosa Ziehau 	atomic_add_int(&txr->hn_txdesc_avail, 1);
146015516c77SSepherosa Ziehau #endif
146185e4ae1eSSepherosa Ziehau 	buf_ring_enqueue(txr->hn_txdesc_br, txd);
146285e4ae1eSSepherosa Ziehau #endif	/* !HN_USE_TXDESC_BUFRING */
146315516c77SSepherosa Ziehau 
146415516c77SSepherosa Ziehau 	return 1;
146515516c77SSepherosa Ziehau }
146615516c77SSepherosa Ziehau 
146715516c77SSepherosa Ziehau static __inline struct hn_txdesc *
146815516c77SSepherosa Ziehau hn_txdesc_get(struct hn_tx_ring *txr)
146915516c77SSepherosa Ziehau {
147015516c77SSepherosa Ziehau 	struct hn_txdesc *txd;
147115516c77SSepherosa Ziehau 
147215516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
147315516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
147415516c77SSepherosa Ziehau 	txd = SLIST_FIRST(&txr->hn_txlist);
147515516c77SSepherosa Ziehau 	if (txd != NULL) {
147615516c77SSepherosa Ziehau 		KASSERT(txr->hn_txdesc_avail > 0,
147715516c77SSepherosa Ziehau 		    ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail));
147815516c77SSepherosa Ziehau 		txr->hn_txdesc_avail--;
147915516c77SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&txr->hn_txlist, link);
148015516c77SSepherosa Ziehau 	}
148115516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
148215516c77SSepherosa Ziehau #else
148315516c77SSepherosa Ziehau 	txd = buf_ring_dequeue_sc(txr->hn_txdesc_br);
148415516c77SSepherosa Ziehau #endif
148515516c77SSepherosa Ziehau 
148615516c77SSepherosa Ziehau 	if (txd != NULL) {
148715516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
148885e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
148915516c77SSepherosa Ziehau 		atomic_subtract_int(&txr->hn_txdesc_avail, 1);
149015516c77SSepherosa Ziehau #endif
149185e4ae1eSSepherosa Ziehau #endif	/* HN_USE_TXDESC_BUFRING */
149215516c77SSepherosa Ziehau 		KASSERT(txd->m == NULL && txd->refs == 0 &&
1493dc13fee6SSepherosa Ziehau 		    STAILQ_EMPTY(&txd->agg_list) &&
149415516c77SSepherosa Ziehau 		    txd->chim_index == HN_NVS_CHIM_IDX_INVALID &&
1495dc13fee6SSepherosa Ziehau 		    txd->chim_size == 0 &&
149615516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONLIST) &&
1497dc13fee6SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_ONAGG) == 0 &&
149815516c77SSepherosa Ziehau 		    (txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("invalid txd"));
149915516c77SSepherosa Ziehau 		txd->flags &= ~HN_TXD_FLAG_ONLIST;
150015516c77SSepherosa Ziehau 		txd->refs = 1;
150115516c77SSepherosa Ziehau 	}
150215516c77SSepherosa Ziehau 	return txd;
150315516c77SSepherosa Ziehau }
150415516c77SSepherosa Ziehau 
150515516c77SSepherosa Ziehau static __inline void
150615516c77SSepherosa Ziehau hn_txdesc_hold(struct hn_txdesc *txd)
150715516c77SSepherosa Ziehau {
150815516c77SSepherosa Ziehau 
150915516c77SSepherosa Ziehau 	/* 0->1 transition will never work */
151025641fc7SSepherosa Ziehau 	KASSERT(txd->refs > 0, ("invalid txd refs %d", txd->refs));
151115516c77SSepherosa Ziehau 	atomic_add_int(&txd->refs, 1);
151215516c77SSepherosa Ziehau }
151315516c77SSepherosa Ziehau 
1514dc13fee6SSepherosa Ziehau static __inline void
1515dc13fee6SSepherosa Ziehau hn_txdesc_agg(struct hn_txdesc *agg_txd, struct hn_txdesc *txd)
1516dc13fee6SSepherosa Ziehau {
1517dc13fee6SSepherosa Ziehau 
1518dc13fee6SSepherosa Ziehau 	KASSERT((agg_txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1519dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on aggregating txdesc"));
1520dc13fee6SSepherosa Ziehau 
1521dc13fee6SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_ONAGG) == 0,
1522dc13fee6SSepherosa Ziehau 	    ("already aggregated"));
1523dc13fee6SSepherosa Ziehau 	KASSERT(STAILQ_EMPTY(&txd->agg_list),
1524dc13fee6SSepherosa Ziehau 	    ("recursive aggregation on to-be-aggregated txdesc"));
1525dc13fee6SSepherosa Ziehau 
1526dc13fee6SSepherosa Ziehau 	txd->flags |= HN_TXD_FLAG_ONAGG;
1527dc13fee6SSepherosa Ziehau 	STAILQ_INSERT_TAIL(&agg_txd->agg_list, txd, agg_link);
1528dc13fee6SSepherosa Ziehau }
1529dc13fee6SSepherosa Ziehau 
153015516c77SSepherosa Ziehau static bool
153115516c77SSepherosa Ziehau hn_tx_ring_pending(struct hn_tx_ring *txr)
153215516c77SSepherosa Ziehau {
153315516c77SSepherosa Ziehau 	bool pending = false;
153415516c77SSepherosa Ziehau 
153515516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
153615516c77SSepherosa Ziehau 	mtx_lock_spin(&txr->hn_txlist_spin);
153715516c77SSepherosa Ziehau 	if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt)
153815516c77SSepherosa Ziehau 		pending = true;
153915516c77SSepherosa Ziehau 	mtx_unlock_spin(&txr->hn_txlist_spin);
154015516c77SSepherosa Ziehau #else
154115516c77SSepherosa Ziehau 	if (!buf_ring_full(txr->hn_txdesc_br))
154215516c77SSepherosa Ziehau 		pending = true;
154315516c77SSepherosa Ziehau #endif
154415516c77SSepherosa Ziehau 	return (pending);
154515516c77SSepherosa Ziehau }
154615516c77SSepherosa Ziehau 
154715516c77SSepherosa Ziehau static __inline void
154815516c77SSepherosa Ziehau hn_txeof(struct hn_tx_ring *txr)
154915516c77SSepherosa Ziehau {
155015516c77SSepherosa Ziehau 	txr->hn_has_txeof = 0;
155115516c77SSepherosa Ziehau 	txr->hn_txeof(txr);
155215516c77SSepherosa Ziehau }
155315516c77SSepherosa Ziehau 
155415516c77SSepherosa Ziehau static void
155515516c77SSepherosa Ziehau hn_txpkt_done(struct hn_nvs_sendctx *sndc, struct hn_softc *sc,
155615516c77SSepherosa Ziehau     struct vmbus_channel *chan, const void *data __unused, int dlen __unused)
155715516c77SSepherosa Ziehau {
155815516c77SSepherosa Ziehau 	struct hn_txdesc *txd = sndc->hn_cbarg;
155915516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
156015516c77SSepherosa Ziehau 
156115516c77SSepherosa Ziehau 	txr = txd->txr;
156215516c77SSepherosa Ziehau 	KASSERT(txr->hn_chan == chan,
156315516c77SSepherosa Ziehau 	    ("channel mismatch, on chan%u, should be chan%u",
1564aa1a2adcSSepherosa Ziehau 	     vmbus_chan_id(chan), vmbus_chan_id(txr->hn_chan)));
156515516c77SSepherosa Ziehau 
156615516c77SSepherosa Ziehau 	txr->hn_has_txeof = 1;
156715516c77SSepherosa Ziehau 	hn_txdesc_put(txr, txd);
156815516c77SSepherosa Ziehau 
156915516c77SSepherosa Ziehau 	++txr->hn_txdone_cnt;
157015516c77SSepherosa Ziehau 	if (txr->hn_txdone_cnt >= HN_EARLY_TXEOF_THRESH) {
157115516c77SSepherosa Ziehau 		txr->hn_txdone_cnt = 0;
157215516c77SSepherosa Ziehau 		if (txr->hn_oactive)
157315516c77SSepherosa Ziehau 			hn_txeof(txr);
157415516c77SSepherosa Ziehau 	}
157515516c77SSepherosa Ziehau }
157615516c77SSepherosa Ziehau 
157715516c77SSepherosa Ziehau static void
157815516c77SSepherosa Ziehau hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
157915516c77SSepherosa Ziehau {
158015516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
158115516c77SSepherosa Ziehau 	tcp_lro_flush_all(&rxr->hn_lro);
158215516c77SSepherosa Ziehau #endif
158315516c77SSepherosa Ziehau 
158415516c77SSepherosa Ziehau 	/*
158515516c77SSepherosa Ziehau 	 * NOTE:
158615516c77SSepherosa Ziehau 	 * 'txr' could be NULL, if multiple channels and
158715516c77SSepherosa Ziehau 	 * ifnet.if_start method are enabled.
158815516c77SSepherosa Ziehau 	 */
158915516c77SSepherosa Ziehau 	if (txr == NULL || !txr->hn_has_txeof)
159015516c77SSepherosa Ziehau 		return;
159115516c77SSepherosa Ziehau 
159215516c77SSepherosa Ziehau 	txr->hn_txdone_cnt = 0;
159315516c77SSepherosa Ziehau 	hn_txeof(txr);
159415516c77SSepherosa Ziehau }
159515516c77SSepherosa Ziehau 
159615516c77SSepherosa Ziehau static __inline uint32_t
159715516c77SSepherosa Ziehau hn_rndis_pktmsg_offset(uint32_t ofs)
159815516c77SSepherosa Ziehau {
159915516c77SSepherosa Ziehau 
160015516c77SSepherosa Ziehau 	KASSERT(ofs >= sizeof(struct rndis_packet_msg),
160115516c77SSepherosa Ziehau 	    ("invalid RNDIS packet msg offset %u", ofs));
160215516c77SSepherosa Ziehau 	return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset));
160315516c77SSepherosa Ziehau }
160415516c77SSepherosa Ziehau 
160515516c77SSepherosa Ziehau static __inline void *
160615516c77SSepherosa Ziehau hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
160715516c77SSepherosa Ziehau     size_t pi_dlen, uint32_t pi_type)
160815516c77SSepherosa Ziehau {
160915516c77SSepherosa Ziehau 	const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
161015516c77SSepherosa Ziehau 	struct rndis_pktinfo *pi;
161115516c77SSepherosa Ziehau 
161215516c77SSepherosa Ziehau 	KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
161315516c77SSepherosa Ziehau 	    ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
161415516c77SSepherosa Ziehau 
161515516c77SSepherosa Ziehau 	/*
161615516c77SSepherosa Ziehau 	 * Per-packet-info does not move; it only grows.
161715516c77SSepherosa Ziehau 	 *
161815516c77SSepherosa Ziehau 	 * NOTE:
161915516c77SSepherosa Ziehau 	 * rm_pktinfooffset in this phase counts from the beginning
162015516c77SSepherosa Ziehau 	 * of rndis_packet_msg.
162115516c77SSepherosa Ziehau 	 */
162215516c77SSepherosa Ziehau 	KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
162315516c77SSepherosa Ziehau 	    ("%u pktinfo overflows RNDIS packet msg", pi_type));
162415516c77SSepherosa Ziehau 	pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
162515516c77SSepherosa Ziehau 	    pkt->rm_pktinfolen);
162615516c77SSepherosa Ziehau 	pkt->rm_pktinfolen += pi_size;
162715516c77SSepherosa Ziehau 
162815516c77SSepherosa Ziehau 	pi->rm_size = pi_size;
162915516c77SSepherosa Ziehau 	pi->rm_type = pi_type;
163015516c77SSepherosa Ziehau 	pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
163115516c77SSepherosa Ziehau 
163215516c77SSepherosa Ziehau 	/* Data immediately follow per-packet-info. */
163315516c77SSepherosa Ziehau 	pkt->rm_dataoffset += pi_size;
163415516c77SSepherosa Ziehau 
163515516c77SSepherosa Ziehau 	/* Update RNDIS packet msg length */
163615516c77SSepherosa Ziehau 	pkt->rm_len += pi_size;
163715516c77SSepherosa Ziehau 
163815516c77SSepherosa Ziehau 	return (pi->rm_data);
163915516c77SSepherosa Ziehau }
164015516c77SSepherosa Ziehau 
1641dc13fee6SSepherosa Ziehau static __inline int
1642dc13fee6SSepherosa Ziehau hn_flush_txagg(struct ifnet *ifp, struct hn_tx_ring *txr)
1643dc13fee6SSepherosa Ziehau {
1644dc13fee6SSepherosa Ziehau 	struct hn_txdesc *txd;
1645dc13fee6SSepherosa Ziehau 	struct mbuf *m;
1646dc13fee6SSepherosa Ziehau 	int error, pkts;
1647dc13fee6SSepherosa Ziehau 
1648dc13fee6SSepherosa Ziehau 	txd = txr->hn_agg_txd;
1649dc13fee6SSepherosa Ziehau 	KASSERT(txd != NULL, ("no aggregate txdesc"));
1650dc13fee6SSepherosa Ziehau 
1651dc13fee6SSepherosa Ziehau 	/*
1652dc13fee6SSepherosa Ziehau 	 * Since hn_txpkt() will reset this temporary stat, save
1653dc13fee6SSepherosa Ziehau 	 * it now, so that oerrors can be updated properly, if
1654dc13fee6SSepherosa Ziehau 	 * hn_txpkt() ever fails.
1655dc13fee6SSepherosa Ziehau 	 */
1656dc13fee6SSepherosa Ziehau 	pkts = txr->hn_stat_pkts;
1657dc13fee6SSepherosa Ziehau 
1658dc13fee6SSepherosa Ziehau 	/*
1659dc13fee6SSepherosa Ziehau 	 * Since txd's mbuf will _not_ be freed upon hn_txpkt()
1660dc13fee6SSepherosa Ziehau 	 * failure, save it for later freeing, if hn_txpkt() ever
1661dc13fee6SSepherosa Ziehau 	 * fails.
1662dc13fee6SSepherosa Ziehau 	 */
1663dc13fee6SSepherosa Ziehau 	m = txd->m;
1664dc13fee6SSepherosa Ziehau 	error = hn_txpkt(ifp, txr, txd);
1665dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
1666dc13fee6SSepherosa Ziehau 		/* txd is freed, but m is not. */
1667dc13fee6SSepherosa Ziehau 		m_freem(m);
1668dc13fee6SSepherosa Ziehau 
1669dc13fee6SSepherosa Ziehau 		txr->hn_flush_failed++;
1670dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, pkts);
1671dc13fee6SSepherosa Ziehau 	}
1672dc13fee6SSepherosa Ziehau 
1673dc13fee6SSepherosa Ziehau 	/* Reset all aggregation states. */
1674dc13fee6SSepherosa Ziehau 	txr->hn_agg_txd = NULL;
1675dc13fee6SSepherosa Ziehau 	txr->hn_agg_szleft = 0;
1676dc13fee6SSepherosa Ziehau 	txr->hn_agg_pktleft = 0;
1677dc13fee6SSepherosa Ziehau 	txr->hn_agg_prevpkt = NULL;
1678dc13fee6SSepherosa Ziehau 
1679dc13fee6SSepherosa Ziehau 	return (error);
1680dc13fee6SSepherosa Ziehau }
1681dc13fee6SSepherosa Ziehau 
1682dc13fee6SSepherosa Ziehau static void *
1683dc13fee6SSepherosa Ziehau hn_try_txagg(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
1684dc13fee6SSepherosa Ziehau     int pktsize)
1685dc13fee6SSepherosa Ziehau {
1686dc13fee6SSepherosa Ziehau 	void *chim;
1687dc13fee6SSepherosa Ziehau 
1688dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL) {
1689dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft >= 1 && txr->hn_agg_szleft > pktsize) {
1690dc13fee6SSepherosa Ziehau 			struct hn_txdesc *agg_txd = txr->hn_agg_txd;
1691dc13fee6SSepherosa Ziehau 			struct rndis_packet_msg *pkt = txr->hn_agg_prevpkt;
1692dc13fee6SSepherosa Ziehau 			int olen;
1693dc13fee6SSepherosa Ziehau 
1694dc13fee6SSepherosa Ziehau 			/*
1695dc13fee6SSepherosa Ziehau 			 * Update the previous RNDIS packet's total length,
1696dc13fee6SSepherosa Ziehau 			 * it can be increased due to the mandatory alignment
1697dc13fee6SSepherosa Ziehau 			 * padding for this RNDIS packet.  And update the
1698dc13fee6SSepherosa Ziehau 			 * aggregating txdesc's chimney sending buffer size
1699dc13fee6SSepherosa Ziehau 			 * accordingly.
1700dc13fee6SSepherosa Ziehau 			 *
1701dc13fee6SSepherosa Ziehau 			 * XXX
1702dc13fee6SSepherosa Ziehau 			 * Zero-out the padding, as required by the RNDIS spec.
1703dc13fee6SSepherosa Ziehau 			 */
1704dc13fee6SSepherosa Ziehau 			olen = pkt->rm_len;
1705dc13fee6SSepherosa Ziehau 			pkt->rm_len = roundup2(olen, txr->hn_agg_align);
1706dc13fee6SSepherosa Ziehau 			agg_txd->chim_size += pkt->rm_len - olen;
1707dc13fee6SSepherosa Ziehau 
1708dc13fee6SSepherosa Ziehau 			/* Link this txdesc to the parent. */
1709dc13fee6SSepherosa Ziehau 			hn_txdesc_agg(agg_txd, txd);
1710dc13fee6SSepherosa Ziehau 
1711dc13fee6SSepherosa Ziehau 			chim = (uint8_t *)pkt + pkt->rm_len;
1712dc13fee6SSepherosa Ziehau 			/* Save the current packet for later fixup. */
1713dc13fee6SSepherosa Ziehau 			txr->hn_agg_prevpkt = chim;
1714dc13fee6SSepherosa Ziehau 
1715dc13fee6SSepherosa Ziehau 			txr->hn_agg_pktleft--;
1716dc13fee6SSepherosa Ziehau 			txr->hn_agg_szleft -= pktsize;
1717dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_szleft <=
1718dc13fee6SSepherosa Ziehau 			    HN_PKTSIZE_MIN(txr->hn_agg_align)) {
1719dc13fee6SSepherosa Ziehau 				/*
1720dc13fee6SSepherosa Ziehau 				 * Probably can't aggregate more packets,
1721dc13fee6SSepherosa Ziehau 				 * flush this aggregating txdesc proactively.
1722dc13fee6SSepherosa Ziehau 				 */
1723dc13fee6SSepherosa Ziehau 				txr->hn_agg_pktleft = 0;
1724dc13fee6SSepherosa Ziehau 			}
1725dc13fee6SSepherosa Ziehau 			/* Done! */
1726dc13fee6SSepherosa Ziehau 			return (chim);
1727dc13fee6SSepherosa Ziehau 		}
1728dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
1729dc13fee6SSepherosa Ziehau 	}
1730dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
1731dc13fee6SSepherosa Ziehau 
1732dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney_tried++;
1733dc13fee6SSepherosa Ziehau 	txd->chim_index = hn_chim_alloc(txr->hn_sc);
1734dc13fee6SSepherosa Ziehau 	if (txd->chim_index == HN_NVS_CHIM_IDX_INVALID)
1735dc13fee6SSepherosa Ziehau 		return (NULL);
1736dc13fee6SSepherosa Ziehau 	txr->hn_tx_chimney++;
1737dc13fee6SSepherosa Ziehau 
1738dc13fee6SSepherosa Ziehau 	chim = txr->hn_sc->hn_chim +
1739dc13fee6SSepherosa Ziehau 	    (txd->chim_index * txr->hn_sc->hn_chim_szmax);
1740dc13fee6SSepherosa Ziehau 
1741dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_pktmax > 1 &&
1742dc13fee6SSepherosa Ziehau 	    txr->hn_agg_szmax > pktsize + HN_PKTSIZE_MIN(txr->hn_agg_align)) {
1743dc13fee6SSepherosa Ziehau 		txr->hn_agg_txd = txd;
1744dc13fee6SSepherosa Ziehau 		txr->hn_agg_pktleft = txr->hn_agg_pktmax - 1;
1745dc13fee6SSepherosa Ziehau 		txr->hn_agg_szleft = txr->hn_agg_szmax - pktsize;
1746dc13fee6SSepherosa Ziehau 		txr->hn_agg_prevpkt = chim;
1747dc13fee6SSepherosa Ziehau 	}
1748dc13fee6SSepherosa Ziehau 	return (chim);
1749dc13fee6SSepherosa Ziehau }
1750dc13fee6SSepherosa Ziehau 
175115516c77SSepherosa Ziehau /*
175215516c77SSepherosa Ziehau  * NOTE:
175315516c77SSepherosa Ziehau  * If this function fails, then both txd and m_head0 will be freed.
175415516c77SSepherosa Ziehau  */
175515516c77SSepherosa Ziehau static int
1756dc13fee6SSepherosa Ziehau hn_encap(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd,
1757dc13fee6SSepherosa Ziehau     struct mbuf **m_head0)
175815516c77SSepherosa Ziehau {
175915516c77SSepherosa Ziehau 	bus_dma_segment_t segs[HN_TX_DATA_SEGCNT_MAX];
176015516c77SSepherosa Ziehau 	int error, nsegs, i;
176115516c77SSepherosa Ziehau 	struct mbuf *m_head = *m_head0;
176215516c77SSepherosa Ziehau 	struct rndis_packet_msg *pkt;
176315516c77SSepherosa Ziehau 	uint32_t *pi_data;
17648966e5d5SSepherosa Ziehau 	void *chim = NULL;
1765dc13fee6SSepherosa Ziehau 	int pkt_hlen, pkt_size;
176615516c77SSepherosa Ziehau 
176715516c77SSepherosa Ziehau 	pkt = txd->rndis_pkt;
1768dc13fee6SSepherosa Ziehau 	pkt_size = HN_PKTSIZE(m_head, txr->hn_agg_align);
1769dc13fee6SSepherosa Ziehau 	if (pkt_size < txr->hn_chim_size) {
1770dc13fee6SSepherosa Ziehau 		chim = hn_try_txagg(ifp, txr, txd, pkt_size);
1771dc13fee6SSepherosa Ziehau 		if (chim != NULL)
17728966e5d5SSepherosa Ziehau 			pkt = chim;
1773dc13fee6SSepherosa Ziehau 	} else {
1774dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL)
1775dc13fee6SSepherosa Ziehau 			hn_flush_txagg(ifp, txr);
17768966e5d5SSepherosa Ziehau 	}
17778966e5d5SSepherosa Ziehau 
177815516c77SSepherosa Ziehau 	pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
177915516c77SSepherosa Ziehau 	pkt->rm_len = sizeof(*pkt) + m_head->m_pkthdr.len;
178015516c77SSepherosa Ziehau 	pkt->rm_dataoffset = sizeof(*pkt);
178115516c77SSepherosa Ziehau 	pkt->rm_datalen = m_head->m_pkthdr.len;
1782dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataoffset = 0;
1783dc13fee6SSepherosa Ziehau 	pkt->rm_oobdatalen = 0;
1784dc13fee6SSepherosa Ziehau 	pkt->rm_oobdataelements = 0;
178515516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = sizeof(*pkt);
178615516c77SSepherosa Ziehau 	pkt->rm_pktinfolen = 0;
1787dc13fee6SSepherosa Ziehau 	pkt->rm_vchandle = 0;
1788dc13fee6SSepherosa Ziehau 	pkt->rm_reserved = 0;
178915516c77SSepherosa Ziehau 
179015516c77SSepherosa Ziehau 	if (txr->hn_tx_flags & HN_TX_FLAG_HASHVAL) {
179115516c77SSepherosa Ziehau 		/*
179215516c77SSepherosa Ziehau 		 * Set the hash value for this packet, so that the host could
179315516c77SSepherosa Ziehau 		 * dispatch the TX done event for this packet back to this TX
179415516c77SSepherosa Ziehau 		 * ring's channel.
179515516c77SSepherosa Ziehau 		 */
179615516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
179715516c77SSepherosa Ziehau 		    HN_NDIS_HASH_VALUE_SIZE, HN_NDIS_PKTINFO_TYPE_HASHVAL);
179815516c77SSepherosa Ziehau 		*pi_data = txr->hn_tx_idx;
179915516c77SSepherosa Ziehau 	}
180015516c77SSepherosa Ziehau 
180115516c77SSepherosa Ziehau 	if (m_head->m_flags & M_VLANTAG) {
180215516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
180315516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
180415516c77SSepherosa Ziehau 		*pi_data = NDIS_VLAN_INFO_MAKE(
180515516c77SSepherosa Ziehau 		    EVL_VLANOFTAG(m_head->m_pkthdr.ether_vtag),
180615516c77SSepherosa Ziehau 		    EVL_PRIOFTAG(m_head->m_pkthdr.ether_vtag),
180715516c77SSepherosa Ziehau 		    EVL_CFIOFTAG(m_head->m_pkthdr.ether_vtag));
180815516c77SSepherosa Ziehau 	}
180915516c77SSepherosa Ziehau 
181015516c77SSepherosa Ziehau 	if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
181115516c77SSepherosa Ziehau #if defined(INET6) || defined(INET)
181215516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
181315516c77SSepherosa Ziehau 		    NDIS_LSO2_INFO_SIZE, NDIS_PKTINFO_TYPE_LSO);
181415516c77SSepherosa Ziehau #ifdef INET
181515516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_IP_TSO) {
181615516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV4(0,
181715516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
181815516c77SSepherosa Ziehau 		}
181915516c77SSepherosa Ziehau #endif
182015516c77SSepherosa Ziehau #if defined(INET6) && defined(INET)
182115516c77SSepherosa Ziehau 		else
182215516c77SSepherosa Ziehau #endif
182315516c77SSepherosa Ziehau #ifdef INET6
182415516c77SSepherosa Ziehau 		{
182515516c77SSepherosa Ziehau 			*pi_data = NDIS_LSO2_INFO_MAKEIPV6(0,
182615516c77SSepherosa Ziehau 			    m_head->m_pkthdr.tso_segsz);
182715516c77SSepherosa Ziehau 		}
182815516c77SSepherosa Ziehau #endif
182915516c77SSepherosa Ziehau #endif	/* INET6 || INET */
183015516c77SSepherosa Ziehau 	} else if (m_head->m_pkthdr.csum_flags & txr->hn_csum_assist) {
183115516c77SSepherosa Ziehau 		pi_data = hn_rndis_pktinfo_append(pkt, HN_RNDIS_PKT_LEN,
183215516c77SSepherosa Ziehau 		    NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
183315516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags &
183415516c77SSepherosa Ziehau 		    (CSUM_IP6_TCP | CSUM_IP6_UDP)) {
183515516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV6;
183615516c77SSepherosa Ziehau 		} else {
183715516c77SSepherosa Ziehau 			*pi_data = NDIS_TXCSUM_INFO_IPV4;
183815516c77SSepherosa Ziehau 			if (m_head->m_pkthdr.csum_flags & CSUM_IP)
183915516c77SSepherosa Ziehau 				*pi_data |= NDIS_TXCSUM_INFO_IPCS;
184015516c77SSepherosa Ziehau 		}
184115516c77SSepherosa Ziehau 
184215516c77SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP))
184315516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_TCPCS;
184415516c77SSepherosa Ziehau 		else if (m_head->m_pkthdr.csum_flags &
184515516c77SSepherosa Ziehau 		    (CSUM_IP_UDP | CSUM_IP6_UDP))
184615516c77SSepherosa Ziehau 			*pi_data |= NDIS_TXCSUM_INFO_UDPCS;
184715516c77SSepherosa Ziehau 	}
184815516c77SSepherosa Ziehau 
1849dc13fee6SSepherosa Ziehau 	pkt_hlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
185015516c77SSepherosa Ziehau 	/* Convert RNDIS packet message offsets */
185115516c77SSepherosa Ziehau 	pkt->rm_dataoffset = hn_rndis_pktmsg_offset(pkt->rm_dataoffset);
185215516c77SSepherosa Ziehau 	pkt->rm_pktinfooffset = hn_rndis_pktmsg_offset(pkt->rm_pktinfooffset);
185315516c77SSepherosa Ziehau 
185415516c77SSepherosa Ziehau 	/*
18558966e5d5SSepherosa Ziehau 	 * Fast path: Chimney sending.
185615516c77SSepherosa Ziehau 	 */
18578966e5d5SSepherosa Ziehau 	if (chim != NULL) {
1858dc13fee6SSepherosa Ziehau 		struct hn_txdesc *tgt_txd = txd;
1859dc13fee6SSepherosa Ziehau 
1860dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_txd != NULL) {
1861dc13fee6SSepherosa Ziehau 			tgt_txd = txr->hn_agg_txd;
1862dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
1863dc13fee6SSepherosa Ziehau 			*m_head0 = NULL;
1864dc13fee6SSepherosa Ziehau #endif
1865dc13fee6SSepherosa Ziehau 		}
1866dc13fee6SSepherosa Ziehau 
1867dc13fee6SSepherosa Ziehau 		KASSERT(pkt == chim,
1868dc13fee6SSepherosa Ziehau 		    ("RNDIS pkt not in chimney sending buffer"));
1869dc13fee6SSepherosa Ziehau 		KASSERT(tgt_txd->chim_index != HN_NVS_CHIM_IDX_INVALID,
1870dc13fee6SSepherosa Ziehau 		    ("chimney sending buffer is not used"));
1871dc13fee6SSepherosa Ziehau 		tgt_txd->chim_size += pkt->rm_len;
187215516c77SSepherosa Ziehau 
18738966e5d5SSepherosa Ziehau 		m_copydata(m_head, 0, m_head->m_pkthdr.len,
1874dc13fee6SSepherosa Ziehau 		    ((uint8_t *)chim) + pkt_hlen);
187515516c77SSepherosa Ziehau 
187615516c77SSepherosa Ziehau 		txr->hn_gpa_cnt = 0;
187715516c77SSepherosa Ziehau 		txr->hn_sendpkt = hn_txpkt_chim;
187815516c77SSepherosa Ziehau 		goto done;
187915516c77SSepherosa Ziehau 	}
1880dc13fee6SSepherosa Ziehau 
1881dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("aggregating sglist txdesc"));
18828966e5d5SSepherosa Ziehau 	KASSERT(txd->chim_index == HN_NVS_CHIM_IDX_INVALID,
18838966e5d5SSepherosa Ziehau 	    ("chimney buffer is used"));
18848966e5d5SSepherosa Ziehau 	KASSERT(pkt == txd->rndis_pkt, ("RNDIS pkt not in txdesc"));
188515516c77SSepherosa Ziehau 
188615516c77SSepherosa Ziehau 	error = hn_txdesc_dmamap_load(txr, txd, &m_head, segs, &nsegs);
1887dc13fee6SSepherosa Ziehau 	if (__predict_false(error)) {
188815516c77SSepherosa Ziehau 		int freed;
188915516c77SSepherosa Ziehau 
189015516c77SSepherosa Ziehau 		/*
189115516c77SSepherosa Ziehau 		 * This mbuf is not linked w/ the txd yet, so free it now.
189215516c77SSepherosa Ziehau 		 */
189315516c77SSepherosa Ziehau 		m_freem(m_head);
189415516c77SSepherosa Ziehau 		*m_head0 = NULL;
189515516c77SSepherosa Ziehau 
189615516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
189715516c77SSepherosa Ziehau 		KASSERT(freed != 0,
189815516c77SSepherosa Ziehau 		    ("fail to free txd upon txdma error"));
189915516c77SSepherosa Ziehau 
190015516c77SSepherosa Ziehau 		txr->hn_txdma_failed++;
1901dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
190215516c77SSepherosa Ziehau 		return error;
190315516c77SSepherosa Ziehau 	}
190415516c77SSepherosa Ziehau 	*m_head0 = m_head;
190515516c77SSepherosa Ziehau 
190615516c77SSepherosa Ziehau 	/* +1 RNDIS packet message */
190715516c77SSepherosa Ziehau 	txr->hn_gpa_cnt = nsegs + 1;
190815516c77SSepherosa Ziehau 
190915516c77SSepherosa Ziehau 	/* send packet with page buffer */
191015516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_page = atop(txd->rndis_pkt_paddr);
191115516c77SSepherosa Ziehau 	txr->hn_gpa[0].gpa_ofs = txd->rndis_pkt_paddr & PAGE_MASK;
1912dc13fee6SSepherosa Ziehau 	txr->hn_gpa[0].gpa_len = pkt_hlen;
191315516c77SSepherosa Ziehau 
191415516c77SSepherosa Ziehau 	/*
191515516c77SSepherosa Ziehau 	 * Fill the page buffers with mbuf info after the page
191615516c77SSepherosa Ziehau 	 * buffer for RNDIS packet message.
191715516c77SSepherosa Ziehau 	 */
191815516c77SSepherosa Ziehau 	for (i = 0; i < nsegs; ++i) {
191915516c77SSepherosa Ziehau 		struct vmbus_gpa *gpa = &txr->hn_gpa[i + 1];
192015516c77SSepherosa Ziehau 
192115516c77SSepherosa Ziehau 		gpa->gpa_page = atop(segs[i].ds_addr);
192215516c77SSepherosa Ziehau 		gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK;
192315516c77SSepherosa Ziehau 		gpa->gpa_len = segs[i].ds_len;
192415516c77SSepherosa Ziehau 	}
192515516c77SSepherosa Ziehau 
192615516c77SSepherosa Ziehau 	txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
192715516c77SSepherosa Ziehau 	txd->chim_size = 0;
192815516c77SSepherosa Ziehau 	txr->hn_sendpkt = hn_txpkt_sglist;
192915516c77SSepherosa Ziehau done:
193015516c77SSepherosa Ziehau 	txd->m = m_head;
193115516c77SSepherosa Ziehau 
193215516c77SSepherosa Ziehau 	/* Set the completion routine */
193315516c77SSepherosa Ziehau 	hn_nvs_sendctx_init(&txd->send_ctx, hn_txpkt_done, txd);
193415516c77SSepherosa Ziehau 
1935dc13fee6SSepherosa Ziehau 	/* Update temporary stats for later use. */
1936dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts++;
1937dc13fee6SSepherosa Ziehau 	txr->hn_stat_size += m_head->m_pkthdr.len;
1938dc13fee6SSepherosa Ziehau 	if (m_head->m_flags & M_MCAST)
1939dc13fee6SSepherosa Ziehau 		txr->hn_stat_mcasts++;
1940dc13fee6SSepherosa Ziehau 
194115516c77SSepherosa Ziehau 	return 0;
194215516c77SSepherosa Ziehau }
194315516c77SSepherosa Ziehau 
194415516c77SSepherosa Ziehau /*
194515516c77SSepherosa Ziehau  * NOTE:
194615516c77SSepherosa Ziehau  * If this function fails, then txd will be freed, but the mbuf
194715516c77SSepherosa Ziehau  * associated w/ the txd will _not_ be freed.
194815516c77SSepherosa Ziehau  */
194915516c77SSepherosa Ziehau static int
195015516c77SSepherosa Ziehau hn_txpkt(struct ifnet *ifp, struct hn_tx_ring *txr, struct hn_txdesc *txd)
195115516c77SSepherosa Ziehau {
19528e7d3136SSepherosa Ziehau 	int error, send_failed = 0, has_bpf;
195315516c77SSepherosa Ziehau 
195415516c77SSepherosa Ziehau again:
19558e7d3136SSepherosa Ziehau 	has_bpf = bpf_peers_present(ifp->if_bpf);
19568e7d3136SSepherosa Ziehau 	if (has_bpf) {
195715516c77SSepherosa Ziehau 		/*
19588e7d3136SSepherosa Ziehau 		 * Make sure that this txd and any aggregated txds are not
19598e7d3136SSepherosa Ziehau 		 * freed before ETHER_BPF_MTAP.
196015516c77SSepherosa Ziehau 		 */
196115516c77SSepherosa Ziehau 		hn_txdesc_hold(txd);
19628e7d3136SSepherosa Ziehau 	}
196315516c77SSepherosa Ziehau 	error = txr->hn_sendpkt(txr, txd);
196415516c77SSepherosa Ziehau 	if (!error) {
19658e7d3136SSepherosa Ziehau 		if (has_bpf) {
1966dc13fee6SSepherosa Ziehau 			const struct hn_txdesc *tmp_txd;
1967dc13fee6SSepherosa Ziehau 
196815516c77SSepherosa Ziehau 			ETHER_BPF_MTAP(ifp, txd->m);
1969dc13fee6SSepherosa Ziehau 			STAILQ_FOREACH(tmp_txd, &txd->agg_list, agg_link)
1970dc13fee6SSepherosa Ziehau 				ETHER_BPF_MTAP(ifp, tmp_txd->m);
1971dc13fee6SSepherosa Ziehau 		}
1972dc13fee6SSepherosa Ziehau 
1973dc13fee6SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, txr->hn_stat_pkts);
197423bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
197523bf9e15SSepherosa Ziehau 		if (!hn_use_if_start)
197623bf9e15SSepherosa Ziehau #endif
197723bf9e15SSepherosa Ziehau 		{
197815516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OBYTES,
1979dc13fee6SSepherosa Ziehau 			    txr->hn_stat_size);
1980dc13fee6SSepherosa Ziehau 			if (txr->hn_stat_mcasts != 0) {
1981dc13fee6SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OMCASTS,
1982dc13fee6SSepherosa Ziehau 				    txr->hn_stat_mcasts);
198315516c77SSepherosa Ziehau 			}
1984dc13fee6SSepherosa Ziehau 		}
1985dc13fee6SSepherosa Ziehau 		txr->hn_pkts += txr->hn_stat_pkts;
1986dc13fee6SSepherosa Ziehau 		txr->hn_sends++;
198715516c77SSepherosa Ziehau 	}
19888e7d3136SSepherosa Ziehau 	if (has_bpf)
198915516c77SSepherosa Ziehau 		hn_txdesc_put(txr, txd);
199015516c77SSepherosa Ziehau 
199115516c77SSepherosa Ziehau 	if (__predict_false(error)) {
199215516c77SSepherosa Ziehau 		int freed;
199315516c77SSepherosa Ziehau 
199415516c77SSepherosa Ziehau 		/*
199515516c77SSepherosa Ziehau 		 * This should "really rarely" happen.
199615516c77SSepherosa Ziehau 		 *
199715516c77SSepherosa Ziehau 		 * XXX Too many RX to be acked or too many sideband
199815516c77SSepherosa Ziehau 		 * commands to run?  Ask netvsc_channel_rollup()
199915516c77SSepherosa Ziehau 		 * to kick start later.
200015516c77SSepherosa Ziehau 		 */
200115516c77SSepherosa Ziehau 		txr->hn_has_txeof = 1;
200215516c77SSepherosa Ziehau 		if (!send_failed) {
200315516c77SSepherosa Ziehau 			txr->hn_send_failed++;
200415516c77SSepherosa Ziehau 			send_failed = 1;
200515516c77SSepherosa Ziehau 			/*
200615516c77SSepherosa Ziehau 			 * Try sending again after set hn_has_txeof;
200715516c77SSepherosa Ziehau 			 * in case that we missed the last
200815516c77SSepherosa Ziehau 			 * netvsc_channel_rollup().
200915516c77SSepherosa Ziehau 			 */
201015516c77SSepherosa Ziehau 			goto again;
201115516c77SSepherosa Ziehau 		}
201215516c77SSepherosa Ziehau 		if_printf(ifp, "send failed\n");
201315516c77SSepherosa Ziehau 
201415516c77SSepherosa Ziehau 		/*
201515516c77SSepherosa Ziehau 		 * Caller will perform further processing on the
201615516c77SSepherosa Ziehau 		 * associated mbuf, so don't free it in hn_txdesc_put();
201715516c77SSepherosa Ziehau 		 * only unload it from the DMA map in hn_txdesc_put(),
201815516c77SSepherosa Ziehau 		 * if it was loaded.
201915516c77SSepherosa Ziehau 		 */
202015516c77SSepherosa Ziehau 		txd->m = NULL;
202115516c77SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
202215516c77SSepherosa Ziehau 		KASSERT(freed != 0,
202315516c77SSepherosa Ziehau 		    ("fail to free txd upon send error"));
202415516c77SSepherosa Ziehau 
202515516c77SSepherosa Ziehau 		txr->hn_send_failed++;
202615516c77SSepherosa Ziehau 	}
2027dc13fee6SSepherosa Ziehau 
2028dc13fee6SSepherosa Ziehau 	/* Reset temporary stats, after this sending is done. */
2029dc13fee6SSepherosa Ziehau 	txr->hn_stat_size = 0;
2030dc13fee6SSepherosa Ziehau 	txr->hn_stat_pkts = 0;
2031dc13fee6SSepherosa Ziehau 	txr->hn_stat_mcasts = 0;
2032dc13fee6SSepherosa Ziehau 
2033dc13fee6SSepherosa Ziehau 	return (error);
203415516c77SSepherosa Ziehau }
203515516c77SSepherosa Ziehau 
203615516c77SSepherosa Ziehau /*
203715516c77SSepherosa Ziehau  * Append the specified data to the indicated mbuf chain,
203815516c77SSepherosa Ziehau  * Extend the mbuf chain if the new data does not fit in
203915516c77SSepherosa Ziehau  * existing space.
204015516c77SSepherosa Ziehau  *
204115516c77SSepherosa Ziehau  * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c.
204215516c77SSepherosa Ziehau  * There should be an equivalent in the kernel mbuf code,
204315516c77SSepherosa Ziehau  * but there does not appear to be one yet.
204415516c77SSepherosa Ziehau  *
204515516c77SSepherosa Ziehau  * Differs from m_append() in that additional mbufs are
204615516c77SSepherosa Ziehau  * allocated with cluster size MJUMPAGESIZE, and filled
204715516c77SSepherosa Ziehau  * accordingly.
204815516c77SSepherosa Ziehau  *
204915516c77SSepherosa Ziehau  * Return 1 if able to complete the job; otherwise 0.
205015516c77SSepherosa Ziehau  */
205115516c77SSepherosa Ziehau static int
205215516c77SSepherosa Ziehau hv_m_append(struct mbuf *m0, int len, c_caddr_t cp)
205315516c77SSepherosa Ziehau {
205415516c77SSepherosa Ziehau 	struct mbuf *m, *n;
205515516c77SSepherosa Ziehau 	int remainder, space;
205615516c77SSepherosa Ziehau 
205715516c77SSepherosa Ziehau 	for (m = m0; m->m_next != NULL; m = m->m_next)
205815516c77SSepherosa Ziehau 		;
205915516c77SSepherosa Ziehau 	remainder = len;
206015516c77SSepherosa Ziehau 	space = M_TRAILINGSPACE(m);
206115516c77SSepherosa Ziehau 	if (space > 0) {
206215516c77SSepherosa Ziehau 		/*
206315516c77SSepherosa Ziehau 		 * Copy into available space.
206415516c77SSepherosa Ziehau 		 */
206515516c77SSepherosa Ziehau 		if (space > remainder)
206615516c77SSepherosa Ziehau 			space = remainder;
206715516c77SSepherosa Ziehau 		bcopy(cp, mtod(m, caddr_t) + m->m_len, space);
206815516c77SSepherosa Ziehau 		m->m_len += space;
206915516c77SSepherosa Ziehau 		cp += space;
207015516c77SSepherosa Ziehau 		remainder -= space;
207115516c77SSepherosa Ziehau 	}
207215516c77SSepherosa Ziehau 	while (remainder > 0) {
207315516c77SSepherosa Ziehau 		/*
207415516c77SSepherosa Ziehau 		 * Allocate a new mbuf; could check space
207515516c77SSepherosa Ziehau 		 * and allocate a cluster instead.
207615516c77SSepherosa Ziehau 		 */
207715516c77SSepherosa Ziehau 		n = m_getjcl(M_NOWAIT, m->m_type, 0, MJUMPAGESIZE);
207815516c77SSepherosa Ziehau 		if (n == NULL)
207915516c77SSepherosa Ziehau 			break;
208015516c77SSepherosa Ziehau 		n->m_len = min(MJUMPAGESIZE, remainder);
208115516c77SSepherosa Ziehau 		bcopy(cp, mtod(n, caddr_t), n->m_len);
208215516c77SSepherosa Ziehau 		cp += n->m_len;
208315516c77SSepherosa Ziehau 		remainder -= n->m_len;
208415516c77SSepherosa Ziehau 		m->m_next = n;
208515516c77SSepherosa Ziehau 		m = n;
208615516c77SSepherosa Ziehau 	}
208715516c77SSepherosa Ziehau 	if (m0->m_flags & M_PKTHDR)
208815516c77SSepherosa Ziehau 		m0->m_pkthdr.len += len - remainder;
208915516c77SSepherosa Ziehau 
209015516c77SSepherosa Ziehau 	return (remainder == 0);
209115516c77SSepherosa Ziehau }
209215516c77SSepherosa Ziehau 
209315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
209415516c77SSepherosa Ziehau static __inline int
209515516c77SSepherosa Ziehau hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m)
209615516c77SSepherosa Ziehau {
209715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
209815516c77SSepherosa Ziehau 	if (hn_lro_mbufq_depth) {
209915516c77SSepherosa Ziehau 		tcp_lro_queue_mbuf(lc, m);
210015516c77SSepherosa Ziehau 		return 0;
210115516c77SSepherosa Ziehau 	}
210215516c77SSepherosa Ziehau #endif
210315516c77SSepherosa Ziehau 	return tcp_lro_rx(lc, m, 0);
210415516c77SSepherosa Ziehau }
210515516c77SSepherosa Ziehau #endif
210615516c77SSepherosa Ziehau 
210715516c77SSepherosa Ziehau static int
210815516c77SSepherosa Ziehau hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
210915516c77SSepherosa Ziehau     const struct hn_rxinfo *info)
211015516c77SSepherosa Ziehau {
211115516c77SSepherosa Ziehau 	struct ifnet *ifp = rxr->hn_ifp;
211215516c77SSepherosa Ziehau 	struct mbuf *m_new;
211315516c77SSepherosa Ziehau 	int size, do_lro = 0, do_csum = 1;
211415516c77SSepherosa Ziehau 	int hash_type;
211515516c77SSepherosa Ziehau 
211615516c77SSepherosa Ziehau 	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
211715516c77SSepherosa Ziehau 		return (0);
211815516c77SSepherosa Ziehau 
211915516c77SSepherosa Ziehau 	/*
212015516c77SSepherosa Ziehau 	 * Bail out if packet contains more data than configured MTU.
212115516c77SSepherosa Ziehau 	 */
212215516c77SSepherosa Ziehau 	if (dlen > (ifp->if_mtu + ETHER_HDR_LEN)) {
212315516c77SSepherosa Ziehau 		return (0);
212415516c77SSepherosa Ziehau 	} else if (dlen <= MHLEN) {
212515516c77SSepherosa Ziehau 		m_new = m_gethdr(M_NOWAIT, MT_DATA);
212615516c77SSepherosa Ziehau 		if (m_new == NULL) {
212715516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
212815516c77SSepherosa Ziehau 			return (0);
212915516c77SSepherosa Ziehau 		}
213015516c77SSepherosa Ziehau 		memcpy(mtod(m_new, void *), data, dlen);
213115516c77SSepherosa Ziehau 		m_new->m_pkthdr.len = m_new->m_len = dlen;
213215516c77SSepherosa Ziehau 		rxr->hn_small_pkts++;
213315516c77SSepherosa Ziehau 	} else {
213415516c77SSepherosa Ziehau 		/*
213515516c77SSepherosa Ziehau 		 * Get an mbuf with a cluster.  For packets 2K or less,
213615516c77SSepherosa Ziehau 		 * get a standard 2K cluster.  For anything larger, get a
213715516c77SSepherosa Ziehau 		 * 4K cluster.  Any buffers larger than 4K can cause problems
213815516c77SSepherosa Ziehau 		 * if looped around to the Hyper-V TX channel, so avoid them.
213915516c77SSepherosa Ziehau 		 */
214015516c77SSepherosa Ziehau 		size = MCLBYTES;
214115516c77SSepherosa Ziehau 		if (dlen > MCLBYTES) {
214215516c77SSepherosa Ziehau 			/* 4096 */
214315516c77SSepherosa Ziehau 			size = MJUMPAGESIZE;
214415516c77SSepherosa Ziehau 		}
214515516c77SSepherosa Ziehau 
214615516c77SSepherosa Ziehau 		m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size);
214715516c77SSepherosa Ziehau 		if (m_new == NULL) {
214815516c77SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
214915516c77SSepherosa Ziehau 			return (0);
215015516c77SSepherosa Ziehau 		}
215115516c77SSepherosa Ziehau 
215215516c77SSepherosa Ziehau 		hv_m_append(m_new, dlen, data);
215315516c77SSepherosa Ziehau 	}
215415516c77SSepherosa Ziehau 	m_new->m_pkthdr.rcvif = ifp;
215515516c77SSepherosa Ziehau 
215615516c77SSepherosa Ziehau 	if (__predict_false((ifp->if_capenable & IFCAP_RXCSUM) == 0))
215715516c77SSepherosa Ziehau 		do_csum = 0;
215815516c77SSepherosa Ziehau 
215915516c77SSepherosa Ziehau 	/* receive side checksum offload */
216015516c77SSepherosa Ziehau 	if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) {
216115516c77SSepherosa Ziehau 		/* IP csum offload */
216215516c77SSepherosa Ziehau 		if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) {
216315516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
216415516c77SSepherosa Ziehau 			    (CSUM_IP_CHECKED | CSUM_IP_VALID);
216515516c77SSepherosa Ziehau 			rxr->hn_csum_ip++;
216615516c77SSepherosa Ziehau 		}
216715516c77SSepherosa Ziehau 
216815516c77SSepherosa Ziehau 		/* TCP/UDP csum offload */
216915516c77SSepherosa Ziehau 		if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK |
217015516c77SSepherosa Ziehau 		     NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) {
217115516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_flags |=
217215516c77SSepherosa Ziehau 			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
217315516c77SSepherosa Ziehau 			m_new->m_pkthdr.csum_data = 0xffff;
217415516c77SSepherosa Ziehau 			if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK)
217515516c77SSepherosa Ziehau 				rxr->hn_csum_tcp++;
217615516c77SSepherosa Ziehau 			else
217715516c77SSepherosa Ziehau 				rxr->hn_csum_udp++;
217815516c77SSepherosa Ziehau 		}
217915516c77SSepherosa Ziehau 
218015516c77SSepherosa Ziehau 		/*
218115516c77SSepherosa Ziehau 		 * XXX
218215516c77SSepherosa Ziehau 		 * As of this write (Oct 28th, 2016), host side will turn
218315516c77SSepherosa Ziehau 		 * on only TCPCS_OK and IPCS_OK even for UDP datagrams, so
218415516c77SSepherosa Ziehau 		 * the do_lro setting here is actually _not_ accurate.  We
218515516c77SSepherosa Ziehau 		 * depend on the RSS hash type check to reset do_lro.
218615516c77SSepherosa Ziehau 		 */
218715516c77SSepherosa Ziehau 		if ((info->csum_info &
218815516c77SSepherosa Ziehau 		     (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) ==
218915516c77SSepherosa Ziehau 		    (NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK))
219015516c77SSepherosa Ziehau 			do_lro = 1;
219115516c77SSepherosa Ziehau 	} else {
219215516c77SSepherosa Ziehau 		const struct ether_header *eh;
219315516c77SSepherosa Ziehau 		uint16_t etype;
219415516c77SSepherosa Ziehau 		int hoff;
219515516c77SSepherosa Ziehau 
219615516c77SSepherosa Ziehau 		hoff = sizeof(*eh);
219715516c77SSepherosa Ziehau 		if (m_new->m_len < hoff)
219815516c77SSepherosa Ziehau 			goto skip;
219915516c77SSepherosa Ziehau 		eh = mtod(m_new, struct ether_header *);
220015516c77SSepherosa Ziehau 		etype = ntohs(eh->ether_type);
220115516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_VLAN) {
220215516c77SSepherosa Ziehau 			const struct ether_vlan_header *evl;
220315516c77SSepherosa Ziehau 
220415516c77SSepherosa Ziehau 			hoff = sizeof(*evl);
220515516c77SSepherosa Ziehau 			if (m_new->m_len < hoff)
220615516c77SSepherosa Ziehau 				goto skip;
220715516c77SSepherosa Ziehau 			evl = mtod(m_new, struct ether_vlan_header *);
220815516c77SSepherosa Ziehau 			etype = ntohs(evl->evl_proto);
220915516c77SSepherosa Ziehau 		}
221015516c77SSepherosa Ziehau 
221115516c77SSepherosa Ziehau 		if (etype == ETHERTYPE_IP) {
221215516c77SSepherosa Ziehau 			int pr;
221315516c77SSepherosa Ziehau 
221415516c77SSepherosa Ziehau 			pr = hn_check_iplen(m_new, hoff);
221515516c77SSepherosa Ziehau 			if (pr == IPPROTO_TCP) {
221615516c77SSepherosa Ziehau 				if (do_csum &&
221715516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
221815516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_TCP)) {
221915516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
222015516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
222115516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
222215516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
222315516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
222415516c77SSepherosa Ziehau 				}
222515516c77SSepherosa Ziehau 				do_lro = 1;
222615516c77SSepherosa Ziehau 			} else if (pr == IPPROTO_UDP) {
222715516c77SSepherosa Ziehau 				if (do_csum &&
222815516c77SSepherosa Ziehau 				    (rxr->hn_trust_hcsum &
222915516c77SSepherosa Ziehau 				     HN_TRUST_HCSUM_UDP)) {
223015516c77SSepherosa Ziehau 					rxr->hn_csum_trusted++;
223115516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_flags |=
223215516c77SSepherosa Ziehau 					   (CSUM_IP_CHECKED | CSUM_IP_VALID |
223315516c77SSepherosa Ziehau 					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
223415516c77SSepherosa Ziehau 					m_new->m_pkthdr.csum_data = 0xffff;
223515516c77SSepherosa Ziehau 				}
223615516c77SSepherosa Ziehau 			} else if (pr != IPPROTO_DONE && do_csum &&
223715516c77SSepherosa Ziehau 			    (rxr->hn_trust_hcsum & HN_TRUST_HCSUM_IP)) {
223815516c77SSepherosa Ziehau 				rxr->hn_csum_trusted++;
223915516c77SSepherosa Ziehau 				m_new->m_pkthdr.csum_flags |=
224015516c77SSepherosa Ziehau 				    (CSUM_IP_CHECKED | CSUM_IP_VALID);
224115516c77SSepherosa Ziehau 			}
224215516c77SSepherosa Ziehau 		}
224315516c77SSepherosa Ziehau 	}
224415516c77SSepherosa Ziehau skip:
224515516c77SSepherosa Ziehau 	if (info->vlan_info != HN_NDIS_VLAN_INFO_INVALID) {
224615516c77SSepherosa Ziehau 		m_new->m_pkthdr.ether_vtag = EVL_MAKETAG(
224715516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_ID(info->vlan_info),
224815516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_PRI(info->vlan_info),
224915516c77SSepherosa Ziehau 		    NDIS_VLAN_INFO_CFI(info->vlan_info));
225015516c77SSepherosa Ziehau 		m_new->m_flags |= M_VLANTAG;
225115516c77SSepherosa Ziehau 	}
225215516c77SSepherosa Ziehau 
225315516c77SSepherosa Ziehau 	if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) {
225415516c77SSepherosa Ziehau 		rxr->hn_rss_pkts++;
225515516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = info->hash_value;
225615516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE_HASH;
225715516c77SSepherosa Ziehau 		if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) ==
225815516c77SSepherosa Ziehau 		    NDIS_HASH_FUNCTION_TOEPLITZ) {
225915516c77SSepherosa Ziehau 			uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK);
226015516c77SSepherosa Ziehau 
226115516c77SSepherosa Ziehau 			/*
226215516c77SSepherosa Ziehau 			 * NOTE:
226315516c77SSepherosa Ziehau 			 * do_lro is resetted, if the hash types are not TCP
226415516c77SSepherosa Ziehau 			 * related.  See the comment in the above csum_flags
226515516c77SSepherosa Ziehau 			 * setup section.
226615516c77SSepherosa Ziehau 			 */
226715516c77SSepherosa Ziehau 			switch (type) {
226815516c77SSepherosa Ziehau 			case NDIS_HASH_IPV4:
226915516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV4;
227015516c77SSepherosa Ziehau 				do_lro = 0;
227115516c77SSepherosa Ziehau 				break;
227215516c77SSepherosa Ziehau 
227315516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV4:
227415516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV4;
227515516c77SSepherosa Ziehau 				break;
227615516c77SSepherosa Ziehau 
227715516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6:
227815516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6;
227915516c77SSepherosa Ziehau 				do_lro = 0;
228015516c77SSepherosa Ziehau 				break;
228115516c77SSepherosa Ziehau 
228215516c77SSepherosa Ziehau 			case NDIS_HASH_IPV6_EX:
228315516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_IPV6_EX;
228415516c77SSepherosa Ziehau 				do_lro = 0;
228515516c77SSepherosa Ziehau 				break;
228615516c77SSepherosa Ziehau 
228715516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6:
228815516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6;
228915516c77SSepherosa Ziehau 				break;
229015516c77SSepherosa Ziehau 
229115516c77SSepherosa Ziehau 			case NDIS_HASH_TCP_IPV6_EX:
229215516c77SSepherosa Ziehau 				hash_type = M_HASHTYPE_RSS_TCP_IPV6_EX;
229315516c77SSepherosa Ziehau 				break;
229415516c77SSepherosa Ziehau 			}
229515516c77SSepherosa Ziehau 		}
229615516c77SSepherosa Ziehau 	} else {
229715516c77SSepherosa Ziehau 		m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
229815516c77SSepherosa Ziehau 		hash_type = M_HASHTYPE_OPAQUE;
229915516c77SSepherosa Ziehau 	}
230015516c77SSepherosa Ziehau 	M_HASHTYPE_SET(m_new, hash_type);
230115516c77SSepherosa Ziehau 
230215516c77SSepherosa Ziehau 	/*
230315516c77SSepherosa Ziehau 	 * Note:  Moved RX completion back to hv_nv_on_receive() so all
230415516c77SSepherosa Ziehau 	 * messages (not just data messages) will trigger a response.
230515516c77SSepherosa Ziehau 	 */
230615516c77SSepherosa Ziehau 
230715516c77SSepherosa Ziehau 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
230815516c77SSepherosa Ziehau 	rxr->hn_pkts++;
230915516c77SSepherosa Ziehau 
231015516c77SSepherosa Ziehau 	if ((ifp->if_capenable & IFCAP_LRO) && do_lro) {
231115516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
231215516c77SSepherosa Ziehau 		struct lro_ctrl *lro = &rxr->hn_lro;
231315516c77SSepherosa Ziehau 
231415516c77SSepherosa Ziehau 		if (lro->lro_cnt) {
231515516c77SSepherosa Ziehau 			rxr->hn_lro_tried++;
231615516c77SSepherosa Ziehau 			if (hn_lro_rx(lro, m_new) == 0) {
231715516c77SSepherosa Ziehau 				/* DONE! */
231815516c77SSepherosa Ziehau 				return 0;
231915516c77SSepherosa Ziehau 			}
232015516c77SSepherosa Ziehau 		}
232115516c77SSepherosa Ziehau #endif
232215516c77SSepherosa Ziehau 	}
232315516c77SSepherosa Ziehau 
232415516c77SSepherosa Ziehau 	/* We're not holding the lock here, so don't release it */
232515516c77SSepherosa Ziehau 	(*ifp->if_input)(ifp, m_new);
232615516c77SSepherosa Ziehau 
232715516c77SSepherosa Ziehau 	return (0);
232815516c77SSepherosa Ziehau }
232915516c77SSepherosa Ziehau 
233015516c77SSepherosa Ziehau static int
233115516c77SSepherosa Ziehau hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
233215516c77SSepherosa Ziehau {
233315516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
233415516c77SSepherosa Ziehau 	struct ifreq *ifr = (struct ifreq *)data;
233515516c77SSepherosa Ziehau 	int mask, error = 0;
233615516c77SSepherosa Ziehau 
233715516c77SSepherosa Ziehau 	switch (cmd) {
233815516c77SSepherosa Ziehau 	case SIOCSIFMTU:
233915516c77SSepherosa Ziehau 		if (ifr->ifr_mtu > HN_MTU_MAX) {
234015516c77SSepherosa Ziehau 			error = EINVAL;
234115516c77SSepherosa Ziehau 			break;
234215516c77SSepherosa Ziehau 		}
234315516c77SSepherosa Ziehau 
234415516c77SSepherosa Ziehau 		HN_LOCK(sc);
234515516c77SSepherosa Ziehau 
234615516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
234715516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
234815516c77SSepherosa Ziehau 			break;
234915516c77SSepherosa Ziehau 		}
235015516c77SSepherosa Ziehau 
235115516c77SSepherosa Ziehau 		if ((sc->hn_caps & HN_CAP_MTU) == 0) {
235215516c77SSepherosa Ziehau 			/* Can't change MTU */
235315516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
235415516c77SSepherosa Ziehau 			error = EOPNOTSUPP;
235515516c77SSepherosa Ziehau 			break;
235615516c77SSepherosa Ziehau 		}
235715516c77SSepherosa Ziehau 
235815516c77SSepherosa Ziehau 		if (ifp->if_mtu == ifr->ifr_mtu) {
235915516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
236015516c77SSepherosa Ziehau 			break;
236115516c77SSepherosa Ziehau 		}
236215516c77SSepherosa Ziehau 
236315516c77SSepherosa Ziehau 		/*
236415516c77SSepherosa Ziehau 		 * Suspend this interface before the synthetic parts
236515516c77SSepherosa Ziehau 		 * are ripped.
236615516c77SSepherosa Ziehau 		 */
236715516c77SSepherosa Ziehau 		hn_suspend(sc);
236815516c77SSepherosa Ziehau 
236915516c77SSepherosa Ziehau 		/*
237015516c77SSepherosa Ziehau 		 * Detach the synthetics parts, i.e. NVS and RNDIS.
237115516c77SSepherosa Ziehau 		 */
237215516c77SSepherosa Ziehau 		hn_synth_detach(sc);
237315516c77SSepherosa Ziehau 
237415516c77SSepherosa Ziehau 		/*
237515516c77SSepherosa Ziehau 		 * Reattach the synthetic parts, i.e. NVS and RNDIS,
237615516c77SSepherosa Ziehau 		 * with the new MTU setting.
237715516c77SSepherosa Ziehau 		 */
237815516c77SSepherosa Ziehau 		error = hn_synth_attach(sc, ifr->ifr_mtu);
237915516c77SSepherosa Ziehau 		if (error) {
238015516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
238115516c77SSepherosa Ziehau 			break;
238215516c77SSepherosa Ziehau 		}
238315516c77SSepherosa Ziehau 
238415516c77SSepherosa Ziehau 		/*
238515516c77SSepherosa Ziehau 		 * Commit the requested MTU, after the synthetic parts
238615516c77SSepherosa Ziehau 		 * have been successfully attached.
238715516c77SSepherosa Ziehau 		 */
238815516c77SSepherosa Ziehau 		ifp->if_mtu = ifr->ifr_mtu;
238915516c77SSepherosa Ziehau 
239015516c77SSepherosa Ziehau 		/*
239115516c77SSepherosa Ziehau 		 * Make sure that various parameters based on MTU are
239215516c77SSepherosa Ziehau 		 * still valid, after the MTU change.
239315516c77SSepherosa Ziehau 		 */
239415516c77SSepherosa Ziehau 		if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax)
239515516c77SSepherosa Ziehau 			hn_set_chim_size(sc, sc->hn_chim_szmax);
239615516c77SSepherosa Ziehau 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ifp->if_mtu);
239715516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
239815516c77SSepherosa Ziehau 		if (sc->hn_rx_ring[0].hn_lro.lro_length_lim <
239915516c77SSepherosa Ziehau 		    HN_LRO_LENLIM_MIN(ifp))
240015516c77SSepherosa Ziehau 			hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
240115516c77SSepherosa Ziehau #endif
240215516c77SSepherosa Ziehau 
240315516c77SSepherosa Ziehau 		/*
240415516c77SSepherosa Ziehau 		 * All done!  Resume the interface now.
240515516c77SSepherosa Ziehau 		 */
240615516c77SSepherosa Ziehau 		hn_resume(sc);
240715516c77SSepherosa Ziehau 
240815516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
240915516c77SSepherosa Ziehau 		break;
241015516c77SSepherosa Ziehau 
241115516c77SSepherosa Ziehau 	case SIOCSIFFLAGS:
241215516c77SSepherosa Ziehau 		HN_LOCK(sc);
241315516c77SSepherosa Ziehau 
241415516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
241515516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
241615516c77SSepherosa Ziehau 			break;
241715516c77SSepherosa Ziehau 		}
241815516c77SSepherosa Ziehau 
241915516c77SSepherosa Ziehau 		if (ifp->if_flags & IFF_UP) {
2420fdc4f478SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2421fdc4f478SSepherosa Ziehau 				/*
2422fdc4f478SSepherosa Ziehau 				 * Caller meight hold mutex, e.g.
2423fdc4f478SSepherosa Ziehau 				 * bpf; use busy-wait for the RNDIS
2424fdc4f478SSepherosa Ziehau 				 * reply.
2425fdc4f478SSepherosa Ziehau 				 */
2426fdc4f478SSepherosa Ziehau 				HN_NO_SLEEPING(sc);
242715516c77SSepherosa Ziehau 				hn_set_rxfilter(sc);
2428fdc4f478SSepherosa Ziehau 				HN_SLEEPING_OK(sc);
2429fdc4f478SSepherosa Ziehau 			} else {
243015516c77SSepherosa Ziehau 				hn_init_locked(sc);
2431fdc4f478SSepherosa Ziehau 			}
243215516c77SSepherosa Ziehau 		} else {
243315516c77SSepherosa Ziehau 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
243415516c77SSepherosa Ziehau 				hn_stop(sc);
243515516c77SSepherosa Ziehau 		}
243615516c77SSepherosa Ziehau 		sc->hn_if_flags = ifp->if_flags;
243715516c77SSepherosa Ziehau 
243815516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
243915516c77SSepherosa Ziehau 		break;
244015516c77SSepherosa Ziehau 
244115516c77SSepherosa Ziehau 	case SIOCSIFCAP:
244215516c77SSepherosa Ziehau 		HN_LOCK(sc);
244315516c77SSepherosa Ziehau 		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
244415516c77SSepherosa Ziehau 
244515516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM) {
244615516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM;
244715516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM)
244815516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP_HWASSIST(sc);
244915516c77SSepherosa Ziehau 			else
245015516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP_HWASSIST(sc);
245115516c77SSepherosa Ziehau 		}
245215516c77SSepherosa Ziehau 		if (mask & IFCAP_TXCSUM_IPV6) {
245315516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
245415516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
245515516c77SSepherosa Ziehau 				ifp->if_hwassist |= HN_CSUM_IP6_HWASSIST(sc);
245615516c77SSepherosa Ziehau 			else
245715516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~HN_CSUM_IP6_HWASSIST(sc);
245815516c77SSepherosa Ziehau 		}
245915516c77SSepherosa Ziehau 
246015516c77SSepherosa Ziehau 		/* TODO: flip RNDIS offload parameters for RXCSUM. */
246115516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM)
246215516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM;
246315516c77SSepherosa Ziehau #ifdef foo
246415516c77SSepherosa Ziehau 		/* We can't diff IPv6 packets from IPv4 packets on RX path. */
246515516c77SSepherosa Ziehau 		if (mask & IFCAP_RXCSUM_IPV6)
246615516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
246715516c77SSepherosa Ziehau #endif
246815516c77SSepherosa Ziehau 
246915516c77SSepherosa Ziehau 		if (mask & IFCAP_LRO)
247015516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_LRO;
247115516c77SSepherosa Ziehau 
247215516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO4) {
247315516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO4;
247415516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO4)
247515516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP_TSO;
247615516c77SSepherosa Ziehau 			else
247715516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP_TSO;
247815516c77SSepherosa Ziehau 		}
247915516c77SSepherosa Ziehau 		if (mask & IFCAP_TSO6) {
248015516c77SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO6;
248115516c77SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO6)
248215516c77SSepherosa Ziehau 				ifp->if_hwassist |= CSUM_IP6_TSO;
248315516c77SSepherosa Ziehau 			else
248415516c77SSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_IP6_TSO;
248515516c77SSepherosa Ziehau 		}
248615516c77SSepherosa Ziehau 
248715516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
248815516c77SSepherosa Ziehau 		break;
248915516c77SSepherosa Ziehau 
249015516c77SSepherosa Ziehau 	case SIOCADDMULTI:
249115516c77SSepherosa Ziehau 	case SIOCDELMULTI:
249215516c77SSepherosa Ziehau 		HN_LOCK(sc);
249315516c77SSepherosa Ziehau 
249415516c77SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) {
249515516c77SSepherosa Ziehau 			HN_UNLOCK(sc);
249615516c77SSepherosa Ziehau 			break;
249715516c77SSepherosa Ziehau 		}
2498fdc4f478SSepherosa Ziehau 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2499fdc4f478SSepherosa Ziehau 			/*
2500fdc4f478SSepherosa Ziehau 			 * Multicast uses mutex; use busy-wait for
2501fdc4f478SSepherosa Ziehau 			 * the RNDIS reply.
2502fdc4f478SSepherosa Ziehau 			 */
2503fdc4f478SSepherosa Ziehau 			HN_NO_SLEEPING(sc);
250415516c77SSepherosa Ziehau 			hn_set_rxfilter(sc);
2505fdc4f478SSepherosa Ziehau 			HN_SLEEPING_OK(sc);
2506fdc4f478SSepherosa Ziehau 		}
250715516c77SSepherosa Ziehau 
250815516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
250915516c77SSepherosa Ziehau 		break;
251015516c77SSepherosa Ziehau 
251115516c77SSepherosa Ziehau 	case SIOCSIFMEDIA:
251215516c77SSepherosa Ziehau 	case SIOCGIFMEDIA:
251315516c77SSepherosa Ziehau 		error = ifmedia_ioctl(ifp, ifr, &sc->hn_media, cmd);
251415516c77SSepherosa Ziehau 		break;
251515516c77SSepherosa Ziehau 
251615516c77SSepherosa Ziehau 	default:
251715516c77SSepherosa Ziehau 		error = ether_ioctl(ifp, cmd, data);
251815516c77SSepherosa Ziehau 		break;
251915516c77SSepherosa Ziehau 	}
252015516c77SSepherosa Ziehau 	return (error);
252115516c77SSepherosa Ziehau }
252215516c77SSepherosa Ziehau 
252315516c77SSepherosa Ziehau static void
252415516c77SSepherosa Ziehau hn_stop(struct hn_softc *sc)
252515516c77SSepherosa Ziehau {
252615516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
252715516c77SSepherosa Ziehau 	int i;
252815516c77SSepherosa Ziehau 
252915516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
253015516c77SSepherosa Ziehau 
253115516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
253215516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
253315516c77SSepherosa Ziehau 
253415516c77SSepherosa Ziehau 	/* Clear RUNNING bit _before_ hn_suspend_data() */
253515516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
253615516c77SSepherosa Ziehau 	hn_suspend_data(sc);
253715516c77SSepherosa Ziehau 
253815516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
253915516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
254015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
254115516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
254215516c77SSepherosa Ziehau }
254315516c77SSepherosa Ziehau 
254415516c77SSepherosa Ziehau static void
254515516c77SSepherosa Ziehau hn_init_locked(struct hn_softc *sc)
254615516c77SSepherosa Ziehau {
254715516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
254815516c77SSepherosa Ziehau 	int i;
254915516c77SSepherosa Ziehau 
255015516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
255115516c77SSepherosa Ziehau 
255215516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0)
255315516c77SSepherosa Ziehau 		return;
255415516c77SSepherosa Ziehau 
255515516c77SSepherosa Ziehau 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
255615516c77SSepherosa Ziehau 		return;
255715516c77SSepherosa Ziehau 
255815516c77SSepherosa Ziehau 	/* Configure RX filter */
255915516c77SSepherosa Ziehau 	hn_set_rxfilter(sc);
256015516c77SSepherosa Ziehau 
256115516c77SSepherosa Ziehau 	/* Clear OACTIVE bit. */
256215516c77SSepherosa Ziehau 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
256315516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
256415516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_oactive = 0;
256515516c77SSepherosa Ziehau 
256615516c77SSepherosa Ziehau 	/* Clear TX 'suspended' bit. */
256715516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_inuse);
256815516c77SSepherosa Ziehau 
256915516c77SSepherosa Ziehau 	/* Everything is ready; unleash! */
257015516c77SSepherosa Ziehau 	atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
257115516c77SSepherosa Ziehau }
257215516c77SSepherosa Ziehau 
257315516c77SSepherosa Ziehau static void
257415516c77SSepherosa Ziehau hn_init(void *xsc)
257515516c77SSepherosa Ziehau {
257615516c77SSepherosa Ziehau 	struct hn_softc *sc = xsc;
257715516c77SSepherosa Ziehau 
257815516c77SSepherosa Ziehau 	HN_LOCK(sc);
257915516c77SSepherosa Ziehau 	hn_init_locked(sc);
258015516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
258115516c77SSepherosa Ziehau }
258215516c77SSepherosa Ziehau 
258315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
258415516c77SSepherosa Ziehau 
258515516c77SSepherosa Ziehau static int
258615516c77SSepherosa Ziehau hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
258715516c77SSepherosa Ziehau {
258815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
258915516c77SSepherosa Ziehau 	unsigned int lenlim;
259015516c77SSepherosa Ziehau 	int error;
259115516c77SSepherosa Ziehau 
259215516c77SSepherosa Ziehau 	lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim;
259315516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &lenlim, 0, req);
259415516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
259515516c77SSepherosa Ziehau 		return error;
259615516c77SSepherosa Ziehau 
259715516c77SSepherosa Ziehau 	HN_LOCK(sc);
259815516c77SSepherosa Ziehau 	if (lenlim < HN_LRO_LENLIM_MIN(sc->hn_ifp) ||
259915516c77SSepherosa Ziehau 	    lenlim > TCP_LRO_LENGTH_MAX) {
260015516c77SSepherosa Ziehau 		HN_UNLOCK(sc);
260115516c77SSepherosa Ziehau 		return EINVAL;
260215516c77SSepherosa Ziehau 	}
260315516c77SSepherosa Ziehau 	hn_set_lro_lenlim(sc, lenlim);
260415516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
260515516c77SSepherosa Ziehau 
260615516c77SSepherosa Ziehau 	return 0;
260715516c77SSepherosa Ziehau }
260815516c77SSepherosa Ziehau 
260915516c77SSepherosa Ziehau static int
261015516c77SSepherosa Ziehau hn_lro_ackcnt_sysctl(SYSCTL_HANDLER_ARGS)
261115516c77SSepherosa Ziehau {
261215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
261315516c77SSepherosa Ziehau 	int ackcnt, error, i;
261415516c77SSepherosa Ziehau 
261515516c77SSepherosa Ziehau 	/*
261615516c77SSepherosa Ziehau 	 * lro_ackcnt_lim is append count limit,
261715516c77SSepherosa Ziehau 	 * +1 to turn it into aggregation limit.
261815516c77SSepherosa Ziehau 	 */
261915516c77SSepherosa Ziehau 	ackcnt = sc->hn_rx_ring[0].hn_lro.lro_ackcnt_lim + 1;
262015516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &ackcnt, 0, req);
262115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
262215516c77SSepherosa Ziehau 		return error;
262315516c77SSepherosa Ziehau 
262415516c77SSepherosa Ziehau 	if (ackcnt < 2 || ackcnt > (TCP_LRO_ACKCNT_MAX + 1))
262515516c77SSepherosa Ziehau 		return EINVAL;
262615516c77SSepherosa Ziehau 
262715516c77SSepherosa Ziehau 	/*
262815516c77SSepherosa Ziehau 	 * Convert aggregation limit back to append
262915516c77SSepherosa Ziehau 	 * count limit.
263015516c77SSepherosa Ziehau 	 */
263115516c77SSepherosa Ziehau 	--ackcnt;
263215516c77SSepherosa Ziehau 	HN_LOCK(sc);
2633a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i)
263415516c77SSepherosa Ziehau 		sc->hn_rx_ring[i].hn_lro.lro_ackcnt_lim = ackcnt;
263515516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
263615516c77SSepherosa Ziehau 	return 0;
263715516c77SSepherosa Ziehau }
263815516c77SSepherosa Ziehau 
263915516c77SSepherosa Ziehau #endif
264015516c77SSepherosa Ziehau 
264115516c77SSepherosa Ziehau static int
264215516c77SSepherosa Ziehau hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS)
264315516c77SSepherosa Ziehau {
264415516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
264515516c77SSepherosa Ziehau 	int hcsum = arg2;
264615516c77SSepherosa Ziehau 	int on, error, i;
264715516c77SSepherosa Ziehau 
264815516c77SSepherosa Ziehau 	on = 0;
264915516c77SSepherosa Ziehau 	if (sc->hn_rx_ring[0].hn_trust_hcsum & hcsum)
265015516c77SSepherosa Ziehau 		on = 1;
265115516c77SSepherosa Ziehau 
265215516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &on, 0, req);
265315516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
265415516c77SSepherosa Ziehau 		return error;
265515516c77SSepherosa Ziehau 
265615516c77SSepherosa Ziehau 	HN_LOCK(sc);
2657a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
265815516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
265915516c77SSepherosa Ziehau 
266015516c77SSepherosa Ziehau 		if (on)
266115516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= hcsum;
266215516c77SSepherosa Ziehau 		else
266315516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum &= ~hcsum;
266415516c77SSepherosa Ziehau 	}
266515516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
266615516c77SSepherosa Ziehau 	return 0;
266715516c77SSepherosa Ziehau }
266815516c77SSepherosa Ziehau 
266915516c77SSepherosa Ziehau static int
267015516c77SSepherosa Ziehau hn_chim_size_sysctl(SYSCTL_HANDLER_ARGS)
267115516c77SSepherosa Ziehau {
267215516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
267315516c77SSepherosa Ziehau 	int chim_size, error;
267415516c77SSepherosa Ziehau 
267515516c77SSepherosa Ziehau 	chim_size = sc->hn_tx_ring[0].hn_chim_size;
267615516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &chim_size, 0, req);
267715516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
267815516c77SSepherosa Ziehau 		return error;
267915516c77SSepherosa Ziehau 
268015516c77SSepherosa Ziehau 	if (chim_size > sc->hn_chim_szmax || chim_size <= 0)
268115516c77SSepherosa Ziehau 		return EINVAL;
268215516c77SSepherosa Ziehau 
268315516c77SSepherosa Ziehau 	HN_LOCK(sc);
268415516c77SSepherosa Ziehau 	hn_set_chim_size(sc, chim_size);
268515516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
268615516c77SSepherosa Ziehau 	return 0;
268715516c77SSepherosa Ziehau }
268815516c77SSepherosa Ziehau 
268915516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
269015516c77SSepherosa Ziehau static int
269115516c77SSepherosa Ziehau hn_rx_stat_int_sysctl(SYSCTL_HANDLER_ARGS)
269215516c77SSepherosa Ziehau {
269315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
269415516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
269515516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
269615516c77SSepherosa Ziehau 	uint64_t stat;
269715516c77SSepherosa Ziehau 
269815516c77SSepherosa Ziehau 	stat = 0;
269915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
270015516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
270115516c77SSepherosa Ziehau 		stat += *((int *)((uint8_t *)rxr + ofs));
270215516c77SSepherosa Ziehau 	}
270315516c77SSepherosa Ziehau 
270415516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
270515516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
270615516c77SSepherosa Ziehau 		return error;
270715516c77SSepherosa Ziehau 
270815516c77SSepherosa Ziehau 	/* Zero out this stat. */
270915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
271015516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
271115516c77SSepherosa Ziehau 		*((int *)((uint8_t *)rxr + ofs)) = 0;
271215516c77SSepherosa Ziehau 	}
271315516c77SSepherosa Ziehau 	return 0;
271415516c77SSepherosa Ziehau }
271515516c77SSepherosa Ziehau #else
271615516c77SSepherosa Ziehau static int
271715516c77SSepherosa Ziehau hn_rx_stat_u64_sysctl(SYSCTL_HANDLER_ARGS)
271815516c77SSepherosa Ziehau {
271915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
272015516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
272115516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
272215516c77SSepherosa Ziehau 	uint64_t stat;
272315516c77SSepherosa Ziehau 
272415516c77SSepherosa Ziehau 	stat = 0;
2725a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
272615516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
272715516c77SSepherosa Ziehau 		stat += *((uint64_t *)((uint8_t *)rxr + ofs));
272815516c77SSepherosa Ziehau 	}
272915516c77SSepherosa Ziehau 
273015516c77SSepherosa Ziehau 	error = sysctl_handle_64(oidp, &stat, 0, req);
273115516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
273215516c77SSepherosa Ziehau 		return error;
273315516c77SSepherosa Ziehau 
273415516c77SSepherosa Ziehau 	/* Zero out this stat. */
2735a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
273615516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
273715516c77SSepherosa Ziehau 		*((uint64_t *)((uint8_t *)rxr + ofs)) = 0;
273815516c77SSepherosa Ziehau 	}
273915516c77SSepherosa Ziehau 	return 0;
274015516c77SSepherosa Ziehau }
274115516c77SSepherosa Ziehau 
274215516c77SSepherosa Ziehau #endif
274315516c77SSepherosa Ziehau 
274415516c77SSepherosa Ziehau static int
274515516c77SSepherosa Ziehau hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
274615516c77SSepherosa Ziehau {
274715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
274815516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
274915516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
275015516c77SSepherosa Ziehau 	u_long stat;
275115516c77SSepherosa Ziehau 
275215516c77SSepherosa Ziehau 	stat = 0;
2753a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
275415516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
275515516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)rxr + ofs));
275615516c77SSepherosa Ziehau 	}
275715516c77SSepherosa Ziehau 
275815516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
275915516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
276015516c77SSepherosa Ziehau 		return error;
276115516c77SSepherosa Ziehau 
276215516c77SSepherosa Ziehau 	/* Zero out this stat. */
2763a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
276415516c77SSepherosa Ziehau 		rxr = &sc->hn_rx_ring[i];
276515516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)rxr + ofs)) = 0;
276615516c77SSepherosa Ziehau 	}
276715516c77SSepherosa Ziehau 	return 0;
276815516c77SSepherosa Ziehau }
276915516c77SSepherosa Ziehau 
277015516c77SSepherosa Ziehau static int
277115516c77SSepherosa Ziehau hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS)
277215516c77SSepherosa Ziehau {
277315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
277415516c77SSepherosa Ziehau 	int ofs = arg2, i, error;
277515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
277615516c77SSepherosa Ziehau 	u_long stat;
277715516c77SSepherosa Ziehau 
277815516c77SSepherosa Ziehau 	stat = 0;
2779a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
278015516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
278115516c77SSepherosa Ziehau 		stat += *((u_long *)((uint8_t *)txr + ofs));
278215516c77SSepherosa Ziehau 	}
278315516c77SSepherosa Ziehau 
278415516c77SSepherosa Ziehau 	error = sysctl_handle_long(oidp, &stat, 0, req);
278515516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
278615516c77SSepherosa Ziehau 		return error;
278715516c77SSepherosa Ziehau 
278815516c77SSepherosa Ziehau 	/* Zero out this stat. */
2789a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
279015516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
279115516c77SSepherosa Ziehau 		*((u_long *)((uint8_t *)txr + ofs)) = 0;
279215516c77SSepherosa Ziehau 	}
279315516c77SSepherosa Ziehau 	return 0;
279415516c77SSepherosa Ziehau }
279515516c77SSepherosa Ziehau 
279615516c77SSepherosa Ziehau static int
279715516c77SSepherosa Ziehau hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS)
279815516c77SSepherosa Ziehau {
279915516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
280015516c77SSepherosa Ziehau 	int ofs = arg2, i, error, conf;
280115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
280215516c77SSepherosa Ziehau 
280315516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[0];
280415516c77SSepherosa Ziehau 	conf = *((int *)((uint8_t *)txr + ofs));
280515516c77SSepherosa Ziehau 
280615516c77SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &conf, 0, req);
280715516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
280815516c77SSepherosa Ziehau 		return error;
280915516c77SSepherosa Ziehau 
281015516c77SSepherosa Ziehau 	HN_LOCK(sc);
2811a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
281215516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
281315516c77SSepherosa Ziehau 		*((int *)((uint8_t *)txr + ofs)) = conf;
281415516c77SSepherosa Ziehau 	}
281515516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
281615516c77SSepherosa Ziehau 
281715516c77SSepherosa Ziehau 	return 0;
281815516c77SSepherosa Ziehau }
281915516c77SSepherosa Ziehau 
282015516c77SSepherosa Ziehau static int
2821dc13fee6SSepherosa Ziehau hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS)
2822dc13fee6SSepherosa Ziehau {
2823dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2824dc13fee6SSepherosa Ziehau 	int error, size;
2825dc13fee6SSepherosa Ziehau 
2826dc13fee6SSepherosa Ziehau 	size = sc->hn_agg_size;
2827dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &size, 0, req);
2828dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
2829dc13fee6SSepherosa Ziehau 		return (error);
2830dc13fee6SSepherosa Ziehau 
2831dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
2832dc13fee6SSepherosa Ziehau 	sc->hn_agg_size = size;
2833dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
2834dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
2835dc13fee6SSepherosa Ziehau 
2836dc13fee6SSepherosa Ziehau 	return (0);
2837dc13fee6SSepherosa Ziehau }
2838dc13fee6SSepherosa Ziehau 
2839dc13fee6SSepherosa Ziehau static int
2840dc13fee6SSepherosa Ziehau hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS)
2841dc13fee6SSepherosa Ziehau {
2842dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2843dc13fee6SSepherosa Ziehau 	int error, pkts;
2844dc13fee6SSepherosa Ziehau 
2845dc13fee6SSepherosa Ziehau 	pkts = sc->hn_agg_pkts;
2846dc13fee6SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &pkts, 0, req);
2847dc13fee6SSepherosa Ziehau 	if (error || req->newptr == NULL)
2848dc13fee6SSepherosa Ziehau 		return (error);
2849dc13fee6SSepherosa Ziehau 
2850dc13fee6SSepherosa Ziehau 	HN_LOCK(sc);
2851dc13fee6SSepherosa Ziehau 	sc->hn_agg_pkts = pkts;
2852dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
2853dc13fee6SSepherosa Ziehau 	HN_UNLOCK(sc);
2854dc13fee6SSepherosa Ziehau 
2855dc13fee6SSepherosa Ziehau 	return (0);
2856dc13fee6SSepherosa Ziehau }
2857dc13fee6SSepherosa Ziehau 
2858dc13fee6SSepherosa Ziehau static int
2859dc13fee6SSepherosa Ziehau hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS)
2860dc13fee6SSepherosa Ziehau {
2861dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2862dc13fee6SSepherosa Ziehau 	int pkts;
2863dc13fee6SSepherosa Ziehau 
2864dc13fee6SSepherosa Ziehau 	pkts = sc->hn_tx_ring[0].hn_agg_pktmax;
2865dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &pkts, 0, req));
2866dc13fee6SSepherosa Ziehau }
2867dc13fee6SSepherosa Ziehau 
2868dc13fee6SSepherosa Ziehau static int
2869dc13fee6SSepherosa Ziehau hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS)
2870dc13fee6SSepherosa Ziehau {
2871dc13fee6SSepherosa Ziehau 	struct hn_softc *sc = arg1;
2872dc13fee6SSepherosa Ziehau 	int align;
2873dc13fee6SSepherosa Ziehau 
2874dc13fee6SSepherosa Ziehau 	align = sc->hn_tx_ring[0].hn_agg_align;
2875dc13fee6SSepherosa Ziehau 	return (sysctl_handle_int(oidp, &align, 0, req));
2876dc13fee6SSepherosa Ziehau }
2877dc13fee6SSepherosa Ziehau 
2878dc13fee6SSepherosa Ziehau static int
287915516c77SSepherosa Ziehau hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS)
288015516c77SSepherosa Ziehau {
288115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
288215516c77SSepherosa Ziehau 	char verstr[16];
288315516c77SSepherosa Ziehau 
288415516c77SSepherosa Ziehau 	snprintf(verstr, sizeof(verstr), "%u.%u",
288515516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
288615516c77SSepherosa Ziehau 	    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
288715516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
288815516c77SSepherosa Ziehau }
288915516c77SSepherosa Ziehau 
289015516c77SSepherosa Ziehau static int
289115516c77SSepherosa Ziehau hn_caps_sysctl(SYSCTL_HANDLER_ARGS)
289215516c77SSepherosa Ziehau {
289315516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
289415516c77SSepherosa Ziehau 	char caps_str[128];
289515516c77SSepherosa Ziehau 	uint32_t caps;
289615516c77SSepherosa Ziehau 
289715516c77SSepherosa Ziehau 	HN_LOCK(sc);
289815516c77SSepherosa Ziehau 	caps = sc->hn_caps;
289915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
290015516c77SSepherosa Ziehau 	snprintf(caps_str, sizeof(caps_str), "%b", caps, HN_CAP_BITS);
290115516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req);
290215516c77SSepherosa Ziehau }
290315516c77SSepherosa Ziehau 
290415516c77SSepherosa Ziehau static int
290515516c77SSepherosa Ziehau hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS)
290615516c77SSepherosa Ziehau {
290715516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
290815516c77SSepherosa Ziehau 	char assist_str[128];
290915516c77SSepherosa Ziehau 	uint32_t hwassist;
291015516c77SSepherosa Ziehau 
291115516c77SSepherosa Ziehau 	HN_LOCK(sc);
291215516c77SSepherosa Ziehau 	hwassist = sc->hn_ifp->if_hwassist;
291315516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
291415516c77SSepherosa Ziehau 	snprintf(assist_str, sizeof(assist_str), "%b", hwassist, CSUM_BITS);
291515516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, assist_str, sizeof(assist_str), req);
291615516c77SSepherosa Ziehau }
291715516c77SSepherosa Ziehau 
291815516c77SSepherosa Ziehau static int
291915516c77SSepherosa Ziehau hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS)
292015516c77SSepherosa Ziehau {
292115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
292215516c77SSepherosa Ziehau 	char filter_str[128];
292315516c77SSepherosa Ziehau 	uint32_t filter;
292415516c77SSepherosa Ziehau 
292515516c77SSepherosa Ziehau 	HN_LOCK(sc);
292615516c77SSepherosa Ziehau 	filter = sc->hn_rx_filter;
292715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
292815516c77SSepherosa Ziehau 	snprintf(filter_str, sizeof(filter_str), "%b", filter,
292915516c77SSepherosa Ziehau 	    NDIS_PACKET_TYPES);
293015516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, filter_str, sizeof(filter_str), req);
293115516c77SSepherosa Ziehau }
293215516c77SSepherosa Ziehau 
2933*34d68912SSepherosa Ziehau #ifndef RSS
2934*34d68912SSepherosa Ziehau 
293515516c77SSepherosa Ziehau static int
293615516c77SSepherosa Ziehau hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
293715516c77SSepherosa Ziehau {
293815516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
293915516c77SSepherosa Ziehau 	int error;
294015516c77SSepherosa Ziehau 
294115516c77SSepherosa Ziehau 	HN_LOCK(sc);
294215516c77SSepherosa Ziehau 
294315516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
294415516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
294515516c77SSepherosa Ziehau 		goto back;
294615516c77SSepherosa Ziehau 
294715516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key));
294815516c77SSepherosa Ziehau 	if (error)
294915516c77SSepherosa Ziehau 		goto back;
295015516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
295115516c77SSepherosa Ziehau 
295215516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse > 1) {
295315516c77SSepherosa Ziehau 		error = hn_rss_reconfig(sc);
295415516c77SSepherosa Ziehau 	} else {
295515516c77SSepherosa Ziehau 		/* Not RSS capable, at least for now; just save the RSS key. */
295615516c77SSepherosa Ziehau 		error = 0;
295715516c77SSepherosa Ziehau 	}
295815516c77SSepherosa Ziehau back:
295915516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
296015516c77SSepherosa Ziehau 	return (error);
296115516c77SSepherosa Ziehau }
296215516c77SSepherosa Ziehau 
296315516c77SSepherosa Ziehau static int
296415516c77SSepherosa Ziehau hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS)
296515516c77SSepherosa Ziehau {
296615516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
296715516c77SSepherosa Ziehau 	int error;
296815516c77SSepherosa Ziehau 
296915516c77SSepherosa Ziehau 	HN_LOCK(sc);
297015516c77SSepherosa Ziehau 
297115516c77SSepherosa Ziehau 	error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
297215516c77SSepherosa Ziehau 	if (error || req->newptr == NULL)
297315516c77SSepherosa Ziehau 		goto back;
297415516c77SSepherosa Ziehau 
297515516c77SSepherosa Ziehau 	/*
297615516c77SSepherosa Ziehau 	 * Don't allow RSS indirect table change, if this interface is not
297715516c77SSepherosa Ziehau 	 * RSS capable currently.
297815516c77SSepherosa Ziehau 	 */
297915516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse == 1) {
298015516c77SSepherosa Ziehau 		error = EOPNOTSUPP;
298115516c77SSepherosa Ziehau 		goto back;
298215516c77SSepherosa Ziehau 	}
298315516c77SSepherosa Ziehau 
298415516c77SSepherosa Ziehau 	error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind));
298515516c77SSepherosa Ziehau 	if (error)
298615516c77SSepherosa Ziehau 		goto back;
298715516c77SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_HAS_RSSIND;
298815516c77SSepherosa Ziehau 
2989afd4971bSSepherosa Ziehau 	hn_rss_ind_fixup(sc);
299015516c77SSepherosa Ziehau 	error = hn_rss_reconfig(sc);
299115516c77SSepherosa Ziehau back:
299215516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
299315516c77SSepherosa Ziehau 	return (error);
299415516c77SSepherosa Ziehau }
299515516c77SSepherosa Ziehau 
2996*34d68912SSepherosa Ziehau #endif	/* !RSS */
2997*34d68912SSepherosa Ziehau 
299815516c77SSepherosa Ziehau static int
299915516c77SSepherosa Ziehau hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS)
300015516c77SSepherosa Ziehau {
300115516c77SSepherosa Ziehau 	struct hn_softc *sc = arg1;
300215516c77SSepherosa Ziehau 	char hash_str[128];
300315516c77SSepherosa Ziehau 	uint32_t hash;
300415516c77SSepherosa Ziehau 
300515516c77SSepherosa Ziehau 	HN_LOCK(sc);
300615516c77SSepherosa Ziehau 	hash = sc->hn_rss_hash;
300715516c77SSepherosa Ziehau 	HN_UNLOCK(sc);
300815516c77SSepherosa Ziehau 	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
300915516c77SSepherosa Ziehau 	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
301015516c77SSepherosa Ziehau }
301115516c77SSepherosa Ziehau 
301215516c77SSepherosa Ziehau static int
301315516c77SSepherosa Ziehau hn_check_iplen(const struct mbuf *m, int hoff)
301415516c77SSepherosa Ziehau {
301515516c77SSepherosa Ziehau 	const struct ip *ip;
301615516c77SSepherosa Ziehau 	int len, iphlen, iplen;
301715516c77SSepherosa Ziehau 	const struct tcphdr *th;
301815516c77SSepherosa Ziehau 	int thoff;				/* TCP data offset */
301915516c77SSepherosa Ziehau 
302015516c77SSepherosa Ziehau 	len = hoff + sizeof(struct ip);
302115516c77SSepherosa Ziehau 
302215516c77SSepherosa Ziehau 	/* The packet must be at least the size of an IP header. */
302315516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < len)
302415516c77SSepherosa Ziehau 		return IPPROTO_DONE;
302515516c77SSepherosa Ziehau 
302615516c77SSepherosa Ziehau 	/* The fixed IP header must reside completely in the first mbuf. */
302715516c77SSepherosa Ziehau 	if (m->m_len < len)
302815516c77SSepherosa Ziehau 		return IPPROTO_DONE;
302915516c77SSepherosa Ziehau 
303015516c77SSepherosa Ziehau 	ip = mtodo(m, hoff);
303115516c77SSepherosa Ziehau 
303215516c77SSepherosa Ziehau 	/* Bound check the packet's stated IP header length. */
303315516c77SSepherosa Ziehau 	iphlen = ip->ip_hl << 2;
303415516c77SSepherosa Ziehau 	if (iphlen < sizeof(struct ip))		/* minimum header length */
303515516c77SSepherosa Ziehau 		return IPPROTO_DONE;
303615516c77SSepherosa Ziehau 
303715516c77SSepherosa Ziehau 	/* The full IP header must reside completely in the one mbuf. */
303815516c77SSepherosa Ziehau 	if (m->m_len < hoff + iphlen)
303915516c77SSepherosa Ziehau 		return IPPROTO_DONE;
304015516c77SSepherosa Ziehau 
304115516c77SSepherosa Ziehau 	iplen = ntohs(ip->ip_len);
304215516c77SSepherosa Ziehau 
304315516c77SSepherosa Ziehau 	/*
304415516c77SSepherosa Ziehau 	 * Check that the amount of data in the buffers is as
304515516c77SSepherosa Ziehau 	 * at least much as the IP header would have us expect.
304615516c77SSepherosa Ziehau 	 */
304715516c77SSepherosa Ziehau 	if (m->m_pkthdr.len < hoff + iplen)
304815516c77SSepherosa Ziehau 		return IPPROTO_DONE;
304915516c77SSepherosa Ziehau 
305015516c77SSepherosa Ziehau 	/*
305115516c77SSepherosa Ziehau 	 * Ignore IP fragments.
305215516c77SSepherosa Ziehau 	 */
305315516c77SSepherosa Ziehau 	if (ntohs(ip->ip_off) & (IP_OFFMASK | IP_MF))
305415516c77SSepherosa Ziehau 		return IPPROTO_DONE;
305515516c77SSepherosa Ziehau 
305615516c77SSepherosa Ziehau 	/*
305715516c77SSepherosa Ziehau 	 * The TCP/IP or UDP/IP header must be entirely contained within
305815516c77SSepherosa Ziehau 	 * the first fragment of a packet.
305915516c77SSepherosa Ziehau 	 */
306015516c77SSepherosa Ziehau 	switch (ip->ip_p) {
306115516c77SSepherosa Ziehau 	case IPPROTO_TCP:
306215516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct tcphdr))
306315516c77SSepherosa Ziehau 			return IPPROTO_DONE;
306415516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct tcphdr))
306515516c77SSepherosa Ziehau 			return IPPROTO_DONE;
306615516c77SSepherosa Ziehau 		th = (const struct tcphdr *)((const uint8_t *)ip + iphlen);
306715516c77SSepherosa Ziehau 		thoff = th->th_off << 2;
306815516c77SSepherosa Ziehau 		if (thoff < sizeof(struct tcphdr) || thoff + iphlen > iplen)
306915516c77SSepherosa Ziehau 			return IPPROTO_DONE;
307015516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + thoff)
307115516c77SSepherosa Ziehau 			return IPPROTO_DONE;
307215516c77SSepherosa Ziehau 		break;
307315516c77SSepherosa Ziehau 	case IPPROTO_UDP:
307415516c77SSepherosa Ziehau 		if (iplen < iphlen + sizeof(struct udphdr))
307515516c77SSepherosa Ziehau 			return IPPROTO_DONE;
307615516c77SSepherosa Ziehau 		if (m->m_len < hoff + iphlen + sizeof(struct udphdr))
307715516c77SSepherosa Ziehau 			return IPPROTO_DONE;
307815516c77SSepherosa Ziehau 		break;
307915516c77SSepherosa Ziehau 	default:
308015516c77SSepherosa Ziehau 		if (iplen < iphlen)
308115516c77SSepherosa Ziehau 			return IPPROTO_DONE;
308215516c77SSepherosa Ziehau 		break;
308315516c77SSepherosa Ziehau 	}
308415516c77SSepherosa Ziehau 	return ip->ip_p;
308515516c77SSepherosa Ziehau }
308615516c77SSepherosa Ziehau 
308715516c77SSepherosa Ziehau static int
308815516c77SSepherosa Ziehau hn_create_rx_data(struct hn_softc *sc, int ring_cnt)
308915516c77SSepherosa Ziehau {
309015516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
309115516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
309215516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
309315516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
309415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
309515516c77SSepherosa Ziehau 	int lroent_cnt;
309615516c77SSepherosa Ziehau #endif
309715516c77SSepherosa Ziehau #endif
309815516c77SSepherosa Ziehau 	int i;
309915516c77SSepherosa Ziehau 
310015516c77SSepherosa Ziehau 	/*
310115516c77SSepherosa Ziehau 	 * Create RXBUF for reception.
310215516c77SSepherosa Ziehau 	 *
310315516c77SSepherosa Ziehau 	 * NOTE:
310415516c77SSepherosa Ziehau 	 * - It is shared by all channels.
310515516c77SSepherosa Ziehau 	 * - A large enough buffer is allocated, certain version of NVSes
310615516c77SSepherosa Ziehau 	 *   may further limit the usable space.
310715516c77SSepherosa Ziehau 	 */
310815516c77SSepherosa Ziehau 	sc->hn_rxbuf = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
310915516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_RXBUF_SIZE, &sc->hn_rxbuf_dma,
311015516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
311115516c77SSepherosa Ziehau 	if (sc->hn_rxbuf == NULL) {
311215516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate rxbuf failed\n");
311315516c77SSepherosa Ziehau 		return (ENOMEM);
311415516c77SSepherosa Ziehau 	}
311515516c77SSepherosa Ziehau 
311615516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = ring_cnt;
311715516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = sc->hn_rx_ring_cnt;
311815516c77SSepherosa Ziehau 
311915516c77SSepherosa Ziehau 	sc->hn_rx_ring = malloc(sizeof(struct hn_rx_ring) * sc->hn_rx_ring_cnt,
312015516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
312115516c77SSepherosa Ziehau 
312215516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
312315516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
312415516c77SSepherosa Ziehau 	lroent_cnt = hn_lro_entry_count;
312515516c77SSepherosa Ziehau 	if (lroent_cnt < TCP_LRO_ENTRIES)
312615516c77SSepherosa Ziehau 		lroent_cnt = TCP_LRO_ENTRIES;
312715516c77SSepherosa Ziehau 	if (bootverbose)
312815516c77SSepherosa Ziehau 		device_printf(dev, "LRO: entry count %d\n", lroent_cnt);
312915516c77SSepherosa Ziehau #endif
313015516c77SSepherosa Ziehau #endif	/* INET || INET6 */
313115516c77SSepherosa Ziehau 
313215516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(dev);
313315516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
313415516c77SSepherosa Ziehau 
313515516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.rx sysctl tree */
313615516c77SSepherosa Ziehau 	sc->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rx",
313715516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
313815516c77SSepherosa Ziehau 
313915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
314015516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
314115516c77SSepherosa Ziehau 
314215516c77SSepherosa Ziehau 		rxr->hn_br = hyperv_dmamem_alloc(bus_get_dma_tag(dev),
314315516c77SSepherosa Ziehau 		    PAGE_SIZE, 0, HN_TXBR_SIZE + HN_RXBR_SIZE,
314415516c77SSepherosa Ziehau 		    &rxr->hn_br_dma, BUS_DMA_WAITOK);
314515516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL) {
314615516c77SSepherosa Ziehau 			device_printf(dev, "allocate bufring failed\n");
314715516c77SSepherosa Ziehau 			return (ENOMEM);
314815516c77SSepherosa Ziehau 		}
314915516c77SSepherosa Ziehau 
315015516c77SSepherosa Ziehau 		if (hn_trust_hosttcp)
315115516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP;
315215516c77SSepherosa Ziehau 		if (hn_trust_hostudp)
315315516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP;
315415516c77SSepherosa Ziehau 		if (hn_trust_hostip)
315515516c77SSepherosa Ziehau 			rxr->hn_trust_hcsum |= HN_TRUST_HCSUM_IP;
315615516c77SSepherosa Ziehau 		rxr->hn_ifp = sc->hn_ifp;
315715516c77SSepherosa Ziehau 		if (i < sc->hn_tx_ring_cnt)
315815516c77SSepherosa Ziehau 			rxr->hn_txr = &sc->hn_tx_ring[i];
315915516c77SSepherosa Ziehau 		rxr->hn_pktbuf_len = HN_PKTBUF_LEN_DEF;
316015516c77SSepherosa Ziehau 		rxr->hn_pktbuf = malloc(rxr->hn_pktbuf_len, M_DEVBUF, M_WAITOK);
316115516c77SSepherosa Ziehau 		rxr->hn_rx_idx = i;
316215516c77SSepherosa Ziehau 		rxr->hn_rxbuf = sc->hn_rxbuf;
316315516c77SSepherosa Ziehau 
316415516c77SSepherosa Ziehau 		/*
316515516c77SSepherosa Ziehau 		 * Initialize LRO.
316615516c77SSepherosa Ziehau 		 */
316715516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
316815516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100095
316915516c77SSepherosa Ziehau 		tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt,
317015516c77SSepherosa Ziehau 		    hn_lro_mbufq_depth);
317115516c77SSepherosa Ziehau #else
317215516c77SSepherosa Ziehau 		tcp_lro_init(&rxr->hn_lro);
317315516c77SSepherosa Ziehau 		rxr->hn_lro.ifp = sc->hn_ifp;
317415516c77SSepherosa Ziehau #endif
317515516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
317615516c77SSepherosa Ziehau 		rxr->hn_lro.lro_length_lim = HN_LRO_LENLIM_DEF;
317715516c77SSepherosa Ziehau 		rxr->hn_lro.lro_ackcnt_lim = HN_LRO_ACKCNT_DEF;
317815516c77SSepherosa Ziehau #endif
317915516c77SSepherosa Ziehau #endif	/* INET || INET6 */
318015516c77SSepherosa Ziehau 
318115516c77SSepherosa Ziehau 		if (sc->hn_rx_sysctl_tree != NULL) {
318215516c77SSepherosa Ziehau 			char name[16];
318315516c77SSepherosa Ziehau 
318415516c77SSepherosa Ziehau 			/*
318515516c77SSepherosa Ziehau 			 * Create per RX ring sysctl tree:
318615516c77SSepherosa Ziehau 			 * dev.hn.UNIT.rx.RINGID
318715516c77SSepherosa Ziehau 			 */
318815516c77SSepherosa Ziehau 			snprintf(name, sizeof(name), "%d", i);
318915516c77SSepherosa Ziehau 			rxr->hn_rx_sysctl_tree = SYSCTL_ADD_NODE(ctx,
319015516c77SSepherosa Ziehau 			    SYSCTL_CHILDREN(sc->hn_rx_sysctl_tree),
319115516c77SSepherosa Ziehau 			    OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
319215516c77SSepherosa Ziehau 
319315516c77SSepherosa Ziehau 			if (rxr->hn_rx_sysctl_tree != NULL) {
319415516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
319515516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
319615516c77SSepherosa Ziehau 				    OID_AUTO, "packets", CTLFLAG_RW,
319715516c77SSepherosa Ziehau 				    &rxr->hn_pkts, "# of packets received");
319815516c77SSepherosa Ziehau 				SYSCTL_ADD_ULONG(ctx,
319915516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
320015516c77SSepherosa Ziehau 				    OID_AUTO, "rss_pkts", CTLFLAG_RW,
320115516c77SSepherosa Ziehau 				    &rxr->hn_rss_pkts,
320215516c77SSepherosa Ziehau 				    "# of packets w/ RSS info received");
320315516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx,
320415516c77SSepherosa Ziehau 				    SYSCTL_CHILDREN(rxr->hn_rx_sysctl_tree),
320515516c77SSepherosa Ziehau 				    OID_AUTO, "pktbuf_len", CTLFLAG_RD,
320615516c77SSepherosa Ziehau 				    &rxr->hn_pktbuf_len, 0,
320715516c77SSepherosa Ziehau 				    "Temporary channel packet buffer length");
320815516c77SSepherosa Ziehau 			}
320915516c77SSepherosa Ziehau 		}
321015516c77SSepherosa Ziehau 	}
321115516c77SSepherosa Ziehau 
321215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_queued",
321315516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
321415516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_queued),
321515516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
321615516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
321715516c77SSepherosa Ziehau #else
321815516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
321915516c77SSepherosa Ziehau #endif
322015516c77SSepherosa Ziehau 	    "LU", "LRO queued");
322115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_flushed",
322215516c77SSepherosa Ziehau 	    CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
322315516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro.lro_flushed),
322415516c77SSepherosa Ziehau #if __FreeBSD_version < 1100095
322515516c77SSepherosa Ziehau 	    hn_rx_stat_int_sysctl,
322615516c77SSepherosa Ziehau #else
322715516c77SSepherosa Ziehau 	    hn_rx_stat_u64_sysctl,
322815516c77SSepherosa Ziehau #endif
322915516c77SSepherosa Ziehau 	    "LU", "LRO flushed");
323015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_tried",
323115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
323215516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_lro_tried),
323315516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of LRO tries");
323415516c77SSepherosa Ziehau #if __FreeBSD_version >= 1100099
323515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_length_lim",
323615516c77SSepherosa Ziehau 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
323715516c77SSepherosa Ziehau 	    hn_lro_lenlim_sysctl, "IU",
323815516c77SSepherosa Ziehau 	    "Max # of data bytes to be aggregated by LRO");
323915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ackcnt_lim",
324015516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
324115516c77SSepherosa Ziehau 	    hn_lro_ackcnt_sysctl, "I",
324215516c77SSepherosa Ziehau 	    "Max # of ACKs to be aggregated by LRO");
324315516c77SSepherosa Ziehau #endif
324415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp",
324515516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_TCP,
324615516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
324715516c77SSepherosa Ziehau 	    "Trust tcp segement verification on host side, "
324815516c77SSepherosa Ziehau 	    "when csum info is missing");
324915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp",
325015516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_UDP,
325115516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
325215516c77SSepherosa Ziehau 	    "Trust udp datagram verification on host side, "
325315516c77SSepherosa Ziehau 	    "when csum info is missing");
325415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostip",
325515516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, HN_TRUST_HCSUM_IP,
325615516c77SSepherosa Ziehau 	    hn_trust_hcsum_sysctl, "I",
325715516c77SSepherosa Ziehau 	    "Trust ip packet verification on host side, "
325815516c77SSepherosa Ziehau 	    "when csum info is missing");
325915516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_ip",
326015516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
326115516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_ip),
326215516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM IP");
326315516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_tcp",
326415516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
326515516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_tcp),
326615516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM TCP");
326715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_udp",
326815516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
326915516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_udp),
327015516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "RXCSUM UDP");
327115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "csum_trusted",
327215516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
327315516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_csum_trusted),
327415516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU",
327515516c77SSepherosa Ziehau 	    "# of packets that we trust host's csum verification");
327615516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "small_pkts",
327715516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
327815516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_small_pkts),
327915516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of small packets received");
328015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_ack_failed",
328115516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
328215516c77SSepherosa Ziehau 	    __offsetof(struct hn_rx_ring, hn_ack_failed),
328315516c77SSepherosa Ziehau 	    hn_rx_stat_ulong_sysctl, "LU", "# of RXBUF ack failures");
328415516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_cnt",
328515516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_cnt, 0, "# created RX rings");
328615516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_inuse",
328715516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_rx_ring_inuse, 0, "# used RX rings");
328815516c77SSepherosa Ziehau 
328915516c77SSepherosa Ziehau 	return (0);
329015516c77SSepherosa Ziehau }
329115516c77SSepherosa Ziehau 
329215516c77SSepherosa Ziehau static void
329315516c77SSepherosa Ziehau hn_destroy_rx_data(struct hn_softc *sc)
329415516c77SSepherosa Ziehau {
329515516c77SSepherosa Ziehau 	int i;
329615516c77SSepherosa Ziehau 
329715516c77SSepherosa Ziehau 	if (sc->hn_rxbuf != NULL) {
32982494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_RXBUF_REF) == 0)
329915516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_rxbuf_dma, sc->hn_rxbuf);
33002494d735SSepherosa Ziehau 		else
33012494d735SSepherosa Ziehau 			device_printf(sc->hn_dev, "RXBUF is referenced\n");
330215516c77SSepherosa Ziehau 		sc->hn_rxbuf = NULL;
330315516c77SSepherosa Ziehau 	}
330415516c77SSepherosa Ziehau 
330515516c77SSepherosa Ziehau 	if (sc->hn_rx_ring_cnt == 0)
330615516c77SSepherosa Ziehau 		return;
330715516c77SSepherosa Ziehau 
330815516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
330915516c77SSepherosa Ziehau 		struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
331015516c77SSepherosa Ziehau 
331115516c77SSepherosa Ziehau 		if (rxr->hn_br == NULL)
331215516c77SSepherosa Ziehau 			continue;
33132494d735SSepherosa Ziehau 		if ((rxr->hn_rx_flags & HN_RX_FLAG_BR_REF) == 0) {
331415516c77SSepherosa Ziehau 			hyperv_dmamem_free(&rxr->hn_br_dma, rxr->hn_br);
33152494d735SSepherosa Ziehau 		} else {
33162494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
33172494d735SSepherosa Ziehau 			    "%dth channel bufring is referenced", i);
33182494d735SSepherosa Ziehau 		}
331915516c77SSepherosa Ziehau 		rxr->hn_br = NULL;
332015516c77SSepherosa Ziehau 
332115516c77SSepherosa Ziehau #if defined(INET) || defined(INET6)
332215516c77SSepherosa Ziehau 		tcp_lro_free(&rxr->hn_lro);
332315516c77SSepherosa Ziehau #endif
332415516c77SSepherosa Ziehau 		free(rxr->hn_pktbuf, M_DEVBUF);
332515516c77SSepherosa Ziehau 	}
332615516c77SSepherosa Ziehau 	free(sc->hn_rx_ring, M_DEVBUF);
332715516c77SSepherosa Ziehau 	sc->hn_rx_ring = NULL;
332815516c77SSepherosa Ziehau 
332915516c77SSepherosa Ziehau 	sc->hn_rx_ring_cnt = 0;
333015516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = 0;
333115516c77SSepherosa Ziehau }
333215516c77SSepherosa Ziehau 
333315516c77SSepherosa Ziehau static int
333415516c77SSepherosa Ziehau hn_tx_ring_create(struct hn_softc *sc, int id)
333515516c77SSepherosa Ziehau {
333615516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[id];
333715516c77SSepherosa Ziehau 	device_t dev = sc->hn_dev;
333815516c77SSepherosa Ziehau 	bus_dma_tag_t parent_dtag;
333915516c77SSepherosa Ziehau 	int error, i;
334015516c77SSepherosa Ziehau 
334115516c77SSepherosa Ziehau 	txr->hn_sc = sc;
334215516c77SSepherosa Ziehau 	txr->hn_tx_idx = id;
334315516c77SSepherosa Ziehau 
334415516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
334515516c77SSepherosa Ziehau 	mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN);
334615516c77SSepherosa Ziehau #endif
334715516c77SSepherosa Ziehau 	mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF);
334815516c77SSepherosa Ziehau 
334915516c77SSepherosa Ziehau 	txr->hn_txdesc_cnt = HN_TX_DESC_CNT;
335015516c77SSepherosa Ziehau 	txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt,
335115516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
335215516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
335315516c77SSepherosa Ziehau 	SLIST_INIT(&txr->hn_txlist);
335415516c77SSepherosa Ziehau #else
335515516c77SSepherosa Ziehau 	txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_DEVBUF,
335615516c77SSepherosa Ziehau 	    M_WAITOK, &txr->hn_tx_lock);
335715516c77SSepherosa Ziehau #endif
335815516c77SSepherosa Ziehau 
33590e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode == HN_TX_TASKQ_M_EVTTQ) {
33600e11868dSSepherosa Ziehau 		txr->hn_tx_taskq = VMBUS_GET_EVENT_TASKQ(
33610e11868dSSepherosa Ziehau 		    device_get_parent(dev), dev, HN_RING_IDX2CPU(sc, id));
33620e11868dSSepherosa Ziehau 	} else {
3363fdd0222aSSepherosa Ziehau 		txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt];
33640e11868dSSepherosa Ziehau 	}
336515516c77SSepherosa Ziehau 
336623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
336715516c77SSepherosa Ziehau 	if (hn_use_if_start) {
336815516c77SSepherosa Ziehau 		txr->hn_txeof = hn_start_txeof;
336915516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_start_taskfunc, txr);
337015516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_start_txeof_taskfunc, txr);
337123bf9e15SSepherosa Ziehau 	} else
337223bf9e15SSepherosa Ziehau #endif
337323bf9e15SSepherosa Ziehau 	{
337415516c77SSepherosa Ziehau 		int br_depth;
337515516c77SSepherosa Ziehau 
337615516c77SSepherosa Ziehau 		txr->hn_txeof = hn_xmit_txeof;
337715516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_tx_task, 0, hn_xmit_taskfunc, txr);
337815516c77SSepherosa Ziehau 		TASK_INIT(&txr->hn_txeof_task, 0, hn_xmit_txeof_taskfunc, txr);
337915516c77SSepherosa Ziehau 
338015516c77SSepherosa Ziehau 		br_depth = hn_get_txswq_depth(txr);
338115516c77SSepherosa Ziehau 		txr->hn_mbuf_br = buf_ring_alloc(br_depth, M_DEVBUF,
338215516c77SSepherosa Ziehau 		    M_WAITOK, &txr->hn_tx_lock);
338315516c77SSepherosa Ziehau 	}
338415516c77SSepherosa Ziehau 
338515516c77SSepherosa Ziehau 	txr->hn_direct_tx_size = hn_direct_tx_size;
338615516c77SSepherosa Ziehau 
338715516c77SSepherosa Ziehau 	/*
338815516c77SSepherosa Ziehau 	 * Always schedule transmission instead of trying to do direct
338915516c77SSepherosa Ziehau 	 * transmission.  This one gives the best performance so far.
339015516c77SSepherosa Ziehau 	 */
339115516c77SSepherosa Ziehau 	txr->hn_sched_tx = 1;
339215516c77SSepherosa Ziehau 
339315516c77SSepherosa Ziehau 	parent_dtag = bus_get_dma_tag(dev);
339415516c77SSepherosa Ziehau 
339515516c77SSepherosa Ziehau 	/* DMA tag for RNDIS packet messages. */
339615516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
339715516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_ALIGN,		/* alignment */
339815516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_BOUNDARY,	/* boundary */
339915516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
340015516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
340115516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
340215516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsize */
340315516c77SSepherosa Ziehau 	    1,				/* nsegments */
340415516c77SSepherosa Ziehau 	    HN_RNDIS_PKT_LEN,		/* maxsegsize */
340515516c77SSepherosa Ziehau 	    0,				/* flags */
340615516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
340715516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
340815516c77SSepherosa Ziehau 	    &txr->hn_tx_rndis_dtag);
340915516c77SSepherosa Ziehau 	if (error) {
341015516c77SSepherosa Ziehau 		device_printf(dev, "failed to create rndis dmatag\n");
341115516c77SSepherosa Ziehau 		return error;
341215516c77SSepherosa Ziehau 	}
341315516c77SSepherosa Ziehau 
341415516c77SSepherosa Ziehau 	/* DMA tag for data. */
341515516c77SSepherosa Ziehau 	error = bus_dma_tag_create(parent_dtag, /* parent */
341615516c77SSepherosa Ziehau 	    1,				/* alignment */
341715516c77SSepherosa Ziehau 	    HN_TX_DATA_BOUNDARY,	/* boundary */
341815516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* lowaddr */
341915516c77SSepherosa Ziehau 	    BUS_SPACE_MAXADDR,		/* highaddr */
342015516c77SSepherosa Ziehau 	    NULL, NULL,			/* filter, filterarg */
342115516c77SSepherosa Ziehau 	    HN_TX_DATA_MAXSIZE,		/* maxsize */
342215516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGCNT_MAX,	/* nsegments */
342315516c77SSepherosa Ziehau 	    HN_TX_DATA_SEGSIZE,		/* maxsegsize */
342415516c77SSepherosa Ziehau 	    0,				/* flags */
342515516c77SSepherosa Ziehau 	    NULL,			/* lockfunc */
342615516c77SSepherosa Ziehau 	    NULL,			/* lockfuncarg */
342715516c77SSepherosa Ziehau 	    &txr->hn_tx_data_dtag);
342815516c77SSepherosa Ziehau 	if (error) {
342915516c77SSepherosa Ziehau 		device_printf(dev, "failed to create data dmatag\n");
343015516c77SSepherosa Ziehau 		return error;
343115516c77SSepherosa Ziehau 	}
343215516c77SSepherosa Ziehau 
343315516c77SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i) {
343415516c77SSepherosa Ziehau 		struct hn_txdesc *txd = &txr->hn_txdesc[i];
343515516c77SSepherosa Ziehau 
343615516c77SSepherosa Ziehau 		txd->txr = txr;
343715516c77SSepherosa Ziehau 		txd->chim_index = HN_NVS_CHIM_IDX_INVALID;
3438dc13fee6SSepherosa Ziehau 		STAILQ_INIT(&txd->agg_list);
343915516c77SSepherosa Ziehau 
344015516c77SSepherosa Ziehau 		/*
344115516c77SSepherosa Ziehau 		 * Allocate and load RNDIS packet message.
344215516c77SSepherosa Ziehau 		 */
344315516c77SSepherosa Ziehau         	error = bus_dmamem_alloc(txr->hn_tx_rndis_dtag,
344415516c77SSepherosa Ziehau 		    (void **)&txd->rndis_pkt,
344515516c77SSepherosa Ziehau 		    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
344615516c77SSepherosa Ziehau 		    &txd->rndis_pkt_dmap);
344715516c77SSepherosa Ziehau 		if (error) {
344815516c77SSepherosa Ziehau 			device_printf(dev,
344915516c77SSepherosa Ziehau 			    "failed to allocate rndis_packet_msg, %d\n", i);
345015516c77SSepherosa Ziehau 			return error;
345115516c77SSepherosa Ziehau 		}
345215516c77SSepherosa Ziehau 
345315516c77SSepherosa Ziehau 		error = bus_dmamap_load(txr->hn_tx_rndis_dtag,
345415516c77SSepherosa Ziehau 		    txd->rndis_pkt_dmap,
345515516c77SSepherosa Ziehau 		    txd->rndis_pkt, HN_RNDIS_PKT_LEN,
345615516c77SSepherosa Ziehau 		    hyperv_dma_map_paddr, &txd->rndis_pkt_paddr,
345715516c77SSepherosa Ziehau 		    BUS_DMA_NOWAIT);
345815516c77SSepherosa Ziehau 		if (error) {
345915516c77SSepherosa Ziehau 			device_printf(dev,
346015516c77SSepherosa Ziehau 			    "failed to load rndis_packet_msg, %d\n", i);
346115516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
346215516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
346315516c77SSepherosa Ziehau 			return error;
346415516c77SSepherosa Ziehau 		}
346515516c77SSepherosa Ziehau 
346615516c77SSepherosa Ziehau 		/* DMA map for TX data. */
346715516c77SSepherosa Ziehau 		error = bus_dmamap_create(txr->hn_tx_data_dtag, 0,
346815516c77SSepherosa Ziehau 		    &txd->data_dmap);
346915516c77SSepherosa Ziehau 		if (error) {
347015516c77SSepherosa Ziehau 			device_printf(dev,
347115516c77SSepherosa Ziehau 			    "failed to allocate tx data dmamap\n");
347215516c77SSepherosa Ziehau 			bus_dmamap_unload(txr->hn_tx_rndis_dtag,
347315516c77SSepherosa Ziehau 			    txd->rndis_pkt_dmap);
347415516c77SSepherosa Ziehau 			bus_dmamem_free(txr->hn_tx_rndis_dtag,
347515516c77SSepherosa Ziehau 			    txd->rndis_pkt, txd->rndis_pkt_dmap);
347615516c77SSepherosa Ziehau 			return error;
347715516c77SSepherosa Ziehau 		}
347815516c77SSepherosa Ziehau 
347915516c77SSepherosa Ziehau 		/* All set, put it to list */
348015516c77SSepherosa Ziehau 		txd->flags |= HN_TXD_FLAG_ONLIST;
348115516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
348215516c77SSepherosa Ziehau 		SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link);
348315516c77SSepherosa Ziehau #else
348415516c77SSepherosa Ziehau 		buf_ring_enqueue(txr->hn_txdesc_br, txd);
348515516c77SSepherosa Ziehau #endif
348615516c77SSepherosa Ziehau 	}
348715516c77SSepherosa Ziehau 	txr->hn_txdesc_avail = txr->hn_txdesc_cnt;
348815516c77SSepherosa Ziehau 
348915516c77SSepherosa Ziehau 	if (sc->hn_tx_sysctl_tree != NULL) {
349015516c77SSepherosa Ziehau 		struct sysctl_oid_list *child;
349115516c77SSepherosa Ziehau 		struct sysctl_ctx_list *ctx;
349215516c77SSepherosa Ziehau 		char name[16];
349315516c77SSepherosa Ziehau 
349415516c77SSepherosa Ziehau 		/*
349515516c77SSepherosa Ziehau 		 * Create per TX ring sysctl tree:
349615516c77SSepherosa Ziehau 		 * dev.hn.UNIT.tx.RINGID
349715516c77SSepherosa Ziehau 		 */
349815516c77SSepherosa Ziehau 		ctx = device_get_sysctl_ctx(dev);
349915516c77SSepherosa Ziehau 		child = SYSCTL_CHILDREN(sc->hn_tx_sysctl_tree);
350015516c77SSepherosa Ziehau 
350115516c77SSepherosa Ziehau 		snprintf(name, sizeof(name), "%d", id);
350215516c77SSepherosa Ziehau 		txr->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
350315516c77SSepherosa Ziehau 		    name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
350415516c77SSepherosa Ziehau 
350515516c77SSepherosa Ziehau 		if (txr->hn_tx_sysctl_tree != NULL) {
350615516c77SSepherosa Ziehau 			child = SYSCTL_CHILDREN(txr->hn_tx_sysctl_tree);
350715516c77SSepherosa Ziehau 
350885e4ae1eSSepherosa Ziehau #ifdef HN_DEBUG
350915516c77SSepherosa Ziehau 			SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_avail",
351015516c77SSepherosa Ziehau 			    CTLFLAG_RD, &txr->hn_txdesc_avail, 0,
351115516c77SSepherosa Ziehau 			    "# of available TX descs");
351285e4ae1eSSepherosa Ziehau #endif
351323bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
351423bf9e15SSepherosa Ziehau 			if (!hn_use_if_start)
351523bf9e15SSepherosa Ziehau #endif
351623bf9e15SSepherosa Ziehau 			{
351715516c77SSepherosa Ziehau 				SYSCTL_ADD_INT(ctx, child, OID_AUTO, "oactive",
351815516c77SSepherosa Ziehau 				    CTLFLAG_RD, &txr->hn_oactive, 0,
351915516c77SSepherosa Ziehau 				    "over active");
352015516c77SSepherosa Ziehau 			}
352115516c77SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "packets",
352215516c77SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_pkts,
352315516c77SSepherosa Ziehau 			    "# of packets transmitted");
3524dc13fee6SSepherosa Ziehau 			SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "sends",
3525dc13fee6SSepherosa Ziehau 			    CTLFLAG_RW, &txr->hn_sends, "# of sends");
352615516c77SSepherosa Ziehau 		}
352715516c77SSepherosa Ziehau 	}
352815516c77SSepherosa Ziehau 
352915516c77SSepherosa Ziehau 	return 0;
353015516c77SSepherosa Ziehau }
353115516c77SSepherosa Ziehau 
353215516c77SSepherosa Ziehau static void
353315516c77SSepherosa Ziehau hn_txdesc_dmamap_destroy(struct hn_txdesc *txd)
353415516c77SSepherosa Ziehau {
353515516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = txd->txr;
353615516c77SSepherosa Ziehau 
353715516c77SSepherosa Ziehau 	KASSERT(txd->m == NULL, ("still has mbuf installed"));
353815516c77SSepherosa Ziehau 	KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped"));
353915516c77SSepherosa Ziehau 
354015516c77SSepherosa Ziehau 	bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_pkt_dmap);
354115516c77SSepherosa Ziehau 	bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_pkt,
354215516c77SSepherosa Ziehau 	    txd->rndis_pkt_dmap);
354315516c77SSepherosa Ziehau 	bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap);
354415516c77SSepherosa Ziehau }
354515516c77SSepherosa Ziehau 
354615516c77SSepherosa Ziehau static void
354725641fc7SSepherosa Ziehau hn_txdesc_gc(struct hn_tx_ring *txr, struct hn_txdesc *txd)
354825641fc7SSepherosa Ziehau {
354925641fc7SSepherosa Ziehau 
355025641fc7SSepherosa Ziehau 	KASSERT(txd->refs == 0 || txd->refs == 1,
355125641fc7SSepherosa Ziehau 	    ("invalid txd refs %d", txd->refs));
355225641fc7SSepherosa Ziehau 
355325641fc7SSepherosa Ziehau 	/* Aggregated txds will be freed by their aggregating txd. */
355425641fc7SSepherosa Ziehau 	if (txd->refs > 0 && (txd->flags & HN_TXD_FLAG_ONAGG) == 0) {
355525641fc7SSepherosa Ziehau 		int freed;
355625641fc7SSepherosa Ziehau 
355725641fc7SSepherosa Ziehau 		freed = hn_txdesc_put(txr, txd);
355825641fc7SSepherosa Ziehau 		KASSERT(freed, ("can't free txdesc"));
355925641fc7SSepherosa Ziehau 	}
356025641fc7SSepherosa Ziehau }
356125641fc7SSepherosa Ziehau 
356225641fc7SSepherosa Ziehau static void
356315516c77SSepherosa Ziehau hn_tx_ring_destroy(struct hn_tx_ring *txr)
356415516c77SSepherosa Ziehau {
356525641fc7SSepherosa Ziehau 	int i;
356615516c77SSepherosa Ziehau 
356715516c77SSepherosa Ziehau 	if (txr->hn_txdesc == NULL)
356815516c77SSepherosa Ziehau 		return;
356915516c77SSepherosa Ziehau 
357025641fc7SSepherosa Ziehau 	/*
357125641fc7SSepherosa Ziehau 	 * NOTE:
357225641fc7SSepherosa Ziehau 	 * Because the freeing of aggregated txds will be deferred
357325641fc7SSepherosa Ziehau 	 * to the aggregating txd, two passes are used here:
357425641fc7SSepherosa Ziehau 	 * - The first pass GCes any pending txds.  This GC is necessary,
357525641fc7SSepherosa Ziehau 	 *   since if the channels are revoked, hypervisor will not
357625641fc7SSepherosa Ziehau 	 *   deliver send-done for all pending txds.
357725641fc7SSepherosa Ziehau 	 * - The second pass frees the busdma stuffs, i.e. after all txds
357825641fc7SSepherosa Ziehau 	 *   were freed.
357925641fc7SSepherosa Ziehau 	 */
358025641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
358125641fc7SSepherosa Ziehau 		hn_txdesc_gc(txr, &txr->hn_txdesc[i]);
358225641fc7SSepherosa Ziehau 	for (i = 0; i < txr->hn_txdesc_cnt; ++i)
358325641fc7SSepherosa Ziehau 		hn_txdesc_dmamap_destroy(&txr->hn_txdesc[i]);
358415516c77SSepherosa Ziehau 
358515516c77SSepherosa Ziehau 	if (txr->hn_tx_data_dtag != NULL)
358615516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_data_dtag);
358715516c77SSepherosa Ziehau 	if (txr->hn_tx_rndis_dtag != NULL)
358815516c77SSepherosa Ziehau 		bus_dma_tag_destroy(txr->hn_tx_rndis_dtag);
358915516c77SSepherosa Ziehau 
359015516c77SSepherosa Ziehau #ifdef HN_USE_TXDESC_BUFRING
359115516c77SSepherosa Ziehau 	buf_ring_free(txr->hn_txdesc_br, M_DEVBUF);
359215516c77SSepherosa Ziehau #endif
359315516c77SSepherosa Ziehau 
359415516c77SSepherosa Ziehau 	free(txr->hn_txdesc, M_DEVBUF);
359515516c77SSepherosa Ziehau 	txr->hn_txdesc = NULL;
359615516c77SSepherosa Ziehau 
359715516c77SSepherosa Ziehau 	if (txr->hn_mbuf_br != NULL)
359815516c77SSepherosa Ziehau 		buf_ring_free(txr->hn_mbuf_br, M_DEVBUF);
359915516c77SSepherosa Ziehau 
360015516c77SSepherosa Ziehau #ifndef HN_USE_TXDESC_BUFRING
360115516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_txlist_spin);
360215516c77SSepherosa Ziehau #endif
360315516c77SSepherosa Ziehau 	mtx_destroy(&txr->hn_tx_lock);
360415516c77SSepherosa Ziehau }
360515516c77SSepherosa Ziehau 
360615516c77SSepherosa Ziehau static int
360715516c77SSepherosa Ziehau hn_create_tx_data(struct hn_softc *sc, int ring_cnt)
360815516c77SSepherosa Ziehau {
360915516c77SSepherosa Ziehau 	struct sysctl_oid_list *child;
361015516c77SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
361115516c77SSepherosa Ziehau 	int i;
361215516c77SSepherosa Ziehau 
361315516c77SSepherosa Ziehau 	/*
361415516c77SSepherosa Ziehau 	 * Create TXBUF for chimney sending.
361515516c77SSepherosa Ziehau 	 *
361615516c77SSepherosa Ziehau 	 * NOTE: It is shared by all channels.
361715516c77SSepherosa Ziehau 	 */
361815516c77SSepherosa Ziehau 	sc->hn_chim = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev),
361915516c77SSepherosa Ziehau 	    PAGE_SIZE, 0, HN_CHIM_SIZE, &sc->hn_chim_dma,
362015516c77SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
362115516c77SSepherosa Ziehau 	if (sc->hn_chim == NULL) {
362215516c77SSepherosa Ziehau 		device_printf(sc->hn_dev, "allocate txbuf failed\n");
362315516c77SSepherosa Ziehau 		return (ENOMEM);
362415516c77SSepherosa Ziehau 	}
362515516c77SSepherosa Ziehau 
362615516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = ring_cnt;
362715516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
362815516c77SSepherosa Ziehau 
362915516c77SSepherosa Ziehau 	sc->hn_tx_ring = malloc(sizeof(struct hn_tx_ring) * sc->hn_tx_ring_cnt,
363015516c77SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
363115516c77SSepherosa Ziehau 
363215516c77SSepherosa Ziehau 	ctx = device_get_sysctl_ctx(sc->hn_dev);
363315516c77SSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->hn_dev));
363415516c77SSepherosa Ziehau 
363515516c77SSepherosa Ziehau 	/* Create dev.hn.UNIT.tx sysctl tree */
363615516c77SSepherosa Ziehau 	sc->hn_tx_sysctl_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tx",
363715516c77SSepherosa Ziehau 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
363815516c77SSepherosa Ziehau 
363915516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
364015516c77SSepherosa Ziehau 		int error;
364115516c77SSepherosa Ziehau 
364215516c77SSepherosa Ziehau 		error = hn_tx_ring_create(sc, i);
364315516c77SSepherosa Ziehau 		if (error)
364415516c77SSepherosa Ziehau 			return error;
364515516c77SSepherosa Ziehau 	}
364615516c77SSepherosa Ziehau 
364715516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "no_txdescs",
364815516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
364915516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_no_txdescs),
365015516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of times short of TX descs");
365115516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "send_failed",
365215516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
365315516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_send_failed),
365415516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of hyper-v sending failure");
365515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdma_failed",
365615516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
365715516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_txdma_failed),
365815516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX DMA failure");
3659dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_flush_failed",
3660dc13fee6SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
3661dc13fee6SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_flush_failed),
3662dc13fee6SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU",
3663dc13fee6SSepherosa Ziehau 	    "# of packet transmission aggregation flush failure");
366415516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_collapsed",
366515516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
366615516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_collapsed),
366715516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of TX mbuf collapsed");
366815516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney",
366915516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
367015516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney),
367115516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send");
367215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_tried",
367315516c77SSepherosa Ziehau 	    CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
367415516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_tx_chimney_tried),
367515516c77SSepherosa Ziehau 	    hn_tx_stat_ulong_sysctl, "LU", "# of chimney send tries");
367615516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "txdesc_cnt",
367715516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_txdesc_cnt, 0,
367815516c77SSepherosa Ziehau 	    "# of total TX descs");
367915516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_chimney_max",
368015516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_chim_szmax, 0,
368115516c77SSepherosa Ziehau 	    "Chimney send packet size upper boundary");
368215516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size",
368315516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
368415516c77SSepherosa Ziehau 	    hn_chim_size_sysctl, "I", "Chimney send packet size limit");
368515516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "direct_tx_size",
368615516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
368715516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_direct_tx_size),
368815516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
368915516c77SSepherosa Ziehau 	    "Size of the packet for direct transmission");
369015516c77SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "sched_tx",
369115516c77SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
369215516c77SSepherosa Ziehau 	    __offsetof(struct hn_tx_ring, hn_sched_tx),
369315516c77SSepherosa Ziehau 	    hn_tx_conf_int_sysctl, "I",
369415516c77SSepherosa Ziehau 	    "Always schedule transmission "
369515516c77SSepherosa Ziehau 	    "instead of doing direct transmission");
369615516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_cnt",
369715516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_cnt, 0, "# created TX rings");
369815516c77SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_inuse",
369915516c77SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring_inuse, 0, "# used TX rings");
3700dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "agg_szmax",
3701dc13fee6SSepherosa Ziehau 	    CTLFLAG_RD, &sc->hn_tx_ring[0].hn_agg_szmax, 0,
3702dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation size");
3703dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pktmax",
3704dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
3705dc13fee6SSepherosa Ziehau 	    hn_txagg_pktmax_sysctl, "I",
3706dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation packets");
3707dc13fee6SSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_align",
3708dc13fee6SSepherosa Ziehau 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
3709dc13fee6SSepherosa Ziehau 	    hn_txagg_align_sysctl, "I",
3710dc13fee6SSepherosa Ziehau 	    "Applied packet transmission aggregation alignment");
371115516c77SSepherosa Ziehau 
371215516c77SSepherosa Ziehau 	return 0;
371315516c77SSepherosa Ziehau }
371415516c77SSepherosa Ziehau 
371515516c77SSepherosa Ziehau static void
371615516c77SSepherosa Ziehau hn_set_chim_size(struct hn_softc *sc, int chim_size)
371715516c77SSepherosa Ziehau {
371815516c77SSepherosa Ziehau 	int i;
371915516c77SSepherosa Ziehau 
3720a7ba7648SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
372115516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_chim_size = chim_size;
372215516c77SSepherosa Ziehau }
372315516c77SSepherosa Ziehau 
372415516c77SSepherosa Ziehau static void
372515516c77SSepherosa Ziehau hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu)
372615516c77SSepherosa Ziehau {
372715516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
372815516c77SSepherosa Ziehau 	int tso_minlen;
372915516c77SSepherosa Ziehau 
373015516c77SSepherosa Ziehau 	if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0)
373115516c77SSepherosa Ziehau 		return;
373215516c77SSepherosa Ziehau 
373315516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_sgmin >= 2,
373415516c77SSepherosa Ziehau 	    ("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin));
373515516c77SSepherosa Ziehau 	tso_minlen = sc->hn_ndis_tso_sgmin * mtu;
373615516c77SSepherosa Ziehau 
373715516c77SSepherosa Ziehau 	KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen &&
373815516c77SSepherosa Ziehau 	    sc->hn_ndis_tso_szmax <= IP_MAXPACKET,
373915516c77SSepherosa Ziehau 	    ("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax));
374015516c77SSepherosa Ziehau 
374115516c77SSepherosa Ziehau 	if (tso_maxlen < tso_minlen)
374215516c77SSepherosa Ziehau 		tso_maxlen = tso_minlen;
374315516c77SSepherosa Ziehau 	else if (tso_maxlen > IP_MAXPACKET)
374415516c77SSepherosa Ziehau 		tso_maxlen = IP_MAXPACKET;
374515516c77SSepherosa Ziehau 	if (tso_maxlen > sc->hn_ndis_tso_szmax)
374615516c77SSepherosa Ziehau 		tso_maxlen = sc->hn_ndis_tso_szmax;
374715516c77SSepherosa Ziehau 	ifp->if_hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
374815516c77SSepherosa Ziehau 	if (bootverbose)
374915516c77SSepherosa Ziehau 		if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax);
375015516c77SSepherosa Ziehau }
375115516c77SSepherosa Ziehau 
375215516c77SSepherosa Ziehau static void
375315516c77SSepherosa Ziehau hn_fixup_tx_data(struct hn_softc *sc)
375415516c77SSepherosa Ziehau {
375515516c77SSepherosa Ziehau 	uint64_t csum_assist;
375615516c77SSepherosa Ziehau 	int i;
375715516c77SSepherosa Ziehau 
375815516c77SSepherosa Ziehau 	hn_set_chim_size(sc, sc->hn_chim_szmax);
375915516c77SSepherosa Ziehau 	if (hn_tx_chimney_size > 0 &&
376015516c77SSepherosa Ziehau 	    hn_tx_chimney_size < sc->hn_chim_szmax)
376115516c77SSepherosa Ziehau 		hn_set_chim_size(sc, hn_tx_chimney_size);
376215516c77SSepherosa Ziehau 
376315516c77SSepherosa Ziehau 	csum_assist = 0;
376415516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_IPCS)
376515516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP;
376615516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP4CS)
376715516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_TCP;
376815516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP4CS)
376915516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP_UDP;
377015516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_TCP6CS)
377115516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_TCP;
377215516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_UDP6CS)
377315516c77SSepherosa Ziehau 		csum_assist |= CSUM_IP6_UDP;
377415516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
377515516c77SSepherosa Ziehau 		sc->hn_tx_ring[i].hn_csum_assist = csum_assist;
377615516c77SSepherosa Ziehau 
377715516c77SSepherosa Ziehau 	if (sc->hn_caps & HN_CAP_HASHVAL) {
377815516c77SSepherosa Ziehau 		/*
377915516c77SSepherosa Ziehau 		 * Support HASHVAL pktinfo on TX path.
378015516c77SSepherosa Ziehau 		 */
378115516c77SSepherosa Ziehau 		if (bootverbose)
378215516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n");
378315516c77SSepherosa Ziehau 		for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
378415516c77SSepherosa Ziehau 			sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL;
378515516c77SSepherosa Ziehau 	}
378615516c77SSepherosa Ziehau }
378715516c77SSepherosa Ziehau 
378815516c77SSepherosa Ziehau static void
378915516c77SSepherosa Ziehau hn_destroy_tx_data(struct hn_softc *sc)
379015516c77SSepherosa Ziehau {
379115516c77SSepherosa Ziehau 	int i;
379215516c77SSepherosa Ziehau 
379315516c77SSepherosa Ziehau 	if (sc->hn_chim != NULL) {
37942494d735SSepherosa Ziehau 		if ((sc->hn_flags & HN_FLAG_CHIM_REF) == 0) {
379515516c77SSepherosa Ziehau 			hyperv_dmamem_free(&sc->hn_chim_dma, sc->hn_chim);
37962494d735SSepherosa Ziehau 		} else {
37972494d735SSepherosa Ziehau 			device_printf(sc->hn_dev,
37982494d735SSepherosa Ziehau 			    "chimney sending buffer is referenced");
37992494d735SSepherosa Ziehau 		}
380015516c77SSepherosa Ziehau 		sc->hn_chim = NULL;
380115516c77SSepherosa Ziehau 	}
380215516c77SSepherosa Ziehau 
380315516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt == 0)
380415516c77SSepherosa Ziehau 		return;
380515516c77SSepherosa Ziehau 
380615516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i)
380715516c77SSepherosa Ziehau 		hn_tx_ring_destroy(&sc->hn_tx_ring[i]);
380815516c77SSepherosa Ziehau 
380915516c77SSepherosa Ziehau 	free(sc->hn_tx_ring, M_DEVBUF);
381015516c77SSepherosa Ziehau 	sc->hn_tx_ring = NULL;
381115516c77SSepherosa Ziehau 
381215516c77SSepherosa Ziehau 	sc->hn_tx_ring_cnt = 0;
381315516c77SSepherosa Ziehau 	sc->hn_tx_ring_inuse = 0;
381415516c77SSepherosa Ziehau }
381515516c77SSepherosa Ziehau 
381623bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
381723bf9e15SSepherosa Ziehau 
381815516c77SSepherosa Ziehau static void
381915516c77SSepherosa Ziehau hn_start_taskfunc(void *xtxr, int pending __unused)
382015516c77SSepherosa Ziehau {
382115516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
382215516c77SSepherosa Ziehau 
382315516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
382415516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
382515516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
382615516c77SSepherosa Ziehau }
382715516c77SSepherosa Ziehau 
382823bf9e15SSepherosa Ziehau static int
382923bf9e15SSepherosa Ziehau hn_start_locked(struct hn_tx_ring *txr, int len)
383023bf9e15SSepherosa Ziehau {
383123bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
383223bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
3833dc13fee6SSepherosa Ziehau 	int sched = 0;
383423bf9e15SSepherosa Ziehau 
383523bf9e15SSepherosa Ziehau 	KASSERT(hn_use_if_start,
383623bf9e15SSepherosa Ziehau 	    ("hn_start_locked is called, when if_start is disabled"));
383723bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
383823bf9e15SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
3839dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
384023bf9e15SSepherosa Ziehau 
384123bf9e15SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
3842dc13fee6SSepherosa Ziehau 		return (0);
384323bf9e15SSepherosa Ziehau 
384423bf9e15SSepherosa Ziehau 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
384523bf9e15SSepherosa Ziehau 	    IFF_DRV_RUNNING)
3846dc13fee6SSepherosa Ziehau 		return (0);
384723bf9e15SSepherosa Ziehau 
384823bf9e15SSepherosa Ziehau 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
384923bf9e15SSepherosa Ziehau 		struct hn_txdesc *txd;
385023bf9e15SSepherosa Ziehau 		struct mbuf *m_head;
385123bf9e15SSepherosa Ziehau 		int error;
385223bf9e15SSepherosa Ziehau 
385323bf9e15SSepherosa Ziehau 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
385423bf9e15SSepherosa Ziehau 		if (m_head == NULL)
385523bf9e15SSepherosa Ziehau 			break;
385623bf9e15SSepherosa Ziehau 
385723bf9e15SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
385823bf9e15SSepherosa Ziehau 			/*
385923bf9e15SSepherosa Ziehau 			 * This sending could be time consuming; let callers
386023bf9e15SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
386123bf9e15SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
386223bf9e15SSepherosa Ziehau 			 */
386323bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
3864dc13fee6SSepherosa Ziehau 			sched = 1;
3865dc13fee6SSepherosa Ziehau 			break;
386623bf9e15SSepherosa Ziehau 		}
386723bf9e15SSepherosa Ziehau 
3868edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
3869edd3f315SSepherosa Ziehau 		if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
3870edd3f315SSepherosa Ziehau 			m_head = hn_tso_fixup(m_head);
3871edd3f315SSepherosa Ziehau 			if (__predict_false(m_head == NULL)) {
3872edd3f315SSepherosa Ziehau 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
3873edd3f315SSepherosa Ziehau 				continue;
3874edd3f315SSepherosa Ziehau 			}
3875edd3f315SSepherosa Ziehau 		}
3876edd3f315SSepherosa Ziehau #endif
3877edd3f315SSepherosa Ziehau 
387823bf9e15SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
387923bf9e15SSepherosa Ziehau 		if (txd == NULL) {
388023bf9e15SSepherosa Ziehau 			txr->hn_no_txdescs++;
388123bf9e15SSepherosa Ziehau 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
388223bf9e15SSepherosa Ziehau 			atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
388323bf9e15SSepherosa Ziehau 			break;
388423bf9e15SSepherosa Ziehau 		}
388523bf9e15SSepherosa Ziehau 
3886dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
388723bf9e15SSepherosa Ziehau 		if (error) {
388823bf9e15SSepherosa Ziehau 			/* Both txd and m_head are freed */
3889dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
3890dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
389123bf9e15SSepherosa Ziehau 			continue;
389223bf9e15SSepherosa Ziehau 		}
389323bf9e15SSepherosa Ziehau 
3894dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
3895dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
3896dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
3897dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
3898dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
3899dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
3900dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
3901dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
3902dc13fee6SSepherosa Ziehau 					break;
3903dc13fee6SSepherosa Ziehau 				}
3904dc13fee6SSepherosa Ziehau 			} else {
3905dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
390623bf9e15SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
390723bf9e15SSepherosa Ziehau 				if (__predict_false(error)) {
390823bf9e15SSepherosa Ziehau 					/* txd is freed, but m_head is not */
390923bf9e15SSepherosa Ziehau 					IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
3910dc13fee6SSepherosa Ziehau 					atomic_set_int(&ifp->if_drv_flags,
3911dc13fee6SSepherosa Ziehau 					    IFF_DRV_OACTIVE);
391223bf9e15SSepherosa Ziehau 					break;
391323bf9e15SSepherosa Ziehau 				}
391423bf9e15SSepherosa Ziehau 			}
3915dc13fee6SSepherosa Ziehau 		}
3916dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
3917dc13fee6SSepherosa Ziehau 		else {
3918dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
3919dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
3920dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
3921dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
3922dc13fee6SSepherosa Ziehau 		}
3923dc13fee6SSepherosa Ziehau #endif
3924dc13fee6SSepherosa Ziehau 	}
3925dc13fee6SSepherosa Ziehau 
3926dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
3927dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
3928dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
3929dc13fee6SSepherosa Ziehau 	return (sched);
393023bf9e15SSepherosa Ziehau }
393123bf9e15SSepherosa Ziehau 
393223bf9e15SSepherosa Ziehau static void
393323bf9e15SSepherosa Ziehau hn_start(struct ifnet *ifp)
393423bf9e15SSepherosa Ziehau {
393523bf9e15SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
393623bf9e15SSepherosa Ziehau 	struct hn_tx_ring *txr = &sc->hn_tx_ring[0];
393723bf9e15SSepherosa Ziehau 
393823bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
393923bf9e15SSepherosa Ziehau 		goto do_sched;
394023bf9e15SSepherosa Ziehau 
394123bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
394223bf9e15SSepherosa Ziehau 		int sched;
394323bf9e15SSepherosa Ziehau 
394423bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
394523bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
394623bf9e15SSepherosa Ziehau 		if (!sched)
394723bf9e15SSepherosa Ziehau 			return;
394823bf9e15SSepherosa Ziehau 	}
394923bf9e15SSepherosa Ziehau do_sched:
395023bf9e15SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
395123bf9e15SSepherosa Ziehau }
395223bf9e15SSepherosa Ziehau 
395315516c77SSepherosa Ziehau static void
395415516c77SSepherosa Ziehau hn_start_txeof_taskfunc(void *xtxr, int pending __unused)
395515516c77SSepherosa Ziehau {
395615516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
395715516c77SSepherosa Ziehau 
395815516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
395915516c77SSepherosa Ziehau 	atomic_clear_int(&txr->hn_sc->hn_ifp->if_drv_flags, IFF_DRV_OACTIVE);
396015516c77SSepherosa Ziehau 	hn_start_locked(txr, 0);
396115516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
396215516c77SSepherosa Ziehau }
396315516c77SSepherosa Ziehau 
396423bf9e15SSepherosa Ziehau static void
396523bf9e15SSepherosa Ziehau hn_start_txeof(struct hn_tx_ring *txr)
396623bf9e15SSepherosa Ziehau {
396723bf9e15SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
396823bf9e15SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
396923bf9e15SSepherosa Ziehau 
397023bf9e15SSepherosa Ziehau 	KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring"));
397123bf9e15SSepherosa Ziehau 
397223bf9e15SSepherosa Ziehau 	if (txr->hn_sched_tx)
397323bf9e15SSepherosa Ziehau 		goto do_sched;
397423bf9e15SSepherosa Ziehau 
397523bf9e15SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
397623bf9e15SSepherosa Ziehau 		int sched;
397723bf9e15SSepherosa Ziehau 
397823bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
397923bf9e15SSepherosa Ziehau 		sched = hn_start_locked(txr, txr->hn_direct_tx_size);
398023bf9e15SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
398123bf9e15SSepherosa Ziehau 		if (sched) {
398223bf9e15SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
398323bf9e15SSepherosa Ziehau 			    &txr->hn_tx_task);
398423bf9e15SSepherosa Ziehau 		}
398523bf9e15SSepherosa Ziehau 	} else {
398623bf9e15SSepherosa Ziehau do_sched:
398723bf9e15SSepherosa Ziehau 		/*
398823bf9e15SSepherosa Ziehau 		 * Release the OACTIVE earlier, with the hope, that
398923bf9e15SSepherosa Ziehau 		 * others could catch up.  The task will clear the
399023bf9e15SSepherosa Ziehau 		 * flag again with the hn_tx_lock to avoid possible
399123bf9e15SSepherosa Ziehau 		 * races.
399223bf9e15SSepherosa Ziehau 		 */
399323bf9e15SSepherosa Ziehau 		atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
399423bf9e15SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
399523bf9e15SSepherosa Ziehau 	}
399623bf9e15SSepherosa Ziehau }
399723bf9e15SSepherosa Ziehau 
399823bf9e15SSepherosa Ziehau #endif	/* HN_IFSTART_SUPPORT */
399923bf9e15SSepherosa Ziehau 
400015516c77SSepherosa Ziehau static int
400115516c77SSepherosa Ziehau hn_xmit(struct hn_tx_ring *txr, int len)
400215516c77SSepherosa Ziehau {
400315516c77SSepherosa Ziehau 	struct hn_softc *sc = txr->hn_sc;
400415516c77SSepherosa Ziehau 	struct ifnet *ifp = sc->hn_ifp;
400515516c77SSepherosa Ziehau 	struct mbuf *m_head;
4006dc13fee6SSepherosa Ziehau 	int sched = 0;
400715516c77SSepherosa Ziehau 
400815516c77SSepherosa Ziehau 	mtx_assert(&txr->hn_tx_lock, MA_OWNED);
400923bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
401015516c77SSepherosa Ziehau 	KASSERT(hn_use_if_start == 0,
401115516c77SSepherosa Ziehau 	    ("hn_xmit is called, when if_start is enabled"));
401223bf9e15SSepherosa Ziehau #endif
4013dc13fee6SSepherosa Ziehau 	KASSERT(txr->hn_agg_txd == NULL, ("lingering aggregating txdesc"));
401415516c77SSepherosa Ziehau 
401515516c77SSepherosa Ziehau 	if (__predict_false(txr->hn_suspended))
4016dc13fee6SSepherosa Ziehau 		return (0);
401715516c77SSepherosa Ziehau 
401815516c77SSepherosa Ziehau 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive)
4019dc13fee6SSepherosa Ziehau 		return (0);
402015516c77SSepherosa Ziehau 
402115516c77SSepherosa Ziehau 	while ((m_head = drbr_peek(ifp, txr->hn_mbuf_br)) != NULL) {
402215516c77SSepherosa Ziehau 		struct hn_txdesc *txd;
402315516c77SSepherosa Ziehau 		int error;
402415516c77SSepherosa Ziehau 
402515516c77SSepherosa Ziehau 		if (len > 0 && m_head->m_pkthdr.len > len) {
402615516c77SSepherosa Ziehau 			/*
402715516c77SSepherosa Ziehau 			 * This sending could be time consuming; let callers
402815516c77SSepherosa Ziehau 			 * dispatch this packet sending (and sending of any
402915516c77SSepherosa Ziehau 			 * following up packets) to tx taskqueue.
403015516c77SSepherosa Ziehau 			 */
403115516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
4032dc13fee6SSepherosa Ziehau 			sched = 1;
4033dc13fee6SSepherosa Ziehau 			break;
403415516c77SSepherosa Ziehau 		}
403515516c77SSepherosa Ziehau 
403615516c77SSepherosa Ziehau 		txd = hn_txdesc_get(txr);
403715516c77SSepherosa Ziehau 		if (txd == NULL) {
403815516c77SSepherosa Ziehau 			txr->hn_no_txdescs++;
403915516c77SSepherosa Ziehau 			drbr_putback(ifp, txr->hn_mbuf_br, m_head);
404015516c77SSepherosa Ziehau 			txr->hn_oactive = 1;
404115516c77SSepherosa Ziehau 			break;
404215516c77SSepherosa Ziehau 		}
404315516c77SSepherosa Ziehau 
4044dc13fee6SSepherosa Ziehau 		error = hn_encap(ifp, txr, txd, &m_head);
404515516c77SSepherosa Ziehau 		if (error) {
404615516c77SSepherosa Ziehau 			/* Both txd and m_head are freed; discard */
4047dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd == NULL,
4048dc13fee6SSepherosa Ziehau 			    ("encap failed w/ pending aggregating txdesc"));
404915516c77SSepherosa Ziehau 			drbr_advance(ifp, txr->hn_mbuf_br);
405015516c77SSepherosa Ziehau 			continue;
405115516c77SSepherosa Ziehau 		}
405215516c77SSepherosa Ziehau 
4053dc13fee6SSepherosa Ziehau 		if (txr->hn_agg_pktleft == 0) {
4054dc13fee6SSepherosa Ziehau 			if (txr->hn_agg_txd != NULL) {
4055dc13fee6SSepherosa Ziehau 				KASSERT(m_head == NULL,
4056dc13fee6SSepherosa Ziehau 				    ("pending mbuf for aggregating txdesc"));
4057dc13fee6SSepherosa Ziehau 				error = hn_flush_txagg(ifp, txr);
405815516c77SSepherosa Ziehau 				if (__predict_false(error)) {
405915516c77SSepherosa Ziehau 					txr->hn_oactive = 1;
406015516c77SSepherosa Ziehau 					break;
406115516c77SSepherosa Ziehau 				}
4062dc13fee6SSepherosa Ziehau 			} else {
4063dc13fee6SSepherosa Ziehau 				KASSERT(m_head != NULL, ("mbuf was freed"));
4064dc13fee6SSepherosa Ziehau 				error = hn_txpkt(ifp, txr, txd);
4065dc13fee6SSepherosa Ziehau 				if (__predict_false(error)) {
4066dc13fee6SSepherosa Ziehau 					/* txd is freed, but m_head is not */
4067dc13fee6SSepherosa Ziehau 					drbr_putback(ifp, txr->hn_mbuf_br,
4068dc13fee6SSepherosa Ziehau 					    m_head);
4069dc13fee6SSepherosa Ziehau 					txr->hn_oactive = 1;
4070dc13fee6SSepherosa Ziehau 					break;
4071dc13fee6SSepherosa Ziehau 				}
4072dc13fee6SSepherosa Ziehau 			}
4073dc13fee6SSepherosa Ziehau 		}
4074dc13fee6SSepherosa Ziehau #ifdef INVARIANTS
4075dc13fee6SSepherosa Ziehau 		else {
4076dc13fee6SSepherosa Ziehau 			KASSERT(txr->hn_agg_txd != NULL,
4077dc13fee6SSepherosa Ziehau 			    ("no aggregating txdesc"));
4078dc13fee6SSepherosa Ziehau 			KASSERT(m_head == NULL,
4079dc13fee6SSepherosa Ziehau 			    ("pending mbuf for aggregating txdesc"));
4080dc13fee6SSepherosa Ziehau 		}
4081dc13fee6SSepherosa Ziehau #endif
408215516c77SSepherosa Ziehau 
408315516c77SSepherosa Ziehau 		/* Sent */
408415516c77SSepherosa Ziehau 		drbr_advance(ifp, txr->hn_mbuf_br);
408515516c77SSepherosa Ziehau 	}
4086dc13fee6SSepherosa Ziehau 
4087dc13fee6SSepherosa Ziehau 	/* Flush pending aggerated transmission. */
4088dc13fee6SSepherosa Ziehau 	if (txr->hn_agg_txd != NULL)
4089dc13fee6SSepherosa Ziehau 		hn_flush_txagg(ifp, txr);
4090dc13fee6SSepherosa Ziehau 	return (sched);
409115516c77SSepherosa Ziehau }
409215516c77SSepherosa Ziehau 
409315516c77SSepherosa Ziehau static int
409415516c77SSepherosa Ziehau hn_transmit(struct ifnet *ifp, struct mbuf *m)
409515516c77SSepherosa Ziehau {
409615516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
409715516c77SSepherosa Ziehau 	struct hn_tx_ring *txr;
409815516c77SSepherosa Ziehau 	int error, idx = 0;
409915516c77SSepherosa Ziehau 
4100edd3f315SSepherosa Ziehau #if defined(INET6) || defined(INET)
4101edd3f315SSepherosa Ziehau 	/*
4102edd3f315SSepherosa Ziehau 	 * Perform TSO packet header fixup now, since the TSO
4103edd3f315SSepherosa Ziehau 	 * packet header should be cache-hot.
4104edd3f315SSepherosa Ziehau 	 */
4105edd3f315SSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
4106edd3f315SSepherosa Ziehau 		m = hn_tso_fixup(m);
4107edd3f315SSepherosa Ziehau 		if (__predict_false(m == NULL)) {
4108edd3f315SSepherosa Ziehau 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
4109edd3f315SSepherosa Ziehau 			return EIO;
4110edd3f315SSepherosa Ziehau 		}
4111edd3f315SSepherosa Ziehau 	}
4112edd3f315SSepherosa Ziehau #endif
4113edd3f315SSepherosa Ziehau 
411415516c77SSepherosa Ziehau 	/*
411515516c77SSepherosa Ziehau 	 * Select the TX ring based on flowid
411615516c77SSepherosa Ziehau 	 */
4117*34d68912SSepherosa Ziehau 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
4118*34d68912SSepherosa Ziehau #ifdef RSS
4119*34d68912SSepherosa Ziehau 		uint32_t bid;
4120*34d68912SSepherosa Ziehau 
4121*34d68912SSepherosa Ziehau 		if (rss_hash2bucket(m->m_pkthdr.flowid, M_HASHTYPE_GET(m),
4122*34d68912SSepherosa Ziehau 		    &bid) == 0)
4123*34d68912SSepherosa Ziehau 			idx = bid % sc->hn_tx_ring_inuse;
4124*34d68912SSepherosa Ziehau 		else
4125*34d68912SSepherosa Ziehau #endif
412615516c77SSepherosa Ziehau 			idx = m->m_pkthdr.flowid % sc->hn_tx_ring_inuse;
4127*34d68912SSepherosa Ziehau 	}
412815516c77SSepherosa Ziehau 	txr = &sc->hn_tx_ring[idx];
412915516c77SSepherosa Ziehau 
413015516c77SSepherosa Ziehau 	error = drbr_enqueue(ifp, txr->hn_mbuf_br, m);
413115516c77SSepherosa Ziehau 	if (error) {
413215516c77SSepherosa Ziehau 		if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
413315516c77SSepherosa Ziehau 		return error;
413415516c77SSepherosa Ziehau 	}
413515516c77SSepherosa Ziehau 
413615516c77SSepherosa Ziehau 	if (txr->hn_oactive)
413715516c77SSepherosa Ziehau 		return 0;
413815516c77SSepherosa Ziehau 
413915516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
414015516c77SSepherosa Ziehau 		goto do_sched;
414115516c77SSepherosa Ziehau 
414215516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
414315516c77SSepherosa Ziehau 		int sched;
414415516c77SSepherosa Ziehau 
414515516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
414615516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
414715516c77SSepherosa Ziehau 		if (!sched)
414815516c77SSepherosa Ziehau 			return 0;
414915516c77SSepherosa Ziehau 	}
415015516c77SSepherosa Ziehau do_sched:
415115516c77SSepherosa Ziehau 	taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_tx_task);
415215516c77SSepherosa Ziehau 	return 0;
415315516c77SSepherosa Ziehau }
415415516c77SSepherosa Ziehau 
415515516c77SSepherosa Ziehau static void
415615516c77SSepherosa Ziehau hn_tx_ring_qflush(struct hn_tx_ring *txr)
415715516c77SSepherosa Ziehau {
415815516c77SSepherosa Ziehau 	struct mbuf *m;
415915516c77SSepherosa Ziehau 
416015516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
416115516c77SSepherosa Ziehau 	while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL)
416215516c77SSepherosa Ziehau 		m_freem(m);
416315516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
416415516c77SSepherosa Ziehau }
416515516c77SSepherosa Ziehau 
416615516c77SSepherosa Ziehau static void
416715516c77SSepherosa Ziehau hn_xmit_qflush(struct ifnet *ifp)
416815516c77SSepherosa Ziehau {
416915516c77SSepherosa Ziehau 	struct hn_softc *sc = ifp->if_softc;
417015516c77SSepherosa Ziehau 	int i;
417115516c77SSepherosa Ziehau 
417215516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i)
417315516c77SSepherosa Ziehau 		hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
417415516c77SSepherosa Ziehau 	if_qflush(ifp);
417515516c77SSepherosa Ziehau }
417615516c77SSepherosa Ziehau 
417715516c77SSepherosa Ziehau static void
417815516c77SSepherosa Ziehau hn_xmit_txeof(struct hn_tx_ring *txr)
417915516c77SSepherosa Ziehau {
418015516c77SSepherosa Ziehau 
418115516c77SSepherosa Ziehau 	if (txr->hn_sched_tx)
418215516c77SSepherosa Ziehau 		goto do_sched;
418315516c77SSepherosa Ziehau 
418415516c77SSepherosa Ziehau 	if (mtx_trylock(&txr->hn_tx_lock)) {
418515516c77SSepherosa Ziehau 		int sched;
418615516c77SSepherosa Ziehau 
418715516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
418815516c77SSepherosa Ziehau 		sched = hn_xmit(txr, txr->hn_direct_tx_size);
418915516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
419015516c77SSepherosa Ziehau 		if (sched) {
419115516c77SSepherosa Ziehau 			taskqueue_enqueue(txr->hn_tx_taskq,
419215516c77SSepherosa Ziehau 			    &txr->hn_tx_task);
419315516c77SSepherosa Ziehau 		}
419415516c77SSepherosa Ziehau 	} else {
419515516c77SSepherosa Ziehau do_sched:
419615516c77SSepherosa Ziehau 		/*
419715516c77SSepherosa Ziehau 		 * Release the oactive earlier, with the hope, that
419815516c77SSepherosa Ziehau 		 * others could catch up.  The task will clear the
419915516c77SSepherosa Ziehau 		 * oactive again with the hn_tx_lock to avoid possible
420015516c77SSepherosa Ziehau 		 * races.
420115516c77SSepherosa Ziehau 		 */
420215516c77SSepherosa Ziehau 		txr->hn_oactive = 0;
420315516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
420415516c77SSepherosa Ziehau 	}
420515516c77SSepherosa Ziehau }
420615516c77SSepherosa Ziehau 
420715516c77SSepherosa Ziehau static void
420815516c77SSepherosa Ziehau hn_xmit_taskfunc(void *xtxr, int pending __unused)
420915516c77SSepherosa Ziehau {
421015516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
421115516c77SSepherosa Ziehau 
421215516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
421315516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
421415516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
421515516c77SSepherosa Ziehau }
421615516c77SSepherosa Ziehau 
421715516c77SSepherosa Ziehau static void
421815516c77SSepherosa Ziehau hn_xmit_txeof_taskfunc(void *xtxr, int pending __unused)
421915516c77SSepherosa Ziehau {
422015516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = xtxr;
422115516c77SSepherosa Ziehau 
422215516c77SSepherosa Ziehau 	mtx_lock(&txr->hn_tx_lock);
422315516c77SSepherosa Ziehau 	txr->hn_oactive = 0;
422415516c77SSepherosa Ziehau 	hn_xmit(txr, 0);
422515516c77SSepherosa Ziehau 	mtx_unlock(&txr->hn_tx_lock);
422615516c77SSepherosa Ziehau }
422715516c77SSepherosa Ziehau 
422815516c77SSepherosa Ziehau static int
422915516c77SSepherosa Ziehau hn_chan_attach(struct hn_softc *sc, struct vmbus_channel *chan)
423015516c77SSepherosa Ziehau {
423115516c77SSepherosa Ziehau 	struct vmbus_chan_br cbr;
423215516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
423315516c77SSepherosa Ziehau 	struct hn_tx_ring *txr = NULL;
423415516c77SSepherosa Ziehau 	int idx, error;
423515516c77SSepherosa Ziehau 
423615516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
423715516c77SSepherosa Ziehau 
423815516c77SSepherosa Ziehau 	/*
423915516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
424015516c77SSepherosa Ziehau 	 */
424115516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
424215516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
424315516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
424415516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
424515516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED) == 0,
424615516c77SSepherosa Ziehau 	    ("RX ring %d already attached", idx));
424715516c77SSepherosa Ziehau 	rxr->hn_rx_flags |= HN_RX_FLAG_ATTACHED;
424815516c77SSepherosa Ziehau 
424915516c77SSepherosa Ziehau 	if (bootverbose) {
425015516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "link RX ring %d to chan%u\n",
425115516c77SSepherosa Ziehau 		    idx, vmbus_chan_id(chan));
425215516c77SSepherosa Ziehau 	}
425315516c77SSepherosa Ziehau 
425415516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
425515516c77SSepherosa Ziehau 		txr = &sc->hn_tx_ring[idx];
425615516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED) == 0,
425715516c77SSepherosa Ziehau 		    ("TX ring %d already attached", idx));
425815516c77SSepherosa Ziehau 		txr->hn_tx_flags |= HN_TX_FLAG_ATTACHED;
425915516c77SSepherosa Ziehau 
426015516c77SSepherosa Ziehau 		txr->hn_chan = chan;
426115516c77SSepherosa Ziehau 		if (bootverbose) {
426215516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "link TX ring %d to chan%u\n",
426315516c77SSepherosa Ziehau 			    idx, vmbus_chan_id(chan));
426415516c77SSepherosa Ziehau 		}
426515516c77SSepherosa Ziehau 	}
426615516c77SSepherosa Ziehau 
426715516c77SSepherosa Ziehau 	/* Bind this channel to a proper CPU. */
42680e11868dSSepherosa Ziehau 	vmbus_chan_cpu_set(chan, HN_RING_IDX2CPU(sc, idx));
426915516c77SSepherosa Ziehau 
427015516c77SSepherosa Ziehau 	/*
427115516c77SSepherosa Ziehau 	 * Open this channel
427215516c77SSepherosa Ziehau 	 */
427315516c77SSepherosa Ziehau 	cbr.cbr = rxr->hn_br;
427415516c77SSepherosa Ziehau 	cbr.cbr_paddr = rxr->hn_br_dma.hv_paddr;
427515516c77SSepherosa Ziehau 	cbr.cbr_txsz = HN_TXBR_SIZE;
427615516c77SSepherosa Ziehau 	cbr.cbr_rxsz = HN_RXBR_SIZE;
427715516c77SSepherosa Ziehau 	error = vmbus_chan_open_br(chan, &cbr, NULL, 0, hn_chan_callback, rxr);
427815516c77SSepherosa Ziehau 	if (error) {
427971e8ac56SSepherosa Ziehau 		if (error == EISCONN) {
428071e8ac56SSepherosa Ziehau 			if_printf(sc->hn_ifp, "bufring is connected after "
428171e8ac56SSepherosa Ziehau 			    "chan%u open failure\n", vmbus_chan_id(chan));
428271e8ac56SSepherosa Ziehau 			rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
428371e8ac56SSepherosa Ziehau 		} else {
428415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "open chan%u failed: %d\n",
428515516c77SSepherosa Ziehau 			    vmbus_chan_id(chan), error);
428671e8ac56SSepherosa Ziehau 		}
428715516c77SSepherosa Ziehau 	}
428815516c77SSepherosa Ziehau 	return (error);
428915516c77SSepherosa Ziehau }
429015516c77SSepherosa Ziehau 
429115516c77SSepherosa Ziehau static void
429215516c77SSepherosa Ziehau hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan)
429315516c77SSepherosa Ziehau {
429415516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr;
42952494d735SSepherosa Ziehau 	int idx, error;
429615516c77SSepherosa Ziehau 
429715516c77SSepherosa Ziehau 	idx = vmbus_chan_subidx(chan);
429815516c77SSepherosa Ziehau 
429915516c77SSepherosa Ziehau 	/*
430015516c77SSepherosa Ziehau 	 * Link this channel to RX/TX ring.
430115516c77SSepherosa Ziehau 	 */
430215516c77SSepherosa Ziehau 	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
430315516c77SSepherosa Ziehau 	    ("invalid channel index %d, should > 0 && < %d",
430415516c77SSepherosa Ziehau 	     idx, sc->hn_rx_ring_inuse));
430515516c77SSepherosa Ziehau 	rxr = &sc->hn_rx_ring[idx];
430615516c77SSepherosa Ziehau 	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED),
430715516c77SSepherosa Ziehau 	    ("RX ring %d is not attached", idx));
430815516c77SSepherosa Ziehau 	rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
430915516c77SSepherosa Ziehau 
431015516c77SSepherosa Ziehau 	if (idx < sc->hn_tx_ring_inuse) {
431115516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[idx];
431215516c77SSepherosa Ziehau 
431315516c77SSepherosa Ziehau 		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED),
431415516c77SSepherosa Ziehau 		    ("TX ring %d is not attached attached", idx));
431515516c77SSepherosa Ziehau 		txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
431615516c77SSepherosa Ziehau 	}
431715516c77SSepherosa Ziehau 
431815516c77SSepherosa Ziehau 	/*
431915516c77SSepherosa Ziehau 	 * Close this channel.
432015516c77SSepherosa Ziehau 	 *
432115516c77SSepherosa Ziehau 	 * NOTE:
432215516c77SSepherosa Ziehau 	 * Channel closing does _not_ destroy the target channel.
432315516c77SSepherosa Ziehau 	 */
43242494d735SSepherosa Ziehau 	error = vmbus_chan_close_direct(chan);
43252494d735SSepherosa Ziehau 	if (error == EISCONN) {
4326aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u bufring is connected "
4327aa1a2adcSSepherosa Ziehau 		    "after being closed\n", vmbus_chan_id(chan));
43282494d735SSepherosa Ziehau 		rxr->hn_rx_flags |= HN_RX_FLAG_BR_REF;
43292494d735SSepherosa Ziehau 	} else if (error) {
4330aa1a2adcSSepherosa Ziehau 		if_printf(sc->hn_ifp, "chan%u close failed: %d\n",
4331aa1a2adcSSepherosa Ziehau 		    vmbus_chan_id(chan), error);
43322494d735SSepherosa Ziehau 	}
433315516c77SSepherosa Ziehau }
433415516c77SSepherosa Ziehau 
433515516c77SSepherosa Ziehau static int
433615516c77SSepherosa Ziehau hn_attach_subchans(struct hn_softc *sc)
433715516c77SSepherosa Ziehau {
433815516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
433915516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
434015516c77SSepherosa Ziehau 	int i, error = 0;
434115516c77SSepherosa Ziehau 
434271e8ac56SSepherosa Ziehau 	KASSERT(subchan_cnt > 0, ("no sub-channels"));
434315516c77SSepherosa Ziehau 
434415516c77SSepherosa Ziehau 	/* Attach the sub-channels. */
434515516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
434615516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i) {
434771e8ac56SSepherosa Ziehau 		int error1;
434871e8ac56SSepherosa Ziehau 
434971e8ac56SSepherosa Ziehau 		error1 = hn_chan_attach(sc, subchans[i]);
435071e8ac56SSepherosa Ziehau 		if (error1) {
435171e8ac56SSepherosa Ziehau 			error = error1;
435271e8ac56SSepherosa Ziehau 			/* Move on; all channels will be detached later. */
435371e8ac56SSepherosa Ziehau 		}
435415516c77SSepherosa Ziehau 	}
435515516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
435615516c77SSepherosa Ziehau 
435715516c77SSepherosa Ziehau 	if (error) {
435815516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "sub-channels attach failed: %d\n", error);
435915516c77SSepherosa Ziehau 	} else {
436015516c77SSepherosa Ziehau 		if (bootverbose) {
436115516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "%d sub-channels attached\n",
436215516c77SSepherosa Ziehau 			    subchan_cnt);
436315516c77SSepherosa Ziehau 		}
436415516c77SSepherosa Ziehau 	}
436515516c77SSepherosa Ziehau 	return (error);
436615516c77SSepherosa Ziehau }
436715516c77SSepherosa Ziehau 
436815516c77SSepherosa Ziehau static void
436915516c77SSepherosa Ziehau hn_detach_allchans(struct hn_softc *sc)
437015516c77SSepherosa Ziehau {
437115516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
437215516c77SSepherosa Ziehau 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
437315516c77SSepherosa Ziehau 	int i;
437415516c77SSepherosa Ziehau 
437515516c77SSepherosa Ziehau 	if (subchan_cnt == 0)
437615516c77SSepherosa Ziehau 		goto back;
437715516c77SSepherosa Ziehau 
437815516c77SSepherosa Ziehau 	/* Detach the sub-channels. */
437915516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
438015516c77SSepherosa Ziehau 	for (i = 0; i < subchan_cnt; ++i)
438115516c77SSepherosa Ziehau 		hn_chan_detach(sc, subchans[i]);
438215516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, subchan_cnt);
438315516c77SSepherosa Ziehau 
438415516c77SSepherosa Ziehau back:
438515516c77SSepherosa Ziehau 	/*
438615516c77SSepherosa Ziehau 	 * Detach the primary channel, _after_ all sub-channels
438715516c77SSepherosa Ziehau 	 * are detached.
438815516c77SSepherosa Ziehau 	 */
438915516c77SSepherosa Ziehau 	hn_chan_detach(sc, sc->hn_prichan);
439015516c77SSepherosa Ziehau 
439115516c77SSepherosa Ziehau 	/* Wait for sub-channels to be destroyed, if any. */
439215516c77SSepherosa Ziehau 	vmbus_subchan_drain(sc->hn_prichan);
439315516c77SSepherosa Ziehau 
439415516c77SSepherosa Ziehau #ifdef INVARIANTS
439515516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
439615516c77SSepherosa Ziehau 		KASSERT((sc->hn_rx_ring[i].hn_rx_flags &
439715516c77SSepherosa Ziehau 		    HN_RX_FLAG_ATTACHED) == 0,
439815516c77SSepherosa Ziehau 		    ("%dth RX ring is still attached", i));
439915516c77SSepherosa Ziehau 	}
440015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
440115516c77SSepherosa Ziehau 		KASSERT((sc->hn_tx_ring[i].hn_tx_flags &
440215516c77SSepherosa Ziehau 		    HN_TX_FLAG_ATTACHED) == 0,
440315516c77SSepherosa Ziehau 		    ("%dth TX ring is still attached", i));
440415516c77SSepherosa Ziehau 	}
440515516c77SSepherosa Ziehau #endif
440615516c77SSepherosa Ziehau }
440715516c77SSepherosa Ziehau 
440815516c77SSepherosa Ziehau static int
440915516c77SSepherosa Ziehau hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch)
441015516c77SSepherosa Ziehau {
441115516c77SSepherosa Ziehau 	struct vmbus_channel **subchans;
441215516c77SSepherosa Ziehau 	int nchan, rxr_cnt, error;
441315516c77SSepherosa Ziehau 
441415516c77SSepherosa Ziehau 	nchan = *nsubch + 1;
441515516c77SSepherosa Ziehau 	if (nchan == 1) {
441615516c77SSepherosa Ziehau 		/*
441715516c77SSepherosa Ziehau 		 * Multiple RX/TX rings are not requested.
441815516c77SSepherosa Ziehau 		 */
441915516c77SSepherosa Ziehau 		*nsubch = 0;
442015516c77SSepherosa Ziehau 		return (0);
442115516c77SSepherosa Ziehau 	}
442215516c77SSepherosa Ziehau 
442315516c77SSepherosa Ziehau 	/*
442415516c77SSepherosa Ziehau 	 * Query RSS capabilities, e.g. # of RX rings, and # of indirect
442515516c77SSepherosa Ziehau 	 * table entries.
442615516c77SSepherosa Ziehau 	 */
442715516c77SSepherosa Ziehau 	error = hn_rndis_query_rsscaps(sc, &rxr_cnt);
442815516c77SSepherosa Ziehau 	if (error) {
442915516c77SSepherosa Ziehau 		/* No RSS; this is benign. */
443015516c77SSepherosa Ziehau 		*nsubch = 0;
443115516c77SSepherosa Ziehau 		return (0);
443215516c77SSepherosa Ziehau 	}
443315516c77SSepherosa Ziehau 	if (bootverbose) {
443415516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
443515516c77SSepherosa Ziehau 		    rxr_cnt, nchan);
443615516c77SSepherosa Ziehau 	}
443715516c77SSepherosa Ziehau 
443815516c77SSepherosa Ziehau 	if (nchan > rxr_cnt)
443915516c77SSepherosa Ziehau 		nchan = rxr_cnt;
444015516c77SSepherosa Ziehau 	if (nchan == 1) {
444115516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n");
444215516c77SSepherosa Ziehau 		*nsubch = 0;
444315516c77SSepherosa Ziehau 		return (0);
444415516c77SSepherosa Ziehau 	}
444515516c77SSepherosa Ziehau 
444615516c77SSepherosa Ziehau 	/*
444715516c77SSepherosa Ziehau 	 * Allocate sub-channels from NVS.
444815516c77SSepherosa Ziehau 	 */
444915516c77SSepherosa Ziehau 	*nsubch = nchan - 1;
445015516c77SSepherosa Ziehau 	error = hn_nvs_alloc_subchans(sc, nsubch);
445115516c77SSepherosa Ziehau 	if (error || *nsubch == 0) {
445215516c77SSepherosa Ziehau 		/* Failed to allocate sub-channels. */
445315516c77SSepherosa Ziehau 		*nsubch = 0;
445415516c77SSepherosa Ziehau 		return (0);
445515516c77SSepherosa Ziehau 	}
445615516c77SSepherosa Ziehau 
445715516c77SSepherosa Ziehau 	/*
445815516c77SSepherosa Ziehau 	 * Wait for all sub-channels to become ready before moving on.
445915516c77SSepherosa Ziehau 	 */
446015516c77SSepherosa Ziehau 	subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch);
446115516c77SSepherosa Ziehau 	vmbus_subchan_rel(subchans, *nsubch);
446215516c77SSepherosa Ziehau 	return (0);
446315516c77SSepherosa Ziehau }
446415516c77SSepherosa Ziehau 
44652494d735SSepherosa Ziehau static bool
44662494d735SSepherosa Ziehau hn_synth_attachable(const struct hn_softc *sc)
44672494d735SSepherosa Ziehau {
44682494d735SSepherosa Ziehau 	int i;
44692494d735SSepherosa Ziehau 
44702494d735SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_ERRORS)
44712494d735SSepherosa Ziehau 		return (false);
44722494d735SSepherosa Ziehau 
44732494d735SSepherosa Ziehau 	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
44742494d735SSepherosa Ziehau 		const struct hn_rx_ring *rxr = &sc->hn_rx_ring[i];
44752494d735SSepherosa Ziehau 
44762494d735SSepherosa Ziehau 		if (rxr->hn_rx_flags & HN_RX_FLAG_BR_REF)
44772494d735SSepherosa Ziehau 			return (false);
44782494d735SSepherosa Ziehau 	}
44792494d735SSepherosa Ziehau 	return (true);
44802494d735SSepherosa Ziehau }
44812494d735SSepherosa Ziehau 
448215516c77SSepherosa Ziehau static int
448315516c77SSepherosa Ziehau hn_synth_attach(struct hn_softc *sc, int mtu)
448415516c77SSepherosa Ziehau {
448571e8ac56SSepherosa Ziehau #define ATTACHED_NVS		0x0002
448671e8ac56SSepherosa Ziehau #define ATTACHED_RNDIS		0x0004
448771e8ac56SSepherosa Ziehau 
448815516c77SSepherosa Ziehau 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
448915516c77SSepherosa Ziehau 	int error, nsubch, nchan, i;
449071e8ac56SSepherosa Ziehau 	uint32_t old_caps, attached = 0;
449115516c77SSepherosa Ziehau 
449215516c77SSepherosa Ziehau 	KASSERT((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0,
449315516c77SSepherosa Ziehau 	    ("synthetic parts were attached"));
449415516c77SSepherosa Ziehau 
44952494d735SSepherosa Ziehau 	if (!hn_synth_attachable(sc))
44962494d735SSepherosa Ziehau 		return (ENXIO);
44972494d735SSepherosa Ziehau 
449815516c77SSepherosa Ziehau 	/* Save capabilities for later verification. */
449915516c77SSepherosa Ziehau 	old_caps = sc->hn_caps;
450015516c77SSepherosa Ziehau 	sc->hn_caps = 0;
450115516c77SSepherosa Ziehau 
450215516c77SSepherosa Ziehau 	/* Clear RSS stuffs. */
450315516c77SSepherosa Ziehau 	sc->hn_rss_ind_size = 0;
450415516c77SSepherosa Ziehau 	sc->hn_rss_hash = 0;
450515516c77SSepherosa Ziehau 
450615516c77SSepherosa Ziehau 	/*
450715516c77SSepherosa Ziehau 	 * Attach the primary channel _before_ attaching NVS and RNDIS.
450815516c77SSepherosa Ziehau 	 */
450915516c77SSepherosa Ziehau 	error = hn_chan_attach(sc, sc->hn_prichan);
451015516c77SSepherosa Ziehau 	if (error)
451171e8ac56SSepherosa Ziehau 		goto failed;
451215516c77SSepherosa Ziehau 
451315516c77SSepherosa Ziehau 	/*
451415516c77SSepherosa Ziehau 	 * Attach NVS.
451515516c77SSepherosa Ziehau 	 */
451615516c77SSepherosa Ziehau 	error = hn_nvs_attach(sc, mtu);
451715516c77SSepherosa Ziehau 	if (error)
451871e8ac56SSepherosa Ziehau 		goto failed;
451971e8ac56SSepherosa Ziehau 	attached |= ATTACHED_NVS;
452015516c77SSepherosa Ziehau 
452115516c77SSepherosa Ziehau 	/*
452215516c77SSepherosa Ziehau 	 * Attach RNDIS _after_ NVS is attached.
452315516c77SSepherosa Ziehau 	 */
452415516c77SSepherosa Ziehau 	error = hn_rndis_attach(sc, mtu);
452515516c77SSepherosa Ziehau 	if (error)
452671e8ac56SSepherosa Ziehau 		goto failed;
452771e8ac56SSepherosa Ziehau 	attached |= ATTACHED_RNDIS;
452815516c77SSepherosa Ziehau 
452915516c77SSepherosa Ziehau 	/*
453015516c77SSepherosa Ziehau 	 * Make sure capabilities are not changed.
453115516c77SSepherosa Ziehau 	 */
453215516c77SSepherosa Ziehau 	if (device_is_attached(sc->hn_dev) && old_caps != sc->hn_caps) {
453315516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "caps mismatch old 0x%08x, new 0x%08x\n",
453415516c77SSepherosa Ziehau 		    old_caps, sc->hn_caps);
453571e8ac56SSepherosa Ziehau 		error = ENXIO;
453671e8ac56SSepherosa Ziehau 		goto failed;
453715516c77SSepherosa Ziehau 	}
453815516c77SSepherosa Ziehau 
453915516c77SSepherosa Ziehau 	/*
454015516c77SSepherosa Ziehau 	 * Allocate sub-channels for multi-TX/RX rings.
454115516c77SSepherosa Ziehau 	 *
454215516c77SSepherosa Ziehau 	 * NOTE:
454315516c77SSepherosa Ziehau 	 * The # of RX rings that can be used is equivalent to the # of
454415516c77SSepherosa Ziehau 	 * channels to be requested.
454515516c77SSepherosa Ziehau 	 */
454615516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_cnt - 1;
454715516c77SSepherosa Ziehau 	error = hn_synth_alloc_subchans(sc, &nsubch);
454815516c77SSepherosa Ziehau 	if (error)
454971e8ac56SSepherosa Ziehau 		goto failed;
455071e8ac56SSepherosa Ziehau 	/* NOTE: _Full_ synthetic parts detach is required now. */
455171e8ac56SSepherosa Ziehau 	sc->hn_flags |= HN_FLAG_SYNTH_ATTACHED;
455215516c77SSepherosa Ziehau 
455371e8ac56SSepherosa Ziehau 	/*
455471e8ac56SSepherosa Ziehau 	 * Set the # of TX/RX rings that could be used according to
455571e8ac56SSepherosa Ziehau 	 * the # of channels that NVS offered.
455671e8ac56SSepherosa Ziehau 	 */
455715516c77SSepherosa Ziehau 	nchan = nsubch + 1;
455871e8ac56SSepherosa Ziehau 	hn_set_ring_inuse(sc, nchan);
455915516c77SSepherosa Ziehau 	if (nchan == 1) {
456015516c77SSepherosa Ziehau 		/* Only the primary channel can be used; done */
456115516c77SSepherosa Ziehau 		goto back;
456215516c77SSepherosa Ziehau 	}
456315516c77SSepherosa Ziehau 
456415516c77SSepherosa Ziehau 	/*
456571e8ac56SSepherosa Ziehau 	 * Attach the sub-channels.
4566afd4971bSSepherosa Ziehau 	 *
4567afd4971bSSepherosa Ziehau 	 * NOTE: hn_set_ring_inuse() _must_ have been called.
456815516c77SSepherosa Ziehau 	 */
456971e8ac56SSepherosa Ziehau 	error = hn_attach_subchans(sc);
457071e8ac56SSepherosa Ziehau 	if (error)
457171e8ac56SSepherosa Ziehau 		goto failed;
457215516c77SSepherosa Ziehau 
457371e8ac56SSepherosa Ziehau 	/*
457471e8ac56SSepherosa Ziehau 	 * Configure RSS key and indirect table _after_ all sub-channels
457571e8ac56SSepherosa Ziehau 	 * are attached.
457671e8ac56SSepherosa Ziehau 	 */
457715516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSKEY) == 0) {
457815516c77SSepherosa Ziehau 		/*
457915516c77SSepherosa Ziehau 		 * RSS key is not set yet; set it to the default RSS key.
458015516c77SSepherosa Ziehau 		 */
458115516c77SSepherosa Ziehau 		if (bootverbose)
458215516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS key\n");
4583*34d68912SSepherosa Ziehau #ifdef RSS
4584*34d68912SSepherosa Ziehau 		rss_getkey(rss->rss_key);
4585*34d68912SSepherosa Ziehau #else
458615516c77SSepherosa Ziehau 		memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key));
4587*34d68912SSepherosa Ziehau #endif
458815516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSKEY;
458915516c77SSepherosa Ziehau 	}
459015516c77SSepherosa Ziehau 
459115516c77SSepherosa Ziehau 	if ((sc->hn_flags & HN_FLAG_HAS_RSSIND) == 0) {
459215516c77SSepherosa Ziehau 		/*
459315516c77SSepherosa Ziehau 		 * RSS indirect table is not set yet; set it up in round-
459415516c77SSepherosa Ziehau 		 * robin fashion.
459515516c77SSepherosa Ziehau 		 */
459615516c77SSepherosa Ziehau 		if (bootverbose) {
459715516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "setup default RSS indirect "
459815516c77SSepherosa Ziehau 			    "table\n");
459915516c77SSepherosa Ziehau 		}
4600*34d68912SSepherosa Ziehau 		for (i = 0; i < NDIS_HASH_INDCNT; ++i) {
4601*34d68912SSepherosa Ziehau 			uint32_t subidx;
4602*34d68912SSepherosa Ziehau 
4603*34d68912SSepherosa Ziehau #ifdef RSS
4604*34d68912SSepherosa Ziehau 			subidx = rss_get_indirection_to_bucket(i);
4605*34d68912SSepherosa Ziehau #else
4606*34d68912SSepherosa Ziehau 			subidx = i;
4607*34d68912SSepherosa Ziehau #endif
4608*34d68912SSepherosa Ziehau 			rss->rss_ind[i] = subidx % nchan;
4609*34d68912SSepherosa Ziehau 		}
461015516c77SSepherosa Ziehau 		sc->hn_flags |= HN_FLAG_HAS_RSSIND;
461115516c77SSepherosa Ziehau 	} else {
461215516c77SSepherosa Ziehau 		/*
461315516c77SSepherosa Ziehau 		 * # of usable channels may be changed, so we have to
461415516c77SSepherosa Ziehau 		 * make sure that all entries in RSS indirect table
461515516c77SSepherosa Ziehau 		 * are valid.
4616afd4971bSSepherosa Ziehau 		 *
4617afd4971bSSepherosa Ziehau 		 * NOTE: hn_set_ring_inuse() _must_ have been called.
461815516c77SSepherosa Ziehau 		 */
4619afd4971bSSepherosa Ziehau 		hn_rss_ind_fixup(sc);
462015516c77SSepherosa Ziehau 	}
462115516c77SSepherosa Ziehau 
462215516c77SSepherosa Ziehau 	error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE);
462315516c77SSepherosa Ziehau 	if (error)
462471e8ac56SSepherosa Ziehau 		goto failed;
462571e8ac56SSepherosa Ziehau back:
4626dc13fee6SSepherosa Ziehau 	/*
4627dc13fee6SSepherosa Ziehau 	 * Fixup transmission aggregation setup.
4628dc13fee6SSepherosa Ziehau 	 */
4629dc13fee6SSepherosa Ziehau 	hn_set_txagg(sc);
463015516c77SSepherosa Ziehau 	return (0);
463171e8ac56SSepherosa Ziehau 
463271e8ac56SSepherosa Ziehau failed:
463371e8ac56SSepherosa Ziehau 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
463471e8ac56SSepherosa Ziehau 		hn_synth_detach(sc);
463571e8ac56SSepherosa Ziehau 	} else {
463671e8ac56SSepherosa Ziehau 		if (attached & ATTACHED_RNDIS)
463771e8ac56SSepherosa Ziehau 			hn_rndis_detach(sc);
463871e8ac56SSepherosa Ziehau 		if (attached & ATTACHED_NVS)
463971e8ac56SSepherosa Ziehau 			hn_nvs_detach(sc);
464071e8ac56SSepherosa Ziehau 		hn_chan_detach(sc, sc->hn_prichan);
464171e8ac56SSepherosa Ziehau 		/* Restore old capabilities. */
464271e8ac56SSepherosa Ziehau 		sc->hn_caps = old_caps;
464371e8ac56SSepherosa Ziehau 	}
464471e8ac56SSepherosa Ziehau 	return (error);
464571e8ac56SSepherosa Ziehau 
464671e8ac56SSepherosa Ziehau #undef ATTACHED_RNDIS
464771e8ac56SSepherosa Ziehau #undef ATTACHED_NVS
464815516c77SSepherosa Ziehau }
464915516c77SSepherosa Ziehau 
465015516c77SSepherosa Ziehau /*
465115516c77SSepherosa Ziehau  * NOTE:
465215516c77SSepherosa Ziehau  * The interface must have been suspended though hn_suspend(), before
465315516c77SSepherosa Ziehau  * this function get called.
465415516c77SSepherosa Ziehau  */
465515516c77SSepherosa Ziehau static void
465615516c77SSepherosa Ziehau hn_synth_detach(struct hn_softc *sc)
465715516c77SSepherosa Ziehau {
465815516c77SSepherosa Ziehau 
465915516c77SSepherosa Ziehau 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
466015516c77SSepherosa Ziehau 	    ("synthetic parts were not attached"));
466115516c77SSepherosa Ziehau 
466215516c77SSepherosa Ziehau 	/* Detach the RNDIS first. */
466315516c77SSepherosa Ziehau 	hn_rndis_detach(sc);
466415516c77SSepherosa Ziehau 
466515516c77SSepherosa Ziehau 	/* Detach NVS. */
466615516c77SSepherosa Ziehau 	hn_nvs_detach(sc);
466715516c77SSepherosa Ziehau 
466815516c77SSepherosa Ziehau 	/* Detach all of the channels. */
466915516c77SSepherosa Ziehau 	hn_detach_allchans(sc);
467015516c77SSepherosa Ziehau 
467115516c77SSepherosa Ziehau 	sc->hn_flags &= ~HN_FLAG_SYNTH_ATTACHED;
467215516c77SSepherosa Ziehau }
467315516c77SSepherosa Ziehau 
467415516c77SSepherosa Ziehau static void
467515516c77SSepherosa Ziehau hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt)
467615516c77SSepherosa Ziehau {
467715516c77SSepherosa Ziehau 	KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt,
467815516c77SSepherosa Ziehau 	    ("invalid ring count %d", ring_cnt));
467915516c77SSepherosa Ziehau 
468015516c77SSepherosa Ziehau 	if (sc->hn_tx_ring_cnt > ring_cnt)
468115516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = ring_cnt;
468215516c77SSepherosa Ziehau 	else
468315516c77SSepherosa Ziehau 		sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
468415516c77SSepherosa Ziehau 	sc->hn_rx_ring_inuse = ring_cnt;
468515516c77SSepherosa Ziehau 
4686*34d68912SSepherosa Ziehau #ifdef RSS
4687*34d68912SSepherosa Ziehau 	if (sc->hn_rx_ring_inuse != rss_getnumbuckets()) {
4688*34d68912SSepherosa Ziehau 		if_printf(sc->hn_ifp, "# of RX rings (%d) does not match "
4689*34d68912SSepherosa Ziehau 		    "# of RSS buckets (%d)\n", sc->hn_rx_ring_inuse,
4690*34d68912SSepherosa Ziehau 		    rss_getnumbuckets());
4691*34d68912SSepherosa Ziehau 	}
4692*34d68912SSepherosa Ziehau #endif
4693*34d68912SSepherosa Ziehau 
469415516c77SSepherosa Ziehau 	if (bootverbose) {
469515516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n",
469615516c77SSepherosa Ziehau 		    sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
469715516c77SSepherosa Ziehau 	}
469815516c77SSepherosa Ziehau }
469915516c77SSepherosa Ziehau 
470015516c77SSepherosa Ziehau static void
470125641fc7SSepherosa Ziehau hn_chan_drain(struct hn_softc *sc, struct vmbus_channel *chan)
470215516c77SSepherosa Ziehau {
470315516c77SSepherosa Ziehau 
470425641fc7SSepherosa Ziehau 	/*
470525641fc7SSepherosa Ziehau 	 * NOTE:
470625641fc7SSepherosa Ziehau 	 * The TX bufring will not be drained by the hypervisor,
470725641fc7SSepherosa Ziehau 	 * if the primary channel is revoked.
470825641fc7SSepherosa Ziehau 	 */
470925641fc7SSepherosa Ziehau 	while (!vmbus_chan_rx_empty(chan) ||
471025641fc7SSepherosa Ziehau 	    (!vmbus_chan_is_revoked(sc->hn_prichan) &&
471125641fc7SSepherosa Ziehau 	     !vmbus_chan_tx_empty(chan)))
471215516c77SSepherosa Ziehau 		pause("waitch", 1);
471315516c77SSepherosa Ziehau 	vmbus_chan_intr_drain(chan);
471415516c77SSepherosa Ziehau }
471515516c77SSepherosa Ziehau 
471615516c77SSepherosa Ziehau static void
471715516c77SSepherosa Ziehau hn_suspend_data(struct hn_softc *sc)
471815516c77SSepherosa Ziehau {
471915516c77SSepherosa Ziehau 	struct vmbus_channel **subch = NULL;
472025641fc7SSepherosa Ziehau 	struct hn_tx_ring *txr;
472115516c77SSepherosa Ziehau 	int i, nsubch;
472215516c77SSepherosa Ziehau 
472315516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
472415516c77SSepherosa Ziehau 
472515516c77SSepherosa Ziehau 	/*
472615516c77SSepherosa Ziehau 	 * Suspend TX.
472715516c77SSepherosa Ziehau 	 */
472815516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
472925641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
473015516c77SSepherosa Ziehau 
473115516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
473215516c77SSepherosa Ziehau 		txr->hn_suspended = 1;
473315516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
473415516c77SSepherosa Ziehau 		/* No one is able send more packets now. */
473515516c77SSepherosa Ziehau 
473625641fc7SSepherosa Ziehau 		/*
473725641fc7SSepherosa Ziehau 		 * Wait for all pending sends to finish.
473825641fc7SSepherosa Ziehau 		 *
473925641fc7SSepherosa Ziehau 		 * NOTE:
474025641fc7SSepherosa Ziehau 		 * We will _not_ receive all pending send-done, if the
474125641fc7SSepherosa Ziehau 		 * primary channel is revoked.
474225641fc7SSepherosa Ziehau 		 */
474325641fc7SSepherosa Ziehau 		while (hn_tx_ring_pending(txr) &&
474425641fc7SSepherosa Ziehau 		    !vmbus_chan_is_revoked(sc->hn_prichan))
474515516c77SSepherosa Ziehau 			pause("hnwtx", 1 /* 1 tick */);
474615516c77SSepherosa Ziehau 	}
474715516c77SSepherosa Ziehau 
474815516c77SSepherosa Ziehau 	/*
474915516c77SSepherosa Ziehau 	 * Disable RX by clearing RX filter.
475015516c77SSepherosa Ziehau 	 */
475115516c77SSepherosa Ziehau 	sc->hn_rx_filter = NDIS_PACKET_TYPE_NONE;
475215516c77SSepherosa Ziehau 	hn_rndis_set_rxfilter(sc, sc->hn_rx_filter);
475315516c77SSepherosa Ziehau 
475415516c77SSepherosa Ziehau 	/*
475515516c77SSepherosa Ziehau 	 * Give RNDIS enough time to flush all pending data packets.
475615516c77SSepherosa Ziehau 	 */
475715516c77SSepherosa Ziehau 	pause("waitrx", (200 * hz) / 1000);
475815516c77SSepherosa Ziehau 
475915516c77SSepherosa Ziehau 	/*
476015516c77SSepherosa Ziehau 	 * Drain RX/TX bufrings and interrupts.
476115516c77SSepherosa Ziehau 	 */
476215516c77SSepherosa Ziehau 	nsubch = sc->hn_rx_ring_inuse - 1;
476315516c77SSepherosa Ziehau 	if (nsubch > 0)
476415516c77SSepherosa Ziehau 		subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
476515516c77SSepherosa Ziehau 
476615516c77SSepherosa Ziehau 	if (subch != NULL) {
476715516c77SSepherosa Ziehau 		for (i = 0; i < nsubch; ++i)
476825641fc7SSepherosa Ziehau 			hn_chan_drain(sc, subch[i]);
476915516c77SSepherosa Ziehau 	}
477025641fc7SSepherosa Ziehau 	hn_chan_drain(sc, sc->hn_prichan);
477115516c77SSepherosa Ziehau 
477215516c77SSepherosa Ziehau 	if (subch != NULL)
477315516c77SSepherosa Ziehau 		vmbus_subchan_rel(subch, nsubch);
477425641fc7SSepherosa Ziehau 
477525641fc7SSepherosa Ziehau 	/*
477625641fc7SSepherosa Ziehau 	 * Drain any pending TX tasks.
477725641fc7SSepherosa Ziehau 	 *
477825641fc7SSepherosa Ziehau 	 * NOTE:
477925641fc7SSepherosa Ziehau 	 * The above hn_chan_drain() can dispatch TX tasks, so the TX
478025641fc7SSepherosa Ziehau 	 * tasks will have to be drained _after_ the above hn_chan_drain()
478125641fc7SSepherosa Ziehau 	 * calls.
478225641fc7SSepherosa Ziehau 	 */
478325641fc7SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
478425641fc7SSepherosa Ziehau 		txr = &sc->hn_tx_ring[i];
478525641fc7SSepherosa Ziehau 
478625641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_tx_task);
478725641fc7SSepherosa Ziehau 		taskqueue_drain(txr->hn_tx_taskq, &txr->hn_txeof_task);
478825641fc7SSepherosa Ziehau 	}
478915516c77SSepherosa Ziehau }
479015516c77SSepherosa Ziehau 
479115516c77SSepherosa Ziehau static void
479215516c77SSepherosa Ziehau hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused)
479315516c77SSepherosa Ziehau {
479415516c77SSepherosa Ziehau 
479515516c77SSepherosa Ziehau 	((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL;
479615516c77SSepherosa Ziehau }
479715516c77SSepherosa Ziehau 
479815516c77SSepherosa Ziehau static void
479915516c77SSepherosa Ziehau hn_suspend_mgmt(struct hn_softc *sc)
480015516c77SSepherosa Ziehau {
480115516c77SSepherosa Ziehau 	struct task task;
480215516c77SSepherosa Ziehau 
480315516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
480415516c77SSepherosa Ziehau 
480515516c77SSepherosa Ziehau 	/*
480615516c77SSepherosa Ziehau 	 * Make sure that hn_mgmt_taskq0 can nolonger be accessed
480715516c77SSepherosa Ziehau 	 * through hn_mgmt_taskq.
480815516c77SSepherosa Ziehau 	 */
480915516c77SSepherosa Ziehau 	TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc);
481015516c77SSepherosa Ziehau 	vmbus_chan_run_task(sc->hn_prichan, &task);
481115516c77SSepherosa Ziehau 
481215516c77SSepherosa Ziehau 	/*
481315516c77SSepherosa Ziehau 	 * Make sure that all pending management tasks are completed.
481415516c77SSepherosa Ziehau 	 */
481515516c77SSepherosa Ziehau 	taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init);
481615516c77SSepherosa Ziehau 	taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status);
481715516c77SSepherosa Ziehau 	taskqueue_drain_all(sc->hn_mgmt_taskq0);
481815516c77SSepherosa Ziehau }
481915516c77SSepherosa Ziehau 
482015516c77SSepherosa Ziehau static void
482115516c77SSepherosa Ziehau hn_suspend(struct hn_softc *sc)
482215516c77SSepherosa Ziehau {
482315516c77SSepherosa Ziehau 
482415516c77SSepherosa Ziehau 	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
482515516c77SSepherosa Ziehau 		hn_suspend_data(sc);
482615516c77SSepherosa Ziehau 	hn_suspend_mgmt(sc);
482715516c77SSepherosa Ziehau }
482815516c77SSepherosa Ziehau 
482915516c77SSepherosa Ziehau static void
483015516c77SSepherosa Ziehau hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt)
483115516c77SSepherosa Ziehau {
483215516c77SSepherosa Ziehau 	int i;
483315516c77SSepherosa Ziehau 
483415516c77SSepherosa Ziehau 	KASSERT(tx_ring_cnt <= sc->hn_tx_ring_cnt,
483515516c77SSepherosa Ziehau 	    ("invalid TX ring count %d", tx_ring_cnt));
483615516c77SSepherosa Ziehau 
483715516c77SSepherosa Ziehau 	for (i = 0; i < tx_ring_cnt; ++i) {
483815516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
483915516c77SSepherosa Ziehau 
484015516c77SSepherosa Ziehau 		mtx_lock(&txr->hn_tx_lock);
484115516c77SSepherosa Ziehau 		txr->hn_suspended = 0;
484215516c77SSepherosa Ziehau 		mtx_unlock(&txr->hn_tx_lock);
484315516c77SSepherosa Ziehau 	}
484415516c77SSepherosa Ziehau }
484515516c77SSepherosa Ziehau 
484615516c77SSepherosa Ziehau static void
484715516c77SSepherosa Ziehau hn_resume_data(struct hn_softc *sc)
484815516c77SSepherosa Ziehau {
484915516c77SSepherosa Ziehau 	int i;
485015516c77SSepherosa Ziehau 
485115516c77SSepherosa Ziehau 	HN_LOCK_ASSERT(sc);
485215516c77SSepherosa Ziehau 
485315516c77SSepherosa Ziehau 	/*
485415516c77SSepherosa Ziehau 	 * Re-enable RX.
485515516c77SSepherosa Ziehau 	 */
485615516c77SSepherosa Ziehau 	hn_set_rxfilter(sc);
485715516c77SSepherosa Ziehau 
485815516c77SSepherosa Ziehau 	/*
485915516c77SSepherosa Ziehau 	 * Make sure to clear suspend status on "all" TX rings,
486015516c77SSepherosa Ziehau 	 * since hn_tx_ring_inuse can be changed after
486115516c77SSepherosa Ziehau 	 * hn_suspend_data().
486215516c77SSepherosa Ziehau 	 */
486315516c77SSepherosa Ziehau 	hn_resume_tx(sc, sc->hn_tx_ring_cnt);
486415516c77SSepherosa Ziehau 
486523bf9e15SSepherosa Ziehau #ifdef HN_IFSTART_SUPPORT
486623bf9e15SSepherosa Ziehau 	if (!hn_use_if_start)
486723bf9e15SSepherosa Ziehau #endif
486823bf9e15SSepherosa Ziehau 	{
486915516c77SSepherosa Ziehau 		/*
487015516c77SSepherosa Ziehau 		 * Flush unused drbrs, since hn_tx_ring_inuse may be
487115516c77SSepherosa Ziehau 		 * reduced.
487215516c77SSepherosa Ziehau 		 */
487315516c77SSepherosa Ziehau 		for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i)
487415516c77SSepherosa Ziehau 			hn_tx_ring_qflush(&sc->hn_tx_ring[i]);
487515516c77SSepherosa Ziehau 	}
487615516c77SSepherosa Ziehau 
487715516c77SSepherosa Ziehau 	/*
487815516c77SSepherosa Ziehau 	 * Kick start TX.
487915516c77SSepherosa Ziehau 	 */
488015516c77SSepherosa Ziehau 	for (i = 0; i < sc->hn_tx_ring_inuse; ++i) {
488115516c77SSepherosa Ziehau 		struct hn_tx_ring *txr = &sc->hn_tx_ring[i];
488215516c77SSepherosa Ziehau 
488315516c77SSepherosa Ziehau 		/*
488415516c77SSepherosa Ziehau 		 * Use txeof task, so that any pending oactive can be
488515516c77SSepherosa Ziehau 		 * cleared properly.
488615516c77SSepherosa Ziehau 		 */
488715516c77SSepherosa Ziehau 		taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
488815516c77SSepherosa Ziehau 	}
488915516c77SSepherosa Ziehau }
489015516c77SSepherosa Ziehau 
489115516c77SSepherosa Ziehau static void
489215516c77SSepherosa Ziehau hn_resume_mgmt(struct hn_softc *sc)
489315516c77SSepherosa Ziehau {
489415516c77SSepherosa Ziehau 
489515516c77SSepherosa Ziehau 	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
489615516c77SSepherosa Ziehau 
489715516c77SSepherosa Ziehau 	/*
489815516c77SSepherosa Ziehau 	 * Kick off network change detection, if it was pending.
489915516c77SSepherosa Ziehau 	 * If no network change was pending, start link status
490015516c77SSepherosa Ziehau 	 * checks, which is more lightweight than network change
490115516c77SSepherosa Ziehau 	 * detection.
490215516c77SSepherosa Ziehau 	 */
490315516c77SSepherosa Ziehau 	if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
490415516c77SSepherosa Ziehau 		hn_change_network(sc);
490515516c77SSepherosa Ziehau 	else
490615516c77SSepherosa Ziehau 		hn_update_link_status(sc);
490715516c77SSepherosa Ziehau }
490815516c77SSepherosa Ziehau 
490915516c77SSepherosa Ziehau static void
491015516c77SSepherosa Ziehau hn_resume(struct hn_softc *sc)
491115516c77SSepherosa Ziehau {
491215516c77SSepherosa Ziehau 
491315516c77SSepherosa Ziehau 	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
491415516c77SSepherosa Ziehau 		hn_resume_data(sc);
491515516c77SSepherosa Ziehau 	hn_resume_mgmt(sc);
491615516c77SSepherosa Ziehau }
491715516c77SSepherosa Ziehau 
491815516c77SSepherosa Ziehau static void
491915516c77SSepherosa Ziehau hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen)
492015516c77SSepherosa Ziehau {
492115516c77SSepherosa Ziehau 	const struct rndis_status_msg *msg;
492215516c77SSepherosa Ziehau 	int ofs;
492315516c77SSepherosa Ziehau 
492415516c77SSepherosa Ziehau 	if (dlen < sizeof(*msg)) {
492515516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid RNDIS status\n");
492615516c77SSepherosa Ziehau 		return;
492715516c77SSepherosa Ziehau 	}
492815516c77SSepherosa Ziehau 	msg = data;
492915516c77SSepherosa Ziehau 
493015516c77SSepherosa Ziehau 	switch (msg->rm_status) {
493115516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_CONNECT:
493215516c77SSepherosa Ziehau 	case RNDIS_STATUS_MEDIA_DISCONNECT:
493315516c77SSepherosa Ziehau 		hn_update_link_status(sc);
493415516c77SSepherosa Ziehau 		break;
493515516c77SSepherosa Ziehau 
493615516c77SSepherosa Ziehau 	case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
493715516c77SSepherosa Ziehau 		/* Not really useful; ignore. */
493815516c77SSepherosa Ziehau 		break;
493915516c77SSepherosa Ziehau 
494015516c77SSepherosa Ziehau 	case RNDIS_STATUS_NETWORK_CHANGE:
494115516c77SSepherosa Ziehau 		ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
494215516c77SSepherosa Ziehau 		if (dlen < ofs + msg->rm_stbuflen ||
494315516c77SSepherosa Ziehau 		    msg->rm_stbuflen < sizeof(uint32_t)) {
494415516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed\n");
494515516c77SSepherosa Ziehau 		} else {
494615516c77SSepherosa Ziehau 			uint32_t change;
494715516c77SSepherosa Ziehau 
494815516c77SSepherosa Ziehau 			memcpy(&change, ((const uint8_t *)msg) + ofs,
494915516c77SSepherosa Ziehau 			    sizeof(change));
495015516c77SSepherosa Ziehau 			if_printf(sc->hn_ifp, "network changed, change %u\n",
495115516c77SSepherosa Ziehau 			    change);
495215516c77SSepherosa Ziehau 		}
495315516c77SSepherosa Ziehau 		hn_change_network(sc);
495415516c77SSepherosa Ziehau 		break;
495515516c77SSepherosa Ziehau 
495615516c77SSepherosa Ziehau 	default:
495715516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
495815516c77SSepherosa Ziehau 		    msg->rm_status);
495915516c77SSepherosa Ziehau 		break;
496015516c77SSepherosa Ziehau 	}
496115516c77SSepherosa Ziehau }
496215516c77SSepherosa Ziehau 
496315516c77SSepherosa Ziehau static int
496415516c77SSepherosa Ziehau hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info)
496515516c77SSepherosa Ziehau {
496615516c77SSepherosa Ziehau 	const struct rndis_pktinfo *pi = info_data;
496715516c77SSepherosa Ziehau 	uint32_t mask = 0;
496815516c77SSepherosa Ziehau 
496915516c77SSepherosa Ziehau 	while (info_dlen != 0) {
497015516c77SSepherosa Ziehau 		const void *data;
497115516c77SSepherosa Ziehau 		uint32_t dlen;
497215516c77SSepherosa Ziehau 
497315516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < sizeof(*pi)))
497415516c77SSepherosa Ziehau 			return (EINVAL);
497515516c77SSepherosa Ziehau 		if (__predict_false(info_dlen < pi->rm_size))
497615516c77SSepherosa Ziehau 			return (EINVAL);
497715516c77SSepherosa Ziehau 		info_dlen -= pi->rm_size;
497815516c77SSepherosa Ziehau 
497915516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
498015516c77SSepherosa Ziehau 			return (EINVAL);
498115516c77SSepherosa Ziehau 		if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
498215516c77SSepherosa Ziehau 			return (EINVAL);
498315516c77SSepherosa Ziehau 		dlen = pi->rm_size - pi->rm_pktinfooffset;
498415516c77SSepherosa Ziehau 		data = pi->rm_data;
498515516c77SSepherosa Ziehau 
498615516c77SSepherosa Ziehau 		switch (pi->rm_type) {
498715516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_VLAN:
498815516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
498915516c77SSepherosa Ziehau 				return (EINVAL);
499015516c77SSepherosa Ziehau 			info->vlan_info = *((const uint32_t *)data);
499115516c77SSepherosa Ziehau 			mask |= HN_RXINFO_VLAN;
499215516c77SSepherosa Ziehau 			break;
499315516c77SSepherosa Ziehau 
499415516c77SSepherosa Ziehau 		case NDIS_PKTINFO_TYPE_CSUM:
499515516c77SSepherosa Ziehau 			if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
499615516c77SSepherosa Ziehau 				return (EINVAL);
499715516c77SSepherosa Ziehau 			info->csum_info = *((const uint32_t *)data);
499815516c77SSepherosa Ziehau 			mask |= HN_RXINFO_CSUM;
499915516c77SSepherosa Ziehau 			break;
500015516c77SSepherosa Ziehau 
500115516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHVAL:
500215516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
500315516c77SSepherosa Ziehau 				return (EINVAL);
500415516c77SSepherosa Ziehau 			info->hash_value = *((const uint32_t *)data);
500515516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHVAL;
500615516c77SSepherosa Ziehau 			break;
500715516c77SSepherosa Ziehau 
500815516c77SSepherosa Ziehau 		case HN_NDIS_PKTINFO_TYPE_HASHINF:
500915516c77SSepherosa Ziehau 			if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
501015516c77SSepherosa Ziehau 				return (EINVAL);
501115516c77SSepherosa Ziehau 			info->hash_info = *((const uint32_t *)data);
501215516c77SSepherosa Ziehau 			mask |= HN_RXINFO_HASHINF;
501315516c77SSepherosa Ziehau 			break;
501415516c77SSepherosa Ziehau 
501515516c77SSepherosa Ziehau 		default:
501615516c77SSepherosa Ziehau 			goto next;
501715516c77SSepherosa Ziehau 		}
501815516c77SSepherosa Ziehau 
501915516c77SSepherosa Ziehau 		if (mask == HN_RXINFO_ALL) {
502015516c77SSepherosa Ziehau 			/* All found; done */
502115516c77SSepherosa Ziehau 			break;
502215516c77SSepherosa Ziehau 		}
502315516c77SSepherosa Ziehau next:
502415516c77SSepherosa Ziehau 		pi = (const struct rndis_pktinfo *)
502515516c77SSepherosa Ziehau 		    ((const uint8_t *)pi + pi->rm_size);
502615516c77SSepherosa Ziehau 	}
502715516c77SSepherosa Ziehau 
502815516c77SSepherosa Ziehau 	/*
502915516c77SSepherosa Ziehau 	 * Final fixup.
503015516c77SSepherosa Ziehau 	 * - If there is no hash value, invalidate the hash info.
503115516c77SSepherosa Ziehau 	 */
503215516c77SSepherosa Ziehau 	if ((mask & HN_RXINFO_HASHVAL) == 0)
503315516c77SSepherosa Ziehau 		info->hash_info = HN_NDIS_HASH_INFO_INVALID;
503415516c77SSepherosa Ziehau 	return (0);
503515516c77SSepherosa Ziehau }
503615516c77SSepherosa Ziehau 
503715516c77SSepherosa Ziehau static __inline bool
503815516c77SSepherosa Ziehau hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
503915516c77SSepherosa Ziehau {
504015516c77SSepherosa Ziehau 
504115516c77SSepherosa Ziehau 	if (off < check_off) {
504215516c77SSepherosa Ziehau 		if (__predict_true(off + len <= check_off))
504315516c77SSepherosa Ziehau 			return (false);
504415516c77SSepherosa Ziehau 	} else if (off > check_off) {
504515516c77SSepherosa Ziehau 		if (__predict_true(check_off + check_len <= off))
504615516c77SSepherosa Ziehau 			return (false);
504715516c77SSepherosa Ziehau 	}
504815516c77SSepherosa Ziehau 	return (true);
504915516c77SSepherosa Ziehau }
505015516c77SSepherosa Ziehau 
505115516c77SSepherosa Ziehau static void
505215516c77SSepherosa Ziehau hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen)
505315516c77SSepherosa Ziehau {
505415516c77SSepherosa Ziehau 	const struct rndis_packet_msg *pkt;
505515516c77SSepherosa Ziehau 	struct hn_rxinfo info;
505615516c77SSepherosa Ziehau 	int data_off, pktinfo_off, data_len, pktinfo_len;
505715516c77SSepherosa Ziehau 
505815516c77SSepherosa Ziehau 	/*
505915516c77SSepherosa Ziehau 	 * Check length.
506015516c77SSepherosa Ziehau 	 */
506115516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*pkt))) {
506215516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
506315516c77SSepherosa Ziehau 		return;
506415516c77SSepherosa Ziehau 	}
506515516c77SSepherosa Ziehau 	pkt = data;
506615516c77SSepherosa Ziehau 
506715516c77SSepherosa Ziehau 	if (__predict_false(dlen < pkt->rm_len)) {
506815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
506915516c77SSepherosa Ziehau 		    "dlen %d, msglen %u\n", dlen, pkt->rm_len);
507015516c77SSepherosa Ziehau 		return;
507115516c77SSepherosa Ziehau 	}
507215516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_len <
507315516c77SSepherosa Ziehau 	    pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
507415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
507515516c77SSepherosa Ziehau 		    "msglen %u, data %u, oob %u, pktinfo %u\n",
507615516c77SSepherosa Ziehau 		    pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
507715516c77SSepherosa Ziehau 		    pkt->rm_pktinfolen);
507815516c77SSepherosa Ziehau 		return;
507915516c77SSepherosa Ziehau 	}
508015516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_datalen == 0)) {
508115516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
508215516c77SSepherosa Ziehau 		return;
508315516c77SSepherosa Ziehau 	}
508415516c77SSepherosa Ziehau 
508515516c77SSepherosa Ziehau 	/*
508615516c77SSepherosa Ziehau 	 * Check offests.
508715516c77SSepherosa Ziehau 	 */
508815516c77SSepherosa Ziehau #define IS_OFFSET_INVALID(ofs)			\
508915516c77SSepherosa Ziehau 	((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN ||	\
509015516c77SSepherosa Ziehau 	 ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
509115516c77SSepherosa Ziehau 
509215516c77SSepherosa Ziehau 	/* XXX Hyper-V does not meet data offset alignment requirement */
509315516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
509415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
509515516c77SSepherosa Ziehau 		    "data offset %u\n", pkt->rm_dataoffset);
509615516c77SSepherosa Ziehau 		return;
509715516c77SSepherosa Ziehau 	}
509815516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdataoffset > 0 &&
509915516c77SSepherosa Ziehau 	    IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
510015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
510115516c77SSepherosa Ziehau 		    "oob offset %u\n", pkt->rm_oobdataoffset);
510215516c77SSepherosa Ziehau 		return;
510315516c77SSepherosa Ziehau 	}
510415516c77SSepherosa Ziehau 	if (__predict_true(pkt->rm_pktinfooffset > 0) &&
510515516c77SSepherosa Ziehau 	    __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
510615516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
510715516c77SSepherosa Ziehau 		    "pktinfo offset %u\n", pkt->rm_pktinfooffset);
510815516c77SSepherosa Ziehau 		return;
510915516c77SSepherosa Ziehau 	}
511015516c77SSepherosa Ziehau 
511115516c77SSepherosa Ziehau #undef IS_OFFSET_INVALID
511215516c77SSepherosa Ziehau 
511315516c77SSepherosa Ziehau 	data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
511415516c77SSepherosa Ziehau 	data_len = pkt->rm_datalen;
511515516c77SSepherosa Ziehau 	pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
511615516c77SSepherosa Ziehau 	pktinfo_len = pkt->rm_pktinfolen;
511715516c77SSepherosa Ziehau 
511815516c77SSepherosa Ziehau 	/*
511915516c77SSepherosa Ziehau 	 * Check OOB coverage.
512015516c77SSepherosa Ziehau 	 */
512115516c77SSepherosa Ziehau 	if (__predict_false(pkt->rm_oobdatalen != 0)) {
512215516c77SSepherosa Ziehau 		int oob_off, oob_len;
512315516c77SSepherosa Ziehau 
512415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "got oobdata\n");
512515516c77SSepherosa Ziehau 		oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
512615516c77SSepherosa Ziehau 		oob_len = pkt->rm_oobdatalen;
512715516c77SSepherosa Ziehau 
512815516c77SSepherosa Ziehau 		if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
512915516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
513015516c77SSepherosa Ziehau 			    "oob overflow, msglen %u, oob abs %d len %d\n",
513115516c77SSepherosa Ziehau 			    pkt->rm_len, oob_off, oob_len);
513215516c77SSepherosa Ziehau 			return;
513315516c77SSepherosa Ziehau 		}
513415516c77SSepherosa Ziehau 
513515516c77SSepherosa Ziehau 		/*
513615516c77SSepherosa Ziehau 		 * Check against data.
513715516c77SSepherosa Ziehau 		 */
513815516c77SSepherosa Ziehau 		if (hn_rndis_check_overlap(oob_off, oob_len,
513915516c77SSepherosa Ziehau 		    data_off, data_len)) {
514015516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
514115516c77SSepherosa Ziehau 			    "oob overlaps data, oob abs %d len %d, "
514215516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
514315516c77SSepherosa Ziehau 			    oob_off, oob_len, data_off, data_len);
514415516c77SSepherosa Ziehau 			return;
514515516c77SSepherosa Ziehau 		}
514615516c77SSepherosa Ziehau 
514715516c77SSepherosa Ziehau 		/*
514815516c77SSepherosa Ziehau 		 * Check against pktinfo.
514915516c77SSepherosa Ziehau 		 */
515015516c77SSepherosa Ziehau 		if (pktinfo_len != 0 &&
515115516c77SSepherosa Ziehau 		    hn_rndis_check_overlap(oob_off, oob_len,
515215516c77SSepherosa Ziehau 		    pktinfo_off, pktinfo_len)) {
515315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
515415516c77SSepherosa Ziehau 			    "oob overlaps pktinfo, oob abs %d len %d, "
515515516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
515615516c77SSepherosa Ziehau 			    oob_off, oob_len, pktinfo_off, pktinfo_len);
515715516c77SSepherosa Ziehau 			return;
515815516c77SSepherosa Ziehau 		}
515915516c77SSepherosa Ziehau 	}
516015516c77SSepherosa Ziehau 
516115516c77SSepherosa Ziehau 	/*
516215516c77SSepherosa Ziehau 	 * Check per-packet-info coverage and find useful per-packet-info.
516315516c77SSepherosa Ziehau 	 */
516415516c77SSepherosa Ziehau 	info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
516515516c77SSepherosa Ziehau 	info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
516615516c77SSepherosa Ziehau 	info.hash_info = HN_NDIS_HASH_INFO_INVALID;
516715516c77SSepherosa Ziehau 	if (__predict_true(pktinfo_len != 0)) {
516815516c77SSepherosa Ziehau 		bool overlap;
516915516c77SSepherosa Ziehau 		int error;
517015516c77SSepherosa Ziehau 
517115516c77SSepherosa Ziehau 		if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
517215516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
517315516c77SSepherosa Ziehau 			    "pktinfo overflow, msglen %u, "
517415516c77SSepherosa Ziehau 			    "pktinfo abs %d len %d\n",
517515516c77SSepherosa Ziehau 			    pkt->rm_len, pktinfo_off, pktinfo_len);
517615516c77SSepherosa Ziehau 			return;
517715516c77SSepherosa Ziehau 		}
517815516c77SSepherosa Ziehau 
517915516c77SSepherosa Ziehau 		/*
518015516c77SSepherosa Ziehau 		 * Check packet info coverage.
518115516c77SSepherosa Ziehau 		 */
518215516c77SSepherosa Ziehau 		overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
518315516c77SSepherosa Ziehau 		    data_off, data_len);
518415516c77SSepherosa Ziehau 		if (__predict_false(overlap)) {
518515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
518615516c77SSepherosa Ziehau 			    "pktinfo overlap data, pktinfo abs %d len %d, "
518715516c77SSepherosa Ziehau 			    "data abs %d len %d\n",
518815516c77SSepherosa Ziehau 			    pktinfo_off, pktinfo_len, data_off, data_len);
518915516c77SSepherosa Ziehau 			return;
519015516c77SSepherosa Ziehau 		}
519115516c77SSepherosa Ziehau 
519215516c77SSepherosa Ziehau 		/*
519315516c77SSepherosa Ziehau 		 * Find useful per-packet-info.
519415516c77SSepherosa Ziehau 		 */
519515516c77SSepherosa Ziehau 		error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
519615516c77SSepherosa Ziehau 		    pktinfo_len, &info);
519715516c77SSepherosa Ziehau 		if (__predict_false(error)) {
519815516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
519915516c77SSepherosa Ziehau 			    "pktinfo\n");
520015516c77SSepherosa Ziehau 			return;
520115516c77SSepherosa Ziehau 		}
520215516c77SSepherosa Ziehau 	}
520315516c77SSepherosa Ziehau 
520415516c77SSepherosa Ziehau 	if (__predict_false(data_off + data_len > pkt->rm_len)) {
520515516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
520615516c77SSepherosa Ziehau 		    "data overflow, msglen %u, data abs %d len %d\n",
520715516c77SSepherosa Ziehau 		    pkt->rm_len, data_off, data_len);
520815516c77SSepherosa Ziehau 		return;
520915516c77SSepherosa Ziehau 	}
521015516c77SSepherosa Ziehau 	hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
521115516c77SSepherosa Ziehau }
521215516c77SSepherosa Ziehau 
521315516c77SSepherosa Ziehau static __inline void
521415516c77SSepherosa Ziehau hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen)
521515516c77SSepherosa Ziehau {
521615516c77SSepherosa Ziehau 	const struct rndis_msghdr *hdr;
521715516c77SSepherosa Ziehau 
521815516c77SSepherosa Ziehau 	if (__predict_false(dlen < sizeof(*hdr))) {
521915516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
522015516c77SSepherosa Ziehau 		return;
522115516c77SSepherosa Ziehau 	}
522215516c77SSepherosa Ziehau 	hdr = data;
522315516c77SSepherosa Ziehau 
522415516c77SSepherosa Ziehau 	if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) {
522515516c77SSepherosa Ziehau 		/* Hot data path. */
522615516c77SSepherosa Ziehau 		hn_rndis_rx_data(rxr, data, dlen);
522715516c77SSepherosa Ziehau 		/* Done! */
522815516c77SSepherosa Ziehau 		return;
522915516c77SSepherosa Ziehau 	}
523015516c77SSepherosa Ziehau 
523115516c77SSepherosa Ziehau 	if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG)
523215516c77SSepherosa Ziehau 		hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen);
523315516c77SSepherosa Ziehau 	else
523415516c77SSepherosa Ziehau 		hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen);
523515516c77SSepherosa Ziehau }
523615516c77SSepherosa Ziehau 
523715516c77SSepherosa Ziehau static void
523815516c77SSepherosa Ziehau hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
523915516c77SSepherosa Ziehau {
524015516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *hdr;
524115516c77SSepherosa Ziehau 
524215516c77SSepherosa Ziehau 	if (VMBUS_CHANPKT_DATALEN(pkt) < sizeof(*hdr)) {
524315516c77SSepherosa Ziehau 		if_printf(sc->hn_ifp, "invalid nvs notify\n");
524415516c77SSepherosa Ziehau 		return;
524515516c77SSepherosa Ziehau 	}
524615516c77SSepherosa Ziehau 	hdr = VMBUS_CHANPKT_CONST_DATA(pkt);
524715516c77SSepherosa Ziehau 
524815516c77SSepherosa Ziehau 	if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) {
524915516c77SSepherosa Ziehau 		/* Useless; ignore */
525015516c77SSepherosa Ziehau 		return;
525115516c77SSepherosa Ziehau 	}
525215516c77SSepherosa Ziehau 	if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type);
525315516c77SSepherosa Ziehau }
525415516c77SSepherosa Ziehau 
525515516c77SSepherosa Ziehau static void
525615516c77SSepherosa Ziehau hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan,
525715516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkt)
525815516c77SSepherosa Ziehau {
525915516c77SSepherosa Ziehau 	struct hn_nvs_sendctx *sndc;
526015516c77SSepherosa Ziehau 
526115516c77SSepherosa Ziehau 	sndc = (struct hn_nvs_sendctx *)(uintptr_t)pkt->cph_xactid;
526215516c77SSepherosa Ziehau 	sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt),
526315516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_DATALEN(pkt));
526415516c77SSepherosa Ziehau 	/*
526515516c77SSepherosa Ziehau 	 * NOTE:
526615516c77SSepherosa Ziehau 	 * 'sndc' CAN NOT be accessed anymore, since it can be freed by
526715516c77SSepherosa Ziehau 	 * its callback.
526815516c77SSepherosa Ziehau 	 */
526915516c77SSepherosa Ziehau }
527015516c77SSepherosa Ziehau 
527115516c77SSepherosa Ziehau static void
527215516c77SSepherosa Ziehau hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
527315516c77SSepherosa Ziehau     const struct vmbus_chanpkt_hdr *pkthdr)
527415516c77SSepherosa Ziehau {
527515516c77SSepherosa Ziehau 	const struct vmbus_chanpkt_rxbuf *pkt;
527615516c77SSepherosa Ziehau 	const struct hn_nvs_hdr *nvs_hdr;
527715516c77SSepherosa Ziehau 	int count, i, hlen;
527815516c77SSepherosa Ziehau 
527915516c77SSepherosa Ziehau 	if (__predict_false(VMBUS_CHANPKT_DATALEN(pkthdr) < sizeof(*nvs_hdr))) {
528015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid nvs RNDIS\n");
528115516c77SSepherosa Ziehau 		return;
528215516c77SSepherosa Ziehau 	}
528315516c77SSepherosa Ziehau 	nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr);
528415516c77SSepherosa Ziehau 
528515516c77SSepherosa Ziehau 	/* Make sure that this is a RNDIS message. */
528615516c77SSepherosa Ziehau 	if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) {
528715516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n",
528815516c77SSepherosa Ziehau 		    nvs_hdr->nvs_type);
528915516c77SSepherosa Ziehau 		return;
529015516c77SSepherosa Ziehau 	}
529115516c77SSepherosa Ziehau 
529215516c77SSepherosa Ziehau 	hlen = VMBUS_CHANPKT_GETLEN(pkthdr->cph_hlen);
529315516c77SSepherosa Ziehau 	if (__predict_false(hlen < sizeof(*pkt))) {
529415516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf chanpkt\n");
529515516c77SSepherosa Ziehau 		return;
529615516c77SSepherosa Ziehau 	}
529715516c77SSepherosa Ziehau 	pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
529815516c77SSepherosa Ziehau 
529915516c77SSepherosa Ziehau 	if (__predict_false(pkt->cp_rxbuf_id != HN_NVS_RXBUF_SIG)) {
530015516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_id 0x%08x\n",
530115516c77SSepherosa Ziehau 		    pkt->cp_rxbuf_id);
530215516c77SSepherosa Ziehau 		return;
530315516c77SSepherosa Ziehau 	}
530415516c77SSepherosa Ziehau 
530515516c77SSepherosa Ziehau 	count = pkt->cp_rxbuf_cnt;
530615516c77SSepherosa Ziehau 	if (__predict_false(hlen <
530715516c77SSepherosa Ziehau 	    __offsetof(struct vmbus_chanpkt_rxbuf, cp_rxbuf[count]))) {
530815516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "invalid rxbuf_cnt %d\n", count);
530915516c77SSepherosa Ziehau 		return;
531015516c77SSepherosa Ziehau 	}
531115516c77SSepherosa Ziehau 
531215516c77SSepherosa Ziehau 	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
531315516c77SSepherosa Ziehau 	for (i = 0; i < count; ++i) {
531415516c77SSepherosa Ziehau 		int ofs, len;
531515516c77SSepherosa Ziehau 
531615516c77SSepherosa Ziehau 		ofs = pkt->cp_rxbuf[i].rb_ofs;
531715516c77SSepherosa Ziehau 		len = pkt->cp_rxbuf[i].rb_len;
531815516c77SSepherosa Ziehau 		if (__predict_false(ofs + len > HN_RXBUF_SIZE)) {
531915516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "%dth RNDIS msg overflow rxbuf, "
532015516c77SSepherosa Ziehau 			    "ofs %d, len %d\n", i, ofs, len);
532115516c77SSepherosa Ziehau 			continue;
532215516c77SSepherosa Ziehau 		}
532315516c77SSepherosa Ziehau 		hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len);
532415516c77SSepherosa Ziehau 	}
532515516c77SSepherosa Ziehau 
532615516c77SSepherosa Ziehau 	/*
532715516c77SSepherosa Ziehau 	 * Ack the consumed RXBUF associated w/ this channel packet,
532815516c77SSepherosa Ziehau 	 * so that this RXBUF can be recycled by the hypervisor.
532915516c77SSepherosa Ziehau 	 */
533015516c77SSepherosa Ziehau 	hn_nvs_ack_rxbuf(rxr, chan, pkt->cp_hdr.cph_xactid);
533115516c77SSepherosa Ziehau }
533215516c77SSepherosa Ziehau 
533315516c77SSepherosa Ziehau static void
533415516c77SSepherosa Ziehau hn_nvs_ack_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
533515516c77SSepherosa Ziehau     uint64_t tid)
533615516c77SSepherosa Ziehau {
533715516c77SSepherosa Ziehau 	struct hn_nvs_rndis_ack ack;
533815516c77SSepherosa Ziehau 	int retries, error;
533915516c77SSepherosa Ziehau 
534015516c77SSepherosa Ziehau 	ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK;
534115516c77SSepherosa Ziehau 	ack.nvs_status = HN_NVS_STATUS_OK;
534215516c77SSepherosa Ziehau 
534315516c77SSepherosa Ziehau 	retries = 0;
534415516c77SSepherosa Ziehau again:
534515516c77SSepherosa Ziehau 	error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP,
534615516c77SSepherosa Ziehau 	    VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid);
534715516c77SSepherosa Ziehau 	if (__predict_false(error == EAGAIN)) {
534815516c77SSepherosa Ziehau 		/*
534915516c77SSepherosa Ziehau 		 * NOTE:
535015516c77SSepherosa Ziehau 		 * This should _not_ happen in real world, since the
535115516c77SSepherosa Ziehau 		 * consumption of the TX bufring from the TX path is
535215516c77SSepherosa Ziehau 		 * controlled.
535315516c77SSepherosa Ziehau 		 */
535415516c77SSepherosa Ziehau 		if (rxr->hn_ack_failed == 0)
535515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "RXBUF ack retry\n");
535615516c77SSepherosa Ziehau 		rxr->hn_ack_failed++;
535715516c77SSepherosa Ziehau 		retries++;
535815516c77SSepherosa Ziehau 		if (retries < 10) {
535915516c77SSepherosa Ziehau 			DELAY(100);
536015516c77SSepherosa Ziehau 			goto again;
536115516c77SSepherosa Ziehau 		}
536215516c77SSepherosa Ziehau 		/* RXBUF leaks! */
536315516c77SSepherosa Ziehau 		if_printf(rxr->hn_ifp, "RXBUF ack failed\n");
536415516c77SSepherosa Ziehau 	}
536515516c77SSepherosa Ziehau }
536615516c77SSepherosa Ziehau 
536715516c77SSepherosa Ziehau static void
536815516c77SSepherosa Ziehau hn_chan_callback(struct vmbus_channel *chan, void *xrxr)
536915516c77SSepherosa Ziehau {
537015516c77SSepherosa Ziehau 	struct hn_rx_ring *rxr = xrxr;
537115516c77SSepherosa Ziehau 	struct hn_softc *sc = rxr->hn_ifp->if_softc;
537215516c77SSepherosa Ziehau 
537315516c77SSepherosa Ziehau 	for (;;) {
537415516c77SSepherosa Ziehau 		struct vmbus_chanpkt_hdr *pkt = rxr->hn_pktbuf;
537515516c77SSepherosa Ziehau 		int error, pktlen;
537615516c77SSepherosa Ziehau 
537715516c77SSepherosa Ziehau 		pktlen = rxr->hn_pktbuf_len;
537815516c77SSepherosa Ziehau 		error = vmbus_chan_recv_pkt(chan, pkt, &pktlen);
537915516c77SSepherosa Ziehau 		if (__predict_false(error == ENOBUFS)) {
538015516c77SSepherosa Ziehau 			void *nbuf;
538115516c77SSepherosa Ziehau 			int nlen;
538215516c77SSepherosa Ziehau 
538315516c77SSepherosa Ziehau 			/*
538415516c77SSepherosa Ziehau 			 * Expand channel packet buffer.
538515516c77SSepherosa Ziehau 			 *
538615516c77SSepherosa Ziehau 			 * XXX
538715516c77SSepherosa Ziehau 			 * Use M_WAITOK here, since allocation failure
538815516c77SSepherosa Ziehau 			 * is fatal.
538915516c77SSepherosa Ziehau 			 */
539015516c77SSepherosa Ziehau 			nlen = rxr->hn_pktbuf_len * 2;
539115516c77SSepherosa Ziehau 			while (nlen < pktlen)
539215516c77SSepherosa Ziehau 				nlen *= 2;
539315516c77SSepherosa Ziehau 			nbuf = malloc(nlen, M_DEVBUF, M_WAITOK);
539415516c77SSepherosa Ziehau 
539515516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "expand pktbuf %d -> %d\n",
539615516c77SSepherosa Ziehau 			    rxr->hn_pktbuf_len, nlen);
539715516c77SSepherosa Ziehau 
539815516c77SSepherosa Ziehau 			free(rxr->hn_pktbuf, M_DEVBUF);
539915516c77SSepherosa Ziehau 			rxr->hn_pktbuf = nbuf;
540015516c77SSepherosa Ziehau 			rxr->hn_pktbuf_len = nlen;
540115516c77SSepherosa Ziehau 			/* Retry! */
540215516c77SSepherosa Ziehau 			continue;
540315516c77SSepherosa Ziehau 		} else if (__predict_false(error == EAGAIN)) {
540415516c77SSepherosa Ziehau 			/* No more channel packets; done! */
540515516c77SSepherosa Ziehau 			break;
540615516c77SSepherosa Ziehau 		}
540715516c77SSepherosa Ziehau 		KASSERT(!error, ("vmbus_chan_recv_pkt failed: %d", error));
540815516c77SSepherosa Ziehau 
540915516c77SSepherosa Ziehau 		switch (pkt->cph_type) {
541015516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_COMP:
541115516c77SSepherosa Ziehau 			hn_nvs_handle_comp(sc, chan, pkt);
541215516c77SSepherosa Ziehau 			break;
541315516c77SSepherosa Ziehau 
541415516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_RXBUF:
541515516c77SSepherosa Ziehau 			hn_nvs_handle_rxbuf(rxr, chan, pkt);
541615516c77SSepherosa Ziehau 			break;
541715516c77SSepherosa Ziehau 
541815516c77SSepherosa Ziehau 		case VMBUS_CHANPKT_TYPE_INBAND:
541915516c77SSepherosa Ziehau 			hn_nvs_handle_notify(sc, pkt);
542015516c77SSepherosa Ziehau 			break;
542115516c77SSepherosa Ziehau 
542215516c77SSepherosa Ziehau 		default:
542315516c77SSepherosa Ziehau 			if_printf(rxr->hn_ifp, "unknown chan pkt %u\n",
542415516c77SSepherosa Ziehau 			    pkt->cph_type);
542515516c77SSepherosa Ziehau 			break;
542615516c77SSepherosa Ziehau 		}
542715516c77SSepherosa Ziehau 	}
542815516c77SSepherosa Ziehau 	hn_chan_rollup(rxr, rxr->hn_txr);
542915516c77SSepherosa Ziehau }
543015516c77SSepherosa Ziehau 
543115516c77SSepherosa Ziehau static void
543215516c77SSepherosa Ziehau hn_tx_taskq_create(void *arg __unused)
543315516c77SSepherosa Ziehau {
5434fdd0222aSSepherosa Ziehau 	int i;
5435fdd0222aSSepherosa Ziehau 
5436fdd0222aSSepherosa Ziehau 	/*
5437fdd0222aSSepherosa Ziehau 	 * Fix the # of TX taskqueues.
5438fdd0222aSSepherosa Ziehau 	 */
5439fdd0222aSSepherosa Ziehau 	if (hn_tx_taskq_cnt <= 0)
5440fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = 1;
5441fdd0222aSSepherosa Ziehau 	else if (hn_tx_taskq_cnt > mp_ncpus)
5442fdd0222aSSepherosa Ziehau 		hn_tx_taskq_cnt = mp_ncpus;
544315516c77SSepherosa Ziehau 
54440e11868dSSepherosa Ziehau 	/*
54450e11868dSSepherosa Ziehau 	 * Fix the TX taskqueue mode.
54460e11868dSSepherosa Ziehau 	 */
54470e11868dSSepherosa Ziehau 	switch (hn_tx_taskq_mode) {
54480e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_INDEP:
54490e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_GLOBAL:
54500e11868dSSepherosa Ziehau 	case HN_TX_TASKQ_M_EVTTQ:
54510e11868dSSepherosa Ziehau 		break;
54520e11868dSSepherosa Ziehau 	default:
54530e11868dSSepherosa Ziehau 		hn_tx_taskq_mode = HN_TX_TASKQ_M_INDEP;
54540e11868dSSepherosa Ziehau 		break;
54550e11868dSSepherosa Ziehau 	}
54560e11868dSSepherosa Ziehau 
545715516c77SSepherosa Ziehau 	if (vm_guest != VM_GUEST_HV)
545815516c77SSepherosa Ziehau 		return;
545915516c77SSepherosa Ziehau 
54600e11868dSSepherosa Ziehau 	if (hn_tx_taskq_mode != HN_TX_TASKQ_M_GLOBAL)
546115516c77SSepherosa Ziehau 		return;
546215516c77SSepherosa Ziehau 
5463fdd0222aSSepherosa Ziehau 	hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *),
5464fdd0222aSSepherosa Ziehau 	    M_DEVBUF, M_WAITOK);
5465fdd0222aSSepherosa Ziehau 	for (i = 0; i < hn_tx_taskq_cnt; ++i) {
5466fdd0222aSSepherosa Ziehau 		hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK,
5467fdd0222aSSepherosa Ziehau 		    taskqueue_thread_enqueue, &hn_tx_taskque[i]);
5468fdd0222aSSepherosa Ziehau 		taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET,
5469fdd0222aSSepherosa Ziehau 		    "hn tx%d", i);
5470fdd0222aSSepherosa Ziehau 	}
547115516c77SSepherosa Ziehau }
547215516c77SSepherosa Ziehau SYSINIT(hn_txtq_create, SI_SUB_DRIVERS, SI_ORDER_SECOND,
547315516c77SSepherosa Ziehau     hn_tx_taskq_create, NULL);
547415516c77SSepherosa Ziehau 
547515516c77SSepherosa Ziehau static void
547615516c77SSepherosa Ziehau hn_tx_taskq_destroy(void *arg __unused)
547715516c77SSepherosa Ziehau {
547815516c77SSepherosa Ziehau 
5479fdd0222aSSepherosa Ziehau 	if (hn_tx_taskque != NULL) {
5480fdd0222aSSepherosa Ziehau 		int i;
5481fdd0222aSSepherosa Ziehau 
5482fdd0222aSSepherosa Ziehau 		for (i = 0; i < hn_tx_taskq_cnt; ++i)
5483fdd0222aSSepherosa Ziehau 			taskqueue_free(hn_tx_taskque[i]);
5484fdd0222aSSepherosa Ziehau 		free(hn_tx_taskque, M_DEVBUF);
5485fdd0222aSSepherosa Ziehau 	}
548615516c77SSepherosa Ziehau }
548715516c77SSepherosa Ziehau SYSUNINIT(hn_txtq_destroy, SI_SUB_DRIVERS, SI_ORDER_SECOND,
548815516c77SSepherosa Ziehau     hn_tx_taskq_destroy, NULL);
5489